@k2b/cloud 0.6.0-rc.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 (540) hide show
  1. package/README.md +98 -0
  2. package/package.json +128 -0
  3. package/public/logo.svg +1 -0
  4. package/scripts/app-favicon.test.ts +49 -0
  5. package/scripts/app-favicon.ts +51 -0
  6. package/scripts/build.ts +205 -0
  7. package/scripts/preload.ts +164 -0
  8. package/scripts/sync-recovery-smoke.ts +200 -0
  9. package/src/_internal/app-favicon.ts +2 -0
  10. package/src/_internal/app-presentation.ts +61 -0
  11. package/src/_internal/app-workspace-state.ts +24 -0
  12. package/src/_internal/bounded-json.ts +47 -0
  13. package/src/_internal/build-metadata.ts +9 -0
  14. package/src/_internal/capabilities.ts +1118 -0
  15. package/src/_internal/define-app.ts +801 -0
  16. package/src/_internal/heartbeat.ts +167 -0
  17. package/src/_internal/help-catalog.ts +241 -0
  18. package/src/_internal/help.ts +95 -0
  19. package/src/_internal/nats-connection.ts +34 -0
  20. package/src/_internal/page-responses.ts +40 -0
  21. package/src/_internal/process-sync.ts +117 -0
  22. package/src/_internal/readiness.ts +3 -0
  23. package/src/_internal/registry-validation.ts +136 -0
  24. package/src/_internal/registry-watch.ts +52 -0
  25. package/src/_internal/registry.ts +338 -0
  26. package/src/_internal/runtime-compatibility.ts +64 -0
  27. package/src/_internal/runtime-context.ts +84 -0
  28. package/src/_internal/runtime-watcher.ts +78 -0
  29. package/src/_internal/static-assets.ts +86 -0
  30. package/src/_internal/status-preserving-ssr.ts +49 -0
  31. package/src/access/PermissionEditor.tsx +486 -0
  32. package/src/access/ResourceApiKeys.tsx +271 -0
  33. package/src/access/messages.ts +121 -0
  34. package/src/access/ui.ts +16 -0
  35. package/src/account/Avatar.tsx +28 -0
  36. package/src/account/EntitySearch.tsx +363 -0
  37. package/src/account/avatar-upload-dialog.tsx +197 -0
  38. package/src/account/avatar-upload.ts +149 -0
  39. package/src/account/ui.ts +3 -0
  40. package/src/ai/admin.ts +47 -0
  41. package/src/ai/approval-routes.ts +130 -0
  42. package/src/ai/approvals.ts +139 -0
  43. package/src/ai/assistant-models.ts +61 -0
  44. package/src/ai/attachments.ts +40 -0
  45. package/src/ai/browser.ts +92 -0
  46. package/src/ai/capabilities.ts +714 -0
  47. package/src/ai/capability-execution.ts +151 -0
  48. package/src/ai/chat/blocks.render.test.tsx +1108 -0
  49. package/src/ai/chat/blocks.tsx +730 -0
  50. package/src/ai/chat/builtin-tools.tsx +428 -0
  51. package/src/ai/chat/capability-table.tsx +87 -0
  52. package/src/ai/chat/composer-adapter.ts +169 -0
  53. package/src/ai/chat/file-tools.tsx +81 -0
  54. package/src/ai/chat/message-actions.tsx +370 -0
  55. package/src/ai/chat/message-utils.ts +479 -0
  56. package/src/ai/chat/messages.ts +43 -0
  57. package/src/ai/chat/presentation.tsx +395 -0
  58. package/src/ai/chat/primitives.tsx +3 -0
  59. package/src/ai/chat/tool-disclosure.tsx +41 -0
  60. package/src/ai/chat/turn-navigator-utils.ts +28 -0
  61. package/src/ai/chat/turn-navigator.tsx +164 -0
  62. package/src/ai/chat/user-message.tsx +149 -0
  63. package/src/ai/chat/visual-tools.tsx +435 -0
  64. package/src/ai/chat/web-tools.tsx +202 -0
  65. package/src/ai/chat-task-contracts.ts +113 -0
  66. package/src/ai/chat-tasks.ts +952 -0
  67. package/src/ai/client/controller.ts +1211 -0
  68. package/src/ai/client/file-source.ts +95 -0
  69. package/src/ai/client/live-connection.ts +140 -0
  70. package/src/ai/client/projection.ts +178 -0
  71. package/src/ai/client/transport.ts +111 -0
  72. package/src/ai/compaction.ts +182 -0
  73. package/src/ai/credentials.ts +124 -0
  74. package/src/ai/default-tool-contracts.ts +108 -0
  75. package/src/ai/default-tools.ts +127 -0
  76. package/src/ai/enrich.ts +280 -0
  77. package/src/ai/executor.ts +1624 -0
  78. package/src/ai/fetch-file-tool.ts +313 -0
  79. package/src/ai/file-context.ts +92 -0
  80. package/src/ai/file-media-type.ts +28 -0
  81. package/src/ai/file-mount.ts +16 -0
  82. package/src/ai/file-tools.ts +566 -0
  83. package/src/ai/files-store.ts +390 -0
  84. package/src/ai/firecrawl-tools.ts +305 -0
  85. package/src/ai/grids-skill.ts +126 -0
  86. package/src/ai/http.ts +265 -0
  87. package/src/ai/index.ts +337 -0
  88. package/src/ai/kit-skill.ts +22 -0
  89. package/src/ai/limits.ts +5 -0
  90. package/src/ai/live-events.ts +289 -0
  91. package/src/ai/live-messages.ts +45 -0
  92. package/src/ai/live-outbox.ts +102 -0
  93. package/src/ai/live-routes.ts +412 -0
  94. package/src/ai/live.ts +2 -0
  95. package/src/ai/maintenance.ts +302 -0
  96. package/src/ai/markdown-pdf-tool.ts +95 -0
  97. package/src/ai/memories.ts +605 -0
  98. package/src/ai/memory-learning-runs.ts +222 -0
  99. package/src/ai/memory-learning.ts +619 -0
  100. package/src/ai/memory-tool.ts +120 -0
  101. package/src/ai/memory-workflow-evidence.ts +158 -0
  102. package/src/ai/migrate.ts +2082 -0
  103. package/src/ai/model-access-migrate.ts +30 -0
  104. package/src/ai/model-access.ts +191 -0
  105. package/src/ai/personal-agent.ts +6 -0
  106. package/src/ai/prefs.ts +72 -0
  107. package/src/ai/project-tool.ts +94 -0
  108. package/src/ai/projects-routes.ts +277 -0
  109. package/src/ai/projects.ts +902 -0
  110. package/src/ai/protocol.ts +279 -0
  111. package/src/ai/provider.ts +73 -0
  112. package/src/ai/public-projection.ts +25 -0
  113. package/src/ai/resource-markers.ts +31 -0
  114. package/src/ai/resource-refs.ts +70 -0
  115. package/src/ai/routes.ts +1131 -0
  116. package/src/ai/runtime-tools.ts +39 -0
  117. package/src/ai/runtime.ts +544 -0
  118. package/src/ai/settings.ts +529 -0
  119. package/src/ai/short-id.ts +45 -0
  120. package/src/ai/skill-catalog.ts +73 -0
  121. package/src/ai/skill-format.ts +145 -0
  122. package/src/ai/skill-seeds.ts +430 -0
  123. package/src/ai/skill-tool.ts +81 -0
  124. package/src/ai/skills-routes.ts +143 -0
  125. package/src/ai/skills.ts +934 -0
  126. package/src/ai/solid.ts +27 -0
  127. package/src/ai/store.ts +3113 -0
  128. package/src/ai/stream.ts +308 -0
  129. package/src/ai/structured-runs.ts +66 -0
  130. package/src/ai/structured.ts +186 -0
  131. package/src/ai/system-prompt.ts +170 -0
  132. package/src/ai/task-prompt.ts +22 -0
  133. package/src/ai/timeline.ts +148 -0
  134. package/src/ai/tool-audit.ts +177 -0
  135. package/src/ai/tool-result-budget.ts +16 -0
  136. package/src/ai/tools.ts +155 -0
  137. package/src/ai/types.ts +967 -0
  138. package/src/ai/ui.tsx +39 -0
  139. package/src/ai/usage-migrate.ts +81 -0
  140. package/src/ai/usage.ts +315 -0
  141. package/src/ai/validate.ts +54 -0
  142. package/src/ai/vision-tool.ts +79 -0
  143. package/src/api/accounts-entities.ts +174 -0
  144. package/src/api/admin-ai-projects.ts +74 -0
  145. package/src/api/admin-ai-skills.ts +76 -0
  146. package/src/api/admin-ai-usage.ts +42 -0
  147. package/src/api/admin-core-settings.ts +508 -0
  148. package/src/api/admin-identity.ts +148 -0
  149. package/src/api/admin-lifecycle.ts +206 -0
  150. package/src/api/admin-linux-identities.ts +66 -0
  151. package/src/api/announcements.ts +131 -0
  152. package/src/api/app-approval.ts +129 -0
  153. package/src/api/apps.ts +51 -0
  154. package/src/api/auth/schemas.ts +54 -0
  155. package/src/api/auth.ts +370 -0
  156. package/src/api/capabilities.ts +658 -0
  157. package/src/api/help-messages.ts +19 -0
  158. package/src/api/help.ts +78 -0
  159. package/src/api/index.ts +108 -0
  160. package/src/api/mcp.ts +744 -0
  161. package/src/api/me-rail.ts +45 -0
  162. package/src/api/me.ts +753 -0
  163. package/src/api/search/schemas.ts +79 -0
  164. package/src/api/search.bench.ts +185 -0
  165. package/src/api/search.ts +407 -0
  166. package/src/api/sync-ops.ts +79 -0
  167. package/src/api/widgets.ts +143 -0
  168. package/src/browser/CloudResourceSearch.behavior.test.tsx +74 -0
  169. package/src/browser/CloudResourceSearch.tsx +791 -0
  170. package/src/browser/app-approval-vault.ts +305 -0
  171. package/src/browser/app-approval.ts +234 -0
  172. package/src/browser/live-websocket.ts +268 -0
  173. package/src/browser/locale-preference.ts +25 -0
  174. package/src/browser/notification-target.ts +27 -0
  175. package/src/browser/notification-timeout.ts +14 -0
  176. package/src/browser/notifications.ts +181 -0
  177. package/src/browser/resource-clipboard.ts +70 -0
  178. package/src/browser/resource-picker.tsx +39 -0
  179. package/src/browser/resource-search-messages.ts +55 -0
  180. package/src/browser/resource-search.ts +27 -0
  181. package/src/capabilities/client.ts +149 -0
  182. package/src/capabilities/response.ts +39 -0
  183. package/src/capabilities/server.ts +215 -0
  184. package/src/capabilities/signals.ts +4 -0
  185. package/src/capabilities/testing.ts +12 -0
  186. package/src/capabilities/types.ts +32 -0
  187. package/src/cli/access.ts +499 -0
  188. package/src/cli/account.ts +382 -0
  189. package/src/cli/admin/account-administration.ts +45 -0
  190. package/src/cli/admin/account-categories.ts +49 -0
  191. package/src/cli/admin/ai-usage.ts +118 -0
  192. package/src/cli/admin/app-sign-in.ts +49 -0
  193. package/src/cli/admin/data.ts +343 -0
  194. package/src/cli/admin/documentation.ts +34 -0
  195. package/src/cli/admin/gateway.ts +155 -0
  196. package/src/cli/admin/index.ts +61 -0
  197. package/src/cli/admin/instance.ts +250 -0
  198. package/src/cli/admin/jobs.ts +223 -0
  199. package/src/cli/admin/legal.ts +122 -0
  200. package/src/cli/admin/linux.ts +53 -0
  201. package/src/cli/admin/logs.ts +324 -0
  202. package/src/cli/admin/metrics.ts +142 -0
  203. package/src/cli/admin/nats.ts +167 -0
  204. package/src/cli/admin/notifications.ts +516 -0
  205. package/src/cli/admin/shared.ts +113 -0
  206. package/src/cli/admin/sync.ts +188 -0
  207. package/src/cli/admin/telemetry.ts +314 -0
  208. package/src/cli/admin/webhooks.ts +222 -0
  209. package/src/cli/admin/workflows.ts +367 -0
  210. package/src/cli/apps.ts +40 -0
  211. package/src/cli/capabilities.ts +239 -0
  212. package/src/cli/commands.ts +604 -0
  213. package/src/cli/index.ts +61 -0
  214. package/src/cli/locale.ts +31 -0
  215. package/src/cli/output.ts +58 -0
  216. package/src/clients/core.ts +20 -0
  217. package/src/config/env.ts +54 -0
  218. package/src/config/index.ts +6 -0
  219. package/src/contracts/account-categories.ts +62 -0
  220. package/src/contracts/announcements.ts +121 -0
  221. package/src/contracts/app-approval.ts +197 -0
  222. package/src/contracts/app.ts +162 -0
  223. package/src/contracts/capabilities.ts +484 -0
  224. package/src/contracts/index.ts +14 -0
  225. package/src/contracts/notification-live.ts +66 -0
  226. package/src/contracts/notification-types.ts +235 -0
  227. package/src/contracts/posix.ts +69 -0
  228. package/src/contracts/profile.ts +85 -0
  229. package/src/contracts/rail-preferences.ts +53 -0
  230. package/src/contracts/registry.ts +110 -0
  231. package/src/contracts/resource-clipboard.ts +33 -0
  232. package/src/contracts/settings-types.ts +98 -0
  233. package/src/contracts/shared.ts +408 -0
  234. package/src/contracts/user-notifications.ts +101 -0
  235. package/src/contracts/widgets.ts +183 -0
  236. package/src/desktop/index.ts +704 -0
  237. package/src/desktop/solid.tsx +938 -0
  238. package/src/index.ts +58 -0
  239. package/src/server/actor.ts +41 -0
  240. package/src/server/api/index.ts +2 -0
  241. package/src/server/api/respond.ts +96 -0
  242. package/src/server/api-client.ts +54 -0
  243. package/src/server/app-context.ts +39 -0
  244. package/src/server/help.ts +187 -0
  245. package/src/server/index.ts +89 -0
  246. package/src/server/locale.ts +55 -0
  247. package/src/server/middleware/auth.ts +386 -0
  248. package/src/server/middleware/index.ts +28 -0
  249. package/src/server/middleware/invocation.ts +55 -0
  250. package/src/server/middleware/middleware.ts +65 -0
  251. package/src/server/middleware/openapi.ts +126 -0
  252. package/src/server/middleware/rate-limit.ts +125 -0
  253. package/src/server/middleware/request-logger.ts +41 -0
  254. package/src/server/middleware/route-template.ts +46 -0
  255. package/src/server/middleware/runtime.ts +22 -0
  256. package/src/server/middleware/settings.ts +55 -0
  257. package/src/server/middleware/validator.ts +49 -0
  258. package/src/server/middleware/workload.ts +22 -0
  259. package/src/server/ratelimit.ts +151 -0
  260. package/src/server/request-cookies.ts +18 -0
  261. package/src/server/services/access.ts +644 -0
  262. package/src/server/services/freeipa/client.ts +137 -0
  263. package/src/server/services/freeipa/index.ts +9 -0
  264. package/src/server/services/freeipa/session.ts +123 -0
  265. package/src/server/services/freeipa/test-certificates.ts +44 -0
  266. package/src/server/services/freeipa/tls.ts +44 -0
  267. package/src/server/services/freeipa/transport.ts +116 -0
  268. package/src/server/services/freeipa/util.ts +59 -0
  269. package/src/server/services/geo.ts +198 -0
  270. package/src/server/services/index.ts +48 -0
  271. package/src/server/services/pagination.ts +22 -0
  272. package/src/server/services/services.ts +13 -0
  273. package/src/server/time.ts +33 -0
  274. package/src/services/account-category-policy.ts +51 -0
  275. package/src/services/account-lifecycle/audit.ts +41 -0
  276. package/src/services/account-lifecycle/index.ts +940 -0
  277. package/src/services/account-lifecycle/ipa-backfill.ts +152 -0
  278. package/src/services/account-lifecycle/notification-sender.ts +13 -0
  279. package/src/services/account-lifecycle/scheduler.ts +506 -0
  280. package/src/services/account-model.ts +22 -0
  281. package/src/services/accounts/app.ts +1671 -0
  282. package/src/services/accounts/authz.ts +44 -0
  283. package/src/services/accounts/avatar.ts +120 -0
  284. package/src/services/accounts/base-group.ts +11 -0
  285. package/src/services/accounts/base-user.ts +46 -0
  286. package/src/services/accounts/duplicate-emails.ts +82 -0
  287. package/src/services/accounts/entities.ts +622 -0
  288. package/src/services/accounts/group-sql.ts +106 -0
  289. package/src/services/accounts/groups.ts +272 -0
  290. package/src/services/accounts/index.ts +14 -0
  291. package/src/services/accounts/ipa-data.ts +66 -0
  292. package/src/services/accounts/lifecycle.ts +2 -0
  293. package/src/services/accounts/local-groups.ts +499 -0
  294. package/src/services/accounts/model.ts +129 -0
  295. package/src/services/accounts/notification-sender.ts +31 -0
  296. package/src/services/accounts/posix.ts +386 -0
  297. package/src/services/accounts/request-policy.ts +11 -0
  298. package/src/services/accounts/switching.ts +126 -0
  299. package/src/services/accounts/users.ts +745 -0
  300. package/src/services/announcements/index.ts +224 -0
  301. package/src/services/app-approval.ts +498 -0
  302. package/src/services/audit/index.ts +438 -0
  303. package/src/services/auth-flows/index.ts +15 -0
  304. package/src/services/auth-flows/ipa.ts +197 -0
  305. package/src/services/auth-flows/magic-link.ts +185 -0
  306. package/src/services/auth-flows/notification-sender.ts +10 -0
  307. package/src/services/auth-flows/password-reset.ts +268 -0
  308. package/src/services/auth-flows/proxy-return.ts +49 -0
  309. package/src/services/document-extraction.ts +148 -0
  310. package/src/services/freeipa-config.ts +179 -0
  311. package/src/services/gateway.ts +186 -0
  312. package/src/services/identity/constants.ts +18 -0
  313. package/src/services/identity/index.ts +52 -0
  314. package/src/services/identity/invocation-actor.ts +120 -0
  315. package/src/services/identity/invocation-authority.ts +53 -0
  316. package/src/services/identity/invocation-operations.ts +15 -0
  317. package/src/services/identity/invocation-token.ts +276 -0
  318. package/src/services/identity/key-config.ts +41 -0
  319. package/src/services/identity/key-ring.ts +530 -0
  320. package/src/services/identity/metrics.ts +29 -0
  321. package/src/services/identity/routes.ts +18 -0
  322. package/src/services/identity/runtime-config.ts +88 -0
  323. package/src/services/identity/session-token.ts +152 -0
  324. package/src/services/identity/signer-refresh.ts +44 -0
  325. package/src/services/identity/workload-auth.ts +64 -0
  326. package/src/services/index.ts +187 -0
  327. package/src/services/ipa/auth.ts +216 -0
  328. package/src/services/ipa/connection.ts +57 -0
  329. package/src/services/ipa/effective-groups.ts +70 -0
  330. package/src/services/ipa/groups.ts +722 -0
  331. package/src/services/ipa/guard.ts +17 -0
  332. package/src/services/ipa/index.ts +17 -0
  333. package/src/services/ipa/posix.ts +19 -0
  334. package/src/services/ipa/profile.ts +132 -0
  335. package/src/services/ipa/runtime.ts +28 -0
  336. package/src/services/ipa/search.ts +154 -0
  337. package/src/services/ipa/service-account.ts +15 -0
  338. package/src/services/ipa/sync-planning.ts +100 -0
  339. package/src/services/ipa/sync.ts +862 -0
  340. package/src/services/ipa/users.ts +806 -0
  341. package/src/services/legal-consent.ts +76 -0
  342. package/src/services/logging/index.ts +477 -0
  343. package/src/services/logging/redaction.ts +20 -0
  344. package/src/services/logging/trace.ts +1231 -0
  345. package/src/services/mandates/index.ts +855 -0
  346. package/src/services/mandates/policy.ts +85 -0
  347. package/src/services/network-security.ts +31 -0
  348. package/src/services/notifications/batches.ts +722 -0
  349. package/src/services/notifications/browser.ts +252 -0
  350. package/src/services/notifications/catalog.ts +113 -0
  351. package/src/services/notifications/channels.ts +104 -0
  352. package/src/services/notifications/dispatcher.ts +139 -0
  353. package/src/services/notifications/email.ts +118 -0
  354. package/src/services/notifications/index.ts +633 -0
  355. package/src/services/notifications/live.ts +50 -0
  356. package/src/services/notifications/observability.ts +407 -0
  357. package/src/services/notifications/platform.ts +421 -0
  358. package/src/services/notifications/runtime.ts +120 -0
  359. package/src/services/notifications/user.ts +248 -0
  360. package/src/services/notifications/web-push-transport.ts +135 -0
  361. package/src/services/oauth-tokens.ts +209 -0
  362. package/src/services/outbox.ts +187 -0
  363. package/src/services/pdf/gotenberg.ts +290 -0
  364. package/src/services/pdf/index.ts +43 -0
  365. package/src/services/pdf/markdown.ts +209 -0
  366. package/src/services/pdf/template-preview.ts +122 -0
  367. package/src/services/postgres.ts +76 -0
  368. package/src/services/providers/index.ts +27 -0
  369. package/src/services/providers/local/auth.ts +51 -0
  370. package/src/services/providers/local/index.ts +4 -0
  371. package/src/services/providers/local/users.ts +263 -0
  372. package/src/services/rail-preferences.ts +27 -0
  373. package/src/services/runtime-lifecycle.ts +191 -0
  374. package/src/services/secrets.ts +10 -0
  375. package/src/services/service-account-credentials.ts +891 -0
  376. package/src/services/service-accounts.ts +184 -0
  377. package/src/services/session/index.ts +236 -0
  378. package/src/services/session/test-fixture.ts +18 -0
  379. package/src/services/session/user.ts +144 -0
  380. package/src/services/settings/api.ts +61 -0
  381. package/src/services/settings/app.ts +86 -0
  382. package/src/services/settings/core-settings.ts +796 -0
  383. package/src/services/settings/crypto.ts +69 -0
  384. package/src/services/settings/defaults.ts +374 -0
  385. package/src/services/settings/index.ts +215 -0
  386. package/src/services/settings/namespace.ts +9 -0
  387. package/src/services/settings/snapshot.ts +49 -0
  388. package/src/services/settings/store.ts +241 -0
  389. package/src/services/settings/templates.ts +4 -0
  390. package/src/services/sync-ops.ts +403 -0
  391. package/src/services/topic-cursor.ts +22 -0
  392. package/src/services/weather/forecast.ts +323 -0
  393. package/src/services/weather/geo.ts +119 -0
  394. package/src/services/weather/index.ts +67 -0
  395. package/src/services/weather/location.ts +24 -0
  396. package/src/services/weather/locations.ts +133 -0
  397. package/src/services/weather/migrate.ts +45 -0
  398. package/src/services/weather/settings.ts +66 -0
  399. package/src/services/weather/short-id.ts +57 -0
  400. package/src/services/weather/types.ts +61 -0
  401. package/src/services/weather/ui.ts +50 -0
  402. package/src/services/webauthn.ts +385 -0
  403. package/src/shared/account-action-notice.ts +70 -0
  404. package/src/shared/account-display.ts +15 -0
  405. package/src/shared/account-session.ts +15 -0
  406. package/src/shared/ai-platform-prompt.ts +134 -0
  407. package/src/shared/ai-usage.ts +49 -0
  408. package/src/shared/app-presentation.ts +48 -0
  409. package/src/shared/app-url.ts +12 -0
  410. package/src/shared/branding.ts +14 -0
  411. package/src/shared/capability-messages.ts +70 -0
  412. package/src/shared/email-html.ts +54 -0
  413. package/src/shared/format.ts +91 -0
  414. package/src/shared/help.ts +68 -0
  415. package/src/shared/icons.ts +400 -0
  416. package/src/shared/index.ts +54 -0
  417. package/src/shared/locale.ts +48 -0
  418. package/src/shared/login-method.ts +44 -0
  419. package/src/shared/markdown/client.ts +130 -0
  420. package/src/shared/markdown/extensions/code.ts +105 -0
  421. package/src/shared/markdown/extensions/guided-help.ts +100 -0
  422. package/src/shared/markdown/extensions/images.ts +79 -0
  423. package/src/shared/markdown/extensions/info-blocks.ts +97 -0
  424. package/src/shared/markdown/extensions/katex.ts +120 -0
  425. package/src/shared/markdown/extensions/links.ts +43 -0
  426. package/src/shared/markdown/extensions/mark.ts +48 -0
  427. package/src/shared/markdown/extensions/sub-sup.ts +60 -0
  428. package/src/shared/markdown/extensions/tables.ts +109 -0
  429. package/src/shared/markdown/extensions/task-list.ts +53 -0
  430. package/src/shared/markdown/formula.ts +1187 -0
  431. package/src/shared/markdown/index.ts +193 -0
  432. package/src/shared/markdown/shared.ts +36 -0
  433. package/src/shared/mock-cover.ts +130 -0
  434. package/src/shared/network-address.ts +106 -0
  435. package/src/shared/redirect.ts +56 -0
  436. package/src/shared/template-rendering.ts +140 -0
  437. package/src/shared/theme.ts +68 -0
  438. package/src/shared/time.ts +13 -0
  439. package/src/ssr/AdminLayout.tsx +53 -0
  440. package/src/ssr/AdminSidebar.tsx +50 -0
  441. package/src/ssr/AppLaunchpad.island.tsx +236 -0
  442. package/src/ssr/AppWorkspaceController.island.tsx +21 -0
  443. package/src/ssr/BrowserNotifications.island.tsx +135 -0
  444. package/src/ssr/GlobalAnnouncements.island.tsx +142 -0
  445. package/src/ssr/GlobalSearchDialog.behavior.test.tsx +96 -0
  446. package/src/ssr/GlobalSearchDialog.tsx +35 -0
  447. package/src/ssr/GlobalSearchHelpDialog.tsx +104 -0
  448. package/src/ssr/GlobalSearchTrigger.island.tsx +55 -0
  449. package/src/ssr/HotkeysHelpRail.island.tsx +55 -0
  450. package/src/ssr/Layout.render.test.tsx +148 -0
  451. package/src/ssr/Layout.tsx +292 -0
  452. package/src/ssr/LayoutBreadcrumbs.island.tsx +44 -0
  453. package/src/ssr/LayoutFooter.tsx +22 -0
  454. package/src/ssr/LayoutHeader.tsx +81 -0
  455. package/src/ssr/LayoutHelp.tsx +869 -0
  456. package/src/ssr/LayoutPreferences.island.tsx +36 -0
  457. package/src/ssr/LayoutRail.tsx +58 -0
  458. package/src/ssr/MinimalLayout.tsx +46 -0
  459. package/src/ssr/PageError.tsx +29 -0
  460. package/src/ssr/ProfilePreferences.island.tsx +92 -0
  461. package/src/ssr/RailApps.island.tsx +61 -0
  462. package/src/ssr/RailEditor.tsx +293 -0
  463. package/src/ssr/RegisteredHelpDocuments.island.tsx +3 -0
  464. package/src/ssr/TimezoneCookie.island.tsx +23 -0
  465. package/src/ssr/admin-active-link.ts +47 -0
  466. package/src/ssr/admin-navigation.ts +78 -0
  467. package/src/ssr/app-appearance.ts +23 -0
  468. package/src/ssr/app-navigation.ts +41 -0
  469. package/src/ssr/help-messages.ts +104 -0
  470. package/src/ssr/index.ts +14 -0
  471. package/src/ssr/islands/SearchBar.island.tsx +80 -0
  472. package/src/ssr/islands/index.ts +16 -0
  473. package/src/ssr/layout-context.ts +17 -0
  474. package/src/ssr/layout-help-markdown.ts +9 -0
  475. package/src/ssr/layout-help-navigation.ts +24 -0
  476. package/src/ssr/layout-help-url.ts +5 -0
  477. package/src/ssr/layout-runtime.ts +22 -0
  478. package/src/ssr/page-error-messages.ts +25 -0
  479. package/src/ssr/platform-messages.ts +135 -0
  480. package/src/ssr/preference-controller.ts +44 -0
  481. package/src/ssr/profile-preferences-messages.ts +29 -0
  482. package/src/ssr/rail-context.ts +21 -0
  483. package/src/ssr/rail-messages.ts +66 -0
  484. package/src/ssr/rail-navigation.ts +60 -0
  485. package/src/ssr/runtime.ts +31 -0
  486. package/src/ssr/url-filter.ts +127 -0
  487. package/src/styles/base-popover.css +36 -0
  488. package/src/styles/effects.css +851 -0
  489. package/src/styles/global.css +268 -0
  490. package/src/styles/input.css +58 -0
  491. package/src/styles/tokens.css +230 -0
  492. package/src/styles/utilities-buttons.css +405 -0
  493. package/src/styles/utilities-data.css +33 -0
  494. package/src/styles/utilities-feedback.css +232 -0
  495. package/src/styles/utilities-layout.css +603 -0
  496. package/src/styles/utilities-markdown-editor.css +525 -0
  497. package/src/styles/utilities-markdown-table.css +234 -0
  498. package/src/styles/utilities-navigation.css +1054 -0
  499. package/src/types/ambient.d.ts +24 -0
  500. package/src/workflows/ai/index.ts +17 -0
  501. package/src/workflows/ai/runtime.ts +286 -0
  502. package/src/workflows/ai/store.ts +314 -0
  503. package/src/workflows/ai/types.ts +111 -0
  504. package/src/workflows/ai-actions.ts +269 -0
  505. package/src/workflows/authoring.ts +88 -0
  506. package/src/workflows/builtins.ts +193 -0
  507. package/src/workflows/contracts.ts +280 -0
  508. package/src/workflows/definition.ts +334 -0
  509. package/src/workflows/editor.ts +113 -0
  510. package/src/workflows/index.ts +71 -0
  511. package/src/workflows/language/binder.ts +45 -0
  512. package/src/workflows/language/canonical.ts +29 -0
  513. package/src/workflows/language/compiler.ts +396 -0
  514. package/src/workflows/language/expressions.ts +34 -0
  515. package/src/workflows/language/index.ts +20 -0
  516. package/src/workflows/language/references.ts +55 -0
  517. package/src/workflows/language/schema.ts +134 -0
  518. package/src/workflows/language/strict-yaml.ts +131 -0
  519. package/src/workflows/manifest.ts +24 -0
  520. package/src/workflows/module.ts +12 -0
  521. package/src/workflows/runtime/coordinator.ts +115 -0
  522. package/src/workflows/runtime/executor.ts +1003 -0
  523. package/src/workflows/runtime/index.ts +60 -0
  524. package/src/workflows/runtime/instant.ts +8 -0
  525. package/src/workflows/runtime/ports.ts +213 -0
  526. package/src/workflows/runtime/schedule.ts +203 -0
  527. package/src/workflows/runtime/trigger.ts +37 -0
  528. package/src/workflows/runtime/wake.ts +13 -0
  529. package/src/workflows/store/actions.ts +438 -0
  530. package/src/workflows/store/budget.ts +145 -0
  531. package/src/workflows/store/definitions.ts +345 -0
  532. package/src/workflows/store/events.ts +383 -0
  533. package/src/workflows/store/index.ts +107 -0
  534. package/src/workflows/store/observability.ts +594 -0
  535. package/src/workflows/store/runs.ts +975 -0
  536. package/src/workflows/store/transaction.ts +23 -0
  537. package/src/workflows/store/worker.ts +439 -0
  538. package/src/workflows/testing/conformance.ts +72 -0
  539. package/src/workflows/testing/index.ts +11 -0
  540. package/src/workflows/testing/process-fixtures.ts +275 -0
package/README.md ADDED
@@ -0,0 +1,98 @@
1
+ <p align="center">
2
+ <img src="https://raw.githubusercontent.com/k2b-dev/cloud/main/packages/cloud/public/logo.svg" alt="Cloud" width="96" height="96">
3
+ </p>
4
+
5
+ <h1 align="center">@k2b/cloud</h1>
6
+
7
+ <p align="center">
8
+ <em>Modular Hono+SolidJS framework for building per-app docker services behind a dynamic gateway.</em>
9
+ </p>
10
+
11
+ The runtime that powers [github.com/k2b-dev/cloud](https://github.com/k2b-dev/cloud) — an application platform that runs on infrastructure you operate, where every feature ships as its own Bun container, registers with a gateway through Redis, and inherits a shared session, UI kit, settings store, search, logging, email, websockets, and admin surface.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ bun add @k2b/cloud
17
+ ```
18
+
19
+ The package is published as `.ts` source. It is intended for **Bun** consumers.
20
+
21
+ ## Quick start
22
+
23
+ ```ts
24
+ // packages/my-app/src/config.ts
25
+ import { defineApp } from "@k2b/cloud";
26
+
27
+ export const app = defineApp({
28
+ id: "my-app",
29
+ name: "My App",
30
+ icon: "ti ti-rocket",
31
+ description: "What this app does",
32
+ basePath: "/app/my-app",
33
+ baseUrl: "http://app-my-app:3000",
34
+ nav: { href: "/app/my-app", section: "more", requiresAuth: true },
35
+ routes: ["/api/my-app", "/app/my-app", "/admin/my-app", "/public/my-app"],
36
+ });
37
+
38
+ export const { ssr, plugin } = app;
39
+ ```
40
+
41
+ ```ts
42
+ // packages/my-app/src/index.ts
43
+ import { app } from "./config";
44
+ import { Hono } from "hono";
45
+
46
+ export default await app.start({
47
+ routes: {
48
+ api: new Hono().get("/", (c) => c.json({ ok: true })),
49
+ pages: new Hono().get("/", ...ssr(() => () => <div>hello</div>)),
50
+ },
51
+ });
52
+ ```
53
+
54
+ A standard app declares four prefixes (`/api/<id>`, `/app/<id>`, `/admin/<id>`, `/public/<id>`); the gateway routes them to your container by URL prefix from a Redis-backed registry.
55
+
56
+ ## Public building blocks
57
+
58
+ | Import | Use for |
59
+ |---|---|
60
+ | `@k2b/cloud` | `defineApp`, common types |
61
+ | `@k2b/cloud/server` | server context, auth, route helpers |
62
+ | `@k2b/cloud/browser` | typed browser client |
63
+ | `@k2b/cloud/services` | settings, logging, notifications, search |
64
+ | `@k2b/cloud/contracts` | shared public contracts |
65
+ | `@k2b/cloud/ssr` | Cloud SSR helpers and islands |
66
+ | `@k2b/cloud/workflows` | durable, inspectable application workflows |
67
+ | `@k2b/cloud/ai` | AI and tool-calling contracts |
68
+ | `@k2b/cloud/cli` | application CLI commands |
69
+ | `@k2b/cloud/config` | documented configuration helpers |
70
+ | `@k2b/ui` | Portable UI components and application layouts |
71
+ | `@k2b/stdlib/solid` | owner-local queries, mutations, and interaction primitives |
72
+ | `@k2b/ssr` | portable SolidJS SSR, islands, and navigation |
73
+ | `@k2b/sync` | distributed coordination, jobs, queues, and schedulers |
74
+ | `@k2b/cloud/access/ui` | Cloud access and resource-key controls |
75
+ | `@k2b/cloud/account/ui` | Cloud account selectors and avatars |
76
+ | `@k2b/cloud/ai/ui` | Cloud AI protocol adapters |
77
+ | `@k2b/cloud/styles/global.css` | base Tailwind stylesheet |
78
+
79
+ ## Documentation
80
+
81
+ Full walkthroughs, the per-app anatomy, deployment templates, and a reference app:
82
+
83
+ - **[github.com/ValentinKolb/cloud-template](https://github.com/ValentinKolb/cloud-template)** — starter repo with a working reference app + the complete app-authoring guide
84
+ - **[github.com/k2b-dev/cloud](https://github.com/k2b-dev/cloud)** — the platform monorepo (gateway, core, all platform apps)
85
+
86
+ ## License
87
+
88
+ GNU Affero General Public License v3.0 or later.
89
+
90
+ Commercial use, hosting, modification, and redistribution are permitted under
91
+ the AGPL. If you modify Cloud and let users interact with it over a network,
92
+ you must provide those users access to the corresponding source code under the
93
+ same license.
94
+
95
+ Separate commercial licenses for proprietary, reseller, managed-service,
96
+ white-label, or embedded product use are available by contacting the maintainer.
97
+
98
+ See the repository `LICENSE` file.
package/package.json ADDED
@@ -0,0 +1,128 @@
1
+ {
2
+ "name": "@k2b/cloud",
3
+ "version": "0.6.0-rc.0",
4
+ "description": "Modular Hono+SolidJS framework for building per-app docker services behind a dynamic gateway. Powers cloud.stuve-ulm.de.",
5
+ "license": "AGPL-3.0-or-later",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/k2b-dev/cloud.git",
9
+ "directory": "packages/cloud"
10
+ },
11
+ "homepage": "https://github.com/k2b-dev/cloud",
12
+ "bugs": "https://github.com/k2b-dev/cloud/issues",
13
+ "type": "module",
14
+ "files": [
15
+ "src",
16
+ "scripts",
17
+ "public",
18
+ "!src/**/*.test.ts",
19
+ "!src/**/*.integration.test.ts"
20
+ ],
21
+ "exports": {
22
+ ".": "./src/index.ts",
23
+ "./desktop": "./src/desktop/index.ts",
24
+ "./desktop/solid": "./src/desktop/solid.tsx",
25
+ "./server": "./src/server/index.ts",
26
+ "./server/*": "./src/server/*",
27
+ "./browser": "./src/server/api-client.ts",
28
+ "./browser/app-approval": "./src/browser/app-approval.ts",
29
+ "./browser/live": "./src/browser/live-websocket.ts",
30
+ "./browser/notifications": "./src/browser/notifications.ts",
31
+ "./browser/resource-clipboard": "./src/browser/resource-clipboard.ts",
32
+ "./browser/resource-picker": "./src/browser/resource-picker.tsx",
33
+ "./capabilities": "./src/capabilities/client.ts",
34
+ "./capabilities/server": "./src/capabilities/server.ts",
35
+ "./capabilities/testing": "./src/capabilities/testing.ts",
36
+ "./cli": "./src/cli/index.ts",
37
+ "./cli/access": "./src/cli/access.ts",
38
+ "./cli/account": "./src/cli/account.ts",
39
+ "./cli/apps": "./src/cli/apps.ts",
40
+ "./cli/capabilities": "./src/cli/capabilities.ts",
41
+ "./cli/admin": "./src/cli/admin/index.ts",
42
+ "./shared": "./src/shared/index.ts",
43
+ "./services": "./src/services/index.ts",
44
+ "./services/document-extraction": "./src/services/document-extraction.ts",
45
+ "./services/ipa/service-account": null,
46
+ "./services/*": "./src/services/*",
47
+ "./ai": "./src/ai/index.ts",
48
+ "./ai/admin": "./src/ai/admin.ts",
49
+ "./ai/browser": "./src/ai/browser.ts",
50
+ "./ai/live": "./src/ai/live.ts",
51
+ "./ai/live-events": "./src/ai/live-events.ts",
52
+ "./ai/runtime": "./src/ai/runtime.ts",
53
+ "./ai/solid": "./src/ai/solid.ts",
54
+ "./ai/tools": "./src/ai/runtime-tools.ts",
55
+ "./ai/ui": "./src/ai/ui.tsx",
56
+ "./account/ui": "./src/account/ui.ts",
57
+ "./access/ui": "./src/access/ui.ts",
58
+ "./ssr": "./src/ssr/index.ts",
59
+ "./ssr/islands": "./src/ssr/islands/index.ts",
60
+ "./ssr/*": "./src/ssr/*",
61
+ "./config": "./src/config/index.ts",
62
+ "./config/*": "./src/config/*",
63
+ "./contracts": "./src/contracts/index.ts",
64
+ "./contracts/notifications": "./src/contracts/notification-types.ts",
65
+ "./contracts/*": "./src/contracts/*",
66
+ "./workflows": "./src/workflows/index.ts",
67
+ "./workflows/ai": "./src/workflows/ai/index.ts",
68
+ "./workflows/editor": "./src/workflows/editor.ts",
69
+ "./workflows/language": "./src/workflows/language/index.ts",
70
+ "./workflows/runtime": "./src/workflows/runtime/index.ts",
71
+ "./workflows/store": "./src/workflows/store/index.ts",
72
+ "./workflows/testing": "./src/workflows/testing/index.ts",
73
+ "./api": "./src/api/index.ts",
74
+ "./clients/core": "./src/clients/core.ts",
75
+ "./styles/global.css": "./src/styles/global.css"
76
+ },
77
+ "scripts": {
78
+ "test": "bun test",
79
+ "typecheck": "tsc -p tsconfig.json --noEmit --pretty false 2>&1 | grep -v node_modules | (! grep -q 'error TS')"
80
+ },
81
+ "dependencies": {
82
+ "@firecrawl/anydoc": "0.1.9",
83
+ "@k2b/nessi": "0.11.0",
84
+ "@k2b/ssr": "0.12.0",
85
+ "@k2b/stdlib": "0.22.0",
86
+ "@k2b/sync": "6.4.0",
87
+ "@k2b/ui": "0.2.0",
88
+ "@modelcontextprotocol/sdk": "1.30.0",
89
+ "@nats-io/transport-node": "3.4.0",
90
+ "@simplewebauthn/server": "13.3.2",
91
+ "@tabler/icons": "3.46.0",
92
+ "@tailwindcss/typography": "0.5.20",
93
+ "bun-plugin-tailwind": "0.1.2",
94
+ "hash-wasm": "4.12.0",
95
+ "hono-openapi": "1.3.1",
96
+ "jose": "6.2.5",
97
+ "katex": "0.16.47",
98
+ "liquidjs": "10.27.2",
99
+ "marked": "17.0.6",
100
+ "mermaid": "11.16.0",
101
+ "nodemailer": "9.1.1",
102
+ "postcss": "8.5.25",
103
+ "reflect-metadata": "0.2.2",
104
+ "sanitize-html": "2.17.6",
105
+ "seroval": "1.6.0",
106
+ "tailwindcss": "4.3.3",
107
+ "web-push": "3.6.7",
108
+ "yaml": "2.9.0"
109
+ },
110
+ "devDependencies": {
111
+ "@babel/core": "7.29.7",
112
+ "@babel/preset-typescript": "7.29.7",
113
+ "@types/bun": "1.3.14",
114
+ "@types/nodemailer": "7.0.12",
115
+ "@types/sanitize-html": "2.16.1",
116
+ "@types/web-push": "3.6.4",
117
+ "babel-preset-solid": "1.9.12",
118
+ "hono": "4.12.32",
119
+ "solid-js": "1.9.14",
120
+ "typescript": "5.9.3",
121
+ "zod": "4.4.3"
122
+ },
123
+ "peerDependencies": {
124
+ "hono": "^4.12.25",
125
+ "solid-js": "^1.9.10",
126
+ "zod": "^4.3.4"
127
+ }
128
+ }
@@ -0,0 +1 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><rect id="ArtBoard1" x="0" y="0" width="24" height="24" style="fill:none;"/><g id="ArtBoard11" serif:id="ArtBoard1"><path d="M9.974,4.062c2.269,-0.689 4.771,-0.231 6.574,1.216c1.433,1.145 2.262,2.777 2.328,4.486l0.003,0.219l0.094,0.004c2.378,0.11 4.283,2.027 4.394,4.414l0.004,0.218c-0,2.488 -1.949,4.519 -4.399,4.633l-0.217,0.005l-12.278,-0l-0.23,-0.008c-3.039,-0.114 -5.496,-2.48 -5.613,-5.441l-0.005,-0.223c0,-2.84 2.15,-5.179 4.945,-5.6l0.118,-0.016l0.073,-0.187c0.685,-1.675 2.125,-3.004 3.958,-3.637l0.252,-0.083l-0.001,0Z" style="fill:url(#_Linear1);fill-rule:nonzero;"/><path d="M0.156,13.767l-0.001,-0.019l-0.005,-0.205l-0,-0.026c-0,-3.044 2.204,-5.581 5.143,-6.192c0.789,-1.718 2.309,-3.082 4.227,-3.743c-0.121,0.041 0.018,-0.007 0.018,-0.007l0.231,-0.076l0.024,-0.007c2.464,-0.749 5.179,-0.246 7.138,1.326c1.439,1.15 2.321,2.745 2.528,4.443c2.416,0.425 4.269,2.487 4.386,5.006l0.001,0.029l0.004,0.2l-0.034,0.035l-0.009,0.029l0.043,-0.043c0,2.864 -2.245,5.2 -5.066,5.331l-0.039,0.001l-0.21,0.005l-11.878,0c0.097,0 0.097,-0.015 0,0l-0.222,-0.008l-0.032,-0.001c-3.389,-0.126 -6.117,-2.777 -6.247,-6.078Zm9.088,-9.164c-0.161,0.076 -0.094,0.044 -0.232,0.109c-1.411,0.656 -2.482,1.819 -3.044,3.191l-0.07,0.181c0,0 -0.57,0.103 -0.943,0.204c-2.31,0.624 -3.955,2.77 -3.955,5.229l0.005,0.216c0.01,0.259 0.039,0.514 0.085,0.762c0,0 0.008,0.083 0.016,0.082c0.495,2.458 2.684,4.32 5.329,4.419l0.016,0.001l0.002,0l0.204,0.007l0.013,-0c0.324,0.047 11.865,-0 11.865,-0l0.21,-0.005c2.37,-0.11 4.255,-2.075 4.255,-4.482l-0.004,-0.211c-0.107,-2.309 -1.95,-4.163 -4.25,-4.27l-0.091,-0.003l-0.003,-0.212c-0.064,-1.654 -0.866,-3.232 -2.252,-4.34c-1.745,-1.4 -4.164,-1.843 -6.359,-1.176l-0.244,0.08c-0.189,0.065 -0.375,0.134 -0.553,0.218Z" style="fill:url(#_Linear2);"/></g><defs><linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.28477,14.9308,-14.9308,0.28477,12.4271,4.32609)"><stop offset="0" style="stop-color:#f0f6ff;stop-opacity:1"/><stop offset="1" style="stop-color:#5a9cff;stop-opacity:1"/></linearGradient><linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.11193e-15,18.1593,-18.1593,1.11193e-15,12,1.69474)"><stop offset="0" style="stop-color:#a6d1ff;stop-opacity:1"/><stop offset="1" style="stop-color:#1f8bff;stop-opacity:1"/></linearGradient></defs></svg>
@@ -0,0 +1,49 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { mkdtemp, readFile, rm } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { renderAppFavicon, tablerIconName, writeAppFavicon } from "./app-favicon";
6
+
7
+ describe("app favicon", () => {
8
+ test("extracts the documented Tabler icon class", () => {
9
+ expect(tablerIconName("ti ti-mail")).toBe("mail");
10
+ expect(() => tablerIconName("mail")).toThrow('such as "ti ti-mail"');
11
+ expect(() => tablerIconName("ti ti-mail extra")).toThrow('such as "ti ti-mail"');
12
+ });
13
+
14
+ test("renders a large icon with the Cloud gradient", () => {
15
+ const source = '<svg viewBox="0 0 24 24"><path d="M3 7h18" /></svg>';
16
+
17
+ const svg = renderAppFavicon(source);
18
+ expect(svg).toContain('<linearGradient id="cloud-icon"');
19
+ expect(svg).toContain(".start { stop-color: #3b82f6; }");
20
+ expect(svg).toContain(".end { stop-color: #1d4ed8; }");
21
+ expect(svg).toContain("@media (prefers-color-scheme: dark)");
22
+ expect(svg).toContain(".start { stop-color: #f0f6ff; }");
23
+ expect(svg).toContain(".end { stop-color: #1f8bff; }");
24
+ expect(svg).toContain('stroke="url(#cloud-icon)"');
25
+ expect(svg).toContain('stroke-width="2"');
26
+ expect(svg).not.toContain("<rect");
27
+ expect(svg).not.toContain("<filter");
28
+ expect(svg).toContain('<path d="M3 7h18" />');
29
+ });
30
+
31
+ test("writes a declared Tabler icon and rejects an unknown one", async () => {
32
+ const publicDir = await mkdtemp(join(tmpdir(), "cloud-app-favicon-"));
33
+ try {
34
+ const target = await writeAppFavicon({ publicDir, appId: "mail", icon: "ti ti-mail" });
35
+ const svg = await readFile(target, "utf8");
36
+ expect(svg).toContain('stroke="url(#cloud-icon)"');
37
+ expect(svg).toContain('d="M3 7l9 6l9 -6"');
38
+
39
+ const tableTarget = await writeAppFavicon({ publicDir, appId: "grids", icon: "ti ti-table" });
40
+ expect(await readFile(tableTarget, "utf8")).toContain('d="M3 10h18"');
41
+
42
+ await expect(writeAppFavicon({ publicDir, appId: "missing", icon: "ti ti-definitely-not-real" })).rejects.toThrow(
43
+ 'Unknown Tabler app icon "ti ti-definitely-not-real"',
44
+ );
45
+ } finally {
46
+ await rm(publicDir, { recursive: true, force: true });
47
+ }
48
+ });
49
+ });
@@ -0,0 +1,51 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { dirname, resolve } from "node:path";
3
+
4
+ const TABLER_ICON = /^ti-([a-z0-9]+(?:-[a-z0-9]+)*)$/;
5
+
6
+ export function tablerIconName(iconClass: string): string {
7
+ const classes = iconClass.trim().split(/\s+/);
8
+ const match = classes.length === 2 && classes[0] === "ti" ? TABLER_ICON.exec(classes[1] ?? "") : null;
9
+ if (!match?.[1]) throw new Error(`App icon must be a Tabler class such as "ti ti-mail"; received ${JSON.stringify(iconClass)}`);
10
+ return match[1];
11
+ }
12
+
13
+ export function renderAppFavicon(sourceSvg: string): string {
14
+ const source = sourceSvg.match(/<svg\b[^>]*>([\s\S]*?)<\/svg>\s*$/i);
15
+ if (!source?.[1]) throw new Error("Tabler icon did not contain an SVG body");
16
+
17
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
18
+ <style>
19
+ .start { stop-color: #3b82f6; }
20
+ .end { stop-color: #1d4ed8; }
21
+ @media (prefers-color-scheme: dark) {
22
+ .start { stop-color: #f0f6ff; }
23
+ .end { stop-color: #1f8bff; }
24
+ }
25
+ </style>
26
+ <defs>
27
+ <linearGradient id="cloud-icon" x1="12" y1="2" x2="12" y2="22" gradientUnits="userSpaceOnUse">
28
+ <stop class="start" />
29
+ <stop class="end" offset="1" />
30
+ </linearGradient>
31
+ </defs>
32
+ <g fill="none" stroke="url(#cloud-icon)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
33
+ ${source[1].trim()}
34
+ </g>
35
+ </svg>\n`;
36
+ }
37
+
38
+ export async function writeAppFavicon(options: { publicDir: string; appId: string; icon: string }): Promise<string> {
39
+ const iconName = tablerIconName(options.icon);
40
+ let sourcePath: string;
41
+ try {
42
+ sourcePath = Bun.resolveSync(`@tabler/icons/outline/${iconName}.svg`, resolve(import.meta.dir, ".."));
43
+ } catch {
44
+ throw new Error(`Unknown Tabler app icon ${JSON.stringify(options.icon)}`);
45
+ }
46
+
47
+ const target = resolve(options.publicDir, options.appId, "favicon.svg");
48
+ await mkdir(dirname(target), { recursive: true });
49
+ await writeFile(target, renderAppFavicon(await readFile(sourcePath, "utf8")));
50
+ return target;
51
+ }
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Production build for a single cloud app.
3
+ *
4
+ * Two consumer shapes:
5
+ *
6
+ * Monorepo (this repo):
7
+ * APP_ID=<id> bun run packages/cloud/scripts/build.ts
8
+ * # appDir defaults to packages/<APP_ID>, run from workspace root.
9
+ *
10
+ * Standalone (npm consumer, see cloud-template):
11
+ * APP_ID=<id> APP_DIR=. bun run node_modules/@k2b/cloud/scripts/build.ts
12
+ * # appDir = APP_DIR (resolved against cwd) and must be the directory
13
+ * # that CONTAINS src/, since entrypoints resolve to <appDir>/src/*.
14
+ *
15
+ * Output goes to <cwd>/dist:
16
+ * server.js bundled Bun entry
17
+ * _ssr/<island>.js hydration bundles (auto-emitted by the SSR plugin)
18
+ * public/<id>/app.css Tailwind, if the app has src/styles/app.css
19
+ * public/<id>/... anything from <appDir>/public/
20
+ *
21
+ * If the app needs additional artefacts (core's global.css, logo, katex),
22
+ * it ships a `scripts/build-extras.ts` that this script runs at the end.
23
+ */
24
+ import { existsSync } from "node:fs";
25
+ import { cp, mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
26
+ import { dirname, extname, resolve } from "node:path";
27
+ import { fileURLToPath } from "node:url";
28
+ import { promisify } from "node:util";
29
+ import { brotliCompress, gzip, constants as zlibConstants } from "node:zlib";
30
+ import { CryptoHasher, Glob } from "bun";
31
+ import tailwind from "bun-plugin-tailwind";
32
+ import { writeAppFavicon } from "./app-favicon";
33
+
34
+ const appId = process.env.APP_ID;
35
+ if (!appId) throw new Error("APP_ID env var required");
36
+
37
+ // `root` = wherever the user is building from. SSR plugin's rootDir is
38
+ // process.cwd() (set in defineApp), so we use the same here for hash parity.
39
+ const root = process.cwd();
40
+
41
+ // Framework dir — works whether this script is in packages/cloud/scripts/
42
+ // (monorepo) or node_modules/@k2b/cloud/scripts/ (npm install).
43
+ const frameworkDir = resolve(dirname(fileURLToPath(import.meta.url)), "..");
44
+
45
+ const release = process.env.CLOUD_RELEASE?.trim() || "local";
46
+ if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(release)) {
47
+ throw new Error(`Invalid CLOUD_RELEASE: ${JSON.stringify(release)}`);
48
+ }
49
+ const syncPackagePath = Bun.resolveSync("@k2b/sync/package.json", frameworkDir);
50
+ const syncPackage = JSON.parse(await readFile(syncPackagePath, "utf8")) as {
51
+ version?: unknown;
52
+ };
53
+ if (typeof syncPackage.version !== "string" || !/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(syncPackage.version)) {
54
+ throw new Error("Could not resolve the installed @k2b/sync version");
55
+ }
56
+ const syncVersion = syncPackage.version;
57
+
58
+ // App dir — APP_DIR override for standalone consumers, defaults to monorepo
59
+ // convention. Resolved against cwd if relative.
60
+ const appDir = process.env.APP_DIR ? resolve(root, process.env.APP_DIR) : resolve(root, "packages", appId);
61
+ if (!existsSync(appDir)) throw new Error(`Unknown app dir: ${appDir} (set APP_DIR or check APP_ID)`);
62
+
63
+ const dist = resolve(root, "dist");
64
+ const distPublic = resolve(dist, "public");
65
+ const compressBrotli = promisify(brotliCompress);
66
+ const compressGzip = promisify(gzip);
67
+
68
+ await rm(dist, { recursive: true, force: true });
69
+ await mkdir(distPublic, { recursive: true });
70
+
71
+ // Mirrors @k2b/ssr's island-id (md5 of POSIX path relative to the
72
+ // SSR plugin's rootDir, truncated to 12 chars). Both this script and the
73
+ // plugin use process.cwd() as the rootDir, so hashes match.
74
+ const islandId = (file: string): string => {
75
+ const rel = file.slice(root.length + 1).replace(/\\/g, "/");
76
+ return new CryptoHasher("md5").update(rel).digest("hex").slice(0, 12);
77
+ };
78
+
79
+ const compressibleExtensions = new Set([".css", ".html", ".js", ".json", ".map", ".svg", ".txt", ".xml"]);
80
+
81
+ async function precompressDistAssets(dir: string): Promise<void> {
82
+ if (!existsSync(dir)) return;
83
+
84
+ for await (const file of new Glob("**/*").scan({ cwd: dir, absolute: true, onlyFiles: true })) {
85
+ if (file.endsWith(".br") || file.endsWith(".gz")) continue;
86
+ if (!compressibleExtensions.has(extname(file))) continue;
87
+
88
+ const source = await readFile(file);
89
+ const [br, gz] = await Promise.all([
90
+ compressBrotli(source, {
91
+ params: {
92
+ [zlibConstants.BROTLI_PARAM_QUALITY]: zlibConstants.BROTLI_MAX_QUALITY,
93
+ },
94
+ }),
95
+ compressGzip(source, { level: zlibConstants.Z_BEST_COMPRESSION }),
96
+ ]);
97
+
98
+ await Promise.all([writeFile(`${file}.br`, br), writeFile(`${file}.gz`, gz)]);
99
+ }
100
+ }
101
+
102
+ // Register the app's SSR plugin (Solid JSX transform + island bundler).
103
+ // In the monorepo this resolves via `packages/<id>/src/config`; in standalone
104
+ // it resolves via the appDir path (because the script's relative imports
105
+ // only work for monorepo, we use absolute file:// for standalone).
106
+ const configPath = resolve(appDir, "src/config");
107
+ const { app, plugin } = await import(configPath);
108
+
109
+ // 1. Server entry — also emits dist/_ssr/<island>.js via the SSR plugin.
110
+ // @peculiar/x509 uses tsyringe, whose decorators require this polyfill before
111
+ // any app dependency is evaluated. A wrapper keeps that ordering identical for
112
+ // every production app without requiring app-owned bootstrap imports.
113
+ const serverEntry = resolve(dist, ".server-entry.ts");
114
+ const reflectMetadata = Bun.resolveSync("reflect-metadata", frameworkDir);
115
+ await writeFile(
116
+ serverEntry,
117
+ `import ${JSON.stringify(reflectMetadata)};\nexport { default } from ${JSON.stringify(resolve(appDir, "src/index.ts"))};\n`,
118
+ );
119
+ let server: Awaited<ReturnType<typeof Bun.build>>;
120
+ try {
121
+ server = await Bun.build({
122
+ entrypoints: [serverEntry],
123
+ outdir: dist,
124
+ naming: "server.js",
125
+ target: "bun",
126
+ minify: true,
127
+ define: {
128
+ __CLOUD_RELEASE__: JSON.stringify(release),
129
+ __CLOUD_SYNC_VERSION__: JSON.stringify(syncVersion),
130
+ },
131
+ plugins: [plugin()],
132
+ });
133
+ } finally {
134
+ await rm(serverEntry, { force: true });
135
+ }
136
+ if (!server.success) {
137
+ for (const m of server.logs) console.error(m);
138
+ throw new Error("Server bundle failed");
139
+ }
140
+
141
+ // 1b. The SSR plugin scans the project root and emits one chunk per island
142
+ // across every reachable package (including any island-shaped files in
143
+ // other workspace packages or in node_modules). Keep only this app's own
144
+ // islands plus the framework's; drop the rest. chunk-* files are shared
145
+ // splits and always kept.
146
+ const ssrDir = resolve(dist, "_ssr");
147
+ if (existsSync(ssrDir)) {
148
+ const allowedDirs = [frameworkDir, appDir];
149
+ const allowedIds = new Set<string>();
150
+ for (const dir of allowedDirs) {
151
+ for await (const file of new Glob("**/*.{island,client}.tsx").scan({ cwd: dir, absolute: true })) {
152
+ allowedIds.add(islandId(file));
153
+ }
154
+ }
155
+ for (const entry of await readdir(ssrDir)) {
156
+ if (entry.startsWith("chunk-") || !entry.endsWith(".js")) continue;
157
+ const id = entry.slice(0, -3);
158
+ if (!allowedIds.has(id)) await rm(resolve(ssrDir, entry));
159
+ }
160
+ }
161
+
162
+ // 2. Per-app Tailwind stylesheet.
163
+ const appCss = resolve(appDir, "src/styles/app.css");
164
+ if (existsSync(appCss)) {
165
+ const out = resolve(distPublic, appId);
166
+ await mkdir(out, { recursive: true });
167
+ const css = await Bun.build({
168
+ entrypoints: [appCss],
169
+ outdir: out,
170
+ naming: "app.css",
171
+ root,
172
+ plugins: [tailwind],
173
+ });
174
+ if (!css.success) {
175
+ for (const m of css.logs) console.error(m);
176
+ throw new Error("App CSS build failed");
177
+ }
178
+ }
179
+
180
+ // 3. Per-app static assets.
181
+ const appPublic = resolve(appDir, "public");
182
+ if (existsSync(appPublic)) {
183
+ await cp(appPublic, resolve(distPublic, appId), { recursive: true });
184
+ }
185
+
186
+ if (appId !== "core" && app) {
187
+ await writeAppFavicon({
188
+ publicDir: distPublic,
189
+ appId,
190
+ icon: app.meta.icon,
191
+ });
192
+ }
193
+
194
+ // 4. Optional app-specific extras (e.g. core's global.css + logo + katex).
195
+ const extras = resolve(appDir, "scripts/build-extras.ts");
196
+ if (existsSync(extras)) {
197
+ process.env.WORKSPACE_ROOT = root;
198
+ process.env.DIST_DIR = dist;
199
+ await import(extras);
200
+ }
201
+
202
+ await precompressDistAssets(resolve(dist, "public"));
203
+ await precompressDistAssets(resolve(dist, "_ssr"));
204
+
205
+ console.log(`Built ${appId} → ${dist}`);