@cosmicdrift/kumiko-samples 0.388.0 → 0.390.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/packages/bundled-features/package.json +25 -13
- package/packages/bundled-features/src/agent-tools/changes.json +6 -0
- package/packages/bundled-features/src/agent-tools/index.ts +1 -1
- package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +42 -26
- package/packages/bundled-features/src/audit/feature.ts +2 -1
- package/packages/bundled-features/src/auth-email-password/auth-user-row.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/bootstrap.ts +13 -1
- package/packages/bundled-features/src/auth-email-password/changes.json +18 -0
- package/packages/bundled-features/src/auth-email-password/feature.ts +2 -2
- package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +7 -7
- package/packages/bundled-features/src/auth-email-password/handlers/confirm-account-unlock.write.ts +3 -3
- package/packages/bundled-features/src/auth-email-password/handlers/confirm-token-flow.ts +5 -5
- package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +9 -7
- package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +11 -7
- package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +4 -4
- package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +2 -2
- package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +9 -7
- package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +23 -16
- package/packages/bundled-features/src/auth-email-password/handlers/request-account-unlock.write.ts +1 -0
- package/packages/bundled-features/src/auth-email-password/handlers/request-email-verification.write.ts +1 -0
- package/packages/bundled-features/src/auth-email-password/handlers/request-password-reset.write.ts +1 -0
- package/packages/bundled-features/src/auth-email-password/handlers/reset-password.write.ts +3 -2
- package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +12 -12
- package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +16 -8
- package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +4 -2
- package/packages/bundled-features/src/auth-email-password/handlers/token-request-handler.ts +10 -2
- package/packages/bundled-features/src/auth-email-password/handlers/verify-email.write.ts +3 -2
- package/packages/bundled-features/src/auth-email-password/magic-link-mail.ts +16 -3
- package/packages/bundled-features/src/auth-email-password/seeding.ts +14 -9
- package/packages/bundled-features/src/auth-email-password/signup-activation.ts +2 -0
- package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +8 -2
- package/packages/bundled-features/src/auth-email-password/web/auth-redirect.ts +23 -21
- package/packages/bundled-features/src/auth-email-password/web/default-auth-pages-gate.tsx +6 -3
- package/packages/bundled-features/src/auth-email-password/web/forgot-password-screen.tsx +11 -1
- package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -0
- package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +16 -5
- package/packages/bundled-features/src/auth-email-password/web/reset-password-screen.tsx +7 -1
- package/packages/bundled-features/src/auth-email-password/web/return-path.ts +35 -0
- package/packages/bundled-features/src/auth-email-password/web/session.tsx +6 -1
- package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +11 -3
- package/packages/bundled-features/src/auth-email-password/web/signup-screen.tsx +12 -2
- package/packages/bundled-features/src/auth-foundation/feature.ts +13 -4
- package/packages/bundled-features/src/auth-mfa/changes.json +6 -0
- package/packages/bundled-features/src/auth-mfa/config.ts +3 -7
- package/packages/bundled-features/src/auth-mfa/handlers/disable.write.ts +5 -5
- package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +24 -14
- package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm.write.ts +9 -3
- package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +6 -1
- package/packages/bundled-features/src/auth-mfa/handlers/enable-start.write.ts +3 -1
- package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +14 -9
- package/packages/bundled-features/src/auth-mfa/handlers/regenerate-recovery.write.ts +5 -4
- package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +25 -14
- package/packages/bundled-features/src/auth-mfa/mfa-code-verifier.ts +10 -4
- package/packages/bundled-features/src/auth-mfa/mfa-status-checker.ts +17 -8
- package/packages/bundled-features/src/auth-mfa/verify-factor.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/billing-info-query.ts +2 -2
- package/packages/bundled-features/src/billing-foundation/changes.json +6 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/consent-gate.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +5 -5
- package/packages/bundled-features/src/billing-foundation/consumer-protection/register-consent.ts +10 -7
- package/packages/bundled-features/src/billing-foundation/consumer-protection/register-termination.ts +15 -12
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-open-cancels.ts +22 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-provider-lock.ts +4 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-receipt-limit.ts +4 -4
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-record.ts +17 -58
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +10 -8
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-revoke.ts +18 -15
- package/packages/bundled-features/src/billing-foundation/events.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/feature.ts +8 -3
- package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +5 -5
- package/packages/bundled-features/src/billing-foundation/handlers/process-payment-event.write.ts +3 -3
- package/packages/bundled-features/src/billing-foundation/plan-catalog.ts +2 -2
- package/packages/bundled-features/src/billing-foundation/projection.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/types.ts +1 -1
- package/packages/bundled-features/src/cap-counter/aggregate-id.ts +1 -1
- package/packages/bundled-features/src/cap-counter/book-cap-usage.ts +5 -4
- package/packages/bundled-features/src/cap-counter/cap-reservation.ts +21 -8
- package/packages/bundled-features/src/cap-counter/changes.json +12 -0
- package/packages/bundled-features/src/cap-counter/constants.ts +1 -1
- package/packages/bundled-features/src/cap-counter/feature.ts +3 -2
- package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +1 -1
- package/packages/bundled-features/src/cap-counter/reservation-chain.ts +1 -1
- package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +4 -4
- package/packages/bundled-features/src/cap-overview/feature.ts +1 -0
- package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -1
- package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
- package/packages/bundled-features/src/compliance-profiles/seeding.ts +12 -7
- package/packages/bundled-features/src/config/changes.json +6 -0
- package/packages/bundled-features/src/config/feature.ts +6 -6
- package/packages/bundled-features/src/config/handlers/cascade.query.ts +1 -1
- package/packages/bundled-features/src/config/handlers/readiness.query.ts +1 -1
- package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +23 -13
- package/packages/bundled-features/src/config/handlers/reset.write.ts +3 -3
- package/packages/bundled-features/src/config/handlers/selected-extensions.query.ts +1 -1
- package/packages/bundled-features/src/config/handlers/set.write.ts +22 -5
- package/packages/bundled-features/src/config/handlers/values.query.ts +1 -1
- package/packages/bundled-features/src/crypto-shredding/changes.json +12 -0
- package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +9 -9
- package/packages/bundled-features/src/crypto-shredding/resolve-file-bytes-deleter.ts +3 -3
- package/packages/bundled-features/src/custom-fields/changes.json +6 -0
- package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/index.ts +4 -0
- package/packages/bundled-features/src/custom-fields/lib/parse-serialized-field.ts +1 -1
- package/packages/bundled-features/src/data-retention/feature.ts +1 -1
- package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +12 -2
- package/packages/bundled-features/src/delivery/attempt-log.ts +1 -1
- package/packages/bundled-features/src/delivery/changes.json +12 -0
- package/packages/bundled-features/src/delivery/delivery-service.ts +6 -5
- package/packages/bundled-features/src/delivery/feature.ts +3 -2
- package/packages/bundled-features/src/delivery/index.ts +5 -0
- package/packages/bundled-features/src/delivery/jobs.ts +11 -11
- package/packages/bundled-features/src/delivery/system-channel-context.ts +33 -0
- package/packages/bundled-features/src/delivery/testing.ts +1 -1
- package/packages/bundled-features/src/document-ingest-foundation/append-missing-extract-event.ts +84 -0
- package/packages/bundled-features/src/document-ingest-foundation/changes.json +6 -0
- package/packages/bundled-features/src/document-ingest-foundation/events.ts +16 -1
- package/packages/bundled-features/src/document-ingest-foundation/index.ts +11 -0
- package/packages/bundled-features/src/feature-toggles/feature.ts +1 -0
- package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/handlers/set.write.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +1 -1
- package/packages/bundled-features/src/file-derivatives/feature.ts +2 -2
- package/packages/bundled-features/src/file-derivatives/handlers/public-variant-by-file-ref.query.ts +5 -1
- package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +7 -5
- package/packages/bundled-features/src/file-foundation/feature.ts +1 -1
- package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +7 -5
- package/packages/bundled-features/src/file-provider-s3/feature.ts +4 -1
- package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +8 -8
- package/packages/bundled-features/src/form-draft/feature.ts +1 -1
- package/packages/bundled-features/src/form-draft/handlers/cleanup.job.ts +22 -12
- package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +3 -3
- package/packages/bundled-features/src/form-draft/handlers/get.query.ts +1 -1
- package/packages/bundled-features/src/foundation-shared/config-helpers.ts +1 -1
- package/packages/bundled-features/src/host-routing/changes.json +6 -0
- package/packages/bundled-features/src/host-routing/validate-options.ts +5 -0
- package/packages/bundled-features/src/inbound-mail-foundation/events.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +2 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/account-state.ts +2 -2
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +10 -10
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/update-account.write.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +1 -1
- package/packages/bundled-features/src/inbound-provider-imap/feature.ts +4 -1
- package/packages/bundled-features/src/jobs/changes.json +6 -0
- package/packages/bundled-features/src/jobs/events.ts +1 -1
- package/packages/bundled-features/src/jobs/feature.ts +1 -0
- package/packages/bundled-features/src/jobs/handlers/consumer.write.ts +7 -4
- package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +11 -5
- package/packages/bundled-features/src/jobs/handlers/retention-cleanup.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/stale-run-sweep.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/trigger.write.ts +2 -2
- package/packages/bundled-features/src/jobs/job-run-logger.ts +139 -90
- package/packages/bundled-features/src/ledger/web/index.ts +1 -1
- package/packages/bundled-features/src/legal-pages/README.md +1 -1
- package/packages/bundled-features/src/legal-pages/lib/boot-check.ts +12 -8
- package/packages/bundled-features/src/legal-pages/seed.ts +5 -2
- package/packages/bundled-features/src/mail-foundation/feature.ts +2 -2
- package/packages/bundled-features/src/mail-transport-smtp/changes.json +12 -0
- package/packages/bundled-features/src/mail-transport-smtp/config-keys.ts +1 -1
- package/packages/bundled-features/src/mail-transport-smtp/feature.ts +13 -12
- package/packages/bundled-features/src/managed-pages/changes.json +6 -0
- package/packages/bundled-features/src/managed-pages/constants.ts +1 -0
- package/packages/bundled-features/src/managed-pages/feature.ts +3 -1
- package/packages/bundled-features/src/managed-pages/index.ts +1 -0
- package/packages/bundled-features/src/managed-pages/seeding.ts +13 -8
- package/packages/bundled-features/src/notes-history/handlers/add-note.write.ts +2 -2
- package/packages/bundled-features/src/personal-access-tokens/feature.ts +2 -1
- package/packages/bundled-features/src/personal-access-tokens/handlers/create.write.ts +2 -2
- package/packages/bundled-features/src/personal-access-tokens/handlers/revoke.write.ts +1 -1
- package/packages/bundled-features/src/rate-limiting/handlers/status.query.ts +2 -2
- package/packages/bundled-features/src/readiness/handlers/status.query.ts +4 -1
- package/packages/bundled-features/src/renderer-foundation/api.ts +3 -3
- package/packages/bundled-features/src/secrets/announce-secret-change.ts +4 -4
- package/packages/bundled-features/src/secrets/changes.json +6 -0
- package/packages/bundled-features/src/secrets/feature.ts +9 -9
- package/packages/bundled-features/src/secrets/handlers/delete.write.ts +4 -3
- package/packages/bundled-features/src/secrets/handlers/rotate.job.ts +13 -8
- package/packages/bundled-features/src/secrets/handlers/set.write.ts +4 -3
- package/packages/bundled-features/src/secrets/secrets-context.ts +16 -6
- package/packages/bundled-features/src/secrets/write-gate.ts +10 -3
- package/packages/bundled-features/src/seo/feature.ts +1 -1
- package/packages/bundled-features/src/sessions/changes.json +19 -0
- package/packages/bundled-features/src/sessions/feature.ts +2 -1
- package/packages/bundled-features/src/sessions/handlers/cleanup.job.ts +2 -2
- package/packages/bundled-features/src/sessions/handlers/detail.query.ts +5 -2
- package/packages/bundled-features/src/sessions/handlers/list.query.ts +5 -2
- package/packages/bundled-features/src/sessions/handlers/mine.query.ts +5 -2
- package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +3 -3
- package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +1 -1
- package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
- package/packages/bundled-features/src/sessions/index.ts +1 -1
- package/packages/bundled-features/src/sessions/screens.ts +8 -4
- package/packages/bundled-features/src/sessions/session-callbacks.ts +1 -9
- package/packages/bundled-features/src/sessions/session-revoked-event.ts +1 -1
- package/packages/bundled-features/src/sessions/web/session-device-cell.tsx +10 -12
- package/packages/bundled-features/src/sessions/web/user-agent.ts +12 -0
- package/packages/bundled-features/src/shared/index.ts +15 -0
- package/packages/bundled-features/src/shared/purge-files-reaching-subject.ts +36 -4
- package/packages/bundled-features/src/shared/require-for-tenant.ts +7 -5
- package/packages/bundled-features/src/shared/run-in-sub-transaction.ts +5 -5
- package/packages/bundled-features/src/shared/stream-tenant-backfill.ts +201 -0
- package/packages/bundled-features/src/shared/stream-tenant-derived-state.ts +107 -0
- package/packages/bundled-features/src/step-dispatcher/changes.json +6 -0
- package/packages/bundled-features/src/step-dispatcher/deliver-dispatch-request.ts +17 -3
- package/packages/bundled-features/src/step-dispatcher/feature.ts +1 -1
- package/packages/bundled-features/src/step-dispatcher/mail-runner.ts +2 -1
- package/packages/bundled-features/src/subscription-dodo/plugin-methods.ts +1 -1
- package/packages/bundled-features/src/subscription-dodo/runtime.ts +7 -7
- package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +5 -3
- package/packages/bundled-features/src/subscription-stripe/runtime.ts +7 -7
- package/packages/bundled-features/src/tags/feature.ts +1 -0
- package/packages/bundled-features/src/template-resolver/api.ts +3 -3
- package/packages/bundled-features/src/template-resolver/changes.json +54 -0
- package/packages/bundled-features/src/template-resolver/document-ops.ts +20 -1
- package/packages/bundled-features/src/template-resolver/feature.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +5 -4
- package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +1 -1
- package/packages/bundled-features/src/template-resolver/handlers/layout-source.query.ts +36 -11
- package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +32 -7
- package/packages/bundled-features/src/template-resolver/handlers/patch-draft.write.ts +1 -1
- package/packages/bundled-features/src/template-resolver/handlers/send-test-shared.ts +1 -1
- package/packages/bundled-features/src/template-resolver/handlers/send-test-status.query.ts +22 -19
- package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/tenant-override-selection.ts +6 -2
- package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +4 -2
- package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +1 -1
- package/packages/bundled-features/src/template-resolver/seeding.ts +22 -5
- package/packages/bundled-features/src/template-resolver/store-template-resource.ts +68 -19
- package/packages/bundled-features/src/template-resolver/template-resources.ts +4 -4
- package/packages/bundled-features/src/template-resolver/testing.ts +2 -2
- package/packages/bundled-features/src/template-resolver/web/document-insert-fields.tsx +222 -0
- package/packages/bundled-features/src/template-resolver/web/document-insert-model.ts +164 -0
- package/packages/bundled-features/src/template-resolver/web/document-insert-panel.tsx +115 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-bubble.tsx +177 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-content.tsx +38 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-context.ts +119 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-editor.tsx +51 -1098
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-helpers.ts +161 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-layout.tsx +83 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar-groups.tsx +153 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar.tsx +182 -0
- package/packages/bundled-features/src/template-resolver/web/editor-handle.ts +18 -0
- package/packages/bundled-features/src/template-resolver/web/i18n.ts +6 -0
- package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor.tsx +19 -6
- package/packages/bundled-features/src/template-resolver/web/qualified-names.ts +1 -0
- package/packages/bundled-features/src/template-resolver/web/use-document-tiptap-model.ts +138 -0
- package/packages/bundled-features/src/tenant/changes.json +19 -0
- package/packages/bundled-features/src/tenant/feature.ts +1 -0
- package/packages/bundled-features/src/tenant/handlers/cancel-invitation.write.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/remove-member.write.ts +2 -2
- package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +3 -3
- package/packages/bundled-features/src/tenant/handlers/update-member-roles.write.ts +1 -1
- package/packages/bundled-features/src/tenant/index.ts +5 -0
- package/packages/bundled-features/src/tenant/invited-membership.ts +6 -1
- package/packages/bundled-features/src/tenant/schema/tenant.ts +4 -1
- package/packages/bundled-features/src/tenant/seeding.ts +65 -62
- package/packages/bundled-features/src/tenant/stream-tenant-backfill.ts +115 -0
- package/packages/bundled-features/src/tenant/testing.ts +77 -0
- package/packages/bundled-features/src/tenant-handover/events.ts +1 -1
- package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
- package/packages/bundled-features/src/tenant-lifecycle/changes.json +6 -0
- package/packages/bundled-features/src/tenant-lifecycle/feature.ts +5 -5
- package/packages/bundled-features/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +22 -10
- package/packages/bundled-features/src/tenant-lifecycle/handlers/request-destruction.write.ts +22 -11
- package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +23 -12
- package/packages/bundled-features/src/tenant-lifecycle/stages.ts +42 -4
- package/packages/bundled-features/src/tenant-lifecycle/testing.ts +9 -8
- package/packages/bundled-features/src/tier-engine/entity.ts +1 -1
- package/packages/bundled-features/src/tier-engine/feature.ts +8 -3
- package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +3 -3
- package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +7 -1
- package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +3 -3
- package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +71 -97
- package/packages/bundled-features/src/user/feature.ts +1 -0
- package/packages/bundled-features/src/user/handlers/find-for-auth.query.ts +2 -2
- package/packages/bundled-features/src/user/handlers/update-roles.ts +2 -2
- package/packages/bundled-features/src/user/index.ts +2 -0
- package/packages/bundled-features/src/user/invited-global-roles.ts +6 -1
- package/packages/bundled-features/src/user/principal-status.ts +1 -1
- package/packages/bundled-features/src/user/seeding.ts +24 -6
- package/packages/bundled-features/src/user/testing.ts +22 -0
- package/packages/bundled-features/src/user-data-rights/COMPLIANCE.md +1 -1
- package/packages/bundled-features/src/user-data-rights/README.md +1 -1
- package/packages/bundled-features/src/user-data-rights/audit-download.ts +12 -2
- package/packages/bundled-features/src/user-data-rights/changes.json +36 -0
- package/packages/bundled-features/src/user-data-rights/feature.ts +30 -24
- package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/handlers/deletion-grace-period.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +4 -4
- package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +12 -6
- package/packages/bundled-features/src/user-data-rights/index.ts +8 -1
- package/packages/bundled-features/src/user-data-rights/lib/mail-transport-resolver.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/lib/storage-provider-resolver.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +6 -1
- package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +8 -2
- package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +14 -3
- package/packages/bundled-features/src/user-data-rights/run-user-export.ts +11 -1
- package/packages/bundled-features/src/user-data-rights/web/constants.ts +16 -0
- package/packages/bundled-features/src/user-data-rights/web/index.ts +6 -0
- package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +8 -6
- package/packages/bundled-features/src/waitlist/changes.json +18 -0
- package/packages/bundled-features/src/waitlist/feature.ts +1 -0
- package/packages/bundled-features/src/waitlist/handlers/export-purge.write.ts +1 -1
- package/packages/bundled-features/src/waitlist/handlers/invite.write.ts +2 -2
- package/packages/bundled-features/src/waitlist/handlers/reject.write.ts +1 -1
- package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +34 -10
- package/packages/bundled-features/src/waitlist/import.ts +23 -3
- package/packages/bundled-features/src/waitlist/legacy-migrate.ts +8 -2
- package/packages/bundled-features/src/waitlist/link-on-signup.ts +7 -1
- package/packages/bundled-features/src/waitlist/options.ts +2 -1
- package/packages/bundled-features/src/workflow-runner/changes.json +6 -0
- package/packages/bundled-features/src/workflow-runner/db/queries/due-runs.ts +1 -1
- package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -3
- package/packages/bundled-features/src/workflow-runner/event-trigger.ts +2 -1
- package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
- package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +8 -8
- package/packages/bundled-features/src/workflow-runner/runner.ts +6 -4
- package/samples/apps/cap-billing-demo/src/feature.ts +19 -5
- package/samples/apps/config-demo/src/app/server.ts +1 -1
- package/samples/apps/styleguide/src/app/client.tsx +2 -0
- package/samples/apps/styleguide/src/app/seed.ts +6 -4
- package/samples/apps/styleguide/src/app/server.ts +6 -3
- package/samples/apps/styleguide/src/features/widgets/feature.ts +15 -4
- package/samples/apps/styleguide/src/features/workboard/feature.ts +185 -0
- package/samples/apps/styleguide/src/features/workboard/i18n.ts +27 -0
- package/samples/apps/styleguide/src/features/workboard/seed.ts +121 -0
- package/samples/apps/styleguide/src/features/workboard/web.ts +13 -0
- package/samples/apps/ui-walkthrough/src/features/rental/i18n.ts +2 -0
- package/samples/apps/ui-walkthrough/src/features/rental/screens.ts +9 -0
- package/samples/apps/use-all-bundled/bin/main.ts +2 -0
- package/samples/apps/use-all-bundled/feature-manifest.json +17 -1
- package/samples/apps/use-all-bundled/kumiko/schema.ts +2 -0
- package/samples/apps/use-all-bundled/kumiko.config.ts +2 -0
- package/samples/apps/use-all-bundled/package.json +2 -1
- package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +2 -0
- package/samples/apps/use-all-bundled/src/app/notes-feature.ts +2 -0
- package/samples/apps/use-all-bundled/src/app/seed.ts +12 -2
- package/samples/apps/use-all-bundled/src/bundled-lists.ts +15 -0
- package/samples/apps/user-data-rights-demo/README.md +1 -1
- package/samples/apps/user-data-rights-demo/src/feature.ts +3 -2
- package/samples/recipes/api-worker-split/README.md +2 -1
- package/samples/recipes/api-worker-split/src/feature.ts +2 -1
- package/samples/recipes/cross-feature-events/README.md +5 -5
- package/samples/recipes/cross-feature-events/package.json +1 -1
- package/samples/recipes/cross-feature-events/src/feature.ts +4 -4
- package/samples/recipes/event-sourcing/README.md +5 -5
- package/samples/recipes/event-sourcing/package.json +1 -1
- package/samples/recipes/event-sourcing/src/feature.ts +15 -15
- package/samples/recipes/files-post-processing/README.md +1 -1
- package/samples/recipes/files-post-processing/package.json +1 -1
- package/samples/recipes/files-post-processing/src/feature.ts +6 -4
- package/samples/recipes/golden-path/src/feature.ts +2 -1
- package/samples/recipes/lane-routing/package.json +1 -1
- package/samples/recipes/legal-pages/README.md +2 -2
- package/samples/recipes/lifecycle-hooks/README.md +4 -0
- package/samples/recipes/lifecycle-hooks/src/feature.ts +26 -1
- package/samples/recipes/list-table-options/README.md +50 -0
- package/samples/recipes/list-table-options/package.json +11 -0
- package/samples/recipes/list-table-options/src/feature.ts +221 -0
- package/samples/recipes/managed-config/README.md +3 -3
- package/samples/recipes/pdf-audit-export/src/feature.ts +2 -1
- package/samples/recipes/search/README.md +1 -1
- package/samples/recipes/search/src/feature.ts +3 -3
- package/samples/recipes/secrets-demo/README.md +1 -1
- package/samples/recipes/secrets-demo/src/feature.ts +5 -2
- package/samples/recipes/state-machine/src/events.ts +4 -3
- package/samples/recipes/state-machine/src/reducer.ts +1 -1
- package/samples/recipes/tenant-isolation/README.md +1 -0
- package/samples/recipes/tenant-isolation/src/feature.ts +36 -0
- package/samples/recipes/workflow-engine/src/resume-loop.ts +4 -4
- package/samples/recipes/workflow-engine/src/workflow-runner.ts +2 -2
|
@@ -107,7 +107,12 @@ export async function seedSystemTemplate(
|
|
|
107
107
|
): Promise<{ id: string }> {
|
|
108
108
|
const tenantId = SYSTEM_TENANT_ID;
|
|
109
109
|
const by = opts.by ?? createSystemUser(tenantId);
|
|
110
|
-
const tdb = createTenantDb({
|
|
110
|
+
const tdb = createTenantDb({
|
|
111
|
+
db,
|
|
112
|
+
tenantId,
|
|
113
|
+
mode: "system",
|
|
114
|
+
reason: "system templates live in the system tenant",
|
|
115
|
+
});
|
|
111
116
|
|
|
112
117
|
const label = `seedSystemTemplate ${opts.slug}/${opts.kind}/${opts.locale}`;
|
|
113
118
|
const slug = templateSlugSchema.safeParse(opts.slug);
|
|
@@ -408,7 +413,12 @@ export async function seedTextBlock(
|
|
|
408
413
|
opts: SeedTextBlockOptions,
|
|
409
414
|
): Promise<{ id: string }> {
|
|
410
415
|
const by = opts.by ?? createSystemUser(opts.tenantId);
|
|
411
|
-
const tdb = createTenantDb({
|
|
416
|
+
const tdb = createTenantDb({
|
|
417
|
+
db,
|
|
418
|
+
tenantId: opts.tenantId,
|
|
419
|
+
mode: "system",
|
|
420
|
+
reason: "seeding writes text blocks into an explicitly named tenant",
|
|
421
|
+
});
|
|
412
422
|
|
|
413
423
|
const existingRow = await fetchOne<TemplateResourceRow>(db, templateResourcesTable, {
|
|
414
424
|
tenantId: opts.tenantId,
|
|
@@ -442,12 +452,14 @@ export async function seedTextBlock(
|
|
|
442
452
|
row: { id: string; version: number },
|
|
443
453
|
current: TemplateResourceRow | null | undefined,
|
|
444
454
|
): Promise<{ id: string }> => {
|
|
455
|
+
// No folder option keeps the row's folder, so a re-seed cannot drop it from the content tree.
|
|
456
|
+
const folder = opts.folder === undefined ? (current?.folder ?? null) : fields.folder;
|
|
445
457
|
// Skip no-op updates so a legal re-seed on every pod boot does not bump
|
|
446
458
|
// version/modifiedAt (ETag, "last changed", event-store growth).
|
|
447
459
|
if (
|
|
448
460
|
current?.title === fields.title &&
|
|
449
461
|
current?.content === fields.content &&
|
|
450
|
-
current?.folder ===
|
|
462
|
+
current?.folder === folder
|
|
451
463
|
) {
|
|
452
464
|
return { id: String(row.id) };
|
|
453
465
|
}
|
|
@@ -458,7 +470,7 @@ export async function seedTextBlock(
|
|
|
458
470
|
changes: {
|
|
459
471
|
title: fields.title,
|
|
460
472
|
content: fields.content,
|
|
461
|
-
folder
|
|
473
|
+
folder,
|
|
462
474
|
// A re-seed must not revive an archived block; only a served one gets a new served version.
|
|
463
475
|
...(current?.status === "active" && servedStampChanges(row)),
|
|
464
476
|
},
|
|
@@ -533,7 +545,11 @@ export type LegalContentBlock = {
|
|
|
533
545
|
export async function seedLegalContentFromJson(
|
|
534
546
|
db: DbConnection,
|
|
535
547
|
blocks: readonly LegalContentBlock[],
|
|
536
|
-
opts: {
|
|
548
|
+
opts: {
|
|
549
|
+
readonly tenantId?: TenantId;
|
|
550
|
+
readonly by?: SessionUser;
|
|
551
|
+
readonly folder?: string;
|
|
552
|
+
} = {},
|
|
537
553
|
): Promise<void> {
|
|
538
554
|
const tenantId = opts.tenantId ?? SYSTEM_TENANT_ID;
|
|
539
555
|
const by = opts.by ?? createSystemUser(tenantId);
|
|
@@ -544,6 +560,7 @@ export async function seedLegalContentFromJson(
|
|
|
544
560
|
locale: block.locale,
|
|
545
561
|
title: block.title,
|
|
546
562
|
content: block.content,
|
|
563
|
+
...(opts.folder !== undefined && { folder: opts.folder }),
|
|
547
564
|
ifExists: "update",
|
|
548
565
|
by,
|
|
549
566
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { fetchOne, selectMany } from "@cosmicdrift/kumiko-framework/db";
|
|
2
2
|
import type {
|
|
3
|
+
BeforeTransactionContext,
|
|
3
4
|
BeforeTransactionResult,
|
|
4
5
|
ConfigAccessor,
|
|
5
6
|
HandlerContext,
|
|
@@ -19,7 +20,7 @@ import {
|
|
|
19
20
|
type UploadedFileBytes,
|
|
20
21
|
uploadFileBytesBeforeTransaction,
|
|
21
22
|
} from "@cosmicdrift/kumiko-framework/files";
|
|
22
|
-
import { fileContextForTenant } from "../file-foundation/index.ts";
|
|
23
|
+
import { fileContextForTenant, readFileRefContent } from "../file-foundation/index.ts";
|
|
23
24
|
import { extensionForResourceContentType, requireForTenant } from "../shared/index.ts";
|
|
24
25
|
import {
|
|
25
26
|
DEFAULT_RESOURCE_MAX_BYTES,
|
|
@@ -29,13 +30,13 @@ import {
|
|
|
29
30
|
import { executor } from "./handlers/shared.ts";
|
|
30
31
|
import {
|
|
31
32
|
attachmentEntriesOf,
|
|
33
|
+
isFileAttachmentEntry,
|
|
32
34
|
type LinkedResourceEntry,
|
|
33
35
|
parseLinkedResourceEntries,
|
|
34
36
|
templatePdfAttachmentLinkSchema,
|
|
35
37
|
} from "./linked-resources.ts";
|
|
36
38
|
import { normalizeResourceImage } from "./resource-image.ts";
|
|
37
39
|
import { type TemplateResourceRow, templateResourcesTable } from "./table.ts";
|
|
38
|
-
import { readTemplateResource } from "./template-resources.ts";
|
|
39
40
|
import { ACTIVE_TEMPLATE_STATUS, SYSTEM_TENANT_ID } from "./web/constants.ts";
|
|
40
41
|
import { TemplateResolverErrors } from "./web/qualified-names.ts";
|
|
41
42
|
|
|
@@ -100,7 +101,7 @@ function isAttachmentKey(links: Readonly<Record<string, LinkedResourceEntry>>, k
|
|
|
100
101
|
// so both receive the target tenant's db and identity.
|
|
101
102
|
function uploadToTenant(
|
|
102
103
|
args: {
|
|
103
|
-
readonly ctx:
|
|
104
|
+
readonly ctx: PrepareContext;
|
|
104
105
|
readonly user: SessionUser;
|
|
105
106
|
readonly tenantId: TenantId;
|
|
106
107
|
},
|
|
@@ -110,7 +111,7 @@ function uploadToTenant(
|
|
|
110
111
|
return uploadFileBytesBeforeTransaction(
|
|
111
112
|
{
|
|
112
113
|
db: requireForTenant(ctx, tenantId).db,
|
|
113
|
-
files: fileContextForTenant(ctx, ctx.user.tenantId, tenantId),
|
|
114
|
+
services: { files: fileContextForTenant(ctx, ctx.user.tenantId, tenantId) },
|
|
114
115
|
registry: ctx.registry,
|
|
115
116
|
user: { ...user, tenantId },
|
|
116
117
|
},
|
|
@@ -119,7 +120,7 @@ function uploadToTenant(
|
|
|
119
120
|
}
|
|
120
121
|
|
|
121
122
|
type TenantScope = {
|
|
122
|
-
readonly ctx:
|
|
123
|
+
readonly ctx: PrepareContext;
|
|
123
124
|
readonly user: SessionUser;
|
|
124
125
|
readonly tenantId: TenantId;
|
|
125
126
|
};
|
|
@@ -133,7 +134,7 @@ function createFileRefFromPrepared(scope: TenantScope, upload: UploadedFileBytes
|
|
|
133
134
|
}
|
|
134
135
|
|
|
135
136
|
async function linkImage(args: {
|
|
136
|
-
readonly ctx:
|
|
137
|
+
readonly ctx: PrepareContext;
|
|
137
138
|
readonly user: SessionUser;
|
|
138
139
|
readonly tenantId: TenantId;
|
|
139
140
|
readonly row: TemplateResourceRow;
|
|
@@ -197,7 +198,7 @@ type ImageTarget = {
|
|
|
197
198
|
|
|
198
199
|
// Runs before the upload (reject early, store nothing) and again in the transaction on the fresh row.
|
|
199
200
|
async function checkImageTarget(args: {
|
|
200
|
-
readonly ctx:
|
|
201
|
+
readonly ctx: PrepareContext;
|
|
201
202
|
readonly tenantId: TenantId;
|
|
202
203
|
readonly templateId?: string | undefined;
|
|
203
204
|
readonly key?: string | undefined;
|
|
@@ -220,7 +221,7 @@ async function checkImageTarget(args: {
|
|
|
220
221
|
// beforeTransaction half: normalizes the image and uploads it to the target tenant's storage.
|
|
221
222
|
// The caller is responsible for authorization; the function trusts tenantId.
|
|
222
223
|
export async function prepareTemplateResourceBeforeTransaction(args: {
|
|
223
|
-
readonly ctx:
|
|
224
|
+
readonly ctx: PrepareContext;
|
|
224
225
|
readonly user: SessionUser;
|
|
225
226
|
readonly tenantId: TenantId;
|
|
226
227
|
readonly bytes: Uint8Array;
|
|
@@ -260,6 +261,10 @@ export async function prepareTemplateResourceBeforeTransaction(args: {
|
|
|
260
261
|
};
|
|
261
262
|
}
|
|
262
263
|
|
|
264
|
+
// The prepare phase runs before the transaction, so it must not rely on anything the in-transaction
|
|
265
|
+
// context adds (events, dispatch.write).
|
|
266
|
+
export type PrepareContext = HandlerContext | BeforeTransactionContext;
|
|
267
|
+
|
|
263
268
|
export type Release = () => Promise<void>;
|
|
264
269
|
|
|
265
270
|
// Tries every release, so one failing delete does not strand the other uploads; the first rejection is rethrown.
|
|
@@ -271,13 +276,13 @@ export async function releaseAll(releases: readonly Release[]): Promise<void> {
|
|
|
271
276
|
|
|
272
277
|
// Failure paths: a failing release must not replace the upload error the caller needs to see.
|
|
273
278
|
export async function releaseAfterFailure(
|
|
274
|
-
ctx:
|
|
279
|
+
ctx: PrepareContext,
|
|
275
280
|
releases: readonly Release[],
|
|
276
281
|
): Promise<void> {
|
|
277
282
|
try {
|
|
278
283
|
await releaseAll(releases);
|
|
279
284
|
} catch (releaseError) {
|
|
280
|
-
ctx.log?.warn("template upload rollback: releasing stored files failed", {
|
|
285
|
+
ctx.obs.log?.warn("template upload rollback: releasing stored files failed", {
|
|
281
286
|
error: releaseError instanceof Error ? releaseError.message : String(releaseError),
|
|
282
287
|
});
|
|
283
288
|
}
|
|
@@ -290,12 +295,50 @@ export type PreparedLinkedResourceCopy = {
|
|
|
290
295
|
readonly upload?: UploadedFileBytes;
|
|
291
296
|
};
|
|
292
297
|
|
|
298
|
+
// The source row's own fileName is personal data and may be ciphertext, so the copy is named from
|
|
299
|
+
// the link entry or the key.
|
|
300
|
+
function copiedFileName(key: string, entry: LinkedResourceEntry, contentType: string): string {
|
|
301
|
+
if (typeof entry !== "string" && isFileAttachmentEntry(entry)) return entry.fileName;
|
|
302
|
+
return `${key}.${extensionForResourceContentType(contentType) ?? "bin"}`;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function sourceUnreadable(): WriteResult<never> {
|
|
306
|
+
return writeFailure(
|
|
307
|
+
new UnprocessableError(TemplateResolverErrors.resourceSourceUnreadable, {
|
|
308
|
+
i18nKey: "templateResolver.errors.resource.sourceUnreadable",
|
|
309
|
+
}),
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Undefined: the fileRef row exists but its bytes cannot be read, which must not look like a
|
|
314
|
+
// deleted file. The provider is chosen by the tenant of the fileRef, not by the caller's.
|
|
315
|
+
async function readCopySource(
|
|
316
|
+
ctx: PrepareContext,
|
|
317
|
+
fileRefId: string,
|
|
318
|
+
): Promise<{ contentType: string; bytes: Uint8Array } | null | undefined> {
|
|
319
|
+
try {
|
|
320
|
+
const found = await readFileRefContent({
|
|
321
|
+
db: ctx.db,
|
|
322
|
+
filesForTenant: (tid) => fileContextForTenant(ctx, ctx.user.tenantId, tid),
|
|
323
|
+
fileRefId,
|
|
324
|
+
allowedTenantIds: [SYSTEM_TENANT_ID, ctx.user.tenantId],
|
|
325
|
+
});
|
|
326
|
+
return found === null ? null : { contentType: found.contentType, bytes: found.content };
|
|
327
|
+
} catch (cause) {
|
|
328
|
+
ctx.obs.log?.warn("template copy: source file could not be read", {
|
|
329
|
+
fileRefId,
|
|
330
|
+
errorClass: cause instanceof Error ? cause.name : typeof cause,
|
|
331
|
+
});
|
|
332
|
+
return undefined;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
293
336
|
// beforeTransaction half: copies the file behind every entry into the target tenant's storage, so a
|
|
294
337
|
// template copied from the system default keeps working once the tenant exports it or measures its
|
|
295
338
|
// attachments. An entry whose source file is gone is left out: it could not be resolved at render
|
|
296
339
|
// time either. A failed or throwing upload releases the ones before it.
|
|
297
340
|
export async function prepareLinkedResourceCopiesBeforeTransaction(args: {
|
|
298
|
-
readonly ctx:
|
|
341
|
+
readonly ctx: PrepareContext;
|
|
299
342
|
readonly user: SessionUser;
|
|
300
343
|
readonly tenantId: TenantId;
|
|
301
344
|
readonly resources: Readonly<Record<string, LinkedResourceEntry>>;
|
|
@@ -309,14 +352,20 @@ export async function prepareLinkedResourceCopiesBeforeTransaction(args: {
|
|
|
309
352
|
copies.push({ key, entry });
|
|
310
353
|
continue;
|
|
311
354
|
}
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
355
|
+
const source = await readCopySource(ctx, typeof entry === "string" ? entry : entry.fileRefId);
|
|
356
|
+
if (source === undefined) {
|
|
357
|
+
await releaseAfterFailure(ctx, releases);
|
|
358
|
+
return sourceUnreadable();
|
|
359
|
+
}
|
|
360
|
+
// skip: the source fileRef is deleted or unknown, so there is nothing to copy
|
|
361
|
+
if (source === null) continue;
|
|
317
362
|
const uploaded = await uploadToTenant(
|
|
318
363
|
{ ctx, user, tenantId },
|
|
319
|
-
{
|
|
364
|
+
{
|
|
365
|
+
fileName: copiedFileName(key, entry, source.contentType),
|
|
366
|
+
mimeType: source.contentType,
|
|
367
|
+
data: source.bytes,
|
|
368
|
+
},
|
|
320
369
|
);
|
|
321
370
|
if (!uploaded.isSuccess) {
|
|
322
371
|
await releaseAfterFailure(ctx, releases);
|
|
@@ -481,7 +530,7 @@ type AttachmentTarget = {
|
|
|
481
530
|
|
|
482
531
|
// Runs before the upload (reject early, store nothing) and again in the transaction on the fresh row.
|
|
483
532
|
async function checkAttachmentTarget(args: {
|
|
484
|
-
readonly ctx:
|
|
533
|
+
readonly ctx: PrepareContext;
|
|
485
534
|
readonly tenantId: TenantId;
|
|
486
535
|
readonly templateId: string;
|
|
487
536
|
readonly key: string;
|
|
@@ -506,7 +555,7 @@ async function checkAttachmentTarget(args: {
|
|
|
506
555
|
// beforeTransaction half: validates a PDF/PNG/JPEG and uploads it unchanged to the target tenant's
|
|
507
556
|
// storage. With templateId the template is checked first; a bundle import has none yet.
|
|
508
557
|
export async function prepareTemplateAttachmentBeforeTransaction(args: {
|
|
509
|
-
readonly ctx:
|
|
558
|
+
readonly ctx: PrepareContext;
|
|
510
559
|
readonly user: SessionUser;
|
|
511
560
|
readonly tenantId: TenantId;
|
|
512
561
|
readonly bytes: Uint8Array;
|
|
@@ -27,16 +27,16 @@ type FileRefRow = {
|
|
|
27
27
|
// Reads the file behind a template resource. Null when the fileRef is unknown
|
|
28
28
|
// to the caller's tenant or has no bytes.
|
|
29
29
|
export async function readTemplateResource(
|
|
30
|
-
ctx: Pick<HandlerContext, "db" | "
|
|
30
|
+
ctx: Pick<HandlerContext, "db" | "services" | "user">,
|
|
31
31
|
fileRefId: string,
|
|
32
32
|
): Promise<TemplateResourceFile | null> {
|
|
33
|
-
if (!ctx.files) return null;
|
|
33
|
+
if (!ctx.services.files) return null;
|
|
34
34
|
const row = await fetchOne<FileRefRow>(ctx.db, fileRefsTable, {
|
|
35
35
|
id: fileRefId,
|
|
36
36
|
isDeleted: false,
|
|
37
37
|
});
|
|
38
38
|
if (!row) return null;
|
|
39
|
-
const handle = ctx.files.refFromFileRef(row);
|
|
39
|
+
const handle = ctx.services.files.refFromFileRef(row);
|
|
40
40
|
if (!(await handle.exists())) return null;
|
|
41
41
|
return { fileName: row.fileName, contentType: row.mimeType, bytes: await handle.read() };
|
|
42
42
|
}
|
|
@@ -44,7 +44,7 @@ export async function readTemplateResource(
|
|
|
44
44
|
// Replaces the whole key map of one row with files that are already stored (bundle import,
|
|
45
45
|
// copy-locale). Single keys go through storePreparedTemplateResource and resource-remove.
|
|
46
46
|
export async function attachTemplateResources(
|
|
47
|
-
ctx: Pick<HandlerContext, "
|
|
47
|
+
ctx: Pick<HandlerContext, "tenants">,
|
|
48
48
|
args: {
|
|
49
49
|
readonly user: SessionUser;
|
|
50
50
|
readonly tenantId: TenantId;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// No bun:test here — callers register cases with their own test runner.
|
|
4
4
|
|
|
5
5
|
import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
6
|
-
import {
|
|
6
|
+
import { seedRowViaEventStore } from "@cosmicdrift/kumiko-testing/helpers";
|
|
7
7
|
import type { ResolveRequest, TemplateResource } from "./api.ts";
|
|
8
8
|
import { TemplateNotFoundError } from "./api.ts";
|
|
9
9
|
import { templateResourcesTable } from "./table.ts";
|
|
@@ -50,7 +50,7 @@ type SeedTemplateArgs = {
|
|
|
50
50
|
};
|
|
51
51
|
|
|
52
52
|
async function seedTemplate(db: DbConnection, args: SeedTemplateArgs): Promise<void> {
|
|
53
|
-
await
|
|
53
|
+
await seedRowViaEventStore(db, templateResourcesTable, {
|
|
54
54
|
tenantId: args.tenantId,
|
|
55
55
|
slug: args.slug,
|
|
56
56
|
kind: args.kind,
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { usePrimitives, VariableChips } from "@cosmicdrift/kumiko-renderer";
|
|
2
|
+
import { AlignCenter, AlignJustify, AlignLeft, AlignRight } from "lucide-react";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import { insertAndCloseOf, type PanelModel } from "./document-insert-model.ts";
|
|
5
|
+
import { DOCUMENT_TEXT_ALIGNMENTS, type DocumentTextAlignment } from "./document-schema.ts";
|
|
6
|
+
import { type PanelKind, variableLabelOf } from "./document-tiptap-helpers.ts";
|
|
7
|
+
|
|
8
|
+
const ALIGNMENT_ICONS: Record<DocumentTextAlignment, ReactNode> = {
|
|
9
|
+
left: <AlignLeft size={16} />,
|
|
10
|
+
center: <AlignCenter size={16} />,
|
|
11
|
+
right: <AlignRight size={16} />,
|
|
12
|
+
justify: <AlignJustify size={16} />,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const ALIGNMENT_LABEL_KEYS: Record<DocumentTextAlignment, string> = {
|
|
16
|
+
left: "template-resolver.documentEditor.alignLeft",
|
|
17
|
+
center: "template-resolver.documentEditor.alignCenter",
|
|
18
|
+
right: "template-resolver.documentEditor.alignRight",
|
|
19
|
+
justify: "template-resolver.documentEditor.alignJustify",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
type OptionSelectProps = {
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly label: string;
|
|
25
|
+
readonly names: readonly string[];
|
|
26
|
+
readonly labels: Readonly<Record<string, string>>;
|
|
27
|
+
readonly value: string;
|
|
28
|
+
readonly onChange: (name: string) => void;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function NameSelect({ id, label, names, labels, value, onChange }: OptionSelectProps): ReactNode {
|
|
32
|
+
const { Field, Input } = usePrimitives();
|
|
33
|
+
return (
|
|
34
|
+
<Field id={id} label={label}>
|
|
35
|
+
<Input
|
|
36
|
+
kind="select"
|
|
37
|
+
id={id}
|
|
38
|
+
name={id}
|
|
39
|
+
value={value}
|
|
40
|
+
onChange={onChange}
|
|
41
|
+
display="dropdown"
|
|
42
|
+
options={names.map((name) => ({ value: name, label: variableLabelOf(name, labels) }))}
|
|
43
|
+
/>
|
|
44
|
+
</Field>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function renderLinkFields(m: PanelModel): ReactNode {
|
|
49
|
+
const { t, Field, Input } = m;
|
|
50
|
+
return (
|
|
51
|
+
<Field id={`${m.idPrefix}-href`} label={t("template-resolver.documentEditor.linkHref")}>
|
|
52
|
+
<Input
|
|
53
|
+
kind="text"
|
|
54
|
+
id={`${m.idPrefix}-href`}
|
|
55
|
+
name="href"
|
|
56
|
+
value={m.href}
|
|
57
|
+
onChange={m.setHref}
|
|
58
|
+
placeholder={t("template-resolver.documentEditor.linkHrefPlaceholder")}
|
|
59
|
+
/>
|
|
60
|
+
</Field>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function renderPlaceholderFields(m: PanelModel): ReactNode {
|
|
65
|
+
return (
|
|
66
|
+
!m.noVariables && (
|
|
67
|
+
<div className="flex flex-wrap gap-1">
|
|
68
|
+
<VariableChips
|
|
69
|
+
variables={m.selectable}
|
|
70
|
+
labels={m.variableLabels}
|
|
71
|
+
onInsert={(name) => insertAndCloseOf(m)({ type: "variable", attrs: { name } })}
|
|
72
|
+
/>
|
|
73
|
+
</div>
|
|
74
|
+
)
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function renderAlignFields(m: PanelModel): ReactNode {
|
|
79
|
+
const { t, Button, editor } = m;
|
|
80
|
+
return (
|
|
81
|
+
<div className="flex flex-wrap gap-1">
|
|
82
|
+
{DOCUMENT_TEXT_ALIGNMENTS.map((alignment) => (
|
|
83
|
+
<Button
|
|
84
|
+
key={alignment}
|
|
85
|
+
type="button"
|
|
86
|
+
variant="secondary"
|
|
87
|
+
size="sm"
|
|
88
|
+
onClick={() => {
|
|
89
|
+
editor
|
|
90
|
+
.chain()
|
|
91
|
+
.focus()
|
|
92
|
+
.updateAttributes("paragraph", { textAlign: alignment })
|
|
93
|
+
.updateAttributes("heading", { textAlign: alignment })
|
|
94
|
+
.run();
|
|
95
|
+
m.onClose();
|
|
96
|
+
}}
|
|
97
|
+
>
|
|
98
|
+
{ALIGNMENT_ICONS[alignment]}
|
|
99
|
+
{t(ALIGNMENT_LABEL_KEYS[alignment])}
|
|
100
|
+
</Button>
|
|
101
|
+
))}
|
|
102
|
+
</div>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function renderImageFields(m: PanelModel): ReactNode {
|
|
107
|
+
const { t, Field, Input, idPrefix } = m;
|
|
108
|
+
return (
|
|
109
|
+
<>
|
|
110
|
+
<Field id={`${idPrefix}-resource`} label={t("template-resolver.documentEditor.resourceKey")}>
|
|
111
|
+
<Input
|
|
112
|
+
kind="text"
|
|
113
|
+
id={`${idPrefix}-resource`}
|
|
114
|
+
name="resource"
|
|
115
|
+
value={m.resource}
|
|
116
|
+
onChange={m.setResource}
|
|
117
|
+
/>
|
|
118
|
+
</Field>
|
|
119
|
+
<Field id={`${idPrefix}-alt`} label={t("template-resolver.documentEditor.imageAlt")}>
|
|
120
|
+
<Input kind="text" id={`${idPrefix}-alt`} name="alt" value={m.alt} onChange={m.setAlt} />
|
|
121
|
+
</Field>
|
|
122
|
+
</>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function renderButtonFields(m: PanelModel): ReactNode {
|
|
127
|
+
const { t, Field, Input, idPrefix } = m;
|
|
128
|
+
return (
|
|
129
|
+
!m.noVariables && (
|
|
130
|
+
<>
|
|
131
|
+
<NameSelect
|
|
132
|
+
id={`${idPrefix}-target`}
|
|
133
|
+
label={t("template-resolver.documentEditor.buttonTarget")}
|
|
134
|
+
names={m.selectable}
|
|
135
|
+
labels={m.variableLabels}
|
|
136
|
+
value={m.selectedName}
|
|
137
|
+
onChange={m.setChosenName}
|
|
138
|
+
/>
|
|
139
|
+
<Field id={`${idPrefix}-text`} label={t("template-resolver.documentEditor.buttonText")}>
|
|
140
|
+
<Input
|
|
141
|
+
kind="text"
|
|
142
|
+
id={`${idPrefix}-text`}
|
|
143
|
+
name="text"
|
|
144
|
+
value={m.buttonText}
|
|
145
|
+
onChange={m.setButtonText}
|
|
146
|
+
/>
|
|
147
|
+
</Field>
|
|
148
|
+
</>
|
|
149
|
+
)
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function renderRepeatFields(m: PanelModel): ReactNode {
|
|
154
|
+
return (
|
|
155
|
+
!m.noVariables && (
|
|
156
|
+
<NameSelect
|
|
157
|
+
id={`${m.idPrefix}-list`}
|
|
158
|
+
label={m.t("template-resolver.documentEditor.repeatList")}
|
|
159
|
+
names={m.selectable}
|
|
160
|
+
labels={m.variableLabels}
|
|
161
|
+
value={m.selectedName}
|
|
162
|
+
onChange={m.setChosenName}
|
|
163
|
+
/>
|
|
164
|
+
)
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function renderImagesFields(m: PanelModel): ReactNode {
|
|
169
|
+
return (
|
|
170
|
+
!m.noVariables && (
|
|
171
|
+
<NameSelect
|
|
172
|
+
id={`${m.idPrefix}-images-variable`}
|
|
173
|
+
label={m.t("template-resolver.documentEditor.imagesVariable")}
|
|
174
|
+
names={m.selectable}
|
|
175
|
+
labels={m.variableLabels}
|
|
176
|
+
value={m.selectedName}
|
|
177
|
+
onChange={m.setChosenName}
|
|
178
|
+
/>
|
|
179
|
+
)
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function renderStepsFields(m: PanelModel): ReactNode {
|
|
184
|
+
const { t, Field, Input, idPrefix } = m;
|
|
185
|
+
return (
|
|
186
|
+
!m.noVariables && (
|
|
187
|
+
<>
|
|
188
|
+
<NameSelect
|
|
189
|
+
id={`${idPrefix}-steps-variable`}
|
|
190
|
+
label={t("template-resolver.documentEditor.stepsVariable")}
|
|
191
|
+
names={m.selectable}
|
|
192
|
+
labels={m.variableLabels}
|
|
193
|
+
value={m.selectedName}
|
|
194
|
+
onChange={m.setChosenName}
|
|
195
|
+
/>
|
|
196
|
+
<Field
|
|
197
|
+
id={`${idPrefix}-steps-list`}
|
|
198
|
+
label={t("template-resolver.documentEditor.stepsList")}
|
|
199
|
+
>
|
|
200
|
+
<Input
|
|
201
|
+
kind="text"
|
|
202
|
+
id={`${idPrefix}-steps-list`}
|
|
203
|
+
name="steps"
|
|
204
|
+
value={m.stepsText}
|
|
205
|
+
onChange={m.setStepsText}
|
|
206
|
+
/>
|
|
207
|
+
</Field>
|
|
208
|
+
</>
|
|
209
|
+
)
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export const PANEL_FIELDS: Readonly<Record<PanelKind, (m: PanelModel) => ReactNode>> = {
|
|
214
|
+
link: renderLinkFields,
|
|
215
|
+
placeholder: renderPlaceholderFields,
|
|
216
|
+
align: renderAlignFields,
|
|
217
|
+
image: renderImageFields,
|
|
218
|
+
button: renderButtonFields,
|
|
219
|
+
repeat: renderRepeatFields,
|
|
220
|
+
images: renderImagesFields,
|
|
221
|
+
steps: renderStepsFields,
|
|
222
|
+
};
|