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,66 +1,56 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module types
|
|
3
|
-
* @audience core-contributor
|
|
4
|
-
* @layer api-handler
|
|
5
|
-
* @stability stable
|
|
6
|
-
*
|
|
7
|
-
* CRUD API for the `types` table. Types are the schema configuration objects
|
|
8
|
-
* that define `design_schema`, `validation_schema`, field definitions, and
|
|
9
|
-
* view configurations for runtime entities (`items`, `people`, `accounts`).
|
|
10
|
-
*
|
|
11
|
-
* **Routed by:** `GET/POST/PATCH/DELETE /.netlify/functions/types`
|
|
12
|
-
*
|
|
13
|
-
* **Authorization model:**
|
|
14
|
-
* - All reads use `ctx.db` (RLS-scoped) and are sanitized via `sanitizeRecordData`.
|
|
15
|
-
* - All writes (`create`, `update`, `remove`) require `isSystemAdmin` AND the
|
|
16
|
-
* caller's account must be a master tenant (`accounts.parent_id IS NULL`).
|
|
17
|
-
* - Unauthenticated `list` calls receive minimal fields only (id, slug, name, kind).
|
|
18
|
-
*
|
|
19
|
-
* **Design schema auto-sync:** `update` regenerates `validation_schema` automatically
|
|
20
|
-
* via `generateValidationSchema` whenever `design_schema` changes.
|
|
21
|
-
*
|
|
22
|
-
* INVARIANT: type slugs must be unique per (kind, app_id) combination.
|
|
23
|
-
* INVARIANT: `ownership` of system types cannot be changed (to prevent constraint violations).
|
|
24
|
-
* INVARIANT: `app_id = null` for system types; must be provided for app/tenant types.
|
|
25
|
-
*
|
|
26
|
-
* @seeAlso middleware.ts (createHandler, CoreContext)
|
|
27
|
-
* @seeAlso permissions.ts (PermissionEngine, sanitizeRecordData, validateUpdatePermissions)
|
|
28
|
-
* @seeAlso schema-utils.ts (generateValidationSchema — auto-called on design_schema updates)
|
|
29
|
-
* @seeAlso audit.ts (emitLog for type.created / type.updated / type.deleted)
|
|
30
|
-
*/
|
|
31
1
|
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
// CIL[BEGIN chunk_id="types_module_header_1783931956" type="module_header" identity="module_header" parent="none"]
|
|
9
|
+
// CIL[DOC-MACRO purpose="Import dependencies for types CRUD API"]
|
|
10
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Provide middleware, database, permissions and schema utilities"]
|
|
11
|
+
// CIL[DOC-CONTEXT module="types" layer="api-handler" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/functions/_shared/schema-utils.ts\",\"custom/apps/portal/pages/ContentPage.tsx\",\"\\\"]"]
|
|
12
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="imported modules and permissions instance" errors="none" side_effects="none"]
|
|
13
|
+
// CIL[DOC-MICRO logic_summary="Imports all required modules for type management operations" notable_decisions="[]"]
|
|
14
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
15
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
16
|
+
// CIL[DOC-AUDIENCE audience="developer"]
|
|
17
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, .framework/functions/_shared/schema-utils.ts, custom/apps/portal/pages/ContentPage.tsx, \."]
|
|
18
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
19
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
20
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
21
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
22
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
32
23
|
import { createHandler } from './_shared/middleware'
|
|
33
24
|
import { adminDb, joins } from './_shared/db'
|
|
34
25
|
import { emitLog } from './_shared/audit'
|
|
26
|
+
import { isSystemAdmin } from './_shared/principal'
|
|
35
27
|
import { PermissionEngine, sanitizeRecordData } from './_shared/permissions'
|
|
36
28
|
import { generateValidationSchema } from './_shared/schema-utils'
|
|
37
29
|
|
|
38
30
|
const permissions = PermissionEngine as any
|
|
39
|
-
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
* @side-effects [DB queries, permission sanitization, schema preservation]
|
|
55
|
-
* @tags types, list, crud, filtering, authentication
|
|
56
|
-
*/
|
|
31
|
+
// CIL[END chunk_id="types_module_header_1783931956"]
|
|
32
|
+
// CIL[BEGIN chunk_id="types_list_1783931956" type="function" identity="list" parent="none"]
|
|
33
|
+
// CIL[DOC-MACRO purpose="List types with filtering and sanitization"]
|
|
34
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Handle type listing with authentication-based response"]
|
|
35
|
+
// CIL[DOC-CONTEXT module="types" layer="api-handler" related_files="[\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/components/ui/dialog.tsx\",\".framework/functions/_shared/principal.ts\",\"\\\"]"]
|
|
36
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="sanitized type array" errors="throws" side_effects="database queries"]
|
|
37
|
+
// CIL[DOC-MICRO logic_summary="Filters types by kind/app/ownership, sanitizes based on auth, preserves schemas" notable_decisions="[]"]
|
|
38
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
39
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
40
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 0. Direct calls: 0. Related files: custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/RolesPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/components/ui/dialog.tsx, .framework/functions/_shared/principal.ts, \."]
|
|
41
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
42
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
43
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
44
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
45
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
57
46
|
export const list = createHandler(async (ctx, body) => {
|
|
58
47
|
const { kind, app_id, ownership, limit = '50', offset = '0', include_schema } = ctx.query || {}
|
|
59
48
|
|
|
60
|
-
|
|
61
|
-
|
|
49
|
+
const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
|
|
50
|
+
|
|
51
|
+
let query = db
|
|
62
52
|
.from('types')
|
|
63
|
-
.select(
|
|
53
|
+
.select('*')
|
|
64
54
|
.eq('is_active', true)
|
|
65
55
|
.order('kind')
|
|
66
56
|
.order('name')
|
|
@@ -84,32 +74,24 @@ export const list = createHandler(async (ctx, body) => {
|
|
|
84
74
|
|
|
85
75
|
if (err) throw err
|
|
86
76
|
|
|
87
|
-
// For authenticated users, always include design_schema for schema-driven UI
|
|
88
|
-
// System admin sees everything, others get sanitized data with design_schema preserved
|
|
89
|
-
// When include_schema=true, preserve full design_schema for all accessible types
|
|
90
77
|
const sanitized = []
|
|
91
78
|
for (const type of data || []) {
|
|
92
79
|
if (ctx.principal) {
|
|
93
|
-
// Authenticated user - get sanitized data but preserve design_schema
|
|
94
80
|
const sanitizedType = await sanitizeRecordData(ctx, type, 'type')
|
|
95
|
-
// Ensure design_schema is preserved for schema-driven UI
|
|
96
81
|
if (type.design_schema && !sanitizedType.design_schema) {
|
|
97
82
|
sanitizedType.design_schema = type.design_schema
|
|
98
83
|
}
|
|
99
|
-
// When include_schema=true, also preserve validation_schema
|
|
100
84
|
if (include_schema === 'true' && type.validation_schema) {
|
|
101
85
|
sanitizedType.validation_schema = type.validation_schema
|
|
102
86
|
}
|
|
103
87
|
sanitized.push(sanitizedType)
|
|
104
88
|
} else {
|
|
105
|
-
// Unauthenticated user - return minimal data
|
|
106
89
|
const minimal: any = {
|
|
107
90
|
id: type.id,
|
|
108
91
|
slug: type.slug,
|
|
109
92
|
name: type.name,
|
|
110
93
|
kind: type.kind
|
|
111
94
|
}
|
|
112
|
-
// When include_schema=true, unauthenticated users also get schema
|
|
113
95
|
if (include_schema === 'true' && type.design_schema) {
|
|
114
96
|
minimal.design_schema = type.design_schema
|
|
115
97
|
}
|
|
@@ -119,23 +101,21 @@ export const list = createHandler(async (ctx, body) => {
|
|
|
119
101
|
|
|
120
102
|
return sanitized
|
|
121
103
|
})
|
|
122
|
-
//
|
|
123
|
-
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
* @tags types, get, crud, single-record
|
|
138
|
-
*/
|
|
104
|
+
// CIL[END chunk_id="types_list_1783931956"]
|
|
105
|
+
// CIL[BEGIN chunk_id="types_get_1783931956" type="function" identity="get" parent="none"]
|
|
106
|
+
// CIL[DOC-MACRO purpose="Get single type by ID with sanitization"]
|
|
107
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Retrieve and sanitize individual type records"]
|
|
108
|
+
// CIL[DOC-CONTEXT module="types" layer="api-handler" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/schema-utils.ts\",\".framework/src/pages/admin/RolesPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
|
|
109
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="sanitized type object" errors="throws" side_effects="database query"]
|
|
110
|
+
// CIL[DOC-MICRO logic_summary="Queries type by ID with app join, sanitizes based on permissions" notable_decisions="[]"]
|
|
111
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
112
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
113
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/schema-utils.ts, .framework/src/pages/admin/RolesPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
|
|
114
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
115
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
116
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
117
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
118
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
139
119
|
export const get = createHandler(async (ctx, body) => {
|
|
140
120
|
const { id } = ctx.query || {}
|
|
141
121
|
|
|
@@ -143,35 +123,34 @@ export const get = createHandler(async (ctx, body) => {
|
|
|
143
123
|
throw new Error('Type ID is required')
|
|
144
124
|
}
|
|
145
125
|
|
|
146
|
-
const
|
|
126
|
+
const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
|
|
127
|
+
|
|
128
|
+
const { data, error: err } = await db
|
|
147
129
|
.from('types')
|
|
148
|
-
.select(
|
|
130
|
+
.select('*')
|
|
149
131
|
.eq('id', id)
|
|
150
132
|
.eq('is_active', true)
|
|
151
133
|
.single()
|
|
152
134
|
|
|
153
135
|
if (err) throw err
|
|
154
136
|
|
|
155
|
-
// Sanitize based on role permissions
|
|
156
137
|
return await sanitizeRecordData(ctx, data, 'type')
|
|
157
138
|
})
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
-
//
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
* @tags types, get, crud, single-record, slug
|
|
174
|
-
*/
|
|
139
|
+
// CIL[END chunk_id="types_get_1783931956"]
|
|
140
|
+
// CIL[BEGIN chunk_id="types_getbyslug_1783931956" type="function" identity="getBySlug" parent="none"]
|
|
141
|
+
// CIL[DOC-MACRO purpose="Get single type by slug with sanitization"]
|
|
142
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Retrieve type records using slug identifier"]
|
|
143
|
+
// CIL[DOC-CONTEXT module="types" layer="api-handler" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/functions/_shared/schema-utils.ts\",\"\\\"]"]
|
|
144
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="sanitized type object" errors="throws" side_effects="database query"]
|
|
145
|
+
// CIL[DOC-MICRO logic_summary="Queries type by slug with app join, sanitizes based on permissions" 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: api-handler. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/pages/admin/RolesPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/functions/_shared/schema-utils.ts, \."]
|
|
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"]
|
|
175
154
|
export const getBySlug = createHandler(async (ctx, body) => {
|
|
176
155
|
const { slug } = ctx.query || {}
|
|
177
156
|
|
|
@@ -188,26 +167,23 @@ export const getBySlug = createHandler(async (ctx, body) => {
|
|
|
188
167
|
|
|
189
168
|
if (err) throw err
|
|
190
169
|
|
|
191
|
-
// Sanitize based on role permissions
|
|
192
170
|
return await sanitizeRecordData(ctx, data, 'type')
|
|
193
171
|
})
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
//
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
* @tags types, schema, rpc, design-schema
|
|
210
|
-
*/
|
|
172
|
+
// CIL[END chunk_id="types_getbyslug_1783931956"]
|
|
173
|
+
// CIL[BEGIN chunk_id="types_getschema_1783931956" type="function" identity="getSchema" parent="none"]
|
|
174
|
+
// CIL[DOC-MACRO purpose="Get type design schema via RPC"]
|
|
175
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Retrieve design schema for specific type"]
|
|
176
|
+
// CIL[DOC-CONTEXT module="types" layer="api-handler" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/functions/_shared/schema-utils.ts\",\".framework/src/pages/admin/RolesPage.tsx\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\"]"]
|
|
177
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="design_schema object" errors="throws" side_effects="database RPC call"]
|
|
178
|
+
// CIL[DOC-MICRO logic_summary="Calls get_type_schema RPC with kind, slug, and optional app_id" notable_decisions="[]"]
|
|
179
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="external_symbols_unknown"]
|
|
180
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
181
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/schema-utils.ts, .framework/src/pages/admin/RolesPage.tsx, custom/apps/cortex/pages/operations/OperationsDashboard.tsx."]
|
|
182
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
183
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
184
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
185
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
186
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
211
187
|
export const getSchema = createHandler(async (ctx, body) => {
|
|
212
188
|
const { kind, slug, app_id } = ctx.query || {}
|
|
213
189
|
|
|
@@ -226,379 +202,286 @@ export const getSchema = createHandler(async (ctx, body) => {
|
|
|
226
202
|
|
|
227
203
|
return { design_schema: data }
|
|
228
204
|
})
|
|
229
|
-
//
|
|
230
|
-
|
|
231
|
-
//
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
205
|
+
// CIL[END chunk_id="types_getschema_1783931956"]
|
|
206
|
+
// CIL[BEGIN chunk_id="types_create_1783931956" type="function" identity="create" parent="none"]
|
|
207
|
+
// CIL[DOC-LEARNING topic="runtime-type:generic/validation" content="The types API stores design_schema and auto-generates validation_schema from it via generateValidationSchema. design_schema must define record_permissions, fields, and views to drive the rest of the framework."]
|
|
208
|
+
// CIL[DOC-NOTE type="design_schema_caveat" content="Hand-editing validation_schema is unsafe; it is overwritten by the API. design_schema changes do not retroactively re-stamp existing runtime records."]
|
|
209
|
+
// CIL[DOC-MACRO purpose="Create new type with validation and audit"]
|
|
210
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Handle type creation with permissions and validation"]
|
|
211
|
+
// CIL[DOC-CONTEXT module="types" layer="api-handler" related_files="[]"]
|
|
212
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="created type record" errors="throws" side_effects="database insert, audit log"]
|
|
213
|
+
// CIL[DOC-MICRO logic_summary="Validates permissions, checks uniqueness, generates validation schema, creates type" notable_decisions="[]"]
|
|
214
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
215
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
216
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
217
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
218
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
219
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
220
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
221
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
246
222
|
export const create = createHandler(async (ctx, body) => {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
if (!kind || !slug || !name) {
|
|
250
|
-
throw new Error('kind, slug, and name are required')
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
if (!ctx.principal || ctx.principal.id === 'anonymous' || !ctx.accountId) {
|
|
254
|
-
throw new Error('User context (person and account) required')
|
|
223
|
+
if (!permissions.isSystemAdmin(ctx)) {
|
|
224
|
+
throw new Error('System admin required')
|
|
255
225
|
}
|
|
256
226
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
throw new Error('Only system administrators can create type configurations')
|
|
227
|
+
if (!body || typeof body !== 'object') {
|
|
228
|
+
throw new Error('Request body is required')
|
|
260
229
|
}
|
|
261
230
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
231
|
+
const {
|
|
232
|
+
name,
|
|
233
|
+
slug,
|
|
234
|
+
kind,
|
|
235
|
+
ownership = 'system',
|
|
236
|
+
app_id = null,
|
|
237
|
+
design_schema = {},
|
|
238
|
+
validation_schema = null,
|
|
239
|
+
view_config = {},
|
|
240
|
+
description = null,
|
|
241
|
+
icon = null,
|
|
242
|
+
color = null
|
|
243
|
+
} = body
|
|
269
244
|
|
|
270
|
-
if (!
|
|
271
|
-
throw new Error('
|
|
245
|
+
if (!name || !slug || !kind) {
|
|
246
|
+
throw new Error('name, slug, and kind are required')
|
|
272
247
|
}
|
|
273
248
|
|
|
274
|
-
|
|
275
|
-
let query = adminDb
|
|
249
|
+
const { data: existing } = await adminDb
|
|
276
250
|
.from('types')
|
|
277
251
|
.select('id')
|
|
278
|
-
.eq('kind', kind)
|
|
279
252
|
.eq('slug', slug)
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
query = query.is('app_id', null)
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
const { data: existing } = await query.single()
|
|
253
|
+
.eq('kind', kind)
|
|
254
|
+
.eq('app_id', app_id)
|
|
255
|
+
.eq('is_active', true)
|
|
256
|
+
.single()
|
|
288
257
|
|
|
289
258
|
if (existing) {
|
|
290
|
-
throw new Error(
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// Basic schema validation
|
|
294
|
-
if (bodySchema && typeof bodySchema === 'object') {
|
|
295
|
-
if (bodySchema.fields && (typeof bodySchema.fields !== 'object' || bodySchema.fields === null)) {
|
|
296
|
-
throw new Error('Schema fields must be an object')
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// For non-system ownership, we need an app_id to satisfy the constraint
|
|
301
|
-
let finalAppId = app_id
|
|
302
|
-
let finalOwnership = ownership
|
|
303
|
-
|
|
304
|
-
if (!app_id && ownership !== 'system') {
|
|
305
|
-
// Get the first available app for tenant/custom types
|
|
306
|
-
const { data: apps } = await adminDb
|
|
307
|
-
.from('apps')
|
|
308
|
-
.select('id')
|
|
309
|
-
.limit(1)
|
|
310
|
-
.single()
|
|
311
|
-
|
|
312
|
-
if (apps?.id) {
|
|
313
|
-
finalAppId = apps.id
|
|
314
|
-
finalOwnership = 'app' // Use 'app' ownership when associated with an app
|
|
315
|
-
} else {
|
|
316
|
-
throw new Error('Cannot create type without app_id for non-system ownership')
|
|
317
|
-
}
|
|
259
|
+
throw new Error(`Type with slug '${slug}' already exists for kind '${kind}'`)
|
|
318
260
|
}
|
|
319
261
|
|
|
320
|
-
|
|
321
|
-
const validationSchema = generateValidationSchema(bodySchema || {})
|
|
262
|
+
const validation = validation_schema || generateValidationSchema(design_schema)
|
|
322
263
|
|
|
323
|
-
const { data, error
|
|
264
|
+
const { data, error } = await adminDb
|
|
324
265
|
.from('types')
|
|
325
266
|
.insert({
|
|
326
|
-
app_id: finalAppId,
|
|
327
|
-
kind,
|
|
328
|
-
slug,
|
|
329
267
|
name,
|
|
268
|
+
slug,
|
|
269
|
+
kind,
|
|
270
|
+
ownership,
|
|
271
|
+
app_id,
|
|
272
|
+
design_schema,
|
|
273
|
+
validation_schema: validation,
|
|
274
|
+
view_config,
|
|
330
275
|
description,
|
|
331
276
|
icon,
|
|
332
277
|
color,
|
|
333
|
-
design_schema: bodySchema || {},
|
|
334
|
-
validation_schema: validationSchema,
|
|
335
|
-
ownership: finalOwnership || 'system',
|
|
336
278
|
is_active: true
|
|
337
279
|
})
|
|
338
280
|
.select()
|
|
339
281
|
.single()
|
|
340
282
|
|
|
341
|
-
if (
|
|
283
|
+
if (error) throw error
|
|
342
284
|
|
|
343
|
-
await emitLog(ctx, 'type.created', {
|
|
285
|
+
await emitLog(ctx, 'type.created', {
|
|
286
|
+
type_id: data.id,
|
|
287
|
+
type_slug: data.slug,
|
|
288
|
+
type_kind: data.kind
|
|
289
|
+
})
|
|
344
290
|
|
|
345
291
|
return data
|
|
346
292
|
})
|
|
347
|
-
//
|
|
348
|
-
|
|
349
|
-
//
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
* @tags types, update, crud, system-admin, schema-generation, audit
|
|
363
|
-
*/
|
|
293
|
+
// CIL[END chunk_id="types_create_1783931956"]
|
|
294
|
+
// CIL[BEGIN chunk_id="types_update_1783931956" type="function" identity="update" parent="none"]
|
|
295
|
+
// CIL[DOC-MACRO purpose="Update existing type with validation"]
|
|
296
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Handle type updates with permissions and schema sync"]
|
|
297
|
+
// CIL[DOC-CONTEXT module="types" layer="api-handler" related_files="[]"]
|
|
298
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="updated type record" errors="throws" side_effects="database update, audit log"]
|
|
299
|
+
// CIL[DOC-MICRO logic_summary="Validates permissions, protects system types, regenerates validation schema on design changes" notable_decisions="[]"]
|
|
300
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
301
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
302
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
303
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
304
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
305
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
306
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
307
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
364
308
|
export const update = createHandler(async (ctx, body) => {
|
|
365
|
-
|
|
366
|
-
|
|
309
|
+
if (!permissions.isSystemAdmin(ctx)) {
|
|
310
|
+
throw new Error('System admin required')
|
|
311
|
+
}
|
|
367
312
|
|
|
313
|
+
const { id } = ctx.query || {}
|
|
314
|
+
|
|
368
315
|
if (!id) {
|
|
369
316
|
throw new Error('Type ID is required')
|
|
370
317
|
}
|
|
371
318
|
|
|
372
|
-
if (!
|
|
373
|
-
throw new Error('
|
|
319
|
+
if (!body || typeof body !== 'object') {
|
|
320
|
+
throw new Error('Request body is required')
|
|
374
321
|
}
|
|
375
322
|
|
|
376
|
-
|
|
377
|
-
const { data: current } = await adminDb
|
|
323
|
+
const { data: existing } = await adminDb
|
|
378
324
|
.from('types')
|
|
379
325
|
.select('*')
|
|
380
326
|
.eq('id', id)
|
|
327
|
+
.eq('is_active', true)
|
|
381
328
|
.single()
|
|
382
329
|
|
|
383
|
-
if (!
|
|
330
|
+
if (!existing) {
|
|
384
331
|
throw new Error('Type not found')
|
|
385
332
|
}
|
|
386
333
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
throw new Error('Only system administrators can update type configurations')
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
// System types can only be updated by system admins (already checked above)
|
|
393
|
-
// App types require app ownership verification
|
|
394
|
-
if (current.ownership === 'app' && current.app_id) {
|
|
395
|
-
// Verify user has access to this app
|
|
396
|
-
const { data: appAccess } = await adminDb
|
|
397
|
-
.from('apps')
|
|
398
|
-
.select('id')
|
|
399
|
-
.eq('id', current.app_id)
|
|
400
|
-
.eq('is_active', true)
|
|
401
|
-
.single()
|
|
402
|
-
|
|
403
|
-
if (!appAccess) {
|
|
404
|
-
throw new Error('App not found or inactive')
|
|
405
|
-
}
|
|
334
|
+
if (existing.ownership === 'system' && body.ownership && body.ownership !== 'system') {
|
|
335
|
+
throw new Error('Cannot change ownership of system types')
|
|
406
336
|
}
|
|
407
337
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
338
|
+
const {
|
|
339
|
+
name,
|
|
340
|
+
slug,
|
|
341
|
+
design_schema,
|
|
342
|
+
view_config,
|
|
343
|
+
description,
|
|
344
|
+
icon,
|
|
345
|
+
color,
|
|
346
|
+
is_active,
|
|
347
|
+
kind,
|
|
348
|
+
app_id,
|
|
349
|
+
ownership
|
|
350
|
+
} = body
|
|
415
351
|
|
|
416
|
-
|
|
417
|
-
throw new Error('Type configurations can only be updated in master tenant accounts')
|
|
418
|
-
}
|
|
352
|
+
const updates: any = {}
|
|
419
353
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
)
|
|
427
|
-
|
|
428
|
-
if (
|
|
429
|
-
|
|
430
|
-
}
|
|
354
|
+
if (name !== undefined) updates.name = name
|
|
355
|
+
if (slug !== undefined) updates.slug = slug
|
|
356
|
+
if (view_config !== undefined) updates.view_config = view_config
|
|
357
|
+
if (description !== undefined) updates.description = description
|
|
358
|
+
if (icon !== undefined) updates.icon = icon
|
|
359
|
+
if (color !== undefined) updates.color = color
|
|
360
|
+
if (is_active !== undefined) updates.is_active = is_active
|
|
361
|
+
if (kind !== undefined) updates.kind = kind
|
|
362
|
+
if (app_id !== undefined) updates.app_id = app_id
|
|
363
|
+
if (ownership !== undefined) updates.ownership = ownership
|
|
431
364
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
delete updates.ownership
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
// Handle app_id null conversion for system types
|
|
439
|
-
if (updates.app_id === '') {
|
|
440
|
-
updates.app_id = null
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// Validate design_schema if being updated
|
|
444
|
-
if (updates.design_schema) {
|
|
445
|
-
if (typeof updates.design_schema !== 'object' || updates.design_schema === null) {
|
|
446
|
-
throw new Error('Design schema must be an object')
|
|
447
|
-
}
|
|
448
|
-
if (updates.design_schema.fields && (typeof updates.design_schema.fields !== 'object' || updates.design_schema.fields === null)) {
|
|
449
|
-
throw new Error('Design schema fields must be an object')
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
// Auto-generate validation_schema when design_schema changes
|
|
453
|
-
updates.validation_schema = generateValidationSchema(updates.design_schema)
|
|
365
|
+
if (design_schema !== undefined) {
|
|
366
|
+
updates.design_schema = design_schema
|
|
367
|
+
updates.validation_schema = generateValidationSchema(design_schema)
|
|
454
368
|
}
|
|
455
369
|
|
|
456
|
-
const { data, error
|
|
370
|
+
const { data, error } = await adminDb
|
|
457
371
|
.from('types')
|
|
458
|
-
.update(
|
|
459
|
-
...updates,
|
|
460
|
-
updated_at: new Date().toISOString()
|
|
461
|
-
})
|
|
372
|
+
.update(updates)
|
|
462
373
|
.eq('id', id)
|
|
463
374
|
.select()
|
|
464
375
|
.single()
|
|
465
376
|
|
|
466
|
-
if (
|
|
377
|
+
if (error) throw error
|
|
467
378
|
|
|
468
|
-
await emitLog(ctx, 'type.updated', {
|
|
379
|
+
await emitLog(ctx, 'type.updated', {
|
|
380
|
+
type_id: data.id,
|
|
381
|
+
type_slug: data.slug,
|
|
382
|
+
type_kind: data.kind
|
|
383
|
+
})
|
|
469
384
|
|
|
470
385
|
return data
|
|
471
386
|
})
|
|
472
|
-
//
|
|
473
|
-
|
|
474
|
-
//
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
* @tags types, remove, soft-delete, system-admin, audit
|
|
488
|
-
*/
|
|
387
|
+
// CIL[END chunk_id="types_update_1783931956"]
|
|
388
|
+
// CIL[BEGIN chunk_id="types_remove_1783931956" type="function" identity="remove" parent="none"]
|
|
389
|
+
// CIL[DOC-MACRO purpose="Soft delete type with validation"]
|
|
390
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Handle type deletion with permissions and protection"]
|
|
391
|
+
// CIL[DOC-CONTEXT module="types" layer="api-handler" related_files="[]"]
|
|
392
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="success indicator" errors="throws" side_effects="database update, audit log"]
|
|
393
|
+
// CIL[DOC-MICRO logic_summary="Validates permissions, protects system types, soft deletes by setting is_active=false" notable_decisions="[]"]
|
|
394
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
395
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
396
|
+
// CIL[DOC-VECTOR type="context" content="Layer: api-handler. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
397
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
398
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
399
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
400
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
401
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
489
402
|
export const remove = createHandler(async (ctx, body) => {
|
|
490
|
-
|
|
403
|
+
if (!permissions.isSystemAdmin(ctx)) {
|
|
404
|
+
throw new Error('System admin required')
|
|
405
|
+
}
|
|
491
406
|
|
|
407
|
+
const { id } = ctx.query || {}
|
|
408
|
+
|
|
492
409
|
if (!id) {
|
|
493
410
|
throw new Error('Type ID is required')
|
|
494
411
|
}
|
|
495
412
|
|
|
496
|
-
|
|
497
|
-
throw new Error('User context (person and account) required')
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
// Get current state for audit - RLS will filter to accessible types
|
|
501
|
-
const { data: current } = await ctx.db
|
|
413
|
+
const { data: existing } = await adminDb
|
|
502
414
|
.from('types')
|
|
503
415
|
.select('*')
|
|
504
416
|
.eq('id', id)
|
|
417
|
+
.eq('is_active', true)
|
|
505
418
|
.single()
|
|
506
419
|
|
|
507
|
-
if (!
|
|
420
|
+
if (!existing) {
|
|
508
421
|
throw new Error('Type not found')
|
|
509
422
|
}
|
|
510
423
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
throw new Error('Only system administrators can delete type configurations')
|
|
424
|
+
if (existing.ownership === 'system') {
|
|
425
|
+
throw new Error('Cannot delete system types')
|
|
514
426
|
}
|
|
515
427
|
|
|
516
|
-
|
|
517
|
-
// App types require app ownership verification
|
|
518
|
-
if (current.ownership === 'app' && current.app_id) {
|
|
519
|
-
// Verify user has access to this app
|
|
520
|
-
const { data: appAccess } = await ctx.db
|
|
521
|
-
.from('apps')
|
|
522
|
-
.select('id')
|
|
523
|
-
.eq('id', current.app_id)
|
|
524
|
-
.eq('is_active', true)
|
|
525
|
-
.single()
|
|
526
|
-
|
|
527
|
-
if (!appAccess) {
|
|
528
|
-
throw new Error('App not found or inactive')
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// Verify the current account is a master tenant (parent_id IS NULL)
|
|
533
|
-
// Use adminDb for this check since we're verifying account structure
|
|
534
|
-
const { data: accountData } = await adminDb
|
|
535
|
-
.from('accounts')
|
|
536
|
-
.select('parent_id')
|
|
537
|
-
.eq('id', ctx.accountId!)
|
|
538
|
-
.single()
|
|
539
|
-
|
|
540
|
-
if (!accountData || accountData.parent_id !== null) {
|
|
541
|
-
throw new Error('Type configurations can only be deleted in master tenant accounts')
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
const { data, error: err } = await ctx.db
|
|
428
|
+
const { error } = await adminDb
|
|
545
429
|
.from('types')
|
|
546
|
-
.update({
|
|
547
|
-
is_active: false
|
|
548
|
-
updated_at: new Date().toISOString()
|
|
430
|
+
.update({
|
|
431
|
+
is_active: false
|
|
549
432
|
})
|
|
550
433
|
.eq('id', id)
|
|
551
|
-
.select()
|
|
552
|
-
.single()
|
|
553
434
|
|
|
554
|
-
if (
|
|
435
|
+
if (error) throw error
|
|
555
436
|
|
|
556
|
-
await emitLog(ctx, 'type.deleted', {
|
|
437
|
+
await emitLog(ctx, 'type.deleted', {
|
|
438
|
+
type_id: existing.id,
|
|
439
|
+
type_slug: existing.slug,
|
|
440
|
+
type_kind: existing.kind
|
|
441
|
+
})
|
|
557
442
|
|
|
558
|
-
return
|
|
443
|
+
return { success: true }
|
|
559
444
|
})
|
|
560
|
-
//
|
|
561
|
-
|
|
562
|
-
//
|
|
563
|
-
|
|
564
|
-
//
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
* @micro Routes HTTP methods and actions to appropriate type handlers
|
|
571
|
-
* @inputs ctx: CoreContext — Request context with principal and database
|
|
572
|
-
* @inputs body: any — Request body for POST/PATCH/DELETE operations
|
|
573
|
-
* @outputs Varies — Depends on routed handler (list/get/getBySlug/getSchema/create/update/remove)
|
|
574
|
-
* @depends-on [createHandler, list, get, getBySlug, getSchema, create, update, remove]
|
|
575
|
-
* @depended-by [Netlify function routing]
|
|
576
|
-
* @side-effects [Delegates to appropriate handler]
|
|
577
|
-
* @tags types, router, crud, netlify-function
|
|
578
|
-
*/
|
|
445
|
+
// CIL[END chunk_id="types_remove_1783931956"]
|
|
446
|
+
// CIL[BEGIN chunk_id="types_handler_1783931956" type="function" identity="handler" parent="none"]
|
|
447
|
+
// CIL[DOC-MACRO purpose="Netlify function entrypoint for types API"]
|
|
448
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Dispatch incoming requests to list, get, getBySlug, getSchema, create, update, or remove based on HTTP method and query parameters"]
|
|
449
|
+
// CIL[DOC-CONTEXT module="types" layer="api-handler" related_files="[\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/hooks/useSchemaRecord.ts\",\".framework/src/hooks/useListSchema.ts\"]"]
|
|
450
|
+
// CIL[DOC-CONTRACT inputs="http context and optional body" outputs="routed handler result" errors="throws on unsupported action or method" side_effects="none"]
|
|
451
|
+
// CIL[DOC-MICRO logic_summary="Routes GET by action/id/slug to list, get, getBySlug, or getSchema; POST to create; PATCH to update; DELETE to remove" notable_decisions="[]"]
|
|
452
|
+
// CIL[DOC-CONFIDENCE pass="first" score="0.95" flags="none"]
|
|
453
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
454
|
+
// CIL[DOC-AUDIENCE audience="developer"]
|
|
579
455
|
export const handler = createHandler(async (ctx, body) => {
|
|
456
|
+
const { action, id, slug, kind } = ctx.query || {}
|
|
580
457
|
const method = ctx.query?.method || 'GET'
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
458
|
+
|
|
459
|
+
if (action === 'schema') {
|
|
460
|
+
return await getSchema(ctx, body)
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (action === 'list' || (method === 'GET' && !id && !slug && !kind)) {
|
|
464
|
+
return await list(ctx, body)
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (method === 'GET') {
|
|
468
|
+
if (slug) return await getBySlug(ctx, body)
|
|
469
|
+
if (id || (kind && action !== 'schema')) return await get(ctx, body)
|
|
470
|
+
return await list(ctx, body)
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (method === 'POST') {
|
|
474
|
+
return await create(ctx, body)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (method === 'PATCH') {
|
|
478
|
+
return await update(ctx, body)
|
|
602
479
|
}
|
|
480
|
+
|
|
481
|
+
if (method === 'DELETE') {
|
|
482
|
+
return await remove(ctx, body)
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
throw new Error('Invalid action or method')
|
|
603
486
|
})
|
|
604
|
-
//
|
|
487
|
+
// CIL[END chunk_id="types_handler_1783931956"]
|