spine-framework 0.1.20 → 0.1.22
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.
- package/.framework/cli/commands/init.ts +43 -47
- package/.framework/cli/commands/migrate.ts +13 -8
- package/.framework/cli/index.ts +58 -51
- package/.framework/functions/_shared/db.ts +3 -3
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/migrate.d.ts.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -30,9 +30,6 @@ const PACKAGE_ROOT = resolve(__dirname, '../../..')
|
|
|
30
30
|
|
|
31
31
|
interface InitOptions {
|
|
32
32
|
dryRun: boolean
|
|
33
|
-
url?: string
|
|
34
|
-
anonKey?: string
|
|
35
|
-
serviceRoleKey?: string
|
|
36
33
|
}
|
|
37
34
|
|
|
38
35
|
function scaffoldCustomWorkspace(dryRun: boolean): void {
|
|
@@ -58,38 +55,47 @@ function scaffoldCustomWorkspace(dryRun: boolean): void {
|
|
|
58
55
|
}
|
|
59
56
|
}
|
|
60
57
|
|
|
61
|
-
function writeEnvFile(
|
|
58
|
+
function writeEnvFile(dryRun: boolean): void {
|
|
62
59
|
const envPath = resolve(PROJECT_ROOT, '.env')
|
|
60
|
+
|
|
61
|
+
if (existsSync(envPath)) {
|
|
62
|
+
console.log(' ⏭️ .env already exists, skipping')
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
|
|
63
66
|
const envContent = [
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
'# ─── Supabase ────────────────────────────────────────────────────────────────',
|
|
68
|
+
'# Get these from: https://supabase.com/dashboard/project/_/settings/api',
|
|
69
|
+
'SUPABASE_URL=https://your-project.supabase.co',
|
|
70
|
+
'SUPABASE_ANON_KEY=your-anon-key',
|
|
71
|
+
'SUPABASE_SERVICE_ROLE_KEY=your-service-role-key',
|
|
72
|
+
'',
|
|
73
|
+
'# DB password for running migrations (direct Postgres connection)',
|
|
74
|
+
'# Get from: https://supabase.com/dashboard/project/_/settings/database',
|
|
75
|
+
'SUPABASE_DB_PASSWORD=your-db-password',
|
|
76
|
+
'',
|
|
77
|
+
'# ─── Vite / Frontend ─────────────────────────────────────────────────────────',
|
|
78
|
+
'VITE_SUPABASE_URL=https://your-project.supabase.co',
|
|
79
|
+
'VITE_SUPABASE_ANON_KEY=your-anon-key',
|
|
80
|
+
'VITE_APP_NAME=Spine',
|
|
81
|
+
'',
|
|
82
|
+
'# ─── OpenAI ──────────────────────────────────────────────────────────────────',
|
|
83
|
+
'OPENAI_API_KEY=your-openai-api-key',
|
|
84
|
+
'',
|
|
85
|
+
'# ─── App config ──────────────────────────────────────────────────────────────',
|
|
86
|
+
'DB_SCHEMA=public',
|
|
71
87
|
].join('\n') + '\n'
|
|
72
88
|
|
|
73
89
|
if (dryRun) {
|
|
74
|
-
console.log(
|
|
90
|
+
console.log(' [dry-run] Would write .env with placeholder values')
|
|
75
91
|
return
|
|
76
92
|
}
|
|
77
93
|
|
|
78
|
-
const existed = existsSync(envPath)
|
|
79
94
|
writeFileSync(envPath, envContent, 'utf8')
|
|
80
|
-
console.log(
|
|
81
|
-
|
|
82
|
-
// Also inject into process.env for the rest of this run
|
|
83
|
-
process.env.SUPABASE_URL = url
|
|
84
|
-
process.env.SUPABASE_ANON_KEY = anonKey
|
|
85
|
-
process.env.SUPABASE_SERVICE_ROLE_KEY = serviceRoleKey
|
|
86
|
-
process.env.VITE_SUPABASE_URL = url
|
|
87
|
-
process.env.VITE_SUPABASE_ANON_KEY = anonKey
|
|
95
|
+
console.log(' ✓ Created .env')
|
|
88
96
|
}
|
|
89
97
|
|
|
90
98
|
function copyFrameworkFiles(dryRun: boolean): void {
|
|
91
|
-
console.log(` package: ${PACKAGE_ROOT}`)
|
|
92
|
-
console.log(` project: ${PROJECT_ROOT}`)
|
|
93
99
|
// Directories and files to copy from the package root into the consumer project root
|
|
94
100
|
const items = [
|
|
95
101
|
{ src: '.framework', dest: '.framework' },
|
|
@@ -129,40 +135,30 @@ function copyFrameworkFiles(dryRun: boolean): void {
|
|
|
129
135
|
async function initCommand(options: InitOptions): Promise<void> {
|
|
130
136
|
console.log('\n🚀 Spine Framework — Init\n')
|
|
131
137
|
|
|
132
|
-
// Step 1:
|
|
133
|
-
|
|
134
|
-
console.log('🔑 Step 1: Writing environment configuration...')
|
|
135
|
-
writeEnvFile(options.url, options.anonKey, options.serviceRoleKey, options.dryRun)
|
|
136
|
-
} else if (!process.env.SUPABASE_URL) {
|
|
137
|
-
console.error('❌ No Supabase credentials found.')
|
|
138
|
-
console.error(' spine-framework init --url <url> --anon-key <key> --service-role-key <key>')
|
|
139
|
-
process.exit(1)
|
|
140
|
-
} else {
|
|
141
|
-
console.log(' ✓ Using existing .env credentials')
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Step 2: Copy framework files to project root
|
|
145
|
-
console.log('\n📦 Step 2: Installing framework files...')
|
|
138
|
+
// Step 1: Copy framework files to project root
|
|
139
|
+
console.log('📦 Step 1: Installing framework files...')
|
|
146
140
|
copyFrameworkFiles(options.dryRun)
|
|
147
141
|
|
|
148
|
-
// Step
|
|
149
|
-
console.log('\n📁 Step
|
|
142
|
+
// Step 2: Scaffold custom workspace
|
|
143
|
+
console.log('\n📁 Step 2: Scaffolding custom workspace...')
|
|
150
144
|
scaffoldCustomWorkspace(options.dryRun)
|
|
151
145
|
|
|
146
|
+
// Step 3: Write .env with placeholders
|
|
147
|
+
console.log('\n🔑 Step 3: Writing environment configuration...')
|
|
148
|
+
writeEnvFile(options.dryRun)
|
|
149
|
+
|
|
152
150
|
console.log('\n✅ Project initialized!')
|
|
153
|
-
console.log('\n Next
|
|
154
|
-
console.log('
|
|
155
|
-
console.log('
|
|
156
|
-
console.log('
|
|
151
|
+
console.log('\n Next steps:')
|
|
152
|
+
console.log(' 1. Fill in your Supabase credentials in .env')
|
|
153
|
+
console.log(' (get them from https://supabase.com/dashboard/project/_/settings/api)')
|
|
154
|
+
console.log(' 2. Run: npx spine-framework migrate --db-password <your-db-password>')
|
|
155
|
+
console.log(' (get DB password from https://supabase.com/dashboard/project/_/settings/database)')
|
|
157
156
|
}
|
|
158
157
|
|
|
159
158
|
export function registerInitCommands(program: Command) {
|
|
160
159
|
program
|
|
161
160
|
.command('init')
|
|
162
|
-
.description('
|
|
163
|
-
.option('--url <url>', 'Supabase project URL')
|
|
164
|
-
.option('--anon-key <key>', 'Supabase anon key')
|
|
165
|
-
.option('--service-role-key <key>', 'Supabase service role key')
|
|
161
|
+
.description('Install framework files, scaffold custom/ workspace, and write .env template')
|
|
166
162
|
.option('--dry-run', 'Show what would happen without making changes', false)
|
|
167
163
|
.action(async (opts) => {
|
|
168
164
|
try {
|
|
@@ -28,7 +28,7 @@ const __dirname = dirname(__filename)
|
|
|
28
28
|
const MIGRATIONS_DIR = resolve(__dirname, '../../migrations')
|
|
29
29
|
|
|
30
30
|
interface MigrateOptions {
|
|
31
|
-
dbPassword
|
|
31
|
+
dbPassword?: string
|
|
32
32
|
dryRun: boolean
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -36,16 +36,21 @@ async function migrateCommand(options: MigrateOptions): Promise<void> {
|
|
|
36
36
|
console.log('\n🗄️ Spine Framework — Migrate\n')
|
|
37
37
|
|
|
38
38
|
const supabaseUrl = process.env.SUPABASE_URL
|
|
39
|
-
if (!supabaseUrl) {
|
|
40
|
-
console.error('❌ SUPABASE_URL not set.
|
|
39
|
+
if (!supabaseUrl || supabaseUrl === 'https://your-project.supabase.co') {
|
|
40
|
+
console.error('❌ SUPABASE_URL not set. Fill in your .env file first.')
|
|
41
|
+
process.exit(1)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const dbPassword = options.dbPassword || process.env.SUPABASE_DB_PASSWORD
|
|
45
|
+
if (!dbPassword || dbPassword === 'your-db-password') {
|
|
46
|
+
console.error('❌ SUPABASE_DB_PASSWORD not set.')
|
|
47
|
+
console.error(' Add it to .env or pass --db-password <password>')
|
|
48
|
+
console.error(' Get it from: https://supabase.com/dashboard/project/_/settings/database')
|
|
41
49
|
process.exit(1)
|
|
42
50
|
}
|
|
43
51
|
|
|
44
|
-
// Derive connection string from Supabase URL
|
|
45
|
-
// Format: https://<ref>.supabase.co → postgres://postgres.<ref>:<password>@aws-0-<region>.pooler.supabase.com:5432/postgres
|
|
46
|
-
// Use direct connection (port 5432) via the db.<ref>.supabase.co host
|
|
47
52
|
const projectRef = supabaseUrl.replace('https://', '').split('.')[0]
|
|
48
|
-
const connectionString = `postgresql://postgres:${
|
|
53
|
+
const connectionString = `postgresql://postgres:${dbPassword}@db.${projectRef}.supabase.co:5432/postgres`
|
|
49
54
|
|
|
50
55
|
if (!existsSync(MIGRATIONS_DIR)) {
|
|
51
56
|
console.error(`❌ Migrations directory not found: ${MIGRATIONS_DIR}`)
|
|
@@ -120,7 +125,7 @@ export function registerMigrateCommands(program: Command) {
|
|
|
120
125
|
program
|
|
121
126
|
.command('migrate')
|
|
122
127
|
.description('Apply SQL migrations via direct Postgres connection')
|
|
123
|
-
.
|
|
128
|
+
.option('--db-password <password>', 'DB password override (default: reads SUPABASE_DB_PASSWORD from .env)')
|
|
124
129
|
.option('--dry-run', 'Show what would happen without making changes', false)
|
|
125
130
|
.action(async (opts) => {
|
|
126
131
|
try {
|
package/.framework/cli/index.ts
CHANGED
|
@@ -39,7 +39,6 @@
|
|
|
39
39
|
* @seeAlso functions/_shared/index.ts (core functions exposed to CLI)
|
|
40
40
|
*/
|
|
41
41
|
|
|
42
|
-
import './env-loader.ts'
|
|
43
42
|
import { Command } from 'commander'
|
|
44
43
|
|
|
45
44
|
const program = new Command()
|
|
@@ -50,59 +49,67 @@ program
|
|
|
50
49
|
.version('2.0.0')
|
|
51
50
|
.option('--account <id>', 'Override the account ID for this command')
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
{ registerItemCommands },
|
|
57
|
-
{ registerAgentCommands },
|
|
58
|
-
{ registerMigrationCommands },
|
|
59
|
-
{ registerDoctorCommands },
|
|
60
|
-
{ registerDevCommands },
|
|
61
|
-
{ registerTestCommands },
|
|
62
|
-
{ registerSystemCommands },
|
|
63
|
-
{ registerGenerateCommands },
|
|
64
|
-
{ registerCreateAppCommands },
|
|
65
|
-
{ registerInitCommands },
|
|
66
|
-
{ registerInstallAppCommands },
|
|
67
|
-
{ registerStatusCommands },
|
|
68
|
-
{ registerUninstallAppCommands },
|
|
69
|
-
{ registerMigrateCommands },
|
|
70
|
-
] = await Promise.all([
|
|
71
|
-
import('./commands/auth.ts'),
|
|
72
|
-
import('./commands/pipelines.ts'),
|
|
73
|
-
import('./commands/items.ts'),
|
|
74
|
-
import('./commands/agents.ts'),
|
|
75
|
-
import('./commands/migrations.ts'),
|
|
76
|
-
import('./commands/doctor.ts'),
|
|
77
|
-
import('./commands/dev.ts'),
|
|
78
|
-
import('./commands/test.ts'),
|
|
79
|
-
import('./commands/system.ts'),
|
|
80
|
-
import('./commands/generate.ts'),
|
|
81
|
-
import('./commands/create-app.ts'),
|
|
82
|
-
import('./commands/init.ts'),
|
|
83
|
-
import('./commands/install-app.ts'),
|
|
84
|
-
import('./commands/status.ts'),
|
|
85
|
-
import('./commands/uninstall-app.ts'),
|
|
86
|
-
import('./commands/migrate.ts'),
|
|
87
|
-
])
|
|
88
|
-
|
|
89
|
-
registerAuthCommands(program)
|
|
90
|
-
registerPipelineCommands(program)
|
|
91
|
-
registerItemCommands(program)
|
|
92
|
-
registerAgentCommands(program)
|
|
93
|
-
registerMigrationCommands(program)
|
|
94
|
-
registerDoctorCommands(program)
|
|
95
|
-
registerDevCommands(program)
|
|
96
|
-
registerTestCommands(program)
|
|
97
|
-
registerSystemCommands(program)
|
|
98
|
-
registerGenerateCommands(program)
|
|
99
|
-
registerCreateAppCommands(program)
|
|
52
|
+
// Commands that do NOT need DB/env — safe to run on a fresh install
|
|
53
|
+
const { registerInitCommands } = await import('./commands/init.ts')
|
|
54
|
+
const { registerMigrateCommands } = await import('./commands/migrate.ts')
|
|
100
55
|
registerInitCommands(program)
|
|
101
|
-
registerInstallAppCommands(program)
|
|
102
|
-
registerStatusCommands(program)
|
|
103
|
-
registerUninstallAppCommands(program)
|
|
104
56
|
registerMigrateCommands(program)
|
|
105
57
|
|
|
58
|
+
// All other commands require SUPABASE_URL to be set — only load if not init/migrate
|
|
59
|
+
const subcommand = process.argv[2]
|
|
60
|
+
const noDbCommands = ['init', 'migrate', '--help', '-h', '--version', '-V', undefined]
|
|
61
|
+
|
|
62
|
+
if (!noDbCommands.includes(subcommand)) {
|
|
63
|
+
await import('./env-loader.ts')
|
|
64
|
+
|
|
65
|
+
const [
|
|
66
|
+
{ registerAuthCommands },
|
|
67
|
+
{ registerPipelineCommands },
|
|
68
|
+
{ registerItemCommands },
|
|
69
|
+
{ registerAgentCommands },
|
|
70
|
+
{ registerMigrationCommands },
|
|
71
|
+
{ registerDoctorCommands },
|
|
72
|
+
{ registerDevCommands },
|
|
73
|
+
{ registerTestCommands },
|
|
74
|
+
{ registerSystemCommands },
|
|
75
|
+
{ registerGenerateCommands },
|
|
76
|
+
{ registerCreateAppCommands },
|
|
77
|
+
{ registerInstallAppCommands },
|
|
78
|
+
{ registerStatusCommands },
|
|
79
|
+
{ registerUninstallAppCommands },
|
|
80
|
+
] = await Promise.all([
|
|
81
|
+
import('./commands/auth.ts'),
|
|
82
|
+
import('./commands/pipelines.ts'),
|
|
83
|
+
import('./commands/items.ts'),
|
|
84
|
+
import('./commands/agents.ts'),
|
|
85
|
+
import('./commands/migrations.ts'),
|
|
86
|
+
import('./commands/doctor.ts'),
|
|
87
|
+
import('./commands/dev.ts'),
|
|
88
|
+
import('./commands/test.ts'),
|
|
89
|
+
import('./commands/system.ts'),
|
|
90
|
+
import('./commands/generate.ts'),
|
|
91
|
+
import('./commands/create-app.ts'),
|
|
92
|
+
import('./commands/install-app.ts'),
|
|
93
|
+
import('./commands/status.ts'),
|
|
94
|
+
import('./commands/uninstall-app.ts'),
|
|
95
|
+
])
|
|
96
|
+
|
|
97
|
+
registerAuthCommands(program)
|
|
98
|
+
registerPipelineCommands(program)
|
|
99
|
+
registerItemCommands(program)
|
|
100
|
+
registerAgentCommands(program)
|
|
101
|
+
registerMigrationCommands(program)
|
|
102
|
+
registerDoctorCommands(program)
|
|
103
|
+
registerDevCommands(program)
|
|
104
|
+
registerTestCommands(program)
|
|
105
|
+
registerSystemCommands(program)
|
|
106
|
+
registerGenerateCommands(program)
|
|
107
|
+
registerCreateAppCommands(program)
|
|
108
|
+
registerInstallAppCommands(program)
|
|
109
|
+
registerStatusCommands(program)
|
|
110
|
+
registerUninstallAppCommands(program)
|
|
111
|
+
}
|
|
112
|
+
|
|
106
113
|
program.parseAsync(process.argv).catch((err) => {
|
|
107
114
|
console.error('Error:', err.message)
|
|
108
115
|
process.exit(1)
|
|
@@ -31,9 +31,9 @@ import { createClient } from '@supabase/supabase-js'
|
|
|
31
31
|
* @calledBy adminDb, getUserDb (applied at client construction time)
|
|
32
32
|
*/
|
|
33
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
|
|
34
|
+
const supabaseUrl: string = _env.SUPABASE_URL || 'https://placeholder.supabase.co'
|
|
35
|
+
const supabaseServiceKey: string = _env.SUPABASE_SERVICE_ROLE_KEY || ''
|
|
36
|
+
const supabaseAnonKey: string = _env.SUPABASE_ANON_KEY || ''
|
|
37
37
|
const dbSchema: string = _env.DB_SCHEMA || 'public'
|
|
38
38
|
|
|
39
39
|
// ─── CLIENTS ─────────────────────────────────────────────────────────────────
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../.framework/cli/commands/init.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../.framework/cli/commands/init.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AA0IxC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,QAcpD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../../.framework/cli/commands/migrate.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../../.framework/cli/commands/migrate.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAuGxC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,QAevD"}
|
package/dist/cli/index.d.ts
CHANGED
package/dist/cli/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../.framework/cli/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../.framework/cli/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG"}
|