@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,622 @@
1
+ import { sql } from "bun";
2
+ import type { EntityKind, EntityListItem, UserProfile, UserProvider } from "../../contracts/shared";
3
+ import { getFreeIpaConfig } from "../freeipa-config";
4
+ import { escapeLikePattern, toPgTextArray, toPgUuidArray } from "../postgres";
5
+ import { buildBaseGroup } from "./base-group";
6
+ import { buildBaseUser } from "./base-user";
7
+ import { buildManagedGroupScopeCondition, recursiveGroupIdsSubquery } from "./group-sql";
8
+
9
+ type DbRow = Record<string, unknown>;
10
+ type SqlFragment = any;
11
+
12
+ export type EntityListParams = {
13
+ visibility: { type: "directory" } | { type: "self_and_effective_groups"; userId: string };
14
+ search?: string;
15
+ kinds?: EntityKind[];
16
+ provider?: UserProvider;
17
+ profile?: UserProfile;
18
+ userIds?: string[];
19
+ groupIds?: string[];
20
+ excludeUserIds?: string[];
21
+ excludeGroupIds?: string[];
22
+ excludeServiceAccountIds?: string[];
23
+ userMemberOfGroupIds?: string[];
24
+ memberOfGroupId?: string;
25
+ managerOfGroupId?: string;
26
+ parentGroupId?: string;
27
+ managedByUserId?: string;
28
+ recursive?: boolean;
29
+ page?: number;
30
+ perPage?: number;
31
+ };
32
+
33
+ type EntityQuerySpec = {
34
+ recursive: boolean;
35
+ prelude: SqlFragment;
36
+ userFrom: SqlFragment;
37
+ userDirectExpr: SqlFragment;
38
+ userWhere: SqlFragment;
39
+ groupFrom: SqlFragment;
40
+ groupDirectExpr: SqlFragment;
41
+ groupWhere: SqlFragment;
42
+ };
43
+
44
+ const buildNoRelationSpec = (): EntityQuerySpec => ({
45
+ recursive: false,
46
+ prelude: sql`scope_seed AS (SELECT 1 AS seed)`,
47
+ userFrom: sql`FROM auth.users u`,
48
+ userDirectExpr: sql`NULL::boolean`,
49
+ userWhere: sql`TRUE`,
50
+ groupFrom: sql`FROM auth.groups g`,
51
+ groupDirectExpr: sql`NULL::boolean`,
52
+ groupWhere: sql`TRUE`,
53
+ });
54
+
55
+ const buildMemberOfGroupSpec = (groupId: string, recursive: boolean): EntityQuerySpec => {
56
+ if (recursive) {
57
+ return {
58
+ recursive: true,
59
+ prelude: sql`
60
+ target_group AS (
61
+ SELECT id, provider
62
+ FROM auth.groups
63
+ WHERE id = ${groupId}::uuid
64
+ ),
65
+ member_group_tree AS (
66
+ SELECT gg.child_group_id AS group_id
67
+ FROM target_group tg
68
+ JOIN auth.group_groups_v2 gg ON gg.parent_group_id = tg.id
69
+ JOIN auth.groups g_child ON g_child.id = gg.child_group_id
70
+ WHERE g_child.provider = tg.provider
71
+ UNION
72
+ SELECT gg.child_group_id AS group_id
73
+ FROM auth.group_groups_v2 gg
74
+ JOIN auth.groups g_child ON g_child.id = gg.child_group_id
75
+ JOIN member_group_tree tree ON gg.parent_group_id = tree.group_id
76
+ JOIN target_group tg ON TRUE
77
+ WHERE g_child.provider = tg.provider
78
+ ),
79
+ member_user_rel AS (
80
+ SELECT ug.user_id AS entity_id, TRUE AS direct
81
+ FROM auth.user_groups_v2 ug
82
+ JOIN target_group tg ON ug.group_id = tg.id
83
+ JOIN auth.users u ON u.id = ug.user_id
84
+ WHERE tg.provider <> 'ipa' OR u.provider = 'ipa'
85
+ UNION ALL
86
+ SELECT ug.user_id AS entity_id, FALSE AS direct
87
+ FROM auth.user_groups_v2 ug
88
+ JOIN member_group_tree tree ON ug.group_id = tree.group_id
89
+ JOIN target_group tg ON TRUE
90
+ JOIN auth.users u ON u.id = ug.user_id
91
+ WHERE tg.provider <> 'ipa' OR u.provider = 'ipa'
92
+ ),
93
+ member_group_rel AS (
94
+ SELECT gg.child_group_id AS entity_id, TRUE AS direct
95
+ FROM target_group tg
96
+ JOIN auth.group_groups_v2 gg ON gg.parent_group_id = tg.id
97
+ JOIN auth.groups g ON g.id = gg.child_group_id
98
+ WHERE g.provider = tg.provider
99
+ UNION ALL
100
+ SELECT tree.group_id AS entity_id, FALSE AS direct
101
+ FROM member_group_tree tree
102
+ ),
103
+ relation_rows AS (
104
+ SELECT 'user'::text AS kind, entity_id, BOOL_OR(direct) AS direct
105
+ FROM member_user_rel
106
+ GROUP BY entity_id
107
+ UNION ALL
108
+ SELECT 'group'::text AS kind, entity_id, BOOL_OR(direct) AS direct
109
+ FROM member_group_rel
110
+ GROUP BY entity_id
111
+ )
112
+ `,
113
+ userFrom: sql`FROM auth.users u JOIN relation_rows rr ON rr.kind = 'user' AND rr.entity_id = u.id`,
114
+ userDirectExpr: sql`rr.direct`,
115
+ userWhere: sql`TRUE`,
116
+ groupFrom: sql`FROM auth.groups g JOIN relation_rows rr ON rr.kind = 'group' AND rr.entity_id = g.id`,
117
+ groupDirectExpr: sql`rr.direct`,
118
+ groupWhere: sql`TRUE`,
119
+ };
120
+ }
121
+
122
+ return {
123
+ recursive: false,
124
+ prelude: sql`
125
+ target_group AS (
126
+ SELECT id, provider
127
+ FROM auth.groups
128
+ WHERE id = ${groupId}::uuid
129
+ ),
130
+ relation_rows AS (
131
+ SELECT 'user'::text AS kind, ug.user_id AS entity_id, TRUE AS direct
132
+ FROM auth.user_groups_v2 ug
133
+ JOIN target_group tg ON ug.group_id = tg.id
134
+ JOIN auth.users u ON u.id = ug.user_id
135
+ WHERE tg.provider <> 'ipa' OR u.provider = 'ipa'
136
+ UNION ALL
137
+ SELECT 'group'::text AS kind, gg.child_group_id AS entity_id, TRUE AS direct
138
+ FROM target_group tg
139
+ JOIN auth.group_groups_v2 gg ON gg.parent_group_id = tg.id
140
+ JOIN auth.groups g ON g.id = gg.child_group_id
141
+ WHERE g.provider = tg.provider
142
+ )
143
+ `,
144
+ userFrom: sql`FROM auth.users u JOIN relation_rows rr ON rr.kind = 'user' AND rr.entity_id = u.id`,
145
+ userDirectExpr: sql`rr.direct`,
146
+ userWhere: sql`TRUE`,
147
+ groupFrom: sql`FROM auth.groups g JOIN relation_rows rr ON rr.kind = 'group' AND rr.entity_id = g.id`,
148
+ groupDirectExpr: sql`rr.direct`,
149
+ groupWhere: sql`TRUE`,
150
+ };
151
+ };
152
+
153
+ const buildManagerOfGroupSpec = (groupId: string, recursive: boolean): EntityQuerySpec => {
154
+ if (recursive) {
155
+ return {
156
+ recursive: true,
157
+ prelude: sql`
158
+ target_group AS (
159
+ SELECT id, provider
160
+ FROM auth.groups
161
+ WHERE id = ${groupId}::uuid
162
+ ),
163
+ manager_group_tree AS (
164
+ SELECT gmg.manager_group_id AS group_id
165
+ FROM target_group tg
166
+ JOIN auth.group_manager_groups_v2 gmg ON gmg.group_id = tg.id
167
+ JOIN auth.groups g_manager ON g_manager.id = gmg.manager_group_id
168
+ WHERE g_manager.provider = tg.provider
169
+ UNION
170
+ SELECT gg.parent_group_id AS group_id
171
+ FROM auth.group_groups_v2 gg
172
+ JOIN auth.groups g_parent ON g_parent.id = gg.parent_group_id
173
+ JOIN manager_group_tree tree ON gg.child_group_id = tree.group_id
174
+ JOIN target_group tg ON TRUE
175
+ WHERE g_parent.provider = tg.provider
176
+ ),
177
+ manager_user_rel AS (
178
+ SELECT gmu.user_id AS entity_id, TRUE AS direct
179
+ FROM auth.group_manager_users_v2 gmu
180
+ JOIN target_group tg ON gmu.group_id = tg.id
181
+ JOIN auth.users u ON u.id = gmu.user_id
182
+ WHERE tg.provider <> 'ipa' OR u.provider = 'ipa'
183
+ UNION ALL
184
+ SELECT ug.user_id AS entity_id, FALSE AS direct
185
+ FROM auth.user_groups_v2 ug
186
+ JOIN manager_group_tree tree ON ug.group_id = tree.group_id
187
+ JOIN target_group tg ON TRUE
188
+ JOIN auth.users u ON u.id = ug.user_id
189
+ WHERE tg.provider <> 'ipa' OR u.provider = 'ipa'
190
+ ),
191
+ manager_group_rel AS (
192
+ SELECT gmg.manager_group_id AS entity_id, TRUE AS direct
193
+ FROM target_group tg
194
+ JOIN auth.group_manager_groups_v2 gmg ON gmg.group_id = tg.id
195
+ JOIN auth.groups g ON g.id = gmg.manager_group_id
196
+ WHERE g.provider = tg.provider
197
+ UNION ALL
198
+ SELECT tree.group_id AS entity_id, FALSE AS direct
199
+ FROM manager_group_tree tree
200
+ ),
201
+ relation_rows AS (
202
+ SELECT 'user'::text AS kind, entity_id, BOOL_OR(direct) AS direct
203
+ FROM manager_user_rel
204
+ GROUP BY entity_id
205
+ UNION ALL
206
+ SELECT 'group'::text AS kind, entity_id, BOOL_OR(direct) AS direct
207
+ FROM manager_group_rel
208
+ GROUP BY entity_id
209
+ )
210
+ `,
211
+ userFrom: sql`FROM auth.users u JOIN relation_rows rr ON rr.kind = 'user' AND rr.entity_id = u.id`,
212
+ userDirectExpr: sql`rr.direct`,
213
+ userWhere: sql`TRUE`,
214
+ groupFrom: sql`FROM auth.groups g JOIN relation_rows rr ON rr.kind = 'group' AND rr.entity_id = g.id`,
215
+ groupDirectExpr: sql`rr.direct`,
216
+ groupWhere: sql`TRUE`,
217
+ };
218
+ }
219
+
220
+ return {
221
+ recursive: false,
222
+ prelude: sql`
223
+ target_group AS (
224
+ SELECT id, provider
225
+ FROM auth.groups
226
+ WHERE id = ${groupId}::uuid
227
+ ),
228
+ relation_rows AS (
229
+ SELECT 'user'::text AS kind, gmu.user_id AS entity_id, TRUE AS direct
230
+ FROM auth.group_manager_users_v2 gmu
231
+ JOIN target_group tg ON gmu.group_id = tg.id
232
+ JOIN auth.users u ON u.id = gmu.user_id
233
+ WHERE tg.provider <> 'ipa' OR u.provider = 'ipa'
234
+ UNION ALL
235
+ SELECT 'group'::text AS kind, gmg.manager_group_id AS entity_id, TRUE AS direct
236
+ FROM target_group tg
237
+ JOIN auth.group_manager_groups_v2 gmg ON gmg.group_id = tg.id
238
+ JOIN auth.groups g ON g.id = gmg.manager_group_id
239
+ WHERE g.provider = tg.provider
240
+ )
241
+ `,
242
+ userFrom: sql`FROM auth.users u JOIN relation_rows rr ON rr.kind = 'user' AND rr.entity_id = u.id`,
243
+ userDirectExpr: sql`rr.direct`,
244
+ userWhere: sql`TRUE`,
245
+ groupFrom: sql`FROM auth.groups g JOIN relation_rows rr ON rr.kind = 'group' AND rr.entity_id = g.id`,
246
+ groupDirectExpr: sql`rr.direct`,
247
+ groupWhere: sql`TRUE`,
248
+ };
249
+ };
250
+
251
+ const buildParentGroupSpec = (groupId: string, recursive: boolean): EntityQuerySpec => {
252
+ if (recursive) {
253
+ return {
254
+ recursive: true,
255
+ prelude: sql`
256
+ target_group AS (
257
+ SELECT id, provider
258
+ FROM auth.groups
259
+ WHERE id = ${groupId}::uuid
260
+ ),
261
+ parent_group_tree AS (
262
+ SELECT gg.parent_group_id AS group_id
263
+ FROM target_group tg
264
+ JOIN auth.group_groups_v2 gg ON gg.child_group_id = tg.id
265
+ JOIN auth.groups g_parent ON g_parent.id = gg.parent_group_id
266
+ WHERE g_parent.provider = tg.provider
267
+ UNION
268
+ SELECT gg.parent_group_id AS group_id
269
+ FROM auth.group_groups_v2 gg
270
+ JOIN auth.groups g_parent ON g_parent.id = gg.parent_group_id
271
+ JOIN parent_group_tree tree ON gg.child_group_id = tree.group_id
272
+ JOIN target_group tg ON TRUE
273
+ WHERE g_parent.provider = tg.provider
274
+ ),
275
+ parent_group_rel AS (
276
+ SELECT gg.parent_group_id AS entity_id, TRUE AS direct
277
+ FROM target_group tg
278
+ JOIN auth.group_groups_v2 gg ON gg.child_group_id = tg.id
279
+ JOIN auth.groups g_parent ON g_parent.id = gg.parent_group_id
280
+ WHERE g_parent.provider = tg.provider
281
+ UNION ALL
282
+ SELECT tree.group_id AS entity_id, FALSE AS direct
283
+ FROM parent_group_tree tree
284
+ ),
285
+ relation_rows AS (
286
+ SELECT 'group'::text AS kind, entity_id, BOOL_OR(direct) AS direct
287
+ FROM parent_group_rel
288
+ GROUP BY entity_id
289
+ )
290
+ `,
291
+ userFrom: sql`FROM auth.users u JOIN relation_rows rr ON rr.kind = 'user' AND rr.entity_id = u.id`,
292
+ userDirectExpr: sql`rr.direct`,
293
+ userWhere: sql`FALSE`,
294
+ groupFrom: sql`FROM auth.groups g JOIN relation_rows rr ON rr.kind = 'group' AND rr.entity_id = g.id`,
295
+ groupDirectExpr: sql`rr.direct`,
296
+ groupWhere: sql`TRUE`,
297
+ };
298
+ }
299
+
300
+ return {
301
+ recursive: false,
302
+ prelude: sql`
303
+ target_group AS (
304
+ SELECT id, provider
305
+ FROM auth.groups
306
+ WHERE id = ${groupId}::uuid
307
+ ),
308
+ relation_rows AS (
309
+ SELECT 'group'::text AS kind, gg.parent_group_id AS entity_id, TRUE AS direct
310
+ FROM target_group tg
311
+ JOIN auth.group_groups_v2 gg ON gg.child_group_id = tg.id
312
+ JOIN auth.groups g_parent ON g_parent.id = gg.parent_group_id
313
+ WHERE g_parent.provider = tg.provider
314
+ )
315
+ `,
316
+ userFrom: sql`FROM auth.users u JOIN relation_rows rr ON rr.kind = 'user' AND rr.entity_id = u.id`,
317
+ userDirectExpr: sql`rr.direct`,
318
+ userWhere: sql`FALSE`,
319
+ groupFrom: sql`FROM auth.groups g JOIN relation_rows rr ON rr.kind = 'group' AND rr.entity_id = g.id`,
320
+ groupDirectExpr: sql`rr.direct`,
321
+ groupWhere: sql`TRUE`,
322
+ };
323
+ };
324
+
325
+ const buildManagedByUserSpec = (userId: string, recursive: boolean): EntityQuerySpec => {
326
+ const directCondition = sql`
327
+ (
328
+ g.id IN (
329
+ SELECT DISTINCT g_manage.id
330
+ FROM auth.groups g_manage
331
+ LEFT JOIN auth.group_manager_users_v2 gmu ON gmu.group_id = g_manage.id AND gmu.user_id = ${userId}::uuid
332
+ LEFT JOIN auth.group_manager_groups_v2 gmg ON gmg.group_id = g_manage.id
333
+ LEFT JOIN auth.user_groups_v2 ug ON ug.group_id = gmg.manager_group_id AND ug.user_id = ${userId}::uuid
334
+ LEFT JOIN auth.groups g_manager ON g_manager.id = gmg.manager_group_id
335
+ WHERE g_manage.provider = g.provider
336
+ AND (gmu.user_id IS NOT NULL OR (ug.user_id IS NOT NULL AND g_manager.provider = g_manage.provider))
337
+ )
338
+ )
339
+ `;
340
+
341
+ return {
342
+ recursive: false,
343
+ prelude: sql`scope_seed AS (SELECT 1 AS seed)`,
344
+ userFrom: sql`FROM auth.users u`,
345
+ userDirectExpr: sql`NULL::boolean`,
346
+ userWhere: sql`FALSE`,
347
+ groupFrom: sql`FROM auth.groups g`,
348
+ groupDirectExpr: sql`NULL::boolean`,
349
+ groupWhere: recursive ? buildManagedGroupScopeCondition({ userId, groupProvider: sql`g.provider` }) : directCondition,
350
+ };
351
+ };
352
+
353
+ const buildQuerySpec = (params: EntityListParams): EntityQuerySpec => {
354
+ const relationFilters = [params.memberOfGroupId, params.managerOfGroupId, params.parentGroupId, params.managedByUserId].filter(Boolean);
355
+
356
+ if (relationFilters.length > 1) {
357
+ throw new Error("Only one relation filter can be used at a time.");
358
+ }
359
+
360
+ if (params.memberOfGroupId) return buildMemberOfGroupSpec(params.memberOfGroupId, Boolean(params.recursive));
361
+ if (params.managerOfGroupId) return buildManagerOfGroupSpec(params.managerOfGroupId, Boolean(params.recursive));
362
+ if (params.parentGroupId) return buildParentGroupSpec(params.parentGroupId, Boolean(params.recursive));
363
+ if (params.managedByUserId) return buildManagedByUserSpec(params.managedByUserId, params.recursive !== false);
364
+ return buildNoRelationSpec();
365
+ };
366
+
367
+ const mapEntityRow = (row: DbRow): EntityListItem => {
368
+ const direct = typeof row.direct === "boolean" ? row.direct : undefined;
369
+
370
+ if (row.kind === "user") {
371
+ return {
372
+ kind: "user",
373
+ user: buildBaseUser(row),
374
+ relation: direct === undefined ? undefined : { direct },
375
+ };
376
+ }
377
+
378
+ if (row.kind === "service_account") {
379
+ return {
380
+ kind: "service_account",
381
+ serviceAccount: {
382
+ id: String(row.id),
383
+ name: String(row.name ?? ""),
384
+ kind: row.service_account_kind === "resource_bound" ? "resource_bound" : "user_delegated",
385
+ status: row.status === "disabled" ? "disabled" : "active",
386
+ delegatedUserId: typeof row.delegated_user_id === "string" ? row.delegated_user_id : null,
387
+ appId: typeof row.app_id === "string" ? row.app_id : null,
388
+ resourceType: typeof row.resource_type === "string" ? row.resource_type : null,
389
+ resourceId: typeof row.resource_id === "string" ? row.resource_id : null,
390
+ createdBy: typeof row.created_by === "string" ? row.created_by : null,
391
+ createdAt: row.created_at instanceof Date ? row.created_at.toISOString() : String(row.created_at),
392
+ },
393
+ relation: direct === undefined ? undefined : { direct },
394
+ };
395
+ }
396
+
397
+ return {
398
+ kind: "group",
399
+ group: buildBaseGroup(row),
400
+ relation: direct === undefined ? undefined : { direct },
401
+ };
402
+ };
403
+
404
+ export const list = async (
405
+ params: EntityListParams,
406
+ ): Promise<{
407
+ items: EntityListItem[];
408
+ total: number;
409
+ pagination: { page: number; perPage: number; totalPages: number; hasNext: boolean };
410
+ }> => {
411
+ const page = params.page ?? 1;
412
+ const perPage = params.perPage ?? 100;
413
+ const offset = (page - 1) * perPage;
414
+ const pattern = params.search ? `%${escapeLikePattern(params.search.trim().toLowerCase())}%` : null;
415
+ const groupsAdmin = (await getFreeIpaConfig()).groupsAdmin;
416
+ const groupsAdminLiteral = toPgTextArray(groupsAdmin);
417
+ const spec = buildQuerySpec(params);
418
+ const visibilityCondition =
419
+ params.visibility.type === "directory"
420
+ ? sql`TRUE`
421
+ : sql`(
422
+ (kind = 'user' AND id = ${params.visibility.userId}::uuid)
423
+ OR (
424
+ kind = 'group'
425
+ AND id IN (${recursiveGroupIdsSubquery(params.visibility.userId)})
426
+ )
427
+ )`;
428
+ const kindsCondition = (params.kinds?.length ?? 0) === 0 ? sql`TRUE` : sql`kind = ANY(${toPgTextArray(params.kinds ?? [])}::text[])`;
429
+ const hasIdFilter = params.userIds !== undefined || params.groupIds !== undefined;
430
+ const includeIdCondition = !hasIdFilter
431
+ ? sql`TRUE`
432
+ : sql`(
433
+ (kind = 'user' AND id = ANY(${toPgUuidArray(params.userIds ?? [])}::uuid[]))
434
+ OR (kind = 'group' AND id = ANY(${toPgUuidArray(params.groupIds ?? [])}::uuid[]))
435
+ )`;
436
+ const excludeUserCondition =
437
+ (params.excludeUserIds?.length ?? 0) === 0
438
+ ? sql`TRUE`
439
+ : sql`(kind <> 'user' OR id <> ALL(${toPgUuidArray(params.excludeUserIds ?? [])}::uuid[]))`;
440
+ const excludeGroupCondition =
441
+ (params.excludeGroupIds?.length ?? 0) === 0
442
+ ? sql`TRUE`
443
+ : sql`(kind <> 'group' OR id <> ALL(${toPgUuidArray(params.excludeGroupIds ?? [])}::uuid[]))`;
444
+ const excludeServiceAccountCondition =
445
+ (params.excludeServiceAccountIds?.length ?? 0) === 0
446
+ ? sql`TRUE`
447
+ : sql`(kind <> 'service_account' OR id <> ALL(${toPgUuidArray(params.excludeServiceAccountIds ?? [])}::uuid[]))`;
448
+ const userMemberOfGroupCondition =
449
+ (params.userMemberOfGroupIds?.length ?? 0) === 0
450
+ ? sql`TRUE`
451
+ : sql`(kind <> 'user' OR EXISTS (
452
+ SELECT 1
453
+ FROM auth.user_groups_v2 ug
454
+ WHERE ug.user_id = id
455
+ AND ug.group_id = ANY(${toPgUuidArray(params.userMemberOfGroupIds ?? [])}::uuid[])
456
+ ))`;
457
+
458
+ const where = sql`
459
+ ${visibilityCondition}
460
+ AND ${kindsCondition}
461
+ AND ${includeIdCondition}
462
+ AND (${params.provider ?? null}::text IS NULL OR provider = ${params.provider ?? null})
463
+ AND (${params.profile ?? null}::text IS NULL OR kind = 'group' OR profile = ${params.profile ?? null})
464
+ AND ${excludeUserCondition}
465
+ AND ${excludeGroupCondition}
466
+ AND ${excludeServiceAccountCondition}
467
+ AND ${userMemberOfGroupCondition}
468
+ AND (
469
+ ${pattern}::text IS NULL
470
+ OR (
471
+ kind = 'user' AND (
472
+ LOWER(uid) LIKE ${pattern} ESCAPE '\\'
473
+ OR LOWER(COALESCE(display_name, '')) LIKE ${pattern} ESCAPE '\\'
474
+ OR LOWER(COALESCE(given_name, '')) LIKE ${pattern} ESCAPE '\\'
475
+ OR LOWER(COALESCE(sn, '')) LIKE ${pattern} ESCAPE '\\'
476
+ OR LOWER(COALESCE(mail, '')) LIKE ${pattern} ESCAPE '\\'
477
+ )
478
+ )
479
+ OR (
480
+ kind = 'group' AND (
481
+ LOWER(name) LIKE ${pattern} ESCAPE '\\'
482
+ OR LOWER(COALESCE(description, '')) LIKE ${pattern} ESCAPE '\\'
483
+ )
484
+ )
485
+ OR (
486
+ kind = 'service_account' AND (
487
+ LOWER(name) LIKE ${pattern} ESCAPE '\\'
488
+ OR LOWER(COALESCE(app_id, '')) LIKE ${pattern} ESCAPE '\\'
489
+ OR LOWER(COALESCE(resource_type, '')) LIKE ${pattern} ESCAPE '\\'
490
+ OR LOWER(COALESCE(resource_id, '')) LIKE ${pattern} ESCAPE '\\'
491
+ )
492
+ )
493
+ )
494
+ `;
495
+
496
+ const rows = await sql<DbRow[]>`
497
+ WITH ${spec.recursive ? sql`RECURSIVE` : sql``}
498
+ ${spec.prelude},
499
+ user_rows AS (
500
+ SELECT
501
+ 'user'::text AS kind,
502
+ ${spec.userDirectExpr} AS direct,
503
+ u.id,
504
+ u.provider,
505
+ u.profile,
506
+ u.uid,
507
+ u.given_name,
508
+ u.sn,
509
+ u.display_name,
510
+ u.mail,
511
+ u.avatar_hash,
512
+ NULL::text AS name,
513
+ NULL::text AS description,
514
+ NULL::int AS gid_number,
515
+ CASE
516
+ WHEN u.provider = 'local' THEN u.admin
517
+ ELSE EXISTS(
518
+ SELECT 1
519
+ FROM auth.ipa_user_effective_groups eg
520
+ WHERE eg.user_id = u.id
521
+ AND eg.group_name = ANY(${groupsAdminLiteral}::text[])
522
+ )
523
+ END AS effective_admin,
524
+ NULL::text AS service_account_kind,
525
+ NULL::text AS status,
526
+ NULL::uuid AS delegated_user_id,
527
+ NULL::text AS app_id,
528
+ NULL::text AS resource_type,
529
+ NULL::text AS resource_id,
530
+ NULL::uuid AS created_by,
531
+ NULL::timestamptz AS created_at,
532
+ LOWER(COALESCE(NULLIF(u.display_name, ''), NULLIF(u.mail, ''), u.uid)) AS sort_label
533
+ ${spec.userFrom}
534
+ WHERE ${spec.userWhere}
535
+ ),
536
+ group_rows AS (
537
+ SELECT
538
+ 'group'::text AS kind,
539
+ ${spec.groupDirectExpr} AS direct,
540
+ g.id,
541
+ g.provider,
542
+ NULL::text AS profile,
543
+ NULL::text AS uid,
544
+ NULL::text AS given_name,
545
+ NULL::text AS sn,
546
+ NULL::text AS display_name,
547
+ NULL::text AS mail,
548
+ NULL::text AS avatar_hash,
549
+ g.name,
550
+ g.description,
551
+ g.gid_number,
552
+ NULL::boolean AS effective_admin,
553
+ NULL::text AS service_account_kind,
554
+ NULL::text AS status,
555
+ NULL::uuid AS delegated_user_id,
556
+ NULL::text AS app_id,
557
+ NULL::text AS resource_type,
558
+ NULL::text AS resource_id,
559
+ NULL::uuid AS created_by,
560
+ NULL::timestamptz AS created_at,
561
+ LOWER(g.name) AS sort_label
562
+ ${spec.groupFrom}
563
+ WHERE ${spec.groupWhere}
564
+ ),
565
+ service_account_rows AS (
566
+ SELECT
567
+ 'service_account'::text AS kind,
568
+ NULL::boolean AS direct,
569
+ sa.id,
570
+ NULL::text AS provider,
571
+ NULL::text AS profile,
572
+ NULL::text AS uid,
573
+ NULL::text AS given_name,
574
+ NULL::text AS sn,
575
+ NULL::text AS display_name,
576
+ NULL::text AS mail,
577
+ NULL::text AS avatar_hash,
578
+ sa.name,
579
+ CASE
580
+ WHEN sa.kind = 'user_delegated' THEN 'Personal automation keys'
581
+ ELSE CONCAT_WS(' · ', sa.app_id, sa.resource_type, sa.resource_id)
582
+ END AS description,
583
+ NULL::int AS gid_number,
584
+ NULL::boolean AS effective_admin,
585
+ sa.kind AS service_account_kind,
586
+ sa.status,
587
+ sa.delegated_user_id,
588
+ sa.app_id,
589
+ sa.resource_type,
590
+ sa.resource_id,
591
+ sa.created_by,
592
+ sa.created_at,
593
+ LOWER(sa.name) AS sort_label
594
+ FROM auth.service_accounts sa
595
+ ),
596
+ entity_rows AS (
597
+ SELECT * FROM user_rows
598
+ UNION ALL
599
+ SELECT * FROM group_rows
600
+ UNION ALL
601
+ SELECT * FROM service_account_rows
602
+ )
603
+ SELECT *, COUNT(*) OVER() AS total
604
+ FROM entity_rows
605
+ WHERE ${where}
606
+ ORDER BY sort_label, kind, id
607
+ LIMIT ${perPage}
608
+ OFFSET ${offset}
609
+ `;
610
+
611
+ const total = rows.length > 0 ? Number((rows[0] as Record<string, unknown>).total) : 0;
612
+ return {
613
+ items: rows.map(mapEntityRow),
614
+ total,
615
+ pagination: {
616
+ page,
617
+ perPage,
618
+ totalPages: Math.ceil(total / perPage),
619
+ hasNext: page * perPage < total,
620
+ },
621
+ };
622
+ };