@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
|
@@ -1,17 +1,26 @@
|
|
|
1
|
-
export declare const RENDER_KINDS: readonly ["
|
|
1
|
+
export declare const RENDER_KINDS: readonly ["mail", "document-pdf", "image-snapshot"];
|
|
2
2
|
export type RenderKind = (typeof RENDER_KINDS)[number];
|
|
3
|
-
export declare const
|
|
3
|
+
export declare const DOCUMENT_HTML_KINDS: readonly ["mail", "document-pdf"];
|
|
4
|
+
export type DocumentHtmlKind = (typeof DOCUMENT_HTML_KINDS)[number];
|
|
5
|
+
export declare const NON_RENDER_KINDS: readonly ["notification", "text-block", "snippet", "ai-prompt", "mail-layout", "pdf-layout"];
|
|
4
6
|
export type NonRenderKind = (typeof NON_RENDER_KINDS)[number];
|
|
5
|
-
export declare const TEMPLATE_KINDS: readonly ["
|
|
7
|
+
export declare const TEMPLATE_KINDS: readonly ["mail", "document-pdf", "image-snapshot", "notification", "text-block", "snippet", "ai-prompt", "mail-layout", "pdf-layout"];
|
|
6
8
|
export type TemplateKind = (typeof TEMPLATE_KINDS)[number];
|
|
7
|
-
export declare const UPSERT_KINDS: readonly ["
|
|
9
|
+
export declare const UPSERT_KINDS: readonly ["mail", "document-pdf", "image-snapshot", "ai-prompt", "mail-layout", "pdf-layout"];
|
|
8
10
|
export type UpsertKind = (typeof UPSERT_KINDS)[number];
|
|
9
11
|
export declare const TEXT_BLOCK_KIND: "text-block";
|
|
12
|
+
export declare const COLLECTION_REFUSED_KINDS: readonly string[];
|
|
10
13
|
export declare const CONTENT_FORMATS: readonly ["markdown", "mjml", "html", "plain"];
|
|
11
14
|
export type ContentFormat = (typeof CONTENT_FORMATS)[number];
|
|
12
15
|
export declare const TEMPLATE_SCOPES: readonly ["system", "tenant"];
|
|
13
16
|
export type TemplateScope = (typeof TEMPLATE_SCOPES)[number];
|
|
14
17
|
export declare const TEMPLATE_STATUSES: readonly ["draft", "active", "archived"];
|
|
15
18
|
export type TemplateStatus = (typeof TEMPLATE_STATUSES)[number];
|
|
19
|
+
export { PDF_DEFAULT_MARGIN_MM, PDF_FOOTER_MARGIN_MM, PDF_HEADER_MARGIN_MM, PDF_ORIENTATIONS, PDF_PAGE_FORMATS, type PdfOrientation, type PdfPageFormat, } from "./pdf-constants.js";
|
|
20
|
+
export declare const HEX_COLOR_PATTERN: RegExp;
|
|
21
|
+
export declare const DEFAULT_MAIL_LAYOUT_SLUG = "default";
|
|
22
|
+
export declare const MAIL_PREVIEW_MAX_BYTES: number;
|
|
23
|
+
export declare const TEST_MAIL_NOTIFICATION_TYPE = "template-resolver:test-mail";
|
|
24
|
+
export declare const TEST_MAIL_SUBJECT_PREFIX = "[TEST] ";
|
|
16
25
|
export { SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
17
26
|
export declare const FALLBACK_LOCALE = "de";
|
|
@@ -6,30 +6,52 @@
|
|
|
6
6
|
// Plugin-Renderer in `renderer-foundation` matchen auf kind; der
|
|
7
7
|
// Resolver hier ist kind-agnostisch — er lädt nur, das Content-Format
|
|
8
8
|
// (markdown/mjml/html) entscheidet wer's rendert.
|
|
9
|
-
export const RENDER_KINDS = [
|
|
9
|
+
export const RENDER_KINDS = ["mail", "document-pdf", "image-snapshot"];
|
|
10
|
+
// Kinds whose html body is a rich document: the server rebuilds it through the
|
|
11
|
+
// document schema on every write (see document-sanitizer.ts).
|
|
12
|
+
export const DOCUMENT_HTML_KINDS = ["mail", "document-pdf"];
|
|
13
|
+
// Kinds without a renderer plugin: `notification` is the retired sections-JSON
|
|
14
|
+
// notification kind, kept so rows stored before mails moved to `mail` stay
|
|
15
|
+
// valid on replay; nothing writes or renders it any more. `text-block` is the Markdown text store
|
|
16
|
+
// (ex text-content feature), `snippet` is the content of app collections such
|
|
17
|
+
// as reply snippets and signatures (own kind so they stay out of the text-block
|
|
18
|
+
// content tree), `ai-prompt` holds LLM prompts, `mail-layout` and
|
|
19
|
+
// `pdf-layout` hold the frame a mail/pdf body is rendered into. All are read,
|
|
20
|
+
// not rendered on their own — keeping them out of RENDER_KINDS is what stops
|
|
21
|
+
// DEFAULT_PLUGIN_BY_KIND from demanding a plugin for them.
|
|
22
|
+
export const NON_RENDER_KINDS = [
|
|
10
23
|
"notification",
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
24
|
+
"text-block",
|
|
25
|
+
"snippet",
|
|
26
|
+
"ai-prompt",
|
|
27
|
+
"mail-layout",
|
|
28
|
+
"pdf-layout",
|
|
14
29
|
];
|
|
15
|
-
// Kinds without a renderer plugin: `text-block` is the Markdown text store
|
|
16
|
-
// (ex text-content feature), `ai-prompt` holds LLM prompts. Both are read,
|
|
17
|
-
// not rendered — keeping them out of RENDER_KINDS is what stops
|
|
18
|
-
// DEFAULT_PLUGIN_BY_KIND from demanding a plugin for them.
|
|
19
|
-
export const NON_RENDER_KINDS = ["text-block", "ai-prompt"];
|
|
20
30
|
// Full kind domain of the entity; RENDER_KINDS is the renderer-foundation subset.
|
|
21
31
|
export const TEMPLATE_KINDS = [...RENDER_KINDS, ...NON_RENDER_KINDS];
|
|
22
32
|
// Kinds written through upsertSystem/upsertTenant. `text-block` is absent on
|
|
23
33
|
// purpose: it goes through set.write (title + folder tree); two write paths
|
|
24
34
|
// onto the same row would drift apart.
|
|
25
|
-
export const UPSERT_KINDS = [...RENDER_KINDS, "ai-prompt"];
|
|
35
|
+
export const UPSERT_KINDS = [...RENDER_KINDS, "ai-prompt", "mail-layout", "pdf-layout"];
|
|
26
36
|
// The only kind served by the anonymous-capable by-slug/by-tenant queries and
|
|
27
37
|
// by set.write — mail templates and AI prompts are operational internals and
|
|
28
38
|
// must not leak through the anonymous path.
|
|
29
39
|
export const TEXT_BLOCK_KIND = "text-block";
|
|
40
|
+
// Kinds a content collection must not write: a tenant row of these kinds would
|
|
41
|
+
// shadow the system notification template or layout without the meta and
|
|
42
|
+
// placeholder gates that upsertTenant applies.
|
|
43
|
+
export const COLLECTION_REFUSED_KINDS = ["mail", "mail-layout", "pdf-layout"];
|
|
30
44
|
export const CONTENT_FORMATS = ["markdown", "mjml", "html", "plain"];
|
|
31
45
|
export const TEMPLATE_SCOPES = ["system", "tenant"];
|
|
32
46
|
export const TEMPLATE_STATUSES = ["draft", "active", "archived"];
|
|
47
|
+
export { PDF_DEFAULT_MARGIN_MM, PDF_FOOTER_MARGIN_MM, PDF_HEADER_MARGIN_MM, PDF_ORIENTATIONS, PDF_PAGE_FORMATS, } from "./pdf-constants.js";
|
|
48
|
+
// Colors end up inside MJML attributes, so only a strict hex is ever written there.
|
|
49
|
+
export const HEX_COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;
|
|
50
|
+
export const DEFAULT_MAIL_LAYOUT_SLUG = "default";
|
|
51
|
+
// The mail transport enforces no size limit of its own; 10 MiB is a common provider ceiling.
|
|
52
|
+
export const MAIL_PREVIEW_MAX_BYTES = 10 * 1024 * 1024;
|
|
53
|
+
export const TEST_MAIL_NOTIFICATION_TYPE = "template-resolver:test-mail";
|
|
54
|
+
export const TEST_MAIL_SUBJECT_PREFIX = "[TEST] ";
|
|
33
55
|
// System-Templates leben unter der canonical SYSTEM_TENANT_ID-Sentinel-UUID.
|
|
34
56
|
// Re-Export aus framework — single source of truth, vermeidet Drift.
|
|
35
57
|
export { SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { FieldIssue } from "@cosmicdrift/kumiko-framework/errors";
|
|
2
|
+
import { type Element as ScanElement } from "happy-dom";
|
|
3
|
+
import type { ContentFormat } from "./constants.js";
|
|
4
|
+
export type DocumentViolationCode = "script_element" | "event_handler_attribute" | "disallowed_link_href" | "external_image_source" | "image_without_resource" | "invalid_reference_name" | "embedded_content" | "unsafe_attribute_value" | "button_href_not_placeholder" | "document_requires_html_format" | "layout_requires_mjml_format" | "layout_invalid_structure" | "layout_missing_content_slot" | "layout_source_system_only";
|
|
5
|
+
export type DocumentViolation = {
|
|
6
|
+
readonly code: DocumentViolationCode;
|
|
7
|
+
readonly detail: string;
|
|
8
|
+
readonly message: string;
|
|
9
|
+
};
|
|
10
|
+
export type SanitizeHtmlResult = {
|
|
11
|
+
readonly ok: true;
|
|
12
|
+
readonly html: string;
|
|
13
|
+
} | {
|
|
14
|
+
readonly ok: false;
|
|
15
|
+
readonly violations: readonly DocumentViolation[];
|
|
16
|
+
};
|
|
17
|
+
export type SanitizeBodyResult = {
|
|
18
|
+
readonly ok: true;
|
|
19
|
+
readonly content: string | null;
|
|
20
|
+
} | {
|
|
21
|
+
readonly ok: false;
|
|
22
|
+
readonly violations: readonly DocumentViolation[];
|
|
23
|
+
};
|
|
24
|
+
export declare function violation(code: DocumentViolationCode, detail: string, message: string): DocumentViolation;
|
|
25
|
+
export declare function withParsedDocument<T>(html: string, read: (body: ScanElement) => T): T;
|
|
26
|
+
export declare function sanitizeDocumentHtml(html: string): SanitizeHtmlResult;
|
|
27
|
+
export declare function sanitizeTemplateBody(input: {
|
|
28
|
+
readonly kind: string;
|
|
29
|
+
readonly contentFormat: ContentFormat;
|
|
30
|
+
readonly content: string | null;
|
|
31
|
+
}): SanitizeBodyResult;
|
|
32
|
+
export declare function documentViolationsToFieldIssues(violations: readonly DocumentViolation[]): FieldIssue[];
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
|
|
2
|
+
import { generateHTML, generateJSON } from "@tiptap/html/server";
|
|
3
|
+
import { Window } from "happy-dom";
|
|
4
|
+
import { DOCUMENT_HTML_KINDS } from "./constants.js";
|
|
5
|
+
import { documentExtensions, isAllowedDocumentLinkHref, isDocumentPlaceholderHref, isDocumentReferenceName, isDocumentResourceKey, } from "./document-schema.js";
|
|
6
|
+
export function violation(code, detail, message) {
|
|
7
|
+
return { code, detail, message };
|
|
8
|
+
}
|
|
9
|
+
// Same switches tiptap's generateJSON uses, plus navigation off: the scan
|
|
10
|
+
// window must never fetch or navigate anything.
|
|
11
|
+
function createScanWindow() {
|
|
12
|
+
return new Window({
|
|
13
|
+
settings: {
|
|
14
|
+
disableJavaScriptEvaluation: true,
|
|
15
|
+
disableJavaScriptFileLoading: true,
|
|
16
|
+
disableCSSFileLoading: true,
|
|
17
|
+
disableIframePageLoading: true,
|
|
18
|
+
disableComputedStyleRendering: true,
|
|
19
|
+
navigation: {
|
|
20
|
+
disableMainFrameNavigation: true,
|
|
21
|
+
disableChildFrameNavigation: true,
|
|
22
|
+
disableChildPageNavigation: true,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function scanScriptAndHandlers(tag, element, out) {
|
|
28
|
+
if (tag === "script") {
|
|
29
|
+
out.push(violation("script_element", "script", "<script> elements are not allowed in template bodies"));
|
|
30
|
+
}
|
|
31
|
+
for (const attribute of Array.from(element.attributes)) {
|
|
32
|
+
if (/^on/i.test(attribute.name)) {
|
|
33
|
+
out.push(violation("event_handler_attribute", attribute.name, `Inline event handler "${attribute.name}" on <${tag}> is not allowed`));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function scanAnchor(element, out) {
|
|
38
|
+
const href = element.getAttribute("href");
|
|
39
|
+
if (href !== null && !isAllowedDocumentLinkHref(href)) {
|
|
40
|
+
out.push(violation("disallowed_link_href", href, `Link target "${href}" is not allowed; use https, http, mailto, tel or a {{placeholder}}`));
|
|
41
|
+
}
|
|
42
|
+
if (element.hasAttribute("data-button") && !isDocumentPlaceholderHref(href ?? "")) {
|
|
43
|
+
out.push(violation("button_href_not_placeholder", href ?? "", `Button target "${href ?? ""}" must be a {{placeholder}}`));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function scanImage(element, out) {
|
|
47
|
+
const source = element.getAttribute("src") ?? element.getAttribute("srcset");
|
|
48
|
+
if (source !== null) {
|
|
49
|
+
out.push(violation("external_image_source", source, `Images must reference an uploaded resource via data-resource; external or inline image source "${source}" is not allowed`));
|
|
50
|
+
}
|
|
51
|
+
if (!element.hasAttribute("data-resource")) {
|
|
52
|
+
out.push(violation("image_without_resource", "img", "Images must reference an uploaded resource via the data-resource attribute"));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const REFERENCE_ATTRIBUTES = [
|
|
56
|
+
["data-variable", isDocumentReferenceName],
|
|
57
|
+
["data-each", isDocumentReferenceName],
|
|
58
|
+
["data-resource", isDocumentResourceKey],
|
|
59
|
+
];
|
|
60
|
+
function scanReferences(tag, element, out) {
|
|
61
|
+
for (const [attribute, isValid] of REFERENCE_ATTRIBUTES) {
|
|
62
|
+
const value = element.getAttribute(attribute);
|
|
63
|
+
if (value !== null && !isValid(value)) {
|
|
64
|
+
out.push(violation("invalid_reference_name", value, `Value "${value}" of ${attribute} on <${tag}> is not a valid name`));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const EMBEDDING_TAGS = new Set([
|
|
69
|
+
"iframe",
|
|
70
|
+
"frame",
|
|
71
|
+
"frameset",
|
|
72
|
+
"object",
|
|
73
|
+
"embed",
|
|
74
|
+
"applet",
|
|
75
|
+
"portal",
|
|
76
|
+
]);
|
|
77
|
+
const SVG_IMAGE_TAGS = new Set(["image", "feimage", "use"]);
|
|
78
|
+
const URL_ATTRIBUTES = ["href", "xlink:href", "action", "formaction"];
|
|
79
|
+
function scanEmbedding(tag, out) {
|
|
80
|
+
if (EMBEDDING_TAGS.has(tag)) {
|
|
81
|
+
out.push(violation("embedded_content", tag, `<${tag}> elements are not allowed in template bodies`));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// html <a href> has its own rules in scanAnchor; everywhere else (svg, base,
|
|
85
|
+
// form controls) a URL attribute has no business in a template body.
|
|
86
|
+
function scanUrlAttributes(tag, element, out) {
|
|
87
|
+
for (const name of URL_ATTRIBUTES) {
|
|
88
|
+
const value = element.getAttribute(name);
|
|
89
|
+
if (value === null || (tag === "a" && name === "href"))
|
|
90
|
+
continue;
|
|
91
|
+
if (SVG_IMAGE_TAGS.has(tag) && name.endsWith("href")) {
|
|
92
|
+
out.push(violation("external_image_source", value, `Images must reference an uploaded resource via data-resource; image source "${value}" is not allowed`));
|
|
93
|
+
}
|
|
94
|
+
else if (tag === "base" || !isAllowedDocumentLinkHref(value)) {
|
|
95
|
+
out.push(violation("disallowed_link_href", value, `Link target "${value}" is not allowed; use https, http, mailto, tel or a {{placeholder}}`));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// happy-dom serializes < and > inside attribute values unescaped, so a later
|
|
100
|
+
// parser (MJML) could read them as markup.
|
|
101
|
+
function scanAltText(element, out) {
|
|
102
|
+
const alt = element.getAttribute("alt");
|
|
103
|
+
if (alt !== null && /[<>]/.test(alt)) {
|
|
104
|
+
out.push(violation("unsafe_attribute_value", alt, `Attribute alt must not contain "<" or ">": "${alt}"`));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function scanElement(element, out) {
|
|
108
|
+
const tag = element.tagName.toLowerCase();
|
|
109
|
+
scanEmbedding(tag, out);
|
|
110
|
+
scanUrlAttributes(tag, element, out);
|
|
111
|
+
scanAltText(element, out);
|
|
112
|
+
scanScriptAndHandlers(tag, element, out);
|
|
113
|
+
if (tag === "a")
|
|
114
|
+
scanAnchor(element, out);
|
|
115
|
+
if (tag === "img")
|
|
116
|
+
scanImage(element, out);
|
|
117
|
+
scanReferences(tag, element, out);
|
|
118
|
+
}
|
|
119
|
+
// Parses `html` in the hardened scan window and always closes it again, also
|
|
120
|
+
// when `read` throws. Shared by the sanitizer and the placeholder scan so there
|
|
121
|
+
// is exactly one DOM setup.
|
|
122
|
+
export function withParsedDocument(html, read) {
|
|
123
|
+
const window = createScanWindow();
|
|
124
|
+
try {
|
|
125
|
+
const parsed = new window.DOMParser().parseFromString(["<!DOCTYPE html><html><body>", html, "</body></html>"].join(""), "text/html");
|
|
126
|
+
return read(parsed.body);
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
window.happyDOM.abort();
|
|
130
|
+
window.happyDOM.close();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function scanDocumentHtml(html) {
|
|
134
|
+
const violations = [];
|
|
135
|
+
withParsedDocument(html, (body) => {
|
|
136
|
+
// A second `<body ...>` in the input merges its attributes into this body.
|
|
137
|
+
for (const element of [body, ...Array.from(body.querySelectorAll("*"))]) {
|
|
138
|
+
scanElement(element, violations);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
return violations;
|
|
142
|
+
}
|
|
143
|
+
// Rejects hostile constructs, then rebuilds the body from the document model.
|
|
144
|
+
// The rebuilt HTML is always what gets returned (never the input), so anything
|
|
145
|
+
// the model cannot express is dropped silently.
|
|
146
|
+
export function sanitizeDocumentHtml(html) {
|
|
147
|
+
const violations = scanDocumentHtml(html);
|
|
148
|
+
if (violations.length > 0)
|
|
149
|
+
return { ok: false, violations };
|
|
150
|
+
return {
|
|
151
|
+
ok: true,
|
|
152
|
+
html: generateHTML(generateJSON(html, documentExtensions), documentExtensions),
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
// Snippets accept any format, but their html is as untrusted as a mail body.
|
|
156
|
+
function isSanitizedHtmlKind(kind) {
|
|
157
|
+
return kind === "snippet" || isOneOf(DOCUMENT_HTML_KINDS, kind);
|
|
158
|
+
}
|
|
159
|
+
const HTML_ONLY_KINDS = new Set(DOCUMENT_HTML_KINDS);
|
|
160
|
+
function requiredFormatViolation(kind, contentFormat) {
|
|
161
|
+
if (HTML_ONLY_KINDS.has(kind) && contentFormat !== "html") {
|
|
162
|
+
return violation("document_requires_html_format", contentFormat, `Templates of kind ${kind} require contentFormat html, got "${contentFormat}"`);
|
|
163
|
+
}
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
export function sanitizeTemplateBody(input) {
|
|
167
|
+
const formatViolation = requiredFormatViolation(input.kind, input.contentFormat);
|
|
168
|
+
if (formatViolation !== null)
|
|
169
|
+
return { ok: false, violations: [formatViolation] };
|
|
170
|
+
if (!isSanitizedHtmlKind(input.kind) ||
|
|
171
|
+
input.contentFormat !== "html" ||
|
|
172
|
+
input.content === null) {
|
|
173
|
+
return { ok: true, content: input.content };
|
|
174
|
+
}
|
|
175
|
+
const result = sanitizeDocumentHtml(input.content);
|
|
176
|
+
return result.ok ? { ok: true, content: result.html } : result;
|
|
177
|
+
}
|
|
178
|
+
const VIOLATION_I18N_KEYS = {
|
|
179
|
+
script_element: "templateResolver.errors.document.scriptElement",
|
|
180
|
+
event_handler_attribute: "templateResolver.errors.document.eventHandlerAttribute",
|
|
181
|
+
disallowed_link_href: "templateResolver.errors.document.disallowedLinkHref",
|
|
182
|
+
external_image_source: "templateResolver.errors.document.externalImageSource",
|
|
183
|
+
image_without_resource: "templateResolver.errors.document.imageWithoutResource",
|
|
184
|
+
invalid_reference_name: "templateResolver.errors.document.invalidReferenceName",
|
|
185
|
+
embedded_content: "templateResolver.errors.document.embeddedContent",
|
|
186
|
+
unsafe_attribute_value: "templateResolver.errors.document.unsafeAttributeValue",
|
|
187
|
+
button_href_not_placeholder: "templateResolver.errors.document.buttonHrefNotPlaceholder",
|
|
188
|
+
document_requires_html_format: "templateResolver.errors.document.documentRequiresHtmlFormat",
|
|
189
|
+
layout_requires_mjml_format: "templateResolver.errors.document.layoutRequiresMjmlFormat",
|
|
190
|
+
layout_invalid_structure: "templateResolver.errors.document.layoutInvalidStructure",
|
|
191
|
+
layout_missing_content_slot: "templateResolver.errors.document.layoutMissingContentSlot",
|
|
192
|
+
layout_source_system_only: "templateResolver.errors.document.layoutSourceSystemOnly",
|
|
193
|
+
};
|
|
194
|
+
export function documentViolationsToFieldIssues(violations) {
|
|
195
|
+
return violations.map((item) => ({
|
|
196
|
+
path: "content",
|
|
197
|
+
code: item.code,
|
|
198
|
+
i18nKey: VIOLATION_I18N_KEYS[item.code],
|
|
199
|
+
params: { detail: item.detail },
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Extension, type Extensions, Node } from "@tiptap/core";
|
|
2
|
+
export declare function isDocumentPlaceholderHref(href: string): boolean;
|
|
3
|
+
export declare function isAllowedDocumentLinkHref(href: string): boolean;
|
|
4
|
+
export declare function isDocumentReferenceName(value: string): boolean;
|
|
5
|
+
export declare function isDocumentResourceKey(value: string): boolean;
|
|
6
|
+
export declare const DOCUMENT_NODE_NAMES: readonly ["variable", "resource", "button", "divider", "pageBreak"];
|
|
7
|
+
export declare const DocumentVariable: Node<any, any>;
|
|
8
|
+
export declare const DocumentResource: Node<any, any>;
|
|
9
|
+
export declare const DocumentButton: Node<any, any>;
|
|
10
|
+
export declare const DocumentDivider: Node<any, any>;
|
|
11
|
+
export declare const DocumentPageBreak: Node<any, any>;
|
|
12
|
+
export declare const DocumentTableRow: Node<import("@tiptap/extension-table").TableRowOptions, any>;
|
|
13
|
+
export declare const DocumentTable: Node<import("@tiptap/extension-table").TableOptions, any>;
|
|
14
|
+
export declare const DocumentTableCell: Node<import("@tiptap/extension-table").TableCellOptions, any>;
|
|
15
|
+
export declare const DocumentTableHeader: Node<import("@tiptap/extension-table").TableHeaderOptions, any>;
|
|
16
|
+
export declare const DocumentLink: import("@tiptap/core").Mark<import("@tiptap/extension-link").LinkOptions, any>;
|
|
17
|
+
export declare const DOCUMENT_TEXT_ALIGNMENTS: readonly ["left", "center", "right", "justify"];
|
|
18
|
+
export type DocumentTextAlignment = (typeof DOCUMENT_TEXT_ALIGNMENTS)[number];
|
|
19
|
+
export declare const DocumentTextAlign: Extension<any, any>;
|
|
20
|
+
export declare const DocumentTextSize: Extension<any, any>;
|
|
21
|
+
export declare const documentExtensions: Extensions;
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
// @runtime client
|
|
2
|
+
// Canonical document model for template bodies (kinds mail, document-pdf).
|
|
3
|
+
// Universal on purpose: the web editor and the server sanitizer load the same
|
|
4
|
+
// extension list, so what the editor can produce is exactly what the server
|
|
5
|
+
// keeps. No DOM access at module level, no happy-dom here.
|
|
6
|
+
import { isOneOf, isPlainObject } from "@cosmicdrift/kumiko-types/type-guards";
|
|
7
|
+
import { Extension, Node } from "@tiptap/core";
|
|
8
|
+
import { Link } from "@tiptap/extension-link";
|
|
9
|
+
import { Table, TableCell, TableHeader, TableRow } from "@tiptap/extension-table";
|
|
10
|
+
import StarterKit from "@tiptap/starter-kit";
|
|
11
|
+
const PLACEHOLDER_HREF = /^\{\{(.+)\}\}$/;
|
|
12
|
+
const REFERENCE_NAME = /^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$/;
|
|
13
|
+
const RESOURCE_KEY = /^[A-Za-z0-9][A-Za-z0-9_.-]*$/;
|
|
14
|
+
const ALLOWED_LINK_SCHEMES = ["https://", "http://", "mailto:", "tel:"];
|
|
15
|
+
export function isDocumentPlaceholderHref(href) {
|
|
16
|
+
const name = PLACEHOLDER_HREF.exec(href)?.[1];
|
|
17
|
+
return name !== undefined && isDocumentReferenceName(name);
|
|
18
|
+
}
|
|
19
|
+
const UNSAFE_URL_CHARACTERS = new Set(["<", ">", '"']);
|
|
20
|
+
const FORBIDDEN_REFERENCE_SEGMENTS = new Set(["__proto__", "prototype", "constructor"]);
|
|
21
|
+
function hasUnsafeUrlCharacter(value) {
|
|
22
|
+
return Array.from(value).some((character) => {
|
|
23
|
+
const code = character.charCodeAt(0);
|
|
24
|
+
return UNSAFE_URL_CHARACTERS.has(character) || code <= 0x1f || code === 0x7f;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function isParsableWebUrl(href, protocol) {
|
|
28
|
+
try {
|
|
29
|
+
return new URL(href).protocol === protocol;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function hasAllowedLinkScheme(href) {
|
|
36
|
+
if (href.startsWith("https://"))
|
|
37
|
+
return isParsableWebUrl(href, "https:");
|
|
38
|
+
if (href.startsWith("http://"))
|
|
39
|
+
return isParsableWebUrl(href, "http:");
|
|
40
|
+
return ALLOWED_LINK_SCHEMES.some((scheme) => href.startsWith(scheme));
|
|
41
|
+
}
|
|
42
|
+
// Exact lowercase prefix on the unchanged value: no trim, no case folding, so
|
|
43
|
+
// "JaVaScRiPt:", "HTTPS://" or a leading tab can never slip through as a
|
|
44
|
+
// scheme variant. Markup and control characters are refused outright because
|
|
45
|
+
// downstream parsers (MJML, PDF renderer) re-read the serialized attribute.
|
|
46
|
+
export function isAllowedDocumentLinkHref(href) {
|
|
47
|
+
if (hasUnsafeUrlCharacter(href))
|
|
48
|
+
return false;
|
|
49
|
+
return hasAllowedLinkScheme(href) || isDocumentPlaceholderHref(href);
|
|
50
|
+
}
|
|
51
|
+
// Segments that hit the prototype chain are refused: the renderer later walks
|
|
52
|
+
// the dotted path into a data object.
|
|
53
|
+
export function isDocumentReferenceName(value) {
|
|
54
|
+
return (REFERENCE_NAME.test(value) &&
|
|
55
|
+
!value.split(".").some((segment) => FORBIDDEN_REFERENCE_SEGMENTS.has(segment)));
|
|
56
|
+
}
|
|
57
|
+
export function isDocumentResourceKey(value) {
|
|
58
|
+
return RESOURCE_KEY.test(value);
|
|
59
|
+
}
|
|
60
|
+
export const DOCUMENT_NODE_NAMES = [
|
|
61
|
+
"variable",
|
|
62
|
+
"resource",
|
|
63
|
+
"button",
|
|
64
|
+
"divider",
|
|
65
|
+
"pageBreak",
|
|
66
|
+
];
|
|
67
|
+
export const DocumentVariable = Node.create({
|
|
68
|
+
name: "variable",
|
|
69
|
+
group: "inline",
|
|
70
|
+
inline: true,
|
|
71
|
+
atom: true,
|
|
72
|
+
addAttributes() {
|
|
73
|
+
return { name: { default: null } };
|
|
74
|
+
},
|
|
75
|
+
parseHTML() {
|
|
76
|
+
return [
|
|
77
|
+
{
|
|
78
|
+
tag: "span[data-variable]",
|
|
79
|
+
getAttrs: (element) => {
|
|
80
|
+
const name = element.getAttribute("data-variable");
|
|
81
|
+
return name !== null && isDocumentReferenceName(name) ? { name } : false;
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
},
|
|
86
|
+
renderHTML({ node }) {
|
|
87
|
+
return ["span", { "data-variable": node.attrs["name"] }];
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
export const DocumentResource = Node.create({
|
|
91
|
+
name: "resource",
|
|
92
|
+
group: "block",
|
|
93
|
+
atom: true,
|
|
94
|
+
addAttributes() {
|
|
95
|
+
return { resource: { default: null }, alt: { default: null } };
|
|
96
|
+
},
|
|
97
|
+
parseHTML() {
|
|
98
|
+
return [
|
|
99
|
+
{
|
|
100
|
+
tag: "img[data-resource]",
|
|
101
|
+
getAttrs: (element) => {
|
|
102
|
+
const resource = element.getAttribute("data-resource");
|
|
103
|
+
if (resource === null || !isDocumentResourceKey(resource))
|
|
104
|
+
return false;
|
|
105
|
+
return { resource, alt: element.getAttribute("alt") };
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
},
|
|
110
|
+
// Never emits src: the renderer resolves the resource key at render time.
|
|
111
|
+
renderHTML({ node }) {
|
|
112
|
+
const alt = node.attrs["alt"];
|
|
113
|
+
return [
|
|
114
|
+
"img",
|
|
115
|
+
alt === null || alt === undefined
|
|
116
|
+
? { "data-resource": node.attrs["resource"] }
|
|
117
|
+
: { "data-resource": node.attrs["resource"], alt },
|
|
118
|
+
];
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
export const DocumentButton = Node.create({
|
|
122
|
+
name: "button",
|
|
123
|
+
group: "block",
|
|
124
|
+
content: "text*",
|
|
125
|
+
marks: "",
|
|
126
|
+
defining: true,
|
|
127
|
+
addAttributes() {
|
|
128
|
+
return { href: { default: null } };
|
|
129
|
+
},
|
|
130
|
+
parseHTML() {
|
|
131
|
+
return [
|
|
132
|
+
{
|
|
133
|
+
tag: "a[data-button]",
|
|
134
|
+
// Must win against the Link mark's `a[href]` rule.
|
|
135
|
+
priority: 1000,
|
|
136
|
+
getAttrs: (element) => {
|
|
137
|
+
const href = element.getAttribute("href");
|
|
138
|
+
return href !== null && isDocumentPlaceholderHref(href) ? { href } : false;
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
];
|
|
142
|
+
},
|
|
143
|
+
renderHTML({ node }) {
|
|
144
|
+
return ["a", { "data-button": "", href: node.attrs["href"] }, 0];
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
export const DocumentDivider = Node.create({
|
|
148
|
+
name: "divider",
|
|
149
|
+
group: "block",
|
|
150
|
+
atom: true,
|
|
151
|
+
parseHTML() {
|
|
152
|
+
return [{ tag: "hr" }];
|
|
153
|
+
},
|
|
154
|
+
renderHTML() {
|
|
155
|
+
return ["hr"];
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
export const DocumentPageBreak = Node.create({
|
|
159
|
+
name: "pageBreak",
|
|
160
|
+
group: "block",
|
|
161
|
+
atom: true,
|
|
162
|
+
parseHTML() {
|
|
163
|
+
return [{ tag: "div[data-page-break]" }];
|
|
164
|
+
},
|
|
165
|
+
renderHTML() {
|
|
166
|
+
return ["div", { "data-page-break": "" }];
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
// A repeat row is a table row carrying `each`: prosemirror-tables requires
|
|
170
|
+
// the tableRow node type, so a separate node type is not an option.
|
|
171
|
+
export const DocumentTableRow = TableRow.extend({
|
|
172
|
+
addAttributes() {
|
|
173
|
+
return {
|
|
174
|
+
each: {
|
|
175
|
+
default: null,
|
|
176
|
+
parseHTML: (element) => {
|
|
177
|
+
const each = element.getAttribute("data-each");
|
|
178
|
+
return each !== null && isDocumentReferenceName(each) ? each : null;
|
|
179
|
+
},
|
|
180
|
+
renderHTML: (attributes) => {
|
|
181
|
+
const each = attributes["each"];
|
|
182
|
+
return typeof each === "string" && each ? { "data-each": each } : {};
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
repeatHeader: {
|
|
186
|
+
default: false,
|
|
187
|
+
parseHTML: (element) => element.hasAttribute("data-repeat-header"),
|
|
188
|
+
renderHTML: (attributes) => attributes["repeatHeader"] ? { "data-repeat-header": "" } : {},
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
export const DocumentTable = Table.extend({
|
|
194
|
+
renderHTML() {
|
|
195
|
+
return ["table", ["tbody", 0]];
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
// Span attributes are rendered only when they differ from the default, and
|
|
199
|
+
// colwidth (an editor-resize artefact) never, so `<td><p>x</p></td>` is the
|
|
200
|
+
// canonical cell.
|
|
201
|
+
function plainObjectOrEmpty(value) {
|
|
202
|
+
return isPlainObject(value) ? value : {};
|
|
203
|
+
}
|
|
204
|
+
function canonicalCellAttributes(attributes) {
|
|
205
|
+
return {
|
|
206
|
+
...attributes,
|
|
207
|
+
colspan: {
|
|
208
|
+
...plainObjectOrEmpty(attributes["colspan"]),
|
|
209
|
+
renderHTML: (attrs) => attrs["colspan"] && attrs["colspan"] !== 1 ? { colspan: attrs["colspan"] } : {},
|
|
210
|
+
},
|
|
211
|
+
rowspan: {
|
|
212
|
+
...plainObjectOrEmpty(attributes["rowspan"]),
|
|
213
|
+
renderHTML: (attrs) => attrs["rowspan"] && attrs["rowspan"] !== 1 ? { rowspan: attrs["rowspan"] } : {},
|
|
214
|
+
},
|
|
215
|
+
colwidth: {
|
|
216
|
+
...plainObjectOrEmpty(attributes["colwidth"]),
|
|
217
|
+
renderHTML: () => ({}),
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
export const DocumentTableCell = TableCell.extend({
|
|
222
|
+
addAttributes() {
|
|
223
|
+
return canonicalCellAttributes(this.parent?.() ?? {});
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
export const DocumentTableHeader = TableHeader.extend({
|
|
227
|
+
addAttributes() {
|
|
228
|
+
return canonicalCellAttributes(this.parent?.() ?? {});
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
// Only href survives a parse: target, rel, class and title from the input would
|
|
232
|
+
// otherwise be kept verbatim, and the renderer decides those itself.
|
|
233
|
+
export const DocumentLink = Link.extend({
|
|
234
|
+
addAttributes() {
|
|
235
|
+
return { href: { default: null, parseHTML: (element) => element.getAttribute("href") } };
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
export const DOCUMENT_TEXT_ALIGNMENTS = ["left", "center", "right", "justify"];
|
|
239
|
+
// Serialized as data-align, never as a style attribute: the sanitizer keeps
|
|
240
|
+
// styles out of the model, and each renderer maps the value to its own CSS.
|
|
241
|
+
export const DocumentTextAlign = Extension.create({
|
|
242
|
+
name: "documentTextAlign",
|
|
243
|
+
addGlobalAttributes() {
|
|
244
|
+
return [
|
|
245
|
+
{
|
|
246
|
+
types: ["paragraph", "heading"],
|
|
247
|
+
attributes: {
|
|
248
|
+
textAlign: {
|
|
249
|
+
default: null,
|
|
250
|
+
parseHTML: (element) => {
|
|
251
|
+
const align = element.getAttribute("data-align");
|
|
252
|
+
return isOneOf(DOCUMENT_TEXT_ALIGNMENTS, align) ? align : null;
|
|
253
|
+
},
|
|
254
|
+
renderHTML: (attributes) => {
|
|
255
|
+
const align = attributes["textAlign"];
|
|
256
|
+
return isOneOf(DOCUMENT_TEXT_ALIGNMENTS, align) ? { "data-align": align } : {};
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
];
|
|
262
|
+
},
|
|
263
|
+
});
|
|
264
|
+
// Only "small" exists: the sender line above an address block. Serialized as data-size for the
|
|
265
|
+
// same reason as data-align.
|
|
266
|
+
export const DocumentTextSize = Extension.create({
|
|
267
|
+
name: "documentTextSize",
|
|
268
|
+
addGlobalAttributes() {
|
|
269
|
+
return [
|
|
270
|
+
{
|
|
271
|
+
types: ["paragraph"],
|
|
272
|
+
attributes: {
|
|
273
|
+
textSize: {
|
|
274
|
+
default: null,
|
|
275
|
+
parseHTML: (element) => element.getAttribute("data-size") === "small" ? "small" : null,
|
|
276
|
+
renderHTML: (attributes) => attributes["textSize"] === "small" ? { "data-size": "small" } : {},
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
];
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
export const documentExtensions = [
|
|
284
|
+
StarterKit.configure({
|
|
285
|
+
blockquote: false,
|
|
286
|
+
code: false,
|
|
287
|
+
codeBlock: false,
|
|
288
|
+
strike: false,
|
|
289
|
+
horizontalRule: false,
|
|
290
|
+
dropcursor: false,
|
|
291
|
+
gapcursor: false,
|
|
292
|
+
undoRedo: false,
|
|
293
|
+
trailingNode: false,
|
|
294
|
+
listKeymap: false,
|
|
295
|
+
heading: { levels: [1, 2, 3] },
|
|
296
|
+
link: false,
|
|
297
|
+
}),
|
|
298
|
+
DocumentLink.configure({
|
|
299
|
+
openOnClick: false,
|
|
300
|
+
autolink: false,
|
|
301
|
+
linkOnPaste: false,
|
|
302
|
+
HTMLAttributes: { target: null, rel: null, class: null },
|
|
303
|
+
isAllowedUri: (url) => isAllowedDocumentLinkHref(url),
|
|
304
|
+
}),
|
|
305
|
+
DocumentTable,
|
|
306
|
+
DocumentTableRow,
|
|
307
|
+
DocumentTableHeader,
|
|
308
|
+
DocumentTableCell,
|
|
309
|
+
DocumentVariable,
|
|
310
|
+
DocumentResource,
|
|
311
|
+
DocumentButton,
|
|
312
|
+
DocumentDivider,
|
|
313
|
+
DocumentPageBreak,
|
|
314
|
+
DocumentTextAlign,
|
|
315
|
+
DocumentTextSize,
|
|
316
|
+
];
|