@cosmicdrift/kumiko-samples 0.388.0 → 0.390.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/packages/bundled-features/package.json +25 -13
- package/packages/bundled-features/src/agent-tools/changes.json +6 -0
- package/packages/bundled-features/src/agent-tools/index.ts +1 -1
- package/packages/bundled-features/src/agent-tools/tool-dispatch.ts +42 -26
- package/packages/bundled-features/src/audit/feature.ts +2 -1
- package/packages/bundled-features/src/auth-email-password/auth-user-row.ts +1 -1
- package/packages/bundled-features/src/auth-email-password/bootstrap.ts +13 -1
- package/packages/bundled-features/src/auth-email-password/changes.json +18 -0
- package/packages/bundled-features/src/auth-email-password/feature.ts +2 -2
- package/packages/bundled-features/src/auth-email-password/handlers/change-password.write.ts +7 -7
- package/packages/bundled-features/src/auth-email-password/handlers/confirm-account-unlock.write.ts +3 -3
- package/packages/bundled-features/src/auth-email-password/handlers/confirm-token-flow.ts +5 -5
- package/packages/bundled-features/src/auth-email-password/handlers/invite-accept-with-login.write.ts +9 -7
- package/packages/bundled-features/src/auth-email-password/handlers/invite-accept.write.ts +11 -7
- package/packages/bundled-features/src/auth-email-password/handlers/invite-create.write.ts +4 -4
- package/packages/bundled-features/src/auth-email-password/handlers/invite-info.query.ts +2 -2
- package/packages/bundled-features/src/auth-email-password/handlers/invite-signup-complete.write.ts +9 -7
- package/packages/bundled-features/src/auth-email-password/handlers/login.write.ts +23 -16
- package/packages/bundled-features/src/auth-email-password/handlers/request-account-unlock.write.ts +1 -0
- package/packages/bundled-features/src/auth-email-password/handlers/request-email-verification.write.ts +1 -0
- package/packages/bundled-features/src/auth-email-password/handlers/request-password-reset.write.ts +1 -0
- package/packages/bundled-features/src/auth-email-password/handlers/reset-password.write.ts +3 -2
- package/packages/bundled-features/src/auth-email-password/handlers/signup-confirm.write.ts +12 -12
- package/packages/bundled-features/src/auth-email-password/handlers/signup-request.write.ts +16 -8
- package/packages/bundled-features/src/auth-email-password/handlers/switch-tenant-mfa-gate.write.ts +4 -2
- package/packages/bundled-features/src/auth-email-password/handlers/token-request-handler.ts +10 -2
- package/packages/bundled-features/src/auth-email-password/handlers/verify-email.write.ts +3 -2
- package/packages/bundled-features/src/auth-email-password/magic-link-mail.ts +16 -3
- package/packages/bundled-features/src/auth-email-password/seeding.ts +14 -9
- package/packages/bundled-features/src/auth-email-password/signup-activation.ts +2 -0
- package/packages/bundled-features/src/auth-email-password/web/auth-client.ts +8 -2
- package/packages/bundled-features/src/auth-email-password/web/auth-redirect.ts +23 -21
- package/packages/bundled-features/src/auth-email-password/web/default-auth-pages-gate.tsx +6 -3
- package/packages/bundled-features/src/auth-email-password/web/forgot-password-screen.tsx +11 -1
- package/packages/bundled-features/src/auth-email-password/web/index.ts +5 -0
- package/packages/bundled-features/src/auth-email-password/web/login-screen.tsx +16 -5
- package/packages/bundled-features/src/auth-email-password/web/reset-password-screen.tsx +7 -1
- package/packages/bundled-features/src/auth-email-password/web/return-path.ts +35 -0
- package/packages/bundled-features/src/auth-email-password/web/session.tsx +6 -1
- package/packages/bundled-features/src/auth-email-password/web/signup-complete-screen.tsx +11 -3
- package/packages/bundled-features/src/auth-email-password/web/signup-screen.tsx +12 -2
- package/packages/bundled-features/src/auth-foundation/feature.ts +13 -4
- package/packages/bundled-features/src/auth-mfa/changes.json +6 -0
- package/packages/bundled-features/src/auth-mfa/config.ts +3 -7
- package/packages/bundled-features/src/auth-mfa/handlers/disable.write.ts +5 -5
- package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +24 -14
- package/packages/bundled-features/src/auth-mfa/handlers/enable-confirm.write.ts +9 -3
- package/packages/bundled-features/src/auth-mfa/handlers/enable-start-preauth.write.ts +6 -1
- package/packages/bundled-features/src/auth-mfa/handlers/enable-start.write.ts +3 -1
- package/packages/bundled-features/src/auth-mfa/handlers/reencrypt.job.ts +14 -9
- package/packages/bundled-features/src/auth-mfa/handlers/regenerate-recovery.write.ts +5 -4
- package/packages/bundled-features/src/auth-mfa/handlers/verify.write.ts +25 -14
- package/packages/bundled-features/src/auth-mfa/mfa-code-verifier.ts +10 -4
- package/packages/bundled-features/src/auth-mfa/mfa-status-checker.ts +17 -8
- package/packages/bundled-features/src/auth-mfa/verify-factor.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/billing-info-query.ts +2 -2
- package/packages/bundled-features/src/billing-foundation/changes.json +6 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/consent-gate.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/consumer-protection/issue-confirmation.ts +5 -5
- package/packages/bundled-features/src/billing-foundation/consumer-protection/register-consent.ts +10 -7
- package/packages/bundled-features/src/billing-foundation/consumer-protection/register-termination.ts +15 -12
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-open-cancels.ts +22 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-provider-lock.ts +4 -0
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-receipt-limit.ts +4 -4
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-record.ts +17 -58
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-request.ts +10 -8
- package/packages/bundled-features/src/billing-foundation/consumer-protection/termination-revoke.ts +18 -15
- package/packages/bundled-features/src/billing-foundation/events.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/feature.ts +8 -3
- package/packages/bundled-features/src/billing-foundation/get-subscription-for-tenant.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/handlers/process-event.write.ts +5 -5
- package/packages/bundled-features/src/billing-foundation/handlers/process-payment-event.write.ts +3 -3
- package/packages/bundled-features/src/billing-foundation/plan-catalog.ts +2 -2
- package/packages/bundled-features/src/billing-foundation/projection.ts +1 -1
- package/packages/bundled-features/src/billing-foundation/types.ts +1 -1
- package/packages/bundled-features/src/cap-counter/aggregate-id.ts +1 -1
- package/packages/bundled-features/src/cap-counter/book-cap-usage.ts +5 -4
- package/packages/bundled-features/src/cap-counter/cap-reservation.ts +21 -8
- package/packages/bundled-features/src/cap-counter/changes.json +12 -0
- package/packages/bundled-features/src/cap-counter/constants.ts +1 -1
- package/packages/bundled-features/src/cap-counter/feature.ts +3 -2
- package/packages/bundled-features/src/cap-counter/handlers/increment-rolling.write.ts +1 -1
- package/packages/bundled-features/src/cap-counter/reservation-chain.ts +1 -1
- package/packages/bundled-features/src/cap-counter/with-cap-enforcement.ts +4 -4
- package/packages/bundled-features/src/cap-overview/feature.ts +1 -0
- package/packages/bundled-features/src/cap-overview/handlers/caps-usage.query.ts +1 -1
- package/packages/bundled-features/src/cap-overview/handlers/tenant-caps-list.query.ts +1 -1
- package/packages/bundled-features/src/compliance-profiles/seeding.ts +12 -7
- package/packages/bundled-features/src/config/changes.json +6 -0
- package/packages/bundled-features/src/config/feature.ts +6 -6
- package/packages/bundled-features/src/config/handlers/cascade.query.ts +1 -1
- package/packages/bundled-features/src/config/handlers/readiness.query.ts +1 -1
- package/packages/bundled-features/src/config/handlers/reencrypt.job.ts +23 -13
- package/packages/bundled-features/src/config/handlers/reset.write.ts +3 -3
- package/packages/bundled-features/src/config/handlers/selected-extensions.query.ts +1 -1
- package/packages/bundled-features/src/config/handlers/set.write.ts +22 -5
- package/packages/bundled-features/src/config/handlers/values.query.ts +1 -1
- package/packages/bundled-features/src/crypto-shredding/changes.json +12 -0
- package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +9 -9
- package/packages/bundled-features/src/crypto-shredding/resolve-file-bytes-deleter.ts +3 -3
- package/packages/bundled-features/src/custom-fields/changes.json +6 -0
- package/packages/bundled-features/src/custom-fields/handlers/clear-custom-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/handlers/delete-system-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/handlers/delete-tenant-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/handlers/set-custom-field.write.ts +1 -1
- package/packages/bundled-features/src/custom-fields/index.ts +4 -0
- package/packages/bundled-features/src/custom-fields/lib/parse-serialized-field.ts +1 -1
- package/packages/bundled-features/src/data-retention/feature.ts +1 -1
- package/packages/bundled-features/src/data-retention/run-retention-cleanup.ts +12 -2
- package/packages/bundled-features/src/delivery/attempt-log.ts +1 -1
- package/packages/bundled-features/src/delivery/changes.json +12 -0
- package/packages/bundled-features/src/delivery/delivery-service.ts +6 -5
- package/packages/bundled-features/src/delivery/feature.ts +3 -2
- package/packages/bundled-features/src/delivery/index.ts +5 -0
- package/packages/bundled-features/src/delivery/jobs.ts +11 -11
- package/packages/bundled-features/src/delivery/system-channel-context.ts +33 -0
- package/packages/bundled-features/src/delivery/testing.ts +1 -1
- package/packages/bundled-features/src/document-ingest-foundation/append-missing-extract-event.ts +84 -0
- package/packages/bundled-features/src/document-ingest-foundation/changes.json +6 -0
- package/packages/bundled-features/src/document-ingest-foundation/events.ts +16 -1
- package/packages/bundled-features/src/document-ingest-foundation/index.ts +11 -0
- package/packages/bundled-features/src/feature-toggles/feature.ts +1 -0
- package/packages/bundled-features/src/feature-toggles/handlers/registered.query.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/handlers/set.write.ts +1 -1
- package/packages/bundled-features/src/feature-toggles/toggle-sync-signal.ts +1 -1
- package/packages/bundled-features/src/file-derivatives/feature.ts +2 -2
- package/packages/bundled-features/src/file-derivatives/handlers/public-variant-by-file-ref.query.ts +5 -1
- package/packages/bundled-features/src/file-derivatives/handlers/public-variant.query.ts +7 -5
- package/packages/bundled-features/src/file-foundation/feature.ts +1 -1
- package/packages/bundled-features/src/file-foundation/read-file-ref-content.ts +7 -5
- package/packages/bundled-features/src/file-provider-s3/feature.ts +4 -1
- package/packages/bundled-features/src/files-tenant-data/handlers/sweep-orphaned-derivatives.job.ts +8 -8
- package/packages/bundled-features/src/form-draft/feature.ts +1 -1
- package/packages/bundled-features/src/form-draft/handlers/cleanup.job.ts +22 -12
- package/packages/bundled-features/src/form-draft/handlers/discard.write.ts +3 -3
- package/packages/bundled-features/src/form-draft/handlers/get.query.ts +1 -1
- package/packages/bundled-features/src/foundation-shared/config-helpers.ts +1 -1
- package/packages/bundled-features/src/host-routing/changes.json +6 -0
- package/packages/bundled-features/src/host-routing/validate-options.ts +5 -0
- package/packages/bundled-features/src/inbound-mail-foundation/events.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +2 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/account-state.ts +2 -2
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/connect-account.write.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/ingest-message.write.ts +10 -10
- package/packages/bundled-features/src/inbound-mail-foundation/handlers/update-account.write.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/projection.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/watch-supervisor.ts +1 -1
- package/packages/bundled-features/src/inbound-provider-imap/feature.ts +4 -1
- package/packages/bundled-features/src/jobs/changes.json +6 -0
- package/packages/bundled-features/src/jobs/events.ts +1 -1
- package/packages/bundled-features/src/jobs/feature.ts +1 -0
- package/packages/bundled-features/src/jobs/handlers/consumer.write.ts +7 -4
- package/packages/bundled-features/src/jobs/handlers/projection-rebuild.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/reindex-entity.job.ts +11 -5
- package/packages/bundled-features/src/jobs/handlers/retention-cleanup.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/retry.write.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/stale-run-sweep.job.ts +1 -1
- package/packages/bundled-features/src/jobs/handlers/trigger.write.ts +2 -2
- package/packages/bundled-features/src/jobs/job-run-logger.ts +139 -90
- package/packages/bundled-features/src/ledger/web/index.ts +1 -1
- package/packages/bundled-features/src/legal-pages/README.md +1 -1
- package/packages/bundled-features/src/legal-pages/lib/boot-check.ts +12 -8
- package/packages/bundled-features/src/legal-pages/seed.ts +5 -2
- package/packages/bundled-features/src/mail-foundation/feature.ts +2 -2
- package/packages/bundled-features/src/mail-transport-smtp/changes.json +12 -0
- package/packages/bundled-features/src/mail-transport-smtp/config-keys.ts +1 -1
- package/packages/bundled-features/src/mail-transport-smtp/feature.ts +13 -12
- package/packages/bundled-features/src/managed-pages/changes.json +6 -0
- package/packages/bundled-features/src/managed-pages/constants.ts +1 -0
- package/packages/bundled-features/src/managed-pages/feature.ts +3 -1
- package/packages/bundled-features/src/managed-pages/index.ts +1 -0
- package/packages/bundled-features/src/managed-pages/seeding.ts +13 -8
- package/packages/bundled-features/src/notes-history/handlers/add-note.write.ts +2 -2
- package/packages/bundled-features/src/personal-access-tokens/feature.ts +2 -1
- package/packages/bundled-features/src/personal-access-tokens/handlers/create.write.ts +2 -2
- package/packages/bundled-features/src/personal-access-tokens/handlers/revoke.write.ts +1 -1
- package/packages/bundled-features/src/rate-limiting/handlers/status.query.ts +2 -2
- package/packages/bundled-features/src/readiness/handlers/status.query.ts +4 -1
- package/packages/bundled-features/src/renderer-foundation/api.ts +3 -3
- package/packages/bundled-features/src/secrets/announce-secret-change.ts +4 -4
- package/packages/bundled-features/src/secrets/changes.json +6 -0
- package/packages/bundled-features/src/secrets/feature.ts +9 -9
- package/packages/bundled-features/src/secrets/handlers/delete.write.ts +4 -3
- package/packages/bundled-features/src/secrets/handlers/rotate.job.ts +13 -8
- package/packages/bundled-features/src/secrets/handlers/set.write.ts +4 -3
- package/packages/bundled-features/src/secrets/secrets-context.ts +16 -6
- package/packages/bundled-features/src/secrets/write-gate.ts +10 -3
- package/packages/bundled-features/src/seo/feature.ts +1 -1
- package/packages/bundled-features/src/sessions/changes.json +19 -0
- package/packages/bundled-features/src/sessions/feature.ts +2 -1
- package/packages/bundled-features/src/sessions/handlers/cleanup.job.ts +2 -2
- package/packages/bundled-features/src/sessions/handlers/detail.query.ts +5 -2
- package/packages/bundled-features/src/sessions/handlers/list.query.ts +5 -2
- package/packages/bundled-features/src/sessions/handlers/mine.query.ts +5 -2
- package/packages/bundled-features/src/sessions/handlers/revoke-all-for-user.write.ts +3 -3
- package/packages/bundled-features/src/sessions/handlers/revoke-all-others.write.ts +1 -1
- package/packages/bundled-features/src/sessions/handlers/revoke.write.ts +1 -1
- package/packages/bundled-features/src/sessions/index.ts +1 -1
- package/packages/bundled-features/src/sessions/screens.ts +8 -4
- package/packages/bundled-features/src/sessions/session-callbacks.ts +1 -9
- package/packages/bundled-features/src/sessions/session-revoked-event.ts +1 -1
- package/packages/bundled-features/src/sessions/web/session-device-cell.tsx +10 -12
- package/packages/bundled-features/src/sessions/web/user-agent.ts +12 -0
- package/packages/bundled-features/src/shared/index.ts +15 -0
- package/packages/bundled-features/src/shared/purge-files-reaching-subject.ts +36 -4
- package/packages/bundled-features/src/shared/require-for-tenant.ts +7 -5
- package/packages/bundled-features/src/shared/run-in-sub-transaction.ts +5 -5
- package/packages/bundled-features/src/shared/stream-tenant-backfill.ts +201 -0
- package/packages/bundled-features/src/shared/stream-tenant-derived-state.ts +107 -0
- package/packages/bundled-features/src/step-dispatcher/changes.json +6 -0
- package/packages/bundled-features/src/step-dispatcher/deliver-dispatch-request.ts +17 -3
- package/packages/bundled-features/src/step-dispatcher/feature.ts +1 -1
- package/packages/bundled-features/src/step-dispatcher/mail-runner.ts +2 -1
- package/packages/bundled-features/src/subscription-dodo/plugin-methods.ts +1 -1
- package/packages/bundled-features/src/subscription-dodo/runtime.ts +7 -7
- package/packages/bundled-features/src/subscription-stripe/plugin-methods.ts +5 -3
- package/packages/bundled-features/src/subscription-stripe/runtime.ts +7 -7
- package/packages/bundled-features/src/tags/feature.ts +1 -0
- package/packages/bundled-features/src/template-resolver/api.ts +3 -3
- package/packages/bundled-features/src/template-resolver/changes.json +54 -0
- package/packages/bundled-features/src/template-resolver/document-ops.ts +20 -1
- package/packages/bundled-features/src/template-resolver/feature.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/bundle-import.ts +5 -4
- package/packages/bundled-features/src/template-resolver/handlers/copy-locale.write.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/export-bundle.query.ts +1 -1
- package/packages/bundled-features/src/template-resolver/handlers/layout-source.query.ts +36 -11
- package/packages/bundled-features/src/template-resolver/handlers/overview.query.ts +32 -7
- package/packages/bundled-features/src/template-resolver/handlers/patch-draft.write.ts +1 -1
- package/packages/bundled-features/src/template-resolver/handlers/send-test-shared.ts +1 -1
- package/packages/bundled-features/src/template-resolver/handlers/send-test-status.query.ts +22 -19
- package/packages/bundled-features/src/template-resolver/handlers/send-test.write.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/tenant-override-selection.ts +6 -2
- package/packages/bundled-features/src/template-resolver/handlers/tenant-overrides.query.ts +4 -2
- package/packages/bundled-features/src/template-resolver/handlers/usage.query.ts +1 -1
- package/packages/bundled-features/src/template-resolver/seeding.ts +22 -5
- package/packages/bundled-features/src/template-resolver/store-template-resource.ts +68 -19
- package/packages/bundled-features/src/template-resolver/template-resources.ts +4 -4
- package/packages/bundled-features/src/template-resolver/testing.ts +2 -2
- package/packages/bundled-features/src/template-resolver/web/document-insert-fields.tsx +222 -0
- package/packages/bundled-features/src/template-resolver/web/document-insert-model.ts +164 -0
- package/packages/bundled-features/src/template-resolver/web/document-insert-panel.tsx +115 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-bubble.tsx +177 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-content.tsx +38 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-context.ts +119 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-editor.tsx +51 -1098
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-helpers.ts +161 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-layout.tsx +83 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar-groups.tsx +153 -0
- package/packages/bundled-features/src/template-resolver/web/document-tiptap-toolbar.tsx +182 -0
- package/packages/bundled-features/src/template-resolver/web/editor-handle.ts +18 -0
- package/packages/bundled-features/src/template-resolver/web/i18n.ts +6 -0
- package/packages/bundled-features/src/template-resolver/web/placeholder-line-editor.tsx +19 -6
- package/packages/bundled-features/src/template-resolver/web/qualified-names.ts +1 -0
- package/packages/bundled-features/src/template-resolver/web/use-document-tiptap-model.ts +138 -0
- package/packages/bundled-features/src/tenant/changes.json +19 -0
- package/packages/bundled-features/src/tenant/feature.ts +1 -0
- package/packages/bundled-features/src/tenant/handlers/cancel-invitation.write.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/memberships.query.ts +1 -1
- package/packages/bundled-features/src/tenant/handlers/remove-member.write.ts +2 -2
- package/packages/bundled-features/src/tenant/handlers/team-list.query.ts +3 -3
- package/packages/bundled-features/src/tenant/handlers/update-member-roles.write.ts +1 -1
- package/packages/bundled-features/src/tenant/index.ts +5 -0
- package/packages/bundled-features/src/tenant/invited-membership.ts +6 -1
- package/packages/bundled-features/src/tenant/schema/tenant.ts +4 -1
- package/packages/bundled-features/src/tenant/seeding.ts +65 -62
- package/packages/bundled-features/src/tenant/stream-tenant-backfill.ts +115 -0
- package/packages/bundled-features/src/tenant/testing.ts +77 -0
- package/packages/bundled-features/src/tenant-handover/events.ts +1 -1
- package/packages/bundled-features/src/tenant-handover/handlers/claim.write.ts +1 -1
- package/packages/bundled-features/src/tenant-lifecycle/changes.json +6 -0
- package/packages/bundled-features/src/tenant-lifecycle/feature.ts +5 -5
- package/packages/bundled-features/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +22 -10
- package/packages/bundled-features/src/tenant-lifecycle/handlers/request-destruction.write.ts +22 -11
- package/packages/bundled-features/src/tenant-lifecycle/run-tenant-destroy.ts +23 -12
- package/packages/bundled-features/src/tenant-lifecycle/stages.ts +42 -4
- package/packages/bundled-features/src/tenant-lifecycle/testing.ts +9 -8
- package/packages/bundled-features/src/tier-engine/entity.ts +1 -1
- package/packages/bundled-features/src/tier-engine/feature.ts +8 -3
- package/packages/bundled-features/src/tier-engine/handlers/active-tier.query.ts +3 -3
- package/packages/bundled-features/src/tier-engine/handlers/get-tenant-tier.query.ts +7 -1
- package/packages/bundled-features/src/tier-engine/handlers/set-tenant-tier.write.ts +3 -3
- package/packages/bundled-features/src/user/db/queries/stream-tenant-backfill.ts +71 -97
- package/packages/bundled-features/src/user/feature.ts +1 -0
- package/packages/bundled-features/src/user/handlers/find-for-auth.query.ts +2 -2
- package/packages/bundled-features/src/user/handlers/update-roles.ts +2 -2
- package/packages/bundled-features/src/user/index.ts +2 -0
- package/packages/bundled-features/src/user/invited-global-roles.ts +6 -1
- package/packages/bundled-features/src/user/principal-status.ts +1 -1
- package/packages/bundled-features/src/user/seeding.ts +24 -6
- package/packages/bundled-features/src/user/testing.ts +22 -0
- package/packages/bundled-features/src/user-data-rights/COMPLIANCE.md +1 -1
- package/packages/bundled-features/src/user-data-rights/README.md +1 -1
- package/packages/bundled-features/src/user-data-rights/audit-download.ts +12 -2
- package/packages/bundled-features/src/user-data-rights/changes.json +36 -0
- package/packages/bundled-features/src/user-data-rights/feature.ts +30 -24
- package/packages/bundled-features/src/user-data-rights/handlers/confirm-deletion-by-token.write.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/handlers/deletion-grace-period.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-job.query.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/handlers/download-by-token.query.ts +2 -2
- package/packages/bundled-features/src/user-data-rights/handlers/request-deletion.write.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/handlers/restrict-account.write.ts +4 -4
- package/packages/bundled-features/src/user-data-rights/handlers/run-forget-cleanup.write.ts +12 -6
- package/packages/bundled-features/src/user-data-rights/index.ts +8 -1
- package/packages/bundled-features/src/user-data-rights/lib/mail-transport-resolver.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/lib/storage-provider-resolver.ts +1 -1
- package/packages/bundled-features/src/user-data-rights/lib/update-user-lifecycle.ts +6 -1
- package/packages/bundled-features/src/user-data-rights/run-export-jobs.ts +8 -2
- package/packages/bundled-features/src/user-data-rights/run-forget-cleanup.ts +14 -3
- package/packages/bundled-features/src/user-data-rights/run-user-export.ts +11 -1
- package/packages/bundled-features/src/user-data-rights/web/constants.ts +16 -0
- package/packages/bundled-features/src/user-data-rights/web/index.ts +6 -0
- package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +8 -6
- package/packages/bundled-features/src/waitlist/changes.json +18 -0
- package/packages/bundled-features/src/waitlist/feature.ts +1 -0
- package/packages/bundled-features/src/waitlist/handlers/export-purge.write.ts +1 -1
- package/packages/bundled-features/src/waitlist/handlers/invite.write.ts +2 -2
- package/packages/bundled-features/src/waitlist/handlers/reject.write.ts +1 -1
- package/packages/bundled-features/src/waitlist/handlers/submit.write.ts +34 -10
- package/packages/bundled-features/src/waitlist/import.ts +23 -3
- package/packages/bundled-features/src/waitlist/legacy-migrate.ts +8 -2
- package/packages/bundled-features/src/waitlist/link-on-signup.ts +7 -1
- package/packages/bundled-features/src/waitlist/options.ts +2 -1
- package/packages/bundled-features/src/workflow-runner/changes.json +6 -0
- package/packages/bundled-features/src/workflow-runner/db/queries/due-runs.ts +1 -1
- package/packages/bundled-features/src/workflow-runner/event-subscriber.ts +4 -3
- package/packages/bundled-features/src/workflow-runner/event-trigger.ts +2 -1
- package/packages/bundled-features/src/workflow-runner/feature.ts +2 -2
- package/packages/bundled-features/src/workflow-runner/handlers/resume-run.write.ts +8 -8
- package/packages/bundled-features/src/workflow-runner/runner.ts +6 -4
- package/samples/apps/cap-billing-demo/src/feature.ts +19 -5
- package/samples/apps/config-demo/src/app/server.ts +1 -1
- package/samples/apps/styleguide/src/app/client.tsx +2 -0
- package/samples/apps/styleguide/src/app/seed.ts +6 -4
- package/samples/apps/styleguide/src/app/server.ts +6 -3
- package/samples/apps/styleguide/src/features/widgets/feature.ts +15 -4
- package/samples/apps/styleguide/src/features/workboard/feature.ts +185 -0
- package/samples/apps/styleguide/src/features/workboard/i18n.ts +27 -0
- package/samples/apps/styleguide/src/features/workboard/seed.ts +121 -0
- package/samples/apps/styleguide/src/features/workboard/web.ts +13 -0
- package/samples/apps/ui-walkthrough/src/features/rental/i18n.ts +2 -0
- package/samples/apps/ui-walkthrough/src/features/rental/screens.ts +9 -0
- package/samples/apps/use-all-bundled/bin/main.ts +2 -0
- package/samples/apps/use-all-bundled/feature-manifest.json +17 -1
- package/samples/apps/use-all-bundled/kumiko/schema.ts +2 -0
- package/samples/apps/use-all-bundled/kumiko.config.ts +2 -0
- package/samples/apps/use-all-bundled/package.json +2 -1
- package/samples/apps/use-all-bundled/src/app/dev-app-options.ts +2 -0
- package/samples/apps/use-all-bundled/src/app/notes-feature.ts +2 -0
- package/samples/apps/use-all-bundled/src/app/seed.ts +12 -2
- package/samples/apps/use-all-bundled/src/bundled-lists.ts +15 -0
- package/samples/apps/user-data-rights-demo/README.md +1 -1
- package/samples/apps/user-data-rights-demo/src/feature.ts +3 -2
- package/samples/recipes/api-worker-split/README.md +2 -1
- package/samples/recipes/api-worker-split/src/feature.ts +2 -1
- package/samples/recipes/cross-feature-events/README.md +5 -5
- package/samples/recipes/cross-feature-events/package.json +1 -1
- package/samples/recipes/cross-feature-events/src/feature.ts +4 -4
- package/samples/recipes/event-sourcing/README.md +5 -5
- package/samples/recipes/event-sourcing/package.json +1 -1
- package/samples/recipes/event-sourcing/src/feature.ts +15 -15
- package/samples/recipes/files-post-processing/README.md +1 -1
- package/samples/recipes/files-post-processing/package.json +1 -1
- package/samples/recipes/files-post-processing/src/feature.ts +6 -4
- package/samples/recipes/golden-path/src/feature.ts +2 -1
- package/samples/recipes/lane-routing/package.json +1 -1
- package/samples/recipes/legal-pages/README.md +2 -2
- package/samples/recipes/lifecycle-hooks/README.md +4 -0
- package/samples/recipes/lifecycle-hooks/src/feature.ts +26 -1
- package/samples/recipes/list-table-options/README.md +50 -0
- package/samples/recipes/list-table-options/package.json +11 -0
- package/samples/recipes/list-table-options/src/feature.ts +221 -0
- package/samples/recipes/managed-config/README.md +3 -3
- package/samples/recipes/pdf-audit-export/src/feature.ts +2 -1
- package/samples/recipes/search/README.md +1 -1
- package/samples/recipes/search/src/feature.ts +3 -3
- package/samples/recipes/secrets-demo/README.md +1 -1
- package/samples/recipes/secrets-demo/src/feature.ts +5 -2
- package/samples/recipes/state-machine/src/events.ts +4 -3
- package/samples/recipes/state-machine/src/reducer.ts +1 -1
- package/samples/recipes/tenant-isolation/README.md +1 -0
- package/samples/recipes/tenant-isolation/src/feature.ts +36 -0
- package/samples/recipes/workflow-engine/src/resume-loop.ts +4 -4
- package/samples/recipes/workflow-engine/src/workflow-runner.ts +2 -2
|
@@ -68,7 +68,7 @@ export function createPatCreateHandler(opts: CreatePatOptions = {}) {
|
|
|
68
68
|
escapeHatch: {
|
|
69
69
|
grants: ["systemIdentity"],
|
|
70
70
|
reason:
|
|
71
|
-
"Reads the caller's own passwordHash (privileged-only field) via ctx.queryAs(SYSTEM, " +
|
|
71
|
+
"Reads the caller's own passwordHash (privileged-only field) via ctx.dispatch.queryAs(SYSTEM, " +
|
|
72
72
|
"user:findForAuth) to re-verify the current password before minting the token. Also " +
|
|
73
73
|
"reads the MFA enrollment of the user being re-authenticated via the mfaVerifier callback.",
|
|
74
74
|
},
|
|
@@ -79,7 +79,7 @@ export function createPatCreateHandler(opts: CreatePatOptions = {}) {
|
|
|
79
79
|
agent: { expose: false },
|
|
80
80
|
handler: async (event, ctx) => {
|
|
81
81
|
const systemUser = createSystemUser(event.user.tenantId);
|
|
82
|
-
const me = (await ctx.queryAs(systemUser, UserQueries.findForAuth, {
|
|
82
|
+
const me = (await ctx.dispatch.queryAs(systemUser, UserQueries.findForAuth, {
|
|
83
83
|
id: event.user.id,
|
|
84
84
|
})) as { passwordHash: string | null } | null; // @cast-boundary db-runner
|
|
85
85
|
if (!me?.passwordHash) return reauthFailed();
|
|
@@ -39,7 +39,7 @@ export const revokePatWrite = defineWriteHandler({
|
|
|
39
39
|
// see feature.ts). Without this, the access-invalidation consumer
|
|
40
40
|
// never hears about the revoke and an already-open SSE stream
|
|
41
41
|
// authenticated by this exact token survives it.
|
|
42
|
-
await ctx.
|
|
42
|
+
await ctx.events.unsafeAppend({
|
|
43
43
|
aggregateId: generateId(),
|
|
44
44
|
aggregateType: PAT_REVOKED_AGGREGATE_TYPE,
|
|
45
45
|
type: PAT_REVOKED_EVENT_QN,
|
|
@@ -37,12 +37,12 @@ export const rateLimitStatus = defineQueryHandler({
|
|
|
37
37
|
// about the wiring either.
|
|
38
38
|
const denied = bucketAccessDenied(query.payload.bucket, ctx.user);
|
|
39
39
|
if (denied) throw denied;
|
|
40
|
-
if (!ctx.rateLimit) {
|
|
40
|
+
if (!ctx.services.rateLimit) {
|
|
41
41
|
throw new UnprocessableError(RateLimitErrors.resolverUnavailable, {
|
|
42
42
|
i18nKey: "rateLimiting.errors.resolverUnavailable",
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
|
-
const decision = await ctx.rateLimit.peek(query.payload.bucket, {
|
|
45
|
+
const decision = await ctx.services.rateLimit.peek(query.payload.bucket, {
|
|
46
46
|
limit: query.payload.limit,
|
|
47
47
|
windowSeconds: query.payload.windowSeconds,
|
|
48
48
|
});
|
|
@@ -36,7 +36,10 @@ export const statusQuery = defineQueryHandler({
|
|
|
36
36
|
|
|
37
37
|
// has() is metadata-only: no decryption, no read-audit event — a
|
|
38
38
|
// readiness probe must not pollute the credential-read trail.
|
|
39
|
-
const secrets = requireSecretsContext(
|
|
39
|
+
const secrets = requireSecretsContext(
|
|
40
|
+
{ secrets: ctx.services.secrets, user: ctx.user },
|
|
41
|
+
ReadinessQueries.status,
|
|
42
|
+
);
|
|
40
43
|
const missingSecrets: ReadinessMissingSecret[] = [];
|
|
41
44
|
for (const [qualifiedName, keyDef] of ctx.registry.getAllSecretKeys()) {
|
|
42
45
|
if (keyDef.required !== true) continue;
|
|
@@ -87,12 +87,12 @@ function indexByKind(plugins: ReadonlyArray<RendererPlugin>): Map<RenderKind, Re
|
|
|
87
87
|
// Single source of truth for handlers that require renderer-foundation.
|
|
88
88
|
// The pattern mirrors requireTemplateResolver + requireTextContent.
|
|
89
89
|
export function requireRendererFoundation(
|
|
90
|
-
ctx: { readonly
|
|
90
|
+
ctx: { readonly services: { readonly extensions: Readonly<Record<string, unknown>> } },
|
|
91
91
|
callerName: string,
|
|
92
92
|
): RendererFoundationApi {
|
|
93
93
|
// @cast-boundary engine-bridge — rendererFoundation kommt per extraContext
|
|
94
|
-
// from the app bootstrap.
|
|
95
|
-
const api =
|
|
94
|
+
// from the app bootstrap and lands in services.extensions; the framework does not know its type.
|
|
95
|
+
const api = ctx.services.extensions["rendererFoundation"] as RendererFoundationApi | undefined;
|
|
96
96
|
if (!api) {
|
|
97
97
|
throw new InternalError({
|
|
98
98
|
message:
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
} from "@cosmicdrift/kumiko-framework/redis";
|
|
7
7
|
|
|
8
8
|
type AnnouncingContext = {
|
|
9
|
-
readonly cacheSync?: CacheSyncBus;
|
|
10
|
-
readonly
|
|
9
|
+
readonly services: { readonly cacheSync?: CacheSyncBus };
|
|
10
|
+
readonly lifecycle: { readonly afterCommit?: (hook: () => Promise<void>) => void };
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
// Secret writes bypass config:write:*, yet provider caches (e.g. the S3 secret
|
|
@@ -18,13 +18,13 @@ export function announceSecretChange(
|
|
|
18
18
|
tenantId: TenantId,
|
|
19
19
|
key: string,
|
|
20
20
|
): void {
|
|
21
|
-
const bus = ctx.cacheSync;
|
|
21
|
+
const bus = ctx.services.cacheSync;
|
|
22
22
|
// skip: no bus wired (single-process setup), nothing to announce
|
|
23
23
|
if (!bus) return;
|
|
24
24
|
const message: TenantConfigSyncMessage = { tenantId, key };
|
|
25
25
|
const publish = async (): Promise<void> => {
|
|
26
26
|
bus.publish(CACHE_SYNC_TOPICS.tenantConfig, message);
|
|
27
27
|
};
|
|
28
|
-
if (ctx.
|
|
28
|
+
if (ctx.lifecycle.afterCommit) ctx.lifecycle.afterCommit(publish);
|
|
29
29
|
else bus.publish(CACHE_SYNC_TOPICS.tenantConfig, message);
|
|
30
30
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.389.0",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "Feature-prefixed undeclared secret keys are not deletable",
|
|
6
|
+
"detail": "The delete handler still accepts legacy undeclared keys, but a key starting with \"<feature>:\" of a mounted feature now fails as unknown key. Feature-owned credentials keep their writeRoles protection."
|
|
7
|
+
},
|
|
2
8
|
{
|
|
3
9
|
"version": "0.370.0",
|
|
4
10
|
"type": "improvement",
|
|
@@ -70,19 +70,19 @@ export { type StoredEnvelope, type StoredMetadata, tenantSecretsTable } from "./
|
|
|
70
70
|
export const JOIN_REQUEST_TRANSACTION_REASON =
|
|
71
71
|
"the secret write runs on the request transaction so a failing batch rolls it back together with the config writes";
|
|
72
72
|
|
|
73
|
-
// AppContext carries ctx.secrets via extraContext. requireSecretsContext
|
|
73
|
+
// AppContext carries ctx.services.secrets via extraContext. requireSecretsContext
|
|
74
74
|
// wraps that raw context so every `.get(...)` call automatically includes
|
|
75
75
|
// the current user and handler as audit metadata, preventing feature code
|
|
76
76
|
// from silently bypassing read auditing.
|
|
77
77
|
//
|
|
78
|
-
// The
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
// auditUserId, which takes precedence
|
|
78
|
+
// The source shape stays minimal: handler paths pass `{ secrets: ctx.services.secrets,
|
|
79
|
+
// user: ctx.user }`, provider paths (the S3 plugin in the worker) pass `{ secrets, auditUserId }`.
|
|
80
|
+
// `secrets` is a required key on purpose: a whole HandlerContext or JobContext does not carry
|
|
81
|
+
// it flat, so handing one over is a type error instead of a silently undefined secret store.
|
|
82
|
+
// Provider contexts set auditUserId, which takes precedence over the caller in `user`.
|
|
83
83
|
export function requireSecretsContext(
|
|
84
84
|
ctx: {
|
|
85
|
-
readonly secrets
|
|
85
|
+
readonly secrets: SecretsContext | undefined;
|
|
86
86
|
readonly auditUserId?: string | undefined;
|
|
87
87
|
readonly user?: { readonly id: string };
|
|
88
88
|
},
|
|
@@ -91,7 +91,7 @@ export function requireSecretsContext(
|
|
|
91
91
|
if (!ctx.secrets) {
|
|
92
92
|
throw new InternalError({
|
|
93
93
|
message:
|
|
94
|
-
`[${handlerName}] ctx.secrets missing — pass ` +
|
|
94
|
+
`[${handlerName}] ctx.services.secrets missing — pass ` +
|
|
95
95
|
"createSecretsContext({db, masterKeyProvider, registry}) via extraContext.secrets at boot.",
|
|
96
96
|
});
|
|
97
97
|
}
|
|
@@ -187,7 +187,7 @@ export function createSecretsFeature(
|
|
|
187
187
|
// Read-audit domain-event. Registered here so ops tools + MSPs can
|
|
188
188
|
// discover the type; secrets-context.get parses payloads against
|
|
189
189
|
// `secretReadSchema` at write time because the low-level append() path
|
|
190
|
-
// skips ctx.
|
|
190
|
+
// skips ctx.events.append's schema-validation guard.
|
|
191
191
|
r.defineEvent("read", secretReadSchema, { piiFields: "none" });
|
|
192
192
|
|
|
193
193
|
// Per-tenant handlers (set/delete/list) run in the default tenant-scope,
|
|
@@ -18,9 +18,10 @@ export function createDeleteHandler(access: AccessRule = DEFAULT_SECRETS_ACCESS)
|
|
|
18
18
|
access,
|
|
19
19
|
escapeHatch: { grants: ["unsafeRaw"], reason: JOIN_REQUEST_TRANSACTION_REASON },
|
|
20
20
|
handler: async (event, ctx) => {
|
|
21
|
-
const secrets = requireSecretsContext(
|
|
22
|
-
ctx.
|
|
23
|
-
|
|
21
|
+
const secrets = requireSecretsContext(
|
|
22
|
+
{ secrets: ctx.services.secrets, user: ctx.user },
|
|
23
|
+
SecretsHandlers.delete,
|
|
24
|
+
).withRunner(ctx.db.unsafeRaw());
|
|
24
25
|
const gate = checkSecretKeyWrite(ctx.registry, event.user.roles, event.payload.key, {
|
|
25
26
|
allowUndeclared: true,
|
|
26
27
|
});
|
|
@@ -61,13 +61,13 @@ export async function rotateJob(
|
|
|
61
61
|
db: DbConnection,
|
|
62
62
|
): Promise<void> {
|
|
63
63
|
const payload = rawPayload as RotateJobPayload; // @cast-boundary engine-payload
|
|
64
|
-
if (!ctx.masterKeyProvider) {
|
|
64
|
+
if (!ctx.services.masterKeyProvider) {
|
|
65
65
|
throw new InternalError({
|
|
66
66
|
message:
|
|
67
|
-
"[secrets:rotate] ctx.masterKeyProvider missing — wire it via extraContext.masterKeyProvider at boot.",
|
|
67
|
+
"[secrets:rotate] ctx.services.masterKeyProvider missing — wire it via extraContext.masterKeyProvider at boot.",
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
|
-
const provider = ctx.masterKeyProvider;
|
|
70
|
+
const provider = ctx.services.masterKeyProvider;
|
|
71
71
|
const batchSize = payload.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
72
72
|
const maxFailures = payload.maxFailures ?? DEFAULT_MAX_FAILURES;
|
|
73
73
|
const deadline = payload.maxDurationMs
|
|
@@ -81,7 +81,12 @@ export async function rotateJob(
|
|
|
81
81
|
function tdbFor(tenantId: TenantId): TenantDb {
|
|
82
82
|
let existing = tdbCache.get(tenantId);
|
|
83
83
|
if (!existing) {
|
|
84
|
-
existing = createTenantDb({
|
|
84
|
+
existing = createTenantDb({
|
|
85
|
+
db,
|
|
86
|
+
tenantId,
|
|
87
|
+
mode: "system",
|
|
88
|
+
reason: "secret key rotation job re-encrypts secrets of every tenant",
|
|
89
|
+
});
|
|
85
90
|
tdbCache.set(tenantId, existing);
|
|
86
91
|
}
|
|
87
92
|
return existing;
|
|
@@ -137,7 +142,7 @@ export async function rotateJob(
|
|
|
137
142
|
// potentially even past target.
|
|
138
143
|
if (!result.isSuccess) {
|
|
139
144
|
if (result.error.code === "version_conflict") return "skipped";
|
|
140
|
-
ctx.log?.warn?.(`[secrets:rotate] executor rejected row ${row.id}`, {
|
|
145
|
+
ctx.obs.log?.warn?.(`[secrets:rotate] executor rejected row ${row.id}`, {
|
|
141
146
|
code: result.error.code,
|
|
142
147
|
});
|
|
143
148
|
return "failed";
|
|
@@ -150,9 +155,9 @@ export async function rotateJob(
|
|
|
150
155
|
migrateRow,
|
|
151
156
|
maxFailures,
|
|
152
157
|
deadlineAt: deadline,
|
|
153
|
-
signal: ctx.signal,
|
|
158
|
+
signal: ctx.lifecycle.signal,
|
|
154
159
|
onRowError: (row, err) => {
|
|
155
|
-
ctx.log?.warn?.(`[secrets:rotate] failed to rotate row ${row.id}`, { err });
|
|
160
|
+
ctx.obs.log?.warn?.(`[secrets:rotate] failed to rotate row ${row.id}`, { err });
|
|
156
161
|
},
|
|
157
162
|
});
|
|
158
163
|
|
|
@@ -162,5 +167,5 @@ export async function rotateJob(
|
|
|
162
167
|
batchesProcessed: outcome.batchesProcessed,
|
|
163
168
|
stoppedReason: outcome.stoppedReason,
|
|
164
169
|
};
|
|
165
|
-
ctx.log?.info?.(`[secrets:rotate] complete: ${JSON.stringify(result)}`);
|
|
170
|
+
ctx.obs.log?.info?.(`[secrets:rotate] complete: ${JSON.stringify(result)}`);
|
|
166
171
|
}
|
|
@@ -25,9 +25,10 @@ export function createSetHandler(access: AccessRule = DEFAULT_SECRETS_ACCESS) {
|
|
|
25
25
|
access,
|
|
26
26
|
escapeHatch: { grants: ["unsafeRaw"], reason: JOIN_REQUEST_TRANSACTION_REASON },
|
|
27
27
|
handler: async (event, ctx) => {
|
|
28
|
-
const secrets = requireSecretsContext(
|
|
29
|
-
ctx.
|
|
30
|
-
|
|
28
|
+
const secrets = requireSecretsContext(
|
|
29
|
+
{ secrets: ctx.services.secrets, user: ctx.user },
|
|
30
|
+
SecretsHandlers.set,
|
|
31
|
+
).withRunner(ctx.db.unsafeRaw());
|
|
31
32
|
const { key, value, redactedPreview, hint } = event.payload;
|
|
32
33
|
|
|
33
34
|
// Preview-priority: explicit payload param > feature-declared redact
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// Feature-level accessor injected as `ctx.secrets` at boot. Not a HTTP API —
|
|
1
|
+
// Feature-level accessor injected as `ctx.services.secrets` at boot. Not a HTTP API —
|
|
2
2
|
// feature code that needs a plaintext secret (SMTP-connect, Stripe-call, …)
|
|
3
|
-
// pulls it via ctx.secrets.get. Cleartext never crosses the wire.
|
|
3
|
+
// pulls it via ctx.services.secrets.get. Cleartext never crosses the wire.
|
|
4
4
|
//
|
|
5
5
|
// Post-ES pivot: all three ops (get/set/delete) flow through the events-
|
|
6
6
|
// table.
|
|
@@ -154,7 +154,7 @@ function buildSecretsContext(
|
|
|
154
154
|
const readId = generateId();
|
|
155
155
|
const metadata: EventMetadata = { userId: auditCtx.userId };
|
|
156
156
|
// Parse against the registered schema so the low-level append
|
|
157
|
-
// here gets the same validation guarantee as ctx.
|
|
157
|
+
// here gets the same validation guarantee as ctx.events.append.
|
|
158
158
|
// A payload-shape drift between schema + call-site fails at the
|
|
159
159
|
// source instead of landing on the events-stream.
|
|
160
160
|
const payload = secretReadSchema.parse({
|
|
@@ -206,7 +206,12 @@ function buildSecretsContext(
|
|
|
206
206
|
tenantId,
|
|
207
207
|
roles: SYSTEM_ROLES,
|
|
208
208
|
};
|
|
209
|
-
const tdb = createTenantDb({
|
|
209
|
+
const tdb = createTenantDb({
|
|
210
|
+
db,
|
|
211
|
+
tenantId,
|
|
212
|
+
mode: "system",
|
|
213
|
+
reason: "secrets API writes for a caller-named tenant, outside a request scope",
|
|
214
|
+
});
|
|
210
215
|
|
|
211
216
|
const existing = await lookup(tenantId, key);
|
|
212
217
|
const commonFields = {
|
|
@@ -271,7 +276,12 @@ function buildSecretsContext(
|
|
|
271
276
|
tenantId,
|
|
272
277
|
roles: SYSTEM_ROLES,
|
|
273
278
|
};
|
|
274
|
-
const tdb = createTenantDb({
|
|
279
|
+
const tdb = createTenantDb({
|
|
280
|
+
db,
|
|
281
|
+
tenantId,
|
|
282
|
+
mode: "system",
|
|
283
|
+
reason: "secrets API writes for a caller-named tenant, outside a request scope",
|
|
284
|
+
});
|
|
275
285
|
const result = await executor.delete({ id: existing.id }, actor, tdb);
|
|
276
286
|
return result.isSuccess;
|
|
277
287
|
},
|
|
@@ -279,7 +289,7 @@ function buildSecretsContext(
|
|
|
279
289
|
}
|
|
280
290
|
|
|
281
291
|
// Wrap an executor-level write failure into a KumikoError so callers of
|
|
282
|
-
// ctx.secrets.set / .delete can still branch on .code / details / i18nKey
|
|
292
|
+
// ctx.services.secrets.set / .delete can still branch on .code / details / i18nKey
|
|
283
293
|
// after it propagates up. Plain `new Error(...)` would have stripped the
|
|
284
294
|
// structured payload the error-contract promises.
|
|
285
295
|
function wrapSetFailure(err: WriteErrorInfo): InternalError {
|
|
@@ -28,6 +28,11 @@ function unknownKeyFailure(key: string): SecretKeyWriteCheck {
|
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
function isUnderMountedFeaturePrefix(registry: Registry, key: string): boolean {
|
|
32
|
+
const separator = key.indexOf(":");
|
|
33
|
+
return separator > 0 && registry.getFeature(key.slice(0, separator)) !== undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
31
36
|
function namespaceAcceptsKey(namespace: SecretNamespaceDefinition, key: string): boolean {
|
|
32
37
|
const suffix = key.slice(namespace.qualifiedPrefix.length);
|
|
33
38
|
if (suffix.length === 0) return false;
|
|
@@ -38,7 +43,9 @@ function namespaceAcceptsKey(namespace: SecretNamespaceDefinition, key: string):
|
|
|
38
43
|
// are writable through the API, so a tenant admin cannot plant arbitrary rows
|
|
39
44
|
// next to the feature-owned ones. writeRoles narrows the handler access
|
|
40
45
|
// further for a key or a whole namespace. Delete passes allowUndeclared: it
|
|
41
|
-
// creates nothing, and legacy rows under since-undeclared keys must stay removable
|
|
46
|
+
// creates nothing, and legacy rows under since-undeclared keys must stay removable,
|
|
47
|
+
// unless the key sits under a mounted feature's prefix: those rows belong to the
|
|
48
|
+
// feature and must not be removable by a tenant admin outside its writeRoles.
|
|
42
49
|
export function checkSecretKeyWrite(
|
|
43
50
|
registry: Registry,
|
|
44
51
|
userRoles: readonly string[],
|
|
@@ -50,7 +57,7 @@ export function checkSecretKeyWrite(
|
|
|
50
57
|
if (
|
|
51
58
|
!keyDef &&
|
|
52
59
|
!(namespace && namespaceAcceptsKey(namespace, key)) &&
|
|
53
|
-
options.allowUndeclared !== true
|
|
60
|
+
(options.allowUndeclared !== true || isUnderMountedFeaturePrefix(registry, key))
|
|
54
61
|
) {
|
|
55
62
|
return unknownKeyFailure(key);
|
|
56
63
|
}
|
|
@@ -70,7 +77,7 @@ export function checkSecretKeyWrite(
|
|
|
70
77
|
return { ok: true, keyDef };
|
|
71
78
|
}
|
|
72
79
|
|
|
73
|
-
// The registry surface the value check needs; lets ctx.secrets validate without a full Registry.
|
|
80
|
+
// The registry surface the value check needs; lets ctx.services.secrets validate without a full Registry.
|
|
74
81
|
export type SecretValueSchemaSource = Pick<Registry, "getSecretKey" | "findSecretNamespace">;
|
|
75
82
|
|
|
76
83
|
// Carries neither the value nor the schema's issues.
|
|
@@ -285,7 +285,7 @@ export function createSeoFeature(opts: SeoOptions): FeatureDefinition {
|
|
|
285
285
|
sitemapEntries: opts.sitemapEntries,
|
|
286
286
|
includeLegalPages: opts.includeLegalPages ?? false,
|
|
287
287
|
hasManagedPages: opts.managedPages !== undefined,
|
|
288
|
-
log: ctx.log,
|
|
288
|
+
log: ctx.obs.log,
|
|
289
289
|
}),
|
|
290
290
|
);
|
|
291
291
|
|
|
@@ -1,4 +1,23 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.390.0",
|
|
4
|
+
"type": "fix",
|
|
5
|
+
"title": "Session screens show the device without sessionsClient()",
|
|
6
|
+
"detail": "The list, my-sessions and detail screens showed [object Object] in the device column for apps that do not register sessionsClient(). The session queries (user-session:list, user-session:mine, user-session:detail) now return a deviceLabel string such as \"Chrome 141 · macOS\" next to the unchanged device object, null when the user agent is unknown, and the screens render that field. sessionsClient() only adds the translated \"Unknown device\" for rows without a label."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.390.0",
|
|
10
|
+
"type": "improvement",
|
|
11
|
+
"title": "Sessions tests no longer write projection tables directly",
|
|
12
|
+
"detail": "The sessions integration tests change tenant memberships and user status through the update-member-roles handler or the event-store executor instead of writing into the projection tables. Nothing changes for apps; the package is only republished."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"version": "0.389.0",
|
|
16
|
+
"type": "breaking",
|
|
17
|
+
"title": "isPrincipalBlocked is no longer exported from sessions",
|
|
18
|
+
"detail": "The sessions export dropped its re-export of isPrincipalBlocked, which ignored isDeleted. isPrincipalRowBlocked from the user export covers status and isDeleted and is what the session callbacks use.",
|
|
19
|
+
"migration": "import isPrincipalRowBlocked (for a user row) or isPrincipalBlocked (for a bare status) from \"@cosmicdrift/kumiko-bundled-features/user\" instead of the sessions export"
|
|
20
|
+
},
|
|
2
21
|
{
|
|
3
22
|
"version": "0.384.0",
|
|
4
23
|
"type": "improvement",
|
|
@@ -102,6 +102,7 @@ export function createSessionsFeature(options?: SessionsFeatureOptions): Feature
|
|
|
102
102
|
"sessions",
|
|
103
103
|
(r) => {
|
|
104
104
|
const adminRoles = access[options?.adminAccess ?? "admin"];
|
|
105
|
+
r.adoptsBundledLists();
|
|
105
106
|
r.describe(
|
|
106
107
|
"Tracks signed-in clients in the `store_user_sessions` table (one row per JWT, keyed by the `sid`/`jti` claim) and exposes handlers for `mine` (list your sessions), `revoke`, and `revokeAllOthers`. Session creation and revocation on the hot auth path are handled by `createSessionCallbacks()`, wired into `buildServer({ auth: { ... } })` outside the dispatcher; the same callbacks are also registered as an auth-foundation sessionStore provider, resolvable generically via `resolveSessionStore()`. The feature also ships a manual-trigger cleanup job for pruning expired rows and an optional `autoRevokeOnPasswordChange` hook that mass-revokes all sessions for a user whenever their `passwordHash` changes.",
|
|
107
108
|
);
|
|
@@ -156,7 +157,7 @@ export function createSessionsFeature(options?: SessionsFeatureOptions): Feature
|
|
|
156
157
|
} satisfies SessionStoreProvider);
|
|
157
158
|
|
|
158
159
|
// Custom domain-event for cross-instance access-invalidation.
|
|
159
|
-
// r.defineEvent registers the schema so ctx.
|
|
160
|
+
// r.defineEvent registers the schema so ctx.events.unsafeAppend (revoke,
|
|
160
161
|
// revoke-all-others) enforces it at append time. revoke-all-for-user
|
|
161
162
|
// appends via the low-level append() instead (needs to anchor on
|
|
162
163
|
// SYSTEM_TENANT_ID — see that handler for why) — append() does NOT
|
|
@@ -60,7 +60,7 @@ export async function cleanupJob(
|
|
|
60
60
|
let stoppedReason: SessionCleanupResult["stoppedReason"] = "empty";
|
|
61
61
|
|
|
62
62
|
while (true) {
|
|
63
|
-
if (ctx.signal?.aborted) {
|
|
63
|
+
if (ctx.lifecycle.signal?.aborted) {
|
|
64
64
|
stoppedReason = "signal";
|
|
65
65
|
break;
|
|
66
66
|
}
|
|
@@ -79,5 +79,5 @@ export async function cleanupJob(
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
const result: SessionCleanupResult = { deleted, batchesProcessed, stoppedReason };
|
|
82
|
-
ctx.log?.info?.(`[sessions:cleanup] complete: ${JSON.stringify(result)}`);
|
|
82
|
+
ctx.obs.log?.info?.(`[sessions:cleanup] complete: ${JSON.stringify(result)}`);
|
|
83
83
|
}
|
|
@@ -3,7 +3,7 @@ import { access, defineQueryHandler } from "@cosmicdrift/kumiko-framework/engine
|
|
|
3
3
|
import * as z from "zod";
|
|
4
4
|
import { decryptStoredPii } from "../../shared/index.ts";
|
|
5
5
|
import { userSessionTable } from "../schema/user-session.ts";
|
|
6
|
-
import { parsedDeviceSchema, parseUserAgent } from "../web/user-agent.ts";
|
|
6
|
+
import { formatDeviceLabel, parsedDeviceSchema, parseUserAgent } from "../web/user-agent.ts";
|
|
7
7
|
|
|
8
8
|
// Admin single-session inspector — mirrors list.query's decrypt handling for
|
|
9
9
|
// the one-row case. ctx.db (TenantDb) applies tenant-scoping automatically.
|
|
@@ -16,6 +16,7 @@ const sessionRowSchema = z.object({
|
|
|
16
16
|
ip: z.string().nullable(),
|
|
17
17
|
userAgent: z.string().nullable(),
|
|
18
18
|
device: parsedDeviceSchema,
|
|
19
|
+
deviceLabel: z.string().nullable(),
|
|
19
20
|
});
|
|
20
21
|
|
|
21
22
|
export const createDetailQuery = (adminRoles: readonly string[] = access.admin) =>
|
|
@@ -42,6 +43,7 @@ export const createDetailQuery = (adminRoles: readonly string[] = access.admin)
|
|
|
42
43
|
const userAgent = row.userAgent
|
|
43
44
|
? await decryptStoredPii(row.userAgent, "userAgent", "sessions:detail")
|
|
44
45
|
: row.userAgent;
|
|
46
|
+
const device = parseUserAgent(userAgent);
|
|
45
47
|
return {
|
|
46
48
|
id: row.id,
|
|
47
49
|
userId: row.userId,
|
|
@@ -50,7 +52,8 @@ export const createDetailQuery = (adminRoles: readonly string[] = access.admin)
|
|
|
50
52
|
revokedAt: row.revokedAt,
|
|
51
53
|
ip: row.ip ? await decryptStoredPii(row.ip, "ip", "sessions:detail") : row.ip,
|
|
52
54
|
userAgent,
|
|
53
|
-
device
|
|
55
|
+
device,
|
|
56
|
+
deviceLabel: formatDeviceLabel(device),
|
|
54
57
|
};
|
|
55
58
|
},
|
|
56
59
|
});
|
|
@@ -8,7 +8,7 @@ import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
|
|
|
8
8
|
import * as z from "zod";
|
|
9
9
|
import { decryptStoredPii } from "../../shared/index.ts";
|
|
10
10
|
import { userSessionTable } from "../schema/user-session.ts";
|
|
11
|
-
import { parsedDeviceSchema, parseUserAgent } from "../web/user-agent.ts";
|
|
11
|
+
import { formatDeviceLabel, parsedDeviceSchema, parseUserAgent } from "../web/user-agent.ts";
|
|
12
12
|
|
|
13
13
|
// `sort` arrives raw from the client's query string. selectMany's orderBy
|
|
14
14
|
// has no column-existence check — an unrecognised field just gets
|
|
@@ -49,6 +49,7 @@ export const createListQuery = (adminRoles: readonly string[] = access.admin) =>
|
|
|
49
49
|
ip: z.string().nullable(),
|
|
50
50
|
userAgent: z.string().nullable(),
|
|
51
51
|
device: parsedDeviceSchema,
|
|
52
|
+
deviceLabel: z.string().nullable(),
|
|
52
53
|
}),
|
|
53
54
|
),
|
|
54
55
|
nextCursor: z.string().nullable(),
|
|
@@ -85,6 +86,7 @@ export const createListQuery = (adminRoles: readonly string[] = access.admin) =>
|
|
|
85
86
|
const userAgent = r.userAgent
|
|
86
87
|
? await decryptStoredPii(r.userAgent, "userAgent", "sessions:list")
|
|
87
88
|
: r.userAgent;
|
|
89
|
+
const device = parseUserAgent(userAgent);
|
|
88
90
|
return {
|
|
89
91
|
id: r.id,
|
|
90
92
|
userId: r.userId,
|
|
@@ -93,7 +95,8 @@ export const createListQuery = (adminRoles: readonly string[] = access.admin) =>
|
|
|
93
95
|
revokedAt: r.revokedAt,
|
|
94
96
|
ip: r.ip ? await decryptStoredPii(r.ip, "ip", "sessions:list") : r.ip,
|
|
95
97
|
userAgent,
|
|
96
|
-
device
|
|
98
|
+
device,
|
|
99
|
+
deviceLabel: formatDeviceLabel(device),
|
|
97
100
|
};
|
|
98
101
|
}),
|
|
99
102
|
);
|
|
@@ -3,7 +3,7 @@ import { definePagedQueryHandler } from "@cosmicdrift/kumiko-framework/engine";
|
|
|
3
3
|
import * as z from "zod";
|
|
4
4
|
import { decryptStoredPii } from "../../shared/index.ts";
|
|
5
5
|
import { userSessionTable } from "../schema/user-session.ts";
|
|
6
|
-
import { parsedDeviceSchema, parseUserAgent } from "../web/user-agent.ts";
|
|
6
|
+
import { formatDeviceLabel, parsedDeviceSchema, parseUserAgent } from "../web/user-agent.ts";
|
|
7
7
|
|
|
8
8
|
// "My live sessions" — the backing data for a devices/sessions UI. Returns
|
|
9
9
|
// ONLY the current user's own, currently-live sessions, ordered by most-
|
|
@@ -31,6 +31,7 @@ export const mineQuery = definePagedQueryHandler({
|
|
|
31
31
|
ip: z.string().nullable(),
|
|
32
32
|
userAgent: z.string().nullable(),
|
|
33
33
|
device: parsedDeviceSchema,
|
|
34
|
+
deviceLabel: z.string().nullable(),
|
|
34
35
|
current: z.boolean(),
|
|
35
36
|
}),
|
|
36
37
|
),
|
|
@@ -57,13 +58,15 @@ export const mineQuery = definePagedQueryHandler({
|
|
|
57
58
|
const userAgent = r.userAgent
|
|
58
59
|
? await decryptStoredPii(r.userAgent, "userAgent", "sessions:mine")
|
|
59
60
|
: r.userAgent;
|
|
61
|
+
const device = parseUserAgent(userAgent);
|
|
60
62
|
return {
|
|
61
63
|
id: r.id,
|
|
62
64
|
createdAt: r.createdAt,
|
|
63
65
|
expiresAt: r.expiresAt,
|
|
64
66
|
ip: r.ip ? await decryptStoredPii(r.ip, "ip", "sessions:mine") : r.ip,
|
|
65
67
|
userAgent,
|
|
66
|
-
device
|
|
68
|
+
device,
|
|
69
|
+
deviceLabel: formatDeviceLabel(device),
|
|
67
70
|
current: currentSid === r.id,
|
|
68
71
|
};
|
|
69
72
|
}),
|
|
@@ -67,9 +67,9 @@ export const revokeAllForUserWrite = defineWriteHandler({
|
|
|
67
67
|
// Lightweight append alongside the direct-write above; see revoke.write.ts
|
|
68
68
|
// for why this isn't a lifecycle event on
|
|
69
69
|
// store_user_sessions. Uses the low-level append() (not
|
|
70
|
-
// ctx.
|
|
70
|
+
// ctx.events.unsafeAppend) because this handler is deliberately
|
|
71
71
|
// cross-tenant: the privileged caller's own tenantId (what
|
|
72
|
-
// ctx.
|
|
72
|
+
// ctx.events.unsafeAppend would bind to) has no relationship to the
|
|
73
73
|
// target user's session tenant(s). Anchored on SYSTEM_TENANT_ID
|
|
74
74
|
// instead, same as the jobs feature's cross-tenant run-lifecycle
|
|
75
75
|
// events (job-run-logger.ts) — a fresh aggregate per call, so no
|
|
@@ -77,7 +77,7 @@ export const revokeAllForUserWrite = defineWriteHandler({
|
|
|
77
77
|
//
|
|
78
78
|
// append() itself does NOT validate against the r.defineEvent-
|
|
79
79
|
// registered schema (that guarantee only comes from going through
|
|
80
|
-
// ctx.
|
|
80
|
+
// ctx.events.unsafeAppend's dispatcher path). Mirrors job-run-logger.ts:
|
|
81
81
|
// parse explicitly before the raw append so a shape drift fails loudly
|
|
82
82
|
// here instead of landing unvalidated on the events table.
|
|
83
83
|
if (updated.length > 0) {
|
|
@@ -51,7 +51,7 @@ export const revokeAllOthersWrite = defineWriteHandler({
|
|
|
51
51
|
// store_user_sessions. Skipped when nothing was revoked (no other
|
|
52
52
|
// live sessions) — a spurious invalidation would be the failure mode.
|
|
53
53
|
if (updated.length > 0) {
|
|
54
|
-
await ctx.
|
|
54
|
+
await ctx.events.unsafeAppend({
|
|
55
55
|
aggregateId: generateId(),
|
|
56
56
|
aggregateType: SESSION_REVOKED_AGGREGATE_TYPE,
|
|
57
57
|
type: SESSION_REVOKED_EVENT_QN,
|
|
@@ -55,7 +55,7 @@ export const revokeWrite = defineWriteHandler({
|
|
|
55
55
|
// unmanaged direct-write store, see feature.ts). Own aggregate id per
|
|
56
56
|
// revoke, no predecessor to satisfy, no version_conflict against a
|
|
57
57
|
// concurrent revoke on a different sid.
|
|
58
|
-
await ctx.
|
|
58
|
+
await ctx.events.unsafeAppend({
|
|
59
59
|
aggregateId: generateId(),
|
|
60
60
|
aggregateType: SESSION_REVOKED_AGGREGATE_TYPE,
|
|
61
61
|
type: SESSION_REVOKED_EVENT_QN,
|
|
@@ -15,7 +15,7 @@ export type {
|
|
|
15
15
|
SessionCallbacksOptions,
|
|
16
16
|
SessionMassRevoker,
|
|
17
17
|
} from "./session-callbacks.ts";
|
|
18
|
-
export { createSessionCallbacks
|
|
18
|
+
export { createSessionCallbacks } from "./session-callbacks.ts";
|
|
19
19
|
export type { SessionRevokedPayload } from "./session-revoked-event.ts";
|
|
20
20
|
export {
|
|
21
21
|
SESSION_REVOKED_AGGREGATE_TYPE,
|
|
@@ -39,7 +39,7 @@ export const createSessionListScreen = (
|
|
|
39
39
|
refLabelField: "displayName",
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
|
-
field: "
|
|
42
|
+
field: "deviceLabel",
|
|
43
43
|
label: i18nKey("sessions.list.col.device"),
|
|
44
44
|
renderer: DEVICE_RENDERER,
|
|
45
45
|
},
|
|
@@ -94,7 +94,7 @@ export const createSessionDetailScreen = (
|
|
|
94
94
|
{ field: "createdAt", renderer: { format: "timestamp" } },
|
|
95
95
|
{ field: "expiresAt", renderer: { format: "timestamp" } },
|
|
96
96
|
{ field: "revokedAt", renderer: { format: "timestamp" } },
|
|
97
|
-
{ field: "
|
|
97
|
+
{ field: "deviceLabel", renderer: DEVICE_RENDERER },
|
|
98
98
|
"ip",
|
|
99
99
|
"userAgent",
|
|
100
100
|
],
|
|
@@ -107,7 +107,7 @@ export const createSessionDetailScreen = (
|
|
|
107
107
|
createdAt: i18nKey("sessions.detail.field.createdAt"),
|
|
108
108
|
expiresAt: i18nKey("sessions.detail.field.expiresAt"),
|
|
109
109
|
revokedAt: i18nKey("sessions.detail.field.revokedAt"),
|
|
110
|
-
|
|
110
|
+
deviceLabel: i18nKey("sessions.list.col.device"),
|
|
111
111
|
ip: i18nKey("sessions.detail.field.ip"),
|
|
112
112
|
userAgent: i18nKey("sessions.detail.field.userAgent"),
|
|
113
113
|
},
|
|
@@ -120,7 +120,11 @@ export const sessionMineScreen: ProjectionListScreenDefinition = {
|
|
|
120
120
|
type: "projectionList",
|
|
121
121
|
query: SessionQueries.mine,
|
|
122
122
|
columns: [
|
|
123
|
-
{
|
|
123
|
+
{
|
|
124
|
+
field: "deviceLabel",
|
|
125
|
+
label: i18nKey("sessions.mine.col.userAgent"),
|
|
126
|
+
renderer: DEVICE_RENDERER,
|
|
127
|
+
},
|
|
124
128
|
{ field: "ip", label: i18nKey("sessions.mine.col.ip") },
|
|
125
129
|
{
|
|
126
130
|
field: "current",
|
|
@@ -18,12 +18,7 @@ import { generateId, parseRoles } from "@cosmicdrift/kumiko-framework/utils";
|
|
|
18
18
|
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
19
19
|
import { encryptForDirectWrite } from "../shared/index.ts";
|
|
20
20
|
import { tenantMembershipsTable } from "../tenant/index.ts";
|
|
21
|
-
import {
|
|
22
|
-
isPrincipalBlocked,
|
|
23
|
-
isPrincipalRowBlocked,
|
|
24
|
-
type UserStatus,
|
|
25
|
-
userTable,
|
|
26
|
-
} from "../user/index.ts";
|
|
21
|
+
import { isPrincipalRowBlocked, type UserStatus, userTable } from "../user/index.ts";
|
|
27
22
|
import {
|
|
28
23
|
DEFAULT_SESSION_EXPIRY_MS,
|
|
29
24
|
LAST_SEEN_REFRESH_MS,
|
|
@@ -36,9 +31,6 @@ import {
|
|
|
36
31
|
sessionRevokedSchema,
|
|
37
32
|
} from "./session-revoked-event.ts";
|
|
38
33
|
|
|
39
|
-
// Re-exported so existing `../sessions` importers keep working unchanged.
|
|
40
|
-
export { isPrincipalBlocked };
|
|
41
|
-
|
|
42
34
|
type SettledLookup<T> = { readonly ok: true; readonly value: T } | { readonly ok: false };
|
|
43
35
|
|
|
44
36
|
function settleLookup<T>(lookup: Promise<T>): Promise<SettledLookup<T>> {
|