@k2b/cloud 0.6.0-rc.0 → 0.7.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 (315) hide show
  1. package/README.md +2 -2
  2. package/package.json +30 -17
  3. package/scripts/browser-performance.ts +14 -0
  4. package/scripts/build-pdf-renderer.ts +39 -0
  5. package/scripts/build.ts +15 -35
  6. package/scripts/preload.ts +9 -12
  7. package/scripts/sync-recovery-smoke.ts +2 -1
  8. package/src/_internal/app-presentation.ts +14 -2
  9. package/src/_internal/capabilities.ts +108 -7
  10. package/src/_internal/capability-streams.ts +81 -0
  11. package/src/_internal/define-app.ts +62 -36
  12. package/src/_internal/heartbeat.ts +4 -0
  13. package/src/_internal/help-catalog.ts +27 -172
  14. package/src/_internal/help.ts +13 -76
  15. package/src/_internal/page-responses.ts +2 -0
  16. package/src/_internal/postgres-application-name.ts +30 -0
  17. package/src/_internal/process-identity.ts +15 -0
  18. package/src/_internal/process-sync.ts +1 -1
  19. package/src/_internal/registry-validation.ts +29 -25
  20. package/src/_internal/registry.ts +2 -53
  21. package/src/_internal/runtime-context.ts +5 -16
  22. package/src/_internal/server-timing.ts +13 -0
  23. package/src/_internal/status-preserving-ssr.ts +18 -6
  24. package/src/_internal/web-vitals-asset.ts +10 -0
  25. package/src/access/PermissionEditor.tsx +14 -153
  26. package/src/access/PrincipalPicker.tsx +104 -0
  27. package/src/access/ui.ts +2 -0
  28. package/src/ai/admin.ts +14 -13
  29. package/src/ai/assistant-models.ts +12 -1
  30. package/src/ai/audio-format.ts +34 -0
  31. package/src/ai/audio-tool.ts +90 -0
  32. package/src/ai/browser-code-contracts.ts +79 -0
  33. package/src/ai/browser.ts +2 -0
  34. package/src/ai/capabilities.ts +55 -36
  35. package/src/ai/capability-execution.ts +47 -12
  36. package/src/ai/chat/blocks.tsx +157 -95
  37. package/src/ai/chat/capability-result.ts +15 -0
  38. package/src/ai/chat/capability-table.tsx +2 -10
  39. package/src/ai/chat/composer-adapter.ts +48 -3
  40. package/src/ai/chat/message-actions.tsx +8 -7
  41. package/src/ai/chat/message-utils.ts +12 -1
  42. package/src/ai/chat/messages.ts +2 -0
  43. package/src/ai/chat/presentation.tsx +19 -48
  44. package/src/ai/chat/primitives.tsx +43 -1
  45. package/src/ai/chat/tool-disclosure.tsx +17 -2
  46. package/src/ai/chat/tool-groups.ts +52 -0
  47. package/src/ai/chat-quotas.ts +25 -0
  48. package/src/ai/chat-task-contracts.ts +9 -1
  49. package/src/ai/chat-tasks.ts +276 -43
  50. package/src/ai/client/controller.ts +110 -33
  51. package/src/ai/client/file-source.ts +12 -6
  52. package/src/ai/client/live-connection.ts +1 -0
  53. package/src/ai/client/projection.ts +22 -11
  54. package/src/ai/client/transport.ts +4 -0
  55. package/src/ai/code-capability-routes.ts +110 -0
  56. package/src/ai/code-capability-transport.ts +38 -0
  57. package/src/ai/code-mode-skill.ts +114 -0
  58. package/src/ai/code-runtime-tools.ts +166 -0
  59. package/src/ai/code-source-contracts.ts +202 -0
  60. package/src/ai/code-source-tools.ts +145 -0
  61. package/src/ai/compaction.ts +27 -6
  62. package/src/ai/data-analysis-skill.ts +10 -0
  63. package/src/ai/default-tools.ts +25 -2
  64. package/src/ai/dictation-runtime.ts +171 -0
  65. package/src/ai/dictations.ts +188 -0
  66. package/src/ai/draft-content.ts +34 -0
  67. package/src/ai/enrich.ts +6 -0
  68. package/src/ai/executor.ts +191 -31
  69. package/src/ai/file-content-version.ts +22 -0
  70. package/src/ai/file-context.ts +2 -1
  71. package/src/ai/file-media-type.ts +12 -0
  72. package/src/ai/file-reference-contracts.ts +15 -0
  73. package/src/ai/file-tools.ts +2 -1
  74. package/src/ai/files-store.ts +174 -71
  75. package/src/ai/fixtures/vision-encrypted.pdf +0 -0
  76. package/src/ai/grids-skill.ts +40 -10
  77. package/src/ai/http.ts +15 -8
  78. package/src/ai/index.ts +26 -2
  79. package/src/ai/inference-calls.ts +198 -0
  80. package/src/ai/live-events.ts +5 -1
  81. package/src/ai/memory-learning.ts +60 -28
  82. package/src/ai/message-queue.ts +167 -0
  83. package/src/ai/migrate.ts +187 -11
  84. package/src/ai/model-pricing.ts +43 -0
  85. package/src/ai/pdf-render-worker.ts +74 -0
  86. package/src/ai/pdf-render.fixture.ts +28 -0
  87. package/src/ai/pdf-render.ts +77 -0
  88. package/src/ai/projects-routes.ts +3 -3
  89. package/src/ai/projects.ts +20 -6
  90. package/src/ai/protocol.ts +3 -0
  91. package/src/ai/provider.ts +1 -8
  92. package/src/ai/quota-provider.ts +191 -0
  93. package/src/ai/quota-report.ts +152 -0
  94. package/src/ai/quotas-migrate.ts +45 -0
  95. package/src/ai/quotas.ts +168 -0
  96. package/src/ai/routes.ts +215 -11
  97. package/src/ai/run-timeout.ts +10 -0
  98. package/src/ai/runtime-tools.ts +3 -0
  99. package/src/ai/runtime.ts +55 -16
  100. package/src/ai/settings.ts +36 -8
  101. package/src/ai/short-id.ts +2 -2
  102. package/src/ai/skill-catalog.ts +0 -10
  103. package/src/ai/skill-search.ts +47 -0
  104. package/src/ai/skill-seeds.ts +105 -20
  105. package/src/ai/skill-tool.ts +16 -5
  106. package/src/ai/skills-routes.ts +32 -4
  107. package/src/ai/skills.ts +324 -155
  108. package/src/ai/store.ts +373 -191
  109. package/src/ai/stream.ts +5 -0
  110. package/src/ai/structured-runs.ts +4 -3
  111. package/src/ai/structured.ts +8 -1
  112. package/src/ai/system-prompt.ts +12 -2
  113. package/src/ai/timeline.ts +2 -5
  114. package/src/ai/todo-contracts.ts +20 -0
  115. package/src/ai/todo-tool.ts +16 -0
  116. package/src/ai/tool-audit.ts +30 -40
  117. package/src/ai/tools.ts +6 -0
  118. package/src/ai/transcription.ts +202 -0
  119. package/src/ai/turn-timing.ts +114 -0
  120. package/src/ai/types.ts +58 -10
  121. package/src/ai/ui.tsx +2 -0
  122. package/src/ai/usage.ts +118 -118
  123. package/src/ai/vision-tool.ts +39 -10
  124. package/src/api/admin-ai-projects.ts +2 -2
  125. package/src/api/admin-ai-quotas.ts +74 -0
  126. package/src/api/admin-ai-skills.ts +48 -5
  127. package/src/api/admin-ai-usage.ts +2 -2
  128. package/src/api/admin-core-settings.ts +25 -0
  129. package/src/api/admin-identity.ts +91 -51
  130. package/src/api/admin-rail.ts +58 -0
  131. package/src/api/announcements.ts +14 -0
  132. package/src/api/capabilities.ts +292 -43
  133. package/src/api/capability-streams.ts +262 -0
  134. package/src/api/help.ts +8 -44
  135. package/src/api/index.ts +6 -0
  136. package/src/api/mcp.ts +44 -26
  137. package/src/api/me-web-vitals.ts +35 -0
  138. package/src/api/me.ts +2 -0
  139. package/src/api/search/schemas.ts +26 -15
  140. package/src/api/search.bench.ts +1 -1
  141. package/src/api/search.ts +54 -17
  142. package/src/browser/CloudResourceSearch.tsx +640 -702
  143. package/src/browser/app-approval-vault.ts +19 -7
  144. package/src/browser/command-bridge.ts +109 -0
  145. package/src/browser/command-shortcuts.ts +76 -0
  146. package/src/browser/commands.ts +66 -0
  147. package/src/browser/navigation-search.ts +48 -0
  148. package/src/browser/notifications.ts +1 -1
  149. package/src/browser/resource-picker.tsx +5 -18
  150. package/src/browser/resource-search-dialog.ts +9 -0
  151. package/src/browser/resource-search-input.ts +46 -0
  152. package/src/browser/resource-search-messages.ts +76 -40
  153. package/src/browser/resource-search.ts +7 -0
  154. package/src/browser/search-bridge.ts +102 -0
  155. package/src/browser/search-commands.ts +59 -0
  156. package/src/browser/search.ts +13 -0
  157. package/src/browser/spotlight-position.ts +208 -0
  158. package/src/browser/testing.ts +5 -0
  159. package/src/browser/web-vitals.ts +25 -0
  160. package/src/capabilities/claims.ts +179 -0
  161. package/src/capabilities/client.ts +34 -0
  162. package/src/capabilities/command-link.ts +16 -0
  163. package/src/capabilities/executions.ts +298 -0
  164. package/src/capabilities/migrate.ts +81 -0
  165. package/src/capabilities/server.ts +114 -34
  166. package/src/capabilities/stream-body.ts +16 -0
  167. package/src/capabilities/streams.ts +28 -0
  168. package/src/cli/admin/ai-quotas.ts +161 -0
  169. package/src/cli/admin/ai-skills.ts +64 -0
  170. package/src/cli/admin/ai-usage.ts +53 -30
  171. package/src/cli/admin/app-credentials.ts +79 -0
  172. package/src/cli/admin/data.ts +17 -0
  173. package/src/cli/admin/index.ts +9 -0
  174. package/src/cli/capabilities.ts +29 -0
  175. package/src/cli/capability-streams.ts +25 -0
  176. package/src/cli/index.ts +3 -2
  177. package/src/config/env.ts +11 -8
  178. package/src/contracts/app.ts +23 -3
  179. package/src/contracts/capabilities.ts +68 -5
  180. package/src/contracts/capability-streams.ts +46 -0
  181. package/src/contracts/commands.ts +49 -0
  182. package/src/contracts/index.ts +6 -1
  183. package/src/contracts/rail-admin.ts +38 -0
  184. package/src/contracts/rail-preferences.ts +16 -0
  185. package/src/contracts/registry.ts +3 -27
  186. package/src/contracts/settings-types.ts +1 -1
  187. package/src/contracts/shared.ts +9 -5
  188. package/src/contracts/web-vitals.ts +27 -0
  189. package/src/desktop/solid.tsx +3 -3
  190. package/src/index.ts +0 -4
  191. package/src/server/index.ts +3 -0
  192. package/src/server/middleware/auth.ts +3 -2
  193. package/src/server/middleware/route-template.ts +9 -3
  194. package/src/server/middleware/runtime.ts +2 -1
  195. package/src/server/middleware/settings.ts +17 -11
  196. package/src/server/services/access-revision.ts +10 -0
  197. package/src/server/services/access.ts +1 -1
  198. package/src/server/services/index.ts +1 -0
  199. package/src/services/account-category-policy.ts +9 -0
  200. package/src/services/account-lifecycle/audit.ts +1 -1
  201. package/src/services/accounts/app.ts +12 -2
  202. package/src/services/accounts/email-write.ts +23 -0
  203. package/src/services/accounts/groups.ts +15 -4
  204. package/src/services/accounts/identities.ts +249 -0
  205. package/src/services/accounts/identity-reconciliation.ts +87 -0
  206. package/src/services/accounts/ipa-data.ts +2 -2
  207. package/src/services/accounts/local-groups.ts +2 -2
  208. package/src/services/accounts/posix.ts +45 -29
  209. package/src/services/accounts/users.ts +2 -2
  210. package/src/services/announcements/index.ts +69 -8
  211. package/src/services/audit/index.ts +1 -1
  212. package/src/services/cache-fill.ts +35 -0
  213. package/src/services/help/index.ts +109 -0
  214. package/src/services/help/maintenance.ts +25 -0
  215. package/src/services/help/store.ts +180 -0
  216. package/src/services/help/types.ts +46 -0
  217. package/src/services/identity/invocation-actor.ts +2 -2
  218. package/src/services/identity/key-config.ts +2 -1
  219. package/src/services/identity/key-ring.ts +1 -1
  220. package/src/services/index.ts +15 -0
  221. package/src/services/ipa/users.ts +268 -221
  222. package/src/services/legal-consent.ts +1 -1
  223. package/src/services/logging/index.ts +15 -13
  224. package/src/services/logging/trace.ts +2 -1
  225. package/src/services/logging/web-vitals.ts +81 -0
  226. package/src/services/mandates/index.ts +18 -4
  227. package/src/services/mandates/policy.ts +65 -2
  228. package/src/services/notifications/batches.ts +124 -57
  229. package/src/services/notifications/browser.ts +12 -0
  230. package/src/services/notifications/index.ts +0 -2
  231. package/src/services/notifications/platform.ts +0 -4
  232. package/src/services/oauth-tokens.ts +3 -3
  233. package/src/services/pdf/gotenberg.ts +107 -84
  234. package/src/services/pdf/index.ts +3 -0
  235. package/src/services/providers/local/users.ts +25 -16
  236. package/src/services/public-http.ts +101 -0
  237. package/src/services/rail-shortcuts.ts +95 -0
  238. package/src/services/rail-snapshot.ts +53 -0
  239. package/src/services/request-cache-redis.ts +28 -0
  240. package/src/services/session/index.ts +15 -2
  241. package/src/services/session/user.ts +62 -37
  242. package/src/services/settings/core-settings.ts +21 -28
  243. package/src/services/settings/defaults.ts +5 -0
  244. package/src/services/settings/store.ts +58 -84
  245. package/src/shared/ai-costs.ts +42 -0
  246. package/src/shared/ai-platform-prompt.ts +1 -1
  247. package/src/shared/ai-quotas.ts +136 -0
  248. package/src/shared/ai-usage.ts +6 -16
  249. package/src/shared/app-presentation.ts +21 -15
  250. package/src/shared/capability-messages.ts +14 -0
  251. package/src/shared/help.ts +6 -42
  252. package/src/shared/index.ts +6 -0
  253. package/src/ssr/AdminLayout.tsx +7 -5
  254. package/src/ssr/AdminSidebar.tsx +29 -15
  255. package/src/ssr/AppLaunchpad.island.tsx +24 -137
  256. package/src/ssr/AppLaunchpadPanel.tsx +181 -0
  257. package/src/ssr/BrowserPushRegistration.island.tsx +12 -0
  258. package/src/ssr/GlobalSearchDialog.tsx +167 -20
  259. package/src/ssr/GlobalSearchTrigger.island.tsx +33 -22
  260. package/src/ssr/Layout.tsx +17 -6
  261. package/src/ssr/LayoutBreadcrumbs.island.tsx +3 -5
  262. package/src/ssr/LayoutFooter.tsx +1 -1
  263. package/src/ssr/LayoutHeader.tsx +46 -14
  264. package/src/ssr/LayoutHelp.tsx +23 -22
  265. package/src/ssr/{HotkeysHelpRail.island.tsx → LayoutHelpTrigger.island.tsx} +18 -12
  266. package/src/ssr/LayoutRail.tsx +17 -9
  267. package/src/ssr/MobileNavigation.tsx +71 -0
  268. package/src/ssr/MobileProfileActions.tsx +49 -0
  269. package/src/ssr/ProfilePreferences.island.tsx +3 -36
  270. package/src/ssr/RailApps.island.tsx +2 -2
  271. package/src/ssr/RailEditor.tsx +17 -2
  272. package/src/ssr/WorkspaceNavigation.island.tsx +7 -0
  273. package/src/ssr/WorkspaceNavigationProvider.tsx +16 -0
  274. package/src/ssr/admin-navigation.ts +7 -1
  275. package/src/ssr/help.ts +29 -0
  276. package/src/ssr/islands/SearchBar.tsx +67 -0
  277. package/src/ssr/islands/index.ts +3 -1
  278. package/src/ssr/layout-context.ts +2 -2
  279. package/src/ssr/layout-help-search.ts +15 -0
  280. package/src/ssr/mobile-menu-history.ts +70 -0
  281. package/src/ssr/platform-messages.ts +16 -8
  282. package/src/ssr/profile-actions.ts +42 -0
  283. package/src/ssr/rail-context.ts +8 -4
  284. package/src/ssr/rail-messages.ts +2 -0
  285. package/src/ssr/rail-navigation.ts +3 -3
  286. package/src/ssr/workspace-navigation.ts +75 -0
  287. package/src/styles/effects.css +6 -6
  288. package/src/styles/global.css +54 -0
  289. package/src/styles/input.css +43 -41
  290. package/src/styles/resource-search.css +505 -0
  291. package/src/styles/utilities-feedback.css +13 -0
  292. package/src/styles/utilities-layout.css +1 -5
  293. package/src/styles/utilities-navigation.css +3 -39
  294. package/src/types/ambient.d.ts +5 -0
  295. package/src/workflows/ai/runtime.ts +5 -1
  296. package/src/workflows/ai/store.ts +2 -0
  297. package/src/workflows/ai-actions.ts +16 -13
  298. package/src/workflows/definition.ts +10 -5
  299. package/src/workflows/store/actions.ts +44 -20
  300. package/src/workflows/store/index.ts +2 -0
  301. package/src/workflows/store/runs.ts +36 -0
  302. package/src/workflows/store/worker-pool.ts +55 -0
  303. package/src/workflows/store/worker-runtime.ts +90 -0
  304. package/scripts/app-favicon.test.ts +0 -49
  305. package/src/ai/chat/blocks.render.test.tsx +0 -1108
  306. package/src/ai/kit-skill.ts +0 -22
  307. package/src/ai/usage-migrate.ts +0 -81
  308. package/src/browser/CloudResourceSearch.behavior.test.tsx +0 -74
  309. package/src/browser/notification-target.ts +0 -27
  310. package/src/contracts/notification-live.ts +0 -66
  311. package/src/services/notifications/live.ts +0 -50
  312. package/src/ssr/BrowserNotifications.island.tsx +0 -135
  313. package/src/ssr/GlobalSearchDialog.behavior.test.tsx +0 -96
  314. package/src/ssr/Layout.render.test.tsx +0 -148
  315. package/src/ssr/islands/SearchBar.island.tsx +0 -80
package/README.md CHANGED
@@ -78,9 +78,9 @@ A standard app declares four prefixes (`/api/<id>`, `/app/<id>`, `/admin/<id>`,
78
78
 
79
79
  ## Documentation
80
80
 
81
- Full walkthroughs, the per-app anatomy, deployment templates, and a reference app:
81
+ Application setup, public contracts, and deployment guidance:
82
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
83
+ - **[Create the first application](https://github.com/k2b-dev/cloud/blob/main/docs-site/docs/en/build/getting-started.md)** — standalone project setup and a verified API endpoint
84
84
  - **[github.com/k2b-dev/cloud](https://github.com/k2b-dev/cloud)** — the platform monorepo (gateway, core, all platform apps)
85
85
 
86
86
  ## License
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k2b/cloud",
3
- "version": "0.6.0-rc.0",
3
+ "version": "0.7.0",
4
4
  "description": "Modular Hono+SolidJS framework for building per-app docker services behind a dynamic gateway. Powers cloud.stuve-ulm.de.",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "repository": {
@@ -16,7 +16,10 @@
16
16
  "scripts",
17
17
  "public",
18
18
  "!src/**/*.test.ts",
19
- "!src/**/*.integration.test.ts"
19
+ "!src/**/*.test.tsx",
20
+ "!src/**/*.integration.test.ts",
21
+ "!scripts/**/*.test.ts",
22
+ "!scripts/runtime-recovery-*.ts"
20
23
  ],
21
24
  "exports": {
22
25
  ".": "./src/index.ts",
@@ -29,9 +32,13 @@
29
32
  "./browser/live": "./src/browser/live-websocket.ts",
30
33
  "./browser/notifications": "./src/browser/notifications.ts",
31
34
  "./browser/resource-clipboard": "./src/browser/resource-clipboard.ts",
35
+ "./browser/commands": "./src/browser/commands.ts",
36
+ "./browser/search": "./src/browser/search.ts",
37
+ "./browser/testing": "./src/browser/testing.ts",
32
38
  "./browser/resource-picker": "./src/browser/resource-picker.tsx",
33
39
  "./capabilities": "./src/capabilities/client.ts",
34
40
  "./capabilities/server": "./src/capabilities/server.ts",
41
+ "./capabilities/store": "./src/capabilities/executions.ts",
35
42
  "./capabilities/testing": "./src/capabilities/testing.ts",
36
43
  "./cli": "./src/cli/index.ts",
37
44
  "./cli/access": "./src/cli/access.ts",
@@ -57,6 +64,7 @@
57
64
  "./access/ui": "./src/access/ui.ts",
58
65
  "./ssr": "./src/ssr/index.ts",
59
66
  "./ssr/islands": "./src/ssr/islands/index.ts",
67
+ "./ssr/WorkspaceNavigation.island": "./src/ssr/WorkspaceNavigation.island.tsx",
60
68
  "./ssr/*": "./src/ssr/*",
61
69
  "./config": "./src/config/index.ts",
62
70
  "./config/*": "./src/config/*",
@@ -75,23 +83,26 @@
75
83
  "./styles/global.css": "./src/styles/global.css"
76
84
  },
77
85
  "scripts": {
78
- "test": "bun test",
86
+ "test": "bun test --isolate --path-ignore-patterns '**/*.behavior.test.tsx' --path-ignore-patterns '**/*.dom.test.tsx' && bun run test:dom",
87
+ "test:dom": "bun test --isolate --conditions=browser --preload ../ui/test/solid-dom-preload.ts behavior.test.tsx dom.test.tsx",
79
88
  "typecheck": "tsc -p tsconfig.json --noEmit --pretty false 2>&1 | grep -v node_modules | (! grep -q 'error TS')"
80
89
  },
81
90
  "dependencies": {
82
91
  "@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",
92
+ "@napi-rs/canvas": "1.0.8",
93
+ "pdfjs-dist": "6.3.289",
94
+ "@hono/standard-validator": "0.2.2",
90
95
  "@simplewebauthn/server": "13.3.2",
91
96
  "@tabler/icons": "3.46.0",
92
97
  "@tailwindcss/typography": "0.5.20",
98
+ "@k2b/nessi": "0.12.0",
99
+ "@k2b/ssr": "0.14.0",
100
+ "@k2b/ui": "0.3.0",
101
+ "@k2b/stdlib": "0.25.0",
102
+ "@k2b/sync": "6.4.0",
103
+ "@nats-io/transport-node": "3.4.0",
104
+ "@modelcontextprotocol/sdk": "1.30.0",
93
105
  "bun-plugin-tailwind": "0.1.2",
94
- "hash-wasm": "4.12.0",
95
106
  "hono-openapi": "1.3.1",
96
107
  "jose": "6.2.5",
97
108
  "katex": "0.16.47",
@@ -105,20 +116,22 @@
105
116
  "seroval": "1.6.0",
106
117
  "tailwindcss": "4.3.3",
107
118
  "web-push": "3.6.7",
108
- "yaml": "2.9.0"
119
+ "web-vitals": "6.2.1",
120
+ "yaml": "2.9.0",
121
+ "hash-wasm": "4.12.0",
122
+ "@types/nodemailer": "7.0.12",
123
+ "@types/sanitize-html": "2.16.1",
124
+ "@types/web-push": "3.6.4"
109
125
  },
110
126
  "devDependencies": {
111
127
  "@babel/core": "7.29.7",
112
128
  "@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",
129
+ "@types/bun": "1.4.2",
117
130
  "babel-preset-solid": "1.9.12",
118
131
  "hono": "4.12.32",
119
132
  "solid-js": "1.9.14",
120
133
  "typescript": "5.9.3",
121
- "zod": "4.4.3"
134
+ "zod": "4.6.2"
122
135
  },
123
136
  "peerDependencies": {
124
137
  "hono": "^4.12.25",
@@ -0,0 +1,14 @@
1
+ import { resolve } from "node:path";
2
+ import { WEB_VITALS_ASSET_NAME } from "../src/_internal/web-vitals-asset";
3
+
4
+ export async function buildBrowserPerformance(publicDir: string, appId: string): Promise<void> {
5
+ if (appId !== "core") return;
6
+ const result = await Bun.build({
7
+ entrypoints: [resolve(import.meta.dir, "../src/browser/web-vitals.ts")],
8
+ outdir: publicDir,
9
+ naming: WEB_VITALS_ASSET_NAME,
10
+ target: "browser",
11
+ minify: true,
12
+ });
13
+ if (!result.success) throw new AggregateError(result.logs, "Browser performance build failed");
14
+ }
@@ -0,0 +1,39 @@
1
+ import { cp, mkdir } from "node:fs/promises";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { z } from "zod";
5
+
6
+ /** Package the decoder and native assets only for bundles importing PDF vision. */
7
+ export async function buildPdfRenderer(dist: string) {
8
+ const framework = resolve(dirname(fileURLToPath(import.meta.url)), "..");
9
+ const out = resolve(dist, "pdf-render");
10
+ await mkdir(out, { recursive: true });
11
+ const worker = await Bun.build({
12
+ entrypoints: [resolve(framework, "src/ai/pdf-render-worker.ts")],
13
+ target: "bun",
14
+ outdir: out,
15
+ naming: "worker.js",
16
+ external: ["pdfjs-dist", "@napi-rs/canvas"],
17
+ });
18
+ if (!worker.success) throw new Error(`PDF decoder build failed: ${worker.logs.join("\n")}`);
19
+ for (const name of ["pdfjs-dist", "@napi-rs/canvas"]) {
20
+ const source = dirname(Bun.resolveSync(`${name}/package.json`, framework));
21
+ await cp(source, resolve(out, "node_modules", name), { recursive: true, dereference: true });
22
+ if (name !== "@napi-rs/canvas") continue;
23
+ const manifest = z
24
+ .object({ optionalDependencies: z.record(z.string(), z.string()) })
25
+ .parse(await Bun.file(resolve(source, "package.json")).json());
26
+ let nativePackages = 0;
27
+ for (const dependency of Object.keys(manifest.optionalDependencies)) {
28
+ let location: string;
29
+ try {
30
+ location = dirname(Bun.resolveSync(`${dependency}/package.json`, source));
31
+ } catch {
32
+ continue;
33
+ } // Only the installed target-platform binary is needed.
34
+ await cp(location, resolve(out, "node_modules", dependency), { recursive: true, dereference: true });
35
+ nativePackages++;
36
+ }
37
+ if (!nativePackages) throw new Error("PDF decoder needs an installed native canvas binary for the build platform.");
38
+ }
39
+ }
package/scripts/build.ts CHANGED
@@ -4,11 +4,11 @@
4
4
  * Two consumer shapes:
5
5
  *
6
6
  * Monorepo (this repo):
7
- * APP_ID=<id> bun run packages/cloud/scripts/build.ts
7
+ * NODE_ENV=production APP_ID=<id> bun run packages/cloud/scripts/build.ts
8
8
  * # appDir defaults to packages/<APP_ID>, run from workspace root.
9
9
  *
10
10
  * Standalone (npm consumer, see cloud-template):
11
- * APP_ID=<id> APP_DIR=. bun run node_modules/@k2b/cloud/scripts/build.ts
11
+ * NODE_ENV=production APP_ID=<id> APP_DIR=. bun run node_modules/@k2b/cloud/scripts/build.ts
12
12
  * # appDir = APP_DIR (resolved against cwd) and must be the directory
13
13
  * # that CONTAINS src/, since entrypoints resolve to <appDir>/src/*.
14
14
  *
@@ -22,20 +22,21 @@
22
22
  * it ships a `scripts/build-extras.ts` that this script runs at the end.
23
23
  */
24
24
  import { existsSync } from "node:fs";
25
- import { cp, mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
25
+ import { cp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
26
26
  import { dirname, extname, resolve } from "node:path";
27
27
  import { fileURLToPath } from "node:url";
28
28
  import { promisify } from "node:util";
29
29
  import { brotliCompress, gzip, constants as zlibConstants } from "node:zlib";
30
- import { CryptoHasher, Glob } from "bun";
30
+ import { Glob } from "bun";
31
31
  import tailwind from "bun-plugin-tailwind";
32
32
  import { writeAppFavicon } from "./app-favicon";
33
+ import { buildBrowserPerformance } from "./browser-performance";
34
+ import { buildPdfRenderer } from "./build-pdf-renderer";
33
35
 
34
36
  const appId = process.env.APP_ID;
35
37
  if (!appId) throw new Error("APP_ID env var required");
36
38
 
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
+ // Build output is relative to the consuming project, including npm consumers.
39
40
  const root = process.cwd();
40
41
 
41
42
  // Framework dir — works whether this script is in packages/cloud/scripts/
@@ -59,6 +60,8 @@ const syncVersion = syncPackage.version;
59
60
  // convention. Resolved against cwd if relative.
60
61
  const appDir = process.env.APP_DIR ? resolve(root, process.env.APP_DIR) : resolve(root, "packages", appId);
61
62
  if (!existsSync(appDir)) throw new Error(`Unknown app dir: ${appDir} (set APP_DIR or check APP_ID)`);
63
+ // Share the resolved source directory with defineApp before importing config.
64
+ process.env.APP_DIR = appDir;
62
65
 
63
66
  const dist = resolve(root, "dist");
64
67
  const distPublic = resolve(dist, "public");
@@ -68,14 +71,6 @@ const compressGzip = promisify(gzip);
68
71
  await rm(dist, { recursive: true, force: true });
69
72
  await mkdir(distPublic, { recursive: true });
70
73
 
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
74
  const compressibleExtensions = new Set([".css", ".html", ".js", ".json", ".map", ".svg", ".txt", ".xml"]);
80
75
 
81
76
  async function precompressDistAssets(dir: string): Promise<void> {
@@ -124,11 +119,13 @@ try {
124
119
  naming: "server.js",
125
120
  target: "bun",
126
121
  minify: true,
122
+ metafile: true,
127
123
  define: {
128
124
  __CLOUD_RELEASE__: JSON.stringify(release),
129
125
  __CLOUD_SYNC_VERSION__: JSON.stringify(syncVersion),
126
+ __CLOUD_PDF_RENDER_WORKER__: JSON.stringify("./pdf-render/worker.js"),
130
127
  },
131
- plugins: [plugin()],
128
+ plugins: [(app?.plugin ?? plugin)()],
132
129
  });
133
130
  } finally {
134
131
  await rm(serverEntry, { force: true });
@@ -137,26 +134,8 @@ if (!server.success) {
137
134
  for (const m of server.logs) console.error(m);
138
135
  throw new Error("Server bundle failed");
139
136
  }
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
- }
137
+ if (Object.keys(server.metafile?.inputs ?? {}).some(path => path.endsWith("/ai/pdf-render.ts"))) {
138
+ await buildPdfRenderer(dist);
160
139
  }
161
140
 
162
141
  // 2. Per-app Tailwind stylesheet.
@@ -199,6 +178,7 @@ if (existsSync(extras)) {
199
178
  await import(extras);
200
179
  }
201
180
 
181
+ await buildBrowserPerformance(distPublic, appId);
202
182
  await precompressDistAssets(resolve(dist, "public"));
203
183
  await precompressDistAssets(resolve(dist, "_ssr"));
204
184
 
@@ -23,6 +23,7 @@ import { dirname, resolve } from "node:path";
23
23
  import { fileURLToPath } from "node:url";
24
24
  import tailwind from "bun-plugin-tailwind";
25
25
  import { writeAppFavicon } from "./app-favicon";
26
+ import { buildBrowserPerformance } from "./browser-performance";
26
27
 
27
28
  const appId = process.env.APP_ID ?? "core";
28
29
 
@@ -38,9 +39,11 @@ const frameworkDir = resolve(dirname(fileURLToPath(import.meta.url)), "..");
38
39
  // convention. Resolved against cwd if relative.
39
40
  const appDir = process.env.APP_DIR ? resolve(root, process.env.APP_DIR) : resolve(root, "packages", appId);
40
41
  if (!existsSync(appDir)) throw new Error(`Unknown app dir: ${appDir} (set APP_DIR or check APP_ID)`);
42
+ // Share the resolved source directory with defineApp before importing config.
43
+ process.env.APP_DIR = appDir;
41
44
 
42
45
  const { app, plugin } = await import(resolve(appDir, "src/config"));
43
- Bun.plugin(plugin());
46
+ Bun.plugin((app?.plugin ?? plugin)());
44
47
 
45
48
  // ── Build CSS ───────────────────────────────────────────────────────────────
46
49
  const publicDir = resolve(root, "public");
@@ -125,15 +128,6 @@ if (appId === "core" && existsSync(globalCssEntry)) {
125
128
  await cp(resolve(frameworkDir, "public/logo.svg"), resolve(publicDir, "logo.svg"));
126
129
  }
127
130
 
128
- // katex.css is only needed by notebooks (served by core via Traefik /public/katex.css)
129
- if (appId === "notebooks") {
130
- try {
131
- await cp(resolve(root, "node_modules/katex/dist/katex.min.css"), resolve(publicDir, "katex.css"));
132
- } catch {
133
- console.warn("[preload] katex.css not found, skipping");
134
- }
135
- }
136
-
137
131
  // Each app builds its own app.css
138
132
  const appPublicDir = resolve(publicDir, appId);
139
133
  await mkdir(appPublicDir, { recursive: true });
@@ -146,9 +140,12 @@ if (appId !== "core" && app) {
146
140
  });
147
141
  }
148
142
 
149
- await buildAppCss();
143
+ if (existsSync(appCssPath)) {
144
+ await buildAppCss();
145
+ watchDevCss("app.css", [resolve(appCssPath, "..")], buildAppCss);
146
+ }
147
+ await buildBrowserPerformance(publicDir, appId);
150
148
 
151
- watchDevCss("app.css", [resolve(appCssPath, "..")], buildAppCss);
152
149
  if (appId === "core" && existsSync(globalCssEntry)) {
153
150
  watchDevCss("global.css", [globalCssEntry, resolve(frameworkDir, "src/styles")], buildGlobalCss);
154
151
  }
@@ -7,6 +7,7 @@
7
7
  * No provider or application-domain effects; successful recovery deletes only
8
8
  * the exact test streams after checking their broker identity metadata.
9
9
  */
10
+ import { env } from "../src/config/env";
10
11
  import { createSync, type SyncResourceSummary, type Worker } from "@k2b/sync";
11
12
  import { connect, type NatsConnection } from "@nats-io/transport-node";
12
13
 
@@ -57,7 +58,7 @@ export const main = async (): Promise<void> => {
57
58
  .map((value) => value.trim())
58
59
  .filter(Boolean);
59
60
  const connection = await connect({ servers, name: `${APPLICATION}-${phase}`, ignoreClusterUpdates: true });
60
- const sync = createSync({ connection, namespace, application: APPLICATION, defaults: { replicas: 3 } });
61
+ const sync = createSync({ connection, namespace, application: APPLICATION, defaults: { replicas: env.SYNC_REPLICAS } });
61
62
  const job = sync.job<{ preparedAt: string }>({
62
63
  id: JOB_ID,
63
64
  delivery: { ackWaitMs: 30_000, maxAttempts: 3, backoffMs: [1_000, 2_000] },
@@ -11,12 +11,12 @@ const text = (value: string, label: string, max = MAX_SHORT_TEXT): string => {
11
11
  return normalized;
12
12
  };
13
13
 
14
- const labels = (values: Readonly<Record<string, string>> | undefined, allowed: Set<string>, label: string) => {
14
+ const labels = (values: Readonly<Record<string, string>> | undefined, allowed: Set<string>, label: string, max = MAX_SHORT_TEXT) => {
15
15
  if (!values) return undefined;
16
16
  const normalized: Record<string, string> = {};
17
17
  for (const [key, value] of Object.entries(values)) {
18
18
  if (!allowed.has(key)) throw new Error(`${label} contains unknown key ${JSON.stringify(key)}`);
19
- normalized[key] = text(value, `${label}.${key}`);
19
+ normalized[key] = text(value, `${label}.${key}`, max);
20
20
  }
21
21
  return normalized;
22
22
  };
@@ -34,6 +34,7 @@ export const compileAppPresentation = (app: AppMeta, catalog: AppPresentationCat
34
34
  groupIds.add(group.id);
35
35
  }
36
36
  const adminHrefs = new Set((app.adminNav ?? []).flatMap((group) => group.links.map((link) => link.href)));
37
+ const searchHrefs = new Set((app.searchLinks ?? []).map((link) => link.href));
37
38
  const legalHrefs = new Set((app.legalLinks ?? []).map((link) => link.href));
38
39
  const translations: Record<string, AppPresentationTranslation> = {};
39
40
 
@@ -49,6 +50,17 @@ export const compileAppPresentation = (app: AppMeta, catalog: AppPresentationCat
49
50
  : {}),
50
51
  ...(translation.adminGroups ? { adminGroups: labels(translation.adminGroups, groupIds, `${canonical}.adminGroups`) } : {}),
51
52
  ...(translation.adminLinks ? { adminLinks: labels(translation.adminLinks, adminHrefs, `${canonical}.adminLinks`) } : {}),
53
+ ...(translation.searchLinks ? { searchLinks: labels(translation.searchLinks, searchHrefs, `${canonical}.searchLinks`) } : {}),
54
+ ...(translation.searchLinkDescriptions
55
+ ? {
56
+ searchLinkDescriptions: labels(
57
+ translation.searchLinkDescriptions,
58
+ searchHrefs,
59
+ `${canonical}.searchLinkDescriptions`,
60
+ MAX_DESCRIPTION,
61
+ ),
62
+ }
63
+ : {}),
52
64
  ...(translation.legalLinks ? { legalLinks: labels(translation.legalLinks, legalHrefs, `${canonical}.legalLinks`) } : {}),
53
65
  };
54
66
  }