@cosmicdrift/kumiko-framework 0.369.0 → 0.370.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/AGENTS.md +14 -1
- package/agents/examples/apex-surface-auth.md +2 -1
- package/agents/examples/app-config.md +98 -0
- package/agents/examples/auth-mfa.md +72 -0
- package/agents/examples/compose-stacks.md +188 -0
- package/agents/examples/env-composition.md +268 -0
- package/agents/examples/host-routing.md +181 -0
- package/agents/examples/legal-pages.md +52 -3
- package/agents/examples/managed-config.md +1 -0
- package/agents/examples/managed-pages.md +1 -0
- package/agents/examples/prod-boot-options.md +180 -0
- package/agents/examples/relations.md +4 -0
- package/agents/examples/secrets-demo.md +4 -2
- package/agents/examples/security-baseline.md +20 -17
- package/agents/examples.md +6 -1
- package/agents/features.md +14 -2
- package/dist/api/anonymous-cookie.d.ts +1 -1
- package/dist/api/anonymous-live-entities.d.ts +1 -1
- package/dist/api/auth-middleware.d.ts +2 -2
- package/dist/api/auth-routes.d.ts +7 -7
- package/dist/api/extra-route.d.ts +2 -2
- package/dist/api/index.d.ts +37 -37
- package/dist/api/jwt.d.ts +1 -1
- package/dist/api/observability-middleware.d.ts +1 -1
- package/dist/api/readiness.d.ts +1 -1
- package/dist/api/redis-sse-broker.d.ts +2 -2
- package/dist/api/request-context.d.ts +1 -1
- package/dist/api/request-id-middleware.d.ts +3 -3
- package/dist/api/route-registrars.d.ts +4 -4
- package/dist/api/routes.d.ts +1 -1
- package/dist/api/server.d.ts +16 -16
- package/dist/api/sse-broker.d.ts +1 -1
- package/dist/api/sse-route.d.ts +1 -1
- package/dist/api/websocket-route.d.ts +3 -3
- package/dist/auth/index.d.ts +2 -2
- package/dist/compliance/duration-spec.d.ts +2 -2
- package/dist/compliance/index.d.ts +6 -6
- package/dist/compliance/profiles.d.ts +1 -1
- package/dist/config/index.d.ts +44 -0
- package/dist/config/index.js +61 -0
- package/dist/crypto/blind-index.d.ts +1 -1
- package/dist/crypto/event-pii.d.ts +1 -1
- package/dist/crypto/in-memory-kms-adapter.d.ts +1 -1
- package/dist/crypto/index.d.ts +11 -11
- package/dist/crypto/is-self-pii-field.d.ts +1 -1
- package/dist/crypto/kms-wiring.d.ts +2 -2
- package/dist/crypto/owner-transition-rekey.d.ts +1 -1
- package/dist/crypto/pg-kms-adapter.d.ts +1 -1
- package/dist/crypto/pii-field-encryption.d.ts +4 -4
- package/dist/crypto/request-kms-cache.d.ts +1 -1
- package/dist/crypto/subject-resolver.d.ts +3 -3
- package/dist/db/apply-entity-event.d.ts +4 -4
- package/dist/db/assert-exists-in.d.ts +4 -4
- package/dist/db/blind-index-cleanup.d.ts +2 -2
- package/dist/db/collect-table-metas.d.ts +2 -2
- package/dist/db/compound-types.d.ts +1 -1
- package/dist/db/config-seed.d.ts +5 -5
- package/dist/db/connection.d.ts +1 -6
- package/dist/db/connection.js +15 -4
- package/dist/db/dialect.d.ts +1 -1
- package/dist/db/eagerload.d.ts +3 -3
- package/dist/db/entity-field-encryption.d.ts +3 -3
- package/dist/db/entity-field-encryption.js +3 -1
- package/dist/db/entity-table-from-registry.d.ts +3 -3
- package/dist/db/entity-table-meta.d.ts +3 -3
- package/dist/db/event-store-executor-context.d.ts +9 -9
- package/dist/db/event-store-executor-read.d.ts +2 -2
- package/dist/db/event-store-executor-write.d.ts +2 -2
- package/dist/db/event-store-executor.d.ts +8 -8
- package/dist/db/feature-table-sources.d.ts +1 -1
- package/dist/db/index.d.ts +39 -39
- package/dist/db/located-timestamp.d.ts +1 -1
- package/dist/db/lock-guard.d.ts +2 -2
- package/dist/db/migrate-generator.d.ts +2 -2
- package/dist/db/migrate-runner.d.ts +1 -1
- package/dist/db/money.d.ts +1 -1
- package/dist/db/parent-ref-clause.d.ts +4 -4
- package/dist/db/projection-registry-binding.d.ts +1 -1
- package/dist/db/queries/advisory-lock.d.ts +1 -1
- package/dist/db/queries/backfill-pii.d.ts +2 -2
- package/dist/db/queries/ddl.d.ts +1 -1
- package/dist/db/queries/entity-read.d.ts +1 -1
- package/dist/db/queries/es-ops.d.ts +1 -1
- package/dist/db/queries/event-consumer.d.ts +2 -2
- package/dist/db/queries/event-store-admin.d.ts +1 -1
- package/dist/db/queries/event-store-transfer.d.ts +1 -1
- package/dist/db/queries/event-store.d.ts +1 -1
- package/dist/db/queries/pii-backfill-state.d.ts +1 -1
- package/dist/db/queries/projection-rebuild.d.ts +1 -1
- package/dist/db/queries/raw-sql.d.ts +1 -1
- package/dist/db/queries/seed-context.d.ts +2 -2
- package/dist/db/queries/shadow-swap.d.ts +3 -3
- package/dist/db/queries/table-ops.d.ts +1 -1
- package/dist/db/queries/test-stack.d.ts +2 -2
- package/dist/db/query.d.ts +3 -3
- package/dist/db/rebuild-marker.d.ts +1 -1
- package/dist/db/reference-data.d.ts +3 -3
- package/dist/db/render-ddl.d.ts +1 -1
- package/dist/db/replay-migration-sql.d.ts +1 -1
- package/dist/db/retired-framework-tables.d.ts +1 -1
- package/dist/db/schema-inspection.d.ts +1 -1
- package/dist/db/table-builder.d.ts +4 -4
- package/dist/db/table-push.d.ts +3 -3
- package/dist/db/tenant-db-runner.d.ts +2 -2
- package/dist/db/tenant-db.d.ts +7 -9
- package/dist/db/tenant-db.js +2 -12
- package/dist/derivatives/derivatives-context.d.ts +3 -3
- package/dist/derivatives/field-variants.d.ts +1 -1
- package/dist/derivatives/index.d.ts +6 -6
- package/dist/engine/access.d.ts +1 -1
- package/dist/engine/active-membership.d.ts +2 -2
- package/dist/engine/boot-validator/access-declarations.d.ts +1 -1
- package/dist/engine/boot-validator/access-roles.d.ts +1 -1
- package/dist/engine/boot-validator/action-wiring.d.ts +1 -1
- package/dist/engine/boot-validator/api-ext.d.ts +1 -1
- package/dist/engine/boot-validator/boot-check.d.ts +1 -1
- package/dist/engine/boot-validator/card-meta-overflow.d.ts +1 -1
- package/dist/engine/boot-validator/config-deps.d.ts +1 -1
- package/dist/engine/boot-validator/detail-screens.d.ts +2 -2
- package/dist/engine/boot-validator/entity-handler.d.ts +1 -1
- package/dist/engine/boot-validator/entity-list-screens.d.ts +1 -1
- package/dist/engine/boot-validator/gdpr-storage.d.ts +1 -1
- package/dist/engine/boot-validator/global-tenancy.d.ts +1 -1
- package/dist/engine/boot-validator/handler-field-references.d.ts +1 -1
- package/dist/engine/boot-validator/i18n-keys.d.ts +1 -1
- package/dist/engine/boot-validator/index.d.ts +7 -7
- package/dist/engine/boot-validator/nav.d.ts +1 -1
- package/dist/engine/boot-validator/ownership.d.ts +2 -2
- package/dist/engine/boot-validator/parent-ref.d.ts +1 -1
- package/dist/engine/boot-validator/pii-retention.d.ts +2 -2
- package/dist/engine/boot-validator/projection-list-screens.d.ts +1 -1
- package/dist/engine/boot-validator/query-output-columns.d.ts +1 -1
- package/dist/engine/boot-validator/query-refs.d.ts +1 -1
- package/dist/engine/boot-validator/record-owned.d.ts +1 -1
- package/dist/engine/boot-validator/screens.d.ts +2 -2
- package/dist/engine/boot-validator/security-baseline.d.ts +1 -1
- package/dist/engine/boot-validator/selector-owner-panels.d.ts +1 -1
- package/dist/engine/boot-validator/transfer-graph.d.ts +2 -2
- package/dist/engine/boot-validator/url-prefill-fields.d.ts +1 -1
- package/dist/engine/boot-validator/workspaces.d.ts +1 -1
- package/dist/engine/boot-validator.d.ts +1 -1
- package/dist/engine/bridge-stub.d.ts +1 -1
- package/dist/engine/build-app-schema.d.ts +2 -2
- package/dist/engine/build-config-feature-schema.d.ts +5 -5
- package/dist/engine/build-target.d.ts +2 -2
- package/dist/engine/changeset-changes.d.ts +1 -1
- package/dist/engine/codemod/index.d.ts +2 -2
- package/dist/engine/config-helpers.d.ts +1 -1
- package/dist/engine/constants.d.ts +1 -1
- package/dist/engine/create-app.d.ts +2 -2
- package/dist/engine/cross-tenant.d.ts +2 -2
- package/dist/engine/dedupe-features.d.ts +1 -1
- package/dist/engine/define-feature.d.ts +1 -1
- package/dist/engine/define-feature.js +2 -2
- package/dist/engine/define-handler.d.ts +4 -4
- package/dist/engine/define-step.d.ts +1 -1
- package/dist/engine/define-workflow.d.ts +2 -2
- package/dist/engine/effective-features.d.ts +1 -1
- package/dist/engine/embedded-derived.d.ts +1 -1
- package/dist/engine/entity-handlers.d.ts +6 -5
- package/dist/engine/entity-handlers.js +6 -3
- package/dist/engine/event-def.d.ts +15 -0
- package/dist/engine/event-def.js +123 -0
- package/dist/engine/event-helpers.d.ts +1 -1
- package/dist/engine/extension-names.d.ts +8 -8
- package/dist/engine/extension-selector-plugins.d.ts +2 -2
- package/dist/engine/extensions/escape-hatch-usage.d.ts +1 -1
- package/dist/engine/extensions/storage-provider.d.ts +1 -1
- package/dist/engine/extensions/tenant-data.d.ts +3 -3
- package/dist/engine/extensions/tenant-resource.d.ts +2 -2
- package/dist/engine/extensions/user-data.d.ts +2 -2
- package/dist/engine/factories.d.ts +1 -1
- package/dist/engine/feature-ast/extractors/ai-steps.d.ts +2 -2
- package/dist/engine/feature-ast/extractors/events.d.ts +2 -2
- package/dist/engine/feature-ast/extractors/handlers.d.ts +4 -4
- package/dist/engine/feature-ast/extractors/hooks.d.ts +5 -5
- package/dist/engine/feature-ast/extractors/index.d.ts +14 -14
- package/dist/engine/feature-ast/extractors/jobs-routes.d.ts +3 -3
- package/dist/engine/feature-ast/extractors/projections-screens.d.ts +3 -3
- package/dist/engine/feature-ast/extractors/round1.d.ts +2 -2
- package/dist/engine/feature-ast/extractors/round2.d.ts +2 -2
- package/dist/engine/feature-ast/extractors/round3.d.ts +4 -4
- package/dist/engine/feature-ast/extractors/round5.d.ts +2 -2
- package/dist/engine/feature-ast/extractors/round6.d.ts +2 -2
- package/dist/engine/feature-ast/extractors/shared.d.ts +2 -2
- package/dist/engine/feature-ast/index.d.ts +16 -16
- package/dist/engine/feature-ast/parse.d.ts +2 -2
- package/dist/engine/feature-ast/patch.d.ts +1 -1
- package/dist/engine/feature-ast/patcher.d.ts +15 -15
- package/dist/engine/feature-ast/pattern-change-schema.d.ts +10 -10
- package/dist/engine/feature-ast/patterns.d.ts +15 -15
- package/dist/engine/feature-ast/render.d.ts +1 -1
- package/dist/engine/feature-builder-state.d.ts +5 -5
- package/dist/engine/feature-config-events-jobs.d.ts +3 -3
- package/dist/engine/feature-config-events-jobs.js +8 -130
- package/dist/engine/feature-entity-handlers.d.ts +4 -4
- package/dist/engine/feature-entity-handlers.js +11 -5
- package/dist/engine/feature-manifest.d.ts +1 -1
- package/dist/engine/feature-ui-extensions.d.ts +7 -7
- package/dist/engine/feature-ui-extensions.js +2 -2
- package/dist/engine/field-access.d.ts +1 -1
- package/dist/engine/field-helpers.d.ts +1 -1
- package/dist/engine/handler-helpers.d.ts +1 -1
- package/dist/engine/index.d.ts +89 -88
- package/dist/engine/index.js +1 -0
- package/dist/engine/instruction-fields.d.ts +1 -1
- package/dist/engine/object-form.d.ts +1 -1
- package/dist/engine/object-form.js +5 -6
- package/dist/engine/ownership.d.ts +3 -3
- package/dist/engine/pattern-library/index.d.ts +2 -2
- package/dist/engine/pattern-library/library.d.ts +2 -2
- package/dist/engine/pattern-library/mixed-schemas.d.ts +1 -1
- package/dist/engine/pattern-library/opaque-schemas.d.ts +1 -1
- package/dist/engine/pattern-library/shared-fields.d.ts +1 -1
- package/dist/engine/pattern-library/static-schemas.d.ts +1 -1
- package/dist/engine/pattern-library/types.d.ts +1 -1
- package/dist/engine/personal-data-fields.d.ts +2 -2
- package/dist/engine/pipeline.d.ts +2 -2
- package/dist/engine/project-app-schema-for-roles.d.ts +1 -1
- package/dist/engine/projection-helpers.d.ts +4 -4
- package/dist/engine/read-claim.d.ts +1 -1
- package/dist/engine/registry-facade.d.ts +2 -2
- package/dist/engine/registry-ingest.d.ts +2 -2
- package/dist/engine/registry-state.d.ts +2 -2
- package/dist/engine/registry-validate.d.ts +3 -3
- package/dist/engine/registry.d.ts +1 -1
- package/dist/engine/resolve-config-or-param.d.ts +2 -2
- package/dist/engine/role-assignment.d.ts +1 -1
- package/dist/engine/run-in.d.ts +1 -1
- package/dist/engine/run-pipeline.d.ts +3 -3
- package/dist/engine/schema-builder.d.ts +1 -1
- package/dist/engine/screen-filter-ops.d.ts +1 -1
- package/dist/engine/screen-helpers.d.ts +2 -2
- package/dist/engine/soft-delete-cleanup.d.ts +2 -2
- package/dist/engine/steps/_event-match.d.ts +1 -1
- package/dist/engine/steps/_no-return-guard.d.ts +1 -1
- package/dist/engine/steps/_read-source.d.ts +4 -4
- package/dist/engine/steps/_resolver-utils.d.ts +1 -1
- package/dist/engine/steps/aggregate-append-event.d.ts +1 -1
- package/dist/engine/steps/aggregate-create.d.ts +2 -2
- package/dist/engine/steps/aggregate-update.d.ts +3 -3
- package/dist/engine/steps/branch.d.ts +1 -1
- package/dist/engine/steps/call-feature.d.ts +2 -2
- package/dist/engine/steps/compute.d.ts +1 -1
- package/dist/engine/steps/for-each.d.ts +1 -1
- package/dist/engine/steps/mail-send.d.ts +1 -1
- package/dist/engine/steps/read-find-many.d.ts +2 -2
- package/dist/engine/steps/read-find-one.d.ts +2 -2
- package/dist/engine/steps/retry.d.ts +1 -1
- package/dist/engine/steps/return.d.ts +2 -2
- package/dist/engine/steps/unsafe-projection-delete.d.ts +2 -2
- package/dist/engine/steps/unsafe-projection-upsert.d.ts +1 -1
- package/dist/engine/steps/wait-for-event.d.ts +1 -1
- package/dist/engine/steps/wait.d.ts +1 -1
- package/dist/engine/steps/webhook-send.d.ts +1 -1
- package/dist/engine/strip-disabled-features-from-app-schema.d.ts +4 -4
- package/dist/engine/system-user.d.ts +2 -2
- package/dist/engine/template-variables.d.ts +1 -1
- package/dist/engine/tier-resolver-extension.d.ts +4 -4
- package/dist/engine/transfer-adjacency.d.ts +1 -1
- package/dist/engine/types/index.d.ts +6 -6
- package/dist/engine/validate-projection-allowlist.d.ts +1 -1
- package/dist/engine/validation.d.ts +1 -1
- package/dist/entrypoint/index.d.ts +12 -12
- package/dist/env/dry-run.d.ts +14 -1
- package/dist/env/dry-run.js +50 -0
- package/dist/env/index.d.ts +54 -16
- package/dist/env/index.js +60 -6
- package/dist/errors/classes.d.ts +3 -3
- package/dist/errors/docs-url.d.ts +1 -1
- package/dist/errors/index.d.ts +18 -18
- package/dist/errors/member-resolution.d.ts +1 -1
- package/dist/errors/serialize.d.ts +2 -2
- package/dist/errors/subject-erased.d.ts +1 -1
- package/dist/errors/to-kumiko-error.d.ts +1 -1
- package/dist/errors/write-error-info.d.ts +1 -1
- package/dist/errors/zod-bridge.d.ts +1 -1
- package/dist/es-ops/context.d.ts +4 -4
- package/dist/es-ops/index.d.ts +4 -4
- package/dist/es-ops/operations-schema.d.ts +1 -1
- package/dist/es-ops/runner.d.ts +3 -3
- package/dist/es-ops/runner.js +9 -1
- package/dist/es-ops/types.d.ts +2 -2
- package/dist/event-store/admin-api.d.ts +3 -3
- package/dist/event-store/archive.d.ts +2 -2
- package/dist/event-store/event-store.d.ts +2 -2
- package/dist/event-store/events-schema.d.ts +1 -1
- package/dist/event-store/index.d.ts +15 -15
- package/dist/event-store/provenance-append.d.ts +3 -3
- package/dist/event-store/rebuild-dead-letter.d.ts +2 -2
- package/dist/event-store/row-to-stored-event.d.ts +2 -2
- package/dist/event-store/snapshot.d.ts +2 -2
- package/dist/event-store/tenant-db-append.d.ts +2 -2
- package/dist/event-store/transfer.d.ts +3 -3
- package/dist/event-store/upcaster-dead-letter.d.ts +2 -2
- package/dist/event-store/upcaster.d.ts +3 -3
- package/dist/files/assert-file-refs-belong-to-tenant.d.ts +2 -2
- package/dist/files/bind-pending-file-refs.d.ts +3 -3
- package/dist/files/create-file-ref-from-bytes.d.ts +4 -4
- package/dist/files/create-file-ref.d.ts +3 -3
- package/dist/files/dispose-removed-file-refs.d.ts +2 -2
- package/dist/files/feature.d.ts +3 -3
- package/dist/files/file-handle.d.ts +1 -1
- package/dist/files/file-ref-entity.d.ts +1 -1
- package/dist/files/file-ref-table.d.ts +1 -1
- package/dist/files/file-routes.d.ts +5 -5
- package/dist/files/in-memory-provider.d.ts +1 -1
- package/dist/files/index.d.ts +20 -20
- package/dist/files/load-save-file-refs.d.ts +2 -2
- package/dist/files/local-provider.d.ts +1 -1
- package/dist/files/provider-resolver.d.ts +5 -5
- package/dist/files/purge-expired-file-ref-bytes.d.ts +2 -2
- package/dist/files/record-read-check.d.ts +1 -1
- package/dist/files/record-write-check.d.ts +3 -3
- package/dist/files/storage-tracking.d.ts +2 -2
- package/dist/files/types.d.ts +1 -1
- package/dist/files/zip-stream.d.ts +1 -1
- package/dist/i18n/index.d.ts +4 -4
- package/dist/i18n/mail-registry.d.ts +1 -1
- package/dist/i18n/required-surface-keys.d.ts +1 -1
- package/dist/i18n/settings-hub-keys.d.ts +1 -1
- package/dist/internal/stack-support.d.ts +12 -12
- package/dist/internal/testing.d.ts +4 -4
- package/dist/jobs/index.d.ts +2 -2
- package/dist/jobs/job-runner.d.ts +1 -1
- package/dist/jobs/max-per-tenant.d.ts +1 -1
- package/dist/lifecycle/index.d.ts +2 -2
- package/dist/lifecycle/lifecycle.d.ts +1 -1
- package/dist/lifecycle/signal-handlers.d.ts +1 -1
- package/dist/logging/index.d.ts +4 -4
- package/dist/logging/pino-logger.d.ts +1 -1
- package/dist/logging/utils.d.ts +1 -1
- package/dist/migrations/index.d.ts +4 -4
- package/dist/migrations/kumiko-drift.d.ts +1 -1
- package/dist/migrations/pending-rebuilds.d.ts +5 -5
- package/dist/migrations/pii-event-backfill.d.ts +4 -4
- package/dist/migrations/projection-table-index.d.ts +1 -1
- package/dist/observability/console-provider.d.ts +1 -1
- package/dist/observability/context.d.ts +1 -1
- package/dist/observability/escape-hatch-report.d.ts +3 -3
- package/dist/observability/fallback.d.ts +1 -1
- package/dist/observability/index.d.ts +16 -16
- package/dist/observability/metric-validator.d.ts +1 -1
- package/dist/observability/metrics-handle.d.ts +1 -1
- package/dist/observability/metrics-wiring.d.ts +2 -2
- package/dist/observability/noop-provider.d.ts +1 -1
- package/dist/observability/prometheus-meter.d.ts +1 -1
- package/dist/observability/recording-meter.d.ts +1 -1
- package/dist/observability/recording-tracer.d.ts +1 -1
- package/dist/observability/redis-wrapper.d.ts +1 -1
- package/dist/observability/sensitive-filter.d.ts +1 -1
- package/dist/observability/standard-metrics.d.ts +1 -1
- package/dist/pipeline/active-membership.d.ts +4 -4
- package/dist/pipeline/append-event-core.d.ts +3 -3
- package/dist/pipeline/auth-claims-resolver.d.ts +2 -2
- package/dist/pipeline/cascade-handler.d.ts +3 -3
- package/dist/pipeline/dispatch-batch.d.ts +2 -2
- package/dist/pipeline/dispatch-query.d.ts +4 -4
- package/dist/pipeline/dispatch-shared.d.ts +17 -17
- package/dist/pipeline/dispatch-stream.d.ts +2 -2
- package/dist/pipeline/dispatch-write.d.ts +4 -4
- package/dist/pipeline/dispatcher-utils.d.ts +2 -2
- package/dist/pipeline/dispatcher.d.ts +12 -12
- package/dist/pipeline/event-consumer-state.d.ts +1 -1
- package/dist/pipeline/event-dispatcher-admin.d.ts +1 -1
- package/dist/pipeline/event-dispatcher-delivery.d.ts +7 -7
- package/dist/pipeline/event-dispatcher.d.ts +7 -7
- package/dist/pipeline/event-retention.d.ts +1 -1
- package/dist/pipeline/handler-access-error.d.ts +2 -2
- package/dist/pipeline/index.d.ts +42 -42
- package/dist/pipeline/irreversible-operation-gate.d.ts +1 -1
- package/dist/pipeline/lifecycle-pipeline.d.ts +2 -2
- package/dist/pipeline/member-read-only-transaction.d.ts +2 -2
- package/dist/pipeline/member-reader.d.ts +5 -5
- package/dist/pipeline/msp-rebuild.d.ts +4 -4
- package/dist/pipeline/multi-stream-apply-context.d.ts +3 -3
- package/dist/pipeline/notify-scope.d.ts +3 -3
- package/dist/pipeline/pending-gap-ranges.d.ts +2 -2
- package/dist/pipeline/pre-handler-gates.d.ts +3 -3
- package/dist/pipeline/pre-transaction-reservations.d.ts +4 -4
- package/dist/pipeline/projection-rebuild.d.ts +3 -3
- package/dist/pipeline/projection-state.d.ts +1 -1
- package/dist/pipeline/projections-runner.d.ts +3 -3
- package/dist/pipeline/projections-runner.js +3 -4
- package/dist/pipeline/system-hooks.d.ts +4 -4
- package/dist/pipeline/system-identity-switch.d.ts +3 -3
- package/dist/pipeline/tenant-timezone-cache.d.ts +1 -1
- package/dist/pipeline/write-origin.d.ts +3 -3
- package/dist/pipeline/write-result-masking.d.ts +2 -2
- package/dist/random/index.d.ts +2 -2
- package/dist/rate-limit/bucket.d.ts +1 -1
- package/dist/rate-limit/index.d.ts +3 -3
- package/dist/rate-limit/middleware.d.ts +3 -3
- package/dist/redis/cache-sync-bus.d.ts +2 -2
- package/dist/redis/cache-sync-topics.d.ts +1 -1
- package/dist/redis/index.d.ts +8 -8
- package/dist/redis/pubsub-signal.d.ts +1 -1
- package/dist/schema-cli.d.ts +1 -1
- package/dist/schema-cli.js +9 -1
- package/dist/search/derive-search-adapter-config.d.ts +2 -2
- package/dist/search/in-memory-adapter.d.ts +1 -1
- package/dist/search/index.d.ts +6 -6
- package/dist/search/meilisearch-adapter.d.ts +2 -2
- package/dist/search/purge-subject.d.ts +4 -4
- package/dist/search/reindex-entity.d.ts +3 -3
- package/dist/secrets/dek-cache.d.ts +1 -1
- package/dist/secrets/env-master-key-provider.d.ts +1 -1
- package/dist/secrets/env-master-key-provider.js +26 -11
- package/dist/secrets/envelope-cipher.d.ts +2 -2
- package/dist/secrets/envelope.d.ts +1 -1
- package/dist/secrets/index.d.ts +9 -9
- package/dist/secrets/rotation.d.ts +1 -1
- package/dist/secrets/stored-envelope.d.ts +1 -1
- package/dist/seeding/entity-seed.d.ts +1 -1
- package/dist/seeding/index.d.ts +3 -3
- package/dist/seeding/seed-users.d.ts +1 -1
- package/dist/time/index.d.ts +6 -6
- package/dist/ui-types/app-schema.d.ts +5 -5
- package/dist/ui-types/index.d.ts +23 -23
- package/dist/upgrade-cli.js +13 -3
- package/dist/utils/index.d.ts +9 -9
- package/package.json +19 -66
- package/presets/biome-app.json +80 -0
- package/presets/tsconfig.app.json +19 -0
- package/src/changes.json +78 -2
- package/src/scripts/codemod/README.md +18 -0
- package/src/scripts/codemod/codemod-support.ts +1 -1
- package/src/scripts/codemod/db-factory.ts +1 -1
- package/src/scripts/codemod/feature-factory.ts +1 -1
- package/src/scripts/codemod/import-extensions.ts +118 -0
- package/src/scripts/codemod/migrate-cross-tenant.ts +2 -2
- package/src/scripts/codemod/migrate-db-raw.ts +1 -1
- package/src/scripts/codemod/migrate-open-to-all.ts +1 -1
- package/src/scripts/codemod/object-form.ts +1 -1
- package/src/scripts/codemod/s3-imports.ts +1 -1
- package/src/scripts/codemod/tenant-db-options.ts +1 -1
- package/src/scripts/codemod/testing-move.ts +2 -2
- package/dist/db/bun-db-deprecated.d.ts +0 -10
- package/dist/db/bun-db-deprecated.js +0 -5
- package/dist/stack/index.d.ts +0 -10
- package/dist/stack/index.js +0 -11
- package/dist/testing/e2e-generator.d.ts +0 -5
- package/dist/testing/e2e-generator.js +0 -5
- package/dist/testing/handler-context.d.ts +0 -5
- package/dist/testing/handler-context.js +0 -5
- package/dist/testing/index.d.ts +0 -10
- package/dist/testing/index.js +0 -10
- package/dist/testing/real-providers.d.ts +0 -5
- package/dist/testing/real-providers.js +0 -5
package/AGENTS.md
CHANGED
|
@@ -135,6 +135,7 @@ The scaffold (`bun create kumiko-app <name>`) produces this layout. Keep it.
|
|
|
135
135
|
|
|
136
136
|
| Path | Content |
|
|
137
137
|
| --- | --- |
|
|
138
|
+
| `kumiko.config.ts` | `defineAppConfig({ features, prodFeatures?, client, ports })`: the one list the tooling reads |
|
|
138
139
|
| `src/run-config.ts` | `APP_FEATURES`, the mounted feature list |
|
|
139
140
|
| `src/features/<name>/feature.ts` | `defineFeature(...)` with entities, handlers, screens, navs |
|
|
140
141
|
| `src/features/<name>/index.ts` | Public exports of the feature |
|
|
@@ -143,7 +144,17 @@ The scaffold (`bun create kumiko-app <name>`) produces this layout. Keep it.
|
|
|
143
144
|
| `src/__tests__/*.test.ts` | Unit tests, no services |
|
|
144
145
|
| `src/__tests__/*.integration.test.ts` | Integration tests against Postgres and Redis |
|
|
145
146
|
| `e2e/*.spec.ts` | Playwright tests against a booted app |
|
|
146
|
-
| `kumiko/schema.ts`, `kumiko/migrations/` |
|
|
147
|
+
| `kumiko/schema.ts`, `kumiko/migrations/` | Generated schema shim over `kumiko.config.ts`, and the migrations |
|
|
148
|
+
| `bin/server.ts`, `bin/main.ts`, `bin/env-schema.ts` | Dev server, production boot, env contract |
|
|
149
|
+
| `e2e/_helpers/`, `src/__tests__/_setup.ts` | Shared e2e helpers and the shared integration stack setup |
|
|
150
|
+
|
|
151
|
+
Files whose first line reads `kumiko-managed` (deploy/, `.github/workflows/`,
|
|
152
|
+
`.husky/pre-push`, the bunfigs, `kumiko/schema.ts`) belong to the framework.
|
|
153
|
+
`bun run check` reports drift against the installed version and
|
|
154
|
+
`bunx kumiko sync-managed --write` restores them. Keep a deliberate change with
|
|
155
|
+
`# kumiko-managed: local <reason>` on line 2. `biome.json` and `tsconfig.json`
|
|
156
|
+
extend `@cosmicdrift/kumiko-framework/biome` and `.../tsconfig.app.json`; put
|
|
157
|
+
app overrides next to `extends`. Full list: `docs/reference/app-skeleton.md`.
|
|
147
158
|
|
|
148
159
|
The scaffolded `src/features/tasks/feature.ts` and
|
|
149
160
|
`src/__tests__/tasks.integration.test.ts` are the smallest complete pair of
|
|
@@ -155,6 +166,8 @@ feature and test. Start from them.
|
|
|
155
166
|
| --- | --- |
|
|
156
167
|
| Run the app with demo data | `bun dev` |
|
|
157
168
|
| Boot validation without serving | `bun run boot` |
|
|
169
|
+
| Boot, guards, managed files and script standard | `bun run check` |
|
|
170
|
+
| Restore framework-owned files | `bunx kumiko sync-managed --write` |
|
|
158
171
|
| Types | `bun run typecheck` |
|
|
159
172
|
| Lint | `bun run lint` |
|
|
160
173
|
| Unit tests | `bun run test` |
|
|
@@ -81,6 +81,7 @@ anonymous **email-verified** deletion flow from `user-data-rights`:
|
|
|
81
81
|
|
|
82
82
|
```ts illustration
|
|
83
83
|
runProdApp({
|
|
84
|
+
envSchema, // composeEnvSchema({ core: frameworkCoreEnvSchema, features })
|
|
84
85
|
features: composeApexAccountApp({
|
|
85
86
|
deletionTokenSecret: process.env.DELETION_TOKEN_SECRET!,
|
|
86
87
|
deletionVerifyUrl: "https://app.example.com/delete-account/confirm",
|
|
@@ -299,7 +300,7 @@ describe("apex-surface-auth recipe", () => {
|
|
|
299
300
|
// SERVER-WIRING: die App aktiviert `anonymousAccess` (defaultTenantId = der
|
|
300
301
|
// Apex-Host-Tenant), damit /api/write die anonymen Deletion-Handler erreicht:
|
|
301
302
|
//
|
|
302
|
-
// runProdApp({ features: composeApexAccountApp({...}),
|
|
303
|
+
// runProdApp({ features: composeApexAccountApp({...}), envSchema,
|
|
303
304
|
// anonymousAccess: { defaultTenantId: APEX_TENANT_ID } })
|
|
304
305
|
|
|
305
306
|
import { createAuthEmailPasswordFeature } from "@cosmicdrift/kumiko-bundled-features/auth-email-password";
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<!-- Generated by `bun run gen:agent-docs` from samples/recipes/app-config. Do not edit. -->
|
|
2
|
+
|
|
3
|
+
# app-config
|
|
4
|
+
|
|
5
|
+
kumiko.config.ts with defineAppConfig: the one feature list, client entries and ports the tooling reads.
|
|
6
|
+
|
|
7
|
+
## README
|
|
8
|
+
|
|
9
|
+
# App config
|
|
10
|
+
|
|
11
|
+
`kumiko.config.ts` is the one place an app names its features, client entries
|
|
12
|
+
and ports. `kumiko/schema.ts`, `kumiko agent lint`, `kumiko check` and
|
|
13
|
+
`kumiko ports` all read it.
|
|
14
|
+
|
|
15
|
+
## What it shows
|
|
16
|
+
|
|
17
|
+
- **`defineAppConfig`** from `@cosmicdrift/kumiko-framework/config` validates the
|
|
18
|
+
config when the file loads: ports in range and unique within the app, client
|
|
19
|
+
entries relative and inside the app.
|
|
20
|
+
- **`prodFeatures`** are mounted only in production (provider features such as
|
|
21
|
+
S3 or SMTP). `allAppFeatures(config)` returns `features` plus `prodFeatures`;
|
|
22
|
+
that is the list migrations and agent lint check.
|
|
23
|
+
- **`ports`** with `dev`, `e2e` and optional `infra` (`postgres`, `redis`,
|
|
24
|
+
`meilisearch`, `s3`). Keep them number literals: `kumiko ports` reads them
|
|
25
|
+
statically across all apps of a workspace and reports collisions.
|
|
26
|
+
|
|
27
|
+
## Files
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
kumiko.config.ts defineAppConfig with features, prodFeatures, client, ports
|
|
31
|
+
src/feature.ts two placeholder features
|
|
32
|
+
src/__tests__/app-config.test.ts feature list, port list, validation errors
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
See [`docs/reference/app-skeleton.md`](../../../docs/reference/app-skeleton.md)
|
|
36
|
+
for the files around it.
|
|
37
|
+
|
|
38
|
+
## Source files
|
|
39
|
+
|
|
40
|
+
### src/__tests__/app-config.test.ts
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { describe, expect, test } from "bun:test";
|
|
44
|
+
import {
|
|
45
|
+
allAppFeatures,
|
|
46
|
+
defineAppConfig,
|
|
47
|
+
findAppPortProblems,
|
|
48
|
+
listAppPorts,
|
|
49
|
+
} from "@cosmicdrift/kumiko-framework/config";
|
|
50
|
+
import appConfig from "../../kumiko.config";
|
|
51
|
+
import { notesFeature } from "../feature";
|
|
52
|
+
|
|
53
|
+
describe("kumiko.config.ts", () => {
|
|
54
|
+
test("schema, agent lint and boot see features plus prodFeatures", () => {
|
|
55
|
+
expect(allAppFeatures(appConfig).map((feature) => feature.name)).toEqual([
|
|
56
|
+
"notes",
|
|
57
|
+
"audit-export",
|
|
58
|
+
]);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("ports list every claim, infrastructure included", () => {
|
|
62
|
+
expect(listAppPorts(appConfig.ports)).toEqual([
|
|
63
|
+
{ role: "dev", port: 4510 },
|
|
64
|
+
{ role: "e2e", port: 4511 },
|
|
65
|
+
{ role: "postgres", port: 15510 },
|
|
66
|
+
]);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("defineAppConfig rejects a port claimed twice inside the app", () => {
|
|
70
|
+
const ports = { dev: 4510, e2e: 4510 };
|
|
71
|
+
expect(findAppPortProblems(ports)).not.toEqual([]);
|
|
72
|
+
expect(() =>
|
|
73
|
+
defineAppConfig({ features: [notesFeature], client: { entries: ["src/client.tsx"] }, ports }),
|
|
74
|
+
).toThrow();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("client entries must stay inside the app", () => {
|
|
78
|
+
expect(() =>
|
|
79
|
+
defineAppConfig({
|
|
80
|
+
features: [notesFeature],
|
|
81
|
+
client: { entries: ["../other-app/src/client.tsx"] },
|
|
82
|
+
ports: { dev: 4510, e2e: 4511 },
|
|
83
|
+
}),
|
|
84
|
+
).toThrow();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### src/feature.ts
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
93
|
+
|
|
94
|
+
export const notesFeature = defineFeature("notes", () => {});
|
|
95
|
+
|
|
96
|
+
// Stands in for a provider feature that only production mounts (S3, SMTP).
|
|
97
|
+
export const auditExportFeature = defineFeature("audit-export", () => {});
|
|
98
|
+
```
|
|
@@ -61,6 +61,19 @@ const server = buildServer({
|
|
|
61
61
|
|
|
62
62
|
Apps built via `runDevApp`/`runProdApp` (the dev-server bootstrap used by `create-kumiko-app`) get all of this automatically — just add `createAuthMfaFeature(...)` to `APP_FEATURES`. `composeFeatures` threads the status-checker and the bootstrap wires the session-revoke bind and the verify route for you. This sample shows the raw contract those helpers implement.
|
|
63
63
|
|
|
64
|
+
## Self-service screen
|
|
65
|
+
|
|
66
|
+
`createAccountSecurityFeature({ nav?, access? })` adds one screen,
|
|
67
|
+
`account-security:screen:account-security`, that embeds the MFA enable,
|
|
68
|
+
regenerate and disable screens plus the own-sessions list. It owns no handlers
|
|
69
|
+
and needs no `composeAuthStack`: mount it next to `auth-mfa` and `sessions`.
|
|
70
|
+
Without `nav` the screen stays dormant (reachable by its route, no sidebar
|
|
71
|
+
entry); `access` defaults to every signed-in user.
|
|
72
|
+
|
|
73
|
+
```ts illustration
|
|
74
|
+
features: [..., createSessionsFeature(), mfaFeature, createAccountSecurityFeature({ nav: { order: 90 } })]
|
|
75
|
+
```
|
|
76
|
+
|
|
64
77
|
## Design rules
|
|
65
78
|
|
|
66
79
|
1. **Enrollment is stateless until confirmed.** `enable-start` returns a signed setup token (QR + secret + 8 recovery codes) — nothing is persisted until `enable-confirm` proves the user scanned it with a valid TOTP code.
|
|
@@ -74,9 +87,61 @@ Apps built via `runDevApp`/`runProdApp` (the dev-server bootstrap used by `creat
|
|
|
74
87
|
|
|
75
88
|
- **Baseline:** a user without MFA enrolled still gets a JWT straight from `/auth/login`.
|
|
76
89
|
- **End-to-end:** enroll via `enable-start`/`enable-confirm`, log in (gets a challenge, no JWT), complete via `/auth/mfa/verify` (gets a JWT) — copies the `buildServer({ auth: ... })` block from the sample comment verbatim.
|
|
90
|
+
- **Account security:** the composed screen boot-validates next to `auth-mfa` and `sessions` and shows a sidebar entry once `nav` is set.
|
|
77
91
|
|
|
78
92
|
## Source files
|
|
79
93
|
|
|
94
|
+
### src/__tests__/account-security.test.ts
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
98
|
+
import { createAuthFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
|
|
99
|
+
import { createConfigFeature } from "@cosmicdrift/kumiko-bundled-features/config";
|
|
100
|
+
import { createPersonalAccessTokensFeature } from "@cosmicdrift/kumiko-bundled-features/personal-access-tokens";
|
|
101
|
+
import { createSessionsFeature } from "@cosmicdrift/kumiko-bundled-features/sessions";
|
|
102
|
+
import { createTenantFeature } from "@cosmicdrift/kumiko-bundled-features/tenant";
|
|
103
|
+
import { createUserFeature } from "@cosmicdrift/kumiko-bundled-features/user";
|
|
104
|
+
import { configureEntityFieldEncryption } from "@cosmicdrift/kumiko-framework/db";
|
|
105
|
+
import { validateBoot } from "@cosmicdrift/kumiko-framework/engine";
|
|
106
|
+
import { createTestEnvelopeCipher } from "@cosmicdrift/kumiko-testing/helpers";
|
|
107
|
+
import {
|
|
108
|
+
ACCOUNT_SECURITY_SCREEN_QN,
|
|
109
|
+
createAccountSecurityFeature,
|
|
110
|
+
createAuthMfaFeature,
|
|
111
|
+
} from "../feature";
|
|
112
|
+
|
|
113
|
+
const mfaFeature = createAuthMfaFeature({
|
|
114
|
+
setupTokenSecret: "sample-setup-token-secret-not-for-prod",
|
|
115
|
+
challengeTokenSecret: "sample-mfa-challenge-secret-at-least-32-bytes",
|
|
116
|
+
issuer: "Kumiko Sample",
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe("account-security next to auth-mfa", () => {
|
|
120
|
+
// user-mfa has encrypted fields, so boot validation needs a cipher.
|
|
121
|
+
beforeAll(() => configureEntityFieldEncryption(createTestEnvelopeCipher()));
|
|
122
|
+
afterAll(() => configureEntityFieldEncryption(undefined));
|
|
123
|
+
|
|
124
|
+
test("boot-validates without composeAuthStack and adds a sidebar entry with nav", () => {
|
|
125
|
+
const accountSecurity = createAccountSecurityFeature({ nav: { order: 90 } });
|
|
126
|
+
expect(() =>
|
|
127
|
+
validateBoot([
|
|
128
|
+
createConfigFeature(),
|
|
129
|
+
createUserFeature(),
|
|
130
|
+
createTenantFeature(),
|
|
131
|
+
createAuthFoundationFeature(),
|
|
132
|
+
createPersonalAccessTokensFeature({ scopes: {} }),
|
|
133
|
+
createSessionsFeature(),
|
|
134
|
+
mfaFeature,
|
|
135
|
+
accountSecurity,
|
|
136
|
+
]),
|
|
137
|
+
).not.toThrow();
|
|
138
|
+
expect(Object.values(accountSecurity.navs).map((nav) => nav.screen)).toEqual([
|
|
139
|
+
ACCOUNT_SECURITY_SCREEN_QN,
|
|
140
|
+
]);
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
80
145
|
### src/__tests__/feature.integration.test.ts
|
|
81
146
|
|
|
82
147
|
```ts
|
|
@@ -306,6 +371,13 @@ describe("auth-mfa sample wiring", () => {
|
|
|
306
371
|
// complete exactly one login challenge, then it's burned.
|
|
307
372
|
// 4. Every MFA state change signs out every OTHER live session (stolen-
|
|
308
373
|
// session defense) — but never the session that made the change.
|
|
374
|
+
|
|
375
|
+
// One self-service screen for MFA and own sessions. Dormant until `nav` is
|
|
376
|
+
// set, so apps that mount it only for deep links get no sidebar entry.
|
|
377
|
+
export {
|
|
378
|
+
ACCOUNT_SECURITY_SCREEN_QN,
|
|
379
|
+
createAccountSecurityFeature,
|
|
380
|
+
} from "@cosmicdrift/kumiko-bundled-features/account-security";
|
|
309
381
|
export {
|
|
310
382
|
AuthMfaHandlers,
|
|
311
383
|
base32Decode,
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
<!-- Generated by `bun run gen:agent-docs` from samples/recipes/compose-stacks. Do not edit. -->
|
|
2
|
+
|
|
3
|
+
# compose-stacks
|
|
4
|
+
|
|
5
|
+
compose*Stack helpers for auth, security, GDPR and SaaS billing, and the runProdApp check that names a stack whose boot option is missing.
|
|
6
|
+
|
|
7
|
+
## README
|
|
8
|
+
|
|
9
|
+
# Compose stacks
|
|
10
|
+
|
|
11
|
+
Mount the auth, security, GDPR and SaaS features through the `compose*Stack`
|
|
12
|
+
helpers from `@cosmicdrift/kumiko-dev-server/compose-stacks` instead of
|
|
13
|
+
listing each feature and its require order by hand. A stack that depends on a
|
|
14
|
+
`runProdApp` option marks that on its features (`bootRequires`), and
|
|
15
|
+
`runProdApp` refuses to boot when the option is missing, naming the stack and
|
|
16
|
+
the option.
|
|
17
|
+
|
|
18
|
+
## What it shows
|
|
19
|
+
|
|
20
|
+
- **`composeAuthStack({ mfa, sessions })`**: `auth-foundation`, `sessions`,
|
|
21
|
+
and with `mfa` also `auth-mfa` plus `account-security`. The password login
|
|
22
|
+
itself still comes from the `auth` option or `composeFeatures`.
|
|
23
|
+
- **`composeSecurityStack({ includeSessions })`**: `sessions`,
|
|
24
|
+
`crypto-shredding`, `rate-limiting` and `audit`. Needs a KMS decision
|
|
25
|
+
(`kmsMode`) and fails with `rateLimit: false`. Replaces
|
|
26
|
+
`securityBaselineFeatures()`.
|
|
27
|
+
- **`composeGdprStack({ tenantLifecycle, selfService })`**: `data-retention`
|
|
28
|
+
and `compliance-profiles`, optionally `tenant-lifecycle`. `selfService` adds
|
|
29
|
+
`sessions`, `user-data-rights` and `user-profile` (needs `mail`) and
|
|
30
|
+
replaces `dsgvoSelfServiceFeatures()`.
|
|
31
|
+
- **`composeSaasStack({ billing, tiers, caps, waitlist })`**:
|
|
32
|
+
`billing-foundation` and `tier-engine`, plus `cap-counter`/`cap-overview`
|
|
33
|
+
and `waitlist` when configured. `billing: "stripe"` leaves
|
|
34
|
+
`subscription-stripe` to the `billing` boot option, which also mounts the
|
|
35
|
+
tier-sync webhook route; `billing: "mollie"` mounts `subscription-mollie`
|
|
36
|
+
itself.
|
|
37
|
+
|
|
38
|
+
## Boot requirements
|
|
39
|
+
|
|
40
|
+
| Stack | Boot option | Also satisfied by |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| `composeMailStack` | `mail` | a mounted `channel-email` |
|
|
43
|
+
| `composeFileStack` without providers | `fileStorage` | a mounted file provider |
|
|
44
|
+
| `composeGdprStack` | `kmsMode` | `kms` or `allowPlaintextPii` |
|
|
45
|
+
| `composeGdprStack({ selfService })`, `composeUserDataRightsStack` | `mail` | a mounted `channel-email` |
|
|
46
|
+
| `composeSecurityStack` | `kmsMode`, `rateLimit` not `false` | `kms` or `allowPlaintextPii` |
|
|
47
|
+
| `composeSaasStack({ billing: "stripe" })` | `billing` | a mounted subscription provider |
|
|
48
|
+
|
|
49
|
+
A missing option fails the boot with:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
[runProdApp] stacks in `features` need boot options that are not set:
|
|
53
|
+
- composeSaasStack needs the boot option `billing`: set billing: { stripe: { priceToTier }, defaultTier }
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Flow
|
|
57
|
+
|
|
58
|
+
1. `src/app.ts` lists the stacks and the boot options they need.
|
|
59
|
+
2. The test boots with `KUMIKO_DRY_RUN_ENV=boot`, which runs the whole
|
|
60
|
+
validation and stops before any DB or Redis connection: with the options
|
|
61
|
+
the boot passes, without `billing` or `kmsMode` it fails and names the
|
|
62
|
+
stacks.
|
|
63
|
+
|
|
64
|
+
## Tests
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
bun test samples/recipes/compose-stacks
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Source files
|
|
71
|
+
|
|
72
|
+
### src/__tests__/app.test.ts
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
// KUMIKO_DRY_RUN_ENV=boot runs the full wiring check and stops before any
|
|
76
|
+
// DB/Redis connection, so the stack requirements are checked without infra.
|
|
77
|
+
|
|
78
|
+
import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
|
|
79
|
+
import { randomBytes } from "node:crypto";
|
|
80
|
+
import { composeEnvSchema } from "@cosmicdrift/kumiko-framework/env";
|
|
81
|
+
import { type RunProdAppOptions, runProdApp } from "@cosmicdrift/kumiko-server-runtime";
|
|
82
|
+
import { appFeatures, bootOptions } from "../app";
|
|
83
|
+
|
|
84
|
+
const PRODUCTION_BOOT_ENV: Readonly<Record<string, string>> = {
|
|
85
|
+
DATABASE_URL: "postgres://recipe:recipe@127.0.0.1:1/recipe",
|
|
86
|
+
REDIS_URL: "redis://127.0.0.1:1",
|
|
87
|
+
JWT_SECRET: "r".repeat(32),
|
|
88
|
+
KUMIKO_DRY_RUN_ENV: "boot",
|
|
89
|
+
NODE_ENV: "production",
|
|
90
|
+
PLATFORM_KEK: randomBytes(32).toString("base64"),
|
|
91
|
+
SUBJECT_KEYS_DATABASE_URL: "postgres://kms:kms@127.0.0.1:1/subject_keys",
|
|
92
|
+
KUMIKO_BLIND_INDEX_KEY: randomBytes(32).toString("base64"),
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
async function bootValidate(options: Pick<RunProdAppOptions, "kmsMode" | "billing">) {
|
|
96
|
+
const handle = await runProdApp({
|
|
97
|
+
features: appFeatures(),
|
|
98
|
+
envSchema: composeEnvSchema({ features: [] }),
|
|
99
|
+
autoListen: false,
|
|
100
|
+
migrations: false,
|
|
101
|
+
envSource: { ...PRODUCTION_BOOT_ENV },
|
|
102
|
+
...options,
|
|
103
|
+
});
|
|
104
|
+
await handle.stop();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
describe("compose stacks recipe", () => {
|
|
108
|
+
let logSpy: ReturnType<typeof spyOn>;
|
|
109
|
+
let warnSpy: ReturnType<typeof spyOn>;
|
|
110
|
+
beforeEach(() => {
|
|
111
|
+
logSpy = spyOn(console, "log").mockImplementation(() => {});
|
|
112
|
+
warnSpy = spyOn(console, "warn").mockImplementation(() => {});
|
|
113
|
+
});
|
|
114
|
+
afterEach(() => {
|
|
115
|
+
logSpy.mockRestore();
|
|
116
|
+
warnSpy.mockRestore();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("the stacks with their boot options pass boot validation", async () => {
|
|
120
|
+
await bootValidate(bootOptions());
|
|
121
|
+
const lines = logSpy.mock.calls.map((call: unknown[]) => String(call[0]));
|
|
122
|
+
expect(lines.some((line: string) => line.includes("boot validation OK"))).toBe(true);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("a missing billing option names composeSaasStack and the option", async () => {
|
|
126
|
+
const { billing: _billing, ...withoutBilling } = bootOptions();
|
|
127
|
+
await expect(bootValidate(withoutBilling)).rejects.toThrow(
|
|
128
|
+
"composeSaasStack needs the boot option `billing`",
|
|
129
|
+
);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test("a missing KMS decision names every stack that needs it", async () => {
|
|
133
|
+
const { kmsMode: _kmsMode, ...withoutKms } = bootOptions();
|
|
134
|
+
const failure = bootValidate(withoutKms);
|
|
135
|
+
await expect(failure).rejects.toThrow("composeSecurityStack needs the boot option `kmsMode`");
|
|
136
|
+
await expect(failure).rejects.toThrow("composeGdprStack needs the boot option `kmsMode`");
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### src/app.ts
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
import { createConfigFeature } from "@cosmicdrift/kumiko-bundled-features/config";
|
|
145
|
+
import { createSecretsFeature } from "@cosmicdrift/kumiko-bundled-features/secrets";
|
|
146
|
+
import { createTenantFeature } from "@cosmicdrift/kumiko-bundled-features/tenant";
|
|
147
|
+
import { createUserFeature } from "@cosmicdrift/kumiko-bundled-features/user";
|
|
148
|
+
import {
|
|
149
|
+
composeAuthStack,
|
|
150
|
+
composeGdprStack,
|
|
151
|
+
composeSaasStack,
|
|
152
|
+
composeSecurityStack,
|
|
153
|
+
} from "@cosmicdrift/kumiko-dev-server/compose-stacks";
|
|
154
|
+
import type { RunProdAppOptions } from "@cosmicdrift/kumiko-server-runtime";
|
|
155
|
+
|
|
156
|
+
export const PRO_PRICE_ID = "price_pro_monthly";
|
|
157
|
+
|
|
158
|
+
export function appFeatures(): RunProdAppOptions["features"] {
|
|
159
|
+
return [
|
|
160
|
+
createConfigFeature(),
|
|
161
|
+
createSecretsFeature(),
|
|
162
|
+
createUserFeature(),
|
|
163
|
+
createTenantFeature(),
|
|
164
|
+
...composeAuthStack(),
|
|
165
|
+
...composeSecurityStack(),
|
|
166
|
+
...composeGdprStack({ tenantLifecycle: true }),
|
|
167
|
+
...composeSaasStack({
|
|
168
|
+
billing: "stripe",
|
|
169
|
+
tiers: {
|
|
170
|
+
defaultTier: "free",
|
|
171
|
+
tierMap: {
|
|
172
|
+
free: { features: [], caps: { seats: 1 } },
|
|
173
|
+
pro: { features: [], caps: { seats: 25 } },
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
}),
|
|
177
|
+
];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
type StackBootOptions = Pick<RunProdAppOptions, "kmsMode" | "billing">;
|
|
181
|
+
|
|
182
|
+
export function bootOptions(): StackBootOptions {
|
|
183
|
+
return {
|
|
184
|
+
kmsMode: "required",
|
|
185
|
+
billing: { stripe: { priceToTier: { [PRO_PRICE_ID]: "pro" } }, defaultTier: "free" },
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
```
|