@cosmicdrift/kumiko-bundled-features 0.362.0 → 0.364.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/admin-shell/feature.d.ts +3 -0
- package/dist/admin-shell/feature.js +6 -1
- package/dist/agent-tools/agent-manifest.js +2 -1
- package/dist/agent-tools/filter-ops.d.ts +1 -1
- package/dist/agent-tools/filter-ops.js +1 -3
- package/dist/agent-tools/tool-dispatch.js +2 -1
- package/dist/audit/handlers/list.query.js +9 -5
- package/dist/auth-email-password/bootstrap.d.ts +8 -5
- package/dist/auth-email-password/bootstrap.js +12 -4
- package/dist/auth-email-password/email-rate-limits.d.ts +4 -0
- package/dist/auth-email-password/email-rate-limits.js +13 -0
- package/dist/auth-email-password/email-templates.d.ts +4 -26
- package/dist/auth-email-password/email-templates.js +9 -101
- package/dist/auth-email-password/feature.js +24 -6
- package/dist/auth-email-password/handlers/change-password.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/change-password.write.js +6 -2
- package/dist/auth-email-password/handlers/confirm-account-unlock.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/invite-accept-with-login.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/invite-accept.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/invite-create.write.d.ts +2 -2
- package/dist/auth-email-password/handlers/invite-create.write.js +4 -4
- package/dist/auth-email-password/handlers/invite-signup-complete.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/login.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/logout.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/logout.write.js +6 -2
- package/dist/auth-email-password/handlers/request-account-unlock.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/request-account-unlock.write.js +2 -4
- package/dist/auth-email-password/handlers/request-email-verification.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/request-email-verification.write.js +2 -4
- package/dist/auth-email-password/handlers/request-password-reset.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/request-password-reset.write.js +2 -4
- package/dist/auth-email-password/handlers/reset-password.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/signup-confirm.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/signup-confirm.write.js +3 -4
- package/dist/auth-email-password/handlers/signup-request.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/signup-request.write.js +2 -1
- package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/token-request-handler.d.ts +2 -3
- package/dist/auth-email-password/handlers/token-request-handler.js +2 -2
- package/dist/auth-email-password/handlers/verify-email.write.d.ts +1 -1
- package/dist/auth-email-password/index.d.ts +2 -2
- package/dist/auth-email-password/index.js +1 -1
- package/dist/auth-email-password/magic-link-mail.d.ts +3 -2
- package/dist/auth-email-password/magic-link-mail.js +19 -14
- package/dist/auth-email-password/mail-notifications.d.ts +32 -0
- package/dist/auth-email-password/mail-notifications.js +116 -0
- package/dist/auth-email-password/signup-activation.d.ts +1 -1
- package/dist/auth-email-password/signup-activation.js +2 -3
- package/dist/auth-email-password/web/auth-gate.js +16 -4
- package/dist/auth-foundation/types.js +2 -8
- package/dist/auth-mfa/feature.js +4 -4
- package/dist/auth-mfa/handlers/disable.write.d.ts +1 -1
- package/dist/auth-mfa/handlers/enable-confirm-preauth.write.d.ts +1 -1
- package/dist/auth-mfa/handlers/enable-confirm.write.d.ts +1 -1
- package/dist/auth-mfa/handlers/enable-start-preauth.write.d.ts +1 -1
- package/dist/auth-mfa/handlers/enable-start.write.d.ts +1 -1
- package/dist/auth-mfa/handlers/regenerate-recovery.write.d.ts +1 -1
- package/dist/auth-mfa/handlers/verify.write.d.ts +1 -1
- package/dist/auth-mfa/hmac-token-codec.js +4 -4
- package/dist/auth-mfa/mfa-challenge-token.js +3 -3
- package/dist/auth-mfa/mfa-preauth-setup-token.js +3 -3
- package/dist/auth-mfa/mfa-setup-token.js +8 -8
- package/dist/billing-foundation/constants.d.ts +3 -3
- package/dist/billing-foundation/constants.js +5 -4
- package/dist/billing-foundation/consumer-protection/confirmation-mail.d.ts +32 -14
- package/dist/billing-foundation/consumer-protection/confirmation-mail.js +74 -32
- package/dist/billing-foundation/consumer-protection/consent-gate.d.ts +3 -0
- package/dist/billing-foundation/consumer-protection/consent-gate.js +21 -2
- package/dist/billing-foundation/consumer-protection/issue-confirmation.js +3 -3
- package/dist/billing-foundation/consumer-protection/mail-notifications.d.ts +8 -0
- package/dist/billing-foundation/consumer-protection/mail-notifications.js +95 -0
- package/dist/billing-foundation/consumer-protection/register-consent.js +2 -0
- package/dist/billing-foundation/consumer-protection/register-termination.js +11 -1
- package/dist/billing-foundation/consumer-protection/termination-mail.d.ts +25 -13
- package/dist/billing-foundation/consumer-protection/termination-mail.js +11 -23
- package/dist/billing-foundation/consumer-protection/termination-notify.js +2 -2
- package/dist/billing-foundation/consumer-protection/termination-pages.js +1 -3
- package/dist/billing-foundation/consumer-protection/termination-receipt-limit.d.ts +6 -0
- package/dist/billing-foundation/consumer-protection/termination-receipt-limit.js +34 -0
- package/dist/billing-foundation/consumer-protection/termination-record.d.ts +2 -0
- package/dist/billing-foundation/consumer-protection/termination-record.js +7 -1
- package/dist/billing-foundation/consumer-protection/termination-request.js +31 -21
- package/dist/billing-foundation/consumer-protection/termination-texts.d.ts +1 -1
- package/dist/billing-foundation/consumer-protection/termination-texts.js +6 -0
- package/dist/billing-foundation/consumer-protection/withdrawal-period.d.ts +10 -0
- package/dist/billing-foundation/consumer-protection/withdrawal-period.js +26 -0
- package/dist/billing-foundation/handlers/create-checkout-session.write.js +11 -5
- package/dist/billing-foundation/handlers/process-event.write.js +12 -8
- package/dist/billing-foundation/handlers/process-payment-event.write.js +1 -1
- package/dist/billing-foundation/i18n.js +3 -0
- package/dist/billing-foundation/subscription-tier-sync.d.ts +7 -1
- package/dist/billing-foundation/subscription-tier-sync.js +16 -9
- package/dist/billing-foundation/types.d.ts +7 -2
- package/dist/cap-counter/calendar-cap-usage-reservation.js +2 -0
- package/dist/cap-counter/enforce-cap.d.ts +18 -1
- package/dist/cap-counter/enforce-cap.js +49 -6
- package/dist/cap-counter/index.d.ts +1 -1
- package/dist/cap-counter/index.js +1 -1
- package/dist/cap-counter/with-cap-enforcement.d.ts +2 -0
- package/dist/cap-overview/handlers/tenant-caps-list.query.js +2 -1
- package/dist/cap-overview/web/cap-usage-cell.js +5 -4
- package/dist/channel-email/email-channel.d.ts +2 -2
- package/dist/channel-email/email-channel.js +101 -26
- package/dist/channel-email/feature.js +3 -3
- package/dist/channel-email/index.d.ts +1 -1
- package/dist/channel-email/index.js +1 -1
- package/dist/channel-email/pii-guard.js +10 -0
- package/dist/channel-email/smtp-transport.js +13 -0
- package/dist/channel-email/types.d.ts +8 -0
- package/dist/channel-in-app/handlers/mark-all-read.write.d.ts +1 -1
- package/dist/channel-in-app/handlers/mark-read.write.d.ts +1 -1
- package/dist/compliance-profiles/handlers/set-profile.write.d.ts +1 -1
- package/dist/config/handlers/reset.write.d.ts +1 -1
- package/dist/config/handlers/set.write.d.ts +1 -1
- package/dist/config/handlers/set.write.js +3 -4
- package/dist/config/resolver.d.ts +1 -0
- package/dist/config/resolver.js +11 -14
- package/dist/config/write-helpers.d.ts +2 -0
- package/dist/config/write-helpers.js +19 -0
- package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +1 -1
- package/dist/crypto-shredding/handlers/forget-subject.write.js +29 -19
- package/dist/custom-fields/handlers/update-tenant-field.write.js +0 -1
- package/dist/custom-fields/lib/value-schema.js +10 -11
- package/dist/custom-fields/wire-user-data-rights.js +7 -6
- package/dist/data-retention/index.d.ts +1 -0
- package/dist/data-retention/index.js +1 -0
- package/dist/data-retention/run-retention-cleanup.js +6 -6
- package/dist/delivery/attachment-ref.d.ts +41 -0
- package/dist/delivery/attachment-ref.js +78 -0
- package/dist/delivery/channel-context.d.ts +8 -4
- package/dist/delivery/channel-context.js +94 -2
- package/dist/delivery/constants.d.ts +1 -0
- package/dist/delivery/constants.js +1 -0
- package/dist/delivery/delivery-service.d.ts +4 -1
- package/dist/delivery/delivery-service.js +38 -32
- package/dist/delivery/feature.js +1 -1
- package/dist/delivery/handlers/resubscribe-address.write.d.ts +1 -1
- package/dist/delivery/handlers/resubscribe-user.write.d.ts +1 -1
- package/dist/delivery/handlers/set-preference.write.d.ts +1 -1
- package/dist/delivery/handlers/unsubscribe-address.write.d.ts +1 -1
- package/dist/delivery/handlers/unsubscribe-user.write.d.ts +1 -1
- package/dist/delivery/index.d.ts +5 -2
- package/dist/delivery/index.js +4 -1
- package/dist/delivery/jobs.js +66 -14
- package/dist/delivery/notify-factory.js +4 -1
- package/dist/delivery/testing.d.ts +4 -1
- package/dist/delivery/types.d.ts +26 -14
- package/dist/delivery/unsubscribe.js +4 -1
- package/dist/derivatives-sharp/render.js +1 -18
- package/dist/document-ingest-foundation/pages.js +4 -4
- package/dist/feature-toggles/handlers/set.write.d.ts +1 -1
- package/dist/feature-toggles/toggle-sync-signal.js +4 -4
- package/dist/file-derivatives/handlers/public-variant.query.js +1 -1
- package/dist/file-foundation/index.d.ts +1 -0
- package/dist/file-foundation/index.js +1 -0
- package/dist/file-foundation/read-file-ref-content.d.ts +27 -0
- package/dist/file-foundation/read-file-ref-content.js +51 -0
- package/dist/files-tenant-data/hooks.js +4 -0
- package/dist/folders/web/folder-manager.js +3 -2
- package/dist/form-draft/db/queries/cleanup.js +4 -4
- package/dist/form-draft/db/queries/draft-count.js +2 -2
- package/dist/form-draft/db/queries/owned-file-refs.js +2 -2
- package/dist/form-draft/handlers/discard.write.d.ts +1 -1
- package/dist/form-draft/handlers/save.write.d.ts +1 -1
- package/dist/form-draft/release-file-refs.js +3 -2
- package/dist/inbound-mail-foundation/handlers/connect-account.write.js +1 -1
- package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +6 -6
- package/dist/inbound-mail-foundation/handlers/scope-visibility.d.ts +1 -1
- package/dist/inbound-mail-foundation/oauth-access-token.js +8 -3
- package/dist/inbound-mail-foundation/oauth-state.js +7 -7
- package/dist/inbound-mail-foundation/types.js +4 -4
- package/dist/inbound-mail-foundation/watch-supervisor.js +24 -13
- package/dist/inbound-provider-imap/imap-client.js +4 -3
- package/dist/jobs/db/queries/stale-run-sweep.d.ts +1 -1
- package/dist/jobs/db/queries/stale-run-sweep.js +12 -5
- package/dist/jobs/feature.js +5 -3
- package/dist/jobs/handlers/list.query.js +3 -1
- package/dist/jobs/handlers/retry.write.d.ts +1 -1
- package/dist/jobs/handlers/stale-run-sweep.job.d.ts +1 -1
- package/dist/jobs/handlers/stale-run-sweep.job.js +2 -2
- package/dist/jobs/handlers/trigger.write.d.ts +1 -1
- package/dist/jobs/job-run-logger.js +32 -10
- package/dist/jobs/tenant-job-run-table.js +3 -2
- package/dist/ledger/entity.js +3 -1
- package/dist/ledger/recurring.js +1 -3
- package/dist/managed-pages/branding.d.ts +2 -0
- package/dist/managed-pages/branding.js +24 -2
- package/dist/managed-pages/feature.js +1 -0
- package/dist/managed-pages/handlers/set.write.d.ts +1 -1
- package/dist/managed-pages/i18n.js +1 -0
- package/dist/managed-pages/screens/branding-screen.js +8 -1
- package/dist/page-render/branding.d.ts +1 -0
- package/dist/page-render/branding.js +1 -0
- package/dist/page-render/markdown.js +1 -1
- package/dist/personal-access-tokens/feature.js +1 -1
- package/dist/personal-access-tokens/handlers/create.write.d.ts +1 -1
- package/dist/personal-access-tokens/handlers/list.query.js +2 -1
- package/dist/personal-access-tokens/handlers/revoke.write.d.ts +1 -1
- package/dist/personal-access-tokens/revoke-for-user.js +2 -1
- package/dist/renderer-foundation/api.d.ts +13 -13
- package/dist/renderer-foundation/api.js +1 -1
- package/dist/renderer-foundation/constants.js +2 -4
- package/dist/renderer-foundation/feature.js +7 -7
- package/dist/renderer-foundation/index.d.ts +2 -1
- package/dist/renderer-foundation/index.js +1 -0
- package/dist/renderer-foundation/types.d.ts +94 -32
- package/dist/renderer-pdf/feature.js +7 -1
- package/dist/renderer-pdf/render-table-pdf.d.ts +27 -33
- package/dist/renderer-pdf/render-table-pdf.js +95 -34
- package/dist/secrets/feature.js +4 -3
- package/dist/secrets/handlers/delete.write.d.ts +1 -1
- package/dist/secrets/handlers/set.write.d.ts +1 -1
- package/dist/secrets/secrets-context.js +15 -3
- package/dist/sessions/db/queries/cleanup.js +2 -2
- package/dist/sessions/feature.js +1 -1
- package/dist/sessions/handlers/list.query.js +2 -1
- package/dist/sessions/handlers/revoke-all-for-user.write.d.ts +1 -1
- package/dist/sessions/handlers/revoke-all-others.write.d.ts +1 -1
- package/dist/sessions/handlers/revoke.write.d.ts +1 -1
- package/dist/shared/attachment-file-name.d.ts +3 -0
- package/dist/shared/attachment-file-name.js +35 -0
- package/dist/shared/chunked-entity-migration.d.ts +1 -0
- package/dist/shared/chunked-entity-migration.js +1 -1
- package/dist/shared/index.d.ts +3 -0
- package/dist/shared/index.js +3 -0
- package/dist/shared/is-tenant-db.js +1 -1
- package/dist/shared/mail-template-body.d.ts +7 -0
- package/dist/shared/mail-template-body.js +27 -0
- package/dist/shared/sharp-input-limits.d.ts +6 -0
- package/dist/shared/sharp-input-limits.js +22 -0
- package/dist/shared/signup-handover.js +2 -2
- package/dist/subscription-stripe/plugin-methods.js +18 -8
- package/dist/subscription-stripe/verify-webhook.d.ts +1 -1
- package/dist/tags/handlers/assign-tag.write.js +3 -1
- package/dist/tags/web/tag-chip.js +2 -0
- package/dist/template-resolver/api.d.ts +30 -2
- package/dist/template-resolver/api.js +42 -6
- package/dist/template-resolver/compile-document-body.d.ts +12 -0
- package/dist/template-resolver/compile-document-body.js +205 -0
- package/dist/template-resolver/constants.d.ts +13 -4
- package/dist/template-resolver/constants.js +32 -10
- package/dist/template-resolver/document-sanitizer.d.ts +32 -0
- package/dist/template-resolver/document-sanitizer.js +201 -0
- package/dist/template-resolver/document-schema.d.ts +21 -0
- package/dist/template-resolver/document-schema.js +316 -0
- package/dist/template-resolver/feature.d.ts +20 -0
- package/dist/template-resolver/feature.js +53 -6
- package/dist/template-resolver/handlers/bundle-import.d.ts +20 -0
- package/dist/template-resolver/handlers/bundle-import.js +147 -0
- package/dist/template-resolver/handlers/collection-set.write.d.ts +1 -1
- package/dist/template-resolver/handlers/collection-set.write.js +25 -2
- package/dist/template-resolver/handlers/copy-locale.write.d.ts +19 -0
- package/dist/template-resolver/handlers/copy-locale.write.js +134 -0
- package/dist/template-resolver/handlers/diff-to-system.query.d.ts +22 -0
- package/dist/template-resolver/handlers/diff-to-system.query.js +30 -0
- package/dist/template-resolver/handlers/discard-draft.write.d.ts +13 -0
- package/dist/template-resolver/handlers/discard-draft.write.js +37 -0
- package/dist/template-resolver/handlers/export-bundle.query.d.ts +35 -0
- package/dist/template-resolver/handlers/export-bundle.query.js +118 -0
- package/dist/template-resolver/handlers/find-by-id.query.d.ts +2 -0
- package/dist/template-resolver/handlers/find-by-id.query.js +9 -6
- package/dist/template-resolver/handlers/import-bundle-system.write.d.ts +39 -0
- package/dist/template-resolver/handlers/import-bundle-system.write.js +36 -0
- package/dist/template-resolver/handlers/import-bundle.write.d.ts +40 -0
- package/dist/template-resolver/handlers/import-bundle.write.js +19 -0
- package/dist/template-resolver/handlers/layout-source.query.d.ts +31 -0
- package/dist/template-resolver/handlers/layout-source.query.js +87 -0
- package/dist/template-resolver/handlers/list.query.d.ts +4 -1
- package/dist/template-resolver/handlers/list.query.js +9 -8
- package/dist/template-resolver/handlers/override-diff.d.ts +20 -0
- package/dist/template-resolver/handlers/override-diff.js +41 -0
- package/dist/template-resolver/handlers/overview.query.d.ts +65 -0
- package/dist/template-resolver/handlers/overview.query.js +205 -0
- package/dist/template-resolver/handlers/preview.query.d.ts +12 -0
- package/dist/template-resolver/handlers/preview.query.js +24 -0
- package/dist/template-resolver/handlers/reset-to-system.write.d.ts +8 -0
- package/dist/template-resolver/handlers/reset-to-system.write.js +50 -0
- package/dist/template-resolver/handlers/resource-link-pdf.write.d.ts +8 -0
- package/dist/template-resolver/handlers/resource-link-pdf.write.js +32 -0
- package/dist/template-resolver/handlers/resource-remove.write.d.ts +9 -0
- package/dist/template-resolver/handlers/resource-remove.write.js +44 -0
- package/dist/template-resolver/handlers/resource-shared.d.ts +9 -0
- package/dist/template-resolver/handlers/resource-shared.js +14 -0
- package/dist/template-resolver/handlers/resource-upload.write.d.ts +13 -0
- package/dist/template-resolver/handlers/resource-upload.write.js +98 -0
- package/dist/template-resolver/handlers/send-test.write.d.ts +13 -0
- package/dist/template-resolver/handlers/send-test.write.js +108 -0
- package/dist/template-resolver/handlers/set.write.d.ts +5 -2
- package/dist/template-resolver/handlers/set.write.js +25 -3
- package/dist/template-resolver/handlers/shared.d.ts +9 -5
- package/dist/template-resolver/handlers/shared.js +6 -2
- package/dist/template-resolver/handlers/template-gates.d.ts +36 -0
- package/dist/template-resolver/handlers/template-gates.js +142 -0
- package/dist/template-resolver/handlers/template-write.d.ts +45 -0
- package/dist/template-resolver/handlers/template-write.js +141 -0
- package/dist/template-resolver/handlers/tenant-overrides.query.d.ts +49 -0
- package/dist/template-resolver/handlers/tenant-overrides.query.js +112 -0
- package/dist/template-resolver/handlers/toggle-status.write.d.ts +27 -2
- package/dist/template-resolver/handlers/toggle-status.write.js +47 -15
- package/dist/template-resolver/handlers/upsert-system.write.d.ts +5 -8
- package/dist/template-resolver/handlers/upsert-system.write.js +14 -59
- package/dist/template-resolver/handlers/upsert-tenant.write.d.ts +5 -8
- package/dist/template-resolver/handlers/upsert-tenant.write.js +11 -62
- package/dist/template-resolver/handlers/usage.query.d.ts +17 -0
- package/dist/template-resolver/handlers/usage.query.js +24 -0
- package/dist/template-resolver/handlers/validate.query.d.ts +74 -0
- package/dist/template-resolver/handlers/validate.query.js +80 -0
- package/dist/template-resolver/index.d.ts +19 -1
- package/dist/template-resolver/index.js +17 -1
- package/dist/template-resolver/layout-appearance.d.ts +10 -0
- package/dist/template-resolver/layout-appearance.js +26 -0
- package/dist/template-resolver/layout-regions.d.ts +23 -0
- package/dist/template-resolver/layout-regions.js +125 -0
- package/dist/template-resolver/linked-resources.d.ts +17 -0
- package/dist/template-resolver/linked-resources.js +75 -0
- package/dist/template-resolver/pdf-constants.d.ts +7 -0
- package/dist/template-resolver/pdf-constants.js +8 -0
- package/dist/template-resolver/preview-display-html.d.ts +7 -0
- package/dist/template-resolver/preview-display-html.js +27 -0
- package/dist/template-resolver/print-document.d.ts +1 -0
- package/dist/template-resolver/print-document.js +55 -0
- package/dist/template-resolver/qualified-names.d.ts +34 -0
- package/dist/template-resolver/qualified-names.js +34 -0
- package/dist/template-resolver/record-mapping.d.ts +2 -0
- package/dist/template-resolver/record-mapping.js +21 -0
- package/dist/template-resolver/resource-image.d.ts +15 -0
- package/dist/template-resolver/resource-image.js +34 -0
- package/dist/template-resolver/seeding.d.ts +14 -1
- package/dist/template-resolver/seeding.js +125 -18
- package/dist/template-resolver/store-template-resource.d.ts +64 -0
- package/dist/template-resolver/store-template-resource.js +264 -0
- package/dist/template-resolver/table.d.ts +150 -8
- package/dist/template-resolver/table.js +20 -2
- package/dist/template-resolver/template-bundle.d.ts +36 -0
- package/dist/template-resolver/template-bundle.js +60 -0
- package/dist/template-resolver/template-diff.d.ts +7 -0
- package/dist/template-resolver/template-diff.js +68 -0
- package/dist/template-resolver/template-draft.d.ts +51 -0
- package/dist/template-resolver/template-draft.js +72 -0
- package/dist/template-resolver/template-meta.d.ts +85 -0
- package/dist/template-resolver/template-meta.js +145 -0
- package/dist/template-resolver/template-preview.d.ts +103 -0
- package/dist/template-resolver/template-preview.js +418 -0
- package/dist/template-resolver/template-resources.d.ts +19 -0
- package/dist/template-resolver/template-resources.js +73 -0
- package/dist/template-resolver/template-usage.d.ts +16 -0
- package/dist/template-resolver/template-usage.js +35 -0
- package/dist/template-resolver/template-validation.d.ts +22 -0
- package/dist/template-resolver/template-validation.js +173 -0
- package/dist/template-resolver/testing.js +5 -5
- package/dist/template-resolver/user-content-table.d.ts +14 -8
- package/dist/template-resolver/web/client-plugin.d.ts +1 -0
- package/dist/template-resolver/web/client-plugin.js +12 -7
- package/dist/template-resolver/web/document-editor-extensions.d.ts +18 -0
- package/dist/template-resolver/web/document-editor-extensions.js +145 -0
- package/dist/template-resolver/web/document-editor.d.ts +4 -0
- package/dist/template-resolver/web/document-editor.js +17 -0
- package/dist/template-resolver/web/document-tiptap-editor.d.ts +3 -0
- package/dist/template-resolver/web/document-tiptap-editor.js +492 -0
- package/dist/template-resolver/web/document-toolbar-blocks.d.ts +41 -0
- package/dist/template-resolver/web/document-toolbar-blocks.js +19 -0
- package/dist/template-resolver/web/editor-handle.d.ts +3 -0
- package/dist/template-resolver/web/editor-handle.js +24 -0
- package/dist/template-resolver/web/i18n.js +91 -0
- package/dist/template-resolver/web/index.d.ts +5 -0
- package/dist/template-resolver/web/index.js +5 -0
- package/dist/template-resolver/web/placeholder-line-editor-lazy.d.ts +4 -0
- package/dist/template-resolver/web/placeholder-line-editor-lazy.js +16 -0
- package/dist/template-resolver/web/placeholder-line-editor.d.ts +17 -0
- package/dist/template-resolver/web/placeholder-line-editor.js +94 -0
- package/dist/template-resolver/web/placeholder-text.d.ts +4 -0
- package/dist/template-resolver/web/placeholder-text.js +34 -0
- package/dist/template-resolver/web/use-stable-by-key.d.ts +1 -0
- package/dist/template-resolver/web/use-stable-by-key.js +13 -0
- package/dist/tenant/handlers/add-member.write.d.ts +1 -1
- package/dist/tenant/handlers/cancel-invitation.write.d.ts +1 -1
- package/dist/tenant/handlers/create.write.d.ts +1 -1
- package/dist/tenant/handlers/remove-member.write.d.ts +1 -1
- package/dist/tenant/handlers/team-list.query.js +3 -2
- package/dist/tenant/handlers/toggle-enabled.write.d.ts +2 -2
- package/dist/tenant/handlers/update-member-roles.write.d.ts +1 -1
- package/dist/tenant/handlers/update.write.d.ts +1 -1
- package/dist/tenant/seeding.js +31 -6
- package/dist/tenant-handover/handlers/claim.write.d.ts +1 -1
- package/dist/tenant-lifecycle/handlers/cancel-destruction.write.d.ts +2 -2
- package/dist/tenant-lifecycle/handlers/cancel-destruction.write.js +2 -1
- package/dist/tenant-lifecycle/handlers/request-destruction.write.d.ts +1 -1
- package/dist/tier-engine/feature.js +9 -3
- package/dist/tier-engine/handlers/set-tenant-tier.write.d.ts +1 -1
- package/dist/user/db/queries/stream-tenant-backfill.js +4 -4
- package/dist/user/handlers/create.write.d.ts +1 -1
- package/dist/user/handlers/detail.query.js +2 -1
- package/dist/user/handlers/update.write.d.ts +1 -1
- package/dist/user/resolve-display-names.js +5 -9
- package/dist/user/seeding.js +20 -1
- package/dist/user-data-rights/db/queries/forget-cleanup.d.ts +2 -2
- package/dist/user-data-rights/email-templates.d.ts +1 -29
- package/dist/user-data-rights/email-templates.js +5 -106
- package/dist/user-data-rights/feature.js +53 -35
- package/dist/user-data-rights/handlers/cancel-deletion.write.d.ts +2 -2
- package/dist/user-data-rights/handlers/cancel-deletion.write.js +2 -1
- package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.d.ts +1 -1
- package/dist/user-data-rights/handlers/lift-restriction.write.d.ts +1 -1
- package/dist/user-data-rights/handlers/request-deletion-by-email.write.d.ts +1 -1
- package/dist/user-data-rights/handlers/request-deletion.write.d.ts +1 -1
- package/dist/user-data-rights/handlers/request-deletion.write.js +5 -7
- package/dist/user-data-rights/handlers/request-export.write.d.ts +1 -1
- package/dist/user-data-rights/handlers/restrict-account.write.d.ts +1 -1
- package/dist/user-data-rights/handlers/run-forget-cleanup.write.d.ts +1 -1
- package/dist/user-data-rights/lib/default-mailers.d.ts +15 -7
- package/dist/user-data-rights/lib/default-mailers.js +100 -48
- package/dist/user-data-rights/lib/update-user-lifecycle.js +1 -1
- package/dist/user-data-rights/mail-notifications.d.ts +13 -0
- package/dist/user-data-rights/mail-notifications.js +118 -0
- package/dist/user-data-rights/web/privacy-center-screen.js +2 -1
- package/dist/user-profile/handlers/change-email.write.d.ts +1 -1
- package/dist/user-profile/web/profile-screen.js +2 -1
- package/dist/waitlist/feature.js +10 -0
- package/dist/waitlist/handlers/invite.write.d.ts +1 -1
- package/dist/waitlist/handlers/reject.write.d.ts +1 -1
- package/dist/waitlist/handlers/submit.write.d.ts +1 -1
- package/dist/waitlist/handlers/submit.write.js +3 -4
- package/dist/waitlist/mail.d.ts +19 -6
- package/dist/waitlist/mail.js +50 -14
- package/dist/waitlist/options.js +1 -1
- package/dist/workflow-runner/event-trigger.js +2 -2
- package/dist/workflow-runner/handlers/resume-run.write.js +7 -2
- package/package.json +37 -17
- package/src/admin-shell/changes.json +6 -0
- package/src/audit/changes.json +6 -0
- package/src/auth-email-password/changes.json +51 -0
- package/src/billing-foundation/changes.json +43 -0
- package/src/cap-counter/changes.json +6 -0
- package/src/channel-email/changes.json +19 -0
- package/src/config/changes.json +6 -0
- package/src/crypto-shredding/changes.json +6 -0
- package/src/custom-fields/changes.json +6 -0
- package/src/data-retention/changes.json +6 -0
- package/src/delivery/changes.json +66 -0
- package/src/file-foundation/changes.json +6 -0
- package/src/files-tenant-data/changes.json +6 -0
- package/src/inbound-mail-foundation/changes.json +6 -0
- package/src/jobs/changes.json +19 -0
- package/src/ledger/changes.json +7 -0
- package/src/managed-pages/changes.json +6 -0
- package/src/renderer-foundation/changes.json +39 -0
- package/src/renderer-pdf/changes.json +12 -0
- package/src/secrets/changes.json +6 -0
- package/src/shared/changes.json +6 -0
- package/src/subscription-stripe/changes.json +6 -0
- package/src/template-resolver/changes.json +186 -0
- package/src/tier-engine/changes.json +6 -0
- package/src/user/changes.json +6 -0
- package/src/user-data-rights/changes.json +13 -0
- package/src/user-profile/changes.json +1 -1
- package/src/waitlist/changes.json +7 -0
- package/src/workflow-runner/changes.json +6 -0
- package/dist/renderer-simple/feature.d.ts +0 -10
- package/dist/renderer-simple/feature.js +0 -42
- package/dist/renderer-simple/index.d.ts +0 -3
- package/dist/renderer-simple/index.js +0 -2
- package/dist/renderer-simple/mail-blocks.d.ts +0 -21
- package/dist/renderer-simple/mail-blocks.js +0 -107
- package/dist/renderer-simple/resolve-variables.d.ts +0 -7
- package/dist/renderer-simple/resolve-variables.js +0 -47
- package/dist/renderer-simple/simple-renderer.d.ts +0 -24
- package/dist/renderer-simple/simple-renderer.js +0 -200
- package/src/renderer-simple/changes.json +0 -27
|
@@ -18,13 +18,33 @@ export declare function createTemplateResolverFeature(opts?: TemplateResolverOpt
|
|
|
18
18
|
upsertTenant: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
19
19
|
publish: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
20
20
|
archive: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
21
|
+
publishSystem: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
22
|
+
archiveSystem: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
23
|
+
discardDraft: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
24
|
+
discardDraftSystem: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
25
|
+
resetToSystem: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
21
26
|
set: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
27
|
+
importBundle: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
28
|
+
importBundleSystem: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
29
|
+
copyLocale: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
30
|
+
resourceUpload: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
31
|
+
resourceRemove: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
32
|
+
resourceLinkPdf: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
33
|
+
sendTest: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
22
34
|
};
|
|
23
35
|
queries: {
|
|
24
36
|
findById: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
25
37
|
list: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
26
38
|
bySlug: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
27
39
|
byTenant: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
40
|
+
usage: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
41
|
+
overview: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
42
|
+
layoutSource: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
43
|
+
tenantOverrides: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
44
|
+
diffToSystem: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
45
|
+
validate: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
46
|
+
preview: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
47
|
+
exportBundle: import("@cosmicdrift/kumiko-types/handlers").HandlerRef;
|
|
28
48
|
};
|
|
29
49
|
treeHandle: import("@cosmicdrift/kumiko-types/tree-node").TreeActionsHandle<"template-resolver", {
|
|
30
50
|
readonly edit: {
|
|
@@ -1,15 +1,32 @@
|
|
|
1
|
-
import { defineFeature, } from "@cosmicdrift/kumiko-framework/engine";
|
|
1
|
+
import { createSystemConfig, defineFeature, } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
2
|
import { bySlugQuery } from "./handlers/by-slug.query.js";
|
|
3
3
|
import { byTenantQuery } from "./handlers/by-tenant.query.js";
|
|
4
4
|
import { makeCollectionItemQuery } from "./handlers/collection-item.query.js";
|
|
5
5
|
import { makeCollectionListQuery } from "./handlers/collection-list.query.js";
|
|
6
6
|
import { makeCollectionSetWrite } from "./handlers/collection-set.write.js";
|
|
7
|
+
import { copyLocaleWrite } from "./handlers/copy-locale.write.js";
|
|
8
|
+
import { diffToSystemQuery } from "./handlers/diff-to-system.query.js";
|
|
9
|
+
import { discardDraftSystemWrite, discardDraftWrite } from "./handlers/discard-draft.write.js";
|
|
10
|
+
import { exportBundleQuery } from "./handlers/export-bundle.query.js";
|
|
7
11
|
import { findByIdQuery } from "./handlers/find-by-id.query.js";
|
|
12
|
+
import { importBundleWrite } from "./handlers/import-bundle.write.js";
|
|
13
|
+
import { importBundleSystemWrite } from "./handlers/import-bundle-system.write.js";
|
|
14
|
+
import { layoutSourceQuery } from "./handlers/layout-source.query.js";
|
|
8
15
|
import { listQuery } from "./handlers/list.query.js";
|
|
16
|
+
import { overviewQuery } from "./handlers/overview.query.js";
|
|
17
|
+
import { previewQuery } from "./handlers/preview.query.js";
|
|
18
|
+
import { resetToSystemWrite } from "./handlers/reset-to-system.write.js";
|
|
19
|
+
import { resourceLinkPdfWrite } from "./handlers/resource-link-pdf.write.js";
|
|
20
|
+
import { resourceRemoveWrite } from "./handlers/resource-remove.write.js";
|
|
21
|
+
import { resourceUploadWrite } from "./handlers/resource-upload.write.js";
|
|
22
|
+
import { sendTestWrite } from "./handlers/send-test.write.js";
|
|
9
23
|
import { setWrite } from "./handlers/set.write.js";
|
|
10
|
-
import {
|
|
24
|
+
import { tenantOverridesQuery } from "./handlers/tenant-overrides.query.js";
|
|
25
|
+
import { archiveSystemWrite, archiveWrite, publishSystemWrite, publishWrite, } from "./handlers/toggle-status.write.js";
|
|
11
26
|
import { upsertSystemWrite } from "./handlers/upsert-system.write.js";
|
|
12
27
|
import { upsertTenantWrite } from "./handlers/upsert-tenant.write.js";
|
|
28
|
+
import { usageQuery } from "./handlers/usage.query.js";
|
|
29
|
+
import { validateQuery } from "./handlers/validate.query.js";
|
|
13
30
|
import { templateResourceEntity } from "./table.js";
|
|
14
31
|
import { userContentEntryEntity } from "./user-content-table.js";
|
|
15
32
|
export function createTemplateResolverFeature(opts = {}) {
|
|
@@ -17,11 +34,14 @@ export function createTemplateResolverFeature(opts = {}) {
|
|
|
17
34
|
const hasUserOwned = collections.some((c) => c.ownership === "user");
|
|
18
35
|
return defineFeature("template-resolver", (r) => {
|
|
19
36
|
r.describe([
|
|
20
|
-
"Every piece of editable text lives here, in one entity: mail bodies, notification texts, PDF document templates, AI prompts and plain text blocks. What a record is used for is the `kind` (`notification`, `mail-
|
|
21
|
-
"Reading is one call — `ctx.templateResolver.resolveTemplate({ tenantId, slug, kind, locale })`. It walks four levels: tenant+locale, system+locale, tenant+fallback-locale, system+fallback-locale. A tenant overrides a system default by simply having its own record; no application code changes. Writing programmatically goes through the `upsertSystem`, `upsertTenant`, `publish` and `archive` write handlers.",
|
|
37
|
+
"Every piece of editable text lives here, in one entity: mail bodies, notification texts, PDF document templates, AI prompts and plain text blocks. What a record is used for is the `kind` (`notification`, `mail`, `mail-layout`, `document-pdf`, `pdf-layout`, `ai-prompt`, `text-block`, `snippet`, `image-snapshot`).",
|
|
38
|
+
"Reading is one call — `ctx.templateResolver.resolveTemplate({ tenantId, slug, kind, locale })`. It walks four levels: tenant+locale, system+locale, tenant+fallback-locale, system+fallback-locale. A tenant overrides a system default by simply having its own record; no application code changes. Writing programmatically goes through the `upsertSystem`, `upsertTenant`, `publish` and `archive` write handlers; a SystemAdmin retires or restores a system default with `publishSystem` and `archiveSystem`, and a tenant drops its override with `resetToSystem`. Saving a draft over an active template keeps the active version served and stores the edit beside it (column `draft`); `publish` makes it the served version, `discardDraft` / `discardDraftSystem` throws it away.",
|
|
22
39
|
"Text an editor should be able to change belongs in a collection, declared at mount: `createTemplateResolverFeature({ collections: [{ id, kind, access: { roles }, nav }] })`. It appears in the navigation, and `access` is part of the mount because a bundled feature cannot know the host's roles. Each collection gets its own `<id>-list` / `<id>-item` / `<id>-set` handlers, so the dispatcher enforces the separation.",
|
|
23
40
|
"How a collection is edited follows from `contentFormat`: `plain` gives a text area, `rich` a small WYSIWYG (bold, italic, headings, lists, links), `markdown` a text area that stores markdown text (same insertable chips as `plain`). All three offer the collection's `variableSchema` as insertable chips and a preview rendered with sample data — an editor sees what `{{firstName}}` becomes without sending a mail. An app can register its own editor for a format; the last `clientFeature` that registers a format wins (a conflict logs a warning).",
|
|
24
41
|
'A collection is tenant-wide by default. With `ownership: "user"` every user keeps their own entries — mail signatures being the obvious case. Those rows live in the separate `user-content-entry` entity and count as user data, so mounting one also requires the `template-resolver-user-data` feature and a migration on the app side.',
|
|
42
|
+
"`validate` dry-runs the write pipeline for a draft (sanitizer, layout rules, placeholders) and reports what the template uses and misses. `export-bundle` / `import-bundle` (and `import-bundle-system`) move one template with all locales and resource files between tenants or environments; `copy-locale` starts a translation from an existing locale. Layouts are structured: a mail or PDF layout is `data-header` / `data-content` / `data-signature` / `data-footer` regions, and mjml layout source is system-only.",
|
|
43
|
+
"`preview` renders a draft (or the stored template) with sample values taken from the `example` of each declared variable, through the same gates and the same mail renderer as a real send, and returns subject, html, `displayHtml` (the html with cid images as data URIs for an editor), text, attachments (inline images and files) and `checks` (images resolved, plain text present, size under 10 MiB, required placeholders used); nothing is saved or sent. `send-test` mails that rendering to the calling user's own address only, subject prefixed with `[TEST]`, at most 10 per user and hour; it needs `delivery`, `channel-email` and `renderer-mail-html` to be mounted.",
|
|
44
|
+
'Images used by a template (`<img data-resource="logo">`) are uploaded with `resourceUpload`, which re-encodes them, stores a file and links it under the key; `resourceRemove` unlinks it. `linkedResources` is written only through these two handlers. With `purpose: "attachment"` and a `fileName`, `resourceUpload` stores a PDF, PNG or JPEG as a file attachment of a mail template (original bytes, at most 10) that the mail renderer attaches after the inline images. `resourceLinkPdf` instead links a `document-pdf` template under a key: every mail sent from the template then carries that PDF, rendered at send time with the mail\'s own variables and locale, under a file name pattern such as `invoice-{{number}}.pdf`; files and linked PDFs share the limit of 10.',
|
|
25
45
|
"Replaces the former `text-content` feature; its blocks now live here as kind `text-block`.",
|
|
26
46
|
].join("\n\n"));
|
|
27
47
|
r.uiHints({
|
|
@@ -29,6 +49,11 @@ export function createTemplateResolverFeature(opts = {}) {
|
|
|
29
49
|
category: "notifications",
|
|
30
50
|
recommended: false,
|
|
31
51
|
});
|
|
52
|
+
r.config({
|
|
53
|
+
keys: {
|
|
54
|
+
resourceMaxBytes: createSystemConfig("number", { default: 2_097_152, bounds: { min: 1 } }),
|
|
55
|
+
},
|
|
56
|
+
});
|
|
32
57
|
r.entity("template-resource", templateResourceEntity);
|
|
33
58
|
// Only when the app actually mounts a user-owned collection: the entity's
|
|
34
59
|
// `content` is `userOwned`, which makes it subject data — the boot guard
|
|
@@ -41,13 +66,33 @@ export function createTemplateResolverFeature(opts = {}) {
|
|
|
41
66
|
upsertTenant: r.writeHandler(upsertTenantWrite),
|
|
42
67
|
publish: r.writeHandler(publishWrite),
|
|
43
68
|
archive: r.writeHandler(archiveWrite),
|
|
69
|
+
publishSystem: r.writeHandler(publishSystemWrite),
|
|
70
|
+
archiveSystem: r.writeHandler(archiveSystemWrite),
|
|
71
|
+
discardDraft: r.writeHandler(discardDraftWrite),
|
|
72
|
+
discardDraftSystem: r.writeHandler(discardDraftSystemWrite),
|
|
73
|
+
resetToSystem: r.writeHandler(resetToSystemWrite),
|
|
44
74
|
set: r.writeHandler(setWrite),
|
|
75
|
+
importBundle: r.writeHandler(importBundleWrite),
|
|
76
|
+
importBundleSystem: r.writeHandler(importBundleSystemWrite),
|
|
77
|
+
copyLocale: r.writeHandler(copyLocaleWrite),
|
|
78
|
+
resourceUpload: r.writeHandler(resourceUploadWrite),
|
|
79
|
+
resourceRemove: r.writeHandler(resourceRemoveWrite),
|
|
80
|
+
resourceLinkPdf: r.writeHandler(resourceLinkPdfWrite),
|
|
81
|
+
sendTest: r.writeHandler(sendTestWrite),
|
|
45
82
|
};
|
|
46
83
|
const queries = {
|
|
47
84
|
findById: r.queryHandler(findByIdQuery),
|
|
48
85
|
list: r.queryHandler(listQuery),
|
|
49
86
|
bySlug: r.queryHandler(bySlugQuery),
|
|
50
87
|
byTenant: r.queryHandler(byTenantQuery),
|
|
88
|
+
usage: r.queryHandler(usageQuery),
|
|
89
|
+
overview: r.queryHandler(overviewQuery),
|
|
90
|
+
layoutSource: r.queryHandler(layoutSourceQuery),
|
|
91
|
+
tenantOverrides: r.queryHandler(tenantOverridesQuery),
|
|
92
|
+
diffToSystem: r.queryHandler(diffToSystemQuery),
|
|
93
|
+
validate: r.queryHandler(validateQuery),
|
|
94
|
+
preview: r.queryHandler(previewQuery),
|
|
95
|
+
exportBundle: r.queryHandler(exportBundleQuery),
|
|
51
96
|
};
|
|
52
97
|
for (const collection of collections) {
|
|
53
98
|
r.contentCollection(collection);
|
|
@@ -58,10 +103,12 @@ export function createTemplateResolverFeature(opts = {}) {
|
|
|
58
103
|
// Visual-tree actions for the text-block content tree. The handle is
|
|
59
104
|
// propagated through the setup export so other features can build
|
|
60
105
|
// compile-time-typed cross-feature edit targets.
|
|
106
|
+
// r.treeActions keeps literal types (const generic); the args only declare string-typed slots.
|
|
107
|
+
const emptyString = "";
|
|
61
108
|
const treeHandle = r.treeActions({
|
|
62
|
-
edit: { args: { slug:
|
|
109
|
+
edit: { args: { slug: emptyString, locale: emptyString } },
|
|
63
110
|
list: {},
|
|
64
|
-
create: { args: { folder:
|
|
111
|
+
create: { args: { folder: emptyString } },
|
|
65
112
|
});
|
|
66
113
|
return { handlers, queries, treeHandle };
|
|
67
114
|
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { HandlerContext, SessionUser, TenantId, WriteResult } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
+
import { type FieldIssue } from "@cosmicdrift/kumiko-framework/errors";
|
|
3
|
+
import type { TemplateWriteScope } from "../layout-regions.js";
|
|
4
|
+
import type { TemplateBundle } from "../template-bundle.js";
|
|
5
|
+
export declare function targetExistsIssue(locale: string): FieldIssue;
|
|
6
|
+
type BundleImport = {
|
|
7
|
+
readonly ctx: HandlerContext;
|
|
8
|
+
readonly user: SessionUser;
|
|
9
|
+
readonly tenantId: TenantId;
|
|
10
|
+
readonly scope: TemplateWriteScope;
|
|
11
|
+
readonly bundle: TemplateBundle;
|
|
12
|
+
readonly overwrite: boolean;
|
|
13
|
+
};
|
|
14
|
+
type BundleImportStatus = "draft" | "active";
|
|
15
|
+
export declare function importTemplateBundle(args: BundleImport & {
|
|
16
|
+
readonly status: BundleImportStatus;
|
|
17
|
+
}): Promise<WriteResult<{
|
|
18
|
+
ids: Record<string, string>;
|
|
19
|
+
}>>;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
|
+
import { ValidationError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
|
|
3
|
+
import { requireForTenant } from "../../shared/index.js";
|
|
4
|
+
import { attachmentLimitFailure, attachmentNeedsMailTemplate, readTemplateResourceMaxBytes, storeBundleAttachment, storeTemplateResource, } from "../store-template-resource.js";
|
|
5
|
+
import { templateResourcesTable } from "../table.js";
|
|
6
|
+
import { attachTemplateResources } from "../template-resources.js";
|
|
7
|
+
import { resolveTemplateVariables } from "../template-validation.js";
|
|
8
|
+
import { MAX_FILE_ATTACHMENTS_PER_TEMPLATE } from "./resource-shared.js";
|
|
9
|
+
import { evaluateTemplateWrite } from "./template-gates.js";
|
|
10
|
+
import { refuseTenantScopeUnderSystemTenant, writeTemplateRow, } from "./template-write.js";
|
|
11
|
+
export function targetExistsIssue(locale) {
|
|
12
|
+
return {
|
|
13
|
+
path: "locale",
|
|
14
|
+
code: "target_exists",
|
|
15
|
+
i18nKey: "templateResolver.errors.template.targetExists",
|
|
16
|
+
params: { detail: locale },
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
async function collectBundleIssues(args, status) {
|
|
20
|
+
const { ctx, tenantId, scope, bundle, overwrite } = args;
|
|
21
|
+
const { db } = requireForTenant(ctx, tenantId);
|
|
22
|
+
const variables = resolveTemplateVariables(ctx.registry, bundle.slug, bundle.variableSchema ?? {});
|
|
23
|
+
const issues = [];
|
|
24
|
+
for (const [locale, entry] of Object.entries(bundle.locales)) {
|
|
25
|
+
const evaluated = evaluateTemplateWrite({
|
|
26
|
+
kind: bundle.kind,
|
|
27
|
+
scope,
|
|
28
|
+
contentFormat: bundle.contentFormat,
|
|
29
|
+
content: entry.body,
|
|
30
|
+
rawMeta: entry.meta,
|
|
31
|
+
variables,
|
|
32
|
+
});
|
|
33
|
+
const found = evaluated.ok
|
|
34
|
+
? status === "active"
|
|
35
|
+
? evaluated.publishIssues
|
|
36
|
+
: []
|
|
37
|
+
: evaluated.issues;
|
|
38
|
+
issues.push(...found.map((issue) => ({ ...issue, path: `locales.${locale}.${issue.path}` })));
|
|
39
|
+
if (!overwrite) {
|
|
40
|
+
const existing = await fetchOne(db, templateResourcesTable, {
|
|
41
|
+
tenantId,
|
|
42
|
+
slug: bundle.slug,
|
|
43
|
+
kind: bundle.kind,
|
|
44
|
+
locale,
|
|
45
|
+
});
|
|
46
|
+
if (existing)
|
|
47
|
+
issues.push(targetExistsIssue(locale));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return issues;
|
|
51
|
+
}
|
|
52
|
+
async function storeBundleResources(args) {
|
|
53
|
+
const linked = {};
|
|
54
|
+
const pdfLinks = Object.entries(args.bundle.pdfAttachments);
|
|
55
|
+
const attachmentCount = Object.values(args.bundle.resources).filter((resource) => resource.purpose === "attachment")
|
|
56
|
+
.length + pdfLinks.length;
|
|
57
|
+
if (attachmentCount > 0 && args.bundle.kind !== "mail")
|
|
58
|
+
return attachmentNeedsMailTemplate();
|
|
59
|
+
if (attachmentCount > MAX_FILE_ATTACHMENTS_PER_TEMPLATE)
|
|
60
|
+
return attachmentLimitFailure();
|
|
61
|
+
// The document template is not looked up: a bundle may carry it later than the mail.
|
|
62
|
+
for (const [key, link] of pdfLinks)
|
|
63
|
+
linked[key] = { kind: "rendered-pdf", ...link };
|
|
64
|
+
const maxBytes = await readTemplateResourceMaxBytes(args.ctx.config, args.ctx.registry);
|
|
65
|
+
// A bundle is untrusted input like an upload: the same re-encoding decides the stored
|
|
66
|
+
// content type, so a declared image/png can't smuggle SVG or HTML into a mail or PDF.
|
|
67
|
+
for (const [key, resource] of Object.entries(args.bundle.resources)) {
|
|
68
|
+
const bytes = Uint8Array.from(Buffer.from(resource.base64, "base64"));
|
|
69
|
+
if (resource.purpose === "attachment") {
|
|
70
|
+
const attachment = await storeBundleAttachment({
|
|
71
|
+
ctx: args.ctx,
|
|
72
|
+
user: args.user,
|
|
73
|
+
tenantId: args.tenantId,
|
|
74
|
+
bytes,
|
|
75
|
+
maxBytes,
|
|
76
|
+
key,
|
|
77
|
+
fileName: resource.fileName,
|
|
78
|
+
});
|
|
79
|
+
if (!attachment.isSuccess)
|
|
80
|
+
return attachment;
|
|
81
|
+
linked[key] = attachment.data;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const stored = await storeTemplateResource({
|
|
85
|
+
ctx: args.ctx,
|
|
86
|
+
user: args.user,
|
|
87
|
+
tenantId: args.tenantId,
|
|
88
|
+
bytes,
|
|
89
|
+
maxBytes,
|
|
90
|
+
key,
|
|
91
|
+
});
|
|
92
|
+
if (!stored.isSuccess)
|
|
93
|
+
return stored;
|
|
94
|
+
linked[key] = stored.data.fileRefId;
|
|
95
|
+
}
|
|
96
|
+
return { isSuccess: true, data: linked };
|
|
97
|
+
}
|
|
98
|
+
// Validates every locale first, stores the resource files, then writes one row
|
|
99
|
+
// per locale, so a bad locale never leaves files or half a bundle behind. An image
|
|
100
|
+
// that fails re-encoding stops the import before any row is written; files stored
|
|
101
|
+
// for the resources before it stay as unlinked FileRefs, like a replaced upload.
|
|
102
|
+
export async function importTemplateBundle(args) {
|
|
103
|
+
const refused = refuseTenantScopeUnderSystemTenant(args.scope, args.tenantId);
|
|
104
|
+
if (refused !== null)
|
|
105
|
+
return refused;
|
|
106
|
+
const issues = await collectBundleIssues(args, args.status);
|
|
107
|
+
if (issues.length > 0)
|
|
108
|
+
return writeFailure(new ValidationError({ fields: [...issues] }));
|
|
109
|
+
const linked = await storeBundleResources(args);
|
|
110
|
+
if (!linked.isSuccess)
|
|
111
|
+
return linked;
|
|
112
|
+
const variableSchema = args.bundle.variableSchema ?? {};
|
|
113
|
+
const variables = resolveTemplateVariables(args.ctx.registry, args.bundle.slug, variableSchema);
|
|
114
|
+
const ids = {};
|
|
115
|
+
for (const [locale, entry] of Object.entries(args.bundle.locales)) {
|
|
116
|
+
const payload = {
|
|
117
|
+
slug: args.bundle.slug,
|
|
118
|
+
kind: args.bundle.kind,
|
|
119
|
+
locale,
|
|
120
|
+
content: entry.body,
|
|
121
|
+
contentFormat: args.bundle.contentFormat,
|
|
122
|
+
variableSchema,
|
|
123
|
+
meta: entry.meta,
|
|
124
|
+
};
|
|
125
|
+
const written = await writeTemplateRow({
|
|
126
|
+
ctx: args.ctx,
|
|
127
|
+
user: args.user,
|
|
128
|
+
tenantId: args.tenantId,
|
|
129
|
+
scope: args.scope,
|
|
130
|
+
status: args.status,
|
|
131
|
+
variables,
|
|
132
|
+
payload,
|
|
133
|
+
});
|
|
134
|
+
if (!written.isSuccess)
|
|
135
|
+
return written;
|
|
136
|
+
const attached = await attachTemplateResources(args.ctx, {
|
|
137
|
+
user: args.user,
|
|
138
|
+
tenantId: args.tenantId,
|
|
139
|
+
templateId: written.data.id,
|
|
140
|
+
resources: linked.data,
|
|
141
|
+
});
|
|
142
|
+
if (!attached.isSuccess)
|
|
143
|
+
return attached;
|
|
144
|
+
ids[locale] = written.data.id;
|
|
145
|
+
}
|
|
146
|
+
return { isSuccess: true, data: { ids } };
|
|
147
|
+
}
|
|
@@ -17,4 +17,4 @@ export declare function makeCollectionSetWrite(collection: ContentCollectionDefi
|
|
|
17
17
|
slug: string;
|
|
18
18
|
locale: string;
|
|
19
19
|
isNew: boolean;
|
|
20
|
-
}, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
|
|
20
|
+
}, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined>;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
2
|
import { defineWriteHandler, } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
+
import { ValidationError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
3
4
|
import * as z from "zod";
|
|
4
5
|
import { requireForTenant } from "../../shared/index.js";
|
|
6
|
+
import { COLLECTION_REFUSED_KINDS } from "../constants.js";
|
|
7
|
+
import { documentViolationsToFieldIssues, sanitizeTemplateBody } from "../document-sanitizer.js";
|
|
5
8
|
import { collectionStore, DEFAULT_COLLECTION_ACCESS, } from "./collection-shared.js";
|
|
6
9
|
import { contentFormatSchema, folderSchema, localeSchema, slugSchema } from "./shared.js";
|
|
7
10
|
// Upsert inside one collection. Mirrors set.write for text-blocks, but the
|
|
@@ -30,6 +33,18 @@ export function makeCollectionSetWrite(collection) {
|
|
|
30
33
|
? `Creates or overwrites the caller's own "${collection.id}" entry at a slug and locale, live on save with no draft stage; it always writes the acting user's entry, never another user's.`
|
|
31
34
|
: `Creates or overwrites the tenant-wide "${collection.id}" entry at a slug and locale, live on save with no draft stage; the change is visible to everyone who may reach this shared collection.`,
|
|
32
35
|
handler: async (event, ctx) => {
|
|
36
|
+
if (COLLECTION_REFUSED_KINDS.includes(collection.kind)) {
|
|
37
|
+
return writeFailure(new ValidationError({
|
|
38
|
+
fields: [
|
|
39
|
+
{
|
|
40
|
+
path: "kind",
|
|
41
|
+
code: "kind_not_allowed",
|
|
42
|
+
i18nKey: "templateResolver.errors.collection.kindNotAllowed",
|
|
43
|
+
params: { detail: collection.kind },
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
33
48
|
const override = event.payload.tenantIdOverride;
|
|
34
49
|
// @cast-boundary engine-payload — override is a zod-validated string, the
|
|
35
50
|
// user's own tenantId is already TenantId-branded.
|
|
@@ -39,6 +54,14 @@ export function makeCollectionSetWrite(collection) {
|
|
|
39
54
|
// writing into another tenant still writes their own entry, never
|
|
40
55
|
// someone else's signature.
|
|
41
56
|
const owner = store.scopeOf(event.user);
|
|
57
|
+
const body = sanitizeTemplateBody({
|
|
58
|
+
kind: collection.kind,
|
|
59
|
+
contentFormat: event.payload.contentFormat,
|
|
60
|
+
content: event.payload.content,
|
|
61
|
+
});
|
|
62
|
+
if (!body.ok) {
|
|
63
|
+
return writeFailure(new ValidationError({ fields: documentViolationsToFieldIssues(body.violations) }));
|
|
64
|
+
}
|
|
42
65
|
const existing = await fetchOne(db, store.table, {
|
|
43
66
|
tenantId,
|
|
44
67
|
slug: event.payload.slug,
|
|
@@ -55,7 +78,7 @@ export function makeCollectionSetWrite(collection) {
|
|
|
55
78
|
// the template upserts put on the row.
|
|
56
79
|
changes: {
|
|
57
80
|
title: event.payload.title,
|
|
58
|
-
content:
|
|
81
|
+
content: body.content,
|
|
59
82
|
contentFormat: event.payload.contentFormat,
|
|
60
83
|
folder: event.payload.folder ?? null,
|
|
61
84
|
},
|
|
@@ -73,7 +96,7 @@ export function makeCollectionSetWrite(collection) {
|
|
|
73
96
|
kind: collection.kind,
|
|
74
97
|
locale: event.payload.locale,
|
|
75
98
|
title: event.payload.title,
|
|
76
|
-
content:
|
|
99
|
+
content: body.content,
|
|
77
100
|
contentFormat: event.payload.contentFormat,
|
|
78
101
|
folder: event.payload.folder ?? null,
|
|
79
102
|
...store.createDefaults(tenantId),
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
export declare const copyLocaleWrite: import("@cosmicdrift/kumiko-types/define-handler").WriteHandlerDefinition<"copy-locale", z.ZodObject<{
|
|
3
|
+
slug: z.ZodString;
|
|
4
|
+
kind: z.ZodEnum<{
|
|
5
|
+
"ai-prompt": "ai-prompt";
|
|
6
|
+
"document-pdf": "document-pdf";
|
|
7
|
+
"image-snapshot": "image-snapshot";
|
|
8
|
+
mail: "mail";
|
|
9
|
+
"mail-layout": "mail-layout";
|
|
10
|
+
"pdf-layout": "pdf-layout";
|
|
11
|
+
}>;
|
|
12
|
+
fromLocale: z.ZodString;
|
|
13
|
+
toLocale: z.ZodString;
|
|
14
|
+
overwrite: z.ZodDefault<z.ZodBoolean>;
|
|
15
|
+
scope: z.ZodDefault<z.ZodEnum<{
|
|
16
|
+
system: "system";
|
|
17
|
+
tenant: "tenant";
|
|
18
|
+
}>>;
|
|
19
|
+
}, z.core.$strip>, import("./template-write.js").WrittenTemplateRow, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined>;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
|
+
import { defineWriteHandler, SYSTEM_TENANT_ID, } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
+
import { AccessDeniedError, NotFoundError, ValidationError, writeFailure, } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
|
+
import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
|
|
5
|
+
import * as z from "zod";
|
|
6
|
+
import { requireForTenant } from "../../shared/index.js";
|
|
7
|
+
import { CONTENT_FORMATS } from "../constants.js";
|
|
8
|
+
import { parseLinkedResourceEntries } from "../linked-resources.js";
|
|
9
|
+
import { TemplateResolverErrors } from "../qualified-names.js";
|
|
10
|
+
import { templateResourcesTable } from "../table.js";
|
|
11
|
+
import { toWorkingRow } from "../template-draft.js";
|
|
12
|
+
import { attachTemplateResources, duplicateLinkedResourceFiles } from "../template-resources.js";
|
|
13
|
+
import { resolveTemplateVariables } from "../template-validation.js";
|
|
14
|
+
import { targetExistsIssue } from "./bundle-import.js";
|
|
15
|
+
import { kindSchema, localeSchema, templateSlugSchema } from "./shared.js";
|
|
16
|
+
import { parseStoredJson, storedRecord } from "./template-gates.js";
|
|
17
|
+
import { refuseTenantScopeUnderSystemTenant, writeTemplateRow } from "./template-write.js";
|
|
18
|
+
function readDbFor(ctx, scope) {
|
|
19
|
+
return scope === "system" ? requireForTenant(ctx, SYSTEM_TENANT_ID).db : ctx.db;
|
|
20
|
+
}
|
|
21
|
+
// A tenant copy may start from the system default; a system copy only from system rows.
|
|
22
|
+
async function findCopySource(ctx, where) {
|
|
23
|
+
const { scope, tenantId, slug, kind, locale } = where;
|
|
24
|
+
const readDb = readDbFor(ctx, scope);
|
|
25
|
+
const own = await fetchOne(readDb, templateResourcesTable, {
|
|
26
|
+
tenantId,
|
|
27
|
+
slug,
|
|
28
|
+
kind,
|
|
29
|
+
locale,
|
|
30
|
+
});
|
|
31
|
+
// An archived tenant row is not an active source: the system default applies instead.
|
|
32
|
+
if (scope === "system" || (own && own.status !== "archived"))
|
|
33
|
+
return own;
|
|
34
|
+
return fetchOne(readDb, templateResourcesTable, {
|
|
35
|
+
tenantId: SYSTEM_TENANT_ID,
|
|
36
|
+
slug,
|
|
37
|
+
kind,
|
|
38
|
+
locale,
|
|
39
|
+
status: "active",
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
export const copyLocaleWrite = defineWriteHandler({
|
|
43
|
+
name: "copy-locale",
|
|
44
|
+
schema: z.object({
|
|
45
|
+
slug: templateSlugSchema,
|
|
46
|
+
kind: kindSchema,
|
|
47
|
+
fromLocale: localeSchema,
|
|
48
|
+
toLocale: localeSchema,
|
|
49
|
+
overwrite: z.boolean().default(false),
|
|
50
|
+
/** "system" copies between system-default rows; SystemAdmin only. */
|
|
51
|
+
scope: z.enum(["tenant", "system"]).default("tenant"),
|
|
52
|
+
}),
|
|
53
|
+
access: { roles: ["TenantAdmin", "SystemAdmin"] },
|
|
54
|
+
description: "Copies the text of one locale of a template into another locale as a draft override of the caller's tenant, taking the tenant's own row or else the system default as the source; use it as the starting point for a translation. It refuses an existing target unless overwrite is set. With scope system (SystemAdmin only) both source and target are system-default rows and the target lands as a system draft; any other caller gets a 403.",
|
|
55
|
+
handler: async (event, ctx) => {
|
|
56
|
+
const { slug, kind, fromLocale, toLocale, overwrite, scope } = event.payload;
|
|
57
|
+
if (scope === "system" && !event.user.roles.includes("SystemAdmin")) {
|
|
58
|
+
return writeFailure(new AccessDeniedError({
|
|
59
|
+
i18nKey: "errors.access.denied",
|
|
60
|
+
details: { reason: TemplateResolverErrors.systemAdminRequired },
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
const tenantId = scope === "system" ? SYSTEM_TENANT_ID : event.user.tenantId;
|
|
64
|
+
const refused = refuseTenantScopeUnderSystemTenant(scope, tenantId);
|
|
65
|
+
if (refused !== null)
|
|
66
|
+
return refused;
|
|
67
|
+
const readDb = readDbFor(ctx, scope);
|
|
68
|
+
const storedSource = await findCopySource(ctx, {
|
|
69
|
+
scope,
|
|
70
|
+
tenantId,
|
|
71
|
+
slug,
|
|
72
|
+
kind,
|
|
73
|
+
locale: fromLocale,
|
|
74
|
+
});
|
|
75
|
+
const source = storedSource && toWorkingRow(storedSource, tenantId);
|
|
76
|
+
if (!source || !isOneOf(CONTENT_FORMATS, source.contentFormat)) {
|
|
77
|
+
return writeFailure(new NotFoundError("template-resource", `${slug}/${fromLocale}`));
|
|
78
|
+
}
|
|
79
|
+
if (!overwrite) {
|
|
80
|
+
const target = await fetchOne(readDb, templateResourcesTable, {
|
|
81
|
+
tenantId,
|
|
82
|
+
slug,
|
|
83
|
+
kind,
|
|
84
|
+
locale: toLocale,
|
|
85
|
+
});
|
|
86
|
+
if (target) {
|
|
87
|
+
return writeFailure(new ValidationError({ fields: [targetExistsIssue(toLocale)] }));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const variableSchema = storedRecord(source.variableSchema);
|
|
91
|
+
const written = await writeTemplateRow({
|
|
92
|
+
ctx,
|
|
93
|
+
user: event.user,
|
|
94
|
+
tenantId,
|
|
95
|
+
scope,
|
|
96
|
+
status: "draft",
|
|
97
|
+
variables: resolveTemplateVariables(ctx.registry, slug, variableSchema),
|
|
98
|
+
payload: {
|
|
99
|
+
slug,
|
|
100
|
+
kind,
|
|
101
|
+
locale: toLocale,
|
|
102
|
+
content: source.content,
|
|
103
|
+
contentFormat: source.contentFormat,
|
|
104
|
+
variableSchema,
|
|
105
|
+
meta: parseStoredJson(source.meta),
|
|
106
|
+
title: source.title,
|
|
107
|
+
folder: source.folder,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
if (!written.isSuccess)
|
|
111
|
+
return written;
|
|
112
|
+
const sourceResources = parseLinkedResourceEntries(source.linkedResources);
|
|
113
|
+
// A system source's files belong to the system tenant: the tenant gets its own copies so
|
|
114
|
+
// previews, exports and the tenant's override keep working independent of the system row.
|
|
115
|
+
const resources = source.tenantId === tenantId
|
|
116
|
+
? { isSuccess: true, data: sourceResources }
|
|
117
|
+
: await duplicateLinkedResourceFiles(ctx, {
|
|
118
|
+
user: event.user,
|
|
119
|
+
tenantId,
|
|
120
|
+
resources: sourceResources,
|
|
121
|
+
});
|
|
122
|
+
if (!resources.isSuccess)
|
|
123
|
+
return resources;
|
|
124
|
+
const attached = await attachTemplateResources(ctx, {
|
|
125
|
+
user: event.user,
|
|
126
|
+
tenantId,
|
|
127
|
+
templateId: written.data.id,
|
|
128
|
+
resources: resources.data,
|
|
129
|
+
});
|
|
130
|
+
if (!attached.isSuccess)
|
|
131
|
+
return attached;
|
|
132
|
+
return written;
|
|
133
|
+
},
|
|
134
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
export declare const diffToSystemQuery: import("@cosmicdrift/kumiko-types/define-handler").QueryHandlerDefinition<"diff-to-system", z.ZodObject<{
|
|
3
|
+
id: z.ZodString;
|
|
4
|
+
}, z.core.$strip>, {
|
|
5
|
+
tenant: {
|
|
6
|
+
templateId: string;
|
|
7
|
+
templateVersion: number;
|
|
8
|
+
contentFormat: string;
|
|
9
|
+
};
|
|
10
|
+
system: {
|
|
11
|
+
templateId: string;
|
|
12
|
+
templateVersion: number;
|
|
13
|
+
contentFormat: string;
|
|
14
|
+
};
|
|
15
|
+
identical: boolean;
|
|
16
|
+
blocks: import("../template-diff.js").TemplateDiffBlock[];
|
|
17
|
+
meta: {
|
|
18
|
+
key: string;
|
|
19
|
+
tenant: unknown;
|
|
20
|
+
system: unknown;
|
|
21
|
+
}[];
|
|
22
|
+
}, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { fetchOne } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
2
|
+
import { defineQueryHandler, SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
+
import { NotFoundError } from "@cosmicdrift/kumiko-framework/errors";
|
|
4
|
+
import * as z from "zod";
|
|
5
|
+
import { templateResourcesTable } from "../table.js";
|
|
6
|
+
import { isHiddenSystemDraft } from "../template-draft.js";
|
|
7
|
+
import { buildOverrideDiff } from "./override-diff.js";
|
|
8
|
+
export const diffToSystemQuery = defineQueryHandler({
|
|
9
|
+
name: "diff-to-system",
|
|
10
|
+
schema: z.object({ id: z.string().min(1) }),
|
|
11
|
+
access: { roles: ["TenantAdmin", "SystemAdmin"] },
|
|
12
|
+
description: "Compares one tenant override with the system template of the same slug, kind and locale block by block and lists the changed meta settings; use it to show what an override changes before resetting it to the system version.",
|
|
13
|
+
handler: async (query, ctx) => {
|
|
14
|
+
const tenantRow = await fetchOne(ctx.db, templateResourcesTable, {
|
|
15
|
+
id: query.payload.id,
|
|
16
|
+
});
|
|
17
|
+
if (!tenantRow || tenantRow.tenantId !== query.user.tenantId || tenantRow.scope !== "tenant") {
|
|
18
|
+
throw new NotFoundError("template-resource", query.payload.id);
|
|
19
|
+
}
|
|
20
|
+
const systemRow = await fetchOne(ctx.db, templateResourcesTable, {
|
|
21
|
+
tenantId: SYSTEM_TENANT_ID,
|
|
22
|
+
slug: tenantRow.slug,
|
|
23
|
+
kind: tenantRow.kind,
|
|
24
|
+
locale: tenantRow.locale,
|
|
25
|
+
});
|
|
26
|
+
if (!systemRow || isHiddenSystemDraft(query.user, systemRow))
|
|
27
|
+
throw new NotFoundError("template-resource", tenantRow.slug);
|
|
28
|
+
return buildOverrideDiff(tenantRow, systemRow);
|
|
29
|
+
},
|
|
30
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
export declare const discardDraftWrite: import("@cosmicdrift/kumiko-types/define-handler").WriteHandlerDefinition<string, z.ZodObject<{
|
|
3
|
+
id: z.ZodString;
|
|
4
|
+
}, z.core.$strip>, {
|
|
5
|
+
id: string;
|
|
6
|
+
discarded: boolean;
|
|
7
|
+
}, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined>;
|
|
8
|
+
export declare const discardDraftSystemWrite: import("@cosmicdrift/kumiko-types/define-handler").WriteHandlerDefinition<string, z.ZodObject<{
|
|
9
|
+
id: z.ZodString;
|
|
10
|
+
}, z.core.$strip>, {
|
|
11
|
+
id: string;
|
|
12
|
+
discarded: boolean;
|
|
13
|
+
}, import("@cosmicdrift/kumiko-types/event-type-map").KumikoEventTypeMap, undefined>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { defineWriteHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
+
import { NotFoundError, ValidationError, writeFailure } from "@cosmicdrift/kumiko-framework/errors";
|
|
3
|
+
import * as z from "zod";
|
|
4
|
+
import { TemplateResolverErrors } from "../qualified-names.js";
|
|
5
|
+
import { executor } from "./shared.js";
|
|
6
|
+
import { loadTargetRow, writeAccessFor } from "./toggle-status.write.js";
|
|
7
|
+
function createDiscardDraftHandler(name, target, description) {
|
|
8
|
+
return defineWriteHandler({
|
|
9
|
+
name,
|
|
10
|
+
schema: z.object({ id: z.string().min(1) }),
|
|
11
|
+
access: writeAccessFor(target),
|
|
12
|
+
...(target === "system" ? { agent: { risk: "high" } } : {}),
|
|
13
|
+
description,
|
|
14
|
+
handler: async (event, ctx) => {
|
|
15
|
+
const { db, scoped, row } = await loadTargetRow(ctx, target, event.user, event.payload.id);
|
|
16
|
+
if (!row)
|
|
17
|
+
return writeFailure(new NotFoundError("template-resource", event.payload.id));
|
|
18
|
+
if (row.draft === null) {
|
|
19
|
+
return writeFailure(new ValidationError({
|
|
20
|
+
fields: [
|
|
21
|
+
{
|
|
22
|
+
path: "id",
|
|
23
|
+
code: TemplateResolverErrors.noDraft,
|
|
24
|
+
i18nKey: "templateResolver.errors.noDraft",
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
const result = await executor.update({ id: row.id, version: row.version, changes: { draft: null } }, event.user, db, scoped ? { streamTenantId: scoped.streamTenantId } : undefined);
|
|
30
|
+
if (!result.isSuccess)
|
|
31
|
+
return result;
|
|
32
|
+
return { isSuccess: true, data: { id: String(row.id), discarded: true } };
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export const discardDraftWrite = createDiscardDraftHandler("discard-draft", "own", "Throws away the open draft of one template resource of the caller's tenant so the editor shows the active version again; the served version is untouched. Refused with no_draft when there is no draft.");
|
|
37
|
+
export const discardDraftSystemWrite = createDiscardDraftHandler("discard-draft-system", "system", "Throws away the open draft of one system-default template; the served version stays. SystemAdmin only, refused with no_draft when there is no draft.");
|