@cosmicdrift/kumiko-samples 0.361.0 → 0.363.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 +17 -6
- package/packages/bundled-features/src/admin-shell/changes.json +6 -0
- package/packages/bundled-features/src/admin-shell/feature.ts +8 -1
- package/packages/bundled-features/src/agent-tools/agent-manifest.ts +3 -4
- package/packages/bundled-features/src/agent-tools/filter-ops.ts +1 -3
- package/packages/bundled-features/src/agent-tools/tool-catalog.ts +1 -3
- package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +2 -1
- package/packages/bundled-features/src/auth-email-password/changes.json +14 -0
- package/packages/bundled-features/src/auth-email-password/email-templates.ts +12 -138
- package/packages/bundled-features/src/auth-email-password/feature.ts +30 -9
- package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +4 -5
- package/packages/bundled-features/src/auth-email-password/handlers/request-account-unlock.write.ts +2 -5
- package/packages/bundled-features/src/auth-email-password/handlers/request-email-verification.write.ts +2 -5
- package/packages/bundled-features/src/auth-email-password/handlers/request-password-reset.write.ts +2 -5
- package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +3 -4
- package/packages/bundled-features/src/auth-email-password/handlers/token-request-handler.ts +3 -12
- package/packages/bundled-features/src/auth-email-password/index.ts +2 -17
- package/packages/bundled-features/src/auth-email-password/magic-link-mail.ts +30 -22
- package/packages/bundled-features/src/auth-email-password/mail-notifications.ts +158 -0
- package/packages/bundled-features/src/auth-email-password/signup-activation.ts +2 -3
- package/packages/bundled-features/src/auth-foundation/types.ts +8 -18
- package/packages/bundled-features/src/auth-mfa/feature.ts +8 -10
- package/packages/bundled-features/src/auth-mfa/hmac-token-codec.ts +4 -4
- package/packages/bundled-features/src/auth-mfa/mfa-challenge-token.ts +3 -3
- package/packages/bundled-features/src/auth-mfa/mfa-preauth-setup-token.ts +3 -3
- package/packages/bundled-features/src/auth-mfa/mfa-setup-token.ts +8 -8
- package/packages/bundled-features/src/billing-foundation/changes.json +7 -0
- package/packages/bundled-features/src/billing-foundation/constants.ts +5 -4
- package/packages/bundled-features/src/billing-foundation/consumer-protection/confirmation-mail.ts +38 -44
- package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +3 -3
- package/packages/bundled-features/src/billing-foundation/consumer-protection/mail-notifications.ts +115 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/register-consent.ts +2 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-mail.ts +30 -30
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-notify.ts +2 -2
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-pages.ts +1 -4
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +2 -2
- package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +2 -2
- package/packages/bundled-features/src/billing-foundation/handlers/create-portal-session.write.ts +4 -9
- package/packages/bundled-features/src/billing-foundation/handlers/list-subscriptions.query.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +2 -2
- package/packages/bundled-features/src/billing-foundation/handlers/process-payment-event.write.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/subscription-tier-sync.ts +3 -6
- package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +2 -1
- package/packages/bundled-features/src/cap-overview/web/cap-usage-cell.tsx +6 -4
- package/packages/bundled-features/src/channel-email/changes.json +19 -0
- package/packages/bundled-features/src/channel-email/email-channel.ts +122 -29
- package/packages/bundled-features/src/channel-email/feature.ts +6 -3
- package/packages/bundled-features/src/channel-email/index.ts +7 -1
- package/packages/bundled-features/src/channel-email/pii-guard.ts +13 -0
- package/packages/bundled-features/src/channel-email/smtp-transport.ts +15 -1
- package/packages/bundled-features/src/channel-email/types.ts +23 -0
- package/packages/bundled-features/src/channel-in-app/handlers/mark-read.write.ts +2 -2
- package/packages/bundled-features/src/config/handlers/set.write.ts +1 -5
- package/packages/bundled-features/src/custom-fields/db/queries/user-data-rights.ts +2 -2
- package/packages/bundled-features/src/custom-fields/lib/value-schema.ts +10 -11
- package/packages/bundled-features/src/custom-fields/wire-user-data-rights.ts +7 -6
- package/packages/bundled-features/src/data-retention/changes.json +6 -0
- package/packages/bundled-features/src/data-retention/index.ts +1 -0
- package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +8 -6
- package/packages/bundled-features/src/delivery/attachment-ref.ts +84 -0
- package/packages/bundled-features/src/delivery/changes.json +48 -0
- package/packages/bundled-features/src/delivery/channel-context.ts +129 -4
- package/packages/bundled-features/src/delivery/constants.ts +2 -0
- package/packages/bundled-features/src/delivery/delivery-service.ts +104 -26
- package/packages/bundled-features/src/delivery/feature.ts +1 -1
- package/packages/bundled-features/src/delivery/index.ts +17 -2
- package/packages/bundled-features/src/delivery/jobs.ts +48 -5
- package/packages/bundled-features/src/delivery/notify-factory.ts +14 -9
- package/packages/bundled-features/src/delivery/testing.ts +9 -1
- package/packages/bundled-features/src/delivery/types.ts +28 -18
- package/packages/bundled-features/src/delivery/unsubscribe.ts +5 -2
- package/packages/bundled-features/src/derivatives-sharp/render.ts +1 -22
- package/packages/bundled-features/src/document-ingest-foundation/aggregate-id.ts +10 -0
- package/packages/bundled-features/src/document-ingest-foundation/changes.json +6 -0
- package/packages/bundled-features/src/document-ingest-foundation/events.ts +3 -1
- package/packages/bundled-features/src/document-ingest-foundation/feature.ts +5 -3
- package/packages/bundled-features/src/document-ingest-foundation/index.ts +1 -0
- package/packages/bundled-features/src/document-ingest-foundation/pages.ts +6 -3
- package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +4 -4
- package/packages/bundled-features/src/file-foundation/index.ts +7 -0
- package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +86 -0
- package/packages/bundled-features/src/folders/web/folder-manager.tsx +5 -2
- package/packages/bundled-features/src/form-draft/db/queries/cleanup.ts +11 -11
- package/packages/bundled-features/src/form-draft/db/queries/draft-count.ts +2 -2
- package/packages/bundled-features/src/form-draft/db/queries/owned-file-refs.ts +2 -2
- package/packages/bundled-features/src/form-draft/release-file-refs.ts +3 -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/ingest-message.write.ts +6 -6
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-accounts.query.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/list-messages.query.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/scope-visibility.ts +2 -2
- package/packages/bundled-features/src/inbound-mail-foundation/oauth-state.ts +7 -7
- package/packages/bundled-features/src/inbound-mail-foundation/retention-sweep.ts +2 -6
- package/packages/bundled-features/src/inbound-mail-foundation/tenant-destroy-hook.ts +5 -13
- package/packages/bundled-features/src/inbound-mail-foundation/types.ts +4 -6
- package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +40 -25
- package/packages/bundled-features/src/inbound-provider-imap/imap-client.ts +4 -3
- package/packages/bundled-features/src/jobs/handlers/catalog.query.ts +1 -1
- package/packages/bundled-features/src/ledger/recurring.ts +1 -3
- package/packages/bundled-features/src/managed-pages/branding.ts +33 -9
- package/packages/bundled-features/src/managed-pages/changes.json +6 -0
- package/packages/bundled-features/src/managed-pages/feature.ts +1 -0
- package/packages/bundled-features/src/managed-pages/i18n.ts +1 -0
- package/packages/bundled-features/src/managed-pages/screens/branding-screen.ts +8 -0
- package/packages/bundled-features/src/page-render/branding.ts +3 -0
- package/packages/bundled-features/src/page-render/markdown.ts +1 -1
- package/packages/bundled-features/src/personal-access-tokens/feature.ts +2 -4
- package/packages/bundled-features/src/personal-access-tokens/handlers/list.query.ts +2 -1
- package/packages/bundled-features/src/personal-access-tokens/index.ts +1 -1
- package/packages/bundled-features/src/personal-access-tokens/revoke-for-user.ts +2 -1
- package/packages/bundled-features/src/renderer-foundation/README.md +11 -10
- package/packages/bundled-features/src/renderer-foundation/api.ts +14 -14
- package/packages/bundled-features/src/renderer-foundation/changes.json +39 -0
- package/packages/bundled-features/src/renderer-foundation/constants.ts +6 -8
- package/packages/bundled-features/src/renderer-foundation/feature.ts +7 -7
- package/packages/bundled-features/src/renderer-foundation/index.ts +13 -2
- package/packages/bundled-features/src/renderer-foundation/types.ts +132 -35
- package/packages/bundled-features/src/renderer-pdf/feature.ts +7 -1
- package/packages/bundled-features/src/sessions/db/queries/cleanup.ts +2 -2
- package/packages/bundled-features/src/sessions/feature.ts +2 -4
- package/packages/bundled-features/src/sessions/handlers/list.query.ts +2 -1
- package/packages/bundled-features/src/shared/attachment-file-name.ts +39 -0
- package/packages/bundled-features/src/shared/index.ts +6 -0
- package/packages/bundled-features/src/shared/is-tenant-db.ts +1 -1
- package/packages/bundled-features/src/shared/mail-template-body.ts +25 -0
- package/packages/bundled-features/src/shared/sharp-input-limits.ts +26 -0
- package/packages/bundled-features/src/shared/signup-handover.ts +4 -4
- package/packages/bundled-features/src/tags/handlers/assign-tag.write.ts +5 -1
- package/packages/bundled-features/src/tags/web/tag-chip.tsx +2 -1
- package/packages/bundled-features/src/template-resolver/README.md +63 -7
- package/packages/bundled-features/src/template-resolver/api.ts +83 -8
- package/packages/bundled-features/src/template-resolver/changes.json +118 -0
- package/packages/bundled-features/src/template-resolver/compile-document-body.ts +214 -0
- package/packages/bundled-features/src/template-resolver/constants.ts +39 -11
- package/packages/bundled-features/src/template-resolver/document-sanitizer.ts +335 -0
- package/packages/bundled-features/src/template-resolver/document-schema.ts +323 -0
- package/packages/bundled-features/src/template-resolver/feature.ts +56 -6
- package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +188 -0
- package/packages/bundled-features/src/template-resolver/handlers/collection-set.write.ts +30 -2
- package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +142 -0
- package/packages/bundled-features/src/template-resolver/handlers/diff-to-system.query.ts +72 -0
- package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +83 -0
- package/packages/bundled-features/src/template-resolver/handlers/find-by-id.query.ts +3 -3
- package/packages/bundled-features/src/template-resolver/handlers/import-bundle-system.write.ts +42 -0
- package/packages/bundled-features/src/template-resolver/handlers/import-bundle.write.ts +22 -0
- package/packages/bundled-features/src/template-resolver/handlers/layout-source.query.ts +108 -0
- package/packages/bundled-features/src/template-resolver/handlers/list.query.ts +5 -7
- package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +250 -0
- package/packages/bundled-features/src/template-resolver/handlers/preview.query.ts +25 -0
- package/packages/bundled-features/src/template-resolver/handlers/reset-to-system.write.ts +58 -0
- package/packages/bundled-features/src/template-resolver/handlers/resource-link-pdf.write.ts +34 -0
- package/packages/bundled-features/src/template-resolver/handlers/resource-remove.write.ts +50 -0
- package/packages/bundled-features/src/template-resolver/handlers/resource-shared.ts +24 -0
- package/packages/bundled-features/src/template-resolver/handlers/resource-upload.write.ts +135 -0
- package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +106 -0
- package/packages/bundled-features/src/template-resolver/handlers/set.write.ts +32 -3
- package/packages/bundled-features/src/template-resolver/handlers/shared.ts +7 -2
- package/packages/bundled-features/src/template-resolver/handlers/template-gates.ts +184 -0
- package/packages/bundled-features/src/template-resolver/handlers/template-write.ts +183 -0
- package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +55 -0
- package/packages/bundled-features/src/template-resolver/handlers/toggle-status.write.ts +57 -10
- package/packages/bundled-features/src/template-resolver/handlers/upsert-system.write.ts +19 -71
- package/packages/bundled-features/src/template-resolver/handlers/upsert-tenant.write.ts +15 -76
- package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +17 -0
- package/packages/bundled-features/src/template-resolver/handlers/validate.query.ts +116 -0
- package/packages/bundled-features/src/template-resolver/index.ts +100 -0
- package/packages/bundled-features/src/template-resolver/layout-regions.ts +206 -0
- package/packages/bundled-features/src/template-resolver/linked-resources.ts +102 -0
- package/packages/bundled-features/src/template-resolver/preview-display-html.ts +36 -0
- package/packages/bundled-features/src/template-resolver/print-document.ts +58 -0
- package/packages/bundled-features/src/template-resolver/qualified-names.ts +30 -0
- package/packages/bundled-features/src/template-resolver/record-mapping.ts +26 -0
- package/packages/bundled-features/src/template-resolver/resource-image.ts +47 -0
- package/packages/bundled-features/src/template-resolver/seeding.ts +147 -17
- package/packages/bundled-features/src/template-resolver/store-template-resource.ts +416 -0
- package/packages/bundled-features/src/template-resolver/table.ts +14 -0
- package/packages/bundled-features/src/template-resolver/template-bundle.ts +79 -0
- package/packages/bundled-features/src/template-resolver/template-diff.ts +78 -0
- package/packages/bundled-features/src/template-resolver/template-meta.ts +129 -0
- package/packages/bundled-features/src/template-resolver/template-preview.ts +573 -0
- package/packages/bundled-features/src/template-resolver/template-resources.ts +74 -0
- package/packages/bundled-features/src/template-resolver/template-usage.ts +48 -0
- package/packages/bundled-features/src/template-resolver/template-validation.ts +229 -0
- package/packages/bundled-features/src/template-resolver/testing.ts +5 -5
- package/packages/bundled-features/src/template-resolver/web/client-plugin.tsx +9 -6
- package/packages/bundled-features/src/template-resolver/web/document-editor-extensions.ts +162 -0
- package/packages/bundled-features/src/template-resolver/web/document-editor.tsx +28 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-editor.tsx +850 -0
- package/packages/bundled-features/src/template-resolver/web/document-toolbar-blocks.ts +61 -0
- package/packages/bundled-features/src/template-resolver/web/editor-handle.ts +26 -0
- package/packages/bundled-features/src/template-resolver/web/i18n.ts +100 -0
- package/packages/bundled-features/src/template-resolver/web/index.ts +19 -0
- package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor-lazy.tsx +36 -0
- package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor.tsx +169 -0
- package/packages/bundled-features/src/template-resolver/web/placeholder-text.ts +37 -0
- package/packages/bundled-features/src/template-resolver/web/use-stable-by-key.ts +14 -0
- package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +3 -2
- package/packages/bundled-features/src/tenant/seeding.ts +41 -7
- package/packages/bundled-features/src/tenant-lifecycle/boot-checks.ts +1 -1
- package/packages/bundled-features/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +2 -1
- package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +4 -4
- package/packages/bundled-features/src/user/handlers/detail.query.ts +3 -5
- package/packages/bundled-features/src/user/roles-input-schema.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/changes.json +14 -0
- package/packages/bundled-features/src/user-data-rights/db/queries/forget-cleanup.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/email-templates.ts +5 -149
- package/packages/bundled-features/src/user-data-rights/feature.ts +72 -35
- package/packages/bundled-features/src/user-data-rights/handlers/cancel-deletion.write.ts +2 -1
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +5 -1
- package/packages/bundled-features/src/user-data-rights/handlers/list-download-attempts.query.ts +13 -1
- package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +5 -11
- package/packages/bundled-features/src/user-data-rights/index.ts +1 -0
- package/packages/bundled-features/src/user-data-rights/lib/default-mailers.ts +134 -53
- package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/mail-notifications.ts +157 -0
- package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/schema/download-attempt.ts +6 -12
- package/packages/bundled-features/src/user-data-rights/web/privacy-center-screen.tsx +2 -1
- package/packages/bundled-features/src/user-data-rights-defaults/feature.ts +10 -1
- package/packages/bundled-features/src/user-data-rights-defaults/hooks/download-attempt.userdata-hook.ts +58 -0
- package/packages/bundled-features/src/user-profile/web/profile-screen.tsx +2 -1
- package/packages/bundled-features/src/waitlist/changes.json +7 -0
- package/packages/bundled-features/src/waitlist/feature.ts +17 -0
- package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +4 -5
- package/packages/bundled-features/src/waitlist/mail.ts +69 -18
- package/packages/bundled-features/src/workflow-runner/event-trigger.ts +1 -2
- package/samples/apps/ui-walkthrough/package.json +2 -0
- package/samples/apps/ui-walkthrough/src/app/auth-constants.ts +9 -0
- package/samples/apps/ui-walkthrough/src/app/client.tsx +6 -0
- package/samples/apps/ui-walkthrough/src/app/seed-templates.ts +154 -0
- package/samples/apps/ui-walkthrough/src/app/server.ts +5 -1
- package/samples/apps/ui-walkthrough/src/app/shell.tsx +12 -1
- package/samples/apps/ui-walkthrough/src/app/template-seed-data.ts +354 -0
- package/samples/apps/ui-walkthrough/src/features/billing/feature.ts +68 -0
- package/samples/apps/ui-walkthrough/src/features/billing/i18n.ts +18 -0
- package/samples/apps/ui-walkthrough/src/features/billing/index.ts +2 -0
- package/samples/apps/ui-walkthrough/src/features/billing/web/index.ts +7 -0
- package/samples/apps/ui-walkthrough/src/features/rental/screens.ts +1 -1
- package/samples/apps/ui-walkthrough/src/run-config.ts +37 -1
- package/samples/apps/use-all-bundled/e2e-billing-gallery/gallery-features.ts +0 -2
- package/samples/apps/use-all-bundled/feature-manifest.json +123 -22
- package/samples/apps/use-all-bundled/kumiko/migrations/0044_download-attempt-ip-bidx.rebuild.json +4 -0
- package/samples/apps/use-all-bundled/kumiko/migrations/0045_template-resource-meta.rebuild.json +4 -0
- package/samples/apps/use-all-bundled/kumiko/migrations/0046_pdf-rendered.rebuild.json +4 -0
- package/samples/apps/use-all-bundled/package.json +2 -0
- package/samples/apps/use-all-bundled/playwright.config.ts +38 -3
- package/samples/apps/use-all-bundled/schema/generate.ts +13 -3
- package/samples/apps/use-all-bundled/schema/schema.generated.ts +3 -0
- package/samples/apps/use-all-bundled/scripts/check-coverage.ts +3 -0
- package/samples/apps/use-all-bundled/src/app/auth-constants.ts +3 -0
- package/samples/apps/use-all-bundled/src/app/client.tsx +4 -0
- package/samples/apps/use-all-bundled/src/app/seed-documents.ts +128 -0
- package/samples/apps/use-all-bundled/src/app/seed.ts +4 -0
- package/samples/apps/use-all-bundled/src/run-config.ts +11 -11
- package/samples/recipes/delivery-notifications/README.md +26 -25
- package/samples/recipes/delivery-notifications/package.json +2 -1
- package/samples/recipes/delivery-notifications/src/feature.ts +64 -58
- package/samples/recipes/seed-migration/README.md +1 -1
- package/packages/bundled-features/src/renderer-simple/changes.json +0 -27
- package/packages/bundled-features/src/renderer-simple/feature.ts +0 -66
- package/packages/bundled-features/src/renderer-simple/index.ts +0 -8
- package/packages/bundled-features/src/renderer-simple/mail-blocks.ts +0 -138
- package/packages/bundled-features/src/renderer-simple/resolve-variables.ts +0 -57
- package/packages/bundled-features/src/renderer-simple/simple-renderer.ts +0 -304
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": "samples/apps/use-all-bundled APP_FEATURES (composeFeatures includeBundled + signup)",
|
|
3
|
-
"featureCount":
|
|
3
|
+
"featureCount": 84,
|
|
4
4
|
"features": [
|
|
5
5
|
{
|
|
6
6
|
"name": "admin-shell",
|
|
7
|
-
"description": "Registers tenant-admin and platform-admin workspaces with provider nav into owner-feature screens (`tenant:screen:members`, `audit:screen:audit-log`, `tenant:screen:tenant-list`, `jobs:screen:job-runs`, optional `tier-engine:screen:tier-admin`, optional `cap-overview:screen:my-caps`/`cap-overview:screen:tenant-cap-list`) and the two overview dashboards, built from the metrics list (`metrics` option, default DEFAULT_METRICS). Mount after user, tenant, audit, jobs, metrics and metrics-system; pass `workspaceIds` to match app URL conventions (e.g. Studio `d`/`s`, PublicStatus `admin`/`sysadmin`). Client: `adminShellClient()`, `tenantClient()`, `auditClient()`, `jobsClient()`, optional `tierEngineClient()`.",
|
|
7
|
+
"description": "Registers tenant-admin and platform-admin workspaces with provider nav into owner-feature screens (`tenant:screen:members`, `audit:screen:audit-log`, `tenant:screen:tenant-list`, `jobs:screen:job-runs`, optional `tier-engine:screen:tier-admin`, optional `cap-overview:screen:my-caps`/`cap-overview:screen:tenant-cap-list`, optional `document-designer` template navs) and the two overview dashboards, built from the metrics list (`metrics` option, default DEFAULT_METRICS). Mount after user, tenant, audit, jobs, metrics and metrics-system; pass `workspaceIds` to match app URL conventions (e.g. Studio `d`/`s`, PublicStatus `admin`/`sysadmin`). Client: `adminShellClient()`, `tenantClient()`, `auditClient()`, `jobsClient()`, optional `tierEngineClient()`.",
|
|
8
8
|
"toggleableDefault": null,
|
|
9
9
|
"requires": [
|
|
10
10
|
"user",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"metrics",
|
|
15
15
|
"metrics-system",
|
|
16
16
|
"tier-engine",
|
|
17
|
-
"cap-overview"
|
|
17
|
+
"cap-overview",
|
|
18
|
+
"document-designer"
|
|
18
19
|
],
|
|
19
20
|
"optionalRequires": [],
|
|
20
21
|
"configReads": [],
|
|
@@ -406,7 +407,7 @@
|
|
|
406
407
|
},
|
|
407
408
|
{
|
|
408
409
|
"name": "channel-email",
|
|
409
|
-
"description": "Wires an `EmailTransport` (typically `mail-transport-smtp` in production, `createInMemoryTransport()` in tests) into the delivery system as the `email` channel. Requires `delivery`; pass an `EmailChannelOptions` with a `transport
|
|
410
|
+
"description": "Wires an `EmailTransport` (typically `mail-transport-smtp` in production, `createInMemoryTransport()` in tests) into the delivery system as the `email` channel. Requires `delivery`; pass an `EmailChannelOptions` with a `transport` and a `resolveEmail` function that maps a user ID to their email address. Mails render from stored templates (`renderer-mail-html`): a notification routed to this channel needs `template` + `meta` on `r.notification`, otherwise its delivery fails.",
|
|
410
411
|
"toggleableDefault": null,
|
|
411
412
|
"requires": [
|
|
412
413
|
"delivery"
|
|
@@ -724,7 +725,7 @@
|
|
|
724
725
|
},
|
|
725
726
|
{
|
|
726
727
|
"name": "delivery",
|
|
727
|
-
"description": "The notification dispatch core: call `ctx.notify(notificationType, { to, route, data, priority, idempotencyKey })` from any handler to fan out a notification across all registered channels (email, in-app, push). It stores per-user channel preferences in the `notification-preference` entity, opt-outs for no-account recipient addresses in `notification-address-opt-out` (keyed by a blind-index hash, never the plaintext address), logs every attempt to `store_delivery_attempts`, and enforces idempotency and rate-limiting — add `channel-email`, `channel-in-app`, or `channel-push` on top to actually send anything. Unsubscribe/resubscribe links are served by `createUnsubscribeRoutes({ secret })` mounted via the app's `extraRoutes` at `/api/delivery/unsubscribe` and `/api/delivery/resubscribe`: `GET /unsubscribe?token=` renders a confirmation page (no write), `POST /unsubscribe` performs the opt-out (RFC 8058 one-click, token from the form body or query), `POST /resubscribe` undoes it (JSON `{token}` or form body only, never the query — reachable by a mail-client link prefetcher) — sign links with `signUnsubscribeToken` / `signAddressUnsubscribeToken` using the same secret. `channel-email` sets `List-Unsubscribe` / `List-Unsubscribe-Post` automatically when a message's `data.unsubscribeUrl` points at the unsubscribe route.",
|
|
728
|
+
"description": "The notification dispatch core: call `ctx.notify(notificationType, { to, route, data, priority, idempotencyKey })` from any handler to fan out a notification across all registered channels (email, in-app, push). Inside a write handler the delivery runs after the write has committed (the call returns `{ kind: \"deferred\" }`, a rolled-back write sends nothing); `immediate: true` delivers synchronously and returns `{ kind: \"dispatched\", deliveries }`. It stores per-user channel preferences in the `notification-preference` entity, opt-outs for no-account recipient addresses in `notification-address-opt-out` (keyed by a blind-index hash, never the plaintext address), logs every attempt to `store_delivery_attempts`, and enforces idempotency and rate-limiting — add `channel-email`, `channel-in-app`, or `channel-push` on top to actually send anything. Unsubscribe/resubscribe links are served by `createUnsubscribeRoutes({ secret })` mounted via the app's `extraRoutes` at `/api/delivery/unsubscribe` and `/api/delivery/resubscribe`: `GET /unsubscribe?token=` renders a confirmation page (no write), `POST /unsubscribe` performs the opt-out (RFC 8058 one-click, token from the form body or query), `POST /resubscribe` undoes it (JSON `{token}` or form body only, never the query — reachable by a mail-client link prefetcher) — sign links with `signUnsubscribeToken` / `signAddressUnsubscribeToken` using the same secret. `channel-email` sets `List-Unsubscribe` / `List-Unsubscribe-Post` automatically when a message's `data.unsubscribeUrl` points at the unsubscribe route.",
|
|
728
729
|
"toggleableDefault": null,
|
|
729
730
|
"requires": [
|
|
730
731
|
"tenant"
|
|
@@ -775,6 +776,27 @@
|
|
|
775
776
|
"recommended": false
|
|
776
777
|
}
|
|
777
778
|
},
|
|
779
|
+
{
|
|
780
|
+
"name": "document-designer",
|
|
781
|
+
"description": "Template overview and layout editor: lists the mail, PDF and layout templates of a tenant (platform admins see the system templates and how many tenants customised each) and edits the mail layout and the PDF letterhead in the browser. Mount after template-resolver and, for the branding rail, managed-pages. Client: `documentDesignerClient()`; admin-shell lists the navs with `includeDocumentDesigner`.",
|
|
782
|
+
"toggleableDefault": null,
|
|
783
|
+
"requires": [
|
|
784
|
+
"template-resolver"
|
|
785
|
+
],
|
|
786
|
+
"optionalRequires": [],
|
|
787
|
+
"configReads": [],
|
|
788
|
+
"exposesApis": [],
|
|
789
|
+
"usesApis": [],
|
|
790
|
+
"extensionsUsed": [],
|
|
791
|
+
"configKeys": [],
|
|
792
|
+
"secrets": [],
|
|
793
|
+
"writeHandlers": [],
|
|
794
|
+
"uiHints": {
|
|
795
|
+
"displayLabel": "Documents · Template Designer",
|
|
796
|
+
"category": "content",
|
|
797
|
+
"recommended": false
|
|
798
|
+
}
|
|
799
|
+
},
|
|
778
800
|
{
|
|
779
801
|
"name": "document-ingest-foundation",
|
|
780
802
|
"description": "Shared PDF/Scan/Image → normalized-text ingest primitive. Owns the `documentExtract` entity (fileRefId, storageKey, per-page text + metadata) as an implicit entity-projection, the per-tenant `ocrLanguage`/`maxPagesPerFile` config keys, the `documentIngestProvider` extension-point providers register accepted mimeTypes/size caps under, and a fileRef.created/fileRef.restored trigger that resolves the provider for a file's mimeType and requests ingest via `documentIngest.requested` tagged with the winning provider — a delete→restore round-trip re-requests ingest the same way a fresh upload does. An orphan-extract guard forgets any `documentExtract` whose fileRef is no longer live at processing time, regardless of how a provider's own write races the fileRef's delete/forget — providers should write through `writeDocumentExtractForLiveFileRef`.",
|
|
@@ -1143,7 +1165,9 @@
|
|
|
1143
1165
|
"extensionsUsed": [],
|
|
1144
1166
|
"configKeys": [],
|
|
1145
1167
|
"secrets": [],
|
|
1146
|
-
"writeHandlers": [
|
|
1168
|
+
"writeHandlers": [
|
|
1169
|
+
"files:write:bind-referenced-files"
|
|
1170
|
+
],
|
|
1147
1171
|
"uiHints": {
|
|
1148
1172
|
"displayLabel": "Files · Metadata",
|
|
1149
1173
|
"category": "storage",
|
|
@@ -1798,6 +1822,30 @@
|
|
|
1798
1822
|
"all"
|
|
1799
1823
|
]
|
|
1800
1824
|
},
|
|
1825
|
+
{
|
|
1826
|
+
"key": "branding-logo-file",
|
|
1827
|
+
"qualifiedName": "managed-pages:config:branding-logo-file",
|
|
1828
|
+
"type": "text",
|
|
1829
|
+
"scope": "tenant",
|
|
1830
|
+
"default": "",
|
|
1831
|
+
"encrypted": false,
|
|
1832
|
+
"computed": false,
|
|
1833
|
+
"validated": false,
|
|
1834
|
+
"options": null,
|
|
1835
|
+
"bounds": null,
|
|
1836
|
+
"pattern": {
|
|
1837
|
+
"regex": "^$|^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
|
|
1838
|
+
},
|
|
1839
|
+
"writeRoles": [
|
|
1840
|
+
"system",
|
|
1841
|
+
"TenantAdmin",
|
|
1842
|
+
"Admin",
|
|
1843
|
+
"SystemAdmin"
|
|
1844
|
+
],
|
|
1845
|
+
"readRoles": [
|
|
1846
|
+
"all"
|
|
1847
|
+
]
|
|
1848
|
+
},
|
|
1801
1849
|
{
|
|
1802
1850
|
"key": "branding-logo-url",
|
|
1803
1851
|
"qualifiedName": "managed-pages:config:branding-logo-url",
|
|
@@ -2053,7 +2101,7 @@
|
|
|
2053
2101
|
},
|
|
2054
2102
|
{
|
|
2055
2103
|
"name": "renderer-foundation",
|
|
2056
|
-
"description": "Plugin registry for content rendering (
|
|
2104
|
+
"description": "Plugin registry for content rendering (mail HTML, PDF, images): call `foundation.createRendererForTenant({ tenantId, kind })` at render time to get the right renderer plugin selected by kind, with tenant-level overrides via the `rendererPluginByKind` config key. Requires `template-resolver` (declared via `r.requires`). Low-level building block — add `renderer-mail-html` (or write a custom plugin via `r.useExtension(\"renderer\", name, { kinds, render })`) rather than using this feature alone.",
|
|
2057
2105
|
"toggleableDefault": null,
|
|
2058
2106
|
"requires": [
|
|
2059
2107
|
"template-resolver"
|
|
@@ -2072,6 +2120,28 @@
|
|
|
2072
2120
|
"recommended": false
|
|
2073
2121
|
}
|
|
2074
2122
|
},
|
|
2123
|
+
{
|
|
2124
|
+
"name": "renderer-mail-html",
|
|
2125
|
+
"description": "A `renderer-foundation` plugin that handles `RenderRequest { kind: \"mail\" }` and returns `{ subject, html, text, previewText? }` suitable for sending via `channel-email`. The mail template (`kind: \"mail\"`, document HTML, subject in `meta`) resolves through `template-resolver`'s DB fallback, its body is compiled to Handlebars by template-resolver and rendered with escaping, then placed into an MJML layout (`kind: \"mail-layout\"`, slug `default` unless `meta.layoutSlug` says otherwise, in-code `DEFAULT_MAIL_LAYOUT_MJML` as last resort) that `mjml()` compiles to email-safe table HTML, with `html-to-text` producing the plain-text alternative. Seed an editable system layout with `seedSystemMailLayout(db)`. Requires `renderer-foundation` + `template-resolver`.",
|
|
2126
|
+
"toggleableDefault": null,
|
|
2127
|
+
"requires": [
|
|
2128
|
+
"renderer-foundation",
|
|
2129
|
+
"template-resolver"
|
|
2130
|
+
],
|
|
2131
|
+
"optionalRequires": [],
|
|
2132
|
+
"configReads": [],
|
|
2133
|
+
"exposesApis": [],
|
|
2134
|
+
"usesApis": [],
|
|
2135
|
+
"extensionsUsed": [
|
|
2136
|
+
{
|
|
2137
|
+
"extensionName": "renderer",
|
|
2138
|
+
"entityName": "mail-html"
|
|
2139
|
+
}
|
|
2140
|
+
],
|
|
2141
|
+
"configKeys": [],
|
|
2142
|
+
"secrets": [],
|
|
2143
|
+
"writeHandlers": []
|
|
2144
|
+
},
|
|
2075
2145
|
{
|
|
2076
2146
|
"name": "renderer-pdf",
|
|
2077
2147
|
"description": "Renderer plugin for `kind=\"document-pdf\"` that draws a table document (title, meta lines, weighted columns, repeating header, page footer) as a PDF in pure JavaScript, without a browser or Puppeteer service. `payload.variables` must be a `PdfTableDocument`. Requires `renderer-foundation`; mount a Puppeteer-based plugin instead when you need HTML/CSS layouts.",
|
|
@@ -2099,32 +2169,25 @@
|
|
|
2099
2169
|
}
|
|
2100
2170
|
},
|
|
2101
2171
|
{
|
|
2102
|
-
"name": "renderer-
|
|
2103
|
-
"description": "
|
|
2172
|
+
"name": "renderer-puppeteer-client",
|
|
2173
|
+
"description": "A `renderer-foundation` plugin that prints documents to PDF through a separately deployed `puppeteer-service`. A `document-pdf` request names a stored template (`{ slug, locale, variables }`): the plugin resolves the template and its `pdf-layout` (header, signature and footer regions), embeds every image as a data URI, turns repeating table header rows into a real table head and sends the finished HTML to the service, which performs no network fetches itself. The page format, margins, file name pattern and title come from the template meta. `renderAndStorePdf(ctx, ...)` renders and stores the PDF as a file with a `rendered-pdf` record that keeps the template and layout version, so a stored document can always be traced to the text it was created from. The `puppeteer-status` query tells a TenantAdmin whether the service answers; while it does not, rendering fails with a `puppeteer_unavailable` error (HTTP 503) and no PDF is created. `image-snapshot` requests still take ready HTML in `payload.content`. Configure the endpoint and token with `PUPPETEER_SERVICE_URL` and `PUPPETEER_AUTH_TOKEN`; the client retries 5xx and network errors with exponential backoff (default 3 retries), 4xx fails at once. The feature adds the `rendered_pdfs` table, so apps that mount it need a schema migration.",
|
|
2104
2174
|
"toggleableDefault": null,
|
|
2105
2175
|
"requires": [
|
|
2106
2176
|
"renderer-foundation"
|
|
2107
2177
|
],
|
|
2108
|
-
"optionalRequires": [
|
|
2109
|
-
"template-resolver"
|
|
2110
|
-
],
|
|
2178
|
+
"optionalRequires": [],
|
|
2111
2179
|
"configReads": [],
|
|
2112
2180
|
"exposesApis": [],
|
|
2113
2181
|
"usesApis": [],
|
|
2114
2182
|
"extensionsUsed": [
|
|
2115
2183
|
{
|
|
2116
2184
|
"extensionName": "renderer",
|
|
2117
|
-
"entityName": "
|
|
2185
|
+
"entityName": "puppeteer"
|
|
2118
2186
|
}
|
|
2119
2187
|
],
|
|
2120
2188
|
"configKeys": [],
|
|
2121
2189
|
"secrets": [],
|
|
2122
|
-
"writeHandlers": []
|
|
2123
|
-
"uiHints": {
|
|
2124
|
-
"displayLabel": "Renderer · Simple",
|
|
2125
|
-
"category": "notifications",
|
|
2126
|
-
"recommended": false
|
|
2127
|
-
}
|
|
2190
|
+
"writeHandlers": []
|
|
2128
2191
|
},
|
|
2129
2192
|
{
|
|
2130
2193
|
"name": "secrets",
|
|
@@ -2500,7 +2563,7 @@
|
|
|
2500
2563
|
},
|
|
2501
2564
|
{
|
|
2502
2565
|
"name": "template-resolver",
|
|
2503
|
-
"description": "Every piece of editable text lives here, in one entity: mail bodies, notification texts, PDF document templates, AI prompts and plain text blocks. What a record is used for is the `kind` (`notification`, `mail-
|
|
2566
|
+
"description": "Every piece of editable text lives here, in one entity: mail bodies, notification texts, PDF document templates, AI prompts and plain text blocks. What a record is used for is the `kind` (`notification`, `mail`, `mail-layout`, `document-pdf`, `pdf-layout`, `ai-prompt`, `text-block`, `snippet`, `image-snapshot`).\n\nReading is one call — `ctx.templateResolver.resolveTemplate({ tenantId, slug, kind, locale })`. It walks four levels: tenant+locale, system+locale, tenant+fallback-locale, system+fallback-locale. A tenant overrides a system default by simply having its own record; no application code changes. Writing programmatically goes through the `upsertSystem`, `upsertTenant`, `publish` and `archive` write handlers; a SystemAdmin retires or restores a system default with `publishSystem` and `archiveSystem`, and a tenant drops its override with `resetToSystem`.\n\nText an editor should be able to change belongs in a collection, declared at mount: `createTemplateResolverFeature({ collections: [{ id, kind, access: { roles }, nav }] })`. It appears in the navigation, and `access` is part of the mount because a bundled feature cannot know the host's roles. Each collection gets its own `<id>-list` / `<id>-item` / `<id>-set` handlers, so the dispatcher enforces the separation.\n\nHow a collection is edited follows from `contentFormat`: `plain` gives a text area, `rich` a small WYSIWYG (bold, italic, headings, lists, links), `markdown` a text area that stores markdown text (same insertable chips as `plain`). All three offer the collection's `variableSchema` as insertable chips and a preview rendered with sample data — an editor sees what `{{firstName}}` becomes without sending a mail. An app can register its own editor for a format; the last `clientFeature` that registers a format wins (a conflict logs a warning).\n\nA collection is tenant-wide by default. With `ownership: \"user\"` every user keeps their own entries — mail signatures being the obvious case. Those rows live in the separate `user-content-entry` entity and count as user data, so mounting one also requires the `template-resolver-user-data` feature and a migration on the app side.\n\n`validate` dry-runs the write pipeline for a draft (sanitizer, layout rules, placeholders) and reports what the template uses and misses. `export-bundle` / `import-bundle` (and `import-bundle-system`) move one template with all locales and resource files between tenants or environments; `copy-locale` starts a translation from an existing locale. Layouts are structured: a mail or PDF layout is `data-header` / `data-content` / `data-signature` / `data-footer` regions, and mjml layout source is system-only.\n\n`preview` renders a draft (or the stored template) with sample values taken from the `example` of each declared variable, through the same gates and the same mail renderer as a real send, and returns subject, html, `displayHtml` (the html with cid images as data URIs for an editor), text, attachments (inline images and files) and `checks` (images resolved, plain text present, size under 10 MiB, required placeholders used); nothing is saved or sent. `send-test` mails that rendering to the calling user's own address only, subject prefixed with `[TEST]`, at most 10 per user and hour; it needs `delivery`, `channel-email` and `renderer-mail-html` to be mounted.\n\nImages used by a template (`<img data-resource=\"logo\">`) are uploaded with `resourceUpload`, which re-encodes them, stores a file and links it under the key; `resourceRemove` unlinks it. `linkedResources` is written only through these two handlers. With `purpose: \"attachment\"` and a `fileName`, `resourceUpload` stores a PDF, PNG or JPEG as a file attachment of a mail template (original bytes, at most 10) that the mail renderer attaches after the inline images. `resourceLinkPdf` instead links a `document-pdf` template under a key: every mail sent from the template then carries that PDF, rendered at send time with the mail's own variables and locale, under a file name pattern such as `invoice-{{number}}.pdf`; files and linked PDFs share the limit of 10.\n\nReplaces the former `text-content` feature; its blocks now live here as kind `text-block`.",
|
|
2504
2567
|
"toggleableDefault": null,
|
|
2505
2568
|
"requires": [],
|
|
2506
2569
|
"optionalRequires": [],
|
|
@@ -2508,12 +2571,46 @@
|
|
|
2508
2571
|
"exposesApis": [],
|
|
2509
2572
|
"usesApis": [],
|
|
2510
2573
|
"extensionsUsed": [],
|
|
2511
|
-
"configKeys": [
|
|
2574
|
+
"configKeys": [
|
|
2575
|
+
{
|
|
2576
|
+
"key": "resource-max-bytes",
|
|
2577
|
+
"qualifiedName": "template-resolver:config:resource-max-bytes",
|
|
2578
|
+
"type": "number",
|
|
2579
|
+
"scope": "system",
|
|
2580
|
+
"default": 2097152,
|
|
2581
|
+
"encrypted": false,
|
|
2582
|
+
"computed": false,
|
|
2583
|
+
"validated": false,
|
|
2584
|
+
"options": null,
|
|
2585
|
+
"bounds": {
|
|
2586
|
+
"min": 1
|
|
2587
|
+
},
|
|
2588
|
+
"pattern": null,
|
|
2589
|
+
"writeRoles": [
|
|
2590
|
+
"system"
|
|
2591
|
+
],
|
|
2592
|
+
"readRoles": [
|
|
2593
|
+
"TenantAdmin",
|
|
2594
|
+
"Admin",
|
|
2595
|
+
"SystemAdmin"
|
|
2596
|
+
]
|
|
2597
|
+
}
|
|
2598
|
+
],
|
|
2512
2599
|
"secrets": [],
|
|
2513
2600
|
"writeHandlers": [
|
|
2514
2601
|
"template-resolver:write:archive",
|
|
2602
|
+
"template-resolver:write:archive-system",
|
|
2603
|
+
"template-resolver:write:copy-locale",
|
|
2604
|
+
"template-resolver:write:import-bundle",
|
|
2605
|
+
"template-resolver:write:import-bundle-system",
|
|
2515
2606
|
"template-resolver:write:publish",
|
|
2607
|
+
"template-resolver:write:publish-system",
|
|
2516
2608
|
"template-resolver:write:reply-snippets-set",
|
|
2609
|
+
"template-resolver:write:reset-to-system",
|
|
2610
|
+
"template-resolver:write:resource-link-pdf",
|
|
2611
|
+
"template-resolver:write:resource-remove",
|
|
2612
|
+
"template-resolver:write:resource-upload",
|
|
2613
|
+
"template-resolver:write:send-test",
|
|
2517
2614
|
"template-resolver:write:set",
|
|
2518
2615
|
"template-resolver:write:signatures-set",
|
|
2519
2616
|
"template-resolver:write:upsert-system",
|
|
@@ -3008,7 +3105,7 @@
|
|
|
3008
3105
|
},
|
|
3009
3106
|
{
|
|
3010
3107
|
"name": "user-data-rights-defaults",
|
|
3011
|
-
"description": "Registers ready-made `EXT_USER_DATA` export and delete hooks for the bundled entities that hold per-user data: `user` (delete strategy sets email to `deleted-<id>@anonymized.invalid`, nulls `passwordHash`, sets status to `Deleted`; anonymize strategy sets email to `anonymized-<id>@anonymized.invalid` without touching `passwordHash`), `fileRef` (delete removes both the DB row and the storage binary), plus — gated on the source feature being mounted — `user-session` (ip/userAgent, hard-delete), `api-token` (hard-delete = revoke), `in-app-message` (hard-delete), `tenant-invitation` (invitee email forgotten/pseudonymized, inviter link severed), `notification-preference` and user-scoped `config-value` (purged via the forget verb), plus export-only hooks for the events-only aggregates `delivery-attempt` (recipientAddress) and `job-run` (payload) whose erasure runs via crypto-shredding. Mount this alongside `user-data-rights` for standard GDPR compliance; omit it only if your app needs custom anonymization logic for these entities.",
|
|
3108
|
+
"description": "Registers ready-made `EXT_USER_DATA` export and delete hooks for the bundled entities that hold per-user data: `user` (delete strategy sets email to `deleted-<id>@anonymized.invalid`, nulls `passwordHash`, sets status to `Deleted`; anonymize strategy sets email to `anonymized-<id>@anonymized.invalid` without touching `passwordHash`), `fileRef` (delete removes both the DB row and the storage binary), plus — gated on the source feature being mounted — `user-session` (ip/userAgent, hard-delete), `api-token` (hard-delete = revoke), `in-app-message` (hard-delete), `tenant-invitation` (invitee email forgotten/pseudonymized, inviter link severed), `notification-preference` and user-scoped `config-value` (purged via the forget verb), plus export-only hooks for the events-only aggregates `delivery-attempt` (recipientAddress) and `job-run` (payload) whose erasure runs via crypto-shredding, and `download-attempt` (rejected export-download attempts of the user: result, path, source IP, user agent, time; delete purges the user's own attempts via the forget verb, token-path rows without an owner expire by retention). Mount this alongside `user-data-rights` for standard GDPR compliance; omit it only if your app needs custom anonymization logic for these entities.",
|
|
3012
3109
|
"toggleableDefault": null,
|
|
3013
3110
|
"requires": [
|
|
3014
3111
|
"user",
|
|
@@ -3064,6 +3161,10 @@
|
|
|
3064
3161
|
"extensionName": "userData",
|
|
3065
3162
|
"entityName": "delivery-attempt"
|
|
3066
3163
|
},
|
|
3164
|
+
{
|
|
3165
|
+
"extensionName": "userData",
|
|
3166
|
+
"entityName": "download-attempt"
|
|
3167
|
+
},
|
|
3067
3168
|
{
|
|
3068
3169
|
"extensionName": "userData",
|
|
3069
3170
|
"entityName": "job-run"
|
|
@@ -18,8 +18,10 @@
|
|
|
18
18
|
"@cosmicdrift/kumiko-bundled-features": "workspace:*",
|
|
19
19
|
"@cosmicdrift/kumiko-dev-server": "workspace:*",
|
|
20
20
|
"@cosmicdrift/kumiko-dispatcher-live": "workspace:*",
|
|
21
|
+
"@cosmicdrift/kumiko-document-designer": "workspace:*",
|
|
21
22
|
"@cosmicdrift/kumiko-framework": "workspace:*",
|
|
22
23
|
"@cosmicdrift/kumiko-headless": "workspace:*",
|
|
24
|
+
"@cosmicdrift/kumiko-renderer-puppeteer-client": "workspace:*",
|
|
23
25
|
"@cosmicdrift/kumiko-renderer-web": "workspace:*",
|
|
24
26
|
"@cosmicdrift/kumiko-server-runtime": "workspace:*",
|
|
25
27
|
"@cosmicdrift/kumiko-types": "workspace:*",
|
|
@@ -1,10 +1,45 @@
|
|
|
1
1
|
// @runtime test
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
defineAppE2eConfig,
|
|
4
|
+
E2E_TIMEOUT_MS,
|
|
5
|
+
PLAYWRIGHT_DEMO_ENV,
|
|
6
|
+
} from "@cosmicdrift/kumiko-testing/e2e";
|
|
7
|
+
import { chromium } from "@playwright/test";
|
|
3
8
|
import { E2E_PORTS } from "../../e2e/e2e-ports";
|
|
4
9
|
|
|
5
10
|
const PORT = E2E_PORTS["framework/use-all-bundled"];
|
|
11
|
+
const PRINT_SERVICE_PORT = E2E_PORTS["framework/use-all-bundled-puppeteer-service"];
|
|
12
|
+
// Both sides of the print service handshake; any value of 16+ characters will do for a local run.
|
|
13
|
+
const PRINT_SERVICE_TOKEN = "use-all-bundled-e2e-print-service";
|
|
6
14
|
|
|
7
|
-
|
|
15
|
+
const appConfig = defineAppE2eConfig({
|
|
8
16
|
port: PORT,
|
|
9
|
-
env:
|
|
17
|
+
env: {
|
|
18
|
+
...PLAYWRIGHT_DEMO_ENV,
|
|
19
|
+
PUPPETEER_SERVICE_URL: `http://127.0.0.1:${PRINT_SERVICE_PORT}`,
|
|
20
|
+
PUPPETEER_AUTH_TOKEN: PRINT_SERVICE_TOKEN,
|
|
21
|
+
},
|
|
10
22
|
});
|
|
23
|
+
|
|
24
|
+
// The PDF template editor prints through the real puppeteer-service, on the Chromium
|
|
25
|
+
// that `playwright install chromium` provides instead of a Chrome download of its own.
|
|
26
|
+
export default {
|
|
27
|
+
...appConfig,
|
|
28
|
+
webServer: [
|
|
29
|
+
{
|
|
30
|
+
command: "bun run src/index.ts",
|
|
31
|
+
cwd: "../../../apps/puppeteer-service",
|
|
32
|
+
url: `http://127.0.0.1:${PRINT_SERVICE_PORT}/healthz`,
|
|
33
|
+
env: {
|
|
34
|
+
PORT: String(PRINT_SERVICE_PORT),
|
|
35
|
+
PUPPETEER_AUTH_TOKEN: PRINT_SERVICE_TOKEN,
|
|
36
|
+
PUPPETEER_EXECUTABLE_PATH: chromium.executablePath(),
|
|
37
|
+
},
|
|
38
|
+
reuseExistingServer: false,
|
|
39
|
+
timeout: E2E_TIMEOUT_MS.webServer,
|
|
40
|
+
stdout: "pipe",
|
|
41
|
+
stderr: "pipe",
|
|
42
|
+
},
|
|
43
|
+
...[appConfig.webServer ?? []].flat(),
|
|
44
|
+
],
|
|
45
|
+
};
|
|
@@ -312,15 +312,25 @@ const FEATURE_IMPORT_REGISTRY: Record<string, FeatureImport> = {
|
|
|
312
312
|
path: "@cosmicdrift/kumiko-bundled-features/template-resolver",
|
|
313
313
|
factory: "createTemplateResolverFeature",
|
|
314
314
|
},
|
|
315
|
+
"document-designer": {
|
|
316
|
+
kind: "factory",
|
|
317
|
+
path: "@cosmicdrift/kumiko-document-designer",
|
|
318
|
+
factory: "createDocumentDesignerFeature",
|
|
319
|
+
},
|
|
315
320
|
"renderer-foundation": {
|
|
316
321
|
kind: "factory",
|
|
317
322
|
path: "@cosmicdrift/kumiko-bundled-features/renderer-foundation",
|
|
318
323
|
factory: "createRendererFoundationFeature",
|
|
319
324
|
},
|
|
320
|
-
"renderer-
|
|
325
|
+
"renderer-mail-html": {
|
|
326
|
+
kind: "factory",
|
|
327
|
+
path: "@cosmicdrift/kumiko-renderer-mail-html",
|
|
328
|
+
factory: "createRendererMailHtmlFeature",
|
|
329
|
+
},
|
|
330
|
+
"renderer-puppeteer-client": {
|
|
321
331
|
kind: "factory",
|
|
322
|
-
path: "@cosmicdrift/kumiko-
|
|
323
|
-
factory: "
|
|
332
|
+
path: "@cosmicdrift/kumiko-renderer-puppeteer-client",
|
|
333
|
+
factory: "createRendererPuppeteerClientFeature",
|
|
324
334
|
},
|
|
325
335
|
"renderer-pdf": {
|
|
326
336
|
kind: "factory",
|
|
@@ -19,6 +19,7 @@ import { createDataRetentionFeature } from "@cosmicdrift/kumiko-bundled-features
|
|
|
19
19
|
import { createUserDataRightsFeature } from "@cosmicdrift/kumiko-bundled-features/user-data-rights";
|
|
20
20
|
import { createWaitlistFeature } from "@cosmicdrift/kumiko-bundled-features/waitlist";
|
|
21
21
|
import { createTemplateResolverFeature } from "@cosmicdrift/kumiko-bundled-features/template-resolver";
|
|
22
|
+
import { createRendererPuppeteerClientFeature } from "@cosmicdrift/kumiko-renderer-puppeteer-client";
|
|
22
23
|
import { createManagedPagesFeature } from "@cosmicdrift/kumiko-bundled-features/managed-pages";
|
|
23
24
|
import { customFieldsFeature } from "@cosmicdrift/kumiko-bundled-features/custom-fields";
|
|
24
25
|
import { tagsFeature } from "@cosmicdrift/kumiko-bundled-features/tags";
|
|
@@ -42,6 +43,7 @@ const _dataRetention = createDataRetentionFeature();
|
|
|
42
43
|
const _userDataRights = createUserDataRightsFeature();
|
|
43
44
|
const _waitlist = createWaitlistFeature();
|
|
44
45
|
const _templateResolver = createTemplateResolverFeature();
|
|
46
|
+
const _rendererPuppeteerClient = createRendererPuppeteerClientFeature();
|
|
45
47
|
const _managedPages = createManagedPagesFeature({ resolveApexTenant: () => null, allowCustomCss: true });
|
|
46
48
|
const _customFields = customFieldsFeature;
|
|
47
49
|
const _tags = tagsFeature;
|
|
@@ -71,6 +73,7 @@ export const downloadAttemptTable = buildEntityTable("download-attempt", _userDa
|
|
|
71
73
|
export const waitlistEntryTable = buildEntityTable("waitlistEntry", _waitlist.entities["waitlistEntry"]!);
|
|
72
74
|
export const templateResourceTable = buildEntityTable("template-resource", _templateResolver.entities["template-resource"]!);
|
|
73
75
|
export const userContentEntryTable = buildEntityTable("user-content-entry", _templateResolver.entities["user-content-entry"]!);
|
|
76
|
+
export const renderedPdfTable = buildEntityTable("rendered-pdf", _rendererPuppeteerClient.entities["rendered-pdf"]!);
|
|
74
77
|
export const pageTable = buildEntityTable("page", _managedPages.entities["page"]!);
|
|
75
78
|
export const fieldDefinitionTable = buildEntityTable("field-definition", _customFields.entities["field-definition"]!);
|
|
76
79
|
export const tagTable = buildEntityTable("tag", _tags.entities["tag"]!);
|
|
@@ -51,6 +51,9 @@ const EXPECTED_REGISTRY_ONLY = new Set([
|
|
|
51
51
|
"cap-overview-labels", // app-local (src/app/), labels for this app's example cap-overview caps
|
|
52
52
|
"metrics-system", // from ./metrics, companion of createMetricsFeature (platform-wide scope)
|
|
53
53
|
"locale-de", // @cosmicdrift/kumiko-locale-de, not a bundled-features export
|
|
54
|
+
"renderer-mail-html", // @cosmicdrift/kumiko-renderer-mail-html, auto-mounted with auth by composeFeatures
|
|
55
|
+
"renderer-puppeteer-client", // @cosmicdrift/kumiko-renderer-puppeteer-client, not a bundled-features export
|
|
56
|
+
"document-designer", // @cosmicdrift/kumiko-document-designer, not a bundled-features export
|
|
54
57
|
]);
|
|
55
58
|
|
|
56
59
|
// Sub-paths in bundled-features's package.json exports (./tenant/seeding,
|
|
@@ -14,3 +14,6 @@ export const BETA_TENANT_ID = "00000000-0000-4000-8000-000000000002";
|
|
|
14
14
|
// Fixed id of the first seeded note, so the tags-section screenshot can navigate
|
|
15
15
|
// straight to /note-edit/<id> (the other seeded notes get minted uuids).
|
|
16
16
|
export const DEMO_NOTE_ID = "00000000-0000-4000-8000-00000000d001";
|
|
17
|
+
|
|
18
|
+
// Seeded PDF template that the pdf-template-editor spec opens.
|
|
19
|
+
export const INVOICE_TEMPLATE_SLUG = "billing:invoice";
|
|
@@ -33,6 +33,7 @@ import { tenantClient } from "@cosmicdrift/kumiko-bundled-features/tenant/web";
|
|
|
33
33
|
import { tierEngineClient } from "@cosmicdrift/kumiko-bundled-features/tier-engine/web";
|
|
34
34
|
import { userDataRightsClient } from "@cosmicdrift/kumiko-bundled-features/user-data-rights/web";
|
|
35
35
|
import { userProfileClient } from "@cosmicdrift/kumiko-bundled-features/user-profile/web";
|
|
36
|
+
import { documentDesignerClient } from "@cosmicdrift/kumiko-document-designer/web";
|
|
36
37
|
import { SYSTEM_TENANT_ID } from "@cosmicdrift/kumiko-framework/engine/types";
|
|
37
38
|
import { localeDeClient } from "@cosmicdrift/kumiko-locale-de/web";
|
|
38
39
|
import type { TranslationsByLocale } from "@cosmicdrift/kumiko-renderer";
|
|
@@ -121,6 +122,9 @@ createKumikoApp({
|
|
|
121
122
|
// nav node. Points at SYSTEM_TENANT because that is where the legal and
|
|
122
123
|
// marketing copy is seeded.
|
|
123
124
|
textBlocksClient({ navId: "app-screens:nav:content", tenantId: SYSTEM_TENANT_ID }),
|
|
125
|
+
// PDF template editor with live PDF preview, mounted as the custom screen
|
|
126
|
+
// app-screens declares (no nav entry; opened by URL).
|
|
127
|
+
documentDesignerClient(),
|
|
124
128
|
appScreens,
|
|
125
129
|
],
|
|
126
130
|
});
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// @runtime dev
|
|
2
|
+
// Seed data for the PDF template editor: the system invoice of a small property
|
|
3
|
+
// manager with its letterhead layout, plus one tenant customisation that is live
|
|
4
|
+
// and one that is still a draft, so the editor's "tenant customisations" drawer
|
|
5
|
+
// has both counts to show. System rows go through the template-resolver seed
|
|
6
|
+
// helper, tenant rows through the real upsert-tenant write.
|
|
7
|
+
|
|
8
|
+
import { TemplateResolverHandlers } from "@cosmicdrift/kumiko-bundled-features/template-resolver";
|
|
9
|
+
import { seedSystemTemplate } from "@cosmicdrift/kumiko-bundled-features/template-resolver/seeding";
|
|
10
|
+
import type { SeedFn } from "@cosmicdrift/kumiko-dev-server";
|
|
11
|
+
import type { SessionUser, TenantId } from "@cosmicdrift/kumiko-framework/engine";
|
|
12
|
+
import { TestUsers } from "@cosmicdrift/kumiko-framework/stack";
|
|
13
|
+
import { BETA_TENANT_ID, DEV_TENANT_ID, INVOICE_TEMPLATE_SLUG } from "./auth-constants";
|
|
14
|
+
|
|
15
|
+
type Stack = Parameters<SeedFn>[0];
|
|
16
|
+
|
|
17
|
+
const LETTERHEAD_SLUG = "briefpapier";
|
|
18
|
+
const LOCALE = "de";
|
|
19
|
+
|
|
20
|
+
const LETTERHEAD_BODY = [
|
|
21
|
+
"<div data-header><p>Nordlicht Immobilien GmbH</p><p>Hafenstraße 12 · 24103 Kiel</p></div>",
|
|
22
|
+
"<div data-content></div>",
|
|
23
|
+
'<div data-footer><p>Seite <span data-variable="page"></span> von <span data-variable="pages"></span></p></div>',
|
|
24
|
+
].join("");
|
|
25
|
+
|
|
26
|
+
// The page break puts the payment terms on page 2 whatever the length of the
|
|
27
|
+
// positions list: the print preview shows only two rows of any list.
|
|
28
|
+
const invoiceBody = (paymentNote: string): string =>
|
|
29
|
+
[
|
|
30
|
+
'<h1>Rechnung <span data-variable="number"></span></h1>',
|
|
31
|
+
'<p>Rechnungsdatum: <span data-variable="invoiceDate"></span></p>',
|
|
32
|
+
'<p><span data-variable="recipientName"></span></p>',
|
|
33
|
+
'<p><span data-variable="recipientAddress"></span></p>',
|
|
34
|
+
"<p>für die folgenden Leistungen im Abrechnungszeitraum stellen wir Ihnen in Rechnung:</p>",
|
|
35
|
+
'<table><tbody><tr data-repeat-header=""><th><p>Position</p></th><th><p>Betrag</p></th></tr>',
|
|
36
|
+
'<tr data-each="items"><td><p><span data-variable="description"></span></p></td><td><p><span data-variable="amount"></span></p></td></tr></tbody></table>',
|
|
37
|
+
'<p>Gesamtbetrag: <span data-variable="total"></span></p>',
|
|
38
|
+
'<div data-page-break=""></div>',
|
|
39
|
+
"<h2>Zahlungsbedingungen</h2>",
|
|
40
|
+
`<p>${paymentNote}</p>`,
|
|
41
|
+
"<p>Bankverbindung: Förde Sparkasse, IBAN DE89 3704 0044 0532 0130 00.</p>",
|
|
42
|
+
].join("");
|
|
43
|
+
|
|
44
|
+
const INVOICE_VARIABLES = {
|
|
45
|
+
number: { type: "text", label: "Rechnungsnummer", required: true, example: "2026-0142" },
|
|
46
|
+
invoiceDate: { type: "date", label: "Rechnungsdatum", example: "2026-10-01" },
|
|
47
|
+
recipientName: { type: "text", label: "Empfänger", example: "Mareike Jansen" },
|
|
48
|
+
recipientAddress: { type: "text", label: "Anschrift", example: "Kehdenstraße 14, 24103 Kiel" },
|
|
49
|
+
items: {
|
|
50
|
+
type: "list",
|
|
51
|
+
label: "Positionen",
|
|
52
|
+
item: {
|
|
53
|
+
description: { type: "text", label: "Beschreibung" },
|
|
54
|
+
amount: { type: "money", label: "Betrag" },
|
|
55
|
+
},
|
|
56
|
+
// Money examples are minor units (cents), like stored amounts.
|
|
57
|
+
example: [
|
|
58
|
+
{ description: "Kaltmiete Oktober 2026, Wohnung 3. OG links", amount: 78000 },
|
|
59
|
+
{ description: "Nebenkostenvorauszahlung Oktober 2026", amount: 18500 },
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
total: { type: "money", label: "Gesamtbetrag", example: 96500 },
|
|
63
|
+
} as const;
|
|
64
|
+
|
|
65
|
+
const INVOICE_META = {
|
|
66
|
+
layoutSlug: LETTERHEAD_SLUG,
|
|
67
|
+
pageFormat: "A4",
|
|
68
|
+
margins: { top: 35, bottom: 25 },
|
|
69
|
+
fileName: "Rechnung-{{number}}.pdf",
|
|
70
|
+
metadata: { title: "Rechnung {{number}}" },
|
|
71
|
+
} as const;
|
|
72
|
+
|
|
73
|
+
export async function seedPdfDocuments(stack: Stack, adminUserId: string): Promise<void> {
|
|
74
|
+
await seedSystemTemplate(stack.db, {
|
|
75
|
+
slug: LETTERHEAD_SLUG,
|
|
76
|
+
kind: "pdf-layout",
|
|
77
|
+
locale: LOCALE,
|
|
78
|
+
content: LETTERHEAD_BODY,
|
|
79
|
+
contentFormat: "html",
|
|
80
|
+
meta: {},
|
|
81
|
+
});
|
|
82
|
+
const system = await seedSystemTemplate(stack.db, {
|
|
83
|
+
slug: INVOICE_TEMPLATE_SLUG,
|
|
84
|
+
kind: "document-pdf",
|
|
85
|
+
locale: LOCALE,
|
|
86
|
+
content: invoiceBody("Bitte überweisen Sie den Betrag innerhalb von 14 Tagen."),
|
|
87
|
+
contentFormat: "html",
|
|
88
|
+
meta: INVOICE_META,
|
|
89
|
+
variableSchema: INVOICE_VARIABLES,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const admin: SessionUser = {
|
|
93
|
+
...TestUsers.systemAdmin,
|
|
94
|
+
tenantId: DEV_TENANT_ID as TenantId,
|
|
95
|
+
id: adminUserId,
|
|
96
|
+
};
|
|
97
|
+
const overrides = [
|
|
98
|
+
{
|
|
99
|
+
tenantId: DEV_TENANT_ID,
|
|
100
|
+
status: "active",
|
|
101
|
+
paymentNote:
|
|
102
|
+
"Bitte überweisen Sie den Betrag innerhalb von 7 Tagen unter Angabe der Rechnungsnummer.",
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
tenantId: BETA_TENANT_ID,
|
|
106
|
+
status: "draft",
|
|
107
|
+
paymentNote: "Der Betrag wird zum Monatsersten von Ihrem Konto eingezogen.",
|
|
108
|
+
},
|
|
109
|
+
] as const;
|
|
110
|
+
for (const override of overrides) {
|
|
111
|
+
await stack.http.writeOk(
|
|
112
|
+
TemplateResolverHandlers.upsertTenant,
|
|
113
|
+
{
|
|
114
|
+
slug: INVOICE_TEMPLATE_SLUG,
|
|
115
|
+
kind: "document-pdf",
|
|
116
|
+
locale: LOCALE,
|
|
117
|
+
content: invoiceBody(override.paymentNote),
|
|
118
|
+
contentFormat: "html",
|
|
119
|
+
meta: INVOICE_META,
|
|
120
|
+
variableSchema: INVOICE_VARIABLES,
|
|
121
|
+
parentTemplateId: system.id,
|
|
122
|
+
tenantIdOverride: override.tenantId,
|
|
123
|
+
status: override.status,
|
|
124
|
+
},
|
|
125
|
+
admin,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -37,6 +37,7 @@ import { generateId } from "@cosmicdrift/kumiko-framework/utils";
|
|
|
37
37
|
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
38
38
|
import { ADMIN_EMAIL, BETA_TENANT_ID, DEMO_NOTE_ID, DEV_TENANT_ID } from "./auth-constants";
|
|
39
39
|
import { noteEntity } from "./notes-feature";
|
|
40
|
+
import { seedPdfDocuments } from "./seed-documents";
|
|
40
41
|
|
|
41
42
|
// Event-store executors mirror the real handlers (createEntityExecutor pairs the
|
|
42
43
|
// projection table + executor), so seeded rows are proper event streams, not
|
|
@@ -392,6 +393,9 @@ export const seedScreenshotData: SeedFn = async (stack) => {
|
|
|
392
393
|
await stack.http.writeOk("auth-email-password:write:invite-create", invitee, inviter);
|
|
393
394
|
}
|
|
394
395
|
|
|
396
|
+
// PDF template editor — system invoice + letterhead, one live and one draft tenant override.
|
|
397
|
+
await seedPdfDocuments(stack, devAdminId);
|
|
398
|
+
|
|
395
399
|
// reply-snippets — entries for the rich collection. Written through the
|
|
396
400
|
// collection's own set-handler, the same path the editor uses, so the rows
|
|
397
401
|
// carry whatever the handler derives instead of a hand-built projection.
|