@cosmicdrift/kumiko-samples 0.366.0 → 0.368.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 (411) 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 +6 -0
  39. package/packages/bundled-features/src/channel-email/email-channel.ts +12 -2
  40. package/packages/bundled-features/src/channel-email/feature.ts +1 -1
  41. package/packages/bundled-features/src/channel-in-app/handlers/inbox.query.ts +1 -1
  42. package/packages/bundled-features/src/channel-in-app/handlers/mark-all-read.write.ts +1 -1
  43. package/packages/bundled-features/src/channel-in-app/handlers/mark-read.write.ts +1 -1
  44. package/packages/bundled-features/src/channel-in-app/handlers/unread-count.query.ts +1 -1
  45. package/packages/bundled-features/src/channel-in-app/tables.ts +1 -1
  46. package/packages/bundled-features/src/compliance-profiles/handlers/for-tenant.query.ts +1 -1
  47. package/packages/bundled-features/src/compliance-profiles/handlers/needs-profile.query.ts +1 -1
  48. package/packages/bundled-features/src/compliance-profiles/handlers/set-profile.write.ts +1 -2
  49. package/packages/bundled-features/src/compliance-profiles/resolve-for-tenant.ts +1 -1
  50. package/packages/bundled-features/src/compliance-profiles/seeding.ts +8 -4
  51. package/packages/bundled-features/src/compliance-profiles-ops/index.ts +26 -17
  52. package/packages/bundled-features/src/config/db/queries/resolver.ts +1 -1
  53. package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +2 -2
  54. package/packages/bundled-features/src/config/resolver.ts +1 -1
  55. package/packages/bundled-features/src/config/write-helpers.ts +1 -1
  56. package/packages/bundled-features/src/crypto-shredding/changes.json +6 -0
  57. package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +9 -7
  58. package/packages/bundled-features/src/custom-fields/db/queries/field-access.ts +1 -1
  59. package/packages/bundled-features/src/custom-fields/db/queries/projection.ts +1 -1
  60. package/packages/bundled-features/src/custom-fields/db/queries/quota.ts +1 -1
  61. package/packages/bundled-features/src/custom-fields/db/queries/retention.ts +6 -2
  62. package/packages/bundled-features/src/custom-fields/db/queries/user-data-rights.ts +1 -1
  63. package/packages/bundled-features/src/custom-fields/feature.ts +11 -14
  64. package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +2 -2
  65. package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +2 -2
  66. package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +2 -2
  67. package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +2 -2
  68. package/packages/bundled-features/src/custom-fields/wire-for-entity.ts +4 -4
  69. package/packages/bundled-features/src/data-retention/resolve-for-tenant.ts +1 -1
  70. package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +16 -10
  71. package/packages/bundled-features/src/delivery/address-opt-out.ts +5 -2
  72. package/packages/bundled-features/src/delivery/attempt-log-retention.ts +1 -1
  73. package/packages/bundled-features/src/delivery/changes.json +12 -0
  74. package/packages/bundled-features/src/delivery/channel-context.ts +2 -1
  75. package/packages/bundled-features/src/delivery/db/queries/address-opt-outs.ts +1 -1
  76. package/packages/bundled-features/src/delivery/db/queries/preferences.ts +1 -1
  77. package/packages/bundled-features/src/delivery/delivery-service.ts +70 -8
  78. package/packages/bundled-features/src/delivery/feature.ts +2 -2
  79. package/packages/bundled-features/src/delivery/handlers/log.query.ts +3 -2
  80. package/packages/bundled-features/src/delivery/handlers/preferences.query.ts +1 -1
  81. package/packages/bundled-features/src/delivery/handlers/unsubscribe-address.write.ts +10 -5
  82. package/packages/bundled-features/src/delivery/index.ts +6 -0
  83. package/packages/bundled-features/src/delivery/testing.ts +2 -0
  84. package/packages/bundled-features/src/delivery/types.ts +4 -0
  85. package/packages/bundled-features/src/delivery/unsubscribe-link.ts +73 -0
  86. package/packages/bundled-features/src/delivery/unsubscribe-page-strings.ts +17 -0
  87. package/packages/bundled-features/src/delivery/unsubscribe.ts +94 -31
  88. package/packages/bundled-features/src/delivery/upsert-preference.ts +5 -2
  89. package/packages/bundled-features/src/derivatives-sharp/feature.ts +21 -12
  90. package/packages/bundled-features/src/derivatives-sharp/index.ts +1 -1
  91. package/packages/bundled-features/src/document-ingest-foundation/feature.ts +112 -103
  92. package/packages/bundled-features/src/document-ingest-foundation/forget-extract-with-file-ref.ts +3 -3
  93. package/packages/bundled-features/src/document-ingest-foundation/index.ts +4 -1
  94. package/packages/bundled-features/src/feature-toggles/global-feature-state-table.ts +1 -1
  95. package/packages/bundled-features/src/feature-toggles/handlers/set.write.ts +3 -5
  96. package/packages/bundled-features/src/feature-toggles/toggle-runtime.ts +1 -1
  97. package/packages/bundled-features/src/file-derivatives/feature.ts +134 -129
  98. package/packages/bundled-features/src/file-derivatives/handlers/public-variant-by-file-ref.query.ts +1 -1
  99. package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +1 -1
  100. package/packages/bundled-features/src/file-foundation/feature.ts +38 -29
  101. package/packages/bundled-features/src/file-foundation/index.ts +1 -0
  102. package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +1 -1
  103. package/packages/bundled-features/src/file-provider-inmemory/feature.ts +32 -21
  104. package/packages/bundled-features/src/file-provider-inmemory/index.ts +6 -1
  105. package/packages/bundled-features/src/file-provider-s3/changes.json +10 -1
  106. package/packages/bundled-features/src/file-provider-s3/env-feature.ts +62 -0
  107. package/packages/bundled-features/src/file-provider-s3/feature.ts +107 -73
  108. package/packages/bundled-features/src/file-provider-s3/index.ts +6 -1
  109. package/packages/bundled-features/src/file-provider-s3/lib/index.ts +3 -0
  110. package/packages/bundled-features/src/{files-provider-s3 → file-provider-s3/lib}/s3-provider.ts +19 -19
  111. package/packages/bundled-features/src/file-provider-s3-env/index.ts +7 -2
  112. package/packages/bundled-features/src/files-provider-s3/index.ts +11 -3
  113. package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +1 -1
  114. package/packages/bundled-features/src/files-tenant-data/hooks.ts +1 -2
  115. package/packages/bundled-features/src/folders/feature.ts +8 -3
  116. package/packages/bundled-features/src/folders-user-data/index.ts +27 -18
  117. package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +1 -1
  118. package/packages/bundled-features/src/form-draft/db/queries/draft-count.ts +1 -1
  119. package/packages/bundled-features/src/form-draft/db/queries/owned-file-refs.ts +3 -2
  120. package/packages/bundled-features/src/form-draft/feature.ts +6 -1
  121. package/packages/bundled-features/src/form-draft/handlers/cleanup.job.ts +2 -2
  122. package/packages/bundled-features/src/form-draft/index.ts +1 -1
  123. package/packages/bundled-features/src/form-draft/lookup.ts +1 -1
  124. package/packages/bundled-features/src/form-draft-user-data/index.ts +19 -10
  125. package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +165 -154
  126. package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +1 -2
  127. package/packages/bundled-features/src/inbound-mail-foundation/index.ts +1 -1
  128. package/packages/bundled-features/src/inbound-mail-foundation/oauth-access-token.ts +5 -2
  129. package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +3 -2
  130. package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +1 -1
  131. package/packages/bundled-features/src/inbound-provider-imap/feature.ts +22 -13
  132. package/packages/bundled-features/src/inbound-provider-imap/index.ts +6 -1
  133. package/packages/bundled-features/src/inbound-provider-inmemory/feature.ts +20 -12
  134. package/packages/bundled-features/src/inbound-provider-inmemory/index.ts +1 -0
  135. package/packages/bundled-features/src/jobs/db/queries/retention.ts +1 -1
  136. package/packages/bundled-features/src/jobs/db/queries/stale-run-sweep.ts +1 -1
  137. package/packages/bundled-features/src/jobs/handlers/detail.query.ts +1 -1
  138. package/packages/bundled-features/src/jobs/handlers/list.query.ts +7 -2
  139. package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
  140. package/packages/bundled-features/src/jobs/handlers/tenant-failures.query.ts +1 -1
  141. package/packages/bundled-features/src/jobs/handlers/tenant-runs.query.ts +1 -1
  142. package/packages/bundled-features/src/jobs/job-run-logger.ts +11 -10
  143. package/packages/bundled-features/src/jobs/tenant-job-failure-table.ts +1 -1
  144. package/packages/bundled-features/src/jobs/tenant-job-run-table.ts +1 -1
  145. package/packages/bundled-features/src/ledger/feature.ts +6 -3
  146. package/packages/bundled-features/src/mail-foundation/feature.ts +107 -55
  147. package/packages/bundled-features/src/mail-foundation/index.ts +4 -0
  148. package/packages/bundled-features/src/mail-transport-inmemory/feature.ts +25 -17
  149. package/packages/bundled-features/src/mail-transport-inmemory/index.ts +6 -1
  150. package/packages/bundled-features/src/mail-transport-smtp/feature.ts +91 -79
  151. package/packages/bundled-features/src/mail-transport-smtp/index.ts +1 -0
  152. package/packages/bundled-features/src/managed-pages/handlers/by-slug.query.ts +1 -1
  153. package/packages/bundled-features/src/managed-pages/handlers/by-tenant-published.query.ts +1 -2
  154. package/packages/bundled-features/src/managed-pages/handlers/set.write.ts +1 -2
  155. package/packages/bundled-features/src/managed-pages/seeding.ts +8 -4
  156. package/packages/bundled-features/src/metrics/compute.ts +1 -1
  157. package/packages/bundled-features/src/metrics/filters.ts +1 -1
  158. package/packages/bundled-features/src/metrics/validate.ts +1 -1
  159. package/packages/bundled-features/src/notes-history/feature.ts +6 -3
  160. package/packages/bundled-features/src/notes-history/handlers/add-note.write.ts +1 -1
  161. package/packages/bundled-features/src/notes-history-user-data/hooks.ts +1 -1
  162. package/packages/bundled-features/src/notes-history-user-data/index.ts +27 -18
  163. package/packages/bundled-features/src/personal-access-tokens/changes.json +6 -0
  164. package/packages/bundled-features/src/personal-access-tokens/feature.ts +17 -2
  165. package/packages/bundled-features/src/personal-access-tokens/handlers/create.write.ts +1 -1
  166. package/packages/bundled-features/src/personal-access-tokens/handlers/list.query.ts +2 -2
  167. package/packages/bundled-features/src/personal-access-tokens/handlers/revoke.write.ts +1 -1
  168. package/packages/bundled-features/src/personal-access-tokens/resolver.ts +1 -1
  169. package/packages/bundled-features/src/personal-access-tokens/revoke-for-user.ts +2 -2
  170. package/packages/bundled-features/src/personal-access-tokens/roles.ts +8 -6
  171. package/packages/bundled-features/src/personal-access-tokens/screens.ts +2 -0
  172. package/packages/bundled-features/src/readiness/feature.ts +25 -16
  173. package/packages/bundled-features/src/readiness/index.ts +1 -1
  174. package/packages/bundled-features/src/secrets/db/queries/read.ts +1 -1
  175. package/packages/bundled-features/src/secrets/feature.ts +8 -3
  176. package/packages/bundled-features/src/secrets/handlers/rotate.job.ts +2 -2
  177. package/packages/bundled-features/src/secrets/secrets-context.ts +4 -3
  178. package/packages/bundled-features/src/sessions/db/queries/cleanup.ts +1 -1
  179. package/packages/bundled-features/src/sessions/handlers/detail.query.ts +1 -1
  180. package/packages/bundled-features/src/sessions/handlers/list.query.ts +2 -2
  181. package/packages/bundled-features/src/sessions/handlers/mine.query.ts +1 -1
  182. package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +1 -1
  183. package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +1 -1
  184. package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
  185. package/packages/bundled-features/src/sessions/session-callbacks.ts +14 -7
  186. package/packages/bundled-features/src/sessions/testing.ts +1 -1
  187. package/packages/bundled-features/src/tags/feature.ts +6 -3
  188. package/packages/bundled-features/src/template-resolver/api.ts +1 -1
  189. package/packages/bundled-features/src/template-resolver/changes.json +25 -0
  190. package/packages/bundled-features/src/template-resolver/compile-document-body.ts +61 -9
  191. package/packages/bundled-features/src/template-resolver/document-sanitizer.ts +19 -0
  192. package/packages/bundled-features/src/template-resolver/document-schema.ts +33 -0
  193. package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +10 -2
  194. package/packages/bundled-features/src/template-resolver/handlers/by-slug.query.ts +1 -1
  195. package/packages/bundled-features/src/template-resolver/handlers/by-tenant.query.ts +1 -2
  196. package/packages/bundled-features/src/template-resolver/handlers/collection-item.query.ts +1 -1
  197. package/packages/bundled-features/src/template-resolver/handlers/collection-list.query.ts +1 -2
  198. package/packages/bundled-features/src/template-resolver/handlers/collection-set.write.ts +1 -1
  199. package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +9 -3
  200. package/packages/bundled-features/src/template-resolver/handlers/diff-to-system.query.ts +1 -1
  201. package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +1 -1
  202. package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +9 -2
  203. package/packages/bundled-features/src/template-resolver/handlers/layout-source.query.ts +1 -1
  204. package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +7 -2
  205. package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +8 -3
  206. package/packages/bundled-features/src/template-resolver/handlers/reset-to-system.write.ts +1 -1
  207. package/packages/bundled-features/src/template-resolver/handlers/resource-remove.write.ts +1 -1
  208. package/packages/bundled-features/src/template-resolver/handlers/set.write.ts +1 -1
  209. package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +22 -2
  210. package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +1 -1
  211. package/packages/bundled-features/src/template-resolver/handlers/toggle-status.write.ts +1 -1
  212. package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +1 -1
  213. package/packages/bundled-features/src/template-resolver/handlers/validate.query.ts +1 -1
  214. package/packages/bundled-features/src/template-resolver/index.ts +4 -0
  215. package/packages/bundled-features/src/template-resolver/qualified-names.ts +1 -0
  216. package/packages/bundled-features/src/template-resolver/seeding.ts +57 -10
  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 +3 -1
  219. package/packages/bundled-features/src/template-resolver/template-resources.ts +1 -1
  220. package/packages/bundled-features/src/template-resolver/template-system-only.ts +21 -0
  221. package/packages/bundled-features/src/template-resolver/template-validation.ts +48 -24
  222. package/packages/bundled-features/src/template-resolver/testing.ts +1 -1
  223. package/packages/bundled-features/src/template-resolver/web/i18n.ts +2 -0
  224. package/packages/bundled-features/src/template-resolver-user-data/index.ts +23 -14
  225. package/packages/bundled-features/src/tenant/handlers/active-tenant-ids.query.ts +1 -1
  226. package/packages/bundled-features/src/tenant/handlers/add-member.write.ts +1 -2
  227. package/packages/bundled-features/src/tenant/handlers/cancel-invitation.write.ts +1 -1
  228. package/packages/bundled-features/src/tenant/handlers/invitations.query.ts +1 -1
  229. package/packages/bundled-features/src/tenant/handlers/me.query.ts +1 -1
  230. package/packages/bundled-features/src/tenant/handlers/member-directory.query.ts +1 -1
  231. package/packages/bundled-features/src/tenant/handlers/members.query.ts +1 -1
  232. package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
  233. package/packages/bundled-features/src/tenant/handlers/remove-member.write.ts +2 -1
  234. package/packages/bundled-features/src/tenant/handlers/resolve-user-ids.query.ts +1 -1
  235. package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +1 -1
  236. package/packages/bundled-features/src/tenant/handlers/tenant-directory.query.ts +1 -1
  237. package/packages/bundled-features/src/tenant/handlers/update-member-roles.write.ts +1 -2
  238. package/packages/bundled-features/src/tenant/invited-membership.ts +2 -2
  239. package/packages/bundled-features/src/tenant/last-tenant-admin.ts +1 -2
  240. package/packages/bundled-features/src/tenant/seeding.ts +12 -12
  241. package/packages/bundled-features/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +1 -2
  242. package/packages/bundled-features/src/tenant-lifecycle/handlers/request-destruction.write.ts +1 -2
  243. package/packages/bundled-features/src/tenant-lifecycle/lib/revoke-tenant-sessions.ts +1 -1
  244. package/packages/bundled-features/src/tenant-lifecycle/lifecycle-gate.ts +1 -1
  245. package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +3 -3
  246. package/packages/bundled-features/src/tenant-lifecycle/stages.ts +10 -5
  247. package/packages/bundled-features/src/tenant-lifecycle/testing.ts +3 -3
  248. package/packages/bundled-features/src/tenant-settings/feature.ts +34 -29
  249. package/packages/bundled-features/src/tier-engine/feature.ts +426 -428
  250. package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +2 -3
  251. package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +5 -2
  252. package/packages/bundled-features/src/user/changes.json +6 -0
  253. package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +1 -1
  254. package/packages/bundled-features/src/user/handlers/create.write.ts +1 -2
  255. package/packages/bundled-features/src/user/handlers/find-for-auth.query.ts +1 -1
  256. package/packages/bundled-features/src/user/handlers/list.query.ts +1 -1
  257. package/packages/bundled-features/src/user/handlers/update-roles.ts +2 -1
  258. package/packages/bundled-features/src/user/index.ts +5 -1
  259. package/packages/bundled-features/src/user/invited-global-roles.ts +2 -2
  260. package/packages/bundled-features/src/user/principal-status.ts +13 -3
  261. package/packages/bundled-features/src/user/resolve-display-names.ts +1 -1
  262. package/packages/bundled-features/src/user/seeding.ts +5 -5
  263. package/packages/bundled-features/src/user-data-rights/audit-download.ts +2 -2
  264. package/packages/bundled-features/src/user-data-rights/changes.json +6 -0
  265. package/packages/bundled-features/src/user-data-rights/db/queries/export-jobs.ts +1 -1
  266. package/packages/bundled-features/src/user-data-rights/db/queries/forget-cleanup.ts +1 -1
  267. package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +1 -1
  268. package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +1 -1
  269. package/packages/bundled-features/src/user-data-rights/handlers/export-status.query.ts +1 -1
  270. package/packages/bundled-features/src/user-data-rights/handlers/list-download-attempts.query.ts +1 -1
  271. package/packages/bundled-features/src/user-data-rights/handlers/my-audit-log.query.ts +1 -1
  272. package/packages/bundled-features/src/user-data-rights/handlers/request-export.write.ts +1 -2
  273. package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +3 -3
  274. package/packages/bundled-features/src/user-data-rights/lib/deny-if-target-outside-admin-tenant.ts +1 -1
  275. package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +7 -2
  276. package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +7 -3
  277. package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +11 -5
  278. package/packages/bundled-features/src/user-data-rights/run-user-export.ts +10 -5
  279. package/packages/bundled-features/src/waitlist/handlers/invite.write.ts +1 -2
  280. package/packages/bundled-features/src/waitlist/handlers/reject.write.ts +1 -1
  281. package/packages/bundled-features/src/waitlist/lib.ts +5 -2
  282. package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +1 -1
  283. package/packages/bundled-features/src/workflow-runner/feature.ts +58 -47
  284. package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +1 -1
  285. package/packages/bundled-features/src/workflow-runner/index.ts +1 -1
  286. package/packages/bundled-features/src/workflow-runner/pending-projection.ts +1 -1
  287. package/samples/apps/admin-console/src/run-config.ts +2 -2
  288. package/samples/apps/cap-billing-demo/package.json +3 -0
  289. package/samples/apps/cap-billing-demo/src/feature.ts +2 -2
  290. package/samples/apps/cap-billing-demo/src/run-config.ts +8 -8
  291. package/samples/apps/marketing-demo/src/app/seed.ts +1 -1
  292. package/samples/apps/marketing-demo/src/db/queries/seed-counts.ts +1 -1
  293. package/samples/apps/showcase/package.json +3 -0
  294. package/samples/apps/showcase/src/app/seed-items.ts +1 -1
  295. package/samples/apps/styleguide/src/app/seed.ts +2 -2
  296. package/samples/apps/styleguide/src/features/ai-settings/seed.ts +2 -2
  297. package/samples/apps/ui-walkthrough/scripts/emit-e2e-data.ts +1 -1
  298. package/samples/apps/ui-walkthrough/src/app/auth-constants.ts +1 -1
  299. package/samples/apps/ui-walkthrough/src/app/seed-rental.ts +2 -2
  300. package/samples/apps/ui-walkthrough/src/app/seed-templates.ts +2 -0
  301. package/samples/apps/ui-walkthrough/src/app/seed-vehicles.ts +1 -1
  302. package/samples/apps/ui-walkthrough/src/app/seed.ts +1 -1
  303. package/samples/apps/ui-walkthrough/src/app/template-seed-data.ts +12 -0
  304. package/samples/apps/ui-walkthrough/src/db/queries/row-counts.ts +1 -1
  305. package/samples/apps/ui-walkthrough/src/db/queries/task-counts.ts +1 -1
  306. package/samples/apps/ui-walkthrough/src/features/billing/feature.ts +7 -0
  307. package/samples/apps/ui-walkthrough/src/features/billing/i18n.ts +2 -0
  308. package/samples/apps/use-all-bundled/feature-manifest.json +4 -4
  309. package/samples/apps/use-all-bundled/package.json +4 -0
  310. package/samples/apps/use-all-bundled/scripts/check-coverage.ts +2 -2
  311. package/samples/apps/use-all-bundled/src/app/auth-constants.ts +1 -1
  312. package/samples/apps/use-all-bundled/src/app/cap-overview-caps.ts +2 -2
  313. package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +1 -1
  314. package/samples/apps/use-all-bundled/src/app/seed-documents.ts +1 -1
  315. package/samples/apps/use-all-bundled/src/app/seed.ts +11 -5
  316. package/samples/apps/use-all-bundled/src/run-config.ts +55 -56
  317. package/samples/apps/user-data-rights-demo/README.md +2 -2
  318. package/samples/apps/user-data-rights-demo/package.json +3 -0
  319. package/samples/apps/user-data-rights-demo/src/run-config.ts +7 -7
  320. package/samples/apps/workspaces/package.json +3 -0
  321. package/samples/recipes/access-control/package.json +3 -0
  322. package/samples/recipes/anonymous-access/package.json +3 -0
  323. package/samples/recipes/anonymous-access-multitenant/package.json +3 -0
  324. package/samples/recipes/apex-landing/package.json +1 -0
  325. package/samples/recipes/apex-surface-auth/package.json +3 -0
  326. package/samples/recipes/apex-surface-auth/src/feature.ts +2 -2
  327. package/samples/recipes/api-worker-split/package.json +3 -0
  328. package/samples/recipes/api-worker-split/src/feature.ts +1 -2
  329. package/samples/recipes/auth-claims/package.json +3 -0
  330. package/samples/recipes/auth-foundation-providers/src/feature.ts +1 -1
  331. package/samples/recipes/auth-mfa/package.json +3 -0
  332. package/samples/recipes/basic-entity/package.json +3 -0
  333. package/samples/recipes/chat-channels/package.json +3 -0
  334. package/samples/recipes/compliance-profiles-demo/package.json +3 -0
  335. package/samples/recipes/cross-feature-events/package.json +3 -1
  336. package/samples/recipes/cross-feature-events/src/feature.ts +1 -1
  337. package/samples/recipes/crypto-shredding-hr/package.json +3 -0
  338. package/samples/recipes/currencies-global/package.json +3 -0
  339. package/samples/recipes/currencies-per-tenant/package.json +3 -0
  340. package/samples/recipes/custom-fields-basic/package.json +3 -0
  341. package/samples/recipes/custom-handlers/package.json +3 -0
  342. package/samples/recipes/dashboard-stats/package.json +3 -0
  343. package/samples/recipes/delivery-notifications/package.json +3 -0
  344. package/samples/recipes/e2e-generator/package.json +3 -0
  345. package/samples/recipes/embedded/package.json +3 -0
  346. package/samples/recipes/embedded-entity-form/package.json +1 -0
  347. package/samples/recipes/encrypted-tenant-config/README.md +1 -1
  348. package/samples/recipes/encrypted-tenant-config/package.json +3 -0
  349. package/samples/recipes/error-contract/package.json +3 -0
  350. package/samples/recipes/event-sourcing/package.json +3 -1
  351. package/samples/recipes/event-sourcing/src/feature.ts +16 -20
  352. package/samples/recipes/event-sourcing/tsconfig.json +2 -6
  353. package/samples/recipes/feature-toggles/package.json +3 -0
  354. package/samples/recipes/field-access/package.json +3 -0
  355. package/samples/recipes/files-post-processing/package.json +1 -0
  356. package/samples/recipes/golden-path/README.md +30 -0
  357. package/samples/recipes/golden-path/package.json +11 -0
  358. package/samples/recipes/golden-path/src/feature.ts +70 -0
  359. package/samples/recipes/idempotency/package.json +3 -0
  360. package/samples/recipes/inbound-mail-triage/package.json +3 -0
  361. package/samples/recipes/lane-routing/package.json +3 -0
  362. package/samples/recipes/ledger-banking/package.json +3 -0
  363. package/samples/recipes/ledger-invoicing/package.json +3 -0
  364. package/samples/recipes/legal-pages/package.json +3 -0
  365. package/samples/recipes/lifecycle-hooks/package.json +3 -0
  366. package/samples/recipes/managed-config/package.json +3 -0
  367. package/samples/recipes/managed-pages/package.json +3 -0
  368. package/samples/recipes/notes-history-basic/package.json +3 -0
  369. package/samples/recipes/ownership/package.json +3 -0
  370. package/samples/recipes/pdf-audit-export/package.json +1 -0
  371. package/samples/recipes/pipeline-basics/package.json +3 -0
  372. package/samples/recipes/public-share-token/package.json +3 -0
  373. package/samples/recipes/public-share-token/src/feature.ts +1 -1
  374. package/samples/recipes/rate-limiting/package.json +3 -0
  375. package/samples/recipes/realtime-sse/package.json +3 -0
  376. package/samples/recipes/record-detail-layout/package.json +1 -0
  377. package/samples/recipes/reference-data/package.json +3 -0
  378. package/samples/recipes/relations/package.json +3 -0
  379. package/samples/recipes/screens-nav/package.json +3 -0
  380. package/samples/recipes/search/package.json +3 -0
  381. package/samples/recipes/secrets-demo/package.json +3 -0
  382. package/samples/recipes/security-baseline/src/feature.ts +2 -2
  383. package/samples/recipes/session-revocation/README.md +1 -1
  384. package/samples/recipes/session-revocation/package.json +3 -0
  385. package/samples/recipes/session-revocation/src/feature.ts +1 -1
  386. package/samples/recipes/state-machine/package.json +3 -1
  387. package/samples/recipes/state-machine/src/entities/invoice.ts +2 -2
  388. package/samples/recipes/state-machine/src/events.ts +19 -0
  389. package/samples/recipes/state-machine/src/feature.ts +25 -30
  390. package/samples/recipes/state-machine/src/handlers/_helpers.ts +13 -14
  391. package/samples/recipes/state-machine/src/handlers/create.ts +1 -1
  392. package/samples/recipes/state-machine/src/handlers/transitions.ts +129 -122
  393. package/samples/recipes/state-machine/src/reducer.ts +1 -1
  394. package/samples/recipes/state-machine/tsconfig.json +2 -6
  395. package/samples/recipes/tags-basic/package.json +3 -0
  396. package/samples/recipes/tenant-isolation/package.json +3 -0
  397. package/samples/recipes/tenant-settings/package.json +3 -0
  398. package/samples/recipes/tier-admin/package.json +3 -0
  399. package/samples/recipes/timezones/package.json +3 -0
  400. package/samples/recipes/tsconfig.base.json +1 -1
  401. package/samples/recipes/user-data-rights/package.json +3 -0
  402. package/samples/recipes/user-data-rights/src/feature.ts +6 -2
  403. package/samples/recipes/user-profile/package.json +3 -0
  404. package/samples/recipes/user-profile/src/feature.ts +2 -2
  405. package/samples/recipes/webhook-step/package.json +3 -0
  406. package/samples/recipes/wizard-form/package.json +1 -0
  407. package/samples/recipes/workflow-engine/package.json +3 -0
  408. package/samples/recipes/workflow-engine/src/db/queries/suspended-runs.ts +5 -2
  409. package/samples/recipes/writeform-section/package.json +1 -0
  410. package/packages/bundled-features/src/file-provider-s3-env/feature.ts +0 -58
  411. /package/packages/bundled-features/src/{files-provider-s3 → file-provider-s3/lib}/env-helper.ts +0 -0
@@ -9,12 +9,12 @@
9
9
  // Default ifExists="skip". The actor is `createSystemUser(SYSTEM_TENANT_ID)`,
10
10
  // deliberately not TestUsers (prod seeds are not test utilities).
11
11
 
12
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
13
12
  import {
14
13
  createTenantDb,
15
14
  type DbConnection,
16
15
  deleteMany,
17
16
  type EntityTableMeta,
17
+ fetchOne,
18
18
  type TenantDb,
19
19
  } from "@cosmicdrift/kumiko-framework/db";
20
20
  import {
@@ -28,11 +28,13 @@ import {
28
28
  getStreamVersion,
29
29
  getUnscopedStreamMaxVersionForSeed,
30
30
  } from "@cosmicdrift/kumiko-framework/event-store";
31
+ import type { Dispatcher } from "@cosmicdrift/kumiko-framework/pipeline";
31
32
  import { runEventStoreSeed, type SeedIfExists } from "@cosmicdrift/kumiko-framework/seeding";
33
+ import { isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
32
34
  import { type ContentFormat, TEXT_BLOCK_KIND, type UpsertKind } from "./constants.js";
33
35
  import { executor } from "./handlers/shared.js";
34
36
  import { evaluateTemplateWrite } from "./handlers/template-gates.js";
35
- import { TEMPLATE_RESOLVER_FEATURE } from "./qualified-names.js";
37
+ import { TEMPLATE_RESOLVER_FEATURE, TemplateResolverHandlers } from "./qualified-names.js";
36
38
  import { type TemplateResourceRow, templateResourcesTable } from "./table.js";
37
39
  import type { TemplateBundle } from "./template-bundle.js";
38
40
  import { activeStampChanges, servedStampChanges } from "./template-draft.js";
@@ -87,7 +89,7 @@ export async function seedSystemTemplate(
87
89
  ): Promise<{ id: string }> {
88
90
  const tenantId = SYSTEM_TENANT_ID;
89
91
  const by = opts.by ?? createSystemUser(tenantId);
90
- const tdb = createTenantDb(db, tenantId, "system");
92
+ const tdb = createTenantDb({ db, tenantId, mode: "system" });
91
93
 
92
94
  const label = `seedSystemTemplate ${opts.slug}/${opts.kind}/${opts.locale}`;
93
95
  const slug = templateSlugSchema.safeParse(opts.slug);
@@ -233,20 +235,21 @@ export async function seedSystemTemplate(
233
235
  export type SeedSystemTemplateBundleOptions = {
234
236
  readonly by?: SessionUser;
235
237
  readonly ifExists?: SeedIfExists;
238
+ /** Required for bundles with resources (e.g. a `logo`): the files go through the
239
+ * import-bundle-system write, which needs the file provider of the system tenant. */
240
+ readonly dispatcher?: Dispatcher;
236
241
  };
237
242
 
238
- // Seeds one system row per bundle locale. Bundled resources need a file
239
- // provider and the system tenant's file space, which a boot seed does not
240
- // have, so those go through the import-bundle-system write instead.
243
+ // Seeds one system row per bundle locale. Bundled resources need a file provider and
244
+ // the system tenant's file space, so those bundles are written through the
245
+ // import-bundle-system handler on the seed dispatcher instead of directly.
241
246
  export async function seedSystemTemplateBundle(
242
247
  db: DbConnection,
243
248
  bundle: TemplateBundle,
244
249
  opts: SeedSystemTemplateBundleOptions = {},
245
250
  ): Promise<{ ids: Record<string, string> }> {
246
251
  if (Object.keys(bundle.resources).length > 0) {
247
- throw new Error(
248
- `seedSystemTemplateBundle ${bundle.slug}/${bundle.kind}: bundles with resources cannot be seeded; use the import-bundle-system write`,
249
- );
252
+ return seedSystemTemplateBundleWithResources(db, bundle, opts);
250
253
  }
251
254
  const ids: Record<string, string> = {};
252
255
  for (const [locale, entry] of Object.entries(bundle.locales)) {
@@ -266,6 +269,50 @@ export async function seedSystemTemplateBundle(
266
269
  return { ids };
267
270
  }
268
271
 
272
+ async function seedSystemTemplateBundleWithResources(
273
+ db: DbConnection,
274
+ bundle: TemplateBundle,
275
+ opts: SeedSystemTemplateBundleOptions,
276
+ ): Promise<{ ids: Record<string, string> }> {
277
+ const label = `seedSystemTemplateBundle ${bundle.slug}/${bundle.kind}`;
278
+ const { dispatcher } = opts;
279
+ if (!dispatcher) {
280
+ throw new Error(
281
+ `${label}: bundles with resources need a file provider; pass opts.dispatcher (the dispatcher of the seed deps) so the files are stored through the import-bundle-system write`,
282
+ );
283
+ }
284
+ if ((opts.ifExists ?? "skip") === "skip") {
285
+ const existingIds: Record<string, string> = {};
286
+ for (const locale of Object.keys(bundle.locales)) {
287
+ const row = await fetchOne<TemplateResourceRow>(db, templateResourcesTable, {
288
+ tenantId: SYSTEM_TENANT_ID,
289
+ slug: bundle.slug,
290
+ kind: bundle.kind,
291
+ locale,
292
+ });
293
+ if (row) existingIds[locale] = String(row.id);
294
+ }
295
+ if (Object.keys(existingIds).length === Object.keys(bundle.locales).length) {
296
+ return { ids: existingIds };
297
+ }
298
+ }
299
+ const result = await dispatcher.write(
300
+ TemplateResolverHandlers.importBundleSystem,
301
+ { bundle },
302
+ opts.by ?? createSystemUser(SYSTEM_TENANT_ID, ["SystemAdmin"]),
303
+ );
304
+ if (!result.isSuccess) {
305
+ throw new Error(`${label} failed: ${result.error.code}: ${result.error.message}`);
306
+ }
307
+ return { ids: importedIds(result.data) };
308
+ }
309
+
310
+ function importedIds(data: unknown): Record<string, string> {
311
+ const ids = isPlainObject(data) ? data["ids"] : undefined;
312
+ if (!isPlainObject(ids)) throw new Error("seedSystemTemplateBundle: import returned no ids");
313
+ return Object.fromEntries(Object.entries(ids).map(([locale, id]) => [locale, String(id)]));
314
+ }
315
+
269
316
  export function hasNotificationTemplates(registry: Registry): boolean {
270
317
  return Array.from(registry.getAllNotifications().values()).some(
271
318
  (notification) => notification.template !== undefined,
@@ -332,7 +379,7 @@ export async function seedTextBlock(
332
379
  opts: SeedTextBlockOptions,
333
380
  ): Promise<{ id: string }> {
334
381
  const by = opts.by ?? createSystemUser(opts.tenantId);
335
- const tdb = createTenantDb(db, opts.tenantId, "system");
382
+ const tdb = createTenantDb({ db, tenantId: opts.tenantId, mode: "system" });
336
383
 
337
384
  const existingRow = await fetchOne<TemplateResourceRow>(db, templateResourcesTable, {
338
385
  tenantId: opts.tenantId,
@@ -1,4 +1,4 @@
1
- import { fetchOne, selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { fetchOne, selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import type {
3
3
  BeforeTransactionResult,
4
4
  ConfigAccessor,
@@ -1,4 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import type {
3
3
  HandlerContext,
4
4
  SessionUser,
@@ -69,6 +69,8 @@ function sampleScalar(name: string, def: TemplateScalarVariableDef): unknown {
69
69
  return 0;
70
70
  case "date":
71
71
  return SAMPLE_DATE;
72
+ case "percent":
73
+ return 0;
72
74
  }
73
75
  }
74
76
 
@@ -1,4 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
2
  import type {
3
3
  HandlerContext,
4
4
  SessionUser,
@@ -0,0 +1,21 @@
1
+ import type { Registry } from "@cosmicdrift/kumiko-framework/engine";
2
+ import { isSystemAdmin } from "./template-draft.js";
3
+
4
+ const NOTIFICATION_TEMPLATE_KIND = "mail";
5
+
6
+ // A notification registered with systemOnly keeps its mail template as the system default:
7
+ // tenants neither list nor override it, and overrides stored before the flag are ignored.
8
+ export function isSystemOnlyTemplate(registry: Registry, slug: string, kind: string): boolean {
9
+ return (
10
+ kind === NOTIFICATION_TEMPLATE_KIND &&
11
+ registry.getAllNotifications().get(slug)?.systemOnly === true
12
+ );
13
+ }
14
+
15
+ export function isSystemOnlyTemplateHiddenFrom(
16
+ user: { readonly roles: readonly string[] },
17
+ registry: Registry,
18
+ row: { readonly slug: string; readonly kind: string },
19
+ ): boolean {
20
+ return !isSystemAdmin(user) && isSystemOnlyTemplate(registry, row.slug, row.kind);
21
+ }
@@ -6,8 +6,12 @@ import type {
6
6
  } from "@cosmicdrift/kumiko-framework/engine";
7
7
  import type { Element as ScanElement } from "happy-dom";
8
8
  import * as z from "zod";
9
- import { withParsedDocument } from "./document-sanitizer.js";
10
- import { isDocumentPlaceholderHref, isDocumentReferenceName } from "./document-schema.js";
9
+ import { conditionScopeElement, withParsedDocument } from "./document-sanitizer.js";
10
+ import {
11
+ DOCUMENT_CONDITION_ATTRIBUTE,
12
+ isDocumentPlaceholderHref,
13
+ isDocumentReferenceName,
14
+ } from "./document-schema.js";
11
15
  import type { TemplateMeta } from "./template-meta.js";
12
16
 
13
17
  export const SYSTEM_PLACEHOLDERS: ReadonlySet<string> = new Set([
@@ -56,6 +60,7 @@ const scalarVariableSchema = z.discriminatedUnion("type", [
56
60
  .optional(),
57
61
  }),
58
62
  z.object({ ...variableCommon, type: z.literal("date"), example: textLikeExample }),
63
+ z.object({ ...variableCommon, type: z.literal("percent"), example: z.number().optional() }),
59
64
  ]);
60
65
 
61
66
  const variableDefSchema = z.union([
@@ -154,30 +159,49 @@ const NAME_ATTRIBUTE_BY_TAG: Readonly<Record<string, string>> = {
154
159
  div: "data-steps",
155
160
  };
156
161
 
162
+ function scanRepeatRows(root: ScanElement, scope: PlaceholderScope): void {
163
+ for (const element of Array.from(root.querySelectorAll("tr[data-each]"))) {
164
+ const listName = element.getAttribute("data-each") ?? "";
165
+ const def = Object.hasOwn(scope.variables, listName) ? scope.variables[listName] : undefined;
166
+ if (def?.type === "list") scope.used.add(listName);
167
+ else scope.unknown.add(listName);
168
+ }
169
+ }
170
+
171
+ function scanConditions(root: ScanElement, scope: PlaceholderScope): void {
172
+ for (const element of Array.from(root.querySelectorAll(`[${DOCUMENT_CONDITION_ATTRIBUTE}]`))) {
173
+ const itemFields = listItemFields(
174
+ scope.variables,
175
+ enclosingEachName(conditionScopeElement(element)),
176
+ );
177
+ recordName(element.getAttribute(DOCUMENT_CONDITION_ATTRIBUTE) ?? "", itemFields, scope);
178
+ }
179
+ }
180
+
181
+ function scanReferences(root: ScanElement, scope: PlaceholderScope): void {
182
+ for (const element of Array.from(
183
+ root.querySelectorAll("span[data-variable], div[data-steps], a[href], img[data-resource]"),
184
+ )) {
185
+ const itemFields = listItemFields(scope.variables, enclosingEachName(element));
186
+ const tag = element.tagName.toLowerCase();
187
+ const nameAttribute = NAME_ATTRIBUTE_BY_TAG[tag];
188
+ if (nameAttribute !== undefined) {
189
+ recordName(element.getAttribute(nameAttribute) ?? "", itemFields, scope);
190
+ } else if (tag === "a") {
191
+ const href = element.getAttribute("href") ?? "";
192
+ if (isDocumentPlaceholderHref(href)) recordName(href.slice(2, -2), itemFields, scope);
193
+ } else {
194
+ const key = element.getAttribute("data-resource") ?? "";
195
+ if (!scope.resourceKeys.has(key)) scope.unknownResources.add(key);
196
+ }
197
+ }
198
+ }
199
+
157
200
  function scanBodyPlaceholders(body: string, scope: PlaceholderScope): void {
158
201
  withParsedDocument(body, (root) => {
159
- for (const element of Array.from(root.querySelectorAll("tr[data-each]"))) {
160
- const listName = element.getAttribute("data-each") ?? "";
161
- const def = Object.hasOwn(scope.variables, listName) ? scope.variables[listName] : undefined;
162
- if (def?.type === "list") scope.used.add(listName);
163
- else scope.unknown.add(listName);
164
- }
165
- for (const element of Array.from(
166
- root.querySelectorAll("span[data-variable], div[data-steps], a[href], img[data-resource]"),
167
- )) {
168
- const itemFields = listItemFields(scope.variables, enclosingEachName(element));
169
- const tag = element.tagName.toLowerCase();
170
- const nameAttribute = NAME_ATTRIBUTE_BY_TAG[tag];
171
- if (nameAttribute !== undefined) {
172
- recordName(element.getAttribute(nameAttribute) ?? "", itemFields, scope);
173
- } else if (tag === "a") {
174
- const href = element.getAttribute("href") ?? "";
175
- if (isDocumentPlaceholderHref(href)) recordName(href.slice(2, -2), itemFields, scope);
176
- } else {
177
- const key = element.getAttribute("data-resource") ?? "";
178
- if (!scope.resourceKeys.has(key)) scope.unknownResources.add(key);
179
- }
180
- }
202
+ scanRepeatRows(root, scope);
203
+ scanConditions(root, scope);
204
+ scanReferences(root, scope);
181
205
  });
182
206
  }
183
207
 
@@ -3,7 +3,7 @@
3
3
  // No bun:test here — callers register cases with their own test runner.
4
4
 
5
5
  import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
6
- import { seedRow } from "@cosmicdrift/kumiko-framework/testing";
6
+ import { seedRow } from "@cosmicdrift/kumiko-testing/helpers";
7
7
  import type { ResolveRequest, TemplateResource } from "./api.js";
8
8
  import { TemplateNotFoundError } from "./api.js";
9
9
  import {
@@ -96,6 +96,8 @@ export const defaultTranslations: TranslationsByLocale = {
96
96
  "“{detail}” templates are written through their own editor, not through a collection.",
97
97
  "templateResolver.errors.noSystemTemplate": "There is no active system template to reset to.",
98
98
  "templateResolver.errors.noDraft": "There is no draft to discard.",
99
+ "templateResolver.errors.systemOnlyTemplate":
100
+ "Only the platform maintains this template; it cannot be overridden per tenant.",
99
101
  "templateResolver.errors.template.invalidMeta": "The template settings are invalid.",
100
102
  "templateResolver.errors.template.meta.subject.required": "The subject is missing.",
101
103
  "templateResolver.errors.template.meta.subject.invalid":
@@ -8,18 +8,27 @@
8
8
  import { defineFeature, EXT_USER_DATA } from "@cosmicdrift/kumiko-framework/engine";
9
9
  import { userContentDeleteHook, userContentExportHook } from "./hooks.js";
10
10
 
11
- export const templateResolverUserDataFeature = defineFeature("template-resolver-user-data", (r) => {
12
- r.describe(
13
- "GDPR (Art. 20 export / Art. 17 erasure) coverage for the `template-resolver` feature's `user-content-entry` entity — the per-user half of the content store (mail signatures, personal reply snippets). Mounts the EXT_USER_DATA export hook so a user's own entries land in the export bundle; the delete hook is a deliberate no-op because `content` is annotated `userOwned`, so erasure runs via crypto-shredding (destroying the owner's subject key) rather than a physical delete, which would not survive an event replay. Mount this whenever `createTemplateResolverFeature` declares a collection with `ownership: \"user\"` — the boot guard otherwise refuses the entity. Requires `user-data-rights`, optionalRequires `template-resolver`.",
11
+ export function createTemplateResolverUserDataFeature() {
12
+ return defineFeature(
13
+ "template-resolver-user-data",
14
+ (r) => {
15
+ r.describe(
16
+ "GDPR (Art. 20 export / Art. 17 erasure) coverage for the `template-resolver` feature's `user-content-entry` entity — the per-user half of the content store (mail signatures, personal reply snippets). Mounts the EXT_USER_DATA export hook so a user's own entries land in the export bundle; the delete hook is a deliberate no-op because `content` is annotated `userOwned`, so erasure runs via crypto-shredding (destroying the owner's subject key) rather than a physical delete, which would not survive an event replay. Mount this whenever `createTemplateResolverFeature` declares a collection with `ownership: \"user\"` — the boot guard otherwise refuses the entity. Requires `user-data-rights`, optionalRequires `template-resolver`.",
17
+ );
18
+ // user-data-rights is the hard dependency (EXT_USER_DATA host).
19
+ // template-resolver is optional for the same reason as in
20
+ // notes-history-user-data: a toggleable mount would otherwise trip the
21
+ // "effectively disabled" boot warning even though the entity is there.
22
+ r.requires({ features: ["user-data-rights"] });
23
+ r.optionalRequires("template-resolver");
24
+ r.useExtension(EXT_USER_DATA, "user-content-entry", {
25
+ export: userContentExportHook,
26
+ delete: userContentDeleteHook,
27
+ });
28
+ },
29
+ { dedupeOptions: {} },
14
30
  );
15
- // user-data-rights is the hard dependency (EXT_USER_DATA host).
16
- // template-resolver is optional for the same reason as in
17
- // notes-history-user-data: a toggleable mount would otherwise trip the
18
- // "effectively disabled" boot warning even though the entity is there.
19
- r.requires({ features: ["user-data-rights"] });
20
- r.optionalRequires("template-resolver");
21
- r.useExtension(EXT_USER_DATA, "user-content-entry", {
22
- export: userContentExportHook,
23
- delete: userContentDeleteHook,
24
- });
25
- });
31
+ }
32
+
33
+ /** @deprecated Use createTemplateResolverUserDataFeature(). Run `bun kumiko-upgrade --apply`. Removed in the first release after 2026-10-29. */
34
+ export const templateResolverUserDataFeature = createTemplateResolverUserDataFeature();
@@ -1,4 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import {
3
3
  defineQueryHandler,
4
4
  SYSTEM_ROLE,
@@ -1,5 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
2
- import { createEventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
1
+ import { createEventStoreExecutor, fetchOne } from "@cosmicdrift/kumiko-framework/db";
3
2
  import {
4
3
  defineWriteHandler,
5
4
  type SessionUser,
@@ -10,7 +10,7 @@
10
10
  // invitation = no-op + 200. Cancelling a non-existent invitation
11
11
  // = invitation_not_found.
12
12
 
13
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
13
+ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
14
14
  import { access, defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
15
15
  import { InternalError, NotFoundError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
16
16
  import * as z from "zod";
@@ -1,4 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { access, defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import * as z from "zod";
@@ -1,4 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { fetchOne } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import * as z from "zod";
@@ -1,5 +1,5 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
1
  import type { TenantDb } from "@cosmicdrift/kumiko-framework/db";
2
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
3
3
  import {
4
4
  access,
5
5
  definePagedQueryHandler,
@@ -1,4 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { access, defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import { parseRoles } from "@cosmicdrift/kumiko-framework/utils";
@@ -1,4 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineQueryHandler, SYSTEM_ROLE } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import { parseRoles } from "@cosmicdrift/kumiko-framework/utils";
@@ -1,7 +1,8 @@
1
- import { fetchOne, selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
1
  import {
3
2
  createEventStoreExecutor,
4
3
  type DbRow,
4
+ fetchOne,
5
+ selectMany,
5
6
  type TenantDb,
6
7
  } from "@cosmicdrift/kumiko-framework/db";
7
8
  import {
@@ -1,4 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import { defineQueryHandler, SYSTEM_ROLE } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
4
4
  import * as z from "zod";
@@ -1,4 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import {
3
3
  access,
4
4
  definePagedQueryHandler,
@@ -1,4 +1,4 @@
1
- import { fetchOne, selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
1
+ import { fetchOne, selectMany } from "@cosmicdrift/kumiko-framework/db";
2
2
  import {
3
3
  access,
4
4
  definePagedQueryHandler,
@@ -1,5 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
2
- import { createEventStoreExecutor, type DbRow } from "@cosmicdrift/kumiko-framework/db";
1
+ import { createEventStoreExecutor, type DbRow, fetchOne } from "@cosmicdrift/kumiko-framework/db";
3
2
  import {
4
3
  access,
5
4
  assignableAppRolesOf,
@@ -1,8 +1,8 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
2
1
  import {
3
2
  createEventStoreExecutor,
4
3
  createTenantDb,
5
4
  type DbRunner,
5
+ fetchOne,
6
6
  type TenantDb,
7
7
  } from "@cosmicdrift/kumiko-framework/db";
8
8
  import { createSystemUser, type TenantId } from "@cosmicdrift/kumiko-framework/engine";
@@ -87,7 +87,7 @@ export async function grantInvitedMembershipRole(db: DbRunner, options: InvitedM
87
87
  const updateResult = await membershipExecutor.update(
88
88
  { id: existing.id, version: existing.version, changes: { roles: JSON.stringify(roles) } },
89
89
  createSystemUser(options.tenantId),
90
- createTenantDb(db, options.tenantId, "system"),
90
+ createTenantDb({ db, tenantId: options.tenantId, mode: "system" }),
91
91
  );
92
92
  if (!updateResult.isSuccess) return updateResult;
93
93
  return grantedMembership(true, roles);
@@ -1,5 +1,4 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
- import { acquireNamespacedAdvisoryLock } from "@cosmicdrift/kumiko-framework/db";
1
+ import { acquireNamespacedAdvisoryLock, selectMany } from "@cosmicdrift/kumiko-framework/db";
3
2
  import { ConflictError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
4
3
  import { parseRoles } from "@cosmicdrift/kumiko-framework/utils";
5
4
  import { TenantErrors } from "./constants.js";
@@ -28,11 +28,11 @@
28
28
  // a no-op on the second call. Memberships have no update-semantic — to
29
29
  // change roles, write a new event via the regular handler path.
30
30
 
31
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
32
31
  import {
33
32
  createEventStoreExecutor,
34
33
  createTenantDb,
35
34
  type DbRunner,
35
+ fetchOne,
36
36
  } from "@cosmicdrift/kumiko-framework/db";
37
37
  import {
38
38
  type AppContext,
@@ -48,7 +48,7 @@ import {
48
48
  createDeferringNotify,
49
49
  createLifecycleHooks,
50
50
  } from "@cosmicdrift/kumiko-framework/pipeline";
51
- import { TestUsers } from "@cosmicdrift/kumiko-framework/stack";
51
+ import { TestUsers } from "@cosmicdrift/kumiko-framework/seeding";
52
52
  import { assertAssignableMembershipRoles } from "./membership-roles.js";
53
53
  import { tenantMembershipEntity, tenantMembershipsTable } from "./membership-table.js";
54
54
  import { tenantEntity, tenantTable } from "./schema/tenant.js";
@@ -159,14 +159,14 @@ function scopeSeedHookContext(
159
159
  // afterCommit-phase hook would be dropped: that phase must notify inline.
160
160
  notifyTiming: "deferUntilCommit" | "inline",
161
161
  ): AppContext {
162
- const db = createTenantDb(
163
- runner,
164
- targetTenantId,
165
- "system",
166
- context.tracer,
167
- context.meter,
168
- context.signal,
169
- );
162
+ const db = createTenantDb({
163
+ db: runner,
164
+ tenantId: targetTenantId,
165
+ mode: "system",
166
+ tracer: context.tracer,
167
+ meter: context.meter,
168
+ signal: context.signal,
169
+ });
170
170
 
171
171
  // HandlerContext carries `user`; AppContext only `systemUser`. Prefer the
172
172
  // live handler user when present so notify/hasFeature keep a real SessionUser.
@@ -260,7 +260,7 @@ export async function seedTenant(
260
260
  // tenant-scoped ist, braucht der Wrap-Layer für die runtime-API zu
261
261
  // existieren. by.tenantId reicht — keine Override-Semantik wie bei
262
262
  // seedTenantMembership nötig.
263
- const tdb = createTenantDb(db, by.tenantId, "system");
263
+ const tdb = createTenantDb({ db, tenantId: by.tenantId, mode: "system" });
264
264
 
265
265
  const existing = await fetchOne(db, tenantTable, { id: options.id });
266
266
  if (existing) return { id: options.id };
@@ -323,7 +323,7 @@ export async function seedTenantMembership(
323
323
  const by = options.by ?? createSystemUser(options.tenantId);
324
324
  // System-scoped TenantDb: payload.tenantId may differ from an explicit
325
325
  // `by` override; stream tenant still follows `by` via streamTenantFor.
326
- const tdb = createTenantDb(db, options.tenantId, "system");
326
+ const tdb = createTenantDb({ db, tenantId: options.tenantId, mode: "system" });
327
327
 
328
328
  // Idempotency: duplicate seeds are common across beforeEach-resets where
329
329
  // only certain tables get truncated. A plain executor.create would trip
@@ -1,5 +1,4 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
2
- import { createEventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
1
+ import { createEventStoreExecutor, fetchOne } from "@cosmicdrift/kumiko-framework/db";
3
2
  import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
4
3
  import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
5
4
  import * as z from "zod";
@@ -1,6 +1,5 @@
1
- import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
2
1
  import { addDurationSpec } from "@cosmicdrift/kumiko-framework/compliance";
3
- import { createEventStoreExecutor } from "@cosmicdrift/kumiko-framework/db";
2
+ import { createEventStoreExecutor, fetchOne } from "@cosmicdrift/kumiko-framework/db";
4
3
  import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
5
4
  import { UnprocessableError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
6
5
  import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
@@ -1,5 +1,5 @@
1
- import { updateMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
1
  import type { DbRunner } from "@cosmicdrift/kumiko-framework/db";
2
+ import { updateMany } from "@cosmicdrift/kumiko-framework/db";
3
3
  import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
4
4
  import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
5
5
  import { userSessionTable } from "../../sessions/index.js";
@@ -1,5 +1,5 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
1
  import type { DbRunner } from "@cosmicdrift/kumiko-framework/db";
2
+ import { selectMany } from "@cosmicdrift/kumiko-framework/db";
3
3
  import type { TenantId } from "@cosmicdrift/kumiko-framework/engine";
4
4
  import { tenantTable } from "../tenant/index.js";
5
5
 
@@ -1,9 +1,9 @@
1
1
  /// <reference types="temporal-polyfill/global" preserve="true" />
2
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
3
2
  import type { DbRunner, TenantDb, WhereObject } from "@cosmicdrift/kumiko-framework/db";
4
3
  import {
5
4
  createEventStoreExecutor,
6
5
  createTenantDb,
6
+ selectMany,
7
7
  WritePurposes,
8
8
  } from "@cosmicdrift/kumiko-framework/db";
9
9
  import {
@@ -173,7 +173,7 @@ async function appendTenantStageEventIdempotent(
173
173
 
174
174
  async function markTenantDestroyFailed(db: DbRunner, tenantId: TenantId): Promise<void> {
175
175
  const user = createSystemUser(tenantId);
176
- const scopedDb = createTenantDb(db, tenantId, "system");
176
+ const scopedDb = createTenantDb({ db, tenantId, mode: "system" });
177
177
  await tenantCrud.update(
178
178
  {
179
179
  id: tenantId,
@@ -431,7 +431,7 @@ export async function runTenantDestructionSweep(args: {
431
431
  const events = await loadAggregate(args.db, tenantId, tenantId);
432
432
  const version = lastEventVersion(events);
433
433
  const user = createSystemUser(tenantId);
434
- const scopedDb = createTenantDb(args.db, tenantId, "system");
434
+ const scopedDb = createTenantDb({ db: args.db, tenantId, mode: "system" });
435
435
  // Version-guarded (no skipOptimisticLock): a concurrent cancel-destruction
436
436
  // between the `due` select above and this write also appends to the same
437
437
  // tenant stream, so an unguarded overwrite here would silently revert the
@@ -1,4 +1,3 @@
1
- import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
2
1
  import {
3
2
  configuredPiiSubjectKms,
4
3
  type SubjectId,
@@ -8,6 +7,7 @@ import {
8
7
  createEventStoreExecutor,
9
8
  createTenantDb,
10
9
  type DbRunner,
10
+ selectMany,
11
11
  WritePurposes,
12
12
  } from "@cosmicdrift/kumiko-framework/db";
13
13
  import {
@@ -143,9 +143,14 @@ async function runTenantDataHooks(ctx: DestructionStageCtx): Promise<StageRunOut
143
143
  log: ctx.escapeHatchAuditLog ?? createFallbackLogger("tenant-lifecycle"),
144
144
  });
145
145
  const hookCtx: TenantDataHookCtx = {
146
- db: createTenantDb(ctx.db, ctx.tenantId, "tenant", undefined, undefined, undefined, {
147
- unsafeRaw: reason !== undefined ? { reason } : undefined,
148
- report,
146
+ db: createTenantDb({
147
+ db: ctx.db,
148
+ tenantId: ctx.tenantId,
149
+ mode: "tenant",
150
+ grants: {
151
+ unsafeRaw: reason !== undefined ? { reason } : undefined,
152
+ report,
153
+ },
149
154
  }),
150
155
  registry: ctx.registry,
151
156
  tenantId: ctx.tenantId,
@@ -202,7 +207,7 @@ async function purgeTenantCache(ctx: DestructionStageCtx): Promise<StageRunOutco
202
207
  async function tombstoneTenantRow(ctx: DestructionStageCtx): Promise<StageRunOutcome> {
203
208
  const now = getTemporal().Now.instant();
204
209
  const user = createSystemUser(ctx.tenantId);
205
- const db = createTenantDb(ctx.db, ctx.tenantId, "system");
210
+ const db = createTenantDb({ db: ctx.db, tenantId: ctx.tenantId, mode: "system" });
206
211
  // Per-row forget() through the executor, not a bulk deleteMany: memberships
207
212
  // are an ES-managed projection (add/remove/update-roles all go through
208
213
  // tenantMembershipCrud), so a store table write here is eventless — a future