spine-framework 0.1.5 → 0.1.8

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.
@@ -31,7 +31,6 @@ import type { Command } from 'commander'
31
31
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'
32
32
  import { resolve, dirname } from 'path'
33
33
  import { fileURLToPath } from 'url'
34
- import { adminDb } from '../../functions/_shared/index.ts'
35
34
 
36
35
  const __filename = fileURLToPath(import.meta.url)
37
36
  const __dirname = dirname(__filename)
@@ -70,13 +69,7 @@ async function runMigration(filename: string, dryRun: boolean): Promise<boolean>
70
69
  return false
71
70
  }
72
71
 
73
- // Try exec_sql RPC first (works if schema already has it)
74
- const { error } = await adminDb.rpc('exec_sql', { query: sql }).single()
75
- if (!error) return true
76
-
77
- // Fallback: use the Supabase /pg/query endpoint for raw SQL execution
78
- console.log(` ⚠️ exec_sql not available, using direct SQL endpoint...`)
79
-
72
+ // Use the Supabase /pg/query endpoint for raw SQL execution
80
73
  const pgResponse = await fetch(`${supabaseUrl}/pg/query`, {
81
74
  method: 'POST',
82
75
  headers: {
@@ -137,13 +130,15 @@ function scaffoldCustomWorkspace(dryRun: boolean): void {
137
130
 
138
131
  async function checkAlreadyInitialized(): Promise<boolean> {
139
132
  try {
140
- const { data, error } = await adminDb
141
- .from('apps')
142
- .select('slug')
143
- .eq('slug', 'spine-core')
144
- .single()
145
-
146
- return !error && !!data
133
+ const supabaseUrl = process.env.SUPABASE_URL
134
+ const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY
135
+ if (!supabaseUrl || !serviceKey) return false
136
+ const res = await fetch(
137
+ `${supabaseUrl}/rest/v1/apps?slug=eq.spine-core&select=slug&limit=1`,
138
+ { headers: { apikey: serviceKey, Authorization: `Bearer ${serviceKey}` } }
139
+ )
140
+ const rows = await res.json() as any[]
141
+ return Array.isArray(rows) && rows.length > 0
147
142
  } catch {
148
143
  return false
149
144
  }
@@ -229,12 +224,21 @@ async function initCommand(options: InitOptions): Promise<void> {
229
224
  // Step 3: Record migration versions
230
225
  if (!options.dryRun) {
231
226
  console.log('\n📝 Step 3: Recording migration versions...')
232
- await adminDb
233
- .from('schema_migrations')
234
- .upsert([
227
+ const supabaseUrl = process.env.SUPABASE_URL!
228
+ const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY!
229
+ await fetch(`${supabaseUrl}/rest/v1/schema_migrations`, {
230
+ method: 'POST',
231
+ headers: {
232
+ 'Content-Type': 'application/json',
233
+ 'apikey': serviceKey,
234
+ 'Authorization': `Bearer ${serviceKey}`,
235
+ 'Prefer': 'resolution=merge-duplicates',
236
+ },
237
+ body: JSON.stringify([
235
238
  { version: '000_foundation', applied_at: new Date().toISOString() },
236
239
  { version: '001_seed', applied_at: new Date().toISOString() },
237
- ], { onConflict: 'version' })
240
+ ])
241
+ })
238
242
  console.log(' ✓ Migration versions recorded')
239
243
  }
240
244
 
@@ -41,21 +41,6 @@
41
41
 
42
42
  import './env-loader.ts'
43
43
  import { Command } from 'commander'
44
- import { createRequire } from 'module'
45
- import { resolve, dirname } from 'path'
46
- import { fileURLToPath } from 'url'
47
-
48
- const __filename = fileURLToPath(import.meta.url)
49
- const __dirname = dirname(__filename)
50
-
51
- function printWelcome() {
52
- const require = createRequire(import.meta.url)
53
- try {
54
- require(resolve(__dirname, '../../bin/welcome.cjs'))
55
- } catch {
56
- console.log('Spine Framework — run `spine-framework --help` for commands.')
57
- }
58
- }
59
44
 
60
45
  const program = new Command()
61
46
 
@@ -115,12 +100,6 @@ registerInstallAppCommands(program)
115
100
  registerStatusCommands(program)
116
101
  registerUninstallAppCommands(program)
117
102
 
118
- // Show welcome when run with no arguments
119
- if (process.argv.length === 2) {
120
- printWelcome()
121
- process.exit(0)
122
- }
123
-
124
103
  program.parseAsync(process.argv).catch((err) => {
125
104
  console.error('Error:', err.message)
126
105
  process.exit(1)
@@ -18,11 +18,6 @@ import { createClient } from '@supabase/supabase-js'
18
18
 
19
19
  // ─── ENVIRONMENT RESOLUTION ──────────────────────────────────────────────────
20
20
 
21
- const _env = (globalThis as any).process?.env || {}
22
- const supabaseUrl: string = _env.SUPABASE_URL!
23
- const supabaseServiceKey: string = _env.SUPABASE_SERVICE_ROLE_KEY!
24
- const supabaseAnonKey: string = _env.SUPABASE_ANON_KEY!
25
-
26
21
  /**
27
22
  * Active database schema name, read from `DB_SCHEMA` env var.
28
23
  *
@@ -35,8 +30,22 @@ const supabaseAnonKey: string = _env.SUPABASE_ANON_KEY!
35
30
  * @sideEffects none
36
31
  * @calledBy adminDb, getUserDb (applied at client construction time)
37
32
  */
33
+ const _env = (globalThis as any).process?.env || {}
34
+ const supabaseUrl: string = _env.SUPABASE_URL!
35
+ const supabaseServiceKey: string = _env.SUPABASE_SERVICE_ROLE_KEY!
36
+ const supabaseAnonKey: string = _env.SUPABASE_ANON_KEY!
38
37
  const dbSchema: string = _env.DB_SCHEMA || 'public'
39
38
 
39
+ function getEnv() {
40
+ const e = (globalThis as any).process?.env || {}
41
+ return {
42
+ supabaseUrl: e.SUPABASE_URL as string,
43
+ supabaseServiceKey: e.SUPABASE_SERVICE_ROLE_KEY as string,
44
+ supabaseAnonKey: e.SUPABASE_ANON_KEY as string,
45
+ dbSchema: (e.DB_SCHEMA || 'public') as string,
46
+ }
47
+ }
48
+
40
49
  // ─── CLIENTS ─────────────────────────────────────────────────────────────────
41
50
 
42
51
  /**
@@ -74,9 +83,7 @@ const dbSchema: string = _env.DB_SCHEMA || 'public'
74
83
  * ```
75
84
  */
76
85
  export const adminDb = createClient(supabaseUrl, supabaseServiceKey, {
77
- db: {
78
- schema: dbSchema
79
- }
86
+ db: { schema: dbSchema }
80
87
  })
81
88
 
82
89
  // ─── CHUNK_START: SHARED_DB_GET_USER_DB ──────────────────────────────────────────────
@@ -94,6 +101,7 @@ export const adminDb = createClient(supabaseUrl, supabaseServiceKey, {
94
101
  * @tags database, supabase, rls, authentication, user-scoped
95
102
  */
96
103
  export function getUserDb(jwt: string) {
104
+ const { supabaseUrl, supabaseAnonKey, dbSchema } = getEnv()
97
105
  return createClient(supabaseUrl, supabaseAnonKey, {
98
106
  db: {
99
107
  schema: dbSchema
@@ -1,22 +1,27 @@
1
1
  #!/usr/bin/env node
2
2
  // Thin shebang wrapper — invokes the TypeScript CLI via tsx.
3
3
  // This file is the npm bin entry point for spine-framework.
4
- const { execFileSync, spawnSync } = require('child_process')
4
+ const { execFileSync } = require('child_process')
5
5
  const { resolve } = require('path')
6
6
 
7
- // __dirname = <project>/node_modules/spine-framework/bin
8
- // tsx lives at <project>/node_modules/.bin/tsx
9
7
  const pkgRoot = resolve(__dirname, '..')
10
8
  const projectRoot = resolve(pkgRoot, '../..')
9
+
10
+ // Handle no-args case here — before spawning tsx or loading db.ts
11
+ if (process.argv.length === 2) {
12
+ require(resolve(__dirname, 'welcome.cjs'))
13
+ process.exit(0)
14
+ }
15
+
11
16
  const entry = resolve(pkgRoot, '.framework/cli/index.ts')
12
17
 
13
18
  // Find tsx: prefer consuming project's copy, fall back to our own
19
+ const fs = require('fs')
14
20
  const tsxPaths = [
15
21
  resolve(projectRoot, 'node_modules/.bin/tsx'),
16
22
  resolve(pkgRoot, 'node_modules/.bin/tsx'),
17
23
  ]
18
-
19
- const tsx = tsxPaths.find(p => { try { require('fs').accessSync(p); return true } catch { return false } })
24
+ const tsx = tsxPaths.find(p => { try { fs.accessSync(p); return true } catch { return false } })
20
25
 
21
26
  if (!tsx) {
22
27
  console.error('spine-framework: tsx not found. Run: npm install tsx')
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../.framework/cli/commands/init.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAgOxC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,QAkBpD"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../.framework/cli/commands/init.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAoOxC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,QAkBpD"}
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../../.framework/functions/_shared/db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA2BH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,OAAO,iFAIlB,CAAA;AAGF;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,mFAWpC;AAKD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;IACxB,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACd,KAAK,EAAE,GAAG,CAAA;CACX,CAAA;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,KAAK;;;;;;;;CAQjB,CAAA"}
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../../.framework/functions/_shared/db.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAoCH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,OAAO,iFAElB,CAAA;AAGF;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,mFAYpC;AAKD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;IACxB,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACd,KAAK,EAAE,GAAG,CAAA;CACX,CAAA;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,KAAK;;;;;;;;CAQjB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spine-framework",
3
- "version": "0.1.5",
3
+ "version": "0.1.8",
4
4
  "private": false,
5
5
  "description": "Spine — enterprise application framework built on Supabase + Netlify + React",
6
6
  "type": "module",