spine-framework 0.1.0
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/README.md +129 -0
- package/.framework/cli/bin.cjs +14 -0
- package/.framework/cli/commands/agents.ts +153 -0
- package/.framework/cli/commands/auth.ts +94 -0
- package/.framework/cli/commands/create-app.ts +185 -0
- package/.framework/cli/commands/dev.ts +295 -0
- package/.framework/cli/commands/doctor.ts +442 -0
- package/.framework/cli/commands/generate.ts +332 -0
- package/.framework/cli/commands/init.ts +272 -0
- package/.framework/cli/commands/install-app.ts +391 -0
- package/.framework/cli/commands/items.ts +253 -0
- package/.framework/cli/commands/migrations.ts +141 -0
- package/.framework/cli/commands/pipelines.ts +166 -0
- package/.framework/cli/commands/status.ts +197 -0
- package/.framework/cli/commands/system.ts +184 -0
- package/.framework/cli/commands/test.ts +227 -0
- package/.framework/cli/commands/uninstall-app.ts +166 -0
- package/.framework/cli/context.ts +268 -0
- package/.framework/cli/env-loader.ts +36 -0
- package/.framework/cli/index.ts +106 -0
- package/.framework/cli/welcome.cjs +45 -0
- package/.framework/docs/API.md +384 -0
- package/.framework/docs/STABILITY.md +52 -0
- package/.framework/docs/admin-routes.md +76 -0
- package/.framework/docs/api-docs-progress.md +38 -0
- package/.framework/docs/api-governance.md +146 -0
- package/.framework/docs/api-testing-results.md +212 -0
- package/.framework/docs/apis/admin-configs.md +567 -0
- package/.framework/docs/apis/admin-data.md +272 -0
- package/.framework/docs/apis/index.md +231 -0
- package/.framework/docs/apis/internal.md +295 -0
- package/.framework/docs/apis/runtime.md +537 -0
- package/.framework/docs/assembly-launch-guide.md +138 -0
- package/.framework/docs/audit-results.md +590 -0
- package/.framework/docs/authorization-model.md +170 -0
- package/.framework/docs/db-api-inventory.md +95 -0
- package/.framework/docs/examples/custom-app/README.md +77 -0
- package/.framework/docs/examples/custom-function/README.md +27 -0
- package/.framework/docs/examples/custom-function/handler.ts +48 -0
- package/.framework/docs/examples/custom-webhook/README.md +68 -0
- package/.framework/docs/gap-remediation-backlog.md +103 -0
- package/.framework/docs/guides/cli-guide.md +224 -0
- package/.framework/docs/guides/getting-started.md +103 -0
- package/.framework/docs/guides/import-guide.md +193 -0
- package/.framework/docs/guides/testing-guide.md +229 -0
- package/.framework/docs/permission-examples.md +326 -0
- package/.framework/docs/ui-adoption-verification.md +111 -0
- package/.framework/docs/ui-api-coverage.md +84 -0
- package/.framework/docs/v2-compatibility-audit.md +228 -0
- package/.framework/functions/.gitkeep +1 -0
- package/.framework/functions/_shared/agent-runner.ts +1097 -0
- package/.framework/functions/_shared/app-manifest.ts +184 -0
- package/.framework/functions/_shared/audit.ts +150 -0
- package/.framework/functions/_shared/db.ts +174 -0
- package/.framework/functions/_shared/index.ts +382 -0
- package/.framework/functions/_shared/middleware.ts +490 -0
- package/.framework/functions/_shared/permissions.ts +1325 -0
- package/.framework/functions/_shared/pipeline-runner.ts +731 -0
- package/.framework/functions/_shared/principal.ts +760 -0
- package/.framework/functions/_shared/schema-utils.ts +967 -0
- package/.framework/functions/_shared/testing.ts +258 -0
- package/.framework/functions/_shared/trigger-engine.ts +425 -0
- package/.framework/functions/_shared/webhook-registration.ts +168 -0
- package/.framework/functions/_shared/webhook-registry.ts +129 -0
- package/.framework/functions/account-nodes.ts +111 -0
- package/.framework/functions/admin-data.ts +606 -0
- package/.framework/functions/ai-agents.ts +323 -0
- package/.framework/functions/api-keys.ts +376 -0
- package/.framework/functions/apps.ts +483 -0
- package/.framework/functions/auth.ts +196 -0
- package/.framework/functions/debug-auth.ts +107 -0
- package/.framework/functions/embeddings.ts +556 -0
- package/.framework/functions/integration-routes.ts +523 -0
- package/.framework/functions/integrations.ts +319 -0
- package/.framework/functions/item-progress.ts +272 -0
- package/.framework/functions/logs.ts +438 -0
- package/.framework/functions/observability.ts +275 -0
- package/.framework/functions/pipeline-executions.ts +494 -0
- package/.framework/functions/pipelines.ts +485 -0
- package/.framework/functions/prompt-configs.ts +339 -0
- package/.framework/functions/roles.ts +387 -0
- package/.framework/functions/system-cron.ts +742 -0
- package/.framework/functions/system.ts +323 -0
- package/.framework/functions/tests.ts +119 -0
- package/.framework/functions/timers.ts +357 -0
- package/.framework/functions/triggers.ts +563 -0
- package/.framework/functions/types.ts +604 -0
- package/.framework/migrations/000_foundation.sql +1256 -0
- package/.framework/migrations/001_seed.sql +92 -0
- package/.framework/migrations/002_seed_constraints.sql +13 -0
- package/.framework/migrations/003_auth_user_trigger.sql +59 -0
- package/.framework/src/App.tsx +126 -0
- package/.framework/src/apps/admin/index.tsx +173 -0
- package/.framework/src/components/AppWrapper.tsx +56 -0
- package/.framework/src/components/CustomAppLoader.tsx +116 -0
- package/.framework/src/components/admin/AdminListPage.tsx +151 -0
- package/.framework/src/components/admin/AdminSidebar.tsx +166 -0
- package/.framework/src/components/admin/AdminStatsCard.tsx +62 -0
- package/.framework/src/components/admin/SortableTableHeader.tsx +42 -0
- package/.framework/src/components/app-shell/GenericAppShell.tsx +181 -0
- package/.framework/src/components/app-shell/GenericDetailPage.tsx +200 -0
- package/.framework/src/components/app-shell/GenericListPage.tsx +116 -0
- package/.framework/src/components/app-sidebar.tsx +228 -0
- package/.framework/src/components/auth/ProtectedRoute.tsx +88 -0
- package/.framework/src/components/layout/AppShell.tsx +91 -0
- package/.framework/src/components/layout/Header.tsx +88 -0
- package/.framework/src/components/layout/Layout.tsx +95 -0
- package/.framework/src/components/layout/Sidebar.tsx +329 -0
- package/.framework/src/components/runtime/DataDetailHeader.tsx +77 -0
- package/.framework/src/components/runtime/DataDetailPage.tsx +171 -0
- package/.framework/src/components/runtime/DataFilters.tsx +91 -0
- package/.framework/src/components/runtime/DataHeader.tsx +68 -0
- package/.framework/src/components/runtime/DataListPage.tsx +124 -0
- package/.framework/src/components/runtime/DataStats.tsx +70 -0
- package/.framework/src/components/runtime/DataTable.tsx +174 -0
- package/.framework/src/components/runtime/SchemaDetailForm.tsx +134 -0
- package/.framework/src/components/runtime/index.ts +18 -0
- package/.framework/src/components/search-form.tsx +29 -0
- package/.framework/src/components/shared/AgentView.tsx +213 -0
- package/.framework/src/components/shared/FieldRenderer.tsx +478 -0
- package/.framework/src/components/shared/SchemaFields.tsx +226 -0
- package/.framework/src/components/ui/DataTable.tsx +343 -0
- package/.framework/src/components/ui/Form.tsx +281 -0
- package/.framework/src/components/ui/ItemCard.tsx +296 -0
- package/.framework/src/components/ui/ItemListView.tsx +308 -0
- package/.framework/src/components/ui/LoadingSpinner.tsx +52 -0
- package/.framework/src/components/ui/Modal.tsx +61 -0
- package/.framework/src/components/ui/RichTextEditor.tsx +210 -0
- package/.framework/src/components/ui/accordion.tsx +82 -0
- package/.framework/src/components/ui/alert-dialog.tsx +197 -0
- package/.framework/src/components/ui/alert.tsx +76 -0
- package/.framework/src/components/ui/aspect-ratio.tsx +11 -0
- package/.framework/src/components/ui/avatar.tsx +110 -0
- package/.framework/src/components/ui/badge.tsx +49 -0
- package/.framework/src/components/ui/breadcrumb.tsx +122 -0
- package/.framework/src/components/ui/button-group.tsx +83 -0
- package/.framework/src/components/ui/button.tsx +65 -0
- package/.framework/src/components/ui/calendar.tsx +222 -0
- package/.framework/src/components/ui/card.tsx +100 -0
- package/.framework/src/components/ui/carousel.tsx +240 -0
- package/.framework/src/components/ui/chart.tsx +373 -0
- package/.framework/src/components/ui/checkbox.tsx +31 -0
- package/.framework/src/components/ui/collapsible.tsx +33 -0
- package/.framework/src/components/ui/combobox.tsx +299 -0
- package/.framework/src/components/ui/command.tsx +193 -0
- package/.framework/src/components/ui/context-menu.tsx +261 -0
- package/.framework/src/components/ui/dialog.tsx +165 -0
- package/.framework/src/components/ui/direction.tsx +22 -0
- package/.framework/src/components/ui/drawer.tsx +132 -0
- package/.framework/src/components/ui/dropdown-menu.tsx +269 -0
- package/.framework/src/components/ui/empty.tsx +104 -0
- package/.framework/src/components/ui/field.tsx +238 -0
- package/.framework/src/components/ui/hover-card.tsx +42 -0
- package/.framework/src/components/ui/input-group.tsx +153 -0
- package/.framework/src/components/ui/input-otp.tsx +87 -0
- package/.framework/src/components/ui/input.tsx +19 -0
- package/.framework/src/components/ui/item.tsx +196 -0
- package/.framework/src/components/ui/kbd.tsx +26 -0
- package/.framework/src/components/ui/label.tsx +22 -0
- package/.framework/src/components/ui/menubar.tsx +277 -0
- package/.framework/src/components/ui/native-select.tsx +61 -0
- package/.framework/src/components/ui/navigation-menu.tsx +164 -0
- package/.framework/src/components/ui/pagination.tsx +129 -0
- package/.framework/src/components/ui/popover.tsx +87 -0
- package/.framework/src/components/ui/progress.tsx +31 -0
- package/.framework/src/components/ui/radio-group.tsx +42 -0
- package/.framework/src/components/ui/resizable.tsx +50 -0
- package/.framework/src/components/ui/scroll-area.tsx +53 -0
- package/.framework/src/components/ui/select.tsx +195 -0
- package/.framework/src/components/ui/separator.tsx +26 -0
- package/.framework/src/components/ui/sheet.tsx +145 -0
- package/.framework/src/components/ui/sidebar.tsx +706 -0
- package/.framework/src/components/ui/skeleton.tsx +13 -0
- package/.framework/src/components/ui/slider.tsx +59 -0
- package/.framework/src/components/ui/sonner.tsx +47 -0
- package/.framework/src/components/ui/spinner.tsx +10 -0
- package/.framework/src/components/ui/switch.tsx +33 -0
- package/.framework/src/components/ui/table-primitives.tsx +141 -0
- package/.framework/src/components/ui/table.tsx +114 -0
- package/.framework/src/components/ui/tabs.tsx +90 -0
- package/.framework/src/components/ui/textarea.tsx +18 -0
- package/.framework/src/components/ui/toggle-group.tsx +89 -0
- package/.framework/src/components/ui/toggle.tsx +45 -0
- package/.framework/src/components/ui/tooltip.tsx +57 -0
- package/.framework/src/contexts/AppContext.tsx +133 -0
- package/.framework/src/contexts/AuthContext.tsx +371 -0
- package/.framework/src/hooks/use-mobile.ts +19 -0
- package/.framework/src/hooks/useApi.ts +526 -0
- package/.framework/src/hooks/useApps.ts +114 -0
- package/.framework/src/hooks/useEntityList.ts +190 -0
- package/.framework/src/hooks/useEntityRecord.ts +308 -0
- package/.framework/src/hooks/useForm.ts +307 -0
- package/.framework/src/hooks/useListSchema.ts +264 -0
- package/.framework/src/hooks/useSchemaRecord.ts +223 -0
- package/.framework/src/index.css +128 -0
- package/.framework/src/lib/api.ts +156 -0
- package/.framework/src/lib/supabase.ts +94 -0
- package/.framework/src/lib/utils.ts +317 -0
- package/.framework/src/main.tsx +27 -0
- package/.framework/src/pages/DashboardPage.tsx +181 -0
- package/.framework/src/pages/NotFoundPage.tsx +39 -0
- package/.framework/src/pages/admin/AIAgentDetailPage.tsx +161 -0
- package/.framework/src/pages/admin/AIAgentsPage.tsx +318 -0
- package/.framework/src/pages/admin/APIKeyDetailPage.tsx +199 -0
- package/.framework/src/pages/admin/APIKeysPage.tsx +303 -0
- package/.framework/src/pages/admin/AlertsConfigPage.tsx +523 -0
- package/.framework/src/pages/admin/AppDetailPage.tsx +493 -0
- package/.framework/src/pages/admin/AppsPage.tsx +355 -0
- package/.framework/src/pages/admin/DesignedPage.tsx +491 -0
- package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +534 -0
- package/.framework/src/pages/admin/EmbeddingsPage.tsx +424 -0
- package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +176 -0
- package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +109 -0
- package/.framework/src/pages/admin/IntegratedDashboard.tsx +402 -0
- package/.framework/src/pages/admin/IntegrationDetailPage.tsx +187 -0
- package/.framework/src/pages/admin/IntegrationsPage.tsx +301 -0
- package/.framework/src/pages/admin/LogsPage.tsx +283 -0
- package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +85 -0
- package/.framework/src/pages/admin/ObservabilityDashboard.tsx +470 -0
- package/.framework/src/pages/admin/PipelineDetailPage.tsx +183 -0
- package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +279 -0
- package/.framework/src/pages/admin/PipelinesPage.tsx +390 -0
- package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +299 -0
- package/.framework/src/pages/admin/PromptConfigsPage.tsx +292 -0
- package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +434 -0
- package/.framework/src/pages/admin/RoleDetailPage.tsx +273 -0
- package/.framework/src/pages/admin/RolesPage.tsx +292 -0
- package/.framework/src/pages/admin/SelectTestPage.tsx +61 -0
- package/.framework/src/pages/admin/ShadcnTestPage.tsx +588 -0
- package/.framework/src/pages/admin/SimpleDashboard.tsx +387 -0
- package/.framework/src/pages/admin/TestRunDetailPage.tsx +172 -0
- package/.framework/src/pages/admin/TestingDashboard.tsx +257 -0
- package/.framework/src/pages/admin/TimerDetailPage.tsx +151 -0
- package/.framework/src/pages/admin/TimersPage.tsx +376 -0
- package/.framework/src/pages/admin/TriggerDetailPage.tsx +149 -0
- package/.framework/src/pages/admin/TriggersPage.tsx +381 -0
- package/.framework/src/pages/admin/TypeDetailPage.tsx +694 -0
- package/.framework/src/pages/admin/TypesPage.tsx +295 -0
- package/.framework/src/pages/auth/LoginPage.tsx +188 -0
- package/.framework/src/pages/auth/RegisterPage.tsx +163 -0
- package/.framework/src/pages/spine-framework/APIPage.tsx +17 -0
- package/.framework/src/pages/spine-framework/CLIPage.tsx +25 -0
- package/.framework/src/types/auth.ts +125 -0
- package/.framework/src/types/types.ts +407 -0
- package/STRUCTURE.md +150 -0
- package/config/components.json +25 -0
- package/config/deno.lock +108 -0
- package/config/package-lock.json +17183 -0
- package/config/postcss.config.cjs +10 -0
- package/config/tailwind.config.cjs +78 -0
- package/config/tsconfig.build.json +32 -0
- package/config/tsconfig.cli.json +18 -0
- package/config/tsconfig.json +41 -0
- package/config/tsconfig.node.json +17 -0
- package/config/tsconfig.node.tsbuildinfo +1 -0
- package/config/tsconfig.tsbuildinfo +1 -0
- package/config/typedoc.json +16 -0
- package/config/vite.config.d.ts +2 -0
- package/config/vite.config.ts +72 -0
- package/dist/cli/commands/agents.d.ts +39 -0
- package/dist/cli/commands/agents.d.ts.map +1 -0
- package/dist/cli/commands/auth.d.ts +36 -0
- package/dist/cli/commands/auth.d.ts.map +1 -0
- package/dist/cli/commands/create-app.d.ts +23 -0
- package/dist/cli/commands/create-app.d.ts.map +1 -0
- package/dist/cli/commands/dev.d.ts +39 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/doctor.d.ts +42 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/generate.d.ts +36 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/init.d.ts +30 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/install-app.d.ts +30 -0
- package/dist/cli/commands/install-app.d.ts.map +1 -0
- package/dist/cli/commands/items.d.ts +45 -0
- package/dist/cli/commands/items.d.ts.map +1 -0
- package/dist/cli/commands/migrations.d.ts +41 -0
- package/dist/cli/commands/migrations.d.ts.map +1 -0
- package/dist/cli/commands/pipelines.d.ts +40 -0
- package/dist/cli/commands/pipelines.d.ts.map +1 -0
- package/dist/cli/commands/status.d.ts +23 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/system.d.ts +29 -0
- package/dist/cli/commands/system.d.ts.map +1 -0
- package/dist/cli/commands/test.d.ts +46 -0
- package/dist/cli/commands/test.d.ts.map +1 -0
- package/dist/cli/commands/uninstall-app.d.ts +23 -0
- package/dist/cli/commands/uninstall-app.d.ts.map +1 -0
- package/dist/cli/context.d.ts +88 -0
- package/dist/cli/context.d.ts.map +1 -0
- package/dist/cli/env-loader.d.ts +14 -0
- package/dist/cli/env-loader.d.ts.map +1 -0
- package/dist/cli/index.d.ts +41 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/functions/_shared/agent-runner.d.ts +156 -0
- package/dist/functions/_shared/agent-runner.d.ts.map +1 -0
- package/dist/functions/_shared/app-manifest.d.ts +68 -0
- package/dist/functions/_shared/app-manifest.d.ts.map +1 -0
- package/dist/functions/_shared/audit.d.ts +91 -0
- package/dist/functions/_shared/audit.d.ts.map +1 -0
- package/dist/functions/_shared/db.d.ts +125 -0
- package/dist/functions/_shared/db.d.ts.map +1 -0
- package/dist/functions/_shared/index.d.ts +298 -0
- package/dist/functions/_shared/index.d.ts.map +1 -0
- package/dist/functions/_shared/middleware.d.ts +315 -0
- package/dist/functions/_shared/middleware.d.ts.map +1 -0
- package/dist/functions/_shared/permissions.d.ts +626 -0
- package/dist/functions/_shared/permissions.d.ts.map +1 -0
- package/dist/functions/_shared/pipeline-runner.d.ts +124 -0
- package/dist/functions/_shared/pipeline-runner.d.ts.map +1 -0
- package/dist/functions/_shared/principal.d.ts +284 -0
- package/dist/functions/_shared/principal.d.ts.map +1 -0
- package/dist/functions/_shared/schema-utils.d.ts +181 -0
- package/dist/functions/_shared/schema-utils.d.ts.map +1 -0
- package/dist/functions/_shared/testing.d.ts +172 -0
- package/dist/functions/_shared/testing.d.ts.map +1 -0
- package/dist/functions/_shared/trigger-engine.d.ts +140 -0
- package/dist/functions/_shared/trigger-engine.d.ts.map +1 -0
- package/dist/functions/_shared/webhook-registration.d.ts +81 -0
- package/dist/functions/_shared/webhook-registration.d.ts.map +1 -0
- package/dist/functions/_shared/webhook-registry.d.ts +57 -0
- package/dist/functions/_shared/webhook-registry.d.ts.map +1 -0
- package/dist/functions/account-nodes.d.ts +48 -0
- package/dist/functions/account-nodes.d.ts.map +1 -0
- package/dist/functions/admin-data.d.ts +178 -0
- package/dist/functions/admin-data.d.ts.map +1 -0
- package/dist/functions/ai-agents.d.ts +125 -0
- package/dist/functions/ai-agents.d.ts.map +1 -0
- package/dist/functions/api-keys.d.ts +140 -0
- package/dist/functions/api-keys.d.ts.map +1 -0
- package/dist/functions/apps.d.ts +163 -0
- package/dist/functions/apps.d.ts.map +1 -0
- package/dist/functions/auth.d.ts +74 -0
- package/dist/functions/auth.d.ts.map +1 -0
- package/dist/functions/debug-auth.d.ts +33 -0
- package/dist/functions/debug-auth.d.ts.map +1 -0
- package/dist/functions/embeddings.d.ts +205 -0
- package/dist/functions/embeddings.d.ts.map +1 -0
- package/dist/functions/integration-routes.d.ts +45 -0
- package/dist/functions/integration-routes.d.ts.map +1 -0
- package/dist/functions/integrations.d.ts +124 -0
- package/dist/functions/integrations.d.ts.map +1 -0
- package/dist/functions/item-progress.d.ts +41 -0
- package/dist/functions/item-progress.d.ts.map +1 -0
- package/dist/functions/logs.d.ts +162 -0
- package/dist/functions/logs.d.ts.map +1 -0
- package/dist/functions/observability.d.ts +123 -0
- package/dist/functions/observability.d.ts.map +1 -0
- package/dist/functions/pipeline-executions.d.ts +190 -0
- package/dist/functions/pipeline-executions.d.ts.map +1 -0
- package/dist/functions/pipelines.d.ts +171 -0
- package/dist/functions/pipelines.d.ts.map +1 -0
- package/dist/functions/prompt-configs.d.ts +125 -0
- package/dist/functions/prompt-configs.d.ts.map +1 -0
- package/dist/functions/roles.d.ts +118 -0
- package/dist/functions/roles.d.ts.map +1 -0
- package/dist/functions/system-cron.d.ts +65 -0
- package/dist/functions/system-cron.d.ts.map +1 -0
- package/dist/functions/system.d.ts +29 -0
- package/dist/functions/system.d.ts.map +1 -0
- package/dist/functions/tests.d.ts +28 -0
- package/dist/functions/tests.d.ts.map +1 -0
- package/dist/functions/timers.d.ts +139 -0
- package/dist/functions/timers.d.ts.map +1 -0
- package/dist/functions/triggers.d.ts +203 -0
- package/dist/functions/triggers.d.ts.map +1 -0
- package/dist/functions/types.d.ts +151 -0
- package/dist/functions/types.d.ts.map +1 -0
- package/dist/src/types/types.d.ts +364 -0
- package/dist/src/types/types.d.ts.map +1 -0
- package/package.json +192 -0
- package/scripts/app-install-cli.ts +286 -0
- package/scripts/assemble-frontend.sh +79 -0
- package/scripts/assemble-functions.sh +62 -0
- package/scripts/assemble.sh +35 -0
- package/scripts/boundary-check.sh +106 -0
- package/scripts/build-manifest.sh +80 -0
- package/scripts/check-core-integrity.sh +82 -0
- package/scripts/ingest-chunks.cjs +202 -0
- package/scripts/kb-chunk-parser.cjs +312 -0
- package/scripts/kb-chunk-parser.ts +330 -0
- package/scripts/load-test-app-install.ts +484 -0
- package/scripts/netlify-dev-wrapper.sh +22 -0
- package/scripts/verify-integrity.sh +69 -0
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module logs
|
|
3
|
+
* @audience core-contributor
|
|
4
|
+
* @layer api-handler
|
|
5
|
+
* @stability stable
|
|
6
|
+
*
|
|
7
|
+
* Read API for the `v2.logs` table plus a write endpoint for external log
|
|
8
|
+
* ingestion. The `logs` table schema uses internal column names
|
|
9
|
+
* (`level`, `source`, `source_type`, `source_id`, `context`) that differ from
|
|
10
|
+
* the stable frontend contract. All reads are mapped through `mapLogRow`.
|
|
11
|
+
*
|
|
12
|
+
* **Routed by:** `GET/POST /.netlify/functions/logs`
|
|
13
|
+
*
|
|
14
|
+
* **Actions:**
|
|
15
|
+
* | method | ?action | handler |
|
|
16
|
+
* |--------|---------|------------------|
|
|
17
|
+
* | GET | account | listAccount |
|
|
18
|
+
* | GET | target | listTarget |
|
|
19
|
+
* | GET | person | listPerson |
|
|
20
|
+
* | GET | stats | getStats |
|
|
21
|
+
* | GET | search | search |
|
|
22
|
+
* | POST | cleanup | cleanup |
|
|
23
|
+
* | POST | (default)| log |
|
|
24
|
+
*
|
|
25
|
+
* **Authorization:** All operations use `ctx.db` (RLS-scoped, always filtered
|
|
26
|
+
* to `account_id`). No inserts are made by this module — `emitLog` from
|
|
27
|
+
* `_shared/audit.ts` is the canonical write path.
|
|
28
|
+
*
|
|
29
|
+
* **Column mapping (DB → API):**
|
|
30
|
+
* | DB column | API field |
|
|
31
|
+
* |--------------|-------------|
|
|
32
|
+
* | level | event_type |
|
|
33
|
+
* | person_id | actor_id |
|
|
34
|
+
* | source_type | target_type |
|
|
35
|
+
* | source_id | target_id |
|
|
36
|
+
* | source | action |
|
|
37
|
+
* | context | details |
|
|
38
|
+
*
|
|
39
|
+
* @seeAlso audit.ts (emitLog — canonical write path for all system events)
|
|
40
|
+
* @seeAlso observability.ts (aggregated metrics over logs)
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
import { createHandler, json, error, parseBody } from './_shared/middleware'
|
|
44
|
+
|
|
45
|
+
// ─── HELPERS ─────────────────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
// ─── CHUNK_START: LOGS_MAP_ROW ──────────────────────────────────────────────
|
|
48
|
+
/**
|
|
49
|
+
* @chunk-id LOGS_MAP_ROW_1_0_0
|
|
50
|
+
* @version 1.0.0
|
|
51
|
+
* @hash 52289a18616b71c05c908c27f2fd5d09837e7b861d30b9307bb6bdf265dd4845
|
|
52
|
+
* @macro Log Row Mapper
|
|
53
|
+
* @micro Maps raw DB log rows to stable frontend API contract
|
|
54
|
+
* @inputs row: any — Raw database log row from v2.logs table
|
|
55
|
+
* @outputs object — Mapped log row with API field names
|
|
56
|
+
* @depends-on [none]
|
|
57
|
+
* @depended-by [listAccount, listTarget, listPerson, search]
|
|
58
|
+
* @side-effects [none]
|
|
59
|
+
* @tags logs, mapping, helper, api-contract
|
|
60
|
+
*/
|
|
61
|
+
function mapLogRow(row: any) {
|
|
62
|
+
return {
|
|
63
|
+
id: row.id,
|
|
64
|
+
event_type: row.level,
|
|
65
|
+
actor_id: row.person_id,
|
|
66
|
+
target_type: row.source_type,
|
|
67
|
+
target_id: row.source_id,
|
|
68
|
+
action: row.source,
|
|
69
|
+
message: row.message,
|
|
70
|
+
details: row.context,
|
|
71
|
+
metadata: row.metadata,
|
|
72
|
+
created_at: row.created_at,
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// ─── CHUNK_END: LOGS_MAP_ROW ────────────────────────────────────────────────
|
|
76
|
+
|
|
77
|
+
// ─── HANDLERS ─────────────────────────────────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
// ─── CHUNK_START: LOGS_LIST_ACCOUNT ──────────────────────────────────────────────
|
|
80
|
+
/**
|
|
81
|
+
* @chunk-id LOGS_LIST_ACCOUNT_1_0_0
|
|
82
|
+
* @version 1.0.0
|
|
83
|
+
* @hash d512e35890e479c88f4e6130567b16b1143a164705fca4e887aee643cc76a1e5
|
|
84
|
+
* @macro Account Logs List Handler
|
|
85
|
+
* @micro Lists all account log entries with filtering and mapping
|
|
86
|
+
* @inputs ctx: CoreContext — Request context with principal and database
|
|
87
|
+
* @inputs body: any — Request body (unused for GET)
|
|
88
|
+
* @outputs Array of mapped log rows with API field names
|
|
89
|
+
* @depends-on [createHandler, mapLogRow]
|
|
90
|
+
* @depended-by [Netlify function routing]
|
|
91
|
+
* @side-effects [DB queries, row mapping]
|
|
92
|
+
* @tags logs, list, account, pagination
|
|
93
|
+
*/
|
|
94
|
+
export const listAccount = createHandler(async (ctx, body) => {
|
|
95
|
+
const { event_type, target_type, date_from, date_to, limit = 100, offset = 0 } = ctx.query || {}
|
|
96
|
+
|
|
97
|
+
if (!ctx.accountId) {
|
|
98
|
+
throw new Error('Account context required')
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let query = ctx.db
|
|
102
|
+
.from('logs')
|
|
103
|
+
.select('*')
|
|
104
|
+
.eq('account_id', ctx.accountId)
|
|
105
|
+
.order('created_at', { ascending: false })
|
|
106
|
+
|
|
107
|
+
if (event_type) query = query.eq('level', event_type)
|
|
108
|
+
if (target_type) query = query.eq('source_type', target_type)
|
|
109
|
+
if (date_from) query = query.gte('created_at', date_from)
|
|
110
|
+
if (date_to) query = query.lte('created_at', date_to)
|
|
111
|
+
|
|
112
|
+
const { data, error: err } = await query.range(
|
|
113
|
+
parseInt(offset.toString()),
|
|
114
|
+
parseInt(offset.toString()) + parseInt(limit.toString()) - 1
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
if (err) throw err
|
|
118
|
+
|
|
119
|
+
return (data || []).map(mapLogRow)
|
|
120
|
+
})
|
|
121
|
+
// ─── CHUNK_END: LOGS_LIST_ACCOUNT ────────────────────────────────────────────────
|
|
122
|
+
|
|
123
|
+
// ─── CHUNK_START: LOGS_LIST_TARGET ──────────────────────────────────────────────
|
|
124
|
+
/**
|
|
125
|
+
* @chunk-id LOGS_LIST_TARGET_1_0_0
|
|
126
|
+
* @version 1.0.0
|
|
127
|
+
* @hash 7ea27876f183b59057284ca9007aed6e0e65050b196f00756b8ad5715073e745
|
|
128
|
+
* @macro Target Logs List Handler
|
|
129
|
+
* @micro Lists log entries for specific target entity with filtering
|
|
130
|
+
* @inputs ctx: CoreContext — Request context with principal and database
|
|
131
|
+
* @inputs body: any — Request body (unused for GET)
|
|
132
|
+
* @outputs Array of mapped log rows for target entity
|
|
133
|
+
* @depends-on [createHandler, mapLogRow]
|
|
134
|
+
* @depended-by [Netlify function routing]
|
|
135
|
+
* @side-effects [DB queries, row mapping]
|
|
136
|
+
* @tags logs, list, target, entity-specific
|
|
137
|
+
*/
|
|
138
|
+
export const listTarget = createHandler(async (ctx, body) => {
|
|
139
|
+
const { target_type, target_id, event_type, limit = 100, offset = 0 } = ctx.query || {}
|
|
140
|
+
|
|
141
|
+
if (!target_type || !target_id) {
|
|
142
|
+
throw new Error('target_type and target_id are required')
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!ctx.accountId) {
|
|
146
|
+
throw new Error('Account context required')
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
let query = ctx.db
|
|
150
|
+
.from('logs')
|
|
151
|
+
.select('*')
|
|
152
|
+
.eq('account_id', ctx.accountId)
|
|
153
|
+
.eq('source_type', target_type)
|
|
154
|
+
.eq('source_id', target_id)
|
|
155
|
+
.order('created_at', { ascending: false })
|
|
156
|
+
|
|
157
|
+
if (event_type) query = query.eq('level', event_type)
|
|
158
|
+
|
|
159
|
+
const { data, error: err } = await query.range(
|
|
160
|
+
parseInt(offset.toString()),
|
|
161
|
+
parseInt(offset.toString()) + parseInt(limit.toString()) - 1
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
if (err) throw err
|
|
165
|
+
|
|
166
|
+
return (data || []).map(mapLogRow)
|
|
167
|
+
})
|
|
168
|
+
// ─── CHUNK_END: LOGS_LIST_TARGET ────────────────────────────────────────────────
|
|
169
|
+
|
|
170
|
+
// ─── CHUNK_START: LOGS_LIST_PERSON ──────────────────────────────────────────────
|
|
171
|
+
/**
|
|
172
|
+
* @chunk-id LOGS_LIST_PERSON_1_0_0
|
|
173
|
+
* @version 1.0.0
|
|
174
|
+
* @hash 1c502ddeac8766153f1cc9ff6ffc8a7804dd83519d3c2e8b11dcf610fc6d6dfe
|
|
175
|
+
* @macro Person Activity Feed Handler
|
|
176
|
+
* @micro Returns activity feed for person with system event filtering
|
|
177
|
+
* @inputs ctx: CoreContext — Request context with principal and database
|
|
178
|
+
* @inputs body: any — Request body (unused for GET)
|
|
179
|
+
* @outputs Array of mapped log rows for person activity
|
|
180
|
+
* @depends-on [createHandler, mapLogRow]
|
|
181
|
+
* @depended-by [Netlify function routing]
|
|
182
|
+
* @side-effects [DB queries, row mapping]
|
|
183
|
+
* @tags logs, list, person, activity-feed
|
|
184
|
+
*/
|
|
185
|
+
export const listPerson = createHandler(async (ctx, body) => {
|
|
186
|
+
const { person_id, include_system, limit = 50, offset = 0 } = ctx.query || {}
|
|
187
|
+
|
|
188
|
+
const targetPersonId = person_id || ctx.principal?.id
|
|
189
|
+
|
|
190
|
+
if (!targetPersonId) {
|
|
191
|
+
throw new Error('Person ID is required')
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (!ctx.accountId) {
|
|
195
|
+
throw new Error('Account context required')
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
let query = ctx.db
|
|
199
|
+
.from('logs')
|
|
200
|
+
.select('*')
|
|
201
|
+
.eq('account_id', ctx.accountId)
|
|
202
|
+
.eq('person_id', targetPersonId)
|
|
203
|
+
.order('created_at', { ascending: false })
|
|
204
|
+
|
|
205
|
+
if (include_system !== 'true') {
|
|
206
|
+
query = query.neq('level', 'system')
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const { data, error: err } = await query.range(
|
|
210
|
+
parseInt(offset.toString()),
|
|
211
|
+
parseInt(offset.toString()) + parseInt(limit.toString()) - 1
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
if (err) throw err
|
|
215
|
+
|
|
216
|
+
return (data || []).map(mapLogRow)
|
|
217
|
+
})
|
|
218
|
+
// ─── CHUNK_END: LOGS_LIST_PERSON ────────────────────────────────────────────────
|
|
219
|
+
|
|
220
|
+
// ─── CHUNK_START: LOGS_GET_STATS ──────────────────────────────────────────────
|
|
221
|
+
/**
|
|
222
|
+
* @chunk-id LOGS_GET_STATS_1_0_0
|
|
223
|
+
* @version 1.0.0
|
|
224
|
+
* @hash a25e065d770b9658aa1a7d1db325e044febbac498c06cad735e18167442a2674
|
|
225
|
+
* @macro Logs Statistics Handler
|
|
226
|
+
* @micro Returns log counts by event type with date range filtering
|
|
227
|
+
* @inputs ctx: CoreContext — Request context with principal and database
|
|
228
|
+
* @inputs body: any — Request body (unused for GET)
|
|
229
|
+
* @outputs {total: number, by_type: Record<string, number>} — Log statistics
|
|
230
|
+
* @depends-on [createHandler]
|
|
231
|
+
* @depended-by [Netlify function routing]
|
|
232
|
+
* @side-effects [DB count query, aggregation]
|
|
233
|
+
* @tags logs, stats, analytics, monitoring
|
|
234
|
+
*/
|
|
235
|
+
export const getStats = createHandler(async (ctx, body) => {
|
|
236
|
+
const { date_from, date_to } = ctx.query || {}
|
|
237
|
+
|
|
238
|
+
if (!ctx.accountId) {
|
|
239
|
+
throw new Error('Account context required')
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
let query = ctx.db
|
|
243
|
+
.from('logs')
|
|
244
|
+
.select('id, level')
|
|
245
|
+
.eq('account_id', ctx.accountId)
|
|
246
|
+
|
|
247
|
+
if (date_from) query = query.gte('created_at', date_from)
|
|
248
|
+
if (date_to) query = query.lte('created_at', date_to)
|
|
249
|
+
|
|
250
|
+
const { data, error: err } = await query
|
|
251
|
+
|
|
252
|
+
if (err) throw err
|
|
253
|
+
|
|
254
|
+
const rows = data || []
|
|
255
|
+
const by_type: Record<string, number> = {}
|
|
256
|
+
for (const row of rows) {
|
|
257
|
+
by_type[row.level] = (by_type[row.level] || 0) + 1
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return { total: rows.length, by_type }
|
|
261
|
+
})
|
|
262
|
+
// ─── CHUNK_END: LOGS_GET_STATS ────────────────────────────────────────────────
|
|
263
|
+
|
|
264
|
+
// ─── CHUNK_START: LOGS_SEARCH ──────────────────────────────────────────────
|
|
265
|
+
/**
|
|
266
|
+
* @chunk-id LOGS_SEARCH_1_0_0
|
|
267
|
+
* @version 1.0.0
|
|
268
|
+
* @hash 25f4552cc8b604e280e77c9180dea6435c99f864f8d1578af44ea68793c4c67d
|
|
269
|
+
* @macro Logs Text Search Handler
|
|
270
|
+
* @micro Performs full-text search on log messages with filtering
|
|
271
|
+
* @inputs ctx: CoreContext — Request context with principal and database
|
|
272
|
+
* @inputs body: any — Request body (unused for GET)
|
|
273
|
+
* @outputs Array of mapped log rows matching search query
|
|
274
|
+
* @depends-on [createHandler, mapLogRow]
|
|
275
|
+
* @depended-by [Netlify function routing]
|
|
276
|
+
* @side-effects [DB ILIKE search, row mapping]
|
|
277
|
+
* @tags logs, search, text-search, ilike
|
|
278
|
+
*/
|
|
279
|
+
export const search = createHandler(async (ctx, body) => {
|
|
280
|
+
const { query: searchQuery, event_type, target_type, limit = 50, offset = 0 } = ctx.query || {}
|
|
281
|
+
|
|
282
|
+
if (!searchQuery) {
|
|
283
|
+
throw new Error('Search query is required')
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (!ctx.accountId) {
|
|
287
|
+
throw new Error('Account context required')
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
let query = ctx.db
|
|
291
|
+
.from('logs')
|
|
292
|
+
.select('*')
|
|
293
|
+
.eq('account_id', ctx.accountId)
|
|
294
|
+
.ilike('message', `%${searchQuery}%`)
|
|
295
|
+
.order('created_at', { ascending: false })
|
|
296
|
+
|
|
297
|
+
if (event_type) query = query.eq('level', event_type)
|
|
298
|
+
if (target_type) query = query.eq('source_type', target_type)
|
|
299
|
+
|
|
300
|
+
const { data, error: err } = await query.range(
|
|
301
|
+
parseInt(offset.toString()),
|
|
302
|
+
parseInt(offset.toString()) + parseInt(limit.toString()) - 1
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
if (err) throw err
|
|
306
|
+
|
|
307
|
+
return (data || []).map(mapLogRow)
|
|
308
|
+
})
|
|
309
|
+
// ─── CHUNK_END: LOGS_SEARCH ────────────────────────────────────────────────
|
|
310
|
+
|
|
311
|
+
// ─── CHUNK_START: LOGS_LOG ──────────────────────────────────────────────
|
|
312
|
+
/**
|
|
313
|
+
* @chunk-id LOGS_LOG_1_0_0
|
|
314
|
+
* @version 1.0.0
|
|
315
|
+
* @hash 521255a8c1a7e4110e2873050c8b58c8819fa6540bb039d30117946ef741633f
|
|
316
|
+
* @macro Log Entry Writer
|
|
317
|
+
* @micro Writes external log entry with field mapping and validation
|
|
318
|
+
* @inputs ctx: CoreContext — Request context with principal and database
|
|
319
|
+
* @inputs body: object — Log data including event_type and optional fields
|
|
320
|
+
* @outputs {log_id: string} — ID of created log entry
|
|
321
|
+
* @depends-on [createHandler]
|
|
322
|
+
* @depended-by [Netlify function routing]
|
|
323
|
+
* @side-effects [DB insert with field mapping]
|
|
324
|
+
* @tags logs, create, external, instrumentation
|
|
325
|
+
*/
|
|
326
|
+
export const log = createHandler(async (ctx, body) => {
|
|
327
|
+
const { event_type, target_type, target_id, action, message, details, metadata } = body
|
|
328
|
+
|
|
329
|
+
if (!event_type) {
|
|
330
|
+
throw new Error('event_type is required')
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (!ctx.accountId) {
|
|
334
|
+
throw new Error('Account context required')
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const { data, error: err } = await ctx.db
|
|
338
|
+
.from('logs')
|
|
339
|
+
.insert({
|
|
340
|
+
level: event_type,
|
|
341
|
+
message: message || action || event_type,
|
|
342
|
+
source: action || null,
|
|
343
|
+
source_type: target_type || null,
|
|
344
|
+
source_id: target_id || null,
|
|
345
|
+
person_id: ctx.principal?.id || null,
|
|
346
|
+
account_id: ctx.accountId,
|
|
347
|
+
context: details || {},
|
|
348
|
+
metadata: metadata || {},
|
|
349
|
+
})
|
|
350
|
+
.select('id')
|
|
351
|
+
.single()
|
|
352
|
+
|
|
353
|
+
if (err) throw err
|
|
354
|
+
|
|
355
|
+
return { log_id: data?.id }
|
|
356
|
+
})
|
|
357
|
+
// ─── CHUNK_END: LOGS_LOG ────────────────────────────────────────────────
|
|
358
|
+
|
|
359
|
+
// ─── CHUNK_START: LOGS_CLEANUP ──────────────────────────────────────────────
|
|
360
|
+
/**
|
|
361
|
+
* @chunk-id LOGS_CLEANUP_1_0_0
|
|
362
|
+
* @version 1.0.0
|
|
363
|
+
* @hash 3790847ac4c98e79285483511dcc23c303dc339b4988ac5715c1f165a1bb29c9
|
|
364
|
+
* @macro Logs Cleanup Handler
|
|
365
|
+
* @micro Deletes old log entries beyond retention period
|
|
366
|
+
* @inputs ctx: CoreContext — Request context with principal and database
|
|
367
|
+
* @inputs body: object — days_to_keep (default 90)
|
|
368
|
+
* @outputs {deleted_count: number} — Number of deleted log entries
|
|
369
|
+
* @depends-on [createHandler]
|
|
370
|
+
* @depended-by [Netlify function routing, system-cron.ts]
|
|
371
|
+
* @side-effects [DB delete by date]
|
|
372
|
+
* @tags logs, cleanup, retention, maintenance
|
|
373
|
+
*/
|
|
374
|
+
export const cleanup = createHandler(async (ctx, body) => {
|
|
375
|
+
const { days_to_keep = 90 } = body
|
|
376
|
+
|
|
377
|
+
const cutoff = new Date()
|
|
378
|
+
cutoff.setDate(cutoff.getDate() - parseInt(days_to_keep.toString()))
|
|
379
|
+
|
|
380
|
+
const { data, error: err } = await ctx.db
|
|
381
|
+
.from('logs')
|
|
382
|
+
.delete()
|
|
383
|
+
.lt('created_at', cutoff.toISOString())
|
|
384
|
+
.select('id')
|
|
385
|
+
|
|
386
|
+
if (err) throw err
|
|
387
|
+
|
|
388
|
+
return { deleted_count: (data || []).length }
|
|
389
|
+
})
|
|
390
|
+
// ─── CHUNK_END: LOGS_CLEANUP ────────────────────────────────────────────────
|
|
391
|
+
|
|
392
|
+
// ─── MAIN HANDLER ────────────────────────────────────────────────────────────
|
|
393
|
+
|
|
394
|
+
// ─── CHUNK_START: LOGS_HANDLER ──────────────────────────────────────────────
|
|
395
|
+
/**
|
|
396
|
+
* @chunk-id LOGS_HANDLER_1_0_0
|
|
397
|
+
* @version 1.0.0
|
|
398
|
+
* @hash 62e729c4e43a30a85394c5ed66a1c2a12898135b133b8b712f481670d2351b22
|
|
399
|
+
* @macro Logs Router
|
|
400
|
+
* @micro Routes HTTP methods and actions to appropriate log handlers
|
|
401
|
+
* @inputs ctx: CoreContext — Request context with principal and database
|
|
402
|
+
* @inputs body: any — Request body for POST operations
|
|
403
|
+
* @outputs Varies — Depends on routed handler (listAccount/listTarget/listPerson/getStats/search/cleanup/log)
|
|
404
|
+
* @depends-on [createHandler, listAccount, listTarget, listPerson, getStats, search, cleanup, log]
|
|
405
|
+
* @depended-by [Netlify function routing]
|
|
406
|
+
* @side-effects [Delegates to appropriate handler]
|
|
407
|
+
* @tags logs, router, crud, netlify-function
|
|
408
|
+
*/
|
|
409
|
+
export const handler = createHandler(async (ctx, body) => {
|
|
410
|
+
const { action } = ctx.query || {}
|
|
411
|
+
const method = ctx.query?.method || 'GET'
|
|
412
|
+
|
|
413
|
+
switch (action) {
|
|
414
|
+
case 'account':
|
|
415
|
+
if (method === 'GET') return await listAccount(ctx, body)
|
|
416
|
+
break
|
|
417
|
+
case 'target':
|
|
418
|
+
if (method === 'GET') return await listTarget(ctx, body)
|
|
419
|
+
break
|
|
420
|
+
case 'person':
|
|
421
|
+
if (method === 'GET') return await listPerson(ctx, body)
|
|
422
|
+
break
|
|
423
|
+
case 'stats':
|
|
424
|
+
if (method === 'GET') return await getStats(ctx, body)
|
|
425
|
+
break
|
|
426
|
+
case 'search':
|
|
427
|
+
if (method === 'GET') return await search(ctx, body)
|
|
428
|
+
break
|
|
429
|
+
case 'cleanup':
|
|
430
|
+
if (method === 'POST') return await cleanup(ctx, body)
|
|
431
|
+
break
|
|
432
|
+
default:
|
|
433
|
+
if (method === 'POST') return await log(ctx, body)
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
throw new Error('Invalid action or method')
|
|
437
|
+
})
|
|
438
|
+
// ─── CHUNK_END: LOGS_HANDLER ────────────────────────────────────────────────
|