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.
Files changed (283) hide show
  1. package/.env.example +13 -3
  2. package/.framework/cli/commands/bootstrap.ts +392 -0
  3. package/.framework/cli/commands/dev.ts +91 -218
  4. package/.framework/cli/commands/doctor.ts +132 -26
  5. package/.framework/cli/commands/generate.ts +38 -298
  6. package/.framework/cli/commands/init.ts +20 -1
  7. package/.framework/cli/commands/migrate.ts +36 -30
  8. package/.framework/cli/commands/migrations.ts +16 -56
  9. package/.framework/cli/commands/upgrade.ts +35 -0
  10. package/.framework/cli/commands/validate-schema.ts +147 -0
  11. package/.framework/cli/context.ts +223 -110
  12. package/.framework/cli/index.ts +6 -0
  13. package/.framework/cli/lib/project-files.ts +241 -1
  14. package/.framework/functions/_shared/hash-api-key.ts +183 -79
  15. package/.framework/functions/_shared/logging.ts +562 -224
  16. package/.framework/functions/_shared/middleware.ts +47 -44
  17. package/.framework/functions/admin-data.ts +39 -28
  18. package/.framework/functions/ai-agents.ts +10 -6
  19. package/.framework/functions/api-keys.ts +301 -122
  20. package/.framework/functions/apps.ts +43 -26
  21. package/.framework/functions/cil-ingest.ts +48 -15
  22. package/.framework/functions/debug-auth.ts +14 -8
  23. package/.framework/functions/deliveries.ts +39 -12
  24. package/.framework/functions/embeddings.ts +145 -76
  25. package/.framework/functions/integration-outbound.ts +67 -27
  26. package/.framework/functions/integrations.ts +254 -127
  27. package/.framework/functions/logs.ts +273 -133
  28. package/.framework/functions/observability.ts +277 -147
  29. package/.framework/functions/pipeline-executions.ts +1 -1
  30. package/.framework/functions/pipelines.ts +14 -9
  31. package/.framework/functions/prompt-configs.ts +7 -4
  32. package/.framework/functions/roles.ts +8 -5
  33. package/.framework/functions/security.ts +30 -17
  34. package/.framework/functions/system-cron.ts +240 -127
  35. package/.framework/functions/tests.ts +7 -6
  36. package/.framework/functions/timers.ts +310 -107
  37. package/.framework/functions/triggers.ts +28 -13
  38. package/.framework/functions/types.ts +13 -10
  39. package/.framework/migrations/069_log_stats_window.sql +54 -0
  40. package/.framework/migrations/070_app_type_schema_rpcs.sql +166 -0
  41. package/.framework/migrations/071_timer_interval_keys.sql +96 -0
  42. package/.framework/migrations/072_slug_autofill.sql +77 -0
  43. package/.framework/migrations/073_seed_member_roles.sql +26 -0
  44. package/.framework/src/apps/admin/index.tsx +1141 -775
  45. package/.framework/src/components/ErrorBoundary.tsx +136 -0
  46. package/.framework/src/components/admin/AdminListPage.tsx +81 -73
  47. package/.framework/src/components/admin/AdminSidebar.tsx +88 -79
  48. package/.framework/src/components/admin/EntitySelect.tsx +181 -0
  49. package/.framework/src/components/admin/PageInstructions.tsx +86 -127
  50. package/.framework/src/components/app-shell/GenericDetailPage.tsx +37 -13
  51. package/.framework/src/components/app-shell/GenericListPage.tsx +28 -32
  52. package/.framework/src/components/layout/Sidebar.tsx +300 -177
  53. package/.framework/src/components/runtime/DataDetailPage.tsx +67 -35
  54. package/.framework/src/components/runtime/DataHeader.tsx +96 -48
  55. package/.framework/src/components/runtime/DataListPage.tsx +3 -26
  56. package/.framework/src/components/runtime/DataStats.tsx +10 -10
  57. package/.framework/src/components/runtime/DataTable.tsx +12 -10
  58. package/.framework/src/components/ui/sheet.tsx +24 -26
  59. package/.framework/src/components/ui/textarea.tsx +74 -48
  60. package/.framework/src/hooks/useEntityList.ts +12 -9
  61. package/.framework/src/hooks/useListSchema.ts +108 -58
  62. package/.framework/src/instructions/README.md +57 -0
  63. package/.framework/src/instructions/ai-agents.md +69 -0
  64. package/.framework/src/instructions/alerts.md +80 -0
  65. package/.framework/src/instructions/api-keys.md +87 -0
  66. package/.framework/src/instructions/apps.md +77 -0
  67. package/.framework/src/instructions/concepts/ai-and-prompts.md +150 -0
  68. package/.framework/src/instructions/concepts/apps-and-renderers.md +162 -0
  69. package/.framework/src/instructions/concepts/auth-and-api-keys.md +133 -0
  70. package/.framework/src/instructions/concepts/automation.md +186 -0
  71. package/.framework/src/instructions/concepts/concurrency-and-idempotency.md +125 -0
  72. package/.framework/src/instructions/concepts/core-vs-custom.md +124 -0
  73. package/.framework/src/instructions/concepts/design-schema.md +152 -0
  74. package/.framework/src/instructions/concepts/integrations-and-webhooks.md +127 -0
  75. package/.framework/src/instructions/concepts/observability.md +116 -0
  76. package/.framework/src/instructions/concepts/permissions.md +150 -0
  77. package/.framework/src/instructions/concepts/runtime-records.md +111 -0
  78. package/.framework/src/instructions/concepts/scope-and-accounts.md +112 -0
  79. package/.framework/src/instructions/concepts/spine-way.md +172 -0
  80. package/.framework/src/instructions/deliveries.md +59 -0
  81. package/.framework/src/instructions/guide/00-orientation.md +106 -0
  82. package/.framework/src/instructions/guide/01-install-and-first-run.md +253 -0
  83. package/.framework/src/instructions/guide/02-project-map.md +147 -0
  84. package/.framework/src/instructions/guide/03-domain-model.md +223 -0
  85. package/.framework/src/instructions/guide/04-first-app.md +227 -0
  86. package/.framework/src/instructions/guide/05-glossary.md +183 -0
  87. package/.framework/src/instructions/integrations.md +96 -0
  88. package/.framework/src/instructions/internal/cil-markers.md +83 -0
  89. package/.framework/src/instructions/invites.md +60 -0
  90. package/.framework/src/instructions/kb.md +80 -0
  91. package/.framework/src/instructions/logs.md +77 -0
  92. package/.framework/src/instructions/observability.md +61 -0
  93. package/.framework/src/instructions/operations/deployment.md +115 -0
  94. package/.framework/src/instructions/operations/migrations.md +125 -0
  95. package/.framework/src/instructions/operations/security-checklist.md +148 -0
  96. package/.framework/src/instructions/operations/troubleshooting.md +170 -0
  97. package/.framework/src/instructions/operations/upgrade.md +116 -0
  98. package/.framework/src/instructions/pipeline-executions.md +62 -0
  99. package/.framework/src/instructions/pipelines.md +78 -0
  100. package/.framework/src/instructions/prompts.md +95 -0
  101. package/.framework/src/instructions/reference/api/admin-data.md +162 -0
  102. package/.framework/src/instructions/reference/api/auth.md +113 -0
  103. package/.framework/src/instructions/reference/api/errors-and-envelopes.md +113 -0
  104. package/.framework/src/instructions/reference/app-manifest.md +150 -0
  105. package/.framework/src/instructions/reference/cli.md +124 -0
  106. package/.framework/src/instructions/reference/database.md +132 -0
  107. package/.framework/src/instructions/reference/design-schema.md +280 -0
  108. package/.framework/src/instructions/reference/env-vars.md +133 -0
  109. package/.framework/src/instructions/reference/functions/account-nodes.md +75 -0
  110. package/.framework/src/instructions/reference/functions/admin-data.md +195 -0
  111. package/.framework/src/instructions/reference/functions/admin-funnel.md +90 -0
  112. package/.framework/src/instructions/reference/functions/admin-install-funnel.md +107 -0
  113. package/.framework/src/instructions/reference/functions/admin-signals.md +102 -0
  114. package/.framework/src/instructions/reference/functions/ai-agents.md +148 -0
  115. package/.framework/src/instructions/reference/functions/ai-interactions.md +156 -0
  116. package/.framework/src/instructions/reference/functions/api-keys.md +130 -0
  117. package/.framework/src/instructions/reference/functions/apps.md +140 -0
  118. package/.framework/src/instructions/reference/functions/auth.md +99 -0
  119. package/.framework/src/instructions/reference/functions/debug-auth.md +91 -0
  120. package/.framework/src/instructions/reference/functions/deliveries.md +110 -0
  121. package/.framework/src/instructions/reference/functions/embeddings.md +166 -0
  122. package/.framework/src/instructions/reference/functions/eval-harness.md +149 -0
  123. package/.framework/src/instructions/reference/functions/index.md +103 -0
  124. package/.framework/src/instructions/reference/functions/integration-outbound.md +200 -0
  125. package/.framework/src/instructions/reference/functions/integration-routes.md +151 -0
  126. package/.framework/src/instructions/reference/functions/integrations.md +130 -0
  127. package/.framework/src/instructions/reference/functions/invites.md +182 -0
  128. package/.framework/src/instructions/reference/functions/item-progress.md +107 -0
  129. package/.framework/src/instructions/reference/functions/kb.md +166 -0
  130. package/.framework/src/instructions/reference/functions/logs.md +141 -0
  131. package/.framework/src/instructions/reference/functions/observability.md +105 -0
  132. package/.framework/src/instructions/reference/functions/pipeline-executions.md +132 -0
  133. package/.framework/src/instructions/reference/functions/pipeline-runner-background.md +121 -0
  134. package/.framework/src/instructions/reference/functions/pipelines.md +136 -0
  135. package/.framework/src/instructions/reference/functions/prompt-configs.md +121 -0
  136. package/.framework/src/instructions/reference/functions/roles.md +121 -0
  137. package/.framework/src/instructions/reference/functions/security.md +140 -0
  138. package/.framework/src/instructions/reference/functions/system-cron.md +136 -0
  139. package/.framework/src/instructions/reference/functions/system.md +106 -0
  140. package/.framework/src/instructions/reference/functions/tests.md +97 -0
  141. package/.framework/src/instructions/reference/functions/timers.md +117 -0
  142. package/.framework/src/instructions/reference/functions/trigger-scheduler.md +102 -0
  143. package/.framework/src/instructions/reference/functions/triggers.md +140 -0
  144. package/.framework/src/instructions/reference/functions/types.md +146 -0
  145. package/.framework/src/instructions/reference/seeds.md +126 -0
  146. package/.framework/src/instructions/reference/shared-modules.md +127 -0
  147. package/.framework/src/instructions/reference/spine-config.md +114 -0
  148. package/.framework/src/instructions/roles.md +80 -0
  149. package/.framework/src/instructions/runtime-detail.md +70 -0
  150. package/.framework/src/instructions/runtime-list.md +77 -0
  151. package/.framework/src/instructions/security.md +67 -0
  152. package/.framework/src/instructions/tasks/add-a-pipeline.md +110 -0
  153. package/.framework/src/instructions/tasks/add-a-role.md +96 -0
  154. package/.framework/src/instructions/tasks/add-a-timer.md +114 -0
  155. package/.framework/src/instructions/tasks/add-a-trigger.md +106 -0
  156. package/.framework/src/instructions/tasks/add-a-type.md +151 -0
  157. package/.framework/src/instructions/tasks/add-a-webhook.md +108 -0
  158. package/.framework/src/instructions/tasks/add-an-ai-agent.md +108 -0
  159. package/.framework/src/instructions/tasks/add-an-integration.md +124 -0
  160. package/.framework/src/instructions/tasks/build-a-custom-page.md +118 -0
  161. package/.framework/src/instructions/tasks/package-and-install-an-app.md +127 -0
  162. package/.framework/src/instructions/tasks/test-your-code.md +108 -0
  163. package/.framework/src/instructions/tasks/write-a-function.md +132 -0
  164. package/.framework/src/instructions/tasks/write-a-migration.md +110 -0
  165. package/.framework/src/instructions/testing.md +59 -0
  166. package/.framework/src/instructions/timers.md +82 -0
  167. package/.framework/src/instructions/triggers.md +69 -0
  168. package/.framework/src/instructions/types.md +93 -0
  169. package/.framework/src/pages/NotFoundPage.tsx +62 -31
  170. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +117 -106
  171. package/.framework/src/pages/admin/AIAgentsPage.tsx +86 -48
  172. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +153 -152
  173. package/.framework/src/pages/admin/APIKeysPage.tsx +91 -90
  174. package/.framework/src/pages/admin/AlertsConfigPage.tsx +29 -18
  175. package/.framework/src/pages/admin/AppDetailPage.tsx +6 -60
  176. package/.framework/src/pages/admin/AppsPage.tsx +104 -66
  177. package/.framework/src/pages/admin/DeliveriesPage.tsx +5 -5
  178. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +5 -23
  179. package/.framework/src/pages/admin/EmbeddingsPage.tsx +5 -26
  180. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +7 -7
  181. package/.framework/src/pages/admin/IntegrationsPage.tsx +85 -43
  182. package/.framework/src/pages/admin/LogsPage.tsx +144 -76
  183. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +223 -140
  184. package/.framework/src/pages/admin/PipelineDetailPage.tsx +134 -113
  185. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +108 -45
  186. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -115
  187. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +96 -98
  188. package/.framework/src/pages/admin/PromptConfigsPage.tsx +101 -59
  189. package/.framework/src/pages/admin/RoleDetailPage.tsx +90 -79
  190. package/.framework/src/pages/admin/RolesPage.tsx +86 -43
  191. package/.framework/src/pages/admin/SecurityPage.tsx +1 -1
  192. package/.framework/src/pages/admin/TestingDashboard.tsx +16 -28
  193. package/.framework/src/pages/admin/TimerDetailPage.tsx +117 -100
  194. package/.framework/src/pages/admin/TimersPage.tsx +90 -62
  195. package/.framework/src/pages/admin/TriggerDetailPage.tsx +90 -83
  196. package/.framework/src/pages/admin/TriggersPage.tsx +124 -99
  197. package/.framework/src/pages/admin/TypeDetailPage.tsx +152 -138
  198. package/.framework/src/pages/admin/TypesPage.tsx +90 -48
  199. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +17 -25
  200. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +17 -27
  201. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +72 -40
  202. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +321 -129
  203. package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +18 -29
  204. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +26 -38
  205. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +34 -46
  206. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +189 -103
  207. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +246 -136
  208. package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +11 -22
  209. package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +9 -20
  210. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +26 -38
  211. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +7 -26
  212. package/.framework/templates/agent/AGENTS.md +150 -0
  213. package/.framework/templates/agent/skills/spine-add-ai-agent/SKILL.md +58 -0
  214. package/.framework/templates/agent/skills/spine-add-automation/SKILL.md +62 -0
  215. package/.framework/templates/agent/skills/spine-add-integration/SKILL.md +63 -0
  216. package/.framework/templates/agent/skills/spine-architect/SKILL.md +86 -0
  217. package/.framework/templates/agent/skills/spine-install-app/SKILL.md +72 -0
  218. package/.framework/templates/agent/skills/spine-migration/SKILL.md +75 -0
  219. package/.framework/templates/agent/skills/spine-new-app/SKILL.md +67 -0
  220. package/.framework/templates/agent/skills/spine-new-function/SKILL.md +65 -0
  221. package/.framework/templates/agent/skills/spine-new-type/SKILL.md +65 -0
  222. package/.framework/templates/agent/skills/spine-schema/SKILL.md +77 -0
  223. package/.framework/templates/agent/skills/spine-test/SKILL.md +67 -0
  224. package/.framework/templates/agent/skills/spine-troubleshoot/SKILL.md +74 -0
  225. package/.framework/templates/agent/skills/spine-upgrade/SKILL.md +69 -0
  226. package/.framework/templates/project.json +4 -1
  227. package/.framework/tests/unit/account-scoping-gates.test.ts +392 -0
  228. package/.framework/tests/unit/agent-files.test.ts +355 -0
  229. package/.framework/tests/unit/agent-runner.test.ts +479 -44
  230. package/.framework/tests/unit/api-keys-create-scope-gate.test.ts +160 -0
  231. package/.framework/tests/unit/api-keys-omit-secret-fields.test.ts +38 -0
  232. package/.framework/tests/unit/bootstrap.test.ts +242 -0
  233. package/.framework/tests/unit/cli-context-api-key.test.ts +114 -0
  234. package/.framework/tests/unit/debug-auth.test.ts +38 -0
  235. package/.framework/tests/unit/deliveries-account-scoping.test.ts +185 -0
  236. package/.framework/tests/unit/integration-outbound-credentials.test.ts +167 -0
  237. package/.framework/tests/unit/integrations-audit-redaction.test.ts +130 -0
  238. package/.framework/tests/unit/logging-app-id.test.ts +75 -0
  239. package/.framework/tests/unit/system-context-denial.test.ts +145 -0
  240. package/.framework/tests/unit/system-cron.test.ts +240 -0
  241. package/.framework/tests/unit/timers.test.ts +159 -0
  242. package/README.md +125 -166
  243. package/config/tsconfig.cli.json +2 -2
  244. package/package.json +15 -4
  245. package/templates/project/package-lock.json +2 -2
  246. package/.framework/docs/admin-routes.md +0 -76
  247. package/.framework/docs/api-docs-progress.md +0 -38
  248. package/.framework/docs/api-governance.md +0 -146
  249. package/.framework/docs/api-testing-results.md +0 -212
  250. package/.framework/docs/assembly-launch-guide.md +0 -138
  251. package/.framework/docs/audit-results.md +0 -590
  252. package/.framework/docs/db-api-inventory.md +0 -95
  253. package/.framework/docs/gap-remediation-backlog.md +0 -103
  254. package/.framework/docs/ui-adoption-verification.md +0 -111
  255. package/.framework/docs/ui-api-coverage.md +0 -84
  256. package/.framework/docs/v2-compatibility-audit.md +0 -228
  257. package/.framework/mcp/index.ts +0 -133
  258. package/.framework/mcp/load-env.ts +0 -60
  259. package/.framework/mcp/shared/app-manifest.ts +0 -275
  260. package/.framework/mcp/shared/db.ts +0 -477
  261. package/.framework/mcp/shared/kb.ts +0 -118
  262. package/.framework/mcp/tools/architect.ts +0 -431
  263. package/.framework/mcp/tools/cil/context.ts +0 -345
  264. package/.framework/mcp/tools/cil/graph.ts +0 -242
  265. package/.framework/mcp/tools/cil/ingest.ts +0 -1217
  266. package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +0 -693
  267. package/.framework/mcp/tools/cil/pipeline.ts +0 -767
  268. package/.framework/mcp/tools/cil/project.ts +0 -791
  269. package/.framework/mcp/tools/cil/retrieval.ts +0 -336
  270. package/.framework/mcp/tools/cil/search-core.ts +0 -454
  271. package/.framework/mcp/tools/cil/search.ts +0 -97
  272. package/.framework/mcp/tools/cil/suggest.ts +0 -186
  273. package/.framework/mcp/tools/cil/validate.ts +0 -1369
  274. package/.framework/mcp/tools/kb/delete.ts +0 -139
  275. package/.framework/mcp/tools/kb/index.ts +0 -52
  276. package/.framework/mcp/tools/kb/ingest.ts +0 -84
  277. package/.framework/mcp/tools/kb/list-types.ts +0 -102
  278. package/.framework/mcp/tools/kb/publish.ts +0 -100
  279. package/.framework/mcp/tools/kb/reindex.ts +0 -86
  280. package/.framework/mcp/tools/kb/revoke.ts +0 -85
  281. package/.framework/mcp/tools/kb/search.ts +0 -101
  282. package/.framework/mcp/tools/kb/upsert.ts +0 -125
  283. 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
- // CIL[DOC-MACRO purpose="Import shared utilities used by timer Netlify function handlers."]
3
- // CIL[DOC-RESPONSIBILITY responsibility="Set up module-level imports for middleware, database access, audit logging, and permission helpers."]
4
- // CIL[DOC-CONTEXT module="timers" layer=".framework/functions" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts"]
5
- // CIL[DOC-CONTRACT inputs="None" outputs="None" errors="None" side_effects="None"]
6
- // CIL[DOC-MICRO logic_summary="Imports createHandler, joins, adminDb, emitLog, sanitizeRecordData, and isSystemAdmin." notable_decisions="Uses shared handlers for both admin and account-scoped queries."]
7
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
8
- // CIL[DOC-STABILITY stable]
9
- // CIL[DOC-AUDIENCE audience="Spine framework internal Netlify function handlers that manage scheduled timers."]
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
- // CIL[DOC-MACRO purpose="List timers for the current account with optional filters."]
29
- // CIL[DOC-RESPONSIBILITY responsibility="Return a filtered, sanitized list of timer records scoped to the calling account."]
30
- // CIL[DOC-CONTEXT module="timers" layer=".framework/functions" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/timers.ts"]
31
- // CIL[DOC-CONTRACT inputs="ctx.query may include app_id, timer_type, and is_active." outputs="Array of sanitized timer records." errors="Account context required; database query errors." side_effects="None"]
32
- // CIL[DOC-MICRO logic_summary="Builds a timers query, applies optional equality filters, and sanitizes each returned record." notable_decisions="Falls back to ctx.db unless the caller is a system admin."]
33
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
34
- // CIL[DOC-STABILITY stable]
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
- // CIL[DOC-MACRO purpose="Fetch a single timer by ID."]
79
- // CIL[DOC-RESPONSIBILITY responsibility="Return a sanitized timer record matching the requested ID."]
80
- // CIL[DOC-CONTEXT module="timers" layer=".framework/functions" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/timers.ts"]
81
- // CIL[DOC-CONTRACT inputs="ctx.query.id" outputs="Sanitized timer record." errors="Timer ID is required; not-found or database errors." side_effects="None"]
82
- // CIL[DOC-MICRO logic_summary="Queries the timers table by id and returns the sanitized record." notable_decisions="Uses system admin override to select the database connection."]
83
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
84
- // CIL[DOC-STABILITY stable]
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
- // CIL[DOC-MACRO purpose="Create a new timer record for the current account."]
113
- // CIL[DOC-RESPONSIBILITY responsibility="Insert a timer with the supplied fields and return the created record."]
114
- // CIL[DOC-CONTEXT module="timers" layer=".framework/functions" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/timers.ts"]
115
- // CIL[DOC-CONTRACT inputs="body: app_id, name, description, timer_type, config, pipeline_id, metadata." outputs="Newly created timer record." errors="name and timer_type are required; User context required; database errors." side_effects="Inserts a row into timers; writes an audit log."]
116
- // CIL[DOC-MICRO logic_summary="Validates required fields, inserts a timer row with defaults, emits a creation audit log, and returns the row." notable_decisions="Stores undefined optional fields as null or empty objects."]
117
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
118
- // CIL[DOC-STABILITY stable]
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 { data, error: err } = await ctx.db
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: config || {},
224
+ config: effectiveConfig,
139
225
  pipeline_id: pipeline_id || null,
140
226
  metadata: metadata || {},
141
- created_by: ctx.principal.id
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
- // CIL[DOC-MACRO purpose="Update an existing timer's allowed fields."]
164
- // CIL[DOC-RESPONSIBILITY responsibility="Apply whitelisted field updates to a timer row and return the updated record."]
165
- // CIL[DOC-CONTEXT module="timers" layer=".framework/functions" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/timers.ts"]
166
- // CIL[DOC-CONTRACT inputs="body or ctx.query with id; optional fields from allowed list." outputs="Updated timer record." errors="Timer ID is required; database errors." side_effects="Updates a timers row; writes an audit log."]
167
- // CIL[DOC-MICRO logic_summary="Extracts the id, builds an update payload from an allow-list, sets updated_at, and emits an update audit log." notable_decisions="Ignores id inside the body and does not re-validate allowed values beyond presence."]
168
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
169
- // CIL[DOC-STABILITY stable]
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 allowed = ['name', 'description', 'config', 'pipeline_id', 'metadata', 'is_active', 'timer_type', 'app_id']
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
- const { data, error: err } = await ctx.db
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
- // CIL[DOC-MACRO purpose="Delete a timer by ID."]
209
- // CIL[DOC-RESPONSIBILITY responsibility="Remove a timer record from the database and confirm success."]
210
- // CIL[DOC-CONTEXT module="timers" layer=".framework/functions" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/timers.ts"]
211
- // CIL[DOC-CONTRACT inputs="body or ctx.query with id." outputs="{ success: true }." errors="Timer ID is required; Timer not found; database errors." side_effects="Deletes a timers row; writes an audit log."]
212
- // CIL[DOC-MICRO logic_summary="Fetches the existing timer, deletes the row by id, and emits a deletion audit log." notable_decisions="Reads only name and timer_type before deletion for the audit payload."]
213
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
214
- // CIL[DOC-STABILITY stable]
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 { data: existing } = await ctx.db
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 ctx.db
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
- // CIL[DOC-MACRO purpose="Toggle the active state of a timer."]
255
- // CIL[DOC-RESPONSIBILITY responsibility="Flip a timer's is_active flag and return the updated record."]
256
- // CIL[DOC-CONTEXT module="timers" layer=".framework/functions" related_files=".framework/functions/_shared/audit.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/permissions.ts,.framework/functions/_shared/principal.ts,.framework/functions/timers.ts"]
257
- // CIL[DOC-CONTRACT inputs="body or ctx.query with id." outputs="Updated timer record with toggled is_active." errors="Timer ID is required; Timer not found; database errors." side_effects="Updates is_active on a timers row; writes an audit log."]
258
- // CIL[DOC-MICRO logic_summary="Fetches the existing timer, inverts is_active, writes the new status, and emits a toggle audit log." notable_decisions="Also updates updated_at when toggling status."]
259
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
260
- // CIL[DOC-STABILITY stable]
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 { data: existing } = await ctx.db
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 { data, error: err } = await ctx.db
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
+