@cosmicdrift/kumiko-samples 0.385.0 → 0.387.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 (395) hide show
  1. package/LICENSE +21 -57
  2. package/README.md +1 -1
  3. package/package.json +2 -2
  4. package/packages/bundled-features/package.json +2 -2
  5. package/packages/bundled-features/src/agent-tools/tool-catalog.ts +1 -1
  6. package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +0 -2
  7. package/packages/bundled-features/src/audit/screens.ts +1 -1
  8. package/packages/bundled-features/src/auth-email-password/auth-user-row.ts +10 -10
  9. package/packages/bundled-features/src/auth-email-password/feature.ts +6 -6
  10. package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +3 -3
  11. package/packages/bundled-features/src/auth-email-password/handlers/confirm-token-flow.ts +5 -5
  12. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +1 -1
  13. package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +18 -18
  14. package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +12 -12
  15. package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +1 -1
  16. package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +24 -26
  17. package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +1 -1
  18. package/packages/bundled-features/src/auth-email-password/handlers/self-registration-status.query.ts +1 -1
  19. package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +34 -37
  20. package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +6 -7
  21. package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +1 -5
  22. package/packages/bundled-features/src/auth-email-password/index.ts +5 -5
  23. package/packages/bundled-features/src/auth-email-password/lockout-store.ts +1 -1
  24. package/packages/bundled-features/src/auth-email-password/seeding.ts +63 -66
  25. package/packages/bundled-features/src/auth-email-password/signup-token-store.ts +8 -8
  26. package/packages/bundled-features/src/auth-email-password/testing.ts +3 -3
  27. package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +57 -57
  28. package/packages/bundled-features/src/auth-email-password/web/auth-form-primitives.tsx +14 -14
  29. package/packages/bundled-features/src/auth-email-password/web/auth-gate.tsx +15 -16
  30. package/packages/bundled-features/src/auth-email-password/web/client-plugin.ts +11 -12
  31. package/packages/bundled-features/src/auth-email-password/web/confirm-account-unlock-screen.tsx +1 -1
  32. package/packages/bundled-features/src/auth-email-password/web/constants.ts +3 -3
  33. package/packages/bundled-features/src/auth-email-password/web/default-topbar-actions.tsx +14 -14
  34. package/packages/bundled-features/src/auth-email-password/web/forgot-password-screen.tsx +11 -11
  35. package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -5
  36. package/packages/bundled-features/src/auth-email-password/web/invite-accept-screen.tsx +17 -17
  37. package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +3 -4
  38. package/packages/bundled-features/src/auth-email-password/web/reset-password-screen.tsx +16 -17
  39. package/packages/bundled-features/src/auth-email-password/web/session.tsx +34 -34
  40. package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +3 -3
  41. package/packages/bundled-features/src/auth-email-password/web/signup-screen.tsx +14 -14
  42. package/packages/bundled-features/src/auth-email-password/web/tenant-switcher.tsx +26 -27
  43. package/packages/bundled-features/src/auth-email-password/web/use-shell-user.ts +12 -13
  44. package/packages/bundled-features/src/auth-email-password/web/user-menu.tsx +17 -18
  45. package/packages/bundled-features/src/auth-email-password/web/verify-email-screen.tsx +11 -12
  46. package/packages/bundled-features/src/auth-foundation/boot-checks.ts +4 -4
  47. package/packages/bundled-features/src/auth-foundation/resolve-anonymous-access.ts +4 -4
  48. package/packages/bundled-features/src/auth-foundation/types.ts +2 -2
  49. package/packages/bundled-features/src/auth-mfa/handlers/disable.write.ts +3 -3
  50. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +4 -4
  51. package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm.write.ts +2 -2
  52. package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +1 -1
  53. package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +1 -1
  54. package/packages/bundled-features/src/auth-mfa/handlers/regenerate-recovery.write.ts +5 -5
  55. package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +1 -1
  56. package/packages/bundled-features/src/auth-mfa/token-secrets.ts +1 -1
  57. package/packages/bundled-features/src/auth-mfa/web/client-plugin.ts +2 -2
  58. package/packages/bundled-features/src/auth-mfa/web/i18n.ts +3 -3
  59. package/packages/bundled-features/src/auth-mfa/web/index.ts +4 -4
  60. package/packages/bundled-features/src/auth-mfa/web/mfa-client.ts +17 -16
  61. package/packages/bundled-features/src/auth-mfa/web/mfa-verify-screen.tsx +6 -6
  62. package/packages/bundled-features/src/billing-foundation/aggregate-id.ts +10 -11
  63. package/packages/bundled-features/src/billing-foundation/entities.ts +27 -27
  64. package/packages/bundled-features/src/billing-foundation/events.ts +22 -21
  65. package/packages/bundled-features/src/billing-foundation/feature.ts +42 -43
  66. package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +3 -5
  67. package/packages/bundled-features/src/billing-foundation/handlers/create-checkout-session.write.ts +18 -17
  68. package/packages/bundled-features/src/billing-foundation/handlers/create-portal-session.write.ts +11 -12
  69. package/packages/bundled-features/src/billing-foundation/handlers/list-subscriptions.query.ts +4 -4
  70. package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +20 -20
  71. package/packages/bundled-features/src/billing-foundation/projection.ts +38 -37
  72. package/packages/bundled-features/src/billing-foundation/subscription-tier-sync.ts +3 -3
  73. package/packages/bundled-features/src/billing-foundation/tenant-destroy-hook.ts +7 -8
  74. package/packages/bundled-features/src/billing-foundation/types.ts +64 -65
  75. package/packages/bundled-features/src/billing-foundation/web/billing-plans-panel.tsx +4 -4
  76. package/packages/bundled-features/src/billing-foundation/webhook-handler.ts +1 -1
  77. package/packages/bundled-features/src/cap-counter/aggregate-id.ts +8 -9
  78. package/packages/bundled-features/src/cap-counter/constants.ts +11 -12
  79. package/packages/bundled-features/src/cap-counter/enforce-cap.ts +64 -67
  80. package/packages/bundled-features/src/cap-counter/entity.ts +29 -29
  81. package/packages/bundled-features/src/cap-counter/feature.ts +34 -35
  82. package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +31 -31
  83. package/packages/bundled-features/src/cap-counter/handlers/mark-soft-warned.write.ts +4 -5
  84. package/packages/bundled-features/src/cap-counter/stock-cap-guard.ts +1 -1
  85. package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +3 -5
  86. package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -3
  87. package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
  88. package/packages/bundled-features/src/channel-email/smtp-transport.ts +34 -31
  89. package/packages/bundled-features/src/channel-in-app/handlers/unread-count.query.ts +3 -4
  90. package/packages/bundled-features/src/compliance-profiles/feature.ts +15 -16
  91. package/packages/bundled-features/src/compliance-profiles/handlers/for-tenant.query.ts +3 -6
  92. package/packages/bundled-features/src/compliance-profiles/handlers/list-profiles.query.ts +5 -5
  93. package/packages/bundled-features/src/compliance-profiles/handlers/needs-profile.query.ts +4 -4
  94. package/packages/bundled-features/src/compliance-profiles/handlers/set-profile.write.ts +13 -14
  95. package/packages/bundled-features/src/compliance-profiles/handlers/sub-processors.query.ts +9 -11
  96. package/packages/bundled-features/src/compliance-profiles/resolve-for-tenant.ts +7 -7
  97. package/packages/bundled-features/src/compliance-profiles/schema/profile-selection.ts +18 -23
  98. package/packages/bundled-features/src/compliance-profiles/seeding.ts +14 -15
  99. package/packages/bundled-features/src/compliance-profiles-ops/handlers/tenants-missing-profile.query.ts +3 -3
  100. package/packages/bundled-features/src/compliance-profiles-ops/index.ts +2 -2
  101. package/packages/bundled-features/src/config/handlers/readiness.query.ts +7 -7
  102. package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +4 -5
  103. package/packages/bundled-features/src/config/handlers/set.write.ts +4 -4
  104. package/packages/bundled-features/src/config/resolver.ts +4 -4
  105. package/packages/bundled-features/src/config/table.ts +10 -10
  106. package/packages/bundled-features/src/config/write-helpers.ts +1 -1
  107. package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +13 -12
  108. package/packages/bundled-features/src/custom-fields/aggregate-id.ts +16 -17
  109. package/packages/bundled-features/src/custom-fields/entity.ts +49 -47
  110. package/packages/bundled-features/src/custom-fields/events.ts +7 -8
  111. package/packages/bundled-features/src/custom-fields/feature.ts +70 -72
  112. package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +9 -8
  113. package/packages/bundled-features/src/custom-fields/handlers/define-tenant-field.write.ts +28 -26
  114. package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +6 -7
  115. package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +12 -13
  116. package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +25 -28
  117. package/packages/bundled-features/src/custom-fields/handlers/update-tenant-field.write.ts +6 -6
  118. package/packages/bundled-features/src/custom-fields/lib/field-access.ts +2 -2
  119. package/packages/bundled-features/src/custom-fields/lib/parse-serialized-field.ts +1 -1
  120. package/packages/bundled-features/src/custom-fields/lib/quota.ts +1 -1
  121. package/packages/bundled-features/src/custom-fields/lib/value-schema.ts +10 -12
  122. package/packages/bundled-features/src/custom-fields/run-retention.ts +3 -3
  123. package/packages/bundled-features/src/custom-fields/schemas.ts +14 -14
  124. package/packages/bundled-features/src/custom-fields/web/client-plugin.tsx +2 -5
  125. package/packages/bundled-features/src/custom-fields/web/constants.ts +2 -2
  126. package/packages/bundled-features/src/custom-fields/web/custom-fields-form-section.tsx +26 -26
  127. package/packages/bundled-features/src/custom-fields/wire-for-entity.ts +65 -67
  128. package/packages/bundled-features/src/custom-fields/wire-user-data-rights.ts +3 -3
  129. package/packages/bundled-features/src/data-retention/_internal/parse-override.ts +2 -3
  130. package/packages/bundled-features/src/data-retention/feature.ts +11 -18
  131. package/packages/bundled-features/src/data-retention/handlers/policy-for.query.ts +6 -6
  132. package/packages/bundled-features/src/data-retention/keep-for.ts +17 -17
  133. package/packages/bundled-features/src/data-retention/override-schema.ts +13 -15
  134. package/packages/bundled-features/src/data-retention/presets.ts +18 -23
  135. package/packages/bundled-features/src/data-retention/resolve-for-tenant.ts +1 -1
  136. package/packages/bundled-features/src/data-retention/resolve-tenant-preset.ts +17 -16
  137. package/packages/bundled-features/src/data-retention/resolver.ts +33 -32
  138. package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +71 -58
  139. package/packages/bundled-features/src/data-retention/schema/tenant-retention-override.ts +13 -11
  140. package/packages/bundled-features/src/delivery/feature.ts +3 -3
  141. package/packages/bundled-features/src/delivery/handlers/log.query.ts +1 -1
  142. package/packages/bundled-features/src/delivery/tables.ts +9 -8
  143. package/packages/bundled-features/src/delivery/unsubscribe.ts +4 -4
  144. package/packages/bundled-features/src/delivery/upsert-preference.ts +3 -4
  145. package/packages/bundled-features/src/document-ingest-foundation/entity.ts +5 -5
  146. package/packages/bundled-features/src/document-ingest-foundation/events.ts +2 -2
  147. package/packages/bundled-features/src/document-ingest-foundation/feature.ts +2 -2
  148. package/packages/bundled-features/src/document-ingest-foundation/pages.ts +1 -1
  149. package/packages/bundled-features/src/document-ingest-foundation/tenant-destroy-hook.ts +4 -4
  150. package/packages/bundled-features/src/feature-toggles/compose-tier-resolver.ts +1 -1
  151. package/packages/bundled-features/src/feature-toggles/feature.ts +1 -1
  152. package/packages/bundled-features/src/feature-toggles/global-feature-state-table.ts +1 -1
  153. package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +5 -5
  154. package/packages/bundled-features/src/feature-toggles/toggle-runtime.ts +1 -1
  155. package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +1 -1
  156. package/packages/bundled-features/src/feature-toggles/web/constants.ts +1 -1
  157. package/packages/bundled-features/src/file-derivatives/feature.ts +2 -2
  158. package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +1 -1
  159. package/packages/bundled-features/src/file-derivatives/presets.ts +1 -1
  160. package/packages/bundled-features/src/file-foundation/feature.ts +6 -6
  161. package/packages/bundled-features/src/file-provider-inmemory/feature.ts +16 -16
  162. package/packages/bundled-features/src/file-provider-s3/feature.ts +16 -16
  163. package/packages/bundled-features/src/file-provider-s3/lib/s3-provider.ts +6 -6
  164. package/packages/bundled-features/src/files/feature.ts +6 -6
  165. package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +5 -5
  166. package/packages/bundled-features/src/files-tenant-data/hooks.ts +24 -26
  167. package/packages/bundled-features/src/files-tenant-data/index.ts +1 -1
  168. package/packages/bundled-features/src/folders/feature.ts +1 -1
  169. package/packages/bundled-features/src/folders/web/folder-manager.tsx +2 -2
  170. package/packages/bundled-features/src/folders/web/tree.ts +5 -5
  171. package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +1 -1
  172. package/packages/bundled-features/src/form-draft/db/queries/owned-file-refs.ts +1 -1
  173. package/packages/bundled-features/src/form-draft/entity.ts +3 -3
  174. package/packages/bundled-features/src/form-draft/feature.ts +4 -5
  175. package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +1 -1
  176. package/packages/bundled-features/src/form-draft/release-file-refs.ts +6 -6
  177. package/packages/bundled-features/src/form-draft/schemas.ts +3 -3
  178. package/packages/bundled-features/src/form-draft/web/constants.ts +0 -2
  179. package/packages/bundled-features/src/inbound-mail-foundation/aggregate-id.ts +19 -19
  180. package/packages/bundled-features/src/inbound-mail-foundation/connect-routes.ts +4 -3
  181. package/packages/bundled-features/src/inbound-mail-foundation/constants.ts +30 -33
  182. package/packages/bundled-features/src/inbound-mail-foundation/entities.ts +47 -48
  183. package/packages/bundled-features/src/inbound-mail-foundation/events.ts +54 -50
  184. package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +39 -39
  185. package/packages/bundled-features/src/inbound-mail-foundation/handlers/account-state.ts +8 -8
  186. package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +25 -26
  187. package/packages/bundled-features/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +7 -7
  188. package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +50 -51
  189. package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-accounts.query.ts +8 -8
  190. package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-messages.query.ts +10 -10
  191. package/packages/bundled-features/src/inbound-mail-foundation/handlers/scope-visibility.ts +3 -4
  192. package/packages/bundled-features/src/inbound-mail-foundation/handlers/update-account.write.ts +11 -11
  193. package/packages/bundled-features/src/inbound-mail-foundation/oauth-state.ts +16 -15
  194. package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +31 -29
  195. package/packages/bundled-features/src/inbound-mail-foundation/provider-factory.ts +9 -9
  196. package/packages/bundled-features/src/inbound-mail-foundation/retention-sweep.ts +45 -41
  197. package/packages/bundled-features/src/inbound-mail-foundation/tenant-destroy-hook.ts +14 -16
  198. package/packages/bundled-features/src/inbound-mail-foundation/types.ts +66 -67
  199. package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +69 -68
  200. package/packages/bundled-features/src/inbound-provider-imap/credential-document.ts +13 -13
  201. package/packages/bundled-features/src/inbound-provider-imap/feature.ts +42 -40
  202. package/packages/bundled-features/src/inbound-provider-imap/imap-client.ts +20 -19
  203. package/packages/bundled-features/src/inbound-provider-inmemory/feature.ts +21 -21
  204. package/packages/bundled-features/src/jobs/db/queries/retention.ts +2 -2
  205. package/packages/bundled-features/src/jobs/db/queries/stale-run-sweep.ts +3 -3
  206. package/packages/bundled-features/src/jobs/events.ts +1 -1
  207. package/packages/bundled-features/src/jobs/feature.ts +6 -7
  208. package/packages/bundled-features/src/jobs/handlers/detail.query.ts +4 -4
  209. package/packages/bundled-features/src/jobs/handlers/list.query.ts +1 -1
  210. package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
  211. package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +1 -1
  212. package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
  213. package/packages/bundled-features/src/jobs/job-instant.ts +1 -1
  214. package/packages/bundled-features/src/jobs/job-run-logger.ts +14 -15
  215. package/packages/bundled-features/src/jobs/job-run-table.ts +3 -3
  216. package/packages/bundled-features/src/jobs/screens.ts +1 -1
  217. package/packages/bundled-features/src/jobs/tenant-job-failure-table.ts +1 -1
  218. package/packages/bundled-features/src/jobs/tenant-job-run-table.ts +1 -1
  219. package/packages/bundled-features/src/ledger/entity.ts +5 -5
  220. package/packages/bundled-features/src/ledger/feature.ts +3 -3
  221. package/packages/bundled-features/src/ledger/handlers/confirm-schedule-period.write.ts +3 -3
  222. package/packages/bundled-features/src/ledger/recurring.ts +12 -12
  223. package/packages/bundled-features/src/ledger/schemas.ts +1 -1
  224. package/packages/bundled-features/src/ledger/web/constants.ts +2 -2
  225. package/packages/bundled-features/src/ledger/web/index.ts +7 -7
  226. package/packages/bundled-features/src/legal-pages/feature.ts +40 -41
  227. package/packages/bundled-features/src/legal-pages/markdown.ts +3 -3
  228. package/packages/bundled-features/src/legal-pages/web/client-plugin.ts +23 -24
  229. package/packages/bundled-features/src/legal-pages/web/index.ts +0 -2
  230. package/packages/bundled-features/src/mail-foundation/feature.ts +26 -27
  231. package/packages/bundled-features/src/mail-transport-inmemory/feature.ts +27 -28
  232. package/packages/bundled-features/src/mail-transport-smtp/feature.ts +20 -20
  233. package/packages/bundled-features/src/managed-pages/branding.ts +6 -6
  234. package/packages/bundled-features/src/managed-pages/feature.ts +62 -62
  235. package/packages/bundled-features/src/managed-pages/handlers/by-slug.query.ts +5 -6
  236. package/packages/bundled-features/src/managed-pages/handlers/by-tenant-published.query.ts +8 -8
  237. package/packages/bundled-features/src/managed-pages/handlers/set.write.ts +5 -7
  238. package/packages/bundled-features/src/managed-pages/screens/page-screens.ts +11 -11
  239. package/packages/bundled-features/src/managed-pages/seeding.ts +8 -8
  240. package/packages/bundled-features/src/managed-pages/table.ts +16 -15
  241. package/packages/bundled-features/src/managed-pages/web/client-plugin.tsx +6 -6
  242. package/packages/bundled-features/src/managed-pages/web/i18n.ts +1 -1
  243. package/packages/bundled-features/src/notes-history/entity.ts +4 -4
  244. package/packages/bundled-features/src/notes-history/feature.ts +2 -2
  245. package/packages/bundled-features/src/notes-history-user-data/hooks.ts +1 -1
  246. package/packages/bundled-features/src/page-render/layout.ts +9 -9
  247. package/packages/bundled-features/src/page-render/markdown.ts +11 -11
  248. package/packages/bundled-features/src/page-render/security-headers.ts +7 -6
  249. package/packages/bundled-features/src/personal-access-tokens/feature.ts +5 -5
  250. package/packages/bundled-features/src/personal-access-tokens/roles.ts +2 -2
  251. package/packages/bundled-features/src/readiness/handlers/status.query.ts +3 -3
  252. package/packages/bundled-features/src/renderer-foundation/api.ts +12 -13
  253. package/packages/bundled-features/src/renderer-foundation/constants.ts +2 -2
  254. package/packages/bundled-features/src/renderer-foundation/feature.ts +7 -7
  255. package/packages/bundled-features/src/renderer-foundation/types.ts +11 -12
  256. package/packages/bundled-features/src/secrets/feature.ts +9 -9
  257. package/packages/bundled-features/src/secrets/web/constants.ts +2 -2
  258. package/packages/bundled-features/src/seo/feature.ts +3 -3
  259. package/packages/bundled-features/src/sessions/constants.ts +1 -1
  260. package/packages/bundled-features/src/sessions/feature.ts +9 -9
  261. package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +2 -2
  262. package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +2 -2
  263. package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
  264. package/packages/bundled-features/src/sessions/schema/user-session.ts +4 -4
  265. package/packages/bundled-features/src/sessions/screens.ts +2 -2
  266. package/packages/bundled-features/src/sessions/session-callbacks.ts +2 -2
  267. package/packages/bundled-features/src/sessions/session-revoked-event.ts +2 -2
  268. package/packages/bundled-features/src/shared/assert-no-where-rule-in-ownership-write.ts +1 -1
  269. package/packages/bundled-features/src/shared/decrypt-stored-pii.ts +1 -1
  270. package/packages/bundled-features/src/shared/encrypt-for-direct-write.ts +1 -1
  271. package/packages/bundled-features/src/shared/map-with-concurrency.ts +5 -4
  272. package/packages/bundled-features/src/shared/parent-visibility.ts +2 -2
  273. package/packages/bundled-features/src/shared/password-hashing.ts +1 -1
  274. package/packages/bundled-features/src/shared/signup-handover.ts +1 -2
  275. package/packages/bundled-features/src/shared/single-use-token-store.ts +1 -1
  276. package/packages/bundled-features/src/subscription-mollie/constants.ts +15 -17
  277. package/packages/bundled-features/src/subscription-mollie/feature.ts +41 -42
  278. package/packages/bundled-features/src/subscription-mollie/index.ts +3 -3
  279. package/packages/bundled-features/src/subscription-mollie/plugin-methods.ts +17 -16
  280. package/packages/bundled-features/src/subscription-mollie/verify-webhook.ts +34 -34
  281. package/packages/bundled-features/src/subscription-stripe/constants.ts +4 -6
  282. package/packages/bundled-features/src/subscription-stripe/feature.ts +44 -43
  283. package/packages/bundled-features/src/subscription-stripe/index.ts +6 -6
  284. package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +22 -27
  285. package/packages/bundled-features/src/subscription-stripe/runtime.ts +2 -2
  286. package/packages/bundled-features/src/subscription-stripe/verify-webhook.ts +62 -64
  287. package/packages/bundled-features/src/tags/feature.ts +3 -3
  288. package/packages/bundled-features/src/tags/screens.ts +1 -1
  289. package/packages/bundled-features/src/template-resolver/api.ts +10 -10
  290. package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +5 -5
  291. package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +1 -1
  292. package/packages/bundled-features/src/template-resolver/handlers/shared.ts +2 -2
  293. package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +3 -3
  294. package/packages/bundled-features/src/template-resolver/handlers/upsert-system.write.ts +3 -4
  295. package/packages/bundled-features/src/template-resolver/handlers/upsert-tenant.write.ts +4 -5
  296. package/packages/bundled-features/src/template-resolver/seeding.ts +4 -4
  297. package/packages/bundled-features/src/template-resolver/table.ts +13 -14
  298. package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +2 -2
  299. package/packages/bundled-features/src/tenant/feature.ts +7 -7
  300. package/packages/bundled-features/src/tenant/handlers/member-directory.query.ts +1 -1
  301. package/packages/bundled-features/src/tenant/handlers/members.query.ts +1 -1
  302. package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
  303. package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +1 -1
  304. package/packages/bundled-features/src/tenant/handlers/tenant-directory.query.ts +1 -1
  305. package/packages/bundled-features/src/tenant/invitation-table.ts +37 -40
  306. package/packages/bundled-features/src/tenant/membership-table.ts +3 -3
  307. package/packages/bundled-features/src/tenant/schema/tenant.ts +7 -9
  308. package/packages/bundled-features/src/tenant/screens.ts +1 -1
  309. package/packages/bundled-features/src/tenant/seeding.ts +19 -18
  310. package/packages/bundled-features/src/tenant/testing.ts +5 -6
  311. package/packages/bundled-features/src/tenant/web/constants.ts +2 -2
  312. package/packages/bundled-features/src/tenant-handover/events.ts +5 -7
  313. package/packages/bundled-features/src/tenant-handover/feature.ts +1 -1
  314. package/packages/bundled-features/src/tenant-handover/grant.ts +1 -1
  315. package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
  316. package/packages/bundled-features/src/tenant-handover/move-entity-graph.ts +8 -9
  317. package/packages/bundled-features/src/tenant-handover/signup-handover-provider.ts +1 -2
  318. package/packages/bundled-features/src/tenant-handover/transfer-graph.ts +4 -5
  319. package/packages/bundled-features/src/tenant-lifecycle/boot-checks.ts +1 -1
  320. package/packages/bundled-features/src/tenant-lifecycle/feature.ts +1 -1
  321. package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +2 -2
  322. package/packages/bundled-features/src/tenant-lifecycle/stages.ts +1 -1
  323. package/packages/bundled-features/src/tenant-settings/constants.ts +1 -1
  324. package/packages/bundled-features/src/tenant-settings/tenant-defaults.ts +12 -5
  325. package/packages/bundled-features/src/tier-engine/aggregate-id.ts +15 -16
  326. package/packages/bundled-features/src/tier-engine/compose-app.ts +14 -14
  327. package/packages/bundled-features/src/tier-engine/entity.ts +18 -19
  328. package/packages/bundled-features/src/tier-engine/feature.ts +88 -87
  329. package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +6 -7
  330. package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +4 -4
  331. package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +8 -8
  332. package/packages/bundled-features/src/tier-engine/tier-resolver.ts +2 -2
  333. package/packages/bundled-features/src/tier-engine/trial.ts +13 -13
  334. package/packages/bundled-features/src/tier-engine/web/index.ts +4 -4
  335. package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +8 -8
  336. package/packages/bundled-features/src/user/handlers/create.write.ts +4 -4
  337. package/packages/bundled-features/src/user/schema/user.ts +45 -44
  338. package/packages/bundled-features/src/user/seeding.ts +40 -40
  339. package/packages/bundled-features/src/user/testing.ts +3 -3
  340. package/packages/bundled-features/src/user-data-rights/audit-download.ts +27 -28
  341. package/packages/bundled-features/src/user-data-rights/boot-checks.ts +1 -1
  342. package/packages/bundled-features/src/user-data-rights/deletion-token.ts +1 -1
  343. package/packages/bundled-features/src/user-data-rights/feature.ts +112 -113
  344. package/packages/bundled-features/src/user-data-rights/handlers/cancel-deletion.write.ts +9 -9
  345. package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +8 -8
  346. package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +29 -30
  347. package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +40 -42
  348. package/packages/bundled-features/src/user-data-rights/handlers/export-status.query.ts +8 -9
  349. package/packages/bundled-features/src/user-data-rights/handlers/lift-restriction.write.ts +7 -8
  350. package/packages/bundled-features/src/user-data-rights/handlers/list-download-attempts.query.ts +2 -2
  351. package/packages/bundled-features/src/user-data-rights/handlers/my-audit-log.query.ts +4 -4
  352. package/packages/bundled-features/src/user-data-rights/handlers/request-deletion-by-email.write.ts +30 -29
  353. package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +15 -18
  354. package/packages/bundled-features/src/user-data-rights/handlers/request-export.write.ts +42 -41
  355. package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +22 -19
  356. package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +8 -8
  357. package/packages/bundled-features/src/user-data-rights/index.ts +8 -10
  358. package/packages/bundled-features/src/user-data-rights/lib/default-mailers.ts +3 -3
  359. package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +24 -27
  360. package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +166 -276
  361. package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +85 -107
  362. package/packages/bundled-features/src/user-data-rights/run-user-export.ts +67 -69
  363. package/packages/bundled-features/src/user-data-rights/schema/download-attempt.ts +11 -11
  364. package/packages/bundled-features/src/user-data-rights/schema/download-token.ts +37 -41
  365. package/packages/bundled-features/src/user-data-rights/schema/export-job.ts +65 -67
  366. package/packages/bundled-features/src/user-data-rights/token-helpers.ts +21 -25
  367. package/packages/bundled-features/src/user-data-rights/web/client-plugin.tsx +6 -6
  368. package/packages/bundled-features/src/user-data-rights/web/confirm-deletion-screen.tsx +6 -5
  369. package/packages/bundled-features/src/user-data-rights/web/constants.ts +1 -1
  370. package/packages/bundled-features/src/user-data-rights/web/index.ts +5 -5
  371. package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +14 -13
  372. package/packages/bundled-features/src/user-data-rights/web/public-deletion-gate.tsx +13 -12
  373. package/packages/bundled-features/src/user-data-rights/web/request-deletion-screen.tsx +6 -6
  374. package/packages/bundled-features/src/user-data-rights/zip-path.ts +41 -40
  375. package/packages/bundled-features/src/user-data-rights-defaults/feature.ts +15 -15
  376. package/packages/bundled-features/src/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.ts +3 -5
  377. package/packages/bundled-features/src/user-data-rights-defaults/hooks/file-ref.userdata-hook.ts +45 -51
  378. package/packages/bundled-features/src/user-data-rights-defaults/hooks/job-run.userdata-hook.ts +2 -2
  379. package/packages/bundled-features/src/user-data-rights-defaults/hooks/notification-preference.userdata-hook.ts +1 -1
  380. package/packages/bundled-features/src/user-data-rights-defaults/hooks/user-session.userdata-hook.ts +3 -3
  381. package/packages/bundled-features/src/user-data-rights-defaults/hooks/user.userdata-hook.ts +32 -31
  382. package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +13 -13
  383. package/packages/bundled-features/src/user-profile/index.ts +3 -3
  384. package/packages/bundled-features/src/user-profile/web/client-plugin.ts +1 -1
  385. package/packages/bundled-features/src/user-profile/web/constants.ts +1 -1
  386. package/packages/bundled-features/src/user-profile/web/profile-screen.tsx +1 -1
  387. package/packages/bundled-features/src/workflow-runner/aggregate-id.ts +1 -1
  388. package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -5
  389. package/packages/bundled-features/src/workflow-runner/event-trigger.ts +4 -15
  390. package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
  391. package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +4 -4
  392. package/packages/bundled-features/src/workflow-runner/pending-projection.ts +6 -7
  393. package/packages/bundled-features/src/workflow-runner/runner.ts +6 -6
  394. package/packages/bundled-features/src/workflow-runner/tables.ts +6 -6
  395. package/packages/bundled-features/src/workflow-runner/workflow-registry.ts +1 -1
@@ -23,13 +23,13 @@ import { MANAGED_PAGES_I18N } from "./web/i18n.ts";
23
23
  // 60s-shared-cache saves the origin-revalidate roundtrip; CMS edits are live within 60s.
24
24
  const PUBLIC_PAGE_CACHE = { kind: "revalidate", maxAgeSeconds: 60 } as const;
25
25
 
26
- // QN-Konstante als dokumentierter Public-Contract — der Render-Pfad ruft
27
- // die by-slug-Query via systemQuery in-process (kein Code-Import des
28
- // Handlers, symmetrisch zum legal-pages-Muster).
26
+ // QN constant as a documented public contract — the render path calls
27
+ // the by-slug query in-process via systemQuery (without importing the
28
+ // handler's code, symmetrically with the legal-pages pattern).
29
29
  const BY_SLUG_QN = "managed-pages:query:by-slug";
30
30
 
31
- // Raw Handler-Return von bySlugQuery (published-only) — systemQuery dispatcht
32
- // direkt gegen den Handler, keine `{data}`-Envelope wie am /api/query-Wire.
31
+ // Raw handler return from bySlugQuery (published-only) — systemQuery dispatches
32
+ // directly to the handler, without the `{data}` envelope used on the /api/query wire.
33
33
  type BySlugQueryResult = {
34
34
  title: string;
35
35
  body: string;
@@ -83,61 +83,61 @@ export type ManagedPagesWrapLayout = (opts: {
83
83
  }) => string;
84
84
 
85
85
  export type ManagedPagesOptions = {
86
- /** Host → tenantId für anonyme per-Tenant-Auslieferung. NULL → 404 (kein
87
- * Tenant für diesen Host). Apex-/Marketing-Apps geben hier ihre Subdomain-
88
- * /Custom-Domain-Auflösung rein; single-tenant gibt konstant einen
89
- * tenantId (oder SYSTEM_TENANT_ID) zurück. Erforderlich, weil der Apex-
90
- * Host keinen ambient ctx.tenantId hat. */
86
+ /** Host → tenantId for anonymous per-tenant delivery. NULL → 404 (no
87
+ * tenant for this host). Apex/marketing apps provide their subdomain or
88
+ * custom-domain resolution here; single-tenant apps return a constant
89
+ * tenantId (or SYSTEM_TENANT_ID). Required because the apex host has no
90
+ * ambient ctx.tenantId. */
91
91
  readonly resolveApexTenant: (host: string) => Promise<string | null> | string | null;
92
- /** Custom Layout-Wrapper (Branding/Chrome). Default: minimaler
93
- * page-render-Skeleton. Erhält slug + SEO-Meta zur freien Nutzung.
94
- * **`branding` ist RAW, untrusted tenant input.** `title`/`description`
95
- * sind am Write nur längen-gecappt, NICHT HTML-escaped; `customCss` ist
96
- * ungesanitet. Der Wrapper MUSS sie über die Boundary-Helper emittieren
97
- * (alle re-exported von `@cosmicdrift/kumiko-bundled-features/managed-pages`):
98
- * `brandingHeaderHtml(branding)` + `brandingStyleBlock(branding)` (escapen
99
- * Header/Theme) und — mit allowCustomCss — `tenantStyleBlock(branding.
100
- * customCss)` ins `<head>` plus `TENANT_CONTENT_ATTR` am Body-Container. Ein
101
- * Custom-Wrapper der `branding.title` selbst interpoliert ist stored XSS;
102
- * der Default-Wrapper nutzt durchweg die Helper. */
92
+ /** Custom layout wrapper (branding/chrome). Default: a minimal page-render
93
+ * skeleton. Receives slug + SEO meta for free use.
94
+ * **`branding` is RAW, untrusted tenant input.** `title`/`description`
95
+ * are only length-capped on write, NOT HTML-escaped; `customCss` is
96
+ * unsanitized. The wrapper MUST emit them through the boundary helpers
97
+ * (all re-exported from `@cosmicdrift/kumiko-bundled-features/managed-pages`):
98
+ * `brandingHeaderHtml(branding)` + `brandingStyleBlock(branding)` (which
99
+ * escape header/theme) and, with allowCustomCss, `tenantStyleBlock(branding.
100
+ * customCss)` in the `<head>` plus `TENANT_CONTENT_ATTR` on the body
101
+ * container. A custom wrapper that interpolates `branding.title` itself is
102
+ * stored XSS; the default wrapper uses the helpers throughout. */
103
103
  readonly wrapLayout?: ManagedPagesWrapLayout;
104
- /** Basis-Pfad der Page-Routes. Default "/p" → GET /p/:slug. */
104
+ /** Base path for page routes. Default "/p" → GET /p/:slug. */
105
105
  readonly basePath?: string;
106
- /** Default-Sprache wenn `?lang=` fehlt. Default "en". */
106
+ /** Default language when `?lang=` is missing. Default "en". */
107
107
  readonly defaultLang?: string;
108
- /** Aktiviert die per-Tenant Custom-CSS-Capability (raw, untrusted): ein
109
- * `branding-custom-css` Config-Key + ein CSS-Feld im Branding-Editor + die
110
- * Render-Emission als scoped, allowlist-sanitized `<style data-tenant-css>`.
111
- * Default **false** (fail-closed — opt-in für untrusted-Tenant-Input). Auch
112
- * wenn true, wird die Emission zusätzlich per-Tenant über das
113
- * `managed-pages-css`-Toggle (createManagedPagesCssFeature) gegated, sobald
114
- * ein feature-toggles/tier-engine-Runtime verdrahtet ist. Der Render-time-
115
- * Sanitizer (page-render/css-sanitize) ist der Safety-Boundary. */
108
+ /** Enables the per-tenant custom CSS capability (raw, untrusted): a
109
+ * `branding-custom-css` config key + a CSS field in the branding editor +
110
+ * render emission as a scoped, allowlist-sanitized `<style data-tenant-css>`.
111
+ * Default **false** (fail-closed — opt-in for untrusted tenant input). Even
112
+ * when true, emission is additionally gated per tenant by the
113
+ * `managed-pages-css` toggle (createManagedPagesCssFeature) once a
114
+ * feature-toggles/tier-engine runtime is wired. The render-time sanitizer
115
+ * (page-render/css-sanitize) is the safety boundary. */
116
116
  readonly allowCustomCss?: boolean;
117
117
  };
118
118
 
119
- // managed-pages — vom Tenant editierbare, server-gerenderte Public-Pages.
120
- // Generalisiert das legal-pages-Render-Muster: eine dynamische Slug-Route
121
- // (`GET /p/:slug`), die den Tenant aus dem Host auflöst (resolveApexTenant),
122
- // die published Page lädt, Markdown gehärtet rendert (page-render) und über
123
- // einen optionalen wrapLayout in Chrome legt. Drafts → 404. Per-Tenant-
124
- // Content wird per `Vary: Host` cache-isoliert.
119
+ // managed-pages — tenant-editable, server-rendered public pages.
120
+ // Generalizes the legal-pages rendering pattern: a dynamic slug route
121
+ // (`GET /p/:slug`) that resolves the tenant from the Host (resolveApexTenant),
122
+ // loads the published page, renders hardened Markdown (page-render), and wraps
123
+ // it in chrome through an optional wrapLayout. Drafts → 404. Per-tenant
124
+ // content is cache-isolated through `Vary: Host`.
125
125
  //
126
- // Admin-Authoring: registriert entityList + entityEdit für `page` (TenantAdmin/
127
- // SystemAdmin) + die Convention-CRUD-Handler die der Renderer per Konvention
128
- // dispatcht. Die Screens MÜSSEN hier liegen (Boot-Validator verlangt entity-Ref
129
- // same-feature); Nav/Workspace bleibt App-Sache.
126
+ // Admin authoring: registers entityList + entityEdit for `page` (TenantAdmin/
127
+ // SystemAdmin) and the convention CRUD handlers dispatched by the renderer.
128
+ // The screens MUST live here (the boot validator requires the entity reference
129
+ // in the same feature); navigation/workspace remains the app's responsibility.
130
130
  //
131
- // Voraussetzungen am App-Bootstrap:
132
- // • anonymousAccess so verdrahtet, dass der X-Tenant-Header honoriert wird
133
- // — Multi-Tenant nutzt einen tenantResolver (oder keinen defaultTenantId).
134
- // Ein fixer defaultTenantId lockt Single-Tenant und lehnt den per-Page
135
- // gesetzten X-Tenant mit 400 tenant_mismatch ab.
136
- // • Admin-UI: die App zeigt via `r.nav({ screen: "managed-pages:screen:
137
- // page-list" })` + Workspace-Eintrag auf die hier deklarierten Screens
138
- // (cross-feature Nav→Screen ist global-validiert) und grantet ihren Admins
139
- // TenantAdmin. Ohne Nav bleiben die Screens dormant — kein Leak in
140
- // flat-nav-Apps die managed-pages nur zum Public-Render nutzen.
131
+ // App bootstrap requirements:
132
+ // • anonymousAccess must be wired to honor the X-Tenant header
133
+ // — multi-tenant apps use a tenantResolver (or no defaultTenantId).
134
+ // A fixed defaultTenantId locks the app to single-tenant mode and rejects
135
+ // the per-page X-Tenant with 400 tenant_mismatch.
136
+ // • Admin UI: the app exposes these screens via `r.nav({ screen:
137
+ // "managed-pages:screen:page-list" })` plus a workspace entry
138
+ // (cross-feature Nav→Screen is globally validated) and grants its admins
139
+ // TenantAdmin. Without navigation, the screens remain dormant — no leak in
140
+ // flat-nav apps that use managed-pages only for public rendering.
141
141
  export function createManagedPagesFeature(opts: ManagedPagesOptions): FeatureDefinition {
142
142
  const wrapLayout: ManagedPagesWrapLayout =
143
143
  opts.wrapLayout ??
@@ -192,8 +192,8 @@ export function createManagedPagesFeature(opts: ManagedPagesOptions): FeatureDef
192
192
  path: `${basePath}/:slug`,
193
193
  anonymous: true,
194
194
  handler: async (c, { systemQuery }) => {
195
- // `param("slug")` ist string|undefined, weil `path` ein computed
196
- // Template ist (Hono inferiert `:slug` nur aus String-Literalen).
195
+ // `param("slug")` is string|undefined because `path` is a computed
196
+ // template (Hono infers `:slug` only from string literals).
197
197
  const slug = c.req.param("slug");
198
198
  if (!slug) return c.text("not found", 404);
199
199
  const lang = c.req.query("lang") || defaultLang;
@@ -204,13 +204,13 @@ export function createManagedPagesFeature(opts: ManagedPagesOptions): FeatureDef
204
204
  const tenantId = await opts.resolveApexTenant(host);
205
205
  if (!tenantId) return c.text("not found", 404);
206
206
 
207
- // Page + branding read in parallel, beide über systemQuery in-
208
- // process gegen den host-resolved tenantId erzwungen (kein X-Tenant-
209
- // Header-Trick über app.fetch — der sähe für einen host-basierten
210
- // anonymousAccess-Resolver wie ein Client-Override aus und würde
211
- // von resolverTrust: "authoritative" zurecht abgelehnt; siehe
212
- // systemQuery's Doc in http-route.ts). Branding ist Deko → ein
213
- // Fehlschlag degradiert zum unbranded Default, blockt nie die Page.
207
+ // Page and branding are read in parallel, both forced through systemQuery
208
+ // in-process for the host-resolved tenantId (no X-Tenant header trick
209
+ // through app.fetch — for a host-based anonymousAccess resolver, that
210
+ // would look like a client override and would rightly be rejected by
211
+ // resolverTrust: "authoritative"; see systemQuery's documentation in
212
+ // http-route.ts). Branding is decorative → a failure degrades to the
213
+ // unbranded default and never blocks the page.
214
214
  let pageSettled: { ok: true; data: BySlugQueryResult } | { ok: false };
215
215
  let brandingResult: BrandingTokens;
216
216
  try {
@@ -246,8 +246,8 @@ export function createManagedPagesFeature(opts: ManagedPagesOptions): FeatureDef
246
246
  "content-type": "text/html; charset=utf-8",
247
247
  vary: "Host",
248
248
  } as const;
249
- // 304 (Revision unverändert) und HEAD überspringen beide das
250
- // Markdown-Rendern — der Body wird ohnehin verworfen.
249
+ // 304 (unchanged revision) and HEAD both skip Markdown rendering — the body
250
+ // would be discarded anyway.
251
251
  if (etagMatches(c.req.raw.headers.get("if-none-match"), etag) || c.req.method === "HEAD") {
252
252
  return cachedSecurePageResponse(c.req.raw, {
253
253
  body: null,
@@ -3,12 +3,11 @@ import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import * as z from "zod";
4
4
  import { type PageRow, pagesTable } from "../table.ts";
5
5
 
6
- // Public-Read by (tenantId, slug, lang). Anonymous-capable (Landing-/
7
- // Marketing-Pages). Tenant kommt aus query.user.tenantId — am Render-Pfad
8
- // via X-Tenant = Host-resolved-tenant gesetzt. Liefert NUR published Pages
9
- // mit Body: Drafts + leere Pages sind für anonyme Besucher unsichtbar
10
- // (Route → 404). Admin-Editing nutzt die Entity-List/Edit-Screens, nicht
11
- // diese Query.
6
+ // Public read by (tenantId, slug, lang), including anonymous access for landing and
7
+ // marketing pages. The tenant comes from query.user.tenantId, set on the render path
8
+ // via X-Tenant = Host-resolved-tenant. Returns ONLY published pages with a body:
9
+ // drafts and empty pages are invisible to anonymous visitors (the route returns 404).
10
+ // Admin editing uses the entity list/edit screens instead of this query.
12
11
  export const bySlugQuery = defineQueryHandler({
13
12
  name: "by-slug",
14
13
  schema: z.object({
@@ -3,12 +3,12 @@ import { defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
3
3
  import * as z from "zod";
4
4
  import { type PageRow, pagesTable } from "../table.ts";
5
5
 
6
- // Public-Read aller published Pages eines Tenants — Discovery-Quelle für
7
- // sitemap.xml/llms.txt (siehe seo-Feature). Anders als by-slug (single-row,
8
- // nur der angefragte Slug) listet dies alle published Slugs auf einmal, SQL-
9
- // seitig auf `published = true` gefiltert (Drafts nie im Ergebnis, kein
10
- // Body-Content — Discovery-Zweck braucht nur Slug/Title/updatedAt).
11
- // Anonymous: explizit in roles, symmetrisch zu text-content's by-tenant.
6
+ // Public read of all published pages for a tenant, used to discover URLs for
7
+ // sitemap.xml/llms.txt (see the seo feature). Unlike by-slug, which fetches one
8
+ // slug's content, this lists all published slugs in one query, filtered in SQL
9
+ // with `published = true`; drafts never appear, and only slug/title/updatedAt are
10
+ // returned because discovery does not require body content.
11
+ // Anonymous access is explicit in roles, matching text-content's by-tenant.
12
12
  export type PublishedPageSummary = {
13
13
  readonly slug: string;
14
14
  readonly lang: string;
@@ -19,8 +19,8 @@ export type PublishedPageSummary = {
19
19
  export const byTenantPublishedQuery = defineQueryHandler({
20
20
  name: "by-tenant-published",
21
21
  schema: z.object({
22
- /** Optional cross-tenant read — nur für SystemAdmin. Symmetrisch zur
23
- * by-slug.query Override-Logik. */
22
+ /** Optional cross-tenant read — only for SystemAdmin. Matches the override
23
+ * logic in by-slug.query. */
24
24
  tenantIdOverride: z.string().min(1).optional(),
25
25
  }),
26
26
  access: { roles: ["anonymous", "User", "TenantAdmin", "SystemAdmin"] },
@@ -18,12 +18,10 @@ const langSchema = z
18
18
 
19
19
  const executor = createEventStoreExecutor(pagesTable, pageEntity, { entityName: "page" });
20
20
 
21
- // Upsert einer Page — eine Operation pro (tenantId, slug, lang). Tenant-
22
- // Scope default aus event.user; SystemAdmin kann via `tenantIdOverride`
23
- // für einen anderen Tenant schreiben (typisch SYSTEM_TENANT_ID für app-
24
- // weite Pages). published/description/ogImage werden bei Update preserved
25
- // wenn im Payload weggelassen (undefined) — damit ein Publish-Toggle nicht
26
- // den Body überschreiben muss und umgekehrt.
21
+ // Upserts one page per (tenantId, slug, lang). The tenant scope defaults to event.user;
22
+ // SystemAdmin can write to another tenant via `tenantIdOverride` (typically SYSTEM_TENANT_ID
23
+ // for app-wide pages). On update, omitted published/description/ogImage values are preserved
24
+ // so a publish toggle does not overwrite the body, and vice versa.
27
25
  export const setWrite = defineWriteHandler({
28
26
  name: "set",
29
27
  schema: z.object({
@@ -34,7 +32,7 @@ export const setWrite = defineWriteHandler({
34
32
  description: z.string().max(500).nullable().optional(),
35
33
  ogImage: z.string().max(2000).nullable().optional(),
36
34
  published: z.boolean().optional(),
37
- /** Cross-tenant write — nur SystemAdmin (z.B. SYSTEM_TENANT_ID-Pages). */
35
+ /** Cross-tenant write — only SystemAdmin (for example, SYSTEM_TENANT_ID pages). */
38
36
  tenantIdOverride: z.string().min(1).optional(),
39
37
  }),
40
38
  access: { roles: ["TenantAdmin", "SystemAdmin"] },
@@ -3,14 +3,14 @@ import type {
3
3
  EntityListScreenDefinition,
4
4
  } from "@cosmicdrift/kumiko-framework/engine";
5
5
 
6
- // Admin-Authoring-Screens für die `page`-Entity. Reine Daten (JSON-safe) —
7
- // der generische DataTable-/Form-Renderer mountet sie, kein React-Component
8
- // nötig. Beide MÜSSEN im managed-pages-Feature registriert werden (nicht in
9
- // der App): der Boot-Validator verlangt, dass `entity: "page"` im selben
10
- // Feature deklariert ist wie der Screen. Nav/Workspace bleibt App-Sache
11
- // (placement-spezifisch, `default`-Workspace ist ein App-Singleton) — die
12
- // App zeigt via `r.nav({ screen: "managed-pages:screen:page-list" })` darauf
13
- // (cross-feature Nav→Screen ist gegen den globalen Screen-QN-Set validiert).
6
+ // Admin authoring screens for the `page` entity. These are JSON-safe data only —
7
+ // the generic DataTable/form renderer mounts them, so no React component is
8
+ // needed. Both MUST be registered in the managed-pages feature (not in the
9
+ // app): the boot validator requires `entity: "page"` to be declared in the
10
+ // same feature as the screen. Navigation and workspace placement remain app-
11
+ // specific (`default` workspace is an app singleton) — the app points to this
12
+ // via `r.nav({ screen: "managed-pages:screen:page-list" })`.
13
+ // Cross-feature Nav→Screen is validated against the global screen QN set.
14
14
 
15
15
  const ADMIN_ROLES = ["TenantAdmin", "SystemAdmin"] as const;
16
16
 
@@ -72,9 +72,9 @@ export const pageEditScreen: EntityEditScreenDefinition = {
72
72
  { field: "title", span: 2 },
73
73
  { field: "description", span: 2 },
74
74
  { field: "ogImage", span: 2 },
75
- // Publish/Unpublish: der `published`-Toggle hier IST der
76
- // Publish-Mechanismus (kein separater One-Click-List-Action —
77
- // rowAction-payload kann keine Konstanten injizieren).
75
+ // Publish/Unpublish: the `published` toggle here IS the publishing
76
+ // mechanism (there is no separate one-click list action —
77
+ // rowAction-payload cannot inject constants).
78
78
  { field: "published", span: 1 },
79
79
  ],
80
80
  },
@@ -1,6 +1,6 @@
1
- // Test-/Seed-Helper für managed-pages. Legt eine Page direkt über den
2
- // Event-Store-Executor an — gleicher Pfad wie der echte set-Handler, aber
3
- // ohne Access-Check. Default ifExists="skip".
1
+ // Test/seed helper for managed-pages. Creates a page directly through the
2
+ // event-store executor—the same path as the real set handler, but without an
3
+ // access check. Default ifExists="skip".
4
4
 
5
5
  import {
6
6
  createEventStoreExecutor,
@@ -33,9 +33,9 @@ export type SeedPageOptions = {
33
33
  };
34
34
 
35
35
  export async function seedPage(db: DbConnection, opts: SeedPageOptions): Promise<{ id: string }> {
36
- // Default-user muss user.tenantId === opts.tenantId haben (sonst landet
37
- // der event-store-stream im falschen tenant-bucket → version_conflict
38
- // bei späteren echten writes). TestUsers.systemAdmin ist testTenantId(1).
36
+ // The default user must have user.tenantId === opts.tenantId; otherwise the
37
+ // event-store stream ends up in the wrong tenant bucket → version_conflict
38
+ // on subsequent real writes. TestUsers.systemAdmin is testTenantId(1).
39
39
  const by = opts.by ?? { ...TestUsers.systemAdmin, tenantId: opts.tenantId };
40
40
  const tdb = createTenantDb({ db, tenantId: opts.tenantId, mode: "system" });
41
41
 
@@ -70,8 +70,8 @@ export async function seedPage(db: DbConnection, opts: SeedPageOptions): Promise
70
70
  if (!result.isSuccess) {
71
71
  throw new Error(`seedPage create failed: ${JSON.stringify(result)}`);
72
72
  }
73
- // @cast-boundary db-row: executor.create result.data ist die inserted
74
- // Drizzle-Row (Record<string, unknown>), projected nach RETURNING.
73
+ // @cast-boundary db-row: executor.create result.data is the inserted
74
+ // Drizzle row (Record<string, unknown>), projected from RETURNING.
75
75
  const data = result.data as Partial<PageRow>;
76
76
  if (data.id === undefined) {
77
77
  throw new Error("seedPage: executor.create did not return an id");
@@ -5,12 +5,13 @@ import {
5
5
  createTextField,
6
6
  } from "@cosmicdrift/kumiko-framework/engine";
7
7
 
8
- // Page — vom Tenant editierbare, server-gerenderte Public-Page (Landing,
9
- // About, custom). Pro (tenantId, slug, lang) genau eine Row. Body ist
10
- // Markdown (gehärtet server-gerendert über page-render). `published` gated
11
- // die Auslieferung an anonyme Besucher: Drafts → 404. description/ogImage
12
- // für SEO + Social-Preview. SYSTEM_TENANT_ID für app-weite Pages, sonst
13
- // Tenant-eigene Pages (Host → tenantId via resolveApexTenant am Render-Pfad).
8
+ // Page — a tenant-editable, server-rendered public page (landing,
9
+ // about, custom). Exactly one row per (tenantId, slug, lang). The body is
10
+ // Markdown, rendered securely on the server via page-render. `published`
11
+ // gates delivery to anonymous visitors: drafts return 404. description and
12
+ // ogImage support SEO and social previews. SYSTEM_TENANT_ID is used for
13
+ // app-wide pages; otherwise the page belongs to the tenant resolved from the
14
+ // host via resolveApexTenant during rendering.
14
15
  export const pageEntity = createEntity({
15
16
  table: "read_pages",
16
17
  description:
@@ -38,12 +39,12 @@ export const pageEntity = createEntity({
38
39
  personal: false,
39
40
  reason: "is_business_data",
40
41
  }),
41
- // Body + description sind vom Tenant-Admin authored Business-Content
42
- // (Markdown), keine User-Generated-PII. `multiline` → der entityEdit-
43
- // Renderer gibt ein <textarea> aus (createLongTextField hat aktuell
44
- // einen Render-Gap: edit.ts/render-field.tsx gaten nur type==="text").
45
- // maxLengths spiegeln die Handler-Schemas (set.write + Convention-CRUD
46
- // leiten ihre zod-Caps aus diesen Field-maxLengths ab).
42
+ // Body and description are tenant-admin-authored business content
43
+ // (Markdown), not user-generated PII. `multiline` makes the entityEdit
44
+ // renderer output a <textarea> (createLongTextField currently has a
45
+ // rendering gap: edit.ts/render-field.tsx only gates on type==="text").
46
+ // maxLengths mirror the handler schemas (set.write and convention CRUD
47
+ // derive their zod caps from these field maxLengths).
47
48
  body: createTextField({
48
49
  multiline: { rows: 16 },
49
50
  maxLength: 100_000,
@@ -59,9 +60,9 @@ export const pageEntity = createEntity({
59
60
 
60
61
  export const pagesTable = buildEntityTable("page", pageEntity);
61
62
 
62
- // Concrete Row-Type — single-source für die benannten Werte (statt
63
- // `row["x"] as Y`-Casts in Handlern). entity.fields + Standard-Spalten
64
- // (id, version, tenantId, createdAt, updatedAt, createdBy, updatedBy).
63
+ // Concrete row type — the single source of truth for named values instead
64
+ // of `row["x"] as Y` casts in handlers. Includes entity.fields and standard
65
+ // columns (id, version, tenantId, createdAt, updatedAt, createdBy, updatedBy).
65
66
  export type PageRow = {
66
67
  readonly id: string;
67
68
  readonly version: number;
@@ -1,15 +1,15 @@
1
- // Client-Feature-Factory für managed-pages. Bringt NUR die Übersetzungen mit —
2
- // die Screens (page-list/page-edit/branding-settings) sind schema-driven
3
- // (entityList/entityEdit/configEdit), also keine custom-React-Components zu
4
- // registrieren. Apps mounten es in createKumikoApp({ clientFeatures:
5
- // [managedPagesClient()] }), damit die Admin-Labels übersetzt rendern.
1
+ // Client feature factory for managed-pages. It provides ONLY translations —
2
+ // the screens (page-list/page-edit/branding-settings) are schema-driven
3
+ // (entityList/entityEdit/configEdit), so no custom React components are
4
+ // registered. Apps mount it in createKumikoApp({ clientFeatures:
5
+ // [managedPagesClient()] }) so the admin labels render translated.
6
6
 
7
7
  import { mergeTranslations, type TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
8
8
  import type { ClientFeatureDefinition } from "@cosmicdrift/kumiko-renderer/web";
9
9
  import { defaultTranslations } from "./default-translations.ts";
10
10
 
11
11
  export type ManagedPagesClientOptions = {
12
- /** Key-wise Overrides über die Default-Bundles (de/en). */
12
+ /** Key-wise overrides of the default bundles (de/en). */
13
13
  readonly translations?: TranslationsByLocale;
14
14
  };
15
15
 
@@ -56,7 +56,7 @@ export const MANAGED_PAGES_I18N: Readonly<Record<string, LocalizedString>> = {
56
56
  en: "Delete this page?",
57
57
  },
58
58
 
59
- // Nur bei allowCustomCss:true im Screen — unconditional geliefert
59
+ // Only used when allowCustomCss:true in the screen; supplied unconditionally
60
60
  "managed-pages:entity:__config-edit__:field:customCss": { en: "Custom CSS" },
61
61
  "managed-pages:branding.section.custom-css": { en: "Custom CSS" },
62
62
  };
@@ -15,7 +15,7 @@ import {
15
15
  // Strictly append-only by design: no update/delete write-handler is
16
16
  // registered (see feature.ts). A correction is a new entry, not an edit —
17
17
  // that is the whole point of a note *history* instead of the single
18
- // overwritable textarea this bundle replaces (solon#13).
18
+ // overwritable textarea this bundle replaces.
19
19
  //
20
20
  // `body` is about the HOST entity (entityType/entityId), not the author — the
21
21
  // author is never the data subject of a note's content, so it is deliberately
@@ -24,7 +24,7 @@ import {
24
24
  // employee leaving triggers a forget), garbling unrelated business notes
25
25
  // about customers/projects/etc. — data loss, not privacy.
26
26
  //
27
- // `body` is instead `personal: { of: "id" }` (Row-Subject, fw#2596/#2786):
27
+ // `body` is instead `personal: { of: "id" }` (Row-Subject):
28
28
  // the note's OWN row is its content's subject, so `body` is encrypted under a
29
29
  // per-note key that nothing else shares. That key gets erased only when the
30
30
  // note is reached by a forgotten subject: `note-mention` (below) names the
@@ -34,7 +34,7 @@ import {
34
34
  // shreds `authorName` (`personal: { of: "authorId" }`, the name as stamped at
35
35
  // write time); the two erasures are independent.
36
36
  //
37
- // Known gap (fw#2596, not fixed by this entity): prose that names a third
37
+ // Known gap (not fixed by this entity): prose that names a third
38
38
  // party without a structured @-mention is not tracked — regex/NLP over
39
39
  // free text is unreliable. An operator must erase such a note's own record
40
40
  // subject (`forget-subject` kind "record", entity "note-entry") to cover it.
@@ -86,7 +86,7 @@ export function createNoteEntryEntity(
86
86
  body: createLongTextField({
87
87
  required: true,
88
88
  maxLength: 20_000,
89
- // Row-Subject (fw#2596/#2786): the note itself is the subject, so its
89
+ // Row-Subject: the note itself is the subject, so its
90
90
  // key is erased per-note via `note-mention` lookups, not tied to any
91
91
  // user's own forget.
92
92
  personal: { of: "id" },
@@ -78,8 +78,8 @@ export type NotesHistoryFeatureOptions = {
78
78
  /** Row-level ownership on the note-entry rows themselves — orthogonal to
79
79
  * `access`, which only gates whether a caller may dispatch create/list at
80
80
  * all. `ownership.read` is no longer what keeps a caller from reading notes
81
- * on host entities they can't see: that gate is default-on since fw#2766
82
- * and derives from the entity's `parentRef`. Use `ownership.read` for an
81
+ * on host entities they can't see: that gate is default-on and derives from
82
+ * the entity's `parentRef`. Use `ownership.read` for an
83
83
  * ADDITIONAL row rule on the note row itself (e.g. author-only visibility);
84
84
  * it is AND-ed with the host-visibility gate, never a replacement for it.
85
85
  *
@@ -74,7 +74,7 @@ async function selectNotesReachingSubject(
74
74
  // (entity.ts), so forgetting the AUTHOR already crypto-shreds that field on
75
75
  // its own. `body` is Row-Subject (`personal: { of: "id" }`): its key is per
76
76
  // note, so forgetting a subject only reaches a body when the note structurally
77
- // @-mentions the subject (`note-mention`, fw#2787) or hangs on it as host.
77
+ // @-mentions the subject (`note-mention`) or hangs on it as host.
78
78
  // Free-text mentions are NOT detected — the documented gap in entity.ts.
79
79
  //
80
80
  // Reached bodies are shredded regardless of the host entity's retention strategy:
@@ -51,19 +51,19 @@ const TENANT_CLIP = `${TENANT_SCOPE}{overflow:hidden}`;
51
51
  export function tenantStyleBlock(customCss: string): string {
52
52
  const sanitized = sanitizeTenantCss(customCss, TENANT_SCOPE);
53
53
  if (!sanitized) return "";
54
- // html-ok: sanitizeTenantCss ist die Escaping-Boundary (Allowlist, strippt `<`).
54
+ // html-ok: sanitizeTenantCss is the escaping boundary (allowlist, strips `<`).
55
55
  return `\n<style data-tenant-css>${TENANT_CONTAINMENT}\n${TENANT_CLIP}\n${sanitized}</style>`;
56
56
  }
57
57
 
58
- // Minimaler HTML5-Skeleton mit Inline-CSS — Default-`wrapLayout` für
59
- // server-gerenderte Public-Pages, damit sie auch ohne App-Layout sauber
60
- // aussehen. Apps die ihr eigenes Marketing-Layout (Header/Footer/Theme)
61
- // um den Body legen wollen, übergeben ihre eigene Render-Function.
58
+ // Minimal HTML5 skeleton with inline CSS — the default `wrapLayout` for
59
+ // server-rendered public pages, so they look clean without an app layout.
60
+ // Apps that want to wrap the body in their own marketing layout
61
+ // (header/footer/theme) pass their own render function.
62
62
  //
63
- // Branding (optional): emittiert nach dem Base-`<style>` einen scoped
64
- // `:root`-Override (Accent-Farbe, Layout-Preset → max-width) plus einen
65
- // Logo-/Titel-Header. Alle Branding-Werte sind tenant-supplied + untrusted
66
- // und werden in branding.ts re-validiert/escaped, bevor sie ins Markup gehen.
63
+ // Branding (optional): emits a scoped `:root` override after the base
64
+ // `<style>` (accent color, layout preset → max-width) and a logo/title header.
65
+ // All branding values are tenant-supplied and untrusted; branding.ts
66
+ // revalidates/escapes them before they enter the markup.
67
67
  export function wrapInLayout(opts: {
68
68
  title: string;
69
69
  bodyHtml: string;
@@ -1,15 +1,15 @@
1
1
  import { escapeHtml, isSafeHref } from "@cosmicdrift/kumiko-renderer/headless";
2
2
  import { Marked } from "marked";
3
3
 
4
- // Geteilter, gehärteter Markdown→HTML-Kern für server-gerenderte Public-
5
- // Pages (legal-pages, managed-pages). Annahme: untrusted Tenant-Authoren.
6
- // Raw-HTML-Tokens werden als Text escaped (kein <script>/<img onerror>-
7
- // Passthrough), und link/image-hrefs auf http(s)/mailto/relativ beschränkt
8
- // (kein javascript:/data:). Markdown-Struktur (Headings, Listen, Links,
9
- // Code) bleibt intakt — das neutralisiert die XSS-Vektoren ohne Sanitizer-
10
- // Dependency. Defense-in-Depth ergänzt `securePageHeaders` (`script-src
11
- // 'none'`). GFM aus, breaks aus — strukturierte Pages brauchen keine
12
- // Tables/Strikethrough/Task-Lists.
4
+ // Shared, hardened Markdown→HTML core for server-rendered public
5
+ // pages (legal-pages, managed-pages). Assumption: untrusted tenant authors.
6
+ // Raw HTML tokens are escaped as text (no <script>/<img onerror>-
7
+ // passthrough), and link/image hrefs are restricted to http(s)/mailto/relative
8
+ // (no javascript:/data:). Markdown structure (headings, lists, links,
9
+ // code) remains intact—this neutralizes XSS vectors without a sanitizer
10
+ // dependency. Defense in depth complements `securePageHeaders` (`script-src
11
+ // 'none'`). GFM and breaks are disabled—structured pages do not need
12
+ // tables/strikethrough/task lists.
13
13
  const safeRenderer = new Marked({ gfm: false, breaks: false });
14
14
  safeRenderer.use({
15
15
  walkTokens(token) {
@@ -25,7 +25,7 @@ safeRenderer.use({
25
25
  });
26
26
 
27
27
  export function renderSafeMarkdown(markdown: string): string {
28
- // @cast-boundary third-party-type-gap marked.parse return-type ist `string | Promise<string>`;
29
- // `{ async: false }` garantiert sync (string) — Cast nur API-Vertragsfix.
28
+ // @cast-boundary third-party-type-gap marked.parse return type is `string | Promise<string>`;
29
+ // `{ async: false }` guarantees synchronous output (string)—the cast only fixes the API contract.
30
30
  return safeRenderer.parse(markdown, { async: false }) as string;
31
31
  }
@@ -1,9 +1,10 @@
1
- // Security-Header für server-gerenderte Public-HTML-Pages (legal-pages,
2
- // managed-pages). `script-src 'none'` ist Defense-in-Depth: selbst wenn
3
- // HTML-Injection durchrutscht, läuft kein Script. Bewusst KEIN `default-src`
4
- // → Styles/Images/Fonts bleiben unrestricted (rückwärtskompatibel zu
5
- // Inline-<style>-Layouts wie publicstatus' renderLegalLayout).
6
- // nosniff/SAMEORIGIN/Referrer-Policy sind universell sichere Defaults.
1
+ // Security headers for server-rendered public HTML pages (legal-pages,
2
+ // managed-pages). `script-src 'none'` provides defense in depth: even if
3
+ // HTML injection gets through, no script can run. Deliberately omit
4
+ // `default-src` so styles, images, and fonts remain unrestricted for
5
+ // backward compatibility with inline-<style> layouts such as
6
+ // publicstatus' renderLegalLayout.
7
+ // nosniff/SAMEORIGIN/Referrer-Policy are broadly safe defaults.
7
8
  const PUBLIC_PAGE_SECURITY_HEADERS = {
8
9
  "content-security-policy": "script-src 'none'; object-src 'none'; base-uri 'none'",
9
10
  "x-content-type-options": "nosniff",
@@ -123,12 +123,12 @@ export function createPersonalAccessTokensFeature(
123
123
  } satisfies AuthProviderPlugin);
124
124
  // Direct-write store like store_user_sessions: create/revoke write it, the
125
125
  // resolver point-reads it. r.entity would make it a rebuildable projection
126
- // whose replay (no token events) would wipe every live token (#498/#494).
126
+ // whose replay (no token events) would wipe every live token.
127
127
  r.storeTable(
128
128
  deriveEntityTableMeta(API_TOKEN_ENTITY_NAME, apiTokenEntity, { source: "unmanaged" }),
129
129
  {
130
130
  reason: "read_side.api_tokens_direct_write",
131
- // create.write encrypts `name` via encryptForDirectWrite (#820).
131
+ // create.write encrypts `name` via encryptForDirectWrite.
132
132
  piiEncryptedOnWrite: true,
133
133
  },
134
134
  );
@@ -145,9 +145,9 @@ export function createPersonalAccessTokensFeature(
145
145
  // Password-change auto-revoke — mirrors sessions' own
146
146
  // autoRevokeOnPasswordChange postSave hook, including WHY it's a
147
147
  // late-bind callback rather than direct ctx.db use: user:write:user:update
148
- // is r.systemScope()'d (the user aggregate is a systemStream, framework
149
- // #497), so a postSave hook on "user" gets a poisoned ctx.db here. The
150
- // concrete revoker is bound once run{Prod,Dev}App has a real db handle.
148
+ // is r.systemScope()'d (the user aggregate is a systemStream), so a postSave hook
149
+ // on "user" gets a poisoned ctx.db here. The concrete revoker is bound once
150
+ // run{Prod,Dev}App has a real db handle.
151
151
  // Explicit option wins; the runtime binding is replaceable so a second boot of the same
152
152
  // feature instance binds its own database.
153
153
  let boundAutoRevoke: ((userId: string) => Promise<number>) | undefined;