@k2b/cloud 0.6.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (540) hide show
  1. package/README.md +98 -0
  2. package/package.json +128 -0
  3. package/public/logo.svg +1 -0
  4. package/scripts/app-favicon.test.ts +49 -0
  5. package/scripts/app-favicon.ts +51 -0
  6. package/scripts/build.ts +205 -0
  7. package/scripts/preload.ts +164 -0
  8. package/scripts/sync-recovery-smoke.ts +200 -0
  9. package/src/_internal/app-favicon.ts +2 -0
  10. package/src/_internal/app-presentation.ts +61 -0
  11. package/src/_internal/app-workspace-state.ts +24 -0
  12. package/src/_internal/bounded-json.ts +47 -0
  13. package/src/_internal/build-metadata.ts +9 -0
  14. package/src/_internal/capabilities.ts +1118 -0
  15. package/src/_internal/define-app.ts +801 -0
  16. package/src/_internal/heartbeat.ts +167 -0
  17. package/src/_internal/help-catalog.ts +241 -0
  18. package/src/_internal/help.ts +95 -0
  19. package/src/_internal/nats-connection.ts +34 -0
  20. package/src/_internal/page-responses.ts +40 -0
  21. package/src/_internal/process-sync.ts +117 -0
  22. package/src/_internal/readiness.ts +3 -0
  23. package/src/_internal/registry-validation.ts +136 -0
  24. package/src/_internal/registry-watch.ts +52 -0
  25. package/src/_internal/registry.ts +338 -0
  26. package/src/_internal/runtime-compatibility.ts +64 -0
  27. package/src/_internal/runtime-context.ts +84 -0
  28. package/src/_internal/runtime-watcher.ts +78 -0
  29. package/src/_internal/static-assets.ts +86 -0
  30. package/src/_internal/status-preserving-ssr.ts +49 -0
  31. package/src/access/PermissionEditor.tsx +486 -0
  32. package/src/access/ResourceApiKeys.tsx +271 -0
  33. package/src/access/messages.ts +121 -0
  34. package/src/access/ui.ts +16 -0
  35. package/src/account/Avatar.tsx +28 -0
  36. package/src/account/EntitySearch.tsx +363 -0
  37. package/src/account/avatar-upload-dialog.tsx +197 -0
  38. package/src/account/avatar-upload.ts +149 -0
  39. package/src/account/ui.ts +3 -0
  40. package/src/ai/admin.ts +47 -0
  41. package/src/ai/approval-routes.ts +130 -0
  42. package/src/ai/approvals.ts +139 -0
  43. package/src/ai/assistant-models.ts +61 -0
  44. package/src/ai/attachments.ts +40 -0
  45. package/src/ai/browser.ts +92 -0
  46. package/src/ai/capabilities.ts +714 -0
  47. package/src/ai/capability-execution.ts +151 -0
  48. package/src/ai/chat/blocks.render.test.tsx +1108 -0
  49. package/src/ai/chat/blocks.tsx +730 -0
  50. package/src/ai/chat/builtin-tools.tsx +428 -0
  51. package/src/ai/chat/capability-table.tsx +87 -0
  52. package/src/ai/chat/composer-adapter.ts +169 -0
  53. package/src/ai/chat/file-tools.tsx +81 -0
  54. package/src/ai/chat/message-actions.tsx +370 -0
  55. package/src/ai/chat/message-utils.ts +479 -0
  56. package/src/ai/chat/messages.ts +43 -0
  57. package/src/ai/chat/presentation.tsx +395 -0
  58. package/src/ai/chat/primitives.tsx +3 -0
  59. package/src/ai/chat/tool-disclosure.tsx +41 -0
  60. package/src/ai/chat/turn-navigator-utils.ts +28 -0
  61. package/src/ai/chat/turn-navigator.tsx +164 -0
  62. package/src/ai/chat/user-message.tsx +149 -0
  63. package/src/ai/chat/visual-tools.tsx +435 -0
  64. package/src/ai/chat/web-tools.tsx +202 -0
  65. package/src/ai/chat-task-contracts.ts +113 -0
  66. package/src/ai/chat-tasks.ts +952 -0
  67. package/src/ai/client/controller.ts +1211 -0
  68. package/src/ai/client/file-source.ts +95 -0
  69. package/src/ai/client/live-connection.ts +140 -0
  70. package/src/ai/client/projection.ts +178 -0
  71. package/src/ai/client/transport.ts +111 -0
  72. package/src/ai/compaction.ts +182 -0
  73. package/src/ai/credentials.ts +124 -0
  74. package/src/ai/default-tool-contracts.ts +108 -0
  75. package/src/ai/default-tools.ts +127 -0
  76. package/src/ai/enrich.ts +280 -0
  77. package/src/ai/executor.ts +1624 -0
  78. package/src/ai/fetch-file-tool.ts +313 -0
  79. package/src/ai/file-context.ts +92 -0
  80. package/src/ai/file-media-type.ts +28 -0
  81. package/src/ai/file-mount.ts +16 -0
  82. package/src/ai/file-tools.ts +566 -0
  83. package/src/ai/files-store.ts +390 -0
  84. package/src/ai/firecrawl-tools.ts +305 -0
  85. package/src/ai/grids-skill.ts +126 -0
  86. package/src/ai/http.ts +265 -0
  87. package/src/ai/index.ts +337 -0
  88. package/src/ai/kit-skill.ts +22 -0
  89. package/src/ai/limits.ts +5 -0
  90. package/src/ai/live-events.ts +289 -0
  91. package/src/ai/live-messages.ts +45 -0
  92. package/src/ai/live-outbox.ts +102 -0
  93. package/src/ai/live-routes.ts +412 -0
  94. package/src/ai/live.ts +2 -0
  95. package/src/ai/maintenance.ts +302 -0
  96. package/src/ai/markdown-pdf-tool.ts +95 -0
  97. package/src/ai/memories.ts +605 -0
  98. package/src/ai/memory-learning-runs.ts +222 -0
  99. package/src/ai/memory-learning.ts +619 -0
  100. package/src/ai/memory-tool.ts +120 -0
  101. package/src/ai/memory-workflow-evidence.ts +158 -0
  102. package/src/ai/migrate.ts +2082 -0
  103. package/src/ai/model-access-migrate.ts +30 -0
  104. package/src/ai/model-access.ts +191 -0
  105. package/src/ai/personal-agent.ts +6 -0
  106. package/src/ai/prefs.ts +72 -0
  107. package/src/ai/project-tool.ts +94 -0
  108. package/src/ai/projects-routes.ts +277 -0
  109. package/src/ai/projects.ts +902 -0
  110. package/src/ai/protocol.ts +279 -0
  111. package/src/ai/provider.ts +73 -0
  112. package/src/ai/public-projection.ts +25 -0
  113. package/src/ai/resource-markers.ts +31 -0
  114. package/src/ai/resource-refs.ts +70 -0
  115. package/src/ai/routes.ts +1131 -0
  116. package/src/ai/runtime-tools.ts +39 -0
  117. package/src/ai/runtime.ts +544 -0
  118. package/src/ai/settings.ts +529 -0
  119. package/src/ai/short-id.ts +45 -0
  120. package/src/ai/skill-catalog.ts +73 -0
  121. package/src/ai/skill-format.ts +145 -0
  122. package/src/ai/skill-seeds.ts +430 -0
  123. package/src/ai/skill-tool.ts +81 -0
  124. package/src/ai/skills-routes.ts +143 -0
  125. package/src/ai/skills.ts +934 -0
  126. package/src/ai/solid.ts +27 -0
  127. package/src/ai/store.ts +3113 -0
  128. package/src/ai/stream.ts +308 -0
  129. package/src/ai/structured-runs.ts +66 -0
  130. package/src/ai/structured.ts +186 -0
  131. package/src/ai/system-prompt.ts +170 -0
  132. package/src/ai/task-prompt.ts +22 -0
  133. package/src/ai/timeline.ts +148 -0
  134. package/src/ai/tool-audit.ts +177 -0
  135. package/src/ai/tool-result-budget.ts +16 -0
  136. package/src/ai/tools.ts +155 -0
  137. package/src/ai/types.ts +967 -0
  138. package/src/ai/ui.tsx +39 -0
  139. package/src/ai/usage-migrate.ts +81 -0
  140. package/src/ai/usage.ts +315 -0
  141. package/src/ai/validate.ts +54 -0
  142. package/src/ai/vision-tool.ts +79 -0
  143. package/src/api/accounts-entities.ts +174 -0
  144. package/src/api/admin-ai-projects.ts +74 -0
  145. package/src/api/admin-ai-skills.ts +76 -0
  146. package/src/api/admin-ai-usage.ts +42 -0
  147. package/src/api/admin-core-settings.ts +508 -0
  148. package/src/api/admin-identity.ts +148 -0
  149. package/src/api/admin-lifecycle.ts +206 -0
  150. package/src/api/admin-linux-identities.ts +66 -0
  151. package/src/api/announcements.ts +131 -0
  152. package/src/api/app-approval.ts +129 -0
  153. package/src/api/apps.ts +51 -0
  154. package/src/api/auth/schemas.ts +54 -0
  155. package/src/api/auth.ts +370 -0
  156. package/src/api/capabilities.ts +658 -0
  157. package/src/api/help-messages.ts +19 -0
  158. package/src/api/help.ts +78 -0
  159. package/src/api/index.ts +108 -0
  160. package/src/api/mcp.ts +744 -0
  161. package/src/api/me-rail.ts +45 -0
  162. package/src/api/me.ts +753 -0
  163. package/src/api/search/schemas.ts +79 -0
  164. package/src/api/search.bench.ts +185 -0
  165. package/src/api/search.ts +407 -0
  166. package/src/api/sync-ops.ts +79 -0
  167. package/src/api/widgets.ts +143 -0
  168. package/src/browser/CloudResourceSearch.behavior.test.tsx +74 -0
  169. package/src/browser/CloudResourceSearch.tsx +791 -0
  170. package/src/browser/app-approval-vault.ts +305 -0
  171. package/src/browser/app-approval.ts +234 -0
  172. package/src/browser/live-websocket.ts +268 -0
  173. package/src/browser/locale-preference.ts +25 -0
  174. package/src/browser/notification-target.ts +27 -0
  175. package/src/browser/notification-timeout.ts +14 -0
  176. package/src/browser/notifications.ts +181 -0
  177. package/src/browser/resource-clipboard.ts +70 -0
  178. package/src/browser/resource-picker.tsx +39 -0
  179. package/src/browser/resource-search-messages.ts +55 -0
  180. package/src/browser/resource-search.ts +27 -0
  181. package/src/capabilities/client.ts +149 -0
  182. package/src/capabilities/response.ts +39 -0
  183. package/src/capabilities/server.ts +215 -0
  184. package/src/capabilities/signals.ts +4 -0
  185. package/src/capabilities/testing.ts +12 -0
  186. package/src/capabilities/types.ts +32 -0
  187. package/src/cli/access.ts +499 -0
  188. package/src/cli/account.ts +382 -0
  189. package/src/cli/admin/account-administration.ts +45 -0
  190. package/src/cli/admin/account-categories.ts +49 -0
  191. package/src/cli/admin/ai-usage.ts +118 -0
  192. package/src/cli/admin/app-sign-in.ts +49 -0
  193. package/src/cli/admin/data.ts +343 -0
  194. package/src/cli/admin/documentation.ts +34 -0
  195. package/src/cli/admin/gateway.ts +155 -0
  196. package/src/cli/admin/index.ts +61 -0
  197. package/src/cli/admin/instance.ts +250 -0
  198. package/src/cli/admin/jobs.ts +223 -0
  199. package/src/cli/admin/legal.ts +122 -0
  200. package/src/cli/admin/linux.ts +53 -0
  201. package/src/cli/admin/logs.ts +324 -0
  202. package/src/cli/admin/metrics.ts +142 -0
  203. package/src/cli/admin/nats.ts +167 -0
  204. package/src/cli/admin/notifications.ts +516 -0
  205. package/src/cli/admin/shared.ts +113 -0
  206. package/src/cli/admin/sync.ts +188 -0
  207. package/src/cli/admin/telemetry.ts +314 -0
  208. package/src/cli/admin/webhooks.ts +222 -0
  209. package/src/cli/admin/workflows.ts +367 -0
  210. package/src/cli/apps.ts +40 -0
  211. package/src/cli/capabilities.ts +239 -0
  212. package/src/cli/commands.ts +604 -0
  213. package/src/cli/index.ts +61 -0
  214. package/src/cli/locale.ts +31 -0
  215. package/src/cli/output.ts +58 -0
  216. package/src/clients/core.ts +20 -0
  217. package/src/config/env.ts +54 -0
  218. package/src/config/index.ts +6 -0
  219. package/src/contracts/account-categories.ts +62 -0
  220. package/src/contracts/announcements.ts +121 -0
  221. package/src/contracts/app-approval.ts +197 -0
  222. package/src/contracts/app.ts +162 -0
  223. package/src/contracts/capabilities.ts +484 -0
  224. package/src/contracts/index.ts +14 -0
  225. package/src/contracts/notification-live.ts +66 -0
  226. package/src/contracts/notification-types.ts +235 -0
  227. package/src/contracts/posix.ts +69 -0
  228. package/src/contracts/profile.ts +85 -0
  229. package/src/contracts/rail-preferences.ts +53 -0
  230. package/src/contracts/registry.ts +110 -0
  231. package/src/contracts/resource-clipboard.ts +33 -0
  232. package/src/contracts/settings-types.ts +98 -0
  233. package/src/contracts/shared.ts +408 -0
  234. package/src/contracts/user-notifications.ts +101 -0
  235. package/src/contracts/widgets.ts +183 -0
  236. package/src/desktop/index.ts +704 -0
  237. package/src/desktop/solid.tsx +938 -0
  238. package/src/index.ts +58 -0
  239. package/src/server/actor.ts +41 -0
  240. package/src/server/api/index.ts +2 -0
  241. package/src/server/api/respond.ts +96 -0
  242. package/src/server/api-client.ts +54 -0
  243. package/src/server/app-context.ts +39 -0
  244. package/src/server/help.ts +187 -0
  245. package/src/server/index.ts +89 -0
  246. package/src/server/locale.ts +55 -0
  247. package/src/server/middleware/auth.ts +386 -0
  248. package/src/server/middleware/index.ts +28 -0
  249. package/src/server/middleware/invocation.ts +55 -0
  250. package/src/server/middleware/middleware.ts +65 -0
  251. package/src/server/middleware/openapi.ts +126 -0
  252. package/src/server/middleware/rate-limit.ts +125 -0
  253. package/src/server/middleware/request-logger.ts +41 -0
  254. package/src/server/middleware/route-template.ts +46 -0
  255. package/src/server/middleware/runtime.ts +22 -0
  256. package/src/server/middleware/settings.ts +55 -0
  257. package/src/server/middleware/validator.ts +49 -0
  258. package/src/server/middleware/workload.ts +22 -0
  259. package/src/server/ratelimit.ts +151 -0
  260. package/src/server/request-cookies.ts +18 -0
  261. package/src/server/services/access.ts +644 -0
  262. package/src/server/services/freeipa/client.ts +137 -0
  263. package/src/server/services/freeipa/index.ts +9 -0
  264. package/src/server/services/freeipa/session.ts +123 -0
  265. package/src/server/services/freeipa/test-certificates.ts +44 -0
  266. package/src/server/services/freeipa/tls.ts +44 -0
  267. package/src/server/services/freeipa/transport.ts +116 -0
  268. package/src/server/services/freeipa/util.ts +59 -0
  269. package/src/server/services/geo.ts +198 -0
  270. package/src/server/services/index.ts +48 -0
  271. package/src/server/services/pagination.ts +22 -0
  272. package/src/server/services/services.ts +13 -0
  273. package/src/server/time.ts +33 -0
  274. package/src/services/account-category-policy.ts +51 -0
  275. package/src/services/account-lifecycle/audit.ts +41 -0
  276. package/src/services/account-lifecycle/index.ts +940 -0
  277. package/src/services/account-lifecycle/ipa-backfill.ts +152 -0
  278. package/src/services/account-lifecycle/notification-sender.ts +13 -0
  279. package/src/services/account-lifecycle/scheduler.ts +506 -0
  280. package/src/services/account-model.ts +22 -0
  281. package/src/services/accounts/app.ts +1671 -0
  282. package/src/services/accounts/authz.ts +44 -0
  283. package/src/services/accounts/avatar.ts +120 -0
  284. package/src/services/accounts/base-group.ts +11 -0
  285. package/src/services/accounts/base-user.ts +46 -0
  286. package/src/services/accounts/duplicate-emails.ts +82 -0
  287. package/src/services/accounts/entities.ts +622 -0
  288. package/src/services/accounts/group-sql.ts +106 -0
  289. package/src/services/accounts/groups.ts +272 -0
  290. package/src/services/accounts/index.ts +14 -0
  291. package/src/services/accounts/ipa-data.ts +66 -0
  292. package/src/services/accounts/lifecycle.ts +2 -0
  293. package/src/services/accounts/local-groups.ts +499 -0
  294. package/src/services/accounts/model.ts +129 -0
  295. package/src/services/accounts/notification-sender.ts +31 -0
  296. package/src/services/accounts/posix.ts +386 -0
  297. package/src/services/accounts/request-policy.ts +11 -0
  298. package/src/services/accounts/switching.ts +126 -0
  299. package/src/services/accounts/users.ts +745 -0
  300. package/src/services/announcements/index.ts +224 -0
  301. package/src/services/app-approval.ts +498 -0
  302. package/src/services/audit/index.ts +438 -0
  303. package/src/services/auth-flows/index.ts +15 -0
  304. package/src/services/auth-flows/ipa.ts +197 -0
  305. package/src/services/auth-flows/magic-link.ts +185 -0
  306. package/src/services/auth-flows/notification-sender.ts +10 -0
  307. package/src/services/auth-flows/password-reset.ts +268 -0
  308. package/src/services/auth-flows/proxy-return.ts +49 -0
  309. package/src/services/document-extraction.ts +148 -0
  310. package/src/services/freeipa-config.ts +179 -0
  311. package/src/services/gateway.ts +186 -0
  312. package/src/services/identity/constants.ts +18 -0
  313. package/src/services/identity/index.ts +52 -0
  314. package/src/services/identity/invocation-actor.ts +120 -0
  315. package/src/services/identity/invocation-authority.ts +53 -0
  316. package/src/services/identity/invocation-operations.ts +15 -0
  317. package/src/services/identity/invocation-token.ts +276 -0
  318. package/src/services/identity/key-config.ts +41 -0
  319. package/src/services/identity/key-ring.ts +530 -0
  320. package/src/services/identity/metrics.ts +29 -0
  321. package/src/services/identity/routes.ts +18 -0
  322. package/src/services/identity/runtime-config.ts +88 -0
  323. package/src/services/identity/session-token.ts +152 -0
  324. package/src/services/identity/signer-refresh.ts +44 -0
  325. package/src/services/identity/workload-auth.ts +64 -0
  326. package/src/services/index.ts +187 -0
  327. package/src/services/ipa/auth.ts +216 -0
  328. package/src/services/ipa/connection.ts +57 -0
  329. package/src/services/ipa/effective-groups.ts +70 -0
  330. package/src/services/ipa/groups.ts +722 -0
  331. package/src/services/ipa/guard.ts +17 -0
  332. package/src/services/ipa/index.ts +17 -0
  333. package/src/services/ipa/posix.ts +19 -0
  334. package/src/services/ipa/profile.ts +132 -0
  335. package/src/services/ipa/runtime.ts +28 -0
  336. package/src/services/ipa/search.ts +154 -0
  337. package/src/services/ipa/service-account.ts +15 -0
  338. package/src/services/ipa/sync-planning.ts +100 -0
  339. package/src/services/ipa/sync.ts +862 -0
  340. package/src/services/ipa/users.ts +806 -0
  341. package/src/services/legal-consent.ts +76 -0
  342. package/src/services/logging/index.ts +477 -0
  343. package/src/services/logging/redaction.ts +20 -0
  344. package/src/services/logging/trace.ts +1231 -0
  345. package/src/services/mandates/index.ts +855 -0
  346. package/src/services/mandates/policy.ts +85 -0
  347. package/src/services/network-security.ts +31 -0
  348. package/src/services/notifications/batches.ts +722 -0
  349. package/src/services/notifications/browser.ts +252 -0
  350. package/src/services/notifications/catalog.ts +113 -0
  351. package/src/services/notifications/channels.ts +104 -0
  352. package/src/services/notifications/dispatcher.ts +139 -0
  353. package/src/services/notifications/email.ts +118 -0
  354. package/src/services/notifications/index.ts +633 -0
  355. package/src/services/notifications/live.ts +50 -0
  356. package/src/services/notifications/observability.ts +407 -0
  357. package/src/services/notifications/platform.ts +421 -0
  358. package/src/services/notifications/runtime.ts +120 -0
  359. package/src/services/notifications/user.ts +248 -0
  360. package/src/services/notifications/web-push-transport.ts +135 -0
  361. package/src/services/oauth-tokens.ts +209 -0
  362. package/src/services/outbox.ts +187 -0
  363. package/src/services/pdf/gotenberg.ts +290 -0
  364. package/src/services/pdf/index.ts +43 -0
  365. package/src/services/pdf/markdown.ts +209 -0
  366. package/src/services/pdf/template-preview.ts +122 -0
  367. package/src/services/postgres.ts +76 -0
  368. package/src/services/providers/index.ts +27 -0
  369. package/src/services/providers/local/auth.ts +51 -0
  370. package/src/services/providers/local/index.ts +4 -0
  371. package/src/services/providers/local/users.ts +263 -0
  372. package/src/services/rail-preferences.ts +27 -0
  373. package/src/services/runtime-lifecycle.ts +191 -0
  374. package/src/services/secrets.ts +10 -0
  375. package/src/services/service-account-credentials.ts +891 -0
  376. package/src/services/service-accounts.ts +184 -0
  377. package/src/services/session/index.ts +236 -0
  378. package/src/services/session/test-fixture.ts +18 -0
  379. package/src/services/session/user.ts +144 -0
  380. package/src/services/settings/api.ts +61 -0
  381. package/src/services/settings/app.ts +86 -0
  382. package/src/services/settings/core-settings.ts +796 -0
  383. package/src/services/settings/crypto.ts +69 -0
  384. package/src/services/settings/defaults.ts +374 -0
  385. package/src/services/settings/index.ts +215 -0
  386. package/src/services/settings/namespace.ts +9 -0
  387. package/src/services/settings/snapshot.ts +49 -0
  388. package/src/services/settings/store.ts +241 -0
  389. package/src/services/settings/templates.ts +4 -0
  390. package/src/services/sync-ops.ts +403 -0
  391. package/src/services/topic-cursor.ts +22 -0
  392. package/src/services/weather/forecast.ts +323 -0
  393. package/src/services/weather/geo.ts +119 -0
  394. package/src/services/weather/index.ts +67 -0
  395. package/src/services/weather/location.ts +24 -0
  396. package/src/services/weather/locations.ts +133 -0
  397. package/src/services/weather/migrate.ts +45 -0
  398. package/src/services/weather/settings.ts +66 -0
  399. package/src/services/weather/short-id.ts +57 -0
  400. package/src/services/weather/types.ts +61 -0
  401. package/src/services/weather/ui.ts +50 -0
  402. package/src/services/webauthn.ts +385 -0
  403. package/src/shared/account-action-notice.ts +70 -0
  404. package/src/shared/account-display.ts +15 -0
  405. package/src/shared/account-session.ts +15 -0
  406. package/src/shared/ai-platform-prompt.ts +134 -0
  407. package/src/shared/ai-usage.ts +49 -0
  408. package/src/shared/app-presentation.ts +48 -0
  409. package/src/shared/app-url.ts +12 -0
  410. package/src/shared/branding.ts +14 -0
  411. package/src/shared/capability-messages.ts +70 -0
  412. package/src/shared/email-html.ts +54 -0
  413. package/src/shared/format.ts +91 -0
  414. package/src/shared/help.ts +68 -0
  415. package/src/shared/icons.ts +400 -0
  416. package/src/shared/index.ts +54 -0
  417. package/src/shared/locale.ts +48 -0
  418. package/src/shared/login-method.ts +44 -0
  419. package/src/shared/markdown/client.ts +130 -0
  420. package/src/shared/markdown/extensions/code.ts +105 -0
  421. package/src/shared/markdown/extensions/guided-help.ts +100 -0
  422. package/src/shared/markdown/extensions/images.ts +79 -0
  423. package/src/shared/markdown/extensions/info-blocks.ts +97 -0
  424. package/src/shared/markdown/extensions/katex.ts +120 -0
  425. package/src/shared/markdown/extensions/links.ts +43 -0
  426. package/src/shared/markdown/extensions/mark.ts +48 -0
  427. package/src/shared/markdown/extensions/sub-sup.ts +60 -0
  428. package/src/shared/markdown/extensions/tables.ts +109 -0
  429. package/src/shared/markdown/extensions/task-list.ts +53 -0
  430. package/src/shared/markdown/formula.ts +1187 -0
  431. package/src/shared/markdown/index.ts +193 -0
  432. package/src/shared/markdown/shared.ts +36 -0
  433. package/src/shared/mock-cover.ts +130 -0
  434. package/src/shared/network-address.ts +106 -0
  435. package/src/shared/redirect.ts +56 -0
  436. package/src/shared/template-rendering.ts +140 -0
  437. package/src/shared/theme.ts +68 -0
  438. package/src/shared/time.ts +13 -0
  439. package/src/ssr/AdminLayout.tsx +53 -0
  440. package/src/ssr/AdminSidebar.tsx +50 -0
  441. package/src/ssr/AppLaunchpad.island.tsx +236 -0
  442. package/src/ssr/AppWorkspaceController.island.tsx +21 -0
  443. package/src/ssr/BrowserNotifications.island.tsx +135 -0
  444. package/src/ssr/GlobalAnnouncements.island.tsx +142 -0
  445. package/src/ssr/GlobalSearchDialog.behavior.test.tsx +96 -0
  446. package/src/ssr/GlobalSearchDialog.tsx +35 -0
  447. package/src/ssr/GlobalSearchHelpDialog.tsx +104 -0
  448. package/src/ssr/GlobalSearchTrigger.island.tsx +55 -0
  449. package/src/ssr/HotkeysHelpRail.island.tsx +55 -0
  450. package/src/ssr/Layout.render.test.tsx +148 -0
  451. package/src/ssr/Layout.tsx +292 -0
  452. package/src/ssr/LayoutBreadcrumbs.island.tsx +44 -0
  453. package/src/ssr/LayoutFooter.tsx +22 -0
  454. package/src/ssr/LayoutHeader.tsx +81 -0
  455. package/src/ssr/LayoutHelp.tsx +869 -0
  456. package/src/ssr/LayoutPreferences.island.tsx +36 -0
  457. package/src/ssr/LayoutRail.tsx +58 -0
  458. package/src/ssr/MinimalLayout.tsx +46 -0
  459. package/src/ssr/PageError.tsx +29 -0
  460. package/src/ssr/ProfilePreferences.island.tsx +92 -0
  461. package/src/ssr/RailApps.island.tsx +61 -0
  462. package/src/ssr/RailEditor.tsx +293 -0
  463. package/src/ssr/RegisteredHelpDocuments.island.tsx +3 -0
  464. package/src/ssr/TimezoneCookie.island.tsx +23 -0
  465. package/src/ssr/admin-active-link.ts +47 -0
  466. package/src/ssr/admin-navigation.ts +78 -0
  467. package/src/ssr/app-appearance.ts +23 -0
  468. package/src/ssr/app-navigation.ts +41 -0
  469. package/src/ssr/help-messages.ts +104 -0
  470. package/src/ssr/index.ts +14 -0
  471. package/src/ssr/islands/SearchBar.island.tsx +80 -0
  472. package/src/ssr/islands/index.ts +16 -0
  473. package/src/ssr/layout-context.ts +17 -0
  474. package/src/ssr/layout-help-markdown.ts +9 -0
  475. package/src/ssr/layout-help-navigation.ts +24 -0
  476. package/src/ssr/layout-help-url.ts +5 -0
  477. package/src/ssr/layout-runtime.ts +22 -0
  478. package/src/ssr/page-error-messages.ts +25 -0
  479. package/src/ssr/platform-messages.ts +135 -0
  480. package/src/ssr/preference-controller.ts +44 -0
  481. package/src/ssr/profile-preferences-messages.ts +29 -0
  482. package/src/ssr/rail-context.ts +21 -0
  483. package/src/ssr/rail-messages.ts +66 -0
  484. package/src/ssr/rail-navigation.ts +60 -0
  485. package/src/ssr/runtime.ts +31 -0
  486. package/src/ssr/url-filter.ts +127 -0
  487. package/src/styles/base-popover.css +36 -0
  488. package/src/styles/effects.css +851 -0
  489. package/src/styles/global.css +268 -0
  490. package/src/styles/input.css +58 -0
  491. package/src/styles/tokens.css +230 -0
  492. package/src/styles/utilities-buttons.css +405 -0
  493. package/src/styles/utilities-data.css +33 -0
  494. package/src/styles/utilities-feedback.css +232 -0
  495. package/src/styles/utilities-layout.css +603 -0
  496. package/src/styles/utilities-markdown-editor.css +525 -0
  497. package/src/styles/utilities-markdown-table.css +234 -0
  498. package/src/styles/utilities-navigation.css +1054 -0
  499. package/src/types/ambient.d.ts +24 -0
  500. package/src/workflows/ai/index.ts +17 -0
  501. package/src/workflows/ai/runtime.ts +286 -0
  502. package/src/workflows/ai/store.ts +314 -0
  503. package/src/workflows/ai/types.ts +111 -0
  504. package/src/workflows/ai-actions.ts +269 -0
  505. package/src/workflows/authoring.ts +88 -0
  506. package/src/workflows/builtins.ts +193 -0
  507. package/src/workflows/contracts.ts +280 -0
  508. package/src/workflows/definition.ts +334 -0
  509. package/src/workflows/editor.ts +113 -0
  510. package/src/workflows/index.ts +71 -0
  511. package/src/workflows/language/binder.ts +45 -0
  512. package/src/workflows/language/canonical.ts +29 -0
  513. package/src/workflows/language/compiler.ts +396 -0
  514. package/src/workflows/language/expressions.ts +34 -0
  515. package/src/workflows/language/index.ts +20 -0
  516. package/src/workflows/language/references.ts +55 -0
  517. package/src/workflows/language/schema.ts +134 -0
  518. package/src/workflows/language/strict-yaml.ts +131 -0
  519. package/src/workflows/manifest.ts +24 -0
  520. package/src/workflows/module.ts +12 -0
  521. package/src/workflows/runtime/coordinator.ts +115 -0
  522. package/src/workflows/runtime/executor.ts +1003 -0
  523. package/src/workflows/runtime/index.ts +60 -0
  524. package/src/workflows/runtime/instant.ts +8 -0
  525. package/src/workflows/runtime/ports.ts +213 -0
  526. package/src/workflows/runtime/schedule.ts +203 -0
  527. package/src/workflows/runtime/trigger.ts +37 -0
  528. package/src/workflows/runtime/wake.ts +13 -0
  529. package/src/workflows/store/actions.ts +438 -0
  530. package/src/workflows/store/budget.ts +145 -0
  531. package/src/workflows/store/definitions.ts +345 -0
  532. package/src/workflows/store/events.ts +383 -0
  533. package/src/workflows/store/index.ts +107 -0
  534. package/src/workflows/store/observability.ts +594 -0
  535. package/src/workflows/store/runs.ts +975 -0
  536. package/src/workflows/store/transaction.ts +23 -0
  537. package/src/workflows/store/worker.ts +439 -0
  538. package/src/workflows/testing/conformance.ts +72 -0
  539. package/src/workflows/testing/index.ts +11 -0
  540. package/src/workflows/testing/process-fixtures.ts +275 -0
package/src/api/me.ts ADDED
@@ -0,0 +1,753 @@
1
+ /**
2
+ * Self-service endpoints — everything a logged-in user does with their OWN
3
+ * account. Owned by core, mounted at /api/me/*. Auth flows live in /auth;
4
+ * third-party management lives in the accounts admin app.
5
+ */
6
+
7
+ import { ok } from "@k2b/stdlib";
8
+ import { Hono, type MiddlewareHandler } from "hono";
9
+ import { createMiddleware } from "hono/factory";
10
+ import { describeRoute } from "hono-openapi";
11
+ import { z } from "zod";
12
+ import {
13
+ AccountActivityListResponseSchema,
14
+ BrowserNotificationConfigurationSchema,
15
+ BrowserNotificationEndpointSchema,
16
+ BrowserPushSubscriptionSchema,
17
+ ChangePasswordSchema,
18
+ CreateAccountRequestSchema,
19
+ CreateUserApiKeyResponseSchema,
20
+ CreateUserApiKeySchema,
21
+ CreateWebAuthnPasskeySchema,
22
+ ErrorResponseSchema,
23
+ ListWebAuthnPasskeysResponseSchema,
24
+ MessageResponseSchema,
25
+ NotificationDeliveryStatusSchema,
26
+ RegisterBrowserNotificationEndpointSchema,
27
+ ServiceAccountCredentialSchema,
28
+ UpdateAvatarResponseSchema,
29
+ UpdateAvatarSchema,
30
+ UpdateProfileSchema,
31
+ UpdateUserNotificationPreferenceSchema,
32
+ UserNotificationHistoryResponseSchema,
33
+ UserNotificationPreferenceSchema,
34
+ UserNotificationPreferencesResponseSchema,
35
+ UserSchema,
36
+ WebAuthnPasskeySchema,
37
+ } from "../contracts";
38
+ import { CapabilityAppIdSchema } from "../contracts/capabilities";
39
+ import { type AuthContext, auth, getLocale, jsonResponse, rateLimit, requiresAuth, respond, v } from "../server";
40
+ import {
41
+ accountLifecycle,
42
+ accountsAppService as accountsService,
43
+ audit,
44
+ browserNotifications,
45
+ mandates,
46
+ notifications,
47
+ serviceAccountCredentials,
48
+ webauthn,
49
+ } from "../services";
50
+ import { MandatePolicyV1Schema } from "../services/mandates";
51
+
52
+ import { createMeRailRoutes } from "./me-rail";
53
+
54
+ const toAccountsActor = (user: AuthContext["Variables"]["user"]) => ({
55
+ userId: user.id,
56
+ uid: user.uid,
57
+ roles: user.roles,
58
+ provider: user.provider,
59
+ });
60
+
61
+ /**
62
+ * Guards the endpoints that manage how the account is authenticated: passkeys,
63
+ * API keys, the password, and account deletion.
64
+ *
65
+ * `auth.requireUser()` is not enough for these. A personal API key acts as
66
+ * its user, so it passes that check — and could then enrol a passkey, which is
67
+ * a full account takeover, or mint further keys that outlive the revocation of
68
+ * the one that was leaked. No scope in the vocabulary means "may add an
69
+ * authenticator", so a credential must not reach these endpoints at all.
70
+ *
71
+ * A credential may still *read* its account's passkeys and keys; only the
72
+ * mutations are gated. Browser sessions and user-issued OAuth access tokens
73
+ * both resolve to a `user` actor and are unaffected.
74
+ */
75
+ const requireDirectUserActor = createMiddleware<AuthContext>(async (c, next) => {
76
+ if (c.get("actor")?.kind !== "user") {
77
+ return c.json(
78
+ {
79
+ message: "Credentials cannot manage account authentication. Sign in to change passkeys, API keys, or your password.",
80
+ code: "FORBIDDEN",
81
+ },
82
+ 403,
83
+ );
84
+ }
85
+ return next();
86
+ });
87
+
88
+ const ExtendAccountResponseSchema = z.object({
89
+ message: z.string(),
90
+ newExpiry: z.string().datetime().optional(),
91
+ });
92
+
93
+ const AccountRequestResponseSchema = z.object({
94
+ id: z.uuid(),
95
+ message: z.string(),
96
+ });
97
+
98
+ const ListApiKeysResponseSchema = z.object({
99
+ items: z.array(ServiceAccountCredentialSchema),
100
+ });
101
+
102
+ const AccountActivityQuerySchema = z.object({
103
+ days: z.coerce
104
+ .number()
105
+ .int()
106
+ .pipe(z.union([z.literal(7), z.literal(30), z.literal(90)]))
107
+ .optional()
108
+ .default(30),
109
+ });
110
+ const MandateListQuerySchema = z
111
+ .object({
112
+ page: z.coerce.number().int().min(1).default(1),
113
+ perPage: z.coerce.number().int().min(1).max(100).default(50),
114
+ state: z.enum(["active", "paused", "revoked"]).optional(),
115
+ })
116
+ .strict();
117
+ const CreatePendingMandateSchema = z
118
+ .object({
119
+ ownerAppId: CapabilityAppIdSchema,
120
+ workloadType: z
121
+ .string()
122
+ .trim()
123
+ .min(1)
124
+ .max(120)
125
+ .regex(/^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/),
126
+ workloadId: z.string().trim().min(1).max(200),
127
+ policy: MandatePolicyV1Schema,
128
+ expiresAt: z.iso.datetime().nullable().optional(),
129
+ })
130
+ .strict();
131
+
132
+ const requireSessionMandateCreation = createMiddleware<AuthContext>(async (c, next) => {
133
+ if (c.get("credentialKind") !== "session" || c.get("actor")?.kind !== "user") {
134
+ return c.json({ code: "FORBIDDEN", message: "Sign in with a browser session to create background authority" }, 403);
135
+ }
136
+ return next();
137
+ });
138
+
139
+ type MeMandateDependencies = Pick<typeof mandates, "createPending" | "list">;
140
+
141
+ export const createMeMandateRoutes = (
142
+ service: MeMandateDependencies = mandates,
143
+ contextSetup: MiddlewareHandler<AuthContext> = async (_c, next) => next(),
144
+ ) =>
145
+ new Hono<AuthContext>()
146
+ .use("*", contextSetup)
147
+ .get("/mandates", v("query", MandateListQuerySchema), async (c) => {
148
+ const query = c.req.valid("query");
149
+ return c.json(
150
+ await service.list({
151
+ scope: { kind: "user", userId: c.get("user").id },
152
+ pagination: { page: query.page, perPage: query.perPage },
153
+ filter: { state: query.state },
154
+ }),
155
+ );
156
+ })
157
+ .post("/mandates", requireSessionMandateCreation, v("json", CreatePendingMandateSchema), async (c) => {
158
+ const user = c.get("user");
159
+ const input = c.req.valid("json");
160
+ return respond(
161
+ c,
162
+ () =>
163
+ service.createPending({
164
+ authority: { kind: "interactive", userId: user.id },
165
+ subject: { type: "user", id: user.id },
166
+ ownerAppId: input.ownerAppId,
167
+ workloadType: input.workloadType,
168
+ workloadId: input.workloadId,
169
+ policy: input.policy,
170
+ expiresAt: input.expiresAt,
171
+ }),
172
+ 201,
173
+ );
174
+ });
175
+
176
+ const NotificationDefinitionParamSchema = z.object({ definitionId: z.string().min(1).max(200) });
177
+ const DisableBrowserNotificationEndpointSchema = z.object({ subscription: BrowserPushSubscriptionSchema });
178
+ const NotificationHistoryQuerySchema = z.object({
179
+ page: z.coerce.number().int().positive().optional().default(1),
180
+ perPage: z.coerce.number().int().min(1).max(100).optional().default(25),
181
+ status: NotificationDeliveryStatusSchema.optional(),
182
+ });
183
+ const mandateRoutes = createMeMandateRoutes();
184
+ const app = new Hono<AuthContext>()
185
+ .use(rateLimit())
186
+ .use(auth.requireRole("authenticated"))
187
+ .use(auth.requireUser())
188
+ .route("/", mandateRoutes)
189
+ .route("/", createMeRailRoutes())
190
+
191
+ .get(
192
+ "/activity",
193
+ describeRoute({
194
+ tags: ["Me"],
195
+ summary: "List current user account activity",
196
+ description: "List safe self-service audit activity for the authenticated account.",
197
+ ...requiresAuth,
198
+ responses: {
199
+ 200: jsonResponse(AccountActivityListResponseSchema, "Account activity"),
200
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
201
+ },
202
+ }),
203
+ v("query", AccountActivityQuerySchema),
204
+ async (c) =>
205
+ respond(c, async () => {
206
+ const page = await audit.listSelfServiceActivity({
207
+ userId: c.get("user").id,
208
+ days: c.req.valid("query").days,
209
+ pagination: { page: 1, perPage: 50 },
210
+ });
211
+ return ok({ items: page.items });
212
+ }),
213
+ )
214
+
215
+ .get(
216
+ "/notifications/browser/configuration",
217
+ describeRoute({
218
+ tags: ["Me"],
219
+ summary: "Get browser notification configuration",
220
+ description: "Return the public Web Push application key for this Cloud deployment.",
221
+ ...requiresAuth,
222
+ responses: {
223
+ 200: jsonResponse(BrowserNotificationConfigurationSchema, "Browser notification configuration"),
224
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
225
+ },
226
+ }),
227
+ async (c) => respond(c, async () => ok(await browserNotifications.configuration())),
228
+ )
229
+
230
+ .post(
231
+ "/notifications/browser/endpoints",
232
+ describeRoute({
233
+ tags: ["Me"],
234
+ summary: "Register browser notification endpoint",
235
+ description: "Register or refresh a Web Push subscription for the authenticated account.",
236
+ ...requiresAuth,
237
+ responses: {
238
+ 200: jsonResponse(BrowserNotificationEndpointSchema, "Registered browser notification endpoint"),
239
+ 400: jsonResponse(ErrorResponseSchema, "Invalid browser subscription"),
240
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
241
+ },
242
+ }),
243
+ v("json", RegisterBrowserNotificationEndpointSchema),
244
+ async (c) => {
245
+ const data = c.req.valid("json");
246
+ return respond(c, async () =>
247
+ ok(
248
+ await browserNotifications.registerEndpoint({
249
+ userId: c.get("user").id,
250
+ subscription: data.subscription,
251
+ label: data.label,
252
+ }),
253
+ ),
254
+ );
255
+ },
256
+ )
257
+
258
+ .delete(
259
+ "/notifications/browser/endpoints",
260
+ describeRoute({
261
+ tags: ["Me"],
262
+ summary: "Disable browser notification endpoint",
263
+ description: "Disable a Web Push subscription owned by the authenticated account.",
264
+ ...requiresAuth,
265
+ responses: {
266
+ 200: jsonResponse(MessageResponseSchema, "Browser notification endpoint disabled"),
267
+ 400: jsonResponse(ErrorResponseSchema, "Invalid browser subscription"),
268
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
269
+ },
270
+ }),
271
+ v("json", DisableBrowserNotificationEndpointSchema),
272
+ async (c) =>
273
+ respond(c, async () => {
274
+ await browserNotifications.disableEndpoint({
275
+ userId: c.get("user").id,
276
+ subscription: c.req.valid("json").subscription,
277
+ });
278
+ return ok({ message: "Browser notification endpoint disabled." });
279
+ }),
280
+ )
281
+
282
+ .get(
283
+ "/notifications/preferences",
284
+ describeRoute({
285
+ tags: ["Me"],
286
+ summary: "List current user notification preferences",
287
+ description: "List active user-facing notification kinds, app recommendations, required channels, and explicit preferences.",
288
+ ...requiresAuth,
289
+ responses: {
290
+ 200: jsonResponse(UserNotificationPreferencesResponseSchema, "Notification preferences"),
291
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
292
+ },
293
+ }),
294
+ async (c) =>
295
+ respond(c, async () => {
296
+ const data = await notifications.user.preferences.list(c.get("user").id, getLocale(c));
297
+ return ok(data);
298
+ }),
299
+ )
300
+
301
+ .put(
302
+ "/notifications/preferences/:definitionId",
303
+ describeRoute({
304
+ tags: ["Me"],
305
+ summary: "Set current user notification preference",
306
+ description: "Replace optional channels for one notification kind. Required channels remain enforced by the definition.",
307
+ ...requiresAuth,
308
+ responses: {
309
+ 200: jsonResponse(UserNotificationPreferenceSchema, "Updated notification preference"),
310
+ 400: jsonResponse(ErrorResponseSchema, "Invalid or unavailable channel"),
311
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
312
+ 404: jsonResponse(ErrorResponseSchema, "Notification preference not found"),
313
+ },
314
+ }),
315
+ v("param", NotificationDefinitionParamSchema),
316
+ v("json", UpdateUserNotificationPreferenceSchema),
317
+ async (c) =>
318
+ respond(
319
+ c,
320
+ notifications.user.preferences.set({
321
+ userId: c.get("user").id,
322
+ definitionId: c.req.valid("param").definitionId,
323
+ channels: c.req.valid("json").channels,
324
+ locale: getLocale(c),
325
+ }),
326
+ ),
327
+ )
328
+
329
+ .delete(
330
+ "/notifications/preferences/:definitionId",
331
+ describeRoute({
332
+ tags: ["Me"],
333
+ summary: "Reset current user notification preference",
334
+ description: "Remove an explicit preference so the app recommendation applies again.",
335
+ ...requiresAuth,
336
+ responses: {
337
+ 200: jsonResponse(UserNotificationPreferenceSchema, "Reset notification preference"),
338
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
339
+ 404: jsonResponse(ErrorResponseSchema, "Notification preference not found"),
340
+ },
341
+ }),
342
+ v("param", NotificationDefinitionParamSchema),
343
+ async (c) =>
344
+ respond(
345
+ c,
346
+ notifications.user.preferences.reset({
347
+ userId: c.get("user").id,
348
+ definitionId: c.req.valid("param").definitionId,
349
+ locale: getLocale(c),
350
+ }),
351
+ ),
352
+ )
353
+
354
+ .get(
355
+ "/notifications/history",
356
+ describeRoute({
357
+ tags: ["Me"],
358
+ summary: "List current user notification delivery history",
359
+ description: "List bodyless delivery metadata and safe error details for the authenticated account.",
360
+ ...requiresAuth,
361
+ responses: {
362
+ 200: jsonResponse(UserNotificationHistoryResponseSchema, "Notification delivery history"),
363
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
364
+ },
365
+ }),
366
+ v("query", NotificationHistoryQuerySchema),
367
+ async (c) =>
368
+ respond(c, async () => {
369
+ const query = c.req.valid("query");
370
+ const data = await notifications.user.history.list({ userId: c.get("user").id, locale: getLocale(c), ...query });
371
+ return ok(data);
372
+ }),
373
+ )
374
+
375
+ .get(
376
+ "/",
377
+ describeRoute({
378
+ tags: ["Me"],
379
+ summary: "Get current user",
380
+ description: "Return the authenticated user resource.",
381
+ ...requiresAuth,
382
+ responses: {
383
+ 200: jsonResponse(UserSchema, "Current user"),
384
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
385
+ },
386
+ }),
387
+ async (c) => respond(c, ok(c.get("user"))),
388
+ )
389
+
390
+ .patch(
391
+ "/",
392
+ describeRoute({
393
+ tags: ["Me"],
394
+ summary: "Update current user",
395
+ description: "Update the authenticated user's canonical profile fields and IPA-only self-service fields.",
396
+ ...requiresAuth,
397
+ responses: {
398
+ 200: jsonResponse(MessageResponseSchema, "Profile updated"),
399
+ 400: jsonResponse(ErrorResponseSchema, "Failed to update profile"),
400
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
401
+ },
402
+ }),
403
+ v("json", UpdateProfileSchema),
404
+ async (c) =>
405
+ respond(c, async () => {
406
+ const user = c.get("user");
407
+ const data = c.req.valid("json");
408
+ const result = await accountsService.user.update({ actor: toAccountsActor(user), id: user.id, data });
409
+ if (!result.ok) return result;
410
+ return ok({ message: "Profile updated." });
411
+ }),
412
+ )
413
+
414
+ .put(
415
+ "/avatar",
416
+ describeRoute({
417
+ tags: ["Me"],
418
+ summary: "Update current user avatar",
419
+ description: "Store a small profile picture for the authenticated account. Avatars are visible to user-backed authenticated actors.",
420
+ ...requiresAuth,
421
+ responses: {
422
+ 200: jsonResponse(UpdateAvatarResponseSchema, "Avatar updated"),
423
+ 400: jsonResponse(ErrorResponseSchema, "Failed to update avatar"),
424
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
425
+ },
426
+ }),
427
+ v("json", UpdateAvatarSchema),
428
+ async (c) =>
429
+ respond(c, async () => {
430
+ const user = c.get("user");
431
+ const data = c.req.valid("json");
432
+ const result = await accountsService.user.setAvatar({
433
+ actor: toAccountsActor(user),
434
+ id: user.id,
435
+ dataUrl: data.dataUrl,
436
+ });
437
+ if (!result.ok) return result;
438
+ return ok({ message: "Avatar updated.", avatarHash: result.data.avatarHash });
439
+ }),
440
+ )
441
+
442
+ .delete(
443
+ "/avatar",
444
+ describeRoute({
445
+ tags: ["Me"],
446
+ summary: "Delete current user avatar",
447
+ description: "Remove the authenticated account's profile picture.",
448
+ ...requiresAuth,
449
+ responses: {
450
+ 200: jsonResponse(MessageResponseSchema, "Avatar deleted"),
451
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
452
+ 404: jsonResponse(ErrorResponseSchema, "User not found"),
453
+ },
454
+ }),
455
+ async (c) =>
456
+ respond(c, async () => {
457
+ const user = c.get("user");
458
+ const result = await accountsService.user.clearAvatar({ actor: toAccountsActor(user), id: user.id });
459
+ if (!result.ok) return result;
460
+ return ok({ message: "Avatar deleted." });
461
+ }),
462
+ )
463
+
464
+ .get(
465
+ "/passkeys",
466
+ describeRoute({
467
+ tags: ["Me"],
468
+ summary: "List current user passkeys",
469
+ description: "List WebAuthn passkeys registered to the authenticated account.",
470
+ ...requiresAuth,
471
+ responses: {
472
+ 200: jsonResponse(ListWebAuthnPasskeysResponseSchema, "Passkeys"),
473
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
474
+ },
475
+ }),
476
+ async (c) =>
477
+ respond(c, async () => {
478
+ const items = await webauthn.listForUser({ userId: c.get("user").id });
479
+ return ok({ items });
480
+ }),
481
+ )
482
+
483
+ .post(
484
+ "/passkeys/registration/start",
485
+ requireDirectUserActor,
486
+ describeRoute({
487
+ tags: ["Me"],
488
+ summary: "Start passkey registration",
489
+ description: "Create WebAuthn registration options for the authenticated account.",
490
+ ...requiresAuth,
491
+ responses: {
492
+ 200: jsonResponse(z.unknown(), "Passkey registration options"),
493
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
494
+ 403: jsonResponse(ErrorResponseSchema, "Not permitted for API keys or other credentials"),
495
+ },
496
+ }),
497
+ async (c) => respond(c, webauthn.beginRegistration({ user: c.get("user") })),
498
+ )
499
+
500
+ .post(
501
+ "/passkeys/registration/verify",
502
+ requireDirectUserActor,
503
+ describeRoute({
504
+ tags: ["Me"],
505
+ summary: "Verify passkey registration",
506
+ description: "Verify a WebAuthn registration response and store the passkey public credential.",
507
+ ...requiresAuth,
508
+ responses: {
509
+ 201: jsonResponse(WebAuthnPasskeySchema, "Passkey created"),
510
+ 400: jsonResponse(ErrorResponseSchema, "Passkey registration failed"),
511
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
512
+ 403: jsonResponse(ErrorResponseSchema, "Not permitted for API keys or other credentials"),
513
+ },
514
+ }),
515
+ v("json", CreateWebAuthnPasskeySchema),
516
+ async (c) =>
517
+ respond(
518
+ c,
519
+ () => {
520
+ const data = c.req.valid("json");
521
+ return webauthn.finishRegistration({
522
+ user: c.get("user"),
523
+ name: data.name,
524
+ response: data.response as never,
525
+ });
526
+ },
527
+ 201,
528
+ ),
529
+ )
530
+
531
+ .delete(
532
+ "/passkeys/:id",
533
+ requireDirectUserActor,
534
+ describeRoute({
535
+ tags: ["Me"],
536
+ summary: "Delete current user passkey",
537
+ description: "Delete a WebAuthn passkey registered to the authenticated account.",
538
+ ...requiresAuth,
539
+ responses: {
540
+ 200: jsonResponse(MessageResponseSchema, "Passkey deleted"),
541
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
542
+ 403: jsonResponse(ErrorResponseSchema, "Not permitted for API keys or other credentials"),
543
+ 404: jsonResponse(ErrorResponseSchema, "Passkey not found"),
544
+ },
545
+ }),
546
+ async (c) =>
547
+ respond(c, async () => {
548
+ const result = await webauthn.deleteForUser({ user: c.get("user"), id: c.req.param("id") });
549
+ if (!result.ok) return result;
550
+ return ok({ message: "Passkey deleted." });
551
+ }),
552
+ )
553
+
554
+ .post(
555
+ "/api-keys",
556
+ requireDirectUserActor,
557
+ describeRoute({
558
+ tags: ["Me"],
559
+ summary: "Create current user API key",
560
+ description: "Create a user-bound API key for the authenticated account. The raw token is returned once.",
561
+ ...requiresAuth,
562
+ responses: {
563
+ 201: jsonResponse(CreateUserApiKeyResponseSchema, "API key created"),
564
+ 400: jsonResponse(ErrorResponseSchema, "Failed to create API key"),
565
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
566
+ 403: jsonResponse(ErrorResponseSchema, "Not permitted for API keys or other credentials"),
567
+ },
568
+ }),
569
+ v("json", CreateUserApiKeySchema),
570
+ async (c) =>
571
+ respond(
572
+ c,
573
+ async () => {
574
+ const user = c.get("user");
575
+ const data = c.req.valid("json");
576
+ return serviceAccountCredentials.createUserApiToken({
577
+ user,
578
+ name: data.name,
579
+ expiresAt: data.expiresAt ?? null,
580
+ });
581
+ },
582
+ 201,
583
+ ),
584
+ )
585
+
586
+ .get(
587
+ "/api-keys",
588
+ describeRoute({
589
+ tags: ["Me"],
590
+ summary: "List current user API keys",
591
+ description: "List active user-bound API keys owned by the authenticated account.",
592
+ ...requiresAuth,
593
+ responses: {
594
+ 200: jsonResponse(ListApiKeysResponseSchema, "API keys"),
595
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
596
+ },
597
+ }),
598
+ async (c) =>
599
+ respond(c, async () => {
600
+ const items = await serviceAccountCredentials.listForDelegatedUser({ userId: c.get("user").id });
601
+ return ok({ items });
602
+ }),
603
+ )
604
+
605
+ .delete(
606
+ "/api-keys/:id",
607
+ requireDirectUserActor,
608
+ describeRoute({
609
+ tags: ["Me"],
610
+ summary: "Revoke current user API key",
611
+ description: "Revoke an API key owned by the authenticated account.",
612
+ ...requiresAuth,
613
+ responses: {
614
+ 200: jsonResponse(MessageResponseSchema, "API key revoked"),
615
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
616
+ 403: jsonResponse(ErrorResponseSchema, "Not permitted for API keys or other credentials"),
617
+ 404: jsonResponse(ErrorResponseSchema, "API key not found"),
618
+ },
619
+ }),
620
+ async (c) =>
621
+ respond(c, async () => {
622
+ const result = await serviceAccountCredentials.revokeForDelegatedUser({
623
+ credentialId: c.req.param("id"),
624
+ user: c.get("user"),
625
+ });
626
+ if (!result.ok) return result;
627
+ return ok({ message: "API key revoked." });
628
+ }),
629
+ )
630
+
631
+ .post(
632
+ "/password",
633
+ requireDirectUserActor,
634
+ describeRoute({
635
+ tags: ["Me"],
636
+ summary: "Change current user password",
637
+ description: "Change the authenticated user's password. Requires the current password for verification.",
638
+ ...requiresAuth,
639
+ responses: {
640
+ 200: jsonResponse(MessageResponseSchema, "Password changed"),
641
+ 400: jsonResponse(ErrorResponseSchema, "Failed to change password"),
642
+ 401: jsonResponse(ErrorResponseSchema, "Current password is incorrect"),
643
+ 403: jsonResponse(ErrorResponseSchema, "Not permitted for API keys or other credentials"),
644
+ },
645
+ }),
646
+ v("json", ChangePasswordSchema),
647
+ async (c) =>
648
+ respond(c, async () => {
649
+ const result = await accountsService.user.changeOwnPassword({
650
+ user: c.get("user"),
651
+ currentPassword: c.req.valid("json").currentPassword,
652
+ newPassword: c.req.valid("json").newPassword,
653
+ });
654
+ if (!result.ok) return result;
655
+ return ok({ message: "Password changed successfully." });
656
+ }),
657
+ )
658
+
659
+ .post(
660
+ "/account-extension",
661
+ describeRoute({
662
+ tags: ["Me"],
663
+ summary: "Extend current user account",
664
+ description: "Extends the authenticated account according to lifecycle settings.",
665
+ ...requiresAuth,
666
+ responses: {
667
+ 200: jsonResponse(ExtendAccountResponseSchema, "Account extension result"),
668
+ 400: jsonResponse(ErrorResponseSchema, "Unable to extend account"),
669
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
670
+ },
671
+ }),
672
+ async (c) =>
673
+ respond(c, async () => {
674
+ const user = c.get("user");
675
+ const result = await accountLifecycle.extendCurrentUserAccount({ user });
676
+ return result;
677
+ }),
678
+ )
679
+
680
+ .delete(
681
+ "/",
682
+ requireDirectUserActor,
683
+ describeRoute({
684
+ tags: ["Me"],
685
+ summary: "Delete current user",
686
+ description: "Delete the authenticated user's account. Only available for guest-profile users.",
687
+ ...requiresAuth,
688
+ responses: {
689
+ 200: jsonResponse(MessageResponseSchema, "Account deleted"),
690
+ 400: jsonResponse(ErrorResponseSchema, "Failed to delete account"),
691
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
692
+ 403: jsonResponse(ErrorResponseSchema, "Only guest accounts can be self-deleted"),
693
+ },
694
+ }),
695
+ async (c) =>
696
+ respond(c, async () => {
697
+ const user = c.get("user");
698
+ const result = await accountsService.user.removeSelf({ user });
699
+ if (!result.ok) return result;
700
+ await auth.session.delete(c);
701
+ return ok({ message: "Account deleted." });
702
+ }),
703
+ )
704
+
705
+ // Account request: a local user asks for an IPA-backed account. Each user
706
+ // has at most one pending request; `POST` creates it, `DELETE` withdraws
707
+ // the current one. Admin processing of requests lives in the accounts app.
708
+ .post(
709
+ "/account-request",
710
+ describeRoute({
711
+ tags: ["Me"],
712
+ summary: "Submit account request",
713
+ description: "Local accounts can request a centrally managed FreeIPA account. Must accept terms of service.",
714
+ ...requiresAuth,
715
+ responses: {
716
+ 201: jsonResponse(AccountRequestResponseSchema, "Request created"),
717
+ 400: jsonResponse(ErrorResponseSchema, "FreeIPA is disabled"),
718
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
719
+ 403: jsonResponse(ErrorResponseSchema, "Only local accounts can request FreeIPA access"),
720
+ 409: jsonResponse(ErrorResponseSchema, "Pending request already exists"),
721
+ },
722
+ }),
723
+ v("json", CreateAccountRequestSchema),
724
+ async (c) => respond(c, accountsService.accountRequest.create({ user: c.get("user"), data: c.req.valid("json") }), 201),
725
+ )
726
+
727
+ .delete(
728
+ "/account-request",
729
+ describeRoute({
730
+ tags: ["Me"],
731
+ summary: "Withdraw pending account request",
732
+ description: "Withdraws the current user's pending FreeIPA account request, if any.",
733
+ ...requiresAuth,
734
+ responses: {
735
+ 200: jsonResponse(MessageResponseSchema, "Request withdrawn"),
736
+ 401: jsonResponse(ErrorResponseSchema, "Authentication required"),
737
+ 404: jsonResponse(ErrorResponseSchema, "No pending request"),
738
+ },
739
+ }),
740
+ async (c) =>
741
+ respond(c, async () => {
742
+ const user = c.get("user");
743
+ const pending = await accountsService.accountRequest.getPendingForUser({ userId: user.id });
744
+ if (!pending) {
745
+ return { ok: false, error: "No pending request", status: 404 };
746
+ }
747
+ const result = await accountsService.accountRequest.withdraw({ id: pending.id, actor: toAccountsActor(user) });
748
+ if (!result.ok) return result;
749
+ return ok({ message: "Request withdrawn" });
750
+ }),
751
+ );
752
+
753
+ export default app;