spine-framework 0.1.60 → 0.2.0
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/create-app.ts +1 -1
- package/.framework/cli/commands/dev.ts +215 -33
- package/.framework/cli/index.ts +37 -63
- package/.framework/functions/_shared/app-manifest.ts +8 -15
- package/.framework/functions/_shared/db.ts +11 -15
- package/.framework/functions/_shared/index.ts +0 -9
- package/.framework/functions/_shared/principal.ts +4 -62
- package/.framework/functions/_shared/resolve-ids.ts +6 -6
- package/.framework/functions/_shared/webhook-registry.ts +1 -1
- package/.framework/functions/admin-funnel.ts +104 -0
- package/.framework/functions/admin-install-funnel.ts +225 -0
- package/.framework/functions/admin-signals.ts +241 -0
- package/.framework/migrations/001_schema.sql +406 -0
- package/.framework/migrations/002_rls_and_functions.sql +710 -0
- package/.framework/migrations/003_system_data.sql +520 -0
- package/.framework/migrations/004_enhancements.sql +43 -0
- package/.framework/public/_redirects +3 -0
- package/.framework/public/spine-logo.jpg +0 -0
- package/.framework/public/spine-logo.svg +3 -0
- package/{scripts → .framework/scripts}/assemble-frontend.sh +1 -1
- package/{scripts → .framework/scripts}/assemble-functions.sh +1 -1
- package/{scripts → .framework/scripts}/assemble.sh +2 -8
- package/{scripts → .framework/scripts}/check-core-integrity.sh +0 -0
- package/.framework/seeds/link_types/account_cli_instances.json +9 -0
- package/.framework/seeds/types/funnel_signal_use.json +98 -0
- package/.framework/seeds/types/spine_instance.json +109 -0
- package/.framework/src/App.tsx +6 -4
- package/.framework/src/components/ui/accordion.tsx +1 -1
- package/.framework/src/components/ui/alert-dialog.tsx +1 -1
- package/.framework/src/components/ui/aspect-ratio.tsx +1 -1
- package/.framework/src/components/ui/avatar.tsx +1 -1
- package/.framework/src/components/ui/badge.tsx +2 -2
- package/.framework/src/components/ui/breadcrumb.tsx +2 -2
- package/.framework/src/components/ui/button-group.tsx +2 -2
- package/.framework/src/components/ui/button.tsx +2 -2
- package/.framework/src/components/ui/chart.tsx +6 -1
- package/.framework/src/components/ui/checkbox.tsx +1 -1
- package/.framework/src/components/ui/collapsible.tsx +1 -1
- package/.framework/src/components/ui/context-menu.tsx +1 -1
- package/.framework/src/components/ui/dialog.tsx +1 -1
- package/.framework/src/components/ui/direction.tsx +17 -1
- package/.framework/src/components/ui/dropdown-menu.tsx +1 -1
- package/.framework/src/components/ui/hover-card.tsx +1 -1
- package/.framework/src/components/ui/item.tsx +2 -2
- package/.framework/src/components/ui/label.tsx +1 -1
- package/.framework/src/components/ui/menubar.tsx +1 -1
- package/.framework/src/components/ui/navigation-menu.tsx +1 -1
- package/.framework/src/components/ui/popover.tsx +1 -1
- package/.framework/src/components/ui/progress.tsx +1 -1
- package/.framework/src/components/ui/radio-group.tsx +1 -1
- package/.framework/src/components/ui/scroll-area.tsx +1 -1
- package/.framework/src/components/ui/select.tsx +1 -1
- package/.framework/src/components/ui/separator.tsx +1 -1
- package/.framework/src/components/ui/sheet.tsx +1 -1
- package/.framework/src/components/ui/sidebar.tsx +6 -6
- package/.framework/src/components/ui/slider.tsx +1 -1
- package/.framework/src/components/ui/switch.tsx +1 -1
- package/.framework/src/components/ui/tabs.tsx +1 -1
- package/.framework/src/components/ui/toggle-group.tsx +1 -1
- package/.framework/src/components/ui/toggle.tsx +1 -1
- package/.framework/src/components/ui/tooltip.tsx +1 -1
- package/.framework/src/pages/auth/LoginPage.tsx +10 -9
- package/LICENSE.md +193 -0
- package/README.md +254 -0
- package/custom/.devin/skills/install-app/SKILL.md +39 -0
- package/custom/.devin/workflows/app-install.yaml +83 -0
- package/custom/README.md +79 -0
- package/docs/APPS.md +232 -0
- package/docs/ARCHITECTURE.md +246 -0
- package/docs/INSTALL.md +155 -0
- package/docs/README.md +170 -0
- package/docs/design-schema-spec.md +1837 -0
- package/docs/dev-guides/01-create-an-app.md +183 -0
- package/docs/dev-guides/02-create-a-function.md +178 -0
- package/docs/dev-guides/03-create-a-component.md +178 -0
- package/docs/dev-guides/04-webhook-handlers.md +129 -0
- package/docs/dev-guides/05-testing.md +168 -0
- package/docs/dev-guides/README.md +40 -0
- package/docs/npm-packages-plan.md +288 -0
- package/docs/spine-core--api-reference.md +822 -0
- package/package.json +78 -144
- package/.framework/cli/bin.cjs +0 -14
- package/.framework/cli/commands/init.ts +0 -186
- package/.framework/cli/commands/install-app.ts +0 -560
- package/.framework/cli/commands/migrate.ts +0 -139
- package/.framework/cli/commands/status.ts +0 -197
- package/.framework/cli/commands/uninstall-app.ts +0 -166
- package/.framework/cli/welcome.cjs +0 -45
- package/.framework/docs/STABILITY.md +0 -52
- package/.framework/docs/examples/custom-app/README.md +0 -77
- package/.framework/docs/examples/custom-function/README.md +0 -27
- package/.framework/docs/examples/custom-function/handler.ts +0 -48
- package/.framework/docs/examples/custom-webhook/README.md +0 -68
- package/.framework/migrations/000_foundation.sql +0 -1265
- package/.framework/migrations/001_seed.sql +0 -163
- package/.framework/migrations/002_seed_constraints.sql +0 -19
- package/.framework/migrations/003_auth_user_trigger.sql +0 -67
- package/.framework/src/pages/auth/RegisterPage.tsx +0 -163
- package/STRUCTURE.md +0 -150
- package/bin/spine-framework.cjs +0 -62
- package/bin/welcome.cjs +0 -45
- package/bin/ws-shim.cjs +0 -8
- package/bin/ws-shim.ts +0 -10
- package/config/components.json +0 -25
- package/config/deno.lock +0 -108
- package/config/package-lock.json +0 -17183
- package/config/postcss.config.cjs +0 -10
- package/config/tailwind.config.cjs +0 -78
- package/config/tsconfig.build.json +0 -32
- package/config/tsconfig.cli.json +0 -18
- package/config/tsconfig.json +0 -41
- package/config/tsconfig.node.json +0 -17
- package/config/tsconfig.node.tsbuildinfo +0 -1
- package/config/tsconfig.tsbuildinfo +0 -1
- package/config/typedoc.json +0 -16
- package/config/vite.config.d.ts +0 -2
- package/config/vite.config.ts +0 -72
- package/dist/cli/commands/agents.d.ts +0 -39
- package/dist/cli/commands/agents.d.ts.map +0 -1
- package/dist/cli/commands/auth.d.ts +0 -36
- package/dist/cli/commands/auth.d.ts.map +0 -1
- package/dist/cli/commands/create-app.d.ts +0 -23
- package/dist/cli/commands/create-app.d.ts.map +0 -1
- package/dist/cli/commands/dev.d.ts +0 -24
- package/dist/cli/commands/dev.d.ts.map +0 -1
- package/dist/cli/commands/doctor.d.ts +0 -42
- package/dist/cli/commands/doctor.d.ts.map +0 -1
- package/dist/cli/commands/generate.d.ts +0 -36
- package/dist/cli/commands/generate.d.ts.map +0 -1
- package/dist/cli/commands/init.d.ts +0 -20
- package/dist/cli/commands/init.d.ts.map +0 -1
- package/dist/cli/commands/install-app.d.ts +0 -30
- package/dist/cli/commands/install-app.d.ts.map +0 -1
- package/dist/cli/commands/items.d.ts +0 -45
- package/dist/cli/commands/items.d.ts.map +0 -1
- package/dist/cli/commands/migrate.d.ts +0 -21
- package/dist/cli/commands/migrate.d.ts.map +0 -1
- package/dist/cli/commands/migrations.d.ts +0 -41
- package/dist/cli/commands/migrations.d.ts.map +0 -1
- package/dist/cli/commands/pipelines.d.ts +0 -40
- package/dist/cli/commands/pipelines.d.ts.map +0 -1
- package/dist/cli/commands/status.d.ts +0 -23
- package/dist/cli/commands/status.d.ts.map +0 -1
- package/dist/cli/commands/system.d.ts +0 -29
- package/dist/cli/commands/system.d.ts.map +0 -1
- package/dist/cli/commands/test.d.ts +0 -46
- package/dist/cli/commands/test.d.ts.map +0 -1
- package/dist/cli/commands/uninstall-app.d.ts +0 -23
- package/dist/cli/commands/uninstall-app.d.ts.map +0 -1
- package/dist/cli/context.d.ts +0 -88
- package/dist/cli/context.d.ts.map +0 -1
- package/dist/cli/env-loader.d.ts +0 -14
- package/dist/cli/env-loader.d.ts.map +0 -1
- package/dist/cli/index.d.ts +0 -41
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/functions/_shared/agent-runner.d.ts +0 -156
- package/dist/functions/_shared/agent-runner.d.ts.map +0 -1
- package/dist/functions/_shared/app-manifest.d.ts +0 -68
- package/dist/functions/_shared/app-manifest.d.ts.map +0 -1
- package/dist/functions/_shared/audit.d.ts +0 -91
- package/dist/functions/_shared/audit.d.ts.map +0 -1
- package/dist/functions/_shared/db.d.ts +0 -125
- package/dist/functions/_shared/db.d.ts.map +0 -1
- package/dist/functions/_shared/index.d.ts +0 -299
- package/dist/functions/_shared/index.d.ts.map +0 -1
- package/dist/functions/_shared/middleware.d.ts +0 -315
- package/dist/functions/_shared/middleware.d.ts.map +0 -1
- package/dist/functions/_shared/permissions.d.ts +0 -626
- package/dist/functions/_shared/permissions.d.ts.map +0 -1
- package/dist/functions/_shared/pipeline-runner.d.ts +0 -124
- package/dist/functions/_shared/pipeline-runner.d.ts.map +0 -1
- package/dist/functions/_shared/principal.d.ts +0 -284
- package/dist/functions/_shared/principal.d.ts.map +0 -1
- package/dist/functions/_shared/resolve-ids.d.ts +0 -10
- package/dist/functions/_shared/resolve-ids.d.ts.map +0 -1
- package/dist/functions/_shared/schema-utils.d.ts +0 -181
- package/dist/functions/_shared/schema-utils.d.ts.map +0 -1
- package/dist/functions/_shared/testing.d.ts +0 -172
- package/dist/functions/_shared/testing.d.ts.map +0 -1
- package/dist/functions/_shared/trigger-engine.d.ts +0 -140
- package/dist/functions/_shared/trigger-engine.d.ts.map +0 -1
- package/dist/functions/_shared/webhook-registration.d.ts +0 -81
- package/dist/functions/_shared/webhook-registration.d.ts.map +0 -1
- package/dist/functions/_shared/webhook-registry.d.ts +0 -57
- package/dist/functions/_shared/webhook-registry.d.ts.map +0 -1
- package/dist/functions/account-nodes.d.ts +0 -48
- package/dist/functions/account-nodes.d.ts.map +0 -1
- package/dist/functions/admin-data.d.ts +0 -178
- package/dist/functions/admin-data.d.ts.map +0 -1
- package/dist/functions/ai-agents.d.ts +0 -125
- package/dist/functions/ai-agents.d.ts.map +0 -1
- package/dist/functions/api-keys.d.ts +0 -140
- package/dist/functions/api-keys.d.ts.map +0 -1
- package/dist/functions/apps.d.ts +0 -163
- package/dist/functions/apps.d.ts.map +0 -1
- package/dist/functions/auth.d.ts +0 -74
- package/dist/functions/auth.d.ts.map +0 -1
- package/dist/functions/debug-auth.d.ts +0 -33
- package/dist/functions/debug-auth.d.ts.map +0 -1
- package/dist/functions/embeddings.d.ts +0 -205
- package/dist/functions/embeddings.d.ts.map +0 -1
- package/dist/functions/integration-routes.d.ts +0 -45
- package/dist/functions/integration-routes.d.ts.map +0 -1
- package/dist/functions/integrations.d.ts +0 -124
- package/dist/functions/integrations.d.ts.map +0 -1
- package/dist/functions/item-progress.d.ts +0 -41
- package/dist/functions/item-progress.d.ts.map +0 -1
- package/dist/functions/logs.d.ts +0 -162
- package/dist/functions/logs.d.ts.map +0 -1
- package/dist/functions/observability.d.ts +0 -123
- package/dist/functions/observability.d.ts.map +0 -1
- package/dist/functions/pipeline-executions.d.ts +0 -190
- package/dist/functions/pipeline-executions.d.ts.map +0 -1
- package/dist/functions/pipelines.d.ts +0 -171
- package/dist/functions/pipelines.d.ts.map +0 -1
- package/dist/functions/prompt-configs.d.ts +0 -125
- package/dist/functions/prompt-configs.d.ts.map +0 -1
- package/dist/functions/roles.d.ts +0 -118
- package/dist/functions/roles.d.ts.map +0 -1
- package/dist/functions/system-cron.d.ts +0 -65
- package/dist/functions/system-cron.d.ts.map +0 -1
- package/dist/functions/system.d.ts +0 -29
- package/dist/functions/system.d.ts.map +0 -1
- package/dist/functions/tests.d.ts +0 -28
- package/dist/functions/tests.d.ts.map +0 -1
- package/dist/functions/timers.d.ts +0 -139
- package/dist/functions/timers.d.ts.map +0 -1
- package/dist/functions/triggers.d.ts +0 -203
- package/dist/functions/triggers.d.ts.map +0 -1
- package/dist/functions/types.d.ts +0 -151
- package/dist/functions/types.d.ts.map +0 -1
- package/dist/src/types/types.d.ts +0 -364
- package/dist/src/types/types.d.ts.map +0 -1
- package/index.html +0 -13
- package/netlify.toml +0 -36
- package/package-project.json +0 -64
- package/scripts/ingest-chunks.cjs +0 -202
- package/scripts/kb-chunk-parser.cjs +0 -312
- package/scripts/kb-chunk-parser.ts +0 -330
- package/scripts/load-test-app-install.ts +0 -484
- package/scripts/netlify-dev-wrapper.sh +0 -22
- package/vitest.config.ts +0 -45
- /package/{scripts → .framework/scripts}/app-install-cli.ts +0 -0
- /package/{scripts → .framework/scripts}/boundary-check.sh +0 -0
- /package/{scripts → .framework/scripts}/build-manifest.sh +0 -0
- /package/{scripts → .framework/scripts}/verify-integrity.sh +0 -0
|
@@ -28,7 +28,7 @@ import { adminDb } from '../../functions/_shared/index.ts'
|
|
|
28
28
|
|
|
29
29
|
const __filename = fileURLToPath(import.meta.url)
|
|
30
30
|
const __dirname = dirname(__filename)
|
|
31
|
-
const PROJECT_ROOT =
|
|
31
|
+
const PROJECT_ROOT = resolve(__dirname, '../../../')
|
|
32
32
|
|
|
33
33
|
function toTitleCase(slug: string): string {
|
|
34
34
|
return slug.split('-').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join(' ')
|
|
@@ -5,81 +5,177 @@
|
|
|
5
5
|
* @layer cli
|
|
6
6
|
* @stability stable
|
|
7
7
|
*
|
|
8
|
-
* `spine
|
|
8
|
+
* `spine dev` command — unified development server for Spine.
|
|
9
|
+
* Handles assembly, integrity verification, and Vite dev server startup.
|
|
10
|
+
*
|
|
11
|
+
* **Commands:**
|
|
12
|
+
* | Subcommand | Description |
|
|
13
|
+
* |-------------------|-------------------------------------------------------|
|
|
14
|
+
* | `dev` | Start dev server with assembly and integrity check |
|
|
15
|
+
* | `dev --no-verify` | Skip integrity verification (faster) |
|
|
16
|
+
* | `dev --port 3002` | Use custom port (default: 3001) |
|
|
17
|
+
* | `dev --watch` | Watch v2-custom for changes and auto-reassemble |
|
|
18
|
+
* | `dev --no-watch` | Disable file watching (manual rebuild only) |
|
|
9
19
|
*
|
|
10
20
|
* **What happens:**
|
|
11
|
-
* 1. Runs `
|
|
12
|
-
* 2.
|
|
21
|
+
* 1. Runs `assemble:v2` to merge v2-core + v2-custom
|
|
22
|
+
* 2. Runs `verify` to check core integrity (unless --no-verify)
|
|
23
|
+
* 3. Starts Vite dev server on port 3001 (or --port)
|
|
24
|
+
* 4. Watches v2-custom/ for changes (--watch by default)
|
|
25
|
+
* 5. Fast incremental reassembly on custom code changes
|
|
13
26
|
*
|
|
14
27
|
* **Usage:**
|
|
15
28
|
* ```bash
|
|
16
|
-
* spine
|
|
17
|
-
* spine
|
|
29
|
+
* spine dev
|
|
30
|
+
* spine dev --port 3002
|
|
31
|
+
* spine dev --no-verify
|
|
18
32
|
* ```
|
|
19
33
|
*
|
|
20
|
-
* @seeAlso scripts/assemble.sh (assembly script)
|
|
21
|
-
* @seeAlso
|
|
34
|
+
* @seeAlso scripts/assemble-v2.sh (assembly script)
|
|
35
|
+
* @seeAlso scripts/verify-integrity.sh (verification script)
|
|
36
|
+
* @seeAlso vite.config.ts (Vite configuration)
|
|
22
37
|
*/
|
|
23
38
|
|
|
24
39
|
import type { Command } from 'commander'
|
|
25
|
-
import { spawn } from 'child_process'
|
|
40
|
+
import { spawn, execSync } from 'child_process'
|
|
26
41
|
import { resolve, dirname } from 'path'
|
|
27
42
|
import { fileURLToPath } from 'url'
|
|
28
|
-
import { existsSync } from 'fs'
|
|
43
|
+
import { watch, existsSync, statSync, readdirSync } from 'fs'
|
|
29
44
|
|
|
30
45
|
const __filename = fileURLToPath(import.meta.url)
|
|
31
46
|
const __dirname = dirname(__filename)
|
|
32
|
-
const PROJECT_ROOT =
|
|
47
|
+
const PROJECT_ROOT = resolve(__dirname, '../../../')
|
|
33
48
|
|
|
34
49
|
// ─── COMMAND REGISTRATION ──────────────────────────────────────────────────
|
|
35
50
|
|
|
36
51
|
export function registerDevCommands(program: Command) {
|
|
37
52
|
program
|
|
38
53
|
.command('dev')
|
|
39
|
-
.description('
|
|
40
|
-
.option('--no-
|
|
54
|
+
.description('Start Spine development server')
|
|
55
|
+
.option('--no-verify', 'Skip integrity verification')
|
|
56
|
+
.option('--port <port>', 'Dev server port', '3001')
|
|
57
|
+
.option('--host', 'Expose to network', false)
|
|
58
|
+
.option('--no-watch', 'Disable file watching')
|
|
59
|
+
.option('--watch-delay <ms>', 'Debounce delay for reassembly', '500')
|
|
41
60
|
.action(async (opts) => {
|
|
42
61
|
console.log('\n🚀 Starting Spine dev server...\n')
|
|
43
62
|
|
|
44
63
|
try {
|
|
45
64
|
// Step 1: Assembly
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
65
|
+
console.log('📦 Step 1: Assembling v2-core + v2-custom...')
|
|
66
|
+
const assemblyExitCode = await runCommand(
|
|
67
|
+
'bash',
|
|
68
|
+
[resolve(PROJECT_ROOT, 'scripts/assemble-v2.sh')],
|
|
69
|
+
PROJECT_ROOT
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
if (assemblyExitCode !== 0) {
|
|
73
|
+
console.error('\n❌ Assembly failed. Please check the errors above.')
|
|
74
|
+
process.exit(1)
|
|
75
|
+
}
|
|
76
|
+
console.log('✓ Assembly complete\n')
|
|
49
77
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
78
|
+
// Step 2: Integrity verification (unless skipped)
|
|
79
|
+
if (opts.verify !== false) {
|
|
80
|
+
console.log('🔒 Step 2: Verifying core integrity...')
|
|
81
|
+
const verifyExitCode = await runCommand(
|
|
82
|
+
'bash',
|
|
83
|
+
[resolve(PROJECT_ROOT, 'scripts/verify-integrity.sh')],
|
|
84
|
+
PROJECT_ROOT
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if (verifyExitCode !== 0) {
|
|
88
|
+
console.warn('\n⚠️ Integrity check failed. Continuing anyway (--no-verify to skip)\n')
|
|
89
|
+
} else {
|
|
90
|
+
console.log('✓ Integrity verified\n')
|
|
53
91
|
}
|
|
54
|
-
console.log('✓ Assembly complete\n')
|
|
55
92
|
} else {
|
|
56
|
-
console.log('⏭️ Step
|
|
93
|
+
console.log('⏭️ Step 2: Skipping integrity verification (--no-verify)\n')
|
|
57
94
|
}
|
|
58
95
|
|
|
59
|
-
// Step
|
|
60
|
-
console.log(
|
|
96
|
+
// Step 3: Start Vite
|
|
97
|
+
console.log(`🌐 Step 3: Starting Vite dev server on port ${opts.port}...`)
|
|
61
98
|
console.log(' (Press Ctrl+C to stop)\n')
|
|
62
99
|
|
|
63
|
-
const
|
|
64
|
-
|
|
100
|
+
const vite = spawn(
|
|
101
|
+
resolve(PROJECT_ROOT, 'node_modules/.bin/vite'),
|
|
102
|
+
[
|
|
103
|
+
'--config', resolve(PROJECT_ROOT, 'vite.config.ts'),
|
|
104
|
+
'--port', opts.port,
|
|
105
|
+
...(opts.host ? ['--host'] : [])
|
|
106
|
+
],
|
|
107
|
+
{
|
|
108
|
+
cwd: PROJECT_ROOT,
|
|
109
|
+
stdio: 'inherit',
|
|
110
|
+
env: { ...process.env, SPINE_DEV: 'true' }
|
|
111
|
+
}
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
// Step 4: Watch v2-custom for changes (unless disabled)
|
|
115
|
+
let watcher: ReturnType<typeof watch> | null = null
|
|
116
|
+
if (opts.watch !== false) {
|
|
117
|
+
const watchDelay = parseInt(opts.watchDelay) || 500
|
|
118
|
+
const customDir = resolve(PROJECT_ROOT, 'v2-custom')
|
|
65
119
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
120
|
+
if (existsSync(customDir)) {
|
|
121
|
+
console.log(`👁️ Step 4: Watching v2-custom/ for changes...`)
|
|
122
|
+
console.log(` (Changes trigger fast reassembly after ${watchDelay}ms debounce)\n`)
|
|
123
|
+
|
|
124
|
+
let reassemblyTimeout: NodeJS.Timeout | null = null
|
|
125
|
+
|
|
126
|
+
watcher = watch(customDir, { recursive: true }, (eventType, filename) => {
|
|
127
|
+
// Ignore node_modules, .git, and temp files
|
|
128
|
+
if (!filename || filename.includes('node_modules') || filename.startsWith('.')) {
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
console.log(`\n📝 Change detected in v2-custom/${filename}`)
|
|
71
133
|
|
|
72
|
-
|
|
134
|
+
// Debounce reassembly
|
|
135
|
+
if (reassemblyTimeout) {
|
|
136
|
+
clearTimeout(reassemblyTimeout)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
reassemblyTimeout = setTimeout(async () => {
|
|
140
|
+
console.log('🔧 Running fast reassembly...')
|
|
141
|
+
try {
|
|
142
|
+
const start = Date.now()
|
|
143
|
+
await fastReassemble(PROJECT_ROOT)
|
|
144
|
+
const duration = Date.now() - start
|
|
145
|
+
console.log(`✓ Reassembly complete (${duration}ms)\n`)
|
|
146
|
+
} catch (err: any) {
|
|
147
|
+
console.error(`✗ Reassembly failed: ${err.message}\n`)
|
|
148
|
+
}
|
|
149
|
+
}, watchDelay)
|
|
150
|
+
})
|
|
151
|
+
} else {
|
|
152
|
+
console.log('⏭️ Step 4: v2-custom/ not found, skipping watch mode\n')
|
|
153
|
+
}
|
|
154
|
+
} else {
|
|
155
|
+
console.log('⏭️ Step 4: File watching disabled (--no-watch)\n')
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
vite.on('exit', (code) => {
|
|
159
|
+
if (watcher) {
|
|
160
|
+
watcher.close()
|
|
161
|
+
}
|
|
73
162
|
process.exit(code || 0)
|
|
74
163
|
})
|
|
75
164
|
|
|
165
|
+
// Handle Ctrl+C gracefully
|
|
76
166
|
process.on('SIGINT', () => {
|
|
77
|
-
console.log('\n\n🛑 Shutting down...')
|
|
78
|
-
|
|
167
|
+
console.log('\n\n🛑 Shutting down dev server...')
|
|
168
|
+
if (watcher) {
|
|
169
|
+
watcher.close()
|
|
170
|
+
}
|
|
171
|
+
vite.kill('SIGTERM')
|
|
79
172
|
})
|
|
80
173
|
|
|
81
174
|
process.on('SIGTERM', () => {
|
|
82
|
-
|
|
175
|
+
if (watcher) {
|
|
176
|
+
watcher.close()
|
|
177
|
+
}
|
|
178
|
+
vite.kill('SIGTERM')
|
|
83
179
|
})
|
|
84
180
|
|
|
85
181
|
} catch (err: any) {
|
|
@@ -111,3 +207,89 @@ function runCommand(command: string, args: string[], cwd: string): Promise<numbe
|
|
|
111
207
|
})
|
|
112
208
|
})
|
|
113
209
|
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Fast incremental reassembly of v2-custom files only.
|
|
213
|
+
* Uses rsync if available, falls back to selective copy.
|
|
214
|
+
*/
|
|
215
|
+
async function fastReassemble(projectRoot: string): Promise<void> {
|
|
216
|
+
const customDir = resolve(projectRoot, 'v2-custom')
|
|
217
|
+
const srcDest = resolve(projectRoot, 'src/v2-assembled')
|
|
218
|
+
const funcsDest = resolve(projectRoot, 'functions')
|
|
219
|
+
|
|
220
|
+
// Check if rsync is available
|
|
221
|
+
let hasRsync = false
|
|
222
|
+
try {
|
|
223
|
+
execSync('which rsync', { stdio: 'pipe' })
|
|
224
|
+
hasRsync = true
|
|
225
|
+
} catch {
|
|
226
|
+
hasRsync = false
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Reassemble custom frontend files
|
|
230
|
+
const customSrcDir = resolve(customDir, 'src')
|
|
231
|
+
if (existsSync(customSrcDir)) {
|
|
232
|
+
const destDir = srcDest
|
|
233
|
+
|
|
234
|
+
if (hasRsync) {
|
|
235
|
+
// Use rsync for efficient incremental sync
|
|
236
|
+
execSync(
|
|
237
|
+
`rsync -av --delete "${customSrcDir}/" "${destDir}/"`,
|
|
238
|
+
{ stdio: 'pipe', cwd: projectRoot }
|
|
239
|
+
)
|
|
240
|
+
} else {
|
|
241
|
+
// Fallback: copy files that have changed
|
|
242
|
+
copyChangedFiles(customSrcDir, destDir)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Reassemble custom function files
|
|
247
|
+
const customFuncsDir = resolve(customDir, 'functions')
|
|
248
|
+
if (existsSync(customFuncsDir)) {
|
|
249
|
+
if (hasRsync) {
|
|
250
|
+
execSync(
|
|
251
|
+
`rsync -av --delete "${customFuncsDir}/" "${funcsDest}/"`,
|
|
252
|
+
{ stdio: 'pipe', cwd: projectRoot }
|
|
253
|
+
)
|
|
254
|
+
} else {
|
|
255
|
+
copyChangedFiles(customFuncsDir, funcsDest)
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Copy only files that have changed (mtime comparison).
|
|
262
|
+
* Fallback when rsync is not available.
|
|
263
|
+
*/
|
|
264
|
+
function copyChangedFiles(src: string, dest: string): void {
|
|
265
|
+
const files = readdirSync(src, { withFileTypes: true })
|
|
266
|
+
|
|
267
|
+
for (const entry of files) {
|
|
268
|
+
const srcPath = resolve(src, entry.name)
|
|
269
|
+
const destPath = resolve(dest, entry.name)
|
|
270
|
+
|
|
271
|
+
if (entry.isDirectory()) {
|
|
272
|
+
if (!existsSync(destPath)) {
|
|
273
|
+
// Create directory
|
|
274
|
+
const { mkdirSync } = require('fs')
|
|
275
|
+
mkdirSync(destPath, { recursive: true })
|
|
276
|
+
}
|
|
277
|
+
// Recurse
|
|
278
|
+
copyChangedFiles(srcPath, destPath)
|
|
279
|
+
} else {
|
|
280
|
+
// Check if file needs copying
|
|
281
|
+
const srcStat = statSync(srcPath)
|
|
282
|
+
let needsCopy = true
|
|
283
|
+
|
|
284
|
+
if (existsSync(destPath)) {
|
|
285
|
+
const destStat = statSync(destPath)
|
|
286
|
+
needsCopy = srcStat.mtime > destStat.mtime
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (needsCopy) {
|
|
290
|
+
const { copyFileSync } = require('fs')
|
|
291
|
+
copyFileSync(srcPath, destPath)
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
package/.framework/cli/index.ts
CHANGED
|
@@ -19,10 +19,6 @@
|
|
|
19
19
|
* | items | commands/items.ts |
|
|
20
20
|
* | agents | commands/agents.ts |
|
|
21
21
|
* | migrations | commands/migrations.ts |
|
|
22
|
-
* | init | commands/init.ts |
|
|
23
|
-
* | install-app | commands/install-app.ts |
|
|
24
|
-
* | status | commands/status.ts |
|
|
25
|
-
* | uninstall | commands/uninstall-app.ts |
|
|
26
22
|
*
|
|
27
23
|
* **Usage:**
|
|
28
24
|
* ```bash
|
|
@@ -39,6 +35,7 @@
|
|
|
39
35
|
* @seeAlso functions/_shared/index.ts (core functions exposed to CLI)
|
|
40
36
|
*/
|
|
41
37
|
|
|
38
|
+
import './env-loader.ts'
|
|
42
39
|
import { Command } from 'commander'
|
|
43
40
|
|
|
44
41
|
const program = new Command()
|
|
@@ -49,66 +46,43 @@ program
|
|
|
49
46
|
.version('2.0.0')
|
|
50
47
|
.option('--account <id>', 'Override the account ID for this command')
|
|
51
48
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
const [
|
|
50
|
+
{ registerAuthCommands },
|
|
51
|
+
{ registerPipelineCommands },
|
|
52
|
+
{ registerItemCommands },
|
|
53
|
+
{ registerAgentCommands },
|
|
54
|
+
{ registerMigrationCommands },
|
|
55
|
+
{ registerDoctorCommands },
|
|
56
|
+
{ registerDevCommands },
|
|
57
|
+
{ registerTestCommands },
|
|
58
|
+
{ registerSystemCommands },
|
|
59
|
+
{ registerGenerateCommands },
|
|
60
|
+
{ registerCreateAppCommands },
|
|
61
|
+
] = await Promise.all([
|
|
62
|
+
import('./commands/auth.ts'),
|
|
63
|
+
import('./commands/pipelines.ts'),
|
|
64
|
+
import('./commands/items.ts'),
|
|
65
|
+
import('./commands/agents.ts'),
|
|
66
|
+
import('./commands/migrations.ts'),
|
|
67
|
+
import('./commands/doctor.ts'),
|
|
68
|
+
import('./commands/dev.ts'),
|
|
69
|
+
import('./commands/test.ts'),
|
|
70
|
+
import('./commands/system.ts'),
|
|
71
|
+
import('./commands/generate.ts'),
|
|
72
|
+
import('./commands/create-app.ts'),
|
|
73
|
+
])
|
|
57
74
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
}
|
|
75
|
+
registerAuthCommands(program)
|
|
76
|
+
registerPipelineCommands(program)
|
|
77
|
+
registerItemCommands(program)
|
|
78
|
+
registerAgentCommands(program)
|
|
79
|
+
registerMigrationCommands(program)
|
|
80
|
+
registerDoctorCommands(program)
|
|
81
|
+
registerDevCommands(program)
|
|
82
|
+
registerTestCommands(program)
|
|
83
|
+
registerSystemCommands(program)
|
|
84
|
+
registerGenerateCommands(program)
|
|
85
|
+
registerCreateAppCommands(program)
|
|
112
86
|
|
|
113
87
|
program.parseAsync(process.argv).catch((err) => {
|
|
114
88
|
console.error('Error:', err.message)
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
* @seeAlso 015_simplify_apps_table.sql (database structure)
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import { readFileSync
|
|
20
|
-
import { resolve
|
|
19
|
+
import { readFileSync } from 'fs'
|
|
20
|
+
import { resolve } from 'path'
|
|
21
21
|
|
|
22
22
|
export interface AppManifest {
|
|
23
23
|
name: string
|
|
@@ -168,17 +168,10 @@ export function mergeWithManifest(dbRecord: any): any {
|
|
|
168
168
|
* @returns Array of discovered app slugs and their paths
|
|
169
169
|
*/
|
|
170
170
|
export function discoverManifests(): Array<{slug: string, path: string}> {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (entry.name === 'lib' || entry.name.startsWith('.')) continue
|
|
178
|
-
const manifestPath = join('custom/apps', entry.name, 'manifest.json')
|
|
179
|
-
if (existsSync(resolve(process.cwd(), manifestPath))) {
|
|
180
|
-
results.push({ slug: entry.name, path: manifestPath })
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return results
|
|
171
|
+
// In production, this would scan the filesystem
|
|
172
|
+
// For now, return known manifests based on the plan
|
|
173
|
+
return [
|
|
174
|
+
{ slug: 'cortex', path: 'custom/apps/cortex/manifest.json' },
|
|
175
|
+
{ slug: 'customer-portal', path: 'custom/apps/customer-portal/manifest.json' }
|
|
176
|
+
]
|
|
184
177
|
}
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { createClient } from '@supabase/supabase-js'
|
|
18
|
-
import WebSocket from 'ws'
|
|
19
|
-
|
|
20
|
-
// WebSocket constructor for Supabase Realtime in Node.js environment
|
|
21
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
-
const RealtimeWebSocket = WebSocket as any
|
|
23
18
|
|
|
24
19
|
// ─── ENVIRONMENT RESOLUTION ──────────────────────────────────────────────────
|
|
25
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
26
|
/**
|
|
27
27
|
* Active database schema name, read from `DB_SCHEMA` env var.
|
|
28
28
|
*
|
|
@@ -35,10 +35,6 @@ const RealtimeWebSocket = WebSocket as any
|
|
|
35
35
|
* @sideEffects none
|
|
36
36
|
* @calledBy adminDb, getUserDb (applied at client construction time)
|
|
37
37
|
*/
|
|
38
|
-
const _env = (globalThis as any).process?.env || {}
|
|
39
|
-
const supabaseUrl: string = _env.SUPABASE_URL || 'https://placeholder.supabase.co'
|
|
40
|
-
const supabaseServiceKey: string = _env.SUPABASE_SERVICE_ROLE_KEY || ''
|
|
41
|
-
const supabaseAnonKey: string = _env.SUPABASE_ANON_KEY || ''
|
|
42
38
|
const dbSchema: string = _env.DB_SCHEMA || 'public'
|
|
43
39
|
|
|
44
40
|
// ─── CLIENTS ─────────────────────────────────────────────────────────────────
|
|
@@ -78,9 +74,9 @@ const dbSchema: string = _env.DB_SCHEMA || 'public'
|
|
|
78
74
|
* ```
|
|
79
75
|
*/
|
|
80
76
|
export const adminDb = createClient(supabaseUrl, supabaseServiceKey, {
|
|
81
|
-
db: {
|
|
82
|
-
|
|
83
|
-
|
|
77
|
+
db: {
|
|
78
|
+
schema: dbSchema
|
|
79
|
+
}
|
|
84
80
|
})
|
|
85
81
|
|
|
86
82
|
// ─── CHUNK_START: SHARED_DB_GET_USER_DB ──────────────────────────────────────────────
|
|
@@ -99,9 +95,9 @@ export const adminDb = createClient(supabaseUrl, supabaseServiceKey, {
|
|
|
99
95
|
*/
|
|
100
96
|
export function getUserDb(jwt: string) {
|
|
101
97
|
return createClient(supabaseUrl, supabaseAnonKey, {
|
|
102
|
-
db: {
|
|
103
|
-
|
|
104
|
-
|
|
98
|
+
db: {
|
|
99
|
+
schema: dbSchema
|
|
100
|
+
},
|
|
105
101
|
global: {
|
|
106
102
|
headers: {
|
|
107
103
|
Authorization: `Bearer ${jwt}`
|
|
@@ -380,12 +380,3 @@ export {
|
|
|
380
380
|
expectErrorResponse
|
|
381
381
|
} from './testing'
|
|
382
382
|
export type { TestContext, TestPrincipal, TestLogger } from './testing'
|
|
383
|
-
|
|
384
|
-
export {
|
|
385
|
-
resolveTypeIds,
|
|
386
|
-
resolveTypeId,
|
|
387
|
-
resolveLinkTypeIds,
|
|
388
|
-
resolveAccountId,
|
|
389
|
-
resolveAgentId,
|
|
390
|
-
resolvePromptConfigId
|
|
391
|
-
} from './resolve-ids'
|
|
@@ -32,11 +32,6 @@
|
|
|
32
32
|
|
|
33
33
|
import { getUserDb, adminDb } from './db'
|
|
34
34
|
import { createClient } from '@supabase/supabase-js'
|
|
35
|
-
import WebSocket from 'ws'
|
|
36
|
-
|
|
37
|
-
// WebSocket constructor for Supabase Realtime in Node.js environment
|
|
38
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
|
-
const RealtimeWebSocket = WebSocket as any
|
|
40
35
|
|
|
41
36
|
// ─── AUTH CLIENT ─────────────────────────────────────────────────────────────
|
|
42
37
|
|
|
@@ -51,8 +46,7 @@ const supabase = createClient(
|
|
|
51
46
|
auth: {
|
|
52
47
|
autoRefreshToken: false,
|
|
53
48
|
persistSession: false
|
|
54
|
-
}
|
|
55
|
-
realtime: { transport: RealtimeWebSocket } // WebSocket for Node.js 20+
|
|
49
|
+
}
|
|
56
50
|
}
|
|
57
51
|
)
|
|
58
52
|
|
|
@@ -501,7 +495,7 @@ async function resolveHumanPrincipal(token: string, event: any): Promise<Princip
|
|
|
501
495
|
type: 'human',
|
|
502
496
|
accountId: person.account_id || null,
|
|
503
497
|
roles: roleSlugs,
|
|
504
|
-
displayName: person.
|
|
498
|
+
displayName: person.display_name || person.email,
|
|
505
499
|
email: person.email,
|
|
506
500
|
provenance: {
|
|
507
501
|
sourceType: 'jwt',
|
|
@@ -567,60 +561,8 @@ async function resolveInternalPersonId(authUserId: string, email?: string): Prom
|
|
|
567
561
|
|
|
568
562
|
if (byAuthId) return byAuthId.id
|
|
569
563
|
|
|
570
|
-
// Not found
|
|
571
|
-
|
|
572
|
-
const { data: account } = await adminDb
|
|
573
|
-
.from('accounts')
|
|
574
|
-
.select('id')
|
|
575
|
-
.eq('slug', 'spine-system')
|
|
576
|
-
.single()
|
|
577
|
-
|
|
578
|
-
const { data: type } = await adminDb
|
|
579
|
-
.from('types')
|
|
580
|
-
.select('id')
|
|
581
|
-
.eq('kind', 'person')
|
|
582
|
-
.eq('slug', 'person')
|
|
583
|
-
.single()
|
|
584
|
-
|
|
585
|
-
if (!account || !type) {
|
|
586
|
-
throw new Error('Cannot auto-create person: spine-system account or person type not found in DB')
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
// First person ever gets system_admin role
|
|
590
|
-
const { count } = await adminDb
|
|
591
|
-
.from('people')
|
|
592
|
-
.select('id', { count: 'exact', head: true })
|
|
593
|
-
|
|
594
|
-
let roleId: string | null = null
|
|
595
|
-
if ((count ?? 0) === 0) {
|
|
596
|
-
const { data: adminRole } = await adminDb
|
|
597
|
-
.from('roles')
|
|
598
|
-
.select('id')
|
|
599
|
-
.eq('slug', 'system_admin')
|
|
600
|
-
.single()
|
|
601
|
-
roleId = adminRole?.id ?? null
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
const { data: newPerson, error: createError } = await adminDb
|
|
605
|
-
.from('people')
|
|
606
|
-
.upsert({
|
|
607
|
-
id: authUserId,
|
|
608
|
-
auth_uid: authUserId,
|
|
609
|
-
email: email ?? '',
|
|
610
|
-
full_name: email ? email.split('@')[0] : 'Unknown',
|
|
611
|
-
account_id: account.id,
|
|
612
|
-
type_id: type.id,
|
|
613
|
-
role_id: roleId,
|
|
614
|
-
is_active: true
|
|
615
|
-
}, { onConflict: 'id' })
|
|
616
|
-
.select('id')
|
|
617
|
-
.single()
|
|
618
|
-
|
|
619
|
-
if (createError || !newPerson) {
|
|
620
|
-
throw new Error('Failed to auto-create person for auth user ' + authUserId + ': ' + createError?.message)
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
return newPerson.id
|
|
564
|
+
// Not found - return the auth ID as fallback
|
|
565
|
+
return authUserId
|
|
624
566
|
}
|
|
625
567
|
|
|
626
568
|
// ─── HELPER FUNCTIONS ────────────────────────────────────────────────────────
|
|
@@ -4,12 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import { adminDb } from './db'
|
|
6
6
|
|
|
7
|
-
interface ResolvedIds {
|
|
8
|
-
types: Record<string, string>
|
|
9
|
-
linkTypes: Record<string, string>
|
|
10
|
-
accounts: Record<string, string>
|
|
11
|
-
}
|
|
12
|
-
|
|
13
7
|
// Resolve type IDs by (kind, slug) pairs
|
|
14
8
|
export async function resolveTypeIds(
|
|
15
9
|
pairs: Array<{ kind: string; slug: string }>
|
|
@@ -67,6 +61,12 @@ export async function resolveLinkTypeIds(slugs: string[]): Promise<Record<string
|
|
|
67
61
|
return result
|
|
68
62
|
}
|
|
69
63
|
|
|
64
|
+
// Resolve a single link type ID — throws if not found
|
|
65
|
+
export async function resolveLinkTypeId(slug: string): Promise<string> {
|
|
66
|
+
const ids = await resolveLinkTypeIds([slug])
|
|
67
|
+
return ids[slug]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
70
|
// Resolve account ID by slug
|
|
71
71
|
export async function resolveAccountId(slug: string): Promise<string> {
|
|
72
72
|
const { data, error } = await adminDb
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* - Multi-tenancy: different tenants can have different handlers
|
|
19
19
|
*
|
|
20
20
|
* @seeAlso integration-routes.ts (uses this registry)
|
|
21
|
-
* @seeAlso
|
|
21
|
+
* @seeAlso custom_webhook-handlers.ts (legacy static registry - being phased out)
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
24
|
import { adminDb } from './db'
|