spine-framework 0.4.4 → 0.5.0-rc.5

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.
Files changed (305) hide show
  1. package/.env.example +13 -3
  2. package/.framework/cli/commands/bootstrap.ts +392 -0
  3. package/.framework/cli/commands/dev.ts +91 -218
  4. package/.framework/cli/commands/doctor.ts +132 -26
  5. package/.framework/cli/commands/generate.ts +38 -298
  6. package/.framework/cli/commands/init.ts +20 -1
  7. package/.framework/cli/commands/install-app.ts +183 -13
  8. package/.framework/cli/commands/migrate.ts +36 -30
  9. package/.framework/cli/commands/migrations.ts +16 -56
  10. package/.framework/cli/commands/upgrade.ts +35 -0
  11. package/.framework/cli/commands/validate-app.ts +127 -1
  12. package/.framework/cli/commands/validate-schema.ts +147 -0
  13. package/.framework/cli/context.ts +223 -110
  14. package/.framework/cli/index.ts +6 -0
  15. package/.framework/cli/lib/project-files.ts +241 -1
  16. package/.framework/functions/_shared/app-manifest.ts +2 -0
  17. package/.framework/functions/_shared/hash-api-key.ts +183 -79
  18. package/.framework/functions/_shared/logging.ts +562 -224
  19. package/.framework/functions/_shared/middleware.ts +47 -44
  20. package/.framework/functions/_shared/permissions.ts +4 -0
  21. package/.framework/functions/admin-data.ts +51 -28
  22. package/.framework/functions/ai-agents.ts +10 -6
  23. package/.framework/functions/api-keys.ts +301 -122
  24. package/.framework/functions/apps.ts +63 -29
  25. package/.framework/functions/cil-ingest.ts +48 -15
  26. package/.framework/functions/debug-auth.ts +14 -8
  27. package/.framework/functions/deliveries.ts +39 -12
  28. package/.framework/functions/embeddings.ts +149 -78
  29. package/.framework/functions/integration-outbound.ts +67 -27
  30. package/.framework/functions/integrations.ts +254 -127
  31. package/.framework/functions/logs.ts +273 -133
  32. package/.framework/functions/observability.ts +278 -148
  33. package/.framework/functions/pipeline-executions.ts +1 -1
  34. package/.framework/functions/pipelines.ts +14 -9
  35. package/.framework/functions/prompt-configs.ts +7 -4
  36. package/.framework/functions/roles.ts +8 -5
  37. package/.framework/functions/security.ts +30 -17
  38. package/.framework/functions/system-cron.ts +240 -127
  39. package/.framework/functions/tests.ts +7 -6
  40. package/.framework/functions/timers.ts +310 -107
  41. package/.framework/functions/triggers.ts +28 -13
  42. package/.framework/functions/types.ts +13 -10
  43. package/.framework/migrations/069_log_stats_window.sql +54 -0
  44. package/.framework/migrations/070_app_type_schema_rpcs.sql +166 -0
  45. package/.framework/migrations/071_timer_interval_keys.sql +96 -0
  46. package/.framework/migrations/072_slug_autofill.sql +77 -0
  47. package/.framework/migrations/073_seed_member_roles.sql +26 -0
  48. package/.framework/migrations/074_app_route_prefix_domains.sql +168 -0
  49. package/.framework/migrations/075_security_definer_grants.sql +157 -0
  50. package/.framework/src/apps/admin/index.tsx +1141 -775
  51. package/.framework/src/components/ErrorBoundary.tsx +136 -0
  52. package/.framework/src/components/admin/AdminListPage.tsx +81 -73
  53. package/.framework/src/components/admin/AdminSidebar.tsx +88 -79
  54. package/.framework/src/components/admin/EntitySelect.tsx +181 -0
  55. package/.framework/src/components/admin/PageInstructions.tsx +86 -127
  56. package/.framework/src/components/app-shell/GenericDetailPage.tsx +37 -13
  57. package/.framework/src/components/app-shell/GenericListPage.tsx +28 -32
  58. package/.framework/src/components/layout/Sidebar.tsx +300 -177
  59. package/.framework/src/components/runtime/DataDetailPage.tsx +67 -35
  60. package/.framework/src/components/runtime/DataHeader.tsx +96 -48
  61. package/.framework/src/components/runtime/DataListPage.tsx +3 -26
  62. package/.framework/src/components/runtime/DataStats.tsx +10 -10
  63. package/.framework/src/components/runtime/DataTable.tsx +12 -10
  64. package/.framework/src/components/ui/sheet.tsx +24 -26
  65. package/.framework/src/components/ui/textarea.tsx +74 -48
  66. package/.framework/src/contexts/AppContext.tsx +5 -12
  67. package/.framework/src/contexts/AuthContext.tsx +17 -9
  68. package/.framework/src/hooks/useApps.ts +18 -22
  69. package/.framework/src/hooks/useEntityList.ts +12 -9
  70. package/.framework/src/hooks/useListSchema.ts +108 -58
  71. package/.framework/src/instructions/README.md +74 -0
  72. package/.framework/src/instructions/accounts.md +97 -0
  73. package/.framework/src/instructions/ai-agents.md +69 -0
  74. package/.framework/src/instructions/alerts.md +80 -0
  75. package/.framework/src/instructions/api-keys.md +87 -0
  76. package/.framework/src/instructions/apps.md +77 -0
  77. package/.framework/src/instructions/concepts/ai-and-prompts.md +150 -0
  78. package/.framework/src/instructions/concepts/apps-and-renderers.md +228 -0
  79. package/.framework/src/instructions/concepts/auth-and-api-keys.md +133 -0
  80. package/.framework/src/instructions/concepts/automation.md +186 -0
  81. package/.framework/src/instructions/concepts/concurrency-and-idempotency.md +125 -0
  82. package/.framework/src/instructions/concepts/core-vs-custom.md +124 -0
  83. package/.framework/src/instructions/concepts/design-schema.md +152 -0
  84. package/.framework/src/instructions/concepts/integrations-and-webhooks.md +127 -0
  85. package/.framework/src/instructions/concepts/observability.md +116 -0
  86. package/.framework/src/instructions/concepts/permissions.md +150 -0
  87. package/.framework/src/instructions/concepts/runtime-records.md +111 -0
  88. package/.framework/src/instructions/concepts/scope-and-accounts.md +112 -0
  89. package/.framework/src/instructions/concepts/spine-way.md +172 -0
  90. package/.framework/src/instructions/deliveries.md +59 -0
  91. package/.framework/src/instructions/guide/00-orientation.md +106 -0
  92. package/.framework/src/instructions/guide/01-install-and-first-run.md +253 -0
  93. package/.framework/src/instructions/guide/02-project-map.md +147 -0
  94. package/.framework/src/instructions/guide/03-domain-model.md +223 -0
  95. package/.framework/src/instructions/guide/04-first-app.md +227 -0
  96. package/.framework/src/instructions/guide/05-glossary.md +183 -0
  97. package/.framework/src/instructions/integrations.md +96 -0
  98. package/.framework/src/instructions/internal/cil-markers.md +83 -0
  99. package/.framework/src/instructions/internal/docs-contract.md +158 -0
  100. package/.framework/src/instructions/invites.md +60 -0
  101. package/.framework/src/instructions/kb.md +80 -0
  102. package/.framework/src/instructions/logs.md +77 -0
  103. package/.framework/src/instructions/notifications.md +77 -0
  104. package/.framework/src/instructions/observability.md +61 -0
  105. package/.framework/src/instructions/operations/deployment.md +115 -0
  106. package/.framework/src/instructions/operations/migrations.md +125 -0
  107. package/.framework/src/instructions/operations/security-checklist.md +170 -0
  108. package/.framework/src/instructions/operations/troubleshooting.md +170 -0
  109. package/.framework/src/instructions/operations/upgrade.md +116 -0
  110. package/.framework/src/instructions/people.md +91 -0
  111. package/.framework/src/instructions/pipeline-executions.md +62 -0
  112. package/.framework/src/instructions/pipelines.md +78 -0
  113. package/.framework/src/instructions/prompts.md +95 -0
  114. package/.framework/src/instructions/reference/api/admin-data.md +162 -0
  115. package/.framework/src/instructions/reference/api/auth.md +113 -0
  116. package/.framework/src/instructions/reference/api/errors-and-envelopes.md +113 -0
  117. package/.framework/src/instructions/reference/app-manifest.md +184 -0
  118. package/.framework/src/instructions/reference/cli.md +124 -0
  119. package/.framework/src/instructions/reference/database.md +132 -0
  120. package/.framework/src/instructions/reference/design-schema.md +280 -0
  121. package/.framework/src/instructions/reference/env-vars.md +133 -0
  122. package/.framework/src/instructions/reference/frontend-sdk.md +207 -0
  123. package/.framework/src/instructions/reference/functions/account-nodes.md +75 -0
  124. package/.framework/src/instructions/reference/functions/admin-data.md +197 -0
  125. package/.framework/src/instructions/reference/functions/admin-funnel.md +90 -0
  126. package/.framework/src/instructions/reference/functions/admin-install-funnel.md +107 -0
  127. package/.framework/src/instructions/reference/functions/admin-signals.md +102 -0
  128. package/.framework/src/instructions/reference/functions/ai-agents.md +148 -0
  129. package/.framework/src/instructions/reference/functions/ai-interactions.md +156 -0
  130. package/.framework/src/instructions/reference/functions/api-keys.md +130 -0
  131. package/.framework/src/instructions/reference/functions/apps.md +140 -0
  132. package/.framework/src/instructions/reference/functions/auth.md +99 -0
  133. package/.framework/src/instructions/reference/functions/debug-auth.md +91 -0
  134. package/.framework/src/instructions/reference/functions/deliveries.md +110 -0
  135. package/.framework/src/instructions/reference/functions/embeddings.md +166 -0
  136. package/.framework/src/instructions/reference/functions/eval-harness.md +149 -0
  137. package/.framework/src/instructions/reference/functions/index.md +103 -0
  138. package/.framework/src/instructions/reference/functions/integration-outbound.md +200 -0
  139. package/.framework/src/instructions/reference/functions/integration-routes.md +151 -0
  140. package/.framework/src/instructions/reference/functions/integrations.md +130 -0
  141. package/.framework/src/instructions/reference/functions/invites.md +182 -0
  142. package/.framework/src/instructions/reference/functions/item-progress.md +107 -0
  143. package/.framework/src/instructions/reference/functions/kb.md +166 -0
  144. package/.framework/src/instructions/reference/functions/logs.md +141 -0
  145. package/.framework/src/instructions/reference/functions/observability.md +105 -0
  146. package/.framework/src/instructions/reference/functions/pipeline-executions.md +132 -0
  147. package/.framework/src/instructions/reference/functions/pipeline-runner-background.md +121 -0
  148. package/.framework/src/instructions/reference/functions/pipelines.md +136 -0
  149. package/.framework/src/instructions/reference/functions/prompt-configs.md +121 -0
  150. package/.framework/src/instructions/reference/functions/roles.md +121 -0
  151. package/.framework/src/instructions/reference/functions/security.md +140 -0
  152. package/.framework/src/instructions/reference/functions/system-cron.md +136 -0
  153. package/.framework/src/instructions/reference/functions/system.md +106 -0
  154. package/.framework/src/instructions/reference/functions/tests.md +97 -0
  155. package/.framework/src/instructions/reference/functions/timers.md +117 -0
  156. package/.framework/src/instructions/reference/functions/trigger-scheduler.md +102 -0
  157. package/.framework/src/instructions/reference/functions/triggers.md +140 -0
  158. package/.framework/src/instructions/reference/functions/types.md +146 -0
  159. package/.framework/src/instructions/reference/seeds.md +126 -0
  160. package/.framework/src/instructions/reference/shared-modules.md +127 -0
  161. package/.framework/src/instructions/reference/spine-config.md +114 -0
  162. package/.framework/src/instructions/roles.md +80 -0
  163. package/.framework/src/instructions/runtime-collaboration.md +106 -0
  164. package/.framework/src/instructions/runtime-detail.md +70 -0
  165. package/.framework/src/instructions/runtime-list.md +77 -0
  166. package/.framework/src/instructions/security.md +67 -0
  167. package/.framework/src/instructions/tasks/add-a-pipeline.md +110 -0
  168. package/.framework/src/instructions/tasks/add-a-role.md +96 -0
  169. package/.framework/src/instructions/tasks/add-a-timer.md +114 -0
  170. package/.framework/src/instructions/tasks/add-a-trigger.md +106 -0
  171. package/.framework/src/instructions/tasks/add-a-type.md +151 -0
  172. package/.framework/src/instructions/tasks/add-a-webhook.md +108 -0
  173. package/.framework/src/instructions/tasks/add-an-ai-agent.md +108 -0
  174. package/.framework/src/instructions/tasks/add-an-integration.md +124 -0
  175. package/.framework/src/instructions/tasks/build-a-custom-page.md +118 -0
  176. package/.framework/src/instructions/tasks/document-your-app.md +117 -0
  177. package/.framework/src/instructions/tasks/package-and-install-an-app.md +136 -0
  178. package/.framework/src/instructions/tasks/register-an-app.md +137 -0
  179. package/.framework/src/instructions/tasks/test-your-code.md +108 -0
  180. package/.framework/src/instructions/tasks/write-a-function.md +132 -0
  181. package/.framework/src/instructions/tasks/write-a-migration.md +110 -0
  182. package/.framework/src/instructions/testing.md +59 -0
  183. package/.framework/src/instructions/timers.md +84 -0
  184. package/.framework/src/instructions/triggers.md +69 -0
  185. package/.framework/src/instructions/types.md +93 -0
  186. package/.framework/src/lib/app-mount.ts +88 -0
  187. package/.framework/src/pages/NotFoundPage.tsx +62 -31
  188. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +117 -106
  189. package/.framework/src/pages/admin/AIAgentsPage.tsx +86 -48
  190. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +153 -152
  191. package/.framework/src/pages/admin/APIKeysPage.tsx +91 -90
  192. package/.framework/src/pages/admin/AlertsConfigPage.tsx +29 -18
  193. package/.framework/src/pages/admin/AppDetailPage.tsx +6 -60
  194. package/.framework/src/pages/admin/AppsPage.tsx +104 -66
  195. package/.framework/src/pages/admin/DeliveriesPage.tsx +5 -5
  196. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +5 -23
  197. package/.framework/src/pages/admin/EmbeddingsPage.tsx +5 -26
  198. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +7 -7
  199. package/.framework/src/pages/admin/IntegrationsPage.tsx +85 -43
  200. package/.framework/src/pages/admin/LogsPage.tsx +144 -76
  201. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +223 -140
  202. package/.framework/src/pages/admin/PipelineDetailPage.tsx +134 -113
  203. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +108 -45
  204. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -115
  205. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +96 -98
  206. package/.framework/src/pages/admin/PromptConfigsPage.tsx +101 -59
  207. package/.framework/src/pages/admin/RoleDetailPage.tsx +90 -79
  208. package/.framework/src/pages/admin/RolesPage.tsx +86 -43
  209. package/.framework/src/pages/admin/SecurityPage.tsx +1 -1
  210. package/.framework/src/pages/admin/TestingDashboard.tsx +16 -28
  211. package/.framework/src/pages/admin/TimerDetailPage.tsx +117 -100
  212. package/.framework/src/pages/admin/TimersPage.tsx +90 -62
  213. package/.framework/src/pages/admin/TriggerDetailPage.tsx +90 -83
  214. package/.framework/src/pages/admin/TriggersPage.tsx +124 -99
  215. package/.framework/src/pages/admin/TypeDetailPage.tsx +152 -138
  216. package/.framework/src/pages/admin/TypesPage.tsx +90 -48
  217. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +17 -25
  218. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +17 -27
  219. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +72 -40
  220. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +321 -129
  221. package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +18 -29
  222. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +26 -38
  223. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +34 -46
  224. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +189 -103
  225. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +246 -136
  226. package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +11 -22
  227. package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +9 -20
  228. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +26 -38
  229. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +7 -26
  230. package/.framework/src/pages/auth/LoginPage.tsx +3 -2
  231. package/.framework/src/pages/auth/RegisterPage.tsx +16 -8
  232. package/.framework/templates/agent/AGENTS.md +167 -0
  233. package/.framework/templates/agent/skills/spine-add-ai-agent/SKILL.md +58 -0
  234. package/.framework/templates/agent/skills/spine-add-automation/SKILL.md +62 -0
  235. package/.framework/templates/agent/skills/spine-add-integration/SKILL.md +63 -0
  236. package/.framework/templates/agent/skills/spine-architect/SKILL.md +86 -0
  237. package/.framework/templates/agent/skills/spine-install-app/SKILL.md +79 -0
  238. package/.framework/templates/agent/skills/spine-migration/SKILL.md +75 -0
  239. package/.framework/templates/agent/skills/spine-new-app/SKILL.md +79 -0
  240. package/.framework/templates/agent/skills/spine-new-function/SKILL.md +71 -0
  241. package/.framework/templates/agent/skills/spine-new-type/SKILL.md +72 -0
  242. package/.framework/templates/agent/skills/spine-schema/SKILL.md +77 -0
  243. package/.framework/templates/agent/skills/spine-test/SKILL.md +67 -0
  244. package/.framework/templates/agent/skills/spine-troubleshoot/SKILL.md +74 -0
  245. package/.framework/templates/agent/skills/spine-upgrade/SKILL.md +69 -0
  246. package/.framework/templates/project.json +4 -1
  247. package/.framework/tests/unit/account-scoping-gates.test.ts +394 -0
  248. package/.framework/tests/unit/agent-files.test.ts +355 -0
  249. package/.framework/tests/unit/agent-runner.test.ts +479 -44
  250. package/.framework/tests/unit/api-keys-create-scope-gate.test.ts +160 -0
  251. package/.framework/tests/unit/api-keys-omit-secret-fields.test.ts +38 -0
  252. package/.framework/tests/unit/app-mount.test.ts +80 -0
  253. package/.framework/tests/unit/bootstrap.test.ts +242 -0
  254. package/.framework/tests/unit/cli-context-api-key.test.ts +114 -0
  255. package/.framework/tests/unit/debug-auth.test.ts +38 -0
  256. package/.framework/tests/unit/deliveries-account-scoping.test.ts +185 -0
  257. package/.framework/tests/unit/integration-outbound-credentials.test.ts +167 -0
  258. package/.framework/tests/unit/integrations-audit-redaction.test.ts +130 -0
  259. package/.framework/tests/unit/logging-app-id.test.ts +75 -0
  260. package/.framework/tests/unit/security-definer-grants.test.ts +154 -0
  261. package/.framework/tests/unit/system-context-denial.test.ts +145 -0
  262. package/.framework/tests/unit/system-cron.test.ts +240 -0
  263. package/.framework/tests/unit/timers.test.ts +159 -0
  264. package/README.md +125 -166
  265. package/config/tsconfig.cli.json +2 -2
  266. package/package.json +15 -4
  267. package/templates/project/package-lock.json +2 -2
  268. package/.framework/docs/admin-routes.md +0 -76
  269. package/.framework/docs/api-docs-progress.md +0 -38
  270. package/.framework/docs/api-governance.md +0 -146
  271. package/.framework/docs/api-testing-results.md +0 -212
  272. package/.framework/docs/assembly-launch-guide.md +0 -138
  273. package/.framework/docs/audit-results.md +0 -590
  274. package/.framework/docs/db-api-inventory.md +0 -95
  275. package/.framework/docs/gap-remediation-backlog.md +0 -103
  276. package/.framework/docs/ui-adoption-verification.md +0 -111
  277. package/.framework/docs/ui-api-coverage.md +0 -84
  278. package/.framework/docs/v2-compatibility-audit.md +0 -228
  279. package/.framework/mcp/index.ts +0 -133
  280. package/.framework/mcp/load-env.ts +0 -60
  281. package/.framework/mcp/shared/app-manifest.ts +0 -275
  282. package/.framework/mcp/shared/db.ts +0 -477
  283. package/.framework/mcp/shared/kb.ts +0 -118
  284. package/.framework/mcp/tools/architect.ts +0 -431
  285. package/.framework/mcp/tools/cil/context.ts +0 -345
  286. package/.framework/mcp/tools/cil/graph.ts +0 -242
  287. package/.framework/mcp/tools/cil/ingest.ts +0 -1217
  288. package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +0 -693
  289. package/.framework/mcp/tools/cil/pipeline.ts +0 -767
  290. package/.framework/mcp/tools/cil/project.ts +0 -791
  291. package/.framework/mcp/tools/cil/retrieval.ts +0 -336
  292. package/.framework/mcp/tools/cil/search-core.ts +0 -454
  293. package/.framework/mcp/tools/cil/search.ts +0 -97
  294. package/.framework/mcp/tools/cil/suggest.ts +0 -186
  295. package/.framework/mcp/tools/cil/validate.ts +0 -1369
  296. package/.framework/mcp/tools/kb/delete.ts +0 -139
  297. package/.framework/mcp/tools/kb/index.ts +0 -52
  298. package/.framework/mcp/tools/kb/ingest.ts +0 -84
  299. package/.framework/mcp/tools/kb/list-types.ts +0 -102
  300. package/.framework/mcp/tools/kb/publish.ts +0 -100
  301. package/.framework/mcp/tools/kb/reindex.ts +0 -86
  302. package/.framework/mcp/tools/kb/revoke.ts +0 -85
  303. package/.framework/mcp/tools/kb/search.ts +0 -101
  304. package/.framework/mcp/tools/kb/upsert.ts +0 -125
  305. package/.framework/mcp/tools/observability.ts +0 -510
@@ -52,15 +52,14 @@ import { adminDb } from './_shared/db'
52
52
  import { emitLog } from './_shared/audit'
53
53
  import { isSystemAdmin } from './_shared/principal'
54
54
  import { PermissionEngine, sanitizeRecordData } from './_shared/permissions'
55
+ // CIL[END stable_id="~/.framework/functions/apps.ts:module_header:module_header"]
55
56
  // CIL[DOC-VECTOR type="context" content="purpose='Application management handlers and CRUD operations for public.apps'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
56
57
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
57
58
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
58
59
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
59
60
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
60
61
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
61
- // CIL[END stable_id="~/.framework/functions/apps.ts:module_header:module_header"]
62
62
 
63
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:permissions:constant" type="constant" identity="permissions" parent="~/.framework/functions/apps.ts"]
64
63
  // CIL[DOC-MACRO purpose="Type alias shim for PermissionEngine"]
65
64
  // CIL[DOC-RESPONSIBILITY responsibility="Reference PermissionEngine with loose typing for app handlers"]
66
65
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -68,15 +67,15 @@ import { PermissionEngine, sanitizeRecordData } from './_shared/permissions'
68
67
  // CIL[DOC-MICRO logic_summary="Casts PermissionEngine to any to avoid strict type errors in this module" notable_decisions="Should be replaced by a properly typed export from the permissions engine"]
69
68
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
70
69
  // CIL[DOC-STABILITY stability="stable"]
70
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:permissions:constant" type="constant" identity="permissions" parent="~/.framework/functions/apps.ts"]
71
71
  const permissions = PermissionEngine as any
72
+ // CIL[END stable_id="~/.framework/functions/apps.ts:permissions:constant"]
72
73
  // CIL[DOC-VECTOR type="context" content="purpose='Type alias shim for PermissionEngine'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
73
74
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
74
75
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
75
76
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
76
77
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
77
78
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
78
- // CIL[END stable_id="~/.framework/functions/apps.ts:permissions:constant"]
79
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:list:constant" type="constant" identity="list" parent="~/.framework/functions/apps.ts"]
80
79
  // CIL[DOC-MACRO purpose="List apps for an account with optional filters"]
81
80
  // CIL[DOC-RESPONSIBILITY responsibility="Return a sanitized list of apps accessible to the caller's roles"]
82
81
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -84,6 +83,7 @@ const permissions = PermissionEngine as any
84
83
  // CIL[DOC-MICRO logic_summary="Resolves target account, selects adminDb for system admins, calls get_account_apps RPC, and sanitizes each record" notable_decisions="Defaults include_system to true unless explicitly false; uses sanitizeRecordData per row"]
85
84
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
86
85
  // CIL[DOC-STABILITY stability="stable"]
86
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:list:constant" type="constant" identity="list" parent="~/.framework/functions/apps.ts"]
87
87
  export const list = createHandler(async (ctx, body) => {
88
88
  const { include_system, include_inactive, account_id } = ctx.query || {}
89
89
 
@@ -93,12 +93,25 @@ export const list = createHandler(async (ctx, body) => {
93
93
  throw new Error('Account context required')
94
94
  }
95
95
 
96
- const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
97
-
98
96
  const userRoles = ctx.principal?.roles || []
99
97
  const isSysAdmin = userRoles.includes('system_admin')
98
+ const isSystem = isSysAdmin || (ctx.principal?.isInternal === true && !ctx.accountId)
99
+
100
+ // get_account_apps is service-role-only — the account boundary is enforced
101
+ // here. A scoped caller may only resolve apps inside its access set
102
+ // (own account plus descendants); the query param alone never widened that.
103
+ if (!isSystem && targetAccountId !== ctx.accountId) {
104
+ const { data: accessible, error: accessErr } = await adminDb
105
+ .rpc('get_accessible_accounts', { actor_id: ctx.principal?.id })
106
+ const ids = (accessible || []).map((r: any) => r.account_id ?? r)
107
+ if (accessErr || !ids.includes(targetAccountId)) {
108
+ const e: any = new Error('Account not accessible')
109
+ e.statusCode = 403
110
+ throw e
111
+ }
112
+ }
100
113
 
101
- const { data, error: err } = await db
114
+ const { data, error: err } = await adminDb
102
115
  .rpc('get_account_apps', {
103
116
  account_id: targetAccountId,
104
117
  include_system: include_system !== 'false',
@@ -117,14 +130,13 @@ export const list = createHandler(async (ctx, body) => {
117
130
 
118
131
  return sanitized
119
132
  })
133
+ // CIL[END stable_id="~/.framework/functions/apps.ts:list:constant"]
120
134
  // CIL[DOC-VECTOR type="context" content="purpose='List apps for an account with optional filters'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
121
135
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
122
136
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
123
137
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
124
138
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
125
139
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
126
- // CIL[END stable_id="~/.framework/functions/apps.ts:list:constant"]
127
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:get:constant" type="constant" identity="get" parent="~/.framework/functions/apps.ts"]
128
140
  // CIL[DOC-MACRO purpose="Fetch a single active app by id or slug"]
129
141
  // CIL[DOC-RESPONSIBILITY responsibility="Return a sanitized app record matching the requested id or slug"]
130
142
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -132,6 +144,7 @@ export const list = createHandler(async (ctx, body) => {
132
144
  // CIL[DOC-MICRO logic_summary="Queries the apps table by id or slug, limits to active records, and returns sanitized data" notable_decisions="Prefers id over slug; uses .single() to enforce a single result"]
133
145
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
134
146
  // CIL[DOC-STABILITY stability="stable"]
147
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:get:constant" type="constant" identity="get" parent="~/.framework/functions/apps.ts"]
135
148
  export const get = createHandler(async (ctx, body) => {
136
149
  const { id, slug } = ctx.query || {}
137
150
 
@@ -159,14 +172,13 @@ export const get = createHandler(async (ctx, body) => {
159
172
 
160
173
  return await sanitizeRecordData(ctx, data, 'app')
161
174
  })
175
+ // CIL[END stable_id="~/.framework/functions/apps.ts:get:constant"]
162
176
  // CIL[DOC-VECTOR type="context" content="purpose='Fetch a single active app by id or slug'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
163
177
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
164
178
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
165
179
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
166
180
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
167
181
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
168
- // CIL[END stable_id="~/.framework/functions/apps.ts:get:constant"]
169
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:getSchema:constant" type="constant" identity="getSchema" parent="~/.framework/functions/apps.ts"]
170
182
  // CIL[DOC-MACRO purpose="Retrieve the design schema for an app by slug"]
171
183
  // CIL[DOC-RESPONSIBILITY responsibility="Return the schema payload from the get_app_schema RPC"]
172
184
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -174,6 +186,7 @@ export const get = createHandler(async (ctx, body) => {
174
186
  // CIL[DOC-MICRO logic_summary="Validates the slug and invokes the get_app_schema RPC, returning the result" notable_decisions="Relies on a database stored procedure for schema generation"]
175
187
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
176
188
  // CIL[DOC-STABILITY stability="stable"]
189
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:getSchema:constant" type="constant" identity="getSchema" parent="~/.framework/functions/apps.ts"]
177
190
  export const getSchema = createHandler(async (ctx, body) => {
178
191
  const { slug } = ctx.query || {}
179
192
 
@@ -188,14 +201,13 @@ export const getSchema = createHandler(async (ctx, body) => {
188
201
 
189
202
  return data
190
203
  })
204
+ // CIL[END stable_id="~/.framework/functions/apps.ts:getSchema:constant"]
191
205
  // CIL[DOC-VECTOR type="context" content="purpose='Retrieve the design schema for an app by slug'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
192
206
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
193
207
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
194
208
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
195
209
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
196
210
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
197
- // CIL[END stable_id="~/.framework/functions/apps.ts:getSchema:constant"]
198
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:create:constant" type="constant" identity="create" parent="~/.framework/functions/apps.ts"]
199
211
  // CIL[DOC-MACRO purpose="Create a new app record"]
200
212
  // CIL[DOC-RESPONSIBILITY responsibility="Validate input and permissions, insert a new app row, and emit an audit log"]
201
213
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -203,8 +215,9 @@ export const getSchema = createHandler(async (ctx, body) => {
203
215
  // CIL[DOC-MICRO logic_summary="Enforces required fields and auth, checks create permission, ensures slug uniqueness, inserts with defaults, and emits an audit event" notable_decisions="Defaults version, app_type, source, route_prefix, and min_role; only system admins bypass permission checks"]
204
216
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
205
217
  // CIL[DOC-STABILITY stability="stable"]
218
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:create:constant" type="constant" identity="create" parent="~/.framework/functions/apps.ts"]
206
219
  export const create = createHandler(async (ctx, body) => {
207
- const { slug, name, description, icon, color, version, app_type, source, owner_account_id, config, nav_items, min_role, integration_deps, metadata, route_prefix, renderer } = body
220
+ const { slug, name, description, icon, color, version, app_type, source, owner_account_id, config, nav_items, min_role, required_roles, integration_deps, metadata, route_prefix, renderer, preview_domain, prod_domain, preview_route_prefix, prod_route_prefix } = body
208
221
 
209
222
  if (!slug || !name) {
210
223
  throw new Error('slug and name are required')
@@ -239,7 +252,7 @@ export const create = createHandler(async (ctx, body) => {
239
252
  throw new Error('App slug already exists')
240
253
  }
241
254
 
242
- const { data, error: err } = await ctx.db
255
+ const { data, error: err } = await adminDb
243
256
  .from('apps')
244
257
  .insert({
245
258
  slug,
@@ -254,10 +267,15 @@ export const create = createHandler(async (ctx, body) => {
254
267
  config: config || {},
255
268
  nav_items: nav_items || [],
256
269
  min_role: min_role || 'member',
270
+ required_roles: required_roles || [],
257
271
  integration_deps: integration_deps || [],
258
272
  metadata: metadata || {},
259
273
  route_prefix: route_prefix !== undefined ? route_prefix : ('/' + slug),
260
274
  renderer: renderer || 'generic',
275
+ preview_domain: preview_domain ?? null,
276
+ prod_domain: prod_domain ?? null,
277
+ preview_route_prefix: preview_route_prefix ?? null,
278
+ prod_route_prefix: prod_route_prefix ?? null,
261
279
  is_active: true,
262
280
  is_system: false
263
281
  })
@@ -270,14 +288,13 @@ export const create = createHandler(async (ctx, body) => {
270
288
 
271
289
  return data
272
290
  })
291
+ // CIL[END stable_id="~/.framework/functions/apps.ts:create:constant"]
273
292
  // CIL[DOC-VECTOR type="context" content="purpose='Create a new app record'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
274
293
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
275
294
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
276
295
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
277
296
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
278
297
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
279
- // CIL[END stable_id="~/.framework/functions/apps.ts:create:constant"]
280
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:update:constant" type="constant" identity="update" parent="~/.framework/functions/apps.ts"]
281
298
  // CIL[DOC-MACRO purpose="Update an existing app"]
282
299
  // CIL[DOC-RESPONSIBILITY responsibility="Validate the caller, load the current record, check field-level permissions, and apply updates"]
283
300
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -285,6 +302,7 @@ export const create = createHandler(async (ctx, body) => {
285
302
  // CIL[DOC-MICRO logic_summary="Finds the current record, validates update permissions, sets updated_at, persists changes, and emits an audit event" notable_decisions="Strips body id from updates; uses validateUpdatePermissions to enforce field-level access"]
286
303
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
287
304
  // CIL[DOC-STABILITY stability="stable"]
305
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:update:constant" type="constant" identity="update" parent="~/.framework/functions/apps.ts"]
288
306
  export const update = createHandler(async (ctx, body) => {
289
307
  const id = body?.id || ctx.query?.id
290
308
  const { id: _bodyId, ...updates } = body || {}
@@ -320,7 +338,7 @@ export const update = createHandler(async (ctx, body) => {
320
338
  throw new Error(fieldValidation.error)
321
339
  }
322
340
 
323
- const { data, error: err } = await ctx.db
341
+ const { data, error: err } = await adminDb
324
342
  .from('apps')
325
343
  .update({
326
344
  ...updates,
@@ -336,14 +354,13 @@ export const update = createHandler(async (ctx, body) => {
336
354
 
337
355
  return data
338
356
  })
357
+ // CIL[END stable_id="~/.framework/functions/apps.ts:update:constant"]
339
358
  // CIL[DOC-VECTOR type="context" content="purpose='Update an existing app'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
340
359
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
341
360
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
342
361
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
343
362
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
344
363
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
345
- // CIL[END stable_id="~/.framework/functions/apps.ts:update:constant"]
346
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:remove:constant" type="constant" identity="remove" parent="~/.framework/functions/apps.ts"]
347
364
  // CIL[DOC-MACRO purpose="Soft-delete an app"]
348
365
  // CIL[DOC-RESPONSIBILITY responsibility="Set is_active to false for an app after authentication and existence checks"]
349
366
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -351,6 +368,7 @@ export const update = createHandler(async (ctx, body) => {
351
368
  // CIL[DOC-MICRO logic_summary="Loads the record, flips the is_active flag and updated_at, and emits an audit event" notable_decisions="Performs a soft delete rather than a hard delete"]
352
369
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
353
370
  // CIL[DOC-STABILITY stability="stable"]
371
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:remove:constant" type="constant" identity="remove" parent="~/.framework/functions/apps.ts"]
354
372
  export const remove = createHandler(async (ctx, body) => {
355
373
  const id = body?.id || ctx.query?.id
356
374
 
@@ -373,7 +391,19 @@ export const remove = createHandler(async (ctx, body) => {
373
391
  throw new Error('App not found')
374
392
  }
375
393
 
376
- const { data, error: err } = await ctx.db
394
+ if (!permissions.isSystemAdmin(ctx)) {
395
+ const perms = await permissions.resolveFirstSurfacePermissions(
396
+ ctx.principal.id,
397
+ ctx.accountId!,
398
+ 'app',
399
+ 'delete'
400
+ )
401
+ if (!perms.canDelete) {
402
+ throw new Error('Insufficient permissions to delete apps')
403
+ }
404
+ }
405
+
406
+ const { data, error: err } = await adminDb
377
407
  .from('apps')
378
408
  .update({
379
409
  is_active: false,
@@ -389,14 +419,13 @@ export const remove = createHandler(async (ctx, body) => {
389
419
 
390
420
  return data
391
421
  })
422
+ // CIL[END stable_id="~/.framework/functions/apps.ts:remove:constant"]
392
423
  // CIL[DOC-VECTOR type="context" content="purpose='Soft-delete an app'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
393
424
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
394
425
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
395
426
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
396
427
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
397
428
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
398
- // CIL[END stable_id="~/.framework/functions/apps.ts:remove:constant"]
399
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:checkAvailability:constant" type="constant" identity="checkAvailability" parent="~/.framework/functions/apps.ts"]
400
429
  // CIL[DOC-MACRO purpose="Check whether a slug is available for an account"]
401
430
  // CIL[DOC-RESPONSIBILITY responsibility="Return an availability boolean from the is_app_available RPC"]
402
431
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -404,6 +433,7 @@ export const remove = createHandler(async (ctx, body) => {
404
433
  // CIL[DOC-MICRO logic_summary="Validates the slug and account, then calls the is_app_available RPC" notable_decisions="Uses an account-scoped stored procedure to determine availability"]
405
434
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
406
435
  // CIL[DOC-STABILITY stability="stable"]
436
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:checkAvailability:constant" type="constant" identity="checkAvailability" parent="~/.framework/functions/apps.ts"]
407
437
  export const checkAvailability = createHandler(async (ctx, body) => {
408
438
  const { slug } = ctx.query || {}
409
439
 
@@ -425,14 +455,13 @@ export const checkAvailability = createHandler(async (ctx, body) => {
425
455
 
426
456
  return { available: data }
427
457
  })
458
+ // CIL[END stable_id="~/.framework/functions/apps.ts:checkAvailability:constant"]
428
459
  // CIL[DOC-VECTOR type="context" content="purpose='Check whether a slug is available for an account'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
429
460
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
430
461
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
431
462
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
432
463
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
433
464
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
434
- // CIL[END stable_id="~/.framework/functions/apps.ts:checkAvailability:constant"]
435
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:updateVersion:constant" type="constant" identity="updateVersion" parent="~/.framework/functions/apps.ts"]
436
465
  // CIL[DOC-MACRO purpose="Update an app version via a stored procedure"]
437
466
  // CIL[DOC-RESPONSIBILITY responsibility="Bump the version of an app and emit an audit log"]
438
467
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -440,6 +469,7 @@ export const checkAvailability = createHandler(async (ctx, body) => {
440
469
  // CIL[DOC-MICRO logic_summary="Validates inputs, calls the update_app_version RPC, and emits an audit event" notable_decisions="RPC encapsulates version logic and any related triggers"]
441
470
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
442
471
  // CIL[DOC-STABILITY stability="stable"]
472
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:updateVersion:constant" type="constant" identity="updateVersion" parent="~/.framework/functions/apps.ts"]
443
473
  export const updateVersion = createHandler(async (ctx, body) => {
444
474
  const { id, version } = body
445
475
 
@@ -447,7 +477,11 @@ export const updateVersion = createHandler(async (ctx, body) => {
447
477
  throw new Error('App ID and version are required')
448
478
  }
449
479
 
450
- const { data, error: err } = await ctx.db
480
+ if (!permissions.isSystemAdmin(ctx)) {
481
+ throw new Error('Insufficient permissions to update app version')
482
+ }
483
+
484
+ const { data, error: err } = await adminDb
451
485
  .rpc('update_app_version', {
452
486
  app_id: id,
453
487
  new_version: version
@@ -459,14 +493,13 @@ export const updateVersion = createHandler(async (ctx, body) => {
459
493
 
460
494
  return { success: true }
461
495
  })
496
+ // CIL[END stable_id="~/.framework/functions/apps.ts:updateVersion:constant"]
462
497
  // CIL[DOC-VECTOR type="context" content="purpose='Update an app version via a stored procedure'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
463
498
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
464
499
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
465
500
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
466
501
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
467
502
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
468
- // CIL[END stable_id="~/.framework/functions/apps.ts:updateVersion:constant"]
469
- // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:handler:constant" type="constant" identity="handler" parent="~/.framework/functions/apps.ts"]
470
503
  // CIL[DOC-MACRO purpose="Dispatch incoming app requests to the correct handler by HTTP method and action"]
471
504
  // CIL[DOC-RESPONSIBILITY responsibility="Route GET/POST/PATCH/DELETE methods to the appropriate list, get, schema, create, update, remove, and version handlers"]
472
505
  // CIL[DOC-CONTEXT module="functions" layer="edge" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/apps.ts"]
@@ -474,6 +507,7 @@ export const updateVersion = createHandler(async (ctx, body) => {
474
507
  // CIL[DOC-MICRO logic_summary="Switches on HTTP method and query params to dispatch to the appropriate app operation" notable_decisions="GET with id or slug maps to get; action schema/available handled; POST action version or create; PATCH update; DELETE remove"]
475
508
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
476
509
  // CIL[DOC-STABILITY stability="stable"]
510
+ // CIL[BEGIN stable_id="~/.framework/functions/apps.ts:handler:constant" type="constant" identity="handler" parent="~/.framework/functions/apps.ts"]
477
511
  export const handler = createHandler(async (ctx, body) => {
478
512
  const method = ctx.query?.method || 'GET'
479
513
 
@@ -504,10 +538,10 @@ export const handler = createHandler(async (ctx, body) => {
504
538
  throw new Error(`Unsupported method: ${method}`)
505
539
  }
506
540
  })
541
+ // CIL[END stable_id="~/.framework/functions/apps.ts:handler:constant"]
507
542
  // CIL[DOC-VECTOR type="context" content="purpose='Dispatch incoming app requests to the correct handler by HTTP method and action'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
508
543
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
509
544
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
510
545
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
511
546
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
512
547
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
513
- // CIL[END stable_id="~/.framework/functions/apps.ts:handler:constant"]
@@ -168,9 +168,9 @@ interface ChunkProposal {
168
168
  // CIL[DOC-MICRO logic_summary="Holds the static LANGUAGE_MAP value" notable_decisions="Static value used across cil-ingest"]
169
169
  const LANGUAGE_MAP: Record<string, string> = {
170
170
  '.ts': 'typescript',
171
- '.tsx': 'typescript',
171
+ '.tsx': 'typescriptreact',
172
172
  '.js': 'javascript',
173
- '.jsx': 'javascript',
173
+ '.jsx': 'javascriptreact',
174
174
  '.sql': 'sql',
175
175
  '.py': 'python',
176
176
  '.go': 'go',
@@ -1606,9 +1606,9 @@ async function pass2Chunk(
1606
1606
  for (const fileItem of fileItems || []) {
1607
1607
  const relPath: string = fileItem.data?.file_path || fileItem.title
1608
1608
  const absPath = path.join(repoPath, relPath)
1609
- const language = fileItem.data?.language || 'unknown'
1609
+ const language = detectLanguage(relPath)
1610
1610
 
1611
- if (!['typescript', 'javascript'].includes(language)) continue
1611
+ if (!['typescript', 'typescriptreact', 'javascript', 'javascriptreact'].includes(language)) continue
1612
1612
 
1613
1613
  if (!forceReprocess && alreadyChunkedFileIds.has(fileItem.id)) continue
1614
1614
 
@@ -1628,13 +1628,23 @@ async function pass2Chunk(
1628
1628
 
1629
1629
  const rawContent = fs.readFileSync(absPath, 'utf-8')
1630
1630
  const rawLines = rawContent.split('\n')
1631
- // Blank (rather than remove) CIL marker/DOC lines when force-reprocessing:
1631
+ // Blank (rather than remove) CIL BEGIN/END marker lines when force-reprocessing:
1632
1632
  // filtering them out shifts every line index, so stored line_start/line_end
1633
1633
  // land in stripped-file coordinates and validate_file reports false drift.
1634
1634
  // Blank lines are invisible to the AST proposer and collapse in
1635
1635
  // computeContentHash, keeping hashes identical to store_markers output.
1636
+ // DOC tags are intentionally preserved — they are source-of-truth docs.
1637
+ // markerResidue tracks blanked marker slots so the write pass can drop
1638
+ // residue that ends up adjacent to a fresh marker (prevents +1 drift).
1639
+ const markerResidue = new Set<number>()
1636
1640
  const lines = forceReprocess
1637
- ? rawLines.map((l: string) => (/^\/\/\s*CIL\[/.test(l.trim()) || /^\s*\/\*\s*CIL\[/.test(l.trim())) ? '' : l)
1641
+ ? rawLines.map((l: string, i: number) => {
1642
+ if (/^\/\/\s*CIL\[(?:BEGIN|END)\b/.test(l.trim()) || /^\s*\/\*\s*CIL\[(?:BEGIN|END)\b/.test(l.trim())) {
1643
+ markerResidue.add(i)
1644
+ return ''
1645
+ }
1646
+ return l
1647
+ })
1638
1648
  : rawLines
1639
1649
  const content = lines.join('\n')
1640
1650
 
@@ -1832,7 +1842,7 @@ async function pass2Chunk(
1832
1842
  },
1833
1843
  })
1834
1844
 
1835
- approvedChunks.push({ name: proposal.name, stable_id: proposal.stable_id, line_start: proposal.line_start, line_end: proposal.line_end, marker_line_end: proposal.marker_line_end, chunk_type: proposal.chunk_type, is_proposal: true })
1845
+ approvedChunks.push({ name: proposal.name, stable_id: proposal.stable_id, parent_stable_id: proposal.parent_stable_id || canonicalPath, line_start: proposal.line_start, line_end: proposal.line_end, marker_line_end: proposal.marker_line_end, chunk_type: proposal.chunk_type, is_proposal: true })
1836
1846
  chunksQueued++
1837
1847
  }
1838
1848
  }
@@ -1844,25 +1854,47 @@ async function pass2Chunk(
1844
1854
  let resultLines = [...lines]
1845
1855
 
1846
1856
 
1847
- const sorted = [...approvedChunks].sort((a, b) => b.line_start - a.line_start)
1848
-
1849
- for (const chunk of sorted) {
1850
- const startLine = resultLines[chunk.line_start - 1]
1857
+ // Compute every insertion index against the pre-insertion `lines`, then
1858
+ // apply splices bottom-up. Indexing the mutating resultLines (the old
1859
+ // approach) broke on nested chunks: declarations inside a component
1860
+ // shifted its closing lines, so the parent's END marker landed mid-JSX.
1861
+ const insertions: { idx: number; begin: boolean; text: string }[] = []
1862
+ for (const chunk of approvedChunks) {
1863
+ const startLine = lines[chunk.line_start - 1]
1851
1864
 
1852
1865
  if (startLine && ANY_MARKER_RE.test(startLine.trim())) continue
1853
1866
 
1854
1867
  const startMarker = chunk.is_proposal ? proposalStartMarker(chunk.name) : chunkStartMarker(chunk.stable_id, chunk.chunk_type, chunk.name, chunk.parent_stable_id)
1855
1868
  const endMarker = chunk.is_proposal ? proposalEndMarker(chunk.name) : chunkEndMarker(chunk.stable_id)
1856
- const startIdx = markerInsertIdx(resultLines, chunk.line_start)
1869
+ const startIdx = markerInsertIdx(lines, chunk.line_start)
1857
1870
 
1858
1871
  const endIdx = chunk.chunk_type === 'module_header'
1859
1872
  ? chunk.marker_line_end
1860
- : markerEndInsertIdx(resultLines, chunk.line_start, chunk.marker_line_end)
1873
+ : markerEndInsertIdx(lines, chunk.line_start, chunk.marker_line_end)
1861
1874
 
1862
- resultLines.splice(endIdx, 0, endMarker)
1863
- resultLines.splice(startIdx, 0, startMarker)
1875
+ insertions.push({ idx: startIdx, begin: true, text: startMarker })
1876
+ insertions.push({ idx: endIdx, begin: false, text: endMarker })
1864
1877
  markersWritten++
1865
1878
  }
1879
+ insertions.sort((a, b) => b.idx - a.idx || (a.begin === b.begin ? 0 : a.begin ? -1 : 1))
1880
+ for (const ins of insertions) {
1881
+ resultLines.splice(ins.idx, 0, ins.text)
1882
+ if (markerResidue.size) {
1883
+ const shifted = new Set<number>()
1884
+ for (const r of markerResidue) shifted.add(r >= ins.idx ? r + 1 : r)
1885
+ markerResidue.clear()
1886
+ shifted.forEach(r => markerResidue.add(r))
1887
+ }
1888
+ }
1889
+ // Remove the blanked old-marker slots after fresh markers are in place.
1890
+ // Fresh markers occupy equivalent positions, so this is a swap where
1891
+ // markers did not move — and it prevents residue lines from ratcheting
1892
+ // +1 line per pass wherever old and new positions disagree.
1893
+ for (let i = resultLines.length - 1; i >= 0; i--) {
1894
+ if (markerResidue.has(i) && (resultLines[i] || '').trim() === '') {
1895
+ resultLines.splice(i, 1)
1896
+ }
1897
+ }
1866
1898
 
1867
1899
 
1868
1900
  fs.writeFileSync(absPath, resultLines.join('\n'), 'utf-8')
@@ -1873,6 +1905,7 @@ async function pass2Chunk(
1873
1905
  id: fileItem.id,
1874
1906
  data: {
1875
1907
  ...fileItem.data,
1908
+ language,
1876
1909
  stored_hash: fileHash,
1877
1910
  file_hash: fileHash,
1878
1911
  content_hash: fileHash,
@@ -24,14 +24,14 @@
24
24
 
25
25
 
26
26
  import { createHandler } from './_shared/middleware'
27
+ import { isSystemAdmin } from './_shared/principal'
28
+ // CIL[END stable_id="~/.framework/functions/debug-auth.ts:module_header:module_header"]
27
29
  // CIL[DOC-VECTOR type="context" content="purpose='Netlify function for debugging authentication state and JWT token resolution'; No verified external callers; imports: .framework/functions/_shared/middleware.ts"]
28
30
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
29
31
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
30
32
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
31
33
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
32
34
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
33
- // CIL[END stable_id="~/.framework/functions/debug-auth.ts:module_header:module_header"]
34
- // CIL[BEGIN stable_id="~/.framework/functions/debug-auth.ts:debug:constant" type="constant" identity="debug" parent="~/.framework/functions/debug-auth.ts"]
35
35
  // CIL[DOC-MACRO purpose="Return a debug payload showing whether a principal and selected environment variables are present"]
36
36
  // CIL[DOC-RESPONSIBILITY responsibility="Builds a safe, read-only debug response from request context and process.env"]
37
37
  // CIL[DOC-CONTEXT module="framework/functions" layer="functions" related_files=".framework/functions/_shared/middleware.ts,.framework/functions/debug-auth.ts"]
@@ -39,6 +39,7 @@ import { createHandler } from './_shared/middleware'
39
39
  // CIL[DOC-MICRO logic_summary="Checks the request context for a principal and masks environment variable presence" notable_decisions="Only reports SET/NOT_SET for sensitive env values"]
40
40
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
41
41
  // CIL[DOC-STABILITY stability="stable"]
42
+ // CIL[BEGIN stable_id="~/.framework/functions/debug-auth.ts:debug:constant" type="constant" identity="debug" parent="~/.framework/functions/debug-auth.ts"]
42
43
  const debug = createHandler(async (ctx, _body) => {
43
44
  const envObj = (globalThis as any).process?.env || {}
44
45
  return {
@@ -54,14 +55,13 @@ const debug = createHandler(async (ctx, _body) => {
54
55
  }
55
56
  }
56
57
  })
58
+ // CIL[END stable_id="~/.framework/functions/debug-auth.ts:debug:constant"]
57
59
  // CIL[DOC-VECTOR type="context" content="purpose='Return a debug payload showing whether a principal and selected environment variables are present'; No verified external callers; imports: .framework/functions/_shared/middleware.ts"]
58
60
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
59
61
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
60
62
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
61
63
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
62
64
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
63
- // CIL[END stable_id="~/.framework/functions/debug-auth.ts:debug:constant"]
64
- // CIL[BEGIN stable_id="~/.framework/functions/debug-auth.ts:testJwt:constant" type="constant" identity="testJwt" parent="~/.framework/functions/debug-auth.ts"]
65
65
  // CIL[DOC-MACRO purpose="Validate and return the resolved JWT principal for a request"]
66
66
  // CIL[DOC-RESPONSIBILITY responsibility="Verifies a principal exists and returns its identity and account association"]
67
67
  // CIL[DOC-CONTEXT module="framework/functions" layer="functions" related_files=".framework/functions/_shared/middleware.ts,.framework/functions/debug-auth.ts"]
@@ -69,6 +69,7 @@ const debug = createHandler(async (ctx, _body) => {
69
69
  // CIL[DOC-MICRO logic_summary="Returns principal data or an error if authentication did not resolve" notable_decisions="Includes accountId from the request context"]
70
70
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
71
71
  // CIL[DOC-STABILITY stability="stable"]
72
+ // CIL[BEGIN stable_id="~/.framework/functions/debug-auth.ts:testJwt:constant" type="constant" identity="testJwt" parent="~/.framework/functions/debug-auth.ts"]
72
73
  const testJwt = createHandler(async (ctx, _body) => {
73
74
  const envObj = (globalThis as any).process?.env || {}
74
75
  if (!ctx.principal) {
@@ -89,14 +90,13 @@ const testJwt = createHandler(async (ctx, _body) => {
89
90
  }
90
91
  }
91
92
  })
93
+ // CIL[END stable_id="~/.framework/functions/debug-auth.ts:testJwt:constant"]
92
94
  // CIL[DOC-VECTOR type="context" content="purpose='Validate and return the resolved JWT principal for a request'; No verified external callers; imports: .framework/functions/_shared/middleware.ts"]
93
95
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
94
96
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
95
97
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
96
98
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
97
99
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
98
- // CIL[END stable_id="~/.framework/functions/debug-auth.ts:testJwt:constant"]
99
- // CIL[BEGIN stable_id="~/.framework/functions/debug-auth.ts:handler:function" type="function" identity="handler" parent="~/.framework/functions/debug-auth.ts"]
100
100
  // CIL[DOC-MACRO purpose="Route incoming requests to the debug or testJwt handler"]
101
101
  // CIL[DOC-RESPONSIBILITY responsibility="Dispatches by query method to the appropriate handler and returns the result"]
102
102
  // CIL[DOC-CONTEXT module="framework/functions" layer="functions" related_files=".framework/functions/_shared/middleware.ts,.framework/functions/debug-auth.ts"]
@@ -104,10 +104,16 @@ const testJwt = createHandler(async (ctx, _body) => {
104
104
  // CIL[DOC-MICRO logic_summary="Reads the method query parameter, switches to debug or testJwt, and awaits the handler" notable_decisions="Defaults unknown methods to debug"]
105
105
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
106
106
  // CIL[DOC-STABILITY stability="stable"]
107
+ // CIL[BEGIN stable_id="~/.framework/functions/debug-auth.ts:handler:function" type="function" identity="handler" parent="~/.framework/functions/debug-auth.ts"]
107
108
  export async function handler(event: any, context: any) {
108
109
  const method = event.queryStringParameters?.method || 'debug'
109
110
 
110
111
  const ctx = await createHandler(async (ctx, _body) => {
112
+ if (!isSystemAdmin(ctx.principal)) {
113
+ const e: any = new Error('system_admin required')
114
+ e.statusCode = 403
115
+ throw e
116
+ }
111
117
  switch (method) {
112
118
  case 'debug':
113
119
  return await debug(ctx, _body)
@@ -120,10 +126,10 @@ export async function handler(event: any, context: any) {
120
126
 
121
127
  return ctx
122
128
  }
129
+ // CIL[END stable_id="~/.framework/functions/debug-auth.ts:handler:function"]
123
130
  // CIL[DOC-VECTOR type="context" content="purpose='Route incoming requests to the debug or testJwt handler'; No verified external callers; imports: .framework/functions/_shared/middleware.ts"]
124
131
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
125
132
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
126
133
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
127
134
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
128
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
129
- // CIL[END stable_id="~/.framework/functions/debug-auth.ts:handler:function"]
135
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]