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
- 'SUPABASE_URL=https://<project-ref>.supabase.co',
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=https://<project-ref>.supabase.co',
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('Error: SUPABASE_URL not set. Edit your .env file first.')
120
- console.error(' Get it from: https://supabase.com/dashboard/project/_/settings/api')
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('Error: SUPABASE_DB_PASSWORD not set.')
127
- console.error(' Add it to .env or pass --db-password <password>')
128
- console.error(' Get it from: https://supabase.com/dashboard/project/_/settings/database')
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
- const envPath = resolve(__dirname, '../.xenv')
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
- const supabaseUrl: string = _env.SUPABASE_URL || 'https://placeholder.supabase.co'
24
- const supabaseServiceKey: string = _env.SUPABASE_SERVICE_ROLE_KEY || 'placeholder'
25
- const supabaseAnonKey: string = _env.SUPABASE_ANON_KEY || 'placeholder'
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 ─────────────────────────────────────────────────────────────────
@@ -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, or dashboard if no apps */}
89
- <Route path="/" element={<Navigate to={defaultRedirect} replace />} />
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) */}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spine-framework",
3
- "version": "0.3.79",
3
+ "version": "0.3.82",
4
4
  "description": "Multi-tenant, modular application platform for modern SaaS systems",
5
5
  "type": "module",
6
6
  "bin": {