spine-framework 0.3.125 → 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 +169 -97
  6. package/.framework/cli/commands/generate.ts +82 -160
  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} +147 -54
  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 +222 -347
  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 +162 -14
  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 +687 -533
  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 +173 -145
  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 +192 -115
  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 +3 -3
  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,56 +1,72 @@
1
- /**
2
- * @module src/contexts/AuthContext
3
- * @audience installer
4
- * @layer frontend-hook
5
- * @stability stable
6
- *
7
- * React authentication context and provider for the Spine frontend.
8
- * Manages the full Supabase auth lifecycle: initial session hydration,
9
- * login, logout, auth state change events, and a server-side user context
10
- * fetch (principal, account, roles, permissions).
11
- *
12
- * **Session hydration strategy:**
13
- * 1. On mount, restore user from `localStorage` with TTL/version check
14
- * (cross-tab sync, survives page reloads without a loading flash)
15
- * 2. Always verify stored context with the server before rendering routes
16
- * 3. Subscribe to `supabase.auth.onAuthStateChange` for `SIGNED_IN`,
17
- * `TOKEN_REFRESHED`, and `SIGNED_OUT` events
18
- *
19
- * **Race-condition guards:**
20
- * - `isLoggingIn` ref prevents `onAuthStateChange` from re-fetching context
21
- * while `login()` is already in progress
22
- * - `onAuthStateChange` checks current user ref before async fetch
23
- * - `checkAuth` always verifies with server, even with stored user
24
- *
25
- * **Account scope:** Calls `setAccountId(userContext.account_id)` after
26
- * every successful context fetch, keeping `src/lib/api.ts` in sync.
27
- *
28
- * @seeAlso src/lib/supabase.ts (supabase client singleton)
29
- * @seeAlso src/lib/api.ts (setAccountId, apiFetch, onUnauthorized)
30
- * @seeAlso src/types/auth.ts (User shape)
31
- * @seeAlso functions/auth.ts (backend `/api/auth?action=context` endpoint)
32
- */
33
1
 
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+ // CIL[BEGIN chunk_id="AuthContext_module_header_1783749485" type="module_header" identity="module_header" parent="none"]
12
+ // CIL[DOC-MACRO purpose="Auth module imports and constants"]
13
+ // CIL[DOC-RESPONSIBILITY responsibility="Define React context types and storage constants"]
14
+ // CIL[DOC-CONTEXT module="AuthContext" layer="frontend-context" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/migrations/015_simplify_apps_table.sql\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
15
+ // CIL[DOC-CONTRACT inputs="none" outputs="type definitions" errors="none" side_effects="none"]
16
+ // CIL[DOC-MICRO logic_summary="Sets up imports and storage constants for auth management" 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: frontend-context. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/migrations/015_simplify_apps_table.sql, .framework/functions/_shared/principal.ts, .framework/src/pages/admin/RolesPage.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"]
34
26
  import React, { createContext, useContext, useEffect, useState, useRef, useCallback } from 'react'
35
27
  import { supabase } from '../lib/supabase'
36
28
  import { setAccountId, apiFetch, onUnauthorized } from '../lib/api'
37
29
  import { User } from '../types/auth'
38
30
 
39
- // ─── STORAGE ──────────────────────────────────────────────────────────────────
40
-
41
- /** Version stamp for stored user; bump when User shape changes */
42
31
  const STORAGE_VERSION = 1
43
32
  const STORAGE_KEY = 'spine_user'
44
- /** Max age (ms) before stored user is considered stale and discarded */
45
- const STORAGE_TTL_MS = 24 * 60 * 60 * 1000 // 24 hours
46
- const SESSION_TIMEOUT_MS = 15000 // guard against stale Supabase sessions hanging on reload
47
-
33
+ const STORAGE_TTL_MS = 24 * 60 * 60 * 1000
34
+ const SESSION_TIMEOUT_MS = 15000
35
+ // CIL[END chunk_id="AuthContext_module_header_1783749485"]
36
+ // CIL[BEGIN chunk_id="AuthContext_storeduserenvelope_1783749485" type="interface" identity="StoredUserEnvelope" parent="none"]
37
+ // CIL[DOC-MACRO purpose="Define stored user envelope interface"]
38
+ // CIL[DOC-RESPONSIBILITY responsibility="Type definition for localStorage user storage"]
39
+ // CIL[DOC-CONTEXT module="AuthContext" layer="frontend-types" related_files="[\".framework/functions/_shared/schema-utils.ts\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\"\\\"]"]
40
+ // CIL[DOC-CONTRACT inputs="none" outputs="interface definition" errors="none" side_effects="none"]
41
+ // CIL[DOC-MICRO logic_summary="Envelope wrapper for user data with version and timestamp" notable_decisions="[]"]
42
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
43
+ // CIL[DOC-STABILITY stability="stable"]
44
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-types. Direct callers: 0. Direct calls: 0. Related files: .framework/functions/_shared/schema-utils.ts, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/principal.ts, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/cortex/functions/custom_cil-embeddings.ts, \."]
45
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
46
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
47
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
48
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
49
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
48
50
  interface StoredUserEnvelope {
49
51
  version: number
50
52
  timestamp: number
51
53
  user: User
52
54
  }
53
-
55
+ // CIL[END chunk_id="AuthContext_storeduserenvelope_1783749485"]
56
+ // CIL[BEGIN chunk_id="AuthContext_readstoreduser_1783749485" type="function" identity="readStoredUser" parent="none"]
57
+ // CIL[DOC-MACRO purpose="Read stored user from localStorage"]
58
+ // CIL[DOC-RESPONSIBILITY responsibility="Retrieve and validate cached user data"]
59
+ // CIL[DOC-CONTEXT module="AuthContext" layer="frontend-utility" related_files="[\"\\\"]"]
60
+ // CIL[DOC-CONTRACT inputs="none" outputs="User | null" errors="none" side_effects="localStorage read"]
61
+ // CIL[DOC-MICRO logic_summary="Validates version and TTL before returning cached user" notable_decisions="[]"]
62
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
63
+ // CIL[DOC-STABILITY stability="stable"]
64
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-utility. Direct callers: 1. Direct calls: 0. Related files: \."]
65
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 1. Total affected: 1."]
66
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
67
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
68
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
69
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
54
70
  function readStoredUser(): User | null {
55
71
  try {
56
72
  const raw = localStorage.getItem(STORAGE_KEY)
@@ -63,7 +79,21 @@ function readStoredUser(): User | null {
63
79
  return null
64
80
  }
65
81
  }
66
-
82
+ // CIL[END chunk_id="AuthContext_readstoreduser_1783749485"]
83
+ // CIL[BEGIN chunk_id="AuthContext_writestoreduser_1783749485" type="function" identity="writeStoredUser" parent="none"]
84
+ // CIL[DOC-MACRO purpose="Write user to localStorage"]
85
+ // CIL[DOC-RESPONSIBILITY responsibility="Cache user data with envelope wrapper"]
86
+ // CIL[DOC-CONTEXT module="AuthContext" layer="frontend-utility" related_files="[\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\"custom/apps/portal/pages/ContentPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\".framework/src/components/ui/table-primitives.tsx\",\"\\\"]"]
87
+ // CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="localStorage write"]
88
+ // CIL[DOC-MICRO logic_summary="Stores user in envelope or removes entry if null" notable_decisions="[]"]
89
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
90
+ // CIL[DOC-STABILITY stability="stable"]
91
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-utility. Direct callers: 1. Direct calls: 0. Related files: custom/apps/cortex/functions/custom_cil-embeddings.ts, custom/apps/portal/pages/ContentPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/pages/admin/RolesPage.tsx, .framework/src/components/ui/table-primitives.tsx, \."]
92
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 1. Total affected: 1."]
93
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
94
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
95
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
96
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
67
97
  function writeStoredUser(user: User | null) {
68
98
  try {
69
99
  if (user) {
@@ -77,14 +107,23 @@ function writeStoredUser(user: User | null) {
77
107
  localStorage.removeItem(STORAGE_KEY)
78
108
  }
79
109
  } catch {
80
- // Storage unavailable (private browsing, quota exceeded)
81
110
  }
82
111
  }
83
-
84
- /**
85
- * Wrapper around supabase.auth.getSession() that times out to prevent the
86
- * app from getting stuck on a corrupted/stale stored session.
87
- */
112
+ // CIL[END chunk_id="AuthContext_writestoreduser_1783749485"]
113
+ // CIL[BEGIN chunk_id="AuthContext_getsessionwithtimeout_1783749485" type="function" identity="getSessionWithTimeout" parent="none"]
114
+ // CIL[DOC-MACRO purpose="Get Supabase session with timeout"]
115
+ // CIL[DOC-RESPONSIBILITY responsibility="Prevent hanging on stale sessions"]
116
+ // CIL[DOC-CONTEXT module="AuthContext" layer="frontend-utility" related_files="[\".framework/src/pages/admin/RolesPage.tsx\",\".framework/functions/_shared/schema-utils.ts\",\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/db.ts\",\".framework/src/components/ui/table-primitives.tsx\",\"\\\"]"]
117
+ // CIL[DOC-CONTRACT inputs="none" outputs="session data" errors="none" side_effects="none"]
118
+ // CIL[DOC-MICRO logic_summary="Races session fetch against timeout to prevent hanging" notable_decisions="[]"]
119
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
120
+ // CIL[DOC-STABILITY stability="stable"]
121
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-utility. Direct callers: 1. Direct calls: 0. Related files: .framework/src/pages/admin/RolesPage.tsx, .framework/functions/_shared/schema-utils.ts, .framework/functions/_shared/principal.ts, .framework/functions/_shared/db.ts, .framework/src/components/ui/table-primitives.tsx, \."]
122
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 1. Total affected: 1."]
123
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
124
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
125
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
126
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
88
127
  async function getSessionWithTimeout(): Promise<{ data: { session: any | null } }> {
89
128
  try {
90
129
  return await Promise.race([
@@ -97,38 +136,45 @@ async function getSessionWithTimeout(): Promise<{ data: { session: any | null }
97
136
  return { data: { session: null } }
98
137
  }
99
138
  }
100
-
101
- // ─── TYPES ───────────────────────────────────────────────────────────────────
102
-
103
- /**
104
- * Shape of the value provided by `AuthContext`.
105
- *
106
- * @prop user - Resolved server-side user context, or null if unauthenticated
107
- * @prop isLoading - True during initial `checkAuth` (prevents premature redirects)
108
- * @prop login - Sign in with email/password and hydrate user context
109
- * @prop logout - Sign out and clear user + account scope
110
- * @prop refreshUser - Re-fetch user context from the server (e.g. after role change)
111
- */
139
+ // CIL[END chunk_id="AuthContext_getsessionwithtimeout_1783749485"]
140
+ // CIL[BEGIN chunk_id="AuthContext_authcontexttype_1783749485" type="interface" identity="AuthContextType" parent="none"]
141
+ // CIL[DOC-MACRO purpose="Define auth context interface"]
142
+ // CIL[DOC-RESPONSIBILITY responsibility="Type definition for auth context value"]
143
+ // CIL[DOC-CONTEXT module="AuthContext" layer="frontend-types" related_files="[]"]
144
+ // CIL[DOC-CONTRACT inputs="none" outputs="interface definition" errors="none" side_effects="none"]
145
+ // CIL[DOC-MICRO logic_summary="Defines shape of auth context with user state and actions" notable_decisions="[]"]
146
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
147
+ // CIL[DOC-STABILITY stability="stable"]
148
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-types. Direct callers: 0. Direct calls: 0. Related files: none."]
149
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
150
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
151
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
152
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
153
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
112
154
  interface AuthContextType {
113
155
  user: User | null
114
156
  isLoading: boolean
115
- login: (email: string, password: string) => Promise<void>
157
+ login: (email: string, password: string) => Promise<User | null>
116
158
  logout: () => Promise<void>
117
- refreshUser: () => Promise<void>
159
+ refreshUser: () => Promise<User | null>
118
160
  }
119
161
 
120
162
  const AuthContext = createContext<AuthContextType | undefined>(undefined)
121
-
122
- // ─── useAuth ─────────────────────────────────────────────────────────────────
123
-
124
- /**
125
- * Hook to access the authentication context. Must be called inside `AuthProvider`.
126
- *
127
- * @returns `AuthContextType` — user, isLoading, login, logout, refreshUser
128
- * @throws Error('useAuth must be used within an AuthProvider') if called outside provider
129
- * @sideEffects none (read-only context access)
130
- * @calledBy every component that needs the current user or auth actions
131
- */
163
+ // CIL[END chunk_id="AuthContext_authcontexttype_1783749485"]
164
+ // CIL[BEGIN chunk_id="AuthContext_useauth_1783749485" type="function" identity="useAuth" parent="none"]
165
+ // CIL[DOC-MACRO purpose="Access auth context hook"]
166
+ // CIL[DOC-RESPONSIBILITY responsibility="Provide auth context to components"]
167
+ // CIL[DOC-CONTEXT module="AuthContext" layer="frontend-hook" related_files="[]"]
168
+ // CIL[DOC-CONTRACT inputs="none" outputs="AuthContextType" errors="throws if no provider" side_effects="none"]
169
+ // CIL[DOC-MICRO logic_summary="Returns auth context with safety check" notable_decisions="[]"]
170
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
171
+ // CIL[DOC-STABILITY stability="stable"]
172
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 0. Direct calls: 0. Related files: none."]
173
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
174
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
175
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
176
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
177
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
132
178
  export function useAuth() {
133
179
  const context = useContext(AuthContext)
134
180
  if (context === undefined) {
@@ -136,44 +182,54 @@ export function useAuth() {
136
182
  }
137
183
  return context
138
184
  }
139
-
185
+ // CIL[END chunk_id="AuthContext_useauth_1783749485"]
186
+ // CIL[BEGIN chunk_id="AuthContext_authproviderprops_1783749485" type="interface" identity="AuthProviderProps" parent="none"]
187
+ // CIL[DOC-MACRO purpose="Define auth provider props interface"]
188
+ // CIL[DOC-RESPONSIBILITY responsibility="Type definition for AuthProvider component"]
189
+ // CIL[DOC-CONTEXT module="AuthContext" layer="frontend-types" related_files="[]"]
190
+ // CIL[DOC-CONTRACT inputs="none" outputs="interface definition" errors="none" side_effects="none"]
191
+ // CIL[DOC-MICRO logic_summary="Simple props interface with only children" notable_decisions="[]"]
192
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
193
+ // CIL[DOC-STABILITY stability="stable"]
194
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-types. Direct callers: 0. Direct calls: 0. Related files: none."]
195
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
196
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
197
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
198
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
199
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
140
200
  interface AuthProviderProps {
141
201
  children: React.ReactNode
142
202
  }
143
-
144
- // ─── INTERNAL HELPERS ───────────────────────────────────────────────────────────
145
-
146
- /**
147
- * Fetches the server-side user context from `GET /api/auth` with retry.
148
- * Returns null on any persistent error rather than throwing, so callers
149
- * can apply fallback logic without try/catch.
150
- *
151
- * Retries up to `maxRetries` times on network errors and 5xx responses.
152
- * Does NOT retry 401/403 (auth failures are not transient).
153
- *
154
- * @returns Resolved `User` object or null on failure
155
- * @throws never (all errors are caught internally)
156
- * @sideEffects Network request via apiFetch; console logging
157
- * @calledBy AuthProvider.login, AuthProvider.refreshUser, AuthProvider.checkAuth
158
- */
203
+ // CIL[END chunk_id="AuthContext_authproviderprops_1783749485"]
204
+ // CIL[BEGIN chunk_id="AuthContext_fetchusercontext_1783749485" type="function" identity="fetchUserContext" parent="none"]
205
+ // CIL[DOC-MACRO purpose="Fetch user context with retry"]
206
+ // CIL[DOC-RESPONSIBILITY responsibility="Get server-side user data with resilience"]
207
+ // CIL[DOC-CONTEXT module="AuthContext" layer="frontend-utility" related_files="[]"]
208
+ // CIL[DOC-CONTRACT inputs="none" outputs="User | null" errors="none" side_effects="API calls"]
209
+ // CIL[DOC-MICRO logic_summary="Retries on network errors with exponential backoff" notable_decisions="[]"]
210
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
211
+ // CIL[DOC-STABILITY stability="stable"]
212
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-utility. Direct callers: 0. Direct calls: 0. Related files: none."]
213
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
214
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
215
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
216
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
217
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
159
218
  async function fetchUserContext(maxRetries = 2): Promise<User | null> {
160
219
  let lastError: unknown = null
161
220
 
162
221
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
163
222
  try {
164
223
  if (attempt > 0) {
165
- // Exponential backoff: 200ms, 800ms, 3200ms
166
224
  await new Promise(r => setTimeout(r, 200 * Math.pow(4, attempt - 1)))
167
225
  }
168
226
 
169
227
  const response = await apiFetch('/api/auth', { method: 'GET' })
170
228
 
171
- // Don't retry auth failures
172
229
  if (response.status === 401 || response.status === 403) {
173
230
  return null
174
231
  }
175
232
 
176
- // Retry on 5xx
177
233
  if (response.status >= 500) {
178
234
  lastError = new Error(`Server error: ${response.status}`)
179
235
  continue
@@ -188,45 +244,34 @@ async function fetchUserContext(maxRetries = 2): Promise<User | null> {
188
244
  return data.data
189
245
  } catch (error) {
190
246
  lastError = error
191
- // Network error (TypeError: Failed to fetch) — retry
192
247
  if (error instanceof TypeError) continue
193
- // Other errors — don't retry
194
248
  return null
195
249
  }
196
250
  }
197
251
  return null
198
252
  }
199
-
200
- // ─── AuthProvider ──────────────────────────────────────────────────────────────
201
-
202
- /**
203
- * Root authentication provider. Wrap the entire application with this component
204
- * to enable `useAuth()` in any descendant.
205
- *
206
- * @param children - React subtree to wrap
207
- * @sideEffects
208
- * - Reads/writes `localStorage` key `spine_user` for persistence
209
- * - Calls `setAccountId` (mutates `src/lib/api.ts` module state)
210
- * - Subscribes to `supabase.auth.onAuthStateChange`; unsubscribes on unmount
211
- * - Registers 401 interceptor via `onUnauthorized`
212
- * @calledBy src/main.tsx (app root)
213
- *
214
- * @example
215
- * ```tsx
216
- * <AuthProvider>
217
- * <App />
218
- * </AuthProvider>
219
- * ```
220
- */
253
+ // CIL[END chunk_id="AuthContext_fetchusercontext_1783749485"]
254
+ // CIL[BEGIN chunk_id="AuthContext_authprovider_1783749485" type="function" identity="AuthProvider" parent="none"]
255
+ // CIL[DOC-MACRO purpose="Manage authentication state and lifecycle"]
256
+ // CIL[DOC-RESPONSIBILITY responsibility="Handle auth flow, storage sync, and session management"]
257
+ // CIL[DOC-CONTEXT module="AuthContext" layer="frontend-provider" related_files="[]"]
258
+ // CIL[DOC-CONTRACT inputs="none" outputs="Provider component" errors="auth errors" side_effects="localStorage, API calls, Supabase auth"]
259
+ // CIL[DOC-MICRO logic_summary="Complex auth provider with storage sync, race guards, and cross-tab support" notable_decisions="[]"]
260
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
261
+ // CIL[DOC-STABILITY stability="stable"]
262
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-provider. Direct callers: 0. Direct calls: 0. Related files: none."]
263
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
264
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
265
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
266
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
267
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
221
268
  export function AuthProvider({ children }: AuthProviderProps) {
222
269
  const storedUser = readStoredUser()
223
270
  const [user, setUser] = useState<User | null>(storedUser)
224
- // If we have a stored user, start loading to verify context before rendering routes
225
271
  const [isLoading, setIsLoading] = useState(true)
226
272
  const isLoggingInRef = useRef(false)
227
273
  const userRef = useRef<User | null>(storedUser)
228
274
 
229
- // Keep ref in sync with state so async callbacks see current value
230
275
  useEffect(() => { userRef.current = user }, [user])
231
276
 
232
277
  const setUserWithStorage = useCallback((u: User | null) => {
@@ -245,8 +290,6 @@ export function AuthProvider({ children }: AuthProviderProps) {
245
290
  setAccountId(ctx.account_id)
246
291
  }, [setUserWithStorage])
247
292
 
248
- // ── Login ──────────────────────────────────────────────────────────────────
249
-
250
293
  const login = useCallback(async (email: string, password: string) => {
251
294
  isLoggingInRef.current = true
252
295
 
@@ -256,76 +299,69 @@ export function AuthProvider({ children }: AuthProviderProps) {
256
299
  if (error) throw error
257
300
 
258
301
  if (data.user) {
259
- // Brief pause for session to establish
260
302
  await new Promise(resolve => setTimeout(resolve, 100))
261
303
 
262
304
  const userContext = await fetchUserContext()
263
305
  if (userContext) {
264
306
  applyUserContext(userContext)
307
+ return userContext
265
308
  } else {
266
- // Fallback to minimal user object
267
- applyUserContext({
309
+ const fallback: User = {
268
310
  id: data.user.id,
269
311
  email: data.user.email || '',
270
312
  full_name: data.user.user_metadata?.full_name || data.user.email || 'User',
271
313
  account_id: '',
272
314
  roles: [],
273
315
  permissions: [],
274
- })
316
+ }
317
+ applyUserContext(fallback)
318
+ return fallback
275
319
  }
276
320
  }
321
+ return null
277
322
  } finally {
278
323
  isLoggingInRef.current = false
279
324
  }
280
325
  }, [applyUserContext])
281
326
 
282
- // ── Logout ─────────────────────────────────────────────────────────────────
283
-
284
327
  const logout = useCallback(async () => {
285
328
  await supabase.auth.signOut()
286
329
  clearUser()
287
330
  }, [clearUser])
288
331
 
289
- // ── Refresh ────────────────────────────────────────────────────────────────
290
-
291
332
  const refreshUser = useCallback(async () => {
292
333
  const { data: { session } } = await getSessionWithTimeout()
293
334
 
294
335
  if (!session?.user) {
295
336
  clearUser()
296
- return
337
+ return null
297
338
  }
298
339
 
299
340
  const userContext = await fetchUserContext()
300
341
  if (userContext) {
301
342
  applyUserContext(userContext)
343
+ return userContext
302
344
  } else {
303
345
  clearUser()
346
+ return null
304
347
  }
305
348
  }, [applyUserContext, clearUser])
306
349
 
307
- // ── Register 401 interceptor ───────────────────────────────────────────────
308
-
309
350
  useEffect(() => {
310
351
  const unregister = onUnauthorized(() => {
311
- // Session expired — sign out cleanly
312
352
  supabase.auth.signOut().then(() => clearUser())
313
353
  })
314
354
  return unregister
315
355
  }, [clearUser])
316
356
 
317
- // ── Listen for storage events from other tabs ──────────────────────────────
318
-
319
357
  useEffect(() => {
320
358
  const handleStorage = (e: StorageEvent) => {
321
359
  if (e.key !== STORAGE_KEY) return
322
360
  if (e.newValue === null) {
323
- // Other tab logged out
324
361
  setUser(null)
325
362
  userRef.current = null
326
363
  setAccountId(null)
327
364
  } else {
328
- // Other tab logged in or refreshed
329
365
  const parsed = readStoredUser()
330
366
  if (parsed) {
331
367
  setUser(parsed)
@@ -338,8 +374,6 @@ export function AuthProvider({ children }: AuthProviderProps) {
338
374
  return () => window.removeEventListener('storage', handleStorage)
339
375
  }, [])
340
376
 
341
- // ── Initial auth check + subscription ──────────────────────────────────────
342
-
343
377
  useEffect(() => {
344
378
  let cancelled = false
345
379
 
@@ -358,14 +392,12 @@ export function AuthProvider({ children }: AuthProviderProps) {
358
392
  if (userContext) {
359
393
  applyUserContext(userContext)
360
394
  } else if (userRef.current) {
361
- // Network issue but we have a stored user — keep it (offline resilience)
362
395
  setAccountId(userRef.current.account_id)
363
396
  } else {
364
397
  clearUser()
365
398
  }
366
399
  } catch (error) {
367
400
  if (!cancelled) {
368
- // Network down with stored user — keep going (offline resilience)
369
401
  if (userRef.current) {
370
402
  setAccountId(userRef.current.account_id)
371
403
  } else {
@@ -379,19 +411,14 @@ export function AuthProvider({ children }: AuthProviderProps) {
379
411
 
380
412
  checkAuth()
381
413
 
382
- // Listen for auth changes — async work is in the callback body, not
383
- // inside a state updater (React anti-pattern)
384
414
  const { data: { subscription } } = supabase.auth.onAuthStateChange(
385
415
  async (event, session) => {
386
416
  if (cancelled) return
387
417
 
388
- // Don't refresh during login to avoid conflicts
389
418
  if (isLoggingInRef.current) return
390
419
 
391
420
  if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED') {
392
421
  if (!session?.user) return
393
- // Skip re-fetch if user is already loaded — prevents blocking
394
- // page fetches when Supabase re-fires SIGNED_IN on browser focus
395
422
  if (userRef.current) return
396
423
 
397
424
  const userContext = await fetchUserContext()
@@ -422,3 +449,4 @@ export function AuthProvider({ children }: AuthProviderProps) {
422
449
  </AuthContext.Provider>
423
450
  )
424
451
  }
452
+ // CIL[END chunk_id="AuthContext_authprovider_1783749485"]
@@ -1,7 +1,52 @@
1
- import * as React from "react"
2
1
 
3
- const MOBILE_BREAKPOINT = 768
4
2
 
3
+ // CIL[BEGIN chunk_id="use-mobile_module_header_1783740744" type="module_header" identity="imports" parent="none"]
4
+ // CIL[DOC-MACRO purpose="Import React library for mobile detection functionality"]
5
+ // CIL[DOC-RESPONSIBILITY responsibility="Provide core React dependency for state management"]
6
+ // CIL[DOC-CONTEXT module="use-mobile" layer="frontend-hook" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/schema-utils.ts\",\"\\\"]"]
7
+ // CIL[DOC-CONTRACT inputs="none" outputs="React library" errors="none" side_effects="Module imports"]
8
+ // CIL[DOC-MICRO logic_summary="Imports React as namespace for hooks and component functionality" notable_decisions="[]"]
9
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
10
+ // CIL[DOC-STABILITY stability="stable"]
11
+ // CIL[DOC-AUDIENCE audience="developer"]
12
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, .framework/functions/_shared/schema-utils.ts, \."]
13
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
14
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
15
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
16
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
17
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
18
+ import * as React from "react"
19
+ // CIL[END chunk_id="use-mobile_module_header_1783740744"]
20
+ // CIL[BEGIN chunk_id="use-mobile_constants_1783740744" type="constant" identity="MOBILE_BREAKPOINT" parent="none"]
21
+ // CIL[DOC-MACRO purpose="Define mobile screen breakpoint for responsive detection"]
22
+ // CIL[DOC-RESPONSIBILITY responsibility="Own the mobile breakpoint threshold value"]
23
+ // CIL[DOC-CONTEXT module="use-mobile" layer="frontend-hook" related_files="[\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/schema-utils.ts\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
24
+ // CIL[DOC-CONTRACT inputs="none" outputs="constant value" errors="none" side_effects="Constant definition"]
25
+ // CIL[DOC-MICRO logic_summary="Sets mobile breakpoint at 768px for tablet/mobile boundary" notable_decisions="[]"]
26
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
27
+ // CIL[DOC-STABILITY stability="stable"]
28
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 0. Direct calls: 0. Related files: .framework/functions/_shared/principal.ts, .framework/functions/_shared/schema-utils.ts, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/pages/admin/IntegrationsPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
29
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
30
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
31
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
32
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
33
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
34
+ const MOBILE_BREAKPOINT = 768
35
+ // CIL[END chunk_id="use-mobile_constants_1783740744"]
36
+ // CIL[BEGIN chunk_id="use-mobile_useismobile_1783740744" type="function" identity="useIsMobile" parent="none"]
37
+ // CIL[DOC-MACRO purpose="Detect mobile screen size with responsive breakpoint tracking"]
38
+ // CIL[DOC-RESPONSIBILITY responsibility="Manage mobile detection state and media query listeners"]
39
+ // CIL[DOC-CONTEXT module="use-mobile" layer="frontend-hook" related_files="[\".framework/functions/_shared/schema-utils.ts\",\".framework/src/components/ui/dialog.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/db.ts\",\".framework/src/components/ui/table-primitives.tsx\",\"\\\"]"]
40
+ // CIL[DOC-CONTRACT inputs="none" outputs="boolean mobile flag" errors="none" side_effects="MediaQuery event listeners"]
41
+ // CIL[DOC-MICRO logic_summary="Uses matchMedia API to track screen width changes and update mobile state" notable_decisions="[]"]
42
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
43
+ // CIL[DOC-STABILITY stability="stable"]
44
+ // CIL[DOC-VECTOR type="context" content="Layer: frontend-hook. Direct callers: 1. Direct calls: 0. Related files: .framework/functions/_shared/schema-utils.ts, .framework/src/components/ui/dialog.tsx, .framework/functions/_shared/principal.ts, .framework/functions/_shared/db.ts, .framework/src/components/ui/table-primitives.tsx, \."]
45
+ // CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 1. Total affected: 1."]
46
+ // CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
47
+ // CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
48
+ // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
49
+ // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
5
50
  export function useIsMobile() {
6
51
  const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
7
52
 
@@ -17,3 +62,4 @@ export function useIsMobile() {
17
62
 
18
63
  return !!isMobile
19
64
  }
65
+ // CIL[END chunk_id="use-mobile_useismobile_1783740744"]