@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,386 @@
1
+ import type { Context } from "hono";
2
+ import { createMiddleware } from "hono/factory";
3
+ import type { MessageResponse, Role, RoleOrSpecial, User, UserProfile, UserProvider } from "../../contracts/shared";
4
+ import { isAccountExpired } from "../../services/account-model";
5
+ import { isReservedWorkloadApiCredential } from "../../services/identity/workload-auth";
6
+ import { oauthTokens } from "../../services/oauth-tokens";
7
+ import { serviceAccountCredentials } from "../../services/service-account-credentials";
8
+ import type { ServiceAccount } from "../../services/service-accounts";
9
+ import { session } from "../../services/session";
10
+ import { createLoginRedirectUrl } from "../../shared/redirect";
11
+ import type { AccessSubject } from "../services/access";
12
+
13
+ // ==========================
14
+ // Types
15
+ // ==========================
16
+
17
+ export type InvocationProvenance = {
18
+ kind: "invocation";
19
+ callingAppId: string;
20
+ credentialKind: "session" | "oauth" | "api_key" | "mandate";
21
+ invocationId: string;
22
+ requestId?: string | null;
23
+ mandateId?: string;
24
+ mandateRevision?: number;
25
+ workloadType?: string;
26
+ workloadId?: string;
27
+ };
28
+
29
+ export type UserRequestActor = {
30
+ kind: "user";
31
+ user: User;
32
+ delegation?: InvocationProvenance;
33
+ };
34
+
35
+ export type ServiceAccountRequestActor =
36
+ | {
37
+ kind: "service_account";
38
+ serviceAccount: ServiceAccount;
39
+ delegatedUser: User;
40
+ scopes: string[];
41
+ credentialId?: string | null;
42
+ credentialExpiresAt?: string | null;
43
+ delegation?: InvocationProvenance;
44
+ }
45
+ | {
46
+ kind: "service_account";
47
+ serviceAccount: ServiceAccount;
48
+ delegatedUser: null;
49
+ scopes: string[];
50
+ credentialId?: string | null;
51
+ credentialExpiresAt?: string | null;
52
+ delegation?: InvocationProvenance;
53
+ };
54
+
55
+ export type RequestActor = UserRequestActor | ServiceAccountRequestActor;
56
+
57
+ export type RequestCredentialKind = "session" | "oauth" | "api_key" | "invocation";
58
+
59
+ export type RequestAuthority = {
60
+ actor: RequestActor;
61
+ accessSubject: AccessSubject;
62
+ credentialKind: RequestCredentialKind;
63
+ scopes: string[];
64
+ };
65
+
66
+ /** Hono context with authenticated user variables. */
67
+ export type AuthContext = {
68
+ Variables: {
69
+ actor: RequestActor;
70
+ accessSubject: AccessSubject;
71
+ user: User;
72
+ sessionToken?: string;
73
+ /** Credential class resolved once for downstream delegation. */
74
+ credentialKind?: RequestCredentialKind;
75
+ /** Constraints carried by OAuth/API credentials; absent sessions are unrestricted by transport scope. */
76
+ credentialScopes?: string[];
77
+ /** OAuth scopes for bearer-token requests. Absent for sessions and API credentials. */
78
+ oauthScopes?: string[];
79
+ };
80
+ };
81
+
82
+ // ==========================
83
+ // Role-based Middleware
84
+ // ==========================
85
+
86
+ type RejectResult = string | Response | { message: string; status: number };
87
+
88
+ type RoleOptions = {
89
+ onReject?: (c: Context, reason: "unauthenticated" | "forbidden") => RejectResult | Promise<RejectResult>;
90
+ /** Require any of these audiences for OAuth bearer tokens. Sessions and API keys are unaffected. */
91
+ oauthAudience?: string | string[] | (() => string | string[] | Promise<string | string[]>);
92
+ };
93
+
94
+ type AccountOptions = RoleOptions & {
95
+ provider?: UserProvider;
96
+ profile?: UserProfile;
97
+ };
98
+
99
+ const handleReject = async (c: Context, options: RoleOptions, reason: "unauthenticated" | "forbidden"): Promise<Response> => {
100
+ if (options.onReject) {
101
+ const result = await options.onReject(c, reason);
102
+ if (typeof result === "string") return c.redirect(result);
103
+ if (result instanceof Response) return result;
104
+ return c.json({ message: result.message } as MessageResponse, result.status as 400 | 401 | 403 | 404 | 500);
105
+ }
106
+ // Default: JSON response
107
+ if (reason === "unauthenticated") {
108
+ return c.json({ message: "Authentication required" } as MessageResponse, 401);
109
+ }
110
+ return c.json({ message: "Insufficient permissions" } as MessageResponse, 403);
111
+ };
112
+
113
+ type AuthenticatedActorResult = {
114
+ token: string | null;
115
+ user: User | null;
116
+ actor: RequestActor | null;
117
+ };
118
+
119
+ const actorResolutionByRequest = new WeakMap<Context, Promise<AuthenticatedActorResult>>();
120
+
121
+ const loadAuthenticatedActorUncached = async (
122
+ c: Context<AuthContext>,
123
+ options: Pick<RoleOptions, "oauthAudience"> = {},
124
+ ): Promise<AuthenticatedActorResult> => {
125
+ const token = session.getToken(c);
126
+ const authenticatedSession = token ? await session.authenticateRequest(c, token) : null;
127
+ const user = authenticatedSession?.user ?? null;
128
+
129
+ if (user && token) {
130
+ c.set("actor", { kind: "user", user });
131
+ c.set("accessSubject", { type: "user", userId: user.id });
132
+ c.set("user", user);
133
+ c.set("sessionToken", token);
134
+ c.set("credentialKind", "session");
135
+ }
136
+
137
+ if (user) return { token, user, actor: { kind: "user", user } };
138
+
139
+ const bearer = session.getBearerToken(c);
140
+ if (bearer && serviceAccountCredentials.isApiToken(bearer)) {
141
+ const authResult = await serviceAccountCredentials.authenticateApiToken(bearer);
142
+ if (!authResult) return { token: null, user: null, actor: null };
143
+ // App workload keys enter only through Core's dedicated broker/authority
144
+ // handlers, which authenticate their exact app binding directly.
145
+ if (isReservedWorkloadApiCredential(authResult)) return { token: null, user: null, actor: null };
146
+ if (authResult.delegatedUser && isAccountExpired(authResult.delegatedUser.accountExpires)) {
147
+ return { token: null, user: null, actor: null };
148
+ }
149
+
150
+ const actor: RequestActor = {
151
+ kind: "service_account",
152
+ serviceAccount: authResult.serviceAccount,
153
+ delegatedUser: authResult.delegatedUser,
154
+ scopes: authResult.credential.scopes,
155
+ credentialId: authResult.credential.id,
156
+ credentialExpiresAt: authResult.credential.expiresAt,
157
+ };
158
+ c.set("actor", actor);
159
+ c.set("credentialKind", "api_key");
160
+ c.set("credentialScopes", authResult.credential.scopes);
161
+ if (authResult.delegatedUser) {
162
+ c.set("accessSubject", { type: "user", userId: authResult.delegatedUser.id });
163
+ c.set("user", authResult.delegatedUser);
164
+ } else {
165
+ c.set("accessSubject", { type: "service_account", serviceAccountId: authResult.serviceAccount.id });
166
+ }
167
+ return { token: null, user: authResult.delegatedUser, actor };
168
+ }
169
+
170
+ if (bearer) {
171
+ const expectedAudience = typeof options.oauthAudience === "function" ? await options.oauthAudience() : options.oauthAudience;
172
+ const authResult = await oauthTokens.verifyAccessToken(bearer, expectedAudience);
173
+ if (!authResult) return { token: null, user: null, actor: null };
174
+
175
+ if (authResult.kind === "user") {
176
+ if (isAccountExpired(authResult.user.accountExpires)) return { token: null, user: null, actor: null };
177
+ const actor: RequestActor = { kind: "user", user: authResult.user };
178
+ c.set("actor", actor);
179
+ c.set("accessSubject", { type: "user", userId: authResult.user.id });
180
+ c.set("user", authResult.user);
181
+ c.set("oauthScopes", authResult.scopes);
182
+ c.set("credentialKind", "oauth");
183
+ c.set("credentialScopes", authResult.scopes);
184
+ return { token: null, user: authResult.user, actor };
185
+ }
186
+
187
+ if (authResult.delegatedUser && isAccountExpired(authResult.delegatedUser.accountExpires)) {
188
+ return { token: null, user: null, actor: null };
189
+ }
190
+ const actor: RequestActor = {
191
+ kind: "service_account",
192
+ serviceAccount: authResult.serviceAccount,
193
+ delegatedUser: authResult.delegatedUser,
194
+ scopes: authResult.scopes,
195
+ credentialId: null,
196
+ credentialExpiresAt: typeof authResult.payload.exp === "number" ? new Date(authResult.payload.exp * 1_000).toISOString() : null,
197
+ };
198
+ c.set("actor", actor);
199
+ c.set("oauthScopes", authResult.scopes);
200
+ c.set("credentialKind", "oauth");
201
+ c.set("credentialScopes", authResult.scopes);
202
+ if (authResult.delegatedUser) {
203
+ c.set("accessSubject", { type: "user", userId: authResult.delegatedUser.id });
204
+ c.set("user", authResult.delegatedUser);
205
+ } else {
206
+ c.set("accessSubject", { type: "service_account", serviceAccountId: authResult.serviceAccount.id });
207
+ }
208
+ return { token: null, user: authResult.delegatedUser, actor };
209
+ }
210
+
211
+ return { token: null, user: null, actor: null };
212
+ };
213
+
214
+ const loadAuthenticatedActor = (
215
+ c: Context<AuthContext>,
216
+ options: Pick<RoleOptions, "oauthAudience"> = {},
217
+ ): Promise<AuthenticatedActorResult> => {
218
+ if (options.oauthAudience) return loadAuthenticatedActorUncached(c, options);
219
+ const existing = actorResolutionByRequest.get(c);
220
+ if (existing) return existing;
221
+ const pending = loadAuthenticatedActorUncached(c, options);
222
+ actorResolutionByRequest.set(c, pending);
223
+ return pending;
224
+ };
225
+
226
+ /**
227
+ * Universal auth middleware. Handles authentication AND authorization.
228
+ *
229
+ * @param args - Roles to check (OR logic) + optional RoleOptions at the end. Special roles:
230
+ * - "*": No check, always passes (like optionalAuth)
231
+ * - "authenticated": Any logged-in user
232
+ * - "anonymous": Only non-logged-in users (for login page)
233
+ *
234
+ * @example
235
+ * // API: Only admins (returns JSON 401/403)
236
+ * .use(requireRole("admin"))
237
+ *
238
+ * // API: Admins OR group managers
239
+ * .use(requireRole("admin", "group-manager"))
240
+ *
241
+ * // SSR: Admin area with redirect
242
+ * .use(requireRole("admin", redirect("/")))
243
+ *
244
+ * // SSR: Protected page with login redirect
245
+ * .use(requireRole("authenticated", redirectToLogin))
246
+ *
247
+ * // SSR: Login page (only for non-logged-in users)
248
+ * .use(requireRole("anonymous", redirect("/")))
249
+ */
250
+ const requireRole = (...args: (RoleOrSpecial | RoleOptions)[]) => {
251
+ // Parse args: roles + optional options at the end
252
+ const lastArg = args[args.length - 1];
253
+ const hasOptions = typeof lastArg === "object" && lastArg !== null && ("onReject" in lastArg || "oauthAudience" in lastArg);
254
+ const options: RoleOptions = hasOptions ? (args.pop() as RoleOptions) : {};
255
+ const roles = args as RoleOrSpecial[];
256
+
257
+ return createMiddleware<AuthContext>(async (c, next) => {
258
+ // "*" = no check at all, pass through (but try to load user)
259
+ if (roles.includes("*")) {
260
+ await loadAuthenticatedActor(c, options);
261
+ return next();
262
+ }
263
+
264
+ const { user, actor } = await loadAuthenticatedActor(c, options);
265
+
266
+ // "anonymous" = must NOT be logged in
267
+ if (roles.includes("anonymous")) {
268
+ if (actor) {
269
+ return handleReject(c, options, "forbidden");
270
+ }
271
+ return next();
272
+ }
273
+
274
+ // All other roles require authentication
275
+ if (!actor) {
276
+ return handleReject(c, options, "unauthenticated");
277
+ }
278
+
279
+ // "authenticated" = any logged-in user
280
+ if (roles.includes("authenticated")) {
281
+ return next();
282
+ }
283
+
284
+ if (!user) {
285
+ return handleReject(c, options, "forbidden");
286
+ }
287
+
288
+ // Check if user has at least one required role
289
+ const hasRequiredRole = roles.some((role) => user.roles.includes(role as Role));
290
+ if (!hasRequiredRole) {
291
+ return handleReject(c, options, "forbidden");
292
+ }
293
+
294
+ return next();
295
+ });
296
+ };
297
+
298
+ /**
299
+ * Require a request that has a user behind it.
300
+ *
301
+ * `requireRole("authenticated")` deliberately admits any authenticated
302
+ * principal, including a resource-bound service account that has no user at
303
+ * all — that is what lets an API key reach an ordinary app route. It is the one
304
+ * role branch that does not imply a user, so a route gated with it that then
305
+ * reaches for roles, ownership or a display name is reaching for something that
306
+ * may not be there.
307
+ *
308
+ * Use this alongside it wherever the handler needs the user itself, so the
309
+ * caller gets a 403 stating the reason instead of whatever the missing user
310
+ * turns into further down.
311
+ */
312
+ const requireUser = (options: RoleOptions = {}) =>
313
+ createMiddleware<AuthContext>(async (c, next) => {
314
+ const { user } = await loadAuthenticatedActor(c);
315
+ if (user) return next();
316
+ // A caller that reaches here is authenticated but has no user, so the
317
+ // generic "Insufficient permissions" would send them looking for a missing
318
+ // role. `onReject` still wins, which is what keeps SSR redirects working.
319
+ if (options.onReject) return handleReject(c, options, "forbidden");
320
+ return c.json({ message: "Self-service endpoints require a user-backed actor", code: "FORBIDDEN" }, 403);
321
+ });
322
+
323
+ /** Require one OAuth scope when the caller uses OAuth. Sessions and API credentials are unaffected. */
324
+ const requireOAuthScope = (...requiredScopes: string[]) =>
325
+ createMiddleware<AuthContext>(async (c, next) => {
326
+ const scopes = c.get("oauthScopes");
327
+ if (!scopes || requiredScopes.some((scope) => scopes.includes(scope))) return next();
328
+ return c.json({ code: "FORBIDDEN", message: `OAuth scope ${requiredScopes.join(" or ")} is required` }, 403);
329
+ });
330
+
331
+ const getAuthority = (c: Context<AuthContext>): RequestAuthority => {
332
+ const actor = c.get("actor");
333
+ const accessSubject = c.get("accessSubject");
334
+ const credentialKind = c.get("credentialKind");
335
+ if (!actor || !accessSubject || !credentialKind) throw new Error("Request authority has not been resolved");
336
+ return {
337
+ actor,
338
+ accessSubject,
339
+ credentialKind,
340
+ scopes: [...(c.get("credentialScopes") ?? [])],
341
+ };
342
+ };
343
+
344
+ /** Preset: Redirect to a fixed URL on rejection */
345
+ const redirect = (url: string): RoleOptions => ({
346
+ onReject: () => url,
347
+ });
348
+
349
+ /** Preset: Redirect to login page with returnTo parameter */
350
+ const redirectToLogin: RoleOptions = {
351
+ onReject: (c) => createLoginRedirectUrl(c.req.url),
352
+ };
353
+
354
+ const requireAccount = (options: AccountOptions) =>
355
+ createMiddleware<AuthContext>(async (c, next) => {
356
+ const { user } = await loadAuthenticatedActor(c);
357
+
358
+ if (!user) {
359
+ return handleReject(c, options, "unauthenticated");
360
+ }
361
+
362
+ if (options.provider && user.provider !== options.provider) {
363
+ return handleReject(c, options, "forbidden");
364
+ }
365
+
366
+ if (options.profile && user.profile !== options.profile) {
367
+ return handleReject(c, options, "forbidden");
368
+ }
369
+
370
+ return next();
371
+ });
372
+
373
+ // ==========================
374
+ // Export
375
+ // ==========================
376
+
377
+ export const auth = {
378
+ session,
379
+ requireRole,
380
+ requireUser,
381
+ requireOAuthScope,
382
+ getAuthority,
383
+ requireAccount,
384
+ redirect,
385
+ redirectToLogin,
386
+ };
@@ -0,0 +1,28 @@
1
+ export type { AccessSubject } from "../services/access";
2
+
3
+ export {
4
+ type AuthContext,
5
+ auth,
6
+ type InvocationProvenance,
7
+ type RequestActor,
8
+ type RequestAuthority,
9
+ type RequestCredentialKind,
10
+ type ServiceAccountRequestActor,
11
+ type UserRequestActor,
12
+ } from "./auth";
13
+ export { type InvocationExpectation, requireInvocation } from "./invocation";
14
+ export { middleware } from "./middleware";
15
+ export {
16
+ imageResponse,
17
+ jsonResponse,
18
+ openApiMeta,
19
+ requiresAdmin,
20
+ requiresAuth,
21
+ requiresIpa,
22
+ requiresIpaUser,
23
+ requiresUser,
24
+ } from "./openapi";
25
+ export { type RateLimitConfig, type RateLimitRouteOverride, rateLimit } from "./rate-limit";
26
+ export { requestLogger } from "./request-logger";
27
+ export { type ValidatorError, type ValidatorErrorResolver, v, validator } from "./validator";
28
+ export { isReservedWorkloadCredential, rejectReservedWorkloadCredential } from "./workload";
@@ -0,0 +1,55 @@
1
+ import type { Context, MiddlewareHandler } from "hono";
2
+ import { createMiddleware } from "hono/factory";
3
+ import { type ResolvedInvocationAuthority, resolveInvocationAuthority } from "../../services/identity/invocation-actor";
4
+ import { type CloudInvocationClaims, isInvocationJwtCandidate, verifyInvocationToken } from "../../services/identity/invocation-token";
5
+ import type { AuthContext } from "./auth";
6
+
7
+ export type InvocationExpectation = {
8
+ targetAppId: string;
9
+ operation: string;
10
+ schemaHash: string | null;
11
+ };
12
+
13
+ type InvocationMiddlewareDependencies = {
14
+ verify?: typeof verifyInvocationToken;
15
+ resolve?: typeof resolveInvocationAuthority;
16
+ };
17
+
18
+ const bearerToken = (c: Context): string | null => {
19
+ const header = c.req.header("Authorization");
20
+ const match = header?.match(/^Bearer\s+(\S+)$/i);
21
+ return match?.[1] ?? null;
22
+ };
23
+
24
+ const reject = (c: Context<AuthContext>): Response =>
25
+ c.json({ code: "UNAUTHORIZED", message: "A valid Cloud invocation is required" }, 401);
26
+
27
+ const installAuthority = (c: Context<AuthContext>, claims: CloudInvocationClaims, authority: ResolvedInvocationAuthority): void => {
28
+ c.set("actor", authority.actor);
29
+ c.set("accessSubject", authority.accessSubject);
30
+ c.set("credentialKind", "invocation");
31
+ c.set("credentialScopes", authority.scopes);
32
+ if (authority.actor.kind === "user") c.set("user", authority.actor.user);
33
+ else if (authority.actor.delegatedUser) c.set("user", authority.actor.delegatedUser);
34
+ if (claims.credential_kind === "oauth") c.set("oauthScopes", authority.scopes);
35
+ };
36
+
37
+ export const requireInvocation = (
38
+ expected: (c: Context<AuthContext>) => InvocationExpectation | null,
39
+ dependencies: InvocationMiddlewareDependencies = {},
40
+ ): MiddlewareHandler<AuthContext> =>
41
+ createMiddleware<AuthContext>(async (c, next) => {
42
+ const token = bearerToken(c);
43
+ const expectation = expected(c);
44
+ if (!token || !expectation || !isInvocationJwtCandidate(token)) return reject(c);
45
+
46
+ const claims = await (dependencies.verify ?? verifyInvocationToken)(token, expectation, { deferSchemaBinding: true });
47
+ if (!claims) return reject(c);
48
+ const authority = await (dependencies.resolve ?? resolveInvocationAuthority)(claims);
49
+ if (!authority) return reject(c);
50
+ if (claims.schema_hash !== expectation.schemaHash) {
51
+ return c.json({ code: "SCHEMA_MISMATCH", message: "The invocation schema no longer matches the target" }, 409);
52
+ }
53
+ installAuthority(c, claims, authority);
54
+ return next();
55
+ });
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The `middleware` namespace bundles the request-lifecycle primitives
3
+ * that every cloud app composes into its own router. Apps register
4
+ * what they need; the framework no longer injects anything implicitly.
5
+ *
6
+ * import { middleware, auth } from "@k2b/cloud/server"
7
+ *
8
+ * const router = new Hono<AuthContext>()
9
+ * .use("*", middleware.logger())
10
+ * .use("*", middleware.runtime()) // for Layout / Sidebar / dashboard / search
11
+ * .use("*", middleware.settings()) // for c.get("settings")
12
+ * .use("*", middleware.ratelimit())
13
+ * .use(auth.requireRole("user"))
14
+ * .post(
15
+ * "/",
16
+ * middleware.validator("json", Schema),
17
+ * middleware.openapi({ tags: ["foo"], summary: "Create" }),
18
+ * handler,
19
+ * )
20
+ *
21
+ * `auth` lives separately because it has its own surface
22
+ * (requireRole, redirectToLogin, session.*) and is conceptually
23
+ * orthogonal to the request lifecycle.
24
+ */
25
+ import { describeRoute } from "hono-openapi";
26
+ import { rateLimit } from "./rate-limit";
27
+ import { requestLogger } from "./request-logger";
28
+ import { routeTemplate } from "./route-template";
29
+ import { runtime } from "./runtime";
30
+ import { settings } from "./settings";
31
+ import { validator } from "./validator";
32
+
33
+ export const middleware = {
34
+ /**
35
+ * Live cluster registry on `c.get("runtime")`. Required for Layout/Sidebar.
36
+ * Also reports the matched route template to gateway telemetry — you do not
37
+ * need `observability()` on top of this.
38
+ */
39
+ runtime,
40
+ /** Frozen per-request settings snapshot on `c.get("settings")`. */
41
+ settings,
42
+ /**
43
+ * Reports the matched Hono route template to gateway telemetry, so the
44
+ * admin telemetry page can break an app down per endpoint instead of
45
+ * lumping every request under one registry prefix.
46
+ *
47
+ * **Only use this if you do NOT already use `middleware.runtime()`** —
48
+ * `runtime()` does the same thing, and installing both just runs it twice.
49
+ * Practically every app renders `<Layout>` and therefore needs `runtime()`
50
+ * anyway; this exists for the rare app that serves an API surface only.
51
+ *
52
+ * ```ts
53
+ * new Hono().use("*", middleware.observability()) // no runtime() here
54
+ * ```
55
+ */
56
+ observability: () => routeTemplate,
57
+ /** HTTP request logger (logs 5xx as error, 429 as warn, 401/403 as info). */
58
+ logger: () => requestLogger,
59
+ /** Sliding-window rate limiter, keyed by user id (auto fallback to IP). */
60
+ ratelimit: rateLimit,
61
+ /** Zod input validator. `c.req.valid(target)` is fully typed afterward. */
62
+ validator,
63
+ /** OpenAPI route metadata — re-export of hono-openapi's `describeRoute`. */
64
+ openapi: describeRoute,
65
+ } as const;
@@ -0,0 +1,126 @@
1
+ import { type GenerateSpecOptions, resolver } from "hono-openapi";
2
+ import type { ZodType } from "zod";
3
+
4
+ // ==========================
5
+ // Response Helpers
6
+ // ==========================
7
+
8
+ /**
9
+ * Helper to define JSON response schema for OpenAPI documentation.
10
+ *
11
+ * @param schema - Zod schema for the response body
12
+ * @param description - Human-readable description of the response
13
+ * @returns OpenAPI response object with application/json content type
14
+ */
15
+ export const jsonResponse = <T extends ZodType>(schema: T, description: string) => ({
16
+ description,
17
+ content: {
18
+ "application/json": {
19
+ schema: resolver(schema),
20
+ },
21
+ },
22
+ });
23
+
24
+ /**
25
+ * Helper to define image response for OpenAPI documentation.
26
+ *
27
+ * @param description - Human-readable description of the response
28
+ * @returns OpenAPI response object with image/webp content type
29
+ */
30
+ export const imageResponse = (description: string) => ({
31
+ description,
32
+ content: {
33
+ "image/webp": {
34
+ schema: { type: "string" as const, format: "binary" },
35
+ },
36
+ },
37
+ });
38
+
39
+ // ==========================
40
+ // OpenAPI Specification
41
+ // ==========================
42
+
43
+ /**
44
+ * OpenAPI spec metadata for the API documentation.
45
+ * Includes info, tags, and security schemes.
46
+ */
47
+ export const openApiMeta: Partial<GenerateSpecOptions> = {
48
+ documentation: {
49
+ info: {
50
+ // Hardcoded — the OpenAPI spec is generated at module-load and
51
+ // settings reads are async. The dynamic per-deployment app name
52
+ // appears elsewhere (Layout header, page titles).
53
+ title: "Cloud API",
54
+ version: "0.0.1",
55
+ description: "IPA Management Tool API",
56
+ },
57
+ servers: [{ url: "/api", description: "API Server" }],
58
+ tags: [
59
+ {
60
+ name: "Auth",
61
+ description: "Authentication endpoints (login, logout, refresh)",
62
+ },
63
+ { name: "Users", description: "User listing and search (admin)" },
64
+ { name: "Groups", description: "Group listing and search (admin)" },
65
+ ],
66
+ components: {
67
+ securitySchemes: {
68
+ cookieAuth: {
69
+ type: "apiKey",
70
+ in: "cookie",
71
+ name: "session_token",
72
+ description: "Session cookie (automatically set after login)",
73
+ },
74
+ bearerAuth: {
75
+ type: "http",
76
+ scheme: "bearer",
77
+ description: "Bearer token in Authorization header",
78
+ },
79
+ },
80
+ },
81
+ },
82
+ };
83
+
84
+ // ==========================
85
+ // Security Requirements
86
+ // ==========================
87
+
88
+ /**
89
+ * Security requirement for routes that need authentication.
90
+ * Accepts either cookie or bearer token.
91
+ */
92
+ export const requiresAuth = {
93
+ security: [{ cookieAuth: [] as string[], bearerAuth: [] as string[] }],
94
+ };
95
+
96
+ /**
97
+ * Security requirement for routes that need admin role.
98
+ * Accepts either cookie or bearer token.
99
+ */
100
+ export const requiresAdmin = {
101
+ security: [{ cookieAuth: [] as string[], bearerAuth: [] as string[] }],
102
+ };
103
+
104
+ /**
105
+ * Security requirement for routes that need any authenticated user.
106
+ * Accepts either cookie or bearer token.
107
+ */
108
+ export const requiresIpa = {
109
+ security: [{ cookieAuth: [] as string[], bearerAuth: [] as string[] }],
110
+ };
111
+
112
+ /**
113
+ * Security requirement for routes that need a full user profile.
114
+ * Accepts either cookie or bearer token.
115
+ */
116
+ export const requiresUser = {
117
+ security: [{ cookieAuth: [] as string[], bearerAuth: [] as string[] }],
118
+ };
119
+
120
+ /**
121
+ * Security requirement for routes that need an IPA-backed full user.
122
+ * Accepts either cookie or bearer token.
123
+ */
124
+ export const requiresIpaUser = {
125
+ security: [{ cookieAuth: [] as string[], bearerAuth: [] as string[] }],
126
+ };