spine-framework 0.3.144 → 0.4.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.
Files changed (451) hide show
  1. package/.env.example +76 -0
  2. package/.framework/.spine-manifest.json +19 -0
  3. package/.framework/cli/commands/agents.ts +61 -33
  4. package/.framework/cli/commands/auth.ts +60 -28
  5. package/.framework/cli/commands/create-app.ts +212 -80
  6. package/.framework/cli/commands/dev.ts +184 -68
  7. package/.framework/cli/commands/doctor.ts +324 -152
  8. package/.framework/cli/commands/generate.ts +119 -68
  9. package/.framework/cli/commands/init.ts +141 -242
  10. package/.framework/cli/commands/install-app.ts +1336 -314
  11. package/.framework/cli/commands/items.ts +31 -29
  12. package/.framework/cli/commands/migrate.ts +299 -156
  13. package/.framework/cli/commands/migrations.ts +62 -30
  14. package/.framework/cli/commands/pipelines.ts +31 -29
  15. package/.framework/cli/commands/status.ts +105 -45
  16. package/.framework/cli/commands/system.ts +47 -42
  17. package/.framework/cli/commands/test.ts +161 -102
  18. package/.framework/cli/commands/upgrade.ts +260 -0
  19. package/.framework/cli/commands/validate-app.ts +517 -161
  20. package/.framework/cli/context.ts +117 -85
  21. package/.framework/cli/env-loader.ts +74 -43
  22. package/.framework/cli/index.ts +70 -46
  23. package/.framework/cli/lib/project-files.ts +404 -0
  24. package/.framework/docs/guides/testing-guide.md +1 -1
  25. package/.framework/docs/runtime-types.md +72 -72
  26. package/.framework/functions/_shared/access.ts +84 -0
  27. package/.framework/functions/_shared/agent-runner.ts +5051 -1026
  28. package/.framework/functions/_shared/app-manifest.ts +214 -94
  29. package/.framework/functions/_shared/ast.ts +214 -0
  30. package/.framework/functions/_shared/audit.ts +91 -55
  31. package/.framework/functions/_shared/cil.ts +368 -127
  32. package/.framework/functions/_shared/db.ts +337 -68
  33. package/.framework/functions/_shared/funnel.ts +228 -0
  34. package/.framework/functions/_shared/geo.ts +105 -0
  35. package/.framework/functions/_shared/hash-api-key.ts +94 -17
  36. package/.framework/functions/_shared/index.ts +22 -224
  37. package/.framework/functions/_shared/kb.ts +832 -58
  38. package/.framework/functions/_shared/llm.ts +118 -18
  39. package/.framework/functions/_shared/logging.ts +317 -19
  40. package/.framework/functions/_shared/middleware.ts +701 -131
  41. package/.framework/functions/_shared/notify.ts +70 -0
  42. package/.framework/functions/_shared/outcomes.ts +34 -19
  43. package/.framework/functions/_shared/permissions.ts +501 -315
  44. package/.framework/functions/_shared/pipeline-runner.ts +704 -155
  45. package/.framework/functions/_shared/principal.ts +436 -263
  46. package/.framework/functions/_shared/rate-limit.ts +233 -0
  47. package/.framework/functions/_shared/resolve-credentials.ts +86 -19
  48. package/.framework/functions/_shared/resolve-ids.ts +203 -139
  49. package/.framework/functions/_shared/retry-deliveries.ts +51 -16
  50. package/.framework/functions/_shared/schema-utils.ts +602 -521
  51. package/.framework/functions/_shared/security.ts +345 -0
  52. package/.framework/functions/_shared/testing.ts +197 -172
  53. package/.framework/functions/_shared/tracing.ts +351 -21
  54. package/.framework/functions/_shared/trigger-engine.ts +425 -136
  55. package/.framework/functions/_shared/webhook-registration.ts +71 -70
  56. package/.framework/functions/_shared/webhook-registry.ts +126 -83
  57. package/.framework/functions/account-nodes.ts +30 -30
  58. package/.framework/functions/adapters/generic-webhook-inbound.ts +49 -16
  59. package/.framework/functions/adapters/generic-webhook-outbound.ts +17 -17
  60. package/.framework/functions/adapters/openai-outbound.ts +15 -16
  61. package/.framework/functions/admin-data.ts +596 -173
  62. package/.framework/functions/admin-funnel.ts +64 -60
  63. package/.framework/functions/admin-install-funnel.ts +84 -66
  64. package/.framework/functions/admin-signals.ts +69 -51
  65. package/.framework/functions/ai-agents.ts +431 -106
  66. package/.framework/functions/ai-interactions.ts +186 -112
  67. package/.framework/functions/api-keys.ts +107 -107
  68. package/.framework/functions/apps.ts +154 -136
  69. package/.framework/functions/auth.ts +83 -65
  70. package/.framework/functions/cil-agent-ingest.ts +189 -232
  71. package/.framework/functions/cil-agent.ts +433 -177
  72. package/.framework/functions/cil-callmap.ts +642 -430
  73. package/.framework/functions/cil-config.ts +139 -135
  74. package/.framework/functions/cil-context.ts +214 -127
  75. package/.framework/functions/cil-doc.ts +587 -458
  76. package/.framework/functions/cil-embeddings.ts +453 -364
  77. package/.framework/functions/cil-graph.ts +427 -142
  78. package/.framework/functions/cil-ingest.ts +1418 -1154
  79. package/.framework/functions/cil-pipeline.ts +276 -21
  80. package/.framework/functions/cil-project.ts +659 -132
  81. package/.framework/functions/cil-validate.ts +198 -164
  82. package/.framework/functions/debug-auth.ts +57 -55
  83. package/.framework/functions/deliveries.ts +80 -21
  84. package/.framework/functions/embeddings.ts +1023 -318
  85. package/.framework/functions/eval-harness.ts +146 -108
  86. package/.framework/functions/integration-outbound.ts +205 -75
  87. package/.framework/functions/integration-routes.ts +128 -23
  88. package/.framework/functions/integrations.ts +125 -100
  89. package/.framework/functions/invites.ts +1095 -460
  90. package/.framework/functions/item-progress.ts +158 -102
  91. package/.framework/functions/kb.ts +34 -10
  92. package/.framework/functions/logs.ts +133 -133
  93. package/.framework/functions/observability.ts +152 -122
  94. package/.framework/functions/pipeline-executions.ts +147 -132
  95. package/.framework/functions/pipelines.ts +134 -119
  96. package/.framework/functions/prompt-configs.ts +96 -80
  97. package/.framework/functions/roles.ts +112 -82
  98. package/.framework/functions/security.ts +450 -0
  99. package/.framework/functions/system-cron.ts +117 -80
  100. package/.framework/functions/system.ts +158 -98
  101. package/.framework/functions/tests.ts +29 -29
  102. package/.framework/functions/timers.ts +94 -95
  103. package/.framework/functions/trigger-scheduler.ts +10 -0
  104. package/.framework/functions/triggers.ts +179 -149
  105. package/.framework/functions/types.ts +137 -125
  106. package/.framework/mcp/index.ts +133 -0
  107. package/.framework/mcp/load-env.ts +60 -0
  108. package/.framework/mcp/shared/app-manifest.ts +275 -0
  109. package/.framework/mcp/shared/db.ts +477 -0
  110. package/.framework/mcp/shared/kb.ts +118 -0
  111. package/.framework/mcp/tools/architect.ts +431 -0
  112. package/.framework/mcp/tools/cil/context.ts +345 -0
  113. package/.framework/mcp/tools/cil/graph.ts +242 -0
  114. package/.framework/mcp/tools/cil/ingest.ts +1217 -0
  115. package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +693 -0
  116. package/.framework/mcp/tools/cil/pipeline.ts +767 -0
  117. package/.framework/mcp/tools/cil/project.ts +791 -0
  118. package/.framework/mcp/tools/cil/retrieval.ts +336 -0
  119. package/.framework/mcp/tools/cil/search-core.ts +454 -0
  120. package/.framework/mcp/tools/cil/search.ts +97 -0
  121. package/.framework/mcp/tools/cil/suggest.ts +186 -0
  122. package/.framework/mcp/tools/cil/validate.ts +1369 -0
  123. package/.framework/mcp/tools/kb/delete.ts +139 -0
  124. package/.framework/mcp/tools/kb/index.ts +52 -0
  125. package/.framework/mcp/tools/kb/ingest.ts +84 -0
  126. package/.framework/mcp/tools/kb/list-types.ts +102 -0
  127. package/.framework/mcp/tools/kb/publish.ts +100 -0
  128. package/.framework/mcp/tools/kb/reindex.ts +86 -0
  129. package/.framework/mcp/tools/kb/revoke.ts +85 -0
  130. package/.framework/mcp/tools/kb/search.ts +101 -0
  131. package/.framework/mcp/tools/kb/upsert.ts +125 -0
  132. package/.framework/mcp/tools/observability.ts +510 -0
  133. package/.framework/migrations/001_core_schema.sql +15 -0
  134. package/.framework/migrations/002_core_rls_and_functions.sql +15 -0
  135. package/.framework/migrations/003_core_system_data.sql +16 -1
  136. package/.framework/migrations/004_core_rpc_and_broker.sql +17 -1
  137. package/.framework/migrations/005_core_observability.sql +17 -1
  138. package/.framework/migrations/006_security_hardening_rls.sql +15 -0
  139. package/.framework/migrations/007_kb_article_list.sql +17 -1
  140. package/.framework/migrations/008_items_target.sql +15 -0
  141. package/.framework/migrations/009_roles_slug_unique.sql +15 -0
  142. package/.framework/migrations/010_auth_user_trigger.sql +15 -0
  143. package/.framework/migrations/011_spine_system_account.sql +16 -0
  144. package/.framework/migrations/012_service_role_grants.sql +16 -0
  145. package/.framework/migrations/013_get_account_apps_role_filter.sql +15 -0
  146. package/.framework/migrations/014_apps_required_roles.sql +16 -0
  147. package/.framework/migrations/015_types_kind_slug_unique.sql +20 -0
  148. package/.framework/migrations/016_cil_types.sql +281 -0
  149. package/.framework/migrations/017_cil_stable_ids.sql +37 -0
  150. package/.framework/migrations/018_runtime_tables.sql +129 -0
  151. package/.framework/migrations/019_agent_prompt_columns.sql +56 -0
  152. package/.framework/migrations/020_schema_reconciliation.sql +67 -0
  153. package/.framework/migrations/021_kb_embedding_lifecycle.sql +31 -0
  154. package/.framework/migrations/032_cil_status_migration.sql +73 -0
  155. package/.framework/migrations/033_cil_versioning.sql +73 -0
  156. package/.framework/migrations/034_match_embeddings_knn.sql +115 -0
  157. package/.framework/migrations/035_rate_limits.sql +55 -0
  158. package/.framework/migrations/036_demo_record_flags.sql +72 -0
  159. package/.framework/migrations/037_kb_types_canonical.sql +244 -0
  160. package/.framework/migrations/038_drop_demo_record_flags.sql +38 -0
  161. package/.framework/migrations/042_registration_hierarchy.sql +309 -0
  162. package/.framework/migrations/043_policy_actor_cleanup.sql +39 -0
  163. package/.framework/migrations/044_match_embeddings_filtered_knn.sql +151 -0
  164. package/.framework/migrations/045_security_critical_rls.sql +139 -0
  165. package/.framework/migrations/046_security_missing_rls.sql +79 -0
  166. package/.framework/migrations/047_people_updated_by.sql +27 -0
  167. package/.framework/migrations/048_watcher_last_seen_at.sql +24 -0
  168. package/.framework/migrations/049_security_blocklist.sql +148 -0
  169. package/.framework/migrations/050_notifications.sql +49 -0
  170. package/.framework/migrations/051_message_agent_fields.sql +74 -0
  171. package/.framework/migrations/052_registration_security.sql +421 -0
  172. package/.framework/migrations/053_builtin_action_seeds.sql +66 -0
  173. package/.framework/migrations/054_kb_ingest_lease.sql +157 -0
  174. package/.framework/migrations/055_type_id_drift_reconciliation.sql +33 -0
  175. package/.framework/migrations/056_slug_column_reconciliation.sql +38 -0
  176. package/.framework/migrations/057_pipelines_slug_identity.sql +14 -0
  177. package/.framework/migrations/058_account_data_field_declarations.sql +53 -0
  178. package/.framework/migrations/059_registration_placement_fixes.sql +269 -0
  179. package/.framework/migrations/060_account_person_record_permissions.sql +38 -0
  180. package/.framework/migrations/061_fk_dedup.sql +32 -0
  181. package/.framework/public/spine-logo.svg +10 -3
  182. package/.framework/scripts/app-install-cli.ts +190 -93
  183. package/.framework/scripts/assemble-frontend.sh +127 -44
  184. package/.framework/scripts/assemble-functions.sh +128 -30
  185. package/.framework/scripts/boundary-check.sh +6 -2
  186. package/.framework/scripts/build-manifest.sh +24 -68
  187. package/.framework/scripts/check-core-integrity.sh +15 -76
  188. package/.framework/scripts/checksum-manifest.mts +343 -0
  189. package/.framework/scripts/cil-migrate-markers.ts +403 -0
  190. package/.framework/scripts/fix-cil-markers.mjs +176 -0
  191. package/.framework/scripts/verify-integrity.sh +21 -57
  192. package/.framework/scripts/verify-manifest.mts +305 -0
  193. package/.framework/seeds/types/funnel_signal_use.json +74 -21
  194. package/.framework/seeds/types/spine_instance.json +73 -21
  195. package/.framework/src/App.tsx +118 -72
  196. package/.framework/src/apps/admin/index.tsx +855 -58
  197. package/.framework/src/components/AppWrapper.tsx +43 -45
  198. package/.framework/src/components/CustomAppLoader.tsx +160 -116
  199. package/.framework/src/components/admin/AdminListPage.tsx +46 -44
  200. package/.framework/src/components/admin/AdminSidebar.tsx +57 -47
  201. package/.framework/src/components/admin/AdminStatsCard.tsx +46 -44
  202. package/.framework/src/components/admin/PageInstructions.tsx +98 -2
  203. package/.framework/src/components/admin/SortableTableHeader.tsx +44 -45
  204. package/.framework/src/components/app-shell/GenericAppShell.tsx +64 -65
  205. package/.framework/src/components/app-shell/GenericDetailPage.tsx +44 -47
  206. package/.framework/src/components/app-shell/GenericListPage.tsx +45 -49
  207. package/.framework/src/components/app-sidebar.tsx +42 -45
  208. package/.framework/src/components/auth/ProtectedRoute.tsx +48 -41
  209. package/.framework/src/components/auth/TurnstileWidget.tsx +27 -0
  210. package/.framework/src/components/kb/KBArticleEditor.tsx +231 -22
  211. package/.framework/src/components/kb/KBArticleList.tsx +251 -10
  212. package/.framework/src/components/layout/AppShell.tsx +51 -45
  213. package/.framework/src/components/layout/Header.tsx +42 -43
  214. package/.framework/src/components/layout/Layout.tsx +46 -46
  215. package/.framework/src/components/layout/Sidebar.tsx +196 -96
  216. package/.framework/src/components/runtime/DataDetailHeader.tsx +55 -30
  217. package/.framework/src/components/runtime/DataDetailPage.tsx +31 -269
  218. package/.framework/src/components/runtime/DataFilters.tsx +49 -74
  219. package/.framework/src/components/runtime/DataHeader.tsx +53 -32
  220. package/.framework/src/components/runtime/DataListPage.tsx +51 -155
  221. package/.framework/src/components/runtime/DataStats.tsx +66 -44
  222. package/.framework/src/components/runtime/DataTable.tsx +49 -149
  223. package/.framework/src/components/runtime/SchemaDetailForm.tsx +45 -75
  224. package/.framework/src/components/runtime/index.ts +119 -16
  225. package/.framework/src/components/search-form.tsx +46 -29
  226. package/.framework/src/components/shared/AgentView.tsx +65 -48
  227. package/.framework/src/components/shared/FieldRenderer.tsx +144 -50
  228. package/.framework/src/components/shared/InviteManager.tsx +207 -97
  229. package/.framework/src/components/shared/MemberList.tsx +97 -0
  230. package/.framework/src/components/shared/SchemaFields.tsx +107 -86
  231. package/.framework/src/components/ui/DataTable.tsx +80 -68
  232. package/.framework/src/components/ui/Form.tsx +157 -146
  233. package/.framework/src/components/ui/ItemCard.tsx +74 -67
  234. package/.framework/src/components/ui/ItemListView.tsx +73 -68
  235. package/.framework/src/components/ui/LoadingSpinner.tsx +43 -48
  236. package/.framework/src/components/ui/Modal.tsx +78 -68
  237. package/.framework/src/components/ui/RichTextEditor.tsx +89 -69
  238. package/.framework/src/components/ui/accordion.tsx +85 -86
  239. package/.framework/src/components/ui/alert-dialog.tsx +197 -184
  240. package/.framework/src/components/ui/alert.tsx +105 -94
  241. package/.framework/src/components/ui/aspect-ratio.tsx +57 -43
  242. package/.framework/src/components/ui/avatar.tsx +122 -107
  243. package/.framework/src/components/ui/badge.tsx +60 -55
  244. package/.framework/src/components/ui/breadcrumb.tsx +127 -128
  245. package/.framework/src/components/ui/button-group.tsx +86 -72
  246. package/.framework/src/components/ui/button.tsx +71 -50
  247. package/.framework/src/components/ui/calendar.tsx +72 -57
  248. package/.framework/src/components/ui/card.tsx +136 -129
  249. package/.framework/src/components/ui/carousel.tsx +226 -107
  250. package/.framework/src/components/ui/chart.tsx +252 -147
  251. package/.framework/src/components/ui/checkbox.tsx +43 -44
  252. package/.framework/src/components/ui/collapsible.tsx +86 -71
  253. package/.framework/src/components/ui/combobox.tsx +282 -249
  254. package/.framework/src/components/ui/command.tsx +158 -146
  255. package/.framework/src/components/ui/context-menu.tsx +239 -240
  256. package/.framework/src/components/ui/dialog.tsx +174 -157
  257. package/.framework/src/components/ui/direction.tsx +72 -56
  258. package/.framework/src/components/ui/drawer.tsx +168 -169
  259. package/.framework/src/components/ui/dropdown-menu.tsx +254 -223
  260. package/.framework/src/components/ui/empty.tsx +131 -120
  261. package/.framework/src/components/ui/field.tsx +205 -173
  262. package/.framework/src/components/ui/hover-card.tsx +71 -72
  263. package/.framework/src/components/ui/input-group.tsx +148 -133
  264. package/.framework/src/components/ui/input-otp.tsx +99 -86
  265. package/.framework/src/components/ui/input.tsx +43 -41
  266. package/.framework/src/components/ui/item.tsx +207 -185
  267. package/.framework/src/components/ui/kbd.tsx +57 -56
  268. package/.framework/src/components/ui/label.tsx +45 -41
  269. package/.framework/src/components/ui/menubar.tsx +268 -236
  270. package/.framework/src/components/ui/native-select.tsx +85 -86
  271. package/.framework/src/components/ui/navigation-menu.tsx +166 -156
  272. package/.framework/src/components/ui/pagination.tsx +131 -141
  273. package/.framework/src/components/ui/popover.tsx +125 -128
  274. package/.framework/src/components/ui/progress.tsx +47 -44
  275. package/.framework/src/components/ui/radio-group.tsx +60 -55
  276. package/.framework/src/components/ui/resizable.tsx +85 -72
  277. package/.framework/src/components/ui/scroll-area.tsx +57 -58
  278. package/.framework/src/components/ui/select.tsx +182 -169
  279. package/.framework/src/components/ui/separator.tsx +42 -43
  280. package/.framework/src/components/ui/sheet.tsx +170 -159
  281. package/.framework/src/components/ui/sidebar.tsx +395 -398
  282. package/.framework/src/components/ui/skeleton.tsx +42 -43
  283. package/.framework/src/components/ui/slider.tsx +61 -44
  284. package/.framework/src/components/ui/sonner.tsx +44 -44
  285. package/.framework/src/components/ui/spinner.tsx +47 -42
  286. package/.framework/src/components/ui/switch.tsx +56 -42
  287. package/.framework/src/components/ui/table-primitives.tsx +272 -132
  288. package/.framework/src/components/ui/table.tsx +140 -142
  289. package/.framework/src/components/ui/tabs.tsx +110 -93
  290. package/.framework/src/components/ui/textarea.tsx +43 -44
  291. package/.framework/src/components/ui/toggle-group.tsx +87 -71
  292. package/.framework/src/components/ui/toggle.tsx +56 -56
  293. package/.framework/src/components/ui/tooltip.tsx +99 -85
  294. package/.framework/src/contexts/AppContext.tsx +166 -114
  295. package/.framework/src/contexts/AuthContext.tsx +232 -137
  296. package/.framework/src/hooks/use-mobile.ts +43 -44
  297. package/.framework/src/hooks/useApi.ts +185 -172
  298. package/.framework/src/hooks/useAppPath.ts +31 -29
  299. package/.framework/src/hooks/useApps.ts +77 -42
  300. package/.framework/src/hooks/useEntityList.ts +66 -29
  301. package/.framework/src/hooks/useEntityRecord.ts +76 -32
  302. package/.framework/src/hooks/useForm.ts +62 -30
  303. package/.framework/src/hooks/useListSchema.ts +60 -43
  304. package/.framework/src/hooks/useSchemaRecord.ts +115 -95
  305. package/.framework/src/lib/api.ts +258 -134
  306. package/.framework/src/lib/registration.ts +181 -0
  307. package/.framework/src/lib/supabase.ts +118 -81
  308. package/.framework/src/lib/utils.ts +266 -266
  309. package/.framework/src/main.tsx +43 -44
  310. package/.framework/src/pages/DashboardPage.tsx +44 -43
  311. package/.framework/src/pages/NoAppPage.tsx +50 -0
  312. package/.framework/src/pages/NotFoundPage.tsx +32 -29
  313. package/.framework/src/pages/SetupPage.tsx +34 -33
  314. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +69 -58
  315. package/.framework/src/pages/admin/AIAgentsPage.tsx +43 -40
  316. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +63 -55
  317. package/.framework/src/pages/admin/APIKeysPage.tsx +44 -42
  318. package/.framework/src/pages/admin/AlertsConfigPage.tsx +117 -94
  319. package/.framework/src/pages/admin/AppDetailPage.tsx +48 -42
  320. package/.framework/src/pages/admin/AppsPage.tsx +45 -42
  321. package/.framework/src/pages/admin/DeliveriesPage.tsx +49 -17
  322. package/.framework/src/pages/admin/DesignedPage.tsx +31 -30
  323. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +58 -0
  324. package/.framework/src/pages/admin/EmbeddingsPage.tsx +49 -0
  325. package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +31 -29
  326. package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +46 -29
  327. package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -29
  328. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +68 -55
  329. package/.framework/src/pages/admin/IntegrationsPage.tsx +45 -42
  330. package/.framework/src/pages/admin/InvitesPage.tsx +60 -44
  331. package/.framework/src/pages/admin/LogsPage.tsx +87 -137
  332. package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +31 -29
  333. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +150 -89
  334. package/.framework/src/pages/admin/PipelineDetailPage.tsx +77 -104
  335. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +44 -43
  336. package/.framework/src/pages/admin/PipelinesPage.tsx +59 -145
  337. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +53 -42
  338. package/.framework/src/pages/admin/PromptConfigsPage.tsx +47 -117
  339. package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +31 -44
  340. package/.framework/src/pages/admin/RoleDetailPage.tsx +49 -92
  341. package/.framework/src/pages/admin/RolesPage.tsx +47 -164
  342. package/.framework/src/pages/admin/SecurityPage.tsx +310 -0
  343. package/.framework/src/pages/admin/SelectTestPage.tsx +30 -32
  344. package/.framework/src/pages/admin/ShadcnTestPage.tsx +37 -44
  345. package/.framework/src/pages/admin/SimpleDashboard.tsx +32 -44
  346. package/.framework/src/pages/admin/TestRunDetailPage.tsx +97 -44
  347. package/.framework/src/pages/admin/TestingDashboard.tsx +126 -71
  348. package/.framework/src/pages/admin/TimerDetailPage.tsx +67 -55
  349. package/.framework/src/pages/admin/TimersPage.tsx +44 -42
  350. package/.framework/src/pages/admin/TriggerDetailPage.tsx +47 -42
  351. package/.framework/src/pages/admin/TriggersPage.tsx +58 -57
  352. package/.framework/src/pages/admin/TypeDetailPage.tsx +91 -55
  353. package/.framework/src/pages/admin/TypesPage.tsx +45 -42
  354. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +258 -128
  355. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +127 -123
  356. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +308 -235
  357. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +159 -110
  358. package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +432 -0
  359. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +200 -178
  360. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +286 -239
  361. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +211 -90
  362. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +156 -143
  363. package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +379 -0
  364. package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +337 -0
  365. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +219 -214
  366. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
  367. package/.framework/src/pages/auth/AuthConfirmPage.tsx +135 -65
  368. package/.framework/src/pages/auth/ForgotPasswordPage.tsx +39 -31
  369. package/.framework/src/pages/auth/LoginPage.tsx +38 -32
  370. package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -28
  371. package/.framework/src/pages/auth/RegisterPage.tsx +429 -155
  372. package/.framework/src/pages/spine-framework/APIPage.tsx +33 -30
  373. package/.framework/src/pages/spine-framework/CLIPage.tsx +32 -30
  374. package/.framework/src/types/auth.ts +101 -93
  375. package/.framework/src/types/types.ts +283 -262
  376. package/.framework/templates/project.json +87 -0
  377. package/.framework/templates/spine.config.neutral.json +7 -0
  378. package/.framework/tests/api/api-surface.test.ts +381 -0
  379. package/.framework/tests/fixtures/seed.ts +427 -0
  380. package/.framework/tests/fixtures/teardown.ts +228 -0
  381. package/.framework/tests/reporter.ts +351 -0
  382. package/.framework/tests/setup.ts +135 -0
  383. package/.framework/tests/ui/ui-sweep.ts +278 -0
  384. package/.framework/tests/unit/admin-data-logger.test.ts +310 -0
  385. package/.framework/tests/unit/agent-runner.test.ts +2389 -0
  386. package/.framework/tests/unit/ai-interactions.test.ts +81 -0
  387. package/.framework/tests/unit/app-manifest.test.ts +359 -0
  388. package/.framework/tests/unit/assembly-scripts.test.ts +172 -0
  389. package/.framework/tests/unit/cil-determinism.test.ts +85 -0
  390. package/.framework/tests/unit/core-isolation.test.ts +153 -0
  391. package/.framework/tests/unit/funnel-signals.test.ts +135 -0
  392. package/.framework/tests/unit/install-app.test.ts +1759 -0
  393. package/.framework/tests/unit/invites-security.test.ts +572 -0
  394. package/.framework/tests/unit/kb-ingest-lease.test.ts +287 -0
  395. package/.framework/tests/unit/kb-search.test.ts +119 -0
  396. package/.framework/tests/unit/migrate.test.ts +509 -0
  397. package/.framework/tests/unit/notify.test.ts +136 -0
  398. package/.framework/tests/unit/permissions.test.ts +269 -0
  399. package/.framework/tests/unit/pipeline-runner.test.ts +755 -0
  400. package/.framework/tests/unit/principal-cache.test.ts +138 -0
  401. package/.framework/tests/unit/retrieval-golden.test.ts +520 -0
  402. package/.framework/tests/unit/runtime-isolation.test.ts +642 -0
  403. package/.framework/tests/unit/schema-utils.test.ts +225 -0
  404. package/.framework/tests/unit/trigger-engine.test.ts +513 -0
  405. package/.framework/tests/unit/validate-app.test.ts +527 -0
  406. package/README.md +34 -3
  407. package/bin/spine-framework.cjs +1 -0
  408. package/config/tailwind.config.cjs +7 -0
  409. package/config/tsconfig.functions.json +42 -0
  410. package/config/tsconfig.json +37 -9
  411. package/config/vite.config.ts +31 -2
  412. package/netlify.toml +31 -3
  413. package/package.json +46 -29
  414. package/scripts/assemble-frontend.sh +127 -44
  415. package/scripts/assemble-functions.sh +127 -29
  416. package/scripts/boundary-check.sh +6 -2
  417. package/scripts/build-manifest.sh +24 -68
  418. package/scripts/checksum-manifest.mts +345 -0
  419. package/scripts/dev-clean.sh +86 -0
  420. package/scripts/dev-netlify.sh +49 -0
  421. package/scripts/netlify-dev-wrapper.sh +2 -0
  422. package/scripts/verify-install.ts +358 -0
  423. package/scripts/verify-integrity.sh +21 -57
  424. package/scripts/verify-manifest.mts +305 -0
  425. package/templates/project/gitignore +45 -0
  426. package/{config → templates/project}/package-lock.json +22335 -9366
  427. package/vitest.config.ts +46 -0
  428. package/.framework/public/spine.config.json +0 -91
  429. package/config/deno.lock +0 -108
  430. package/config/tsconfig.node.tsbuildinfo +0 -1
  431. package/config/tsconfig.tsbuildinfo +0 -1
  432. package/config/vite.config.d.ts +0 -2
  433. package/custom/.devin/AGENT.md +0 -357
  434. package/custom/.devin/skills/install-app/SKILL.md +0 -39
  435. package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +0 -39
  436. package/custom/.devin/skills/spine-workbench-idea/SKILL.md +0 -36
  437. package/custom/.devin/skills/spine-workbench-implement/SKILL.md +0 -46
  438. package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +0 -28
  439. package/custom/.devin/skills/spine-workbench-plan/SKILL.md +0 -38
  440. package/custom/.devin/workflows/app-install.yaml +0 -83
  441. package/custom/README.md +0 -79
  442. package/docs/README.md +0 -15
  443. package/scripts/app-install-cli.ts +0 -286
  444. package/scripts/check-core-integrity.sh +0 -82
  445. package/scripts/ingest-chunks.cjs +0 -202
  446. package/scripts/kb-chunk-parser.cjs +0 -312
  447. package/scripts/kb-chunk-parser.ts +0 -330
  448. package/scripts/kb-ingest-docs.ts +0 -203
  449. package/scripts/load-test-app-install.ts +0 -484
  450. package/scripts/test-login.js +0 -33
  451. package/spine.config.json +0 -91
@@ -0,0 +1,228 @@
1
+ /**
2
+ * @module funnel
3
+ * @audience internal
4
+ * @layer shared-core
5
+ * @stability stable
6
+ *
7
+ * Generic typed-signal emission + account data-flag reads
8
+ *
9
+ * @seeAlso db (provides database access for signal insertion).
10
+ * @seeAlso trigger-engine (handles the creation of triggers based on emitted signals).
11
+ * @seeAlso middleware (defines the core context used in signal processing).
12
+ *
13
+ * @cil-generated
14
+ */
15
+ // CIL[BEGIN stable_id="~/.framework/functions/_shared/funnel.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/functions/_shared/funnel.ts"]
16
+ // CIL[DOC-MACRO purpose="Generic typed-signal emission for app-defined journey milestones plus account data-flag reads"]
17
+ // CIL[DOC-RESPONSIBILITY responsibility="Write signal items under a caller-declared type_slug for journey events (demo_started, workflow_completed, install_attempted, install_verified, feedback_submitted, escalation/completion signals, etc.)"]
18
+ // CIL[DOC-CONTEXT module="funnel" layer="shared-core" related_files=".framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/trigger-engine.ts"]
19
+ // CIL[DOC-CONTRACT inputs="ctx, SignalInput {type_slug, action, data?, dedupe?, dedupe_scope?}" outputs="created item or null on skip" errors="never throws — failures are logged and swallowed" side_effects="items insert"]
20
+ // CIL[DOC-MICRO logic_summary="Resolve the declared item type once per call, dedupe on (account_id, action_type) or (account_id, action_type, dedupe_scope) when a scope is provided, insert the signal" notable_decisions="Milestones are once-per-account by default; dedupe_scope narrows dedupe to one-per-run; dedupe:false disables it entirely"]
21
+ // CIL[DOC-STABILITY stability="stable"]
22
+ // CIL[DOC-AUDIENCE audience="internal"]
23
+
24
+ import { adminDb } from './db'
25
+ import type { CoreContext } from './middleware'
26
+ import { fireCreateTriggers } from './trigger-engine'
27
+ // CIL[END stable_id="~/.framework/functions/_shared/funnel.ts:module_header:module_header"]
28
+
29
+ // CIL[DOC-MACRO purpose="SignalInput defines the typed request shape for emitSignal: which item type slug to write under, which action name to record, and the dedupe policy."]
30
+ // CIL[DOC-RESPONSIBILITY responsibility="SignalInput defines the typed request shape for emitSignal. It lets each caller namespace its own signal item type (e.g. funnel_signal, demo_signal) and choose per-account or run-scoped deduplication."]
31
+ // CIL[DOC-CONTEXT module="funnel" layer="app-specific" related_files=".framework/functions/_shared/db,.framework/functions/_shared/middleware,.framework/functions/_shared/trigger-engine"]
32
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
33
+ // CIL[DOC-MICRO logic_summary="SignalInput is a plain options object: type_slug selects the item type, action is stored as data.action_type, data merges into the row, dedupe toggles deduplication, dedupe_scope narrows the dedupe key to data->>dedupe_scope." notable_decisions="dedupe_scope is stamped after ...data so the stored value can never disagree with the lookup key"]
34
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
35
+ // CIL[DOC-STABILITY stability="stable"]
36
+ /**
37
+ * SignalInput describes a typed signal emission request: which item type to
38
+ * write under, which action name to record, and whether to dedupe per account.
39
+ *
40
+ * @sideEffects none
41
+ * @stability stable
42
+ * @cil-generated
43
+ */
44
+ // CIL[BEGIN stable_id="~/.framework/functions/_shared/funnel.ts:SignalInput:type" type="type" identity="SignalInput" parent="~/.framework/functions/_shared/funnel.ts"]
45
+ // CIL[DOC-MACRO purpose="SignalInput type"]
46
+ // CIL[DOC-RESPONSIBILITY responsibility="Implements the SignalInput type."]
47
+ // CIL[DOC-CONTEXT module=".framework/functions/_shared/funnel.ts" layer="app-specific" related_files=""]
48
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
49
+ // CIL[DOC-MICRO logic_summary="Implements the SignalInput type." notable_decisions="[]"]
50
+ // CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
51
+ // CIL[DOC-STABILITY stability="stable"]
52
+ export type SignalInput = {
53
+ /** Item type slug (kind='item') the signal is written under. */
54
+ type_slug: string
55
+ /** Caller-defined action name, recorded as data.action_type. */
56
+ action: string
57
+ /** Extra payload merged into the item's data. */
58
+ data?: Record<string, any>
59
+ /** When true (default), skip the write if this account already recorded the same action. */
60
+ dedupe?: boolean
61
+ /**
62
+ * Optional dedupe scope. When set, the dedupe lookup additionally matches
63
+ * data->>dedupe_scope and the inserted row carries the value — e.g. one
64
+ * milestone per demo run instead of once per account.
65
+ */
66
+ dedupe_scope?: string
67
+ }
68
+ // CIL[END stable_id="~/.framework/functions/_shared/funnel.ts:SignalInput:type"]
69
+ // CIL[DOC-VECTOR type="context" content="purpose='SignalInput defines the typed request shape for emitSignal: item type slug, action name, data, and dedupe policy.'; No verified external callers" status="ready"]
70
+ // CIL[DOC-VECTOR type="blast_radius" content="Consumed by emitSignal and every caller emitting typed signals (demo triage/case-analysis/journey, ai-interactions)" status="ready"]
71
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified" status="ready"]
72
+ // CIL[DOC-VECTOR type="constraint" content="dedupe_scope, when present, must equal data->>dedupe_scope on the inserted row so later lookups dedupe correctly" status="ready"]
73
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
74
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
75
+
76
+ // CIL[DOC-MACRO purpose="Records a caller-defined action as a signal item under the declared type, ensuring that milestones are only recorded once per account (or per dedupe_scope) to prevent inflation of verified states."]
77
+ // CIL[DOC-RESPONSIBILITY responsibility="Records a caller-defined action as a signal item under the declared type_slug, ensuring that milestones are only recorded once per account by default to prevent inflation of verified states. This function is designed to never throw, maintaining the integrity of the product path."]
78
+ // CIL[DOC-CONTEXT module="funnel" layer="app-specific" related_files=".framework/functions/_shared/db,.framework/functions/_shared/middleware,.framework/functions/_shared/trigger-engine"]
79
+ // CIL[DOC-CONTRACT inputs="- ctx: CoreContext (required) — the context containing account information.\n- opts: SignalInput (required) — type_slug, action, optional data, dedupe flag, and dedupe_scope." outputs="Promise<any | null> — resolves to the created signal item or null if no action was taken." errors="none" side_effects="Writes to the database and triggers external event dispatch." dependencies="adminDb.from('types'), adminDb.from('items'), fireCreateTriggers"]
80
+ // CIL[DOC-MICRO logic_summary="Resolve the caller-declared type_slug to an item type; if dedupe is on, look up an existing item for (type_id, account_id, action_type) — additionally matching data->>dedupe_scope when provided — and return null on a hit; otherwise insert the signal item with dedupe_scope stamped into data after ...data so the stored key always matches the lookup." notable_decisions="logs warnings on insert and trigger dispatch failures without throwing; dedupe_scope is stamped post-spread so a caller-supplied data.dedupe_scope cannot disagree with the lookup key"]
81
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
82
+ // CIL[DOC-STABILITY stability="stable"]
83
+ /**
84
+ * Records a caller-defined action as a signal item under the declared type, ensuring that milestones are only recorded once per account by default to prevent inflation of verified states. This function is designed to never throw, maintaining the integrity of the product path.
85
+ *
86
+ * @inputSpec
87
+ * - ctx: CoreContext (required) — the context containing account information.
88
+ * - opts: SignalInput (required) — type_slug, action, optional data and dedupe flag.
89
+ * @outputSpec Promise<any | null> — resolves to the created signal item or null if no action was taken.
90
+ * @sideEffects Writes to the database and triggers external event dispatch.
91
+ * @stability stable
92
+ * @calls adminDb.from('types'), adminDb.from('items'), fireCreateTriggers
93
+ * @errorHandling logs warnings on insert and trigger dispatch failures without throwing
94
+ * @cil-generated
95
+ */
96
+ /**
97
+ * Record a caller-defined action as a signal item under the declared type.
98
+ * Signals are once-per-account by default: if this account already recorded
99
+ * the same action_type the call is a no-op, so "verified" states can't be
100
+ * inflated by retries. Never throws — a signal write must never break the
101
+ * product path.
102
+ */
103
+ // CIL[BEGIN stable_id="~/.framework/functions/_shared/funnel.ts:emitSignal:function" type="function" identity="emitSignal" parent="~/.framework/functions/_shared/funnel.ts"]
104
+ // CIL[DOC-MACRO purpose="emitSignal function"]
105
+ // CIL[DOC-RESPONSIBILITY responsibility="Implements the emitSignal function."]
106
+ // CIL[DOC-CONTEXT module=".framework/functions/_shared/funnel.ts" layer="app-specific" related_files=""]
107
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
108
+ // CIL[DOC-MICRO logic_summary="Implements the emitSignal function." notable_decisions="[]"]
109
+ // CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
110
+ // CIL[DOC-STABILITY stability="stable"]
111
+ // CIL[DOC-NOTE type="invariant" content="Signal items must be stamped with the type's design_schema/validation_schema (and created_by for human principals) — records without stamped schemas fail admin-data's 'No permissions defined' gate. Found as a fresh-install defect: demo_signal items were created unstamped."]
112
+ export async function emitSignal(
113
+ ctx: CoreContext,
114
+ opts: SignalInput
115
+ ): Promise<any | null> {
116
+ const { type_slug, action, data = {}, dedupe = true, dedupe_scope } = opts
117
+ try {
118
+ const { data: typeRow } = await adminDb
119
+ .from('types').select('id, design_schema, validation_schema').eq('kind', 'item').eq('slug', type_slug).maybeSingle()
120
+ if (!typeRow?.id) return null
121
+
122
+ if (dedupe) {
123
+ let existingQ = adminDb
124
+ .from('items').select('id')
125
+ .eq('type_id', typeRow.id)
126
+ .eq('account_id', ctx.accountId)
127
+ .eq('data->>action_type', action)
128
+ if (dedupe_scope !== undefined) {
129
+ existingQ = existingQ.eq('data->>dedupe_scope', dedupe_scope)
130
+ }
131
+ const { data: existing } = await existingQ.limit(1)
132
+ if (existing?.length) return null
133
+ }
134
+
135
+ const { data: created, error } = await adminDb
136
+ .from('items')
137
+ .insert({
138
+ type_id: typeRow.id,
139
+ account_id: ctx.accountId,
140
+ title: `${action} — ${new Date().toISOString().slice(0, 10)}`,
141
+ status: 'active',
142
+ // Stamp the type's schemas like admin-data does — unstamped items hit
143
+ // the 'No permissions defined' gate when surfaced through admin-data.
144
+ design_schema: typeRow.design_schema || {},
145
+ validation_schema: typeRow.validation_schema || {},
146
+ created_by: ctx.principal?.type === 'human' ? ctx.principal.id : null,
147
+ data: {
148
+ action_type: action,
149
+ action_value: 1,
150
+ occurred_at: new Date().toISOString(),
151
+ source: data.source || 'app',
152
+ ...data,
153
+ // Stamped after ...data so the stored scope always matches the
154
+ // dedupe lookup key — a caller-supplied data.dedupe_scope can never
155
+ // disagree with it.
156
+ ...(dedupe_scope !== undefined ? { dedupe_scope } : {}),
157
+ },
158
+ })
159
+ .select('*')
160
+ .single()
161
+ if (error) {
162
+ console.warn(`emitSignal(${type_slug}/${action}) insert failed:`, error.message)
163
+ return null
164
+ }
165
+ // Signals are inserted via adminDb which bypasses admin-data's trigger
166
+ // dispatch — fire item_created explicitly so signal consumers (e.g. app
167
+ // pipelines wired to the signal type) see the event.
168
+ fireCreateTriggers('items', created.id, created, ctx).catch(err =>
169
+ console.warn(`emitSignal(${type_slug}/${action}) trigger dispatch failed:`, err?.message)
170
+ )
171
+ return created
172
+ } catch (err: any) {
173
+ console.warn(`emitSignal(${type_slug}/${action}) failed:`, err?.message)
174
+ return null
175
+ }
176
+ }
177
+ // CIL[END stable_id="~/.framework/functions/_shared/funnel.ts:emitSignal:function"]
178
+ // CIL[DOC-VECTOR type="context" content="purpose='Records a caller-defined action as a signal item under the declared type_slug, deduped once per account by default or once per dedupe_scope when provided.'; Called by demo triage/case-analysis/journey functions and ai-interactions submitFeedback" status="ready"]
179
+ // CIL[DOC-VECTOR type="blast_radius" content="Callers: custom_demo-triage (escalation signals), custom_demo-case-analysis (completion signals), custom_demo-journey (milestone signals), ai-interactions submitFeedback (funnel_signal)" status="ready"]
180
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified" status="ready"]
181
+ // CIL[DOC-VECTOR type="constraint" content="Never throws — a signal write must never break the product path; dedupe_scope must match data->>dedupe_scope on the stored row" status="ready"]
182
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
183
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
184
+
185
+ // CIL[DOC-MACRO purpose="Reads a caller-named boolean flag off the account's data bag."]
186
+ // CIL[DOC-RESPONSIBILITY responsibility="Reads accounts.data[flag] for the context account and reports whether it is strictly true. Generic replacement for single-purpose flag helpers — callers supply the data key."]
187
+ // CIL[DOC-CONTEXT module="funnel" layer="app-specific" related_files=".framework/functions/_shared/db,.framework/functions/_shared/middleware,.framework/functions/_shared/trigger-engine"]
188
+ // CIL[DOC-CONTRACT inputs="ctx: CoreContext (required) — the context containing the account ID to check; flag: string (required) — the data key to read." outputs="Promise<boolean> — resolves to true if the flag is set, otherwise false." errors="none" side_effects="Makes a call to the database to retrieve account data." dependencies="adminDb.from('accounts')"]
189
+ // CIL[DOC-MICRO logic_summary="Select accounts.data for ctx.accountId and return data[flag] === true; any read failure resolves to false." notable_decisions="strict === true check keeps truthy-but-non-boolean values from masquerading as flags"]
190
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
191
+ // CIL[DOC-STABILITY stability="stable"]
192
+ /**
193
+ * Reads a caller-named boolean flag off the account's data bag.
194
+ *
195
+ * @inputSpec
196
+ * ctx: CoreContext (required) — the context containing the account ID to check.
197
+ * flag: string (required) — the data key to read.
198
+ * @outputSpec Promise<boolean> — resolves to true if the flag is set, otherwise false.
199
+ * @sideEffects Makes a call to the database to retrieve account data.
200
+ * @stability stable
201
+ * @calls adminDb.from('accounts')
202
+ * @cil-generated
203
+ */
204
+ /** True when accounts.data[flag] === true for the context account. */
205
+ // CIL[BEGIN stable_id="~/.framework/functions/_shared/funnel.ts:accountDataFlag:function" type="function" identity="accountDataFlag" parent="~/.framework/functions/_shared/funnel.ts"]
206
+ // CIL[DOC-MACRO purpose="accountDataFlag function"]
207
+ // CIL[DOC-RESPONSIBILITY responsibility="Implements the accountDataFlag function."]
208
+ // CIL[DOC-CONTEXT module=".framework/functions/_shared/funnel.ts" layer="app-specific" related_files=""]
209
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
210
+ // CIL[DOC-MICRO logic_summary="Implements the accountDataFlag function." notable_decisions="[]"]
211
+ // CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
212
+ // CIL[DOC-STABILITY stability="stable"]
213
+ export async function accountDataFlag(ctx: CoreContext, flag: string): Promise<boolean> {
214
+ try {
215
+ const { data } = await adminDb
216
+ .from('accounts').select('data').eq('id', ctx.accountId).maybeSingle()
217
+ return data?.data?.[flag] === true
218
+ } catch {
219
+ return false
220
+ }
221
+ }
222
+ // CIL[END stable_id="~/.framework/functions/_shared/funnel.ts:accountDataFlag:function"]
223
+ // CIL[DOC-VECTOR type="context" content="purpose='Reads accounts.data[flag] for the context account and reports whether it is strictly true.'; No verified external callers" status="ready"]
224
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only" status="ready"]
225
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified" status="ready"]
226
+ // CIL[DOC-VECTOR type="constraint" content="Returns false on any read failure — never throws" status="ready"]
227
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
228
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
@@ -0,0 +1,105 @@
1
+ /**
2
+ * @module functions/_shared
3
+ * @audience internal
4
+ * @layer geo
5
+ * @stability stable
6
+ *
7
+ * Best-effort client geo/IP extraction from request headers
8
+ *
9
+ * @seeAlso .framework/functions/_shared/middleware.ts (provides RequestContext type)
10
+ * @seeAlso .framework/functions/_shared/funnel.ts (related functionality for handling requests)
11
+ *
12
+ * @cil-generated
13
+ */
14
+ // CIL[BEGIN stable_id="~/.framework/functions/_shared/geo.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/functions/_shared/geo.ts"]
15
+ // CIL[DOC-MACRO purpose="Best-effort client geo/IP extraction from request headers"]
16
+ // CIL[DOC-RESPONSIBILITY responsibility="Parse Netlify/CDN geo headers and client IP from ctx.headers for logging and policy decisions"]
17
+ // CIL[DOC-CONTEXT module="functions/_shared" layer="geo" related_files=".framework/functions/_shared/middleware.ts,.framework/functions/_shared/funnel.ts"]
18
+ // CIL[DOC-CONTRACT inputs="RequestContext with headers" outputs="{ country, ip } — both optional, 'unknown' never thrown" errors="never throws" side_effects="none"]
19
+ // CIL[DOC-MICRO logic_summary="Check x-nf-geo JSON (Netlify), then CDN fallbacks (cf-ipcountry, x-country, x-vercel-ip-country); IP from x-nf-client-connection-ip then first x-forwarded-for hop" notable_decisions="Log-and-allow: geo is a signal, never a gate — missing headers yield undefined, callers decide policy"]
20
+ // CIL[DOC-STABILITY stability="stable"]
21
+ // CIL[DOC-AUDIENCE audience="internal"]
22
+ // CIL[DOC-VECTOR type="context" content="purpose='Best-effort client geo/IP extraction from request headers'; No verified external callers; imports: .framework/functions/_shared/middleware.ts"]
23
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
24
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
25
+ // CIL[DOC-VECTOR type="constraint" content="Never blocks; headers absent in local dev yield undefined"]
26
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
27
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
28
+
29
+ import type { RequestContext } from './middleware'
30
+ // CIL[END stable_id="~/.framework/functions/_shared/geo.ts:module_header:module_header"]
31
+
32
+ // CIL[DOC-MACRO purpose="ClientGeo represents geographical information about a client, including their country code and IP address."]
33
+ // CIL[DOC-RESPONSIBILITY responsibility="ClientGeo represents geographical information about a client, including their country code and IP address. It is used to provide location-based services and analytics."]
34
+ // CIL[DOC-CONTEXT module="geo" layer="app-specific" related_files=".framework/functions/_shared/middleware"]
35
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
36
+ // CIL[DOC-MICRO logic_summary="ClientGeo represents geographical information about a client, including their country code and IP address. It is used to provide location-based services and analytics." notable_decisions="none"]
37
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
38
+ // CIL[DOC-STABILITY stability="stable"]
39
+ /**
40
+ * ClientGeo represents geographical information about a client, including their country code and IP address. It is used to provide location-based services and analytics.
41
+ *
42
+ * @sideEffects none
43
+ * @stability stable
44
+ * @cil-generated
45
+ */
46
+ // CIL[BEGIN stable_id="~/.framework/functions/_shared/geo.ts:clientgeo:type" type="type" identity="ClientGeo" parent="~/.framework/functions/_shared/geo.ts"]
47
+ // CIL[DOC-MACRO purpose="ClientGeo type"]
48
+ // CIL[DOC-RESPONSIBILITY responsibility="Implements the ClientGeo type."]
49
+ // CIL[DOC-CONTEXT module=".framework/functions/_shared/geo.ts" layer="app-specific" related_files=""]
50
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
51
+ // CIL[DOC-MICRO logic_summary="Implements the ClientGeo type." notable_decisions="[]"]
52
+ // CIL[DOC-CONFIDENCE pass="first" score="0.8" flags="none"]
53
+ // CIL[DOC-STABILITY stability="stable"]
54
+ export type ClientGeo = {
55
+ /** ISO 3166-1 alpha-2 country code, lowercase (e.g. 'us', 'ca'). Undefined when unavailable. */
56
+ country?: string
57
+ /** Client IP address. Undefined when unavailable. */
58
+ ip?: string
59
+ }
60
+ // CIL[END stable_id="~/.framework/functions/_shared/geo.ts:clientgeo:type"]
61
+ // CIL[DOC-VECTOR type="context" content="purpose='ClientGeo represents geographical information about a client, including their country code and IP address.'; No verified external callers" status="ready"]
62
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only" status="ready"]
63
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified" status="ready"]
64
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented" status="ready"]
65
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
66
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
67
+
68
+ // CIL[BEGIN stable_id="~/.framework/functions/_shared/geo.ts:getclientgeo:function" type="function" identity="getClientGeo" parent="~/.framework/functions/_shared/geo.ts"]
69
+ // CIL[DOC-MACRO purpose="Extract client country and IP from request headers"]
70
+ // CIL[DOC-RESPONSIBILITY responsibility="Implements getClientGeo"]
71
+ // CIL[DOC-CONTRACT inputs="RequestContext" outputs="ClientGeo" errors="none" side_effects="none"]
72
+ // CIL[DOC-MICRO logic_summary="Parses x-nf-geo JSON for country.code, falls back to flat country headers, then resolves IP from Netlify or forwarded-for headers" notable_decisions="[]"]
73
+ // CIL[DOC-STABILITY stability="stable"]
74
+ export function getClientGeo(ctx: RequestContext): ClientGeo {
75
+ const headers = ctx.headers || {}
76
+ let country: string | undefined
77
+
78
+ const nfGeo = headers['x-nf-geo']
79
+ if (nfGeo) {
80
+ try {
81
+ const parsed = JSON.parse(nfGeo)
82
+ const code = parsed?.country?.code
83
+ if (typeof code === 'string' && code) country = code.toLowerCase()
84
+ } catch { /* non-JSON header, ignore */ }
85
+ }
86
+
87
+ if (!country) {
88
+ const flat =
89
+ headers['cf-ipcountry'] ||
90
+ headers['x-country'] ||
91
+ headers['x-country-code'] ||
92
+ headers['x-vercel-ip-country']
93
+ if (typeof flat === 'string' && /^[a-zA-Z]{2}$/.test(flat)) {
94
+ country = flat.toLowerCase()
95
+ }
96
+ }
97
+
98
+ const ip =
99
+ headers['x-nf-client-connection-ip'] ||
100
+ (headers['x-forwarded-for'] || '').split(',')[0].trim() ||
101
+ undefined
102
+
103
+ return { country, ip }
104
+ }
105
+ // CIL[END stable_id="~/.framework/functions/_shared/geo.ts:getclientgeo:function"]
@@ -1,25 +1,81 @@
1
- // CIL[BEGIN chunk_id="hash_api_key_module_header_1784200005" type="module_header" identity="imports" parent="none"]
2
- // CIL[DOC-MACRO purpose="Hash and verify API keys using PBKDF2"]
3
- // CIL[DOC-RESPONSIBILITY responsibility="Generate secure, salted key hashes and verify raw keys"]
4
- // CIL[DOC-CONTEXT module="hash_api_key" layer="infrastructure" related_files="[".framework/functions/api-keys.ts",".framework/functions/integration-routes.ts"]"]
5
- // CIL[DOC-CONTRACT inputs="raw key" outputs="{ key_prefix, key_hash }" errors="hashing error" side_effects="none"]
6
- // CIL[DOC-MICRO logic_summary="Uses crypto.pbkdf2Sync to derive a 32-byte key from a random salt and the raw key. Stored format is pbkdf2$<iterations>$<salt base64>$<hash base64>." notable_decisions="["PBKDF2 is built into Node; no extra dependency.","Format is self-describing so iterations can be upgraded later.","key_prefix is the first 8 characters of the raw key for lookup."]"]
7
- // CIL[DOC-CONFIDENCE pass="first" score="0.95" flags="none"]
8
- // CIL[DOC-STABILITY stability="experimental"]
9
- // CIL[DOC-AUDIENCE audience="developer"]
10
- // CIL[DOC-VECTOR type="context" content="Layer: infrastructure. Direct callers: 0. Direct calls: 0. Related files: .framework/functions/api-keys.ts, .framework/functions/integration-routes.ts."]
11
- // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
12
- // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
13
- // CIL[DOC-VECTOR type="constraint" content="Uses Node crypto only."]
14
- // CIL[DOC-VECTOR type="implementation_pattern" content="Hash on key creation; verify on inbound webhook."]
15
- // CIL[DOC-VECTOR type="user_journey" content="Machine-principal credential lifecycle."]
1
+ // CIL[BEGIN stable_id="~/.framework/functions/_shared/hash-api-key.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/functions/_shared/hash-api-key.ts"]
2
+ // CIL[DOC-MACRO purpose="Provides PBKDF2-based API key hashing and verification utilities"]
3
+ // CIL[DOC-RESPONSIBILITY responsibility="Imports crypto primitives and exports hashApiKey and verifyApiKey"]
4
+ // CIL[DOC-CONTEXT module="functions/_shared" layer="shared" related_files=".framework/functions/_shared/hash-api-key.ts"]
5
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
6
+ // CIL[DOC-MICRO logic_summary="Imports crypto functions used by hashing and verification" notable_decisions="[]"]
7
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
8
+ // CIL[DOC-STABILITY stability="stable"]
9
+ // CIL[DOC-AUDIENCE audience="developers"]
10
+
16
11
 
17
12
  import { randomBytes, pbkdf2Sync, timingSafeEqual } from 'crypto'
13
+ // CIL[DOC-VECTOR type="context" content="purpose='Provides PBKDF2-based API key hashing and verification utilities'; No verified external callers; imports: none"]
14
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
15
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
16
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
17
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
18
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
19
+ // CIL[END stable_id="~/.framework/functions/_shared/hash-api-key.ts:module_header:module_header"]
18
20
 
21
+ // CIL[BEGIN stable_id="~/.framework/functions/_shared/hash-api-key.ts:ITERATIONS:constant" type="constant" identity="ITERATIONS" parent="~/.framework/functions/_shared/hash-api-key.ts"]
22
+ // CIL[DOC-MACRO purpose="Defines the default PBKDF2 iteration count"]
23
+ // CIL[DOC-RESPONSIBILITY responsibility="Stores the default number of PBKDF2 iterations for hashing"]
24
+ // CIL[DOC-CONTEXT module="functions/_shared" layer="shared" related_files=".framework/functions/_shared/hash-api-key.ts"]
25
+ // CIL[DOC-CONTRACT inputs="none" outputs="number" errors="none" side_effects="none"]
26
+ // CIL[DOC-MICRO logic_summary="Constant default iteration count used by hashApiKey" notable_decisions="[]"]
27
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
28
+ // CIL[DOC-STABILITY stability="stable"]
19
29
  const ITERATIONS = 100000
30
+ // CIL[DOC-VECTOR type="context" content="purpose='Defines the default PBKDF2 iteration count'; No verified external callers; imports: none"]
31
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
32
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
33
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
34
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
35
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
36
+ // CIL[END stable_id="~/.framework/functions/_shared/hash-api-key.ts:ITERATIONS:constant"]
37
+ // CIL[BEGIN stable_id="~/.framework/functions/_shared/hash-api-key.ts:KEY_LENGTH:constant" type="constant" identity="KEY_LENGTH" parent="~/.framework/functions/_shared/hash-api-key.ts"]
38
+ // CIL[DOC-MACRO purpose="Defines the derived key length in bytes for PBKDF2"]
39
+ // CIL[DOC-RESPONSIBILITY responsibility="Stores the PBKDF2 derived key length"]
40
+ // CIL[DOC-CONTEXT module="functions/_shared" layer="shared" related_files=".framework/functions/_shared/hash-api-key.ts"]
41
+ // CIL[DOC-CONTRACT inputs="none" outputs="number" errors="none" side_effects="none"]
42
+ // CIL[DOC-MICRO logic_summary="Constant derived key length used by hashApiKey" notable_decisions="[]"]
43
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
44
+ // CIL[DOC-STABILITY stability="stable"]
20
45
  const KEY_LENGTH = 32
46
+ // CIL[DOC-VECTOR type="context" content="purpose='Defines the derived key length in bytes for PBKDF2'; No verified external callers; imports: none"]
47
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
48
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
49
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
50
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
51
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
52
+ // CIL[END stable_id="~/.framework/functions/_shared/hash-api-key.ts:KEY_LENGTH:constant"]
53
+ // CIL[BEGIN stable_id="~/.framework/functions/_shared/hash-api-key.ts:DIGEST:constant" type="constant" identity="DIGEST" parent="~/.framework/functions/_shared/hash-api-key.ts"]
54
+ // CIL[DOC-MACRO purpose="Defines the digest algorithm for PBKDF2"]
55
+ // CIL[DOC-RESPONSIBILITY responsibility="Stores the PBKDF2 digest algorithm"]
56
+ // CIL[DOC-CONTEXT module="functions/_shared" layer="shared" related_files=".framework/functions/_shared/hash-api-key.ts"]
57
+ // CIL[DOC-CONTRACT inputs="none" outputs="string" errors="none" side_effects="none"]
58
+ // CIL[DOC-MICRO logic_summary="Constant digest algorithm used by hashApiKey and verifyApiKey" notable_decisions="[]"]
59
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
60
+ // CIL[DOC-STABILITY stability="stable"]
21
61
  const DIGEST = 'sha256'
62
+ // CIL[DOC-VECTOR type="context" content="purpose='Defines the digest algorithm for PBKDF2'; No verified external callers; imports: none"]
63
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
64
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
65
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
66
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
67
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
68
+ // CIL[END stable_id="~/.framework/functions/_shared/hash-api-key.ts:DIGEST:constant"]
69
+
22
70
 
71
+ // CIL[BEGIN stable_id="~/.framework/functions/_shared/hash-api-key.ts:hashApiKey:function" type="function" identity="hashApiKey" parent="~/.framework/functions/_shared/hash-api-key.ts"]
72
+ // CIL[DOC-MACRO purpose="Hash a raw API key using PBKDF2 and return a storable key record"]
73
+ // CIL[DOC-RESPONSIBILITY responsibility="Derive a salted PBKDF2 hash, prefix the raw key, and return a hash string"]
74
+ // CIL[DOC-CONTEXT module="functions/_shared" layer="shared" related_files=".framework/functions/_shared/hash-api-key.ts"]
75
+ // CIL[DOC-CONTRACT inputs="rawKey: string, iterations = ITERATIONS" outputs="{ key_prefix: string, key_hash: string, rawKey: string }" errors="none" side_effects="Uses crypto.randomBytes and pbkdf2Sync to generate salt and hash"]
76
+ // CIL[DOC-MICRO logic_summary="Extracts an 8-character prefix, generates a random salt, derives a 32-byte PBKDF2 hash, and encodes the result as pbkdf2$iterations$salt$hash" notable_decisions="[]"]
77
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
78
+ // CIL[DOC-STABILITY stability="stable"]
23
79
  export function hashApiKey(rawKey: string, iterations = ITERATIONS): { key_prefix: string; key_hash: string; rawKey: string } {
24
80
  const key_prefix = rawKey.slice(0, 8)
25
81
  const salt = randomBytes(16)
@@ -28,7 +84,23 @@ export function hashApiKey(rawKey: string, iterations = ITERATIONS): { key_prefi
28
84
 
29
85
  return { key_prefix, key_hash, rawKey }
30
86
  }
87
+ // CIL[DOC-VECTOR type="context" content="purpose='Hash a raw API key using PBKDF2 and return a storable key record'; No verified external callers; imports: none"]
88
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
89
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
90
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
91
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
92
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
93
+ // CIL[END stable_id="~/.framework/functions/_shared/hash-api-key.ts:hashApiKey:function"]
31
94
 
95
+
96
+ // CIL[BEGIN stable_id="~/.framework/functions/_shared/hash-api-key.ts:verifyApiKey:function" type="function" identity="verifyApiKey" parent="~/.framework/functions/_shared/hash-api-key.ts"]
97
+ // CIL[DOC-MACRO purpose="Verify a raw API key against a stored PBKDF2 hash"]
98
+ // CIL[DOC-RESPONSIBILITY responsibility="Parse the stored hash, re-derive the key, and compare hashes timing-safely"]
99
+ // CIL[DOC-CONTEXT module="functions/_shared" layer="shared" related_files=".framework/functions/_shared/hash-api-key.ts"]
100
+ // CIL[DOC-CONTRACT inputs="rawKey: string, keyHash: string" outputs="boolean" errors="Returns false for invalid format, missing parts, non-positive iterations, base64 decode errors, or mismatched lengths" side_effects="Uses crypto.pbkdf2Sync and timingSafeEqual"]
101
+ // CIL[DOC-MICRO logic_summary="Validates the keyHash format, extracts iterations and salt, derives the hash with the stored length, and compares with timingSafeEqual" notable_decisions="[]"]
102
+ // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
103
+ // CIL[DOC-STABILITY stability="stable"]
32
104
  export function verifyApiKey(rawKey: string, keyHash: string): boolean {
33
105
  if (!keyHash || !keyHash.startsWith('pbkdf2$')) {
34
106
  return false
@@ -59,5 +131,10 @@ export function verifyApiKey(rawKey: string, keyHash: string): boolean {
59
131
  return false
60
132
  }
61
133
  }
62
-
63
- // CIL[END chunk_id="hash_api_key_module_header_1784200005"]
134
+ // CIL[DOC-VECTOR type="context" content="purpose='Verify a raw API key against a stored PBKDF2 hash'; No verified external callers; imports: none"]
135
+ // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
136
+ // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
137
+ // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
138
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
139
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
140
+ // CIL[END stable_id="~/.framework/functions/_shared/hash-api-key.ts:verifyApiKey:function"]