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,317 @@
1
+ /**
2
+ * @module src/lib/utils
3
+ * @audience installer
4
+ * @layer frontend-hook
5
+ * @stability stable
6
+ *
7
+ * General-purpose frontend utility functions. Pure helpers only — no React,
8
+ * no Supabase, no side effects. Safe to use in any component or hook.
9
+ *
10
+ * **Exports:** `cn`, `formatDate`, `formatTime`, `formatDateTime`,
11
+ * `formatRelativeTime`, `formatFileSize`, `formatCurrency`, `formatNumber`,
12
+ * `truncateText`, `generateSlug`, `capitalize`, `debounce`, `throttle`,
13
+ * `isValidUrl`, `getFileExtension`, `generateId`, `deepClone`
14
+ *
15
+ * @seeAlso src/lib/api.ts (fetch utilities)
16
+ * @seeAlso functions/_shared/schema-utils.ts (server-side field formatters
17
+ * for storage-layer data; parallel set to the date/currency helpers here)
18
+ */
19
+
20
+ import { type ClassValue, clsx } from 'clsx'
21
+ import { twMerge } from 'tailwind-merge'
22
+
23
+ // ─── TAILWIND HELPERS ───────────────────────────────────────────────────────────
24
+
25
+ /**
26
+ * Merges Tailwind class strings with conflict resolution via `tailwind-merge`
27
+ * and conditional class support via `clsx`. The standard utility for
28
+ * composing class names in all Spine components.
29
+ *
30
+ * @param inputs - Any number of class values (strings, arrays, objects)
31
+ * @returns Merged, deduplicated class string
32
+ * @throws never
33
+ * @example
34
+ * ```ts
35
+ * cn('px-4 py-2', isActive && 'bg-blue-500', 'px-6') // → 'py-2 bg-blue-500 px-6'
36
+ * ```
37
+ */
38
+ export function cn(...inputs: ClassValue[]) {
39
+ return twMerge(clsx(inputs))
40
+ }
41
+
42
+ // ─── DATE FORMATTERS ────────────────────────────────────────────────────────────
43
+
44
+ /**
45
+ * Formats a date as a locale date string ('Jan 15, 2024').
46
+ * Returns `'N/A'` for null/undefined, `'Invalid Date'` for non-parseable input.
47
+ * @param date - ISO string, Date object, null, or undefined
48
+ * @param options - Optional `Intl.DateTimeFormatOptions` overrides
49
+ * @throws never
50
+ */
51
+ export function formatDate(date: string | Date | null | undefined, options?: Intl.DateTimeFormatOptions) {
52
+ if (!date) return 'N/A'
53
+
54
+ const dateObj = typeof date === 'string' ? new Date(date) : date
55
+
56
+ // Check if date is invalid
57
+ if (!dateObj || isNaN(dateObj.getTime())) return 'Invalid Date'
58
+
59
+ return dateObj.toLocaleDateString('en-US', {
60
+ year: 'numeric',
61
+ month: 'short',
62
+ day: 'numeric',
63
+ ...options,
64
+ })
65
+ }
66
+
67
+ /**
68
+ * Formats a date as a locale time string ('02:30 PM').
69
+ * Returns `'N/A'` for null/undefined, `'Invalid Date'` for bad input.
70
+ * @throws never
71
+ */
72
+ export function formatTime(date: string | Date | null | undefined, options?: Intl.DateTimeFormatOptions) {
73
+ if (!date) return 'N/A'
74
+
75
+ const dateObj = typeof date === 'string' ? new Date(date) : date
76
+
77
+ // Check if date is invalid
78
+ if (!dateObj || isNaN(dateObj.getTime())) return 'Invalid Date'
79
+
80
+ return dateObj.toLocaleTimeString('en-US', {
81
+ hour: '2-digit',
82
+ minute: '2-digit',
83
+ ...options,
84
+ })
85
+ }
86
+
87
+ /**
88
+ * Formats a date as a locale date+time string ('Jan 15, 2024, 02:30 PM').
89
+ * Returns `'N/A'` for null/undefined, `'Invalid Date'` for bad input.
90
+ * @throws never
91
+ */
92
+ export function formatDateTime(date: string | Date | null | undefined, options?: Intl.DateTimeFormatOptions) {
93
+ if (!date) return 'N/A'
94
+
95
+ const dateObj = typeof date === 'string' ? new Date(date) : date
96
+
97
+ // Check if date is invalid
98
+ if (!dateObj || isNaN(dateObj.getTime())) return 'Invalid Date'
99
+
100
+ return dateObj.toLocaleString('en-US', {
101
+ year: 'numeric',
102
+ month: 'short',
103
+ day: 'numeric',
104
+ hour: '2-digit',
105
+ minute: '2-digit',
106
+ ...options,
107
+ })
108
+ }
109
+
110
+ /**
111
+ * Formats a date as a human-readable relative string
112
+ * ('just now', '5 minutes ago', '3 days ago', or falls back to `formatDate`
113
+ * for dates older than 7 days).
114
+ * Returns `'N/A'` for null/undefined, `'Invalid Date'` for bad input.
115
+ * @throws never
116
+ */
117
+ export function formatRelativeTime(date: string | Date | null | undefined) {
118
+ if (!date) return 'N/A'
119
+
120
+ const dateObj = typeof date === 'string' ? new Date(date) : date
121
+
122
+ // Check if date is invalid
123
+ if (isNaN(dateObj.getTime())) return 'Invalid Date'
124
+
125
+ const now = new Date()
126
+ const diffMs = now.getTime() - dateObj.getTime()
127
+ const diffSecs = Math.floor(diffMs / 1000)
128
+ const diffMins = Math.floor(diffSecs / 60)
129
+ const diffHours = Math.floor(diffMins / 60)
130
+ const diffDays = Math.floor(diffHours / 24)
131
+
132
+ if (diffSecs < 60) {
133
+ return 'just now'
134
+ } else if (diffMins < 60) {
135
+ return `${diffMins} minute${diffMins > 1 ? 's' : ''} ago`
136
+ } else if (diffHours < 24) {
137
+ return `${diffHours} hour${diffHours > 1 ? 's' : ''} ago`
138
+ } else if (diffDays < 7) {
139
+ return `${diffDays} day${diffDays > 1 ? 's' : ''} ago`
140
+ } else {
141
+ return formatDate(dateObj)
142
+ }
143
+ }
144
+
145
+ // ─── NUMBER FORMATTERS ───────────────────────────────────────────────────────────
146
+
147
+ /**
148
+ * Formats bytes as a human-readable size string ('1.23 MB').
149
+ * Returns `'0 Bytes'` for 0.
150
+ * @param bytes - Non-negative byte count
151
+ * @param decimals - Decimal places (default 2)
152
+ * @throws never
153
+ */
154
+ export function formatFileSize(bytes: number, decimals = 2) {
155
+ if (bytes === 0) return '0 Bytes'
156
+
157
+ const k = 1024
158
+ const dm = decimals < 0 ? 0 : decimals
159
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
160
+
161
+ const i = Math.floor(Math.log(bytes) / Math.log(k))
162
+
163
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
164
+ }
165
+
166
+ /**
167
+ * Formats a number as a locale currency string ('$1,234.56').
168
+ * @param amount - Numeric value
169
+ * @param currency - ISO 4217 code (default 'USD')
170
+ * @param locale - BCP 47 locale tag (default 'en-US')
171
+ * @throws never
172
+ */
173
+ export function formatCurrency(amount: number, currency = 'USD', locale = 'en-US') {
174
+ return new Intl.NumberFormat(locale, {
175
+ style: 'currency',
176
+ currency,
177
+ }).format(amount)
178
+ }
179
+
180
+ /**
181
+ * Formats a number using `Intl.NumberFormat` with optional format options.
182
+ * @throws never
183
+ */
184
+ export function formatNumber(num: number, options?: Intl.NumberFormatOptions) {
185
+ return new Intl.NumberFormat('en-US', options).format(num)
186
+ }
187
+
188
+ // ─── STRING UTILITIES ────────────────────────────────────────────────────────────
189
+
190
+ /**
191
+ * Truncates text to `maxLength` characters, appending `'...'` if truncated.
192
+ * Returns the original string if it fits within `maxLength`.
193
+ * @throws never
194
+ */
195
+ export function truncateText(text: string, maxLength: number) {
196
+ if (text.length <= maxLength) return text
197
+ return text.slice(0, maxLength) + '...'
198
+ }
199
+
200
+ /**
201
+ * Converts text to a URL-friendly slug: lowercased, diacritics stripped,
202
+ * spaces/underscores/hyphens collapsed to single `-`, leading/trailing
203
+ * hyphens removed.
204
+ * @throws never
205
+ */
206
+ export function generateSlug(text: string) {
207
+ return text
208
+ .toLowerCase()
209
+ .replace(/[^\w\s-]/g, '')
210
+ .replace(/[\s_-]+/g, '-')
211
+ .replace(/^-+|-+$/g, '')
212
+ }
213
+
214
+ /** Capitalises the first character of a string. @throws never */
215
+ export function capitalize(text: string) {
216
+ return text.charAt(0).toUpperCase() + text.slice(1)
217
+ }
218
+
219
+ // ─── TIMING UTILITIES ────────────────────────────────────────────────────────────
220
+
221
+ /**
222
+ * Returns a debounced wrapper that delays invoking `func` until `wait` ms
223
+ * after the last call. Resets the timer on each call.
224
+ * @param func - The function to debounce
225
+ * @param wait - Delay in milliseconds
226
+ * @throws never (the wrapper itself never throws; `func` may throw)
227
+ * @example
228
+ * ```ts
229
+ * const search = debounce((q: string) => fetchResults(q), 300)
230
+ * ```
231
+ */
232
+ export function debounce<T extends (...args: any[]) => any>(
233
+ func: T,
234
+ wait: number
235
+ ): (...args: Parameters<T>) => void {
236
+ let timeout: ReturnType<typeof setTimeout>
237
+ return (...args: Parameters<T>) => {
238
+ clearTimeout(timeout)
239
+ timeout = setTimeout(() => func(...args), wait)
240
+ }
241
+ }
242
+
243
+ /**
244
+ * Returns a throttled wrapper that invokes `func` at most once per `limit` ms.
245
+ * Subsequent calls within the window are dropped.
246
+ * @param func - The function to throttle
247
+ * @param limit - Throttle window in milliseconds
248
+ * @throws never
249
+ */
250
+ export function throttle<T extends (...args: any[]) => any>(
251
+ func: T,
252
+ limit: number
253
+ ): (...args: Parameters<T>) => void {
254
+ let inThrottle: boolean
255
+ return (...args: Parameters<T>) => {
256
+ if (!inThrottle) {
257
+ func(...args)
258
+ inThrottle = true
259
+ setTimeout(() => (inThrottle = false), limit)
260
+ }
261
+ }
262
+ }
263
+
264
+ // ─── VALIDATION & FILE UTILITIES ────────────────────────────────────────────────────
265
+
266
+ /** Returns true if `url` is a valid absolute URL (any protocol). @throws never */
267
+ export function isValidUrl(url: string) {
268
+ try {
269
+ new URL(url)
270
+ return true
271
+ } catch {
272
+ return false
273
+ }
274
+ }
275
+
276
+ /**
277
+ * Extracts the file extension from a filename. Returns an empty string if
278
+ * there is no extension. Works correctly for dotfiles (e.g. `.gitignore` → `''`).
279
+ * @throws never
280
+ */
281
+ export function getFileExtension(filename: string) {
282
+ return filename.slice((filename.lastIndexOf('.') - 1 >>> 0) + 2)
283
+ }
284
+
285
+ /** Generates a random alphanumeric ID of the given length (default 8). @throws never */
286
+ export function generateId(length = 8) {
287
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
288
+ let result = ''
289
+ for (let i = 0; i < length; i++) {
290
+ result += chars.charAt(Math.floor(Math.random() * chars.length))
291
+ }
292
+ return result
293
+ }
294
+
295
+ // ─── OBJECT UTILITIES ─────────────────────────────────────────────────────────────
296
+
297
+ /**
298
+ * Recursively deep-clones an object, array, or Date. Primitives and null
299
+ * are returned by value. Does not handle Maps, Sets, or class instances
300
+ * with custom prototypes.
301
+ * @throws never
302
+ */
303
+ export function deepClone<T>(obj: T): T {
304
+ if (obj === null || typeof obj !== 'object') return obj
305
+ if (obj instanceof Date) return new Date(obj.getTime()) as unknown as T
306
+ if (obj instanceof Array) return obj.map(item => deepClone(item)) as unknown as T
307
+ if (typeof obj === 'object') {
308
+ const clonedObj = {} as T
309
+ for (const key in obj) {
310
+ if (obj.hasOwnProperty(key)) {
311
+ clonedObj[key] = deepClone(obj[key])
312
+ }
313
+ }
314
+ return clonedObj
315
+ }
316
+ return obj
317
+ }
@@ -0,0 +1,27 @@
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom/client'
3
+ import { BrowserRouter } from 'react-router-dom'
4
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
5
+ import App from './App'
6
+ import { AuthProvider } from './contexts/AuthContext'
7
+ import './index.css'
8
+
9
+ // Create a client
10
+ const queryClient = new QueryClient({
11
+ defaultOptions: {
12
+ queries: {
13
+ retry: 1,
14
+ refetchOnWindowFocus: false,
15
+ },
16
+ },
17
+ })
18
+
19
+ ReactDOM.createRoot(document.getElementById('root')!).render(
20
+ <QueryClientProvider client={queryClient}>
21
+ <BrowserRouter>
22
+ <AuthProvider>
23
+ <App />
24
+ </AuthProvider>
25
+ </BrowserRouter>
26
+ </QueryClientProvider>,
27
+ )
@@ -0,0 +1,181 @@
1
+ /**
2
+ * @module src/pages/DashboardPage
3
+ * @audience installer
4
+ * @layer frontend-page
5
+ * @stability stable
6
+ *
7
+ * Admin home page. On mount, fetches all active item types (`kind=item`)
8
+ * from `/api/types` and then fans out parallel requests to
9
+ * `/api/admin-data?action=stats&entity=items&type_slug=…` to collect
10
+ * per-type item counts (capped at 8 types). Renders:
11
+ * - **Entity overview grid** — one stat card per type + a "Configuration"
12
+ * shortcut card
13
+ * - **Quick Actions row** — "New <Type>" buttons for the first 4 types plus
14
+ * a "Configure Types" shortcut
15
+ *
16
+ * @seeAlso src/contexts/AuthContext.tsx (provides current user)
17
+ * @seeAlso src/lib/api.ts (apiFetch)
18
+ */
19
+
20
+ import React, { useState, useEffect } from 'react'
21
+ import { useAuth } from '../contexts/AuthContext'
22
+ import { useApi } from '../hooks/useApi'
23
+ import { apiFetch } from '../lib/api'
24
+ import { useNavigate } from 'react-router-dom'
25
+ import { Box, UserGroupIcon, FileText, BarChart3, Settings, Plus } from 'lucide-react';
26
+
27
+ interface TypeStat {
28
+ name: string
29
+ count: number
30
+ slug: string
31
+ icon: any
32
+ }
33
+
34
+ export function DashboardPage() {
35
+ const { user } = useAuth()
36
+ const navigate = useNavigate()
37
+ const [stats, setStats] = useState<Array<{
38
+ title: string
39
+ value: number
40
+ icon: any
41
+ color: string
42
+ href: string
43
+ }>>([])
44
+ const [typeStats, setTypeStats] = useState<TypeStat[]>([])
45
+ const [loading, setLoading] = useState(true)
46
+
47
+ useEffect(() => {
48
+ const fetchStats = async () => {
49
+ try {
50
+ // Fetch active types with their counts
51
+ const typesResponse = await apiFetch('/api/types?kind=item&is_active=true')
52
+ if (typesResponse.ok) {
53
+ const response = await typesResponse.json()
54
+ const types = response.data || response // Handle both wrapped and unwrapped responses
55
+
56
+ if (!Array.isArray(types)) {
57
+ console.error('Expected array of types, got:', types)
58
+ setTypeStats([])
59
+ return
60
+ }
61
+
62
+ // Get counts for each type
63
+ const statsPromises = types.map(async (type: any) => {
64
+ const countResponse = await apiFetch(`/api/admin-data?action=stats&entity=items&type_slug=${type.slug}`)
65
+ if (countResponse.ok) {
66
+ const countData = await countResponse.json()
67
+ return {
68
+ name: type.name,
69
+ count: countData.count || 0,
70
+ slug: type.slug,
71
+ icon: CubeIcon // Default icon, could be enhanced to use type.icon
72
+ }
73
+ }
74
+ return null
75
+ })
76
+
77
+ const resolvedStats = await Promise.all(statsPromises)
78
+ const validStats = resolvedStats.filter((s): s is NonNullable<typeof s> => s !== null).slice(0, 8) // Limit to 8 types
79
+ setTypeStats(validStats)
80
+ }
81
+ } catch (error) {
82
+ console.error('Failed to fetch dashboard stats:', error)
83
+ } finally {
84
+ setLoading(false)
85
+ }
86
+ }
87
+
88
+ fetchStats()
89
+ }, [apiFetch])
90
+
91
+ const handleCreateNewItem = (typeSlug: string) => {
92
+ navigate(`/spine-framework/admin/data/items/create?typeSlug=${typeSlug}`)
93
+ }
94
+
95
+ const handleViewItems = (typeSlug: string) => {
96
+ navigate(`/spine-framework/admin/data/items?typeSlug=${typeSlug}`)
97
+ }
98
+
99
+ if (loading) {
100
+ return (
101
+ <div className="flex items-center justify-center h-64">
102
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
103
+ </div>
104
+ )
105
+ }
106
+
107
+ return (
108
+ <div className="space-y-6">
109
+ {/* Type Stats */}
110
+ <div>
111
+ <h2 className="text-lg font-semibold text-slate-900 mb-4">Entity Overview</h2>
112
+ <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
113
+ {typeStats.map((stat) => {
114
+ const Icon = stat.icon
115
+ return (
116
+ <div
117
+ key={stat.slug}
118
+ className="rounded-xl border border-slate-200 bg-white p-5 hover:shadow-md transition-shadow cursor-pointer"
119
+ onClick={() => handleViewItems(stat.slug)}
120
+ >
121
+ <div className="flex items-center gap-4">
122
+ <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-blue-50 text-blue-600">
123
+ <Icon className="h-5 w-5" />
124
+ </div>
125
+ <div>
126
+ <p className="text-sm text-slate-500">{stat.name}</p>
127
+ <p className="text-xl font-semibold text-slate-900">{stat.count.toLocaleString()}</p>
128
+ </div>
129
+ </div>
130
+ </div>
131
+ )
132
+ })}
133
+
134
+ {/* Quick Actions Card */}
135
+ <div
136
+ className="rounded-xl border border-slate-200 bg-white p-5 hover:shadow-md transition-shadow cursor-pointer"
137
+ onClick={() => navigate('/spine-framework/admin/configs/types')}
138
+ >
139
+ <div className="flex items-center gap-4">
140
+ <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-green-50 text-green-600">
141
+ <Settings className="h-5 w-5" />
142
+ </div>
143
+ <div>
144
+ <p className="text-sm text-slate-500">Configuration</p>
145
+ <p className="text-xl font-semibold text-slate-900">Manage</p>
146
+ </div>
147
+ </div>
148
+ </div>
149
+ </div>
150
+ </div>
151
+
152
+ {/* Quick Actions */}
153
+ <div className="rounded-xl border border-slate-200 bg-white p-6">
154
+ <h3 className="text-sm font-semibold text-slate-900 mb-4">
155
+ Quick Actions
156
+ </h3>
157
+
158
+ <div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
159
+ {typeStats.slice(0, 4).map((stat) => (
160
+ <button
161
+ key={`create-${stat.slug}`}
162
+ onClick={() => handleCreateNewItem(stat.slug)}
163
+ className="flex flex-col items-center gap-2 rounded-lg border border-slate-200 p-5 text-slate-600 hover:border-blue-200 hover:bg-blue-50 hover:text-blue-700 transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500"
164
+ >
165
+ <Plus className="h-6 w-6" />
166
+ <span className="text-sm font-medium">New {stat.name}</span>
167
+ </button>
168
+ ))}
169
+
170
+ <button
171
+ onClick={() => navigate('/spine-framework/admin/configs/types')}
172
+ className="flex flex-col items-center gap-2 rounded-lg border border-slate-200 p-5 text-slate-600 hover:border-blue-200 hover:bg-blue-50 hover:text-blue-700 transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500"
173
+ >
174
+ <Settings className="h-6 w-6" />
175
+ <span className="text-sm font-medium">Configure Types</span>
176
+ </button>
177
+ </div>
178
+ </div>
179
+ </div>
180
+ )
181
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * @module src/pages/NotFoundPage
3
+ * @audience installer
4
+ * @layer frontend-page
5
+ * @stability stable
6
+ *
7
+ * Generic 404 page rendered by the catch-all route. Displays a large
8
+ * "404" heading and a "Go back home" link to `/dashboard`.
9
+ */
10
+
11
+ import React from 'react'
12
+ import { Link } from 'react-router-dom'
13
+ import { Home } from 'lucide-react';
14
+
15
+ export function NotFoundPage() {
16
+ return (
17
+ <div className="min-h-screen bg-slate-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
18
+ <div className="sm:mx-auto sm:w-full sm:max-w-md">
19
+ <div className="text-center">
20
+ <h1 className="text-9xl font-bold text-slate-900">404</h1>
21
+ <h2 className="mt-4 text-3xl font-bold text-slate-900">Page not found</h2>
22
+ <p className="mt-2 text-sm text-slate-600">
23
+ Sorry, we couldn't find the page you're looking for.
24
+ </p>
25
+
26
+ <div className="mt-6">
27
+ <Link
28
+ to="/dashboard"
29
+ className="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
30
+ >
31
+ <Home className="w-4 h-4 mr-2" />
32
+ Go back home
33
+ </Link>
34
+ </div>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ )
39
+ }