@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,206 @@
1
+ import { ok } from "@k2b/stdlib";
2
+ import { Hono } from "hono";
3
+ import { describeRoute } from "hono-openapi";
4
+ import { z } from "zod";
5
+ import { createPagination, ErrorResponseSchema, MessageResponseSchema, PaginationQuerySchema, parsePagination } from "../contracts";
6
+ import { type AuthContext, auth, jsonResponse, requiresAdmin, respond, v } from "../server";
7
+ import { accountLifecycle, lifecycleJobs } from "../services";
8
+
9
+ const DeletedAccountSchema = z.object({
10
+ id: z.uuid(),
11
+ deletedUserId: z.uuid(),
12
+ uid: z.string(),
13
+ mail: z.string().nullable(),
14
+ displayName: z.string().nullable(),
15
+ previousProvider: z.string().nullable(),
16
+ previousProfile: z.string().nullable(),
17
+ reason: z.string(),
18
+ deletedAt: z.string().datetime(),
19
+ meta: z.record(z.string(), z.unknown()),
20
+ });
21
+
22
+ const ReminderAuditSchema = z.object({
23
+ id: z.uuid(),
24
+ userId: z.uuid().nullable(),
25
+ uid: z.string().nullable(),
26
+ mail: z.string().nullable(),
27
+ displayName: z.string().nullable(),
28
+ kind: z.enum(["account_expiry"]),
29
+ thresholdDays: z.number().int().positive(),
30
+ targetExpiryAt: z.string().datetime(),
31
+ status: z.enum(["pending", "sent", "error"]),
32
+ attemptCount: z.number().int().nonnegative(),
33
+ lastAttemptAt: z.string().datetime().nullable(),
34
+ sentAt: z.string().datetime().nullable(),
35
+ lastError: z.string().nullable(),
36
+ createdAt: z.string().datetime(),
37
+ });
38
+
39
+ const DeletedAccountsResponseSchema = z.object({
40
+ items: z.array(DeletedAccountSchema),
41
+ pagination: z.object({
42
+ page: z.number(),
43
+ per_page: z.number(),
44
+ total: z.number(),
45
+ total_pages: z.number(),
46
+ has_next: z.boolean(),
47
+ }),
48
+ });
49
+
50
+ const ReminderAuditResponseSchema = z.object({
51
+ items: z.array(ReminderAuditSchema),
52
+ pagination: z.object({
53
+ page: z.number(),
54
+ per_page: z.number(),
55
+ total: z.number(),
56
+ total_pages: z.number(),
57
+ has_next: z.boolean(),
58
+ }),
59
+ });
60
+
61
+ const TriggerJobResponseSchema = z.object({
62
+ message: z.string(),
63
+ jobId: z.string(),
64
+ });
65
+
66
+ const app = new Hono<AuthContext>()
67
+ .use(auth.requireRole("admin"))
68
+ .get(
69
+ "/deleted-accounts",
70
+ describeRoute({
71
+ tags: ["Admin Lifecycle"],
72
+ summary: "List deleted account lifecycle entries",
73
+ ...requiresAdmin,
74
+ responses: {
75
+ 200: jsonResponse(DeletedAccountsResponseSchema, "Deleted account lifecycle entries"),
76
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
77
+ 403: jsonResponse(ErrorResponseSchema, "Admin access required"),
78
+ },
79
+ }),
80
+ v(
81
+ "query",
82
+ z.object({
83
+ ...PaginationQuerySchema.shape,
84
+ reason: z.string().optional(),
85
+ search: z.string().optional(),
86
+ }),
87
+ ),
88
+ async (c) => {
89
+ const query = c.req.valid("query");
90
+ const pagination = parsePagination(query);
91
+ const result = await accountLifecycle.listDeletedAccounts({
92
+ page: pagination.page,
93
+ perPage: pagination.perPage,
94
+ reason: query.reason,
95
+ search: query.search,
96
+ });
97
+
98
+ return c.json({
99
+ items: result.items,
100
+ pagination: createPagination(pagination, result.total),
101
+ });
102
+ },
103
+ )
104
+ .get(
105
+ "/reminders",
106
+ describeRoute({
107
+ tags: ["Admin Lifecycle"],
108
+ summary: "List reminder history entries",
109
+ ...requiresAdmin,
110
+ responses: {
111
+ 200: jsonResponse(ReminderAuditResponseSchema, "Reminder history entries"),
112
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
113
+ 403: jsonResponse(ErrorResponseSchema, "Admin access required"),
114
+ },
115
+ }),
116
+ v(
117
+ "query",
118
+ z.object({
119
+ ...PaginationQuerySchema.shape,
120
+ status: z.enum(["pending", "sent", "error"]).optional(),
121
+ kind: z.enum(["account_expiry"]).optional(),
122
+ search: z.string().optional(),
123
+ }),
124
+ ),
125
+ async (c) => {
126
+ const query = c.req.valid("query");
127
+ const pagination = parsePagination(query);
128
+ const result = await accountLifecycle.listReminderAudit({
129
+ page: pagination.page,
130
+ perPage: pagination.perPage,
131
+ status: query.status,
132
+ kind: query.kind,
133
+ search: query.search,
134
+ });
135
+
136
+ return c.json({
137
+ items: result.items,
138
+ pagination: createPagination(pagination, result.total),
139
+ });
140
+ },
141
+ )
142
+ // Manual-only lifecycle jobs. Scheduled jobs such as IPA sync and reminders
143
+ // run from their broker schedules; Admin Observability Jobs can run them now.
144
+ .post(
145
+ "/jobs",
146
+ describeRoute({
147
+ tags: ["Admin Lifecycle"],
148
+ summary: "Submit a lifecycle job",
149
+ description:
150
+ "Dispatches one of the account-lifecycle backfill jobs. Scheduled lifecycle jobs are controlled from Admin Observability Jobs.",
151
+ ...requiresAdmin,
152
+ responses: {
153
+ 200: jsonResponse(TriggerJobResponseSchema, "Job submitted"),
154
+ 400: jsonResponse(ErrorResponseSchema, "Unknown job kind"),
155
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
156
+ 403: jsonResponse(ErrorResponseSchema, "Admin access required"),
157
+ },
158
+ }),
159
+ v(
160
+ "json",
161
+ z.object({
162
+ kind: z.enum(["ipa-backfill", "local-user-backfill", "guest-backfill"]),
163
+ }),
164
+ ),
165
+ async (c) =>
166
+ respond(c, async () => {
167
+ const { kind } = c.req.valid("json");
168
+ switch (kind) {
169
+ case "ipa-backfill":
170
+ return ok({ message: "IPA backfill job submitted", jobId: await lifecycleJobs.submitIpaBackfill() });
171
+ case "local-user-backfill":
172
+ return ok({ message: "Local user backfill job submitted", jobId: await lifecycleJobs.submitLocalUserBackfill() });
173
+ case "guest-backfill":
174
+ return ok({ message: "Local guest backfill job submitted", jobId: await lifecycleJobs.submitGuestBackfill() });
175
+ }
176
+ }),
177
+ )
178
+ .get(
179
+ "/health",
180
+ describeRoute({
181
+ tags: ["Admin Lifecycle"],
182
+ summary: "Lifecycle worker metrics",
183
+ ...requiresAdmin,
184
+ responses: {
185
+ 200: jsonResponse(z.object({ metrics: z.record(z.string(), z.unknown()) }), "Process-local worker metrics"),
186
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
187
+ 403: jsonResponse(ErrorResponseSchema, "Admin access required"),
188
+ },
189
+ }),
190
+ async (c) => c.json({ metrics: lifecycleJobs.metrics() }),
191
+ )
192
+ .get(
193
+ "/",
194
+ describeRoute({
195
+ tags: ["Admin Lifecycle"],
196
+ summary: "Lifecycle API root",
197
+ ...requiresAdmin,
198
+ responses: {
199
+ 200: jsonResponse(MessageResponseSchema, "Lifecycle API available"),
200
+ },
201
+ }),
202
+ (c) => c.json({ message: "Account lifecycle admin API" }),
203
+ );
204
+
205
+ export default app;
206
+ export type ApiType = typeof app;
@@ -0,0 +1,66 @@
1
+ import { Hono, type MiddlewareHandler } from "hono";
2
+ import { describeRoute } from "hono-openapi";
3
+ import { z } from "zod";
4
+ import { LinuxIdentityConfigurationSchema, PosixOverridesSchema } from "../contracts/posix";
5
+ import { auth, type AuthContext, v } from "../server";
6
+ import { posix, PosixError } from "../services/accounts/posix";
7
+
8
+ const Id = z.object({ id: z.uuid() });
9
+ const Configure = z.object({ config: LinuxIdentityConfigurationSchema, rangeReserved: z.boolean() }).strict();
10
+
11
+ export const createAdminLinuxIdentityRoutes = (
12
+ authenticate: MiddlewareHandler<AuthContext> = auth.requireRole("admin"),
13
+ service: typeof posix = posix,
14
+ ) =>
15
+ new Hono<AuthContext>()
16
+ .use(authenticate)
17
+ .onError((error, c) => {
18
+ if (error instanceof PosixError) return c.json({ code: error.code }, error.status);
19
+ throw error;
20
+ })
21
+ .get(
22
+ "/",
23
+ describeRoute({ tags: ["Linux identities"], summary: "Preview Linux identities without provisioning accounts" }),
24
+ v(
25
+ "query",
26
+ z.object({ after: z.uuid().optional(), search: z.string().trim().optional(), scope: z.enum(["ready", "all"]).optional() }),
27
+ ),
28
+ async (c) => c.json(await service.overview(c.get("user"), c.req.valid("query").after ?? null, c.req.valid("query"))),
29
+ )
30
+ .put(
31
+ "/configuration",
32
+ describeRoute({ tags: ["Linux identities"], summary: "Configure automatic local Linux identity assignment; does not enable computer login" }),
33
+ v("json", Configure),
34
+ async (c) => {
35
+ const { config, rangeReserved } = c.req.valid("json");
36
+ if (config.enabled && !rangeReserved) throw new PosixError("range_confirmation_required", 400);
37
+ return c.json(await service.configure(c.get("user"), config));
38
+ },
39
+ )
40
+ .get(
41
+ "/users/:id",
42
+ describeRoute({ tags: ["Linux identities"], summary: "Read a local or FreeIPA Linux identity" }),
43
+ v("param", Id),
44
+ async (c) => c.json(await service.get(c.get("user"), c.req.valid("param").id)),
45
+ )
46
+ .post(
47
+ "/users/:id",
48
+ describeRoute({ tags: ["Linux identities"], summary: "Backfill missing Linux attributes for one local full account; safe to repeat" }),
49
+ v("param", Id),
50
+ async (c) => c.json(await service.provision(c.get("user"), c.req.valid("param").id)),
51
+ )
52
+ .post(
53
+ "/groups/:id",
54
+ describeRoute({ tags: ["Linux identities"], summary: "Assign a stable Linux GID to a local group" }),
55
+ v("param", Id),
56
+ async (c) => c.json(await service.provisionGroup(c.get("user"), c.req.valid("param").id)),
57
+ )
58
+ .patch(
59
+ "/users/:id",
60
+ describeRoute({ tags: ["Linux identities"], summary: "Change local home and shell without changing numeric IDs or moving files" }),
61
+ v("param", Id),
62
+ v("json", PosixOverridesSchema),
63
+ async (c) => c.json(await service.update(c.get("user"), c.req.valid("param").id, c.req.valid("json"))),
64
+ );
65
+
66
+ export default createAdminLinuxIdentityRoutes();
@@ -0,0 +1,131 @@
1
+ import { ok } from "@k2b/stdlib";
2
+ import { Hono } from "hono";
3
+ import { describeRoute } from "hono-openapi";
4
+ import { z } from "zod";
5
+ import {
6
+ ActiveAnnouncementsResponseSchema,
7
+ AnnouncementEntrySchema,
8
+ AnnouncementListResponseSchema,
9
+ CreateAnnouncementSchema,
10
+ ErrorResponseSchema,
11
+ MessageResponseSchema,
12
+ parseAnnouncementCookieHeader,
13
+ UpdateAnnouncementSchema,
14
+ } from "../contracts";
15
+ import { type AuthContext, auth, jsonResponse, requiresAdmin, requiresAuth, respond, v } from "../server";
16
+ import { announcements } from "../services";
17
+
18
+ const IdParamSchema = z.object({ id: z.uuid() });
19
+
20
+ const withMessage = async <T>(operation: Promise<import("@k2b/stdlib").Result<T>>, message: string) => {
21
+ const result = await operation;
22
+ if (!result.ok) return result;
23
+ return ok({ message });
24
+ };
25
+
26
+ export const announcementRoutes = new Hono<AuthContext>().get(
27
+ "/active",
28
+ auth.requireRole("authenticated"),
29
+ describeRoute({
30
+ tags: ["Announcements"],
31
+ summary: "List active user announcements",
32
+ description: "Returns active banners and unseen announcements for the current request cookie state.",
33
+ ...requiresAuth,
34
+ responses: {
35
+ 200: jsonResponse(ActiveAnnouncementsResponseSchema, "Active announcements"),
36
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
37
+ },
38
+ }),
39
+ async (c) => {
40
+ const state = parseAnnouncementCookieHeader(c.req.header("Cookie"));
41
+ return respond(c, ok(await announcements.active.forState({ state })));
42
+ },
43
+ );
44
+
45
+ export const adminAnnouncementRoutes = new Hono<AuthContext>()
46
+ .use(auth.requireRole("admin"))
47
+ .get(
48
+ "/",
49
+ describeRoute({
50
+ tags: ["Admin Announcements"],
51
+ summary: "List announcements",
52
+ ...requiresAdmin,
53
+ responses: {
54
+ 200: jsonResponse(AnnouncementListResponseSchema, "Announcements"),
55
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
56
+ 403: jsonResponse(ErrorResponseSchema, "Admin access required"),
57
+ },
58
+ }),
59
+ v(
60
+ "query",
61
+ z.object({
62
+ kind: z.enum(["announcement", "banner"]).optional(),
63
+ search: z.string().optional(),
64
+ }),
65
+ ),
66
+ async (c) => {
67
+ const query = c.req.valid("query");
68
+ const items = await announcements.admin.list({
69
+ filter: { kind: query.kind, query: query.search },
70
+ });
71
+ return respond(c, ok({ items }));
72
+ },
73
+ )
74
+ .post(
75
+ "/",
76
+ describeRoute({
77
+ tags: ["Admin Announcements"],
78
+ summary: "Create announcement",
79
+ ...requiresAdmin,
80
+ responses: {
81
+ 201: jsonResponse(AnnouncementEntrySchema, "Created announcement"),
82
+ 400: jsonResponse(ErrorResponseSchema, "Validation error"),
83
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
84
+ 403: jsonResponse(ErrorResponseSchema, "Admin access required"),
85
+ },
86
+ }),
87
+ v("json", CreateAnnouncementSchema),
88
+ async (c) => respond(c, announcements.admin.create({ data: c.req.valid("json"), actorId: c.get("user").id }), 201),
89
+ )
90
+ .patch(
91
+ "/:id",
92
+ describeRoute({
93
+ tags: ["Admin Announcements"],
94
+ summary: "Update announcement",
95
+ ...requiresAdmin,
96
+ responses: {
97
+ 200: jsonResponse(AnnouncementEntrySchema, "Updated announcement"),
98
+ 400: jsonResponse(ErrorResponseSchema, "Validation error"),
99
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
100
+ 403: jsonResponse(ErrorResponseSchema, "Admin access required"),
101
+ 404: jsonResponse(ErrorResponseSchema, "Announcement not found"),
102
+ },
103
+ }),
104
+ v("param", IdParamSchema),
105
+ v("json", UpdateAnnouncementSchema),
106
+ async (c) =>
107
+ respond(
108
+ c,
109
+ announcements.admin.update({
110
+ id: c.req.valid("param").id,
111
+ data: c.req.valid("json"),
112
+ actorId: c.get("user").id,
113
+ }),
114
+ ),
115
+ )
116
+ .delete(
117
+ "/:id",
118
+ describeRoute({
119
+ tags: ["Admin Announcements"],
120
+ summary: "Delete announcement",
121
+ ...requiresAdmin,
122
+ responses: {
123
+ 200: jsonResponse(MessageResponseSchema, "Announcement deleted"),
124
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
125
+ 403: jsonResponse(ErrorResponseSchema, "Admin access required"),
126
+ 404: jsonResponse(ErrorResponseSchema, "Announcement not found"),
127
+ },
128
+ }),
129
+ v("param", IdParamSchema),
130
+ async (c) => respond(c, withMessage(announcements.admin.remove({ id: c.req.valid("param").id }), "Announcement deleted.")),
131
+ );
@@ -0,0 +1,129 @@
1
+ import { Hono } from "hono";
2
+ import { bodyLimit } from "hono/body-limit";
3
+ import { HTTPException } from "hono/http-exception";
4
+ import { describeRoute } from "hono-openapi";
5
+ import { z } from "zod";
6
+ import {
7
+ APP_APPROVAL_LIMITS,
8
+ AppDeviceMutationSchema,
9
+ AppDeviceRequestSchema,
10
+ AppLoginReferenceSchema,
11
+ AppLoginStartSchema,
12
+ AppPairingClaimSchema,
13
+ AppPairingConfirmSchema,
14
+ AppPairingReferenceSchema,
15
+ AppPairingStartSchema,
16
+ } from "../contracts/app-approval";
17
+ import { auth, type AuthContext, rateLimit, v } from "../server";
18
+ import { appApproval, AppApprovalError, type AppApprovalActor, type createAppApprovalService } from "../services/app-approval";
19
+
20
+ const PairingIdSchema = z.object({ pairingId: z.string().uuid() }).strict();
21
+ const DevicePageSchema = z.object({ after: z.string().uuid().optional() }).strict();
22
+ type Service = ReturnType<typeof createAppApprovalService>;
23
+
24
+ /** This is a separate credential surface, never a user API-key or OAuth scope. */
25
+ export const createAppApprovalRoutes = (service: Service = appApproval) => {
26
+ const actor = async (c: Parameters<typeof auth.session.getToken>[0]): Promise<AppApprovalActor> => {
27
+ const token = auth.session.getToken(c);
28
+ const session = token ? await auth.session.authenticateRequest(c, token) : null;
29
+ if (!session) throw new AppApprovalError("REAUTHENTICATE", 403);
30
+ return { userId: session.user.id, sid: session.data.sid, admin: session.user.roles.includes("admin") };
31
+ };
32
+ return new Hono<AuthContext>()
33
+ .onError((error, c) => {
34
+ if (error instanceof AppApprovalError) return c.json({ code: error.code, message: error.code }, error.status);
35
+ if (error instanceof HTTPException && error.status < 500) return c.json({ code: "INVALID_REQUEST" }, error.status);
36
+ // Never include SQL, pairing secrets, signature bodies or keys in errors.
37
+ console.error("[app-approval] operation failed", error instanceof Error ? error.name : "UnknownError");
38
+ return c.json({ code: "UNAVAILABLE", message: "App approval is unavailable." }, 503);
39
+ })
40
+ .use("*", async (c, next) => {
41
+ c.header("Cache-Control", "no-store");
42
+ c.header("Referrer-Policy", "no-referrer");
43
+ c.header("Vary", "Origin");
44
+ const cfg = await service.config(c.req.path.includes("/manage/") ? false : true);
45
+ const origin = c.req.header("Origin");
46
+ const deviceSurface = /\/(info|pairings\/claim|pairings\/result|device)$/.test(c.req.path);
47
+ if (origin && origin !== cfg.issuer && !(deviceSurface && origin === cfg.appOrigin)) return c.json({ code: "FORBIDDEN" }, 403);
48
+ if (!deviceSurface && c.req.method !== "GET" && origin !== cfg.issuer) return c.json({ code: "FORBIDDEN" }, 403);
49
+ if (deviceSurface && origin === cfg.appOrigin) {
50
+ c.header("Access-Control-Allow-Origin", cfg.appOrigin);
51
+ c.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
52
+ c.header("Access-Control-Allow-Headers", "Content-Type");
53
+ c.header("Access-Control-Max-Age", "300");
54
+ }
55
+ if (c.req.method === "OPTIONS") return c.body(null, 204);
56
+ await next();
57
+ })
58
+ .use("*", bodyLimit({ maxSize: APP_APPROVAL_LIMITS.bodyBytes }))
59
+ .use("*", rateLimit({ keyBy: "ip" }))
60
+ .use("/manage/*", auth.requireRole("authenticated"))
61
+ .get("/info", describeRoute({ tags: ["App approval"], summary: "Discover the enabled app approval protocol" }), async (c) =>
62
+ c.json(await service.info()),
63
+ )
64
+ .post(
65
+ "/manage/pairings/start",
66
+ describeRoute({ tags: ["App approval"], summary: "Start recent-session authorized device pairing" }),
67
+ v("json", AppPairingStartSchema),
68
+ async (c) => c.json(await service.startPairing(await actor(c), c.req.valid("json").userId), 201),
69
+ )
70
+ .post("/manage/pairings/status", v("json", PairingIdSchema), async (c) =>
71
+ c.json(await service.inspectPairing(await actor(c), c.req.valid("json").pairingId)),
72
+ )
73
+ .post("/manage/pairings/confirm", v("json", AppPairingConfirmSchema), async (c) => {
74
+ const input = c.req.valid("json");
75
+ return c.json(await service.confirmPairing(await actor(c), input.pairingId, input.comparison));
76
+ })
77
+ .post("/manage/pairings/cancel", v("json", PairingIdSchema), async (c) => {
78
+ await service.cancelPairing(await actor(c), c.req.valid("json").pairingId);
79
+ return c.body(null, 204);
80
+ })
81
+ .get("/manage/devices", v("query", DevicePageSchema), async (c) =>
82
+ c.json(await service.listDevices(await actor(c), c.req.valid("query").after)),
83
+ )
84
+ .post("/manage/devices/update", v("json", AppDeviceMutationSchema), async (c) => {
85
+ const input = c.req.valid("json");
86
+ await service.mutateDevice(await actor(c), input.deviceId, input.operation === "rename" ? input.name : undefined);
87
+ return c.body(null, 204);
88
+ })
89
+ .post(
90
+ "/pairings/claim",
91
+ describeRoute({ tags: ["App approval"], summary: "Claim a pairing with device proof of possession" }),
92
+ v("json", AppPairingClaimSchema),
93
+ async (c) => c.json(await service.claimPairing(c.req.valid("json"))),
94
+ )
95
+ .post("/pairings/result", v("json", AppPairingReferenceSchema), async (c) => {
96
+ const input = c.req.valid("json");
97
+ return c.json(await service.pairingResult(input.pairingId, input.secret, input.publicKey));
98
+ })
99
+ .post(
100
+ "/device",
101
+ describeRoute({ tags: ["App approval"], summary: "Execute a one-use signed device command" }),
102
+ v("json", AppDeviceRequestSchema),
103
+ async (c) => c.json(await service.deviceCommand(c.req.valid("json"))),
104
+ )
105
+ .post(
106
+ "/login/start",
107
+ describeRoute({ tags: ["App approval"], summary: "Start a browser-bound app login without revealing account existence" }),
108
+ v("json", AppLoginStartSchema),
109
+ async (c) => {
110
+ const input = c.req.valid("json");
111
+ return c.json(await service.startLogin(input.identifier, input.category), 202);
112
+ },
113
+ )
114
+ .post("/login/status", v("json", AppLoginReferenceSchema), async (c) => {
115
+ const input = c.req.valid("json");
116
+ return c.json(await service.browserStatus(input.requestId, input.browserSecret));
117
+ })
118
+ .post(
119
+ "/login/complete",
120
+ describeRoute({ tags: ["App approval"], summary: "Consume an approval once and set only the original browser session cookie" }),
121
+ v("json", AppLoginReferenceSchema),
122
+ async (c) => {
123
+ const input = c.req.valid("json");
124
+ const userId = await service.consumeLogin(input.requestId, input.browserSecret);
125
+ await auth.session.create(c, userId);
126
+ return c.body(null, 204);
127
+ },
128
+ );
129
+ };
@@ -0,0 +1,51 @@
1
+ import { Hono } from "hono";
2
+ import { describeRoute } from "hono-openapi";
3
+ import { z } from "zod";
4
+ import { ErrorResponseSchema } from "../contracts";
5
+ import { type AuthContext, auth, jsonResponse, requiresAuth, v } from "../server";
6
+ import { visibleNavigationApps } from "../ssr/app-navigation";
7
+ import { getLocalizedRuntimeContext } from "../ssr/runtime";
8
+
9
+ const AppListQuerySchema = z.object({
10
+ search: z.string().trim().min(1).optional(),
11
+ });
12
+
13
+ const VisibleAppSchema = z.object({
14
+ id: z.string(),
15
+ name: z.string(),
16
+ description: z.string(),
17
+ icon: z.string(),
18
+ href: z.string(),
19
+ });
20
+
21
+ const VisibleAppListSchema = z.object({
22
+ items: z.array(VisibleAppSchema),
23
+ });
24
+
25
+ export const appDiscoveryRoutes = new Hono<AuthContext>().use(auth.requireRole("authenticated")).get(
26
+ "/",
27
+ describeRoute({
28
+ tags: ["Apps"],
29
+ summary: "List apps available to the current user",
30
+ description: "Returns live Cloud apps that are visible in the current user's navigation.",
31
+ ...requiresAuth,
32
+ responses: {
33
+ 200: jsonResponse(VisibleAppListSchema, "Available apps"),
34
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
35
+ },
36
+ }),
37
+ v("query", AppListQuerySchema),
38
+ (c) => {
39
+ const search = c.req.valid("query").search?.toLowerCase();
40
+ const items = visibleNavigationApps(getLocalizedRuntimeContext(c).apps, c.get("user"))
41
+ .map((app) => ({
42
+ id: app.id,
43
+ name: app.name,
44
+ description: app.description,
45
+ icon: app.icon,
46
+ href: app.nav.href,
47
+ }))
48
+ .filter((app) => !search || `${app.id} ${app.name} ${app.description}`.toLowerCase().includes(search));
49
+ return c.json({ items });
50
+ },
51
+ );
@@ -0,0 +1,54 @@
1
+ import { z } from "zod";
2
+
3
+ import { UserSchema } from "../../contracts";
4
+
5
+ export const LoginSchema = z.object({
6
+ username: z.string(),
7
+ password: z.string(),
8
+ acceptedAgb: z.literal(true).optional(),
9
+ });
10
+
11
+ export const EmailLoginSchema = z.object({
12
+ email: z.email(),
13
+ category: z.enum(["guest", "login"]).optional(),
14
+ acceptedAgb: z.literal(true).optional(),
15
+ redirectTo: z.string().max(2048).optional(),
16
+ });
17
+
18
+ export const VerifyTokenSchema = z.object({
19
+ token: z.uuid(),
20
+ acceptedAgb: z.literal(true).optional(),
21
+ });
22
+
23
+ export const PasswordResetRequestSchema = z.object({
24
+ email: z.email(),
25
+ acceptedAgb: z.literal(true),
26
+ redirectTo: z.string().max(2048).optional(),
27
+ });
28
+
29
+ export const PasswordResetCompleteSchema = z
30
+ .object({
31
+ token: z.uuid(),
32
+ newPassword: z.string().min(8),
33
+ confirmPassword: z.string().min(1),
34
+ acceptedAgb: z.literal(true).optional(),
35
+ })
36
+ .refine((data) => data.newPassword === data.confirmPassword, {
37
+ message: "Passwords do not match",
38
+ path: ["confirmPassword"],
39
+ });
40
+
41
+ export const AdminLoginSchema = z.object({
42
+ token: z.string().min(1),
43
+ restoreLocalLogin: z.boolean().default(false),
44
+ });
45
+
46
+ export const AuthResponseSchema = z.object({
47
+ session_token: z.string(),
48
+ user: UserSchema,
49
+ });
50
+
51
+ export const VerifyPasskeyAuthenticationSchema = z.object({
52
+ response: z.unknown(),
53
+ acceptedAgb: z.literal(true).optional(),
54
+ });