spine-framework 0.3.124 → 0.3.126

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 (319) hide show
  1. package/.framework/cli/commands/agents.ts +35 -37
  2. package/.framework/cli/commands/auth.ts +35 -34
  3. package/.framework/cli/commands/create-app.ts +104 -40
  4. package/.framework/cli/commands/dev.ts +104 -69
  5. package/.framework/cli/commands/doctor.ts +179 -69
  6. package/.framework/cli/commands/generate.ts +83 -143
  7. package/.framework/cli/commands/init.ts +72 -34
  8. package/.framework/cli/commands/install-app.ts +260 -125
  9. package/.framework/cli/commands/items.ts +33 -44
  10. package/.framework/cli/commands/migrate.ts +122 -40
  11. package/.framework/cli/commands/migrations.ts +33 -40
  12. package/.framework/cli/commands/pipelines.ts +31 -39
  13. package/.framework/cli/commands/status.ts +47 -23
  14. package/.framework/cli/commands/system.ts +47 -37
  15. package/.framework/cli/commands/test.ts +112 -68
  16. package/.framework/cli/commands/validate-app.ts +215 -121
  17. package/.framework/cli/context.ts +112 -130
  18. package/.framework/cli/env-loader.ts +47 -18
  19. package/.framework/cli/index.ts +81 -42
  20. package/.framework/docs/runtime-types.md +1024 -0
  21. package/.framework/functions/_shared/agent-runner.ts +1296 -961
  22. package/.framework/functions/_shared/app-manifest.ts +82 -68
  23. package/.framework/functions/_shared/audit.ts +135 -83
  24. package/.framework/functions/_shared/{cil-state.ts → cil.ts} +158 -56
  25. package/.framework/functions/_shared/db.ts +80 -126
  26. package/.framework/functions/_shared/hash-api-key.ts +63 -0
  27. package/.framework/functions/_shared/index.ts +224 -335
  28. package/.framework/functions/_shared/kb.ts +319 -0
  29. package/.framework/functions/_shared/llm.ts +92 -0
  30. package/.framework/functions/_shared/logging.ts +288 -0
  31. package/.framework/functions/_shared/middleware.ts +329 -365
  32. package/.framework/functions/_shared/outcomes.ts +36 -0
  33. package/.framework/functions/_shared/permissions.ts +359 -643
  34. package/.framework/functions/_shared/pipeline-runner.ts +243 -316
  35. package/.framework/functions/_shared/principal.ts +376 -468
  36. package/.framework/functions/_shared/resolve-credentials.ts +102 -0
  37. package/.framework/functions/_shared/resolve-ids.ts +188 -16
  38. package/.framework/functions/_shared/retry-deliveries.ts +104 -0
  39. package/.framework/functions/_shared/schema-utils.ts +611 -373
  40. package/.framework/functions/_shared/testing.ts +207 -137
  41. package/.framework/functions/_shared/tracing.ts +276 -0
  42. package/.framework/functions/_shared/trigger-engine.ts +159 -211
  43. package/.framework/functions/_shared/webhook-registration.ts +95 -81
  44. package/.framework/functions/_shared/webhook-registry.ts +153 -75
  45. package/.framework/functions/account-nodes.ts +31 -53
  46. package/.framework/functions/adapters/generic-webhook-inbound.ts +56 -0
  47. package/.framework/functions/adapters/generic-webhook-outbound.ts +43 -0
  48. package/.framework/functions/adapters/openai-outbound.ts +40 -0
  49. package/.framework/functions/admin-data.ts +685 -537
  50. package/.framework/functions/admin-funnel.ts +31 -20
  51. package/.framework/functions/admin-install-funnel.ts +47 -28
  52. package/.framework/functions/admin-signals.ts +47 -29
  53. package/.framework/functions/ai-agents.ts +122 -147
  54. package/.framework/functions/ai-interactions.ts +180 -90
  55. package/.framework/functions/api-keys.ts +250 -192
  56. package/.framework/functions/apps.ts +203 -197
  57. package/.framework/functions/auth.ts +98 -91
  58. package/.framework/functions/cil-agent-ingest.ts +773 -0
  59. package/.framework/functions/cil-agent.ts +592 -0
  60. package/.framework/functions/cil-callmap.ts +1227 -0
  61. package/.framework/functions/cil-config.ts +583 -0
  62. package/.framework/functions/cil-context.ts +445 -0
  63. package/.framework/functions/cil-doc.ts +1752 -0
  64. package/.framework/functions/cil-embeddings.ts +1202 -0
  65. package/.framework/functions/cil-graph.ts +585 -0
  66. package/.framework/functions/cil-ingest.ts +2416 -0
  67. package/.framework/functions/cil-pipeline.ts +318 -0
  68. package/.framework/functions/cil-project.ts +499 -0
  69. package/.framework/functions/cil-validate.ts +469 -0
  70. package/.framework/functions/debug-auth.ts +73 -53
  71. package/.framework/functions/deliveries.ts +117 -0
  72. package/.framework/functions/embeddings.ts +528 -516
  73. package/.framework/functions/eval-harness.ts +158 -106
  74. package/.framework/functions/integration-outbound.ts +311 -0
  75. package/.framework/functions/integration-routes.ts +240 -466
  76. package/.framework/functions/integrations.ts +132 -140
  77. package/.framework/functions/invites.ts +401 -201
  78. package/.framework/functions/item-progress.ts +113 -53
  79. package/.framework/functions/kb.ts +28 -0
  80. package/.framework/functions/logs.ts +239 -222
  81. package/.framework/functions/observability.ts +308 -259
  82. package/.framework/functions/pipeline-executions.ts +179 -235
  83. package/.framework/functions/pipelines.ts +163 -205
  84. package/.framework/functions/prompt-configs.ts +109 -156
  85. package/.framework/functions/roles.ts +97 -147
  86. package/.framework/functions/system-cron.ts +132 -218
  87. package/.framework/functions/system.ts +112 -52
  88. package/.framework/functions/tests.ts +32 -28
  89. package/.framework/functions/timers.ts +162 -210
  90. package/.framework/functions/triggers.ts +282 -346
  91. package/.framework/functions/types.ts +283 -400
  92. package/.framework/migrations/001_core_schema.sql +630 -0
  93. package/.framework/migrations/002_core_rls_and_functions.sql +532 -0
  94. package/.framework/migrations/{003_system_data.sql → 003_core_system_data.sql} +26 -153
  95. package/.framework/migrations/004_core_rpc_and_broker.sql +421 -0
  96. package/.framework/migrations/005_core_observability.sql +598 -0
  97. package/.framework/migrations/006_security_hardening_rls.sql +97 -0
  98. package/.framework/migrations/007_kb_article_list.sql +237 -0
  99. package/.framework/migrations/008_items_target.sql +8 -0
  100. package/.framework/migrations/009_roles_slug_unique.sql +11 -0
  101. package/.framework/public/spine.config.json +91 -0
  102. package/.framework/scripts/app-install-cli.ts +112 -98
  103. package/.framework/src/App.tsx +67 -20
  104. package/.framework/src/apps/admin/index.tsx +97 -27
  105. package/.framework/src/components/AppWrapper.tsx +50 -11
  106. package/.framework/src/components/CustomAppLoader.tsx +131 -22
  107. package/.framework/src/components/admin/AdminListPage.tsx +75 -8
  108. package/.framework/src/components/admin/AdminSidebar.tsx +148 -36
  109. package/.framework/src/components/admin/AdminStatsCard.tsx +48 -29
  110. package/.framework/src/components/admin/PageInstructions.tsx +49 -0
  111. package/.framework/src/components/admin/SortableTableHeader.tsx +49 -2
  112. package/.framework/src/components/app-shell/GenericAppShell.tsx +69 -11
  113. package/.framework/src/components/app-shell/GenericDetailPage.tsx +55 -10
  114. package/.framework/src/components/app-shell/GenericListPage.tsx +76 -9
  115. package/.framework/src/components/app-sidebar.tsx +50 -3
  116. package/.framework/src/components/auth/ProtectedRoute.tsx +53 -45
  117. package/.framework/src/components/kb/KBArticleEditor.tsx +409 -0
  118. package/.framework/src/components/kb/KBArticleList.tsx +557 -0
  119. package/.framework/src/components/layout/AppShell.tsx +54 -16
  120. package/.framework/src/components/layout/Header.tsx +50 -38
  121. package/.framework/src/components/layout/Layout.tsx +48 -32
  122. package/.framework/src/components/layout/Sidebar.tsx +167 -16
  123. package/.framework/src/components/runtime/DataDetailHeader.tsx +33 -1
  124. package/.framework/src/components/runtime/DataDetailPage.tsx +289 -4
  125. package/.framework/src/components/runtime/DataFilters.tsx +78 -1
  126. package/.framework/src/components/runtime/DataHeader.tsx +32 -29
  127. package/.framework/src/components/runtime/DataListPage.tsx +161 -2
  128. package/.framework/src/components/runtime/DataStats.tsx +48 -1
  129. package/.framework/src/components/runtime/DataTable.tsx +153 -1
  130. package/.framework/src/components/runtime/SchemaDetailForm.tsx +77 -46
  131. package/.framework/src/components/runtime/index.ts +16 -9
  132. package/.framework/src/components/search-form.tsx +33 -1
  133. package/.framework/src/components/shared/AgentView.tsx +48 -51
  134. package/.framework/src/components/shared/FieldRenderer.tsx +84 -67
  135. package/.framework/src/components/shared/InviteManager.tsx +113 -52
  136. package/.framework/src/components/shared/MemberList.tsx +182 -0
  137. package/.framework/src/components/shared/SchemaFields.tsx +96 -78
  138. package/.framework/src/components/ui/DataTable.tsx +86 -56
  139. package/.framework/src/components/ui/Form.tsx +188 -109
  140. package/.framework/src/components/ui/ItemCard.tsx +86 -58
  141. package/.framework/src/components/ui/ItemListView.tsx +88 -61
  142. package/.framework/src/components/ui/LoadingSpinner.tsx +52 -27
  143. package/.framework/src/components/ui/Modal.tsx +81 -4
  144. package/.framework/src/components/ui/RichTextEditor.tsx +101 -9
  145. package/.framework/src/components/ui/accordion.tsx +97 -5
  146. package/.framework/src/components/ui/alert-dialog.tsx +225 -13
  147. package/.framework/src/components/ui/alert.tsx +113 -6
  148. package/.framework/src/components/ui/aspect-ratio.tsx +49 -2
  149. package/.framework/src/components/ui/avatar.tsx +129 -7
  150. package/.framework/src/components/ui/badge.tsx +65 -3
  151. package/.framework/src/components/ui/breadcrumb.tsx +145 -8
  152. package/.framework/src/components/ui/button-group.tsx +81 -4
  153. package/.framework/src/components/ui/button.tsx +49 -2
  154. package/.framework/src/components/ui/calendar.tsx +65 -3
  155. package/.framework/src/components/ui/card.tsx +145 -8
  156. package/.framework/src/components/ui/carousel.tsx +129 -7
  157. package/.framework/src/components/ui/chart.tsx +161 -10
  158. package/.framework/src/components/ui/checkbox.tsx +49 -2
  159. package/.framework/src/components/ui/collapsible.tsx +81 -5
  160. package/.framework/src/components/ui/combobox.tsx +305 -20
  161. package/.framework/src/components/ui/command.tsx +177 -11
  162. package/.framework/src/components/ui/context-menu.tsx +273 -17
  163. package/.framework/src/components/ui/dialog.tsx +209 -27
  164. package/.framework/src/components/ui/direction.tsx +64 -4
  165. package/.framework/src/components/ui/drawer.tsx +193 -12
  166. package/.framework/src/components/ui/dropdown-menu.tsx +273 -18
  167. package/.framework/src/components/ui/empty.tsx +145 -9
  168. package/.framework/src/components/ui/field.tsx +209 -14
  169. package/.framework/src/components/ui/hover-card.tsx +81 -4
  170. package/.framework/src/components/ui/input-group.tsx +162 -10
  171. package/.framework/src/components/ui/input-otp.tsx +98 -5
  172. package/.framework/src/components/ui/input.tsx +49 -2
  173. package/.framework/src/components/ui/item.tsx +225 -13
  174. package/.framework/src/components/ui/kbd.tsx +65 -3
  175. package/.framework/src/components/ui/label.tsx +49 -2
  176. package/.framework/src/components/ui/menubar.tsx +289 -17
  177. package/.framework/src/components/ui/native-select.tsx +97 -5
  178. package/.framework/src/components/ui/navigation-menu.tsx +177 -10
  179. package/.framework/src/components/ui/pagination.tsx +161 -9
  180. package/.framework/src/components/ui/popover.tsx +145 -8
  181. package/.framework/src/components/ui/progress.tsx +49 -2
  182. package/.framework/src/components/ui/radio-group.tsx +65 -3
  183. package/.framework/src/components/ui/resizable.tsx +82 -4
  184. package/.framework/src/components/ui/scroll-area.tsx +65 -3
  185. package/.framework/src/components/ui/select.tsx +193 -11
  186. package/.framework/src/components/ui/separator.tsx +49 -2
  187. package/.framework/src/components/ui/sheet.tsx +193 -11
  188. package/.framework/src/components/ui/sidebar.tsx +481 -38
  189. package/.framework/src/components/ui/skeleton.tsx +49 -2
  190. package/.framework/src/components/ui/slider.tsx +49 -2
  191. package/.framework/src/components/ui/sonner.tsx +49 -2
  192. package/.framework/src/components/ui/spinner.tsx +49 -2
  193. package/.framework/src/components/ui/switch.tsx +49 -2
  194. package/.framework/src/components/ui/table-primitives.tsx +160 -33
  195. package/.framework/src/components/ui/table.tsx +161 -9
  196. package/.framework/src/components/ui/tabs.tsx +113 -6
  197. package/.framework/src/components/ui/textarea.tsx +49 -2
  198. package/.framework/src/components/ui/toggle-group.tsx +81 -4
  199. package/.framework/src/components/ui/toggle.tsx +65 -3
  200. package/.framework/src/components/ui/tooltip.tsx +97 -5
  201. package/.framework/src/contexts/AppContext.tsx +129 -45
  202. package/.framework/src/contexts/AuthContext.tsx +187 -144
  203. package/.framework/src/hooks/use-mobile.ts +48 -2
  204. package/.framework/src/hooks/useApi.ts +208 -159
  205. package/.framework/src/hooks/useAppPath.ts +32 -23
  206. package/.framework/src/hooks/useApps.ts +51 -20
  207. package/.framework/src/hooks/useEntityList.ts +32 -78
  208. package/.framework/src/hooks/useEntityRecord.ts +35 -96
  209. package/.framework/src/hooks/useForm.ts +32 -92
  210. package/.framework/src/hooks/useListSchema.ts +49 -78
  211. package/.framework/src/hooks/useSchemaRecord.ts +114 -105
  212. package/.framework/src/lib/api.ts +195 -116
  213. package/.framework/src/lib/supabase.ts +98 -64
  214. package/.framework/src/lib/utils.ts +287 -151
  215. package/.framework/src/main.tsx +49 -3
  216. package/.framework/src/pages/DashboardPage.tsx +52 -29
  217. package/.framework/src/pages/NotFoundPage.tsx +32 -10
  218. package/.framework/src/pages/SetupPage.tsx +32 -12
  219. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +119 -10
  220. package/.framework/src/pages/admin/AIAgentsPage.tsx +48 -19
  221. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +187 -17
  222. package/.framework/src/pages/admin/APIKeysPage.tsx +98 -22
  223. package/.framework/src/pages/admin/AlertsConfigPage.tsx +113 -26
  224. package/.framework/src/pages/admin/AppDetailPage.tsx +125 -8
  225. package/.framework/src/pages/admin/AppsPage.tsx +49 -2
  226. package/.framework/src/pages/admin/DeliveriesPage.tsx +196 -0
  227. package/.framework/src/pages/admin/DesignedPage.tsx +32 -18
  228. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +215 -484
  229. package/.framework/src/pages/admin/EmbeddingsPage.tsx +116 -319
  230. package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +34 -9
  231. package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +34 -9
  232. package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -16
  233. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +183 -26
  234. package/.framework/src/pages/admin/IntegrationsPage.tsx +48 -19
  235. package/.framework/src/pages/admin/InvitesPage.tsx +48 -14
  236. package/.framework/src/pages/admin/LogsPage.tsx +422 -75
  237. package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +34 -9
  238. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +113 -24
  239. package/.framework/src/pages/admin/PipelineDetailPage.tsx +206 -34
  240. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +50 -17
  241. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -21
  242. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +378 -88
  243. package/.framework/src/pages/admin/PromptConfigsPage.tsx +125 -16
  244. package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +49 -10
  245. package/.framework/src/pages/admin/RoleDetailPage.tsx +130 -10
  246. package/.framework/src/pages/admin/RolesPage.tsx +171 -18
  247. package/.framework/src/pages/admin/SelectTestPage.tsx +34 -9
  248. package/.framework/src/pages/admin/ShadcnTestPage.tsx +49 -11
  249. package/.framework/src/pages/admin/SimpleDashboard.tsx +49 -10
  250. package/.framework/src/pages/admin/TestRunDetailPage.tsx +49 -4
  251. package/.framework/src/pages/admin/TestingDashboard.tsx +98 -28
  252. package/.framework/src/pages/admin/TimerDetailPage.tsx +143 -33
  253. package/.framework/src/pages/admin/TimersPage.tsx +48 -20
  254. package/.framework/src/pages/admin/TriggerDetailPage.tsx +118 -30
  255. package/.framework/src/pages/admin/TriggersPage.tsx +64 -19
  256. package/.framework/src/pages/admin/TypeDetailPage.tsx +138 -15
  257. package/.framework/src/pages/admin/TypesPage.tsx +48 -20
  258. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +465 -0
  259. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +787 -0
  260. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +699 -0
  261. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +647 -0
  262. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +616 -0
  263. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +1402 -0
  264. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +614 -0
  265. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +571 -0
  266. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +731 -0
  267. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
  268. package/.framework/src/pages/auth/AuthConfirmPage.tsx +52 -51
  269. package/.framework/src/pages/auth/ForgotPasswordPage.tsx +31 -22
  270. package/.framework/src/pages/auth/LoginPage.tsx +50 -23
  271. package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -15
  272. package/.framework/src/pages/auth/RegisterPage.tsx +281 -317
  273. package/.framework/src/pages/spine-framework/APIPage.tsx +33 -0
  274. package/.framework/src/pages/spine-framework/CLIPage.tsx +33 -0
  275. package/.framework/src/types/auth.ts +128 -71
  276. package/.framework/src/types/types.ts +373 -157
  277. package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +39 -0
  278. package/custom/.devin/skills/spine-workbench-idea/SKILL.md +36 -0
  279. package/custom/.devin/skills/spine-workbench-implement/SKILL.md +46 -0
  280. package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +28 -0
  281. package/custom/.devin/skills/spine-workbench-plan/SKILL.md +38 -0
  282. package/docs/README.md +9 -130
  283. package/netlify.toml +5 -2
  284. package/package.json +13 -25
  285. package/scripts/kb-ingest-docs.ts +203 -0
  286. package/spine.config.json +65 -4
  287. package/.framework/migrations/001_schema.sql +0 -425
  288. package/.framework/migrations/002_rls_and_functions.sql +0 -763
  289. package/.framework/migrations/004_enhancements.sql +0 -43
  290. package/.framework/migrations/005_auth_user_trigger.sql +0 -105
  291. package/.framework/migrations/006_fix_current_actor_id.sql +0 -21
  292. package/.framework/migrations/016_invites.sql +0 -27
  293. package/.framework/migrations/017_fix_get_account_apps.sql +0 -78
  294. package/.framework/migrations/018_apps_required_roles.sql +0 -17
  295. package/.framework/migrations/019_triggers_unique_constraint.sql +0 -13
  296. package/.framework/migrations/020_get_account_apps_role_filter.sql +0 -117
  297. package/.framework/migrations/021_app_domains.sql +0 -112
  298. package/.framework/migrations/022_route_prefix_domain_unique.sql +0 -21
  299. package/.framework/migrations/023_match_embeddings_rpc.sql +0 -78
  300. package/.framework/migrations/024_messages_account_id.sql +0 -9
  301. package/.framework/migrations/025_retype_threads_messages.sql +0 -240
  302. package/.framework/migrations/026_fix_rls_policies.sql +0 -47
  303. package/.framework/migrations/027_embedding_lifecycle.sql +0 -176
  304. package/.framework/migrations/028_fix_message_data_permissions.sql +0 -49
  305. package/.framework/migrations/029_tighten_support_triage_prompt.sql +0 -41
  306. package/.framework/migrations/030_messages_updated_by.sql +0 -6
  307. package/.framework/migrations/031_seed_upsert_constraints.sql +0 -35
  308. package/docs/APPS.md +0 -232
  309. package/docs/ARCHITECTURE.md +0 -246
  310. package/docs/INSTALL.md +0 -155
  311. package/docs/design-schema-spec.md +0 -1837
  312. package/docs/dev-guides/01-create-an-app.md +0 -183
  313. package/docs/dev-guides/02-create-a-function.md +0 -178
  314. package/docs/dev-guides/03-create-a-component.md +0 -178
  315. package/docs/dev-guides/04-webhook-handlers.md +0 -129
  316. package/docs/dev-guides/05-testing.md +0 -168
  317. package/docs/dev-guides/README.md +0 -40
  318. package/docs/npm-packages-plan.md +0 -288
  319. package/docs/spine-core--api-reference.md +0 -822
@@ -1,87 +1,147 @@
1
- /**
2
- * @module src/lib/api
3
- * @audience installer
4
- * @layer frontend-hook
5
- * @stability stable
6
- *
7
- * Authenticated fetch wrapper and account context for all Spine frontend
8
- * API calls. Injects the Supabase JWT and `X-Account-Id` header into every
9
- * request made via `apiFetch`.
10
- *
11
- * **Account context** is a module-level singleton set once after login:
12
- * ```ts
13
- * setAccountId(ctx.account_id) // called in AuthContext after auth.context()
14
- * ```
15
- * All subsequent `apiFetch` calls include `X-Account-Id` automatically.
16
- *
17
- * **401 interceptor:** Register a callback via `onUnauthorized(cb)` to be
18
- * notified when any non-auth API call returns 401. AuthContext uses this to
19
- * trigger logout when the session expires mid-use.
20
- *
21
- * INVARIANT: Call `setAccountId` before making any authenticated API requests.
22
- * If `_accountId` is null, the backend may reject scoped requests.
23
- *
24
- * @seeAlso src/lib/supabase.ts (supabase client used for getSession)
25
- * @seeAlso src/hooks/useApi.ts (wraps apiFetch with React state management)
26
- * @seeAlso src/contexts/AuthContext.tsx (calls setAccountId after login)
27
- */
28
1
 
29
- import { supabase } from './supabase'
30
2
 
31
- // ─── ACCOUNT CONTEXT ─────────────────────────────────────────────────────────
32
3
 
33
- let _accountId: string | null = null
34
4
 
35
- /**
36
- * Sets the module-level account ID injected into all subsequent `apiFetch`
37
- * calls as `X-Account-Id`. Pass `null` to clear (e.g. on logout).
38
- *
39
- * @param id - UUID of the active account, or null to clear
40
- * @sideEffects Mutates module-level `_accountId`
41
- * @calledBy src/contexts/AuthContext.tsx (after successful login)
42
- */
5
+
6
+
7
+
8
+
9
+
10
+
11
+ // CIL[BEGIN chunk_id="api_imports_1783716639" type="module_header" identity="imports" parent="none"]
12
+ // CIL[DOC-MACRO purpose="Import Supabase client for authentication"]
13
+ // CIL[DOC-RESPONSIBILITY responsibility="Provide Supabase client dependency"]
14
+ // CIL[DOC-CONTEXT module="api" layer="utility" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/schema-utils.ts\",\"custom/apps/portal/pages/ContentPage.tsx\",\"\\\"]"]
15
+ // CIL[DOC-CONTRACT inputs="none" outputs="supabase client" errors="none" side_effects="none"]
16
+ // CIL[DOC-MICRO logic_summary="Import statement for external dependency" notable_decisions="[]"]
17
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
18
+ // CIL[DOC-STABILITY stability="stable"]
19
+ // CIL[DOC-AUDIENCE audience="developer"]
20
+ // CIL[DOC-VECTOR type="context" content="Layer: utility. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, .framework/functions/_shared/schema-utils.ts, custom/apps/portal/pages/ContentPage.tsx, \."]
21
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
22
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
23
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
24
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
25
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
26
+ import { supabase } from './supabase'
27
+ // CIL[END chunk_id="api_imports_1783716639"]
28
+ // CIL[BEGIN chunk_id="api__accountid_1783716639" type="variable" identity="_accountId" parent="none"]
29
+ // CIL[DOC-MACRO purpose="Store current account context"]
30
+ // CIL[DOC-RESPONSIBILITY responsibility="Maintain account ID state"]
31
+ // CIL[DOC-CONTEXT module="api" layer="state" related_files="[\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
32
+ // CIL[DOC-CONTRACT inputs="none" outputs="account ID storage" errors="none" side_effects="state_modification"]
33
+ // CIL[DOC-MICRO logic_summary="Module-level variable for account context" notable_decisions="[]"]
34
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
35
+ // CIL[DOC-STABILITY stability="stable"]
36
+ // CIL[DOC-VECTOR type="context" content="Layer: state. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/RolesPage.tsx, \."]
37
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
38
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
39
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
40
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
41
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
42
+ let _accountId: string | null = null
43
+ // CIL[END chunk_id="api__accountid_1783716639"]
44
+ // CIL[BEGIN chunk_id="api_setaccountid_1783716639" type="function" identity="setAccountId" parent="none"]
45
+ // CIL[DOC-MACRO purpose="Set current account context"]
46
+ // CIL[DOC-RESPONSIBILITY responsibility="Update account ID state"]
47
+ // CIL[DOC-CONTEXT module="api" layer="state" related_files="[\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
48
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="state_modification"]
49
+ // CIL[DOC-MICRO logic_summary="Assign account ID to module variable" notable_decisions="[]"]
50
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
51
+ // CIL[DOC-STABILITY stability="stable"]
52
+ // CIL[DOC-VECTOR type="context" content="Layer: state. Direct callers: 1. Direct calls: 0. Related files: .framework/src/pages/admin/RolesPage.tsx, \."]
53
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 1. Total affected: 1."]
54
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
55
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
56
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
57
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
43
58
  export function setAccountId(id: string | null) {
44
59
  _accountId = id
45
60
  }
46
-
47
- /**
48
- * Returns the currently active account ID, or null if not set.
49
- *
50
- * @returns UUID string or null
51
- * @sideEffects none
52
- * @calledBy src/hooks/useApi.ts, any component needing the current account scope
53
- */
61
+ // CIL[END chunk_id="api_setaccountid_1783716639"]
62
+ // CIL[BEGIN chunk_id="api_getaccountid_1783716639" type="function" identity="getAccountId" parent="none"]
63
+ // CIL[DOC-MACRO purpose="Get current account context"]
64
+ // CIL[DOC-RESPONSIBILITY responsibility="Retrieve account ID state"]
65
+ // CIL[DOC-CONTEXT module="api" layer="state" related_files="[\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
66
+ // CIL[DOC-CONTRACT inputs="none" outputs="account_id: string|null" errors="none" side_effects="none"]
67
+ // CIL[DOC-MICRO logic_summary="Return account ID from module variable" notable_decisions="[]"]
68
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
69
+ // CIL[DOC-STABILITY stability="stable"]
70
+ // CIL[DOC-VECTOR type="context" content="Layer: state. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/RolesPage.tsx, \."]
71
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
72
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
73
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
74
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
75
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
54
76
  export function getAccountId(): string | null {
55
77
  return _accountId
56
78
  }
57
-
58
- // ─── 401 INTERCEPTOR ─────────────────────────────────────────────────────────
59
-
60
- /** Paths that are expected to return 401 (don't trigger the interceptor) */
61
- const AUTH_PATHS = ['/api/auth']
62
-
79
+ // CIL[END chunk_id="api_getaccountid_1783716639"]
80
+ // CIL[BEGIN chunk_id="api_authpaths_1783716639" type="variable" identity="AUTH_PATHS" parent="none"]
81
+ // CIL[DOC-MACRO purpose="Define authentication API endpoints"]
82
+ // CIL[DOC-RESPONSIBILITY responsibility="Maintain auth path configuration"]
83
+ // CIL[DOC-CONTEXT module="api" layer="config" related_files="[\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/schema-utils.ts\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\"\\\"]"]
84
+ // CIL[DOC-CONTRACT inputs="none" outputs="auth paths array" errors="none" side_effects="none"]
85
+ // CIL[DOC-MICRO logic_summary="Constant array of auth endpoint paths" notable_decisions="[]"]
86
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
87
+ // CIL[DOC-STABILITY stability="stable"]
88
+ // CIL[DOC-VECTOR type="context" content="Layer: config. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/principal.ts, .framework/functions/_shared/schema-utils.ts, custom/apps/cortex/functions/custom_cil-embeddings.ts, \."]
89
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
90
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
91
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
92
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
93
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
94
+ const AUTH_PATHS = ['/api/auth', '/api/admin-data']
95
+ // CIL[END chunk_id="api_authpaths_1783716639"]
96
+ // CIL[BEGIN chunk_id="api__unauthorizedcallback_1783716639" type="variable" identity="_onUnauthorizedCallback" parent="none"]
97
+ // CIL[DOC-MACRO purpose="Store unauthorized response handler"]
98
+ // CIL[DOC-RESPONSIBILITY responsibility="Maintain callback state for 401 errors"]
99
+ // CIL[DOC-CONTEXT module="api" layer="state" related_files="[]"]
100
+ // CIL[DOC-CONTRACT inputs="none" outputs="callback storage" errors="none" side_effects="state_modification"]
101
+ // CIL[DOC-MICRO logic_summary="Module-level variable for unauthorized callback" notable_decisions="[]"]
102
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
103
+ // CIL[DOC-STABILITY stability="stable"]
104
+ // CIL[DOC-VECTOR type="context" content="Layer: state. Direct callers: 0. Direct calls: 0. Related files: none."]
105
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
106
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
107
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
108
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
109
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
63
110
  let _onUnauthorizedCallback: (() => void) | null = null
64
-
65
- /**
66
- * Register a callback to be invoked when a non-auth API call returns 401.
67
- * Returns an unregister function. Only one callback may be active at a time.
68
- *
69
- * @param cb - Callback invoked once on 401
70
- * @returns Unregister function
71
- * @calledBy AuthContext (registers logout handler)
72
- */
111
+ // CIL[END chunk_id="api__unauthorizedcallback_1783716639"]
112
+ // CIL[BEGIN chunk_id="api_onunauthorized_1783716639" type="function" identity="onUnauthorized" parent="none"]
113
+ // CIL[DOC-MACRO purpose="Register unauthorized response handler"]
114
+ // CIL[DOC-RESPONSIBILITY responsibility="Manage 401 error callback lifecycle"]
115
+ // CIL[DOC-CONTEXT module="api" layer="error_handling" related_files="[]"]
116
+ // CIL[DOC-CONTRACT inputs="none" outputs="cleanup: () => void" errors="none" side_effects="state_modification"]
117
+ // CIL[DOC-MICRO logic_summary="Set callback and return cleanup function" notable_decisions="[]"]
118
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
119
+ // CIL[DOC-STABILITY stability="stable"]
120
+ // CIL[DOC-VECTOR type="context" content="Layer: error_handling. Direct callers: 0. Direct calls: 0. Related files: none."]
121
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
122
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
123
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
124
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
125
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
73
126
  export function onUnauthorized(cb: () => void): () => void {
74
127
  _onUnauthorizedCallback = cb
75
128
  return () => { _onUnauthorizedCallback = null }
76
129
  }
77
-
78
- // ─── INTERNAL HELPERS ─────────────────────────────────────────────────────────
79
-
80
- /**
81
- * Normalises any `HeadersInit` variant to a plain `Record<string, string>`
82
- * so headers can be safely spread and merged.
83
- * @throws never
84
- */
130
+ // CIL[END chunk_id="api_onunauthorized_1783716639"]
131
+ // CIL[BEGIN chunk_id="api_normalizeheaders_1783716639" type="function" identity="normalizeHeaders" parent="none"]
132
+ // CIL[DOC-MACRO purpose="Convert headers to plain object format"]
133
+ // CIL[DOC-RESPONSIBILITY responsibility="Normalize header data structures"]
134
+ // CIL[DOC-CONTEXT module="api" layer="utility" related_files="[]"]
135
+ // CIL[DOC-CONTRACT inputs="none" outputs="Record<string,string>" errors="none" side_effects="none"]
136
+ // CIL[DOC-MICRO logic_summary="Handle Headers, array, and object formats" notable_decisions="[]"]
137
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
138
+ // CIL[DOC-STABILITY stability="stable"]
139
+ // CIL[DOC-VECTOR type="context" content="Layer: utility. Direct callers: 0. Direct calls: 0. Related files: none."]
140
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
141
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
142
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
143
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
144
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
85
145
  function normalizeHeaders(headers?: HeadersInit): Record<string, string> {
86
146
  if (!headers) return {}
87
147
 
@@ -97,27 +157,29 @@ function normalizeHeaders(headers?: HeadersInit): Record<string, string> {
97
157
  Object.entries(headers).map(([key, value]) => [key, String(value)])
98
158
  )
99
159
  }
100
-
101
- // ─── AUTH HEADERS ─────────────────────────────────────────────────────────────────
102
-
103
- /**
104
- * Builds the auth header map for a request: `Authorization: Bearer <jwt>`
105
- * and, if set, `X-Account-Id: <accountId>`.
106
- *
107
- * Called internally by `apiFetch` — do not call directly unless constructing
108
- * a manual `fetch` outside of `apiFetch`.
109
- *
110
- * @returns Plain header object; empty if no active session
111
- * @throws never — missing session returns empty headers, not an error
112
- * @sideEffects DB read: supabase.auth.getSession (reads localStorage)
113
- * @calledBy apiFetch
114
- */
160
+ // CIL[END chunk_id="api_normalizeheaders_1783716639"]
161
+ // CIL[BEGIN chunk_id="api_getauthheaders_1783716639" type="function" identity="getAuthHeaders" parent="none"]
162
+ // CIL[DOC-MACRO purpose="Build authentication headers for API requests"]
163
+ // CIL[DOC-RESPONSIBILITY responsibility="Generate auth and account context headers"]
164
+ // CIL[DOC-CONTEXT module="api" layer="auth" related_files="[]"]
165
+ // CIL[DOC-CONTRACT inputs="none" outputs="Record<string,string>" errors="supabase_errors" side_effects="none"]
166
+ // CIL[DOC-MICRO logic_summary="Get session token and add account ID to headers" notable_decisions="[]"]
167
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
168
+ // CIL[DOC-STABILITY stability="stable"]
169
+ // CIL[DOC-VECTOR type="context" content="Layer: auth. Direct callers: 0. Direct calls: 0. Related files: none."]
170
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
171
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
172
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
173
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
174
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
115
175
  export async function getAuthHeaders(): Promise<Record<string, string>> {
116
176
  const headers: Record<string, string> = {}
117
177
 
118
178
  const { data: { session } } = await supabase.auth.getSession()
119
179
  if (session?.access_token) {
120
180
  headers['Authorization'] = `Bearer ${session.access_token}`
181
+ } else {
182
+
121
183
  }
122
184
 
123
185
  if (_accountId) {
@@ -126,38 +188,43 @@ export async function getAuthHeaders(): Promise<Record<string, string>> {
126
188
 
127
189
  return headers
128
190
  }
191
+ // CIL[END chunk_id="api_getauthheaders_1783716639"]
192
+ // CIL[BEGIN chunk_id="api_apifetch_1783716639" type="function" identity="apiFetch" parent="none"]
193
+ // CIL[DOC-MACRO purpose="Authenticated HTTP request wrapper"]
194
+ // CIL[DOC-RESPONSIBILITY responsibility="Handle API requests with auth and error handling"]
195
+ // CIL[DOC-CONTEXT module="api" layer="client" related_files="[]"]
196
+ // CIL[DOC-CONTRACT inputs="none" outputs="Response" errors="network_errors" side_effects="callback_execution"]
197
+ // CIL[DOC-MICRO logic_summary="Add auth headers, clean invalid tokens, handle 401s" notable_decisions="[]"]
198
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
199
+ // CIL[DOC-STABILITY stability="stable"]
200
+ // CIL[DOC-VECTOR type="context" content="Layer: client. Direct callers: 0. Direct calls: 0. Related files: none."]
201
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
202
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
203
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
204
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
205
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
206
+ let _sessionTraceId: string | null = null
207
+ let _sessionTraceState: string = ''
208
+
209
+ function generateHexId(length: number): string {
210
+ const uuid = crypto.randomUUID().replace(/-/g, '')
211
+ if (length > uuid.length) {
212
+ return (uuid + crypto.randomUUID().replace(/-/g, '')).slice(0, length).toLowerCase()
213
+ }
214
+ return uuid.slice(0, length).toLowerCase()
215
+ }
216
+
217
+ function getSessionTraceId(): string {
218
+ if (!_sessionTraceId) {
219
+ _sessionTraceId = generateHexId(32)
220
+ }
221
+ return _sessionTraceId
222
+ }
223
+
224
+ function buildTraceParent(): string {
225
+ return `00-${getSessionTraceId()}-${generateHexId(16)}-01`
226
+ }
129
227
 
130
- // ─── FETCH WRAPPER ────────────────────────────────────────────────────────────────
131
-
132
- /**
133
- * Authenticated fetch wrapper. Injects `Authorization` + `X-Account-Id`
134
- * headers, strips invalid Bearer values (`null`/`undefined`/empty), and
135
- * forwards all other options (including `signal` for AbortController).
136
- *
137
- * If a non-auth endpoint returns 401, the registered `onUnauthorized`
138
- * callback fires (typically triggers logout).
139
- *
140
- * Use this for ALL Spine API calls from the frontend. Never call `fetch`
141
- * directly for API routes.
142
- *
143
- * @param path - API path, e.g. `'/.netlify/functions/items'`
144
- * @param options - Standard `RequestInit` options (method, body, signal, etc.)
145
- * @returns Raw `Response` — callers must check `response.ok` / status
146
- * @throws Network errors from `fetch` (e.g. `TypeError: Failed to fetch`)
147
- * @inputSpec path: string — relative URL to a Netlify function
148
- * @inputSpec options.signal: AbortSignal | undefined — forwarded for cancellation
149
- * @outputSpec Response — with auth headers injected; not yet parsed
150
- * @sideEffects Network request; reads localStorage via getAuthHeaders;
151
- * may trigger onUnauthorized callback on 401
152
- * @calledBy src/hooks/useApi.ts, useEntityList.ts, useEntityRecord.ts
153
- *
154
- * @example
155
- * ```ts
156
- * const res = await apiFetch('/.netlify/functions/items?action=list')
157
- * if (!res.ok) throw new Error(await res.text())
158
- * const { data } = await res.json()
159
- * ```
160
- */
161
228
  export async function apiFetch(path: string, options: RequestInit = {}): Promise<Response> {
162
229
  const authHeaders = await getAuthHeaders()
163
230
  const optionHeaders = normalizeHeaders(options.headers)
@@ -171,17 +238,28 @@ export async function apiFetch(path: string, options: RequestInit = {}): Promise
171
238
  delete optionHeaders.authorization
172
239
  }
173
240
 
241
+ const traceparent = buildTraceParent()
242
+
174
243
  const fetchOptions = {
175
244
  ...options,
176
245
  headers: {
177
246
  ...authHeaders,
178
247
  ...optionHeaders,
248
+ traceparent,
179
249
  },
180
250
  }
181
251
 
182
252
  const response = await fetch(path, fetchOptions)
183
253
 
184
- // 401 on a non-auth endpoint means the session has expired
254
+ const requestId = response.headers.get('X-Request-ID') || response.headers.get('x-request-id')
255
+ const responseTraceparent = response.headers.get('traceparent') || response.headers.get('Traceparent')
256
+ if (requestId) {
257
+ console.log('[Spine] requestId:', requestId, 'traceparent:', responseTraceparent || traceparent)
258
+ }
259
+
260
+ const responseTracestate = response.headers.get('tracestate') || response.headers.get('Tracestate')
261
+ if (responseTracestate) _sessionTraceState = responseTracestate
262
+
185
263
  if (response.status === 401 && _onUnauthorizedCallback) {
186
264
  const isAuthPath = AUTH_PATHS.some(p => path.startsWith(p))
187
265
  if (!isAuthPath) {
@@ -191,3 +269,4 @@ export async function apiFetch(path: string, options: RequestInit = {}): Promise
191
269
 
192
270
  return response
193
271
  }
272
+ // CIL[END chunk_id="api_apifetch_1783716639"]
@@ -1,94 +1,128 @@
1
- /**
2
- * @module src/lib/supabase
3
- * @audience installer
4
- * @layer frontend-hook
5
- * @stability stable
6
- *
7
- * Browser-side Supabase client singleton and session helpers for the Spine
8
- * frontend. Reads `VITE_SUPABASE_URL` and `VITE_SUPABASE_ANON_KEY` from
9
- * Vite env at build time; throws immediately on missing values so
10
- * misconfigured builds fail loudly rather than silently.
11
- *
12
- * INVARIANT: `supabase` is a module-level singleton — do not call
13
- * `createClient` again in components or hooks. Import this module instead.
14
- *
15
- * @seeAlso src/lib/api.ts (uses supabase.auth.getSession for apiFetch headers)
16
- * @seeAlso src/contexts/AuthContext.tsx (wraps supabase.auth for React state)
17
- */
18
1
 
19
- import { createClient } from '@supabase/supabase-js'
20
2
 
3
+
4
+
5
+
6
+
7
+ // CIL[BEGIN chunk_id="supabase_module_header_1783672456" type="module_header" identity="imports" parent="none"]
8
+ // CIL[DOC-MACRO purpose="Import Supabase client"]
9
+ // CIL[DOC-RESPONSIBILITY responsibility="Import Supabase client factory"]
10
+ // CIL[DOC-CONTEXT module="supabase" layer="frontend-hook" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
11
+ // CIL[DOC-CONTRACT inputs="none" outputs="createClient function" errors="none" side_effects="none"]
12
+ // CIL[DOC-MICRO logic_summary="Imports Supabase client creation function" notable_decisions="[]"]
13
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
14
+ // CIL[DOC-STABILITY stability="stable"]
15
+ // CIL[DOC-AUDIENCE audience="developer"]
16
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
17
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
18
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
19
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
20
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
21
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
22
+ import { createClient } from '@supabase/supabase-js'
23
+ // CIL[END chunk_id="supabase_module_header_1783672456"]
24
+ // CIL[BEGIN chunk_id="supabase_envvars_1783672456" type="variable" identity="environmentVariables" parent="none"]
25
+ // CIL[DOC-MACRO purpose="Load Supabase environment variables"]
26
+ // CIL[DOC-RESPONSIBILITY responsibility="Validate and store Supabase config"]
27
+ // CIL[DOC-CONTEXT module="supabase" layer="frontend-hook" related_files="[\"\\\"]"]
28
+ // CIL[DOC-CONTRACT inputs="none" outputs="Environment variables" errors="Error on missing vars" side_effects="May throw error"]
29
+ // CIL[DOC-MICRO logic_summary="Loads and validates required Supabase env vars" notable_decisions="[]"]
30
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
31
+ // CIL[DOC-STABILITY stability="stable"]
32
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 0. Direct calls: 0. Related files: \."]
33
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
34
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
35
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
36
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
37
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
21
38
  const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
22
39
  const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY
23
40
 
24
41
  if (!supabaseUrl || !supabaseAnonKey) {
25
42
  throw new Error('Missing Supabase environment variables')
26
43
  }
27
-
28
- // ─── CLIENT SINGLETON ─────────────────────────────────────────────────────────
29
-
30
- /**
31
- * Browser-side Supabase client with persistent session, auto-refresh, and
32
- * URL-based session detection enabled. This is the only Supabase client
33
- * instance in the frontend; all auth and RLS-scoped queries flow through it.
34
- *
35
- * @inputSpec VITE_SUPABASE_URL: string — valid Supabase project URL
36
- * @inputSpec VITE_SUPABASE_ANON_KEY: string — anon (public) key
37
- * @throws Error('Missing Supabase environment variables') at module load if
38
- * either env var is absent
39
- * @sideEffects Reads localStorage for persisted session on construction
40
- * @calledBy src/lib/api.ts (getAuthHeaders), src/contexts/AuthContext.tsx
41
- */
44
+ // CIL[END chunk_id="supabase_envvars_1783672456"]
45
+ // CIL[BEGIN chunk_id="supabase_client_1783672456" type="variable" identity="supabase" parent="none"]
46
+ // CIL[DOC-MACRO purpose="Create Supabase client singleton"]
47
+ // CIL[DOC-RESPONSIBILITY responsibility="Initialize Supabase client with auth config"]
48
+ // CIL[DOC-CONTEXT module="supabase" layer="frontend-hook" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/components/ui/dialog.tsx\",\"\\\"]"]
49
+ // CIL[DOC-CONTRACT inputs="none" outputs="Supabase client instance" errors="none" side_effects="Reads localStorage"]
50
+ // CIL[DOC-MICRO logic_summary="Configures session persistence, auto-refresh, and a no-op auth lock to bypass navigator.locks" notable_decisions="[]"]
51
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
52
+ // CIL[DOC-STABILITY stability="stable"]
53
+ // CIL[DOC-NOTE type="caution" content="No-op lock bypasses navigator.locks to avoid NavigatorLockAcquireTimeoutError during login"]
54
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/components/ui/dialog.tsx, \."]
55
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
56
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
57
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
58
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
59
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
42
60
  export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
43
61
  auth: {
44
62
  persistSession: true,
45
63
  autoRefreshToken: true,
46
64
  detectSessionInUrl: true,
65
+ lock: async <T>(_name: string, _acquireTimeout: number, fn: () => Promise<T>): Promise<T> => await fn(),
47
66
  },
48
67
  })
49
-
50
- // ─── SESSION HELPERS ─────────────────────────────────────────────────────────
51
-
52
- /**
53
- * Returns the current Supabase auth session, or `null` if unauthenticated.
54
- *
55
- * @returns Session object or null
56
- * @throws Supabase AuthError on unexpected failure
57
- * @sideEffects none (read-only)
58
- * @calledBy AuthContext.tsx, login flows
59
- */
68
+ // CIL[END chunk_id="supabase_client_1783672456"]
69
+ // CIL[BEGIN chunk_id="supabase_getcurrentsession_1783672456" type="function" identity="getCurrentSession" parent="none"]
70
+ // CIL[DOC-MACRO purpose="Get current Supabase session"]
71
+ // CIL[DOC-RESPONSIBILITY responsibility="Retrieve active auth session"]
72
+ // CIL[DOC-CONTEXT module="supabase" layer="frontend-hook" related_files="[\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
73
+ // CIL[DOC-CONTRACT inputs="none" outputs="Session object or null" errors="Supabase AuthError" side_effects="Reads localStorage"]
74
+ // CIL[DOC-MICRO logic_summary="Calls Supabase getSession and handles errors" notable_decisions="[]"]
75
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
76
+ // CIL[DOC-STABILITY stability="stable"]
77
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/RolesPage.tsx, \."]
78
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
79
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
80
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
81
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
82
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
60
83
  export const getCurrentSession = async () => {
61
84
  const { data: { session }, error } = await supabase.auth.getSession()
62
85
  if (error) throw error
63
86
  return session
64
87
  }
65
-
66
- /**
67
- * Returns the currently authenticated Supabase user, or `null` if not signed in.
68
- *
69
- * @returns User object or null
70
- * @throws Supabase AuthError on unexpected failure
71
- * @sideEffects none (read-only)
72
- * @calledBy AuthContext.tsx
73
- */
88
+ // CIL[END chunk_id="supabase_getcurrentsession_1783672456"]
89
+ // CIL[BEGIN chunk_id="supabase_getcurrentuser_1783672456" type="function" identity="getCurrentUser" parent="none"]
90
+ // CIL[DOC-MACRO purpose="Get current Supabase user"]
91
+ // CIL[DOC-RESPONSIBILITY responsibility="Retrieve authenticated user data"]
92
+ // CIL[DOC-CONTEXT module="supabase" layer="frontend-hook" related_files="[\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
93
+ // CIL[DOC-CONTRACT inputs="none" outputs="User object or null" errors="Supabase AuthError" side_effects="Reads localStorage"]
94
+ // CIL[DOC-MICRO logic_summary="Calls Supabase getUser and handles errors" notable_decisions="[]"]
95
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
96
+ // CIL[DOC-STABILITY stability="stable"]
97
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/RolesPage.tsx, \."]
98
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
99
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
100
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
101
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
102
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
74
103
  export const getCurrentUser = async () => {
75
104
  const { data: { user }, error } = await supabase.auth.getUser()
76
105
  if (error) throw error
77
106
  return user
78
107
  }
79
-
80
- /**
81
- * Forces a session token refresh. Call this when a request returns 401 due
82
- * to an expired JWT. Supabase auto-refresh normally handles this, but this
83
- * function is exposed for explicit refresh flows.
84
- *
85
- * @returns `{ session, user }` after refresh
86
- * @throws Supabase AuthError if refresh fails (e.g. refresh token expired)
87
- * @sideEffects Updates localStorage session via Supabase client
88
- * @calledBy AuthContext.tsx (manual token refresh)
89
- */
108
+ // CIL[END chunk_id="supabase_getcurrentuser_1783672456"]
109
+ // CIL[BEGIN chunk_id="supabase_refreshsession_1783672456" type="function" identity="refreshSession" parent="none"]
110
+ // CIL[DOC-MACRO purpose="Refresh Supabase session"]
111
+ // CIL[DOC-RESPONSIBILITY responsibility="Force session token refresh"]
112
+ // CIL[DOC-CONTEXT module="supabase" layer="frontend-hook" related_files="[]"]
113
+ // CIL[DOC-CONTRACT inputs="none" outputs="Session data" errors="Supabase AuthError" side_effects="Updates localStorage"]
114
+ // CIL[DOC-MICRO logic_summary="Calls Supabase refreshSession and handles errors" notable_decisions="[]"]
115
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
116
+ // CIL[DOC-STABILITY stability="stable"]
117
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 0. Direct calls: 0. Related files: none."]
118
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
119
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
120
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
121
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
122
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
90
123
  export const refreshSession = async () => {
91
124
  const { data, error } = await supabase.auth.refreshSession()
92
125
  if (error) throw error
93
126
  return data
94
127
  }
128
+ // CIL[END chunk_id="supabase_refreshsession_1783672456"]