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,55 +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 = 5 * 60 * 1000 // 5 minutes
46
-
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"]
47
50
  interface StoredUserEnvelope {
48
51
  version: number
49
52
  timestamp: number
50
53
  user: User
51
54
  }
52
-
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"]
53
70
  function readStoredUser(): User | null {
54
71
  try {
55
72
  const raw = localStorage.getItem(STORAGE_KEY)
@@ -62,7 +79,21 @@ function readStoredUser(): User | null {
62
79
  return null
63
80
  }
64
81
  }
65
-
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"]
66
97
  function writeStoredUser(user: User | null) {
67
98
  try {
68
99
  if (user) {
@@ -76,41 +107,74 @@ function writeStoredUser(user: User | null) {
76
107
  localStorage.removeItem(STORAGE_KEY)
77
108
  }
78
109
  } catch {
79
- // Storage unavailable (private browsing, quota exceeded)
80
110
  }
81
111
  }
82
-
83
- // ─── TYPES ───────────────────────────────────────────────────────────────────
84
-
85
- /**
86
- * Shape of the value provided by `AuthContext`.
87
- *
88
- * @prop user - Resolved server-side user context, or null if unauthenticated
89
- * @prop isLoading - True during initial `checkAuth` (prevents premature redirects)
90
- * @prop login - Sign in with email/password and hydrate user context
91
- * @prop logout - Sign out and clear user + account scope
92
- * @prop refreshUser - Re-fetch user context from the server (e.g. after role change)
93
- */
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"]
127
+ async function getSessionWithTimeout(): Promise<{ data: { session: any | null } }> {
128
+ try {
129
+ return await Promise.race([
130
+ supabase.auth.getSession(),
131
+ new Promise<{ data: { session: null } }>((resolve) =>
132
+ setTimeout(() => resolve({ data: { session: null } }), SESSION_TIMEOUT_MS)
133
+ )
134
+ ])
135
+ } catch (error) {
136
+ return { data: { session: null } }
137
+ }
138
+ }
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"]
94
154
  interface AuthContextType {
95
155
  user: User | null
96
156
  isLoading: boolean
97
- login: (email: string, password: string) => Promise<void>
157
+ login: (email: string, password: string) => Promise<User | null>
98
158
  logout: () => Promise<void>
99
- refreshUser: () => Promise<void>
159
+ refreshUser: () => Promise<User | null>
100
160
  }
101
161
 
102
162
  const AuthContext = createContext<AuthContextType | undefined>(undefined)
103
-
104
- // ─── useAuth ─────────────────────────────────────────────────────────────────
105
-
106
- /**
107
- * Hook to access the authentication context. Must be called inside `AuthProvider`.
108
- *
109
- * @returns `AuthContextType` — user, isLoading, login, logout, refreshUser
110
- * @throws Error('useAuth must be used within an AuthProvider') if called outside provider
111
- * @sideEffects none (read-only context access)
112
- * @calledBy every component that needs the current user or auth actions
113
- */
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"]
114
178
  export function useAuth() {
115
179
  const context = useContext(AuthContext)
116
180
  if (context === undefined) {
@@ -118,44 +182,54 @@ export function useAuth() {
118
182
  }
119
183
  return context
120
184
  }
121
-
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"]
122
200
  interface AuthProviderProps {
123
201
  children: React.ReactNode
124
202
  }
125
-
126
- // ─── INTERNAL HELPERS ───────────────────────────────────────────────────────────
127
-
128
- /**
129
- * Fetches the server-side user context from `GET /api/auth` with retry.
130
- * Returns null on any persistent error rather than throwing, so callers
131
- * can apply fallback logic without try/catch.
132
- *
133
- * Retries up to `maxRetries` times on network errors and 5xx responses.
134
- * Does NOT retry 401/403 (auth failures are not transient).
135
- *
136
- * @returns Resolved `User` object or null on failure
137
- * @throws never (all errors are caught internally)
138
- * @sideEffects Network request via apiFetch; console logging
139
- * @calledBy AuthProvider.login, AuthProvider.refreshUser, AuthProvider.checkAuth
140
- */
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"]
141
218
  async function fetchUserContext(maxRetries = 2): Promise<User | null> {
142
219
  let lastError: unknown = null
143
220
 
144
221
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
145
222
  try {
146
223
  if (attempt > 0) {
147
- // Exponential backoff: 200ms, 800ms, 3200ms
148
224
  await new Promise(r => setTimeout(r, 200 * Math.pow(4, attempt - 1)))
149
225
  }
150
226
 
151
227
  const response = await apiFetch('/api/auth', { method: 'GET' })
152
228
 
153
- // Don't retry auth failures
154
229
  if (response.status === 401 || response.status === 403) {
155
230
  return null
156
231
  }
157
232
 
158
- // Retry on 5xx
159
233
  if (response.status >= 500) {
160
234
  lastError = new Error(`Server error: ${response.status}`)
161
235
  continue
@@ -167,51 +241,37 @@ async function fetchUserContext(maxRetries = 2): Promise<User | null> {
167
241
 
168
242
  const data = await response.json()
169
243
  if (data.error || !data.data) return null
170
-
171
244
  return data.data
172
245
  } catch (error) {
173
246
  lastError = error
174
- // Network error (TypeError: Failed to fetch) — retry
175
247
  if (error instanceof TypeError) continue
176
- // Other errors — don't retry
177
248
  return null
178
249
  }
179
250
  }
180
-
181
- console.error('fetchUserContext failed after retries:', lastError)
182
251
  return null
183
252
  }
184
-
185
- // ─── AuthProvider ──────────────────────────────────────────────────────────────
186
-
187
- /**
188
- * Root authentication provider. Wrap the entire application with this component
189
- * to enable `useAuth()` in any descendant.
190
- *
191
- * @param children - React subtree to wrap
192
- * @sideEffects
193
- * - Reads/writes `localStorage` key `spine_user` for persistence
194
- * - Calls `setAccountId` (mutates `src/lib/api.ts` module state)
195
- * - Subscribes to `supabase.auth.onAuthStateChange`; unsubscribes on unmount
196
- * - Registers 401 interceptor via `onUnauthorized`
197
- * @calledBy src/main.tsx (app root)
198
- *
199
- * @example
200
- * ```tsx
201
- * <AuthProvider>
202
- * <App />
203
- * </AuthProvider>
204
- * ```
205
- */
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"]
206
268
  export function AuthProvider({ children }: AuthProviderProps) {
207
269
  const storedUser = readStoredUser()
208
270
  const [user, setUser] = useState<User | null>(storedUser)
209
- // If we have a stored user, start loading to verify context before rendering routes
210
271
  const [isLoading, setIsLoading] = useState(true)
211
272
  const isLoggingInRef = useRef(false)
212
273
  const userRef = useRef<User | null>(storedUser)
213
274
 
214
- // Keep ref in sync with state so async callbacks see current value
215
275
  useEffect(() => { userRef.current = user }, [user])
216
276
 
217
277
  const setUserWithStorage = useCallback((u: User | null) => {
@@ -230,8 +290,6 @@ export function AuthProvider({ children }: AuthProviderProps) {
230
290
  setAccountId(ctx.account_id)
231
291
  }, [setUserWithStorage])
232
292
 
233
- // ── Login ──────────────────────────────────────────────────────────────────
234
-
235
293
  const login = useCallback(async (email: string, password: string) => {
236
294
  isLoggingInRef.current = true
237
295
 
@@ -241,76 +299,69 @@ export function AuthProvider({ children }: AuthProviderProps) {
241
299
  if (error) throw error
242
300
 
243
301
  if (data.user) {
244
- // Brief pause for session to establish
245
302
  await new Promise(resolve => setTimeout(resolve, 100))
246
303
 
247
304
  const userContext = await fetchUserContext()
248
305
  if (userContext) {
249
306
  applyUserContext(userContext)
307
+ return userContext
250
308
  } else {
251
- // Fallback to minimal user object
252
- applyUserContext({
309
+ const fallback: User = {
253
310
  id: data.user.id,
254
311
  email: data.user.email || '',
255
312
  full_name: data.user.user_metadata?.full_name || data.user.email || 'User',
256
313
  account_id: '',
257
314
  roles: [],
258
315
  permissions: [],
259
- })
316
+ }
317
+ applyUserContext(fallback)
318
+ return fallback
260
319
  }
261
320
  }
321
+ return null
262
322
  } finally {
263
323
  isLoggingInRef.current = false
264
324
  }
265
325
  }, [applyUserContext])
266
326
 
267
- // ── Logout ─────────────────────────────────────────────────────────────────
268
-
269
327
  const logout = useCallback(async () => {
270
328
  await supabase.auth.signOut()
271
329
  clearUser()
272
330
  }, [clearUser])
273
331
 
274
- // ── Refresh ────────────────────────────────────────────────────────────────
275
-
276
332
  const refreshUser = useCallback(async () => {
277
- const { data: { session } } = await supabase.auth.getSession()
333
+ const { data: { session } } = await getSessionWithTimeout()
278
334
 
279
335
  if (!session?.user) {
280
336
  clearUser()
281
- return
337
+ return null
282
338
  }
283
339
 
284
340
  const userContext = await fetchUserContext()
285
341
  if (userContext) {
286
342
  applyUserContext(userContext)
343
+ return userContext
287
344
  } else {
288
345
  clearUser()
346
+ return null
289
347
  }
290
348
  }, [applyUserContext, clearUser])
291
349
 
292
- // ── Register 401 interceptor ───────────────────────────────────────────────
293
-
294
350
  useEffect(() => {
295
351
  const unregister = onUnauthorized(() => {
296
- // Session expired — sign out cleanly
297
352
  supabase.auth.signOut().then(() => clearUser())
298
353
  })
299
354
  return unregister
300
355
  }, [clearUser])
301
356
 
302
- // ── Listen for storage events from other tabs ──────────────────────────────
303
-
304
357
  useEffect(() => {
305
358
  const handleStorage = (e: StorageEvent) => {
306
359
  if (e.key !== STORAGE_KEY) return
307
360
  if (e.newValue === null) {
308
- // Other tab logged out
309
361
  setUser(null)
310
362
  userRef.current = null
311
363
  setAccountId(null)
312
364
  } else {
313
- // Other tab logged in or refreshed
314
365
  const parsed = readStoredUser()
315
366
  if (parsed) {
316
367
  setUser(parsed)
@@ -323,14 +374,12 @@ export function AuthProvider({ children }: AuthProviderProps) {
323
374
  return () => window.removeEventListener('storage', handleStorage)
324
375
  }, [])
325
376
 
326
- // ── Initial auth check + subscription ──────────────────────────────────────
327
-
328
377
  useEffect(() => {
329
378
  let cancelled = false
330
379
 
331
380
  const checkAuth = async () => {
332
381
  try {
333
- const { data: { session } } = await supabase.auth.getSession()
382
+ const { data: { session } } = await getSessionWithTimeout()
334
383
 
335
384
  if (!session?.user) {
336
385
  if (!cancelled) clearUser()
@@ -343,14 +392,12 @@ export function AuthProvider({ children }: AuthProviderProps) {
343
392
  if (userContext) {
344
393
  applyUserContext(userContext)
345
394
  } else if (userRef.current) {
346
- // Network issue but we have a stored user — keep it (offline resilience)
347
395
  setAccountId(userRef.current.account_id)
348
396
  } else {
349
397
  clearUser()
350
398
  }
351
399
  } catch (error) {
352
400
  if (!cancelled) {
353
- // Network down with stored user — keep going (offline resilience)
354
401
  if (userRef.current) {
355
402
  setAccountId(userRef.current.account_id)
356
403
  } else {
@@ -364,19 +411,14 @@ export function AuthProvider({ children }: AuthProviderProps) {
364
411
 
365
412
  checkAuth()
366
413
 
367
- // Listen for auth changes — async work is in the callback body, not
368
- // inside a state updater (React anti-pattern)
369
414
  const { data: { subscription } } = supabase.auth.onAuthStateChange(
370
415
  async (event, session) => {
371
416
  if (cancelled) return
372
417
 
373
- // Don't refresh during login to avoid conflicts
374
418
  if (isLoggingInRef.current) return
375
419
 
376
420
  if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED') {
377
421
  if (!session?.user) return
378
- // Skip re-fetch if user is already loaded — prevents blocking
379
- // page fetches when Supabase re-fires SIGNED_IN on browser focus
380
422
  if (userRef.current) return
381
423
 
382
424
  const userContext = await fetchUserContext()
@@ -407,3 +449,4 @@ export function AuthProvider({ children }: AuthProviderProps) {
407
449
  </AuthContext.Provider>
408
450
  )
409
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"]