@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
@@ -0,0 +1,263 @@
1
+ import { sql } from "bun";
2
+ import type { MutationResult, UserProfile } from "../../../contracts/shared";
3
+ import { isAccountCategoryAllowed } from "../../account-category-policy";
4
+ import { writeDeletedAccountAudit } from "../../account-lifecycle/audit";
5
+ import { resolveStoredAdminState } from "../../accounts/model";
6
+ import { writeLocalAccount } from "../../accounts/posix";
7
+ import type { AuditActor } from "../../audit";
8
+ import { generateUniqueAbbreviation } from "../../ipa/users";
9
+ import { isUniqueViolation } from "../../postgres";
10
+ import { session } from "../../session";
11
+ import * as settings from "../../settings";
12
+
13
+ type DbRow = Record<string, unknown>;
14
+
15
+ export type LocalUserCreateData = {
16
+ email: string;
17
+ givenname?: string;
18
+ sn?: string;
19
+ displayName?: string;
20
+ };
21
+
22
+ const createLocalUid = async (): Promise<string> => {
23
+ const abbrLen = await settings.get<number>("user.abbr_length");
24
+ return generateUniqueAbbreviation(abbrLen);
25
+ };
26
+
27
+ export const create = async (params: {
28
+ data: LocalUserCreateData;
29
+ profile: UserProfile;
30
+ accountExpires: Date | null;
31
+ admin?: boolean;
32
+ actor?: AuditActor;
33
+ }): Promise<MutationResult<{ id: string }>> => {
34
+ const uid = await createLocalUid();
35
+ const admin = resolveStoredAdminState({
36
+ provider: "local",
37
+ profile: params.profile,
38
+ requestedAdmin: params.admin,
39
+ });
40
+
41
+ try {
42
+ return await writeLocalAccount(async (tx) => {
43
+ if (!(await isAccountCategoryAllowed({ provider: "local", profile: params.profile }, tx)))
44
+ return { ok: false, error: "This account category is disabled. Contact an administrator.", status: 403 };
45
+ const rows = await tx<{ id: string }[]>`
46
+ INSERT INTO auth.users (
47
+ uid,
48
+ provider,
49
+ profile,
50
+ mail,
51
+ given_name,
52
+ sn,
53
+ display_name,
54
+ admin,
55
+ account_expires
56
+ )
57
+ VALUES (
58
+ ${uid},
59
+ 'local',
60
+ ${params.profile},
61
+ ${params.data.email},
62
+ ${params.data.givenname ?? ""},
63
+ ${params.data.sn ?? ""},
64
+ ${params.data.displayName ?? ""},
65
+ ${admin},
66
+ ${params.accountExpires}
67
+ )
68
+ RETURNING id
69
+ `;
70
+ return { ok: true, data: { id: rows[0]!.id } };
71
+ }, params.actor);
72
+ } catch (error) {
73
+ // Map Postgres unique violations to a typed 409 instead of leaking raw DB
74
+ // errors. Two possible collisions: generated uid (extremely rare, retry at
75
+ // next call) or email already used by another local account.
76
+ if (isUniqueViolation(error, "users_uid_key")) {
77
+ return { ok: false, error: "Generated UID collided. Please retry.", status: 409 };
78
+ }
79
+ if (isUniqueViolation(error, "idx_users_provider_mail")) {
80
+ return { ok: false, error: "A local account with this email already exists.", status: 409 };
81
+ }
82
+ throw error;
83
+ }
84
+ };
85
+
86
+ export const createGuest = async (params: {
87
+ email: string;
88
+ givenname?: string;
89
+ sn?: string;
90
+ displayName?: string;
91
+ accountExpires?: Date | null;
92
+ }): Promise<MutationResult<{ id: string }>> => {
93
+ let accountExpires = params.accountExpires ?? null;
94
+ if (params.accountExpires === undefined) {
95
+ const configured = await settings.get<number | null>("user.account.local_guest_expires_days");
96
+ const days = typeof configured === "number" ? configured : 365;
97
+ accountExpires = days > 0 ? new Date(Date.now() + days * 24 * 60 * 60 * 1000) : null;
98
+ }
99
+
100
+ return create({
101
+ data: {
102
+ email: params.email,
103
+ givenname: params.givenname,
104
+ sn: params.sn,
105
+ displayName: params.displayName,
106
+ },
107
+ profile: "guest",
108
+ accountExpires,
109
+ });
110
+ };
111
+
112
+ export const update = async (params: {
113
+ id: string;
114
+ data: {
115
+ givenname?: string;
116
+ sn?: string;
117
+ displayName?: string;
118
+ mail?: string;
119
+ };
120
+ }): Promise<MutationResult<void>> => {
121
+ const existingRows = await sql<DbRow[]>`SELECT id FROM auth.users WHERE id = ${params.id}::uuid AND provider = 'local'`;
122
+ if (existingRows.length === 0) {
123
+ return { ok: false, error: "Local user not found", status: 404 };
124
+ }
125
+
126
+ await sql`
127
+ UPDATE auth.users
128
+ SET given_name = CASE WHEN ${params.data.givenname !== undefined} THEN ${params.data.givenname ?? ""} ELSE given_name END,
129
+ sn = CASE WHEN ${params.data.sn !== undefined} THEN ${params.data.sn ?? ""} ELSE sn END,
130
+ display_name = CASE WHEN ${params.data.displayName !== undefined} THEN ${params.data.displayName ?? ""} ELSE display_name END,
131
+ mail = CASE WHEN ${params.data.mail !== undefined} THEN ${params.data.mail ?? null} ELSE mail END
132
+ WHERE id = ${params.id}::uuid
133
+ `;
134
+
135
+ return { ok: true, data: undefined };
136
+ };
137
+
138
+ export const setProfile = async (params: {
139
+ id: string;
140
+ profile: UserProfile;
141
+ accountExpires: Date | null;
142
+ actor?: AuditActor;
143
+ }): Promise<MutationResult<void>> => {
144
+ const result = await writeLocalAccount(async (tx) => {
145
+ const rows = await tx<{ provider: string; profile: UserProfile; admin: boolean }[]>`
146
+ SELECT provider, profile, admin
147
+ FROM auth.users
148
+ WHERE id = ${params.id}::uuid
149
+ `;
150
+ if (rows.length === 0) return { ok: false, error: "User not found", status: 404 };
151
+ if (rows[0]!.provider !== "local") {
152
+ return { ok: false, error: "Only local accounts can change profile locally", status: 400 };
153
+ }
154
+ if (rows[0]!.profile !== params.profile && !(await isAccountCategoryAllowed({ provider: "local", profile: params.profile }, tx)))
155
+ return { ok: false, error: "This account category is disabled. Contact an administrator.", status: 403 };
156
+
157
+ const admin = resolveStoredAdminState({
158
+ provider: "local",
159
+ profile: params.profile,
160
+ currentAdmin: Boolean(rows[0]!.admin),
161
+ });
162
+
163
+ await tx`
164
+ UPDATE auth.users
165
+ SET provider = 'local',
166
+ profile = ${params.profile},
167
+ admin = ${admin},
168
+ account_expires = ${params.accountExpires}
169
+ WHERE id = ${params.id}::uuid
170
+ `;
171
+
172
+ return { ok: true, data: { id: params.id, assignIdentity: rows[0]!.profile === "guest" && params.profile === "user" } };
173
+ }, params.actor);
174
+ return result.ok ? { ok: true, data: undefined } : result;
175
+ };
176
+
177
+ export const setExpiry = async (params: {
178
+ id: string;
179
+ profile: UserProfile;
180
+ accountExpires: Date | null;
181
+ }): Promise<MutationResult<void>> => {
182
+ const rows = await sql<DbRow[]>`
183
+ SELECT provider
184
+ FROM auth.users
185
+ WHERE id = ${params.id}::uuid
186
+ `;
187
+ if (rows.length === 0) return { ok: false, error: "User not found", status: 404 };
188
+ if ((rows[0]!.provider as string) !== "local") {
189
+ return { ok: false, error: "Only local accounts support local expiry changes", status: 400 };
190
+ }
191
+
192
+ await sql`
193
+ UPDATE auth.users
194
+ SET account_expires = ${params.accountExpires}
195
+ WHERE id = ${params.id}::uuid
196
+ `;
197
+
198
+ return { ok: true, data: undefined };
199
+ };
200
+
201
+ export const setAdmin = async (params: { id: string; admin: boolean }): Promise<MutationResult<void>> => {
202
+ const rows = await sql<DbRow[]>`
203
+ SELECT provider, profile, admin
204
+ FROM auth.users
205
+ WHERE id = ${params.id}::uuid
206
+ `;
207
+ if (rows.length === 0) return { ok: false, error: "User not found", status: 404 };
208
+ const row = rows[0]!;
209
+ if ((row.provider as string) !== "local") {
210
+ return { ok: false, error: "Only local full accounts can be granted admin access", status: 400 };
211
+ }
212
+ if ((row.profile as string) !== "user") {
213
+ return { ok: false, error: "Guest accounts cannot be granted admin access", status: 400 };
214
+ }
215
+ const currentAdmin = Boolean(row.admin);
216
+ if (currentAdmin === params.admin) {
217
+ return { ok: false, error: params.admin ? "Account is already an admin" : "Account is not an admin", status: 409 };
218
+ }
219
+
220
+ await sql`
221
+ UPDATE auth.users
222
+ SET admin = ${params.admin}
223
+ WHERE id = ${params.id}::uuid
224
+ `;
225
+
226
+ return { ok: true, data: undefined };
227
+ };
228
+
229
+ export const remove = async (params: { id: string; actor: { userId: string; uid: string } }): Promise<MutationResult<void>> => {
230
+ const rows = await sql<DbRow[]>`
231
+ SELECT uid, profile, mail, display_name
232
+ FROM auth.users
233
+ WHERE id = ${params.id}::uuid
234
+ AND provider = 'local'
235
+ `;
236
+ if (rows.length === 0) return { ok: false, error: "Local user not found", status: 404 };
237
+
238
+ const row = rows[0]!;
239
+ const uid = row.uid as string;
240
+ await sql.begin(async (tx) => {
241
+ await writeDeletedAccountAudit({
242
+ db: tx,
243
+ userId: params.id,
244
+ uid,
245
+ mail: (row.mail as string) ?? null,
246
+ displayName: (row.display_name as string) ?? null,
247
+ previousProvider: "local",
248
+ previousProfile: (row.profile as UserProfile | null) ?? "guest",
249
+ reason: "manual_delete",
250
+ meta: {
251
+ actorUserId: params.actor.userId,
252
+ actorUid: params.actor.uid,
253
+ deletedFromFreeIpa: false,
254
+ freeIpaUserAlreadyMissing: false,
255
+ },
256
+ });
257
+ await tx`DELETE FROM auth.users WHERE id = ${params.id}::uuid`;
258
+ });
259
+
260
+ await session.revokeAllForUser(params.id);
261
+
262
+ return { ok: true, data: undefined };
263
+ };
@@ -0,0 +1,27 @@
1
+ import { type SQL, sql } from "bun";
2
+ import { defaultRailPreferences, type RailPreferences, RailPreferencesSchema } from "../contracts/rail-preferences";
3
+
4
+ /** Core-owned data, read by the platform SSR seam without a process-wide cache. */
5
+ export const createRailPreferencesService = (db: SQL = sql) => ({
6
+ async get(userId: string): Promise<RailPreferences> {
7
+ const [row] = await db<{ revision: number; visibility: unknown; shortcuts: unknown }[]>`
8
+ SELECT revision, visibility, shortcuts FROM auth.rail_preferences WHERE user_id = ${userId}::uuid
9
+ `;
10
+ return row ? RailPreferencesSchema.parse(row) : defaultRailPreferences();
11
+ },
12
+ async save(userId: string, input: RailPreferences): Promise<RailPreferences | null> {
13
+ const value = RailPreferencesSchema.parse(input);
14
+ const [row] = await db<{ revision: number; visibility: unknown; shortcuts: unknown }[]>`
15
+ INSERT INTO auth.rail_preferences (user_id, revision, visibility, shortcuts)
16
+ SELECT ${userId}::uuid, 1, (${JSON.stringify(value.visibility)}::text)::jsonb, (${JSON.stringify(value.shortcuts)}::text)::jsonb
17
+ WHERE ${value.revision} = 0 OR EXISTS (SELECT 1 FROM auth.rail_preferences WHERE user_id = ${userId}::uuid)
18
+ ON CONFLICT (user_id) DO UPDATE SET
19
+ revision = auth.rail_preferences.revision + 1,
20
+ visibility = EXCLUDED.visibility, shortcuts = EXCLUDED.shortcuts
21
+ WHERE auth.rail_preferences.revision = ${value.revision}
22
+ RETURNING revision, visibility, shortcuts
23
+ `;
24
+ return row ? RailPreferencesSchema.parse(row) : null;
25
+ },
26
+ });
27
+ export const railPreferences = createRailPreferencesService();
@@ -0,0 +1,191 @@
1
+ import type { Worker } from "@k2b/sync";
2
+
3
+ export type RuntimeTaskTracker = ReturnType<typeof createRuntimeTaskTracker>;
4
+
5
+ export type RuntimeTaskFailure = {
6
+ error: unknown;
7
+ failureCount: number;
8
+ retryInMs: number;
9
+ };
10
+
11
+ type RuntimeTaskSupervisorOptions = {
12
+ signal: AbortSignal;
13
+ run(signal: AbortSignal): Promise<void>;
14
+ onError?(failure: RuntimeTaskFailure): void;
15
+ minRetryMs?: number;
16
+ maxRetryMs?: number;
17
+ resetAfterMs?: number;
18
+ jitter?: number;
19
+ name?: string;
20
+ };
21
+
22
+ const waitForRetry = (delayMs: number, signal: AbortSignal): Promise<void> =>
23
+ new Promise((resolve) => {
24
+ if (signal.aborted) return resolve();
25
+ const finish = () => {
26
+ clearTimeout(timer);
27
+ signal.removeEventListener("abort", finish);
28
+ resolve();
29
+ };
30
+ const timer = setTimeout(finish, delayMs);
31
+ signal.addEventListener("abort", finish, { once: true });
32
+ if (signal.aborted) finish();
33
+ });
34
+
35
+ /** Restart a long-lived task after unexpected failure or completion. */
36
+ export const superviseRuntimeTask = async (options: RuntimeTaskSupervisorOptions): Promise<void> => {
37
+ const minRetryMs = options.minRetryMs ?? 250;
38
+ const maxRetryMs = options.maxRetryMs ?? 5_000;
39
+ const resetAfterMs = options.resetAfterMs ?? 30_000;
40
+ const jitter = options.jitter ?? 0.2;
41
+ if (![minRetryMs, maxRetryMs, resetAfterMs].every((value) => Number.isFinite(value) && value > 0)) {
42
+ throw new RangeError("Runtime task retry timings must be positive finite numbers");
43
+ }
44
+ if (minRetryMs > maxRetryMs) throw new RangeError("Runtime task minimum retry delay cannot exceed its maximum");
45
+ if (!Number.isFinite(jitter) || jitter < 0 || jitter > 1) throw new RangeError("Runtime task retry jitter must be between 0 and 1");
46
+
47
+ let failureCount = 0;
48
+ while (!options.signal.aborted) {
49
+ const startedAt = Date.now();
50
+ let error: unknown;
51
+ try {
52
+ await options.run(options.signal);
53
+ if (options.signal.aborted) return;
54
+ error = new Error(`${options.name ?? "Runtime task"} stopped unexpectedly`);
55
+ } catch (caught) {
56
+ if (options.signal.aborted) return;
57
+ error = caught;
58
+ }
59
+
60
+ failureCount = Date.now() - startedAt >= resetAfterMs ? 1 : failureCount + 1;
61
+ const exponentialRetryMs = minRetryMs * 2 ** Math.min(failureCount - 1, 30);
62
+ const retryInMs = Math.min(maxRetryMs, Math.max(minRetryMs, Math.round(exponentialRetryMs * (1 + (Math.random() * 2 - 1) * jitter))));
63
+ try {
64
+ options.onError?.({ error, failureCount, retryInMs });
65
+ } catch {
66
+ // Reporting failures must not stop recovery.
67
+ }
68
+ await waitForRetry(retryInMs, options.signal);
69
+ }
70
+ };
71
+
72
+ /** Track process work outside Sync handlers, such as recovery scans and publishers. */
73
+ export const createRuntimeTaskTracker = () => {
74
+ const tasks = new Set<Promise<unknown>>();
75
+ let accepting = false;
76
+
77
+ return {
78
+ open: (): void => {
79
+ accepting = true;
80
+ },
81
+ close: (): void => {
82
+ accepting = false;
83
+ },
84
+ run: <T>(operation: () => Promise<T>): Promise<T> | null => {
85
+ if (!accepting) return null;
86
+ const task = Promise.resolve().then(operation);
87
+ tasks.add(task);
88
+ const remove = () => tasks.delete(task);
89
+ task.then(remove, remove);
90
+ return task;
91
+ },
92
+ drain: async (): Promise<void> => {
93
+ while (tasks.size > 0) await Promise.allSettled([...tasks]);
94
+ },
95
+ };
96
+ };
97
+
98
+ /**
99
+ * Stop accepting runtime tasks, stop the @k2b/sync workers from pulling new
100
+ * work, then drain accepted process tasks and workers together. Sync owns
101
+ * handler tracking and cancellation; do not wrap worker handlers in tracker.run.
102
+ * Only work outside those handlers uses the tracker and its separate deadline.
103
+ */
104
+ export const stopRuntimeJobs = async (
105
+ tracker: Pick<RuntimeTaskTracker, "close" | "drain">,
106
+ workers: ReadonlyArray<Pick<Worker, "stop" | "drain">>,
107
+ options: { timeoutMs?: number } = {},
108
+ ): Promise<void> => {
109
+ const timeoutMs = options.timeoutMs ?? 30_000;
110
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) throw new RangeError("Runtime drain timeout must be positive and finite");
111
+ tracker.close();
112
+ const errors: unknown[] = [];
113
+ for (const worker of workers) worker.stop();
114
+ let timer: ReturnType<typeof setTimeout> | undefined;
115
+ const tracked = Promise.race([
116
+ tracker.drain(),
117
+ new Promise<never>((_, reject) => {
118
+ timer = setTimeout(() => reject(new Error(`Runtime tasks did not drain within ${timeoutMs}ms`)), timeoutMs);
119
+ }),
120
+ ]);
121
+ try {
122
+ for (const result of await Promise.allSettled([tracked, ...workers.map((worker) => worker.drain({ timeoutMs }))])) {
123
+ if (result.status === "rejected") errors.push(result.reason);
124
+ }
125
+ } finally {
126
+ clearTimeout(timer);
127
+ }
128
+ if (errors.length === 1) throw errors[0];
129
+ if (errors.length > 1) throw new AggregateError(errors, "Multiple runtime jobs failed to stop");
130
+ };
131
+
132
+ type RuntimeLifecycleHooks = {
133
+ start(): Promise<void>;
134
+ stop(): Promise<void>;
135
+ };
136
+
137
+ export const createRuntimeLifecycle = (hooks: RuntimeLifecycleHooks) => {
138
+ let state: "stopped" | "started" | "cleanup-required" = "stopped";
139
+ let transition = Promise.resolve();
140
+
141
+ const serialize = (operation: () => Promise<void>): Promise<void> => {
142
+ const result = transition.then(operation, operation);
143
+ transition = result.catch(() => undefined);
144
+ return result;
145
+ };
146
+
147
+ return {
148
+ start: (): Promise<void> =>
149
+ serialize(async () => {
150
+ if (state === "started") return;
151
+ if (state === "cleanup-required") {
152
+ await hooks.stop();
153
+ state = "stopped";
154
+ }
155
+
156
+ state = "cleanup-required";
157
+ try {
158
+ await hooks.start();
159
+ state = "started";
160
+ } catch (startError) {
161
+ try {
162
+ await hooks.stop();
163
+ state = "stopped";
164
+ } catch (stopError) {
165
+ throw new AggregateError([startError, stopError], "Runtime startup and cleanup failed");
166
+ }
167
+ throw startError;
168
+ }
169
+ }),
170
+ stop: (): Promise<void> =>
171
+ serialize(async () => {
172
+ if (state === "stopped") return;
173
+ state = "cleanup-required";
174
+ await hooks.stop();
175
+ state = "stopped";
176
+ }),
177
+ };
178
+ };
179
+
180
+ export const stopRuntimeResources = async (resources: ReadonlyArray<() => void | Promise<void>>): Promise<void> => {
181
+ const errors: unknown[] = [];
182
+ for (const stop of resources) {
183
+ try {
184
+ await stop();
185
+ } catch (error) {
186
+ errors.push(error);
187
+ }
188
+ }
189
+ if (errors.length === 1) throw errors[0];
190
+ if (errors.length > 1) throw new AggregateError(errors, "Multiple runtime resources failed to stop");
191
+ };
@@ -0,0 +1,10 @@
1
+ import { decryptValue, encryptValue } from "./settings/crypto";
2
+
3
+ export const encryptSecret = async (value: unknown): Promise<string> => encryptValue(value);
4
+
5
+ export const decryptSecret = async <T = unknown>(value: string): Promise<T> => (await decryptValue(value)) as T;
6
+
7
+ export const secrets = {
8
+ encrypt: encryptSecret,
9
+ decrypt: decryptSecret,
10
+ };