spine-framework 0.3.54 → 0.3.56
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/dev.ts +19 -0
- package/.framework/cli/commands/install-app.ts +89 -1
- package/.framework/functions/auth.ts +2 -0
- package/.framework/functions/invites.ts +655 -0
- package/.framework/migrations/005_auth_user_trigger.sql +52 -14
- package/.framework/migrations/016_invites.sql +27 -0
- package/.framework/src/App.tsx +6 -0
- package/.framework/src/apps/admin/index.tsx +6 -0
- package/.framework/src/components/admin/AdminSidebar.tsx +8 -1
- package/.framework/src/components/shared/InviteManager.tsx +352 -0
- package/.framework/src/pages/admin/InvitesPage.tsx +33 -0
- package/.framework/src/pages/auth/PendingApprovalPage.tsx +54 -0
- package/.framework/src/pages/auth/RegisterPage.tsx +433 -61
- package/.framework/src/types/auth.ts +2 -0
- package/config/vite.config.ts +4 -0
- package/package.json +3 -1
- package/scripts/assemble-frontend.sh +7 -0
- package/spine.config.json +20 -0
|
@@ -255,6 +255,25 @@ async function fastReassemble(projectRoot: string): Promise<void> {
|
|
|
255
255
|
copyChangedFiles(customFuncsDir, funcsDest)
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
|
+
|
|
259
|
+
// Reassemble spine.config.json to public directory
|
|
260
|
+
const spineConfigSrc = resolve(projectRoot, 'spine.config.json')
|
|
261
|
+
const publicDest = resolve(srcDest, 'public')
|
|
262
|
+
if (existsSync(spineConfigSrc)) {
|
|
263
|
+
if (!existsSync(publicDest)) {
|
|
264
|
+
mkdirSync(publicDest, { recursive: true })
|
|
265
|
+
}
|
|
266
|
+
const spineConfigDest = resolve(publicDest, 'spine.config.json')
|
|
267
|
+
const srcStat = statSync(spineConfigSrc)
|
|
268
|
+
let needsCopy = true
|
|
269
|
+
if (existsSync(spineConfigDest)) {
|
|
270
|
+
const destStat = statSync(spineConfigDest)
|
|
271
|
+
needsCopy = srcStat.mtimeMs > destStat.mtimeMs
|
|
272
|
+
}
|
|
273
|
+
if (needsCopy) {
|
|
274
|
+
copyFileSync(spineConfigSrc, spineConfigDest)
|
|
275
|
+
}
|
|
276
|
+
}
|
|
258
277
|
}
|
|
259
278
|
|
|
260
279
|
/**
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import type { Command } from 'commander'
|
|
21
|
-
import { existsSync, readFileSync, mkdirSync, cpSync } from 'fs'
|
|
21
|
+
import { existsSync, readFileSync, mkdirSync, cpSync, writeFileSync } from 'fs'
|
|
22
22
|
import { resolve, dirname, join, basename } from 'path'
|
|
23
23
|
import { fileURLToPath } from 'url'
|
|
24
24
|
import { execSync } from 'child_process'
|
|
@@ -81,6 +81,14 @@ export function registerInstallAppCommands(program: Command) {
|
|
|
81
81
|
await seedApp(appDest, appSlug)
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
// 6. Aggregate registration config from manifest into spine.config.json
|
|
85
|
+
const manifestPath = join(appDest, 'manifest.json')
|
|
86
|
+
let manifest: Record<string, any> = {}
|
|
87
|
+
try { manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) } catch {}
|
|
88
|
+
if (manifest.registration?.enabled) {
|
|
89
|
+
updateRegistrationConfig(appSlug, manifest.registration)
|
|
90
|
+
}
|
|
91
|
+
|
|
84
92
|
console.log(`\n✅ ${appSlug} installed successfully!\n`)
|
|
85
93
|
console.log('Next: npm run assemble && netlify dev\n')
|
|
86
94
|
|
|
@@ -153,6 +161,14 @@ export function registerInstallAppCommands(program: Command) {
|
|
|
153
161
|
}
|
|
154
162
|
}
|
|
155
163
|
|
|
164
|
+
// Update registration config from manifest
|
|
165
|
+
const manifestPath = join(appDest, 'manifest.json')
|
|
166
|
+
let manifest: Record<string, any> = {}
|
|
167
|
+
try { manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) } catch {}
|
|
168
|
+
if (manifest.registration?.enabled) {
|
|
169
|
+
updateRegistrationConfig(appSlug, manifest.registration)
|
|
170
|
+
}
|
|
171
|
+
|
|
156
172
|
console.log(`\n✅ ${appSlug} updated.\n`)
|
|
157
173
|
} catch (err: any) {
|
|
158
174
|
console.error(`\n❌ Update failed: ${err.message}`)
|
|
@@ -278,3 +294,75 @@ async function seedApp(appDir: string, appSlug: string) {
|
|
|
278
294
|
}
|
|
279
295
|
}
|
|
280
296
|
}
|
|
297
|
+
|
|
298
|
+
// ─── SPINE CONFIG HELPERS ───────────────────────────────────────────────────
|
|
299
|
+
|
|
300
|
+
interface RegistrationConfig {
|
|
301
|
+
enabled: boolean
|
|
302
|
+
default_role: string
|
|
303
|
+
redirect_path: string
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
interface SpineConfig {
|
|
307
|
+
registration?: {
|
|
308
|
+
default_app?: string
|
|
309
|
+
default_role?: string
|
|
310
|
+
allow_url_override?: boolean
|
|
311
|
+
apps?: Record<string, {
|
|
312
|
+
role: string
|
|
313
|
+
path: string
|
|
314
|
+
enabled: boolean
|
|
315
|
+
}>
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const SPINE_CONFIG_PATH = join(PROJECT_ROOT, 'spine.config.json')
|
|
320
|
+
|
|
321
|
+
function loadSpineConfig(): SpineConfig {
|
|
322
|
+
if (!existsSync(SPINE_CONFIG_PATH)) {
|
|
323
|
+
return { registration: { apps: {} } }
|
|
324
|
+
}
|
|
325
|
+
try {
|
|
326
|
+
return JSON.parse(readFileSync(SPINE_CONFIG_PATH, 'utf8'))
|
|
327
|
+
} catch {
|
|
328
|
+
return { registration: { apps: {} } }
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function saveSpineConfig(config: SpineConfig): void {
|
|
333
|
+
writeFileSync(SPINE_CONFIG_PATH, JSON.stringify(config, null, 2) + '\n')
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function updateRegistrationConfig(appSlug: string, regConfig: RegistrationConfig): void {
|
|
337
|
+
const config = loadSpineConfig()
|
|
338
|
+
|
|
339
|
+
// Ensure registration section exists
|
|
340
|
+
if (!config.registration) {
|
|
341
|
+
config.registration = { apps: {} }
|
|
342
|
+
}
|
|
343
|
+
if (!config.registration.apps) {
|
|
344
|
+
config.registration.apps = {}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Add/update this app's registration entry
|
|
348
|
+
config.registration.apps[appSlug] = {
|
|
349
|
+
role: regConfig.default_role,
|
|
350
|
+
path: regConfig.redirect_path,
|
|
351
|
+
enabled: regConfig.enabled,
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// If this is the first registration-enabled app, make it the default
|
|
355
|
+
const enabledApps = Object.entries(config.registration.apps).filter(([, cfg]) => cfg.enabled)
|
|
356
|
+
if (enabledApps.length === 1 || !config.registration.default_app) {
|
|
357
|
+
config.registration.default_app = appSlug
|
|
358
|
+
config.registration.default_role = regConfig.default_role
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Default allow_url_override to true if not set
|
|
362
|
+
if (config.registration.allow_url_override === undefined) {
|
|
363
|
+
config.registration.allow_url_override = true
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
saveSpineConfig(config)
|
|
367
|
+
console.log(` ✓ Updated spine.config.json registration for ${appSlug}`)
|
|
368
|
+
}
|
|
@@ -77,6 +77,7 @@ export const context = createHandler(async (ctx, _body) => {
|
|
|
77
77
|
avatar_url,
|
|
78
78
|
account_id,
|
|
79
79
|
role_id,
|
|
80
|
+
status,
|
|
80
81
|
account:accounts!people_account_id_fkey(
|
|
81
82
|
id,
|
|
82
83
|
slug,
|
|
@@ -154,6 +155,7 @@ export const context = createHandler(async (ctx, _body) => {
|
|
|
154
155
|
roles: [roleSlug].filter(Boolean),
|
|
155
156
|
permissions: effectivePermissions,
|
|
156
157
|
is_system_admin: roleSlug === 'system_admin',
|
|
158
|
+
status: personData.status ?? 'active',
|
|
157
159
|
accessible_accounts: accessibleAccounts
|
|
158
160
|
}
|
|
159
161
|
})
|