spine-framework 0.1.61 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (425) hide show
  1. package/LICENSE.md +223 -0
  2. package/README.md +327 -0
  3. package/package.json +107 -216
  4. package/src/cli/commands/init.ts +192 -0
  5. package/src/cli/commands/install.ts +25 -0
  6. package/src/cli/commands/list.ts +33 -0
  7. package/src/cli/commands/migrate.ts +24 -0
  8. package/src/cli/index.ts +46 -0
  9. package/src/components/AppLayout.tsx +21 -0
  10. package/src/components/AuthGuard.tsx +21 -0
  11. package/src/components/RoleGuard.tsx +23 -0
  12. package/src/components/index.ts +3 -0
  13. package/src/contexts/AppContext.tsx +122 -0
  14. package/src/contexts/AuthContext.tsx +87 -0
  15. package/src/contexts/SpineContext.tsx +46 -0
  16. package/src/contexts/index.ts +3 -0
  17. package/src/hooks/index.ts +4 -0
  18. package/src/hooks/useItems.ts +78 -0
  19. package/src/hooks/useThreads.ts +73 -0
  20. package/src/hooks/useWebSocket.ts +97 -0
  21. package/src/index.ts +22 -0
  22. package/src/types/index.ts +163 -0
  23. package/src/utils/api.ts +88 -0
  24. package/src/utils/client.ts +146 -0
  25. package/src/utils/config.ts +20 -0
  26. package/src/utils/index.ts +3 -0
  27. package/.framework/README.md +0 -129
  28. package/.framework/cli/bin.cjs +0 -14
  29. package/.framework/cli/commands/agents.ts +0 -153
  30. package/.framework/cli/commands/auth.ts +0 -94
  31. package/.framework/cli/commands/create-app.ts +0 -185
  32. package/.framework/cli/commands/dev.ts +0 -113
  33. package/.framework/cli/commands/doctor.ts +0 -442
  34. package/.framework/cli/commands/generate.ts +0 -332
  35. package/.framework/cli/commands/init.ts +0 -186
  36. package/.framework/cli/commands/install-app.ts +0 -565
  37. package/.framework/cli/commands/items.ts +0 -253
  38. package/.framework/cli/commands/migrate.ts +0 -139
  39. package/.framework/cli/commands/migrations.ts +0 -141
  40. package/.framework/cli/commands/pipelines.ts +0 -166
  41. package/.framework/cli/commands/status.ts +0 -197
  42. package/.framework/cli/commands/system.ts +0 -184
  43. package/.framework/cli/commands/test.ts +0 -227
  44. package/.framework/cli/commands/uninstall-app.ts +0 -166
  45. package/.framework/cli/context.ts +0 -268
  46. package/.framework/cli/env-loader.ts +0 -36
  47. package/.framework/cli/index.ts +0 -116
  48. package/.framework/cli/welcome.cjs +0 -45
  49. package/.framework/docs/API.md +0 -384
  50. package/.framework/docs/STABILITY.md +0 -52
  51. package/.framework/docs/admin-routes.md +0 -76
  52. package/.framework/docs/api-docs-progress.md +0 -38
  53. package/.framework/docs/api-governance.md +0 -146
  54. package/.framework/docs/api-testing-results.md +0 -212
  55. package/.framework/docs/apis/admin-configs.md +0 -567
  56. package/.framework/docs/apis/admin-data.md +0 -272
  57. package/.framework/docs/apis/index.md +0 -231
  58. package/.framework/docs/apis/internal.md +0 -295
  59. package/.framework/docs/apis/runtime.md +0 -537
  60. package/.framework/docs/assembly-launch-guide.md +0 -138
  61. package/.framework/docs/audit-results.md +0 -590
  62. package/.framework/docs/authorization-model.md +0 -170
  63. package/.framework/docs/db-api-inventory.md +0 -95
  64. package/.framework/docs/examples/custom-app/README.md +0 -77
  65. package/.framework/docs/examples/custom-function/README.md +0 -27
  66. package/.framework/docs/examples/custom-function/handler.ts +0 -48
  67. package/.framework/docs/examples/custom-webhook/README.md +0 -68
  68. package/.framework/docs/gap-remediation-backlog.md +0 -103
  69. package/.framework/docs/guides/cli-guide.md +0 -224
  70. package/.framework/docs/guides/getting-started.md +0 -103
  71. package/.framework/docs/guides/import-guide.md +0 -193
  72. package/.framework/docs/guides/testing-guide.md +0 -229
  73. package/.framework/docs/permission-examples.md +0 -326
  74. package/.framework/docs/ui-adoption-verification.md +0 -111
  75. package/.framework/docs/ui-api-coverage.md +0 -84
  76. package/.framework/docs/v2-compatibility-audit.md +0 -228
  77. package/.framework/functions/.gitkeep +0 -1
  78. package/.framework/functions/_shared/agent-runner.ts +0 -1097
  79. package/.framework/functions/_shared/app-manifest.ts +0 -184
  80. package/.framework/functions/_shared/audit.ts +0 -150
  81. package/.framework/functions/_shared/db.ts +0 -178
  82. package/.framework/functions/_shared/index.ts +0 -391
  83. package/.framework/functions/_shared/middleware.ts +0 -490
  84. package/.framework/functions/_shared/permissions.ts +0 -1325
  85. package/.framework/functions/_shared/pipeline-runner.ts +0 -731
  86. package/.framework/functions/_shared/principal.ts +0 -818
  87. package/.framework/functions/_shared/resolve-ids.ts +0 -106
  88. package/.framework/functions/_shared/schema-utils.ts +0 -967
  89. package/.framework/functions/_shared/testing.ts +0 -258
  90. package/.framework/functions/_shared/trigger-engine.ts +0 -425
  91. package/.framework/functions/_shared/webhook-registration.ts +0 -168
  92. package/.framework/functions/_shared/webhook-registry.ts +0 -129
  93. package/.framework/functions/account-nodes.ts +0 -111
  94. package/.framework/functions/admin-data.ts +0 -606
  95. package/.framework/functions/ai-agents.ts +0 -323
  96. package/.framework/functions/api-keys.ts +0 -376
  97. package/.framework/functions/apps.ts +0 -483
  98. package/.framework/functions/auth.ts +0 -196
  99. package/.framework/functions/debug-auth.ts +0 -107
  100. package/.framework/functions/embeddings.ts +0 -556
  101. package/.framework/functions/integration-routes.ts +0 -523
  102. package/.framework/functions/integrations.ts +0 -319
  103. package/.framework/functions/item-progress.ts +0 -272
  104. package/.framework/functions/logs.ts +0 -438
  105. package/.framework/functions/observability.ts +0 -275
  106. package/.framework/functions/pipeline-executions.ts +0 -494
  107. package/.framework/functions/pipelines.ts +0 -485
  108. package/.framework/functions/prompt-configs.ts +0 -339
  109. package/.framework/functions/roles.ts +0 -387
  110. package/.framework/functions/system-cron.ts +0 -742
  111. package/.framework/functions/system.ts +0 -323
  112. package/.framework/functions/tests.ts +0 -119
  113. package/.framework/functions/timers.ts +0 -357
  114. package/.framework/functions/triggers.ts +0 -563
  115. package/.framework/functions/types.ts +0 -604
  116. package/.framework/index.html +0 -16
  117. package/.framework/migrations/000_foundation.sql +0 -1266
  118. package/.framework/migrations/001_seed.sql +0 -163
  119. package/.framework/migrations/002_seed_constraints.sql +0 -19
  120. package/.framework/migrations/003_auth_user_trigger.sql +0 -67
  121. package/.framework/src/App.tsx +0 -126
  122. package/.framework/src/apps/admin/index.tsx +0 -173
  123. package/.framework/src/components/AppWrapper.tsx +0 -56
  124. package/.framework/src/components/CustomAppLoader.tsx +0 -116
  125. package/.framework/src/components/admin/AdminListPage.tsx +0 -151
  126. package/.framework/src/components/admin/AdminSidebar.tsx +0 -166
  127. package/.framework/src/components/admin/AdminStatsCard.tsx +0 -62
  128. package/.framework/src/components/admin/SortableTableHeader.tsx +0 -42
  129. package/.framework/src/components/app-shell/GenericAppShell.tsx +0 -181
  130. package/.framework/src/components/app-shell/GenericDetailPage.tsx +0 -200
  131. package/.framework/src/components/app-shell/GenericListPage.tsx +0 -116
  132. package/.framework/src/components/app-sidebar.tsx +0 -228
  133. package/.framework/src/components/auth/ProtectedRoute.tsx +0 -88
  134. package/.framework/src/components/layout/AppShell.tsx +0 -91
  135. package/.framework/src/components/layout/Header.tsx +0 -88
  136. package/.framework/src/components/layout/Layout.tsx +0 -95
  137. package/.framework/src/components/layout/Sidebar.tsx +0 -329
  138. package/.framework/src/components/runtime/DataDetailHeader.tsx +0 -77
  139. package/.framework/src/components/runtime/DataDetailPage.tsx +0 -171
  140. package/.framework/src/components/runtime/DataFilters.tsx +0 -91
  141. package/.framework/src/components/runtime/DataHeader.tsx +0 -68
  142. package/.framework/src/components/runtime/DataListPage.tsx +0 -124
  143. package/.framework/src/components/runtime/DataStats.tsx +0 -70
  144. package/.framework/src/components/runtime/DataTable.tsx +0 -174
  145. package/.framework/src/components/runtime/SchemaDetailForm.tsx +0 -134
  146. package/.framework/src/components/runtime/index.ts +0 -18
  147. package/.framework/src/components/search-form.tsx +0 -29
  148. package/.framework/src/components/shared/AgentView.tsx +0 -213
  149. package/.framework/src/components/shared/FieldRenderer.tsx +0 -478
  150. package/.framework/src/components/shared/SchemaFields.tsx +0 -226
  151. package/.framework/src/components/ui/DataTable.tsx +0 -343
  152. package/.framework/src/components/ui/Form.tsx +0 -281
  153. package/.framework/src/components/ui/ItemCard.tsx +0 -296
  154. package/.framework/src/components/ui/ItemListView.tsx +0 -308
  155. package/.framework/src/components/ui/LoadingSpinner.tsx +0 -52
  156. package/.framework/src/components/ui/Modal.tsx +0 -61
  157. package/.framework/src/components/ui/RichTextEditor.tsx +0 -210
  158. package/.framework/src/components/ui/accordion.tsx +0 -82
  159. package/.framework/src/components/ui/alert-dialog.tsx +0 -197
  160. package/.framework/src/components/ui/alert.tsx +0 -76
  161. package/.framework/src/components/ui/aspect-ratio.tsx +0 -11
  162. package/.framework/src/components/ui/avatar.tsx +0 -110
  163. package/.framework/src/components/ui/badge.tsx +0 -49
  164. package/.framework/src/components/ui/breadcrumb.tsx +0 -122
  165. package/.framework/src/components/ui/button-group.tsx +0 -83
  166. package/.framework/src/components/ui/button.tsx +0 -65
  167. package/.framework/src/components/ui/calendar.tsx +0 -222
  168. package/.framework/src/components/ui/card.tsx +0 -100
  169. package/.framework/src/components/ui/carousel.tsx +0 -240
  170. package/.framework/src/components/ui/chart.tsx +0 -368
  171. package/.framework/src/components/ui/checkbox.tsx +0 -31
  172. package/.framework/src/components/ui/collapsible.tsx +0 -33
  173. package/.framework/src/components/ui/combobox.tsx +0 -299
  174. package/.framework/src/components/ui/command.tsx +0 -193
  175. package/.framework/src/components/ui/context-menu.tsx +0 -261
  176. package/.framework/src/components/ui/dialog.tsx +0 -165
  177. package/.framework/src/components/ui/direction.tsx +0 -6
  178. package/.framework/src/components/ui/drawer.tsx +0 -132
  179. package/.framework/src/components/ui/dropdown-menu.tsx +0 -269
  180. package/.framework/src/components/ui/empty.tsx +0 -104
  181. package/.framework/src/components/ui/field.tsx +0 -238
  182. package/.framework/src/components/ui/hover-card.tsx +0 -42
  183. package/.framework/src/components/ui/input-group.tsx +0 -153
  184. package/.framework/src/components/ui/input-otp.tsx +0 -87
  185. package/.framework/src/components/ui/input.tsx +0 -19
  186. package/.framework/src/components/ui/item.tsx +0 -196
  187. package/.framework/src/components/ui/kbd.tsx +0 -26
  188. package/.framework/src/components/ui/label.tsx +0 -22
  189. package/.framework/src/components/ui/menubar.tsx +0 -277
  190. package/.framework/src/components/ui/native-select.tsx +0 -61
  191. package/.framework/src/components/ui/navigation-menu.tsx +0 -164
  192. package/.framework/src/components/ui/pagination.tsx +0 -129
  193. package/.framework/src/components/ui/popover.tsx +0 -87
  194. package/.framework/src/components/ui/progress.tsx +0 -31
  195. package/.framework/src/components/ui/radio-group.tsx +0 -42
  196. package/.framework/src/components/ui/resizable.tsx +0 -50
  197. package/.framework/src/components/ui/scroll-area.tsx +0 -53
  198. package/.framework/src/components/ui/select.tsx +0 -195
  199. package/.framework/src/components/ui/separator.tsx +0 -26
  200. package/.framework/src/components/ui/sheet.tsx +0 -145
  201. package/.framework/src/components/ui/sidebar.tsx +0 -706
  202. package/.framework/src/components/ui/skeleton.tsx +0 -13
  203. package/.framework/src/components/ui/slider.tsx +0 -59
  204. package/.framework/src/components/ui/sonner.tsx +0 -47
  205. package/.framework/src/components/ui/spinner.tsx +0 -10
  206. package/.framework/src/components/ui/switch.tsx +0 -33
  207. package/.framework/src/components/ui/table-primitives.tsx +0 -141
  208. package/.framework/src/components/ui/table.tsx +0 -114
  209. package/.framework/src/components/ui/tabs.tsx +0 -90
  210. package/.framework/src/components/ui/textarea.tsx +0 -18
  211. package/.framework/src/components/ui/toggle-group.tsx +0 -89
  212. package/.framework/src/components/ui/toggle.tsx +0 -45
  213. package/.framework/src/components/ui/tooltip.tsx +0 -57
  214. package/.framework/src/contexts/AppContext.tsx +0 -133
  215. package/.framework/src/contexts/AuthContext.tsx +0 -371
  216. package/.framework/src/hooks/use-mobile.ts +0 -19
  217. package/.framework/src/hooks/useApi.ts +0 -526
  218. package/.framework/src/hooks/useApps.ts +0 -114
  219. package/.framework/src/hooks/useEntityList.ts +0 -190
  220. package/.framework/src/hooks/useEntityRecord.ts +0 -308
  221. package/.framework/src/hooks/useForm.ts +0 -307
  222. package/.framework/src/hooks/useListSchema.ts +0 -264
  223. package/.framework/src/hooks/useSchemaRecord.ts +0 -223
  224. package/.framework/src/index.css +0 -128
  225. package/.framework/src/lib/api.ts +0 -156
  226. package/.framework/src/lib/supabase.ts +0 -94
  227. package/.framework/src/lib/utils.ts +0 -317
  228. package/.framework/src/main.tsx +0 -27
  229. package/.framework/src/pages/DashboardPage.tsx +0 -181
  230. package/.framework/src/pages/NotFoundPage.tsx +0 -39
  231. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +0 -161
  232. package/.framework/src/pages/admin/AIAgentsPage.tsx +0 -318
  233. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +0 -199
  234. package/.framework/src/pages/admin/APIKeysPage.tsx +0 -303
  235. package/.framework/src/pages/admin/AlertsConfigPage.tsx +0 -523
  236. package/.framework/src/pages/admin/AppDetailPage.tsx +0 -493
  237. package/.framework/src/pages/admin/AppsPage.tsx +0 -355
  238. package/.framework/src/pages/admin/DesignedPage.tsx +0 -491
  239. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +0 -534
  240. package/.framework/src/pages/admin/EmbeddingsPage.tsx +0 -424
  241. package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +0 -176
  242. package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +0 -109
  243. package/.framework/src/pages/admin/IntegratedDashboard.tsx +0 -402
  244. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +0 -187
  245. package/.framework/src/pages/admin/IntegrationsPage.tsx +0 -301
  246. package/.framework/src/pages/admin/LogsPage.tsx +0 -283
  247. package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +0 -85
  248. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +0 -470
  249. package/.framework/src/pages/admin/PipelineDetailPage.tsx +0 -183
  250. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +0 -279
  251. package/.framework/src/pages/admin/PipelinesPage.tsx +0 -390
  252. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +0 -299
  253. package/.framework/src/pages/admin/PromptConfigsPage.tsx +0 -292
  254. package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +0 -434
  255. package/.framework/src/pages/admin/RoleDetailPage.tsx +0 -273
  256. package/.framework/src/pages/admin/RolesPage.tsx +0 -292
  257. package/.framework/src/pages/admin/SelectTestPage.tsx +0 -61
  258. package/.framework/src/pages/admin/ShadcnTestPage.tsx +0 -588
  259. package/.framework/src/pages/admin/SimpleDashboard.tsx +0 -387
  260. package/.framework/src/pages/admin/TestRunDetailPage.tsx +0 -172
  261. package/.framework/src/pages/admin/TestingDashboard.tsx +0 -257
  262. package/.framework/src/pages/admin/TimerDetailPage.tsx +0 -151
  263. package/.framework/src/pages/admin/TimersPage.tsx +0 -376
  264. package/.framework/src/pages/admin/TriggerDetailPage.tsx +0 -149
  265. package/.framework/src/pages/admin/TriggersPage.tsx +0 -381
  266. package/.framework/src/pages/admin/TypeDetailPage.tsx +0 -694
  267. package/.framework/src/pages/admin/TypesPage.tsx +0 -295
  268. package/.framework/src/pages/auth/LoginPage.tsx +0 -187
  269. package/.framework/src/pages/auth/RegisterPage.tsx +0 -163
  270. package/.framework/src/pages/spine-framework/APIPage.tsx +0 -17
  271. package/.framework/src/pages/spine-framework/CLIPage.tsx +0 -25
  272. package/.framework/src/types/auth.ts +0 -125
  273. package/.framework/src/types/types.ts +0 -407
  274. package/STRUCTURE.md +0 -150
  275. package/bin/spine-framework.cjs +0 -62
  276. package/bin/welcome.cjs +0 -45
  277. package/bin/ws-shim.cjs +0 -8
  278. package/bin/ws-shim.ts +0 -10
  279. package/config/components.json +0 -25
  280. package/config/deno.lock +0 -108
  281. package/config/package-lock.json +0 -17183
  282. package/config/postcss.config.cjs +0 -10
  283. package/config/tailwind.config.cjs +0 -78
  284. package/config/tsconfig.build.json +0 -32
  285. package/config/tsconfig.cli.json +0 -18
  286. package/config/tsconfig.json +0 -41
  287. package/config/tsconfig.node.json +0 -17
  288. package/config/tsconfig.node.tsbuildinfo +0 -1
  289. package/config/tsconfig.tsbuildinfo +0 -1
  290. package/config/typedoc.json +0 -16
  291. package/config/vite.config.d.ts +0 -2
  292. package/config/vite.config.ts +0 -72
  293. package/dist/cli/commands/agents.d.ts +0 -39
  294. package/dist/cli/commands/agents.d.ts.map +0 -1
  295. package/dist/cli/commands/auth.d.ts +0 -36
  296. package/dist/cli/commands/auth.d.ts.map +0 -1
  297. package/dist/cli/commands/create-app.d.ts +0 -23
  298. package/dist/cli/commands/create-app.d.ts.map +0 -1
  299. package/dist/cli/commands/dev.d.ts +0 -24
  300. package/dist/cli/commands/dev.d.ts.map +0 -1
  301. package/dist/cli/commands/doctor.d.ts +0 -42
  302. package/dist/cli/commands/doctor.d.ts.map +0 -1
  303. package/dist/cli/commands/generate.d.ts +0 -36
  304. package/dist/cli/commands/generate.d.ts.map +0 -1
  305. package/dist/cli/commands/init.d.ts +0 -20
  306. package/dist/cli/commands/init.d.ts.map +0 -1
  307. package/dist/cli/commands/install-app.d.ts +0 -30
  308. package/dist/cli/commands/install-app.d.ts.map +0 -1
  309. package/dist/cli/commands/items.d.ts +0 -45
  310. package/dist/cli/commands/items.d.ts.map +0 -1
  311. package/dist/cli/commands/migrate.d.ts +0 -21
  312. package/dist/cli/commands/migrate.d.ts.map +0 -1
  313. package/dist/cli/commands/migrations.d.ts +0 -41
  314. package/dist/cli/commands/migrations.d.ts.map +0 -1
  315. package/dist/cli/commands/pipelines.d.ts +0 -40
  316. package/dist/cli/commands/pipelines.d.ts.map +0 -1
  317. package/dist/cli/commands/status.d.ts +0 -23
  318. package/dist/cli/commands/status.d.ts.map +0 -1
  319. package/dist/cli/commands/system.d.ts +0 -29
  320. package/dist/cli/commands/system.d.ts.map +0 -1
  321. package/dist/cli/commands/test.d.ts +0 -46
  322. package/dist/cli/commands/test.d.ts.map +0 -1
  323. package/dist/cli/commands/uninstall-app.d.ts +0 -23
  324. package/dist/cli/commands/uninstall-app.d.ts.map +0 -1
  325. package/dist/cli/context.d.ts +0 -88
  326. package/dist/cli/context.d.ts.map +0 -1
  327. package/dist/cli/env-loader.d.ts +0 -14
  328. package/dist/cli/env-loader.d.ts.map +0 -1
  329. package/dist/cli/index.d.ts +0 -41
  330. package/dist/cli/index.d.ts.map +0 -1
  331. package/dist/functions/_shared/agent-runner.d.ts +0 -156
  332. package/dist/functions/_shared/agent-runner.d.ts.map +0 -1
  333. package/dist/functions/_shared/app-manifest.d.ts +0 -68
  334. package/dist/functions/_shared/app-manifest.d.ts.map +0 -1
  335. package/dist/functions/_shared/audit.d.ts +0 -91
  336. package/dist/functions/_shared/audit.d.ts.map +0 -1
  337. package/dist/functions/_shared/db.d.ts +0 -125
  338. package/dist/functions/_shared/db.d.ts.map +0 -1
  339. package/dist/functions/_shared/index.d.ts +0 -299
  340. package/dist/functions/_shared/index.d.ts.map +0 -1
  341. package/dist/functions/_shared/middleware.d.ts +0 -315
  342. package/dist/functions/_shared/middleware.d.ts.map +0 -1
  343. package/dist/functions/_shared/permissions.d.ts +0 -626
  344. package/dist/functions/_shared/permissions.d.ts.map +0 -1
  345. package/dist/functions/_shared/pipeline-runner.d.ts +0 -124
  346. package/dist/functions/_shared/pipeline-runner.d.ts.map +0 -1
  347. package/dist/functions/_shared/principal.d.ts +0 -284
  348. package/dist/functions/_shared/principal.d.ts.map +0 -1
  349. package/dist/functions/_shared/resolve-ids.d.ts +0 -10
  350. package/dist/functions/_shared/resolve-ids.d.ts.map +0 -1
  351. package/dist/functions/_shared/schema-utils.d.ts +0 -181
  352. package/dist/functions/_shared/schema-utils.d.ts.map +0 -1
  353. package/dist/functions/_shared/testing.d.ts +0 -172
  354. package/dist/functions/_shared/testing.d.ts.map +0 -1
  355. package/dist/functions/_shared/trigger-engine.d.ts +0 -140
  356. package/dist/functions/_shared/trigger-engine.d.ts.map +0 -1
  357. package/dist/functions/_shared/webhook-registration.d.ts +0 -81
  358. package/dist/functions/_shared/webhook-registration.d.ts.map +0 -1
  359. package/dist/functions/_shared/webhook-registry.d.ts +0 -57
  360. package/dist/functions/_shared/webhook-registry.d.ts.map +0 -1
  361. package/dist/functions/account-nodes.d.ts +0 -48
  362. package/dist/functions/account-nodes.d.ts.map +0 -1
  363. package/dist/functions/admin-data.d.ts +0 -178
  364. package/dist/functions/admin-data.d.ts.map +0 -1
  365. package/dist/functions/ai-agents.d.ts +0 -125
  366. package/dist/functions/ai-agents.d.ts.map +0 -1
  367. package/dist/functions/api-keys.d.ts +0 -140
  368. package/dist/functions/api-keys.d.ts.map +0 -1
  369. package/dist/functions/apps.d.ts +0 -163
  370. package/dist/functions/apps.d.ts.map +0 -1
  371. package/dist/functions/auth.d.ts +0 -74
  372. package/dist/functions/auth.d.ts.map +0 -1
  373. package/dist/functions/debug-auth.d.ts +0 -33
  374. package/dist/functions/debug-auth.d.ts.map +0 -1
  375. package/dist/functions/embeddings.d.ts +0 -205
  376. package/dist/functions/embeddings.d.ts.map +0 -1
  377. package/dist/functions/integration-routes.d.ts +0 -45
  378. package/dist/functions/integration-routes.d.ts.map +0 -1
  379. package/dist/functions/integrations.d.ts +0 -124
  380. package/dist/functions/integrations.d.ts.map +0 -1
  381. package/dist/functions/item-progress.d.ts +0 -41
  382. package/dist/functions/item-progress.d.ts.map +0 -1
  383. package/dist/functions/logs.d.ts +0 -162
  384. package/dist/functions/logs.d.ts.map +0 -1
  385. package/dist/functions/observability.d.ts +0 -123
  386. package/dist/functions/observability.d.ts.map +0 -1
  387. package/dist/functions/pipeline-executions.d.ts +0 -190
  388. package/dist/functions/pipeline-executions.d.ts.map +0 -1
  389. package/dist/functions/pipelines.d.ts +0 -171
  390. package/dist/functions/pipelines.d.ts.map +0 -1
  391. package/dist/functions/prompt-configs.d.ts +0 -125
  392. package/dist/functions/prompt-configs.d.ts.map +0 -1
  393. package/dist/functions/roles.d.ts +0 -118
  394. package/dist/functions/roles.d.ts.map +0 -1
  395. package/dist/functions/system-cron.d.ts +0 -65
  396. package/dist/functions/system-cron.d.ts.map +0 -1
  397. package/dist/functions/system.d.ts +0 -29
  398. package/dist/functions/system.d.ts.map +0 -1
  399. package/dist/functions/tests.d.ts +0 -28
  400. package/dist/functions/tests.d.ts.map +0 -1
  401. package/dist/functions/timers.d.ts +0 -139
  402. package/dist/functions/timers.d.ts.map +0 -1
  403. package/dist/functions/triggers.d.ts +0 -203
  404. package/dist/functions/triggers.d.ts.map +0 -1
  405. package/dist/functions/types.d.ts +0 -151
  406. package/dist/functions/types.d.ts.map +0 -1
  407. package/dist/src/types/types.d.ts +0 -364
  408. package/dist/src/types/types.d.ts.map +0 -1
  409. package/index.html +0 -13
  410. package/netlify.toml +0 -36
  411. package/package-project.json +0 -64
  412. package/scripts/app-install-cli.ts +0 -286
  413. package/scripts/assemble-frontend.sh +0 -79
  414. package/scripts/assemble-functions.sh +0 -62
  415. package/scripts/assemble.sh +0 -41
  416. package/scripts/boundary-check.sh +0 -106
  417. package/scripts/build-manifest.sh +0 -80
  418. package/scripts/check-core-integrity.sh +0 -82
  419. package/scripts/ingest-chunks.cjs +0 -202
  420. package/scripts/kb-chunk-parser.cjs +0 -312
  421. package/scripts/kb-chunk-parser.ts +0 -330
  422. package/scripts/load-test-app-install.ts +0 -484
  423. package/scripts/netlify-dev-wrapper.sh +0 -22
  424. package/scripts/verify-integrity.sh +0 -69
  425. package/vitest.config.ts +0 -45
@@ -1,742 +0,0 @@
1
- /**
2
- * @module system-cron
3
- * @audience core-contributor
4
- * @layer api-handler
5
- * @stability stable
6
- *
7
- * Scheduled job runner invoked by an external cron service (e.g., AWS
8
- * EventBridge, Google Cloud Scheduler). On each tick it:
9
- *
10
- * 1. Authenticates the request via `SCHEDULER_API_KEY` or machine principal
11
- * 2. Fetches all schedules due via `get_due_schedules` RPC
12
- * 3. For each schedule: validates creator, loads action + machine principal,
13
- * checks scope, executes action, records outcome
14
- * 4. Fetches all timers due via `get_due_timers` RPC and runs each pipeline
15
- * 5. Evaluates threshold alerts via `evaluateThresholds`
16
- * 6. Runs daily log cleanup at 00:00 UTC via `cleanupOldLogs`
17
- *
18
- * **Routed by:** `POST /.netlify/functions/system-cron`
19
- *
20
- * **Authentication:** Request must supply `SCHEDULER_API_KEY` via `?api_key`
21
- * or `?scheduler_key`, OR originate from an internal machine principal
22
- * (type='machine', machineType='internal'). Unauthorized requests receive 403.
23
- *
24
- * **Response shape:**
25
- * ```ts
26
- * {
27
- * executed: number
28
- * success: number
29
- * failed: number
30
- * skipped: number
31
- * thresholds_evaluated: number
32
- * thresholds_breached: number
33
- * logs_cleaned: number
34
- * results: Array<{ scheduleId, actionId, status, error?, durationMs }>
35
- * }
36
- * ```
37
- *
38
- * INVARIANT: Uses `adminDb` (service-role client, bypasses RLS) because
39
- * machine principals must access cross-account data.
40
- * INVARIANT: Log cleanup only runs when the current UTC time is 00:00.
41
- *
42
- * @seeAlso timers.ts (timer configuration CRUD)
43
- * @seeAlso pipelines.ts (pipeline configuration CRUD)
44
- * @seeAlso pipeline-runner.ts (runPipeline — timer/schedule execution)
45
- * @seeAlso observability.ts (analytics RPCs used by evaluateThresholds)
46
- * @seeAlso audit.ts (emitAudit for cron lifecycle events)
47
- */
48
-
49
- import { createHandler, RequestContext } from './_shared/middleware'
50
- import { adminDb } from './_shared/db'
51
- import { emitAudit } from './_shared/audit'
52
- import { runPipeline } from './_shared/pipeline-runner'
53
-
54
- const SCHEDULER_API_KEY: string | undefined = (globalThis as any).process?.env?.SCHEDULER_API_KEY || (globalThis as any).Deno?.env?.get?.('SCHEDULER_API_KEY')
55
-
56
- // ─── MAIN HANDLER ────────────────────────────────────────────────────────────
57
-
58
- /**
59
- * Netlify function entry point — the entire cron tick logic lives here.
60
- * Returns HTTP 200 with a results summary on success, or HTTP 403/500
61
- * on auth/runtime failure.
62
- *
63
- * @throws Returns 403 JSON if scheduler key is missing or invalid
64
- * @throws Returns 500 JSON on unhandled top-level error
65
- * @sideEffects DB read: get_due_schedules, validate_schedule_creator,
66
- * actions, api_keys, get_due_timers
67
- * @sideEffects DB write: schedule_executions (INSERT), update_schedule_after_run
68
- * RPC, update_timer_after_run RPC, cleanup_old_logs RPC
69
- * @sideEffects pipeline: runPipeline (timers + threshold responses)
70
- * @sideEffects audit: emitAudit for unauthorized, error, schedule.execute,
71
- * threshold.breached events
72
- * @calledBy External cron scheduler (AWS EventBridge / Google Cloud Scheduler)
73
- */
74
- export const handler = createHandler(async (ctx: RequestContext) => {
75
- // ============================================
76
- // SECURITY: Validate this is an internal request
77
- // ============================================
78
-
79
- // Check if request has scheduler authentication
80
- const requestApiKey = ctx.query?.api_key || ctx.query?.scheduler_key
81
-
82
- if (requestApiKey !== SCHEDULER_API_KEY) {
83
- // Also allow if the principal is a system machine (for internal invocations)
84
- if (ctx.principal?.type !== 'machine' || ctx.principal?.machineType !== 'internal') {
85
- await emitAudit(ctx, 'system_cron.unauthorized_access', {
86
- type: 'system',
87
- account_id: ctx.accountId || undefined
88
- }, { result: 'denied', error: 'Invalid or missing scheduler authentication' })
89
-
90
- return {
91
- statusCode: 403,
92
- body: JSON.stringify({ error: 'Forbidden - Invalid scheduler authentication' })
93
- }
94
- }
95
- }
96
-
97
- // ============================================
98
- // Find and execute due schedules
99
- // ============================================
100
-
101
- const results: Array<{
102
- scheduleId: string
103
- actionId: string
104
- status: 'success' | 'failed' | 'skipped'
105
- error?: string
106
- durationMs: number
107
- }> = []
108
-
109
- try {
110
- // Get all schedules due for execution
111
- const { data: dueSchedules, error: schedulesError } = await adminDb.rpc('get_due_schedules', {
112
- p_now: new Date().toISOString()
113
- })
114
-
115
- if (schedulesError) {
116
- throw new Error(`Failed to fetch due schedules: ${schedulesError.message}`)
117
- }
118
-
119
- if (!dueSchedules || dueSchedules.length === 0) {
120
- return {
121
- statusCode: 200,
122
- body: JSON.stringify({
123
- message: 'No schedules due for execution',
124
- executed: 0,
125
- results: []
126
- })
127
- }
128
- }
129
-
130
- // Execute each due schedule
131
- for (const schedule of dueSchedules) {
132
- const startTime = Date.now()
133
-
134
- try {
135
- // Validate schedule can run (creator still active)
136
- const { data: validation, error: validationError } = await adminDb.rpc('validate_schedule_creator', {
137
- p_schedule_id: schedule.schedule_id
138
- })
139
-
140
- if (validationError || !validation?.is_valid) {
141
- // Schedule was auto-paused by validation function
142
- results.push({
143
- scheduleId: schedule.schedule_id,
144
- actionId: schedule.action_id,
145
- status: 'skipped',
146
- error: validation?.error_message || 'Schedule validation failed',
147
- durationMs: Date.now() - startTime
148
- })
149
- continue
150
- }
151
-
152
- // Load the action
153
- const { data: action, error: actionError } = await adminDb
154
- .from('actions')
155
- .select('*')
156
- .eq('id', schedule.action_id)
157
- .single()
158
-
159
- if (actionError || !action) {
160
- throw new Error(`Action not found: ${schedule.action_id}`)
161
- }
162
-
163
- // Load the machine principal
164
- const { data: machine, error: machineError } = await adminDb
165
- .from('api_keys')
166
- .select('*')
167
- .eq('id', schedule.machine_principal_id)
168
- .single()
169
-
170
- if (machineError || !machine) {
171
- throw new Error(`Machine principal not found: ${schedule.machine_principal_id}`)
172
- }
173
-
174
- // Create execution context with machine principal
175
- const executionCtx: RequestContext = {
176
- requestId: ctx.requestId,
177
- principal: {
178
- id: machine.id,
179
- type: 'machine',
180
- accountId: machine.account_id,
181
- scopes: schedule.delegated_scopes || machine.scopes || [],
182
- machineType: machine.machine_type,
183
- isInternal: machine.is_internal,
184
- provenance: {
185
- sourceType: 'cron',
186
- createdBy: machine.created_by,
187
- invokedAt: new Date().toISOString(),
188
- cronId: schedule.schedule_id
189
- }
190
- },
191
- db: adminDb, // Machines use adminDb (RLS checks their ID)
192
- accountId: machine.account_id,
193
- appId: null,
194
- requestPath: '/.netlify/functions/system-cron',
195
- query: {}
196
- }
197
-
198
- // Check machine has required scope for this action
199
- const requiredScope = action.required_scopes?.[0] || `${action.handler}:execute`
200
- const hasScope = executionCtx.principal.scopes?.includes(requiredScope) ||
201
- executionCtx.principal.scopes?.includes('*:*')
202
-
203
- if (!hasScope) {
204
- throw new Error(`Machine lacks required scope: ${requiredScope}`)
205
- }
206
-
207
- // Execute the action
208
- const executionResult = await executeAction(executionCtx, action, schedule.config)
209
-
210
- // Record execution success
211
- await adminDb.from('schedule_executions').insert({
212
- schedule_id: schedule.schedule_id,
213
- account_id: schedule.account_id,
214
- machine_principal_id: machine.id,
215
- status: 'success',
216
- input_params: schedule.config,
217
- output_result: executionResult,
218
- duration_ms: Date.now() - startTime
219
- })
220
-
221
- // Update schedule state
222
- await adminDb.rpc('update_schedule_after_run', {
223
- p_schedule_id: schedule.schedule_id,
224
- p_success: true,
225
- p_error_message: null
226
- })
227
-
228
- // Emit audit log
229
- await emitAudit(executionCtx, 'schedule.execute', {
230
- type: 'schedule',
231
- id: schedule.schedule_id,
232
- account_id: schedule.account_id
233
- }, {
234
- action_id: action.id,
235
- action_handler: action.handler,
236
- result: 'success'
237
- })
238
-
239
- results.push({
240
- scheduleId: schedule.schedule_id,
241
- actionId: schedule.action_id,
242
- status: 'success',
243
- durationMs: Date.now() - startTime
244
- })
245
-
246
- } catch (execError: any) {
247
- const errorMessage = execError.message || 'Execution failed'
248
-
249
- // Record execution failure
250
- await adminDb.from('schedule_executions').insert({
251
- schedule_id: schedule.schedule_id,
252
- account_id: schedule.account_id,
253
- machine_principal_id: schedule.machine_principal_id,
254
- status: 'failed',
255
- input_params: schedule.config,
256
- error_message: errorMessage,
257
- duration_ms: Date.now() - startTime
258
- })
259
-
260
- // Update schedule state
261
- await adminDb.rpc('update_schedule_after_run', {
262
- p_schedule_id: schedule.schedule_id,
263
- p_success: false,
264
- p_error_message: errorMessage
265
- })
266
-
267
- results.push({
268
- scheduleId: schedule.schedule_id,
269
- actionId: schedule.action_id,
270
- status: 'failed',
271
- error: errorMessage,
272
- durationMs: Date.now() - startTime
273
- })
274
- }
275
- }
276
-
277
- // ============================================
278
- // Execute due timers (pipeline-based timers)
279
- // ============================================
280
-
281
- try {
282
- const { data: dueTimers, error: timersError } = await adminDb.rpc('get_due_timers', {
283
- p_now: new Date().toISOString()
284
- })
285
-
286
- if (!timersError && dueTimers && dueTimers.length > 0) {
287
- for (const timer of dueTimers) {
288
- const timerStartTime = Date.now()
289
-
290
- try {
291
- // Validate timer can run
292
- if (!timer.pipeline_id) {
293
- throw new Error(`Timer ${timer.timer_id} has no pipeline_id`)
294
- }
295
-
296
- // Create execution context for timer
297
- const timerCtx: RequestContext = {
298
- requestId: ctx.requestId,
299
- principal: {
300
- id: 'timer:' + timer.timer_id,
301
- type: 'machine' as const,
302
- accountId: timer.account_id,
303
- scopes: ['pipelines:execute'],
304
- machineType: 'timer',
305
- isInternal: true,
306
- provenance: {
307
- sourceType: 'timer',
308
- createdBy: timer.created_by,
309
- invokedAt: new Date().toISOString(),
310
- timerId: timer.timer_id
311
- }
312
- },
313
- db: adminDb,
314
- accountId: timer.account_id,
315
- appId: timer.app_id || null,
316
- requestPath: '/.netlify/functions/system-cron',
317
- query: {}
318
- }
319
-
320
- // Run the pipeline
321
- const result = await runPipeline(timer.pipeline_id, {
322
- timer_id: timer.timer_id,
323
- timer_name: timer.name,
324
- execution_count: timer.execution_count || 0
325
- }, timerCtx)
326
-
327
- // Update timer state
328
- await adminDb.rpc('update_timer_after_run', {
329
- p_timer_id: timer.timer_id,
330
- p_success: result.status === 'completed',
331
- p_error_message: result.error || null
332
- })
333
-
334
- results.push({
335
- scheduleId: timer.timer_id,
336
- actionId: timer.pipeline_id,
337
- status: result.status === 'completed' ? 'success' : 'failed',
338
- error: result.error,
339
- durationMs: Date.now() - timerStartTime
340
- })
341
-
342
- } catch (timerError: any) {
343
- // Update timer with failure
344
- await adminDb.rpc('update_timer_after_run', {
345
- p_timer_id: timer.timer_id,
346
- p_success: false,
347
- p_error_message: timerError.message
348
- })
349
-
350
- results.push({
351
- scheduleId: timer.timer_id,
352
- actionId: timer.pipeline_id,
353
- status: 'failed',
354
- error: timerError.message,
355
- durationMs: Date.now() - timerStartTime
356
- })
357
- }
358
- }
359
- }
360
- } catch (timerLoopError) {
361
- console.error('Timer execution error:', timerLoopError)
362
- }
363
-
364
- // ============================================
365
- // Evaluate threshold alerts (every minute)
366
- // ============================================
367
- let thresholdResults: any[] = []
368
- try {
369
- thresholdResults = await evaluateThresholds(ctx)
370
- const breachedCount = thresholdResults.filter(r => r.breached).length
371
- const firedCount = thresholdResults.filter(r => r.fired).length
372
-
373
- if (breachedCount > 0) {
374
- console.log(`Thresholds: ${breachedCount} breached, ${firedCount} pipelines fired`)
375
- }
376
- } catch (thresholdError) {
377
- console.error('Threshold evaluation error:', thresholdError)
378
- }
379
-
380
- // ============================================
381
- // Daily log cleanup (check if it's time)
382
- // ============================================
383
- let logsCleaned = 0
384
- const now = new Date()
385
- const currentHour = now.getUTCHours()
386
- const currentMinute = now.getUTCMinutes()
387
-
388
- // Run cleanup once per day at 00:00 UTC
389
- if (currentHour === 0 && currentMinute === 0) {
390
- try {
391
- logsCleaned = await cleanupOldLogs()
392
- } catch (cleanupError) {
393
- console.error('Log cleanup error:', cleanupError)
394
- }
395
- }
396
-
397
- // Return summary
398
- const successCount = results.filter(r => r.status === 'success').length
399
- const failedCount = results.filter(r => r.status === 'failed').length
400
- const skippedCount = results.filter(r => r.status === 'skipped').length
401
-
402
- return {
403
- statusCode: 200,
404
- body: JSON.stringify({
405
- message: `Executed ${results.length} total (schedules + timers)`,
406
- executed: results.length,
407
- success: successCount,
408
- failed: failedCount,
409
- skipped: skippedCount,
410
- thresholds_evaluated: thresholdResults.length,
411
- thresholds_breached: thresholdResults.filter(r => r.breached).length,
412
- logs_cleaned: logsCleaned,
413
- results
414
- })
415
- }
416
-
417
- } catch (error: any) {
418
- console.error('System cron error:', error)
419
-
420
- await emitAudit(ctx, 'system_cron.error', {
421
- type: 'system',
422
- account_id: ctx.accountId || undefined
423
- }, {
424
- result: 'failure',
425
- error: error.message
426
- })
427
-
428
- return {
429
- statusCode: 500,
430
- body: JSON.stringify({
431
- error: 'System cron execution failed',
432
- message: error.message
433
- })
434
- }
435
- }
436
- })
437
-
438
- // ─── PRIVATE HELPERS ───────────────────────────────────────────────────────────
439
-
440
- /**
441
- * Dispatches to the appropriate handler module (`functions` | `integrations`
442
- * | `custom`) based on `action.handler_module`. Merges action-level config
443
- * with schedule-specific config before invoking.
444
- *
445
- * @throws Error('Unknown handler module: <module>') on unrecognized module
446
- * @throws Error('Custom handlers not yet implemented: <name>')
447
- */
448
- async function executeAction(
449
- ctx: RequestContext,
450
- action: any,
451
- config: any
452
- ): Promise<any> {
453
- const handlerModule = action.handler_module || 'functions'
454
- const handlerName = action.handler
455
-
456
- // Merge action config with schedule-specific config
457
- const mergedConfig = {
458
- ...action.config,
459
- ...config
460
- }
461
-
462
- switch (handlerModule) {
463
- case 'functions':
464
- return await executeFunctionHandler(ctx, handlerName, mergedConfig)
465
-
466
- case 'integrations':
467
- return await executeIntegrationHandler(ctx, handlerName, mergedConfig)
468
-
469
- case 'custom':
470
- // Custom handlers would be loaded from v2-custom
471
- throw new Error(`Custom handlers not yet implemented: ${handlerName}`)
472
-
473
- default:
474
- throw new Error(`Unknown handler module: ${handlerModule}`)
475
- }
476
- }
477
-
478
- /**
479
- * Routes to one of the built-in named handlers: `send_email`,
480
- * `generate_report`, `notify_watchers`, `run_pipeline`.
481
- * `run_pipeline` delegates to `runPipeline` from `_shared/pipeline-runner.ts`.
482
- *
483
- * @throws Error('Unknown function handler: <name>') on unrecognized name
484
- * @throws Error('pipeline_id is required for run_pipeline handler')
485
- */
486
- async function executeFunctionHandler(
487
- ctx: RequestContext,
488
- handlerName: string,
489
- config: any
490
- ): Promise<any> {
491
- // Built-in handlers
492
- const handlers: Record<string, Function> = {
493
- 'send_email': async (ctx: RequestContext, config: any) => {
494
- // Implementation would integrate with email service
495
- console.log(`[${ctx.requestId}] Sending email:`, config)
496
- return { sent: true, recipients: config.recipients }
497
- },
498
-
499
- 'generate_report': async (ctx: RequestContext, config: any) => {
500
- // Implementation would generate and deliver report
501
- console.log(`[${ctx.requestId}] Generating report:`, config)
502
- return { generated: true, format: config.output_format }
503
- },
504
-
505
- 'notify_watchers': async (ctx: RequestContext, config: any) => {
506
- // Implementation would notify item watchers
507
- console.log(`[${ctx.requestId}] Notifying watchers:`, config)
508
- return { notified: true }
509
- },
510
-
511
- 'run_pipeline': async (ctx: RequestContext, config: any) => {
512
- // Execute a pipeline as part of scheduled action
513
- const { pipeline_id, trigger_data = {} } = config
514
-
515
- if (!pipeline_id) {
516
- throw new Error('pipeline_id is required for run_pipeline handler')
517
- }
518
-
519
- const result = await runPipeline(pipeline_id, trigger_data, ctx)
520
- return {
521
- success: result.status === 'completed',
522
- execution_id: result.executionId,
523
- stages_completed: result.stages?.length || 0,
524
- duration_ms: result.durationMs
525
- }
526
- }
527
- }
528
-
529
- const handler = handlers[handlerName]
530
- if (!handler) {
531
- throw new Error(`Unknown function handler: ${handlerName}`)
532
- }
533
-
534
- return await handler(ctx, config)
535
- }
536
-
537
- /**
538
- * Placeholder for integration-based action handlers (external service calls).
539
- * Currently logs and returns `{ executed: true }` for all handler names.
540
- */
541
- async function executeIntegrationHandler(
542
- ctx: RequestContext,
543
- handlerName: string,
544
- config: any
545
- ): Promise<any> {
546
- // Integration handlers would call external services
547
- // This is a placeholder for future implementation
548
- console.log(`[${ctx.requestId}] Integration handler: ${handlerName}`, config)
549
- return { executed: true, handler: handlerName }
550
- }
551
-
552
- /**
553
- * Evaluates all active `threshold_alert` items across all accounts.
554
- * For each threshold, queries the appropriate observability RPC
555
- * (`get_error_rate`, `get_latency_percentiles`, or `get_pipeline_stats`)
556
- * and fires the configured pipeline if the threshold is breached.
557
- *
558
- * Supported metrics: `error_rate`, `latency_p95`, `pipeline_failure_rate`
559
- *
560
- * @returns Array of `{ thresholdId, breached, fired }` results
561
- * @sideEffects DB read: items (threshold_alert), observability RPCs
562
- * @sideEffects pipeline: runPipeline when threshold breached and pipeline_id set
563
- * @sideEffects audit: emitAudit('threshold.breached') for each breached threshold
564
- * @calledBy handler (every tick)
565
- */
566
- async function evaluateThresholds(ctx: RequestContext): Promise<Array<{ thresholdId: string; breached: boolean; fired: boolean }>> {
567
- const results: Array<{ thresholdId: string; breached: boolean; fired: boolean }> = []
568
-
569
- try {
570
- // Load all active threshold alerts from items table
571
- const { data: thresholds, error } = await adminDb
572
- .from('items')
573
- .select('*')
574
- .eq('type', 'threshold_alert')
575
- .eq('data->>is_active', 'true')
576
-
577
- if (error) {
578
- console.error('Failed to load thresholds:', error)
579
- return results
580
- }
581
-
582
- if (!thresholds || thresholds.length === 0) {
583
- return results
584
- }
585
-
586
- // Evaluate each threshold
587
- for (const threshold of thresholds) {
588
- try {
589
- const config = threshold.data || {}
590
- const { metric, operator, value, window_minutes, pipeline_id } = config
591
-
592
- if (!metric || !operator || value === undefined || !window_minutes) {
593
- console.warn(`Threshold ${threshold.id} missing required fields`)
594
- continue
595
- }
596
-
597
- // Calculate time window
598
- const now = new Date()
599
- const from = new Date(now.getTime() - window_minutes * 60 * 1000)
600
-
601
- let breached = false
602
- let actualValue: number = 0
603
-
604
- // Query appropriate RPC based on metric
605
- switch (metric) {
606
- case 'error_rate': {
607
- const { data } = await adminDb.rpc('get_error_rate', {
608
- p_account_id: threshold.account_id,
609
- p_from: from.toISOString(),
610
- p_to: now.toISOString()
611
- })
612
- if (data && data.length > 0) {
613
- actualValue = data[0].rate
614
- breached = operator === 'gt' ? actualValue > value : actualValue < value
615
- }
616
- break
617
- }
618
-
619
- case 'latency_p95': {
620
- const { data } = await adminDb.rpc('get_latency_percentiles', {
621
- p_account_id: threshold.account_id,
622
- p_from: from.toISOString(),
623
- p_to: now.toISOString()
624
- })
625
- if (data && data.length > 0) {
626
- actualValue = data[0].p95
627
- breached = operator === 'gt' ? actualValue > value : actualValue < value
628
- }
629
- break
630
- }
631
-
632
- case 'pipeline_failure_rate': {
633
- const { data } = await adminDb.rpc('get_pipeline_stats', {
634
- p_account_id: threshold.account_id,
635
- p_from: from.toISOString(),
636
- p_to: now.toISOString()
637
- })
638
- if (data && data.length > 0) {
639
- // Calculate overall failure rate across all pipelines
640
- const totalSuccess = data.reduce((sum: number, p: any) => sum + (parseInt(p.success_count) || 0), 0)
641
- const totalFailure = data.reduce((sum: number, p: any) => sum + (parseInt(p.failure_count) || 0), 0)
642
- const total = totalSuccess + totalFailure
643
- actualValue = total > 0 ? (totalFailure / total) * 100 : 0
644
- breached = operator === 'gt' ? actualValue > value : actualValue < value
645
- }
646
- break
647
- }
648
-
649
- default:
650
- console.warn(`Unknown metric: ${metric}`)
651
- continue
652
- }
653
-
654
- // Fire pipeline if breached and pipeline_id configured
655
- let fired = false
656
- if (breached && pipeline_id) {
657
- try {
658
- await runPipeline(pipeline_id, {
659
- threshold_id: threshold.id,
660
- metric,
661
- threshold_value: value,
662
- actual_value: actualValue,
663
- window_minutes,
664
- triggered_at: now.toISOString()
665
- }, ctx)
666
- fired = true
667
- } catch (pipelineError: any) {
668
- console.error(`Failed to fire threshold pipeline ${pipeline_id}:`, pipelineError)
669
- }
670
- }
671
-
672
- // Log threshold event if breached
673
- if (breached) {
674
- await emitAudit(ctx, 'threshold.breached', {
675
- type: 'threshold_alert',
676
- id: threshold.id,
677
- account_id: threshold.account_id
678
- }, {
679
- metric,
680
- operator,
681
- threshold_value: value,
682
- actual_value: actualValue,
683
- window_minutes,
684
- pipeline_fired: fired,
685
- pipeline_id
686
- })
687
- }
688
-
689
- results.push({
690
- thresholdId: threshold.id,
691
- breached,
692
- fired
693
- })
694
-
695
- } catch (thresholdError: any) {
696
- console.error(`Error evaluating threshold ${threshold.id}:`, thresholdError)
697
- results.push({
698
- thresholdId: threshold.id,
699
- breached: false,
700
- fired: false
701
- })
702
- }
703
- }
704
-
705
- return results
706
-
707
- } catch (error: any) {
708
- console.error('Threshold evaluation error:', error)
709
- return results
710
- }
711
- }
712
-
713
- /**
714
- * Runs the `cleanup_old_logs` RPC with 90-day retention. Called once daily
715
- * by the handler at 00:00 UTC.
716
- *
717
- * @returns Number of log records deleted
718
- * @sideEffects DB write: cleanup_old_logs RPC (cross-account DELETE)
719
- * @calledBy handler (daily, 00:00 UTC)
720
- */
721
- async function cleanupOldLogs(): Promise<number> {
722
- try {
723
- const { data, error } = await adminDb.rpc('cleanup_old_logs', {
724
- p_retention_days: 90
725
- })
726
-
727
- if (error) {
728
- console.error('Log cleanup failed:', error)
729
- return 0
730
- }
731
-
732
- const deletedCount = data?.[0]?.deleted_count || 0
733
- if (deletedCount > 0) {
734
- console.log(`Cleaned up ${deletedCount} old log records`)
735
- }
736
-
737
- return deletedCount
738
- } catch (error: any) {
739
- console.error('Log cleanup error:', error)
740
- return 0
741
- }
742
- }