@cosmicdrift/kumiko-bundled-features 0.385.0 → 0.387.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/LICENSE +21 -57
- package/dist/agent-tools/tool-catalog.js +1 -1
- package/dist/agent-tools/tool-dispatch.js +0 -2
- package/dist/audit/screens.js +1 -1
- package/dist/auth-email-password/feature.js +1 -1
- package/dist/auth-email-password/handlers/change-password.write.js +3 -3
- package/dist/auth-email-password/handlers/confirm-token-flow.js +5 -5
- package/dist/auth-email-password/handlers/invite-accept-with-login.write.js +1 -1
- package/dist/auth-email-password/handlers/invite-accept.write.js +18 -18
- package/dist/auth-email-password/handlers/invite-create.write.d.ts +2 -2
- package/dist/auth-email-password/handlers/invite-create.write.js +10 -10
- package/dist/auth-email-password/handlers/invite-info.query.js +1 -1
- package/dist/auth-email-password/handlers/invite-signup-complete.write.js +24 -26
- package/dist/auth-email-password/handlers/login.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/login.write.js +1 -1
- package/dist/auth-email-password/handlers/self-registration-status.query.js +1 -1
- package/dist/auth-email-password/handlers/signup-confirm.write.js +34 -37
- package/dist/auth-email-password/handlers/signup-request.write.js +6 -7
- package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.d.ts +1 -1
- package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.js +1 -4
- package/dist/auth-email-password/index.js +5 -5
- package/dist/auth-email-password/lockout-store.js +1 -1
- package/dist/auth-email-password/seeding.d.ts +42 -45
- package/dist/auth-email-password/seeding.js +51 -53
- package/dist/auth-email-password/signup-token-store.js +8 -8
- package/dist/auth-email-password/testing.js +3 -3
- package/dist/auth-email-password/web/auth-client.d.ts +2 -2
- package/dist/auth-email-password/web/auth-client.js +36 -37
- package/dist/auth-email-password/web/auth-form-primitives.js +10 -10
- package/dist/auth-email-password/web/auth-gate.js +15 -16
- package/dist/auth-email-password/web/client-plugin.d.ts +7 -7
- package/dist/auth-email-password/web/client-plugin.js +4 -5
- package/dist/auth-email-password/web/confirm-account-unlock-screen.js +1 -1
- package/dist/auth-email-password/web/constants.js +3 -3
- package/dist/auth-email-password/web/default-topbar-actions.d.ts +8 -8
- package/dist/auth-email-password/web/default-topbar-actions.js +6 -6
- package/dist/auth-email-password/web/forgot-password-screen.d.ts +2 -2
- package/dist/auth-email-password/web/forgot-password-screen.js +9 -9
- package/dist/auth-email-password/web/index.js +5 -5
- package/dist/auth-email-password/web/invite-accept-screen.d.ts +1 -1
- package/dist/auth-email-password/web/invite-accept-screen.js +16 -16
- package/dist/auth-email-password/web/login-screen.d.ts +1 -1
- package/dist/auth-email-password/web/login-screen.js +2 -3
- package/dist/auth-email-password/web/reset-password-screen.d.ts +4 -4
- package/dist/auth-email-password/web/reset-password-screen.js +12 -13
- package/dist/auth-email-password/web/session.d.ts +10 -9
- package/dist/auth-email-password/web/session.js +28 -29
- package/dist/auth-email-password/web/signup-complete-screen.js +3 -3
- package/dist/auth-email-password/web/signup-screen.d.ts +1 -1
- package/dist/auth-email-password/web/signup-screen.js +13 -13
- package/dist/auth-email-password/web/tenant-switcher.d.ts +4 -4
- package/dist/auth-email-password/web/tenant-switcher.js +21 -22
- package/dist/auth-email-password/web/use-shell-user.js +12 -13
- package/dist/auth-email-password/web/user-menu.d.ts +4 -4
- package/dist/auth-email-password/web/user-menu.js +12 -13
- package/dist/auth-email-password/web/verify-email-screen.d.ts +2 -2
- package/dist/auth-email-password/web/verify-email-screen.js +9 -10
- package/dist/auth-foundation/boot-checks.js +4 -4
- package/dist/auth-foundation/resolve-anonymous-access.d.ts +1 -1
- package/dist/auth-foundation/resolve-anonymous-access.js +3 -3
- package/dist/auth-foundation/types.js +2 -2
- package/dist/auth-mfa/handlers/disable.write.js +3 -3
- package/dist/auth-mfa/handlers/enable-confirm-preauth.write.js +4 -4
- package/dist/auth-mfa/handlers/enable-confirm.write.js +2 -2
- package/dist/auth-mfa/handlers/enable-start-preauth.write.js +1 -1
- package/dist/auth-mfa/handlers/reencrypt.job.js +1 -1
- package/dist/auth-mfa/handlers/regenerate-recovery.write.js +5 -5
- package/dist/auth-mfa/handlers/verify.write.js +1 -1
- package/dist/auth-mfa/token-secrets.js +1 -1
- package/dist/auth-mfa/web/client-plugin.d.ts +1 -1
- package/dist/auth-mfa/web/client-plugin.js +1 -1
- package/dist/auth-mfa/web/i18n.js +3 -3
- package/dist/auth-mfa/web/index.js +4 -4
- package/dist/auth-mfa/web/mfa-client.js +17 -16
- package/dist/auth-mfa/web/mfa-verify-screen.js +6 -6
- package/dist/billing-foundation/aggregate-id.d.ts +5 -5
- package/dist/billing-foundation/aggregate-id.js +10 -11
- package/dist/billing-foundation/entities.js +27 -27
- package/dist/billing-foundation/events.js +18 -17
- package/dist/billing-foundation/feature.js +42 -43
- package/dist/billing-foundation/get-subscription-for-tenant.d.ts +3 -3
- package/dist/billing-foundation/get-subscription-for-tenant.js +3 -5
- package/dist/billing-foundation/handlers/create-checkout-session.write.js +18 -17
- package/dist/billing-foundation/handlers/create-portal-session.write.js +11 -12
- package/dist/billing-foundation/handlers/list-subscriptions.query.js +4 -4
- package/dist/billing-foundation/handlers/process-event.write.js +20 -20
- package/dist/billing-foundation/projection.d.ts +15 -11
- package/dist/billing-foundation/projection.js +38 -37
- package/dist/billing-foundation/subscription-tier-sync.js +3 -3
- package/dist/billing-foundation/tenant-destroy-hook.d.ts +2 -2
- package/dist/billing-foundation/tenant-destroy-hook.js +7 -7
- package/dist/billing-foundation/types.d.ts +40 -41
- package/dist/billing-foundation/types.js +20 -20
- package/dist/billing-foundation/web/billing-plans-panel.js +4 -4
- package/dist/cap-counter/aggregate-id.js +8 -9
- package/dist/cap-counter/constants.js +11 -12
- package/dist/cap-counter/enforce-cap.d.ts +59 -62
- package/dist/cap-counter/enforce-cap.js +47 -48
- package/dist/cap-counter/entity.js +29 -29
- package/dist/cap-counter/feature.js +34 -35
- package/dist/cap-counter/handlers/increment-rolling.write.d.ts +2 -2
- package/dist/cap-counter/handlers/increment-rolling.write.js +31 -31
- package/dist/cap-counter/handlers/mark-soft-warned.write.js +4 -5
- package/dist/cap-counter/stock-cap-guard.js +1 -1
- package/dist/cap-counter/with-cap-enforcement.d.ts +3 -5
- package/dist/channel-email/smtp-transport.d.ts +18 -17
- package/dist/channel-email/smtp-transport.js +24 -21
- package/dist/channel-in-app/handlers/unread-count.query.js +3 -4
- package/dist/compliance-profiles/feature.js +4 -4
- package/dist/compliance-profiles/handlers/for-tenant.query.js +3 -6
- package/dist/compliance-profiles/handlers/list-profiles.query.js +5 -5
- package/dist/compliance-profiles/handlers/needs-profile.query.js +4 -4
- package/dist/compliance-profiles/handlers/set-profile.write.js +13 -14
- package/dist/compliance-profiles/handlers/sub-processors.query.js +9 -11
- package/dist/compliance-profiles/resolve-for-tenant.js +7 -7
- package/dist/compliance-profiles/schema/profile-selection.js +18 -23
- package/dist/compliance-profiles/seeding.js +14 -15
- package/dist/compliance-profiles-ops/handlers/tenants-missing-profile.query.js +3 -3
- package/dist/compliance-profiles-ops/index.js +2 -2
- package/dist/config/handlers/readiness.query.d.ts +4 -4
- package/dist/config/handlers/readiness.query.js +1 -1
- package/dist/config/handlers/reencrypt.job.js +4 -5
- package/dist/config/handlers/set.write.js +4 -4
- package/dist/config/resolver.js +4 -4
- package/dist/config/table.js +10 -10
- package/dist/config/write-helpers.js +1 -1
- package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +2 -2
- package/dist/crypto-shredding/handlers/forget-subject.write.js +12 -11
- package/dist/custom-fields/aggregate-id.d.ts +12 -13
- package/dist/custom-fields/aggregate-id.js +16 -17
- package/dist/custom-fields/entity.js +49 -47
- package/dist/custom-fields/events.js +7 -8
- package/dist/custom-fields/feature.d.ts +14 -14
- package/dist/custom-fields/feature.js +53 -54
- package/dist/custom-fields/handlers/clear-custom-field.write.d.ts +3 -2
- package/dist/custom-fields/handlers/clear-custom-field.write.js +9 -8
- package/dist/custom-fields/handlers/define-tenant-field.write.d.ts +1 -1
- package/dist/custom-fields/handlers/define-tenant-field.write.js +2 -2
- package/dist/custom-fields/handlers/delete-system-field.write.js +6 -7
- package/dist/custom-fields/handlers/delete-tenant-field.write.d.ts +1 -1
- package/dist/custom-fields/handlers/delete-tenant-field.write.js +3 -3
- package/dist/custom-fields/handlers/set-custom-field.write.d.ts +3 -3
- package/dist/custom-fields/handlers/set-custom-field.write.js +25 -28
- package/dist/custom-fields/handlers/update-tenant-field.write.d.ts +1 -1
- package/dist/custom-fields/handlers/update-tenant-field.write.js +1 -1
- package/dist/custom-fields/lib/field-access.js +2 -2
- package/dist/custom-fields/lib/parse-serialized-field.js +1 -1
- package/dist/custom-fields/lib/quota.js +1 -1
- package/dist/custom-fields/lib/value-schema.js +10 -12
- package/dist/custom-fields/run-retention.js +3 -3
- package/dist/custom-fields/schemas.js +14 -14
- package/dist/custom-fields/web/client-plugin.js +2 -5
- package/dist/custom-fields/web/constants.js +2 -2
- package/dist/custom-fields/web/custom-fields-form-section.d.ts +4 -4
- package/dist/custom-fields/web/custom-fields-form-section.js +22 -22
- package/dist/custom-fields/wire-for-entity.js +65 -67
- package/dist/custom-fields/wire-user-data-rights.js +3 -3
- package/dist/data-retention/_internal/parse-override.js +2 -3
- package/dist/data-retention/feature.js +11 -18
- package/dist/data-retention/handlers/policy-for.query.js +6 -6
- package/dist/data-retention/keep-for.d.ts +7 -7
- package/dist/data-retention/keep-for.js +15 -15
- package/dist/data-retention/override-schema.d.ts +3 -4
- package/dist/data-retention/override-schema.js +13 -15
- package/dist/data-retention/presets.d.ts +4 -5
- package/dist/data-retention/presets.js +18 -23
- package/dist/data-retention/resolve-tenant-preset.js +17 -16
- package/dist/data-retention/resolver.d.ts +12 -12
- package/dist/data-retention/resolver.js +24 -23
- package/dist/data-retention/run-retention-cleanup.d.ts +8 -3
- package/dist/data-retention/run-retention-cleanup.js +61 -51
- package/dist/data-retention/schema/tenant-retention-override.js +13 -11
- package/dist/delivery/feature.js +2 -2
- package/dist/delivery/handlers/log.query.js +1 -1
- package/dist/delivery/tables.js +9 -8
- package/dist/delivery/unsubscribe.js +4 -4
- package/dist/document-ingest-foundation/entity.js +4 -4
- package/dist/document-ingest-foundation/events.js +2 -2
- package/dist/document-ingest-foundation/feature.js +2 -2
- package/dist/document-ingest-foundation/pages.js +1 -1
- package/dist/document-ingest-foundation/tenant-destroy-hook.js +4 -4
- package/dist/feature-toggles/compose-tier-resolver.js +1 -1
- package/dist/feature-toggles/feature.js +1 -1
- package/dist/feature-toggles/global-feature-state-table.js +1 -1
- package/dist/feature-toggles/handlers/registered.query.js +5 -5
- package/dist/feature-toggles/toggle-sync-signal.js +1 -1
- package/dist/feature-toggles/web/constants.js +1 -1
- package/dist/file-derivatives/feature.d.ts +1 -1
- package/dist/file-derivatives/feature.js +1 -1
- package/dist/file-derivatives/handlers/public-variant.query.js +1 -1
- package/dist/file-derivatives/presets.js +1 -1
- package/dist/file-foundation/feature.js +6 -6
- package/dist/file-provider-inmemory/feature.d.ts +1 -1
- package/dist/file-provider-inmemory/feature.js +16 -16
- package/dist/file-provider-s3/feature.js +16 -16
- package/dist/file-provider-s3/lib/s3-provider.js +6 -6
- package/dist/files/feature.js +6 -6
- package/dist/files-tenant-data/handlers/sweep-orphaned-derivatives.job.js +4 -4
- package/dist/files-tenant-data/hooks.js +24 -26
- package/dist/files-tenant-data/index.js +1 -1
- package/dist/folders/feature.d.ts +1 -1
- package/dist/folders/web/folder-manager.js +2 -2
- package/dist/folders/web/tree.js +5 -5
- package/dist/form-draft/db/queries/cleanup.js +1 -1
- package/dist/form-draft/db/queries/owned-file-refs.js +1 -1
- package/dist/form-draft/entity.js +3 -3
- package/dist/form-draft/feature.js +4 -5
- package/dist/form-draft/handlers/discard.write.js +1 -1
- package/dist/form-draft/release-file-refs.js +6 -6
- package/dist/form-draft/schemas.js +3 -3
- package/dist/form-draft/web/constants.js +0 -2
- package/dist/inbound-mail-foundation/aggregate-id.d.ts +13 -13
- package/dist/inbound-mail-foundation/aggregate-id.js +19 -19
- package/dist/inbound-mail-foundation/connect-routes.js +4 -3
- package/dist/inbound-mail-foundation/constants.d.ts +22 -24
- package/dist/inbound-mail-foundation/constants.js +30 -33
- package/dist/inbound-mail-foundation/entities.d.ts +12 -12
- package/dist/inbound-mail-foundation/entities.js +47 -48
- package/dist/inbound-mail-foundation/events.d.ts +4 -3
- package/dist/inbound-mail-foundation/events.js +50 -47
- package/dist/inbound-mail-foundation/feature.js +39 -39
- package/dist/inbound-mail-foundation/handlers/account-state.js +8 -8
- package/dist/inbound-mail-foundation/handlers/connect-account.write.js +25 -26
- package/dist/inbound-mail-foundation/handlers/disconnect-account.write.js +7 -7
- package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +50 -51
- package/dist/inbound-mail-foundation/handlers/list-accounts.query.js +8 -8
- package/dist/inbound-mail-foundation/handlers/list-messages.query.js +10 -10
- package/dist/inbound-mail-foundation/handlers/scope-visibility.js +3 -4
- package/dist/inbound-mail-foundation/handlers/update-account.write.js +11 -11
- package/dist/inbound-mail-foundation/oauth-state.d.ts +5 -5
- package/dist/inbound-mail-foundation/oauth-state.js +11 -10
- package/dist/inbound-mail-foundation/projection.d.ts +4 -4
- package/dist/inbound-mail-foundation/projection.js +31 -29
- package/dist/inbound-mail-foundation/provider-factory.d.ts +4 -4
- package/dist/inbound-mail-foundation/provider-factory.js +9 -9
- package/dist/inbound-mail-foundation/retention-sweep.d.ts +5 -3
- package/dist/inbound-mail-foundation/retention-sweep.js +38 -36
- package/dist/inbound-mail-foundation/tenant-destroy-hook.js +14 -16
- package/dist/inbound-mail-foundation/types.d.ts +45 -46
- package/dist/inbound-mail-foundation/types.js +21 -21
- package/dist/inbound-mail-foundation/watch-supervisor.d.ts +10 -10
- package/dist/inbound-mail-foundation/watch-supervisor.js +57 -56
- package/dist/inbound-provider-imap/credential-document.js +13 -13
- package/dist/inbound-provider-imap/feature.d.ts +2 -2
- package/dist/inbound-provider-imap/feature.js +42 -40
- package/dist/inbound-provider-imap/imap-client.d.ts +12 -11
- package/dist/inbound-provider-imap/imap-client.js +20 -19
- package/dist/inbound-provider-inmemory/feature.d.ts +9 -9
- package/dist/inbound-provider-inmemory/feature.js +19 -19
- package/dist/jobs/db/queries/retention.js +2 -2
- package/dist/jobs/db/queries/stale-run-sweep.js +3 -3
- package/dist/jobs/events.js +1 -1
- package/dist/jobs/feature.js +5 -6
- package/dist/jobs/handlers/detail.query.js +4 -4
- package/dist/jobs/handlers/list.query.js +1 -1
- package/dist/jobs/handlers/projection-rebuild.job.js +1 -1
- package/dist/jobs/handlers/reindex-entity.job.js +1 -1
- package/dist/jobs/handlers/retry.write.js +1 -1
- package/dist/jobs/job-instant.js +1 -1
- package/dist/jobs/job-run-logger.js +10 -11
- package/dist/jobs/job-run-table.js +3 -3
- package/dist/jobs/screens.js +1 -1
- package/dist/jobs/tenant-job-failure-table.js +1 -1
- package/dist/jobs/tenant-job-run-table.js +1 -1
- package/dist/ledger/entity.js +5 -5
- package/dist/ledger/feature.js +3 -3
- package/dist/ledger/handlers/confirm-schedule-period.write.js +3 -3
- package/dist/ledger/recurring.js +12 -12
- package/dist/ledger/schemas.js +1 -1
- package/dist/ledger/web/constants.js +2 -2
- package/dist/ledger/web/index.js +7 -7
- package/dist/legal-pages/feature.d.ts +4 -4
- package/dist/legal-pages/feature.js +25 -26
- package/dist/legal-pages/markdown.js +3 -3
- package/dist/legal-pages/web/client-plugin.js +23 -24
- package/dist/legal-pages/web/index.js +0 -1
- package/dist/mail-foundation/feature.d.ts +2 -2
- package/dist/mail-foundation/feature.js +24 -25
- package/dist/mail-transport-inmemory/feature.d.ts +4 -4
- package/dist/mail-transport-inmemory/feature.js +27 -28
- package/dist/mail-transport-smtp/feature.js +20 -20
- package/dist/managed-pages/branding.js +6 -6
- package/dist/managed-pages/feature.d.ts +26 -26
- package/dist/managed-pages/feature.js +34 -34
- package/dist/managed-pages/handlers/by-slug.query.js +5 -6
- package/dist/managed-pages/handlers/by-tenant-published.query.js +2 -2
- package/dist/managed-pages/handlers/set.write.js +5 -7
- package/dist/managed-pages/screens/page-screens.js +11 -11
- package/dist/managed-pages/seeding.js +8 -8
- package/dist/managed-pages/table.js +13 -12
- package/dist/managed-pages/web/client-plugin.d.ts +1 -1
- package/dist/managed-pages/web/client-plugin.js +5 -5
- package/dist/managed-pages/web/i18n.js +1 -1
- package/dist/notes-history/entity.js +4 -4
- package/dist/notes-history/feature.d.ts +2 -2
- package/dist/notes-history-user-data/hooks.js +1 -1
- package/dist/page-render/layout.js +9 -9
- package/dist/page-render/markdown.js +11 -11
- package/dist/page-render/security-headers.js +7 -6
- package/dist/personal-access-tokens/feature.js +5 -5
- package/dist/personal-access-tokens/roles.js +2 -2
- package/dist/readiness/handlers/status.query.js +3 -3
- package/dist/renderer-foundation/api.js +12 -13
- package/dist/renderer-foundation/constants.js +2 -2
- package/dist/renderer-foundation/feature.js +7 -7
- package/dist/secrets/feature.js +9 -9
- package/dist/secrets/web/constants.js +2 -2
- package/dist/seo/feature.js +3 -3
- package/dist/sessions/constants.d.ts +1 -1
- package/dist/sessions/constants.js +1 -1
- package/dist/sessions/feature.js +8 -8
- package/dist/sessions/handlers/revoke-all-for-user.write.js +2 -2
- package/dist/sessions/handlers/revoke-all-others.write.js +2 -2
- package/dist/sessions/handlers/revoke.write.js +1 -1
- package/dist/sessions/schema/user-session.js +4 -4
- package/dist/sessions/screens.js +2 -2
- package/dist/sessions/session-callbacks.js +2 -2
- package/dist/sessions/session-revoked-event.js +2 -2
- package/dist/shared/assert-no-where-rule-in-ownership-write.js +1 -1
- package/dist/shared/decrypt-stored-pii.js +1 -1
- package/dist/shared/encrypt-for-direct-write.js +1 -1
- package/dist/shared/map-with-concurrency.js +5 -4
- package/dist/shared/parent-visibility.js +2 -2
- package/dist/shared/password-hashing.js +1 -1
- package/dist/shared/signup-handover.js +1 -2
- package/dist/shared/single-use-token-store.js +1 -1
- package/dist/subscription-mollie/constants.js +15 -17
- package/dist/subscription-mollie/feature.d.ts +17 -18
- package/dist/subscription-mollie/feature.js +24 -24
- package/dist/subscription-mollie/index.js +3 -3
- package/dist/subscription-mollie/plugin-methods.d.ts +2 -2
- package/dist/subscription-mollie/plugin-methods.js +15 -14
- package/dist/subscription-mollie/verify-webhook.d.ts +10 -10
- package/dist/subscription-mollie/verify-webhook.js +27 -27
- package/dist/subscription-stripe/constants.js +4 -6
- package/dist/subscription-stripe/feature.d.ts +14 -14
- package/dist/subscription-stripe/feature.js +35 -34
- package/dist/subscription-stripe/index.js +6 -6
- package/dist/subscription-stripe/plugin-methods.js +18 -18
- package/dist/subscription-stripe/runtime.d.ts +1 -1
- package/dist/subscription-stripe/runtime.js +1 -1
- package/dist/subscription-stripe/verify-webhook.d.ts +11 -11
- package/dist/subscription-stripe/verify-webhook.js +59 -61
- package/dist/tags/feature.d.ts +3 -3
- package/dist/tags/screens.js +1 -1
- package/dist/template-resolver/api.js +10 -10
- package/dist/template-resolver/handlers/find-by-id.query.js +5 -5
- package/dist/template-resolver/handlers/list.query.js +1 -1
- package/dist/template-resolver/handlers/shared.js +2 -2
- package/dist/template-resolver/handlers/template-write.js +3 -3
- package/dist/template-resolver/handlers/upsert-system.write.js +3 -4
- package/dist/template-resolver/handlers/upsert-tenant.write.js +4 -5
- package/dist/template-resolver/seeding.js +4 -4
- package/dist/template-resolver/table.js +10 -11
- package/dist/template-resolver/web/client-plugin.js +2 -2
- package/dist/tenant/feature.js +7 -7
- package/dist/tenant/handlers/member-directory.query.js +1 -1
- package/dist/tenant/handlers/members.query.js +1 -1
- package/dist/tenant/handlers/team-list.query.js +1 -1
- package/dist/tenant/handlers/tenant-directory.query.js +1 -1
- package/dist/tenant/invitation-table.js +37 -40
- package/dist/tenant/membership-table.js +3 -3
- package/dist/tenant/schema/tenant.js +7 -9
- package/dist/tenant/screens.js +1 -1
- package/dist/tenant/seeding.d.ts +6 -5
- package/dist/tenant/seeding.js +12 -12
- package/dist/tenant/testing.js +5 -6
- package/dist/tenant/web/constants.js +2 -2
- package/dist/tenant-handover/events.js +5 -7
- package/dist/tenant-handover/feature.js +1 -1
- package/dist/tenant-handover/grant.js +1 -1
- package/dist/tenant-handover/handlers/claim.write.js +1 -1
- package/dist/tenant-handover/move-entity-graph.js +8 -9
- package/dist/tenant-handover/signup-handover-provider.js +1 -2
- package/dist/tenant-handover/transfer-graph.js +4 -5
- package/dist/tenant-lifecycle/boot-checks.js +1 -1
- package/dist/tenant-lifecycle/feature.js +1 -1
- package/dist/tenant-settings/constants.js +1 -1
- package/dist/tenant-settings/tenant-defaults.d.ts +1 -1
- package/dist/tenant-settings/tenant-defaults.js +9 -2
- package/dist/tier-engine/aggregate-id.d.ts +11 -11
- package/dist/tier-engine/aggregate-id.js +15 -16
- package/dist/tier-engine/compose-app.d.ts +14 -14
- package/dist/tier-engine/compose-app.js +1 -1
- package/dist/tier-engine/entity.js +18 -19
- package/dist/tier-engine/feature.d.ts +19 -17
- package/dist/tier-engine/feature.js +68 -69
- package/dist/tier-engine/handlers/active-tier.query.js +6 -7
- package/dist/tier-engine/handlers/get-tenant-tier.query.js +4 -4
- package/dist/tier-engine/handlers/set-tenant-tier.write.d.ts +5 -5
- package/dist/tier-engine/handlers/set-tenant-tier.write.js +3 -3
- package/dist/tier-engine/tier-resolver.js +2 -2
- package/dist/tier-engine/trial.js +8 -8
- package/dist/tier-engine/web/index.js +4 -4
- package/dist/user/db/queries/stream-tenant-backfill.js +8 -8
- package/dist/user/handlers/create.write.js +4 -4
- package/dist/user/schema/user.d.ts +11 -11
- package/dist/user/schema/user.js +45 -44
- package/dist/user/seeding.d.ts +15 -15
- package/dist/user/seeding.js +28 -28
- package/dist/user/testing.js +3 -3
- package/dist/user-data-rights/audit-download.d.ts +8 -8
- package/dist/user-data-rights/audit-download.js +19 -20
- package/dist/user-data-rights/boot-checks.js +1 -1
- package/dist/user-data-rights/deletion-token.js +1 -1
- package/dist/user-data-rights/feature.d.ts +49 -50
- package/dist/user-data-rights/feature.js +54 -53
- package/dist/user-data-rights/handlers/cancel-deletion.write.js +9 -9
- package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.js +8 -8
- package/dist/user-data-rights/handlers/download-by-job.query.js +29 -30
- package/dist/user-data-rights/handlers/download-by-token.query.js +40 -42
- package/dist/user-data-rights/handlers/export-status.query.js +8 -9
- package/dist/user-data-rights/handlers/lift-restriction.write.js +7 -8
- package/dist/user-data-rights/handlers/list-download-attempts.query.js +2 -2
- package/dist/user-data-rights/handlers/my-audit-log.query.js +4 -4
- package/dist/user-data-rights/handlers/request-deletion-by-email.write.d.ts +5 -5
- package/dist/user-data-rights/handlers/request-deletion-by-email.write.js +16 -15
- package/dist/user-data-rights/handlers/request-deletion.write.d.ts +2 -2
- package/dist/user-data-rights/handlers/request-deletion.write.js +7 -9
- package/dist/user-data-rights/handlers/request-export.write.js +42 -41
- package/dist/user-data-rights/handlers/restrict-account.write.js +22 -19
- package/dist/user-data-rights/handlers/run-forget-cleanup.write.js +8 -8
- package/dist/user-data-rights/index.js +8 -10
- package/dist/user-data-rights/lib/default-mailers.js +3 -3
- package/dist/user-data-rights/lib/update-user-lifecycle.js +14 -17
- package/dist/user-data-rights/run-export-jobs.d.ts +38 -42
- package/dist/user-data-rights/run-export-jobs.js +127 -233
- package/dist/user-data-rights/run-forget-cleanup.d.ts +16 -20
- package/dist/user-data-rights/run-forget-cleanup.js +63 -82
- package/dist/user-data-rights/run-user-export.d.ts +34 -33
- package/dist/user-data-rights/run-user-export.js +55 -57
- package/dist/user-data-rights/schema/download-attempt.js +11 -11
- package/dist/user-data-rights/schema/download-token.js +37 -41
- package/dist/user-data-rights/schema/export-job.d.ts +4 -4
- package/dist/user-data-rights/schema/export-job.js +65 -67
- package/dist/user-data-rights/token-helpers.d.ts +8 -9
- package/dist/user-data-rights/token-helpers.js +21 -25
- package/dist/user-data-rights/web/client-plugin.d.ts +5 -5
- package/dist/user-data-rights/web/client-plugin.js +1 -1
- package/dist/user-data-rights/web/confirm-deletion-screen.js +6 -5
- package/dist/user-data-rights/web/constants.js +1 -1
- package/dist/user-data-rights/web/index.js +5 -5
- package/dist/user-data-rights/web/privacy-center-screen.js +14 -13
- package/dist/user-data-rights/web/public-deletion-gate.d.ts +4 -4
- package/dist/user-data-rights/web/request-deletion-screen.js +6 -6
- package/dist/user-data-rights/zip-path.d.ts +15 -15
- package/dist/user-data-rights/zip-path.js +41 -40
- package/dist/user-data-rights-defaults/feature.js +15 -15
- package/dist/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.js +3 -5
- package/dist/user-data-rights-defaults/hooks/file-ref.userdata-hook.js +45 -51
- package/dist/user-data-rights-defaults/hooks/job-run.userdata-hook.js +2 -2
- package/dist/user-data-rights-defaults/hooks/notification-preference.userdata-hook.js +1 -1
- package/dist/user-data-rights-defaults/hooks/user-session.userdata-hook.js +3 -3
- package/dist/user-data-rights-defaults/hooks/user.userdata-hook.js +32 -31
- package/dist/user-profile/handlers/change-email.write.js +13 -13
- package/dist/user-profile/index.js +3 -3
- package/dist/user-profile/web/client-plugin.js +1 -1
- package/dist/user-profile/web/constants.js +1 -1
- package/dist/user-profile/web/profile-screen.js +1 -1
- package/dist/workflow-runner/aggregate-id.d.ts +1 -1
- package/dist/workflow-runner/aggregate-id.js +1 -1
- package/dist/workflow-runner/event-subscriber.js +4 -5
- package/dist/workflow-runner/event-trigger.js +4 -17
- package/dist/workflow-runner/feature.js +2 -2
- package/dist/workflow-runner/handlers/resume-run.write.js +4 -4
- package/dist/workflow-runner/pending-projection.js +6 -7
- package/dist/workflow-runner/runner.js +6 -6
- package/dist/workflow-runner/tables.js +6 -6
- package/dist/workflow-runner/workflow-registry.js +1 -1
- package/package.json +10 -10
|
@@ -2,23 +2,21 @@ import { KumikoError } from "@cosmicdrift/kumiko-framework/errors";
|
|
|
2
2
|
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
3
3
|
import { type CapCounterContext } from "./book-cap-usage.ts";
|
|
4
4
|
/**
|
|
5
|
-
* Cap-
|
|
6
|
-
* `project_pricing_byok_caps` §3 + `docs/plans/marketing/produkt/
|
|
7
|
-
* pricing.md` Cap-Verhalten-Block.
|
|
5
|
+
* Cap-tolerance profiles, asymmetric by cap type.
|
|
8
6
|
*
|
|
9
|
-
* **Soft** =
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* **Soft** = notification threshold (multiplier × limit). Once reached,
|
|
8
|
+
* a warning is issued (`lastSoftWarnedAt` sets the flag); caller code emits
|
|
9
|
+
* the actual notification.
|
|
12
10
|
*
|
|
13
|
-
* **Hard** =
|
|
14
|
-
*
|
|
11
|
+
* **Hard** = write-block threshold (multiplier × limit). `enforceCap` throws
|
|
12
|
+
* a `cap_exceeded` error, which the dispatcher maps to 429 with an upgrade hint.
|
|
15
13
|
*/
|
|
16
14
|
export type CapToleranceProfile = {
|
|
17
15
|
readonly soft: number;
|
|
18
16
|
readonly hard: number;
|
|
19
17
|
};
|
|
20
18
|
export declare const CAP_TOLERANCES: {
|
|
21
|
-
/** Mails /
|
|
19
|
+
/** Mails / tokens — inexpensive, with BYOK available from Pro. Generous burst buffer. */
|
|
22
20
|
readonly burstable: {
|
|
23
21
|
readonly soft: 1.1;
|
|
24
22
|
readonly hard: 1.2;
|
|
@@ -28,12 +26,12 @@ export declare const CAP_TOLERANCES: {
|
|
|
28
26
|
readonly soft: 1;
|
|
29
27
|
readonly hard: 1.05;
|
|
30
28
|
};
|
|
31
|
-
/**
|
|
29
|
+
/** App count and platform slots — purchased capacity, with no buffer. */
|
|
32
30
|
readonly hardSlot: {
|
|
33
31
|
readonly soft: 1;
|
|
34
32
|
readonly hard: 1;
|
|
35
33
|
};
|
|
36
|
-
/** Egress —
|
|
34
|
+
/** Egress — bursty traffic is legitimate; only extreme spikes are blocked. */
|
|
37
35
|
readonly egress: {
|
|
38
36
|
readonly soft: 1.1;
|
|
39
37
|
readonly hard: 1.3;
|
|
@@ -92,28 +90,26 @@ export declare function enforceCap(ctx: CapCounterContext, options: {
|
|
|
92
90
|
readonly i18nKey?: string;
|
|
93
91
|
}): Promise<EnforceCapResult>;
|
|
94
92
|
/**
|
|
95
|
-
* Synchronous read-and-check of the calling tenant's
|
|
96
|
-
*
|
|
97
|
-
* `windowDays`
|
|
93
|
+
* Synchronous read-and-check of the calling tenant's rolling-window
|
|
94
|
+
* counter for `capName`. Reads increment events from the last
|
|
95
|
+
* `windowDays` in the event store and sums their `amount`. Returns:
|
|
98
96
|
* - "ok" when sum < soft-threshold
|
|
99
97
|
* - "soft-hit" when soft ≤ sum < hard.
|
|
100
98
|
*
|
|
101
99
|
* **Throws** `CapExceededError` when sum ≥ hard-threshold.
|
|
102
100
|
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* `lastSoftWarnedAt
|
|
106
|
-
*
|
|
107
|
-
* memoization
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* `false` (= "wir tracken's nicht").
|
|
101
|
+
* **The `crossed` flag is intentionally absent:** Unlike the calendar
|
|
102
|
+
* counter, the rolling aggregate has no projection row with a
|
|
103
|
+
* `lastSoftWarnedAt` flag. The caller must deduplicate notification storms
|
|
104
|
+
* using its own mechanism, such as a cache-table key or request-lifetime
|
|
105
|
+
* memoization. The result shape still matches `EnforceCapResult` so the same
|
|
106
|
+
* caller code works with both functions; `crossed` is always `false` here
|
|
107
|
+
* (= "not tracked").
|
|
111
108
|
*
|
|
112
|
-
* **Performance
|
|
113
|
-
* (tenant, capName).
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* vorgezogen.
|
|
109
|
+
* **Performance note:** The read sums ALL events in the window for
|
|
110
|
+
* (tenant, capName). With 10k+ events per tenant in the window, this could
|
|
111
|
+
* become slow; migrate to a multi-stream projection with pre-aggregated
|
|
112
|
+
* daily buckets if needed.
|
|
117
113
|
*/
|
|
118
114
|
export declare function enforceRollingCap(ctx: CapCounterContext, options: {
|
|
119
115
|
readonly capName: string;
|
|
@@ -153,13 +149,13 @@ export declare class CapExceededError extends KumikoError {
|
|
|
153
149
|
export declare function currentCalendarMonthStartIso(now?: Temporal.Instant): string;
|
|
154
150
|
export declare function calendarMonthPeriodEndIso(periodStartIso: string): string;
|
|
155
151
|
/**
|
|
156
|
-
* Soft-hit
|
|
157
|
-
* delivery
|
|
158
|
-
*
|
|
159
|
-
* (`crossed === true
|
|
152
|
+
* Soft-hit notifier callback. The caller supplies the function that emits
|
|
153
|
+
* a delivery event (for example, `delivery.send({to, template, payload})`).
|
|
154
|
+
* It is called exactly once per period for the calendar counter
|
|
155
|
+
* (`crossed === true`, deduplicated via `markSoftWarnedHandler`).
|
|
160
156
|
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
157
|
+
* For the rolling counter, `crossed` is always `false`; the caller must
|
|
158
|
+
* deduplicate notifications itself or intentionally send one per request.
|
|
163
159
|
*/
|
|
164
160
|
export type SoftHitNotifier = (info: {
|
|
165
161
|
readonly capName: string;
|
|
@@ -168,14 +164,14 @@ export type SoftHitNotifier = (info: {
|
|
|
168
164
|
readonly tenantId: string;
|
|
169
165
|
}) => Promise<void> | void;
|
|
170
166
|
/**
|
|
171
|
-
* Calendar-
|
|
172
|
-
*
|
|
173
|
-
* `mark-soft-warned
|
|
174
|
-
*
|
|
167
|
+
* Calendar-period enforcement with automatic soft-hit notification.
|
|
168
|
+
* Calls `enforceCap`; when `crossed: true`, it calls the notifier and the
|
|
169
|
+
* `mark-soft-warned` handler, which flips `lastSoftWarnedAt` so that the
|
|
170
|
+
* same period does not trigger another notification.
|
|
175
171
|
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
172
|
+
* Returns the `EnforceCapResult` unchanged, allowing the caller to branch
|
|
173
|
+
* on the result, such as showing a UI toast in addition to the email
|
|
174
|
+
* notification.
|
|
179
175
|
*/
|
|
180
176
|
export declare function enforceCapAndMaybeNotify(ctx: CapCounterContext, options: {
|
|
181
177
|
readonly capName: string;
|
|
@@ -189,14 +185,14 @@ export declare function enforceCapAndMaybeNotify(ctx: CapCounterContext, options
|
|
|
189
185
|
readonly markSoftWarnedOutsideTransaction?: boolean;
|
|
190
186
|
}): Promise<EnforceCapResult>;
|
|
191
187
|
/**
|
|
192
|
-
* Rolling-
|
|
188
|
+
* Rolling-window enforcement that always sends a notification on a soft hit.
|
|
193
189
|
*
|
|
194
|
-
* **
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
190
|
+
* **Storm risk:** The rolling counter does NOT track `lastSoftWarnedAt`
|
|
191
|
+
* (there is no projection row). On every call while the counter is in the
|
|
192
|
+
* soft range, the notifier fires. The caller must deduplicate, for example
|
|
193
|
+
* with a cache entry `lastNotified[capName]` and a TTL, or call
|
|
194
|
+
* `enforceRollingCapAndMaybeNotify` only once per day or hour
|
|
195
|
+
* (an hourly cron instead of per request).
|
|
200
196
|
*/
|
|
201
197
|
export declare function enforceRollingCapAndMaybeNotify(ctx: CapCounterContext, options: {
|
|
202
198
|
readonly capName: string;
|
|
@@ -215,24 +211,25 @@ export type StockCapResult = {
|
|
|
215
211
|
readonly limit: number;
|
|
216
212
|
};
|
|
217
213
|
/**
|
|
218
|
-
* Stock
|
|
219
|
-
*
|
|
214
|
+
* Stock cap: checks a cardinality counted LIVE by the caller (for example,
|
|
215
|
+
* the number of existing components for a tenant) against a tier limit.
|
|
220
216
|
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
* (`count(*) WHERE tenant_id = …`)
|
|
224
|
-
* (
|
|
225
|
-
*
|
|
217
|
+
* Unlike {@link enforceCap}/{@link enforceRollingCap}, there is NO stored
|
|
218
|
+
* counter: the caller counts the projection itself
|
|
219
|
+
* (`count(*) WHERE tenant_id = …`) and passes `current`. This avoids drift
|
|
220
|
+
* (a delete immediately frees the slot), requires no counter table or
|
|
221
|
+
* increment/decrement bookkeeping, and measures a stock rather than a flow.
|
|
226
222
|
*
|
|
227
|
-
* **TOCTOU
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
223
|
+
* **TOCTOU caveat:** Counting and writing are not atomic—two concurrent
|
|
224
|
+
* creates can both see `ok` and exceed the limit by one (the same race as
|
|
225
|
+
* with {@link enforceCap}). Strictly hard slots need additional
|
|
226
|
+
* serialization in the create path, such as a unique index on
|
|
227
|
+
* tenantId+slot.
|
|
231
228
|
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
229
|
+
* Pure function—it does NOT throw or map an HTTP status. Reaching a stock
|
|
230
|
+
* limit means "upgrade required", not "retry later" (429); the caller
|
|
231
|
+
* chooses the response, typically an app-specific 422/`upgrade_required`
|
|
232
|
+
* with i18n. With `hardSlot` (soft=hard=1.0), the boundary is exactly `limit`.
|
|
236
233
|
*/
|
|
237
234
|
export declare function enforceStockCap(options: {
|
|
238
235
|
readonly current: number;
|
|
@@ -5,13 +5,13 @@ import { markCapSoftWarned, readRollingCapUsage, resolveCapCounterScope, } from
|
|
|
5
5
|
import { capCounterEntity } from "./entity.js";
|
|
6
6
|
const { table } = createEntityExecutor("cap-counter", capCounterEntity);
|
|
7
7
|
export const CAP_TOLERANCES = {
|
|
8
|
-
/** Mails /
|
|
8
|
+
/** Mails / tokens — inexpensive, with BYOK available from Pro. Generous burst buffer. */
|
|
9
9
|
burstable: { soft: 1.1, hard: 1.2 },
|
|
10
10
|
/** DB-Storage / File-Storage — teuer + persistent. Strikter Cut. */
|
|
11
11
|
storage: { soft: 1.0, hard: 1.05 },
|
|
12
|
-
/**
|
|
12
|
+
/** App count and platform slots — purchased capacity, with no buffer. */
|
|
13
13
|
hardSlot: { soft: 1.0, hard: 1.0 },
|
|
14
|
-
/** Egress —
|
|
14
|
+
/** Egress — bursty traffic is legitimate; only extreme spikes are blocked. */
|
|
15
15
|
egress: { soft: 1.1, hard: 1.3 },
|
|
16
16
|
};
|
|
17
17
|
export function assertBelowHardCap(valueSeenByLastUnit, cap) {
|
|
@@ -84,28 +84,26 @@ export async function enforceCap(ctx, options) {
|
|
|
84
84
|
// Enforce-Rolling-Cap helper
|
|
85
85
|
// =============================================================================
|
|
86
86
|
/**
|
|
87
|
-
* Synchronous read-and-check of the calling tenant's
|
|
88
|
-
*
|
|
89
|
-
* `windowDays`
|
|
87
|
+
* Synchronous read-and-check of the calling tenant's rolling-window
|
|
88
|
+
* counter for `capName`. Reads increment events from the last
|
|
89
|
+
* `windowDays` in the event store and sums their `amount`. Returns:
|
|
90
90
|
* - "ok" when sum < soft-threshold
|
|
91
91
|
* - "soft-hit" when soft ≤ sum < hard.
|
|
92
92
|
*
|
|
93
93
|
* **Throws** `CapExceededError` when sum ≥ hard-threshold.
|
|
94
94
|
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* `lastSoftWarnedAt
|
|
98
|
-
*
|
|
99
|
-
* memoization
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* `false` (= "wir tracken's nicht").
|
|
95
|
+
* **The `crossed` flag is intentionally absent:** Unlike the calendar
|
|
96
|
+
* counter, the rolling aggregate has no projection row with a
|
|
97
|
+
* `lastSoftWarnedAt` flag. The caller must deduplicate notification storms
|
|
98
|
+
* using its own mechanism, such as a cache-table key or request-lifetime
|
|
99
|
+
* memoization. The result shape still matches `EnforceCapResult` so the same
|
|
100
|
+
* caller code works with both functions; `crossed` is always `false` here
|
|
101
|
+
* (= "not tracked").
|
|
103
102
|
*
|
|
104
|
-
* **Performance
|
|
105
|
-
* (tenant, capName).
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* vorgezogen.
|
|
103
|
+
* **Performance note:** The read sums ALL events in the window for
|
|
104
|
+
* (tenant, capName). With 10k+ events per tenant in the window, this could
|
|
105
|
+
* become slow; migrate to a multi-stream projection with pre-aggregated
|
|
106
|
+
* daily buckets if needed.
|
|
109
107
|
*/
|
|
110
108
|
export async function enforceRollingCap(ctx, options) {
|
|
111
109
|
const { user, readDb } = resolveCapCounterScope(ctx, false);
|
|
@@ -200,14 +198,14 @@ export function calendarMonthPeriodEndIso(periodStartIso) {
|
|
|
200
198
|
.toString();
|
|
201
199
|
}
|
|
202
200
|
/**
|
|
203
|
-
* Calendar-
|
|
204
|
-
*
|
|
205
|
-
* `mark-soft-warned
|
|
206
|
-
*
|
|
201
|
+
* Calendar-period enforcement with automatic soft-hit notification.
|
|
202
|
+
* Calls `enforceCap`; when `crossed: true`, it calls the notifier and the
|
|
203
|
+
* `mark-soft-warned` handler, which flips `lastSoftWarnedAt` so that the
|
|
204
|
+
* same period does not trigger another notification.
|
|
207
205
|
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
206
|
+
* Returns the `EnforceCapResult` unchanged, allowing the caller to branch
|
|
207
|
+
* on the result, such as showing a UI toast in addition to the email
|
|
208
|
+
* notification.
|
|
211
209
|
*/
|
|
212
210
|
export async function enforceCapAndMaybeNotify(ctx, options) {
|
|
213
211
|
const result = await enforceCap(ctx, {
|
|
@@ -238,14 +236,14 @@ export async function enforceCapAndMaybeNotify(ctx, options) {
|
|
|
238
236
|
return result;
|
|
239
237
|
}
|
|
240
238
|
/**
|
|
241
|
-
* Rolling-
|
|
239
|
+
* Rolling-window enforcement that always sends a notification on a soft hit.
|
|
242
240
|
*
|
|
243
|
-
* **
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
*
|
|
241
|
+
* **Storm risk:** The rolling counter does NOT track `lastSoftWarnedAt`
|
|
242
|
+
* (there is no projection row). On every call while the counter is in the
|
|
243
|
+
* soft range, the notifier fires. The caller must deduplicate, for example
|
|
244
|
+
* with a cache entry `lastNotified[capName]` and a TTL, or call
|
|
245
|
+
* `enforceRollingCapAndMaybeNotify` only once per day or hour
|
|
246
|
+
* (an hourly cron instead of per request).
|
|
249
247
|
*/
|
|
250
248
|
export async function enforceRollingCapAndMaybeNotify(ctx, options) {
|
|
251
249
|
const result = await enforceRollingCap(ctx, {
|
|
@@ -265,24 +263,25 @@ export async function enforceRollingCapAndMaybeNotify(ctx, options) {
|
|
|
265
263
|
return result;
|
|
266
264
|
}
|
|
267
265
|
/**
|
|
268
|
-
* Stock
|
|
269
|
-
*
|
|
266
|
+
* Stock cap: checks a cardinality counted LIVE by the caller (for example,
|
|
267
|
+
* the number of existing components for a tenant) against a tier limit.
|
|
270
268
|
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
* (`count(*) WHERE tenant_id = …`)
|
|
274
|
-
* (
|
|
275
|
-
*
|
|
269
|
+
* Unlike {@link enforceCap}/{@link enforceRollingCap}, there is NO stored
|
|
270
|
+
* counter: the caller counts the projection itself
|
|
271
|
+
* (`count(*) WHERE tenant_id = …`) and passes `current`. This avoids drift
|
|
272
|
+
* (a delete immediately frees the slot), requires no counter table or
|
|
273
|
+
* increment/decrement bookkeeping, and measures a stock rather than a flow.
|
|
276
274
|
*
|
|
277
|
-
* **TOCTOU
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
275
|
+
* **TOCTOU caveat:** Counting and writing are not atomic—two concurrent
|
|
276
|
+
* creates can both see `ok` and exceed the limit by one (the same race as
|
|
277
|
+
* with {@link enforceCap}). Strictly hard slots need additional
|
|
278
|
+
* serialization in the create path, such as a unique index on
|
|
279
|
+
* tenantId+slot.
|
|
281
280
|
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
281
|
+
* Pure function—it does NOT throw or map an HTTP status. Reaching a stock
|
|
282
|
+
* limit means "upgrade required", not "retry later" (429); the caller
|
|
283
|
+
* chooses the response, typically an app-specific 422/`upgrade_required`
|
|
284
|
+
* with i18n. With `hardSlot` (soft=hard=1.0), the boundary is exactly `limit`.
|
|
286
285
|
*/
|
|
287
286
|
export function enforceStockCap(options) {
|
|
288
287
|
const hardThreshold = options.limit * CAP_TOLERANCES[options.profile].hard;
|
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
import { createBigIntField, createEntity, createTextField, createTimestampField, } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
-
// cap-counter —
|
|
3
|
-
//
|
|
2
|
+
// cap-counter — one row per (tenantId, capName, periodStart). tenantId
|
|
3
|
+
// is added automatically as a base column (Kumiko multi-tenant default).
|
|
4
4
|
//
|
|
5
|
-
// **Identity
|
|
6
|
-
// - aggregate-id: UUID (Kumiko
|
|
7
|
-
// - public natural
|
|
8
|
-
//
|
|
9
|
-
//
|
|
5
|
+
// **Identity model:**
|
|
6
|
+
// - aggregate-id: UUID (required by Kumiko ES)
|
|
7
|
+
// - public natural key: (tenantId, capName, periodStart) — the counter
|
|
8
|
+
// engine derives a deterministic uuidv5 from it so increments use the
|
|
9
|
+
// same stream instead of creating two rows per tenant and cap
|
|
10
10
|
//
|
|
11
|
-
// **
|
|
12
|
-
// - capName:
|
|
13
|
-
// "db-storage-bytes").
|
|
14
|
-
//
|
|
15
|
-
// - value:
|
|
16
|
-
//
|
|
17
|
-
// - periodStart:
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
// now() - 7d`
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
11
|
+
// **Fields:**
|
|
12
|
+
// - capName: the domain concept ("platform-mails", "ai-tokens-7day",
|
|
13
|
+
// "db-storage-bytes"). Free-form string — the app defines its cap
|
|
14
|
+
// names; the engine does not enumerate them.
|
|
15
|
+
// - value: the current counter value. Tokens, MB, count, etc. — the unit
|
|
16
|
+
// belongs to the app; the engine only counts numbers.
|
|
17
|
+
// - periodStart: timestamp when the current counter period began.
|
|
18
|
+
// A calendar-month reset sets a new periodStart (= new aggregate
|
|
19
|
+
// identity). A rolling window (e.g. AI tokens over 7 days) does not
|
|
20
|
+
// reset periodStart and filters on read with `WHERE timestamp >
|
|
21
|
+
// now() - 7d` over the event-store stream — this is the caller's
|
|
22
|
+
// responsibility.
|
|
23
|
+
// - lastSoftWarnedAt: prevents notification storms. Once the soft cap at
|
|
24
|
+
// 110% is reached, subsequent increments must not each send an email to
|
|
25
|
+
// the admin. There is at most one soft warning per period, so this
|
|
26
|
+
// nullable column is reset to null when the period resets.
|
|
26
27
|
//
|
|
27
|
-
// **
|
|
28
|
-
// - softLimit / hardLimit / cap-
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
// - userId / aggregate
|
|
32
|
-
//
|
|
33
|
-
// auslöst).
|
|
28
|
+
// **What is intentionally not in the entity:**
|
|
29
|
+
// - softLimit / hardLimit / cap-tolerance multipliers — these come from
|
|
30
|
+
// the app's tier map when enforceCap is called. The counter knows
|
|
31
|
+
// nothing about the tier, only how much is being counted.
|
|
32
|
+
// - userId / aggregate reference — counters are scoped to the platform
|
|
33
|
+
// tenant, not to a user (even when a user triggers the increment).
|
|
34
34
|
export const capCounterEntity = createEntity({
|
|
35
35
|
table: "read_cap_counters",
|
|
36
36
|
description: "One usage counter per tenant, cap name and calendar period, holding the accumulated value and the timestamp of the last soft-limit warning.",
|
|
@@ -1,49 +1,48 @@
|
|
|
1
|
-
// cap-counter — Counter
|
|
1
|
+
// cap-counter — Counter Storage + Increment API + Soft-Warn State.
|
|
2
2
|
//
|
|
3
|
-
// **
|
|
4
|
-
// 1. r.entity({ name: "cap-counter" }) —
|
|
5
|
-
// period)
|
|
6
|
-
// 2. increment
|
|
7
|
-
// aggregate-id (try-create / executor-update)
|
|
8
|
-
// event-store optimistic
|
|
9
|
-
// 3. increment-rolling
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
// 4. mark-soft-warned
|
|
13
|
-
//
|
|
14
|
-
// 5. get-counter
|
|
15
|
-
// (
|
|
16
|
-
// 6. enforceCap + enforceRollingCap
|
|
17
|
-
//
|
|
18
|
-
//
|
|
3
|
+
// **What this feature provides:**
|
|
4
|
+
// 1. r.entity({ name: "cap-counter" }) — counter rows per (tenant, capName,
|
|
5
|
+
// period) for calendar-period caps (mail/month, egress/month).
|
|
6
|
+
// 2. increment handler — atomic counter increment via deterministic
|
|
7
|
+
// aggregate-id (try-create / executor-update), made race-free by the
|
|
8
|
+
// event-store optimistic lock.
|
|
9
|
+
// 3. increment-rolling handler — append-only custom-event stream for
|
|
10
|
+
// rolling-window caps (AI-tokens-7d, egress-24h). No projection; the
|
|
11
|
+
// value is read from the event stream.
|
|
12
|
+
// 4. mark-soft-warned handler — flips the anti-notification-storm flag
|
|
13
|
+
// (calendar-period counters only).
|
|
14
|
+
// 5. get-counter query — synchronous read of the current counter value
|
|
15
|
+
// (calendar period).
|
|
16
|
+
// 6. enforceCap + enforceRollingCap helpers (see enforce-cap.ts) —
|
|
17
|
+
// pre-save wrappers with asymmetric soft and hard tolerances per
|
|
18
|
+
// cap profile.
|
|
19
19
|
//
|
|
20
|
-
// **Calendar vs.
|
|
20
|
+
// **Calendar vs. rolling — when to use which:**
|
|
21
21
|
// - **Calendar period** (bookCapUsage + enforceCap): the cap resets at
|
|
22
|
-
// period start (
|
|
23
|
-
// projection
|
|
22
|
+
// period start (the first of the month, etc.). The counter is one row in
|
|
23
|
+
// the projection, enabling fast reads.
|
|
24
24
|
// - **Rolling window** (CapCounterHandlers.incrementRolling + enforceRollingCap):
|
|
25
|
-
// the cap rolls continuously (e.g. "last 7 days"). Values expire
|
|
26
|
-
//
|
|
27
|
-
//
|
|
25
|
+
// the cap rolls continuously (e.g. "last 7 days"). Values expire event
|
|
26
|
+
// by event without a reset. There is no projection; reads sum the events
|
|
27
|
+
// from the last N days.
|
|
28
28
|
//
|
|
29
29
|
// **What this feature does NOT do:**
|
|
30
30
|
// - **No foundation wiring.** mail-foundation / file-foundation /
|
|
31
|
-
// ai-foundation are BYOK by default
|
|
31
|
+
// ai-foundation are BYOK by default and currently have no platform pool
|
|
32
32
|
// to count. cap-counter is generic: an app owner who wants to use the
|
|
33
33
|
// counter calls `bookCapUsage(...)` /
|
|
34
34
|
// `ctx.write(CapCounterHandlers.incrementRolling, ...)` from their own handler.
|
|
35
|
-
// - **No reset cron for the calendar period.**
|
|
36
|
-
// periodStartIso part of the aggregate id rolls over to a fresh
|
|
37
|
-
//
|
|
38
|
-
// - **
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
// nicht direkt.
|
|
35
|
+
// - **No reset cron for the calendar period.** It works without one: the
|
|
36
|
+
// periodStartIso part of the aggregate id rolls over to a fresh counter
|
|
37
|
+
// at the period boundary. Old rows remain for auditing.
|
|
38
|
+
// - **No notification path is hard-wired.** cap-counter is decoupled —
|
|
39
|
+
// `enforceCapAndMaybeNotify` (see enforce-cap.ts) is a convenience helper
|
|
40
|
+
// that invokes a caller-supplied emit callback; cap-counter does not know
|
|
41
|
+
// the delivery feature directly.
|
|
43
42
|
//
|
|
44
|
-
// **Boot
|
|
45
|
-
// config,
|
|
46
|
-
//
|
|
43
|
+
// **Boot dependencies:** none. cap-counter is plain vanilla — it needs no
|
|
44
|
+
// config, secrets, or tenant feature. Tenant scoping comes from the framework
|
|
45
|
+
// default (Base-Column tenantId).
|
|
47
46
|
import { access, defineEntityListHandler, defineFeature, } from "@cosmicdrift/kumiko-framework/engine";
|
|
48
47
|
import { CAP_COUNTER_FEATURE, CAP_COUNTER_LIST_SCREEN_ID, ROLLING_INCREMENTED_EVENT_SHORT, ROLLING_RELEASED_EVENT_SHORT, } from "./constants.js";
|
|
49
48
|
import { capCounterEntity } from "./entity.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { WriteHandlerDef } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
2
|
import * as z from "zod";
|
|
3
|
-
/** Schema
|
|
4
|
-
*
|
|
3
|
+
/** Schema of the emitted custom event. Identical to the input schema:
|
|
4
|
+
* the caller supplies amount, which we append unchanged to the stream. */
|
|
5
5
|
export declare const rollingIncrementedSchema: z.ZodObject<{
|
|
6
6
|
capName: z.ZodString;
|
|
7
7
|
amount: z.ZodDefault<z.ZodNumber>;
|