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,223 @@
1
+ /**
2
+ * @module src/hooks/useSchemaRecord
3
+ * @audience installer
4
+ * @layer frontend-hook
5
+ * @stability stable
6
+ *
7
+ * Schema-record data management hooks. Two complementary hooks:
8
+ *
9
+ * - **`useSchemaRecord`** — given an already-fetched record and its schema
10
+ * type, returns structured `FieldDefinition[]`, a managed `data` state
11
+ * seeded from `record.data` with schema defaults, and field setters.
12
+ * Used on detail/edit pages where the record is fetched by a parent hook.
13
+ *
14
+ * - **`useTypeSelection`** — fetches all types of a given `kind` and exposes
15
+ * a `selectedTypeId` state. Used on create pages for the type-first flow
16
+ * where the user picks a type before filling in fields.
17
+ *
18
+ * **Data seeding invariant:** `useSchemaRecord` re-seeds `data` state only
19
+ * when `record.id` or `schemaType.id` changes, not on every render. This
20
+ * prevents losing unsaved edits during re-renders.
21
+ *
22
+ * @seeAlso src/hooks/useEntityRecord.ts (fetches the record passed here)
23
+ * @seeAlso src/hooks/useForm.ts (consumes FieldDefinition[] from this hook)
24
+ * @seeAlso src/types/types.ts (FieldDefinition, ItemType)
25
+ */
26
+
27
+ import { useState, useEffect, useCallback } from 'react'
28
+ import { apiFetch } from '../lib/api'
29
+ import { FieldDefinition, ItemType } from '../types/types'
30
+
31
+ // ─── TYPES ───────────────────────────────────────────────────────────────────
32
+
33
+ /**
34
+ * A record from the `types` table as loaded for schema resolution.
35
+ * @prop design_schema - Full design schema including fields and views
36
+ */
37
+ export interface SchemaType {
38
+ id: string
39
+ name: string
40
+ slug: string
41
+ kind?: string
42
+ icon?: string
43
+ color?: string
44
+ app_id?: string
45
+ design_schema: ItemType['design_schema']
46
+ }
47
+
48
+ /**
49
+ * A generic record that may carry its resolved type in a nested `type` join.
50
+ * @prop data - The JSONB `data` column; all custom field values live here
51
+ */
52
+ export interface SchemaRecord {
53
+ id: string
54
+ type_id?: string
55
+ type?: SchemaType
56
+ data: Record<string, any>
57
+ [key: string]: any
58
+ }
59
+
60
+ /** Options for `useSchemaRecord`. */
61
+ export interface UseSchemaRecordOptions {
62
+ typeApiKind: string // e.g. 'account', 'person', 'item'
63
+ }
64
+
65
+ /**
66
+ * Return value of `useSchemaRecord`.
67
+ *
68
+ * @prop fields - Ordered `FieldDefinition[]` from schema; empty if no schema
69
+ * @prop data - Managed field values (seeded from `record.data` + defaults)
70
+ * @prop setData - Replace the entire data map
71
+ * @prop setField - Update a single field by name
72
+ * @prop schemaType - The resolved schema type (passed through)
73
+ * @prop loading - Always false (data is derived, not fetched here)
74
+ * @prop error - Always null
75
+ */
76
+ export interface UseSchemaRecordResult {
77
+ fields: FieldDefinition[]
78
+ data: Record<string, any>
79
+ setData: (data: Record<string, any>) => void
80
+ setField: (name: string, value: any) => void
81
+ schemaType: SchemaType | null
82
+ loading: boolean
83
+ error: string | null
84
+ }
85
+
86
+ // ─── useSchemaRecord ─────────────────────────────────────────────────────────
87
+
88
+ /**
89
+ * Given an already-fetched record and its resolved schema type, returns
90
+ * structured field definitions and a managed data state for the record's
91
+ * `.data` JSONB column, with schema defaults seeded on load.
92
+ *
93
+ * Does NOT fetch anything — this is a pure derived-state hook.
94
+ *
95
+ * @param record - Fetched record (or null while loading)
96
+ * @param schemaType - Resolved schema type (or null while loading)
97
+ * @returns `UseSchemaRecordResult`
98
+ *
99
+ * @inputSpec record.data: Record<string, any> | undefined — custom field values
100
+ * @inputSpec schemaType.design_schema.fields: FieldDefinition map
101
+ * @outputSpec fields: FieldDefinition[] — ordered array with `.name` injected
102
+ * @sideEffects React state mutations (data re-seed on record/type change only)
103
+ * @calledBy DataDetailPage.tsx, create pages
104
+ *
105
+ * @example
106
+ * ```tsx
107
+ * const { fields, data, setField } = useSchemaRecord(record, schemaType)
108
+ * ```
109
+ */
110
+ export function useSchemaRecord(
111
+ record: SchemaRecord | null,
112
+ schemaType: SchemaType | null
113
+ ): UseSchemaRecordResult {
114
+ const [data, setDataState] = useState<Record<string, any>>({})
115
+
116
+ // Re-seed data state only when the record id or schema type id changes
117
+ const recordId = record?.id ?? null
118
+ const schemaTypeId = schemaType?.id ?? null
119
+
120
+ useEffect(() => {
121
+ if (!record) return
122
+
123
+ const base = record.data ? { ...record.data } : {}
124
+
125
+ // Seed defaults for fields that have no value
126
+ if (schemaType?.design_schema?.fields) {
127
+ for (const [name, field] of Object.entries(schemaType.design_schema.fields)) {
128
+ if (base[name] === undefined && (field as any).defaultValue !== undefined) {
129
+ base[name] = (field as any).defaultValue
130
+ }
131
+ }
132
+ }
133
+
134
+ setDataState(base)
135
+ // eslint-disable-next-line react-hooks/exhaustive-deps
136
+ }, [recordId, schemaTypeId])
137
+
138
+ const setData = useCallback((newData: Record<string, any>) => {
139
+ setDataState(newData)
140
+ }, [])
141
+
142
+ const setField = useCallback((name: string, value: any) => {
143
+ setDataState(prev => ({ ...prev, [name]: value }))
144
+ }, [])
145
+
146
+ const fields: FieldDefinition[] = schemaType?.design_schema?.fields
147
+ ? Object.entries(schemaType.design_schema.fields).map(([name, field]) => ({ ...field, name }))
148
+ : []
149
+
150
+ return {
151
+ fields,
152
+ data,
153
+ setData,
154
+ setField,
155
+ schemaType,
156
+ loading: false,
157
+ error: null
158
+ }
159
+ }
160
+
161
+ // ─── useTypeSelection ─────────────────────────────────────────────────────────
162
+
163
+ /**
164
+ * Return value of `useTypeSelection`.
165
+ *
166
+ * @prop types - All active types of the requested kind
167
+ * @prop selectedType - The full `SchemaType` for `selectedTypeId`, or null
168
+ * @prop selectedTypeId - Controlled string state for the `<select>` value
169
+ * @prop setSelectedTypeId - Setter for `selectedTypeId`
170
+ * @prop loading - True while fetching types
171
+ * @prop error - Error message or null
172
+ */
173
+ export interface UseTypeSelectionResult {
174
+ types: SchemaType[]
175
+ selectedType: SchemaType | null
176
+ selectedTypeId: string
177
+ setSelectedTypeId: (id: string) => void
178
+ loading: boolean
179
+ error: string | null
180
+ }
181
+
182
+ /**
183
+ * Fetches all active types of a given `kind` and exposes a controlled
184
+ * `selectedTypeId` state for the type-first create flow.
185
+ *
186
+ * @param kind - Type kind: `'account'`, `'person'`, `'item'`, etc.
187
+ * @returns `UseTypeSelectionResult`
188
+ *
189
+ * @inputSpec kind: string — passed as `?kind=<kind>&is_active=true` to `/api/types`
190
+ * @outputSpec types: SchemaType[] — active types; empty while loading
191
+ * @sideEffects Network request via apiFetch on mount and kind change
192
+ * @calledBy Create pages (e.g. AccountCreatePage, ItemCreatePage)
193
+ */
194
+ export function useTypeSelection(kind: string): UseTypeSelectionResult {
195
+ const [types, setTypes] = useState<SchemaType[]>([])
196
+ const [selectedTypeId, setSelectedTypeId] = useState('')
197
+ const [loading, setLoading] = useState(true)
198
+ const [error, setError] = useState<string | null>(null)
199
+
200
+ useEffect(() => {
201
+ let cancelled = false
202
+ setLoading(true)
203
+ apiFetch(`/api/types?action=list&kind=${kind}&is_active=true`)
204
+ .then(r => r.json())
205
+ .then(result => {
206
+ if (!cancelled) {
207
+ setTypes(result.data || [])
208
+ setLoading(false)
209
+ }
210
+ })
211
+ .catch(err => {
212
+ if (!cancelled) {
213
+ setError(err.message || 'Failed to load types')
214
+ setLoading(false)
215
+ }
216
+ })
217
+ return () => { cancelled = true }
218
+ }, [kind])
219
+
220
+ const selectedType = types.find(t => t.id === selectedTypeId) ?? null
221
+
222
+ return { types, selectedType, selectedTypeId, setSelectedTypeId, loading, error }
223
+ }
@@ -0,0 +1,128 @@
1
+ @import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
2
+
3
+ @tailwind base;
4
+ @tailwind components;
5
+ @tailwind utilities;
6
+
7
+ @layer base {
8
+ :root {
9
+ --background: 0 0% 100%;
10
+ --foreground: 240 10% 3.9%;
11
+ --card: 0 0% 100%;
12
+ --card-foreground: 240 10% 3.9%;
13
+ --popover: 0 0% 100%;
14
+ --popover-foreground: 240 10% 3.9%;
15
+ --primary: 221.2 83.2% 53.3%;
16
+ --primary-foreground: 210 40% 98%;
17
+ --secondary: 240 4.8% 95.9%;
18
+ --secondary-foreground: 240 5.9% 10%;
19
+ --muted: 240 4.8% 95.9%;
20
+ --muted-foreground: 240 3.8% 46.1%;
21
+ --accent: 240 4.8% 95.9%;
22
+ --accent-foreground: 240 5.9% 10%;
23
+ --destructive: 0 84.2% 60.2%;
24
+ --destructive-foreground: 0 0% 98%;
25
+ --border: 240 5.9% 90%;
26
+ --input: 240 5.9% 90%;
27
+ --ring: 221.2 83.2% 53.3%;
28
+ --radius: 0.3rem;
29
+ --chart-1: 221.2 83.2% 53.3%;
30
+ --chart-2: 212 96% 78%;
31
+ --chart-3: 199 98% 48%;
32
+ --chart-4: 245 58% 51%;
33
+ --chart-5: 258 60% 44%;
34
+ --sidebar: 0 0% 98%;
35
+ --sidebar-foreground: 240 5.3% 26.1%;
36
+ --sidebar-primary: 221.2 83.2% 53.3%;
37
+ --sidebar-primary-foreground: 0 0% 100%;
38
+ --sidebar-accent: 240 4.8% 95.9%;
39
+ --sidebar-accent-foreground: 240 5.9% 10%;
40
+ --sidebar-border: 220 13% 91%;
41
+ --sidebar-ring: 217.2 91.2% 59.8%;
42
+ }
43
+
44
+ .dark {
45
+ --background: 240 10% 3.9%;
46
+ --foreground: 0 0% 98%;
47
+ --card: 240 10% 3.9%;
48
+ --card-foreground: 0 0% 98%;
49
+ --popover: 240 10% 3.9%;
50
+ --popover-foreground: 0 0% 98%;
51
+ --primary: 217.2 91.2% 59.8%;
52
+ --primary-foreground: 222.2 47.4% 11.2%;
53
+ --secondary: 240 3.7% 15.9%;
54
+ --secondary-foreground: 0 0% 98%;
55
+ --muted: 240 3.7% 15.9%;
56
+ --muted-foreground: 240 5% 64.9%;
57
+ --accent: 240 3.7% 15.9%;
58
+ --accent-foreground: 0 0% 98%;
59
+ --destructive: 0 62.8% 30.6%;
60
+ --destructive-foreground: 0 0% 98%;
61
+ --border: 240 3.7% 15.9%;
62
+ --input: 240 3.7% 15.9%;
63
+ --ring: 217.2 91.2% 59.8%;
64
+ --chart-1: 217.2 91.2% 59.8%;
65
+ --chart-2: 212 96% 78%;
66
+ --chart-3: 199 98% 60%;
67
+ --chart-4: 245 58% 61%;
68
+ --chart-5: 258 60% 54%;
69
+ --sidebar: 240 5.9% 10%;
70
+ --sidebar-foreground: 240 4.8% 95.9%;
71
+ --sidebar-primary: 224.3 76.3% 48%;
72
+ --sidebar-primary-foreground: 0 0% 100%;
73
+ --sidebar-accent: 240 3.7% 15.9%;
74
+ --sidebar-accent-foreground: 240 4.8% 95.9%;
75
+ --sidebar-border: 240 3.7% 15.9%;
76
+ --sidebar-ring: 217.2 91.2% 59.8%;
77
+ }
78
+ }
79
+
80
+ @layer base {
81
+ * {
82
+ @apply border-border;
83
+ }
84
+ html, body, #root {
85
+ height: 100%;
86
+ }
87
+ body {
88
+ @apply bg-background text-foreground;
89
+ font-family: 'Inter', system-ui, -apple-system, sans-serif;
90
+ font-feature-settings: "rlig" 1, "calt" 1;
91
+ -webkit-font-smoothing: antialiased;
92
+ -moz-osx-font-smoothing: grayscale;
93
+ }
94
+ }
95
+
96
+ @layer utilities {
97
+ .text-balance {
98
+ text-wrap: balance;
99
+ }
100
+ .scrollbar-hide,
101
+ .no-scrollbar {
102
+ -ms-overflow-style: none;
103
+ scrollbar-width: none;
104
+ }
105
+ .scrollbar-hide::-webkit-scrollbar,
106
+ .no-scrollbar::-webkit-scrollbar {
107
+ display: none;
108
+ }
109
+
110
+ /* Tailwind v4 CSS variable shorthand — sidebar layout */
111
+ .w-\(--sidebar-width\) { width: var(--sidebar-width); }
112
+ .w-\(--sidebar-width-icon\) { width: var(--sidebar-width-icon); }
113
+ .max-w-\(--skeleton-width\) { max-width: var(--skeleton-width); }
114
+
115
+ /* Tailwind v4 outline-hidden */
116
+ .outline-hidden { outline: 2px solid transparent; outline-offset: 2px; }
117
+
118
+ /* Tailwind v4 !important suffix variants used in sidebar collapse */
119
+ [data-collapsible="icon"] .group-data-\[collapsible\=icon\]\:size-8\!,
120
+ [data-collapsible="icon"].group .group-data-\[collapsible\=icon\]\:size-8\! {
121
+ width: 2rem !important;
122
+ height: 2rem !important;
123
+ }
124
+ [data-collapsible="icon"] .group-data-\[collapsible\=icon\]\:p-2\!,
125
+ [data-collapsible="icon"].group .group-data-\[collapsible\=icon\]\:p-2\! {
126
+ padding: 0.5rem !important;
127
+ }
128
+ }
@@ -0,0 +1,156 @@
1
+ /**
2
+ * @module src/lib/api
3
+ * @audience installer
4
+ * @layer frontend-hook
5
+ * @stability stable
6
+ *
7
+ * Authenticated fetch wrapper and account context for all Spine frontend
8
+ * API calls. Injects the Supabase JWT and `X-Account-Id` header into every
9
+ * request made via `apiFetch`.
10
+ *
11
+ * **Account context** is a module-level singleton set once after login:
12
+ * ```ts
13
+ * setAccountId(ctx.account_id) // called in AuthContext after auth.context()
14
+ * ```
15
+ * All subsequent `apiFetch` calls include `X-Account-Id` automatically.
16
+ *
17
+ * INVARIANT: Call `setAccountId` before making any authenticated API requests.
18
+ * If `_accountId` is null, the backend may reject scoped requests.
19
+ *
20
+ * @seeAlso src/lib/supabase.ts (supabase client used for getSession)
21
+ * @seeAlso src/hooks/useApi.ts (wraps apiFetch with React state management)
22
+ * @seeAlso src/contexts/AuthContext.tsx (calls setAccountId after login)
23
+ */
24
+
25
+ import { supabase } from './supabase'
26
+
27
+ // ─── ACCOUNT CONTEXT ─────────────────────────────────────────────────────────
28
+
29
+ let _accountId: string | null = null
30
+
31
+ /**
32
+ * Sets the module-level account ID injected into all subsequent `apiFetch`
33
+ * calls as `X-Account-Id`. Pass `null` to clear (e.g. on logout).
34
+ *
35
+ * @param id - UUID of the active account, or null to clear
36
+ * @sideEffects Mutates module-level `_accountId`
37
+ * @calledBy src/contexts/AuthContext.tsx (after successful login)
38
+ */
39
+ export function setAccountId(id: string | null) {
40
+ _accountId = id
41
+ }
42
+
43
+ /**
44
+ * Returns the currently active account ID, or null if not set.
45
+ *
46
+ * @returns UUID string or null
47
+ * @sideEffects none
48
+ * @calledBy src/hooks/useApi.ts, any component needing the current account scope
49
+ */
50
+ export function getAccountId(): string | null {
51
+ return _accountId
52
+ }
53
+
54
+ // ─── INTERNAL HELPERS ─────────────────────────────────────────────────────────
55
+
56
+ /**
57
+ * Normalises any `HeadersInit` variant to a plain `Record<string, string>`
58
+ * so headers can be safely spread and merged.
59
+ * @throws never
60
+ */
61
+ function normalizeHeaders(headers?: HeadersInit): Record<string, string> {
62
+ if (!headers) return {}
63
+
64
+ if (headers instanceof Headers) {
65
+ return Object.fromEntries(headers.entries())
66
+ }
67
+
68
+ if (Array.isArray(headers)) {
69
+ return Object.fromEntries(headers)
70
+ }
71
+
72
+ return Object.fromEntries(
73
+ Object.entries(headers).map(([key, value]) => [key, String(value)])
74
+ )
75
+ }
76
+
77
+ // ─── AUTH HEADERS ─────────────────────────────────────────────────────────────────
78
+
79
+ /**
80
+ * Builds the auth header map for a request: `Authorization: Bearer <jwt>`
81
+ * and, if set, `X-Account-Id: <accountId>`.
82
+ *
83
+ * Called internally by `apiFetch` — do not call directly unless constructing
84
+ * a manual `fetch` outside of `apiFetch`.
85
+ *
86
+ * @returns Plain header object; empty if no active session
87
+ * @throws never — missing session returns empty headers, not an error
88
+ * @sideEffects DB read: supabase.auth.getSession (reads localStorage)
89
+ * @calledBy apiFetch
90
+ */
91
+ export async function getAuthHeaders(): Promise<Record<string, string>> {
92
+ const headers: Record<string, string> = {}
93
+
94
+ const { data: { session } } = await supabase.auth.getSession()
95
+ if (session?.access_token) {
96
+ headers['Authorization'] = `Bearer ${session.access_token}`
97
+ }
98
+
99
+ if (_accountId) {
100
+ headers['X-Account-Id'] = _accountId
101
+ }
102
+
103
+ return headers
104
+ }
105
+
106
+ // ─── FETCH WRAPPER ────────────────────────────────────────────────────────────────
107
+
108
+ /**
109
+ * Authenticated fetch wrapper. Injects `Authorization` + `X-Account-Id`
110
+ * headers, strips invalid Bearer values (`null`/`undefined`/empty), and
111
+ * forwards all other options (including `signal` for AbortController).
112
+ *
113
+ * Use this for ALL Spine API calls from the frontend. Never call `fetch`
114
+ * directly for API routes.
115
+ *
116
+ * @param path - API path, e.g. `'/.netlify/functions/items'`
117
+ * @param options - Standard `RequestInit` options (method, body, signal, etc.)
118
+ * @returns Raw `Response` — callers must check `response.ok` / status
119
+ * @throws Network errors from `fetch` (e.g. `TypeError: Failed to fetch`)
120
+ * @inputSpec path: string — relative URL to a Netlify function
121
+ * @inputSpec options.signal: AbortSignal | undefined — forwarded for cancellation
122
+ * @outputSpec Response — with auth headers injected; not yet parsed
123
+ * @sideEffects Network request; reads localStorage via getAuthHeaders
124
+ * @calledBy src/hooks/useApi.ts, useEntityList.ts, useEntityRecord.ts
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * const res = await apiFetch('/.netlify/functions/items?action=list')
129
+ * if (!res.ok) throw new Error(await res.text())
130
+ * const { data } = await res.json()
131
+ * ```
132
+ */
133
+ export async function apiFetch(path: string, options: RequestInit = {}): Promise<Response> {
134
+ console.log('apiFetch called with:', { path, options, signal: options.signal })
135
+ const authHeaders = await getAuthHeaders()
136
+ const optionHeaders = normalizeHeaders(options.headers)
137
+ const optionAuthorization = optionHeaders.Authorization || optionHeaders.authorization
138
+
139
+ if (
140
+ optionAuthorization &&
141
+ ['Bearer null', 'Bearer undefined', 'null', 'undefined', ''].includes(optionAuthorization.trim())
142
+ ) {
143
+ delete optionHeaders.Authorization
144
+ delete optionHeaders.authorization
145
+ }
146
+
147
+ const fetchOptions = {
148
+ ...options,
149
+ headers: {
150
+ ...authHeaders,
151
+ ...optionHeaders,
152
+ },
153
+ }
154
+ console.log('apiFetch final options:', { fetchOptions, signal: fetchOptions.signal })
155
+ return fetch(path, fetchOptions)
156
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * @module src/lib/supabase
3
+ * @audience installer
4
+ * @layer frontend-hook
5
+ * @stability stable
6
+ *
7
+ * Browser-side Supabase client singleton and session helpers for the Spine
8
+ * frontend. Reads `VITE_SUPABASE_URL` and `VITE_SUPABASE_ANON_KEY` from
9
+ * Vite env at build time; throws immediately on missing values so
10
+ * misconfigured builds fail loudly rather than silently.
11
+ *
12
+ * INVARIANT: `supabase` is a module-level singleton — do not call
13
+ * `createClient` again in components or hooks. Import this module instead.
14
+ *
15
+ * @seeAlso src/lib/api.ts (uses supabase.auth.getSession for apiFetch headers)
16
+ * @seeAlso src/contexts/AuthContext.tsx (wraps supabase.auth for React state)
17
+ */
18
+
19
+ import { createClient } from '@supabase/supabase-js'
20
+
21
+ const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
22
+ const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY
23
+
24
+ if (!supabaseUrl || !supabaseAnonKey) {
25
+ throw new Error('Missing Supabase environment variables')
26
+ }
27
+
28
+ // ─── CLIENT SINGLETON ─────────────────────────────────────────────────────────
29
+
30
+ /**
31
+ * Browser-side Supabase client with persistent session, auto-refresh, and
32
+ * URL-based session detection enabled. This is the only Supabase client
33
+ * instance in the frontend; all auth and RLS-scoped queries flow through it.
34
+ *
35
+ * @inputSpec VITE_SUPABASE_URL: string — valid Supabase project URL
36
+ * @inputSpec VITE_SUPABASE_ANON_KEY: string — anon (public) key
37
+ * @throws Error('Missing Supabase environment variables') at module load if
38
+ * either env var is absent
39
+ * @sideEffects Reads localStorage for persisted session on construction
40
+ * @calledBy src/lib/api.ts (getAuthHeaders), src/contexts/AuthContext.tsx
41
+ */
42
+ export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
43
+ auth: {
44
+ persistSession: true,
45
+ autoRefreshToken: true,
46
+ detectSessionInUrl: true,
47
+ },
48
+ })
49
+
50
+ // ─── SESSION HELPERS ─────────────────────────────────────────────────────────
51
+
52
+ /**
53
+ * Returns the current Supabase auth session, or `null` if unauthenticated.
54
+ *
55
+ * @returns Session object or null
56
+ * @throws Supabase AuthError on unexpected failure
57
+ * @sideEffects none (read-only)
58
+ * @calledBy AuthContext.tsx, login flows
59
+ */
60
+ export const getCurrentSession = async () => {
61
+ const { data: { session }, error } = await supabase.auth.getSession()
62
+ if (error) throw error
63
+ return session
64
+ }
65
+
66
+ /**
67
+ * Returns the currently authenticated Supabase user, or `null` if not signed in.
68
+ *
69
+ * @returns User object or null
70
+ * @throws Supabase AuthError on unexpected failure
71
+ * @sideEffects none (read-only)
72
+ * @calledBy AuthContext.tsx
73
+ */
74
+ export const getCurrentUser = async () => {
75
+ const { data: { user }, error } = await supabase.auth.getUser()
76
+ if (error) throw error
77
+ return user
78
+ }
79
+
80
+ /**
81
+ * Forces a session token refresh. Call this when a request returns 401 due
82
+ * to an expired JWT. Supabase auto-refresh normally handles this, but this
83
+ * function is exposed for explicit refresh flows.
84
+ *
85
+ * @returns `{ session, user }` after refresh
86
+ * @throws Supabase AuthError if refresh fails (e.g. refresh token expired)
87
+ * @sideEffects Updates localStorage session via Supabase client
88
+ * @calledBy AuthContext.tsx (manual token refresh)
89
+ */
90
+ export const refreshSession = async () => {
91
+ const { data, error } = await supabase.auth.refreshSession()
92
+ if (error) throw error
93
+ return data
94
+ }