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,483 @@
1
+ /**
2
+ * @module apps
3
+ * @audience core-contributor
4
+ * @layer api-handler
5
+ * @stability stable
6
+ *
7
+ * CRUD API for the `apps` table. Apps are the installable units of functionality
8
+ * in Spine v2. They group types, roles, integrations, and nav configuration.
9
+ *
10
+ * **Routed by:** `GET/POST/PATCH/DELETE /.netlify/functions/apps`
11
+ *
12
+ * **Authorization model:**
13
+ * - `list` / `get` / `getSchema` / `checkAvailability`: any authenticated principal
14
+ * (RLS-scoped via `ctx.db`). Returns sanitized records.
15
+ * - `create`: requires `isSystemAdmin` or first-surface `canCreate` permission.
16
+ * - `update` / `remove`: requires authenticated principal + field-level permission
17
+ * check via `validateUpdatePermissions`.
18
+ * - `updateVersion`: authenticated principal via RPC.
19
+ *
20
+ * INVARIANT: app slugs are globally unique across the `apps` table.
21
+ * INVARIANT: `is_system` apps can only be manipulated by system admins.
22
+ *
23
+ * @seeAlso middleware.ts (createHandler)
24
+ * @seeAlso permissions.ts (PermissionEngine, sanitizeRecordData)
25
+ * @seeAlso audit.ts (emitLog for app.created / app.updated / app.deleted)
26
+ * @seeAlso types.ts (types reference apps via app_id)
27
+ */
28
+
29
+ import { createHandler } from './_shared/middleware'
30
+ import { joins } from './_shared/db'
31
+ import { emitLog } from './_shared/audit'
32
+ import { PermissionEngine, sanitizeRecordData } from './_shared/permissions'
33
+
34
+ const permissions = PermissionEngine as any
35
+
36
+ // ─── HANDLERS ─────────────────────────────────────────────────────────────────
37
+
38
+ // ─── CHUNK_START: APPS_LIST ──────────────────────────────────────────────
39
+ /**
40
+ * @chunk-id APPS_LIST_1_0_0
41
+ * @version 1.0.0
42
+ * @hash 8eaac3c01786fadeb3c4acb34c9725378f2055766213493859835cadf2bb3963
43
+ * @macro Apps List Handler
44
+ * @micro Lists accessible apps via RPC with filtering and sanitization
45
+ * @inputs ctx: CoreContext — Request context with principal and database
46
+ * @inputs body: any — Request body (unused for GET)
47
+ * @outputs Array of sanitized app records
48
+ * @depends-on [createHandler, sanitizeRecordData]
49
+ * @depended-by [Netlify function routing]
50
+ * @side-effects [RPC call, permission sanitization]
51
+ * @tags apps, list, crud, rpc
52
+ */
53
+ export const list = createHandler(async (ctx, body) => {
54
+ const { include_system, include_inactive, account_id } = ctx.query || {}
55
+
56
+ const targetAccountId = account_id || ctx.accountId
57
+
58
+ if (!targetAccountId) {
59
+ throw new Error('Account context required')
60
+ }
61
+
62
+ // RLS automatically filters to accessible accounts
63
+ const { data, error: err } = await ctx.db
64
+ .rpc('get_account_apps', {
65
+ account_id: targetAccountId,
66
+ include_system: include_system !== 'false',
67
+ include_inactive: include_inactive === 'true'
68
+ })
69
+
70
+ if (err) throw err
71
+
72
+ // Sanitize each record based on role permissions
73
+ const sanitized = []
74
+ for (const app of data || []) {
75
+ sanitized.push(await sanitizeRecordData(ctx, app, 'app'))
76
+ }
77
+
78
+ return sanitized
79
+ })
80
+ // ─── CHUNK_END: APPS_LIST ────────────────────────────────────────────────
81
+
82
+ // ─── CHUNK_START: APPS_GET ──────────────────────────────────────────────
83
+ /**
84
+ * @chunk-id APPS_GET_1_0_0
85
+ * @version 1.0.0
86
+ * @hash 5449bb3ac8726775412df541e1f2abf2400fb18751e3c9aad5f0aafb09cc7f60
87
+ * @macro App Get Handler
88
+ * @micro Returns single app by ID or slug with owner account join
89
+ * @inputs ctx: CoreContext — Request context with principal and database
90
+ * @inputs body: any — Request body (unused for GET)
91
+ * @outputs Sanitized app record with ownerAccount join
92
+ * @depends-on [createHandler, joins, sanitizeRecordData]
93
+ * @depended-by [Netlify function routing]
94
+ * @side-effects [DB single row query, permission sanitization]
95
+ * @tags apps, get, crud, single-record
96
+ */
97
+ export const get = createHandler(async (ctx, body) => {
98
+ const { id, slug } = ctx.query || {}
99
+
100
+ if (!id && !slug) {
101
+ throw new Error('App ID or slug is required')
102
+ }
103
+
104
+ let query = ctx.db
105
+ .from('apps')
106
+ .select(`*, ${joins.ownerAccount}`)
107
+ .eq('is_active', true)
108
+
109
+ if (id) {
110
+ query = query.eq('id', id)
111
+ } else {
112
+ query = query.eq('slug', slug)
113
+ }
114
+
115
+ const { data, error: err } = await query.single()
116
+
117
+ if (err) throw err
118
+
119
+ // Sanitize based on role permissions
120
+ return await sanitizeRecordData(ctx, data, 'app')
121
+ })
122
+ // ─── CHUNK_END: APPS_GET ────────────────────────────────────────────────
123
+
124
+ // ─── CHUNK_START: APPS_GET_SCHEMA ──────────────────────────────────────────────
125
+ /**
126
+ * @chunk-id APPS_GET_SCHEMA_1_0_0
127
+ * @version 1.0.0
128
+ * @hash 8b6b7bb419114cbb699ad841dc4ba760ff36a626e8a9513de24715229e5a064b
129
+ * @macro App Schema Handler
130
+ * @micro Returns full app schema via RPC with types, roles, views, integrations
131
+ * @inputs ctx: CoreContext — Request context with principal and database
132
+ * @inputs body: any — Request body (unused for GET)
133
+ * @outputs App schema object with complete configuration
134
+ * @depends-on [createHandler]
135
+ * @depended-by [Netlify function routing]
136
+ * @side-effects [RPC call for schema retrieval]
137
+ * @tags apps, schema, rpc, configuration
138
+ */
139
+ export const getSchema = createHandler(async (ctx, body) => {
140
+ const { slug } = ctx.query || {}
141
+
142
+ if (!slug) {
143
+ throw new Error('App slug is required')
144
+ }
145
+
146
+ const { data, error: err } = await ctx.db
147
+ .rpc('get_app_schema', { app_slug: slug })
148
+
149
+ if (err) throw err
150
+
151
+ return data
152
+ })
153
+ // ─── CHUNK_END: APPS_GET_SCHEMA ────────────────────────────────────────────────
154
+
155
+ // ─── CHUNK_START: APPS_CREATE ──────────────────────────────────────────────
156
+ /**
157
+ * @chunk-id APPS_CREATE_1_0_0
158
+ * @version 1.0.0
159
+ * @hash f440efbf4a020b2d0d21ed7d90c5995538dd76d631f1b16fc53c1f2e9a1e4f91
160
+ * @macro App Create Handler
161
+ * @micro Creates new app with permission validation and audit logging
162
+ * @inputs ctx: CoreContext — Request context with principal and database
163
+ * @inputs body: object — App configuration data including slug and name
164
+ * @outputs Inserted app record
165
+ * @depends-on [createHandler, permissions, emitLog]
166
+ * @depended-by [Netlify function routing]
167
+ * @side-effects [DB insert, permission checks, audit logging]
168
+ * @tags apps, create, crud, permissions, audit
169
+ */
170
+ export const create = createHandler(async (ctx, body) => {
171
+ const { slug, name, description, icon, color, version, app_type, source, owner_account_id, config, nav_items, min_role, integration_deps, metadata, route_prefix, renderer } = body
172
+
173
+ if (!slug || !name) {
174
+ throw new Error('slug and name are required')
175
+ }
176
+
177
+ if (!ctx.principal || ctx.principal.id === 'anonymous' || !ctx.accountId) {
178
+ throw new Error('User context (person and account) required')
179
+ }
180
+
181
+ // Check create permissions
182
+ if (!permissions.isSystemAdmin(ctx)) {
183
+ const perms = await permissions.resolveFirstSurfacePermissions(
184
+ ctx.principal.id,
185
+ ctx.accountId!,
186
+ 'app',
187
+ 'create'
188
+ )
189
+
190
+ if (!perms.canCreate) {
191
+ throw new Error('Insufficient permissions to create apps')
192
+ }
193
+ }
194
+
195
+ // Check if slug is unique
196
+ const { data: existing } = await ctx.db
197
+ .from('apps')
198
+ .select('id')
199
+ .eq('slug', slug)
200
+ .single()
201
+
202
+ if (existing) {
203
+ throw new Error('App slug already exists')
204
+ }
205
+
206
+ const { data, error: err } = await ctx.db
207
+ .from('apps')
208
+ .insert({
209
+ slug,
210
+ name,
211
+ description,
212
+ icon,
213
+ color,
214
+ version: version || '1.0.0',
215
+ app_type: app_type || 'custom',
216
+ source: source || 'custom',
217
+ owner_account_id: owner_account_id || ctx.accountId,
218
+ config: config || {},
219
+ nav_items: nav_items || [],
220
+ min_role: min_role || 'member',
221
+ integration_deps: integration_deps || [],
222
+ metadata: metadata || {},
223
+ route_prefix: route_prefix !== undefined ? route_prefix : ('/' + slug),
224
+ renderer: renderer || 'generic',
225
+ is_active: true,
226
+ is_system: false
227
+ })
228
+ .select()
229
+ .single()
230
+
231
+ if (err) throw err
232
+
233
+ await emitLog(ctx, 'app.created', { type: 'app', id: data.id }, { after: data })
234
+
235
+ return data
236
+ })
237
+ // ─── CHUNK_END: APPS_CREATE ────────────────────────────────────────────────
238
+
239
+ // ─── CHUNK_START: APPS_UPDATE ──────────────────────────────────────────────
240
+ /**
241
+ * @chunk-id APPS_UPDATE_1_0_0
242
+ * @version 1.0.0
243
+ * @hash 77029f18737fee801ff5ebdde199d6b52454fd9fe3842694b072181fc713b937
244
+ * @macro App Update Handler
245
+ * @micro Updates app with field-level permission validation and audit logging
246
+ * @inputs ctx: CoreContext — Request context with principal and database
247
+ * @inputs body: object — App updates including id
248
+ * @outputs Updated app record
249
+ * @depends-on [createHandler, permissions, emitLog]
250
+ * @depended-by [Netlify function routing]
251
+ * @side-effects [DB update, permission validation, audit logging]
252
+ * @tags apps, update, crud, permissions, audit
253
+ */
254
+ export const update = createHandler(async (ctx, body) => {
255
+ const id = body?.id || ctx.query?.id
256
+ const { id: _bodyId, ...updates } = body || {}
257
+
258
+ if (!id) {
259
+ throw new Error('App ID is required')
260
+ }
261
+
262
+ if (!ctx.principal || ctx.principal.id === 'anonymous' || !ctx.accountId) {
263
+ throw new Error('User context (person and account) required')
264
+ }
265
+
266
+ // Get current state for audit - RLS will filter to accessible apps
267
+ const { data: current } = await ctx.db
268
+ .from('apps')
269
+ .select('*')
270
+ .eq('id', id)
271
+ .single()
272
+
273
+ if (!current) {
274
+ throw new Error('App not found')
275
+ }
276
+
277
+ // Validate field-level permissions
278
+ const fieldValidation = await permissions.validateUpdatePermissions(
279
+ ctx,
280
+ updates,
281
+ current,
282
+ 'apps'
283
+ )
284
+
285
+ if (!fieldValidation.valid) {
286
+ throw new Error(fieldValidation.error)
287
+ }
288
+
289
+ const { data, error: err } = await ctx.db
290
+ .from('apps')
291
+ .update({
292
+ ...updates,
293
+ updated_at: new Date().toISOString()
294
+ })
295
+ .eq('id', id)
296
+ .select()
297
+ .single()
298
+
299
+ if (err) throw err
300
+
301
+ await emitLog(ctx, 'app.updated', { type: 'app', id }, { before: current, after: data })
302
+
303
+ return data
304
+ })
305
+ // ─── CHUNK_END: APPS_UPDATE ────────────────────────────────────────────────
306
+
307
+ // ─── CHUNK_START: APPS_REMOVE ──────────────────────────────────────────────
308
+ /**
309
+ * @chunk-id APPS_REMOVE_1_0_0
310
+ * @version 1.0.0
311
+ * @hash b2c79779820861406f1adabc2279e332727b936abab4c6f5e5762a62d1373169
312
+ * @macro App Remove Handler
313
+ * @micro Soft-deletes app with validation and audit logging
314
+ * @inputs ctx: CoreContext — Request context with principal and database
315
+ * @inputs body: any — Request body with app ID
316
+ * @outputs Updated app record with is_active: false
317
+ * @depends-on [createHandler, emitLog]
318
+ * @depended-by [Netlify function routing]
319
+ * @side-effects [DB soft delete, audit logging]
320
+ * @tags apps, remove, crud, audit
321
+ */
322
+ export const remove = createHandler(async (ctx, body) => {
323
+ const id = body?.id || ctx.query?.id
324
+
325
+ if (!id) {
326
+ throw new Error('App ID is required')
327
+ }
328
+
329
+ if (!ctx.principal || ctx.principal.id === 'anonymous' || !ctx.accountId) {
330
+ throw new Error('User context (person and account) required')
331
+ }
332
+
333
+ // Get current state for audit - RLS will filter to accessible apps
334
+ const { data: current } = await ctx.db
335
+ .from('apps')
336
+ .select('*')
337
+ .eq('id', id)
338
+ .single()
339
+
340
+ if (!current) {
341
+ throw new Error('App not found')
342
+ }
343
+
344
+ const { data, error: err } = await ctx.db
345
+ .from('apps')
346
+ .update({
347
+ is_active: false,
348
+ updated_at: new Date().toISOString()
349
+ })
350
+ .eq('id', id)
351
+ .select()
352
+ .single()
353
+
354
+ if (err) throw err
355
+
356
+ await emitLog(ctx, 'app.deleted', { type: 'app', id }, { before: current })
357
+
358
+ return data
359
+ })
360
+ // ─── CHUNK_END: APPS_REMOVE ────────────────────────────────────────────────
361
+
362
+ // ─── CHUNK_START: APPS_CHECK_AVAILABILITY ──────────────────────────────────────────────
363
+ /**
364
+ * @chunk-id APPS_CHECK_AVAILABILITY_1_0_0
365
+ * @version 1.0.0
366
+ * @hash db7d52bcb1002d923dac039a99e6f6fb0eb9889e9b4a44994bf7bb75477ac9a4
367
+ * @macro App Availability Checker
368
+ * @micro Checks if app is available for account via RPC
369
+ * @inputs ctx: CoreContext — Request context with principal and database
370
+ * @inputs body: any — Request body (unused for GET)
371
+ * @outputs {available: boolean} — Availability status
372
+ * @depends-on [createHandler]
373
+ * @depended-by [Netlify function routing]
374
+ * @side-effects [RPC call for availability check]
375
+ * @tags apps, availability, rpc, check
376
+ */
377
+ export const checkAvailability = createHandler(async (ctx, body) => {
378
+ const { slug } = ctx.query || {}
379
+
380
+ if (!slug) {
381
+ throw new Error('App slug is required')
382
+ }
383
+
384
+ if (!ctx.accountId) {
385
+ throw new Error('Account context required')
386
+ }
387
+
388
+ const { data, error: err } = await ctx.db
389
+ .rpc('is_app_available', {
390
+ app_slug: slug,
391
+ account_id: ctx.accountId
392
+ })
393
+
394
+ if (err) throw err
395
+
396
+ return { available: data }
397
+ })
398
+ // ─── CHUNK_END: APPS_CHECK_AVAILABILITY ────────────────────────────────────────────────
399
+
400
+ // ─── CHUNK_START: APPS_UPDATE_VERSION ──────────────────────────────────────────────
401
+ /**
402
+ * @chunk-id APPS_UPDATE_VERSION_1_0_0
403
+ * @version 1.0.0
404
+ * @hash 04a1a3367e4b8ca0f58e0719e73b0ccda378e84b4b874f3f7e07ee0faa423bfd
405
+ * @macro App Version Update Handler
406
+ * @micro Updates app version string via RPC with audit logging
407
+ * @inputs ctx: CoreContext — Request context with principal and database
408
+ * @inputs body: object — App ID and new version string
409
+ * @outputs {success: true} — Success confirmation
410
+ * @depends-on [createHandler, emitLog]
411
+ * @depended-by [Netlify function routing]
412
+ * @side-effects [RPC call, audit logging]
413
+ * @tags apps, version, update, rpc, audit
414
+ */
415
+ export const updateVersion = createHandler(async (ctx, body) => {
416
+ const { id, version } = body
417
+
418
+ if (!id || !version) {
419
+ throw new Error('App ID and version are required')
420
+ }
421
+
422
+ const { data, error: err } = await ctx.db
423
+ .rpc('update_app_version', {
424
+ app_id: id,
425
+ new_version: version
426
+ })
427
+
428
+ if (err) throw err
429
+
430
+ await emitLog(ctx, 'app.version_updated', { type: 'app', id }, { after: { version } })
431
+
432
+ return { success: true }
433
+ })
434
+ // ─── CHUNK_END: APPS_UPDATE_VERSION ────────────────────────────────────────────────
435
+
436
+ // ─── MAIN HANDLER ────────────────────────────────────────────────────────────
437
+
438
+ // ─── CHUNK_START: APPS_HANDLER ──────────────────────────────────────────────
439
+ /**
440
+ * @chunk-id APPS_HANDLER_1_0_0
441
+ * @version 1.0.0
442
+ * @hash 361e1ba86b38a4611f3170526e4ff7f456d58b929c1d39bf847135afdebf3867
443
+ * @macro Apps Router
444
+ * @micro Routes HTTP methods and actions to appropriate handlers
445
+ * @inputs ctx: CoreContext — Request context with principal and database
446
+ * @inputs body: any — Request body for POST/PATCH operations
447
+ * @outputs Varies — Depends on routed handler (list/get/create/update/remove/schema/available/version)
448
+ * @depends-on [createHandler, list, get, getSchema, checkAvailability, create, update, remove, updateVersion]
449
+ * @depended-by [Netlify function routing]
450
+ * @side-effects [Delegates to appropriate handler]
451
+ * @tags apps, router, crud, netlify-function
452
+ */
453
+ export const handler = createHandler(async (ctx, body) => {
454
+ const method = ctx.query?.method || 'GET'
455
+
456
+ switch (method) {
457
+ case 'GET':
458
+ if (ctx.query?.action === 'get' || ctx.query?.id) {
459
+ return await get(ctx, body)
460
+ } else if (ctx.query?.slug) {
461
+ return await get(ctx, body)
462
+ } else if (ctx.query?.action === 'schema') {
463
+ return await getSchema(ctx, body)
464
+ } else if (ctx.query?.action === 'available') {
465
+ return await checkAvailability(ctx, body)
466
+ } else {
467
+ return await list(ctx, body)
468
+ }
469
+ case 'POST':
470
+ if (ctx.query?.action === 'version') {
471
+ return await updateVersion(ctx, body)
472
+ } else {
473
+ return await create(ctx, body)
474
+ }
475
+ case 'PATCH':
476
+ return await update(ctx, body)
477
+ case 'DELETE':
478
+ return await remove(ctx, body)
479
+ default:
480
+ throw new Error(`Unsupported method: ${method}`)
481
+ }
482
+ })
483
+ // ─── CHUNK_END: APPS_HANDLER ────────────────────────────────────────────────
@@ -0,0 +1,196 @@
1
+ /**
2
+ * @module auth
3
+ * @audience core-contributor
4
+ * @layer api-handler
5
+ * @stability stable
6
+ *
7
+ * Authentication context endpoint. Returns the full user session context for
8
+ * the authenticated principal: person record, account, role, permissions, and
9
+ * accessible child accounts (via the `get_account_hierarchy` RPC).
10
+ *
11
+ * **Routed by:** `GET /.netlify/functions/auth`
12
+ *
13
+ * **Actions:**
14
+ * | method | handler |
15
+ * |--------|----------|
16
+ * | GET | context |
17
+ * | HEALTH | health |
18
+ *
19
+ * **Authorization:** `context` requires a non-anonymous authenticated
20
+ * principal. `health` is unauthenticated.
21
+ *
22
+ * **Returned session shape:**
23
+ * ```ts
24
+ * {
25
+ * id: string // person UUID
26
+ * email: string
27
+ * full_name: string
28
+ * account_id: string
29
+ * account: { id, slug, display_name, parent_id }
30
+ * roles: string[] // role slugs (e.g. ['system_admin'])
31
+ * permissions: string[] // derived from role.slug or role.permissions
32
+ * accessible_accounts: AccountHierarchyRow[]
33
+ * }
34
+ * ```
35
+ *
36
+ * INVARIANT: `system_admin` role always receives the full permission set
37
+ * ['read', 'write', 'admin', 'system'] regardless of `role.permissions`.
38
+ *
39
+ * @seeAlso middleware.ts (createHandler builds ctx.principal from JWT)
40
+ * @seeAlso _shared/db.ts (get_account_hierarchy RPC)
41
+ * @seeAlso roles.ts (role records referenced by FK)
42
+ */
43
+
44
+ import { createHandler } from './_shared/middleware'
45
+
46
+ // ─── HANDLERS ─────────────────────────────────────────────────────────────────
47
+
48
+ /**
49
+ * Returns the full authenticated user context. Fetches person, account,
50
+ * and role in a single query, then calls `get_account_hierarchy` to
51
+ * resolve accessible child accounts.
52
+ *
53
+ * @returns Session object (see module-level shape doc)
54
+ * @throws Error('Authentication required') if principal is anonymous
55
+ * @throws Error('User not found: <id>') if person row is inactive or missing
56
+ * @sideEffects DB read: people table (with account + role joins)
57
+ * @sideEffects DB read: get_account_hierarchy RPC
58
+ * @calledBy handler (GET)
59
+ * @testUnit tests/unit/auth.test.ts — 'context'
60
+ * @testIntegration tests/integration/auth.test.ts — 'returns valid context'
61
+ */
62
+ export const context = createHandler(async (ctx, _body) => {
63
+ // Authentication is required
64
+ if (!ctx.principal || ctx.principal.id === 'anonymous') {
65
+ throw new Error('Authentication required')
66
+ }
67
+
68
+ console.log('Backend: Fetching user context for person:', ctx.principal.id)
69
+
70
+ // Single query gets everything - person, account, role using simplified model
71
+ const { data: personData, error: personError } = await ctx.db
72
+ .from('people')
73
+ .select(`
74
+ id,
75
+ email,
76
+ full_name,
77
+ avatar_url,
78
+ account_id,
79
+ role_id,
80
+ account:accounts!people_account_id_fkey(
81
+ id,
82
+ slug,
83
+ display_name,
84
+ parent_id
85
+ ),
86
+ role:roles(
87
+ id,
88
+ slug,
89
+ name,
90
+ is_system
91
+ )
92
+ `)
93
+ .eq('id', ctx.principal.id)
94
+ .eq('is_active', true)
95
+ .single()
96
+
97
+ if (personError) {
98
+ console.error('Backend: Error fetching person:', personError)
99
+ }
100
+
101
+ if (!personData) {
102
+ throw new Error('User not found: ' + ctx.principal.id)
103
+ }
104
+
105
+ console.log('Backend: Person data found:', {
106
+ id: personData.id,
107
+ email: personData.email,
108
+ account_id: personData.account_id,
109
+ role_id: personData.role_id
110
+ })
111
+
112
+ // Extract account and role (handle array responses)
113
+ const account = Array.isArray(personData.account) ? personData.account[0] : personData.account
114
+ const role = Array.isArray(personData.role) ? personData.role[0] : personData.role
115
+
116
+ // Get child accounts recursively
117
+ let accessibleAccounts = []
118
+ if (personData.account_id) {
119
+ const { data: childAccounts } = await ctx.db
120
+ .rpc('get_account_hierarchy', {
121
+ parent_account_id: personData.account_id
122
+ })
123
+
124
+ accessibleAccounts = childAccounts || []
125
+ console.log('Backend: Found', accessibleAccounts.length, 'accessible accounts')
126
+ }
127
+
128
+ // Determine permissions from role - system_admin role has full permissions
129
+ let effectivePermissions = []
130
+ const roleSlug = role?.slug
131
+
132
+ if (roleSlug === 'system_admin') {
133
+ effectivePermissions = ['read', 'write', 'admin', 'system']
134
+ } else if (role?.permissions && Array.isArray(role.permissions)) {
135
+ effectivePermissions = role.permissions
136
+ }
137
+
138
+ console.log('Backend: User context complete:', {
139
+ id: personData.id,
140
+ email: personData.email,
141
+ account: account?.slug,
142
+ role: roleSlug,
143
+ permissionsCount: effectivePermissions.length
144
+ })
145
+
146
+ // Return complete user context
147
+ // Note: system_admin status is determined by 'system_admin' in roles array
148
+ return {
149
+ id: personData.id,
150
+ email: personData.email,
151
+ full_name: personData.full_name,
152
+ account_id: personData.account_id,
153
+ account: account,
154
+ roles: [roleSlug].filter(Boolean),
155
+ permissions: effectivePermissions,
156
+ is_system_admin: roleSlug === 'system_admin',
157
+ accessible_accounts: accessibleAccounts
158
+ }
159
+ })
160
+
161
+ /**
162
+ * Lightweight health check for the auth function. Returns service name
163
+ * and current timestamp. No authentication required.
164
+ *
165
+ * @returns `{ status: 'healthy', timestamp: string, service: 'auth' }`
166
+ * @calledBy handler (HEALTH method)
167
+ * @calledBy load balancer health probes
168
+ */
169
+ export const health = createHandler(async (ctx, _body) => {
170
+ return {
171
+ status: 'healthy',
172
+ timestamp: new Date().toISOString(),
173
+ service: 'auth'
174
+ }
175
+ })
176
+
177
+ // ─── MAIN HANDLER ────────────────────────────────────────────────────────────
178
+
179
+ /**
180
+ * Netlify function entry point. Routes by HTTP method:
181
+ * GET → context | HEALTH → health
182
+ * @throws Error('Unsupported method: <method>') on unmatched method
183
+ * @calledBy Netlify function routing
184
+ */
185
+ export const handler = createHandler(async (ctx, _body) => {
186
+ const method = ctx.query?.method || 'GET'
187
+
188
+ switch (method) {
189
+ case 'GET':
190
+ return await context(ctx, _body)
191
+ case 'HEALTH':
192
+ return await health(ctx, _body)
193
+ default:
194
+ throw new Error(`Unsupported method: ${method}`)
195
+ }
196
+ })