@cosmicdrift/kumiko-samples 0.386.0 → 0.388.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 (530) hide show
  1. package/LICENSE +21 -57
  2. package/README.md +1 -1
  3. package/package.json +2 -2
  4. package/packages/bundled-features/package.json +9 -2
  5. package/packages/bundled-features/src/agent-tools/changes.json +6 -0
  6. package/packages/bundled-features/src/agent-tools/tool-catalog.ts +1 -1
  7. package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +9 -9
  8. package/packages/bundled-features/src/audit/changes.json +12 -0
  9. package/packages/bundled-features/src/audit/handlers/audit-events.ts +1 -1
  10. package/packages/bundled-features/src/audit/screens.ts +1 -1
  11. package/packages/bundled-features/src/auth-email-password/auth-user-row.ts +10 -10
  12. package/packages/bundled-features/src/auth-email-password/feature.ts +6 -6
  13. package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +3 -3
  14. package/packages/bundled-features/src/auth-email-password/handlers/confirm-token-flow.ts +5 -5
  15. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +1 -1
  16. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +18 -18
  17. package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +12 -12
  18. package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +1 -1
  19. package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +24 -26
  20. package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +1 -1
  21. package/packages/bundled-features/src/auth-email-password/handlers/self-registration-status.query.ts +1 -1
  22. package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +34 -37
  23. package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +6 -7
  24. package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +1 -5
  25. package/packages/bundled-features/src/auth-email-password/index.ts +5 -5
  26. package/packages/bundled-features/src/auth-email-password/lockout-store.ts +1 -1
  27. package/packages/bundled-features/src/auth-email-password/seeding.ts +63 -66
  28. package/packages/bundled-features/src/auth-email-password/signup-token-store.ts +8 -8
  29. package/packages/bundled-features/src/auth-email-password/testing.ts +3 -3
  30. package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +57 -57
  31. package/packages/bundled-features/src/auth-email-password/web/auth-form-primitives.tsx +14 -14
  32. package/packages/bundled-features/src/auth-email-password/web/auth-gate.tsx +15 -16
  33. package/packages/bundled-features/src/auth-email-password/web/client-plugin.ts +11 -12
  34. package/packages/bundled-features/src/auth-email-password/web/confirm-account-unlock-screen.tsx +1 -1
  35. package/packages/bundled-features/src/auth-email-password/web/constants.ts +3 -3
  36. package/packages/bundled-features/src/auth-email-password/web/default-topbar-actions.tsx +14 -14
  37. package/packages/bundled-features/src/auth-email-password/web/forgot-password-screen.tsx +11 -11
  38. package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -5
  39. package/packages/bundled-features/src/auth-email-password/web/invite-accept-screen.tsx +17 -17
  40. package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +3 -4
  41. package/packages/bundled-features/src/auth-email-password/web/reset-password-screen.tsx +16 -17
  42. package/packages/bundled-features/src/auth-email-password/web/session.tsx +34 -34
  43. package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +3 -3
  44. package/packages/bundled-features/src/auth-email-password/web/signup-screen.tsx +14 -14
  45. package/packages/bundled-features/src/auth-email-password/web/tenant-switcher.tsx +26 -27
  46. package/packages/bundled-features/src/auth-email-password/web/use-shell-user.ts +12 -13
  47. package/packages/bundled-features/src/auth-email-password/web/user-menu.tsx +17 -18
  48. package/packages/bundled-features/src/auth-email-password/web/verify-email-screen.tsx +11 -12
  49. package/packages/bundled-features/src/auth-foundation/boot-checks.ts +4 -4
  50. package/packages/bundled-features/src/auth-foundation/resolve-anonymous-access.ts +4 -4
  51. package/packages/bundled-features/src/auth-foundation/types.ts +2 -2
  52. package/packages/bundled-features/src/auth-mfa/changes.json +6 -0
  53. package/packages/bundled-features/src/auth-mfa/feature-exports.ts +2 -2
  54. package/packages/bundled-features/src/auth-mfa/feature.ts +6 -0
  55. package/packages/bundled-features/src/auth-mfa/handlers/disable.write.ts +3 -3
  56. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +4 -4
  57. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm.write.ts +2 -2
  58. package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +1 -1
  59. package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +1 -1
  60. package/packages/bundled-features/src/auth-mfa/handlers/regenerate-recovery.write.ts +5 -5
  61. package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +1 -1
  62. package/packages/bundled-features/src/auth-mfa/token-secrets.ts +1 -1
  63. package/packages/bundled-features/src/auth-mfa/web/client-plugin.ts +2 -2
  64. package/packages/bundled-features/src/auth-mfa/web/i18n.ts +9 -4
  65. package/packages/bundled-features/src/auth-mfa/web/index.ts +4 -4
  66. package/packages/bundled-features/src/auth-mfa/web/mfa-client.ts +17 -16
  67. package/packages/bundled-features/src/auth-mfa/web/mfa-code-or-recovery-field.tsx +68 -0
  68. package/packages/bundled-features/src/auth-mfa/web/mfa-disable-dialog.tsx +23 -13
  69. package/packages/bundled-features/src/auth-mfa/web/mfa-regenerate-recovery-dialog.tsx +23 -13
  70. package/packages/bundled-features/src/auth-mfa/web/mfa-setup-preauth-screen.tsx +15 -6
  71. package/packages/bundled-features/src/auth-mfa/web/mfa-verify-screen.tsx +71 -24
  72. package/packages/bundled-features/src/billing-foundation/aggregate-id.ts +10 -11
  73. package/packages/bundled-features/src/billing-foundation/changes.json +55 -0
  74. package/packages/bundled-features/src/billing-foundation/checkout-core.ts +32 -42
  75. package/packages/bundled-features/src/billing-foundation/consumer-protection/confirmation-mail.ts +8 -2
  76. package/packages/bundled-features/src/billing-foundation/consumer-protection/consent-gate.ts +2 -0
  77. package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +14 -3
  78. package/packages/bundled-features/src/billing-foundation/consumer-protection/mail-notifications.ts +3 -4
  79. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-receipt-limit.ts +12 -6
  80. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-record.ts +35 -19
  81. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +12 -8
  82. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-revoke.ts +14 -8
  83. package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-texts.ts +5 -0
  84. package/packages/bundled-features/src/billing-foundation/consumer-protection/withdrawal-period.ts +8 -10
  85. package/packages/bundled-features/src/billing-foundation/entities.ts +27 -27
  86. package/packages/bundled-features/src/billing-foundation/events.ts +23 -21
  87. package/packages/bundled-features/src/billing-foundation/feature.ts +45 -44
  88. package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +3 -5
  89. package/packages/bundled-features/src/billing-foundation/handlers/billing-plans.query.ts +71 -6
  90. package/packages/bundled-features/src/billing-foundation/handlers/create-checkout-session.write.ts +19 -17
  91. package/packages/bundled-features/src/billing-foundation/handlers/create-portal-session.write.ts +11 -12
  92. package/packages/bundled-features/src/billing-foundation/handlers/list-subscriptions.query.ts +4 -4
  93. package/packages/bundled-features/src/billing-foundation/handlers/plan-switch-preview.query.ts +65 -0
  94. package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +29 -22
  95. package/packages/bundled-features/src/billing-foundation/handlers/start-plan-checkout.write.ts +44 -8
  96. package/packages/bundled-features/src/billing-foundation/handlers/switch-plan.write.ts +72 -82
  97. package/packages/bundled-features/src/billing-foundation/handlers/sync-subscription.write.ts +14 -1
  98. package/packages/bundled-features/src/billing-foundation/i18n.ts +22 -0
  99. package/packages/bundled-features/src/billing-foundation/index.ts +2 -0
  100. package/packages/bundled-features/src/billing-foundation/plan-catalog.ts +62 -27
  101. package/packages/bundled-features/src/billing-foundation/plan-switch.ts +84 -0
  102. package/packages/bundled-features/src/billing-foundation/projection.ts +38 -37
  103. package/packages/bundled-features/src/billing-foundation/subscription-tier-sync.ts +3 -3
  104. package/packages/bundled-features/src/billing-foundation/tenant-destroy-hook.ts +7 -8
  105. package/packages/bundled-features/src/billing-foundation/types.ts +144 -66
  106. package/packages/bundled-features/src/billing-foundation/validate-options.ts +19 -0
  107. package/packages/bundled-features/src/billing-foundation/web/billing-plans-panel.tsx +123 -51
  108. package/packages/bundled-features/src/billing-foundation/web/checkout-consent-dialog.tsx +89 -42
  109. package/packages/bundled-features/src/billing-foundation/web/constants.ts +4 -0
  110. package/packages/bundled-features/src/billing-foundation/web/plan-price.ts +55 -0
  111. package/packages/bundled-features/src/billing-foundation/web/plan-switch-confirm-dialog.tsx +224 -0
  112. package/packages/bundled-features/src/billing-foundation/webhook-handler.ts +1 -1
  113. package/packages/bundled-features/src/cap-counter/aggregate-id.ts +8 -9
  114. package/packages/bundled-features/src/cap-counter/cap-reservation.ts +5 -1
  115. package/packages/bundled-features/src/cap-counter/changes.json +18 -0
  116. package/packages/bundled-features/src/cap-counter/constants.ts +11 -12
  117. package/packages/bundled-features/src/cap-counter/enforce-cap.ts +66 -68
  118. package/packages/bundled-features/src/cap-counter/entity.ts +29 -29
  119. package/packages/bundled-features/src/cap-counter/feature.ts +34 -35
  120. package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +31 -31
  121. package/packages/bundled-features/src/cap-counter/handlers/mark-soft-warned.write.ts +4 -5
  122. package/packages/bundled-features/src/cap-counter/stock-cap-guard.ts +9 -2
  123. package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +3 -5
  124. package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -3
  125. package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
  126. package/packages/bundled-features/src/channel-email/changes.json +6 -0
  127. package/packages/bundled-features/src/channel-email/feature.ts +1 -1
  128. package/packages/bundled-features/src/channel-email/smtp-transport.ts +34 -31
  129. package/packages/bundled-features/src/channel-in-app/handlers/unread-count.query.ts +3 -4
  130. package/packages/bundled-features/src/compliance-profiles/feature.ts +15 -16
  131. package/packages/bundled-features/src/compliance-profiles/handlers/for-tenant.query.ts +3 -6
  132. package/packages/bundled-features/src/compliance-profiles/handlers/list-profiles.query.ts +5 -5
  133. package/packages/bundled-features/src/compliance-profiles/handlers/needs-profile.query.ts +4 -4
  134. package/packages/bundled-features/src/compliance-profiles/handlers/set-profile.write.ts +13 -14
  135. package/packages/bundled-features/src/compliance-profiles/handlers/sub-processors.query.ts +9 -11
  136. package/packages/bundled-features/src/compliance-profiles/resolve-for-tenant.ts +7 -7
  137. package/packages/bundled-features/src/compliance-profiles/schema/profile-selection.ts +18 -23
  138. package/packages/bundled-features/src/compliance-profiles/seeding.ts +14 -15
  139. package/packages/bundled-features/src/compliance-profiles-ops/handlers/tenants-missing-profile.query.ts +3 -3
  140. package/packages/bundled-features/src/compliance-profiles-ops/index.ts +2 -2
  141. package/packages/bundled-features/src/config/changes.json +12 -0
  142. package/packages/bundled-features/src/config/handlers/cascade.query.ts +4 -2
  143. package/packages/bundled-features/src/config/handlers/readiness.query.ts +7 -7
  144. package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +4 -5
  145. package/packages/bundled-features/src/config/handlers/set.write.ts +4 -4
  146. package/packages/bundled-features/src/config/handlers/values.query.ts +4 -2
  147. package/packages/bundled-features/src/config/resolver.ts +4 -4
  148. package/packages/bundled-features/src/config/table.ts +10 -10
  149. package/packages/bundled-features/src/config/write-helpers.ts +28 -9
  150. package/packages/bundled-features/src/crypto-shredding/changes.json +6 -0
  151. package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +23 -21
  152. package/packages/bundled-features/src/custom-fields/aggregate-id.ts +16 -17
  153. package/packages/bundled-features/src/custom-fields/entity.ts +49 -47
  154. package/packages/bundled-features/src/custom-fields/events.ts +7 -8
  155. package/packages/bundled-features/src/custom-fields/feature.ts +70 -72
  156. package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +9 -8
  157. package/packages/bundled-features/src/custom-fields/handlers/define-tenant-field.write.ts +28 -26
  158. package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +6 -7
  159. package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +12 -13
  160. package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +25 -28
  161. package/packages/bundled-features/src/custom-fields/handlers/update-tenant-field.write.ts +6 -6
  162. package/packages/bundled-features/src/custom-fields/lib/field-access.ts +2 -2
  163. package/packages/bundled-features/src/custom-fields/lib/parse-serialized-field.ts +1 -1
  164. package/packages/bundled-features/src/custom-fields/lib/quota.ts +1 -1
  165. package/packages/bundled-features/src/custom-fields/lib/value-schema.ts +10 -12
  166. package/packages/bundled-features/src/custom-fields/run-retention.ts +3 -3
  167. package/packages/bundled-features/src/custom-fields/schemas.ts +14 -14
  168. package/packages/bundled-features/src/custom-fields/web/client-plugin.tsx +2 -5
  169. package/packages/bundled-features/src/custom-fields/web/constants.ts +2 -2
  170. package/packages/bundled-features/src/custom-fields/web/custom-fields-form-section.tsx +26 -26
  171. package/packages/bundled-features/src/custom-fields/wire-for-entity.ts +65 -67
  172. package/packages/bundled-features/src/custom-fields/wire-user-data-rights.ts +3 -3
  173. package/packages/bundled-features/src/data-retention/_internal/parse-override.ts +2 -3
  174. package/packages/bundled-features/src/data-retention/feature.ts +11 -18
  175. package/packages/bundled-features/src/data-retention/handlers/policy-for.query.ts +6 -6
  176. package/packages/bundled-features/src/data-retention/keep-for.ts +17 -17
  177. package/packages/bundled-features/src/data-retention/override-schema.ts +13 -15
  178. package/packages/bundled-features/src/data-retention/presets.ts +18 -23
  179. package/packages/bundled-features/src/data-retention/resolve-for-tenant.ts +1 -1
  180. package/packages/bundled-features/src/data-retention/resolve-tenant-preset.ts +17 -16
  181. package/packages/bundled-features/src/data-retention/resolver.ts +33 -32
  182. package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +71 -58
  183. package/packages/bundled-features/src/data-retention/schema/tenant-retention-override.ts +13 -11
  184. package/packages/bundled-features/src/delivery/changes.json +30 -0
  185. package/packages/bundled-features/src/delivery/channel-context.ts +9 -3
  186. package/packages/bundled-features/src/delivery/db/queries/preferences.ts +2 -2
  187. package/packages/bundled-features/src/delivery/delivery-service.ts +35 -5
  188. package/packages/bundled-features/src/delivery/feature.ts +3 -3
  189. package/packages/bundled-features/src/delivery/handlers/log.query.ts +1 -1
  190. package/packages/bundled-features/src/delivery/handlers/preferences.query.ts +20 -1
  191. package/packages/bundled-features/src/delivery/handlers/unsubscribe-page-chrome.query.ts +1 -1
  192. package/packages/bundled-features/src/delivery/tables.ts +9 -8
  193. package/packages/bundled-features/src/delivery/unsubscribe-link.ts +3 -1
  194. package/packages/bundled-features/src/delivery/unsubscribe-page-strings.ts +1 -0
  195. package/packages/bundled-features/src/delivery/unsubscribe-page.ts +6 -0
  196. package/packages/bundled-features/src/delivery/unsubscribe.ts +40 -19
  197. package/packages/bundled-features/src/delivery/upsert-preference.ts +3 -4
  198. package/packages/bundled-features/src/document-ingest-foundation/entity.ts +5 -5
  199. package/packages/bundled-features/src/document-ingest-foundation/events.ts +2 -2
  200. package/packages/bundled-features/src/document-ingest-foundation/feature.ts +2 -2
  201. package/packages/bundled-features/src/document-ingest-foundation/pages.ts +1 -1
  202. package/packages/bundled-features/src/document-ingest-foundation/tenant-destroy-hook.ts +4 -4
  203. package/packages/bundled-features/src/feature-toggles/compose-tier-resolver.ts +1 -1
  204. package/packages/bundled-features/src/feature-toggles/feature.ts +1 -1
  205. package/packages/bundled-features/src/feature-toggles/global-feature-state-table.ts +1 -1
  206. package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +5 -5
  207. package/packages/bundled-features/src/feature-toggles/toggle-runtime.ts +1 -1
  208. package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +1 -1
  209. package/packages/bundled-features/src/feature-toggles/web/constants.ts +1 -1
  210. package/packages/bundled-features/src/file-derivatives/feature.ts +2 -2
  211. package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +1 -1
  212. package/packages/bundled-features/src/file-derivatives/presets.ts +1 -1
  213. package/packages/bundled-features/src/file-foundation/feature.ts +6 -6
  214. package/packages/bundled-features/src/file-foundation/index.ts +1 -0
  215. package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +7 -1
  216. package/packages/bundled-features/src/file-provider-inmemory/feature.ts +16 -16
  217. package/packages/bundled-features/src/file-provider-s3/env-named-feature.ts +0 -2
  218. package/packages/bundled-features/src/file-provider-s3/feature.ts +16 -16
  219. package/packages/bundled-features/src/file-provider-s3/lib/s3-provider.ts +6 -6
  220. package/packages/bundled-features/src/files/README.md +1 -1
  221. package/packages/bundled-features/src/files/feature.ts +6 -6
  222. package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +5 -5
  223. package/packages/bundled-features/src/files-tenant-data/hooks.ts +24 -26
  224. package/packages/bundled-features/src/files-tenant-data/index.ts +1 -1
  225. package/packages/bundled-features/src/folders/feature.ts +1 -1
  226. package/packages/bundled-features/src/folders/web/folder-manager.tsx +2 -2
  227. package/packages/bundled-features/src/folders/web/tree.ts +5 -5
  228. package/packages/bundled-features/src/form-draft/changes.json +6 -0
  229. package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +3 -3
  230. package/packages/bundled-features/src/form-draft/db/queries/owned-file-refs.ts +1 -1
  231. package/packages/bundled-features/src/form-draft/decrypt-draft.ts +4 -1
  232. package/packages/bundled-features/src/form-draft/entity.ts +3 -3
  233. package/packages/bundled-features/src/form-draft/feature.ts +4 -5
  234. package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +1 -1
  235. package/packages/bundled-features/src/form-draft/release-file-refs.ts +6 -6
  236. package/packages/bundled-features/src/form-draft/schemas.ts +3 -3
  237. package/packages/bundled-features/src/form-draft/web/constants.ts +0 -2
  238. package/packages/bundled-features/src/host-routing/README.md +1 -1
  239. package/packages/bundled-features/src/host-routing/changes.json +6 -0
  240. package/packages/bundled-features/src/host-routing/dispatch.ts +16 -17
  241. package/packages/bundled-features/src/host-routing/options.ts +2 -1
  242. package/packages/bundled-features/src/inbound-mail-foundation/aggregate-id.ts +19 -19
  243. package/packages/bundled-features/src/inbound-mail-foundation/changes.json +18 -0
  244. package/packages/bundled-features/src/inbound-mail-foundation/connect-routes.ts +4 -3
  245. package/packages/bundled-features/src/inbound-mail-foundation/constants.ts +30 -33
  246. package/packages/bundled-features/src/inbound-mail-foundation/entities.ts +47 -48
  247. package/packages/bundled-features/src/inbound-mail-foundation/events.ts +54 -50
  248. package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +39 -39
  249. package/packages/bundled-features/src/inbound-mail-foundation/handlers/account-state.ts +8 -8
  250. package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +25 -26
  251. package/packages/bundled-features/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +7 -7
  252. package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +50 -51
  253. package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-accounts.query.ts +8 -8
  254. package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-messages.query.ts +10 -10
  255. package/packages/bundled-features/src/inbound-mail-foundation/handlers/scope-visibility.ts +3 -4
  256. package/packages/bundled-features/src/inbound-mail-foundation/handlers/update-account.write.ts +27 -15
  257. package/packages/bundled-features/src/inbound-mail-foundation/i18n.ts +0 -1
  258. package/packages/bundled-features/src/inbound-mail-foundation/oauth-state.ts +16 -15
  259. package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +31 -29
  260. package/packages/bundled-features/src/inbound-mail-foundation/provider-factory.ts +9 -9
  261. package/packages/bundled-features/src/inbound-mail-foundation/retention-sweep.ts +45 -41
  262. package/packages/bundled-features/src/inbound-mail-foundation/screens.ts +0 -3
  263. package/packages/bundled-features/src/inbound-mail-foundation/tenant-destroy-hook.ts +14 -16
  264. package/packages/bundled-features/src/inbound-mail-foundation/types.ts +70 -70
  265. package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +101 -84
  266. package/packages/bundled-features/src/inbound-provider-imap/credential-document.ts +13 -13
  267. package/packages/bundled-features/src/inbound-provider-imap/feature.ts +42 -40
  268. package/packages/bundled-features/src/inbound-provider-imap/imap-client.ts +20 -19
  269. package/packages/bundled-features/src/inbound-provider-inmemory/feature.ts +21 -21
  270. package/packages/bundled-features/src/jobs/changes.json +13 -0
  271. package/packages/bundled-features/src/jobs/db/queries/retention.ts +2 -2
  272. package/packages/bundled-features/src/jobs/db/queries/stale-run-sweep.ts +3 -3
  273. package/packages/bundled-features/src/jobs/events.ts +1 -1
  274. package/packages/bundled-features/src/jobs/feature.ts +20 -11
  275. package/packages/bundled-features/src/jobs/handlers/detail.query.ts +4 -4
  276. package/packages/bundled-features/src/jobs/handlers/list.query.ts +1 -1
  277. package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
  278. package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +1 -1
  279. package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
  280. package/packages/bundled-features/src/jobs/handlers/tenant-failures.query.ts +45 -40
  281. package/packages/bundled-features/src/jobs/handlers/tenant-runs.query.ts +63 -59
  282. package/packages/bundled-features/src/jobs/job-instant.ts +1 -1
  283. package/packages/bundled-features/src/jobs/job-run-logger.ts +19 -19
  284. package/packages/bundled-features/src/jobs/job-run-table.ts +3 -3
  285. package/packages/bundled-features/src/jobs/screens.ts +1 -1
  286. package/packages/bundled-features/src/jobs/tenant-job-failure-table.ts +1 -1
  287. package/packages/bundled-features/src/jobs/tenant-job-run-table.ts +1 -1
  288. package/packages/bundled-features/src/ledger/entity.ts +5 -5
  289. package/packages/bundled-features/src/ledger/feature.ts +3 -3
  290. package/packages/bundled-features/src/ledger/handlers/confirm-schedule-period.write.ts +3 -3
  291. package/packages/bundled-features/src/ledger/recurring.ts +12 -12
  292. package/packages/bundled-features/src/ledger/schemas.ts +1 -1
  293. package/packages/bundled-features/src/ledger/web/constants.ts +2 -2
  294. package/packages/bundled-features/src/ledger/web/index.ts +7 -7
  295. package/packages/bundled-features/src/legal-pages/README.md +1 -1
  296. package/packages/bundled-features/src/legal-pages/feature.ts +40 -41
  297. package/packages/bundled-features/src/legal-pages/markdown.ts +3 -3
  298. package/packages/bundled-features/src/legal-pages/web/client-plugin.ts +23 -24
  299. package/packages/bundled-features/src/legal-pages/web/index.ts +0 -2
  300. package/packages/bundled-features/src/mail-foundation/changes.json +6 -0
  301. package/packages/bundled-features/src/mail-foundation/feature.ts +31 -30
  302. package/packages/bundled-features/src/mail-transport-inmemory/feature.ts +27 -28
  303. package/packages/bundled-features/src/mail-transport-smtp/feature.ts +20 -20
  304. package/packages/bundled-features/src/managed-pages/branding.ts +6 -6
  305. package/packages/bundled-features/src/managed-pages/feature.ts +62 -62
  306. package/packages/bundled-features/src/managed-pages/handlers/by-slug.query.ts +5 -6
  307. package/packages/bundled-features/src/managed-pages/handlers/by-tenant-published.query.ts +8 -8
  308. package/packages/bundled-features/src/managed-pages/handlers/set.write.ts +5 -7
  309. package/packages/bundled-features/src/managed-pages/screens/page-screens.ts +11 -11
  310. package/packages/bundled-features/src/managed-pages/seeding.ts +8 -8
  311. package/packages/bundled-features/src/managed-pages/table.ts +16 -15
  312. package/packages/bundled-features/src/managed-pages/web/client-plugin.tsx +6 -6
  313. package/packages/bundled-features/src/managed-pages/web/i18n.ts +1 -1
  314. package/packages/bundled-features/src/notes-history/entity.ts +4 -4
  315. package/packages/bundled-features/src/notes-history/feature.ts +2 -2
  316. package/packages/bundled-features/src/notes-history-user-data/hooks.ts +1 -1
  317. package/packages/bundled-features/src/page-render/layout.ts +9 -9
  318. package/packages/bundled-features/src/page-render/markdown.ts +11 -11
  319. package/packages/bundled-features/src/page-render/security-headers.ts +7 -6
  320. package/packages/bundled-features/src/personal-access-tokens/feature.ts +9 -6
  321. package/packages/bundled-features/src/personal-access-tokens/roles.ts +2 -2
  322. package/packages/bundled-features/src/readiness/handlers/status.query.ts +3 -3
  323. package/packages/bundled-features/src/renderer-foundation/api.ts +12 -13
  324. package/packages/bundled-features/src/renderer-foundation/constants.ts +2 -2
  325. package/packages/bundled-features/src/renderer-foundation/feature.ts +7 -7
  326. package/packages/bundled-features/src/renderer-foundation/types.ts +11 -12
  327. package/packages/bundled-features/src/renderer-pdf/changes.json +6 -0
  328. package/packages/bundled-features/src/renderer-pdf/render-table-pdf.ts +27 -10
  329. package/packages/bundled-features/src/secrets/feature.ts +9 -9
  330. package/packages/bundled-features/src/secrets/web/constants.ts +2 -2
  331. package/packages/bundled-features/src/seo/feature.ts +3 -3
  332. package/packages/bundled-features/src/sessions/constants.ts +1 -1
  333. package/packages/bundled-features/src/sessions/feature.ts +16 -11
  334. package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +2 -2
  335. package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +2 -2
  336. package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
  337. package/packages/bundled-features/src/sessions/schema/user-session.ts +4 -4
  338. package/packages/bundled-features/src/sessions/screens.ts +2 -2
  339. package/packages/bundled-features/src/sessions/session-callbacks.ts +2 -2
  340. package/packages/bundled-features/src/sessions/session-revoked-event.ts +2 -2
  341. package/packages/bundled-features/src/shared/assert-no-where-rule-in-ownership-write.ts +1 -1
  342. package/packages/bundled-features/src/shared/decrypt-stored-pii.ts +11 -1
  343. package/packages/bundled-features/src/shared/encrypt-for-direct-write.ts +1 -1
  344. package/packages/bundled-features/src/shared/index.ts +1 -1
  345. package/packages/bundled-features/src/shared/mail-template-body.ts +10 -3
  346. package/packages/bundled-features/src/shared/map-with-concurrency.ts +5 -4
  347. package/packages/bundled-features/src/shared/parent-visibility.ts +2 -2
  348. package/packages/bundled-features/src/shared/password-hashing.ts +1 -1
  349. package/packages/bundled-features/src/shared/signup-handover.ts +1 -2
  350. package/packages/bundled-features/src/shared/single-use-token-store.ts +1 -1
  351. package/packages/bundled-features/src/step-dispatcher/changes.json +6 -0
  352. package/packages/bundled-features/src/step-dispatcher/feature.ts +1 -0
  353. package/packages/bundled-features/src/subscription-dodo/changes.json +14 -0
  354. package/packages/bundled-features/src/subscription-dodo/client.ts +45 -0
  355. package/packages/bundled-features/src/subscription-dodo/constants.ts +24 -0
  356. package/packages/bundled-features/src/subscription-dodo/feature.ts +207 -0
  357. package/packages/bundled-features/src/subscription-dodo/index.ts +16 -0
  358. package/packages/bundled-features/src/subscription-dodo/plugin-methods.ts +345 -0
  359. package/packages/bundled-features/src/subscription-dodo/runtime.ts +126 -0
  360. package/packages/bundled-features/src/subscription-dodo/verify-webhook.ts +262 -0
  361. package/packages/bundled-features/src/subscription-mollie/constants.ts +15 -17
  362. package/packages/bundled-features/src/subscription-mollie/feature.ts +41 -42
  363. package/packages/bundled-features/src/subscription-mollie/index.ts +3 -3
  364. package/packages/bundled-features/src/subscription-mollie/plugin-methods.ts +17 -16
  365. package/packages/bundled-features/src/subscription-mollie/verify-webhook.ts +34 -34
  366. package/packages/bundled-features/src/subscription-stripe/changes.json +12 -0
  367. package/packages/bundled-features/src/subscription-stripe/constants.ts +4 -6
  368. package/packages/bundled-features/src/subscription-stripe/feature.ts +45 -43
  369. package/packages/bundled-features/src/subscription-stripe/index.ts +6 -6
  370. package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +22 -27
  371. package/packages/bundled-features/src/subscription-stripe/runtime.ts +9 -8
  372. package/packages/bundled-features/src/subscription-stripe/verify-webhook.ts +62 -64
  373. package/packages/bundled-features/src/tags/feature.ts +3 -3
  374. package/packages/bundled-features/src/tags/screens.ts +1 -1
  375. package/packages/bundled-features/src/template-resolver/api.ts +41 -14
  376. package/packages/bundled-features/src/template-resolver/changes.json +48 -0
  377. package/packages/bundled-features/src/template-resolver/compile-document-body.ts +1 -0
  378. package/packages/bundled-features/src/template-resolver/feature.ts +2 -2
  379. package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +3 -2
  380. package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +27 -5
  381. package/packages/bundled-features/src/template-resolver/handlers/diff-to-system.query.ts +3 -2
  382. package/packages/bundled-features/src/template-resolver/handlers/document-base.ts +3 -2
  383. package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +8 -7
  384. package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +19 -20
  385. package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +15 -5
  386. package/packages/bundled-features/src/template-resolver/handlers/shared.ts +2 -2
  387. package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +3 -3
  388. package/packages/bundled-features/src/template-resolver/handlers/tenant-override-counts.query.ts +9 -5
  389. package/packages/bundled-features/src/template-resolver/handlers/tenant-override-selection.ts +8 -6
  390. package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +44 -5
  391. package/packages/bundled-features/src/template-resolver/handlers/upsert-system.write.ts +3 -4
  392. package/packages/bundled-features/src/template-resolver/handlers/upsert-tenant.write.ts +4 -5
  393. package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +37 -26
  394. package/packages/bundled-features/src/template-resolver/handlers/validate.query.ts +7 -2
  395. package/packages/bundled-features/src/template-resolver/seeding.ts +36 -18
  396. package/packages/bundled-features/src/template-resolver/store-template-resource.ts +22 -4
  397. package/packages/bundled-features/src/template-resolver/table.ts +13 -14
  398. package/packages/bundled-features/src/template-resolver/template-delivery-policy.ts +0 -11
  399. package/packages/bundled-features/src/template-resolver/template-meta.ts +12 -4
  400. package/packages/bundled-features/src/template-resolver/template-preview.ts +11 -3
  401. package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +2 -2
  402. package/packages/bundled-features/src/template-resolver/web/constants.ts +7 -5
  403. package/packages/bundled-features/src/template-resolver/web/index.ts +7 -0
  404. package/packages/bundled-features/src/template-resolver/web/mail-layout-constants.ts +8 -0
  405. package/packages/bundled-features/src/tenant/changes.json +6 -0
  406. package/packages/bundled-features/src/tenant/feature.ts +7 -7
  407. package/packages/bundled-features/src/tenant/handlers/member-directory.query.ts +10 -4
  408. package/packages/bundled-features/src/tenant/handlers/members.query.ts +1 -1
  409. package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
  410. package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +1 -1
  411. package/packages/bundled-features/src/tenant/handlers/tenant-directory.query.ts +8 -5
  412. package/packages/bundled-features/src/tenant/invitation-table.ts +37 -40
  413. package/packages/bundled-features/src/tenant/membership-table.ts +3 -3
  414. package/packages/bundled-features/src/tenant/schema/tenant.ts +7 -9
  415. package/packages/bundled-features/src/tenant/screens.ts +1 -1
  416. package/packages/bundled-features/src/tenant/seeding.ts +19 -18
  417. package/packages/bundled-features/src/tenant/testing.ts +5 -6
  418. package/packages/bundled-features/src/tenant/web/constants.ts +2 -2
  419. package/packages/bundled-features/src/tenant-handover/events.ts +5 -7
  420. package/packages/bundled-features/src/tenant-handover/feature.ts +1 -1
  421. package/packages/bundled-features/src/tenant-handover/grant.ts +1 -1
  422. package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
  423. package/packages/bundled-features/src/tenant-handover/move-entity-graph.ts +8 -9
  424. package/packages/bundled-features/src/tenant-handover/signup-handover-provider.ts +1 -2
  425. package/packages/bundled-features/src/tenant-handover/transfer-graph.ts +4 -5
  426. package/packages/bundled-features/src/tenant-lifecycle/boot-checks.ts +1 -1
  427. package/packages/bundled-features/src/tenant-lifecycle/changes.json +6 -0
  428. package/packages/bundled-features/src/tenant-lifecycle/constants.ts +5 -0
  429. package/packages/bundled-features/src/tenant-lifecycle/feature.ts +1 -1
  430. package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +7 -3
  431. package/packages/bundled-features/src/tenant-lifecycle/stages.ts +1 -1
  432. package/packages/bundled-features/src/tenant-settings/constants.ts +1 -1
  433. package/packages/bundled-features/src/tenant-settings/tenant-defaults.ts +12 -5
  434. package/packages/bundled-features/src/tier-engine/aggregate-id.ts +15 -16
  435. package/packages/bundled-features/src/tier-engine/changes.json +6 -0
  436. package/packages/bundled-features/src/tier-engine/compose-app.ts +14 -14
  437. package/packages/bundled-features/src/tier-engine/entity.ts +18 -19
  438. package/packages/bundled-features/src/tier-engine/feature.ts +88 -87
  439. package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +6 -7
  440. package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +4 -4
  441. package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +12 -9
  442. package/packages/bundled-features/src/tier-engine/tier-resolver.ts +2 -2
  443. package/packages/bundled-features/src/tier-engine/trial.ts +13 -13
  444. package/packages/bundled-features/src/tier-engine/web/constants.ts +3 -3
  445. package/packages/bundled-features/src/tier-engine/web/index.ts +4 -4
  446. package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +8 -8
  447. package/packages/bundled-features/src/user/handlers/create.write.ts +4 -4
  448. package/packages/bundled-features/src/user/schema/user.ts +45 -44
  449. package/packages/bundled-features/src/user/seeding.ts +40 -40
  450. package/packages/bundled-features/src/user/testing.ts +3 -3
  451. package/packages/bundled-features/src/user-data-rights/audit-download.ts +27 -28
  452. package/packages/bundled-features/src/user-data-rights/boot-checks.ts +1 -1
  453. package/packages/bundled-features/src/user-data-rights/deletion-token.ts +1 -1
  454. package/packages/bundled-features/src/user-data-rights/feature.ts +112 -113
  455. package/packages/bundled-features/src/user-data-rights/handlers/cancel-deletion.write.ts +9 -9
  456. package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +8 -8
  457. package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +29 -30
  458. package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +40 -42
  459. package/packages/bundled-features/src/user-data-rights/handlers/export-status.query.ts +8 -9
  460. package/packages/bundled-features/src/user-data-rights/handlers/lift-restriction.write.ts +7 -8
  461. package/packages/bundled-features/src/user-data-rights/handlers/list-download-attempts.query.ts +2 -2
  462. package/packages/bundled-features/src/user-data-rights/handlers/my-audit-log.query.ts +4 -4
  463. package/packages/bundled-features/src/user-data-rights/handlers/request-deletion-by-email.write.ts +30 -29
  464. package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +15 -18
  465. package/packages/bundled-features/src/user-data-rights/handlers/request-export.write.ts +42 -41
  466. package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +22 -19
  467. package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +8 -8
  468. package/packages/bundled-features/src/user-data-rights/index.ts +8 -10
  469. package/packages/bundled-features/src/user-data-rights/lib/default-mailers.ts +3 -3
  470. package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +24 -27
  471. package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +169 -280
  472. package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +87 -108
  473. package/packages/bundled-features/src/user-data-rights/run-user-export.ts +67 -69
  474. package/packages/bundled-features/src/user-data-rights/schema/download-attempt.ts +11 -11
  475. package/packages/bundled-features/src/user-data-rights/schema/download-token.ts +37 -41
  476. package/packages/bundled-features/src/user-data-rights/schema/export-job.ts +65 -67
  477. package/packages/bundled-features/src/user-data-rights/token-helpers.ts +21 -25
  478. package/packages/bundled-features/src/user-data-rights/web/client-plugin.tsx +6 -6
  479. package/packages/bundled-features/src/user-data-rights/web/confirm-deletion-screen.tsx +6 -5
  480. package/packages/bundled-features/src/user-data-rights/web/constants.ts +1 -1
  481. package/packages/bundled-features/src/user-data-rights/web/index.ts +5 -5
  482. package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +14 -13
  483. package/packages/bundled-features/src/user-data-rights/web/public-deletion-gate.tsx +13 -12
  484. package/packages/bundled-features/src/user-data-rights/web/request-deletion-screen.tsx +6 -6
  485. package/packages/bundled-features/src/user-data-rights/zip-path.ts +41 -40
  486. package/packages/bundled-features/src/user-data-rights-defaults/feature.ts +15 -15
  487. package/packages/bundled-features/src/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.ts +3 -5
  488. package/packages/bundled-features/src/user-data-rights-defaults/hooks/file-ref.userdata-hook.ts +45 -51
  489. package/packages/bundled-features/src/user-data-rights-defaults/hooks/job-run.userdata-hook.ts +2 -2
  490. package/packages/bundled-features/src/user-data-rights-defaults/hooks/notification-preference.userdata-hook.ts +1 -1
  491. package/packages/bundled-features/src/user-data-rights-defaults/hooks/user-session.userdata-hook.ts +3 -3
  492. package/packages/bundled-features/src/user-data-rights-defaults/hooks/user.userdata-hook.ts +32 -31
  493. package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +13 -13
  494. package/packages/bundled-features/src/user-profile/index.ts +3 -3
  495. package/packages/bundled-features/src/user-profile/web/client-plugin.ts +1 -1
  496. package/packages/bundled-features/src/user-profile/web/constants.ts +1 -1
  497. package/packages/bundled-features/src/user-profile/web/profile-screen.tsx +1 -1
  498. package/packages/bundled-features/src/waitlist/changes.json +18 -0
  499. package/packages/bundled-features/src/waitlist/handlers/export-purge.write.ts +2 -1
  500. package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +5 -5
  501. package/packages/bundled-features/src/waitlist/import.ts +5 -0
  502. package/packages/bundled-features/src/waitlist/legacy-migrate.ts +22 -3
  503. package/packages/bundled-features/src/waitlist/link-on-signup.ts +20 -10
  504. package/packages/bundled-features/src/waitlist/options.ts +3 -0
  505. package/packages/bundled-features/src/workflow-runner/aggregate-id.ts +1 -1
  506. package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -5
  507. package/packages/bundled-features/src/workflow-runner/event-trigger.ts +4 -15
  508. package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
  509. package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +4 -4
  510. package/packages/bundled-features/src/workflow-runner/pending-projection.ts +6 -7
  511. package/packages/bundled-features/src/workflow-runner/runner.ts +6 -6
  512. package/packages/bundled-features/src/workflow-runner/tables.ts +6 -6
  513. package/packages/bundled-features/src/workflow-runner/workflow-registry.ts +1 -1
  514. package/samples/apps/styleguide/src/features/widgets/i18n.ts +11 -0
  515. package/samples/apps/styleguide/src/features/widgets/web/Widgets.tsx +24 -0
  516. package/samples/apps/use-all-bundled/e2e-billing-gallery/gallery-constants.ts +5 -0
  517. package/samples/apps/use-all-bundled/e2e-billing-gallery/gallery-features.ts +90 -15
  518. package/samples/apps/use-all-bundled/e2e-billing-gallery/server.ts +16 -6
  519. package/samples/apps/use-all-bundled/feature-manifest.json +120 -3
  520. package/samples/apps/use-all-bundled/src/run-config.ts +9 -3
  521. package/samples/recipes/auth-mfa/README.md +5 -0
  522. package/samples/recipes/auth-mfa/package.json +5 -2
  523. package/samples/recipes/auth-mfa/src/web/confirmation-code-step.tsx +49 -0
  524. package/samples/recipes/auth-mfa/tsconfig.json +8 -0
  525. package/samples/recipes/env-composition/README.md +3 -1
  526. package/samples/recipes/env-composition/src/env.ts +2 -0
  527. package/samples/recipes/legal-pages/README.md +1 -1
  528. package/samples/recipes/rate-limiting/README.md +18 -0
  529. package/samples/recipes/rate-limiting/src/feature.ts +12 -0
  530. package/packages/bundled-features/src/billing-foundation/consumer-protection/stored-user-email.ts +0 -12
@@ -1,6 +1,6 @@
1
- // imapflow-Wiring + pure Helpers des IMAP-Providers.
2
- // Referenz-Impl: /Users/marc/code/doc-o-mat (HEINZ) — aber inkrementeller
3
- // UIDVALIDITY:lastUid-Cursor statt '1:*'-Vollscan.
1
+ // imapflow wiring and pure helpers for IMAP providers.
2
+ // Reference implementation: /Users/marc/code/doc-o-mat (HEINZ), but uses an
3
+ // incremental UIDVALIDITY:lastUid cursor instead of a '1:*' full scan.
4
4
 
5
5
  import {
6
6
  BlockedHostError,
@@ -95,9 +95,9 @@ export async function createImapClient(
95
95
 
96
96
  /** Server-Fehler → typisierte Foundation-Fehlerklassen (Plan §2). */
97
97
  export function mapImapError(err: unknown, host: string): Error {
98
- // imapflow-Fehler tragen die Server-Antwort in responseText, die
99
- // message ist nur "Command failed" — beides in den Match einbeziehen;
100
- // authenticationFailed ist das verlässliche Flag.
98
+ // imapflow errors carry the server response in responseText; the
99
+ // message is only "Command failed", so both are included in the match;
100
+ // authenticationFailed is the reliable flag.
101
101
  const carrier = isPlainObject(err) ? err : undefined;
102
102
  const responseText = typeof carrier?.["responseText"] === "string" ? carrier["responseText"] : "";
103
103
  const msg = `${err instanceof Error ? err.message : String(err)} ${responseText}`.trim();
@@ -129,9 +129,9 @@ export function parseImapCursor(cursor: SyncCursorPayload | null): ImapCursor |
129
129
  return { uidValidity, lastUid };
130
130
  }
131
131
 
132
- /** Wirft InboundCursorInvalidError bei UIDVALIDITY-Wechsel — die
133
- * Foundation resettet den Cursor und macht einen Voll-Resync im
134
- * Backfill-Fenster (Dedup fängt Dubletten). */
132
+ /** Throws InboundCursorInvalidError when UIDVALIDITY changes; the
133
+ * foundation resets the cursor and performs a full resync within the
134
+ * backfill window (deduplication catches duplicates). */
135
135
  export function assertUidValidity(cursor: ImapCursor | null, serverUidValidity: string): void {
136
136
  if (cursor && cursor.uidValidity !== serverUidValidity) {
137
137
  throw new InboundCursorInvalidError(
@@ -148,8 +148,9 @@ function stripAngles(id: string): string {
148
148
  return id.replace(/^<|>$/g, "").trim();
149
149
  }
150
150
 
151
- /** References-Chain normalisieren: mailparser liefert string | string[]
152
- * | undefined; fehlt References, trägt In-Reply-To den Thread-Anker. */
151
+ /** Normalizes the References chain: mailparser returns string | string[]
152
+ * | undefined; when References is missing, In-Reply-To provides the thread
153
+ * anchor. */
153
154
  export function normalizeReferences(parsed: {
154
155
  references?: string | string[];
155
156
  inReplyTo?: string;
@@ -170,16 +171,16 @@ function addressList(a: AddressObject | AddressObject[] | undefined): string[] {
170
171
  return arr.map((x) => x.text).filter((t): t is string => Boolean(t));
171
172
  }
172
173
 
173
- /** imapflow liefert internalDate je nach Codepfad als Date ODER string.
174
- * String-Form verwerfen wir bewusst (kein Date-Parsing im Feature-Code,
175
- * no-date-api) — toRawInboundMessage fällt dann auf mailparsers
176
- * Date-Header zurück, der immer als echtes Date kommt. */
174
+ /** imapflow provides internalDate as either a Date or string depending on
175
+ * the code path. The string form is deliberately discarded (no date parsing
176
+ * in feature code, no-date-api); toRawInboundMessage then falls back to the
177
+ * mailparser Date header, which is always a real Date. */
177
178
  export function coerceDate(d: Date | string | undefined): Date | undefined {
178
179
  return d instanceof Date ? d : undefined;
179
180
  }
180
181
 
181
- /** providerMessageId: UID ist nur innerhalb einer UIDVALIDITY eindeutig
182
- * — beides zusammen ist der stabile Idempotency-Anchor. */
182
+ /** providerMessageId: a UID is unique only within a UIDVALIDITY; together,
183
+ * they form the stable idempotency anchor. */
183
184
  export function buildProviderMessageId(uidValidity: string, uid: number): string {
184
185
  return `${uidValidity}:${uid}`;
185
186
  }
@@ -204,8 +205,8 @@ export async function toRawInboundMessage(args: {
204
205
  cc: addressList(parsed.cc),
205
206
  subject: parsed.subject ?? "",
206
207
  snippet: text.slice(0, SNIPPET_MAX),
207
- // Lib-Boundary-Bridge (Date von imapflow/mailparser) → Temporal;
208
- // fehlt jedes Datum, ist Epoch der ehrliche Marker.
208
+ // Lib-boundary bridge (Date from imapflow/mailparser) → Temporal;
209
+ // when no date exists, Epoch is the honest marker.
209
210
  receivedAtIso: (receivedAt
210
211
  ? legacyDateToInstant(receivedAt)
211
212
  : Temporal.Instant.fromEpochMilliseconds(0)
@@ -1,15 +1,15 @@
1
1
  // kumiko-feature-version: 1
2
2
  //
3
- // inbound-provider-inmemory — scriptbarer In-Memory-Provider für die
4
- // inbound-mail-foundation Plugin-API. Für Tests, Demos und Sample-Apps:
5
- // Messages werden per `seedInboundMessage()` eingespeist statt von einem
6
- // echten Postfach gefetcht; `watch()` pusht geseedete Messages sofort
7
- // (IDLE-Simulation), `fetch()` liefert sie cursor-basiert nach
8
- // (Reconciliation-Pfad) — beide Pfade zusammen exercisen exakt die
9
- // Dedup-Garantie der Foundation.
3
+ // inbound-provider-inmemory — scriptable in-memory provider for the
4
+ // inbound-mail-foundation plugin API. For tests, demos, and sample apps:
5
+ // messages are supplied via `seedInboundMessage()` instead of being fetched
6
+ // from a real mailbox; `watch()` immediately pushes seeded messages
7
+ // (IDLE simulation), while `fetch()` returns them by cursor
8
+ // (reconciliation path). Together, both paths exercise the foundation's
9
+ // deduplication guarantee exactly.
10
10
  //
11
- // **Pattern-Vorbild:** mail-transport-inmemory (module-level State +
12
- // Test-Helper-Exports). NICHT für Production.
11
+ // **Pattern basis:** mail-transport-inmemory (module-level state +
12
+ // test-helper exports). Not for production.
13
13
 
14
14
  import type {
15
15
  InboundFetchResult,
@@ -24,8 +24,8 @@ const FEATURE_NAME = "inbound-provider-inmemory";
24
24
  export const INMEMORY_PROVIDER_KEY = "inmemory";
25
25
 
26
26
  // =============================================================================
27
- // Module-level State — pro Account: Message-Log (append-only, wie ein
28
- // echtes Postfach), aktive Watch-Handler, One-Shot-Fehlerinjektion.
27
+ // Module-level state — per account: an append-only message log, like a real
28
+ // mailbox; active watch handlers and one-shot error injection.
29
29
  // =============================================================================
30
30
 
31
31
  type WatchHandlers = {
@@ -51,28 +51,28 @@ function stateFor(accountId: string): AccountState {
51
51
  return state;
52
52
  }
53
53
 
54
- /** Test-Helper: Message ins Postfach legen. Läuft ein watch, wird sie
55
- * sofort gepusht (IDLE-Simulation); der nächste fetch liefert sie
56
- * cursor-basiert ebenfalls — Dedup der Foundation macht das idempotent. */
54
+ /** Test helper: adds a message to the mailbox. If a watch is active, it is
55
+ * pushed immediately (IDLE simulation); the next fetch also returns it by
56
+ * cursor — the foundation's deduplication makes this idempotent. */
57
57
  export async function seedInboundMessage(accountId: string, msg: RawInboundMessage): Promise<void> {
58
58
  const state = stateFor(accountId);
59
59
  state.log.push(msg);
60
60
  if (state.watch) await state.watch.onMessages([msg]);
61
61
  }
62
62
 
63
- /** Test-Helper: One-Shot-Fehler für den nächsten fetch (z.B.
64
- * InboundAuthError, InboundCursorInvalidError). */
63
+ /** Test helper: injects a one-shot error into the next fetch (e.g.
64
+ * InboundAuthError or InboundCursorInvalidError). */
65
65
  export function failNextFetchWith(accountId: string, err: unknown): void {
66
66
  stateFor(accountId).nextFetchError = err;
67
67
  }
68
68
 
69
- /** Test-Helper: One-Shot-Fehler für das nächste verify. */
69
+ /** Test helper: injects a one-shot error into the next verify. */
70
70
  export function failNextVerifyWith(accountId: string, err: unknown): void {
71
71
  stateFor(accountId).nextVerifyError = err;
72
72
  }
73
73
 
74
- /** Test-Helper: Tod der Live-Verbindung simulieren (Supervisor muss
75
- * mit Backoff neu starten). */
74
+ /** Test helper: simulates the live connection terminating (the supervisor
75
+ * must restart with backoff). */
76
76
  export function emitWatchError(accountId: string, err: unknown): void {
77
77
  const state = accounts.get(accountId);
78
78
  if (state?.watch) {
@@ -82,7 +82,7 @@ export function emitWatchError(accountId: string, err: unknown): void {
82
82
  }
83
83
  }
84
84
 
85
- /** Test-Helper: läuft gerade ein watch für den Account? */
85
+ /** Test helper: reports whether an account currently has an active watch. */
86
86
  export function isWatching(accountId: string): boolean {
87
87
  return accounts.get(accountId)?.watch != null;
88
88
  }
@@ -94,7 +94,7 @@ export function resetInboundInMemory(): void {
94
94
  }
95
95
 
96
96
  // =============================================================================
97
- // Plugin — cursor = { offset: number } über das append-only-Log.
97
+ // Plugin — cursor = { offset: number } over the append-only log.
98
98
  // =============================================================================
99
99
 
100
100
  function offsetOf(cursor: SyncCursorPayload | null): number {
@@ -1,4 +1,17 @@
1
1
  [
2
+ {
3
+ "version": "0.388.0",
4
+ "type": "improvement",
5
+ "title": "readRoles for tenant job status",
6
+ "detail": "`createJobsFeature({ readRoles: [\"PropertyManager\"] })` lets those app roles call `jobs:query:failures` and `jobs:query:tenant-runs` for their own tenant. They are added to the default `User`, `Editor` and admin roles, which stay. Before, a member who only holds app roles got access_denied.",
7
+ "migration": "Optional. Apps whose members hold only their own roles pass `createJobsFeature({ readRoles: [...] })`."
8
+ },
9
+ {
10
+ "version": "0.388.0",
11
+ "type": "fix",
12
+ "title": "Deduplicated job add keeps the finished tenant run row",
13
+ "detail": "JobQueuedMeta carries the BullMQ creation time of the job. The queued hook only removes finished rows queued before that time (leftovers of a Redis reset), so re-announcing an already finished job no longer turns its row back into queued."
14
+ },
2
15
  {
3
16
  "version": "0.384.0",
4
17
  "type": "improvement",
@@ -1,4 +1,4 @@
1
- // Job-run retention (#2243): store_job_runs/store_job_run_logs are
1
+ // Job-run retention: store_job_runs/store_job_run_logs are
2
2
  // direct-write stores now, not event-sourced projections — nothing else
3
3
  // purges them, so without this query they grow forever with the run count
4
4
  // instead of the runtime. Not the retention-cleanup executor: that executor
@@ -44,7 +44,7 @@ export async function deleteStaleJobRuns(
44
44
  { limit: RETENTION_DELETE_BATCH_SIZE },
45
45
  );
46
46
 
47
- // Same window for the tenant-visible failure records (fw#3079): the run
47
+ // Same window for the tenant-visible failure records: the run
48
48
  // they point at is gone by now, and a job whose subject never ran again
49
49
  // would otherwise keep its record forever.
50
50
  const tenantFailuresResult = await deleteManyBatched(
@@ -1,5 +1,5 @@
1
- // Stale job-run sweep (#2246): store_job_runs is a direct-write store
2
- // (#2243) — status is set to "running" once at onJobStart and only ever
1
+ // Stale job-run sweep: store_job_runs is a direct-write store
2
+ // Status is set to "running" once at onJobStart and only ever
3
3
  // flipped to "completed"/"failed" by onJobComplete/onJobFailed. If the
4
4
  // process dies mid-run (crash, OOM, kill -9), those callbacks never fire and
5
5
  // the row is stuck on "running" forever — nothing else on the read side
@@ -48,7 +48,7 @@ export async function markStaleJobRunsFailed(
48
48
  // user subject annotation as job-run-logger.ts's onJobFailed path
49
49
  // (personal: { of: "triggeredById" } on job-run-table.ts), so it is encrypted
50
50
  // under the triggering user's DEK, or the system tenant key when
51
- // triggeredById is null (whenAbsent: "tenant", fw#3654). Runs are grouped by
51
+ // triggeredById is null (whenAbsent: "tenant"). Runs are grouped by
52
52
  // that subject: one encrypt and one updateMany per subject instead of per run.
53
53
  const stale = await selectMany<{ id: string; triggeredById: string | null }>(db, jobRunsTable, {
54
54
  status: "running",
@@ -1,4 +1,4 @@
1
- // Payload schemas for the jobRun direct-write path (#2243). Pre-#2243 these
1
+ // Payload schemas for the jobRun direct-write path. Previously these
2
2
  // backed jobRun's event-store payloads (r.defineEvent + inline projections);
3
3
  // now job-run-logger.ts parses against them before writing straight into
4
4
  // jobRunsTable/jobRunLogsTable, so an out-of-dispatcher write still gets the
@@ -23,8 +23,8 @@ import {
23
23
  createStaleRunSweepJob,
24
24
  DEFAULT_JOB_RUN_STALE_TIMEOUT_HOURS,
25
25
  } from "./handlers/stale-run-sweep.job.ts";
26
- import { tenantFailuresQuery } from "./handlers/tenant-failures.query.ts";
27
- import { tenantRunsQuery } from "./handlers/tenant-runs.query.ts";
26
+ import { createTenantFailuresQuery } from "./handlers/tenant-failures.query.ts";
27
+ import { createTenantRunsQuery } from "./handlers/tenant-runs.query.ts";
28
28
  import { triggerWrite } from "./handlers/trigger.write.ts";
29
29
  import { jobRunLogsTableMeta, jobRunsTableMeta } from "./job-run-table.ts";
30
30
  import {
@@ -44,16 +44,26 @@ export type JobsFeatureOptions = {
44
44
  // which a tenant-visible "queued" row counts as lost and is dropped by the stale-run sweep.
45
45
  readonly retentionDays?: number;
46
46
  // How long a run can sit at status "running" before the hourly
47
- // stale-run-sweep job marks it "failed" (#2246 — a process kill mid-run
47
+ // stale-run-sweep job marks it "failed" — a process kill mid-run
48
48
  // never fires onJobComplete/onJobFailed, so nothing else ever revisits
49
49
  // it). Must clear any legitimately long-running job (reindexEntity,
50
50
  // projectionRebuild) — set high, not tight.
51
51
  readonly staleRunTimeoutHours?: number;
52
+ // Additional app roles that may read their own tenant's job status and
53
+ // failures (jobs:query:failures, jobs:query:tenant-runs). Added to the default
54
+ // User/Editor/admin roles, which stay; the scope stays the caller's own tenant.
55
+ readonly readRoles?: readonly string[];
52
56
  };
53
57
 
54
58
  export function createJobsFeature(options: JobsFeatureOptions = {}): FeatureDefinition {
55
59
  const retentionDays = options.retentionDays ?? DEFAULT_JOB_RUN_RETENTION_DAYS;
56
60
  const staleRunTimeoutHours = options.staleRunTimeoutHours ?? DEFAULT_JOB_RUN_STALE_TIMEOUT_HOURS;
61
+ const readRoles = options.readRoles ?? [];
62
+ if (readRoles.includes("anonymous")) {
63
+ throw new Error(
64
+ `createJobsFeature: readRoles must not contain "anonymous" — job status and failures are only readable by members of the tenant.`,
65
+ );
66
+ }
57
67
  return defineFeature("jobs", (r) => {
58
68
  r.describe(
59
69
  "Persistence and operator tooling for background jobs registered via `r.job(...)`. Every job execution writes directly into `store_job_runs` (current status + duration) and `store_job_run_logs` (per-line log rows) from the BullMQ callbacks — no event stream in between (#2243). A daily `retention-cleanup` job deletes runs (and their logs) older than `retentionDays`; an hourly `stale-run-sweep` job marks runs stuck at status `running` past `staleRunTimeoutHours` as `failed` (#2246 — a crashed worker never fires the completion callback, so nothing else ever revisits the row). Exposes `jobs:write:trigger` (manual run) and `jobs:write:retry` (operator retry of a failed run), plus `jobs:query:list`, `jobs:query:details`, and `jobs:query:catalog` (manual jobs) for the operator UI. A job that declares `tenantVisibleFailure` also records its last failed attempt per tenant and subject in `store_tenant_job_failures`, which the tenant itself reads through `jobs:query:failures` — a translation key only, never the provider's message (fw#3079). A job that declares `tenantVisibleRun` also keeps its run state per tenant and subject in `store_tenant_job_runs` (queued, running, plus the latest completed or failed run, no payload, error text or logs), which the tenant reads through `jobs:query:tenant-runs` (fw#3616); the stale-run sweep fails its stuck `running` rows and drops `queued` rows older than `retentionDays`.",
@@ -67,11 +77,10 @@ export function createJobsFeature(options: JobsFeatureOptions = {}): FeatureDefi
67
77
  r.storeTable(jobRunsTableMeta, {
68
78
  reason: "direct_write.job_runs",
69
79
  // payload/error carry personal:{of:"triggeredById"} (job-run-table.ts): encrypted under the
70
- // triggering user's DEK, or the system tenant key when triggeredById is null
71
- // (whenAbsent: "tenant", fw#3654).
80
+ // triggering user's DEK, or the system tenant key when triggeredById is null.
72
81
  // job-run-logger.ts manually encrypts both before every insert/update
73
82
  // (encryptStartedPayload/encryptFailureError) since this store bypasses
74
- // the executor's automatic PII pipeline (#2243).
83
+ // the executor's automatic PII pipeline.
75
84
  piiEncryptedOnWrite: true,
76
85
  });
77
86
  r.storeTable(jobRunLogsTableMeta, {
@@ -91,7 +100,7 @@ export function createJobsFeature(options: JobsFeatureOptions = {}): FeatureDefi
91
100
  projectionRebuildJob,
92
101
  );
93
102
 
94
- // Retroactive search backfill (#1206/#1215) — manual + perTenant, so one
103
+ // Retroactive search backfill — manual + perTenant, so one
95
104
  // `jobs:write:trigger` call with { entity } fans out to every active
96
105
  // tenant (job-runner.ts perTenant dispatch applies to manual triggers
97
106
  // too, not just cron).
@@ -107,7 +116,7 @@ export function createJobsFeature(options: JobsFeatureOptions = {}): FeatureDefi
107
116
  );
108
117
 
109
118
  // store_job_runs/store_job_run_logs are direct-write, unbounded-growth
110
- // stores (#2243) — nothing else purges them.
119
+ // stores — nothing else purges them.
111
120
  r.job(
112
121
  "retention-cleanup",
113
122
  { trigger: { cron: "0 3 * * *" }, concurrency: "skip" },
@@ -115,7 +124,7 @@ export function createJobsFeature(options: JobsFeatureOptions = {}): FeatureDefi
115
124
  );
116
125
 
117
126
  // Sweeps store_job_runs for rows stuck at status "running" past the
118
- // timeout (#2246). Hourly matches the timeout's own granularity —
127
+ // timeout. Hourly matches the timeout's own granularity —
119
128
  // frequent enough to catch a stuck run soon after it crosses the
120
129
  // threshold, cheap enough that an (almost always empty) result set
121
130
  // doesn't matter.
@@ -138,8 +147,8 @@ export function createJobsFeature(options: JobsFeatureOptions = {}): FeatureDefi
138
147
  list: r.queryHandler(listQuery),
139
148
  detail: r.queryHandler(detailQuery),
140
149
  catalog: r.queryHandler(catalogQuery),
141
- failures: r.queryHandler(tenantFailuresQuery),
142
- tenantRuns: r.queryHandler(tenantRunsQuery),
150
+ failures: r.queryHandler(createTenantFailuresQuery(readRoles)),
151
+ tenantRuns: r.queryHandler(createTenantRunsQuery(readRoles)),
143
152
  consumers: r.queryHandler(consumersQuery),
144
153
  consumerDetails: r.queryHandler(consumerDetailQuery),
145
154
  };
@@ -32,12 +32,12 @@ export const detailQuery = defineQueryHandler({
32
32
 
33
33
  if (!row) return null;
34
34
 
35
- // payload is stored encrypted under the triggering user's DEK (#799).
35
+ // payload is stored encrypted under the triggering user's DEK.
36
36
  if (typeof row["payload"] === "string") {
37
37
  row["payload"] = await decryptStoredPii(row["payload"], "payload", "job-run-detail");
38
38
  }
39
39
 
40
- // error is stored encrypted under the triggering user's DEK (#2307),
40
+ // error is stored encrypted under the triggering user's DEK,
41
41
  // same mechanism as row.payload above.
42
42
  if (typeof row["error"] === "string") {
43
43
  row["error"] = await decryptStoredPii(row["error"], "error", "job-run-detail");
@@ -52,8 +52,8 @@ export const detailQuery = defineQueryHandler({
52
52
  },
53
53
  );
54
54
 
55
- // message is stored encrypted under the triggering user's DEK (#2247),
56
- // same mechanism as row.payload above. Bounded concurrency (#2307) —
55
+ // message is stored encrypted under the triggering user's DEK,
56
+ // same mechanism as row.payload above. Bounded concurrency —
57
57
  // unbounded Promise.all would fire one decrypt per log line at once
58
58
  // against the KMS adapter's pool.
59
59
  const decryptedLogs = await mapWithConcurrency(logs, KMS_POOL_CONCURRENCY, async (log) => {
@@ -109,7 +109,7 @@ export const listQuery = defineQueryHandler({
109
109
  // capped at the page size and would silently undercount the total.
110
110
  const total =
111
111
  query.payload.totalCount === true ? await countWhere(db, jobRunsTable, where) : undefined;
112
- // payload/error are stored encrypted under the triggering user's DEK (#799, #2307).
112
+ // payload/error are stored encrypted under the triggering user's DEK.
113
113
  return {
114
114
  rows: await mapWithConcurrency(rows, KMS_POOL_CONCURRENCY, decryptRunRow),
115
115
  nextCursor: hasMore ? encodeCursor(String(offset + limit)) : null,
@@ -8,7 +8,7 @@ import * as z from "zod";
8
8
 
9
9
  export const projectionRebuildPayloadSchema = z.object({
10
10
  projection: z.string().min(1),
11
- // Quarantine mode (#760): skip + dead-letter poison events instead of
11
+ // Quarantine mode: skip + dead-letter poison events instead of
12
12
  // failing the whole rebuild. Operator opt-in per run.
13
13
  skipApplyErrors: z.boolean().optional(),
14
14
  });
@@ -1,4 +1,4 @@
1
- // Manual, perTenant backfill job (#1206/#1215) — indexes existing rows for
1
+ // Manual, perTenant backfill job — indexes existing rows for
2
2
  // an entity that only got `searchable: true` after rows already existed.
3
3
  // perTenant fan-out (job-runner.ts) also applies to a manual dispatch, not
4
4
  // just cron: one `jobs:write:trigger` call with { entity } re-runs once per
@@ -58,7 +58,7 @@ export const retryWrite = defineWriteHandler({
58
58
  );
59
59
  }
60
60
 
61
- // payload is stored encrypted under the triggering user's DEK (#799),
61
+ // payload is stored encrypted under the triggering user's DEK,
62
62
  // same mechanism as detail.query.ts/list.query.ts — decrypt before
63
63
  // parsing it as JSON. A key erased since the run finished decrypts to
64
64
  // PII_ERASED_SENTINEL, which is not JSON; reject the retry rather than
@@ -30,44 +30,49 @@ function parseSubject(stored: string | null): Record<string, unknown> | null {
30
30
  return Object.fromEntries(parsed.filter(isSubjectEntry));
31
31
  }
32
32
 
33
- export const tenantFailuresQuery = defineQueryHandler({
34
- name: "failures",
35
- description:
36
- "Lists the calling tenant's own failed jobs — one record per job and subject, newest first, each carrying a translation key for the reason, never the provider's own error message; the optional subject filter matches exactly: all declared subjectFields with the same JSON types as the job payload; use it to tell a tenant that their asynchronous job failed instead of leaving the screen waiting.",
37
- schema: z.object({
38
- jobName: z.string().optional(),
39
- subject: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])).optional(),
40
- limit: z.number().int().min(1).max(200).optional(),
41
- }),
42
- // Every membership rank: a failure record carries a job name and a
43
- // translation key, nothing a team member of the tenant may not see.
44
- access: { roles: access.roles("User", "Editor", ...access.admin) },
45
- handler: async (query, ctx) => {
46
- if (!ctx.systemDb) {
47
- throw new InternalError({
48
- message: "jobs:query:failures requires ctx.systemDb (feature must declare r.systemScope())",
33
+ export function createTenantFailuresQuery(readRoles: readonly string[]) {
34
+ return defineQueryHandler({
35
+ name: "failures",
36
+ description:
37
+ "Lists the calling tenant's own failed jobs — one record per job and subject, newest first, each carrying a translation key for the reason, never the provider's own error message; the optional subject filter matches exactly: all declared subjectFields with the same JSON types as the job payload; use it to tell a tenant that their asynchronous job failed instead of leaving the screen waiting.",
38
+ schema: z.object({
39
+ jobName: z.string().optional(),
40
+ subject: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])).optional(),
41
+ limit: z.number().int().min(1).max(200).optional(),
42
+ }),
43
+ // Every membership rank: a failure record carries a job name and a
44
+ // translation key, nothing a team member of the tenant may not see.
45
+ access: {
46
+ roles: [...new Set([...access.roles("User", "Editor", ...access.admin), ...readRoles])],
47
+ },
48
+ handler: async (query, ctx) => {
49
+ if (!ctx.systemDb) {
50
+ throw new InternalError({
51
+ message:
52
+ "jobs:query:failures requires ctx.systemDb (feature must declare r.systemScope())",
53
+ });
54
+ }
55
+ // assertTenantMatch is a self-check on the caller and returns the same
56
+ // unfiltered system-mode db (tenant-db.ts) — the explicit tenantId below
57
+ // is the filter, assertRowsTenant the second net. There is no
58
+ // cross-tenant mode here: SystemAdmin reads runs via jobs:query:list.
59
+ const db = ctx.systemDb.assertTenantMatch(query.user.tenantId);
60
+ const where: Record<string, unknown> = { tenantId: [query.user.tenantId] };
61
+ if (query.payload.jobName) where["jobName"] = query.payload.jobName;
62
+ if (query.payload.subject) where["subject"] = serializeJobSubject(query.payload.subject);
63
+ const rows = await selectMany<TenantJobFailureRow>(db, tenantJobFailuresTable, where, {
64
+ orderBy: { col: "failedAt", direction: "desc" },
65
+ limit: query.payload.limit ?? DEFAULT_LIMIT,
49
66
  });
50
- }
51
- // assertTenantMatch is a self-check on the caller and returns the same
52
- // unfiltered system-mode db (tenant-db.ts) — the explicit tenantId below
53
- // is the filter, assertRowsTenant the second net. There is no
54
- // cross-tenant mode here: SystemAdmin reads runs via jobs:query:list.
55
- const db = ctx.systemDb.assertTenantMatch(query.user.tenantId);
56
- const where: Record<string, unknown> = { tenantId: [query.user.tenantId] };
57
- if (query.payload.jobName) where["jobName"] = query.payload.jobName;
58
- if (query.payload.subject) where["subject"] = serializeJobSubject(query.payload.subject);
59
- const rows = await selectMany<TenantJobFailureRow>(db, tenantJobFailuresTable, where, {
60
- orderBy: { col: "failedAt", direction: "desc" },
61
- limit: query.payload.limit ?? DEFAULT_LIMIT,
62
- });
63
- return {
64
- rows: ctx.systemDb.assertRowsTenant(rows, "tenantId").map((row) => ({
65
- jobName: row.jobName,
66
- subject: parseSubject(row.subject),
67
- messageKey: row.messageKey,
68
- failedAt: row.failedAt,
69
- })),
70
- nextCursor: null,
71
- };
72
- },
73
- });
67
+ return {
68
+ rows: ctx.systemDb.assertRowsTenant(rows, "tenantId").map((row) => ({
69
+ jobName: row.jobName,
70
+ subject: parseSubject(row.subject),
71
+ messageKey: row.messageKey,
72
+ failedAt: row.failedAt,
73
+ })),
74
+ nextCursor: null,
75
+ };
76
+ },
77
+ });
78
+ }
@@ -32,63 +32,67 @@ function parseSubject(stored: string | null): Record<string, unknown> | null {
32
32
  return Object.fromEntries(parsed.filter(isSubjectEntry));
33
33
  }
34
34
 
35
- export const tenantRunsQuery = defineQueryHandler({
36
- name: "tenant-runs",
37
- description:
38
- "Lists the calling tenant's own job runs that opted in via tenantVisibleRun — per job and subject every queued or running run plus the latest completed or failed one, active runs first, then newest first; each row carries only status and queuedAt/startedAt/finishedAt, never payloads, error text or logs; the optional subject filter matches exactly: all declared subjectFields with the same JSON types as the job payload; use it to show whether work for a subject is waiting, running or done, and to tell a failed run from a finished one.",
39
- schema: z.object({
40
- jobName: z.string().optional(),
41
- subject: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])).optional(),
42
- limit: z.number().int().min(1).max(200).optional(),
43
- }),
44
- // Every membership rank: a run state carries a job name, a status and
45
- // times, nothing a team member of the tenant may not see.
46
- access: { roles: access.roles("User", "Editor", ...access.admin) },
47
- handler: async (query, ctx) => {
48
- if (!ctx.systemDb) {
49
- throw new InternalError({
50
- message:
51
- "jobs:query:tenant-runs requires ctx.systemDb (feature must declare r.systemScope())",
35
+ export function createTenantRunsQuery(readRoles: readonly string[]) {
36
+ return defineQueryHandler({
37
+ name: "tenant-runs",
38
+ description:
39
+ "Lists the calling tenant's own job runs that opted in via tenantVisibleRun — per job and subject every queued or running run plus the latest completed or failed one, active runs first, then newest first; each row carries only status and queuedAt/startedAt/finishedAt, never payloads, error text or logs; the optional subject filter matches exactly: all declared subjectFields with the same JSON types as the job payload; use it to show whether work for a subject is waiting, running or done, and to tell a failed run from a finished one.",
40
+ schema: z.object({
41
+ jobName: z.string().optional(),
42
+ subject: z.record(z.string(), z.union([z.string(), z.number(), z.boolean()])).optional(),
43
+ limit: z.number().int().min(1).max(200).optional(),
44
+ }),
45
+ // Every membership rank: a run state carries a job name, a status and
46
+ // times, nothing a team member of the tenant may not see.
47
+ access: {
48
+ roles: [...new Set([...access.roles("User", "Editor", ...access.admin), ...readRoles])],
49
+ },
50
+ handler: async (query, ctx) => {
51
+ if (!ctx.systemDb) {
52
+ throw new InternalError({
53
+ message:
54
+ "jobs:query:tenant-runs requires ctx.systemDb (feature must declare r.systemScope())",
55
+ });
56
+ }
57
+ // assertTenantMatch returns the same unfiltered system-mode db — the
58
+ // explicit tenantId below is the filter, assertRowsTenant the second net.
59
+ const db = ctx.systemDb.assertTenantMatch(query.user.tenantId);
60
+ const where: Record<string, unknown> = { tenantId: [query.user.tenantId] };
61
+ if (query.payload.jobName) where["jobName"] = query.payload.jobName;
62
+ if (query.payload.subject) where["subject"] = serializeJobSubject(query.payload.subject);
63
+ const limit = query.payload.limit ?? DEFAULT_LIMIT;
64
+ const newestFirst = { col: "updatedAt", direction: "desc" } as const;
65
+ const activeRows = await selectMany<TenantJobRunRow>(
66
+ db,
67
+ tenantJobRunsTable,
68
+ { ...where, status: { in: ["queued", "running"] } },
69
+ { orderBy: newestFirst, limit },
70
+ );
71
+ const finishedRows = await selectMany<TenantJobRunRow>(
72
+ db,
73
+ tenantJobRunsTable,
74
+ { ...where, status: { in: ["completed", "failed"] } },
75
+ { orderBy: newestFirst, limit },
76
+ );
77
+ const seenFinishedKeys = new Set<string>();
78
+ const finishedNewestPerKey = finishedRows.filter((row) => {
79
+ const key = JSON.stringify([row.jobName, row.subject]);
80
+ if (seenFinishedKeys.has(key)) return false;
81
+ seenFinishedKeys.add(key);
82
+ return true;
52
83
  });
53
- }
54
- // assertTenantMatch returns the same unfiltered system-mode db — the
55
- // explicit tenantId below is the filter, assertRowsTenant the second net.
56
- const db = ctx.systemDb.assertTenantMatch(query.user.tenantId);
57
- const where: Record<string, unknown> = { tenantId: [query.user.tenantId] };
58
- if (query.payload.jobName) where["jobName"] = query.payload.jobName;
59
- if (query.payload.subject) where["subject"] = serializeJobSubject(query.payload.subject);
60
- const limit = query.payload.limit ?? DEFAULT_LIMIT;
61
- const newestFirst = { col: "updatedAt", direction: "desc" } as const;
62
- const activeRows = await selectMany<TenantJobRunRow>(
63
- db,
64
- tenantJobRunsTable,
65
- { ...where, status: { in: ["queued", "running"] } },
66
- { orderBy: newestFirst, limit },
67
- );
68
- const finishedRows = await selectMany<TenantJobRunRow>(
69
- db,
70
- tenantJobRunsTable,
71
- { ...where, status: { in: ["completed", "failed"] } },
72
- { orderBy: newestFirst, limit },
73
- );
74
- const seenFinishedKeys = new Set<string>();
75
- const finishedNewestPerKey = finishedRows.filter((row) => {
76
- const key = JSON.stringify([row.jobName, row.subject]);
77
- if (seenFinishedKeys.has(key)) return false;
78
- seenFinishedKeys.add(key);
79
- return true;
80
- });
81
- const activeFirst = [...activeRows, ...finishedNewestPerKey];
82
- return {
83
- rows: ctx.systemDb.assertRowsTenant(activeFirst.slice(0, limit), "tenantId").map((row) => ({
84
- jobName: row.jobName,
85
- subject: parseSubject(row.subject),
86
- status: row.status,
87
- queuedAt: row.queuedAt,
88
- startedAt: row.startedAt,
89
- finishedAt: row.finishedAt,
90
- })),
91
- nextCursor: null,
92
- };
93
- },
94
- });
84
+ const activeFirst = [...activeRows, ...finishedNewestPerKey];
85
+ return {
86
+ rows: ctx.systemDb.assertRowsTenant(activeFirst.slice(0, limit), "tenantId").map((row) => ({
87
+ jobName: row.jobName,
88
+ subject: parseSubject(row.subject),
89
+ status: row.status,
90
+ queuedAt: row.queuedAt,
91
+ startedAt: row.startedAt,
92
+ finishedAt: row.finishedAt,
93
+ })),
94
+ nextCursor: null,
95
+ };
96
+ },
97
+ });
98
+ }
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
2
2
 
3
- // kumiko-framework#1525: the five value-position Temporal.Instant.from
3
+ // The five value-position Temporal.Instant.from
4
4
  // call sites in feature.ts live inside defineApply callbacks with no
5
5
  // exported seam, so this thin wrapper gives the ambient-global-independence
6
6
  // regression test something to import directly.