@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,796 @@
1
+ /**
2
+ * Platform-owned settings, declared in the `defineApp({ settings: ... })` shape.
3
+ *
4
+ * These live in the framework, not in the core app, because every container
5
+ * needs them registered: `settings.get("app.url")` and the per-request snapshot
6
+ * resolve through `SETTINGS_MAP`, which is per-process. `defaults.ts` derives
7
+ * its legacy entries from this object, and the core app passes it straight to
8
+ * `defineApp({ settings })` so `app.settings.get/set` and `c.get("settings")`
9
+ * keep their literal-type inference.
10
+ *
11
+ * Conventions:
12
+ * - omit `key` (it's the object key)
13
+ * - omit `group` (derived from the key prefix in the admin UI)
14
+ * - keep `description`, `label`, `placeholder`, `default`, `kind` complete
15
+ */
16
+
17
+ const envString = (key: string): string | undefined => {
18
+ const value = process.env[key]?.trim();
19
+ return value && value.length > 0 ? value : undefined;
20
+ };
21
+
22
+ const envCsv = (key: string): string | undefined => {
23
+ const value = process.env[key]
24
+ ?.split(",")
25
+ .map((part) => part.trim())
26
+ .filter(Boolean)
27
+ .join(",");
28
+ return value && value.length > 0 ? value : undefined;
29
+ };
30
+
31
+ const hasRequiredFreeIpaEnv = (): boolean =>
32
+ Boolean(envString("FREEIPA_URL") && envString("FREEIPA_SVC_USER") && envString("FREEIPA_SVC_PASSWORD"));
33
+
34
+ const IPA_MATCH_MODE_OPTIONS = [
35
+ { value: "ignore", label: "Ignore local match" },
36
+ { value: "migrate", label: "Migrate matching local account" },
37
+ ] as const;
38
+
39
+ const IPA_ACCOUNT_TRANSITION_OPTIONS = [
40
+ { value: "delete", label: "Delete account" },
41
+ { value: "demote_to_local", label: "Make local (keep profile)" },
42
+ { value: "demote_to_local_guest", label: "Make local guest" },
43
+ { value: "demote_to_local_user", label: "Make local user" },
44
+ ] as const;
45
+
46
+ export const CORE_SETTINGS = {
47
+ "user.app_approval.enabled": {
48
+ kind: "boolean",
49
+ label: "Enable app sign-in",
50
+ description:
51
+ "Show setup under Security. Pairing and sign-in also require a valid app origin. Does not enable Linux login or replace existing sign-in methods.",
52
+ default: false,
53
+ },
54
+ "user.app_approval.origin": {
55
+ kind: "string",
56
+ label: "App website address (origin)",
57
+ description:
58
+ "Trusted HTTPS origin of the authenticator, used for app installation and pairing links. Changing this origin requires reviewing existing devices; never use a wildcard.",
59
+ default: "https://cloud-login.pwa.k2b.dev",
60
+ },
61
+ "user.app_approval.admin_pairing": {
62
+ kind: "boolean",
63
+ label: "Allow administrator-assisted pairing",
64
+ description:
65
+ "Allow recently authenticated administrators to enroll a device for another account, with explicit confirmation and audit.",
66
+ default: false,
67
+ },
68
+ "user.category.guest.enabled": {
69
+ kind: "boolean",
70
+ label: "Guest accounts allowed",
71
+ description: "Allow Guest sign-in and user-bound credentials. Disabling retains accounts and their data.",
72
+ default: true,
73
+ },
74
+ "user.category.guest.visible": {
75
+ kind: "boolean",
76
+ label: "Show Guest in login",
77
+ description: "Hidden allowed accounts can still use direct login links. This does not enable self-registration.",
78
+ default: true,
79
+ },
80
+ "user.category.login.enabled": {
81
+ kind: "boolean",
82
+ label: "Login accounts allowed",
83
+ description: "Allow passwordless local full accounts to sign in and use user-bound credentials.",
84
+ default: true,
85
+ },
86
+ "user.category.login.visible": {
87
+ kind: "boolean",
88
+ label: "Show Login in login",
89
+ description: "Show this category in the general login page. Direct entry remains available when hidden but allowed.",
90
+ default: true,
91
+ },
92
+ "user.category.login.label": {
93
+ kind: "string",
94
+ label: "Login account label",
95
+ description: "Name used for local full accounts, for example Company account. Empty uses Login.",
96
+ default: "Login",
97
+ },
98
+ "user.category.freeipa.enabled": {
99
+ kind: "boolean",
100
+ label: "FreeIPA accounts allowed",
101
+ description: "Allow FreeIPA-backed accounts to sign in and use user-bound credentials. Directory synchronization is not stopped.",
102
+ default: true,
103
+ },
104
+ "user.category.freeipa.visible": {
105
+ kind: "boolean",
106
+ label: "Show FreeIPA in login",
107
+ description: "The FreeIPA connection must also be enabled to offer this login method.",
108
+ default: true,
109
+ },
110
+ "linux.identity_config": {
111
+ kind: "text",
112
+ label: "Local Linux identities",
113
+ description: "Managed through the Linux identity setup in Administration. Does not enable computer login.",
114
+ default: '{"enabled":false,"rangeStart":0,"rangeEnd":0,"homeTemplate":"/home/{username}","loginShell":"/bin/bash"}',
115
+ },
116
+ // ── App ─────────────────────────────────────────────────────────────────
117
+ "app.documentation_url": {
118
+ kind: "url",
119
+ label: "Documentation website",
120
+ description:
121
+ "Base URL for administration help links. Use your own Cloud documentation mirror or a local Fibel server; this does not configure app sign-in.",
122
+ default: "https://cloud.k2b.dev",
123
+ placeholder: "https://cloud.k2b.dev",
124
+ },
125
+ "app.url": {
126
+ kind: "string",
127
+ label: "URL",
128
+ default: "localhost:3000",
129
+ description:
130
+ "Public-facing application URL used for links in emails, OAuth redirects, and WebSocket connections (with or without scheme)",
131
+ placeholder: "e.g. https://cloud.example.org",
132
+ envFallback: () => envString("APP_URL"),
133
+ envBootstrap: () => envString("APP_URL"),
134
+ },
135
+ "app.home_path": {
136
+ kind: "string",
137
+ label: "Home path",
138
+ default: "/app/dashboard",
139
+ description: "Local path opened after login and when visiting the Cloud root. It must be available to all signed-in users.",
140
+ placeholder: "/app/dashboard",
141
+ },
142
+ "app.name": {
143
+ kind: "string",
144
+ label: "Name",
145
+ default: "My App",
146
+ description: "Application display name",
147
+ placeholder: "e.g. MyCloud",
148
+ },
149
+ "app.contact_email": {
150
+ kind: "email",
151
+ label: "Contact Email",
152
+ default: "",
153
+ description: "Support contact email",
154
+ placeholder: "e.g. support@example.org",
155
+ },
156
+ "app.copyright": {
157
+ kind: "string",
158
+ label: "Copyright",
159
+ default: "",
160
+ description: "Copyright holder name shown in footer",
161
+ placeholder: "e.g. MyCompany",
162
+ },
163
+ "app.logo": {
164
+ kind: "image",
165
+ label: "Logo",
166
+ default: "",
167
+ description: "Logo image",
168
+ },
169
+ "app.favicon": {
170
+ kind: "image",
171
+ label: "Favicon",
172
+ default: "",
173
+ description: "Favicon",
174
+ },
175
+ "app.locale": {
176
+ kind: "string",
177
+ label: "Locale",
178
+ default: "en",
179
+ description:
180
+ "Default BCP 47 locale for requests without a locale preference; drives the document language, date/number formatting, and opt-in app message catalogs. It does not translate built-in product copy.",
181
+ placeholder: "e.g. de-CH",
182
+ },
183
+ "app.timezone": {
184
+ kind: "timezone",
185
+ label: "Timezone",
186
+ default: "Europe/Berlin",
187
+ description: "IANA timezone used for all scheduler-based jobs and time-based operations",
188
+ placeholder: "e.g. Europe/Berlin",
189
+ },
190
+ "app.cleanup_schedule": {
191
+ kind: "cron",
192
+ label: "Cleanup Schedule",
193
+ default: "0 4 * * *",
194
+ description: "Five-field cron schedule used by all automatic cleanup jobs in app.timezone",
195
+ },
196
+
197
+ // ── AI ──────────────────────────────────────────────────────────────────
198
+ "ai.enabled": {
199
+ kind: "boolean",
200
+ label: "Enable AI",
201
+ default: false,
202
+ description: "Enable Cloud AI features including personal conversations, Assistant, and app Capabilities.",
203
+ },
204
+ "ai.default_model_id": {
205
+ kind: "string",
206
+ label: "Default Model ID",
207
+ default: "",
208
+ description: "Model profile id used when an app asks for the platform default AI model.",
209
+ placeholder: "e.g. openrouter-fast",
210
+ },
211
+ "ai.model_profiles_json": {
212
+ kind: "text",
213
+ label: "Model Profiles",
214
+ default: "[]",
215
+ description: "JSON array of model profiles. Provider API keys are stored on the profile they belong to.",
216
+ placeholder:
217
+ '[{"id":"openrouter-fast","label":"OpenRouter Fast","provider":"openrouter","model":"openai/gpt-4.1-mini","enabled":true,"dataBoundary":"hosted","capabilities":["streaming"],"apiKey":"sk-or-..."}]',
218
+ },
219
+ "ai.background_model_id": {
220
+ kind: "string",
221
+ label: "Background Model ID",
222
+ default: "",
223
+ description: "Model profile id used for background AI jobs. Empty = platform default model.",
224
+ placeholder: "e.g. openrouter-fast",
225
+ },
226
+ "ai.vision_model_id": {
227
+ kind: "string",
228
+ label: "Vision Model ID",
229
+ default: "",
230
+ description: "Vision-capable model profile used by the view_image tool. Empty disables the tool fallback.",
231
+ placeholder: "e.g. openrouter-vision",
232
+ },
233
+ "ai.workflow_model_id": {
234
+ kind: "string",
235
+ label: "Workflow Model ID",
236
+ default: "",
237
+ description: "Model profile id used for AI workflow actions. Empty = background model, then platform default.",
238
+ placeholder: "e.g. openrouter-fast",
239
+ },
240
+ "ai.enrich_cron": {
241
+ kind: "cron",
242
+ label: "Chat Enrichment Schedule",
243
+ default: "*/10 * * * *",
244
+ description: "How often dirty chats get an AI-generated summary, keywords, and title refresh for search.",
245
+ },
246
+ "ai.memory_learning_cron": {
247
+ kind: "cron",
248
+ label: "Personalization Learning Schedule",
249
+ default: "*/10 * * * *",
250
+ description: "How often completed private-chat turns and repeated Cloud workflows are checked for durable personalization.",
251
+ },
252
+ "ai.memory_learning_monthly_token_budget": {
253
+ kind: "number",
254
+ label: "Personalization Monthly Token Budget",
255
+ default: 100000,
256
+ min: 10000,
257
+ max: 10000000,
258
+ description: "Maximum accounted background-personalization tokens per user and calendar month.",
259
+ },
260
+ "ai.chat_enrichment_instructions": {
261
+ kind: "text",
262
+ label: "Additional Chat Enrichment Instructions",
263
+ default: "",
264
+ description: "Optional organization guidance added to the fixed chat enrichment task and output contract.",
265
+ placeholder: "Prefer organization-specific terminology when it is present in the chat.",
266
+ },
267
+ "ai.memory_learning_instructions": {
268
+ kind: "text",
269
+ label: "Additional Personalization Instructions",
270
+ default: "",
271
+ description: "Optional organization guidance added to the fixed personalization learning task and privacy contract.",
272
+ placeholder: "Keep learned preferences concise and use the user's language.",
273
+ },
274
+ "ai.global_instructions": {
275
+ kind: "template",
276
+ label: "Global Instructions",
277
+ default: "",
278
+ description:
279
+ "Optional instructions applied to every Cloud AI conversation after platform guardrails. Supports Liquid: {{ user.displayName }}, {{ user.uid }}, {{ user.mail }}, {{ appId }}, {{ now }}, {{ today }}, {{ time }}.",
280
+ placeholder: "Keep answers concise. The current user is {{ user.displayName }} and today is {{ today }}.",
281
+ templateVars: ["user.displayName", "user.uid", "user.mail", "appId", "now", "today", "time"],
282
+ },
283
+ "ai.compaction_instructions": {
284
+ kind: "text",
285
+ label: "Additional Compaction Instructions",
286
+ default: "",
287
+ description: "Optional organization guidance added to the fixed long-chat compaction task and completeness contract.",
288
+ placeholder: "Preserve internal ticket ids and use the organization's canonical team names.",
289
+ },
290
+ "ai.max_tool_result_chars": {
291
+ kind: "number",
292
+ label: "Tool Result Ceiling",
293
+ default: 2000000,
294
+ min: 500,
295
+ max: 4000000,
296
+ description:
297
+ "Operator ceiling for one tool result. The runtime uses a smaller budget automatically when the selected model has less context.",
298
+ },
299
+ "ai.firecrawl_api_key": {
300
+ kind: "secret",
301
+ label: "Firecrawl API Key",
302
+ default: "",
303
+ description: "Firecrawl API key used by Cloud AI web_search and web_extract tools.",
304
+ placeholder: "fc-...",
305
+ },
306
+ // ── PDF rendering ─────────────────────────────────────────────────────
307
+ "gotenberg.url": {
308
+ kind: "url",
309
+ label: "Gotenberg URL",
310
+ default: "",
311
+ description: "Internal base URL of the Gotenberg service used for HTML-to-PDF rendering.",
312
+ placeholder: "e.g. http://gotenberg:3000",
313
+ },
314
+ "gotenberg.username": {
315
+ kind: "string",
316
+ label: "Basic Auth Username",
317
+ default: "",
318
+ description: "Optional Gotenberg Basic Auth username.",
319
+ placeholder: "Gotenberg username",
320
+ },
321
+ "gotenberg.password": {
322
+ kind: "secret",
323
+ label: "Basic Auth Password",
324
+ default: "",
325
+ description: "Optional Gotenberg Basic Auth password.",
326
+ placeholder: "Gotenberg password",
327
+ },
328
+ "gotenberg.timeout_ms": {
329
+ kind: "number",
330
+ label: "Timeout",
331
+ default: 10000,
332
+ min: 100,
333
+ max: 120000,
334
+ description: "Maximum time in milliseconds for one Gotenberg render request.",
335
+ },
336
+ "gotenberg.max_html_bytes": {
337
+ kind: "number",
338
+ label: "Max HTML Bytes",
339
+ default: 1048576,
340
+ min: 1024,
341
+ max: 10485760,
342
+ description: "Maximum HTML input size accepted before sending a render request.",
343
+ },
344
+ "gotenberg.max_pdf_bytes": {
345
+ kind: "number",
346
+ label: "Max PDF Bytes",
347
+ default: 10485760,
348
+ min: 1024,
349
+ max: 104857600,
350
+ description: "Maximum PDF output size accepted from Gotenberg.",
351
+ },
352
+
353
+ // ── FreeIPA ─────────────────────────────────────────────────────────────
354
+ "freeipa.enable": {
355
+ kind: "boolean",
356
+ label: "Enable FreeIPA",
357
+ default: false,
358
+ description: "Enable FreeIPA-backed login, sync, account management, and IPA groups.",
359
+ envFallback: () => hasRequiredFreeIpaEnv(),
360
+ envBootstrap: () => (hasRequiredFreeIpaEnv() ? true : undefined),
361
+ },
362
+ "freeipa.url": {
363
+ kind: "string",
364
+ label: "Server Host",
365
+ default: "freeipa.ipa.example.com",
366
+ description: "FreeIPA host name used for RPC and login requests (without protocol).",
367
+ placeholder: "e.g. ipa.example.org",
368
+ envFallback: () => envString("FREEIPA_URL"),
369
+ envBootstrap: () => envString("FREEIPA_URL"),
370
+ },
371
+ "freeipa.ca_cert": {
372
+ kind: "text",
373
+ label: "CA Certificate (PEM)",
374
+ default: "",
375
+ description:
376
+ "Paste the FreeIPA root CA in PEM format to trust self-signed/private-CA servers without disabling validation. Preferred over allow_insecure.",
377
+ placeholder: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
378
+ },
379
+ "freeipa.allow_insecure": {
380
+ kind: "boolean",
381
+ label: "Allow Insecure TLS",
382
+ default: false,
383
+ description:
384
+ "Skip TLS certificate validation entirely. Use only for local dev — disables MITM protection. Ignored when ca_cert is set.",
385
+ },
386
+ "freeipa.service_user": {
387
+ kind: "string",
388
+ label: "Service User",
389
+ default: "svc-cloud",
390
+ description: "FreeIPA service account username used for internal admin operations.",
391
+ placeholder: "e.g. svc-cloud",
392
+ envFallback: () => envString("FREEIPA_SVC_USER"),
393
+ envBootstrap: () => envString("FREEIPA_SVC_USER"),
394
+ },
395
+ "freeipa.service_password": {
396
+ kind: "secret",
397
+ label: "Service Password",
398
+ default: "",
399
+ description: "FreeIPA service account password used for internal admin operations.",
400
+ envFallback: () => envString("FREEIPA_SVC_PASSWORD"),
401
+ envBootstrap: () => envString("FREEIPA_SVC_PASSWORD"),
402
+ },
403
+ "freeipa.groups.admin": {
404
+ kind: "string_list",
405
+ label: "Admin Groups",
406
+ default: ["admins"] as readonly string[],
407
+ description: "FreeIPA groups that imply app admin access.",
408
+ placeholder: "admins,cloud-admins",
409
+ envFallback: () => envCsv("GROUPS_ADMIN"),
410
+ envBootstrap: () => envCsv("GROUPS_ADMIN"),
411
+ },
412
+ "freeipa.groups.base_sync": {
413
+ kind: "string_list",
414
+ label: "Base Sync Groups",
415
+ default: [] as readonly string[],
416
+ description:
417
+ "Required. FreeIPA groups whose members get a Cloud account at all. There is no safe default — leaving this empty keeps FreeIPA incomplete rather than syncing your whole directory.",
418
+ placeholder: "e.g. ipausers",
419
+ envFallback: () => envCsv("GROUPS_BASE_SYNC"),
420
+ envBootstrap: () => envCsv("GROUPS_BASE_SYNC"),
421
+ },
422
+ "freeipa.groups.base_ipa_realm": {
423
+ kind: "string_list",
424
+ label: "Base Realm Groups",
425
+ default: [] as readonly string[],
426
+ description:
427
+ "Required. FreeIPA groups whose members become full users; everyone else in the sync scope becomes a guest. There is no safe default — leaving this empty keeps FreeIPA incomplete rather than demoting every account to guest.",
428
+ placeholder: "e.g. staff",
429
+ envFallback: () => envCsv("GROUPS_BASE_IPA_REALM"),
430
+ envBootstrap: () => envCsv("GROUPS_BASE_IPA_REALM"),
431
+ },
432
+ "freeipa.groups.excluded": {
433
+ kind: "string_list",
434
+ label: "Excluded Groups",
435
+ default: ["editors", "trust admins", "admins"] as readonly string[],
436
+ description: "FreeIPA groups excluded from mirrored memberships and hierarchy logic.",
437
+ placeholder: "editors,trust admins,admins",
438
+ envFallback: () => envCsv("GROUPS_EXCLUDED"),
439
+ envBootstrap: () => envCsv("GROUPS_EXCLUDED"),
440
+ },
441
+ "freeipa.user_match_mode": {
442
+ kind: "enum",
443
+ label: "User Match Mode",
444
+ default: "ignore",
445
+ description: "How IPA sync handles a unique local account match by email.",
446
+ options: IPA_MATCH_MODE_OPTIONS,
447
+ },
448
+ "freeipa.account_transition_policy": {
449
+ kind: "enum",
450
+ label: "Account Transition Policy",
451
+ default: "demote_to_local_guest",
452
+ description: "What happens when an IPA-backed account expires or disappears from sync scope.",
453
+ options: IPA_ACCOUNT_TRANSITION_OPTIONS,
454
+ },
455
+ "freeipa.sync_cron": {
456
+ kind: "cron",
457
+ label: "Sync Cron",
458
+ default: "*/5 * * * *",
459
+ description: "Five-field cron schedule for the FreeIPA sync job in app.timezone.",
460
+ },
461
+ "freeipa.sync_guard.max_user_changes": {
462
+ kind: "number",
463
+ label: "Max User Changes",
464
+ default: 10,
465
+ min: 0,
466
+ description: "Maximum users one sync may remove from scope or demote. Zero blocks every destructive user change.",
467
+ },
468
+ "freeipa.sync_guard.max_user_change_percent": {
469
+ kind: "number",
470
+ label: "Max User Change Percent",
471
+ default: 20,
472
+ min: 0,
473
+ max: 100,
474
+ description: "Maximum percentage of existing IPA users one sync may remove from scope or demote.",
475
+ },
476
+ "freeipa.sync_guard.max_group_deletions": {
477
+ kind: "number",
478
+ label: "Max Group Deletions",
479
+ default: 5,
480
+ min: 0,
481
+ description: "Maximum mirrored IPA groups one sync may delete. Zero blocks every group deletion.",
482
+ },
483
+ "freeipa.sync_guard.max_group_deletion_percent": {
484
+ kind: "number",
485
+ label: "Max Group Deletion Percent",
486
+ default: 20,
487
+ min: 0,
488
+ max: 100,
489
+ description: "Maximum percentage of existing IPA groups one sync may delete.",
490
+ },
491
+
492
+ // ── User ────────────────────────────────────────────────────────────────
493
+ "user.account_requests.enabled": {
494
+ kind: "boolean",
495
+ label: "Allow account requests",
496
+ default: false,
497
+ description:
498
+ "Allow local accounts to request FreeIPA access. Requires enabled FreeIPA access. Existing requests remain available for processing when disabled.",
499
+ },
500
+ "user.action_notice": {
501
+ kind: "template",
502
+ label: "Notice after account or group changes",
503
+ default: "",
504
+ templateVars: ["action", "id", "uid", "name", "email", "provider", "profile", "category", "firstName", "lastName", "relatedId"],
505
+ description:
506
+ "Optional Liquid-Markdown follow-up for the person changing an account or group, not a user notification. Branch on action, for example user.create or group.delete. Empty output shows no notice. Only the documented non-secret context is available.",
507
+ },
508
+ "user.allow_self_registration": {
509
+ kind: "boolean",
510
+ label: "Allow Self-Registration",
511
+ default: false,
512
+ description: "Allow creating a local guest account automatically during first email sign-in when no local account exists yet.",
513
+ },
514
+ "user.abbr_length": {
515
+ kind: "number",
516
+ label: "Username Abbreviation Length",
517
+ default: 5,
518
+ min: 1,
519
+ description: "Length of randomly generated username abbreviations for new accounts",
520
+ },
521
+ "user.session.expiry_hours": {
522
+ kind: "number",
523
+ label: "Session Expiry Hours",
524
+ default: 8,
525
+ min: 1,
526
+ description: "How long a login session stays valid (in hours)",
527
+ },
528
+ "user.account.ipa_expires_days": {
529
+ kind: "number",
530
+ label: "IPA Account Expiry Days",
531
+ default: 365,
532
+ min: 0,
533
+ description: "IPA accounts expire after this many days (0 = never expires)",
534
+ },
535
+ "user.account.local_user_expires_days": {
536
+ kind: "number",
537
+ label: "Local User Expiry Days",
538
+ default: 0,
539
+ min: 0,
540
+ description: "Local user accounts expire after this many days (0 = never expires)",
541
+ },
542
+ "user.account.local_guest_expires_days": {
543
+ kind: "number",
544
+ label: "Local Guest Expiry Days",
545
+ default: 365,
546
+ min: 0,
547
+ description: "Local guest accounts expire after this many days (0 = never expires)",
548
+ },
549
+ "user.account.reminder_days": {
550
+ kind: "number_list",
551
+ label: "Reminder Days",
552
+ default: [30, 7] as readonly number[],
553
+ description: "Days before expiry to send reminder emails.",
554
+ },
555
+ "user.account.reminder_cron": {
556
+ kind: "cron",
557
+ label: "Reminder Cron",
558
+ default: "0 9 * * *",
559
+ description: "Five-field cron schedule for account expiry reminder runs in app.timezone",
560
+ },
561
+ "user.account.deleted_accounts_retention_days": {
562
+ kind: "number",
563
+ label: "Deleted Accounts Retention Days",
564
+ default: 365,
565
+ min: 0,
566
+ description: "How many days deleted account history is kept before cleanup (0 = keep forever)",
567
+ },
568
+ "user.account.reminder_history_retention_days": {
569
+ kind: "number",
570
+ label: "Reminder History Retention Days",
571
+ default: 365,
572
+ min: 0,
573
+ description: "How many days reminder history is kept before cleanup (0 = keep forever)",
574
+ },
575
+
576
+ // Internal Web Push identity. Generated once and encrypted with all other
577
+ // settings; intentionally not exposed as an editable admin settings tab.
578
+ "notifications.web_push_public_key": {
579
+ kind: "string",
580
+ label: "Web Push Public Key",
581
+ default: "",
582
+ description: "Generated VAPID public key for browser notification subscriptions.",
583
+ },
584
+ "notifications.web_push_private_key": {
585
+ kind: "secret",
586
+ label: "Web Push Private Key",
587
+ default: "",
588
+ description: "Generated VAPID private key for browser notification delivery.",
589
+ },
590
+
591
+ // ── Mail (templates + SMTP) ─────────────────────────────────────────────
592
+ "mail.user_welcome_freeipa": {
593
+ kind: "template",
594
+ label: "FreeIPA Welcome Template",
595
+ default: `<p>Your account has been created.</p>
596
+ <p><strong>Login credentials:</strong></p>
597
+ <p>Username: <code style="background:#f4f4f5;padding:2px 6px;border-radius:4px;">{{USERNAME}}</code></p>
598
+ <p>Temporary password: <code style="background:#f4f4f5;padding:2px 6px;border-radius:4px;">{{PASSWORD}}</code></p>
599
+ {% if EXPIRY != blank %}<p>Your account is valid until: <strong>{{EXPIRY}}</strong></p>{% endif %}
600
+ <p><a href="{{LOGIN_URL}}">Click here to login</a></p>
601
+ <p style="margin-top:24px;padding:12px;background:#f4f4f5;border-radius:6px;"><strong>Your username:</strong> <code style="font-size:16px;">{{USERNAME}}</code></p>
602
+ {% if CONTACT_EMAIL != blank %}<p>If you have any questions, please contact us at <a href="mailto:{{CONTACT_EMAIL}}">{{CONTACT_EMAIL}}</a>.</p>{% endif %}`,
603
+ description: "FreeIPA welcome email template (HTML). Subject: Welcome to {{APP_NAME}}",
604
+ templateVars: ["USERNAME", "PASSWORD", "EXPIRY", "LOGIN_URL", "CONTACT_EMAIL", "APP_NAME"] as readonly string[],
605
+ },
606
+ "mail.user_welcome_local": {
607
+ kind: "template",
608
+ label: "Local Welcome Template",
609
+ default: `<p>Your account has been created.</p>
610
+ <p>Sign in with your email address: <code style="background:#f4f4f5;padding:2px 6px;border-radius:4px;">{{EMAIL}}</code></p>
611
+ {% if EXPIRY != blank %}<p>Your account is valid until: <strong>{{EXPIRY}}</strong></p>{% endif %}
612
+ <p><a href="{{LOGIN_URL}}">Open the login page</a> and choose email sign-in.</p>
613
+ {% if CONTACT_EMAIL != blank %}<p>If you have any questions, please contact us at <a href="mailto:{{CONTACT_EMAIL}}">{{CONTACT_EMAIL}}</a>.</p>{% endif %}`,
614
+ description: "Local welcome email template (HTML). Subject: Welcome to {{APP_NAME}}",
615
+ templateVars: ["EMAIL", "EXPIRY", "LOGIN_URL", "CONTACT_EMAIL", "APP_NAME"] as readonly string[],
616
+ },
617
+ "mail.magic_link_login": {
618
+ kind: "template",
619
+ label: "Magic Link Template",
620
+ default: `<p style="text-align:center;margin:0 0 24px 0;">
621
+ <code style="background:#f4f4f5;padding:8px 16px;border-radius:8px;letter-spacing:2px;font-weight:600;">{{TOKEN}}</code>
622
+ </p>
623
+ <p style="text-align:center;margin:0 0 24px 0;">
624
+ <a href="{{MAGIC_LINK}}" target="_blank" style="color:#3b82f6;text-decoration:underline;">Click here to log in directly</a>
625
+ </p>
626
+ <p style="text-align:center;color:#71717a;font-size:12px;margin:0 0 8px 0;">This code expires in 5 minutes. Never share this code or link with anyone. If you didn't request this, please ignore this email.</p>`,
627
+ description: "Magic link login email template (HTML). Subject: {{APP_NAME}} Login Code",
628
+ templateVars: ["TOKEN", "MAGIC_LINK", "APP_NAME"] as readonly string[],
629
+ },
630
+ "mail.ipa_email_login_hint": {
631
+ kind: "template",
632
+ label: "FreeIPA Email Login Hint Template",
633
+ default: `<p>A sign-in link was requested for <code style="background:#f4f4f5;padding:2px 6px;border-radius:4px;">{{EMAIL}}</code>.</p>
634
+ <p>This email address belongs to a FreeIPA-managed account. Please sign in with your FreeIPA username and password. If your email address is unique in FreeIPA, you can also use it instead of your username.</p>
635
+ <p style="text-align:center;margin:24px 0;">
636
+ <a href="{{LOGIN_URL}}" target="_blank" style="color:#3b82f6;text-decoration:underline;">Open FreeIPA sign-in</a>
637
+ </p>
638
+ <p style="color:#71717a;font-size:12px;margin:0 0 8px 0;">No email login code was created. If you didn't request this, please ignore this email.</p>
639
+ {% if CONTACT_EMAIL != blank %}<p style="color:#71717a;font-size:12px;margin:0;">If you need help, contact <a href="mailto:{{CONTACT_EMAIL}}">{{CONTACT_EMAIL}}</a>.</p>{% endif %}`,
640
+ description: "FreeIPA email-login hint template (HTML). Subject: {{APP_NAME}} FreeIPA Sign In",
641
+ templateVars: ["EMAIL", "LOGIN_URL", "CONTACT_EMAIL", "APP_NAME"] as readonly string[],
642
+ },
643
+ "mail.password_reset": {
644
+ kind: "template",
645
+ label: "Password Reset Template",
646
+ default: `<p>You requested a password reset for your {{APP_NAME}} account.</p>
647
+ <p style="text-align:center;margin:24px 0;">
648
+ <a href="{{RESET_LINK}}" target="_blank" style="color:#3b82f6;text-decoration:underline;">Set a new password</a>
649
+ </p>
650
+ <p style="color:#71717a;font-size:12px;margin:0 0 8px 0;">This link expires in 15 minutes. Never share this link with anyone. If you didn't request this, you can ignore this email.</p>
651
+ {% if CONTACT_EMAIL != blank %}<p style="color:#71717a;font-size:12px;margin:0;">If you need help, contact <a href="mailto:{{CONTACT_EMAIL}}">{{CONTACT_EMAIL}}</a>.</p>{% endif %}`,
652
+ description: "Password reset email template (HTML). Subject: {{APP_NAME}} Password Reset",
653
+ templateVars: ["RESET_LINK", "APP_NAME", "CONTACT_EMAIL"] as readonly string[],
654
+ },
655
+ "mail.account_expiry_reminder": {
656
+ kind: "template",
657
+ label: "Account Expiry Reminder Template",
658
+ default: `<p>Hi {{FIRST_NAME}},</p>
659
+ <p>Your {{APP_NAME}} account ({{ACCOUNT_KIND}}) will expire on <strong>{{EXPIRY}}</strong>.</p>
660
+ <p>You can extend your account here: <a href="{{EXTEND_URL}}">{{EXTEND_URL}}</a></p>
661
+ {% if CONTACT_EMAIL != blank %}<p>If you need help, contact <a href="mailto:{{CONTACT_EMAIL}}">{{CONTACT_EMAIL}}</a>.</p>{% endif %}`,
662
+ description: "Account expiry reminder email template (HTML). Subject: {{APP_NAME}} Account Expiry",
663
+ templateVars: ["FIRST_NAME", "DISPLAY_NAME", "EXPIRY", "EXTEND_URL", "APP_NAME", "CONTACT_EMAIL", "ACCOUNT_KIND"] as readonly string[],
664
+ },
665
+ "mail.account_request_denial": {
666
+ kind: "template",
667
+ label: "Account Request Denial Template",
668
+ default: `<p>Hi {{FIRST_NAME}},</p>
669
+ <p>Your request for an account has been reviewed and unfortunately cannot be approved at this time.</p>
670
+ <p><strong>Reason:</strong> {{REASON}}</p>
671
+ {% if CONTACT_EMAIL != blank %}<p>If you have questions, please contact <a href="mailto:{{CONTACT_EMAIL}}">{{CONTACT_EMAIL}}</a>.</p>{% endif %}`,
672
+ description: "Account request denial email template (HTML). Subject: Account Request Update",
673
+ templateVars: ["FIRST_NAME", "REASON", "CONTACT_EMAIL", "APP_NAME"] as readonly string[],
674
+ },
675
+ "mail.noreply.smtp_host": {
676
+ kind: "string",
677
+ label: "SMTP Host",
678
+ default: "",
679
+ description: "SMTP server hostname",
680
+ placeholder: "e.g. smtp.example.org",
681
+ },
682
+ "mail.noreply.smtp_port": {
683
+ kind: "number",
684
+ label: "SMTP Port",
685
+ default: 587,
686
+ min: 1,
687
+ max: 65535,
688
+ description: "SMTP server port (587 for STARTTLS, 465 for SSL)",
689
+ },
690
+ "mail.noreply.from": {
691
+ kind: "email",
692
+ label: "From Address",
693
+ default: "",
694
+ description: "From email address",
695
+ placeholder: "e.g. noreply@example.org",
696
+ },
697
+ "mail.noreply.user": {
698
+ kind: "string",
699
+ label: "SMTP User",
700
+ default: "",
701
+ description: "SMTP username",
702
+ placeholder: "e.g. noreply@example.org",
703
+ },
704
+ "mail.noreply.password": {
705
+ kind: "secret",
706
+ label: "SMTP Password",
707
+ default: "",
708
+ description: "SMTP password",
709
+ placeholder: "SMTP password",
710
+ },
711
+
712
+ // ── Security ────────────────────────────────────────────────────────────
713
+ "security.rate_limit_per_second": {
714
+ kind: "number",
715
+ label: "Requests Per Second",
716
+ default: 60,
717
+ min: 1,
718
+ description: "Maximum API requests per second per IP address",
719
+ },
720
+
721
+ // ── Legal documents (Imprint, Privacy, Terms) ──────────────────────────
722
+ // mode = "local" → render markdown from `legal.<kind>.content`
723
+ // mode = "external" → 302-redirect to `legal.<kind>.url`
724
+ "legal.terms.mode": {
725
+ kind: "enum",
726
+ label: "Terms of Service Source",
727
+ default: "local",
728
+ options: [
729
+ { value: "local", label: "Local content (markdown)" },
730
+ { value: "external", label: "External URL (redirect)" },
731
+ ],
732
+ description: "How the Terms of Service page (/legal/terms) is served.",
733
+ },
734
+ "legal.terms.content": {
735
+ kind: "text",
736
+ label: "Terms of Service Content",
737
+ default: "",
738
+ description: "Markdown rendered at /legal/terms when source = local.",
739
+ placeholder: "# Terms of Service\n\nYour terms here…",
740
+ },
741
+ "legal.terms.url": {
742
+ kind: "url",
743
+ label: "Terms of Service URL",
744
+ default: "",
745
+ description: "External URL redirected to from /legal/terms when source = external.",
746
+ placeholder: "https://example.org/terms",
747
+ },
748
+ "legal.privacy.mode": {
749
+ kind: "enum",
750
+ label: "Privacy Policy Source",
751
+ default: "local",
752
+ options: [
753
+ { value: "local", label: "Local content (markdown)" },
754
+ { value: "external", label: "External URL (redirect)" },
755
+ ],
756
+ description: "How the Privacy Policy page (/legal/privacy) is served.",
757
+ },
758
+ "legal.privacy.content": {
759
+ kind: "text",
760
+ label: "Privacy Policy Content",
761
+ default: "",
762
+ description: "Markdown rendered at /legal/privacy when source = local.",
763
+ placeholder: "# Privacy Policy\n\nYour privacy policy here…",
764
+ },
765
+ "legal.privacy.url": {
766
+ kind: "url",
767
+ label: "Privacy Policy URL",
768
+ default: "",
769
+ description: "External URL redirected to from /legal/privacy when source = external.",
770
+ placeholder: "https://example.org/privacy",
771
+ },
772
+ "legal.imprint.mode": {
773
+ kind: "enum",
774
+ label: "Imprint Source",
775
+ default: "local",
776
+ options: [
777
+ { value: "local", label: "Local content (markdown)" },
778
+ { value: "external", label: "External URL (redirect)" },
779
+ ],
780
+ description: "How the Imprint page (/impressum) is served. Required by §5 TMG (German law).",
781
+ },
782
+ "legal.imprint.content": {
783
+ kind: "text",
784
+ label: "Imprint Content",
785
+ default: "",
786
+ description: "Markdown rendered at /impressum when source = local.",
787
+ placeholder: "# Imprint\n\n**Operator**: Example Org\n\nAddress, contact, …",
788
+ },
789
+ "legal.imprint.url": {
790
+ kind: "url",
791
+ label: "Imprint URL",
792
+ default: "",
793
+ description: "External URL redirected to from /impressum when source = external.",
794
+ placeholder: "https://example.org/imprint",
795
+ },
796
+ } as const;