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.
- 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 +179 -69
- package/.framework/cli/commands/generate.ts +83 -143
- 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} +158 -56
- package/.framework/functions/_shared/db.ts +80 -126
- package/.framework/functions/_shared/hash-api-key.ts +63 -0
- package/.framework/functions/_shared/index.ts +224 -335
- 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 +188 -16
- 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 +685 -537
- 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 +187 -144
- 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 +195 -116
- 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 +5 -2
- 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,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
|
-
|
|
45
|
-
const
|
|
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
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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<
|
|
157
|
+
login: (email: string, password: string) => Promise<User | null>
|
|
98
158
|
logout: () => Promise<void>
|
|
99
|
-
refreshUser: () => Promise<
|
|
159
|
+
refreshUser: () => Promise<User | null>
|
|
100
160
|
}
|
|
101
161
|
|
|
102
162
|
const AuthContext = createContext<AuthContextType | undefined>(undefined)
|
|
103
|
-
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
//
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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
|
-
//
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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"]
|