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.
- package/.framework/cli/commands/agents.ts +35 -37
- package/.framework/cli/commands/auth.ts +35 -34
- package/.framework/cli/commands/create-app.ts +104 -40
- package/.framework/cli/commands/dev.ts +104 -69
- package/.framework/cli/commands/doctor.ts +169 -97
- package/.framework/cli/commands/generate.ts +82 -160
- package/.framework/cli/commands/init.ts +72 -34
- package/.framework/cli/commands/install-app.ts +260 -125
- package/.framework/cli/commands/items.ts +33 -44
- package/.framework/cli/commands/migrate.ts +122 -40
- package/.framework/cli/commands/migrations.ts +33 -40
- package/.framework/cli/commands/pipelines.ts +31 -39
- package/.framework/cli/commands/status.ts +47 -23
- package/.framework/cli/commands/system.ts +47 -37
- package/.framework/cli/commands/test.ts +112 -68
- package/.framework/cli/commands/validate-app.ts +215 -121
- package/.framework/cli/context.ts +112 -130
- package/.framework/cli/env-loader.ts +47 -18
- package/.framework/cli/index.ts +81 -42
- package/.framework/docs/runtime-types.md +1024 -0
- package/.framework/functions/_shared/agent-runner.ts +1296 -961
- package/.framework/functions/_shared/app-manifest.ts +82 -68
- package/.framework/functions/_shared/audit.ts +135 -83
- package/.framework/functions/_shared/{cil-state.ts → cil.ts} +147 -54
- package/.framework/functions/_shared/db.ts +80 -126
- package/.framework/functions/_shared/hash-api-key.ts +63 -0
- package/.framework/functions/_shared/index.ts +222 -347
- package/.framework/functions/_shared/kb.ts +319 -0
- package/.framework/functions/_shared/llm.ts +92 -0
- package/.framework/functions/_shared/logging.ts +288 -0
- package/.framework/functions/_shared/middleware.ts +329 -365
- package/.framework/functions/_shared/outcomes.ts +36 -0
- package/.framework/functions/_shared/permissions.ts +359 -643
- package/.framework/functions/_shared/pipeline-runner.ts +243 -316
- package/.framework/functions/_shared/principal.ts +376 -468
- package/.framework/functions/_shared/resolve-credentials.ts +102 -0
- package/.framework/functions/_shared/resolve-ids.ts +162 -14
- package/.framework/functions/_shared/retry-deliveries.ts +104 -0
- package/.framework/functions/_shared/schema-utils.ts +611 -373
- package/.framework/functions/_shared/testing.ts +207 -137
- package/.framework/functions/_shared/tracing.ts +276 -0
- package/.framework/functions/_shared/trigger-engine.ts +159 -211
- package/.framework/functions/_shared/webhook-registration.ts +95 -81
- package/.framework/functions/_shared/webhook-registry.ts +153 -75
- package/.framework/functions/account-nodes.ts +31 -53
- package/.framework/functions/adapters/generic-webhook-inbound.ts +56 -0
- package/.framework/functions/adapters/generic-webhook-outbound.ts +43 -0
- package/.framework/functions/adapters/openai-outbound.ts +40 -0
- package/.framework/functions/admin-data.ts +687 -533
- package/.framework/functions/admin-funnel.ts +31 -20
- package/.framework/functions/admin-install-funnel.ts +47 -28
- package/.framework/functions/admin-signals.ts +47 -29
- package/.framework/functions/ai-agents.ts +122 -147
- package/.framework/functions/ai-interactions.ts +180 -90
- package/.framework/functions/api-keys.ts +250 -192
- package/.framework/functions/apps.ts +203 -197
- package/.framework/functions/auth.ts +98 -91
- package/.framework/functions/cil-agent-ingest.ts +773 -0
- package/.framework/functions/cil-agent.ts +592 -0
- package/.framework/functions/cil-callmap.ts +1227 -0
- package/.framework/functions/cil-config.ts +583 -0
- package/.framework/functions/cil-context.ts +445 -0
- package/.framework/functions/cil-doc.ts +1752 -0
- package/.framework/functions/cil-embeddings.ts +1202 -0
- package/.framework/functions/cil-graph.ts +585 -0
- package/.framework/functions/cil-ingest.ts +2416 -0
- package/.framework/functions/cil-pipeline.ts +318 -0
- package/.framework/functions/cil-project.ts +499 -0
- package/.framework/functions/cil-validate.ts +469 -0
- package/.framework/functions/debug-auth.ts +73 -53
- package/.framework/functions/deliveries.ts +117 -0
- package/.framework/functions/embeddings.ts +528 -516
- package/.framework/functions/eval-harness.ts +158 -106
- package/.framework/functions/integration-outbound.ts +311 -0
- package/.framework/functions/integration-routes.ts +240 -466
- package/.framework/functions/integrations.ts +132 -140
- package/.framework/functions/invites.ts +401 -201
- package/.framework/functions/item-progress.ts +113 -53
- package/.framework/functions/kb.ts +28 -0
- package/.framework/functions/logs.ts +239 -222
- package/.framework/functions/observability.ts +308 -259
- package/.framework/functions/pipeline-executions.ts +179 -235
- package/.framework/functions/pipelines.ts +163 -205
- package/.framework/functions/prompt-configs.ts +109 -156
- package/.framework/functions/roles.ts +97 -147
- package/.framework/functions/system-cron.ts +132 -218
- package/.framework/functions/system.ts +112 -52
- package/.framework/functions/tests.ts +32 -28
- package/.framework/functions/timers.ts +162 -210
- package/.framework/functions/triggers.ts +282 -346
- package/.framework/functions/types.ts +283 -400
- package/.framework/migrations/001_core_schema.sql +630 -0
- package/.framework/migrations/002_core_rls_and_functions.sql +532 -0
- package/.framework/migrations/{003_system_data.sql → 003_core_system_data.sql} +26 -153
- package/.framework/migrations/004_core_rpc_and_broker.sql +421 -0
- package/.framework/migrations/005_core_observability.sql +598 -0
- package/.framework/migrations/006_security_hardening_rls.sql +97 -0
- package/.framework/migrations/007_kb_article_list.sql +237 -0
- package/.framework/migrations/008_items_target.sql +8 -0
- package/.framework/migrations/009_roles_slug_unique.sql +11 -0
- package/.framework/public/spine.config.json +91 -0
- package/.framework/scripts/app-install-cli.ts +112 -98
- package/.framework/src/App.tsx +67 -20
- package/.framework/src/apps/admin/index.tsx +97 -27
- package/.framework/src/components/AppWrapper.tsx +50 -11
- package/.framework/src/components/CustomAppLoader.tsx +131 -22
- package/.framework/src/components/admin/AdminListPage.tsx +75 -8
- package/.framework/src/components/admin/AdminSidebar.tsx +148 -36
- package/.framework/src/components/admin/AdminStatsCard.tsx +48 -29
- package/.framework/src/components/admin/PageInstructions.tsx +49 -0
- package/.framework/src/components/admin/SortableTableHeader.tsx +49 -2
- package/.framework/src/components/app-shell/GenericAppShell.tsx +69 -11
- package/.framework/src/components/app-shell/GenericDetailPage.tsx +55 -10
- package/.framework/src/components/app-shell/GenericListPage.tsx +76 -9
- package/.framework/src/components/app-sidebar.tsx +50 -3
- package/.framework/src/components/auth/ProtectedRoute.tsx +53 -45
- package/.framework/src/components/kb/KBArticleEditor.tsx +409 -0
- package/.framework/src/components/kb/KBArticleList.tsx +557 -0
- package/.framework/src/components/layout/AppShell.tsx +54 -16
- package/.framework/src/components/layout/Header.tsx +50 -38
- package/.framework/src/components/layout/Layout.tsx +48 -32
- package/.framework/src/components/layout/Sidebar.tsx +167 -16
- package/.framework/src/components/runtime/DataDetailHeader.tsx +33 -1
- package/.framework/src/components/runtime/DataDetailPage.tsx +289 -4
- package/.framework/src/components/runtime/DataFilters.tsx +78 -1
- package/.framework/src/components/runtime/DataHeader.tsx +32 -29
- package/.framework/src/components/runtime/DataListPage.tsx +161 -2
- package/.framework/src/components/runtime/DataStats.tsx +48 -1
- package/.framework/src/components/runtime/DataTable.tsx +153 -1
- package/.framework/src/components/runtime/SchemaDetailForm.tsx +77 -46
- package/.framework/src/components/runtime/index.ts +16 -9
- package/.framework/src/components/search-form.tsx +33 -1
- package/.framework/src/components/shared/AgentView.tsx +48 -51
- package/.framework/src/components/shared/FieldRenderer.tsx +84 -67
- package/.framework/src/components/shared/InviteManager.tsx +113 -52
- package/.framework/src/components/shared/MemberList.tsx +182 -0
- package/.framework/src/components/shared/SchemaFields.tsx +96 -78
- package/.framework/src/components/ui/DataTable.tsx +86 -56
- package/.framework/src/components/ui/Form.tsx +188 -109
- package/.framework/src/components/ui/ItemCard.tsx +86 -58
- package/.framework/src/components/ui/ItemListView.tsx +88 -61
- package/.framework/src/components/ui/LoadingSpinner.tsx +52 -27
- package/.framework/src/components/ui/Modal.tsx +81 -4
- package/.framework/src/components/ui/RichTextEditor.tsx +101 -9
- package/.framework/src/components/ui/accordion.tsx +97 -5
- package/.framework/src/components/ui/alert-dialog.tsx +225 -13
- package/.framework/src/components/ui/alert.tsx +113 -6
- package/.framework/src/components/ui/aspect-ratio.tsx +49 -2
- package/.framework/src/components/ui/avatar.tsx +129 -7
- package/.framework/src/components/ui/badge.tsx +65 -3
- package/.framework/src/components/ui/breadcrumb.tsx +145 -8
- package/.framework/src/components/ui/button-group.tsx +81 -4
- package/.framework/src/components/ui/button.tsx +49 -2
- package/.framework/src/components/ui/calendar.tsx +65 -3
- package/.framework/src/components/ui/card.tsx +145 -8
- package/.framework/src/components/ui/carousel.tsx +129 -7
- package/.framework/src/components/ui/chart.tsx +161 -10
- package/.framework/src/components/ui/checkbox.tsx +49 -2
- package/.framework/src/components/ui/collapsible.tsx +81 -5
- package/.framework/src/components/ui/combobox.tsx +305 -20
- package/.framework/src/components/ui/command.tsx +177 -11
- package/.framework/src/components/ui/context-menu.tsx +273 -17
- package/.framework/src/components/ui/dialog.tsx +209 -27
- package/.framework/src/components/ui/direction.tsx +64 -4
- package/.framework/src/components/ui/drawer.tsx +193 -12
- package/.framework/src/components/ui/dropdown-menu.tsx +273 -18
- package/.framework/src/components/ui/empty.tsx +145 -9
- package/.framework/src/components/ui/field.tsx +209 -14
- package/.framework/src/components/ui/hover-card.tsx +81 -4
- package/.framework/src/components/ui/input-group.tsx +162 -10
- package/.framework/src/components/ui/input-otp.tsx +98 -5
- package/.framework/src/components/ui/input.tsx +49 -2
- package/.framework/src/components/ui/item.tsx +225 -13
- package/.framework/src/components/ui/kbd.tsx +65 -3
- package/.framework/src/components/ui/label.tsx +49 -2
- package/.framework/src/components/ui/menubar.tsx +289 -17
- package/.framework/src/components/ui/native-select.tsx +97 -5
- package/.framework/src/components/ui/navigation-menu.tsx +177 -10
- package/.framework/src/components/ui/pagination.tsx +161 -9
- package/.framework/src/components/ui/popover.tsx +145 -8
- package/.framework/src/components/ui/progress.tsx +49 -2
- package/.framework/src/components/ui/radio-group.tsx +65 -3
- package/.framework/src/components/ui/resizable.tsx +82 -4
- package/.framework/src/components/ui/scroll-area.tsx +65 -3
- package/.framework/src/components/ui/select.tsx +193 -11
- package/.framework/src/components/ui/separator.tsx +49 -2
- package/.framework/src/components/ui/sheet.tsx +193 -11
- package/.framework/src/components/ui/sidebar.tsx +481 -38
- package/.framework/src/components/ui/skeleton.tsx +49 -2
- package/.framework/src/components/ui/slider.tsx +49 -2
- package/.framework/src/components/ui/sonner.tsx +49 -2
- package/.framework/src/components/ui/spinner.tsx +49 -2
- package/.framework/src/components/ui/switch.tsx +49 -2
- package/.framework/src/components/ui/table-primitives.tsx +160 -33
- package/.framework/src/components/ui/table.tsx +161 -9
- package/.framework/src/components/ui/tabs.tsx +113 -6
- package/.framework/src/components/ui/textarea.tsx +49 -2
- package/.framework/src/components/ui/toggle-group.tsx +81 -4
- package/.framework/src/components/ui/toggle.tsx +65 -3
- package/.framework/src/components/ui/tooltip.tsx +97 -5
- package/.framework/src/contexts/AppContext.tsx +129 -45
- package/.framework/src/contexts/AuthContext.tsx +173 -145
- package/.framework/src/hooks/use-mobile.ts +48 -2
- package/.framework/src/hooks/useApi.ts +208 -159
- package/.framework/src/hooks/useAppPath.ts +32 -23
- package/.framework/src/hooks/useApps.ts +51 -20
- package/.framework/src/hooks/useEntityList.ts +32 -78
- package/.framework/src/hooks/useEntityRecord.ts +35 -96
- package/.framework/src/hooks/useForm.ts +32 -92
- package/.framework/src/hooks/useListSchema.ts +49 -78
- package/.framework/src/hooks/useSchemaRecord.ts +114 -105
- package/.framework/src/lib/api.ts +192 -115
- package/.framework/src/lib/supabase.ts +98 -64
- package/.framework/src/lib/utils.ts +287 -151
- package/.framework/src/main.tsx +49 -3
- package/.framework/src/pages/DashboardPage.tsx +52 -29
- package/.framework/src/pages/NotFoundPage.tsx +32 -10
- package/.framework/src/pages/SetupPage.tsx +32 -12
- package/.framework/src/pages/admin/AIAgentDetailPage.tsx +119 -10
- package/.framework/src/pages/admin/AIAgentsPage.tsx +48 -19
- package/.framework/src/pages/admin/APIKeyDetailPage.tsx +187 -17
- package/.framework/src/pages/admin/APIKeysPage.tsx +98 -22
- package/.framework/src/pages/admin/AlertsConfigPage.tsx +113 -26
- package/.framework/src/pages/admin/AppDetailPage.tsx +125 -8
- package/.framework/src/pages/admin/AppsPage.tsx +49 -2
- package/.framework/src/pages/admin/DeliveriesPage.tsx +196 -0
- package/.framework/src/pages/admin/DesignedPage.tsx +32 -18
- package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +215 -484
- package/.framework/src/pages/admin/EmbeddingsPage.tsx +116 -319
- package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -16
- package/.framework/src/pages/admin/IntegrationDetailPage.tsx +183 -26
- package/.framework/src/pages/admin/IntegrationsPage.tsx +48 -19
- package/.framework/src/pages/admin/InvitesPage.tsx +48 -14
- package/.framework/src/pages/admin/LogsPage.tsx +422 -75
- package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/ObservabilityDashboard.tsx +113 -24
- package/.framework/src/pages/admin/PipelineDetailPage.tsx +206 -34
- package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +50 -17
- package/.framework/src/pages/admin/PipelinesPage.tsx +160 -21
- package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +378 -88
- package/.framework/src/pages/admin/PromptConfigsPage.tsx +125 -16
- package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +49 -10
- package/.framework/src/pages/admin/RoleDetailPage.tsx +130 -10
- package/.framework/src/pages/admin/RolesPage.tsx +171 -18
- package/.framework/src/pages/admin/SelectTestPage.tsx +34 -9
- package/.framework/src/pages/admin/ShadcnTestPage.tsx +49 -11
- package/.framework/src/pages/admin/SimpleDashboard.tsx +49 -10
- package/.framework/src/pages/admin/TestRunDetailPage.tsx +49 -4
- package/.framework/src/pages/admin/TestingDashboard.tsx +98 -28
- package/.framework/src/pages/admin/TimerDetailPage.tsx +143 -33
- package/.framework/src/pages/admin/TimersPage.tsx +48 -20
- package/.framework/src/pages/admin/TriggerDetailPage.tsx +118 -30
- package/.framework/src/pages/admin/TriggersPage.tsx +64 -19
- package/.framework/src/pages/admin/TypeDetailPage.tsx +138 -15
- package/.framework/src/pages/admin/TypesPage.tsx +48 -20
- package/.framework/src/pages/admin/cil/CILAgentPage.tsx +465 -0
- package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +787 -0
- package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +699 -0
- package/.framework/src/pages/admin/cil/CILFileListPage.tsx +647 -0
- package/.framework/src/pages/admin/cil/CILGraphPage.tsx +616 -0
- package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +1402 -0
- package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +614 -0
- package/.framework/src/pages/admin/cil/CILSearchPage.tsx +571 -0
- package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +731 -0
- package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
- package/.framework/src/pages/auth/AuthConfirmPage.tsx +52 -51
- package/.framework/src/pages/auth/ForgotPasswordPage.tsx +31 -22
- package/.framework/src/pages/auth/LoginPage.tsx +50 -23
- package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -15
- package/.framework/src/pages/auth/RegisterPage.tsx +281 -317
- package/.framework/src/pages/spine-framework/APIPage.tsx +33 -0
- package/.framework/src/pages/spine-framework/CLIPage.tsx +33 -0
- package/.framework/src/types/auth.ts +128 -71
- package/.framework/src/types/types.ts +373 -157
- package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +39 -0
- package/custom/.devin/skills/spine-workbench-idea/SKILL.md +36 -0
- package/custom/.devin/skills/spine-workbench-implement/SKILL.md +46 -0
- package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +28 -0
- package/custom/.devin/skills/spine-workbench-plan/SKILL.md +38 -0
- package/docs/README.md +9 -130
- package/netlify.toml +3 -3
- package/package.json +13 -25
- package/scripts/kb-ingest-docs.ts +203 -0
- package/spine.config.json +65 -4
- package/.framework/migrations/001_schema.sql +0 -425
- package/.framework/migrations/002_rls_and_functions.sql +0 -763
- package/.framework/migrations/004_enhancements.sql +0 -43
- package/.framework/migrations/005_auth_user_trigger.sql +0 -105
- package/.framework/migrations/006_fix_current_actor_id.sql +0 -21
- package/.framework/migrations/016_invites.sql +0 -27
- package/.framework/migrations/017_fix_get_account_apps.sql +0 -78
- package/.framework/migrations/018_apps_required_roles.sql +0 -17
- package/.framework/migrations/019_triggers_unique_constraint.sql +0 -13
- package/.framework/migrations/020_get_account_apps_role_filter.sql +0 -117
- package/.framework/migrations/021_app_domains.sql +0 -112
- package/.framework/migrations/022_route_prefix_domain_unique.sql +0 -21
- package/.framework/migrations/023_match_embeddings_rpc.sql +0 -78
- package/.framework/migrations/024_messages_account_id.sql +0 -9
- package/.framework/migrations/025_retype_threads_messages.sql +0 -240
- package/.framework/migrations/026_fix_rls_policies.sql +0 -47
- package/.framework/migrations/027_embedding_lifecycle.sql +0 -176
- package/.framework/migrations/028_fix_message_data_permissions.sql +0 -49
- package/.framework/migrations/029_tighten_support_triage_prompt.sql +0 -41
- package/.framework/migrations/030_messages_updated_by.sql +0 -6
- package/.framework/migrations/031_seed_upsert_constraints.sql +0 -35
- package/docs/APPS.md +0 -232
- package/docs/ARCHITECTURE.md +0 -246
- package/docs/INSTALL.md +0 -155
- package/docs/design-schema-spec.md +0 -1837
- package/docs/dev-guides/01-create-an-app.md +0 -183
- package/docs/dev-guides/02-create-a-function.md +0 -178
- package/docs/dev-guides/03-create-a-component.md +0 -178
- package/docs/dev-guides/04-webhook-handlers.md +0 -129
- package/docs/dev-guides/05-testing.md +0 -168
- package/docs/dev-guides/README.md +0 -40
- package/docs/npm-packages-plan.md +0 -288
- 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
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
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
|
-
|
|
86
|
-
|
|
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
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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<
|
|
157
|
+
login: (email: string, password: string) => Promise<User | null>
|
|
116
158
|
logout: () => Promise<void>
|
|
117
|
-
refreshUser: () => Promise<
|
|
159
|
+
refreshUser: () => Promise<User | null>
|
|
118
160
|
}
|
|
119
161
|
|
|
120
162
|
const AuthContext = createContext<AuthContextType | undefined>(undefined)
|
|
121
|
-
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
-
//
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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
|
-
|
|
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"]
|