@cosmicdrift/kumiko-samples 0.389.0 → 0.390.1
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 +27 -15
- package/packages/bundled-features/src/audit/feature.ts +1 -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 +6 -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/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 +12 -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 +2 -2
- package/packages/bundled-features/src/auth-email-password/handlers/verify-email.write.ts +3 -2
- package/packages/bundled-features/src/auth-email-password/seeding.ts +14 -9
- package/packages/bundled-features/src/auth-foundation/feature.ts +13 -4
- 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 +9 -3
- 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 +1 -1
- package/packages/bundled-features/src/cap-counter/constants.ts +1 -1
- package/packages/bundled-features/src/cap-counter/feature.ts +2 -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/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/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 +4 -4
- package/packages/bundled-features/src/config/handlers/values.query.ts +1 -1
- package/packages/bundled-features/src/crypto-shredding/handlers/forget-subject.write.ts +8 -8
- 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/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/delivery-service.ts +6 -5
- package/packages/bundled-features/src/delivery/feature.ts +2 -2
- package/packages/bundled-features/src/delivery/jobs.ts +11 -11
- package/packages/bundled-features/src/delivery/testing.ts +1 -1
- package/packages/bundled-features/src/document-ingest-foundation/events.ts +1 -1
- 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/inbound-mail-foundation/events.ts +1 -1
- package/packages/bundled-features/src/inbound-mail-foundation/feature.ts +1 -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/changes.json +6 -0
- 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/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/legal-pages/README.md +1 -1
- package/packages/bundled-features/src/legal-pages/lib/boot-check.ts +12 -8
- package/packages/bundled-features/src/mail-foundation/feature.ts +2 -2
- package/packages/bundled-features/src/mail-transport-smtp/changes.json +6 -0
- package/packages/bundled-features/src/mail-transport-smtp/feature.ts +4 -1
- package/packages/bundled-features/src/managed-pages/seeding.ts +13 -8
- package/packages/bundled-features/src/notes-history/handlers/add-note.write.ts +1 -1
- package/packages/bundled-features/src/personal-access-tokens/feature.ts +1 -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/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 +1 -1
- package/packages/bundled-features/src/seo/feature.ts +1 -1
- package/packages/bundled-features/src/sessions/changes.json +12 -0
- package/packages/bundled-features/src/sessions/feature.ts +1 -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/screens.ts +8 -4
- 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 +12 -2
- package/packages/bundled-features/src/shared/require-for-tenant.ts +7 -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/feature.ts +1 -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/template-resolver/api.ts +3 -3
- package/packages/bundled-features/src/template-resolver/changes.json +18 -0
- 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/overview.query.ts +2 -2
- package/packages/bundled-features/src/template-resolver/handlers/send-test-shared.ts +1 -1
- 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 +12 -2
- package/packages/bundled-features/src/template-resolver/store-template-resource.ts +18 -13
- 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/placeholder-line-editor.tsx +19 -6
- 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/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/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/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 +7 -3
- 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/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 +24 -0
- package/packages/bundled-features/src/user-data-rights/feature.ts +29 -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 +2 -0
- 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 +10 -0
- package/packages/bundled-features/src/user-data-rights/web/index.ts +6 -1
- package/packages/bundled-features/src/user-profile/handlers/change-email.write.ts +8 -6
- 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 +9 -4
- package/packages/bundled-features/src/waitlist/legacy-migrate.ts +6 -1
- package/packages/bundled-features/src/waitlist/link-on-signup.ts +7 -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/package.json +1 -1
- 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/server.ts +2 -2
- package/samples/apps/ui-walkthrough/package.json +1 -1
- package/samples/apps/use-all-bundled/feature-manifest.json +1 -1
- package/samples/apps/use-all-bundled/package.json +1 -1
- package/samples/apps/use-all-bundled/src/app/seed.ts +12 -2
- package/samples/apps/user-data-rights-demo/README.md +1 -1
- package/samples/apps/user-data-rights-demo/package.json +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/lane-routing/package.json +1 -1
- package/samples/recipes/legal-pages/README.md +2 -2
- package/samples/recipes/lifecycle-hooks/README.md +2 -2
- package/samples/recipes/lifecycle-hooks/src/feature.ts +1 -1
- package/samples/recipes/managed-config/README.md +3 -3
- 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 +1 -1
- package/samples/recipes/state-machine/src/reducer.ts +1 -1
- package/samples/recipes/workflow-engine/src/resume-loop.ts +4 -4
- package/samples/recipes/workflow-engine/src/workflow-runner.ts +2 -2
|
@@ -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 {
|
|
@@ -77,7 +77,7 @@ export function checkSecretKeyWrite(
|
|
|
77
77
|
return { ok: true, keyDef };
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
// 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.
|
|
81
81
|
export type SecretValueSchemaSource = Pick<Registry, "getSecretKey" | "findSecretNamespace">;
|
|
82
82
|
|
|
83
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,16 @@
|
|
|
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
|
+
},
|
|
2
14
|
{
|
|
3
15
|
"version": "0.389.0",
|
|
4
16
|
"type": "breaking",
|
|
@@ -157,7 +157,7 @@ export function createSessionsFeature(options?: SessionsFeatureOptions): Feature
|
|
|
157
157
|
} satisfies SessionStoreProvider);
|
|
158
158
|
|
|
159
159
|
// Custom domain-event for cross-instance access-invalidation.
|
|
160
|
-
// r.defineEvent registers the schema so ctx.
|
|
160
|
+
// r.defineEvent registers the schema so ctx.events.unsafeAppend (revoke,
|
|
161
161
|
// revoke-all-others) enforces it at append time. revoke-all-for-user
|
|
162
162
|
// appends via the low-level append() instead (needs to anchor on
|
|
163
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,
|
|
@@ -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",
|
|
@@ -12,7 +12,7 @@ import * as z from "zod";
|
|
|
12
12
|
// _SHORT/_QN pair mirrors cap-counter's rolling-incremented event:
|
|
13
13
|
// _SHORT — r.defineEvent(short, schema) in feature.ts, framework prefixes
|
|
14
14
|
// it to the QN below.
|
|
15
|
-
// _QN — ctx.
|
|
15
|
+
// _QN — ctx.events.unsafeAppend({ type }) / raw append()'s `type` field.
|
|
16
16
|
export const SESSION_REVOKED_EVENT_SHORT = "session-revoked" as const;
|
|
17
17
|
export const SESSION_REVOKED_EVENT_QN = "sessions:event:session-revoked" as const;
|
|
18
18
|
|
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
// Column renderer for
|
|
1
|
+
// Column renderer for session devices, registered via `sessionsClient()`. Takes the server-made
|
|
2
|
+
// `deviceLabel` string, or the parsed `device` object for screens that bind that column.
|
|
2
3
|
|
|
3
4
|
import { type ColumnRendererProps, useTranslation } from "@cosmicdrift/kumiko-renderer";
|
|
4
5
|
import type { ReactNode } from "react";
|
|
5
|
-
import { parsedDeviceSchema } from "./user-agent.ts";
|
|
6
|
+
import { formatDeviceLabel, parsedDeviceSchema } from "./user-agent.ts";
|
|
7
|
+
|
|
8
|
+
function deviceLabelOf(value: unknown): string | null {
|
|
9
|
+
if (typeof value === "string") return value === "" ? null : value;
|
|
10
|
+
const parsed = parsedDeviceSchema.safeParse(value);
|
|
11
|
+
return parsed.success ? formatDeviceLabel(parsed.data) : null;
|
|
12
|
+
}
|
|
6
13
|
|
|
7
14
|
export function SessionDeviceCell({ value }: ColumnRendererProps): ReactNode {
|
|
8
15
|
const t = useTranslation();
|
|
9
|
-
|
|
10
|
-
const device = parsed.success ? parsed.data : null;
|
|
11
|
-
if (device === null) return t("sessions.device.unknown");
|
|
12
|
-
const browser =
|
|
13
|
-
device.browser === null
|
|
14
|
-
? null
|
|
15
|
-
: device.browserMajor === null
|
|
16
|
-
? device.browser
|
|
17
|
-
: `${device.browser} ${device.browserMajor}`;
|
|
18
|
-
return [browser, device.os].filter((part) => part !== null).join(" · ");
|
|
16
|
+
return deviceLabelOf(value) ?? t("sessions.device.unknown");
|
|
19
17
|
}
|
|
@@ -56,6 +56,18 @@ const OPERATING_SYSTEM_PATTERNS: readonly {
|
|
|
56
56
|
{ os: "Linux", pattern: /\bLinux\b/ },
|
|
57
57
|
];
|
|
58
58
|
|
|
59
|
+
export function formatDeviceLabel(device: ParsedDevice): string | null {
|
|
60
|
+
if (device === null) return null;
|
|
61
|
+
const browser =
|
|
62
|
+
device.browser === null
|
|
63
|
+
? null
|
|
64
|
+
: device.browserMajor === null
|
|
65
|
+
? device.browser
|
|
66
|
+
: `${device.browser} ${device.browserMajor}`;
|
|
67
|
+
const parts = [browser, device.os].filter((part) => part !== null);
|
|
68
|
+
return parts.length === 0 ? null : parts.join(" · ");
|
|
69
|
+
}
|
|
70
|
+
|
|
59
71
|
export function parseUserAgent(userAgent: string | null): ParsedDevice {
|
|
60
72
|
if (userAgent === null || userAgent === "") return null;
|
|
61
73
|
let browser: UserAgentBrowser | null = null;
|
|
@@ -92,5 +92,20 @@ export {
|
|
|
92
92
|
type SignupHandoverProvider,
|
|
93
93
|
} from "./signup-handover.ts";
|
|
94
94
|
export { createSingleUseTokenStore, hashSingleUseToken } from "./single-use-token-store.ts";
|
|
95
|
+
export {
|
|
96
|
+
backfillAggregateStreamTenants,
|
|
97
|
+
type StreamBackfillCandidate,
|
|
98
|
+
type StreamBackfillFailure,
|
|
99
|
+
type StreamBackfillOptions,
|
|
100
|
+
type StreamBackfillResult,
|
|
101
|
+
type StreamTenantTarget,
|
|
102
|
+
} from "./stream-tenant-backfill.ts";
|
|
103
|
+
export {
|
|
104
|
+
createSearchBucketCleanup,
|
|
105
|
+
type DerivedStateMode,
|
|
106
|
+
rebuildAndReindex,
|
|
107
|
+
type StreamBackfillStepFailure,
|
|
108
|
+
stepFailures,
|
|
109
|
+
} from "./stream-tenant-derived-state.ts";
|
|
95
110
|
export type { SystemQueryFn } from "./system-query.ts";
|
|
96
111
|
export { type BurnResult, burnToken, unburnToken } from "./token-burn-store.ts";
|
|
@@ -206,7 +206,12 @@ export async function purgeFilesReachingSubject(args: {
|
|
|
206
206
|
}
|
|
207
207
|
const deleteBytes = await storagePromise;
|
|
208
208
|
const systemUser = createSystemUser(tenantId);
|
|
209
|
-
const tdb = createTenantDb({
|
|
209
|
+
const tdb = createTenantDb({
|
|
210
|
+
db,
|
|
211
|
+
tenantId,
|
|
212
|
+
mode: "system",
|
|
213
|
+
reason: "subject erasure purges file refs in every tenant that holds them",
|
|
214
|
+
});
|
|
210
215
|
|
|
211
216
|
const outcome = await purgeRowFileRefs({
|
|
212
217
|
db,
|
|
@@ -353,7 +358,12 @@ async function purgePendingFileRef(
|
|
|
353
358
|
const forgotten = await fileRefExecutor.forget(
|
|
354
359
|
{ id: fileRefId },
|
|
355
360
|
createSystemUser(tenantId),
|
|
356
|
-
createTenantDb({
|
|
361
|
+
createTenantDb({
|
|
362
|
+
db,
|
|
363
|
+
tenantId,
|
|
364
|
+
mode: "system",
|
|
365
|
+
reason: "subject erasure purges file refs in every tenant that holds them",
|
|
366
|
+
}),
|
|
357
367
|
);
|
|
358
368
|
return forgotten.isSuccess
|
|
359
369
|
? undefined
|
|
@@ -5,14 +5,16 @@ import type {
|
|
|
5
5
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
6
6
|
import { InternalError } from "@cosmicdrift/kumiko-framework/errors";
|
|
7
7
|
|
|
8
|
-
// ctx.
|
|
8
|
+
// ctx.tenants.writeTarget is absent for r.systemScope() handlers and without a db; a write handler that
|
|
9
9
|
// needs a cross-tenant target must fail loudly instead of falling back to ctx.db.
|
|
10
10
|
export function requireForTenant(
|
|
11
|
-
ctx: Pick<HandlerContext, "
|
|
11
|
+
ctx: Pick<HandlerContext, "tenants">,
|
|
12
12
|
targetTenantId: TenantId,
|
|
13
13
|
): TenantWriteTarget {
|
|
14
|
-
if (!ctx.
|
|
15
|
-
throw new InternalError({
|
|
14
|
+
if (!ctx.tenants.writeTarget) {
|
|
15
|
+
throw new InternalError({
|
|
16
|
+
message: "ctx.tenants.writeTarget is not available in this handler context",
|
|
17
|
+
});
|
|
16
18
|
}
|
|
17
|
-
return ctx.
|
|
19
|
+
return ctx.tenants.writeTarget(targetTenantId);
|
|
18
20
|
}
|