spine-framework 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (385) hide show
  1. package/.framework/README.md +129 -0
  2. package/.framework/cli/bin.cjs +14 -0
  3. package/.framework/cli/commands/agents.ts +153 -0
  4. package/.framework/cli/commands/auth.ts +94 -0
  5. package/.framework/cli/commands/create-app.ts +185 -0
  6. package/.framework/cli/commands/dev.ts +295 -0
  7. package/.framework/cli/commands/doctor.ts +442 -0
  8. package/.framework/cli/commands/generate.ts +332 -0
  9. package/.framework/cli/commands/init.ts +272 -0
  10. package/.framework/cli/commands/install-app.ts +391 -0
  11. package/.framework/cli/commands/items.ts +253 -0
  12. package/.framework/cli/commands/migrations.ts +141 -0
  13. package/.framework/cli/commands/pipelines.ts +166 -0
  14. package/.framework/cli/commands/status.ts +197 -0
  15. package/.framework/cli/commands/system.ts +184 -0
  16. package/.framework/cli/commands/test.ts +227 -0
  17. package/.framework/cli/commands/uninstall-app.ts +166 -0
  18. package/.framework/cli/context.ts +268 -0
  19. package/.framework/cli/env-loader.ts +36 -0
  20. package/.framework/cli/index.ts +106 -0
  21. package/.framework/cli/welcome.cjs +45 -0
  22. package/.framework/docs/API.md +384 -0
  23. package/.framework/docs/STABILITY.md +52 -0
  24. package/.framework/docs/admin-routes.md +76 -0
  25. package/.framework/docs/api-docs-progress.md +38 -0
  26. package/.framework/docs/api-governance.md +146 -0
  27. package/.framework/docs/api-testing-results.md +212 -0
  28. package/.framework/docs/apis/admin-configs.md +567 -0
  29. package/.framework/docs/apis/admin-data.md +272 -0
  30. package/.framework/docs/apis/index.md +231 -0
  31. package/.framework/docs/apis/internal.md +295 -0
  32. package/.framework/docs/apis/runtime.md +537 -0
  33. package/.framework/docs/assembly-launch-guide.md +138 -0
  34. package/.framework/docs/audit-results.md +590 -0
  35. package/.framework/docs/authorization-model.md +170 -0
  36. package/.framework/docs/db-api-inventory.md +95 -0
  37. package/.framework/docs/examples/custom-app/README.md +77 -0
  38. package/.framework/docs/examples/custom-function/README.md +27 -0
  39. package/.framework/docs/examples/custom-function/handler.ts +48 -0
  40. package/.framework/docs/examples/custom-webhook/README.md +68 -0
  41. package/.framework/docs/gap-remediation-backlog.md +103 -0
  42. package/.framework/docs/guides/cli-guide.md +224 -0
  43. package/.framework/docs/guides/getting-started.md +103 -0
  44. package/.framework/docs/guides/import-guide.md +193 -0
  45. package/.framework/docs/guides/testing-guide.md +229 -0
  46. package/.framework/docs/permission-examples.md +326 -0
  47. package/.framework/docs/ui-adoption-verification.md +111 -0
  48. package/.framework/docs/ui-api-coverage.md +84 -0
  49. package/.framework/docs/v2-compatibility-audit.md +228 -0
  50. package/.framework/functions/.gitkeep +1 -0
  51. package/.framework/functions/_shared/agent-runner.ts +1097 -0
  52. package/.framework/functions/_shared/app-manifest.ts +184 -0
  53. package/.framework/functions/_shared/audit.ts +150 -0
  54. package/.framework/functions/_shared/db.ts +174 -0
  55. package/.framework/functions/_shared/index.ts +382 -0
  56. package/.framework/functions/_shared/middleware.ts +490 -0
  57. package/.framework/functions/_shared/permissions.ts +1325 -0
  58. package/.framework/functions/_shared/pipeline-runner.ts +731 -0
  59. package/.framework/functions/_shared/principal.ts +760 -0
  60. package/.framework/functions/_shared/schema-utils.ts +967 -0
  61. package/.framework/functions/_shared/testing.ts +258 -0
  62. package/.framework/functions/_shared/trigger-engine.ts +425 -0
  63. package/.framework/functions/_shared/webhook-registration.ts +168 -0
  64. package/.framework/functions/_shared/webhook-registry.ts +129 -0
  65. package/.framework/functions/account-nodes.ts +111 -0
  66. package/.framework/functions/admin-data.ts +606 -0
  67. package/.framework/functions/ai-agents.ts +323 -0
  68. package/.framework/functions/api-keys.ts +376 -0
  69. package/.framework/functions/apps.ts +483 -0
  70. package/.framework/functions/auth.ts +196 -0
  71. package/.framework/functions/debug-auth.ts +107 -0
  72. package/.framework/functions/embeddings.ts +556 -0
  73. package/.framework/functions/integration-routes.ts +523 -0
  74. package/.framework/functions/integrations.ts +319 -0
  75. package/.framework/functions/item-progress.ts +272 -0
  76. package/.framework/functions/logs.ts +438 -0
  77. package/.framework/functions/observability.ts +275 -0
  78. package/.framework/functions/pipeline-executions.ts +494 -0
  79. package/.framework/functions/pipelines.ts +485 -0
  80. package/.framework/functions/prompt-configs.ts +339 -0
  81. package/.framework/functions/roles.ts +387 -0
  82. package/.framework/functions/system-cron.ts +742 -0
  83. package/.framework/functions/system.ts +323 -0
  84. package/.framework/functions/tests.ts +119 -0
  85. package/.framework/functions/timers.ts +357 -0
  86. package/.framework/functions/triggers.ts +563 -0
  87. package/.framework/functions/types.ts +604 -0
  88. package/.framework/migrations/000_foundation.sql +1256 -0
  89. package/.framework/migrations/001_seed.sql +92 -0
  90. package/.framework/migrations/002_seed_constraints.sql +13 -0
  91. package/.framework/migrations/003_auth_user_trigger.sql +59 -0
  92. package/.framework/src/App.tsx +126 -0
  93. package/.framework/src/apps/admin/index.tsx +173 -0
  94. package/.framework/src/components/AppWrapper.tsx +56 -0
  95. package/.framework/src/components/CustomAppLoader.tsx +116 -0
  96. package/.framework/src/components/admin/AdminListPage.tsx +151 -0
  97. package/.framework/src/components/admin/AdminSidebar.tsx +166 -0
  98. package/.framework/src/components/admin/AdminStatsCard.tsx +62 -0
  99. package/.framework/src/components/admin/SortableTableHeader.tsx +42 -0
  100. package/.framework/src/components/app-shell/GenericAppShell.tsx +181 -0
  101. package/.framework/src/components/app-shell/GenericDetailPage.tsx +200 -0
  102. package/.framework/src/components/app-shell/GenericListPage.tsx +116 -0
  103. package/.framework/src/components/app-sidebar.tsx +228 -0
  104. package/.framework/src/components/auth/ProtectedRoute.tsx +88 -0
  105. package/.framework/src/components/layout/AppShell.tsx +91 -0
  106. package/.framework/src/components/layout/Header.tsx +88 -0
  107. package/.framework/src/components/layout/Layout.tsx +95 -0
  108. package/.framework/src/components/layout/Sidebar.tsx +329 -0
  109. package/.framework/src/components/runtime/DataDetailHeader.tsx +77 -0
  110. package/.framework/src/components/runtime/DataDetailPage.tsx +171 -0
  111. package/.framework/src/components/runtime/DataFilters.tsx +91 -0
  112. package/.framework/src/components/runtime/DataHeader.tsx +68 -0
  113. package/.framework/src/components/runtime/DataListPage.tsx +124 -0
  114. package/.framework/src/components/runtime/DataStats.tsx +70 -0
  115. package/.framework/src/components/runtime/DataTable.tsx +174 -0
  116. package/.framework/src/components/runtime/SchemaDetailForm.tsx +134 -0
  117. package/.framework/src/components/runtime/index.ts +18 -0
  118. package/.framework/src/components/search-form.tsx +29 -0
  119. package/.framework/src/components/shared/AgentView.tsx +213 -0
  120. package/.framework/src/components/shared/FieldRenderer.tsx +478 -0
  121. package/.framework/src/components/shared/SchemaFields.tsx +226 -0
  122. package/.framework/src/components/ui/DataTable.tsx +343 -0
  123. package/.framework/src/components/ui/Form.tsx +281 -0
  124. package/.framework/src/components/ui/ItemCard.tsx +296 -0
  125. package/.framework/src/components/ui/ItemListView.tsx +308 -0
  126. package/.framework/src/components/ui/LoadingSpinner.tsx +52 -0
  127. package/.framework/src/components/ui/Modal.tsx +61 -0
  128. package/.framework/src/components/ui/RichTextEditor.tsx +210 -0
  129. package/.framework/src/components/ui/accordion.tsx +82 -0
  130. package/.framework/src/components/ui/alert-dialog.tsx +197 -0
  131. package/.framework/src/components/ui/alert.tsx +76 -0
  132. package/.framework/src/components/ui/aspect-ratio.tsx +11 -0
  133. package/.framework/src/components/ui/avatar.tsx +110 -0
  134. package/.framework/src/components/ui/badge.tsx +49 -0
  135. package/.framework/src/components/ui/breadcrumb.tsx +122 -0
  136. package/.framework/src/components/ui/button-group.tsx +83 -0
  137. package/.framework/src/components/ui/button.tsx +65 -0
  138. package/.framework/src/components/ui/calendar.tsx +222 -0
  139. package/.framework/src/components/ui/card.tsx +100 -0
  140. package/.framework/src/components/ui/carousel.tsx +240 -0
  141. package/.framework/src/components/ui/chart.tsx +373 -0
  142. package/.framework/src/components/ui/checkbox.tsx +31 -0
  143. package/.framework/src/components/ui/collapsible.tsx +33 -0
  144. package/.framework/src/components/ui/combobox.tsx +299 -0
  145. package/.framework/src/components/ui/command.tsx +193 -0
  146. package/.framework/src/components/ui/context-menu.tsx +261 -0
  147. package/.framework/src/components/ui/dialog.tsx +165 -0
  148. package/.framework/src/components/ui/direction.tsx +22 -0
  149. package/.framework/src/components/ui/drawer.tsx +132 -0
  150. package/.framework/src/components/ui/dropdown-menu.tsx +269 -0
  151. package/.framework/src/components/ui/empty.tsx +104 -0
  152. package/.framework/src/components/ui/field.tsx +238 -0
  153. package/.framework/src/components/ui/hover-card.tsx +42 -0
  154. package/.framework/src/components/ui/input-group.tsx +153 -0
  155. package/.framework/src/components/ui/input-otp.tsx +87 -0
  156. package/.framework/src/components/ui/input.tsx +19 -0
  157. package/.framework/src/components/ui/item.tsx +196 -0
  158. package/.framework/src/components/ui/kbd.tsx +26 -0
  159. package/.framework/src/components/ui/label.tsx +22 -0
  160. package/.framework/src/components/ui/menubar.tsx +277 -0
  161. package/.framework/src/components/ui/native-select.tsx +61 -0
  162. package/.framework/src/components/ui/navigation-menu.tsx +164 -0
  163. package/.framework/src/components/ui/pagination.tsx +129 -0
  164. package/.framework/src/components/ui/popover.tsx +87 -0
  165. package/.framework/src/components/ui/progress.tsx +31 -0
  166. package/.framework/src/components/ui/radio-group.tsx +42 -0
  167. package/.framework/src/components/ui/resizable.tsx +50 -0
  168. package/.framework/src/components/ui/scroll-area.tsx +53 -0
  169. package/.framework/src/components/ui/select.tsx +195 -0
  170. package/.framework/src/components/ui/separator.tsx +26 -0
  171. package/.framework/src/components/ui/sheet.tsx +145 -0
  172. package/.framework/src/components/ui/sidebar.tsx +706 -0
  173. package/.framework/src/components/ui/skeleton.tsx +13 -0
  174. package/.framework/src/components/ui/slider.tsx +59 -0
  175. package/.framework/src/components/ui/sonner.tsx +47 -0
  176. package/.framework/src/components/ui/spinner.tsx +10 -0
  177. package/.framework/src/components/ui/switch.tsx +33 -0
  178. package/.framework/src/components/ui/table-primitives.tsx +141 -0
  179. package/.framework/src/components/ui/table.tsx +114 -0
  180. package/.framework/src/components/ui/tabs.tsx +90 -0
  181. package/.framework/src/components/ui/textarea.tsx +18 -0
  182. package/.framework/src/components/ui/toggle-group.tsx +89 -0
  183. package/.framework/src/components/ui/toggle.tsx +45 -0
  184. package/.framework/src/components/ui/tooltip.tsx +57 -0
  185. package/.framework/src/contexts/AppContext.tsx +133 -0
  186. package/.framework/src/contexts/AuthContext.tsx +371 -0
  187. package/.framework/src/hooks/use-mobile.ts +19 -0
  188. package/.framework/src/hooks/useApi.ts +526 -0
  189. package/.framework/src/hooks/useApps.ts +114 -0
  190. package/.framework/src/hooks/useEntityList.ts +190 -0
  191. package/.framework/src/hooks/useEntityRecord.ts +308 -0
  192. package/.framework/src/hooks/useForm.ts +307 -0
  193. package/.framework/src/hooks/useListSchema.ts +264 -0
  194. package/.framework/src/hooks/useSchemaRecord.ts +223 -0
  195. package/.framework/src/index.css +128 -0
  196. package/.framework/src/lib/api.ts +156 -0
  197. package/.framework/src/lib/supabase.ts +94 -0
  198. package/.framework/src/lib/utils.ts +317 -0
  199. package/.framework/src/main.tsx +27 -0
  200. package/.framework/src/pages/DashboardPage.tsx +181 -0
  201. package/.framework/src/pages/NotFoundPage.tsx +39 -0
  202. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +161 -0
  203. package/.framework/src/pages/admin/AIAgentsPage.tsx +318 -0
  204. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +199 -0
  205. package/.framework/src/pages/admin/APIKeysPage.tsx +303 -0
  206. package/.framework/src/pages/admin/AlertsConfigPage.tsx +523 -0
  207. package/.framework/src/pages/admin/AppDetailPage.tsx +493 -0
  208. package/.framework/src/pages/admin/AppsPage.tsx +355 -0
  209. package/.framework/src/pages/admin/DesignedPage.tsx +491 -0
  210. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +534 -0
  211. package/.framework/src/pages/admin/EmbeddingsPage.tsx +424 -0
  212. package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +176 -0
  213. package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +109 -0
  214. package/.framework/src/pages/admin/IntegratedDashboard.tsx +402 -0
  215. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +187 -0
  216. package/.framework/src/pages/admin/IntegrationsPage.tsx +301 -0
  217. package/.framework/src/pages/admin/LogsPage.tsx +283 -0
  218. package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +85 -0
  219. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +470 -0
  220. package/.framework/src/pages/admin/PipelineDetailPage.tsx +183 -0
  221. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +279 -0
  222. package/.framework/src/pages/admin/PipelinesPage.tsx +390 -0
  223. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +299 -0
  224. package/.framework/src/pages/admin/PromptConfigsPage.tsx +292 -0
  225. package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +434 -0
  226. package/.framework/src/pages/admin/RoleDetailPage.tsx +273 -0
  227. package/.framework/src/pages/admin/RolesPage.tsx +292 -0
  228. package/.framework/src/pages/admin/SelectTestPage.tsx +61 -0
  229. package/.framework/src/pages/admin/ShadcnTestPage.tsx +588 -0
  230. package/.framework/src/pages/admin/SimpleDashboard.tsx +387 -0
  231. package/.framework/src/pages/admin/TestRunDetailPage.tsx +172 -0
  232. package/.framework/src/pages/admin/TestingDashboard.tsx +257 -0
  233. package/.framework/src/pages/admin/TimerDetailPage.tsx +151 -0
  234. package/.framework/src/pages/admin/TimersPage.tsx +376 -0
  235. package/.framework/src/pages/admin/TriggerDetailPage.tsx +149 -0
  236. package/.framework/src/pages/admin/TriggersPage.tsx +381 -0
  237. package/.framework/src/pages/admin/TypeDetailPage.tsx +694 -0
  238. package/.framework/src/pages/admin/TypesPage.tsx +295 -0
  239. package/.framework/src/pages/auth/LoginPage.tsx +188 -0
  240. package/.framework/src/pages/auth/RegisterPage.tsx +163 -0
  241. package/.framework/src/pages/spine-framework/APIPage.tsx +17 -0
  242. package/.framework/src/pages/spine-framework/CLIPage.tsx +25 -0
  243. package/.framework/src/types/auth.ts +125 -0
  244. package/.framework/src/types/types.ts +407 -0
  245. package/STRUCTURE.md +150 -0
  246. package/config/components.json +25 -0
  247. package/config/deno.lock +108 -0
  248. package/config/package-lock.json +17183 -0
  249. package/config/postcss.config.cjs +10 -0
  250. package/config/tailwind.config.cjs +78 -0
  251. package/config/tsconfig.build.json +32 -0
  252. package/config/tsconfig.cli.json +18 -0
  253. package/config/tsconfig.json +41 -0
  254. package/config/tsconfig.node.json +17 -0
  255. package/config/tsconfig.node.tsbuildinfo +1 -0
  256. package/config/tsconfig.tsbuildinfo +1 -0
  257. package/config/typedoc.json +16 -0
  258. package/config/vite.config.d.ts +2 -0
  259. package/config/vite.config.ts +72 -0
  260. package/dist/cli/commands/agents.d.ts +39 -0
  261. package/dist/cli/commands/agents.d.ts.map +1 -0
  262. package/dist/cli/commands/auth.d.ts +36 -0
  263. package/dist/cli/commands/auth.d.ts.map +1 -0
  264. package/dist/cli/commands/create-app.d.ts +23 -0
  265. package/dist/cli/commands/create-app.d.ts.map +1 -0
  266. package/dist/cli/commands/dev.d.ts +39 -0
  267. package/dist/cli/commands/dev.d.ts.map +1 -0
  268. package/dist/cli/commands/doctor.d.ts +42 -0
  269. package/dist/cli/commands/doctor.d.ts.map +1 -0
  270. package/dist/cli/commands/generate.d.ts +36 -0
  271. package/dist/cli/commands/generate.d.ts.map +1 -0
  272. package/dist/cli/commands/init.d.ts +30 -0
  273. package/dist/cli/commands/init.d.ts.map +1 -0
  274. package/dist/cli/commands/install-app.d.ts +30 -0
  275. package/dist/cli/commands/install-app.d.ts.map +1 -0
  276. package/dist/cli/commands/items.d.ts +45 -0
  277. package/dist/cli/commands/items.d.ts.map +1 -0
  278. package/dist/cli/commands/migrations.d.ts +41 -0
  279. package/dist/cli/commands/migrations.d.ts.map +1 -0
  280. package/dist/cli/commands/pipelines.d.ts +40 -0
  281. package/dist/cli/commands/pipelines.d.ts.map +1 -0
  282. package/dist/cli/commands/status.d.ts +23 -0
  283. package/dist/cli/commands/status.d.ts.map +1 -0
  284. package/dist/cli/commands/system.d.ts +29 -0
  285. package/dist/cli/commands/system.d.ts.map +1 -0
  286. package/dist/cli/commands/test.d.ts +46 -0
  287. package/dist/cli/commands/test.d.ts.map +1 -0
  288. package/dist/cli/commands/uninstall-app.d.ts +23 -0
  289. package/dist/cli/commands/uninstall-app.d.ts.map +1 -0
  290. package/dist/cli/context.d.ts +88 -0
  291. package/dist/cli/context.d.ts.map +1 -0
  292. package/dist/cli/env-loader.d.ts +14 -0
  293. package/dist/cli/env-loader.d.ts.map +1 -0
  294. package/dist/cli/index.d.ts +41 -0
  295. package/dist/cli/index.d.ts.map +1 -0
  296. package/dist/functions/_shared/agent-runner.d.ts +156 -0
  297. package/dist/functions/_shared/agent-runner.d.ts.map +1 -0
  298. package/dist/functions/_shared/app-manifest.d.ts +68 -0
  299. package/dist/functions/_shared/app-manifest.d.ts.map +1 -0
  300. package/dist/functions/_shared/audit.d.ts +91 -0
  301. package/dist/functions/_shared/audit.d.ts.map +1 -0
  302. package/dist/functions/_shared/db.d.ts +125 -0
  303. package/dist/functions/_shared/db.d.ts.map +1 -0
  304. package/dist/functions/_shared/index.d.ts +298 -0
  305. package/dist/functions/_shared/index.d.ts.map +1 -0
  306. package/dist/functions/_shared/middleware.d.ts +315 -0
  307. package/dist/functions/_shared/middleware.d.ts.map +1 -0
  308. package/dist/functions/_shared/permissions.d.ts +626 -0
  309. package/dist/functions/_shared/permissions.d.ts.map +1 -0
  310. package/dist/functions/_shared/pipeline-runner.d.ts +124 -0
  311. package/dist/functions/_shared/pipeline-runner.d.ts.map +1 -0
  312. package/dist/functions/_shared/principal.d.ts +284 -0
  313. package/dist/functions/_shared/principal.d.ts.map +1 -0
  314. package/dist/functions/_shared/schema-utils.d.ts +181 -0
  315. package/dist/functions/_shared/schema-utils.d.ts.map +1 -0
  316. package/dist/functions/_shared/testing.d.ts +172 -0
  317. package/dist/functions/_shared/testing.d.ts.map +1 -0
  318. package/dist/functions/_shared/trigger-engine.d.ts +140 -0
  319. package/dist/functions/_shared/trigger-engine.d.ts.map +1 -0
  320. package/dist/functions/_shared/webhook-registration.d.ts +81 -0
  321. package/dist/functions/_shared/webhook-registration.d.ts.map +1 -0
  322. package/dist/functions/_shared/webhook-registry.d.ts +57 -0
  323. package/dist/functions/_shared/webhook-registry.d.ts.map +1 -0
  324. package/dist/functions/account-nodes.d.ts +48 -0
  325. package/dist/functions/account-nodes.d.ts.map +1 -0
  326. package/dist/functions/admin-data.d.ts +178 -0
  327. package/dist/functions/admin-data.d.ts.map +1 -0
  328. package/dist/functions/ai-agents.d.ts +125 -0
  329. package/dist/functions/ai-agents.d.ts.map +1 -0
  330. package/dist/functions/api-keys.d.ts +140 -0
  331. package/dist/functions/api-keys.d.ts.map +1 -0
  332. package/dist/functions/apps.d.ts +163 -0
  333. package/dist/functions/apps.d.ts.map +1 -0
  334. package/dist/functions/auth.d.ts +74 -0
  335. package/dist/functions/auth.d.ts.map +1 -0
  336. package/dist/functions/debug-auth.d.ts +33 -0
  337. package/dist/functions/debug-auth.d.ts.map +1 -0
  338. package/dist/functions/embeddings.d.ts +205 -0
  339. package/dist/functions/embeddings.d.ts.map +1 -0
  340. package/dist/functions/integration-routes.d.ts +45 -0
  341. package/dist/functions/integration-routes.d.ts.map +1 -0
  342. package/dist/functions/integrations.d.ts +124 -0
  343. package/dist/functions/integrations.d.ts.map +1 -0
  344. package/dist/functions/item-progress.d.ts +41 -0
  345. package/dist/functions/item-progress.d.ts.map +1 -0
  346. package/dist/functions/logs.d.ts +162 -0
  347. package/dist/functions/logs.d.ts.map +1 -0
  348. package/dist/functions/observability.d.ts +123 -0
  349. package/dist/functions/observability.d.ts.map +1 -0
  350. package/dist/functions/pipeline-executions.d.ts +190 -0
  351. package/dist/functions/pipeline-executions.d.ts.map +1 -0
  352. package/dist/functions/pipelines.d.ts +171 -0
  353. package/dist/functions/pipelines.d.ts.map +1 -0
  354. package/dist/functions/prompt-configs.d.ts +125 -0
  355. package/dist/functions/prompt-configs.d.ts.map +1 -0
  356. package/dist/functions/roles.d.ts +118 -0
  357. package/dist/functions/roles.d.ts.map +1 -0
  358. package/dist/functions/system-cron.d.ts +65 -0
  359. package/dist/functions/system-cron.d.ts.map +1 -0
  360. package/dist/functions/system.d.ts +29 -0
  361. package/dist/functions/system.d.ts.map +1 -0
  362. package/dist/functions/tests.d.ts +28 -0
  363. package/dist/functions/tests.d.ts.map +1 -0
  364. package/dist/functions/timers.d.ts +139 -0
  365. package/dist/functions/timers.d.ts.map +1 -0
  366. package/dist/functions/triggers.d.ts +203 -0
  367. package/dist/functions/triggers.d.ts.map +1 -0
  368. package/dist/functions/types.d.ts +151 -0
  369. package/dist/functions/types.d.ts.map +1 -0
  370. package/dist/src/types/types.d.ts +364 -0
  371. package/dist/src/types/types.d.ts.map +1 -0
  372. package/package.json +192 -0
  373. package/scripts/app-install-cli.ts +286 -0
  374. package/scripts/assemble-frontend.sh +79 -0
  375. package/scripts/assemble-functions.sh +62 -0
  376. package/scripts/assemble.sh +35 -0
  377. package/scripts/boundary-check.sh +106 -0
  378. package/scripts/build-manifest.sh +80 -0
  379. package/scripts/check-core-integrity.sh +82 -0
  380. package/scripts/ingest-chunks.cjs +202 -0
  381. package/scripts/kb-chunk-parser.cjs +312 -0
  382. package/scripts/kb-chunk-parser.ts +330 -0
  383. package/scripts/load-test-app-install.ts +484 -0
  384. package/scripts/netlify-dev-wrapper.sh +22 -0
  385. package/scripts/verify-integrity.sh +69 -0
@@ -0,0 +1,606 @@
1
+ /**
2
+ * @module admin-data
3
+ * @audience both
4
+ * @layer api-handler
5
+ * @stability stable
6
+ *
7
+ * Generic CRUD API for all runtime entities. Provides list, get, create,
8
+ * update, delete, and stats operations over a validated set of entity tables.
9
+ *
10
+ * **Routed by:** `GET/POST/PATCH/DELETE /.netlify/functions/admin-data`
11
+ *
12
+ * **Dispatch table (query params → handler):**
13
+ * | method | ?action | ?id present | Handler |
14
+ * |--------|---------|-------------|---------|
15
+ * | GET | list | any | `list` |
16
+ * | GET | get | any | `get` |
17
+ * | GET | stats | any | `stats` |
18
+ * | GET | — | yes | `get` |
19
+ * | GET | — | no | `list` |
20
+ * | POST | — | — | `create`|
21
+ * | PATCH | — | — | `update`|
22
+ * | DELETE | — | — | `remove`|
23
+ *
24
+ * **Authorization:** All DB reads/writes use `ctx.db` (RLS-scoped client).
25
+ * RLS policies on each table enforce account hierarchy access automatically.
26
+ * `adminDb` is used only for lookups that need bypass (type resolution).
27
+ *
28
+ * **Valid entities:** `accounts`, `people`, `items`, `threads`, `messages`,
29
+ * `links`, `attachments`, `watchers`.
30
+ *
31
+ * INVARIANT: every `create` call requires `type_id` in the body — all runtime
32
+ * records must reference a type.
33
+ * INVARIANT: trigger dispatch (create/update/delete) is fire-and-forget —
34
+ * trigger failures are logged but never surface to the caller.
35
+ * INVARIANT: all returned records are passed through `sanitizeRecordData`
36
+ * before being returned — field-level permission stripping is always applied.
37
+ *
38
+ * @seeAlso middleware.ts (createHandler, CoreContext)
39
+ * @seeAlso permissions.ts (sanitizeRecordData)
40
+ * @seeAlso trigger-engine.ts (fire*Triggers)
41
+ * @seeAlso types.ts (types table, design_schema, validation_schema)
42
+ */
43
+
44
+ import { createHandler } from './_shared/middleware'
45
+ import { sanitizeRecordData } from './_shared/permissions'
46
+ import { adminDb } from './_shared/db'
47
+ import { fireCreateTriggers, fireUpdateTriggers, fireDeleteTriggers } from './_shared/trigger-engine'
48
+
49
+ // ─── CONSTANTS ────────────────────────────────────────────────────────────────
50
+
51
+ const PERMISSIONS_ALL = {
52
+ record_permissions: { all: ['create', 'read', 'update', 'delete'] },
53
+ fields: {}
54
+ }
55
+
56
+ /**
57
+ * Allowlist of entity table names accepted by this handler.
58
+ * Any entity string not in this set causes a 400-equivalent throw.
59
+ */
60
+ const VALID_ENTITIES = ['accounts', 'people', 'items', 'threads', 'messages', 'links', 'attachments', 'watchers', 'item_progress']
61
+
62
+ // ─── HANDLERS ─────────────────────────────────────────────────────────────────
63
+
64
+ // ─── CHUNK_START: ADMIN_DATA_LIST ──────────────────────────────────────────────
65
+ /**
66
+ * @chunk-id ADMIN_DATA_LIST_1_0_0
67
+ * @version 1.0.0
68
+ * @hash 780f1f0c81ea3bff78d40970ba4b03e3211d892bb883e6a099c6e0a55ee53b0c
69
+ * @macro Entity List Handler
70
+ * @micro Lists records with filtering, search, sorting, and pagination
71
+ * @inputs ctx: CoreContext — Request context with principal and database
72
+ * @inputs _body: any — Request body (unused for GET)
73
+ * @outputs Array of sanitized records or {data, schema, view} with view config
74
+ * @depends-on [createHandler, sanitizeRecordData, adminDb, getSearchField]
75
+ * @depended-by [Netlify function routing]
76
+ * @side-effects [DB queries, permission sanitization]
77
+ * @tags admin, crud, list, pagination, search
78
+ */
79
+ export const list = createHandler(async (ctx, _body) => {
80
+ // Extract all reserved query params to prevent them from being used as column filters
81
+ const { entity, action, method, search, sort_field = 'created_at', sort_direction = 'desc', limit = 50, offset = 0, type_slug, view: viewSlug, ...filters } = ctx.query || {}
82
+
83
+ if (!entity || !VALID_ENTITIES.includes(entity)) {
84
+ throw new Error('Valid entity parameter is required')
85
+ }
86
+
87
+ // Use ctx.db - RLS-scoped client based on principal
88
+ // RLS policies enforce account hierarchy access automatically
89
+ let query = ctx.db.from(entity).select('*')
90
+
91
+ // Apply type_slug filter if provided (for schema-driven entities)
92
+ if (type_slug && entity === 'items') {
93
+ // Look up the type ID from the slug
94
+ const { data: typeRecord } = await adminDb
95
+ .from('types')
96
+ .select('id')
97
+ .eq('slug', type_slug)
98
+ .eq('is_active', true)
99
+ .single()
100
+
101
+ if (typeRecord) {
102
+ query = query.eq('type_id', typeRecord.id)
103
+ }
104
+ }
105
+
106
+ // Apply search if provided
107
+ if (search) {
108
+ // Search in display field based on entity
109
+ const searchField = getSearchField(entity)
110
+ query = query.ilike(searchField, `%${search}%`)
111
+ }
112
+
113
+ // Apply filters
114
+ Object.entries(filters).forEach(([key, value]) => {
115
+ if (value !== undefined && value !== null && value !== '') {
116
+ if (key === 'is_active' || key === 'is_verified' || key === 'is_primary') {
117
+ query = query.eq(key, value === 'true')
118
+ } else {
119
+ query = query.eq(key, value)
120
+ }
121
+ }
122
+ })
123
+
124
+ // Apply sorting
125
+ query = query.order(sort_field, { ascending: sort_direction === 'asc' })
126
+
127
+ // Get total count (RLS filters automatically)
128
+ const { count, error: countError } = await ctx.db.from(entity)
129
+ .select('*', { count: 'exact', head: true })
130
+
131
+ if (countError) {
132
+ console.error('List count error:', countError)
133
+ throw new Error(countError.message || 'Database error getting count')
134
+ }
135
+
136
+ // Apply pagination
137
+ query = query.range(parseInt(offset.toString()), parseInt(offset.toString()) + parseInt(limit.toString()) - 1)
138
+
139
+ const { data, error: err } = await query
140
+
141
+ if (err) {
142
+ console.error('List query error:', err)
143
+ throw new Error(err.message || 'Database error listing records')
144
+ }
145
+
146
+ // RLS policies already filtered the data - just sanitize
147
+ const sanitizedData = []
148
+ for (const record of data || []) {
149
+ const sanitizedRecord = await sanitizeRecordData(ctx, record, entity)
150
+ sanitizedData.push(sanitizedRecord)
151
+ }
152
+
153
+ // If ?view=slug was requested, resolve schema + view config from the type record
154
+ if (viewSlug && type_slug) {
155
+ const { data: typeRecord } = await adminDb
156
+ .from('types')
157
+ .select('design_schema')
158
+ .eq('slug', type_slug)
159
+ .eq('is_active', true)
160
+ .single()
161
+
162
+ if (typeRecord?.design_schema) {
163
+ const schema = typeRecord.design_schema
164
+ const resolvedView = schema.views?.[viewSlug] || null
165
+ return { data: sanitizedData, schema, view: resolvedView }
166
+ }
167
+ }
168
+
169
+ return sanitizedData
170
+ })
171
+ // ─── CHUNK_END: ADMIN_DATA_LIST ────────────────────────────────────────────────
172
+
173
+ // ─── CHUNK_START: ADMIN_DATA_GET ──────────────────────────────────────────────
174
+ /**
175
+ * @chunk-id ADMIN_DATA_GET_1_0_0
176
+ * @version 1.0.0
177
+ * @hash 7ee27702615d7ebd144e065d399635ddf7664845685345d8a8f316449f11a7cf
178
+ * @macro Entity Get Handler
179
+ * @micro Returns a single record by ID with optional view configuration
180
+ * @inputs ctx: CoreContext — Request context with principal and database
181
+ * @inputs _body: any — Request body (unused for GET)
182
+ * @outputs Sanitized record or {data, schema, view} with view config
183
+ * @depends-on [createHandler, sanitizeRecordData]
184
+ * @depended-by [Netlify function routing]
185
+ * @side-effects [DB single row query, permission sanitization]
186
+ * @tags admin, crud, get, single-record
187
+ */
188
+ export const get = createHandler(async (ctx, _body) => {
189
+ const { entity, id, view: viewSlug } = ctx.query || {}
190
+
191
+ if (!entity || !VALID_ENTITIES.includes(entity)) {
192
+ throw new Error('Valid entity parameter is required')
193
+ }
194
+
195
+ if (!id) {
196
+ throw new Error('ID parameter is required')
197
+ }
198
+
199
+ // RLS will filter based on account hierarchy access
200
+ const { data, error: err } = await ctx.db.from(entity)
201
+ .select('*')
202
+ .eq('id', id)
203
+ .single()
204
+
205
+ if (err) throw err
206
+
207
+ if (!data) {
208
+ throw new Error('Record not found')
209
+ }
210
+
211
+ const sanitizedRecord = await sanitizeRecordData(ctx, data, entity)
212
+
213
+ // If ?view=slug was requested, include schema + resolved view from the record's stamped schema
214
+ if (viewSlug && sanitizedRecord?.design_schema) {
215
+ const schema = sanitizedRecord.design_schema
216
+ const resolvedView = schema.views?.[viewSlug] || null
217
+ return { data: sanitizedRecord, schema, view: resolvedView }
218
+ }
219
+
220
+ return sanitizedRecord
221
+ })
222
+ // ─── CHUNK_END: ADMIN_DATA_GET ────────────────────────────────────────────────
223
+
224
+ /**
225
+ * Creates a new record for an entity. Stamps `design_schema`,
226
+ * `validation_schema`, audit fields, and `account_id` from the resolved type.
227
+ * Fires `*_created` triggers asynchronously after DB insert.
228
+ *
229
+ * Body params:
230
+ * - `entity` (required) — one of VALID_ENTITIES
231
+ * - `type_id` (required) — UUID of an active type record
232
+ * - all other fields are passed through to the insert
233
+ *
234
+ * @returns Sanitized created record
235
+ * @throws Error('Valid entity parameter is required')
236
+ * @throws Error('type_id is required')
237
+ * @throws Error('type_id not found') — if type UUID doesn't exist
238
+ * @throws Error('type_id references an inactive type')
239
+ * @throws PostgREST error on RLS INSERT denial
240
+ * @inputSpec type_id: string — valid UUID of active type record
241
+ * @inputSpec body fields: Record<string, any> — record field values
242
+ * @outputSpec sanitized created record
243
+ * @sideEffects DB write: entity table (INSERT)
244
+ * @sideEffects DB read: types table (type resolution)
245
+ * @sideEffects fire-and-forget: fireCreateTriggers
246
+ * @calledBy handler (POST)
247
+ * @calls sanitizeRecordData, adminDb (type lookup), fireCreateTriggers
248
+ * @testUnit tests/unit/admin-data.test.ts — 'create'
249
+ * @testIntegration tests/integration/admin-data.test.ts — 'create'
250
+ */
251
+ export const create = createHandler(async (ctx, body) => {
252
+ const entity = body?.entity || ctx.query?.entity
253
+ const { entity: _e, design_schema: _ds, validation_schema: _vs, account_id: _ai, ...recordData } = body || {}
254
+
255
+ if (!entity || !VALID_ENTITIES.includes(entity)) {
256
+ const e: any = new Error('Valid entity parameter is required'); e.statusCode = 400; throw e
257
+ }
258
+
259
+ // type_id is required on all runtime record creation
260
+ if (!recordData.type_id) {
261
+ const e: any = new Error('type_id is required — every runtime record must reference a type'); e.statusCode = 400; throw e
262
+ }
263
+
264
+ // Look up the type to stamp design_schema and validation_schema
265
+ const { data: typeRecord, error: typeErr } = await adminDb
266
+ .from('types')
267
+ .select('id, design_schema, validation_schema, is_active')
268
+ .eq('id', recordData.type_id)
269
+ .single()
270
+
271
+ if (typeErr || !typeRecord) {
272
+ throw new Error(`type_id not found: ${recordData.type_id}`)
273
+ }
274
+
275
+ if (!typeRecord.is_active) {
276
+ throw new Error(`type_id references an inactive type: ${recordData.type_id}`)
277
+ }
278
+
279
+ // Ensure the type has at least permissions=ALL (defensive — migration 062 guarantees this)
280
+ let designSchema = typeRecord.design_schema || {}
281
+ if (!designSchema.record_permissions) {
282
+ designSchema = { ...PERMISSIONS_ALL, ...designSchema }
283
+ }
284
+
285
+ // Resolve account_id and propagate scope via parent inheritance (Option A)
286
+ // Priority: parent reference in body > type's own scope declaration
287
+ let recordAccountId = ctx.accountId
288
+ const parentRef = recordData.thread_id || recordData.target_id || recordData.parent_id
289
+ if (parentRef) {
290
+ const parentTable = recordData.thread_id ? 'threads' : 'items'
291
+ const { data: parentRecord } = await ctx.db
292
+ .from(parentTable)
293
+ .select('account_id, design_schema')
294
+ .eq('id', parentRef)
295
+ .maybeSingle()
296
+ if (!parentRecord) {
297
+ const e: any = new Error('Parent record not found or not accessible'); e.statusCode = 403; throw e
298
+ }
299
+ recordAccountId = parentRecord.account_id
300
+ const parentScope = parentRecord.design_schema?.scope
301
+ if (parentScope) {
302
+ designSchema = { ...designSchema, scope: parentScope }
303
+ }
304
+ } else {
305
+ const scope: string = designSchema.scope ?? 'account'
306
+ if (scope === 'platform') {
307
+ const { data: sysAccount } = await adminDb
308
+ .from('accounts')
309
+ .select('id')
310
+ .eq('slug', 'spine-system')
311
+ .single()
312
+ if (sysAccount?.id) recordAccountId = sysAccount.id
313
+ }
314
+ }
315
+
316
+ // Add audit fields + stamped schema
317
+ const dataToInsert = {
318
+ ...recordData,
319
+ design_schema: designSchema,
320
+ validation_schema: typeRecord.validation_schema || {},
321
+ created_by: ctx.principal?.id,
322
+ account_id: recordAccountId,
323
+ created_at: new Date().toISOString(),
324
+ updated_at: new Date().toISOString()
325
+ }
326
+
327
+ // RLS will check if user has INSERT permission on this account
328
+ const { data, error: err } = await ctx.db.from(entity)
329
+ .insert(dataToInsert)
330
+ .select()
331
+ .single()
332
+
333
+ if (err) throw err
334
+
335
+ // Fire triggers asynchronously (don't block response)
336
+ const entityData = { ...dataToInsert, id: data.id }
337
+ fireCreateTriggers(entity, data.id, entityData, ctx).catch(console.error)
338
+
339
+ return await sanitizeRecordData(ctx, data, entity)
340
+ })
341
+
342
+ /**
343
+ * Updates an existing record by ID. Stamps `updated_by` and `updated_at`.
344
+ * Fires `*_updated` triggers asynchronously after DB update.
345
+ *
346
+ * Query params: `entity` (required), `id` (required)
347
+ * Body: partial record fields to update (no schema re-stamping on update)
348
+ *
349
+ * @returns Sanitized updated record
350
+ * @throws Error('Valid entity parameter is required')
351
+ * @throws Error('ID is required for update')
352
+ * @throws PostgREST error on RLS UPDATE denial
353
+ * @inputSpec id: string — valid UUID of existing record
354
+ * @inputSpec body: Partial<Record> — fields to patch
355
+ * @outputSpec sanitized updated record
356
+ * @sideEffects DB write: entity table (UPDATE)
357
+ * @sideEffects fire-and-forget: fireUpdateTriggers
358
+ * @calledBy handler (PATCH)
359
+ * @calls sanitizeRecordData, fireUpdateTriggers
360
+ * @testUnit tests/unit/admin-data.test.ts — 'update'
361
+ */
362
+ export const update = createHandler(async (ctx, body) => {
363
+ const { entity, id } = ctx.query || {}
364
+ // Strip server-only fields — client must never override these on update
365
+ const { design_schema: _ds, validation_schema: _vs, account_id: _ai, type_id: _ti, ...recordData } = body || {}
366
+
367
+ if (!entity || !VALID_ENTITIES.includes(entity)) {
368
+ throw new Error('Valid entity parameter is required')
369
+ }
370
+
371
+ if (!id) {
372
+ throw new Error('ID is required for update')
373
+ }
374
+
375
+ // Add audit fields
376
+ const dataToUpdate = {
377
+ ...recordData,
378
+ updated_by: ctx.principal?.id,
379
+ updated_at: new Date().toISOString()
380
+ }
381
+
382
+ // RLS will check UPDATE permission on this record
383
+ const { data, error: err } = await ctx.db.from(entity)
384
+ .update(dataToUpdate)
385
+ .eq('id', id)
386
+ .select()
387
+ .single()
388
+
389
+ if (err) throw err
390
+
391
+ // Fire triggers asynchronously (don't block response)
392
+ const entityData = { ...data, ...dataToUpdate }
393
+ fireUpdateTriggers(entity, id, entityData, ctx).catch(console.error)
394
+
395
+ return await sanitizeRecordData(ctx, data, entity)
396
+ })
397
+
398
+ /**
399
+ * Deletes a record by ID. Defaults to soft delete (`is_active = false`) for
400
+ * entities that support it; falls back to hard delete otherwise.
401
+ *
402
+ * Query params:
403
+ * - `entity` (required) — one of VALID_ENTITIES
404
+ * - `id` (required) — UUID of the record
405
+ * - `soft` (default: 'true') — set to 'false' to force hard delete
406
+ *
407
+ * Soft-delete-capable entities: `accounts`, `people`, `items`, `threads`,
408
+ * `messages`, `watchers`. All others always receive a hard delete.
409
+ *
410
+ * @returns `{ deleted: true, soft: true, data }` (soft) or `{ deleted: true, soft: false }` (hard)
411
+ * @throws Error('Valid entity parameter is required')
412
+ * @throws Error('ID is required for delete')
413
+ * @throws PostgREST error on RLS DELETE denial
414
+ * @inputSpec id: string — valid UUID
415
+ * @inputSpec soft: 'true' | 'false'
416
+ * @outputSpec { deleted: boolean, soft: boolean, data?: sanitizedRecord }
417
+ * @sideEffects DB write: UPDATE is_active=false (soft) or DELETE (hard)
418
+ * @sideEffects fire-and-forget: fireDeleteTriggers
419
+ * @calledBy handler (DELETE)
420
+ * @calls sanitizeRecordData, entitySupportsSoftDelete, fireDeleteTriggers
421
+ * @testUnit tests/unit/admin-data.test.ts — 'remove'
422
+ */
423
+ export const remove = createHandler(async (ctx, _body) => {
424
+ const { entity, id, soft = 'true' } = ctx.query || {}
425
+
426
+ if (!entity || !VALID_ENTITIES.includes(entity)) {
427
+ throw new Error('Valid entity parameter is required')
428
+ }
429
+
430
+ if (!id) {
431
+ throw new Error('ID is required for delete')
432
+ }
433
+
434
+ const isSoftDelete = soft === 'true'
435
+
436
+ if (isSoftDelete && entitySupportsSoftDelete(entity)) {
437
+ // Soft delete - set is_active to false
438
+ // RLS will check DELETE permission on this record
439
+ const { data, error: err } = await ctx.db.from(entity)
440
+ .update({
441
+ is_active: false,
442
+ updated_by: ctx.principal?.id,
443
+ updated_at: new Date().toISOString()
444
+ })
445
+ .eq('id', id)
446
+ .select()
447
+ .single()
448
+
449
+ if (err) throw err
450
+ return { deleted: true, soft: true, data: await sanitizeRecordData(ctx, data, entity) }
451
+ } else {
452
+ // Hard delete
453
+ // RLS will check DELETE permission on this record
454
+ const { error: err } = await ctx.db.from(entity)
455
+ .delete()
456
+ .eq('id', id)
457
+
458
+ if (err) throw err
459
+ return { deleted: true, soft: false }
460
+ }
461
+ })
462
+
463
+ // ─── HELPERS ─────────────────────────────────────────────────────────────────
464
+
465
+ /**
466
+ * Returns the primary text field to use for `ilike` search for a given entity.
467
+ * Falls back to 'id' for unmapped entities.
468
+ *
469
+ * @calledBy list (search param handling)
470
+ */
471
+ // ─── CHUNK_START: ADMIN_DATA_GET_SEARCH_FIELD ──────────────────────────────────────────────
472
+ /**
473
+ * @chunk-id ADMIN_DATA_GET_SEARCH_FIELD_1_0_0
474
+ * @version 1.0.0
475
+ * @hash 7c2615cf66a522b9b0df96cfbc8dfc50a2650016e967ceffd9172a770c78a26a
476
+ * @macro Search Field Resolver
477
+ * @micro Returns the primary display field for search functionality
478
+ * @inputs entity: string — Entity name from VALID_ENTITIES
479
+ * @outputs string — Column name to search in
480
+ * @depends-on [none]
481
+ * @depended-by [list]
482
+ * @side-effects [none]
483
+ * @tags admin, search, field-mapping
484
+ */
485
+ function getSearchField(entity: string): string {
486
+ const searchFields: Record<string, string> = {
487
+ accounts: 'display_name',
488
+ people: 'full_name',
489
+ items: 'title',
490
+ threads: 'title',
491
+ messages: 'content',
492
+ links: 'link_type',
493
+ attachments: 'filename',
494
+ watchers: 'watch_type',
495
+ item_progress: 'title'
496
+ }
497
+ return searchFields[entity] || 'id'
498
+ }
499
+ // ─── CHUNK_END: ADMIN_DATA_GET_SEARCH_FIELD ────────────────────────────────────────────────
500
+
501
+ // ─── CHUNK_START: ADMIN_DATA_ENTITY_SUPPORTS_SOFT_DELETE ──────────────────────────────────────────────
502
+ /**
503
+ * @chunk-id ADMIN_DATA_ENTITY_SUPPORTS_SOFT_DELETE_1_0_0
504
+ * @version 1.0.0
505
+ * @hash 0438e650a11bfb4c25b90939780127d8912bdc5caeb772fe3049381d6497412d
506
+ * @macro Soft Delete Support Checker
507
+ * @micro Returns true if entity supports soft delete via is_active column
508
+ * @inputs entity: string — Entity name from VALID_ENTITIES
509
+ * @outputs boolean — True if entity has is_active column
510
+ * @depends-on [none]
511
+ * @depended-by [remove]
512
+ * @side-effects [none]
513
+ * @tags admin, soft-delete, entity-check
514
+ */
515
+ function entitySupportsSoftDelete(entity: string): boolean {
516
+ const softDeleteEntities = ['accounts', 'people', 'items', 'threads', 'messages', 'watchers', 'item_progress']
517
+ return softDeleteEntities.includes(entity)
518
+ }
519
+ // ─── CHUNK_END: ADMIN_DATA_ENTITY_SUPPORTS_SOFT_DELETE ────────────────────────────────────────────────
520
+
521
+ // ─── CHUNK_START: ADMIN_DATA_STATS ──────────────────────────────────────────────
522
+ /**
523
+ * @chunk-id ADMIN_DATA_STATS_1_0_0
524
+ * @version 1.0.0
525
+ * @hash 0bed523a260ab3959cb4e7150cca044f4e97ce91d7ae3386ab14b5f4182d74d7
526
+ * @macro Entity Stats Handler
527
+ * @micro Returns total record count for an entity scoped by account
528
+ * @inputs ctx: CoreContext — Request context with principal and database
529
+ * @inputs _body: any — Request body (unused for GET)
530
+ * @outputs {entity: string, count: number} — Entity name and record count
531
+ * @depends-on [createHandler]
532
+ * @depended-by [Netlify function routing]
533
+ * @side-effects [DB count query with RLS filtering]
534
+ * @tags admin, stats, count, entity
535
+ */
536
+ export const stats = createHandler(async (ctx, _body) => {
537
+ const { entity } = ctx.query || {}
538
+
539
+ if (!entity || !VALID_ENTITIES.includes(entity)) {
540
+ throw new Error('Valid entity parameter is required')
541
+ }
542
+
543
+ // RLS will filter count based on account hierarchy access
544
+ const { count, error: err } = await ctx.db.from(entity)
545
+ .select('*', { count: 'exact', head: true })
546
+
547
+ if (err) throw err
548
+
549
+ return { entity, count }
550
+ })
551
+ // ─── CHUNK_END: ADMIN_DATA_STATS ────────────────────────────────────────────────
552
+
553
+ // ─── MAIN HANDLER ────────────────────────────────────────────────────────────
554
+
555
+ // ─── CHUNK_START: ADMIN_DATA_HANDLER ──────────────────────────────────────────────
556
+ /**
557
+ * @chunk-id ADMIN_DATA_HANDLER_1_0_0
558
+ * @version 1.0.0
559
+ * @hash edceffa0d5c8b3c05b1a89188a274a586b6ebe8793ede427e2326876d7090df9
560
+ * @macro Admin Data Router
561
+ * @micro Routes HTTP methods and actions to appropriate CRUD handlers
562
+ * @inputs ctx: CoreContext — Request context with principal and database
563
+ * @inputs body: any — Request body for POST/PATCH operations
564
+ * @outputs Varies — Depends on routed handler (list/get/create/update/remove/stats)
565
+ * @depends-on [createHandler, list, get, create, update, remove, stats]
566
+ * @depended-by [Netlify function routing]
567
+ * @side-effects [Delegates to appropriate handler]
568
+ * @tags admin, router, crud, netlify-function
569
+ */
570
+ export const handler = createHandler(async (ctx, body) => {
571
+ const { action } = ctx.query || {}
572
+ const method = ctx.query?.method || 'GET'
573
+
574
+ switch (action) {
575
+ case 'list':
576
+ if (method === 'GET') {
577
+ return await list(ctx, body)
578
+ }
579
+ break
580
+ case 'get':
581
+ if (method === 'GET') {
582
+ return await get(ctx, body)
583
+ }
584
+ break
585
+ case 'stats':
586
+ if (method === 'GET') {
587
+ return await stats(ctx, body)
588
+ }
589
+ break
590
+ default:
591
+ if (method === 'GET' && ctx.query?.id) {
592
+ return await get(ctx, body)
593
+ } else if (method === 'GET') {
594
+ return await list(ctx, body)
595
+ } else if (method === 'POST') {
596
+ return await create(ctx, body)
597
+ } else if (method === 'PATCH') {
598
+ return await update(ctx, body)
599
+ } else if (method === 'DELETE') {
600
+ return await remove(ctx, body)
601
+ }
602
+ }
603
+
604
+ throw new Error('Invalid action or method')
605
+ })
606
+ // ─── CHUNK_END: ADMIN_DATA_HANDLER ────────────────────────────────────────────────