@cosmicdrift/kumiko-bundled-features 0.388.0 → 0.390.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.
- package/dist/agent-tools/index.d.ts +1 -1
- package/dist/agent-tools/index.js +1 -1
- package/dist/agent-tools/tool-dispatch.d.ts +8 -3
- package/dist/agent-tools/tool-dispatch.js +36 -25
- package/dist/audit/feature.js +2 -1
- package/dist/auth-email-password/auth-user-row.js +1 -1
- package/dist/auth-email-password/bootstrap.js +6 -1
- package/dist/auth-email-password/feature.js +1 -1
- package/dist/auth-email-password/handlers/change-password.write.js +7 -7
- package/dist/auth-email-password/handlers/confirm-account-unlock.write.js +3 -3
- package/dist/auth-email-password/handlers/confirm-token-flow.js +4 -4
- package/dist/auth-email-password/handlers/invite-accept-with-login.write.js +8 -7
- package/dist/auth-email-password/handlers/invite-accept.write.js +10 -7
- package/dist/auth-email-password/handlers/invite-create.write.js +4 -4
- package/dist/auth-email-password/handlers/invite-info.query.js +2 -2
- package/dist/auth-email-password/handlers/invite-signup-complete.write.js +8 -7
- package/dist/auth-email-password/handlers/login.write.js +17 -15
- package/dist/auth-email-password/handlers/request-account-unlock.write.d.ts +1 -0
- package/dist/auth-email-password/handlers/request-account-unlock.write.js +1 -0
- package/dist/auth-email-password/handlers/request-email-verification.write.d.ts +1 -0
- package/dist/auth-email-password/handlers/request-email-verification.write.js +1 -0
- package/dist/auth-email-password/handlers/request-password-reset.write.d.ts +1 -0
- package/dist/auth-email-password/handlers/request-password-reset.write.js +1 -0
- package/dist/auth-email-password/handlers/reset-password.write.js +2 -2
- package/dist/auth-email-password/handlers/signup-confirm.write.js +12 -12
- package/dist/auth-email-password/handlers/signup-request.write.d.ts +1 -0
- package/dist/auth-email-password/handlers/signup-request.write.js +16 -8
- package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.js +4 -2
- package/dist/auth-email-password/handlers/token-request-handler.d.ts +2 -0
- package/dist/auth-email-password/handlers/token-request-handler.js +7 -2
- package/dist/auth-email-password/handlers/verify-email.write.js +2 -2
- package/dist/auth-email-password/magic-link-mail.d.ts +2 -0
- package/dist/auth-email-password/magic-link-mail.js +7 -3
- package/dist/auth-email-password/seeding.d.ts +1 -1
- package/dist/auth-email-password/seeding.js +9 -8
- package/dist/auth-email-password/signup-activation.d.ts +1 -0
- package/dist/auth-email-password/signup-activation.js +1 -0
- package/dist/auth-email-password/web/auth-client.d.ts +2 -2
- package/dist/auth-email-password/web/auth-client.js +8 -4
- package/dist/auth-email-password/web/auth-redirect.d.ts +5 -1
- package/dist/auth-email-password/web/auth-redirect.js +20 -25
- package/dist/auth-email-password/web/default-auth-pages-gate.js +6 -3
- package/dist/auth-email-password/web/forgot-password-screen.d.ts +4 -1
- package/dist/auth-email-password/web/forgot-password-screen.js +7 -2
- package/dist/auth-email-password/web/index.d.ts +1 -0
- package/dist/auth-email-password/web/index.js +1 -0
- package/dist/auth-email-password/web/login-screen.js +11 -6
- package/dist/auth-email-password/web/reset-password-screen.js +7 -1
- package/dist/auth-email-password/web/return-path.d.ts +4 -0
- package/dist/auth-email-password/web/return-path.js +34 -0
- package/dist/auth-email-password/web/session.js +6 -1
- package/dist/auth-email-password/web/signup-complete-screen.js +11 -3
- package/dist/auth-email-password/web/signup-screen.d.ts +4 -1
- package/dist/auth-email-password/web/signup-screen.js +8 -3
- package/dist/auth-foundation/feature.js +12 -4
- package/dist/auth-mfa/config.d.ts +1 -1
- package/dist/auth-mfa/config.js +3 -7
- package/dist/auth-mfa/handlers/disable.write.js +5 -5
- package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +19 -14
- package/dist/auth-mfa/handlers/enable-confirm.write.js +3 -3
- package/dist/auth-mfa/handlers/enable-start-preauth.write.js +6 -1
- package/dist/auth-mfa/handlers/enable-start.write.js +1 -1
- package/dist/auth-mfa/handlers/reencrypt.job.js +14 -9
- package/dist/auth-mfa/handlers/regenerate-recovery.write.js +4 -4
- package/dist/auth-mfa/handlers/verify.write.js +19 -14
- package/dist/auth-mfa/mfa-code-verifier.js +9 -4
- package/dist/auth-mfa/mfa-status-checker.js +13 -6
- package/dist/auth-mfa/verify-factor.js +1 -1
- package/dist/billing-foundation/billing-info-query.js +2 -2
- package/dist/billing-foundation/consumer-protection/consent-gate.js +1 -1
- package/dist/billing-foundation/consumer-protection/issue-confirmation.js +5 -5
- package/dist/billing-foundation/consumer-protection/register-consent.js +1 -1
- package/dist/billing-foundation/consumer-protection/register-termination.js +1 -1
- package/dist/billing-foundation/consumer-protection/termination-open-cancels.d.ts +4 -0
- package/dist/billing-foundation/consumer-protection/termination-open-cancels.js +14 -0
- package/dist/billing-foundation/consumer-protection/termination-provider-lock.d.ts +2 -0
- package/dist/billing-foundation/consumer-protection/termination-provider-lock.js +3 -0
- package/dist/billing-foundation/consumer-protection/termination-receipt-limit.js +4 -4
- package/dist/billing-foundation/consumer-protection/termination-record.js +11 -48
- package/dist/billing-foundation/consumer-protection/termination-request.js +10 -8
- package/dist/billing-foundation/consumer-protection/termination-revoke.js +10 -12
- package/dist/billing-foundation/events.js +1 -1
- package/dist/billing-foundation/feature.js +3 -3
- package/dist/billing-foundation/get-subscription-for-tenant.d.ts +1 -1
- package/dist/billing-foundation/handlers/process-event.write.js +5 -5
- package/dist/billing-foundation/handlers/process-payment-event.write.js +3 -3
- package/dist/billing-foundation/plan-catalog.js +2 -2
- package/dist/billing-foundation/projection.js +1 -1
- package/dist/billing-foundation/types.js +1 -1
- package/dist/cap-counter/aggregate-id.d.ts +1 -1
- package/dist/cap-counter/aggregate-id.js +1 -1
- package/dist/cap-counter/book-cap-usage.d.ts +2 -2
- package/dist/cap-counter/book-cap-usage.js +3 -3
- package/dist/cap-counter/cap-reservation.js +16 -7
- package/dist/cap-counter/constants.js +1 -1
- package/dist/cap-counter/feature.js +3 -2
- package/dist/cap-counter/handlers/increment-rolling.write.js +1 -1
- package/dist/cap-counter/reservation-chain.js +1 -1
- package/dist/cap-counter/with-cap-enforcement.d.ts +3 -3
- package/dist/cap-counter/with-cap-enforcement.js +1 -1
- package/dist/cap-overview/feature.js +1 -0
- package/dist/cap-overview/handlers/caps-usage.query.js +1 -1
- package/dist/cap-overview/handlers/tenant-caps-list.query.js +1 -1
- package/dist/compliance-profiles/seeding.d.ts +1 -1
- package/dist/compliance-profiles/seeding.js +9 -3
- package/dist/config/feature.js +6 -6
- package/dist/config/handlers/cascade.query.js +1 -1
- package/dist/config/handlers/readiness.query.js +1 -1
- package/dist/config/handlers/reencrypt.job.js +23 -13
- package/dist/config/handlers/reset.write.js +3 -3
- package/dist/config/handlers/selected-extensions.query.js +1 -1
- package/dist/config/handlers/set.write.js +15 -5
- package/dist/config/handlers/values.query.js +1 -1
- package/dist/crypto-shredding/handlers/forget-subject.write.js +9 -9
- package/dist/crypto-shredding/resolve-file-bytes-deleter.js +3 -3
- package/dist/custom-fields/handlers/clear-custom-field.write.js +1 -1
- package/dist/custom-fields/handlers/delete-system-field.write.js +1 -1
- package/dist/custom-fields/handlers/delete-tenant-field.write.js +1 -1
- package/dist/custom-fields/handlers/set-custom-field.write.js +1 -1
- package/dist/custom-fields/index.d.ts +1 -0
- package/dist/custom-fields/index.js +1 -0
- package/dist/custom-fields/lib/parse-serialized-field.js +1 -1
- package/dist/data-retention/feature.js +1 -1
- package/dist/data-retention/run-retention-cleanup.js +12 -2
- package/dist/delivery/attempt-log.js +1 -1
- package/dist/delivery/delivery-service.js +5 -5
- package/dist/delivery/feature.js +3 -2
- package/dist/delivery/index.d.ts +1 -0
- package/dist/delivery/index.js +1 -0
- package/dist/delivery/jobs.js +11 -11
- package/dist/delivery/system-channel-context.d.ts +15 -0
- package/dist/delivery/system-channel-context.js +5 -0
- package/dist/document-ingest-foundation/append-missing-extract-event.d.ts +21 -0
- package/dist/document-ingest-foundation/append-missing-extract-event.js +42 -0
- package/dist/document-ingest-foundation/events.d.ts +11 -0
- package/dist/document-ingest-foundation/events.js +12 -1
- package/dist/document-ingest-foundation/index.d.ts +2 -1
- package/dist/document-ingest-foundation/index.js +2 -1
- package/dist/feature-toggles/feature.js +1 -0
- package/dist/feature-toggles/handlers/registered.query.js +1 -1
- package/dist/feature-toggles/handlers/set.write.js +1 -1
- package/dist/feature-toggles/toggle-sync-signal.js +1 -1
- package/dist/file-derivatives/feature.d.ts +1 -1
- package/dist/file-derivatives/feature.js +1 -1
- package/dist/file-derivatives/handlers/public-variant-by-file-ref.query.js +1 -1
- package/dist/file-derivatives/handlers/public-variant.query.js +5 -5
- package/dist/file-foundation/feature.js +1 -1
- package/dist/file-foundation/read-file-ref-content.d.ts +4 -2
- package/dist/file-foundation/read-file-ref-content.js +3 -3
- package/dist/file-provider-s3/feature.js +1 -1
- package/dist/files-tenant-data/handlers/sweep-orphaned-derivatives.job.js +8 -8
- package/dist/form-draft/feature.js +1 -1
- package/dist/form-draft/handlers/cleanup.job.js +22 -12
- package/dist/form-draft/handlers/discard.write.js +3 -3
- package/dist/form-draft/handlers/get.query.js +1 -1
- package/dist/foundation-shared/config-helpers.d.ts +1 -1
- package/dist/foundation-shared/config-helpers.js +1 -1
- package/dist/host-routing/validate-options.js +3 -0
- package/dist/inbound-mail-foundation/events.js +1 -1
- package/dist/inbound-mail-foundation/feature.js +2 -1
- package/dist/inbound-mail-foundation/handlers/account-state.d.ts +3 -1
- package/dist/inbound-mail-foundation/handlers/account-state.js +1 -1
- package/dist/inbound-mail-foundation/handlers/connect-account.write.js +1 -1
- package/dist/inbound-mail-foundation/handlers/disconnect-account.write.js +1 -1
- package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +10 -10
- package/dist/inbound-mail-foundation/handlers/update-account.write.js +1 -1
- package/dist/inbound-mail-foundation/projection.js +1 -1
- package/dist/inbound-mail-foundation/watch-supervisor.js +1 -1
- package/dist/inbound-provider-imap/feature.js +1 -1
- package/dist/jobs/events.js +1 -1
- package/dist/jobs/feature.js +1 -0
- package/dist/jobs/handlers/consumer.write.js +1 -1
- package/dist/jobs/handlers/projection-rebuild.job.js +1 -1
- package/dist/jobs/handlers/reindex-entity.job.js +5 -5
- package/dist/jobs/handlers/retention-cleanup.job.js +1 -1
- package/dist/jobs/handlers/retry.write.js +1 -1
- package/dist/jobs/handlers/stale-run-sweep.job.js +1 -1
- package/dist/jobs/handlers/trigger.write.js +2 -2
- package/dist/jobs/job-run-logger.d.ts +1 -0
- package/dist/jobs/job-run-logger.js +38 -18
- package/dist/ledger/web/index.js +1 -1
- package/dist/legal-pages/lib/boot-check.d.ts +10 -4
- package/dist/legal-pages/lib/boot-check.js +2 -2
- package/dist/legal-pages/seed.d.ts +3 -1
- package/dist/legal-pages/seed.js +2 -2
- package/dist/mail-foundation/feature.d.ts +2 -2
- package/dist/mail-transport-smtp/config-keys.js +1 -1
- package/dist/mail-transport-smtp/feature.js +7 -6
- package/dist/managed-pages/constants.d.ts +1 -0
- package/dist/managed-pages/constants.js +1 -0
- package/dist/managed-pages/feature.js +3 -1
- package/dist/managed-pages/index.d.ts +1 -0
- package/dist/managed-pages/index.js +1 -0
- package/dist/managed-pages/seeding.d.ts +1 -1
- package/dist/managed-pages/seeding.js +10 -4
- package/dist/notes-history/handlers/add-note.write.js +2 -2
- package/dist/personal-access-tokens/feature.js +2 -1
- package/dist/personal-access-tokens/handlers/create.write.js +2 -2
- package/dist/personal-access-tokens/handlers/revoke.write.js +1 -1
- package/dist/rate-limiting/handlers/status.query.js +2 -2
- package/dist/readiness/handlers/status.query.js +1 -1
- package/dist/renderer-foundation/api.d.ts +4 -2
- package/dist/renderer-foundation/api.js +2 -2
- package/dist/secrets/announce-secret-change.d.ts +6 -2
- package/dist/secrets/announce-secret-change.js +3 -3
- package/dist/secrets/feature.d.ts +1 -1
- package/dist/secrets/feature.js +8 -8
- package/dist/secrets/handlers/delete.write.js +1 -1
- package/dist/secrets/handlers/rotate.job.js +13 -8
- package/dist/secrets/handlers/set.write.js +1 -1
- package/dist/secrets/secrets-context.js +16 -6
- package/dist/secrets/write-gate.js +8 -2
- package/dist/seo/feature.js +1 -1
- package/dist/sessions/feature.js +2 -1
- package/dist/sessions/handlers/cleanup.job.js +2 -2
- package/dist/sessions/handlers/detail.query.d.ts +1 -0
- package/dist/sessions/handlers/detail.query.js +5 -2
- package/dist/sessions/handlers/list.query.d.ts +1 -0
- package/dist/sessions/handlers/list.query.js +5 -2
- package/dist/sessions/handlers/mine.query.d.ts +1 -0
- package/dist/sessions/handlers/mine.query.js +5 -2
- package/dist/sessions/handlers/revoke-all-for-user.write.js +3 -3
- package/dist/sessions/handlers/revoke-all-others.write.js +1 -1
- package/dist/sessions/handlers/revoke.write.js +1 -1
- package/dist/sessions/index.d.ts +1 -1
- package/dist/sessions/index.js +1 -1
- package/dist/sessions/screens.js +8 -4
- package/dist/sessions/session-callbacks.d.ts +0 -2
- package/dist/sessions/session-callbacks.js +1 -3
- package/dist/sessions/session-revoked-event.js +1 -1
- package/dist/sessions/web/session-device-cell.js +10 -12
- package/dist/sessions/web/user-agent.d.ts +1 -0
- package/dist/sessions/web/user-agent.js +11 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.js +2 -0
- package/dist/shared/purge-files-reaching-subject.d.ts +1 -0
- package/dist/shared/purge-files-reaching-subject.js +31 -4
- package/dist/shared/require-for-tenant.d.ts +1 -1
- package/dist/shared/require-for-tenant.js +6 -4
- package/dist/shared/run-in-sub-transaction.js +5 -5
- package/dist/shared/stream-tenant-backfill.d.ts +28 -0
- package/dist/shared/stream-tenant-backfill.js +119 -0
- package/dist/shared/stream-tenant-derived-state.d.ts +25 -0
- package/dist/shared/stream-tenant-derived-state.js +68 -0
- package/dist/step-dispatcher/deliver-dispatch-request.js +16 -3
- package/dist/step-dispatcher/feature.js +1 -1
- package/dist/step-dispatcher/mail-runner.d.ts +1 -0
- package/dist/subscription-dodo/plugin-methods.js +1 -1
- package/dist/subscription-dodo/runtime.js +4 -4
- package/dist/subscription-stripe/plugin-methods.js +3 -3
- package/dist/subscription-stripe/runtime.js +4 -4
- package/dist/tags/feature.js +1 -0
- package/dist/template-resolver/api.d.ts +4 -2
- package/dist/template-resolver/api.js +2 -2
- package/dist/template-resolver/document-ops.d.ts +5 -0
- package/dist/template-resolver/document-ops.js +18 -2
- package/dist/template-resolver/feature.js +2 -2
- package/dist/template-resolver/handlers/bundle-import.d.ts +4 -3
- package/dist/template-resolver/handlers/export-bundle.query.js +1 -1
- package/dist/template-resolver/handlers/layout-source.query.d.ts +4 -0
- package/dist/template-resolver/handlers/layout-source.query.js +26 -6
- package/dist/template-resolver/handlers/overview.query.js +17 -9
- package/dist/template-resolver/handlers/patch-draft.write.js +1 -1
- package/dist/template-resolver/handlers/send-test-shared.js +1 -1
- package/dist/template-resolver/handlers/send-test-status.query.d.ts +2 -1
- package/dist/template-resolver/handlers/send-test-status.query.js +18 -15
- package/dist/template-resolver/handlers/send-test.write.js +2 -2
- package/dist/template-resolver/handlers/tenant-override-selection.d.ts +3 -1
- package/dist/template-resolver/handlers/tenant-override-selection.js +1 -1
- package/dist/template-resolver/handlers/tenant-overrides.query.js +1 -1
- package/dist/template-resolver/handlers/usage.query.js +1 -1
- package/dist/template-resolver/seeding.d.ts +1 -0
- package/dist/template-resolver/seeding.js +17 -4
- package/dist/template-resolver/store-template-resource.d.ts +7 -6
- package/dist/template-resolver/store-template-resource.js +48 -8
- package/dist/template-resolver/template-resources.d.ts +2 -2
- package/dist/template-resolver/template-resources.js +2 -2
- package/dist/template-resolver/testing.js +2 -2
- package/dist/template-resolver/web/document-insert-fields.d.ts +4 -0
- package/dist/template-resolver/web/document-insert-fields.js +69 -0
- package/dist/template-resolver/web/document-insert-model.d.ts +43 -0
- package/dist/template-resolver/web/document-insert-model.js +106 -0
- package/dist/template-resolver/web/document-insert-panel.d.ts +13 -0
- package/dist/template-resolver/web/document-insert-panel.js +49 -0
- package/dist/template-resolver/web/document-tiptap-bubble.d.ts +4 -0
- package/dist/template-resolver/web/document-tiptap-bubble.js +85 -0
- package/dist/template-resolver/web/document-tiptap-content.d.ts +3 -0
- package/dist/template-resolver/web/document-tiptap-content.js +12 -0
- package/dist/template-resolver/web/document-tiptap-context.d.ts +41 -0
- package/dist/template-resolver/web/document-tiptap-context.js +43 -0
- package/dist/template-resolver/web/document-tiptap-editor.js +50 -495
- package/dist/template-resolver/web/document-tiptap-helpers.d.ts +44 -0
- package/dist/template-resolver/web/document-tiptap-helpers.js +129 -0
- package/dist/template-resolver/web/document-tiptap-layout.d.ts +4 -0
- package/dist/template-resolver/web/document-tiptap-layout.js +24 -0
- package/dist/template-resolver/web/document-tiptap-toolbar-groups.d.ts +6 -0
- package/dist/template-resolver/web/document-tiptap-toolbar-groups.js +33 -0
- package/dist/template-resolver/web/document-tiptap-toolbar.d.ts +3 -0
- package/dist/template-resolver/web/document-tiptap-toolbar.js +91 -0
- package/dist/template-resolver/web/editor-handle.d.ts +1 -0
- package/dist/template-resolver/web/editor-handle.js +15 -0
- package/dist/template-resolver/web/i18n.js +3 -0
- package/dist/template-resolver/web/placeholder-line-editor.js +16 -5
- package/dist/template-resolver/web/qualified-names.d.ts +1 -0
- package/dist/template-resolver/web/qualified-names.js +1 -0
- package/dist/template-resolver/web/use-document-tiptap-model.d.ts +54 -0
- package/dist/template-resolver/web/use-document-tiptap-model.js +96 -0
- package/dist/tenant/feature.js +1 -0
- package/dist/tenant/handlers/cancel-invitation.write.js +1 -1
- package/dist/tenant/handlers/memberships.query.js +1 -1
- package/dist/tenant/handlers/remove-member.write.js +2 -2
- package/dist/tenant/handlers/team-list.query.js +3 -3
- package/dist/tenant/handlers/update-member-roles.write.js +1 -1
- package/dist/tenant/index.d.ts +1 -0
- package/dist/tenant/index.js +1 -0
- package/dist/tenant/invited-membership.js +6 -1
- package/dist/tenant/schema/tenant.d.ts +2 -2
- package/dist/tenant/schema/tenant.js +4 -1
- package/dist/tenant/seeding.d.ts +2 -2
- package/dist/tenant/seeding.js +52 -52
- package/dist/tenant/stream-tenant-backfill.d.ts +21 -0
- package/dist/tenant/stream-tenant-backfill.js +63 -0
- package/dist/tenant/testing.d.ts +12 -0
- package/dist/tenant/testing.js +33 -0
- package/dist/tenant-handover/events.js +1 -1
- package/dist/tenant-handover/handlers/claim.write.js +1 -1
- package/dist/tenant-lifecycle/feature.js +5 -5
- package/dist/tenant-lifecycle/handlers/cancel-destruction.write.js +14 -5
- package/dist/tenant-lifecycle/handlers/request-destruction.write.js +12 -4
- package/dist/tenant-lifecycle/run-tenant-destroy.js +23 -13
- package/dist/tenant-lifecycle/stages.js +28 -2
- package/dist/tenant-lifecycle/testing.d.ts +1 -1
- package/dist/tenant-lifecycle/testing.js +6 -5
- package/dist/tier-engine/entity.js +1 -1
- package/dist/tier-engine/feature.js +8 -3
- package/dist/tier-engine/handlers/active-tier.query.js +3 -3
- package/dist/tier-engine/handlers/get-tenant-tier.query.js +6 -1
- package/dist/tier-engine/handlers/set-tenant-tier.write.js +4 -4
- package/dist/user/db/queries/stream-tenant-backfill.d.ts +20 -1
- package/dist/user/db/queries/stream-tenant-backfill.js +40 -77
- package/dist/user/feature.js +1 -0
- package/dist/user/handlers/find-for-auth.query.js +2 -2
- package/dist/user/handlers/update-roles.js +2 -2
- package/dist/user/index.d.ts +1 -1
- package/dist/user/index.js +1 -1
- package/dist/user/invited-global-roles.js +6 -1
- package/dist/user/principal-status.js +1 -1
- package/dist/user/seeding.d.ts +1 -1
- package/dist/user/seeding.js +20 -5
- package/dist/user/testing.d.ts +3 -0
- package/dist/user/testing.js +10 -0
- package/dist/user-data-rights/audit-download.js +12 -2
- package/dist/user-data-rights/feature.js +30 -26
- package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.js +1 -1
- package/dist/user-data-rights/handlers/deletion-grace-period.js +1 -1
- package/dist/user-data-rights/handlers/download-by-job.query.js +2 -2
- package/dist/user-data-rights/handlers/download-by-token.query.js +2 -2
- package/dist/user-data-rights/handlers/request-deletion.write.js +1 -1
- package/dist/user-data-rights/handlers/restrict-account.write.js +4 -4
- package/dist/user-data-rights/handlers/run-forget-cleanup.write.js +8 -6
- package/dist/user-data-rights/index.d.ts +1 -1
- package/dist/user-data-rights/index.js +1 -1
- package/dist/user-data-rights/lib/mail-transport-resolver.js +1 -1
- package/dist/user-data-rights/lib/storage-provider-resolver.js +1 -1
- package/dist/user-data-rights/lib/update-user-lifecycle.js +6 -1
- package/dist/user-data-rights/run-export-jobs.js +7 -2
- package/dist/user-data-rights/run-forget-cleanup.d.ts +1 -0
- package/dist/user-data-rights/run-forget-cleanup.js +9 -1
- package/dist/user-data-rights/run-user-export.js +7 -1
- package/dist/user-data-rights/web/constants.d.ts +14 -0
- package/dist/user-data-rights/web/constants.js +14 -0
- package/dist/user-data-rights/web/index.d.ts +1 -0
- package/dist/user-data-rights/web/index.js +1 -0
- package/dist/user-profile/handlers/change-email.write.js +8 -6
- package/dist/waitlist/feature.js +1 -0
- package/dist/waitlist/handlers/export-purge.write.js +1 -1
- package/dist/waitlist/handlers/invite.write.js +2 -2
- package/dist/waitlist/handlers/reject.write.js +1 -1
- package/dist/waitlist/handlers/submit.write.js +20 -11
- package/dist/waitlist/import.d.ts +2 -1
- package/dist/waitlist/import.js +22 -2
- package/dist/waitlist/legacy-migrate.js +8 -3
- package/dist/waitlist/link-on-signup.js +6 -1
- package/dist/waitlist/options.d.ts +2 -1
- package/dist/workflow-runner/db/queries/due-runs.js +1 -1
- package/dist/workflow-runner/event-subscriber.js +4 -3
- package/dist/workflow-runner/event-trigger.js +2 -1
- package/dist/workflow-runner/feature.js +2 -2
- package/dist/workflow-runner/handlers/resume-run.write.js +6 -6
- package/dist/workflow-runner/runner.d.ts +3 -1
- package/dist/workflow-runner/runner.js +3 -3
- package/package.json +41 -23
- package/src/agent-tools/changes.json +6 -0
- package/src/auth-email-password/changes.json +18 -0
- package/src/auth-mfa/changes.json +6 -0
- package/src/billing-foundation/changes.json +6 -0
- package/src/cap-counter/changes.json +12 -0
- package/src/config/changes.json +6 -0
- package/src/crypto-shredding/changes.json +12 -0
- package/src/custom-fields/changes.json +6 -0
- package/src/delivery/changes.json +12 -0
- package/src/document-ingest-foundation/changes.json +6 -0
- package/src/host-routing/changes.json +6 -0
- package/src/jobs/changes.json +6 -0
- package/src/mail-transport-smtp/changes.json +12 -0
- package/src/managed-pages/changes.json +6 -0
- package/src/secrets/changes.json +6 -0
- package/src/sessions/changes.json +19 -0
- package/src/step-dispatcher/changes.json +6 -0
- package/src/template-resolver/changes.json +54 -0
- package/src/tenant/changes.json +19 -0
- package/src/tenant-lifecycle/changes.json +6 -0
- package/src/user-data-rights/changes.json +36 -0
- package/src/waitlist/changes.json +18 -0
- package/src/workflow-runner/changes.json +6 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
|
|
2
|
+
import { appendEventInTenantDb, getStreamVersionInTenantDb, } from "@cosmicdrift/kumiko-framework/event-store";
|
|
3
|
+
import { DOCUMENT_EXTRACT_AGGREGATE_TYPE, documentExtractFailedPayloadSchema, documentExtractReadyPayloadSchema, } from "./events.js";
|
|
4
|
+
// Version 1 of the stream is the extract's created event; anything beyond it is the terminal event.
|
|
5
|
+
const CREATED_ONLY_STREAM_VERSION = 1;
|
|
6
|
+
const UNKNOWN_EXTRACT_ERROR = "unknown extract error";
|
|
7
|
+
// A previous delivery created the extract but died before appending its ready/failed event.
|
|
8
|
+
// Without the event, consumers waiting on it hang forever.
|
|
9
|
+
export async function appendMissingDocumentExtractEvent(deps, existing, fileRefId, options) {
|
|
10
|
+
if (deps.tenantDb.tenantId !== deps.tenantId) {
|
|
11
|
+
throw new InternalError({
|
|
12
|
+
message: `document-ingest-foundation: tenantDb is bound to tenant ${deps.tenantDb.tenantId}, not ${deps.tenantId}`,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
const version = await getStreamVersionInTenantDb(deps.tenantDb, existing.id);
|
|
16
|
+
// A missing stream means a wrong id; appending would make the terminal event the first event of a new stream.
|
|
17
|
+
if (version === 0) {
|
|
18
|
+
throw new InternalError({
|
|
19
|
+
message: `document-ingest-foundation: no document extract stream for id ${existing.id}`,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
// skip: the terminal event was already written, nothing to catch up
|
|
23
|
+
if (version > CREATED_ONLY_STREAM_VERSION)
|
|
24
|
+
return "already-terminal";
|
|
25
|
+
const metaError = existing.meta?.error;
|
|
26
|
+
const failed = typeof metaError === "string";
|
|
27
|
+
await appendEventInTenantDb(deps.tenantDb, {
|
|
28
|
+
aggregateId: existing.id,
|
|
29
|
+
aggregateType: DOCUMENT_EXTRACT_AGGREGATE_TYPE,
|
|
30
|
+
expectedVersion: version,
|
|
31
|
+
type: failed ? options.failedEventQn : options.readyEventQn,
|
|
32
|
+
payload: failed
|
|
33
|
+
? documentExtractFailedPayloadSchema.parse({
|
|
34
|
+
documentExtractId: existing.id,
|
|
35
|
+
fileRefId,
|
|
36
|
+
error: options.mapError?.(metaError) || metaError || UNKNOWN_EXTRACT_ERROR,
|
|
37
|
+
})
|
|
38
|
+
: documentExtractReadyPayloadSchema.parse({ documentExtractId: existing.id, fileRefId }),
|
|
39
|
+
metadata: { userId: deps.actor.id },
|
|
40
|
+
}, { registry: deps.registry });
|
|
41
|
+
return failed ? "appended-failed" : "appended-ready";
|
|
42
|
+
}
|
|
@@ -26,3 +26,14 @@ export declare const documentIngestSkippedPayloadSchema: z.ZodObject<{
|
|
|
26
26
|
}>;
|
|
27
27
|
}, z.core.$strip>;
|
|
28
28
|
export type DocumentIngestSkippedPayload = z.infer<typeof documentIngestSkippedPayloadSchema>;
|
|
29
|
+
export declare const documentExtractReadyPayloadSchema: z.ZodObject<{
|
|
30
|
+
documentExtractId: z.ZodString;
|
|
31
|
+
fileRefId: z.ZodString;
|
|
32
|
+
}, z.core.$strip>;
|
|
33
|
+
export type DocumentExtractReadyPayload = z.infer<typeof documentExtractReadyPayloadSchema>;
|
|
34
|
+
export declare const documentExtractFailedPayloadSchema: z.ZodObject<{
|
|
35
|
+
documentExtractId: z.ZodString;
|
|
36
|
+
fileRefId: z.ZodString;
|
|
37
|
+
error: z.ZodString;
|
|
38
|
+
}, z.core.$strip>;
|
|
39
|
+
export type DocumentExtractFailedPayload = z.infer<typeof documentExtractFailedPayloadSchema>;
|
|
@@ -10,7 +10,7 @@ export const DOCUMENT_INGEST_AGGREGATE_TYPE = "document-ingest";
|
|
|
10
10
|
// "documentExtract", so the projection replays this stream through an extension.
|
|
11
11
|
export const DOCUMENT_EXTRACT_AGGREGATE_TYPE = "document-extract";
|
|
12
12
|
export const DOCUMENT_INGEST_REQUESTED_EVENT_SHORT = "documentIngest.requested";
|
|
13
|
-
// Qualified name — what ctx.
|
|
13
|
+
// Qualified name — what ctx.events.unsafeAppend's `type` actually needs
|
|
14
14
|
// (r.defineEvent registers under qn(toKebab(feature), "event",
|
|
15
15
|
// toKebab(shortName)); appendEvent looks up the registry by QN, not the
|
|
16
16
|
// short name — see MSP-apply "event not registered" error otherwise).
|
|
@@ -35,3 +35,14 @@ export const documentIngestSkippedPayloadSchema = z.object({
|
|
|
35
35
|
size: z.number().int().min(0),
|
|
36
36
|
reason: z.enum(["file-too-large", "unsupported-mime-type"]),
|
|
37
37
|
});
|
|
38
|
+
// Terminal events of a document-extract stream. The QNs belong to the provider that registers
|
|
39
|
+
// them; the foundation only owns the shared payload shape.
|
|
40
|
+
export const documentExtractReadyPayloadSchema = z.object({
|
|
41
|
+
documentExtractId: z.string().min(1),
|
|
42
|
+
fileRefId: z.string().min(1),
|
|
43
|
+
});
|
|
44
|
+
export const documentExtractFailedPayloadSchema = z.object({
|
|
45
|
+
documentExtractId: z.string().min(1),
|
|
46
|
+
fileRefId: z.string().min(1),
|
|
47
|
+
error: z.string().min(1),
|
|
48
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { documentIngestAggregateId } from "./aggregate-id.ts";
|
|
2
|
+
export { type AppendMissingExtractEventDeps, type AppendMissingExtractEventOptions, type AppendMissingExtractEventResult, appendMissingDocumentExtractEvent, type ExistingDocumentExtract, } from "./append-missing-extract-event.ts";
|
|
2
3
|
export { type DocumentExtractMeta, documentExtractEntity, documentExtractsTable, type IngestPage, } from "./entity.ts";
|
|
3
|
-
export { DOCUMENT_EXTRACT_AGGREGATE_TYPE, DOCUMENT_INGEST_AGGREGATE_TYPE, DOCUMENT_INGEST_REQUESTED_EVENT_QN, DOCUMENT_INGEST_REQUESTED_EVENT_SHORT, DOCUMENT_INGEST_SKIPPED_EVENT_QN, DOCUMENT_INGEST_SKIPPED_EVENT_SHORT, type DocumentIngestRequestedPayload, type DocumentIngestSkippedPayload, documentIngestRequestedPayloadSchema, documentIngestSkippedPayloadSchema, } from "./events.ts";
|
|
4
|
+
export { DOCUMENT_EXTRACT_AGGREGATE_TYPE, DOCUMENT_INGEST_AGGREGATE_TYPE, DOCUMENT_INGEST_REQUESTED_EVENT_QN, DOCUMENT_INGEST_REQUESTED_EVENT_SHORT, DOCUMENT_INGEST_SKIPPED_EVENT_QN, DOCUMENT_INGEST_SKIPPED_EVENT_SHORT, type DocumentExtractFailedPayload, type DocumentExtractReadyPayload, type DocumentIngestRequestedPayload, type DocumentIngestSkippedPayload, documentExtractFailedPayloadSchema, documentExtractReadyPayloadSchema, documentIngestRequestedPayloadSchema, documentIngestSkippedPayloadSchema, } from "./events.ts";
|
|
4
5
|
export { createDocumentIngestFoundationFeature } from "./feature.ts";
|
|
5
6
|
export { readIngestPages, writeIngestPages } from "./pages.ts";
|
|
6
7
|
export { type DocumentIngestProviderOptions, documentIngestProviderOptionsSchema, documentIngestProviderTrigger, EXT_DOCUMENT_INGEST_PROVIDER, listIngestibleMimeTypes, type ResolvedDocumentIngestProvider, resolveDocumentIngestProviders, } from "./providers.ts";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Public API of the document-ingest-foundation bundled-feature.
|
|
2
2
|
export { documentIngestAggregateId } from "./aggregate-id.js";
|
|
3
|
+
export { appendMissingDocumentExtractEvent, } from "./append-missing-extract-event.js";
|
|
3
4
|
export { documentExtractEntity, documentExtractsTable, } from "./entity.js";
|
|
4
|
-
export { DOCUMENT_EXTRACT_AGGREGATE_TYPE, DOCUMENT_INGEST_AGGREGATE_TYPE, DOCUMENT_INGEST_REQUESTED_EVENT_QN, DOCUMENT_INGEST_REQUESTED_EVENT_SHORT, DOCUMENT_INGEST_SKIPPED_EVENT_QN, DOCUMENT_INGEST_SKIPPED_EVENT_SHORT, documentIngestRequestedPayloadSchema, documentIngestSkippedPayloadSchema, } from "./events.js";
|
|
5
|
+
export { DOCUMENT_EXTRACT_AGGREGATE_TYPE, DOCUMENT_INGEST_AGGREGATE_TYPE, DOCUMENT_INGEST_REQUESTED_EVENT_QN, DOCUMENT_INGEST_REQUESTED_EVENT_SHORT, DOCUMENT_INGEST_SKIPPED_EVENT_QN, DOCUMENT_INGEST_SKIPPED_EVENT_SHORT, documentExtractFailedPayloadSchema, documentExtractReadyPayloadSchema, documentIngestRequestedPayloadSchema, documentIngestSkippedPayloadSchema, } from "./events.js";
|
|
5
6
|
export { createDocumentIngestFoundationFeature } from "./feature.js";
|
|
6
7
|
export { readIngestPages, writeIngestPages } from "./pages.js";
|
|
7
8
|
export { documentIngestProviderOptionsSchema, documentIngestProviderTrigger, EXT_DOCUMENT_INGEST_PROVIDER, listIngestibleMimeTypes, resolveDocumentIngestProviders, } from "./providers.js";
|
|
@@ -8,6 +8,7 @@ import { FEATURE_TOGGLES_I18N } from "./i18n.js";
|
|
|
8
8
|
import { FEATURE_TOGGLE_SET_EVENT_NAME, FeatureToggleHandlers, FeatureToggleQueries, TOGGLE_ADMIN_SCREEN_ID, } from "./web/constants.js";
|
|
9
9
|
export function createFeatureTogglesFeature(options = {}) {
|
|
10
10
|
return defineFeature("feature-toggles", (r) => {
|
|
11
|
+
r.adoptsBundledLists();
|
|
11
12
|
r.describe('Persists per-feature enabled/disabled state in the `store_global_feature_state` table and exposes a `set` write-handler plus `list`/`registered` query-handlers so operators can flip features at runtime without redeploying. Each API instance keeps an in-memory `GlobalFeatureToggleRuntime` snapshot (initialize it via `createFeatureToggleRuntime`, pass a `() => runtime` accessor to `createFeatureTogglesFeature`) that the dispatcher gate reads on every request; a `toggle-cache-sync` multi-stream projection with `delivery: "shared"` syncs the snapshot across instances whenever a `toggle-set` event is appended.');
|
|
12
13
|
r.uiHints({
|
|
13
14
|
displayLabel: "Feature Toggles · Operator Switches",
|
|
@@ -35,7 +35,7 @@ export const registeredQuery = defineQueryHandler({
|
|
|
35
35
|
// The per-tenant signature requires SYSTEM_TENANT_ID; the app resolver
|
|
36
36
|
// returns the union of all tier features. The sentinel convention is
|
|
37
37
|
// documented in DispatcherOptions.effectiveFeatures.
|
|
38
|
-
const effective = ctx.effectiveFeatures?.(SYSTEM_TENANT_ID);
|
|
38
|
+
const effective = ctx.services.effectiveFeatures?.(SYSTEM_TENANT_ID);
|
|
39
39
|
const rows = [];
|
|
40
40
|
for (const feature of ctx.registry.features.values()) {
|
|
41
41
|
const toggleable = feature.toggleableDefault !== undefined;
|
|
@@ -111,7 +111,7 @@ export function createSetWriteHandler(getRuntime) {
|
|
|
111
111
|
// its config-changed events.
|
|
112
112
|
// unsafeAppendEvent: the strict appendEvent is bound to an app's own event map, which
|
|
113
113
|
// bundled-features cannot see. Schema validation still runs via r.defineEvent("toggle-set", ...).
|
|
114
|
-
await ctx.
|
|
114
|
+
await ctx.events.unsafeAppend({
|
|
115
115
|
aggregateId: SYSTEM_TENANT_ID,
|
|
116
116
|
aggregateType: FEATURE_TOGGLE_AGGREGATE_TYPE,
|
|
117
117
|
type: FEATURE_TOGGLE_SET_EVENT_NAME,
|
|
@@ -28,7 +28,7 @@ export function createRedisToggleSyncSignal(redisUrl, clientOptions, channelPref
|
|
|
28
28
|
onMessage(listener) {
|
|
29
29
|
signal.onMessage((_channel, payload) => {
|
|
30
30
|
if (!isTogglePayload(payload)) {
|
|
31
|
-
// biome-ignore lint/suspicious/noConsole: ops-visible fallback — no ctx.log in a raw PubSubSignal handler.
|
|
31
|
+
// biome-ignore lint/suspicious/noConsole: ops-visible fallback — no ctx.obs.log in a raw PubSubSignal handler.
|
|
32
32
|
console.error(`[kumiko:feature-toggles] dropping malformed cache-sync message on "${toggleSyncChannel}"`);
|
|
33
33
|
// skip: malformed message already logged above, nothing to apply
|
|
34
34
|
return;
|
|
@@ -10,7 +10,7 @@ export type FileDerivativesOptions = {
|
|
|
10
10
|
* Without this option, neither the httpRoute NOR the `publicVariant`
|
|
11
11
|
* query is registered — it is unreachable via the httpRoute path and via
|
|
12
12
|
* the generic `/api` query dispatch. Existing consumers that only need
|
|
13
|
-
* `ctx.derivatives` are unaffected. See {@link PublicVariantResolveApexTenant}
|
|
13
|
+
* `ctx.services.derivatives` are unaffected. See {@link PublicVariantResolveApexTenant}
|
|
14
14
|
* for the in-memory/sync contract. */
|
|
15
15
|
readonly resolveApexTenant?: PublicVariantResolveApexTenant;
|
|
16
16
|
/** Base path of the public variant route. Default "/media". */
|
|
@@ -45,7 +45,7 @@ export function createFileDerivativesFeature(opts = {}) {
|
|
|
45
45
|
throw new Error("createFileDerivativesFeature: publicTenantResolution requires resolveApexTenant — it only changes which tenant a variant is read from, resolveApexTenant still gates the host.");
|
|
46
46
|
}
|
|
47
47
|
return defineFeature(FEATURE_NAME, (r) => {
|
|
48
|
-
r.describe("Declares the `derivativeRenderer` extension point. `ctx.derivatives.variant(fileRefId, spec, name)` derives a variant of a tracked FileRef the first time it's requested and reuses the stored result afterwards (derive-on-first-use, keyed by a hash of the spec). Mount at least one `derivatives-*` renderer feature alongside this one — without a registered renderer for the FileRef's MIME type, every `variant(...)` call throws. Also declares the `derivativePublicPredicate` extension point (`r.useExtension(EXT_DERIVATIVE_PUBLIC_PREDICATE, '<entityType>', { isPublic })`) and, when `createFileDerivativesFeature({resolveApexTenant})` is passed a host-resolver, mounts an anonymous `GET {basePath}/:fileRefId/:variant` route that serves any variant name the FileRef's field declared in its `variants` for a FileRef whose entityType has a registered predicate returning true — default-deny (404) otherwise, same as an unknown FileRef or an undeclared variant name. The route's only rate-limit (`per: \"ip\"`) depends on the server's `trustedProxyHops` matching the deployment's actual reverse-proxy count — at the default 0 it ignores `x-forwarded-for` entirely, so every caller shares one bucket until that's configured. `publicTenantResolution: \"fileRef\"` keeps resolveApexTenant as the host gate but reads the variant from the FileRef row's own tenant instead of the host's, so one shared platform host serves every tenant's public variants — each FileRef-tenant's own `isPublic` predicate still default-denies. Also declares the `derivativeOverlayResolver` extension point (`r.useExtension(EXT_DERIVATIVE_OVERLAY_RESOLVER, '<entityType>', { resolve })`), used to turn a variant's `overlays[].dataToken` into the actual QR payload for that FileRef's entityType before the variant is rendered — a variant declaring a `qr` overlay throws at request-time if no resolver is registered for the FileRef's entityType.");
|
|
48
|
+
r.describe("Declares the `derivativeRenderer` extension point. `ctx.services.derivatives.variant(fileRefId, spec, name)` derives a variant of a tracked FileRef the first time it's requested and reuses the stored result afterwards (derive-on-first-use, keyed by a hash of the spec). Mount at least one `derivatives-*` renderer feature alongside this one — without a registered renderer for the FileRef's MIME type, every `variant(...)` call throws. Also declares the `derivativePublicPredicate` extension point (`r.useExtension(EXT_DERIVATIVE_PUBLIC_PREDICATE, '<entityType>', { isPublic })`) and, when `createFileDerivativesFeature({resolveApexTenant})` is passed a host-resolver, mounts an anonymous `GET {basePath}/:fileRefId/:variant` route that serves any variant name the FileRef's field declared in its `variants` for a FileRef whose entityType has a registered predicate returning true — default-deny (404) otherwise, same as an unknown FileRef or an undeclared variant name. The route's only rate-limit (`per: \"ip\"`) depends on the server's `trustedProxyHops` matching the deployment's actual reverse-proxy count — at the default 0 it ignores `x-forwarded-for` entirely, so every caller shares one bucket until that's configured. `publicTenantResolution: \"fileRef\"` keeps resolveApexTenant as the host gate but reads the variant from the FileRef row's own tenant instead of the host's, so one shared platform host serves every tenant's public variants — each FileRef-tenant's own `isPublic` predicate still default-denies. Also declares the `derivativeOverlayResolver` extension point (`r.useExtension(EXT_DERIVATIVE_OVERLAY_RESOLVER, '<entityType>', { resolve })`), used to turn a variant's `overlays[].dataToken` into the actual QR payload for that FileRef's entityType before the variant is rendered — a variant declaring a `qr` overlay throws at request-time if no resolver is registered for the FileRef's entityType.");
|
|
49
49
|
r.uiHints({
|
|
50
50
|
displayLabel: "File Derivatives",
|
|
51
51
|
category: "storage",
|
|
@@ -30,6 +30,6 @@ export const publicVariantByFileRefQuery = defineQueryHandler({
|
|
|
30
30
|
const tenant = await fetchOne(db, tenantTable, { id: row.tenantId });
|
|
31
31
|
if (!tenant || !isTenantServingPublicContent(tenant))
|
|
32
32
|
return null;
|
|
33
|
-
return ctx.queryAs(createAnonymousUser(row.tenantId), PUBLIC_VARIANT_QN, query.payload);
|
|
33
|
+
return ctx.dispatch.queryAs(createAnonymousUser(row.tenantId), PUBLIC_VARIANT_QN, query.payload);
|
|
34
34
|
},
|
|
35
35
|
});
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// consumer's `resolverTrust`/anonymousAccess setup, not the host.
|
|
19
19
|
//
|
|
20
20
|
// In `publicTenantResolution: "fileRef"` mode, this handler is also the
|
|
21
|
-
// `ctx.queryAs(createAnonymousUser(fileRefTenantId), ...)` target of
|
|
21
|
+
// `ctx.dispatch.queryAs(createAnonymousUser(fileRefTenantId), ...)` target of
|
|
22
22
|
// publicVariantByFileRefQuery — tenantId there comes from the FileRef row,
|
|
23
23
|
// but this handler's own isPublic gate runs exactly the same either way.
|
|
24
24
|
import { computeRevisionEtag } from "@cosmicdrift/kumiko-framework/api";
|
|
@@ -87,13 +87,13 @@ export const publicVariantQuery = defineQueryHandler({
|
|
|
87
87
|
}, ctx);
|
|
88
88
|
if (!isPublic)
|
|
89
89
|
return null;
|
|
90
|
-
// ctx.files/ctx.derivatives are optional on HandlerContext (only wired
|
|
90
|
+
// ctx.services.files/ctx.services.derivatives are optional on HandlerContext (only wired
|
|
91
91
|
// when file-foundation resolved a provider) — narrow via a plain guard,
|
|
92
92
|
// never `!`/`as`, and surface a real config error (not a silent deny)
|
|
93
93
|
// when the feature isn't actually wired.
|
|
94
|
-
const { files, derivatives } = ctx;
|
|
94
|
+
const { services: { files, derivatives }, } = ctx;
|
|
95
95
|
if (!files || !derivatives) {
|
|
96
|
-
throw new Error("file-derivatives requires ctx.files/ctx.derivatives — is file-foundation mounted?");
|
|
96
|
+
throw new Error("file-derivatives requires ctx.services.files/ctx.services.derivatives — is file-foundation mounted?");
|
|
97
97
|
}
|
|
98
98
|
const spec = resolveFieldVariant(ctx.registry, entityType, fieldName, query.payload.variant);
|
|
99
99
|
if (!spec)
|
|
@@ -102,7 +102,7 @@ export const publicVariantQuery = defineQueryHandler({
|
|
|
102
102
|
const bytes = await files.refFromFileRef(result).read();
|
|
103
103
|
// ponytail: fully buffered (no streaming), +33% over the wire from
|
|
104
104
|
// base64 — HttpRouteHandlerDeps only exposes {app, systemQuery} (no
|
|
105
|
-
// direct ctx.files access from the Hono handler itself), and the local
|
|
105
|
+
// direct ctx.services.files access from the Hono handler itself), and the local
|
|
106
106
|
// dev storage provider has no getSignedUrl (a redirect design wouldn't
|
|
107
107
|
// work in dev). Upgrade path: a binary-passthrough dispatcher primitive
|
|
108
108
|
// would be its own, larger issue.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// extension point + the per-tenant `provider` config key. Provider RESOLUTION
|
|
5
5
|
// (createFileProviderForTenant) + the plugin types now live in the framework
|
|
6
6
|
// (packages/framework/src/files/provider-resolver.ts) so the upload routes,
|
|
7
|
-
// `ctx.files` and the GDPR jobs resolve through ONE path — uploads, export and
|
|
7
|
+
// `ctx.services.files` and the GDPR jobs resolve through ONE path — uploads, export and
|
|
8
8
|
// erasure hit the same store by construction. This feature re-exports the moved
|
|
9
9
|
// symbols unchanged so existing imports keep working.
|
|
10
10
|
//
|
|
@@ -7,8 +7,10 @@ export type FileRefContent = {
|
|
|
7
7
|
readonly size: number;
|
|
8
8
|
};
|
|
9
9
|
export declare function fileContextForTenant(ctx: {
|
|
10
|
-
readonly
|
|
11
|
-
|
|
10
|
+
readonly services: {
|
|
11
|
+
readonly _fileProviderResolver?: FileProviderResolver | undefined;
|
|
12
|
+
readonly files?: FileContext | undefined;
|
|
13
|
+
};
|
|
12
14
|
}, contextTenantId: string, tenantId: string): FileContext | undefined;
|
|
13
15
|
export declare function fileContextFromResolver(resolver: FileProviderResolver, tenantId: string): FileContext;
|
|
14
16
|
export declare class FileRefTooLargeError extends Error {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { selectMany } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import { isUuid } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
3
|
import { createTenantFileContext, fileRefsTable, } from "@cosmicdrift/kumiko-framework/files";
|
|
4
|
-
// Tenant-bound on purpose: without a resolver `ctx.files` only reaches the storage of the
|
|
4
|
+
// Tenant-bound on purpose: without a resolver `ctx.services.files` only reaches the storage of the
|
|
5
5
|
// context's own tenant (`contextTenantId`), so a request for another tenant's files is
|
|
6
6
|
// undefined instead of silently reading through the wrong tenant's storage.
|
|
7
7
|
export function fileContextForTenant(ctx, contextTenantId, tenantId) {
|
|
8
|
-
const resolver = ctx._fileProviderResolver;
|
|
8
|
+
const resolver = ctx.services._fileProviderResolver;
|
|
9
9
|
if (resolver === undefined)
|
|
10
|
-
return tenantId === contextTenantId ? ctx.files : undefined;
|
|
10
|
+
return tenantId === contextTenantId ? ctx.services.files : undefined;
|
|
11
11
|
return fileContextFromResolver(resolver, tenantId);
|
|
12
12
|
}
|
|
13
13
|
export function fileContextFromResolver(resolver, tenantId) {
|
|
@@ -127,7 +127,7 @@ async function buildS3Provider(ctx, tenantId) {
|
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
129
|
async function readSecretAccessKey(ctx, tenantId) {
|
|
130
|
-
const secrets = requireSecretsContext(ctx, FEATURE_NAME);
|
|
130
|
+
const secrets = requireSecretsContext({ secrets: ctx.secrets, auditUserId: ctx.auditUserId }, FEATURE_NAME);
|
|
131
131
|
const branded = await secrets.get(tenantId, S3_SECRET_ACCESS_KEY);
|
|
132
132
|
return requireSecretSet(branded, FEATURE_NAME, S3_SECRET_ACCESS_KEY.name).reveal();
|
|
133
133
|
}
|
|
@@ -34,9 +34,9 @@ export const sweepOrphanedDerivativesPayloadSchema = z.object({
|
|
|
34
34
|
});
|
|
35
35
|
export async function sweepOrphanedDerivativesJob(rawPayload, ctx, db) {
|
|
36
36
|
const payload = sweepOrphanedDerivativesPayloadSchema.parse(rawPayload ?? {});
|
|
37
|
-
const maybeResolver = ctx._fileProviderResolver;
|
|
37
|
+
const maybeResolver = ctx.services._fileProviderResolver;
|
|
38
38
|
if (!maybeResolver) {
|
|
39
|
-
ctx.log?.warn("[files-tenant-data:sweep] no _fileProviderResolver wired — nothing to sweep, skipping run");
|
|
39
|
+
ctx.obs.log?.warn("[files-tenant-data:sweep] no _fileProviderResolver wired — nothing to sweep, skipping run");
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
42
|
const resolver = maybeResolver;
|
|
@@ -65,7 +65,7 @@ export async function sweepOrphanedDerivativesJob(rawPayload, ctx, db) {
|
|
|
65
65
|
provider = await resolver(tenantId);
|
|
66
66
|
}
|
|
67
67
|
catch (err) {
|
|
68
|
-
ctx.log?.warn?.(`[files-tenant-data:sweep] no file provider resolvable for tenant=${tenantId}, skipping: ${err instanceof Error ? err.message : String(err)}`);
|
|
68
|
+
ctx.obs.log?.warn?.(`[files-tenant-data:sweep] no file provider resolvable for tenant=${tenantId}, skipping: ${err instanceof Error ? err.message : String(err)}`);
|
|
69
69
|
continue;
|
|
70
70
|
}
|
|
71
71
|
let keys;
|
|
@@ -73,7 +73,7 @@ export async function sweepOrphanedDerivativesJob(rawPayload, ctx, db) {
|
|
|
73
73
|
keys = await provider.list(`${tenantId}/`);
|
|
74
74
|
}
|
|
75
75
|
catch (err) {
|
|
76
|
-
ctx.log?.warn?.(`[files-tenant-data:sweep] provider.list() failed for tenant=${tenantId}, skipping: ${err instanceof Error ? err.message : String(err)}`);
|
|
76
|
+
ctx.obs.log?.warn?.(`[files-tenant-data:sweep] provider.list() failed for tenant=${tenantId}, skipping: ${err instanceof Error ? err.message : String(err)}`);
|
|
77
77
|
continue;
|
|
78
78
|
}
|
|
79
79
|
for (const key of keys) {
|
|
@@ -99,7 +99,7 @@ export async function sweepOrphanedDerivativesJob(rawPayload, ctx, db) {
|
|
|
99
99
|
const owners = await selectMany(db, fileRefsTable, { tenantId: candidate.tenantId, storageKey: candidate.originalKey }, { limit: 1 });
|
|
100
100
|
if (owners.length > 0)
|
|
101
101
|
return "skipped";
|
|
102
|
-
// Binaries written through ctx.files.ref(key) (and their derive()d
|
|
102
|
+
// Binaries written through ctx.services.files.ref(key) (and their derive()d
|
|
103
103
|
// variants) never get a fileRef row; an original still sitting in storage
|
|
104
104
|
// means the derivative is not an orphan.
|
|
105
105
|
if (await candidate.provider.exists(candidate.originalKey))
|
|
@@ -117,10 +117,10 @@ export async function sweepOrphanedDerivativesJob(rawPayload, ctx, db) {
|
|
|
117
117
|
migrateRow,
|
|
118
118
|
maxFailures,
|
|
119
119
|
deadlineAt: deadline,
|
|
120
|
-
signal: ctx.signal,
|
|
120
|
+
signal: ctx.lifecycle.signal,
|
|
121
121
|
onRowError: (candidate, err) => {
|
|
122
|
-
ctx.log?.warn?.(`[files-tenant-data:sweep] failed to delete key=${candidate.key} tenant=${candidate.tenantId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
122
|
+
ctx.obs.log?.warn?.(`[files-tenant-data:sweep] failed to delete key=${candidate.key} tenant=${candidate.tenantId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
123
123
|
},
|
|
124
124
|
});
|
|
125
|
-
ctx.log?.info?.(`[files-tenant-data:sweep] complete dryRun=${dryRun} deleted=${outcome.migrated} wouldDelete=${dryRunWouldDelete} skipped=${outcome.skipped} failed=${outcome.failed} batches=${outcome.batchesProcessed} stoppedReason=${outcome.stoppedReason}`);
|
|
125
|
+
ctx.obs.log?.info?.(`[files-tenant-data:sweep] complete dryRun=${dryRun} deleted=${outcome.migrated} wouldDelete=${dryRunWouldDelete} skipped=${outcome.skipped} failed=${outcome.failed} batches=${outcome.batchesProcessed} stoppedReason=${outcome.stoppedReason}`);
|
|
126
126
|
}
|
|
@@ -20,7 +20,7 @@ function registerFormDraft(r) {
|
|
|
20
20
|
recommended: false,
|
|
21
21
|
});
|
|
22
22
|
// config is optional: the retention-days key only resolves when the
|
|
23
|
-
// config feature is mounted (ctx.configResolver present) — the cleanup
|
|
23
|
+
// config feature is mounted (ctx.services.configResolver present) — the cleanup
|
|
24
24
|
// job already falls back to FORM_DRAFT_DEFAULT_RETENTION_DAYS otherwise
|
|
25
25
|
// (see handlers/cleanup.job.ts). A hard r.requires({ features: ["config"] }) would break
|
|
26
26
|
// every app that mounts form-draft without config, which is a breaking
|
|
@@ -37,7 +37,12 @@ async function releaseRowFileRefs(row, db, fileProviderResolver, log) {
|
|
|
37
37
|
const isCreateMode = row.draftKey.includes(":new:");
|
|
38
38
|
const ownedRefs = await filterOwnedFileRefs(db, row.tenantId, row.ownerId, keys, row.insertedAt, isCreateMode);
|
|
39
39
|
const systemUser = createSystemUser(row.tenantId);
|
|
40
|
-
const tenantDb = createTenantDb({
|
|
40
|
+
const tenantDb = createTenantDb({
|
|
41
|
+
db,
|
|
42
|
+
tenantId: row.tenantId,
|
|
43
|
+
mode: "system",
|
|
44
|
+
reason: "stale-draft cleanup job removes drafts of each tenant, outside any request scope",
|
|
45
|
+
});
|
|
41
46
|
for (const ref of ownedRefs) {
|
|
42
47
|
const forgetResult = await fileRefExecutor.forget({ id: ref.id }, systemUser, tenantDb);
|
|
43
48
|
if (!forgetResult.isSuccess) {
|
|
@@ -79,7 +84,12 @@ export async function deleteStaleDraftsBatch(batch, db, retentionDays, log) {
|
|
|
79
84
|
const byId = new Map(batch.map((row) => [row.id, row]));
|
|
80
85
|
for (const [tenantId, ids] of groupStaleDraftIdsByTenant(batch)) {
|
|
81
86
|
const systemUser = createSystemUser(tenantId);
|
|
82
|
-
const tenantDb = createTenantDb({
|
|
87
|
+
const tenantDb = createTenantDb({
|
|
88
|
+
db,
|
|
89
|
+
tenantId,
|
|
90
|
+
mode: "system",
|
|
91
|
+
reason: "stale-draft cleanup job removes drafts of each tenant, outside any request scope",
|
|
92
|
+
});
|
|
83
93
|
for (const id of ids) {
|
|
84
94
|
// skip: an unreadable blob hides its FileRefs; deleting now would orphan them, so the next run retries.
|
|
85
95
|
if (byId.get(id)?.draftUnreadable) {
|
|
@@ -106,22 +116,22 @@ export async function deleteStaleDraftsBatch(batch, db, retentionDays, log) {
|
|
|
106
116
|
return { deletedRows, skippedCount, deferredIds };
|
|
107
117
|
}
|
|
108
118
|
export async function cleanupDraftsJob(_payload, ctx, db) {
|
|
109
|
-
const resolved = ctx.configResolver
|
|
110
|
-
? await ctx.configResolver.get(FORM_DRAFT_RETENTION_DAYS_CONFIG_KEY, formDraftRetentionDaysConfig, SYSTEM_TENANT_ID, SYSTEM_USER_ID, db)
|
|
119
|
+
const resolved = ctx.services.configResolver
|
|
120
|
+
? await ctx.services.configResolver.get(FORM_DRAFT_RETENTION_DAYS_CONFIG_KEY, formDraftRetentionDaysConfig, SYSTEM_TENANT_ID, SYSTEM_USER_ID, db)
|
|
111
121
|
: undefined;
|
|
112
122
|
const isValidRetention = typeof resolved === "number" && resolved >= 1;
|
|
113
123
|
// configResolver missing is the legitimate no-config case (r.optionalRequires,
|
|
114
124
|
// see feature.ts) — nothing to warn about there. A resolver that IS wired but
|
|
115
125
|
// returns something unusable means an admin set an invalid value.
|
|
116
|
-
if (ctx.configResolver && !isValidRetention) {
|
|
117
|
-
ctx.log?.warn?.(`[form-draft:cleanup] configResolver returned invalid retention-days value=${String(resolved)} — falling back to default=${FORM_DRAFT_DEFAULT_RETENTION_DAYS}`);
|
|
126
|
+
if (ctx.services.configResolver && !isValidRetention) {
|
|
127
|
+
ctx.obs.log?.warn?.(`[form-draft:cleanup] configResolver returned invalid retention-days value=${String(resolved)} — falling back to default=${FORM_DRAFT_DEFAULT_RETENTION_DAYS}`);
|
|
118
128
|
}
|
|
119
129
|
const retentionDays = isValidRetention ? resolved : FORM_DRAFT_DEFAULT_RETENTION_DAYS;
|
|
120
|
-
const fileProviderResolver = ctx._fileProviderResolver;
|
|
130
|
+
const fileProviderResolver = ctx.services._fileProviderResolver;
|
|
121
131
|
let deleted = 0;
|
|
122
132
|
const deferred = new Set();
|
|
123
133
|
while (true) {
|
|
124
|
-
if (ctx.signal?.aborted)
|
|
134
|
+
if (ctx.lifecycle.signal?.aborted)
|
|
125
135
|
break;
|
|
126
136
|
const batch = await selectStaleDraftsBatch(db, retentionDays, DEFAULT_BATCH_SIZE, [
|
|
127
137
|
...deferred,
|
|
@@ -129,17 +139,17 @@ export async function cleanupDraftsJob(_payload, ctx, db) {
|
|
|
129
139
|
if (batch.length === 0)
|
|
130
140
|
break;
|
|
131
141
|
// Rows span arbitrary tenants (this job sweeps the whole table under
|
|
132
|
-
// SYSTEM_TENANT_ID, not per-tenant) — ctx.files is resolved for a single
|
|
142
|
+
// SYSTEM_TENANT_ID, not per-tenant) — ctx.services.files is resolved for a single
|
|
133
143
|
// tenant per job run and would be wrong here, so each row resolves its
|
|
134
144
|
// own tenant's provider via _fileProviderResolver instead. Skipped
|
|
135
145
|
// entirely for rows with no FileRefs in the blob, the common case.
|
|
136
146
|
// Delete first (with staleness re-check), then release binaries from rows
|
|
137
147
|
// that actually disappeared — never release a draft the user just saved.
|
|
138
|
-
const { deletedRows, skippedCount, deferredIds } = await deleteStaleDraftsBatch(batch, db, retentionDays, ctx.log);
|
|
148
|
+
const { deletedRows, skippedCount, deferredIds } = await deleteStaleDraftsBatch(batch, db, retentionDays, ctx.obs.log);
|
|
139
149
|
for (const id of deferredIds)
|
|
140
150
|
deferred.add(id);
|
|
141
151
|
for (const row of deletedRows) {
|
|
142
|
-
await releaseRowFileRefs(row, db, fileProviderResolver, ctx.log);
|
|
152
|
+
await releaseRowFileRefs(row, db, fileProviderResolver, ctx.obs.log);
|
|
143
153
|
}
|
|
144
154
|
deleted += deletedRows.length;
|
|
145
155
|
// A skipped row is no longer stale, so the next select drops it — a fully
|
|
@@ -149,5 +159,5 @@ export async function cleanupDraftsJob(_payload, ctx, db) {
|
|
|
149
159
|
batch.length < DEFAULT_BATCH_SIZE)
|
|
150
160
|
break;
|
|
151
161
|
}
|
|
152
|
-
ctx.log?.info?.(`[form-draft:cleanup] deleted=${deleted} retentionDays=${retentionDays}`);
|
|
162
|
+
ctx.obs.log?.info?.(`[form-draft:cleanup] deleted=${deleted} retentionDays=${retentionDays}`);
|
|
153
163
|
}
|
|
@@ -47,7 +47,7 @@ export const discardDraftWrite = defineWriteHandler({
|
|
|
47
47
|
// releaseFiles: a successful-submit discard must NOT release — the
|
|
48
48
|
// domain entity the submit just wrote carries the same storageKeys
|
|
49
49
|
// forward (see schemas.ts comment on discardDraftPayloadSchema).
|
|
50
|
-
const files = ctx.files;
|
|
50
|
+
const files = ctx.services.files;
|
|
51
51
|
if (files && event.payload.releaseFiles === true) {
|
|
52
52
|
const candidateKeys = collectDraftFileRefKeys(existing.draft);
|
|
53
53
|
// Only storageKeys with a real file_refs row owned by THIS caller are
|
|
@@ -72,8 +72,8 @@ export const discardDraftWrite = defineWriteHandler({
|
|
|
72
72
|
// Binary delete only after commit — in-tx delete would orphan pointers
|
|
73
73
|
// if the surrounding write transaction rolls back after this handler.
|
|
74
74
|
const keys = ownedRefs.map((ref) => ref.storageKey);
|
|
75
|
-
const log = ctx.log;
|
|
76
|
-
const schedule = ctx.
|
|
75
|
+
const log = ctx.obs.log;
|
|
76
|
+
const schedule = ctx.lifecycle.afterCommit;
|
|
77
77
|
const release = async () => {
|
|
78
78
|
await releaseDraftFileRefs(keys, async (key) => {
|
|
79
79
|
await files.refFromFileRef({ storageKey: key }).delete();
|
|
@@ -18,7 +18,7 @@ export const getDraftQuery = defineQueryHandler({
|
|
|
18
18
|
if (!row.draft) {
|
|
19
19
|
// Schema evolution or a corrupt/erased row: surface it to operators
|
|
20
20
|
// instead of silently making the user's draft vanish.
|
|
21
|
-
ctx.log?.warn?.(`[form-draft:get] stored blob for draftKey=${query.payload.draftKey} failed schema or decryption, treating as absent`);
|
|
21
|
+
ctx.obs.log?.warn?.(`[form-draft:get] stored blob for draftKey=${query.payload.draftKey} failed schema or decryption, treating as absent`);
|
|
22
22
|
return { draft: null };
|
|
23
23
|
}
|
|
24
24
|
return { draft: row.draft };
|
|
@@ -34,7 +34,7 @@ export declare function requireDefined<T>(value: T | undefined, featureName: str
|
|
|
34
34
|
*/
|
|
35
35
|
export declare function requireNonEmpty(value: string | undefined, featureName: string, label: string, uiHint?: string): string;
|
|
36
36
|
/**
|
|
37
|
-
* Narrow a `ctx.secrets.get()` result → set secret. The secrets-counterpart
|
|
37
|
+
* Narrow a `ctx.services.secrets.get()` result → set secret. The secrets-counterpart
|
|
38
38
|
* to requireNonEmpty: a missing secret is a tenant-configuration gap, not a
|
|
39
39
|
* crash — same 422 contract, so clients route to the settings screen.
|
|
40
40
|
*
|
|
@@ -68,7 +68,7 @@ export function requireNonEmpty(value, featureName, label, uiHint = "Set via ten
|
|
|
68
68
|
return trimmed;
|
|
69
69
|
}
|
|
70
70
|
/**
|
|
71
|
-
* Narrow a `ctx.secrets.get()` result → set secret. The secrets-counterpart
|
|
71
|
+
* Narrow a `ctx.services.secrets.get()` result → set secret. The secrets-counterpart
|
|
72
72
|
* to requireNonEmpty: a missing secret is a tenant-configuration gap, not a
|
|
73
73
|
* crash — same 422 contract, so clients route to the settings screen.
|
|
74
74
|
*
|
|
@@ -11,6 +11,9 @@ function validateRedirects(options) {
|
|
|
11
11
|
if (!REDIRECT_PATH_PATTERN.test(rule.from)) {
|
|
12
12
|
throw new Error(`host-routing: redirect from must be a path like "/old", got "${rule.from}"`);
|
|
13
13
|
}
|
|
14
|
+
if (rule.from === "/api" || rule.from.startsWith("/api/")) {
|
|
15
|
+
throw new Error(`host-routing: redirect from must not be an /api path, it would never fire, got "${rule.from}"`);
|
|
16
|
+
}
|
|
14
17
|
if (!REDIRECT_TARGET_PATTERN.test(rule.to)) {
|
|
15
18
|
throw new Error(`host-routing: redirect to must be a same-origin path or an https URL without query, got "${rule.to}"`);
|
|
16
19
|
}
|
|
@@ -26,7 +26,7 @@ export const MAIL_ACCOUNT_AGGREGATE_TYPE = "mail-account";
|
|
|
26
26
|
export const INBOUND_MESSAGE_AGGREGATE_TYPE = "inbound-message";
|
|
27
27
|
export const MAIL_THREAD_AGGREGATE_TYPE = "mail-thread";
|
|
28
28
|
// Event-name constants — short forms (for r.defineEvent) and qualified
|
|
29
|
-
// FQNs (for ctx.
|
|
29
|
+
// FQNs (for ctx.events.unsafeAppend and projection-apply keys).
|
|
30
30
|
export const MAIL_ACCOUNT_CONNECTED_EVENT_SHORT = "mail-account-connected";
|
|
31
31
|
export const MAIL_ACCOUNT_UPDATED_EVENT_SHORT = "mail-account-updated";
|
|
32
32
|
export const MAIL_ACCOUNT_DISCONNECTED_EVENT_SHORT = "mail-account-disconnected";
|
|
@@ -58,6 +58,7 @@ import { mailAccountEditScreen, mailAccountListScreen } from "./screens.js";
|
|
|
58
58
|
import { INBOUND_MAIL_TENANT_DESTROY_ARCHIVE_REASON, inboundMessageTenantDestroyHook, mailAccountTenantDestroyHook, mailThreadTenantDestroyHook, } from "./tenant-destroy-hook.js";
|
|
59
59
|
export function createInboundMailFoundationFeature() {
|
|
60
60
|
return defineFeature(INBOUND_MAIL_FOUNDATION_FEATURE, (r) => {
|
|
61
|
+
r.adoptsBundledLists();
|
|
61
62
|
r.describe("Plugin host for inbound e-mail (inbox federation) — provider plugins (inbound-provider-imap, later M365 Graph / Gmail REST) register at the `inboundMailProvider` extension point with verify/fetch and optional oauth/watch (live push). The foundation owns three event-sourced streams (mail-account lifecycle, inbound-message with exactly-once ingest via deterministic aggregate ids, mail-thread rollup) and their projections `read_mail_accounts`/`read_inbound_messages`/`read_mail_threads`; PII fields are envelope-encrypted per tenant subject key before every append (crypto-shredding on tenant destroy). Wire `createInboundMailConnectRoutes` (OAuth connect + anonymous callback outside /api) and `createInboundMailSupervisor` (IDLE watch with backoff + reconciliation poll) in bin/server.ts. Consume `inbound-mail-foundation:event:inbound-message-received` from app features to attach business processes.");
|
|
62
63
|
r.uiHints({
|
|
63
64
|
displayLabel: "Inbound Mail · Foundation",
|
|
@@ -192,7 +193,7 @@ export function createInboundMailFoundationFeature() {
|
|
|
192
193
|
let providerPromise = null;
|
|
193
194
|
const deleteBodyObject = async (bodyRef) => {
|
|
194
195
|
if (!providerPromise) {
|
|
195
|
-
providerPromise = createFileProviderForTenant({ config: ctx.config, registry: ctx.registry }, tenantId);
|
|
196
|
+
providerPromise = createFileProviderForTenant({ config: ctx.config, registry: ctx.registry, secrets: ctx.services.secrets }, tenantId);
|
|
196
197
|
}
|
|
197
198
|
const provider = await providerPromise;
|
|
198
199
|
await provider.delete(bodyRef);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { HandlerContext } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
2
|
import type { MailAccountEventPayload } from "../events.ts";
|
|
3
|
-
export declare function loadCurrentMailAccountPayload(ctx:
|
|
3
|
+
export declare function loadCurrentMailAccountPayload(ctx: {
|
|
4
|
+
readonly events: Pick<HandlerContext["events"], "load">;
|
|
5
|
+
}, accountId: string): Promise<MailAccountEventPayload | undefined>;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// and is copied byte-for-byte — NEVER re-encrypt it (that would require KMS
|
|
10
10
|
// decryption when unavailable or produce double encryption).
|
|
11
11
|
export async function loadCurrentMailAccountPayload(ctx, accountId) {
|
|
12
|
-
const events = await ctx.
|
|
12
|
+
const events = await ctx.events.load(accountId);
|
|
13
13
|
const last = events[events.length - 1];
|
|
14
14
|
// @cast-boundary engine-payload — eigene events, shape via defineEvent
|
|
15
15
|
return last?.payload;
|
|
@@ -79,7 +79,7 @@ export const connectAccountHandler = {
|
|
|
79
79
|
providerName: payload.provider,
|
|
80
80
|
reason: "connect_flow",
|
|
81
81
|
};
|
|
82
|
-
await ctx.
|
|
82
|
+
await ctx.events.unsafeAppend({
|
|
83
83
|
aggregateId: accountId,
|
|
84
84
|
aggregateType: MAIL_ACCOUNT_AGGREGATE_TYPE,
|
|
85
85
|
type: MAIL_ACCOUNT_CONNECTED_EVENT_QN,
|
|
@@ -43,7 +43,7 @@ export const disconnectAccountHandler = {
|
|
|
43
43
|
providerName: current.provider,
|
|
44
44
|
reason: payload.reason,
|
|
45
45
|
};
|
|
46
|
-
await ctx.
|
|
46
|
+
await ctx.events.unsafeAppend({
|
|
47
47
|
aggregateId: payload.accountId,
|
|
48
48
|
aggregateType: MAIL_ACCOUNT_AGGREGATE_TYPE,
|
|
49
49
|
type: MAIL_ACCOUNT_DISCONNECTED_EVENT_QN,
|