fix(ui): sidebar icon centering and local dev setup (#68)
This commit is contained in:
parent
337117f895
commit
89b0f8e88e
@ -1,104 +1,112 @@
|
||||
# Local Development Setup
|
||||
|
||||
This directory contains patches and scripts to enable local development without WorkOS authentication.
|
||||
This directory contains files for running Compass locally without Cloudflare or WorkOS credentials.
|
||||
|
||||
## What This Does
|
||||
|
||||
These patches modify Compass to run in development mode without requiring WorkOS SSO authentication:
|
||||
1. **Bypasses WorkOS auth** - Middleware skips auth when API keys aren't configured
|
||||
2. **Local SQLite database** - Uses sql.js (pure JS SQLite) instead of Cloudflare D1
|
||||
3. **Dev user** - `dev@compass.io` with admin role
|
||||
4. **Full database support** - Real queries work, not just mocks
|
||||
|
||||
1. **Bypasses WorkOS auth checks** - Middleware redirects `/` to `/dashboard` when WorkOS isn't configured
|
||||
2. **Mock D1 database** - Returns empty arrays for queries instead of throwing errors
|
||||
3. **Wraps Cloudflare context** - Returns mock `{ env: { DB: null }, ctx: {} }` when WorkOS isn't configured
|
||||
4. **Skips OpenNext initialization** - Only runs when WorkOS API keys are properly set
|
||||
|
||||
## How to Use
|
||||
|
||||
### Quick Start
|
||||
## Quick Start
|
||||
|
||||
From the compass directory:
|
||||
|
||||
```bash
|
||||
.dev-setup/apply-dev.sh
|
||||
bun dev
|
||||
```
|
||||
|
||||
This will apply all necessary patches to enable local development.
|
||||
## Manual Setup
|
||||
|
||||
### Manual Application
|
||||
|
||||
If the automated script fails, you can apply patches manually:
|
||||
|
||||
1. **middleware.ts** - Redirects root to dashboard, allows all requests without auth
|
||||
2. **lib/auth.ts** - Checks for "your_" and "placeholder" in WorkOS keys
|
||||
3. **lib/cloudflare-context.ts** - New file that wraps `getCloudflareContext()`
|
||||
4. **db/index.ts** - Returns mock DB when `d1` parameter is `null`
|
||||
5. **next.config.ts** - Only initializes OpenNext Cloudflare when WorkOS is configured
|
||||
6. **.gitignore** - Ignores `src/lib/cloudflare-context.ts` so it's not committed
|
||||
|
||||
### Undoing Changes
|
||||
|
||||
To remove dev setup and restore original behavior:
|
||||
If the script fails, apply manually:
|
||||
|
||||
```bash
|
||||
git restore src/middleware.ts
|
||||
git restore src/lib/auth.ts
|
||||
git restore src/db/index.ts
|
||||
git restore next.config.ts
|
||||
git restore .gitignore
|
||||
rm src/lib/cloudflare-context.ts
|
||||
# 1. Install sql.js
|
||||
bun add sql.js
|
||||
|
||||
# 2. Copy dev files
|
||||
cp .dev-setup/files/middleware.ts src/middleware.ts
|
||||
cp .dev-setup/files/next.config.ts next.config.ts
|
||||
cp .dev-setup/files/cloudflare-context.ts src/lib/cloudflare-context.ts
|
||||
cp .dev-setup/files/db.ts src/lib/db.ts
|
||||
mkdir -p scripts
|
||||
cp .dev-setup/files/init-local-db.ts scripts/init-local-db.ts
|
||||
|
||||
# 3. Replace imports
|
||||
find src -name "*.ts" -o -name "*.tsx" | xargs sed -i '' 's|from "@opennextjs/cloudflare"|from "@/lib/db"|g'
|
||||
|
||||
# 4. Add script to package.json
|
||||
node -e 'const fs=require("fs");const p=JSON.parse(fs.readFileSync("package.json"));p.scripts["db:init-local"]="bun scripts/init-local-db.ts";fs.writeFileSync("package.json",JSON.stringify(p,null,2)+"\n")'
|
||||
|
||||
# 5. Initialize database
|
||||
bun run db:init-local
|
||||
|
||||
# 6. Start dev server
|
||||
bun dev
|
||||
```
|
||||
|
||||
## Reverting
|
||||
|
||||
```bash
|
||||
.dev-setup/restore-dev.sh
|
||||
```
|
||||
|
||||
Or manually:
|
||||
|
||||
```bash
|
||||
git checkout HEAD -- src/middleware.ts next.config.ts package.json bun.lock
|
||||
rm -f src/lib/cloudflare-context.ts src/lib/db.ts scripts/init-local-db.ts
|
||||
find src -name "*.ts" -o -name "*.tsx" | xargs sed -i '' 's|from "@/lib/db"|from "@opennextjs/cloudflare"|g'
|
||||
bun remove sql.js
|
||||
rm -f local.db local.db-wal local.db-shm
|
||||
```
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `files/middleware.ts` | Bypasses WorkOS when not configured |
|
||||
| `files/next.config.ts` | Removes Cloudflare dev proxy |
|
||||
| `files/cloudflare-context.ts` | sql.js wrapper mimicking D1 |
|
||||
| `files/db.ts` | Conditional import wrapper |
|
||||
| `files/init-local-db.ts` | Migration runner for local DB |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
To configure WorkOS auth properly (to disable dev mode):
|
||||
To use real WorkOS auth (disables dev mode):
|
||||
|
||||
```env
|
||||
WORKOS_API_KEY=sk_dev_xxxxx
|
||||
WORKOS_CLIENT_ID=client_xxxxx
|
||||
WORKOS_REDIRECT_URI=http://localhost:3000
|
||||
```
|
||||
|
||||
With these set, the dev patches will automatically skip and use real WorkOS authentication.
|
||||
Values containing "placeholder" trigger dev mode.
|
||||
|
||||
## Dev Mode Indicators
|
||||
## Database
|
||||
|
||||
When in dev mode (WorkOS not configured):
|
||||
- Dashboard loads directly without login redirect
|
||||
- Database queries return empty arrays instead of errors
|
||||
- Cloudflare context returns null DB instead of throwing
|
||||
- Stored in `local.db` at repo root
|
||||
- Migrations applied from `drizzle/` directory
|
||||
- Persisted between sessions
|
||||
|
||||
## Files Created/Modified
|
||||
## Limitations
|
||||
|
||||
### New Files (dev only)
|
||||
- `src/lib/cloudflare-context.ts` - Wraps `getCloudflareContext()` with dev bypass
|
||||
|
||||
### Modified Files
|
||||
- `src/middleware.ts` - Added WorkOS detection and dev bypass
|
||||
- `src/lib/auth.ts` - Enhanced WorkOS configuration detection
|
||||
- `src/db/index.ts` - Added mock DB support for null D1 parameter
|
||||
- `next.config.ts` - Conditional OpenNext initialization
|
||||
- `.gitignore` - Added `cloudflare-context.ts` to prevent commits
|
||||
|
||||
## Future Development
|
||||
|
||||
Place any new dev-only components or patches in this directory following the same pattern:
|
||||
|
||||
1. **Patch files** - Store in `patches/` with `.patch` extension
|
||||
2. **New files** - Store in `files/` directory
|
||||
3. **Update apply-dev.sh** - Add your patches to the apply script
|
||||
4. **Document here** - Update this README with changes
|
||||
Features requiring external APIs won't work offline:
|
||||
- NetSuite sync
|
||||
- Google Drive integration
|
||||
- AI agent (needs OPENROUTER_API_KEY)
|
||||
- Push notifications
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Build errors after applying patches:**
|
||||
- Check that `src/lib/cloudflare-context.ts` exists
|
||||
- Verify all patches applied cleanly
|
||||
- Try manual patch application if automated script fails
|
||||
**"Cannot find module 'sql.js'"**
|
||||
- Run `bun add sql.js`
|
||||
|
||||
**Auth still required:**
|
||||
- Verify `.env.local` or `.dev.vars` doesn't have placeholder values
|
||||
- Check that WorkOS environment variables aren't set (if you want dev mode)
|
||||
- Restart dev server after applying patches
|
||||
**Database errors**
|
||||
- Re-run `bun run db:init-local`
|
||||
- Check `local.db` exists
|
||||
|
||||
**Database errors:**
|
||||
- Ensure `src/db/index.ts` patch was applied
|
||||
- Check that mock DB is being returned when `d1` is null
|
||||
**Auth still required**
|
||||
- Verify no WORKOS_API_KEY set
|
||||
- Check middleware.ts was copied
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "🔧 Applying local development setup patches..."
|
||||
echo "🔧 Applying local development setup..."
|
||||
|
||||
# Check if we're in the compass directory
|
||||
if [ ! -f "package.json" ] || [ ! -d "src" ]; then
|
||||
echo "❌ Error: Please run this script from the compass directory"
|
||||
exit 1
|
||||
@ -11,55 +10,45 @@ fi
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Apply middleware patch
|
||||
echo "📦 Applying middleware.ts patch..."
|
||||
patch -p1 < "$SCRIPT_DIR/patches/middleware.patch" || {
|
||||
echo "⚠️ middleware.ts patch failed, applying manually..."
|
||||
cat "$SCRIPT_DIR/patches/middleware.patch"
|
||||
}
|
||||
# 1. Install sql.js
|
||||
echo "📦 Installing sql.js..."
|
||||
bun add sql.js
|
||||
|
||||
# Apply auth patch
|
||||
echo "📦 Applying auth.ts patch..."
|
||||
patch -p1 < "$SCRIPT_DIR/patches/auth.patch" || {
|
||||
echo "⚠️ auth.ts patch failed, applying manually..."
|
||||
cat "$SCRIPT_DIR/patches/auth.patch"
|
||||
}
|
||||
# 2. Copy dev files
|
||||
echo "📦 Copying dev files..."
|
||||
cp "$SCRIPT_DIR/files/middleware.ts" src/middleware.ts
|
||||
cp "$SCRIPT_DIR/files/next.config.ts" next.config.ts
|
||||
cp "$SCRIPT_DIR/files/cloudflare-context.ts" src/lib/cloudflare-context.ts
|
||||
cp "$SCRIPT_DIR/files/db.ts" src/lib/db.ts
|
||||
mkdir -p scripts
|
||||
cp "$SCRIPT_DIR/files/init-local-db.ts" scripts/init-local-db.ts
|
||||
|
||||
# Apply cloudflare-context (create the wrapper file)
|
||||
echo "📦 Applying cloudflare-context.ts..."
|
||||
if [ ! -f "src/lib/cloudflare-context.ts" ]; then
|
||||
mkdir -p src/lib
|
||||
cp "$SCRIPT_DIR/files/cloudflare-context.ts" src/lib/
|
||||
echo "✓ Created src/lib/cloudflare-context.ts"
|
||||
else
|
||||
echo "⚠️ cloudflare-context.ts already exists, skipping"
|
||||
# 3. Replace all @opennextjs/cloudflare imports with local wrapper
|
||||
echo "📦 Updating imports..."
|
||||
find src -name "*.ts" -o -name "*.tsx" | xargs sed -i '' 's|from "@opennextjs/cloudflare"|from "@/lib/db"|g'
|
||||
|
||||
# 4. Add db:init-local script to package.json if not present
|
||||
if ! grep -q '"db:init-local"' package.json; then
|
||||
echo "📦 Adding db:init-local script..."
|
||||
# Use node to update package.json
|
||||
node -e '
|
||||
const fs = require("fs");
|
||||
const pkg = JSON.parse(fs.readFileSync("package.json"));
|
||||
pkg.scripts["db:init-local"] = "bun scripts/init-local-db.ts";
|
||||
fs.writeFileSync("package.json", JSON.stringify(pkg, null, 2) + "\n");
|
||||
'
|
||||
fi
|
||||
|
||||
# Apply db-index patch
|
||||
echo "📦 Applying db/index.ts patch..."
|
||||
patch -p1 < "$SCRIPT_DIR/patches/db-index.patch" || {
|
||||
echo "⚠️ db/index.ts patch failed, applying manually..."
|
||||
cat "$SCRIPT_DIR/patches/db-index.patch"
|
||||
}
|
||||
|
||||
# Apply next-config patch
|
||||
echo "📦 Applying next.config.ts patch..."
|
||||
patch -p1 < "$SCRIPT_DIR/patches/next-config.patch" || {
|
||||
echo "⚠️ next.config.ts patch failed, applying manually..."
|
||||
cat "$SCRIPT_DIR/patches/next-config.patch"
|
||||
}
|
||||
|
||||
# Update .gitignore
|
||||
echo "📦 Updating .gitignore..."
|
||||
patch -p1 < "$SCRIPT_DIR/patches/gitignore.patch" || {
|
||||
echo "⚠️ .gitignore patch failed, applying manually..."
|
||||
cat "$SCRIPT_DIR/patches/gitignore.patch"
|
||||
}
|
||||
# 5. Initialize local database
|
||||
echo "📦 Initializing local database..."
|
||||
bun run db:init-local
|
||||
|
||||
echo ""
|
||||
echo "✅ Development setup complete!"
|
||||
echo ""
|
||||
echo "📝 Notes:"
|
||||
echo " - These changes allow local development without WorkOS authentication"
|
||||
echo " - To use WorkOS auth, remove these changes or revert the patches"
|
||||
echo " - Modified files: src/lib/cloudflare-context.ts, src/middleware.ts, src/lib/auth.ts, src/db/index.ts, next.config.ts, .gitignore"
|
||||
echo " - Local database stored in local.db"
|
||||
echo " - Dev user: dev@compass.io (admin role)"
|
||||
echo " - Run 'bun dev' to start"
|
||||
echo ""
|
||||
echo "🔄 To revert: run .dev-setup/restore-dev.sh"
|
||||
|
||||
@ -1,20 +1,189 @@
|
||||
import { getCloudflareContext as originalGetCloudflareContext } from "@opennextjs/cloudflare"
|
||||
import initSqlJs, { Database as SqlJsDatabase } from "sql.js"
|
||||
import { readFileSync, writeFileSync, existsSync } from "fs"
|
||||
import { createRequire } from "module"
|
||||
import { getDb } from "@/db"
|
||||
|
||||
const isWorkOSConfigured =
|
||||
process.env.WORKOS_API_KEY &&
|
||||
process.env.WORKOS_CLIENT_ID &&
|
||||
!process.env.WORKOS_API_KEY.includes("your_") &&
|
||||
!process.env.WORKOS_API_KEY.includes("placeholder")
|
||||
const require = createRequire(import.meta.url)
|
||||
const sqlJsWasm = require.resolve("sql.js/dist/sql-wasm.wasm")
|
||||
|
||||
const DB_PATH = process.env.LOCAL_DB_PATH || "local.db"
|
||||
|
||||
let sqlJs: Awaited<ReturnType<typeof initSqlJs>> | null = null
|
||||
let db: SqlJsDatabase | null = null
|
||||
|
||||
async function getLocalDb(): Promise<SqlJsDatabase> {
|
||||
if (!sqlJs) {
|
||||
sqlJs = await initSqlJs({
|
||||
locateFile: (file: string) => {
|
||||
if (file.endsWith(".wasm")) {
|
||||
return sqlJsWasm
|
||||
}
|
||||
return file
|
||||
},
|
||||
})
|
||||
}
|
||||
if (!db) {
|
||||
if (existsSync(DB_PATH)) {
|
||||
const buffer = readFileSync(DB_PATH)
|
||||
db = new sqlJs.Database(buffer)
|
||||
} else {
|
||||
db = new sqlJs.Database()
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
function saveDb(db: SqlJsDatabase) {
|
||||
const data = db.export()
|
||||
const buffer = Buffer.from(data)
|
||||
writeFileSync(DB_PATH, buffer)
|
||||
}
|
||||
|
||||
interface D1Result<T = unknown> {
|
||||
results: T[]
|
||||
success: boolean
|
||||
meta: {
|
||||
duration: number
|
||||
changes: number
|
||||
last_row_id: number
|
||||
rows_read: number
|
||||
rows_written: number
|
||||
}
|
||||
}
|
||||
|
||||
class LocalPreparedStatement {
|
||||
private db: SqlJsDatabase
|
||||
private query: string
|
||||
private boundValues: unknown[] = []
|
||||
|
||||
constructor(db: SqlJsDatabase, query: string) {
|
||||
this.db = db
|
||||
this.query = query
|
||||
}
|
||||
|
||||
bind(...values: unknown[]): this {
|
||||
this.boundValues = values
|
||||
return this
|
||||
}
|
||||
|
||||
async first<T = unknown>(): Promise<T | null> {
|
||||
const stmt = this.db.prepare(this.query)
|
||||
if (this.boundValues.length > 0) {
|
||||
stmt.bind(this.boundValues as number[])
|
||||
}
|
||||
if (stmt.step()) {
|
||||
const row = stmt.getAsObject() as T
|
||||
stmt.free()
|
||||
return row
|
||||
}
|
||||
stmt.free()
|
||||
return null
|
||||
}
|
||||
|
||||
async run(): Promise<D1Result> {
|
||||
this.db.run(this.query, this.boundValues as number[])
|
||||
saveDb(this.db)
|
||||
return {
|
||||
results: [],
|
||||
success: true,
|
||||
meta: {
|
||||
duration: 0,
|
||||
changes: this.db.getRowsModified(),
|
||||
last_row_id: Number(this.db.exec("SELECT last_insert_rowid()")[0]?.values[0]?.[0] || 0),
|
||||
rows_read: 0,
|
||||
rows_written: this.db.getRowsModified(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async all<T = unknown>(): Promise<D1Result<T>> {
|
||||
const stmt = this.db.prepare(this.query)
|
||||
if (this.boundValues.length > 0) {
|
||||
stmt.bind(this.boundValues as number[])
|
||||
}
|
||||
const results: T[] = []
|
||||
while (stmt.step()) {
|
||||
results.push(stmt.getAsObject() as T)
|
||||
}
|
||||
stmt.free()
|
||||
return {
|
||||
results,
|
||||
success: true,
|
||||
meta: {
|
||||
duration: 0,
|
||||
changes: 0,
|
||||
last_row_id: 0,
|
||||
rows_read: results.length,
|
||||
rows_written: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async raw<T = unknown>(): Promise<T[]> {
|
||||
const results = this.db.exec(this.query, this.boundValues as number[])
|
||||
return results[0]?.values as T[] ?? []
|
||||
}
|
||||
}
|
||||
|
||||
class LocalD1Database {
|
||||
constructor(private db: SqlJsDatabase) {}
|
||||
|
||||
prepare(query: string): LocalPreparedStatement {
|
||||
return new LocalPreparedStatement(this.db, query)
|
||||
}
|
||||
|
||||
async batch<T = unknown>(
|
||||
statements: LocalPreparedStatement[]
|
||||
): Promise<D1Result<T>[]> {
|
||||
const results: D1Result<T>[] = []
|
||||
for (const stmt of statements) {
|
||||
results.push(await stmt.all<T>())
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
async exec(query: string): Promise<D1Result> {
|
||||
this.db.run(query)
|
||||
saveDb(this.db)
|
||||
return {
|
||||
results: [],
|
||||
success: true,
|
||||
meta: {
|
||||
duration: 0,
|
||||
changes: this.db.getRowsModified(),
|
||||
last_row_id: 0,
|
||||
rows_read: 0,
|
||||
rows_written: this.db.getRowsModified(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async dump(): Promise<ArrayBuffer> {
|
||||
const data = this.db.export()
|
||||
return data.buffer as ArrayBuffer
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCloudflareContext(): Promise<{
|
||||
env: {
|
||||
DB: D1Database
|
||||
[key: string]: unknown
|
||||
}
|
||||
ctx: {
|
||||
waitUntil: (promise: Promise<unknown>) => void
|
||||
}
|
||||
cf: unknown
|
||||
}> {
|
||||
const localDb = await getLocalDb()
|
||||
const d1 = new LocalD1Database(localDb) as unknown as D1Database
|
||||
|
||||
export async function getCloudflareContext() {
|
||||
if (!isWorkOSConfigured) {
|
||||
return {
|
||||
env: {
|
||||
DB: null,
|
||||
DB: d1,
|
||||
},
|
||||
ctx: {},
|
||||
} as Awaited<ReturnType<typeof originalGetCloudflareContext>>
|
||||
ctx: {
|
||||
waitUntil: () => {},
|
||||
},
|
||||
cf: {},
|
||||
}
|
||||
|
||||
return originalGetCloudflareContext()
|
||||
}
|
||||
|
||||
27
.dev-setup/files/db.ts
Normal file
27
.dev-setup/files/db.ts
Normal file
@ -0,0 +1,27 @@
|
||||
export async function getCloudflareContext(): Promise<{
|
||||
env: {
|
||||
DB: D1Database
|
||||
[key: string]: unknown
|
||||
}
|
||||
ctx: {
|
||||
waitUntil: (promise: Promise<unknown>) => void
|
||||
}
|
||||
cf: unknown
|
||||
}> {
|
||||
const isLocalDev =
|
||||
process.env.NODE_ENV === "development" &&
|
||||
(!process.env.WORKOS_API_KEY ||
|
||||
process.env.WORKOS_API_KEY.includes("placeholder"))
|
||||
|
||||
if (isLocalDev) {
|
||||
const { getCloudflareContext: getLocalContext } = await import(
|
||||
"./cloudflare-context"
|
||||
)
|
||||
return getLocalContext()
|
||||
}
|
||||
|
||||
const { getCloudflareContext: getCfContext } = await import(
|
||||
"@opennextjs/cloudflare"
|
||||
)
|
||||
return getCfContext()
|
||||
}
|
||||
51
.dev-setup/files/init-local-db.ts
Normal file
51
.dev-setup/files/init-local-db.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import initSqlJs from "sql.js"
|
||||
import { readFileSync, readdirSync, writeFileSync, existsSync } from "fs"
|
||||
import { join, dirname } from "path"
|
||||
import { createRequire } from "module"
|
||||
import { fileURLToPath } from "url"
|
||||
|
||||
const require = createRequire(import.meta.url)
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const sqlJsWasm = require.resolve("sql.js/dist/sql-wasm.wasm")
|
||||
|
||||
const DB_PATH = process.env.LOCAL_DB_PATH || "local.db"
|
||||
const MIGRATIONS_DIR = join(process.cwd(), "drizzle")
|
||||
|
||||
async function main() {
|
||||
const sqlJs = await initSqlJs({
|
||||
locateFile: (file: string) => {
|
||||
if (file.endsWith(".wasm")) {
|
||||
return sqlJsWasm
|
||||
}
|
||||
return file
|
||||
},
|
||||
})
|
||||
|
||||
let db: ReturnType<typeof sqlJs.Database>
|
||||
if (existsSync(DB_PATH)) {
|
||||
const buffer = readFileSync(DB_PATH)
|
||||
db = new sqlJs.Database(buffer)
|
||||
} else {
|
||||
db = new sqlJs.Database()
|
||||
}
|
||||
|
||||
const migrations = readdirSync(MIGRATIONS_DIR)
|
||||
.filter((f) => f.endsWith(".sql") && !f.includes("seed"))
|
||||
.sort()
|
||||
|
||||
console.log(`Running ${migrations.length} migrations on ${DB_PATH}...`)
|
||||
|
||||
for (const migration of migrations) {
|
||||
const sql = readFileSync(join(MIGRATIONS_DIR, migration), "utf-8")
|
||||
console.log(` ${migration}`)
|
||||
db.run(sql)
|
||||
}
|
||||
|
||||
const data = db.export()
|
||||
const buffer = Buffer.from(data)
|
||||
writeFileSync(DB_PATH, buffer)
|
||||
|
||||
console.log("Done!")
|
||||
}
|
||||
|
||||
main().catch(console.error)
|
||||
61
.dev-setup/files/middleware.ts
Normal file
61
.dev-setup/files/middleware.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { NextRequest, NextResponse } from "next/server"
|
||||
import { authkit, handleAuthkitHeaders } from "@workos-inc/authkit-nextjs"
|
||||
|
||||
const publicPaths = [
|
||||
"/",
|
||||
"/login",
|
||||
"/signup",
|
||||
"/reset-password",
|
||||
"/verify-email",
|
||||
"/invite",
|
||||
"/callback",
|
||||
]
|
||||
|
||||
const bridgePaths = [
|
||||
"/api/bridge/register",
|
||||
"/api/bridge/tools",
|
||||
"/api/bridge/context",
|
||||
]
|
||||
|
||||
function isPublicPath(pathname: string): boolean {
|
||||
return (
|
||||
publicPaths.includes(pathname) ||
|
||||
bridgePaths.includes(pathname) ||
|
||||
pathname.startsWith("/api/auth/") ||
|
||||
pathname.startsWith("/api/netsuite/") ||
|
||||
pathname.startsWith("/api/google/")
|
||||
)
|
||||
}
|
||||
|
||||
const isWorkOSConfigured =
|
||||
process.env.WORKOS_API_KEY &&
|
||||
process.env.WORKOS_CLIENT_ID &&
|
||||
!process.env.WORKOS_API_KEY.includes("placeholder")
|
||||
|
||||
export default async function middleware(request: NextRequest) {
|
||||
const { pathname } = request.nextUrl
|
||||
|
||||
if (!isWorkOSConfigured) {
|
||||
return NextResponse.next()
|
||||
}
|
||||
|
||||
const { session, headers } = await authkit(request)
|
||||
|
||||
if (isPublicPath(pathname)) {
|
||||
return handleAuthkitHeaders(request, headers)
|
||||
}
|
||||
|
||||
if (!session.user) {
|
||||
const loginUrl = new URL("/login", request.url)
|
||||
loginUrl.searchParams.set("from", pathname)
|
||||
return handleAuthkitHeaders(request, headers, { redirect: loginUrl.toString() })
|
||||
}
|
||||
|
||||
return handleAuthkitHeaders(request, headers)
|
||||
}
|
||||
|
||||
export const config = {
|
||||
matcher: [
|
||||
"/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
|
||||
],
|
||||
}
|
||||
23
.dev-setup/files/next.config.ts
Normal file
23
.dev-setup/files/next.config.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
eslint: {
|
||||
ignoreDuringBuilds: true,
|
||||
},
|
||||
experimental: {
|
||||
optimizePackageImports: [
|
||||
"@tabler/icons-react",
|
||||
"lucide-react",
|
||||
"@radix-ui/react-icons",
|
||||
"recharts",
|
||||
"@workos-inc/node",
|
||||
"date-fns",
|
||||
"remeda",
|
||||
"framer-motion",
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
// Cloudflare dev proxy removed for local dev - uses sql.js instead
|
||||
@ -1,36 +1,39 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "🔄 Removing local development setup patches..."
|
||||
echo "🔄 Removing local development setup..."
|
||||
|
||||
# Check if we're in the compass directory
|
||||
if [ ! -f "package.json" ] || [ ! -d "src" ]; then
|
||||
echo "❌ Error: Please run this script from the compass directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Restore modified files
|
||||
# Revert tracked files
|
||||
echo "📦 Restoring modified files..."
|
||||
git restore src/middleware.ts
|
||||
git restore src/lib/auth.ts
|
||||
git restore src/db/index.ts
|
||||
git restore next.config.ts
|
||||
git restore .gitignore
|
||||
git checkout HEAD -- src/middleware.ts next.config.ts package.json bun.lock
|
||||
|
||||
# Remove dev-only new file
|
||||
# Remove dev-only files
|
||||
echo "📦 Removing dev-only files..."
|
||||
if [ -f "src/lib/cloudflare-context.ts" ]; then
|
||||
rm src/lib/cloudflare-context.ts
|
||||
echo "✓ Removed src/lib/cloudflare-context.ts"
|
||||
else
|
||||
echo "⚠️ src/lib/cloudflare-context.ts not found, skipping"
|
||||
fi
|
||||
rm -f src/lib/cloudflare-context.ts
|
||||
rm -f src/lib/db.ts
|
||||
rm -f scripts/init-local-db.ts
|
||||
echo "✓ Removed dev files"
|
||||
|
||||
# Restore original imports
|
||||
echo "📦 Restoring original imports..."
|
||||
find src -name "*.ts" -o -name "*.tsx" | xargs sed -i '' 's|from "@/lib/db"|from "@opennextjs/cloudflare"|g'
|
||||
|
||||
# Remove sql.js
|
||||
echo "📦 Removing sql.js..."
|
||||
bun remove sql.js
|
||||
|
||||
# Remove local database
|
||||
rm -f local.db local.db-wal local.db-shm
|
||||
|
||||
echo ""
|
||||
echo "✅ Development setup removed!"
|
||||
echo ""
|
||||
echo "📝 Notes:"
|
||||
echo " - Original code has been restored from git"
|
||||
echo " - Dev mode is now disabled"
|
||||
echo " - WorkOS authentication will be required (if configured)"
|
||||
echo " - To re-apply dev setup, run: .dev-setup/apply-dev.sh"
|
||||
echo " - Original code restored from git"
|
||||
echo " - WorkOS/Cloudflare auth will be required"
|
||||
echo " - To re-apply: .dev-setup/apply-dev.sh"
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@ -41,3 +41,10 @@ android/app/build/
|
||||
# Local auth bypass (dev only)
|
||||
src/lib/auth-bypass.ts
|
||||
src/lib/cloudflare-context.ts
|
||||
src/lib/db.ts
|
||||
scripts/init-local-db.ts
|
||||
|
||||
# local dev database
|
||||
local.db
|
||||
local.db-wal
|
||||
local.db-shm
|
||||
|
||||
@ -31,6 +31,7 @@ export function NavSecondary({
|
||||
<SidebarMenuButton
|
||||
asChild={!item.onClick}
|
||||
onClick={item.onClick}
|
||||
tooltip={item.title}
|
||||
>
|
||||
{item.onClick ? (
|
||||
<>
|
||||
|
||||
@ -469,7 +469,7 @@ function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
|
||||
}
|
||||
|
||||
const sidebarMenuButtonVariants = cva(
|
||||
"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-9! group-data-[collapsible=icon]:justify-center! group-data-[collapsible=icon]:p-2.5! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
|
||||
"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:justify-center! group-data-[collapsible=icon]:gap-0! group-data-[collapsible=icon]:[&>*:nth-child(n+2)]:translate-x-10 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
@ -478,9 +478,9 @@ const sidebarMenuButtonVariants = cva(
|
||||
"bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
|
||||
},
|
||||
size: {
|
||||
default: "h-8 text-sm",
|
||||
sm: "h-7 text-xs",
|
||||
lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!",
|
||||
default: "h-8 text-sm group-data-[collapsible=icon]:size-9! group-data-[collapsible=icon]:p-2!",
|
||||
sm: "h-7 text-xs group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-1.5!",
|
||||
lg: "h-12 text-sm group-data-[collapsible=icon]:size-11! group-data-[collapsible=icon]:p-1.5! group-data-[collapsible=icon]:-translate-x-[0.3rem] group-data-[collapsible=icon]:[&>*:first-child]:translate-x-[0.5rem]",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user