spine-framework 0.3.79 → 0.3.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -174,13 +174,14 @@ export function registerInitCommands(program: Command) {
|
|
|
174
174
|
const envTemplate = [
|
|
175
175
|
'# Supabase credentials',
|
|
176
176
|
'# Get these from: Supabase Dashboard → Your Project → Settings → API',
|
|
177
|
-
'
|
|
177
|
+
'# Replace the values below — do not leave them blank or as placeholders',
|
|
178
|
+
'SUPABASE_URL=',
|
|
178
179
|
'SUPABASE_ANON_KEY=',
|
|
179
180
|
'SUPABASE_SERVICE_ROLE_KEY=',
|
|
180
181
|
'SUPABASE_DB_PASSWORD=',
|
|
181
182
|
'',
|
|
182
|
-
'# Vite (browser-safe)',
|
|
183
|
-
'VITE_SUPABASE_URL=
|
|
183
|
+
'# Vite (browser-safe) — copy from above',
|
|
184
|
+
'VITE_SUPABASE_URL=',
|
|
184
185
|
'VITE_SUPABASE_ANON_KEY=',
|
|
185
186
|
'VITE_DB_SCHEMA=public',
|
|
186
187
|
'VITE_APP_NAME=Spine',
|
|
@@ -114,18 +114,33 @@ async function migrateCommand(options: MigrateOptions): Promise<void> {
|
|
|
114
114
|
// Load .env from project root
|
|
115
115
|
loadEnv()
|
|
116
116
|
|
|
117
|
+
const envPath = join(PROJECT_ROOT, '.env')
|
|
118
|
+
const envExists = existsSync(envPath)
|
|
119
|
+
|
|
117
120
|
const supabaseUrl = process.env.SUPABASE_URL
|
|
118
121
|
if (!supabaseUrl || supabaseUrl.includes('placeholder') || supabaseUrl.includes('your-project')) {
|
|
119
|
-
console.error('
|
|
120
|
-
|
|
122
|
+
console.error('❌ SUPABASE_URL is not set.\n')
|
|
123
|
+
if (!envExists) {
|
|
124
|
+
console.error(' No .env file found in this directory.')
|
|
125
|
+
console.error(' Run: npx spine-framework init (to create the .env template)')
|
|
126
|
+
} else {
|
|
127
|
+
console.error(' Your .env file exists but SUPABASE_URL is missing or still set to a placeholder.')
|
|
128
|
+
console.error(' Edit .env and set SUPABASE_URL to your project URL.')
|
|
129
|
+
}
|
|
130
|
+
console.error('\n Get it from: https://supabase.com/dashboard/project/_/settings/api')
|
|
121
131
|
process.exit(1)
|
|
122
132
|
}
|
|
123
133
|
|
|
124
134
|
const dbPassword = options.dbPassword || process.env.SUPABASE_DB_PASSWORD
|
|
125
135
|
if (!dbPassword) {
|
|
126
|
-
console.error('
|
|
127
|
-
|
|
128
|
-
|
|
136
|
+
console.error('❌ SUPABASE_DB_PASSWORD is not set.\n')
|
|
137
|
+
if (!envExists) {
|
|
138
|
+
console.error(' No .env file found. Run: npx spine-framework init')
|
|
139
|
+
} else {
|
|
140
|
+
console.error(' Edit .env and add: SUPABASE_DB_PASSWORD=your-db-password')
|
|
141
|
+
console.error(' Or pass it directly: npx spine-framework migrate --db-password <password>')
|
|
142
|
+
}
|
|
143
|
+
console.error('\n Get it from: https://supabase.com/dashboard/project/_/settings/database')
|
|
129
144
|
process.exit(1)
|
|
130
145
|
}
|
|
131
146
|
|
|
@@ -19,8 +19,8 @@ import { fileURLToPath } from 'url'
|
|
|
19
19
|
const __filename = fileURLToPath(import.meta.url)
|
|
20
20
|
const __dirname = dirname(__filename)
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
if (existsSync(envPath))
|
|
22
|
+
function loadEnvFile(envPath: string) {
|
|
23
|
+
if (!existsSync(envPath)) return
|
|
24
24
|
const lines = readFileSync(envPath, 'utf8').split('\n')
|
|
25
25
|
for (const line of lines) {
|
|
26
26
|
const trimmed = line.trim()
|
|
@@ -34,3 +34,10 @@ if (existsSync(envPath)) {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
// 1. Load project .env first (process.cwd() = the developer's project root)
|
|
39
|
+
// This must happen before any module that reads env vars at import time (e.g. _shared/db.ts)
|
|
40
|
+
loadEnvFile(resolve(process.cwd(), '.env'))
|
|
41
|
+
|
|
42
|
+
// 2. Load framework's own .xenv (lower priority — project .env wins)
|
|
43
|
+
loadEnvFile(resolve(__dirname, '../.xenv'))
|
|
@@ -20,9 +20,21 @@ import WebSocket from 'ws'
|
|
|
20
20
|
// ─── ENVIRONMENT RESOLUTION ──────────────────────────────────────────────────
|
|
21
21
|
|
|
22
22
|
const _env = (globalThis as any).process?.env || {}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
|
|
24
|
+
// Use a known-valid placeholder URL so that createClient() doesn't throw at
|
|
25
|
+
// module load time when env vars haven't been set yet (e.g. during CLI init).
|
|
26
|
+
// All real requests validate credentials before hitting the DB.
|
|
27
|
+
const PLACEHOLDER_URL = 'https://placeholder.supabase.co'
|
|
28
|
+
const PLACEHOLDER_KEY = 'placeholder'
|
|
29
|
+
|
|
30
|
+
function isValidUrl(url: string): boolean {
|
|
31
|
+
try { new URL(url); return true } catch { return false }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const rawUrl = _env.SUPABASE_URL || ''
|
|
35
|
+
const supabaseUrl: string = rawUrl && isValidUrl(rawUrl) ? rawUrl : PLACEHOLDER_URL
|
|
36
|
+
const supabaseServiceKey: string = _env.SUPABASE_SERVICE_ROLE_KEY || PLACEHOLDER_KEY
|
|
37
|
+
const supabaseAnonKey: string = _env.SUPABASE_ANON_KEY || PLACEHOLDER_KEY
|
|
26
38
|
const dbSchema: string = _env.DB_SCHEMA || 'public'
|
|
27
39
|
|
|
28
40
|
// ─── CLIENTS ─────────────────────────────────────────────────────────────────
|
package/.framework/src/App.tsx
CHANGED
|
@@ -85,8 +85,10 @@ function AuthenticatedRouter() {
|
|
|
85
85
|
return (
|
|
86
86
|
<Suspense fallback={<div className="min-h-screen flex items-center justify-center"><LoadingSpinner /></div>}>
|
|
87
87
|
<Routes>
|
|
88
|
-
{/* Default redirect to first available app
|
|
89
|
-
|
|
88
|
+
{/* Default redirect to first available app — only when root is not itself an app */}
|
|
89
|
+
{defaultRedirect !== '/' && (
|
|
90
|
+
<Route path="/" element={<Navigate to={defaultRedirect} replace />} />
|
|
91
|
+
)}
|
|
90
92
|
<Route path="/dashboard" element={<DashboardPage />} />
|
|
91
93
|
|
|
92
94
|
{/* Login/register routes for authenticated users (redirects to qualified app) */}
|