spine-framework 0.4.4 → 0.5.0-rc.4
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/.env.example +13 -3
- package/.framework/cli/commands/bootstrap.ts +392 -0
- package/.framework/cli/commands/dev.ts +91 -218
- package/.framework/cli/commands/doctor.ts +132 -26
- package/.framework/cli/commands/generate.ts +38 -298
- package/.framework/cli/commands/init.ts +20 -1
- package/.framework/cli/commands/migrate.ts +36 -30
- package/.framework/cli/commands/migrations.ts +16 -56
- package/.framework/cli/commands/upgrade.ts +35 -0
- package/.framework/cli/commands/validate-schema.ts +147 -0
- package/.framework/cli/context.ts +223 -110
- package/.framework/cli/index.ts +6 -0
- package/.framework/cli/lib/project-files.ts +241 -1
- package/.framework/functions/_shared/hash-api-key.ts +183 -79
- package/.framework/functions/_shared/logging.ts +562 -224
- package/.framework/functions/_shared/middleware.ts +47 -44
- package/.framework/functions/admin-data.ts +39 -28
- package/.framework/functions/ai-agents.ts +10 -6
- package/.framework/functions/api-keys.ts +301 -122
- package/.framework/functions/apps.ts +43 -26
- package/.framework/functions/cil-ingest.ts +48 -15
- package/.framework/functions/debug-auth.ts +14 -8
- package/.framework/functions/deliveries.ts +39 -12
- package/.framework/functions/embeddings.ts +145 -76
- package/.framework/functions/integration-outbound.ts +67 -27
- package/.framework/functions/integrations.ts +254 -127
- package/.framework/functions/logs.ts +273 -133
- package/.framework/functions/observability.ts +277 -147
- package/.framework/functions/pipeline-executions.ts +1 -1
- package/.framework/functions/pipelines.ts +14 -9
- package/.framework/functions/prompt-configs.ts +7 -4
- package/.framework/functions/roles.ts +8 -5
- package/.framework/functions/security.ts +30 -17
- package/.framework/functions/system-cron.ts +240 -127
- package/.framework/functions/tests.ts +7 -6
- package/.framework/functions/timers.ts +310 -107
- package/.framework/functions/triggers.ts +28 -13
- package/.framework/functions/types.ts +13 -10
- package/.framework/migrations/069_log_stats_window.sql +54 -0
- package/.framework/migrations/070_app_type_schema_rpcs.sql +166 -0
- package/.framework/migrations/071_timer_interval_keys.sql +96 -0
- package/.framework/migrations/072_slug_autofill.sql +77 -0
- package/.framework/migrations/073_seed_member_roles.sql +26 -0
- package/.framework/src/apps/admin/index.tsx +1141 -775
- package/.framework/src/components/ErrorBoundary.tsx +136 -0
- package/.framework/src/components/admin/AdminListPage.tsx +81 -73
- package/.framework/src/components/admin/AdminSidebar.tsx +88 -79
- package/.framework/src/components/admin/EntitySelect.tsx +181 -0
- package/.framework/src/components/admin/PageInstructions.tsx +86 -127
- package/.framework/src/components/app-shell/GenericDetailPage.tsx +37 -13
- package/.framework/src/components/app-shell/GenericListPage.tsx +28 -32
- package/.framework/src/components/layout/Sidebar.tsx +300 -177
- package/.framework/src/components/runtime/DataDetailPage.tsx +67 -35
- package/.framework/src/components/runtime/DataHeader.tsx +96 -48
- package/.framework/src/components/runtime/DataListPage.tsx +3 -26
- package/.framework/src/components/runtime/DataStats.tsx +10 -10
- package/.framework/src/components/runtime/DataTable.tsx +12 -10
- package/.framework/src/components/ui/sheet.tsx +24 -26
- package/.framework/src/components/ui/textarea.tsx +74 -48
- package/.framework/src/hooks/useEntityList.ts +12 -9
- package/.framework/src/hooks/useListSchema.ts +108 -58
- package/.framework/src/instructions/README.md +57 -0
- package/.framework/src/instructions/ai-agents.md +69 -0
- package/.framework/src/instructions/alerts.md +80 -0
- package/.framework/src/instructions/api-keys.md +87 -0
- package/.framework/src/instructions/apps.md +77 -0
- package/.framework/src/instructions/concepts/ai-and-prompts.md +150 -0
- package/.framework/src/instructions/concepts/apps-and-renderers.md +162 -0
- package/.framework/src/instructions/concepts/auth-and-api-keys.md +133 -0
- package/.framework/src/instructions/concepts/automation.md +186 -0
- package/.framework/src/instructions/concepts/concurrency-and-idempotency.md +125 -0
- package/.framework/src/instructions/concepts/core-vs-custom.md +124 -0
- package/.framework/src/instructions/concepts/design-schema.md +152 -0
- package/.framework/src/instructions/concepts/integrations-and-webhooks.md +127 -0
- package/.framework/src/instructions/concepts/observability.md +116 -0
- package/.framework/src/instructions/concepts/permissions.md +150 -0
- package/.framework/src/instructions/concepts/runtime-records.md +111 -0
- package/.framework/src/instructions/concepts/scope-and-accounts.md +112 -0
- package/.framework/src/instructions/concepts/spine-way.md +172 -0
- package/.framework/src/instructions/deliveries.md +59 -0
- package/.framework/src/instructions/guide/00-orientation.md +106 -0
- package/.framework/src/instructions/guide/01-install-and-first-run.md +253 -0
- package/.framework/src/instructions/guide/02-project-map.md +147 -0
- package/.framework/src/instructions/guide/03-domain-model.md +223 -0
- package/.framework/src/instructions/guide/04-first-app.md +227 -0
- package/.framework/src/instructions/guide/05-glossary.md +183 -0
- package/.framework/src/instructions/integrations.md +96 -0
- package/.framework/src/instructions/internal/cil-markers.md +83 -0
- package/.framework/src/instructions/invites.md +60 -0
- package/.framework/src/instructions/kb.md +80 -0
- package/.framework/src/instructions/logs.md +77 -0
- package/.framework/src/instructions/observability.md +61 -0
- package/.framework/src/instructions/operations/deployment.md +115 -0
- package/.framework/src/instructions/operations/migrations.md +125 -0
- package/.framework/src/instructions/operations/security-checklist.md +148 -0
- package/.framework/src/instructions/operations/troubleshooting.md +170 -0
- package/.framework/src/instructions/operations/upgrade.md +116 -0
- package/.framework/src/instructions/pipeline-executions.md +62 -0
- package/.framework/src/instructions/pipelines.md +78 -0
- package/.framework/src/instructions/prompts.md +95 -0
- package/.framework/src/instructions/reference/api/admin-data.md +162 -0
- package/.framework/src/instructions/reference/api/auth.md +113 -0
- package/.framework/src/instructions/reference/api/errors-and-envelopes.md +113 -0
- package/.framework/src/instructions/reference/app-manifest.md +150 -0
- package/.framework/src/instructions/reference/cli.md +124 -0
- package/.framework/src/instructions/reference/database.md +132 -0
- package/.framework/src/instructions/reference/design-schema.md +280 -0
- package/.framework/src/instructions/reference/env-vars.md +133 -0
- package/.framework/src/instructions/reference/functions/account-nodes.md +75 -0
- package/.framework/src/instructions/reference/functions/admin-data.md +195 -0
- package/.framework/src/instructions/reference/functions/admin-funnel.md +90 -0
- package/.framework/src/instructions/reference/functions/admin-install-funnel.md +107 -0
- package/.framework/src/instructions/reference/functions/admin-signals.md +102 -0
- package/.framework/src/instructions/reference/functions/ai-agents.md +148 -0
- package/.framework/src/instructions/reference/functions/ai-interactions.md +156 -0
- package/.framework/src/instructions/reference/functions/api-keys.md +130 -0
- package/.framework/src/instructions/reference/functions/apps.md +140 -0
- package/.framework/src/instructions/reference/functions/auth.md +99 -0
- package/.framework/src/instructions/reference/functions/debug-auth.md +91 -0
- package/.framework/src/instructions/reference/functions/deliveries.md +110 -0
- package/.framework/src/instructions/reference/functions/embeddings.md +166 -0
- package/.framework/src/instructions/reference/functions/eval-harness.md +149 -0
- package/.framework/src/instructions/reference/functions/index.md +103 -0
- package/.framework/src/instructions/reference/functions/integration-outbound.md +200 -0
- package/.framework/src/instructions/reference/functions/integration-routes.md +151 -0
- package/.framework/src/instructions/reference/functions/integrations.md +130 -0
- package/.framework/src/instructions/reference/functions/invites.md +182 -0
- package/.framework/src/instructions/reference/functions/item-progress.md +107 -0
- package/.framework/src/instructions/reference/functions/kb.md +166 -0
- package/.framework/src/instructions/reference/functions/logs.md +141 -0
- package/.framework/src/instructions/reference/functions/observability.md +105 -0
- package/.framework/src/instructions/reference/functions/pipeline-executions.md +132 -0
- package/.framework/src/instructions/reference/functions/pipeline-runner-background.md +121 -0
- package/.framework/src/instructions/reference/functions/pipelines.md +136 -0
- package/.framework/src/instructions/reference/functions/prompt-configs.md +121 -0
- package/.framework/src/instructions/reference/functions/roles.md +121 -0
- package/.framework/src/instructions/reference/functions/security.md +140 -0
- package/.framework/src/instructions/reference/functions/system-cron.md +136 -0
- package/.framework/src/instructions/reference/functions/system.md +106 -0
- package/.framework/src/instructions/reference/functions/tests.md +97 -0
- package/.framework/src/instructions/reference/functions/timers.md +117 -0
- package/.framework/src/instructions/reference/functions/trigger-scheduler.md +102 -0
- package/.framework/src/instructions/reference/functions/triggers.md +140 -0
- package/.framework/src/instructions/reference/functions/types.md +146 -0
- package/.framework/src/instructions/reference/seeds.md +126 -0
- package/.framework/src/instructions/reference/shared-modules.md +127 -0
- package/.framework/src/instructions/reference/spine-config.md +114 -0
- package/.framework/src/instructions/roles.md +80 -0
- package/.framework/src/instructions/runtime-detail.md +70 -0
- package/.framework/src/instructions/runtime-list.md +77 -0
- package/.framework/src/instructions/security.md +67 -0
- package/.framework/src/instructions/tasks/add-a-pipeline.md +110 -0
- package/.framework/src/instructions/tasks/add-a-role.md +96 -0
- package/.framework/src/instructions/tasks/add-a-timer.md +114 -0
- package/.framework/src/instructions/tasks/add-a-trigger.md +106 -0
- package/.framework/src/instructions/tasks/add-a-type.md +151 -0
- package/.framework/src/instructions/tasks/add-a-webhook.md +108 -0
- package/.framework/src/instructions/tasks/add-an-ai-agent.md +108 -0
- package/.framework/src/instructions/tasks/add-an-integration.md +124 -0
- package/.framework/src/instructions/tasks/build-a-custom-page.md +118 -0
- package/.framework/src/instructions/tasks/package-and-install-an-app.md +127 -0
- package/.framework/src/instructions/tasks/test-your-code.md +108 -0
- package/.framework/src/instructions/tasks/write-a-function.md +132 -0
- package/.framework/src/instructions/tasks/write-a-migration.md +110 -0
- package/.framework/src/instructions/testing.md +59 -0
- package/.framework/src/instructions/timers.md +82 -0
- package/.framework/src/instructions/triggers.md +69 -0
- package/.framework/src/instructions/types.md +93 -0
- package/.framework/src/pages/NotFoundPage.tsx +62 -31
- package/.framework/src/pages/admin/AIAgentDetailPage.tsx +117 -106
- package/.framework/src/pages/admin/AIAgentsPage.tsx +86 -48
- package/.framework/src/pages/admin/APIKeyDetailPage.tsx +153 -152
- package/.framework/src/pages/admin/APIKeysPage.tsx +91 -90
- package/.framework/src/pages/admin/AlertsConfigPage.tsx +29 -18
- package/.framework/src/pages/admin/AppDetailPage.tsx +6 -60
- package/.framework/src/pages/admin/AppsPage.tsx +104 -66
- package/.framework/src/pages/admin/DeliveriesPage.tsx +5 -5
- package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +5 -23
- package/.framework/src/pages/admin/EmbeddingsPage.tsx +5 -26
- package/.framework/src/pages/admin/IntegrationDetailPage.tsx +7 -7
- package/.framework/src/pages/admin/IntegrationsPage.tsx +85 -43
- package/.framework/src/pages/admin/LogsPage.tsx +144 -76
- package/.framework/src/pages/admin/ObservabilityDashboard.tsx +223 -140
- package/.framework/src/pages/admin/PipelineDetailPage.tsx +134 -113
- package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +108 -45
- package/.framework/src/pages/admin/PipelinesPage.tsx +160 -115
- package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +96 -98
- package/.framework/src/pages/admin/PromptConfigsPage.tsx +101 -59
- package/.framework/src/pages/admin/RoleDetailPage.tsx +90 -79
- package/.framework/src/pages/admin/RolesPage.tsx +86 -43
- package/.framework/src/pages/admin/SecurityPage.tsx +1 -1
- package/.framework/src/pages/admin/TestingDashboard.tsx +16 -28
- package/.framework/src/pages/admin/TimerDetailPage.tsx +117 -100
- package/.framework/src/pages/admin/TimersPage.tsx +90 -62
- package/.framework/src/pages/admin/TriggerDetailPage.tsx +90 -83
- package/.framework/src/pages/admin/TriggersPage.tsx +124 -99
- package/.framework/src/pages/admin/TypeDetailPage.tsx +152 -138
- package/.framework/src/pages/admin/TypesPage.tsx +90 -48
- package/.framework/src/pages/admin/cil/CILAgentPage.tsx +17 -25
- package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +17 -27
- package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +72 -40
- package/.framework/src/pages/admin/cil/CILFileListPage.tsx +321 -129
- package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +18 -29
- package/.framework/src/pages/admin/cil/CILGraphPage.tsx +26 -38
- package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +34 -46
- package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +189 -103
- package/.framework/src/pages/admin/cil/CILSearchPage.tsx +246 -136
- package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +11 -22
- package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +9 -20
- package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +26 -38
- package/.framework/src/pages/admin/kb/KBAdminPage.tsx +7 -26
- package/.framework/templates/agent/AGENTS.md +150 -0
- package/.framework/templates/agent/skills/spine-add-ai-agent/SKILL.md +58 -0
- package/.framework/templates/agent/skills/spine-add-automation/SKILL.md +62 -0
- package/.framework/templates/agent/skills/spine-add-integration/SKILL.md +63 -0
- package/.framework/templates/agent/skills/spine-architect/SKILL.md +86 -0
- package/.framework/templates/agent/skills/spine-install-app/SKILL.md +72 -0
- package/.framework/templates/agent/skills/spine-migration/SKILL.md +75 -0
- package/.framework/templates/agent/skills/spine-new-app/SKILL.md +67 -0
- package/.framework/templates/agent/skills/spine-new-function/SKILL.md +65 -0
- package/.framework/templates/agent/skills/spine-new-type/SKILL.md +65 -0
- package/.framework/templates/agent/skills/spine-schema/SKILL.md +77 -0
- package/.framework/templates/agent/skills/spine-test/SKILL.md +67 -0
- package/.framework/templates/agent/skills/spine-troubleshoot/SKILL.md +74 -0
- package/.framework/templates/agent/skills/spine-upgrade/SKILL.md +69 -0
- package/.framework/templates/project.json +4 -1
- package/.framework/tests/unit/account-scoping-gates.test.ts +392 -0
- package/.framework/tests/unit/agent-files.test.ts +355 -0
- package/.framework/tests/unit/agent-runner.test.ts +479 -44
- package/.framework/tests/unit/api-keys-create-scope-gate.test.ts +160 -0
- package/.framework/tests/unit/api-keys-omit-secret-fields.test.ts +38 -0
- package/.framework/tests/unit/bootstrap.test.ts +242 -0
- package/.framework/tests/unit/cli-context-api-key.test.ts +114 -0
- package/.framework/tests/unit/debug-auth.test.ts +38 -0
- package/.framework/tests/unit/deliveries-account-scoping.test.ts +185 -0
- package/.framework/tests/unit/integration-outbound-credentials.test.ts +167 -0
- package/.framework/tests/unit/integrations-audit-redaction.test.ts +130 -0
- package/.framework/tests/unit/logging-app-id.test.ts +75 -0
- package/.framework/tests/unit/system-context-denial.test.ts +145 -0
- package/.framework/tests/unit/system-cron.test.ts +240 -0
- package/.framework/tests/unit/timers.test.ts +159 -0
- package/README.md +125 -166
- package/config/tsconfig.cli.json +2 -2
- package/package.json +15 -4
- package/templates/project/package-lock.json +2 -2
- package/.framework/docs/admin-routes.md +0 -76
- package/.framework/docs/api-docs-progress.md +0 -38
- package/.framework/docs/api-governance.md +0 -146
- package/.framework/docs/api-testing-results.md +0 -212
- package/.framework/docs/assembly-launch-guide.md +0 -138
- package/.framework/docs/audit-results.md +0 -590
- package/.framework/docs/db-api-inventory.md +0 -95
- package/.framework/docs/gap-remediation-backlog.md +0 -103
- package/.framework/docs/ui-adoption-verification.md +0 -111
- package/.framework/docs/ui-api-coverage.md +0 -84
- package/.framework/docs/v2-compatibility-audit.md +0 -228
- package/.framework/mcp/index.ts +0 -133
- package/.framework/mcp/load-env.ts +0 -60
- package/.framework/mcp/shared/app-manifest.ts +0 -275
- package/.framework/mcp/shared/db.ts +0 -477
- package/.framework/mcp/shared/kb.ts +0 -118
- package/.framework/mcp/tools/architect.ts +0 -431
- package/.framework/mcp/tools/cil/context.ts +0 -345
- package/.framework/mcp/tools/cil/graph.ts +0 -242
- package/.framework/mcp/tools/cil/ingest.ts +0 -1217
- package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +0 -693
- package/.framework/mcp/tools/cil/pipeline.ts +0 -767
- package/.framework/mcp/tools/cil/project.ts +0 -791
- package/.framework/mcp/tools/cil/retrieval.ts +0 -336
- package/.framework/mcp/tools/cil/search-core.ts +0 -454
- package/.framework/mcp/tools/cil/search.ts +0 -97
- package/.framework/mcp/tools/cil/suggest.ts +0 -186
- package/.framework/mcp/tools/cil/validate.ts +0 -1369
- package/.framework/mcp/tools/kb/delete.ts +0 -139
- package/.framework/mcp/tools/kb/index.ts +0 -52
- package/.framework/mcp/tools/kb/ingest.ts +0 -84
- package/.framework/mcp/tools/kb/list-types.ts +0 -102
- package/.framework/mcp/tools/kb/publish.ts +0 -100
- package/.framework/mcp/tools/kb/reindex.ts +0 -86
- package/.framework/mcp/tools/kb/revoke.ts +0 -85
- package/.framework/mcp/tools/kb/search.ts +0 -101
- package/.framework/mcp/tools/kb/upsert.ts +0 -125
- package/.framework/mcp/tools/observability.ts +0 -510
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
// CIL[BEGIN stable_id="~/.framework/functions/timers.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/functions/timers.ts"]
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
/**
|
|
3
|
+
* @module timers
|
|
4
|
+
* @audience both
|
|
5
|
+
* @layer shared-core
|
|
6
|
+
* @stability stable
|
|
7
|
+
*
|
|
8
|
+
* This module provides timer-related functionalities within the application, leveraging shared middleware and database utilities. It is designed to handle various timer operations, ensuring proper logging and permission checks. INVARIANT: All timer operations must be executed by authenticated users with appropriate permissions.
|
|
9
|
+
*
|
|
10
|
+
* @seeAlso middleware.ts (provides request handling capabilities).
|
|
11
|
+
* @seeAlso db.ts (contains database access utilities).
|
|
12
|
+
* @seeAlso auditing.ts (handles logging of operations).
|
|
13
|
+
* @seeAlso permissions.ts (ensures proper access control).
|
|
14
|
+
*
|
|
15
|
+
* @cil-generated
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
10
26
|
|
|
11
27
|
|
|
12
28
|
|
|
@@ -17,21 +33,63 @@ import { joins, adminDb } from './_shared/db'
|
|
|
17
33
|
import { emitLog } from './_shared/audit'
|
|
18
34
|
import { sanitizeRecordData } from './_shared/permissions'
|
|
19
35
|
import { isSystemAdmin } from './_shared/principal'
|
|
20
|
-
// CIL[DOC-VECTOR type="context" content="purpose='Import shared utilities used by timer Netlify function handlers.'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
|
|
21
|
-
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
22
|
-
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
23
|
-
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
24
|
-
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
25
|
-
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
26
36
|
// CIL[END stable_id="~/.framework/functions/timers.ts:module_header:module_header"]
|
|
37
|
+
|
|
38
|
+
// Interval resolution mirrors public.update_timer_after_run (migration
|
|
39
|
+
// 071_timer_interval_keys.sql): config.interval_minutes (minutes) wins,
|
|
40
|
+
// then config.interval_seconds (seconds → minutes). A parseable
|
|
41
|
+
// config.run_at / config.schedule datetime is the fallback so 'once'
|
|
42
|
+
// timers can be armed too.
|
|
43
|
+
// CIL[BEGIN stable_id="~/.framework/functions/timers.ts:intervalMinutesFromConfig:function" type="function" identity="intervalMinutesFromConfig" parent="~/.framework/functions/timers.ts"]
|
|
44
|
+
function intervalMinutesFromConfig(config: any): number | null {
|
|
45
|
+
const minutes = Number(config?.interval_minutes)
|
|
46
|
+
if (Number.isFinite(minutes) && minutes > 0) return minutes
|
|
47
|
+
const seconds = Number(config?.interval_seconds)
|
|
48
|
+
if (Number.isFinite(seconds) && seconds > 0) return seconds / 60
|
|
49
|
+
return null
|
|
50
|
+
}
|
|
51
|
+
// CIL[END stable_id="~/.framework/functions/timers.ts:intervalMinutesFromConfig:function"]
|
|
52
|
+
|
|
53
|
+
// CIL[BEGIN stable_id="~/.framework/functions/timers.ts:computeNextExecution:function" type="function" identity="computeNextExecution" parent="~/.framework/functions/timers.ts"]
|
|
54
|
+
function computeNextExecution(config: any): string | null {
|
|
55
|
+
const minutes = intervalMinutesFromConfig(config)
|
|
56
|
+
if (minutes !== null) {
|
|
57
|
+
return new Date(Date.now() + minutes * 60_000).toISOString()
|
|
58
|
+
}
|
|
59
|
+
// Date.parse is too lenient (it parses cron text like '*/5 * * * *'
|
|
60
|
+
// into a date), so only ISO-shaped values are accepted as a one-shot
|
|
61
|
+
// fire time.
|
|
62
|
+
const raw = config?.run_at ?? config?.schedule
|
|
63
|
+
if (typeof raw !== 'string' || !/^\d{4}-\d{2}-\d{2}/.test(raw)) return null
|
|
64
|
+
const runAt = Date.parse(raw)
|
|
65
|
+
return Number.isFinite(runAt) ? new Date(runAt).toISOString() : null
|
|
66
|
+
}
|
|
67
|
+
// CIL[END stable_id="~/.framework/functions/timers.ts:computeNextExecution:function"]
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
27
83
|
// CIL[BEGIN stable_id="~/.framework/functions/timers.ts:list:constant" type="constant" identity="list" parent="~/.framework/functions/timers.ts"]
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
84
|
+
/**
|
|
85
|
+
* The 'list' constant retrieves a list of timers based on query parameters and the user's account context. It ensures that only authorized users can access the timer data.
|
|
86
|
+
*
|
|
87
|
+
* @throws Error — Account context required
|
|
88
|
+
* @sideEffects none
|
|
89
|
+
* @stability internal
|
|
90
|
+
* @calls isSystemAdmin, adminDb.from, sanitizeRecordData
|
|
91
|
+
* @cil-generated
|
|
92
|
+
*/
|
|
35
93
|
export const list = createHandler(async (ctx, _body) => {
|
|
36
94
|
const { app_id, timer_type, is_active } = ctx.query || {}
|
|
37
95
|
|
|
@@ -67,21 +125,32 @@ export const list = createHandler(async (ctx, _body) => {
|
|
|
67
125
|
|
|
68
126
|
return sanitized
|
|
69
127
|
})
|
|
70
|
-
// CIL[DOC-VECTOR type="context" content="purpose='List timers for the current account with optional filters.'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
|
|
71
|
-
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
72
|
-
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
73
|
-
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
74
|
-
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
75
|
-
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
76
128
|
// CIL[END stable_id="~/.framework/functions/timers.ts:list:constant"]
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
77
144
|
// CIL[BEGIN stable_id="~/.framework/functions/timers.ts:get:constant" type="constant" identity="get" parent="~/.framework/functions/timers.ts"]
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
145
|
+
/**
|
|
146
|
+
* Retrieves a timer record from the database based on a provided ID while ensuring that only authorized users can access the timer data.
|
|
147
|
+
*
|
|
148
|
+
* @throws Error — Timer ID is required, Error — database query error.
|
|
149
|
+
* @sideEffects none
|
|
150
|
+
* @stability internal
|
|
151
|
+
* @calls adminDb.from('timers'), ctx.db.from('timers'), sanitizeRecordData
|
|
152
|
+
* @cil-generated
|
|
153
|
+
*/
|
|
85
154
|
export const get = createHandler(async (ctx, _body) => {
|
|
86
155
|
const { id } = ctx.query || {}
|
|
87
156
|
|
|
@@ -101,23 +170,34 @@ export const get = createHandler(async (ctx, _body) => {
|
|
|
101
170
|
|
|
102
171
|
return await sanitizeRecordData(ctx, data, 'timer')
|
|
103
172
|
})
|
|
104
|
-
// CIL[DOC-VECTOR type="context" content="purpose='Fetch a single timer by ID.'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
|
|
105
|
-
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
106
|
-
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
107
|
-
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
108
|
-
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
109
|
-
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
110
173
|
// CIL[END stable_id="~/.framework/functions/timers.ts:get:constant"]
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
|
|
111
189
|
// CIL[BEGIN stable_id="~/.framework/functions/timers.ts:create:constant" type="constant" identity="create" parent="~/.framework/functions/timers.ts"]
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
190
|
+
/**
|
|
191
|
+
* Creates a new timer entry in the database based on the provided parameters, ensuring required fields are present and user context is valid. This function is essential for managing timer data within the application.
|
|
192
|
+
*
|
|
193
|
+
* @throws Error — name and timer_type are required, Error — User context (person and account) required, Error — database insert error
|
|
194
|
+
* @sideEffects DB write to 'timers' table, emits a log event for timer creation
|
|
195
|
+
* @stability internal
|
|
196
|
+
* @calls ctx.db.from('timers'), emitLog
|
|
197
|
+
* @cil-generated
|
|
198
|
+
*/
|
|
119
199
|
export const create = createHandler(async (ctx, body) => {
|
|
120
|
-
const { app_id, name, description, timer_type, config, pipeline_id, metadata } = body
|
|
200
|
+
const { app_id, name, description, timer_type, config, pipeline_id, metadata, is_active, next_execution } = body
|
|
121
201
|
|
|
122
202
|
if (!name || !timer_type) {
|
|
123
203
|
throw new Error('name and timer_type are required')
|
|
@@ -127,7 +207,13 @@ export const create = createHandler(async (ctx, body) => {
|
|
|
127
207
|
throw new Error('User context (person and account) required')
|
|
128
208
|
}
|
|
129
209
|
|
|
130
|
-
const
|
|
210
|
+
const effectiveConfig = config || {}
|
|
211
|
+
// Omitted is_active falls through to the column DEFAULT (true); the
|
|
212
|
+
// arming computation mirrors that assumption.
|
|
213
|
+
const willBeActive = is_active !== false
|
|
214
|
+
|
|
215
|
+
const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
|
|
216
|
+
const { data, error: err } = await db
|
|
131
217
|
.from('timers')
|
|
132
218
|
.insert({
|
|
133
219
|
app_id: app_id || null,
|
|
@@ -135,10 +221,15 @@ export const create = createHandler(async (ctx, body) => {
|
|
|
135
221
|
name,
|
|
136
222
|
description: description || null,
|
|
137
223
|
timer_type,
|
|
138
|
-
config:
|
|
224
|
+
config: effectiveConfig,
|
|
139
225
|
pipeline_id: pipeline_id || null,
|
|
140
226
|
metadata: metadata || {},
|
|
141
|
-
|
|
227
|
+
is_active,
|
|
228
|
+
// Arm the timer server-side: get_due_timers requires next_execution
|
|
229
|
+
// IS NOT NULL and nothing else writes it, so a timer created without
|
|
230
|
+
// it could never fire. An explicit caller-supplied value wins.
|
|
231
|
+
next_execution: next_execution ?? (willBeActive ? computeNextExecution(effectiveConfig) : null),
|
|
232
|
+
created_by: ctx.principal.type === 'human' ? ctx.principal.id : null
|
|
142
233
|
})
|
|
143
234
|
.select()
|
|
144
235
|
.single()
|
|
@@ -152,21 +243,32 @@ export const create = createHandler(async (ctx, body) => {
|
|
|
152
243
|
|
|
153
244
|
return data
|
|
154
245
|
})
|
|
155
|
-
// CIL[DOC-VECTOR type="context" content="purpose='Create a new timer record for the current account.'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
|
|
156
|
-
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
157
|
-
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
158
|
-
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
159
|
-
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
160
|
-
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
161
246
|
// CIL[END stable_id="~/.framework/functions/timers.ts:create:constant"]
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
|
|
162
262
|
// CIL[BEGIN stable_id="~/.framework/functions/timers.ts:update:constant" type="constant" identity="update" parent="~/.framework/functions/timers.ts"]
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
263
|
+
/**
|
|
264
|
+
* The 'update' constant defines a handler for updating timer records in the database. It ensures that a valid timer ID is provided and updates the specified fields accordingly.
|
|
265
|
+
*
|
|
266
|
+
* @throws Error — Timer ID is required, Error — database update error
|
|
267
|
+
* @sideEffects Database update to 'timers' table, logging of the update event.
|
|
268
|
+
* @stability internal
|
|
269
|
+
* @calls ctx.db.from('timers'), emitLog
|
|
270
|
+
* @cil-generated
|
|
271
|
+
*/
|
|
170
272
|
export const update = createHandler(async (ctx, body) => {
|
|
171
273
|
const id = body?.id || ctx.query?.id
|
|
172
274
|
const { id: _bodyId, ...updates } = body || {}
|
|
@@ -175,13 +277,34 @@ export const update = createHandler(async (ctx, body) => {
|
|
|
175
277
|
throw new Error('Timer ID is required')
|
|
176
278
|
}
|
|
177
279
|
|
|
178
|
-
const
|
|
280
|
+
const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
|
|
281
|
+
|
|
282
|
+
const allowed = ['name', 'description', 'config', 'pipeline_id', 'metadata', 'is_active', 'timer_type', 'app_id', 'next_execution']
|
|
179
283
|
const updateData: Record<string, any> = { updated_at: new Date().toISOString() }
|
|
180
284
|
for (const key of allowed) {
|
|
181
285
|
if (updates[key] !== undefined) updateData[key] = updates[key]
|
|
182
286
|
}
|
|
183
287
|
|
|
184
|
-
|
|
288
|
+
// Re-arm when schedule-relevant inputs change and the caller did not set
|
|
289
|
+
// next_execution explicitly — mirrors update_timer_after_run's interval
|
|
290
|
+
// resolution so API/UI-edited timers actually fire. Only ever writes a
|
|
291
|
+
// computed value; it never clears a next_execution it cannot recompute
|
|
292
|
+
// (e.g. one manually armed out-of-band for a cron timer).
|
|
293
|
+
if (updateData.next_execution === undefined && (updates.config !== undefined || updates.is_active !== undefined)) {
|
|
294
|
+
const { data: existing } = await db
|
|
295
|
+
.from('timers')
|
|
296
|
+
.select('config, is_active')
|
|
297
|
+
.eq('id', id)
|
|
298
|
+
.single()
|
|
299
|
+
const effectiveActive = updates.is_active ?? existing?.is_active ?? false
|
|
300
|
+
const effectiveConfig = updates.config ?? existing?.config ?? {}
|
|
301
|
+
if (effectiveActive) {
|
|
302
|
+
const computed = computeNextExecution(effectiveConfig)
|
|
303
|
+
if (computed) updateData.next_execution = computed
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const { data, error: err } = await db
|
|
185
308
|
.from('timers')
|
|
186
309
|
.update(updateData)
|
|
187
310
|
.eq('id', id)
|
|
@@ -197,21 +320,32 @@ export const update = createHandler(async (ctx, body) => {
|
|
|
197
320
|
|
|
198
321
|
return data
|
|
199
322
|
})
|
|
200
|
-
// CIL[DOC-VECTOR type="context" content="purpose='Update an existing timer's allowed fields.'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
|
|
201
|
-
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
202
|
-
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
203
|
-
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
204
|
-
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
205
|
-
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
206
323
|
// CIL[END stable_id="~/.framework/functions/timers.ts:update:constant"]
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
|
|
207
339
|
// CIL[BEGIN stable_id="~/.framework/functions/timers.ts:remove:constant" type="constant" identity="remove" parent="~/.framework/functions/timers.ts"]
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
340
|
+
/**
|
|
341
|
+
* The 'remove' constant defines a handler for deleting a timer from the database. It ensures that a valid timer ID is provided and logs the deletion event.
|
|
342
|
+
*
|
|
343
|
+
* @throws Error — Timer ID is required, Error — Timer not found
|
|
344
|
+
* @sideEffects Database write to delete the timer, logging the deletion event.
|
|
345
|
+
* @stability internal
|
|
346
|
+
* @calls ctx.db.from('timers'), emitLog
|
|
347
|
+
* @cil-generated
|
|
348
|
+
*/
|
|
215
349
|
export const remove = createHandler(async (ctx, body) => {
|
|
216
350
|
const id = body?.id || ctx.query?.id
|
|
217
351
|
|
|
@@ -219,7 +353,8 @@ export const remove = createHandler(async (ctx, body) => {
|
|
|
219
353
|
throw new Error('Timer ID is required')
|
|
220
354
|
}
|
|
221
355
|
|
|
222
|
-
const
|
|
356
|
+
const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
|
|
357
|
+
const { data: existing } = await db
|
|
223
358
|
.from('timers')
|
|
224
359
|
.select('name, timer_type')
|
|
225
360
|
.eq('id', id)
|
|
@@ -229,7 +364,7 @@ export const remove = createHandler(async (ctx, body) => {
|
|
|
229
364
|
throw new Error('Timer not found')
|
|
230
365
|
}
|
|
231
366
|
|
|
232
|
-
const { error: err } = await
|
|
367
|
+
const { error: err } = await db
|
|
233
368
|
.from('timers')
|
|
234
369
|
.delete()
|
|
235
370
|
.eq('id', id)
|
|
@@ -243,21 +378,32 @@ export const remove = createHandler(async (ctx, body) => {
|
|
|
243
378
|
|
|
244
379
|
return { success: true }
|
|
245
380
|
})
|
|
246
|
-
// CIL[DOC-VECTOR type="context" content="purpose='Delete a timer by ID.'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
|
|
247
|
-
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
248
|
-
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
249
|
-
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
250
|
-
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
251
|
-
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
252
381
|
// CIL[END stable_id="~/.framework/functions/timers.ts:remove:constant"]
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
|
|
253
397
|
// CIL[BEGIN stable_id="~/.framework/functions/timers.ts:toggle:constant" type="constant" identity="toggle" parent="~/.framework/functions/timers.ts"]
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
398
|
+
/**
|
|
399
|
+
* The toggle function updates the active status of a timer based on its ID, ensuring the timer exists before making changes and logging the event. This function is essential for managing timer states in the application.
|
|
400
|
+
*
|
|
401
|
+
* @throws Error — Timer ID is required, Error — Timer not found
|
|
402
|
+
* @sideEffects Database update to the timers table, logging of the toggle event.
|
|
403
|
+
* @stability internal
|
|
404
|
+
* @calls ctx.db.from('timers'), emitLog
|
|
405
|
+
* @cil-generated
|
|
406
|
+
*/
|
|
261
407
|
export const toggle = createHandler(async (ctx, body) => {
|
|
262
408
|
const id = body?.id || ctx.query?.id
|
|
263
409
|
|
|
@@ -265,9 +411,10 @@ export const toggle = createHandler(async (ctx, body) => {
|
|
|
265
411
|
throw new Error('Timer ID is required')
|
|
266
412
|
}
|
|
267
413
|
|
|
268
|
-
const
|
|
414
|
+
const db = isSystemAdmin(ctx.principal) ? adminDb : ctx.db
|
|
415
|
+
const { data: existing } = await db
|
|
269
416
|
.from('timers')
|
|
270
|
-
.select('is_active, name')
|
|
417
|
+
.select('is_active, name, config, next_execution')
|
|
271
418
|
.eq('id', id)
|
|
272
419
|
.single()
|
|
273
420
|
|
|
@@ -277,12 +424,20 @@ export const toggle = createHandler(async (ctx, body) => {
|
|
|
277
424
|
|
|
278
425
|
const newStatus = !existing.is_active
|
|
279
426
|
|
|
280
|
-
const
|
|
427
|
+
const updateFields: Record<string, any> = {
|
|
428
|
+
is_active: newStatus,
|
|
429
|
+
updated_at: new Date().toISOString()
|
|
430
|
+
}
|
|
431
|
+
// Re-arm on activation when the timer was never scheduled (e.g. created
|
|
432
|
+
// before next_execution became writable).
|
|
433
|
+
if (newStatus && !existing.next_execution) {
|
|
434
|
+
const armed = computeNextExecution(existing.config)
|
|
435
|
+
if (armed) updateFields.next_execution = armed
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const { data, error: err } = await db
|
|
281
439
|
.from('timers')
|
|
282
|
-
.update(
|
|
283
|
-
is_active: newStatus,
|
|
284
|
-
updated_at: new Date().toISOString()
|
|
285
|
-
})
|
|
440
|
+
.update(updateFields)
|
|
286
441
|
.eq('id', id)
|
|
287
442
|
.select()
|
|
288
443
|
.single()
|
|
@@ -299,10 +454,58 @@ export const toggle = createHandler(async (ctx, body) => {
|
|
|
299
454
|
|
|
300
455
|
return data
|
|
301
456
|
})
|
|
302
|
-
// CIL[DOC-VECTOR type="context" content="purpose='Toggle the active state of a timer.'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/audit.ts"]
|
|
303
|
-
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
304
|
-
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
305
|
-
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
306
|
-
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
307
|
-
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
308
457
|
// CIL[END stable_id="~/.framework/functions/timers.ts:toggle:constant"]
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
// CIL[BEGIN stable_id="~/.framework/functions/timers.ts:handler:constant" type="constant" identity="handler" parent="~/.framework/functions/timers.ts"]
|
|
475
|
+
/**
|
|
476
|
+
* The handler processes various actions based on the query parameters from the context, providing a centralized entry point for handling different operations related to the resource. It delegates to specific functions for each action.
|
|
477
|
+
*
|
|
478
|
+
* @throws Error — Unsupported action: {action}
|
|
479
|
+
* @sideEffects none
|
|
480
|
+
* @stability internal
|
|
481
|
+
* @calls list, get, create, update, remove, toggle
|
|
482
|
+
* @cil-generated
|
|
483
|
+
*/
|
|
484
|
+
export const handler = createHandler(async (ctx, body) => {
|
|
485
|
+
const { action } = ctx.query || {}
|
|
486
|
+
|
|
487
|
+
switch (action) {
|
|
488
|
+
case 'list':
|
|
489
|
+
return await list(ctx, body)
|
|
490
|
+
case 'get':
|
|
491
|
+
return await get(ctx, body)
|
|
492
|
+
case 'create':
|
|
493
|
+
return await create(ctx, body)
|
|
494
|
+
case 'update':
|
|
495
|
+
return await update(ctx, body)
|
|
496
|
+
case 'remove':
|
|
497
|
+
return await remove(ctx, body)
|
|
498
|
+
case 'toggle':
|
|
499
|
+
return await toggle(ctx, body)
|
|
500
|
+
default:
|
|
501
|
+
throw new Error(`Unsupported action: ${action}`)
|
|
502
|
+
}
|
|
503
|
+
})
|
|
504
|
+
// CIL[END stable_id="~/.framework/functions/timers.ts:handler:constant"]
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
|