@cosmicdrift/kumiko-samples 0.367.0 → 0.369.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 (406) hide show
  1. package/package.json +1 -1
  2. package/packages/bundled-features/package.json +16 -2
  3. package/packages/bundled-features/src/audit/handlers/details.query.ts +1 -1
  4. package/packages/bundled-features/src/audit/handlers/list.query.ts +1 -1
  5. package/packages/bundled-features/src/audit/run-escape-hatch-retention.ts +5 -5
  6. package/packages/bundled-features/src/auth-email-password/bootstrap.ts +1 -1
  7. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +10 -3
  8. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +10 -3
  9. package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +1 -1
  10. package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +6 -2
  11. package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +1 -1
  12. package/packages/bundled-features/src/auth-email-password/seeding.ts +2 -2
  13. package/packages/bundled-features/src/auth-foundation/feature.ts +43 -34
  14. package/packages/bundled-features/src/auth-foundation/index.ts +1 -0
  15. package/packages/bundled-features/src/auth-mfa/db/queries.ts +5 -2
  16. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +1 -1
  17. package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +1 -1
  18. package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +2 -2
  19. package/packages/bundled-features/src/auth-mfa/handlers/status.query.ts +1 -1
  20. package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +1 -1
  21. package/packages/bundled-features/src/auth-mfa/mfa-code-verifier.ts +1 -1
  22. package/packages/bundled-features/src/auth-mfa/mfa-status-checker.ts +1 -1
  23. package/packages/bundled-features/src/auth-mfa-user-data/index.ts +19 -10
  24. package/packages/bundled-features/src/billing-foundation/billing-info-query.ts +1 -1
  25. package/packages/bundled-features/src/billing-foundation/feature.ts +138 -135
  26. package/packages/bundled-features/src/billing-foundation/handlers/create-portal-session.write.ts +1 -1
  27. package/packages/bundled-features/src/billing-foundation/projection.ts +3 -2
  28. package/packages/bundled-features/src/cap-counter/calendar-cap-usage-reservation.ts +52 -1
  29. package/packages/bundled-features/src/cap-counter/cap-reservation.ts +203 -15
  30. package/packages/bundled-features/src/cap-counter/changes.json +13 -0
  31. package/packages/bundled-features/src/cap-counter/feature.ts +84 -73
  32. package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +3 -4
  33. package/packages/bundled-features/src/cap-counter/index.ts +9 -1
  34. package/packages/bundled-features/src/cap-counter/tables.ts +10 -3
  35. package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -2
  36. package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +6 -2
  37. package/packages/bundled-features/src/cap-overview/handlers/tenant-options.query.ts +1 -1
  38. package/packages/bundled-features/src/channel-email/changes.json +7 -0
  39. package/packages/bundled-features/src/channel-email/email-channel.ts +39 -8
  40. package/packages/bundled-features/src/channel-email/feature.ts +1 -1
  41. package/packages/bundled-features/src/channel-email/index.ts +5 -1
  42. package/packages/bundled-features/src/channel-in-app/handlers/inbox.query.ts +1 -1
  43. package/packages/bundled-features/src/channel-in-app/handlers/mark-all-read.write.ts +1 -1
  44. package/packages/bundled-features/src/channel-in-app/handlers/mark-read.write.ts +1 -1
  45. package/packages/bundled-features/src/channel-in-app/handlers/unread-count.query.ts +1 -1
  46. package/packages/bundled-features/src/channel-in-app/tables.ts +1 -1
  47. package/packages/bundled-features/src/compliance-profiles/handlers/for-tenant.query.ts +1 -1
  48. package/packages/bundled-features/src/compliance-profiles/handlers/needs-profile.query.ts +1 -1
  49. package/packages/bundled-features/src/compliance-profiles/handlers/set-profile.write.ts +1 -2
  50. package/packages/bundled-features/src/compliance-profiles/resolve-for-tenant.ts +1 -1
  51. package/packages/bundled-features/src/compliance-profiles/seeding.ts +8 -4
  52. package/packages/bundled-features/src/compliance-profiles-ops/index.ts +26 -17
  53. package/packages/bundled-features/src/config/db/queries/resolver.ts +1 -1
  54. package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +2 -2
  55. package/packages/bundled-features/src/config/resolver.ts +1 -1
  56. package/packages/bundled-features/src/config/web/i18n.ts +1 -2
  57. package/packages/bundled-features/src/config/write-helpers.ts +1 -1
  58. package/packages/bundled-features/src/crypto-shredding/changes.json +6 -0
  59. package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +9 -7
  60. package/packages/bundled-features/src/custom-fields/db/queries/field-access.ts +1 -1
  61. package/packages/bundled-features/src/custom-fields/db/queries/projection.ts +1 -1
  62. package/packages/bundled-features/src/custom-fields/db/queries/quota.ts +1 -1
  63. package/packages/bundled-features/src/custom-fields/db/queries/retention.ts +6 -2
  64. package/packages/bundled-features/src/custom-fields/db/queries/user-data-rights.ts +1 -1
  65. package/packages/bundled-features/src/custom-fields/feature.ts +11 -14
  66. package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +2 -2
  67. package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +2 -2
  68. package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +2 -2
  69. package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +2 -2
  70. package/packages/bundled-features/src/custom-fields/wire-for-entity.ts +4 -4
  71. package/packages/bundled-features/src/data-retention/resolve-for-tenant.ts +1 -1
  72. package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +16 -10
  73. package/packages/bundled-features/src/delivery/address-opt-out.ts +5 -2
  74. package/packages/bundled-features/src/delivery/attempt-log-retention.ts +1 -1
  75. package/packages/bundled-features/src/delivery/changes.json +6 -0
  76. package/packages/bundled-features/src/delivery/channel-context.ts +1 -1
  77. package/packages/bundled-features/src/delivery/db/queries/address-opt-outs.ts +1 -1
  78. package/packages/bundled-features/src/delivery/db/queries/preferences.ts +1 -1
  79. package/packages/bundled-features/src/delivery/delivery-service.ts +16 -6
  80. package/packages/bundled-features/src/delivery/feature.ts +2 -2
  81. package/packages/bundled-features/src/delivery/handlers/log.query.ts +3 -2
  82. package/packages/bundled-features/src/delivery/handlers/preferences.query.ts +1 -1
  83. package/packages/bundled-features/src/delivery/index.ts +8 -1
  84. package/packages/bundled-features/src/delivery/unsubscribe.ts +66 -37
  85. package/packages/bundled-features/src/delivery/upsert-preference.ts +5 -2
  86. package/packages/bundled-features/src/derivatives-sharp/feature.ts +21 -12
  87. package/packages/bundled-features/src/derivatives-sharp/index.ts +1 -1
  88. package/packages/bundled-features/src/document-ingest-foundation/feature.ts +112 -103
  89. package/packages/bundled-features/src/document-ingest-foundation/forget-extract-with-file-ref.ts +3 -3
  90. package/packages/bundled-features/src/document-ingest-foundation/index.ts +4 -1
  91. package/packages/bundled-features/src/feature-toggles/global-feature-state-table.ts +1 -1
  92. package/packages/bundled-features/src/feature-toggles/handlers/set.write.ts +3 -5
  93. package/packages/bundled-features/src/feature-toggles/toggle-runtime.ts +1 -1
  94. package/packages/bundled-features/src/file-derivatives/feature.ts +134 -129
  95. package/packages/bundled-features/src/file-derivatives/handlers/public-variant-by-file-ref.query.ts +1 -1
  96. package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +1 -1
  97. package/packages/bundled-features/src/file-foundation/feature.ts +38 -29
  98. package/packages/bundled-features/src/file-foundation/index.ts +1 -0
  99. package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +1 -1
  100. package/packages/bundled-features/src/file-provider-inmemory/feature.ts +32 -21
  101. package/packages/bundled-features/src/file-provider-inmemory/index.ts +6 -1
  102. package/packages/bundled-features/src/file-provider-s3/changes.json +10 -1
  103. package/packages/bundled-features/src/file-provider-s3/env-feature.ts +62 -0
  104. package/packages/bundled-features/src/file-provider-s3/feature.ts +107 -73
  105. package/packages/bundled-features/src/file-provider-s3/index.ts +6 -1
  106. package/packages/bundled-features/src/file-provider-s3/lib/index.ts +3 -0
  107. package/packages/bundled-features/src/{files-provider-s3 → file-provider-s3/lib}/s3-provider.ts +19 -19
  108. package/packages/bundled-features/src/file-provider-s3-env/index.ts +7 -2
  109. package/packages/bundled-features/src/files-provider-s3/index.ts +11 -3
  110. package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +1 -1
  111. package/packages/bundled-features/src/files-tenant-data/hooks.ts +1 -2
  112. package/packages/bundled-features/src/folders/feature.ts +8 -3
  113. package/packages/bundled-features/src/folders-user-data/index.ts +27 -18
  114. package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +1 -1
  115. package/packages/bundled-features/src/form-draft/db/queries/draft-count.ts +1 -1
  116. package/packages/bundled-features/src/form-draft/db/queries/owned-file-refs.ts +3 -2
  117. package/packages/bundled-features/src/form-draft/feature.ts +6 -1
  118. package/packages/bundled-features/src/form-draft/handlers/cleanup.job.ts +2 -2
  119. package/packages/bundled-features/src/form-draft/index.ts +1 -1
  120. package/packages/bundled-features/src/form-draft/lookup.ts +1 -1
  121. package/packages/bundled-features/src/form-draft-user-data/index.ts +19 -10
  122. package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +165 -154
  123. package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +1 -2
  124. package/packages/bundled-features/src/inbound-mail-foundation/index.ts +1 -1
  125. package/packages/bundled-features/src/inbound-mail-foundation/oauth-access-token.ts +5 -2
  126. package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +3 -2
  127. package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +1 -1
  128. package/packages/bundled-features/src/inbound-provider-imap/feature.ts +22 -13
  129. package/packages/bundled-features/src/inbound-provider-imap/index.ts +6 -1
  130. package/packages/bundled-features/src/inbound-provider-inmemory/feature.ts +20 -12
  131. package/packages/bundled-features/src/inbound-provider-inmemory/index.ts +1 -0
  132. package/packages/bundled-features/src/jobs/db/queries/retention.ts +1 -1
  133. package/packages/bundled-features/src/jobs/db/queries/stale-run-sweep.ts +1 -1
  134. package/packages/bundled-features/src/jobs/handlers/detail.query.ts +1 -1
  135. package/packages/bundled-features/src/jobs/handlers/list.query.ts +7 -2
  136. package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
  137. package/packages/bundled-features/src/jobs/handlers/tenant-failures.query.ts +1 -1
  138. package/packages/bundled-features/src/jobs/handlers/tenant-runs.query.ts +1 -1
  139. package/packages/bundled-features/src/jobs/job-run-logger.ts +11 -10
  140. package/packages/bundled-features/src/jobs/tenant-job-failure-table.ts +1 -1
  141. package/packages/bundled-features/src/jobs/tenant-job-run-table.ts +1 -1
  142. package/packages/bundled-features/src/ledger/feature.ts +6 -3
  143. package/packages/bundled-features/src/mail-foundation/feature.ts +66 -46
  144. package/packages/bundled-features/src/mail-foundation/i18n.ts +8 -0
  145. package/packages/bundled-features/src/mail-foundation/index.ts +1 -0
  146. package/packages/bundled-features/src/mail-transport-inmemory/feature.ts +31 -17
  147. package/packages/bundled-features/src/mail-transport-inmemory/index.ts +6 -1
  148. package/packages/bundled-features/src/mail-transport-smtp/changes.json +7 -0
  149. package/packages/bundled-features/src/mail-transport-smtp/config-keys.ts +67 -0
  150. package/packages/bundled-features/src/mail-transport-smtp/feature.ts +67 -82
  151. package/packages/bundled-features/src/mail-transport-smtp/i18n.ts +28 -0
  152. package/packages/bundled-features/src/mail-transport-smtp/index.ts +1 -0
  153. package/packages/bundled-features/src/managed-pages/handlers/by-slug.query.ts +1 -1
  154. package/packages/bundled-features/src/managed-pages/handlers/by-tenant-published.query.ts +1 -2
  155. package/packages/bundled-features/src/managed-pages/handlers/set.write.ts +1 -2
  156. package/packages/bundled-features/src/managed-pages/seeding.ts +8 -4
  157. package/packages/bundled-features/src/metrics/compute.ts +1 -1
  158. package/packages/bundled-features/src/metrics/filters.ts +1 -1
  159. package/packages/bundled-features/src/metrics/validate.ts +1 -1
  160. package/packages/bundled-features/src/notes-history/feature.ts +6 -3
  161. package/packages/bundled-features/src/notes-history/handlers/add-note.write.ts +1 -1
  162. package/packages/bundled-features/src/notes-history-user-data/hooks.ts +1 -1
  163. package/packages/bundled-features/src/notes-history-user-data/index.ts +27 -18
  164. package/packages/bundled-features/src/personal-access-tokens/changes.json +6 -0
  165. package/packages/bundled-features/src/personal-access-tokens/feature.ts +17 -2
  166. package/packages/bundled-features/src/personal-access-tokens/handlers/create.write.ts +1 -1
  167. package/packages/bundled-features/src/personal-access-tokens/handlers/list.query.ts +2 -2
  168. package/packages/bundled-features/src/personal-access-tokens/handlers/revoke.write.ts +1 -1
  169. package/packages/bundled-features/src/personal-access-tokens/resolver.ts +1 -1
  170. package/packages/bundled-features/src/personal-access-tokens/revoke-for-user.ts +2 -2
  171. package/packages/bundled-features/src/personal-access-tokens/roles.ts +8 -6
  172. package/packages/bundled-features/src/personal-access-tokens/screens.ts +2 -0
  173. package/packages/bundled-features/src/readiness/feature.ts +25 -16
  174. package/packages/bundled-features/src/readiness/index.ts +1 -1
  175. package/packages/bundled-features/src/secrets/changes.json +6 -0
  176. package/packages/bundled-features/src/secrets/db/queries/read.ts +1 -1
  177. package/packages/bundled-features/src/secrets/feature.ts +26 -6
  178. package/packages/bundled-features/src/secrets/handlers/delete.write.ts +5 -2
  179. package/packages/bundled-features/src/secrets/handlers/rotate.job.ts +2 -2
  180. package/packages/bundled-features/src/secrets/handlers/set.write.ts +5 -2
  181. package/packages/bundled-features/src/secrets/secrets-context.ts +4 -3
  182. package/packages/bundled-features/src/sessions/db/queries/cleanup.ts +1 -1
  183. package/packages/bundled-features/src/sessions/handlers/detail.query.ts +1 -1
  184. package/packages/bundled-features/src/sessions/handlers/list.query.ts +2 -2
  185. package/packages/bundled-features/src/sessions/handlers/mine.query.ts +1 -1
  186. package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +1 -1
  187. package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +1 -1
  188. package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
  189. package/packages/bundled-features/src/sessions/session-callbacks.ts +14 -7
  190. package/packages/bundled-features/src/sessions/testing.ts +1 -1
  191. package/packages/bundled-features/src/tags/feature.ts +6 -3
  192. package/packages/bundled-features/src/template-resolver/api.ts +1 -1
  193. package/packages/bundled-features/src/template-resolver/constants.ts +0 -1
  194. package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +1 -1
  195. package/packages/bundled-features/src/template-resolver/handlers/by-slug.query.ts +1 -1
  196. package/packages/bundled-features/src/template-resolver/handlers/by-tenant.query.ts +1 -2
  197. package/packages/bundled-features/src/template-resolver/handlers/collection-item.query.ts +1 -1
  198. package/packages/bundled-features/src/template-resolver/handlers/collection-list.query.ts +1 -2
  199. package/packages/bundled-features/src/template-resolver/handlers/collection-set.write.ts +1 -1
  200. package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +1 -1
  201. package/packages/bundled-features/src/template-resolver/handlers/diff-to-system.query.ts +1 -1
  202. package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +1 -1
  203. package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +1 -1
  204. package/packages/bundled-features/src/template-resolver/handlers/layout-source.query.ts +1 -1
  205. package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +1 -1
  206. package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +1 -1
  207. package/packages/bundled-features/src/template-resolver/handlers/reset-to-system.write.ts +1 -1
  208. package/packages/bundled-features/src/template-resolver/handlers/resource-remove.write.ts +1 -1
  209. package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +4 -2
  210. package/packages/bundled-features/src/template-resolver/handlers/set.write.ts +1 -1
  211. package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +1 -1
  212. package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +1 -1
  213. package/packages/bundled-features/src/template-resolver/handlers/toggle-status.write.ts +1 -1
  214. package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +1 -1
  215. package/packages/bundled-features/src/template-resolver/handlers/validate.query.ts +1 -1
  216. package/packages/bundled-features/src/template-resolver/seeding.ts +3 -3
  217. package/packages/bundled-features/src/template-resolver/store-template-resource.ts +1 -1
  218. package/packages/bundled-features/src/template-resolver/template-preview.ts +1 -1
  219. package/packages/bundled-features/src/template-resolver/template-resources.ts +1 -1
  220. package/packages/bundled-features/src/template-resolver/testing.ts +1 -1
  221. package/packages/bundled-features/src/template-resolver-user-data/index.ts +23 -14
  222. package/packages/bundled-features/src/tenant/handlers/active-tenant-ids.query.ts +1 -1
  223. package/packages/bundled-features/src/tenant/handlers/add-member.write.ts +1 -2
  224. package/packages/bundled-features/src/tenant/handlers/cancel-invitation.write.ts +1 -1
  225. package/packages/bundled-features/src/tenant/handlers/invitations.query.ts +1 -1
  226. package/packages/bundled-features/src/tenant/handlers/me.query.ts +1 -1
  227. package/packages/bundled-features/src/tenant/handlers/member-directory.query.ts +1 -1
  228. package/packages/bundled-features/src/tenant/handlers/members.query.ts +1 -1
  229. package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
  230. package/packages/bundled-features/src/tenant/handlers/remove-member.write.ts +2 -1
  231. package/packages/bundled-features/src/tenant/handlers/resolve-user-ids.query.ts +1 -1
  232. package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +1 -1
  233. package/packages/bundled-features/src/tenant/handlers/tenant-directory.query.ts +1 -1
  234. package/packages/bundled-features/src/tenant/handlers/update-member-roles.write.ts +1 -2
  235. package/packages/bundled-features/src/tenant/invited-membership.ts +2 -2
  236. package/packages/bundled-features/src/tenant/last-tenant-admin.ts +1 -2
  237. package/packages/bundled-features/src/tenant/seeding.ts +12 -12
  238. package/packages/bundled-features/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +1 -2
  239. package/packages/bundled-features/src/tenant-lifecycle/handlers/request-destruction.write.ts +1 -2
  240. package/packages/bundled-features/src/tenant-lifecycle/lib/revoke-tenant-sessions.ts +1 -1
  241. package/packages/bundled-features/src/tenant-lifecycle/lifecycle-gate.ts +1 -1
  242. package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +3 -3
  243. package/packages/bundled-features/src/tenant-lifecycle/stages.ts +10 -5
  244. package/packages/bundled-features/src/tenant-lifecycle/testing.ts +3 -3
  245. package/packages/bundled-features/src/tenant-settings/feature.ts +34 -29
  246. package/packages/bundled-features/src/tier-engine/feature.ts +426 -428
  247. package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +2 -3
  248. package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +5 -2
  249. package/packages/bundled-features/src/user/changes.json +6 -0
  250. package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +1 -1
  251. package/packages/bundled-features/src/user/handlers/create.write.ts +1 -2
  252. package/packages/bundled-features/src/user/handlers/find-for-auth.query.ts +1 -1
  253. package/packages/bundled-features/src/user/handlers/list.query.ts +1 -1
  254. package/packages/bundled-features/src/user/handlers/update-roles.ts +2 -1
  255. package/packages/bundled-features/src/user/index.ts +5 -1
  256. package/packages/bundled-features/src/user/invited-global-roles.ts +2 -2
  257. package/packages/bundled-features/src/user/principal-status.ts +13 -3
  258. package/packages/bundled-features/src/user/resolve-display-names.ts +1 -1
  259. package/packages/bundled-features/src/user/seeding.ts +5 -5
  260. package/packages/bundled-features/src/user-data-rights/audit-download.ts +2 -2
  261. package/packages/bundled-features/src/user-data-rights/changes.json +6 -0
  262. package/packages/bundled-features/src/user-data-rights/db/queries/export-jobs.ts +1 -1
  263. package/packages/bundled-features/src/user-data-rights/db/queries/forget-cleanup.ts +1 -1
  264. package/packages/bundled-features/src/user-data-rights/feature.ts +7 -4
  265. package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +1 -1
  266. package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +1 -1
  267. package/packages/bundled-features/src/user-data-rights/handlers/export-status.query.ts +1 -1
  268. package/packages/bundled-features/src/user-data-rights/handlers/list-download-attempts.query.ts +1 -1
  269. package/packages/bundled-features/src/user-data-rights/handlers/my-audit-log.query.ts +1 -1
  270. package/packages/bundled-features/src/user-data-rights/handlers/request-export.write.ts +1 -2
  271. package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +3 -3
  272. package/packages/bundled-features/src/user-data-rights/lib/default-mailers.ts +40 -3
  273. package/packages/bundled-features/src/user-data-rights/lib/deny-if-target-outside-admin-tenant.ts +1 -1
  274. package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +7 -2
  275. package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +7 -3
  276. package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +11 -5
  277. package/packages/bundled-features/src/user-data-rights/run-user-export.ts +10 -5
  278. package/packages/bundled-features/src/waitlist/handlers/invite.write.ts +1 -2
  279. package/packages/bundled-features/src/waitlist/handlers/reject.write.ts +1 -1
  280. package/packages/bundled-features/src/waitlist/lib.ts +5 -2
  281. package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +1 -1
  282. package/packages/bundled-features/src/workflow-runner/feature.ts +58 -47
  283. package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +1 -1
  284. package/packages/bundled-features/src/workflow-runner/index.ts +1 -1
  285. package/packages/bundled-features/src/workflow-runner/pending-projection.ts +1 -1
  286. package/samples/apps/admin-console/src/run-config.ts +2 -2
  287. package/samples/apps/cap-billing-demo/package.json +3 -0
  288. package/samples/apps/cap-billing-demo/src/feature.ts +2 -2
  289. package/samples/apps/cap-billing-demo/src/run-config.ts +8 -8
  290. package/samples/apps/marketing-demo/src/app/seed.ts +1 -1
  291. package/samples/apps/marketing-demo/src/db/queries/seed-counts.ts +1 -1
  292. package/samples/apps/showcase/package.json +3 -0
  293. package/samples/apps/showcase/src/app/seed-items.ts +1 -1
  294. package/samples/apps/styleguide/src/app/seed.ts +2 -2
  295. package/samples/apps/styleguide/src/features/ai-settings/seed.ts +2 -2
  296. package/samples/apps/ui-walkthrough/scripts/emit-e2e-data.ts +1 -1
  297. package/samples/apps/ui-walkthrough/src/app/auth-constants.ts +1 -1
  298. package/samples/apps/ui-walkthrough/src/app/seed-rental.ts +2 -2
  299. package/samples/apps/ui-walkthrough/src/app/seed-vehicles.ts +1 -1
  300. package/samples/apps/ui-walkthrough/src/app/seed.ts +1 -1
  301. package/samples/apps/ui-walkthrough/src/db/queries/row-counts.ts +1 -1
  302. package/samples/apps/ui-walkthrough/src/db/queries/task-counts.ts +1 -1
  303. package/samples/apps/use-all-bundled/feature-manifest.json +16 -16
  304. package/samples/apps/use-all-bundled/package.json +3 -0
  305. package/samples/apps/use-all-bundled/scripts/check-coverage.ts +2 -2
  306. package/samples/apps/use-all-bundled/src/app/auth-constants.ts +1 -1
  307. package/samples/apps/use-all-bundled/src/app/cap-overview-caps.ts +2 -2
  308. package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +1 -1
  309. package/samples/apps/use-all-bundled/src/app/seed-documents.ts +1 -1
  310. package/samples/apps/use-all-bundled/src/app/seed.ts +11 -5
  311. package/samples/apps/use-all-bundled/src/run-config.ts +55 -56
  312. package/samples/apps/user-data-rights-demo/README.md +2 -2
  313. package/samples/apps/user-data-rights-demo/package.json +3 -0
  314. package/samples/apps/user-data-rights-demo/src/run-config.ts +7 -7
  315. package/samples/apps/workspaces/package.json +3 -0
  316. package/samples/recipes/access-control/package.json +3 -0
  317. package/samples/recipes/anonymous-access/package.json +3 -0
  318. package/samples/recipes/anonymous-access-multitenant/package.json +3 -0
  319. package/samples/recipes/apex-landing/package.json +1 -0
  320. package/samples/recipes/apex-surface-auth/package.json +3 -0
  321. package/samples/recipes/apex-surface-auth/src/feature.ts +2 -2
  322. package/samples/recipes/api-worker-split/package.json +3 -0
  323. package/samples/recipes/api-worker-split/src/feature.ts +1 -2
  324. package/samples/recipes/auth-claims/package.json +3 -0
  325. package/samples/recipes/auth-foundation-providers/src/feature.ts +1 -1
  326. package/samples/recipes/auth-mfa/package.json +3 -0
  327. package/samples/recipes/basic-entity/package.json +3 -0
  328. package/samples/recipes/chat-channels/package.json +3 -0
  329. package/samples/recipes/compliance-profiles-demo/package.json +3 -0
  330. package/samples/recipes/cross-feature-events/package.json +3 -1
  331. package/samples/recipes/cross-feature-events/src/feature.ts +1 -1
  332. package/samples/recipes/crypto-shredding-hr/package.json +3 -0
  333. package/samples/recipes/currencies-global/package.json +3 -0
  334. package/samples/recipes/currencies-per-tenant/package.json +3 -0
  335. package/samples/recipes/custom-fields-basic/package.json +3 -0
  336. package/samples/recipes/custom-handlers/package.json +3 -0
  337. package/samples/recipes/dashboard-stats/package.json +3 -0
  338. package/samples/recipes/delivery-notifications/package.json +3 -0
  339. package/samples/recipes/e2e-generator/package.json +3 -0
  340. package/samples/recipes/embedded/package.json +3 -0
  341. package/samples/recipes/embedded-entity-form/package.json +1 -0
  342. package/samples/recipes/encrypted-tenant-config/README.md +1 -1
  343. package/samples/recipes/encrypted-tenant-config/package.json +3 -0
  344. package/samples/recipes/error-contract/package.json +3 -0
  345. package/samples/recipes/event-sourcing/package.json +3 -1
  346. package/samples/recipes/event-sourcing/src/feature.ts +16 -20
  347. package/samples/recipes/event-sourcing/tsconfig.json +2 -6
  348. package/samples/recipes/feature-toggles/package.json +3 -0
  349. package/samples/recipes/field-access/package.json +3 -0
  350. package/samples/recipes/files-post-processing/package.json +1 -0
  351. package/samples/recipes/golden-path/README.md +30 -0
  352. package/samples/recipes/golden-path/package.json +11 -0
  353. package/samples/recipes/golden-path/src/feature.ts +70 -0
  354. package/samples/recipes/idempotency/package.json +3 -0
  355. package/samples/recipes/inbound-mail-triage/package.json +3 -0
  356. package/samples/recipes/lane-routing/package.json +3 -0
  357. package/samples/recipes/ledger-banking/package.json +3 -0
  358. package/samples/recipes/ledger-invoicing/package.json +3 -0
  359. package/samples/recipes/legal-pages/package.json +3 -0
  360. package/samples/recipes/lifecycle-hooks/package.json +3 -0
  361. package/samples/recipes/managed-config/package.json +3 -0
  362. package/samples/recipes/managed-pages/package.json +3 -0
  363. package/samples/recipes/notes-history-basic/package.json +3 -0
  364. package/samples/recipes/ownership/package.json +3 -0
  365. package/samples/recipes/pdf-audit-export/package.json +1 -0
  366. package/samples/recipes/pipeline-basics/package.json +3 -0
  367. package/samples/recipes/public-share-token/package.json +3 -0
  368. package/samples/recipes/public-share-token/src/feature.ts +1 -1
  369. package/samples/recipes/rate-limiting/package.json +3 -0
  370. package/samples/recipes/realtime-sse/package.json +3 -0
  371. package/samples/recipes/record-detail-layout/package.json +1 -0
  372. package/samples/recipes/reference-data/package.json +3 -0
  373. package/samples/recipes/relations/package.json +3 -0
  374. package/samples/recipes/screens-nav/package.json +3 -0
  375. package/samples/recipes/search/package.json +3 -0
  376. package/samples/recipes/secrets-demo/package.json +3 -0
  377. package/samples/recipes/security-baseline/src/feature.ts +2 -2
  378. package/samples/recipes/session-revocation/README.md +1 -1
  379. package/samples/recipes/session-revocation/package.json +3 -0
  380. package/samples/recipes/session-revocation/src/feature.ts +1 -1
  381. package/samples/recipes/state-machine/package.json +3 -1
  382. package/samples/recipes/state-machine/src/entities/invoice.ts +2 -2
  383. package/samples/recipes/state-machine/src/events.ts +19 -0
  384. package/samples/recipes/state-machine/src/feature.ts +25 -30
  385. package/samples/recipes/state-machine/src/handlers/_helpers.ts +13 -14
  386. package/samples/recipes/state-machine/src/handlers/create.ts +1 -1
  387. package/samples/recipes/state-machine/src/handlers/transitions.ts +129 -122
  388. package/samples/recipes/state-machine/src/reducer.ts +1 -1
  389. package/samples/recipes/state-machine/tsconfig.json +2 -6
  390. package/samples/recipes/tags-basic/package.json +3 -0
  391. package/samples/recipes/tenant-isolation/package.json +3 -0
  392. package/samples/recipes/tenant-settings/package.json +3 -0
  393. package/samples/recipes/tier-admin/package.json +3 -0
  394. package/samples/recipes/timezones/package.json +3 -0
  395. package/samples/recipes/tsconfig.base.json +1 -1
  396. package/samples/recipes/user-data-rights/package.json +3 -0
  397. package/samples/recipes/user-data-rights/src/feature.ts +6 -2
  398. package/samples/recipes/user-profile/package.json +3 -0
  399. package/samples/recipes/user-profile/src/feature.ts +2 -2
  400. package/samples/recipes/webhook-step/package.json +3 -0
  401. package/samples/recipes/wizard-form/package.json +1 -0
  402. package/samples/recipes/workflow-engine/package.json +3 -0
  403. package/samples/recipes/workflow-engine/src/db/queries/suspended-runs.ts +5 -2
  404. package/samples/recipes/writeform-section/package.json +1 -0
  405. package/packages/bundled-features/src/file-provider-s3-env/feature.ts +0 -58
  406. /package/packages/bundled-features/src/{files-provider-s3 → file-provider-s3/lib}/env-helper.ts +0 -0
@@ -121,108 +121,117 @@ async function requestIngestForFileRef(
121
121
  });
122
122
  }
123
123
 
124
- export const documentIngestFoundationFeature = defineFeature(FEATURE_NAME, (r) => {
125
- r.describe(
126
- "Shared PDF/Scan/Image → normalized-text ingest primitive. Owns the `documentExtract` entity (fileRefId, storageKey, per-page text + metadata) as an implicit entity-projection, the per-tenant `ocrLanguage`/`maxPagesPerFile` config keys, the `documentIngestProvider` extension-point providers register accepted mimeTypes/size caps under, and a fileRef.created/fileRef.restored trigger that resolves the provider for a file's mimeType and requests ingest via `documentIngest.requested` tagged with the winning provider — a delete→restore round-trip re-requests ingest the same way a fresh upload does. An orphan-extract guard forgets any `documentExtract` whose fileRef is no longer live at processing time, regardless of how a provider's own write races the fileRef's delete/forget — providers should write through `writeDocumentExtractForLiveFileRef`.",
127
- );
128
- r.uiHints({
129
- displayLabel: "Document Ingest Foundation",
130
- category: "storage",
131
- recommended: false,
132
- });
133
- // tenant-lifecycle hosts EXT_TENANT_DATA — documentExtract.pages is
134
- // tenant-subject ciphertext and needs the destroy hook below.
135
- r.requires({ features: ["config", "tenant-lifecycle"] });
136
-
137
- r.entity({ name: "documentExtract", ...documentExtractEntity });
138
- r.useExtension(EXT_TENANT_DATA, "documentExtract", {
139
- destroy: documentExtractTenantDestroyHook,
140
- });
141
-
142
- // No onRegister: resolution happens at boot and per-apply, not on register.
143
- r.extendsRegistrar(EXT_DOCUMENT_INGEST_PROVIDER, {});
144
- r.bootCheck(({ features }) => validateDocumentIngestProviderWiring(features));
145
-
146
- const ocrLanguageConfigKey = r.config(
147
- "ocrLanguage",
148
- createTenantConfig("text", {
149
- default: "deu+eng",
150
- // Tesseract -l argument syntax: one or more 3-letter language codes
151
- // joined by "+" (e.g. "deu+eng"). Unconstrained free text here would
152
- // reach the OCR provider call unvalidated (#1501).
153
- pattern: { regex: "^[a-z]{3}(\\+[a-z]{3})*$" },
154
- write: access.roles("TenantAdmin", "SystemAdmin"),
155
- read: access.roles("TenantAdmin", "SystemAdmin", "User"),
156
- }),
157
- );
158
- const maxPagesPerFileConfigKey = r.config(
159
- "maxPagesPerFile",
160
- createTenantConfig("number", {
161
- default: 50,
162
- // Without a bound a tenant could set 0 (silently kills ingest) or an
163
- // unbounded value (OCR worker runs per-file for as long as the PDF
164
- // has pages — job-queue starvation) (#1501).
165
- bounds: { min: 1, max: 500 },
166
- write: access.roles("TenantAdmin", "SystemAdmin"),
167
- read: access.roles("TenantAdmin", "SystemAdmin", "User"),
168
- }),
169
- );
170
-
171
- // "fileName" can carry a real person's name, but it reaches both events already as the
172
- // fileRef's own self-subject ciphertext (copied from fileRef.created/restored), which
173
- // append() passes through; shredding the fileRef's key shreds it here too.
174
- r.defineEvent(DOCUMENT_INGEST_REQUESTED_EVENT_SHORT, documentIngestRequestedPayloadSchema, {
175
- piiFields: "none",
176
- version: 2,
177
- migrations: [
178
- {
179
- fromVersion: 1,
180
- toVersion: 2,
181
- // The sentinel can never match a real where.provider filter (providers
182
- // may not register under it) — an upcast v1 row reads as unclaimed
183
- // instead of silently misrouting to a currently mounted provider.
184
- transform: { default: { provider: UNCLAIMED_PROVIDER_SENTINEL } },
185
- },
186
- ],
187
- });
188
- r.defineEvent(DOCUMENT_INGEST_SKIPPED_EVENT_SHORT, documentIngestSkippedPayloadSchema, {
189
- piiFields: "none",
190
- });
191
-
192
- r.multiStreamProjection({
193
- name: "request-ingest",
194
- apply: {
195
- [FILE_REF_CREATED]: async (event, _tx, ctx) => {
196
- // entity-event payloads are generic Record<string, unknown> — parse
197
- // at the MSP boundary (same pattern as storage-tracking's readNumber).
198
- const parsed = fileRefIngestFieldsSchema.safeParse(event.payload);
199
- // skip: malformed / incomplete payload — don't poison the consumer
200
- if (!parsed.success) return;
201
- await requestIngestForFileRef(event, parsed.data, ctx);
202
- },
203
- [FILE_REF_RESTORED]: async (event, _tx, ctx) => {
204
- // fileRef.restored carries { previous }, the pre-restore soft-deleted
205
- // row (event-store-executor-write.ts restore()) — same field shape
206
- // as fileRef.created's payload.
207
- const parsed = fileRefIngestFieldsSchema.safeParse(event.payload["previous"]);
208
- // skip: malformed / incomplete previous snapshot — don't poison the consumer
209
- if (!parsed.success) return;
210
- await requestIngestForFileRef(event, parsed.data, ctx);
211
- },
212
- },
213
- });
214
-
215
- // fileRef delete/forget cleanup: documentExtract rows are derived data —
216
- // once the source file is gone (soft-deleted or Art.17-forgotten), the
217
- // extracted text has no reason to survive it either.
218
- r.multiStreamProjection({
219
- name: "forget-extract-with-file-ref",
220
- apply: {
221
- [FILE_REF_DELETED]: forgetExtractOnFileRefDeletedHook,
222
- [FILE_REF_FORGOTTEN]: forgetExtractOnFileRefForgottenHook,
223
- [DOCUMENT_EXTRACT_CREATED]: forgetOrphanedDocumentExtractHook,
124
+ export function createDocumentIngestFoundationFeature() {
125
+ return defineFeature(
126
+ FEATURE_NAME,
127
+ (r) => {
128
+ r.describe(
129
+ "Shared PDF/Scan/Image → normalized-text ingest primitive. Owns the `documentExtract` entity (fileRefId, storageKey, per-page text + metadata) as an implicit entity-projection, the per-tenant `ocrLanguage`/`maxPagesPerFile` config keys, the `documentIngestProvider` extension-point providers register accepted mimeTypes/size caps under, and a fileRef.created/fileRef.restored trigger that resolves the provider for a file's mimeType and requests ingest via `documentIngest.requested` tagged with the winning provider — a delete→restore round-trip re-requests ingest the same way a fresh upload does. An orphan-extract guard forgets any `documentExtract` whose fileRef is no longer live at processing time, regardless of how a provider's own write races the fileRef's delete/forget — providers should write through `writeDocumentExtractForLiveFileRef`.",
130
+ );
131
+ r.uiHints({
132
+ displayLabel: "Document Ingest Foundation",
133
+ category: "storage",
134
+ recommended: false,
135
+ });
136
+ // tenant-lifecycle hosts EXT_TENANT_DATA — documentExtract.pages is
137
+ // tenant-subject ciphertext and needs the destroy hook below.
138
+ r.requires({ features: ["config", "tenant-lifecycle"] });
139
+
140
+ r.entity({ name: "documentExtract", ...documentExtractEntity });
141
+ r.useExtension(EXT_TENANT_DATA, "documentExtract", {
142
+ destroy: documentExtractTenantDestroyHook,
143
+ });
144
+
145
+ // No onRegister: resolution happens at boot and per-apply, not on register.
146
+ r.extendsRegistrar(EXT_DOCUMENT_INGEST_PROVIDER, {});
147
+ r.bootCheck(({ features }) => validateDocumentIngestProviderWiring(features));
148
+
149
+ const ocrLanguageConfigKey = r.config(
150
+ "ocrLanguage",
151
+ createTenantConfig("text", {
152
+ default: "deu+eng",
153
+ // Tesseract -l argument syntax: one or more 3-letter language codes
154
+ // joined by "+" (e.g. "deu+eng"). Unconstrained free text here would
155
+ // reach the OCR provider call unvalidated (#1501).
156
+ pattern: { regex: "^[a-z]{3}(\\+[a-z]{3})*$" },
157
+ write: access.roles("TenantAdmin", "SystemAdmin"),
158
+ read: access.roles("TenantAdmin", "SystemAdmin", "User"),
159
+ }),
160
+ );
161
+ const maxPagesPerFileConfigKey = r.config(
162
+ "maxPagesPerFile",
163
+ createTenantConfig("number", {
164
+ default: 50,
165
+ // Without a bound a tenant could set 0 (silently kills ingest) or an
166
+ // unbounded value (OCR worker runs per-file for as long as the PDF
167
+ // has pages — job-queue starvation) (#1501).
168
+ bounds: { min: 1, max: 500 },
169
+ write: access.roles("TenantAdmin", "SystemAdmin"),
170
+ read: access.roles("TenantAdmin", "SystemAdmin", "User"),
171
+ }),
172
+ );
173
+
174
+ // "fileName" can carry a real person's name, but it reaches both events already as the
175
+ // fileRef's own self-subject ciphertext (copied from fileRef.created/restored), which
176
+ // append() passes through; shredding the fileRef's key shreds it here too.
177
+ r.defineEvent(DOCUMENT_INGEST_REQUESTED_EVENT_SHORT, documentIngestRequestedPayloadSchema, {
178
+ piiFields: "none",
179
+ version: 2,
180
+ migrations: [
181
+ {
182
+ fromVersion: 1,
183
+ toVersion: 2,
184
+ // The sentinel can never match a real where.provider filter (providers
185
+ // may not register under it) — an upcast v1 row reads as unclaimed
186
+ // instead of silently misrouting to a currently mounted provider.
187
+ transform: { default: { provider: UNCLAIMED_PROVIDER_SENTINEL } },
188
+ },
189
+ ],
190
+ });
191
+ r.defineEvent(DOCUMENT_INGEST_SKIPPED_EVENT_SHORT, documentIngestSkippedPayloadSchema, {
192
+ piiFields: "none",
193
+ });
194
+
195
+ r.multiStreamProjection({
196
+ name: "request-ingest",
197
+ apply: {
198
+ [FILE_REF_CREATED]: async (event, _tx, ctx) => {
199
+ // entity-event payloads are generic Record<string, unknown> — parse
200
+ // at the MSP boundary (same pattern as storage-tracking's readNumber).
201
+ const parsed = fileRefIngestFieldsSchema.safeParse(event.payload);
202
+ // skip: malformed / incomplete payload — don't poison the consumer
203
+ if (!parsed.success) return;
204
+ await requestIngestForFileRef(event, parsed.data, ctx);
205
+ },
206
+ [FILE_REF_RESTORED]: async (event, _tx, ctx) => {
207
+ // fileRef.restored carries { previous }, the pre-restore soft-deleted
208
+ // row (event-store-executor-write.ts restore()) — same field shape
209
+ // as fileRef.created's payload.
210
+ const parsed = fileRefIngestFieldsSchema.safeParse(event.payload["previous"]);
211
+ // skip: malformed / incomplete previous snapshot — don't poison the consumer
212
+ if (!parsed.success) return;
213
+ await requestIngestForFileRef(event, parsed.data, ctx);
214
+ },
215
+ },
216
+ });
217
+
218
+ // fileRef delete/forget cleanup: documentExtract rows are derived data —
219
+ // once the source file is gone (soft-deleted or Art.17-forgotten), the
220
+ // extracted text has no reason to survive it either.
221
+ r.multiStreamProjection({
222
+ name: "forget-extract-with-file-ref",
223
+ apply: {
224
+ [FILE_REF_DELETED]: forgetExtractOnFileRefDeletedHook,
225
+ [FILE_REF_FORGOTTEN]: forgetExtractOnFileRefForgottenHook,
226
+ [DOCUMENT_EXTRACT_CREATED]: forgetOrphanedDocumentExtractHook,
227
+ },
228
+ });
229
+
230
+ return { ocrLanguageConfigKey, maxPagesPerFileConfigKey };
224
231
  },
225
- });
232
+ { dedupeOptions: {} },
233
+ );
234
+ }
226
235
 
227
- return { ocrLanguageConfigKey, maxPagesPerFileConfigKey };
228
- });
236
+ /** @deprecated Use createDocumentIngestFoundationFeature(). Run `bun kumiko-upgrade --apply`. Removed in the first release after 2026-10-29. */
237
+ export const documentIngestFoundationFeature = createDocumentIngestFoundationFeature();
@@ -57,7 +57,7 @@ export const forgetOrphanedDocumentExtractHook: MultiStreamApplyFn = async (even
57
57
  const parsed = documentExtractCreatedPayloadSchema.safeParse(event.payload);
58
58
  // skip: malformed payload — don't poison the consumer
59
59
  if (!parsed.success) return;
60
- const tenantDb = createTenantDb(tx, event.tenantId);
60
+ const tenantDb = createTenantDb({ db: tx, tenantId: event.tenantId });
61
61
  // skip: fileRef still live — the extract is legitimate
62
62
  if (await isFileRefLive(tenantDb, parsed.data.fileRefId)) return;
63
63
  const user = createSystemUser(event.tenantId);
@@ -70,7 +70,7 @@ export const forgetOrphanedDocumentExtractHook: MultiStreamApplyFn = async (even
70
70
  };
71
71
 
72
72
  export const forgetExtractOnFileRefDeletedHook: MultiStreamApplyFn = async (event, tx) => {
73
- const tenantDb = createTenantDb(tx, event.tenantId);
73
+ const tenantDb = createTenantDb({ db: tx, tenantId: event.tenantId });
74
74
  // skip: fileRef is live again — request-ingest and this consumer poll via
75
75
  // separate cursors, so a delete→restore round-trip can finish before this
76
76
  // consumer sees fileRef.deleted; forgetting would drop the live file's extract.
@@ -79,6 +79,6 @@ export const forgetExtractOnFileRefDeletedHook: MultiStreamApplyFn = async (even
79
79
  };
80
80
 
81
81
  export const forgetExtractOnFileRefForgottenHook: MultiStreamApplyFn = async (event, tx) => {
82
- const tenantDb = createTenantDb(tx, event.tenantId);
82
+ const tenantDb = createTenantDb({ db: tx, tenantId: event.tenantId });
83
83
  await forgetExtractsForFileRef(event, tenantDb);
84
84
  };
@@ -18,7 +18,10 @@ export {
18
18
  documentIngestRequestedPayloadSchema,
19
19
  documentIngestSkippedPayloadSchema,
20
20
  } from "./events.js";
21
- export { documentIngestFoundationFeature } from "./feature.js";
21
+ export {
22
+ createDocumentIngestFoundationFeature,
23
+ documentIngestFoundationFeature,
24
+ } from "./feature.js";
22
25
  export { readIngestPages, writeIngestPages } from "./pages.js";
23
26
  export {
24
27
  type DocumentIngestProviderOptions,
@@ -1,4 +1,3 @@
1
- import { requireEntityTableMeta } from "@cosmicdrift/kumiko-framework/bun-db";
2
1
  import {
3
2
  boolean,
4
3
  declareGlobalTenancy,
@@ -6,6 +5,7 @@ import {
6
5
  instant,
7
6
  integer,
8
7
  table as pgTable,
8
+ requireEntityTableMeta,
9
9
  type SchemaTable,
10
10
  sql,
11
11
  text,
@@ -1,4 +1,4 @@
1
- import { insertOne, selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { insertOne, selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineWriteHandler, SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import {
4
4
  UnprocessableError,
@@ -158,10 +158,8 @@ export function createSetWriteHandler(getRuntime: (() => GlobalFeatureToggleRunt
158
158
  // and filtering by payload.featureName is trivial at query time.
159
159
  // This mirrors how `config` handles the same constraint for
160
160
  // its config-changed events.
161
- // unsafeAppendEvent — bundled-features ohne lokalen Wrapper. Apps
162
- // mit `bun kumiko codegen` kriegen `.kumiko/define.ts` als strict-
163
- // path; bundled-features bleibt bei der unsafe-Variante. Schema-
164
- // Validation läuft trotzdem via r.defineEvent("toggle-set", ...).
161
+ // unsafeAppendEvent: the strict appendEvent is bound to an app's own event map, which
162
+ // bundled-features cannot see. Schema validation still runs via r.defineEvent("toggle-set", ...).
165
163
  await ctx.unsafeAppendEvent({
166
164
  aggregateId: SYSTEM_TENANT_ID,
167
165
  aggregateType: FEATURE_TOGGLE_AGGREGATE_TYPE,
@@ -1,5 +1,5 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
1
  import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
2
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
3
3
  import {
4
4
  computeEffectiveFeatures,
5
5
  type Registry,
@@ -100,137 +100,142 @@ export function createFileDerivativesFeature(opts: FileDerivativesOptions = {}):
100
100
  );
101
101
  }
102
102
 
103
- return defineFeature(FEATURE_NAME, (r) => {
104
- r.describe(
105
- "Declares the `derivativeRenderer` extension point. `ctx.derivatives.variant(fileRefId, spec, name)` derives a variant of a tracked FileRef the first time it's requested and reuses the stored result afterwards (derive-on-first-use, keyed by a hash of the spec). Mount at least one `derivatives-*` renderer feature alongside this one — without a registered renderer for the FileRef's MIME type, every `variant(...)` call throws. Also declares the `derivativePublicPredicate` extension point (`r.useExtension(EXT_DERIVATIVE_PUBLIC_PREDICATE, '<entityType>', { isPublic })`) and, when `createFileDerivativesFeature({resolveApexTenant})` is passed a host-resolver, mounts an anonymous `GET {basePath}/:fileRefId/:variant` route that serves any variant name the FileRef's field declared in its `variants` for a FileRef whose entityType has a registered predicate returning true — default-deny (404) otherwise, same as an unknown FileRef or an undeclared variant name. The route's only rate-limit (`per: \"ip\"`) depends on the server's `trustedProxyHops` matching the deployment's actual reverse-proxy count — at the default 0 it ignores `x-forwarded-for` entirely, so every caller shares one bucket until that's configured. `publicTenantResolution: \"fileRef\"` keeps resolveApexTenant as the host gate but reads the variant from the FileRef row's own tenant instead of the host's, so one shared platform host serves every tenant's public variants — each FileRef-tenant's own `isPublic` predicate still default-denies. Also declares the `derivativeOverlayResolver` extension point (`r.useExtension(EXT_DERIVATIVE_OVERLAY_RESOLVER, '<entityType>', { resolve })`), used to turn a variant's `overlays[].dataToken` into the actual QR payload for that FileRef's entityType before the variant is rendered — a variant declaring a `qr` overlay throws at request-time if no resolver is registered for the FileRef's entityType.",
106
- );
107
- r.uiHints({
108
- displayLabel: "File Derivatives",
109
- category: "storage",
110
- recommended: false,
111
- });
112
- // Needs a storage provider to read the original + write the variant —
113
- // without file-foundation there's nothing to derive from or write to.
114
- r.requires({ features: ["file-foundation"] });
115
- // variant() reads fileRefsTable, which "files" (not file-foundation)
116
- // owns — without this, mounting file-derivatives + file-foundation
117
- // alone boots fine but fails at request-time with a SQL error the first
118
- // time variant() runs.
119
- r.requires({ features: ["files"] });
120
-
121
- r.extendsRegistrar(EXT_DERIVATIVE_RENDERER, {
122
- onRegister: () => {
123
- // No side-effects at register-time — resolution (exact MIME match,
124
- // then `<type>/*` wildcard) happens at request-time in
125
- // resolveRenderer, mirrors file-foundation's fileProvider point.
126
- },
127
- });
128
- r.extendsRegistrar(EXT_DERIVATIVE_PUBLIC_PREDICATE, {
129
- onRegister: () => {
130
- // No side-effects at register-time — resolution happens at
131
- // request-time in publicVariantQuery, keyed by the FileRef's
132
- // entityType.
133
- },
134
- });
135
- r.extendsRegistrar(EXT_DERIVATIVE_OVERLAY_RESOLVER, {
136
- onRegister: () => {
137
- // No side-effects at register-time — resolution happens in
138
- // variant(), keyed by the FileRef's entityType, before the spec
139
- // hash is computed.
140
- },
141
- });
142
-
143
- // Registered ONLY when resolveApexTenant is supplied — r.queryHandler
144
- // registers publicVariantQuery into the feature's dispatch table as a
145
- // side effect of being called, independent of what's done with its
146
- // return value. Calling it unconditionally would make `publicVariant`
147
- // (access: ["anonymous", ...]) reachable via the generic `/api` query
148
- // dispatch even when the httpRoute below isn't mounted, bypassing the
149
- // "tenantId comes from the host, never the payload" invariant that only
150
- // `resolveApexTenant` enforces.
151
- if (opts.resolveApexTenant) {
152
- const resolveApexTenant = opts.resolveApexTenant;
153
- const byFileRef = opts.publicTenantResolution === "fileRef";
154
- const routeQn = byFileRef ? PUBLIC_VARIANT_BY_FILE_REF_QN : PUBLIC_VARIANT_QN;
155
-
156
- r.queryHandler(publicVariantQuery);
157
- // publicVariantByFileRefQuery is the ONLY way "fileRef" mode is
158
- // reachable — registered ONLY in that mode for the same reason
159
- // publicVariantQuery is gated above: registering it unconditionally
160
- // would expose its unsafeRaw, cross-tenant FileRef lookup via the
161
- // generic `/api` query dispatch even in default "host" mode.
162
- if (byFileRef) {
163
- // The handler reads the FileRef-tenant's row to keep a blocked
164
- // tenant's public variants from staying reachable — require the
165
- // dependency so a missing mount fails boot, not the tenant check
166
- // silently no-op-ing at request time.
167
- r.requires({ features: ["tenant"] });
168
- r.queryHandler(publicVariantByFileRefQuery);
169
- }
170
-
171
- r.httpRoute({
172
- method: "GET",
173
- path: `${basePath}/:fileRefId/:variant`,
174
- anonymous: true,
175
- handler: async (c, { systemQuery }) => {
176
- // `param(...)` is string|undefined here — `path` is a computed
177
- // template, so Hono can't infer the param type from a literal.
178
- const fileRefId = c.req.param("fileRefId");
179
- const variant = c.req.param("variant");
180
- // 404, not 400 — a syntactically bad name and "doesn't exist" must
181
- // answer identically, no name-oracle. fileRefsTable.id is a UUID
182
- // column — a malformed id must fail here, not at the DB. Without
183
- // this, an anonymous, internet-facing caller can throw a Postgres
184
- // 22P02 on every request (Bun.SQL pools the failed connection), a
185
- // DoS primitive with no auth required.
186
- if (!fileRefId || !variant || !VARIANT_NAME_RE.test(variant) || !isUuid(fileRefId)) {
187
- return c.text("not found", 404);
188
- }
189
-
190
- const host = c.req.header("host") ?? new URL(c.req.url).host;
191
- const tenantId = await resolveApexTenant(host);
192
- if (!tenantId) return c.text("not found", 404);
193
-
194
- let result: PublicVariantQueryResult;
195
- try {
196
- // @cast-boundary engine-payload — shape comes from
197
- // publicVariantQuery's return type (publicVariantByFileRefQuery
198
- // returns exactly that, or null, never its own shape).
199
- result = (await systemQuery(
200
- routeQn,
201
- { fileRefId, variant },
202
- tenantId,
203
- )) as PublicVariantQueryResult;
204
- } catch (err) {
205
- if (err instanceof RateLimitError) {
206
- return c.text("rate limited", 429);
207
- }
208
- // biome-ignore lint/suspicious/noConsole: ops-visible fallback, no logger wired into HttpRouteHandlerDeps
209
- console.error(
210
- `file-derivatives: public-variant query failed for fileRefId="${fileRefId}" variant="${variant}"`,
211
- err,
212
- );
213
- return c.text("variant unavailable", 503);
214
- }
215
- if (!result) return c.text("not found", 404);
216
-
217
- const bytes = Buffer.from(result.dataBase64, "base64");
218
- const etag = computeRevisionEtag([tenantId, fileRefId, variant, result.revision]);
219
- return cachedResponse(c.req.raw, {
220
- body: bytes,
221
- etag,
222
- cache: { kind: "revalidate", maxAgeSeconds: 60 },
223
- // Explicit here, not left to the app-wide security-headers default, so the route stays safe standalone.
224
- headers: {
225
- "content-type": result.mimeType,
226
- vary: "Host",
227
- "x-content-type-options": "nosniff",
228
- },
229
- });
103
+ return defineFeature(
104
+ FEATURE_NAME,
105
+ (r) => {
106
+ r.describe(
107
+ "Declares the `derivativeRenderer` extension point. `ctx.derivatives.variant(fileRefId, spec, name)` derives a variant of a tracked FileRef the first time it's requested and reuses the stored result afterwards (derive-on-first-use, keyed by a hash of the spec). Mount at least one `derivatives-*` renderer feature alongside this one — without a registered renderer for the FileRef's MIME type, every `variant(...)` call throws. Also declares the `derivativePublicPredicate` extension point (`r.useExtension(EXT_DERIVATIVE_PUBLIC_PREDICATE, '<entityType>', { isPublic })`) and, when `createFileDerivativesFeature({resolveApexTenant})` is passed a host-resolver, mounts an anonymous `GET {basePath}/:fileRefId/:variant` route that serves any variant name the FileRef's field declared in its `variants` for a FileRef whose entityType has a registered predicate returning true — default-deny (404) otherwise, same as an unknown FileRef or an undeclared variant name. The route's only rate-limit (`per: \"ip\"`) depends on the server's `trustedProxyHops` matching the deployment's actual reverse-proxy count — at the default 0 it ignores `x-forwarded-for` entirely, so every caller shares one bucket until that's configured. `publicTenantResolution: \"fileRef\"` keeps resolveApexTenant as the host gate but reads the variant from the FileRef row's own tenant instead of the host's, so one shared platform host serves every tenant's public variants — each FileRef-tenant's own `isPublic` predicate still default-denies. Also declares the `derivativeOverlayResolver` extension point (`r.useExtension(EXT_DERIVATIVE_OVERLAY_RESOLVER, '<entityType>', { resolve })`), used to turn a variant's `overlays[].dataToken` into the actual QR payload for that FileRef's entityType before the variant is rendered — a variant declaring a `qr` overlay throws at request-time if no resolver is registered for the FileRef's entityType.",
108
+ );
109
+ r.uiHints({
110
+ displayLabel: "File Derivatives",
111
+ category: "storage",
112
+ recommended: false,
113
+ });
114
+ // Needs a storage provider to read the original + write the variant —
115
+ // without file-foundation there's nothing to derive from or write to.
116
+ r.requires({ features: ["file-foundation"] });
117
+ // variant() reads fileRefsTable, which "files" (not file-foundation)
118
+ // owns — without this, mounting file-derivatives + file-foundation
119
+ // alone boots fine but fails at request-time with a SQL error the first
120
+ // time variant() runs.
121
+ r.requires({ features: ["files"] });
122
+
123
+ r.extendsRegistrar(EXT_DERIVATIVE_RENDERER, {
124
+ onRegister: () => {
125
+ // No side-effects at register-time — resolution (exact MIME match,
126
+ // then `<type>/*` wildcard) happens at request-time in
127
+ // resolveRenderer, mirrors file-foundation's fileProvider point.
128
+ },
129
+ });
130
+ r.extendsRegistrar(EXT_DERIVATIVE_PUBLIC_PREDICATE, {
131
+ onRegister: () => {
132
+ // No side-effects at register-time — resolution happens at
133
+ // request-time in publicVariantQuery, keyed by the FileRef's
134
+ // entityType.
230
135
  },
231
136
  });
232
- }
233
- });
137
+ r.extendsRegistrar(EXT_DERIVATIVE_OVERLAY_RESOLVER, {
138
+ onRegister: () => {
139
+ // No side-effects at register-time — resolution happens in
140
+ // variant(), keyed by the FileRef's entityType, before the spec
141
+ // hash is computed.
142
+ },
143
+ });
144
+
145
+ // Registered ONLY when resolveApexTenant is supplied — r.queryHandler
146
+ // registers publicVariantQuery into the feature's dispatch table as a
147
+ // side effect of being called, independent of what's done with its
148
+ // return value. Calling it unconditionally would make `publicVariant`
149
+ // (access: ["anonymous", ...]) reachable via the generic `/api` query
150
+ // dispatch even when the httpRoute below isn't mounted, bypassing the
151
+ // "tenantId comes from the host, never the payload" invariant that only
152
+ // `resolveApexTenant` enforces.
153
+ if (opts.resolveApexTenant) {
154
+ const resolveApexTenant = opts.resolveApexTenant;
155
+ const byFileRef = opts.publicTenantResolution === "fileRef";
156
+ const routeQn = byFileRef ? PUBLIC_VARIANT_BY_FILE_REF_QN : PUBLIC_VARIANT_QN;
157
+
158
+ r.queryHandler(publicVariantQuery);
159
+ // publicVariantByFileRefQuery is the ONLY way "fileRef" mode is
160
+ // reachable — registered ONLY in that mode for the same reason
161
+ // publicVariantQuery is gated above: registering it unconditionally
162
+ // would expose its unsafeRaw, cross-tenant FileRef lookup via the
163
+ // generic `/api` query dispatch even in default "host" mode.
164
+ if (byFileRef) {
165
+ // The handler reads the FileRef-tenant's row to keep a blocked
166
+ // tenant's public variants from staying reachable — require the
167
+ // dependency so a missing mount fails boot, not the tenant check
168
+ // silently no-op-ing at request time.
169
+ r.requires({ features: ["tenant"] });
170
+ r.queryHandler(publicVariantByFileRefQuery);
171
+ }
172
+
173
+ r.httpRoute({
174
+ method: "GET",
175
+ path: `${basePath}/:fileRefId/:variant`,
176
+ anonymous: true,
177
+ handler: async (c, { systemQuery }) => {
178
+ // `param(...)` is string|undefined here — `path` is a computed
179
+ // template, so Hono can't infer the param type from a literal.
180
+ const fileRefId = c.req.param("fileRefId");
181
+ const variant = c.req.param("variant");
182
+ // 404, not 400 — a syntactically bad name and "doesn't exist" must
183
+ // answer identically, no name-oracle. fileRefsTable.id is a UUID
184
+ // column — a malformed id must fail here, not at the DB. Without
185
+ // this, an anonymous, internet-facing caller can throw a Postgres
186
+ // 22P02 on every request (Bun.SQL pools the failed connection), a
187
+ // DoS primitive with no auth required.
188
+ if (!fileRefId || !variant || !VARIANT_NAME_RE.test(variant) || !isUuid(fileRefId)) {
189
+ return c.text("not found", 404);
190
+ }
191
+
192
+ const host = c.req.header("host") ?? new URL(c.req.url).host;
193
+ const tenantId = await resolveApexTenant(host);
194
+ if (!tenantId) return c.text("not found", 404);
195
+
196
+ let result: PublicVariantQueryResult;
197
+ try {
198
+ // @cast-boundary engine-payload — shape comes from
199
+ // publicVariantQuery's return type (publicVariantByFileRefQuery
200
+ // returns exactly that, or null, never its own shape).
201
+ result = (await systemQuery(
202
+ routeQn,
203
+ { fileRefId, variant },
204
+ tenantId,
205
+ )) as PublicVariantQueryResult;
206
+ } catch (err) {
207
+ if (err instanceof RateLimitError) {
208
+ return c.text("rate limited", 429);
209
+ }
210
+ // biome-ignore lint/suspicious/noConsole: ops-visible fallback, no logger wired into HttpRouteHandlerDeps
211
+ console.error(
212
+ `file-derivatives: public-variant query failed for fileRefId="${fileRefId}" variant="${variant}"`,
213
+ err,
214
+ );
215
+ return c.text("variant unavailable", 503);
216
+ }
217
+ if (!result) return c.text("not found", 404);
218
+
219
+ const bytes = Buffer.from(result.dataBase64, "base64");
220
+ const etag = computeRevisionEtag([tenantId, fileRefId, variant, result.revision]);
221
+ return cachedResponse(c.req.raw, {
222
+ body: bytes,
223
+ etag,
224
+ cache: { kind: "revalidate", maxAgeSeconds: 60 },
225
+ // Explicit here, not left to the app-wide security-headers default, so the route stays safe standalone.
226
+ headers: {
227
+ "content-type": result.mimeType,
228
+ vary: "Host",
229
+ "x-content-type-options": "nosniff",
230
+ },
231
+ });
232
+ },
233
+ });
234
+ }
235
+ },
236
+ Object.keys(opts).length === 0 ? { dedupeOptions: {} } : undefined,
237
+ );
234
238
  }
235
239
 
240
+ /** @deprecated Use createFileDerivativesFeature(). Run `bun kumiko-upgrade --apply`. Removed in the first release after 2026-10-29. */
236
241
  export const fileDerivativesFeature = createFileDerivativesFeature();
@@ -1,4 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
2
  import {
3
3
  createAnonymousUser,
4
4
  defineQueryHandler,
@@ -23,7 +23,7 @@
23
23
  // but this handler's own isPublic gate runs exactly the same either way.
24
24
 
25
25
  import { computeRevisionEtag } from "@cosmicdrift/kumiko-framework/api";
26
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
26
+ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
27
27
  import { resolveFieldVariant } from "@cosmicdrift/kumiko-framework/derivatives";
28
28
  import {
29
29
  defineQueryHandler,