ddd-ts-kit 0.13.0 → 0.15.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/README.md +34 -3
- package/dist/check/catalogue/architecture-rules.d.ts.map +1 -1
- package/dist/check/catalogue/architecture-rules.js +2 -0
- package/dist/check/catalogue/architecture-rules.js.map +1 -1
- package/dist/check/errors/kit-error-codes.d.ts.map +1 -1
- package/dist/check/errors/kit-error-codes.js +1 -0
- package/dist/check/errors/kit-error-codes.js.map +1 -1
- package/dist/check/explain/authz-docs.d.ts.map +1 -1
- package/dist/check/explain/authz-docs.js +12 -0
- package/dist/check/explain/authz-docs.js.map +1 -1
- package/dist/check/explain/errors-docs.js +1 -1
- package/dist/check/explain/errors-docs.js.map +1 -1
- package/dist/check/explain/tenancy-docs.d.ts.map +1 -1
- package/dist/check/explain/tenancy-docs.js +3 -1
- package/dist/check/explain/tenancy-docs.js.map +1 -1
- package/dist/check/fixtures/authz-fixtures.d.ts.map +1 -1
- package/dist/check/fixtures/authz-fixtures.js +38 -1
- package/dist/check/fixtures/authz-fixtures.js.map +1 -1
- package/dist/check/fixtures/tenancy-fixtures.d.ts.map +1 -1
- package/dist/check/fixtures/tenancy-fixtures.js +28 -0
- package/dist/check/fixtures/tenancy-fixtures.js.map +1 -1
- package/dist/check/rules/authz-fields-by-schema.d.ts +3 -0
- package/dist/check/rules/authz-fields-by-schema.d.ts.map +1 -0
- package/dist/check/rules/authz-fields-by-schema.js +33 -0
- package/dist/check/rules/authz-fields-by-schema.js.map +1 -0
- package/dist/check/tenancy/knex-unscoped.d.ts +6 -1
- package/dist/check/tenancy/knex-unscoped.d.ts.map +1 -1
- package/dist/check/tenancy/knex-unscoped.js +19 -6
- package/dist/check/tenancy/knex-unscoped.js.map +1 -1
- package/dist/check/tenancy/raw-reaches-rows.d.ts +8 -0
- package/dist/check/tenancy/raw-reaches-rows.d.ts.map +1 -0
- package/dist/check/tenancy/raw-reaches-rows.js +91 -0
- package/dist/check/tenancy/raw-reaches-rows.js.map +1 -0
- package/dist/check/tenancy/raw-sql-text.d.ts +9 -0
- package/dist/check/tenancy/raw-sql-text.d.ts.map +1 -0
- package/dist/check/tenancy/raw-sql-text.js +29 -0
- package/dist/check/tenancy/raw-sql-text.js.map +1 -0
- package/dist/commands/generate.js +2 -0
- package/dist/commands/generate.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +13 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/parse-stack.d.ts.map +1 -1
- package/dist/config/parse-stack.js +3 -1
- package/dist/config/parse-stack.js.map +1 -1
- package/dist/config/stack.d.ts +14 -0
- package/dist/config/stack.d.ts.map +1 -1
- package/dist/config/stack.js +2 -0
- package/dist/config/stack.js.map +1 -1
- package/dist/declared/injection/laid-out-calls.d.ts +7 -0
- package/dist/declared/injection/laid-out-calls.d.ts.map +1 -0
- package/dist/declared/injection/laid-out-calls.js +14 -0
- package/dist/declared/injection/laid-out-calls.js.map +1 -0
- package/dist/declared/render-barrel.d.ts.map +1 -1
- package/dist/declared/render-barrel.js +2 -1
- package/dist/declared/render-barrel.js.map +1 -1
- package/dist/declared/render-dependencies-file.d.ts.map +1 -1
- package/dist/declared/render-dependencies-file.js +2 -1
- package/dist/declared/render-dependencies-file.js.map +1 -1
- package/dist/describe/context-description.d.ts +6 -0
- package/dist/describe/context-description.d.ts.map +1 -1
- package/dist/describe/format-description.js +9 -1
- package/dist/describe/format-description.js.map +1 -1
- package/dist/describe/presentation-of-route.d.ts +4 -0
- package/dist/describe/presentation-of-route.d.ts.map +1 -0
- package/dist/describe/presentation-of-route.js +15 -0
- package/dist/describe/presentation-of-route.js.map +1 -0
- package/dist/describe/read-controllers.d.ts.map +1 -1
- package/dist/describe/read-controllers.js +4 -1
- package/dist/describe/read-controllers.js.map +1 -1
- package/dist/describe/read-routes.d.ts.map +1 -1
- package/dist/describe/read-routes.js +2 -0
- package/dist/describe/read-routes.js.map +1 -1
- package/dist/generate/kind.d.ts +2 -0
- package/dist/generate/kind.d.ts.map +1 -1
- package/dist/generate/kinds/context-kind.d.ts.map +1 -1
- package/dist/generate/kinds/context-kind.js +13 -6
- package/dist/generate/kinds/context-kind.js.map +1 -1
- package/dist/generate/kinds/form-kind.d.ts +3 -0
- package/dist/generate/kinds/form-kind.d.ts.map +1 -0
- package/dist/generate/kinds/form-kind.js +38 -0
- package/dist/generate/kinds/form-kind.js.map +1 -0
- package/dist/generate/kinds/next-adr-number.d.ts +4 -0
- package/dist/generate/kinds/next-adr-number.d.ts.map +1 -0
- package/dist/generate/kinds/next-adr-number.js +7 -0
- package/dist/generate/kinds/next-adr-number.js.map +1 -0
- package/dist/generate/kinds/presentation/controller-of.d.ts +10 -0
- package/dist/generate/kinds/presentation/controller-of.d.ts.map +1 -0
- package/dist/generate/kinds/presentation/controller-of.js +13 -0
- package/dist/generate/kinds/presentation/controller-of.js.map +1 -0
- package/dist/generate/kinds/presentation/controller-source.d.ts +13 -0
- package/dist/generate/kinds/presentation/controller-source.d.ts.map +1 -0
- package/dist/generate/kinds/presentation/controller-source.js +44 -0
- package/dist/generate/kinds/presentation/controller-source.js.map +1 -0
- package/dist/generate/kinds/representation-kind.d.ts +3 -0
- package/dist/generate/kinds/representation-kind.d.ts.map +1 -0
- package/dist/generate/kinds/representation-kind.js +54 -0
- package/dist/generate/kinds/representation-kind.js.map +1 -0
- package/dist/generate/kinds/write-adr.js +3 -6
- package/dist/generate/kinds/write-adr.js.map +1 -1
- package/dist/generate/kinds.d.ts.map +1 -1
- package/dist/generate/kinds.js +4 -0
- package/dist/generate/kinds.js.map +1 -1
- package/dist/help/usage.d.ts +1 -1
- package/dist/help/usage.d.ts.map +1 -1
- package/dist/help/usage.js +3 -2
- package/dist/help/usage.js.map +1 -1
- package/dist/init/files/platform-files.js +3 -1
- package/dist/init/files/platform-files.js.map +1 -1
- package/dist/init/manifest/versions.js +24 -24
- package/dist/init/run-init.d.ts +2 -0
- package/dist/init/run-init.d.ts.map +1 -1
- package/dist/init/run-init.js +15 -1
- package/dist/init/run-init.js.map +1 -1
- package/dist/init/stack/resolve-stack.d.ts.map +1 -1
- package/dist/init/stack/resolve-stack.js +15 -1
- package/dist/init/stack/resolve-stack.js.map +1 -1
- package/dist/init/stack/stack-options.d.ts +2 -0
- package/dist/init/stack/stack-options.d.ts.map +1 -1
- package/dist/presets/apply-preset.d.ts +15 -0
- package/dist/presets/apply-preset.d.ts.map +1 -0
- package/dist/presets/apply-preset.js +94 -0
- package/dist/presets/apply-preset.js.map +1 -0
- package/dist/presets/grant-to-signed-in.d.ts +9 -0
- package/dist/presets/grant-to-signed-in.d.ts.map +1 -0
- package/dist/presets/grant-to-signed-in.js +61 -0
- package/dist/presets/grant-to-signed-in.js.map +1 -0
- package/dist/presets/identity-preset.d.ts +9 -0
- package/dist/presets/identity-preset.d.ts.map +1 -0
- package/dist/presets/identity-preset.js +44 -0
- package/dist/presets/identity-preset.js.map +1 -0
- package/dist/presets/identity-refusal.d.ts +5 -0
- package/dist/presets/identity-refusal.d.ts.map +1 -0
- package/dist/presets/identity-refusal.js +29 -0
- package/dist/presets/identity-refusal.js.map +1 -0
- package/dist/presets/identity-terms.d.ts +4 -0
- package/dist/presets/identity-terms.d.ts.map +1 -0
- package/dist/presets/identity-terms.js +57 -0
- package/dist/presets/identity-terms.js.map +1 -0
- package/dist/presets/no-flags.d.ts +4 -0
- package/dist/presets/no-flags.d.ts.map +1 -0
- package/dist/presets/no-flags.js +18 -0
- package/dist/presets/no-flags.js.map +1 -0
- package/dist/presets/organisations-as-tenants.d.ts +9 -0
- package/dist/presets/organisations-as-tenants.d.ts.map +1 -0
- package/dist/presets/organisations-as-tenants.js +43 -0
- package/dist/presets/organisations-as-tenants.js.map +1 -0
- package/dist/presets/preset-decision.d.ts +8 -0
- package/dist/presets/preset-decision.d.ts.map +1 -0
- package/dist/presets/preset-decision.js +19 -0
- package/dist/presets/preset-decision.js.map +1 -0
- package/dist/presets/preset-file.d.ts +13 -0
- package/dist/presets/preset-file.d.ts.map +1 -0
- package/dist/presets/preset-file.js +2 -0
- package/dist/presets/preset-file.js.map +1 -0
- package/dist/presets/preset-files.d.ts +9 -0
- package/dist/presets/preset-files.d.ts.map +1 -0
- package/dist/presets/preset-files.js +34 -0
- package/dist/presets/preset-files.js.map +1 -0
- package/dist/presets/preset-named.d.ts +3 -0
- package/dist/presets/preset-named.d.ts.map +1 -0
- package/dist/presets/preset-named.js +12 -0
- package/dist/presets/preset-named.js.map +1 -0
- package/dist/presets/preset-refusal.d.ts +6 -0
- package/dist/presets/preset-refusal.d.ts.map +1 -0
- package/dist/presets/preset-refusal.js +2 -0
- package/dist/presets/preset-refusal.js.map +1 -0
- package/dist/presets/preset-step.d.ts +8 -0
- package/dist/presets/preset-step.d.ts.map +1 -0
- package/dist/presets/preset-step.js +2 -0
- package/dist/presets/preset-step.js.map +1 -0
- package/dist/presets/preset.d.ts +36 -0
- package/dist/presets/preset.d.ts.map +1 -0
- package/dist/presets/preset.js +2 -0
- package/dist/presets/preset.js.map +1 -0
- package/dist/presets/with-authorizer-import.d.ts +6 -0
- package/dist/presets/with-authorizer-import.d.ts.map +1 -0
- package/dist/presets/with-authorizer-import.js +27 -0
- package/dist/presets/with-authorizer-import.js.map +1 -0
- package/dist/stack/stack-vars.js +19 -2
- package/dist/stack/stack-vars.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workspace/workspace.d.ts +2 -0
- package/dist/workspace/workspace.d.ts.map +1 -1
- package/dist/workspace/workspace.js +4 -0
- package/dist/workspace/workspace.js.map +1 -1
- package/package.json +2 -2
- package/templates/docs/openapi.json.tpl +15 -0
- package/templates/init/CLAUDE.md.tpl +2 -2
- package/templates/init/platform/auth/http-boundary.ts.tpl +20 -3
- package/templates/init/platform/compose-application.manual.ts.tpl +18 -0
- package/templates/init/platform/compose-application.tsyringe.ts.tpl +23 -0
- package/templates/init/platform/http/presentation-of.ts.tpl +27 -0
- package/templates/init/platform/http/start-http-server.express.ts.tpl +1 -1
- package/templates/init/platform/http/start-http-server.fastify.ts.tpl +1 -1
- package/templates/init/platform/http/start-http-server.hono.ts.tpl +1 -1
- package/templates/init/platform/http/start-http-server.nest.ts.tpl +2 -2
- package/templates/init/platform/http/with-documentation.ts.tpl +13 -3
- package/templates/init/platform/http/with-forms.ts.tpl +7 -0
- package/templates/init/rules/application.md.tpl +1 -1
- package/templates/init/rules/presentation.md.tpl +1 -1
- package/templates/init/scripts/openapi.ts.tpl +27 -6
- package/templates/pipeline/biome.json.tpl +1 -0
- package/templates/pipeline/package-scripts.json +1 -1
- package/templates/presets/identity/context/application/authorization/__context__.permissions.ts.tpl +23 -0
- package/templates/presets/identity/context/application/authorization/change-member-roles.policy.ts.tpl +17 -0
- package/templates/presets/identity/context/application/authorization/grant-delegations.policy.ts.tpl +17 -0
- package/templates/presets/identity/context/application/authorization/invite-members.policy.ts.tpl +17 -0
- package/templates/presets/identity/context/application/authorization/read-members.policy.ts.tpl +17 -0
- package/templates/presets/identity/context/application/authorization/remove-members.policy.ts.tpl +17 -0
- package/templates/presets/identity/context/application/authorization/revoke-delegations.policy.ts.tpl +17 -0
- package/templates/presets/identity/context/application/authorization/revoke-invitations.policy.ts.tpl +17 -0
- package/templates/presets/identity/context/application/commands/accept-invitation/accept-invitation.command.ts.tpl +14 -0
- package/templates/presets/identity/context/application/commands/accept-invitation/accept-invitation.handler.ts.tpl +56 -0
- package/templates/presets/identity/context/application/commands/change-member-role/change-member-role.command.ts.tpl +17 -0
- package/templates/presets/identity/context/application/commands/change-member-role/change-member-role.handler.ts.tpl +82 -0
- package/templates/presets/identity/context/application/commands/deactivate-account/deactivate-account.command.ts.tpl +7 -0
- package/templates/presets/identity/context/application/commands/deactivate-account/deactivate-account.handler.ts.tpl +69 -0
- package/templates/presets/identity/context/application/commands/decline-invitation/decline-invitation.command.ts.tpl +14 -0
- package/templates/presets/identity/context/application/commands/decline-invitation/decline-invitation.handler.ts.tpl +36 -0
- package/templates/presets/identity/context/application/commands/grant-delegation/grant-delegation.command.ts.tpl +21 -0
- package/templates/presets/identity/context/application/commands/grant-delegation/grant-delegation.handler.ts.tpl +43 -0
- package/templates/presets/identity/context/application/commands/invite-member/invite-member.command.ts.tpl +16 -0
- package/templates/presets/identity/context/application/commands/invite-member/invite-member.handler.ts.tpl +53 -0
- package/templates/presets/identity/context/application/commands/open-organisation/open-organisation.command.ts.tpl +14 -0
- package/templates/presets/identity/context/application/commands/open-organisation/open-organisation.handler.ts.tpl +50 -0
- package/templates/presets/identity/context/application/commands/provision-account/provision-account.command.ts.tpl +14 -0
- package/templates/presets/identity/context/application/commands/provision-account/provision-account.handler.ts.tpl +41 -0
- package/templates/presets/identity/context/application/commands/remove-member/remove-member.command.ts.tpl +15 -0
- package/templates/presets/identity/context/application/commands/remove-member/remove-member.handler.ts.tpl +79 -0
- package/templates/presets/identity/context/application/commands/revoke-delegation/revoke-delegation.command.ts.tpl +15 -0
- package/templates/presets/identity/context/application/commands/revoke-delegation/revoke-delegation.handler.ts.tpl +39 -0
- package/templates/presets/identity/context/application/commands/revoke-invitation/revoke-invitation.command.ts.tpl +15 -0
- package/templates/presets/identity/context/application/commands/revoke-invitation/revoke-invitation.handler.ts.tpl +42 -0
- package/templates/presets/identity/context/application/integration/handlers/account-deactivated.integration-handler.ts.tpl +19 -0
- package/templates/presets/identity/context/application/integration/handlers/member-joined.integration-handler.ts.tpl +33 -0
- package/templates/presets/identity/context/application/integration/handlers/member-removed.integration-handler.ts.tpl +30 -0
- package/templates/presets/identity/context/application/integration/handlers/organisation-opened.integration-handler.ts.tpl +19 -0
- package/templates/presets/identity/context/application/integration/publishers/account-deactivated.publisher.ts.tpl +24 -0
- package/templates/presets/identity/context/application/integration/publishers/delegation-granted.publisher.ts.tpl +36 -0
- package/templates/presets/identity/context/application/integration/publishers/delegation-revoked.publisher.ts.tpl +33 -0
- package/templates/presets/identity/context/application/integration/publishers/member-joined.publisher.ts.tpl +33 -0
- package/templates/presets/identity/context/application/integration/publishers/member-removed.publisher.ts.tpl +33 -0
- package/templates/presets/identity/context/application/integration/publishers/member-role-changed.publisher.ts.tpl +35 -0
- package/templates/presets/identity/context/application/integration/publishers/organisation-opened.publisher.ts.tpl +32 -0
- package/templates/presets/identity/context/application/ports/identity-provider-admin.port.ts.tpl +17 -0
- package/templates/presets/identity/context/application/ports/identity-provider-connection.port.ts.tpl +14 -0
- package/templates/presets/identity/context/application/ports/invitation-tokens.port.ts.tpl +7 -0
- package/templates/presets/identity/context/application/ports/search-members-reader.port.ts.tpl +10 -0
- package/templates/presets/identity/context/application/queries/search-members/search-members.handler.ts.tpl +33 -0
- package/templates/presets/identity/context/application/queries/search-members/search-members.query.ts.tpl +19 -0
- package/templates/presets/identity/context/application/queries/search-members/search-members.result.ts.tpl +17 -0
- package/templates/presets/identity/context/domain/aggregates/account.aggregate.ts.tpl +92 -0
- package/templates/presets/identity/context/domain/aggregates/delegation.aggregate.ts.tpl +117 -0
- package/templates/presets/identity/context/domain/aggregates/invitation.aggregate.ts.tpl +128 -0
- package/templates/presets/identity/context/domain/aggregates/member.aggregate.ts.tpl +149 -0
- package/templates/presets/identity/context/domain/aggregates/organisation.aggregate.ts.tpl +52 -0
- package/templates/presets/identity/context/domain/errors/account.error.ts.tpl +40 -0
- package/templates/presets/identity/context/domain/errors/delegation.error.ts.tpl +45 -0
- package/templates/presets/identity/context/domain/errors/invitation.error.ts.tpl +30 -0
- package/templates/presets/identity/context/domain/errors/member.error.ts.tpl +50 -0
- package/templates/presets/identity/context/domain/errors/organisation.error.ts.tpl +32 -0
- package/templates/presets/identity/context/domain/events/account-deactivated.event.ts.tpl +13 -0
- package/templates/presets/identity/context/domain/events/account-provisioned.event.ts.tpl +17 -0
- package/templates/presets/identity/context/domain/events/delegation-granted.event.ts.tpl +22 -0
- package/templates/presets/identity/context/domain/events/delegation-revoked.event.ts.tpl +18 -0
- package/templates/presets/identity/context/domain/events/invitation-accepted.event.ts.tpl +17 -0
- package/templates/presets/identity/context/domain/events/invitation-declined.event.ts.tpl +16 -0
- package/templates/presets/identity/context/domain/events/invitation-issued.event.ts.tpl +22 -0
- package/templates/presets/identity/context/domain/events/invitation-revoked.event.ts.tpl +16 -0
- package/templates/presets/identity/context/domain/events/member-joined.event.ts.tpl +19 -0
- package/templates/presets/identity/context/domain/events/member-removed.event.ts.tpl +19 -0
- package/templates/presets/identity/context/domain/events/member-role-changed.event.ts.tpl +22 -0
- package/templates/presets/identity/context/domain/events/organisation-opened.event.ts.tpl +17 -0
- package/templates/presets/identity/context/domain/repositories/account.repository.ts.tpl +5 -0
- package/templates/presets/identity/context/domain/repositories/delegation.repository.ts.tpl +10 -0
- package/templates/presets/identity/context/domain/repositories/invitation.repository.ts.tpl +7 -0
- package/templates/presets/identity/context/domain/repositories/member.repository.ts.tpl +13 -0
- package/templates/presets/identity/context/domain/repositories/organisation.repository.ts.tpl +5 -0
- package/templates/presets/identity/context/domain/services/role-rights.service.ts.tpl +59 -0
- package/templates/presets/identity/context/domain/value-objects/delegation-period.vo.ts.tpl +42 -0
- package/templates/presets/identity/context/domain/value-objects/display-name.vo.ts.tpl +29 -0
- package/templates/presets/identity/context/domain/value-objects/email-address.vo.ts.tpl +31 -0
- package/templates/presets/identity/context/domain/value-objects/organisation-name.vo.ts.tpl +29 -0
- package/templates/presets/identity/context/domain/value-objects/organisation-rights.vo.ts.tpl +43 -0
- package/templates/presets/identity/context/domain/value-objects/organisation-slug.vo.ts.tpl +30 -0
- package/templates/presets/identity/context/domain/vocabularies/account-status.vocabulary.ts.tpl +7 -0
- package/templates/presets/identity/context/domain/vocabularies/invitation-status.vocabulary.ts.tpl +9 -0
- package/templates/presets/identity/context/domain/vocabularies/member-right.vocabulary.ts.tpl +9 -0
- package/templates/presets/identity/context/domain/vocabularies/member-role.vocabulary.ts.tpl +8 -0
- package/templates/presets/identity/context/infrastructure/external/crypto-invitation-tokens.adapter.ts.tpl +20 -0
- package/templates/presets/identity/context/infrastructure/external/environment-identity-provider-connection.adapter.ts.tpl +37 -0
- package/templates/presets/identity/context/infrastructure/external/keycloak-identity-provider-admin.adapter.ts.tpl +149 -0
- package/templates/presets/identity/context/infrastructure/persistence/__context__.schema.drizzle.ts.tpl +102 -0
- package/templates/presets/identity/context/infrastructure/persistence/account-row.schema.knex.ts.tpl +15 -0
- package/templates/presets/identity/context/infrastructure/persistence/account.mapper.drizzle.ts.tpl +38 -0
- package/templates/presets/identity/context/infrastructure/persistence/account.mapper.knex.ts.tpl +33 -0
- package/templates/presets/identity/context/infrastructure/persistence/create-__context__-tables.schema.knex.ts.tpl +107 -0
- package/templates/presets/identity/context/infrastructure/persistence/delegation-row.schema.knex.ts.tpl +17 -0
- package/templates/presets/identity/context/infrastructure/persistence/delegation.mapper.drizzle.ts.tpl +50 -0
- package/templates/presets/identity/context/infrastructure/persistence/delegation.mapper.knex.ts.tpl +45 -0
- package/templates/presets/identity/context/infrastructure/persistence/drizzle-account.repository.drizzle.ts.tpl +59 -0
- package/templates/presets/identity/context/infrastructure/persistence/drizzle-delegation.repository.drizzle.ts.tpl +77 -0
- package/templates/presets/identity/context/infrastructure/persistence/drizzle-invitation.repository.drizzle.ts.tpl +65 -0
- package/templates/presets/identity/context/infrastructure/persistence/drizzle-member.repository.drizzle.ts.tpl +84 -0
- package/templates/presets/identity/context/infrastructure/persistence/drizzle-organisation.repository.drizzle.ts.tpl +59 -0
- package/templates/presets/identity/context/infrastructure/persistence/drizzle-search-members-reader.repository.drizzle.ts.tpl +53 -0
- package/templates/presets/identity/context/infrastructure/persistence/invitation-row.schema.knex.ts.tpl +20 -0
- package/templates/presets/identity/context/infrastructure/persistence/invitation.mapper.drizzle.ts.tpl +45 -0
- package/templates/presets/identity/context/infrastructure/persistence/invitation.mapper.knex.ts.tpl +40 -0
- package/templates/presets/identity/context/infrastructure/persistence/knex-account.repository.knex.ts.tpl +61 -0
- package/templates/presets/identity/context/infrastructure/persistence/knex-delegation.repository.knex.ts.tpl +80 -0
- package/templates/presets/identity/context/infrastructure/persistence/knex-invitation.repository.knex.ts.tpl +67 -0
- package/templates/presets/identity/context/infrastructure/persistence/knex-member.repository.knex.ts.tpl +82 -0
- package/templates/presets/identity/context/infrastructure/persistence/knex-organisation.repository.knex.ts.tpl +61 -0
- package/templates/presets/identity/context/infrastructure/persistence/knex-search-members-reader.repository.knex.ts.tpl +77 -0
- package/templates/presets/identity/context/infrastructure/persistence/member-row.schema.knex.ts.tpl +15 -0
- package/templates/presets/identity/context/infrastructure/persistence/member.mapper.drizzle.ts.tpl +36 -0
- package/templates/presets/identity/context/infrastructure/persistence/member.mapper.knex.ts.tpl +31 -0
- package/templates/presets/identity/context/infrastructure/persistence/organisation-row.schema.knex.ts.tpl +12 -0
- package/templates/presets/identity/context/infrastructure/persistence/organisation.mapper.drizzle.ts.tpl +28 -0
- package/templates/presets/identity/context/infrastructure/persistence/organisation.mapper.knex.ts.tpl +26 -0
- package/templates/presets/identity/context/presentation/http/accounts/deactivate-account/deactivate-account.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/accounts/deactivate-account/deactivate-account.controller.ts.tpl +71 -0
- package/templates/presets/identity/context/presentation/http/accounts/provision-account/provision-account.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/accounts/provision-account/provision-account.body.class-validator.ts.tpl +9 -0
- package/templates/presets/identity/context/presentation/http/accounts/provision-account/provision-account.controller.ts.tpl +85 -0
- package/templates/presets/identity/context/presentation/http/accounts.routes.ts.tpl +5 -0
- package/templates/presets/identity/context/presentation/http/invitations/accept-invitation/accept-invitation.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/invitations/accept-invitation/accept-invitation.body.class-validator.per-route.ts.tpl +8 -0
- package/templates/presets/identity/context/presentation/http/invitations/accept-invitation/accept-invitation.controller.ts.tpl +100 -0
- package/templates/presets/identity/context/presentation/http/invitations/decline-invitation/decline-invitation.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/invitations/decline-invitation/decline-invitation.body.class-validator.per-route.ts.tpl +8 -0
- package/templates/presets/identity/context/presentation/http/invitations/decline-invitation/decline-invitation.controller.ts.tpl +98 -0
- package/templates/presets/identity/context/presentation/http/invitations.routes.ts.tpl +5 -0
- package/templates/presets/identity/context/presentation/http/organisations/change-member-role/change-member-role.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/organisations/change-member-role/change-member-role.body.class-validator.ts.tpl +7 -0
- package/templates/presets/identity/context/presentation/http/organisations/change-member-role/change-member-role.controller.ts.tpl +83 -0
- package/templates/presets/identity/context/presentation/http/organisations/change-member-role/change-member-role.params.class-validator.ts.tpl +11 -0
- package/templates/presets/identity/context/presentation/http/organisations/grant-delegation/grant-delegation.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/organisations/grant-delegation/grant-delegation.body.class-validator.ts.tpl +18 -0
- package/templates/presets/identity/context/presentation/http/organisations/grant-delegation/grant-delegation.controller.ts.tpl +103 -0
- package/templates/presets/identity/context/presentation/http/organisations/grant-delegation/grant-delegation.params.class-validator.ts.tpl +7 -0
- package/templates/presets/identity/context/presentation/http/organisations/invite-member/invite-member.accepted.class-validator.ts.tpl +10 -0
- package/templates/presets/identity/context/presentation/http/organisations/invite-member/invite-member.body.class-validator.ts.tpl +10 -0
- package/templates/presets/identity/context/presentation/http/organisations/invite-member/invite-member.controller.ts.tpl +65 -0
- package/templates/presets/identity/context/presentation/http/organisations/invite-member/invite-member.params.class-validator.ts.tpl +7 -0
- package/templates/presets/identity/context/presentation/http/organisations/open-organisation/open-organisation.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/organisations/open-organisation/open-organisation.body.class-validator.ts.tpl +12 -0
- package/templates/presets/identity/context/presentation/http/organisations/open-organisation/open-organisation.controller.ts.tpl +79 -0
- package/templates/presets/identity/context/presentation/http/organisations/remove-member/remove-member.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/organisations/remove-member/remove-member.controller.ts.tpl +73 -0
- package/templates/presets/identity/context/presentation/http/organisations/remove-member/remove-member.params.class-validator.ts.tpl +11 -0
- package/templates/presets/identity/context/presentation/http/organisations/revoke-delegation/revoke-delegation.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/organisations/revoke-delegation/revoke-delegation.controller.ts.tpl +73 -0
- package/templates/presets/identity/context/presentation/http/organisations/revoke-delegation/revoke-delegation.params.class-validator.ts.tpl +11 -0
- package/templates/presets/identity/context/presentation/http/organisations/revoke-invitation/revoke-invitation.accepted.class-validator.per-route.ts.tpl +6 -0
- package/templates/presets/identity/context/presentation/http/organisations/revoke-invitation/revoke-invitation.controller.ts.tpl +73 -0
- package/templates/presets/identity/context/presentation/http/organisations/revoke-invitation/revoke-invitation.params.class-validator.ts.tpl +11 -0
- package/templates/presets/identity/context/presentation/http/organisations/search-members/search-members.controller.ts.tpl +86 -0
- package/templates/presets/identity/context/presentation/http/organisations/search-members/search-members.line.class-validator.ts.tpl +22 -0
- package/templates/presets/identity/context/presentation/http/organisations/search-members/search-members.params.class-validator.ts.tpl +7 -0
- package/templates/presets/identity/context/presentation/http/organisations.routes.ts.tpl +5 -0
- package/templates/presets/identity/context/presentation/http/shared/invitation-token.schema.class-validator.shared.ts.tpl +9 -0
- package/templates/presets/identity/context/presentation/http/shared/invitation-token.schema.zod.shared.ts.tpl +9 -0
- package/templates/presets/identity/context/published-language/account-deactivated.v1.integration-event.ts.tpl +33 -0
- package/templates/presets/identity/context/published-language/account-deactivated.v1.payload.class-validator.ts.tpl +7 -0
- package/templates/presets/identity/context/published-language/delegation-granted.v1.integration-event.ts.tpl +39 -0
- package/templates/presets/identity/context/published-language/delegation-granted.v1.payload.class-validator.ts.tpl +28 -0
- package/templates/presets/identity/context/published-language/delegation-revoked.v1.integration-event.ts.tpl +36 -0
- package/templates/presets/identity/context/published-language/delegation-revoked.v1.payload.class-validator.ts.tpl +16 -0
- package/templates/presets/identity/context/published-language/member-joined.v1.integration-event.ts.tpl +36 -0
- package/templates/presets/identity/context/published-language/member-joined.v1.payload.class-validator.ts.tpl +16 -0
- package/templates/presets/identity/context/published-language/member-removed.v1.integration-event.ts.tpl +36 -0
- package/templates/presets/identity/context/published-language/member-removed.v1.payload.class-validator.ts.tpl +18 -0
- package/templates/presets/identity/context/published-language/member-role-changed.v1.integration-event.ts.tpl +38 -0
- package/templates/presets/identity/context/published-language/member-role-changed.v1.payload.class-validator.ts.tpl +24 -0
- package/templates/presets/identity/context/published-language/organisation-opened.v1.integration-event.ts.tpl +35 -0
- package/templates/presets/identity/context/published-language/organisation-opened.v1.payload.class-validator.ts.tpl +13 -0
- package/templates/presets/identity/context/test/builders/account.builder.ts.tpl +59 -0
- package/templates/presets/identity/context/test/builders/delegation.builder.ts.tpl +67 -0
- package/templates/presets/identity/context/test/builders/invitation.builder.ts.tpl +60 -0
- package/templates/presets/identity/context/test/builders/member.builder.ts.tpl +59 -0
- package/templates/presets/identity/context/test/builders/organisation.builder.ts.tpl +44 -0
- package/templates/presets/identity/context/test/fakes/account.repository.fake.ts.tpl +10 -0
- package/templates/presets/identity/context/test/fakes/delegation.repository.fake.ts.tpl +26 -0
- package/templates/presets/identity/context/test/fakes/identity-provider-admin.fake.ts.tpl +41 -0
- package/templates/presets/identity/context/test/fakes/invitation-tokens.fake.ts.tpl +18 -0
- package/templates/presets/identity/context/test/fakes/invitation.repository.fake.ts.tpl +14 -0
- package/templates/presets/identity/context/test/fakes/member.repository.fake.ts.tpl +29 -0
- package/templates/presets/identity/context/test/fakes/organisation.repository.fake.ts.tpl +10 -0
- package/templates/presets/identity/context/test/fakes/search-members-reader.fake.ts.tpl +25 -0
- package/templates/presets/identity/context/test/integration/account.repository.contract.spec.ts.tpl +48 -0
- package/templates/presets/identity/context/test/integration/delegation.repository.contract.spec.ts.tpl +84 -0
- package/templates/presets/identity/context/test/integration/invitation.repository.contract.spec.ts.tpl +76 -0
- package/templates/presets/identity/context/test/integration/keycloak-identity-provider-admin.adapter.spec.ts.tpl +123 -0
- package/templates/presets/identity/context/test/integration/member.repository.contract.spec.ts.tpl +92 -0
- package/templates/presets/identity/context/test/integration/organisation.repository.contract.spec.ts.tpl +46 -0
- package/templates/presets/identity/context/test/integration/search-members-reader.spec.ts.tpl +86 -0
- package/templates/presets/identity/context/test/unit/accept-invitation.controller.spec.ts.tpl +57 -0
- package/templates/presets/identity/context/test/unit/accept-invitation.handler.spec.ts.tpl +69 -0
- package/templates/presets/identity/context/test/unit/account-deactivated.integration-handler.spec.ts.tpl +24 -0
- package/templates/presets/identity/context/test/unit/account-deactivated.publisher.spec.ts.tpl +25 -0
- package/templates/presets/identity/context/test/unit/account.aggregate.spec.ts.tpl +72 -0
- package/templates/presets/identity/context/test/unit/change-member-role.controller.spec.ts.tpl +57 -0
- package/templates/presets/identity/context/test/unit/change-member-role.handler.spec.ts.tpl +135 -0
- package/templates/presets/identity/context/test/unit/crypto-invitation-tokens.adapter.spec.ts.tpl +15 -0
- package/templates/presets/identity/context/test/unit/deactivate-account.controller.spec.ts.tpl +44 -0
- package/templates/presets/identity/context/test/unit/deactivate-account.handler.spec.ts.tpl +106 -0
- package/templates/presets/identity/context/test/unit/decline-invitation.controller.spec.ts.tpl +57 -0
- package/templates/presets/identity/context/test/unit/decline-invitation.handler.spec.ts.tpl +40 -0
- package/templates/presets/identity/context/test/unit/delegation-granted.publisher.spec.ts.tpl +36 -0
- package/templates/presets/identity/context/test/unit/delegation-period.vo.spec.ts.tpl +32 -0
- package/templates/presets/identity/context/test/unit/delegation-revoked.publisher.spec.ts.tpl +35 -0
- package/templates/presets/identity/context/test/unit/delegation.aggregate.spec.ts.tpl +111 -0
- package/templates/presets/identity/context/test/unit/display-name.vo.spec.ts.tpl +13 -0
- package/templates/presets/identity/context/test/unit/email-address.vo.spec.ts.tpl +24 -0
- package/templates/presets/identity/context/test/unit/environment-identity-provider-connection.adapter.spec.ts.tpl +41 -0
- package/templates/presets/identity/context/test/unit/grant-delegation.controller.spec.ts.tpl +57 -0
- package/templates/presets/identity/context/test/unit/grant-delegation.handler.spec.ts.tpl +66 -0
- package/templates/presets/identity/context/test/unit/identity-application.ts.tpl +79 -0
- package/templates/presets/identity/context/test/unit/invitation.aggregate.spec.ts.tpl +118 -0
- package/templates/presets/identity/context/test/unit/invite-member.controller.spec.ts.tpl +57 -0
- package/templates/presets/identity/context/test/unit/invite-member.handler.spec.ts.tpl +110 -0
- package/templates/presets/identity/context/test/unit/member-joined.integration-handler.spec.ts.tpl +38 -0
- package/templates/presets/identity/context/test/unit/member-joined.publisher.spec.ts.tpl +36 -0
- package/templates/presets/identity/context/test/unit/member-removed.integration-handler.spec.ts.tpl +45 -0
- package/templates/presets/identity/context/test/unit/member-removed.publisher.spec.ts.tpl +35 -0
- package/templates/presets/identity/context/test/unit/member-role-changed.publisher.spec.ts.tpl +36 -0
- package/templates/presets/identity/context/test/unit/member.aggregate.spec.ts.tpl +142 -0
- package/templates/presets/identity/context/test/unit/open-organisation.controller.spec.ts.tpl +57 -0
- package/templates/presets/identity/context/test/unit/open-organisation.handler.spec.ts.tpl +52 -0
- package/templates/presets/identity/context/test/unit/organisation-name.vo.spec.ts.tpl +13 -0
- package/templates/presets/identity/context/test/unit/organisation-opened.integration-handler.spec.ts.tpl +24 -0
- package/templates/presets/identity/context/test/unit/organisation-opened.publisher.spec.ts.tpl +35 -0
- package/templates/presets/identity/context/test/unit/organisation-rights.vo.spec.ts.tpl +23 -0
- package/templates/presets/identity/context/test/unit/organisation-slug.vo.spec.ts.tpl +17 -0
- package/templates/presets/identity/context/test/unit/organisation.aggregate.spec.ts.tpl +33 -0
- package/templates/presets/identity/context/test/unit/provision-account.controller.spec.ts.tpl +73 -0
- package/templates/presets/identity/context/test/unit/provision-account.handler.spec.ts.tpl +65 -0
- package/templates/presets/identity/context/test/unit/remove-member.controller.spec.ts.tpl +44 -0
- package/templates/presets/identity/context/test/unit/remove-member.handler.spec.ts.tpl +125 -0
- package/templates/presets/identity/context/test/unit/revoke-delegation.controller.spec.ts.tpl +44 -0
- package/templates/presets/identity/context/test/unit/revoke-delegation.handler.spec.ts.tpl +51 -0
- package/templates/presets/identity/context/test/unit/revoke-invitation.controller.spec.ts.tpl +44 -0
- package/templates/presets/identity/context/test/unit/revoke-invitation.handler.spec.ts.tpl +44 -0
- package/templates/presets/identity/context/test/unit/role-rights.service.spec.ts.tpl +54 -0
- package/templates/presets/identity/context/test/unit/search-members.controller.spec.ts.tpl +43 -0
- package/templates/presets/identity/context/test/unit/search-members.handler.spec.ts.tpl +38 -0
- package/templates/presets/identity/decision.md.tpl +37 -0
- package/templates/presets/identity/design.md.tpl +71 -0
- package/templates/presets/signed-in-grants.ts.tpl +12 -0
package/README.md
CHANGED
|
@@ -58,6 +58,7 @@ ddd-ts-kit init [--http express|fastify|hono|nest|none]
|
|
|
58
58
|
[--allow-no-outbox "<reason>"] [--import-alias '$<name>/']
|
|
59
59
|
[--import-extension none|js] [--sdk]
|
|
60
60
|
[--context <name>:<core|supporting|generic>]...
|
|
61
|
+
[--preset identity]...
|
|
61
62
|
[--dry-run] [--force]
|
|
62
63
|
```
|
|
63
64
|
|
|
@@ -202,6 +203,7 @@ config, `docsUi`, `ci` and `logger` included.
|
|
|
202
203
|
| tracing | wired once, by the platform (`tracing/platform-only`): no `decorate` hook, no `decorate-bindings.ts`. `tracing.ts` starts `initTracing` of `@ddd-ts-kit/tracing/node` before any other module, on what `config/read-tracing.ts` validates: `OTEL_EXPORTER_OTLP_ENDPOINT` (a URL; left out, no span leaves the process), `TRACE_SAMPLE_RATIO` (0 to 1) and `TRACE_CONSUMERS` (`continue`, the default: a consumed event stays in the trace of its publication; `link`: each delivery starts a trace linked to it). With `--di tsyringe`: `lay-foundations.ts` builds `traceApplication({ consumers })`, `compose-application.ts` hands it to `kernelModule({ instrumentation })` (one span per use case, repository call, domain event, publication, consumer and job) and gives the outbox relay `tracedPublisher(bus)`. With hand wiring: `create-platform.ts` applies the members of `traceApplication()` itself (`useCase` on both buses, `domainEvents`, `publisher`, `binding` around every adapter, `job`, `executionScope`, `errorReporter`), with `tracedSubscriber` and `tracedPublisher` around the provider. With an HTTP stack, in both families, `auth/http-boundary.ts` sets `around: tracedRoutes()`: one `SERVER` span per request, named by its route |
|
|
203
204
|
| `--logger` | `src/platform/observability/create-logger.ts`, one per choice: `stdout` (the default) is the `StdoutLogger` of `@ddd-ts-kit/aspects`, JSON lines, credentials not redacted; `pino` is `createPinoLogger` of `@ddd-ts-kit/pino` (dependencies `pino` and `pino-pretty`); `winston` is `createWinstonLogger` of `@ddd-ts-kit/winston`; these two redact the credential keys of the kernel. Every entry carries `traceLogFields(scope)`: the correlation id, origin, actor and tenant of the work in progress and the ids of the active trace. `LOG_LEVEL`, `LOG_FORMAT` (`json`, the default, or `pretty`; with `stdout`, which has no pretty format, `pretty` is refused when the configuration is loaded) and `LOG_SCRUB_MESSAGES` (`[message removed]` in place of the message of a logged error that is not a `DomainError`) are validated in `config/load-config.ts`. Stopping the application flushes the error reporter, then the logger, last: `container.stop()` does it on tsyringe, `compose-application.ts` flushes explicitly with hand wiring. The tools and the tests compose the application without `log` and write nothing |
|
|
204
205
|
| `src/platform/auth/` | `create-authenticator.ts` (`--authn jwt`: `JwtAuthenticator` on `AUTH_ISSUER`, `AUTH_AUDIENCE`, `AUTH_JWKS_URI`; `--authn keycloak`: `keycloakAuthenticator` on `KEYCLOAK_URL`, `KEYCLOAK_REALM`, `KEYCLOAK_AUDIENCE` and the optional `KEYCLOAK_CLIENT_ID`; `--authn none`: `development-header-authenticator.ts`, which reads `x-development-actor` and throws in production), `principal-of.ts`, `security-schemes.ts`, `offline-authenticator.ts`, `http-boundary.ts` (`resolvePrincipal` answering a `Session`, `executionScope`, `errorMapper` and `onError`, spread into the mount options: every request runs inside the execution scope, with its correlation id), `create-authorizer.ts` and the files of the model (`roles.ts`, with the role `system` every system actor holds; `attribute-policies.ts`; `relationship-schema.ts`, `create-tuple-store.ts` and its contract spec, `relation-tuples.ts`, `relate-system-actors.ts`, `permission-mapping.ts` and `permissions.ts`; `custom-authorizer.ts`, its `authorizerContract` spec and `permissions.ts`), `authorization.ts` (`authorizationModule` with tsyringe) or `use-case-protection.ts` (the guard of the hand-wired buses), `access-policies.ts`, and with `--audit off` `log-decisions.ts` (one log entry per decision, ids and codes only). Without an HTTP stack there is no authenticator and no boundary |
|
|
206
|
+
| `--representations negotiated`, `--forms on` | `src/platform/http/presentation-of.ts` (`Representations.standard()` with `negotiated`, and `fieldDeciderOf` over the `Access` of the application), spread into the HTTP boundary and given to the contract script; with `--forms on`, `src/platform/http/with-forms.ts` adds `formRoutes` to the routes and `scripts/openapi.ts` writes `openapi/forms/<operationId>.json`. Both are the default with an HTTP stack; `json` and `off` leave them out ([docs/CONFIG.md](../../docs/CONFIG.md)) |
|
|
205
207
|
| `--audit on` | `src/platform/audit/`: `create-audit.ts` (the trail, the `onDecision` of the authorization, the refusals of the guards at the edge given to the HTTP boundary as `onGuardRefusal`, the middleware before the unit of work, the integration events subscribed under the consumer name `audit`), `audited-events.ts` (the registry `generate integration-event` adds to), `audit.module.ts`, and with an HTTP stack the read side: `audit.permissions.ts` (`audit:trail.read`), `search-audit-entries.query.ts`, its handler, `search-audit-entries.route.ts` (`GET /audit/entries`: cursor pages, filters `actorId`, `action`, `outcome`, `correlationId`). It is a capability of the platform, not a bounded context: no model, one protected query over the `AuditReader` port, bounded by the tenant of the actor (with `--tenancy shared-table`, by the tenant of the work through `TenantAuditReader`: platform staff read across tenants only inside `acrossTenants`). The refusals of a caller without a credential are not recorded. A scheduled job is audited like a request: origin `schedule`, actor `system:<context>.<job>`. With knex the two tables and their append-only triggers are created by the first migration; with drizzle the tables are in `schema.ts` and `npm run db:audit-guard` prints the trigger statements for a custom migration; with prisma, typeorm, `custom` or no ORM the trail is an `InMemoryAuditTrail` behind a `TODO(platform)`. The test databases leave the audit schema out of `reset()` |
|
|
206
208
|
| `--tenancy shared-table` | recorded as `stack.tenancy`; Knex or Drizzle only. Every `generate repository` is tenant-scoped (as `--tenant-scoped`), through `tenantTable` and `ownTenantTable` or `tenantCondition` and `ownTenantCondition`; the outbox keeps the tenant of each event (`createOutboxTables(knex, { tenant: true })` and `KnexOutboxStore`'s `tenant: true`, or `tenantOutboxTable`), so consumers run in it; `tenancy/scoped-statement` judges the adapters. Row-level security, schema per tenant and database per tenant are refused, with what to wire by hand ([Multitenancy](../../docs/concepts/multitenancy.md)) |
|
|
207
209
|
| `--queue database\|redis\|memory` | recorded as `stack.queue`. `database` (the default on Knex or Drizzle with tsyringe): `createJobTable` and `createProcessTable`, or `jobsTable` and `processesTable`, in the `messaging` schema, `Persistence` gains `jobs` and `processes`, and the platform module rebinds `JobStore` and `ProcessStore` to them, so a job enqueued by a command is written in its transaction; `redis` (with `--cache redis`): `RedisJobStore` on the connection of the cache, the processes in the database; `memory` (the default otherwise): nothing is written, the kernel module keeps both in the process. Refused off tsyringe, `database` with another ORM, `redis` without the cache |
|
|
@@ -261,6 +263,32 @@ and `@typescript/native` (`npm:typescript@~7.0.2`), which `build` and `typecheck
|
|
|
261
263
|
`init` and `generate context` start with the language: the first entry of `next` is the glossary
|
|
262
264
|
of the context to fill in.
|
|
263
265
|
|
|
266
|
+
### Presets
|
|
267
|
+
|
|
268
|
+
`--preset identity` (on `init`, or on `generate context`; once per project) writes a whole bounded
|
|
269
|
+
context instead of an empty one: who the people of the application are, the organisations they
|
|
270
|
+
belong to and in which role. Accounts are provisioned from the identity provider at the first
|
|
271
|
+
sign-in (no password is kept), organisations (the tenants under `--tenancy shared-table`),
|
|
272
|
+
members with roles of a declared vocabulary, invitations by token with an expiry, delegations of
|
|
273
|
+
rights for a period; permissions, policies, the published language (member joined, role changed,
|
|
274
|
+
account deactivated...), a search, controllers, specs with builders and fakes, the adapters of
|
|
275
|
+
the ORM, and the port to the administration API of the identity provider, kept in line at least
|
|
276
|
+
once by the consumers of the published facts, with a Keycloak adapter given as a recipe (proven
|
|
277
|
+
against a server that answers as Keycloak does, not against Keycloak in the pipeline). Nobody
|
|
278
|
+
changes their own role or acts above it, whatever a delegation lends; a deactivated account
|
|
279
|
+
leaves its organisations; an address the provider did not verify provisions no account. On `init` without a `--context` of its name, the context `identity` is declared
|
|
280
|
+
`generic`. Every signed-in person holds the permissions of the context whatever `--authz` says:
|
|
281
|
+
the grant `'identity:*'` of `platform/auth/signed-in-grants.ts`, answered by
|
|
282
|
+
`SignedInGrantsAuthorizer` before the model in `createAuthorizer`. With tenants, the tables of
|
|
283
|
+
the context belong to none, under a decision record the preset writes, and with `--authn
|
|
284
|
+
keycloak` the authenticator reads the `organization` claim as the tenants of the person
|
|
285
|
+
(another authenticator gets a next step saying what to map). The preset is written for
|
|
286
|
+
`declared` with `signature` dependencies, `factories`, `throwing` value objects, `controllers`,
|
|
287
|
+
Knex or Drizzle on PostgreSQL, Zod or class-validator, Express or Fastify, and a token verifier
|
|
288
|
+
(`jwt` or `keycloak`); another stack is refused with what to change, and so is a second context
|
|
289
|
+
written from the same preset. Why, and which other contexts deserve one:
|
|
290
|
+
[Bootstrap with well-designed contexts](../../docs/guides/bootstrap-with-well-designed-contexts.md).
|
|
291
|
+
|
|
264
292
|
## generate (alias g)
|
|
265
293
|
|
|
266
294
|
```
|
|
@@ -270,7 +298,7 @@ ddd-ts-kit generate --help --json
|
|
|
270
298
|
|
|
271
299
|
| Kind | Arguments | Writes |
|
|
272
300
|
|---|---|---|
|
|
273
|
-
| `context` | `<name> --classification <c> [--purpose "<two sentences>"] [--term ...]... [--upstream <ctx>[:relationship]]
|
|
301
|
+
| `context` | `<name> --classification <c> [--purpose "<two sentences>"] [--term ...]... [--upstream <ctx>[:relationship]]... [--preset identity]` | `CONTEXT.md` with its glossary, `published-language/index.ts`, config entry, registration in `platform/compose-application.ts` and in `test/architecture/extractable.spec.ts`; on tsyringe, with HTTP, `presentation/http/<name>.routes.ts` (a function of the two buses, in both styles); declared: the barrel `<name>.declarations.ts`; explicit and hand wiring: `<name>.module.ts`. `application/authorization/<name>.permissions.ts` is born with the first permission, or at once when `platform/auth/permissions.ts` lists the permission sets (rebac, custom). With `--preset`, the context is then written whole from that preset, its classification and purpose those of the preset unless the flags say otherwise ([Presets](#presets)) |
|
|
274
302
|
| `aggregate` | `<context> <Name>` | aggregate, builder, spec in given / when / then |
|
|
275
303
|
| `builder` | `<context> <Aggregate>` | `test/builders/<name>.builder.ts`, a class extending `Builder` |
|
|
276
304
|
| `entity` | `<context> <Name>` | entity, spec |
|
|
@@ -289,6 +317,8 @@ ddd-ts-kit generate --help --json
|
|
|
289
317
|
| `controller` | the same arguments as `route` | the controller class, whatever `stack.routes` says: for a project of function routes that writes its next route as a class. `--cache` writes its cache policy: `private` (a `GET` of a caller, `max-age=0`, `must-revalidate`, strong `ETag`), `public` (a `GET` of a public use case, `max-age` 1m, `s-maxage` 5m, tagged with the resources of its path), `no-store`; refused on a write, and `public` behind a route group |
|
|
290
318
|
| `route-group` (`group`) | `<context> <Name> [--prefix <path>] [--group <ParentName>] [--public \| --role <role>]` | `presentation/http/<name>.routes.ts`: an empty class carrying `@RouteGroup`, behind `Authenticated` unless `--public` or `--role` says otherwise (`HasRole(Role.Admin)`, the role read from the vocabulary of the platform, `<platformDir>/auth/role.ts`, which gets it when it does not hold it); with `--group` it refines that group and inherits from it |
|
|
291
319
|
| `guard` | `<context> <Name>` | `presentation/http/guards/<name>.guard.ts`: a declared guard class to fill, and its spec |
|
|
320
|
+
| `representation` | `<context> <UseCase> <xml\|csv\|media/type>[,...]` | adds `produces` to the `@Controller` of the use case, and `consumes: ['application/xml']` to one that receives a body when XML is asked; says when CSV needs a page or a streamed list, and when `stack.representations` is not `negotiated` |
|
|
321
|
+
| `form` | `<context> <UseCase>` | adds `const form = defineForm<Infer<typeof body>>({ ... })` before the `@Controller` of a use case that receives a body, and `form` to its options: the hints of its form at `GET /forms/<operationId>` |
|
|
292
322
|
| `schema` | `<context\|shared-kernel> <Name>` | `presentation/http/shared/<name>.schema.ts` of the context, or `presentation/<name>.schema.ts` of the shared kernel: one shape of the contract declared once (a zod schema with `.meta({ id })`, a class-validator class, or a schema wrapped by `sharedSchema`), to fill; the routes use it whole, nested or in part |
|
|
293
323
|
| `integration-event` | `<context> <Aggregate> <Fact> [--version n]` | `defineIntegrationEvent` declaration in the published language (its payload in `<event>.v<n>.payload.ts` with class-validator or a schema of your own), index export, the publisher `application/integration/publishers/<event>.publisher.ts`, spec, registration, a line of `platform/audit/audited-events.ts` |
|
|
294
324
|
| `integration-handler` (`consumer`) | `<context> <upstreamContext> <eventType>` | `application/integration/handlers/<name>.integration-handler.ts`, a class `<Name>IntegrationHandler` depending on `CommandBus`, its spec, its idempotent subscription under the consumer name `<context>.<name>`; refused unless the upstream is declared |
|
|
@@ -637,7 +667,7 @@ ddd-ts-kit describe <context>
|
|
|
637
667
|
|
|
638
668
|
One context as facts read from the config and the source text, in both styles: use cases with
|
|
639
669
|
their permission (or `public`), routes (method, path, operation id, use case, schema names, error
|
|
640
|
-
codes), consumed and published events, ports with their adapters, policies, gateways with their
|
|
670
|
+
codes, the media types they answer and read in besides JSON, their form), consumed and published events, ports with their adapters, policies, gateways with their
|
|
641
671
|
upstream, scheduled jobs, upstreams and downstreams. Field lists are not guessed: they are in
|
|
642
672
|
`openapi/openapi.yaml` and `docs/integration/event-catalog.md`. `docs` writes the same facts in
|
|
643
673
|
each `CONTEXT.md`.
|
|
@@ -650,7 +680,7 @@ each `CONTEXT.md`.
|
|
|
650
680
|
| `glossary`, `aggregates`, `domainEvents`, `permissions` | names |
|
|
651
681
|
| `upstreams`, `downstreams` | `{ context, relationship }` |
|
|
652
682
|
| `useCases` | `{ kind, name, permission, file }`, `kind` being `command` or `query` |
|
|
653
|
-
| `routes` | `{ method, path, operationId, useCase, permission, request: [{ part, schema }], responses: [{ status, schema }], errors, file }` |
|
|
683
|
+
| `routes` | `{ method, path, operationId, useCase, permission, request: [{ part, schema }], responses: [{ status, schema }], errors, file }`, and `produces`, `consumes` (media types besides JSON) and `form` (`GET /forms/<operationId>`) when the route declares them |
|
|
654
684
|
| `consumedEvents` | `{ type, version, from, handler, consumer, file }` |
|
|
655
685
|
| `publishedEvents` | `{ type, versions, publishers }` |
|
|
656
686
|
| `ports` | `{ name, kind, adapters, file }`, `kind` being that of its binding (`repository`, `external`, `gateway`) |
|
|
@@ -783,6 +813,7 @@ saying what to do instead. Exit code 1 when there is at least one error.
|
|
|
783
813
|
| `authz/declared` | in a module file, `builder.command(X)` or `builder.query(X)` without `.requires(` or `.public(` in its chain, unless the message class carries `@Requires` or `@Public` of `@ddd-ts-kit/kernel/declarations`; with manual or nest wiring, a command or query class absent from every `requires(X, ...)` and `publicUseCase(X)` of the module file and of `application/authorization/`; a `defineRoute` without `security` (the route type refuses it already, and an empty list too: this is the text-level net for a definition built loosely); in the declared style, the exported class of a `*.command.ts` or `*.query.ts` file carrying neither `@Requires` nor `@Public` |
|
|
784
814
|
| `authz/in-application` | `presentation/`: a test on roles, `isAdmin`, the import of an authorizer or of `Access`; `infrastructure/`: `authorize(` or `check(` on an authorizer or access, `ForbiddenError`; `domain/`: any import of `@ddd-ts-kit/auth`, of the actor types of the kernel (`Actor`, `ActorContext`, `Session`, `ExecutionContext`, the authorized messages), a read of `.roles` or `.permissions` on an actor. The request glue of `@ddd-ts-kit/auth` (`actorOf`, `sessionOf`, `resolveSession`, `SessionAuthenticator`) is free in `presentation/`. `presentation/` and `infrastructure/`: the import of `Requires`, `Public` or `Policy` from `@ddd-ts-kit/kernel/declarations`, or of the ports `Access` and `PolicyAccess` from `@ddd-ts-kit/auth`; they are free in `application/` |
|
|
785
815
|
| `authz/actor-explicit` | in `domain/` and `application/`: `ActorContext`, `ExecutionScope` (as a type or as a value: the class is the token of a dependency list), `AsyncLocalStorageExecutionScope`, `ScopedActorContext`, `AsyncLocalStorage`; `.current()` or `.require()` on an actor context or on something named `scope`, `scopes` or `...executionScope`; an import of `stampCreation`, `stampUpdate` or `tenantScopeOf` |
|
|
816
|
+
| `authz/fields-by-schema` | under `application/queries/`: `roles.includes(`, `.some(`, `.every(`, `.find(`, `.indexOf(`, a comparison with a `role`, `isAdmin` |
|
|
786
817
|
| `aspects/outside-in` | an import of `@ddd-ts-kit/aspects/decorators` outside `infrastructure/` of a context and the platform directory: `presentation/`, the module file, `published-language/`, the shared kernel, `main.ts`, any other source (`domain/` and `application/` are reported by the two `layer/*` rules instead) |
|
|
787
818
|
| `tracing/platform-only` | an import of `@ddd-ts-kit/tracing` or of an `@opentelemetry/*` package outside the platform directory, `main.ts` and `apps/`, tests included |
|
|
788
819
|
| `tenancy/scoped-statement` | with `stack.tenancy` other than `none`, in `infrastructure/` of a context, tests aside: on Knex the executor used other than as an argument (`executor()(`, `executor().from(`, `executor().raw(`, `const db = ...executor();`) and any `.raw(`; on Drizzle, statement by statement, a read, update or delete on the executor whose where has no `tenantCondition(` nor `ownTenantCondition(` (inline or in the local it is given), an insert whose row has no `tenantScopeOf(`, a relational query (`executor().query`), a raw `execute(`, or the executor held in a variable; on both, a read model store built without its `tenant` option. A where built by another function is not followed |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"architecture-rules.d.ts","sourceRoot":"","sources":["../../../src/check/catalogue/architecture-rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"architecture-rules.d.ts","sourceRoot":"","sources":["../../../src/check/catalogue/architecture-rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAgF7C,gHAAgH;AAChH,eAAO,MAAM,kBAAkB,EAAE,SAAS,IAAI,EA+E7C,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { aspectsOutsideIn } from '../rules/aspects-outside-in.js';
|
|
2
2
|
import { authzActorExplicit } from '../rules/authz-actor-explicit.js';
|
|
3
|
+
import { authzFieldsBySchema } from '../rules/authz-fields-by-schema.js';
|
|
3
4
|
import { authzDeclared } from '../rules/authz-declared.js';
|
|
4
5
|
import { authzInApplication } from '../rules/authz-in-application.js';
|
|
5
6
|
import { cleanBlankLines } from '../rules/clean-blank-lines.js';
|
|
@@ -128,6 +129,7 @@ export const ARCHITECTURE_RULES = [
|
|
|
128
129
|
authzDeclared,
|
|
129
130
|
authzInApplication,
|
|
130
131
|
authzActorExplicit,
|
|
132
|
+
authzFieldsBySchema,
|
|
131
133
|
aspectsOutsideIn,
|
|
132
134
|
tracingPlatformOnly,
|
|
133
135
|
tenancyScopedStatement,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"architecture-rules.js","sourceRoot":"","sources":["../../../src/check/catalogue/architecture-rules.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"architecture-rules.js","sourceRoot":"","sources":["../../../src/check/catalogue/architecture-rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kit-error-codes.d.ts","sourceRoot":"","sources":["../../../src/check/errors/kit-error-codes.ts"],"names":[],"mappings":"AAAA,yHAAyH;AACzH,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,
|
|
1
|
+
{"version":3,"file":"kit-error-codes.d.ts","sourceRoot":"","sources":["../../../src/check/errors/kit-error-codes.ts"],"names":[],"mappings":"AAAA,yHAAyH;AACzH,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAsB5C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kit-error-codes.js","sourceRoot":"","sources":["../../../src/check/errors/kit-error-codes.ts"],"names":[],"mappings":"AAAA,yHAAyH;AACzH,MAAM,CAAC,MAAM,eAAe,GAAsB;IAChD,mBAAmB;IACnB,WAAW;IACX,UAAU;IACV,qBAAqB;IACrB,cAAc;IACd,WAAW;IACX,sBAAsB;IACtB,kBAAkB;IAClB,sBAAsB;IACtB,SAAS;IACT,cAAc;IACd,eAAe;IACf,oBAAoB;IACpB,qBAAqB;IACrB,uBAAuB;IACvB,gBAAgB;IAChB,wBAAwB;IACxB,gBAAgB;IAChB,eAAe;IACf,kBAAkB;CACnB,CAAC"}
|
|
1
|
+
{"version":3,"file":"kit-error-codes.js","sourceRoot":"","sources":["../../../src/check/errors/kit-error-codes.ts"],"names":[],"mappings":"AAAA,yHAAyH;AACzH,MAAM,CAAC,MAAM,eAAe,GAAsB;IAChD,mBAAmB;IACnB,WAAW;IACX,UAAU;IACV,qBAAqB;IACrB,cAAc;IACd,WAAW;IACX,gBAAgB;IAChB,sBAAsB;IACtB,kBAAkB;IAClB,sBAAsB;IACtB,SAAS;IACT,cAAc;IACd,eAAe;IACf,oBAAoB;IACpB,qBAAqB;IACrB,uBAAuB;IACvB,gBAAgB;IAChB,wBAAwB;IACxB,gBAAgB;IAChB,eAAe;IACf,kBAAkB;CACnB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authz-docs.d.ts","sourceRoot":"","sources":["../../../src/check/explain/authz-docs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEpD,eAAO,MAAM,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"authz-docs.d.ts","sourceRoot":"","sources":["../../../src/check/explain/authz-docs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEpD,eAAO,MAAM,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwDxD,CAAC"}
|
|
@@ -42,5 +42,17 @@ const { actor } = command;
|
|
|
42
42
|
// infrastructure/persistence/drizzle-invoice.repository.ts
|
|
43
43
|
const row = { ...toRow(invoice), ...stampCreation(this.scope, this.clock), ...tenantScopeOf(this.scope) };`,
|
|
44
44
|
},
|
|
45
|
+
'authz/fields-by-schema': {
|
|
46
|
+
why: 'A query that removes a field for the callers without a role answers one way in JSON and is forgotten in the CSV export, the XML of a partner and the form of the front end, and nobody reading the contract knows the field may be missing. Marked on the response schema with withFieldAccess of @ddd-ts-kit/http, the field is reserved to a permission or a policy once: the pipeline leaves it out of every representation for an actor who may not read it, refuses it in a request body from one who may not set it, the contract says so with x-field-access, and a form described by the server shows it read-only or not at all. Which rows the actor may read stays the access scope of the query. Judged: a test on the roles (roles.includes, some, every, find, indexOf), a comparison with a role, or isAdmin, in a file under application/queries/ of a context.',
|
|
47
|
+
bad: `// application/queries/get-appointment/get-appointment.handler.ts
|
|
48
|
+
const row = await this.appointments.findById(query.appointmentId);
|
|
49
|
+
return query.actor.roles.includes('practitioner') ? row : { ...row, internalNote: undefined };`,
|
|
50
|
+
good: `// application/queries/get-appointment/get-appointment.handler.ts
|
|
51
|
+
return this.appointments.findById(query.appointmentId);
|
|
52
|
+
// presentation/http/appointments/get-appointment/get-appointment.controller.ts
|
|
53
|
+
const answer = withFieldAccess(classSchema(GetAppointmentAnswer), {
|
|
54
|
+
internalNote: { read: { permission: schedulingPermissions['appointment.note.read'] } },
|
|
55
|
+
});`,
|
|
56
|
+
},
|
|
45
57
|
};
|
|
46
58
|
//# sourceMappingURL=authz-docs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authz-docs.js","sourceRoot":"","sources":["../../../src/check/explain/authz-docs.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,UAAU,GAAsC;IAC3D,gBAAgB,EAAE;QAChB,GAAG,EAAE,mvBAAmvB;QACxvB,GAAG,EAAE;;;mEAG0D;QAC/D,IAAI,EAAE;;;;;mEAKyD;KAChE;IACD,sBAAsB,EAAE;QACtB,GAAG,EAAE,q0BAAq0B;QAC10B,GAAG,EAAE;;;;;4DAKmD;QACxD,IAAI,EAAE;;;;;;sCAM4B;KACnC;IACD,sBAAsB,EAAE;QACtB,GAAG,EAAE,ykBAAykB;QAC9kB,GAAG,EAAE;;;;qDAI4C;QACjD,IAAI,EAAE;;;;;2GAKiG;KACxG;CACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"authz-docs.js","sourceRoot":"","sources":["../../../src/check/explain/authz-docs.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,UAAU,GAAsC;IAC3D,gBAAgB,EAAE;QAChB,GAAG,EAAE,mvBAAmvB;QACxvB,GAAG,EAAE;;;mEAG0D;QAC/D,IAAI,EAAE;;;;;mEAKyD;KAChE;IACD,sBAAsB,EAAE;QACtB,GAAG,EAAE,q0BAAq0B;QAC10B,GAAG,EAAE;;;;;4DAKmD;QACxD,IAAI,EAAE;;;;;;sCAM4B;KACnC;IACD,sBAAsB,EAAE;QACtB,GAAG,EAAE,ykBAAykB;QAC9kB,GAAG,EAAE;;;;qDAI4C;QACjD,IAAI,EAAE;;;;;2GAKiG;KACxG;IACD,wBAAwB,EAAE;QACxB,GAAG,EAAE,i1BAAi1B;QACt1B,GAAG,EAAE;;+FAEsF;QAC3F,IAAI,EAAE;;;;;IAKN;KACD;CACF,CAAC"}
|
|
@@ -21,7 +21,7 @@ export const ERRORS_DOCS = {
|
|
|
21
21
|
}`,
|
|
22
22
|
},
|
|
23
23
|
'errors/known-code': {
|
|
24
|
-
why: 'The `errors` list of a route is what the OpenAPI document promises: one problem response per status of the codes it names. A code written there that no refusal sets, misspelled or left behind by a renamed factory, is a response the contract documents and the API never gives, while the refusal really raised is missing from it. A code exists when a factory or an error class of the context of the route sets it, when a class outside the contexts (the platform, the shared kernel) does, or when it is a code of the kit: VALIDATION_FAILED, NOT_FOUND, CONFLICT, INVARIANT_VIOLATION, UNAUTHORIZED, FORBIDDEN, CONCURRENCY_CONFLICT, INVALID_CRITERIA, INVALID_PAGE_REQUEST, TIMEOUT, CIRCUIT_OPEN, BULKHEAD_FULL, ATTEMPTS_EXHAUSTED, the conditions of a write: PRECONDITION_FAILED, PRECONDITION_REQUIRED, and the refusals of a file: FILE_TOO_LARGE, UNSUPPORTED_MEDIA_TYPE, FILE_NOT_FOUND, FILE_REJECTED, INVALID_FILE_KEY. A code another context sets does not count: a context answers with its own language. Judged under "stack.refusals": "factories" only.',
|
|
24
|
+
why: 'The `errors` list of a route is what the OpenAPI document promises: one problem response per status of the codes it names. A code written there that no refusal sets, misspelled or left behind by a renamed factory, is a response the contract documents and the API never gives, while the refusal really raised is missing from it. A code exists when a factory or an error class of the context of the route sets it, when a class outside the contexts (the platform, the shared kernel) does, or when it is a code of the kit: VALIDATION_FAILED, NOT_FOUND, CONFLICT, INVARIANT_VIOLATION, UNAUTHORIZED, FORBIDDEN, NOT_ACCEPTABLE, CONCURRENCY_CONFLICT, INVALID_CRITERIA, INVALID_PAGE_REQUEST, TIMEOUT, CIRCUIT_OPEN, BULKHEAD_FULL, ATTEMPTS_EXHAUSTED, the conditions of a write: PRECONDITION_FAILED, PRECONDITION_REQUIRED, and the refusals of a file: FILE_TOO_LARGE, UNSUPPORTED_MEDIA_TYPE, FILE_NOT_FOUND, FILE_REJECTED, INVALID_FILE_KEY. A code another context sets does not count: a context answers with its own language. Judged under "stack.refusals": "factories" only.',
|
|
25
25
|
bad: `// domain/errors/appointment.error.ts sets 'SLOT_TAKEN'
|
|
26
26
|
defineRoute({ method: 'POST', path: '/appointments', errors: ['FORBIDDEN', 'SLOT_ALREADY_TAKEN'], security: ['bearer'] }, book);`,
|
|
27
27
|
good: `defineRoute({ method: 'POST', path: '/appointments', errors: ['FORBIDDEN', 'SLOT_TAKEN'], security: ['bearer'] }, book);`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors-docs.js","sourceRoot":"","sources":["../../../src/check/explain/errors-docs.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,WAAW,GAAsC;IAC5D,oBAAoB,EAAE;QACpB,GAAG,EAAE,y1BAAy1B;QAC91B,GAAG,EAAE;;;;;;;;EAQP;QACE,IAAI,EAAE;;;;;;;;EAQR;KACC;IACD,mBAAmB,EAAE;QACnB,GAAG,EAAE,
|
|
1
|
+
{"version":3,"file":"errors-docs.js","sourceRoot":"","sources":["../../../src/check/explain/errors-docs.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,WAAW,GAAsC;IAC5D,oBAAoB,EAAE;QACpB,GAAG,EAAE,y1BAAy1B;QAC91B,GAAG,EAAE;;;;;;;;EAQP;QACE,IAAI,EAAE;;;;;;;;EAQR;KACC;IACD,mBAAmB,EAAE;QACnB,GAAG,EAAE,wiCAAwiC;QAC7iC,GAAG,EAAE;iIACwH;QAC7H,IAAI,EAAE,0HAA0H;KACjI;CACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenancy-docs.d.ts","sourceRoot":"","sources":["../../../src/check/explain/tenancy-docs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEpD,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"tenancy-docs.d.ts","sourceRoot":"","sources":["../../../src/check/explain/tenancy-docs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEpD,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAe1D,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const TENANCY_DOCS = {
|
|
2
2
|
'tenancy/scoped-statement': {
|
|
3
|
-
why: 'On shared tables, one statement without its tenant condition reads or overwrites the data of every tenant: the most common and the most damaging leak of a multi-tenant application. The kit puts the condition in one place, the helpers of the ORM package, which read the tenant from the execution scope, refuse work that names none, widen reads only under an audited elevation and never widen writes. A table reached straight from the executor bypasses all of it. Judged in a project whose "stack.tenancy" is not "none": the infrastructure of the contexts, tests aside. Checked by text, statement by statement: on Knex the executor used other than as the argument of a helper, and raw SQL; on Drizzle a read, update or delete whose where carries no tenant condition (inline or in the local it is given), an insert whose row names no tenant, a relational query or a raw execute; on both, a read model store built without its tenant option. A where built by another function is not followed: inline it, or record a deviation.',
|
|
3
|
+
why: 'On shared tables, one statement without its tenant condition reads or overwrites the data of every tenant: the most common and the most damaging leak of a multi-tenant application. The kit puts the condition in one place, the helpers of the ORM package, which read the tenant from the execution scope, refuse work that names none, widen reads only under an audited elevation and never widen writes. A table reached straight from the executor bypasses all of it. Judged in a project whose "stack.tenancy" is not "none": the infrastructure of the contexts, tests aside. Checked by text, statement by statement: on Knex the executor used other than as the argument of a helper, and raw SQL that may reach rows by itself: a word that reads or writes rows (`select`, `from`, `join`, `insert`, `update`, `delete`, `values`, `call`...) or starts a statement (`table`, `with`, `do`...), a call to a function that is not a known expression (an aggregate, a cast, arithmetic, text), a text that is not a literal or a template that interpolates; a statement of the schema (`create`, `alter`, `drop`, `comment`) with no word of rows, and an aggregate in a select, reach no row by themselves; on Drizzle a read, update or delete whose where carries no tenant condition (inline or in the local it is given), an insert whose row names no tenant, a relational query or a raw execute; on both, a read model store built without its tenant option. A where built by another function is not followed: inline it, or record a deviation.',
|
|
4
4
|
bad: `// infrastructure/persistence/knex-invoice.repository.ts
|
|
5
5
|
const row = await this.database.executor()<InvoiceRow, InvoiceRow[]>('invoices').where({ id }).first();
|
|
6
6
|
const all = await this.database.executor().from('invoices').where({ status }); // the executor chained
|
|
@@ -9,6 +9,8 @@ await this.database.executor().select().from(invoices).where(eq(invoices.id, id)
|
|
|
9
9
|
await this.database.executor().query.invoices.findMany(); // a relational query cannot carry the condition`,
|
|
10
10
|
good: `const row = await tenantTable<InvoiceRow>(this.database, this.scope, INVOICES).where({ id }).first();
|
|
11
11
|
await ownTenantTable<InvoiceRow>(this.database, this.scope, INVOICES).where({ id, version }).update(changes);
|
|
12
|
+
const grouped = tenantTable(this.database, this.scope, INVOICES).select('status', this.database.executor().raw('sum(amount) as due')).groupBy('status');
|
|
13
|
+
const pages = await derivedTable(this.database, grouped, 'dues').orderBy('due', 'desc').limit(20);
|
|
12
14
|
await this.database.executor().select().from(invoices).where(and(eq(invoices.id, id), tenantCondition(invoices.tenantId, this.scope)));`,
|
|
13
15
|
},
|
|
14
16
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenancy-docs.js","sourceRoot":"","sources":["../../../src/check/explain/tenancy-docs.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAsC;IAC7D,0BAA0B,EAAE;QAC1B,GAAG,EAAE
|
|
1
|
+
{"version":3,"file":"tenancy-docs.js","sourceRoot":"","sources":["../../../src/check/explain/tenancy-docs.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAsC;IAC7D,0BAA0B,EAAE;QAC1B,GAAG,EAAE,2+CAA2+C;QACh/C,GAAG,EAAE;;;;;2GAKkG;QACvG,IAAI,EAAE;;;;wIAI8H;KACrI;CACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authz-fixtures.d.ts","sourceRoot":"","sources":["../../../src/check/fixtures/authz-fixtures.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"authz-fixtures.d.ts","sourceRoot":"","sources":["../../../src/check/fixtures/authz-fixtures.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAQ5C,eAAO,MAAM,cAAc,EAAE,SAAS,OAAO,EA8O5C,CAAC"}
|
|
@@ -4,7 +4,8 @@ import { declaredProject } from './declared-project.js';
|
|
|
4
4
|
import { handler } from './handler.js';
|
|
5
5
|
import { PATHS } from './paths.js';
|
|
6
6
|
import { project } from './project.js';
|
|
7
|
-
|
|
7
|
+
import { SAMPLES } from './samples.js';
|
|
8
|
+
const { ADAPTER, AGGREGATE, COMMAND, HANDLER, POLICY, QUERY_HANDLER, QUERY_HANDLER_SPEC, ROUTE } = PATHS;
|
|
8
9
|
export const AUTHZ_FIXTURES = [
|
|
9
10
|
{
|
|
10
11
|
ruleId: 'authz/in-application',
|
|
@@ -151,5 +152,41 @@ export const AUTHZ_FIXTURES = [
|
|
|
151
152
|
...handler("import { ExecutionScope } from '@ddd-ts-kit/kernel';\nimport { CommandHandler } from '@ddd-ts-kit/kernel/declarations';\nimport { IssueInvoiceCommand } from '@/contexts/billing/application/commands/issue-invoice/issue-invoice.command.js';\n\n@CommandHandler(IssueInvoiceCommand, [ExecutionScope])\nexport class IssueInvoiceHandler {}\n"),
|
|
152
153
|
}),
|
|
153
154
|
},
|
|
155
|
+
{
|
|
156
|
+
ruleId: 'authz/fields-by-schema',
|
|
157
|
+
name: 'a query that answers what its read model holds, the scope narrowing the rows',
|
|
158
|
+
expect: 'pass',
|
|
159
|
+
files: project({
|
|
160
|
+
[QUERY_HANDLER]: "export class InvoicesIssuedHandler {\n async execute(query: InvoicesIssuedQuery): Promise<readonly InvoiceLine[]> {\n const scope = await this.access.scope(query.actor, permission, 'invoice');\n\n return this.invoices.search(scope);\n }\n}\n",
|
|
161
|
+
[QUERY_HANDLER_SPEC]: SAMPLES.SPEC,
|
|
162
|
+
}),
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
ruleId: 'authz/fields-by-schema',
|
|
166
|
+
name: 'a query that tests the roles it took out of the actor first',
|
|
167
|
+
expect: { file: QUERY_HANDLER },
|
|
168
|
+
files: project({
|
|
169
|
+
[QUERY_HANDLER]: "export class InvoicesIssuedHandler {\n async execute(query: InvoicesIssuedQuery): Promise<readonly InvoiceLine[]> {\n const { roles } = query.actor;\n const lines = await this.invoices.search(query.scope);\n\n return roles.includes('accountant') ? lines : lines.map(({ margin: _margin, ...line }) => line);\n }\n}\n",
|
|
170
|
+
[QUERY_HANDLER_SPEC]: SAMPLES.SPEC,
|
|
171
|
+
}),
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
ruleId: 'authz/fields-by-schema',
|
|
175
|
+
name: 'a query that compares a role held in a variable of its own',
|
|
176
|
+
expect: { file: QUERY_HANDLER },
|
|
177
|
+
files: project({
|
|
178
|
+
[QUERY_HANDLER]: "export class InvoicesIssuedHandler {\n async execute(query: InvoicesIssuedQuery): Promise<readonly InvoiceLine[]> {\n const role = query.actor.attributes['role'];\n const lines = await this.invoices.search(query.scope);\n\n return role === 'accountant' ? lines : lines.map(({ margin: _margin, ...line }) => line);\n }\n}\n",
|
|
179
|
+
[QUERY_HANDLER_SPEC]: SAMPLES.SPEC,
|
|
180
|
+
}),
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
ruleId: 'authz/fields-by-schema',
|
|
184
|
+
name: 'a query that removes a field for the callers without a role',
|
|
185
|
+
expect: { file: QUERY_HANDLER },
|
|
186
|
+
files: project({
|
|
187
|
+
[QUERY_HANDLER]: "export class InvoicesIssuedHandler {\n async execute(query: InvoicesIssuedQuery): Promise<readonly InvoiceLine[]> {\n const lines = await this.invoices.search(query.scope);\n\n return query.actor.roles.includes('accountant') ? lines : lines.map(({ margin: _margin, ...line }) => line);\n }\n}\n",
|
|
188
|
+
[QUERY_HANDLER_SPEC]: SAMPLES.SPEC,
|
|
189
|
+
}),
|
|
190
|
+
},
|
|
154
191
|
];
|
|
155
192
|
//# sourceMappingURL=authz-fixtures.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authz-fixtures.js","sourceRoot":"","sources":["../../../src/check/fixtures/authz-fixtures.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"authz-fixtures.js","sourceRoot":"","sources":["../../../src/check/fixtures/authz-fixtures.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenancy-fixtures.d.ts","sourceRoot":"","sources":["../../../src/check/fixtures/tenancy-fixtures.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"tenancy-fixtures.d.ts","sourceRoot":"","sources":["../../../src/check/fixtures/tenancy-fixtures.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAkG5C,eAAO,MAAM,gBAAgB,EAAE,SAAS,OAAO,EAqH9C,CAAC"}
|
|
@@ -53,6 +53,17 @@ const DRIZZLE_UNSCOPED = `export class DrizzleInvoiceRepository {
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
`;
|
|
56
|
+
/** Aggregates over the rows `tenantTable` confines: raw expressions that reach no table themselves. */
|
|
57
|
+
const RAW_EXPRESSIONS = `export class KnexInvoiceRepository {
|
|
58
|
+
totals() {
|
|
59
|
+
return tenantTable(this.database, this.scope, INVOICES).select(
|
|
60
|
+
this.database.executor().raw('(count(*) filter (where paid))::integer as paid'),
|
|
61
|
+
this.database.executor().raw('coalesce(sum(round(amount)) filter (where state = any(?)), 0)::numeric(12, 2) as due', [states]),
|
|
62
|
+
this.database.executor().raw("customer_id || ' from ' || day as label"),
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
`;
|
|
56
67
|
const tenancy = (orm, value = 'shared-table') => ({
|
|
57
68
|
[CONFIG_FILE]: config({ stack: { orm, tenancy: value } }),
|
|
58
69
|
});
|
|
@@ -99,6 +110,23 @@ export const TENANCY_FIXTURES = [
|
|
|
99
110
|
bypass('knex', 'a select chained on the executor', "return this.database.executor().select('id').from('invoices');"),
|
|
100
111
|
bypass('knex', 'a table reached by table()', "return this.database.executor().table('invoices');"),
|
|
101
112
|
bypass('knex', 'raw SQL', "return this.database.executor().raw('select * from invoices');"),
|
|
113
|
+
bypass('knex', 'raw SQL in a template', 'return this.database.executor().raw(`select * from ${INVOICES}`);'),
|
|
114
|
+
bypass('knex', 'raw SQL whose text is not a literal', 'return this.database.executor().raw(statement);'),
|
|
115
|
+
bypass('knex', 'raw SQL completed by an interpolation', 'return this.database.executor().raw(`${statement} where id = ?`, [id]);'),
|
|
116
|
+
bypass('knex', 'raw SQL that names a table alone', "return this.database.executor().raw('table invoices');"),
|
|
117
|
+
bypass('knex', 'raw SQL that starts with a common table', "return this.database.executor().raw('with due as (table invoices) table due');"),
|
|
118
|
+
bypass('knex', 'raw SQL of values', "return this.database.executor().raw('values (1), (2)');"),
|
|
119
|
+
bypass('knex', 'raw SQL that calls a procedure', "return this.database.executor().raw('call purge_invoices()');"),
|
|
120
|
+
bypass('knex', 'raw SQL that calls a function', "return this.database.executor().raw('purge_all()');"),
|
|
121
|
+
{
|
|
122
|
+
ruleId: RULE,
|
|
123
|
+
name: 'knex: a raw expression in the select of a confined statement, and a constraint of the schema',
|
|
124
|
+
expect: 'pass',
|
|
125
|
+
files: project({
|
|
126
|
+
[KNEX_ADAPTER]: RAW_EXPRESSIONS,
|
|
127
|
+
[`${PATHS.BILLING}/infrastructure/persistence/create-billing-tables.schema.ts`]: "export const holdOnce = (knex: Knex) => knex.raw('alter table ??.?? add constraint held_once exclude using gist (desk with =)', [S, T]);\n",
|
|
128
|
+
}, tenancy('knex')),
|
|
129
|
+
},
|
|
102
130
|
bypass('knex', 'the executor held in a variable', "const db = this.database.executor();\n\n return db('invoices');"),
|
|
103
131
|
{
|
|
104
132
|
ruleId: RULE,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenancy-fixtures.js","sourceRoot":"","sources":["../../../src/check/fixtures/tenancy-fixtures.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,MAAM,IAAI,GAAG,0BAA0B,CAAC;AACxC,MAAM,YAAY,GAAG,GAAG,KAAK,CAAC,OAAO,wDAAwD,CAAC;AAC9F,MAAM,eAAe,GAAG,GAAG,KAAK,CAAC,OAAO,2DAA2D,CAAC;AAEpG,MAAM,WAAW,GAAG;;;;;;;;;;;CAWnB,CAAC;AAEF,MAAM,aAAa,GAAG;;;;;CAKrB,CAAC;AAEF,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuBtB,CAAC;AAEF,MAAM,gBAAgB,GAAG;;;;;CAKxB,CAAC;AAEF,MAAM,OAAO,GAAG,CAAC,GAAW,EAAE,KAAK,GAAG,cAAc,EAAE,EAAE,CAAC,CAAC;IACxD,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC;CAC1D,CAAC,CAAC;AAEH,uFAAuF;AACvF,MAAM,MAAM,GAAG,CAAC,GAAuB,EAAE,IAAY,EAAE,IAAY,EAAW,EAAE;IAC9E,MAAM,OAAO,GAAG,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC;IAChE,MAAM,KAAK,GAAG,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,0BAA0B,CAAC;IAEpF,OAAO;QACL,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,GAAG,GAAG,KAAK,IAAI,EAAE;QACvB,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;QACzB,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,gBAAgB,KAAK,uBAAuB,IAAI,YAAY,EAAE,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;KAC1G,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,GAAG,KAAK,CAAC,OAAO,+DAA+D,CAAC;AAEnG,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,MAAc,EAAE,QAA2B,EAAW,EAAE,CAAC,CAAC;IACzF,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,oBAAoB,IAAI,EAAE;IAChC,MAAM,EAAE,QAAQ;IAChB,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;CAC1D,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAuB;IAClD;QACE,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,yDAAyD;QAC/D,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,WAAW,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;KACjE;IACD;QACE,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,kEAAkE;QACxE,MAAM,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;QAC9B,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,aAAa,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;KACnE;IACD;QACE,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,uDAAuD;QAC7D,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,OAAO,CACZ;YACE,CAAC,YAAY,CAAC,EACZ,2LAA2L;SAC9L,EACD,OAAO,CAAC,MAAM,CAAC,CAChB;KACF;IACD,MAAM,CAAC,MAAM,EAAE,2BAA2B,EAAE,mDAAmD,CAAC;IAChG,MAAM,CAAC,MAAM,EAAE,kCAAkC,EAAE,gEAAgE,CAAC;IACpH,MAAM,CAAC,MAAM,EAAE,4BAA4B,EAAE,oDAAoD,CAAC;IAClG,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,gEAAgE,CAAC;IAC3F,MAAM,CACJ,MAAM,EACN,iCAAiC,EACjC,oEAAoE,CACrE;IACD;QACE,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,mDAAmD;QACzD,MAAM,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE;QACjC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,gBAAgB,EAAE,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;KAC5E;IACD;QACE,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,gEAAgE;QACtE,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,eAAe,CAAC,EAAE,cAAc,EAAE,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;KAC1E;IACD;QACE,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,qFAAqF;QAC3F,MAAM,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE;QACjC,KAAK,EAAE,OAAO,CACZ;YACE,CAAC,eAAe,CAAC,EAAE,cAAc,CAAC,OAAO,CACvC,wBAAwB,EACxB,wGAAwG,CACzG;SACF,EACD,OAAO,CAAC,SAAS,CAAC,CACnB;KACF;IACD,MAAM,CACJ,SAAS,EACT,gCAAgC,EAChC,iEAAiE,CAClE;IACD,MAAM,CAAC,SAAS,EAAE,oBAAoB,EAAE,4DAA4D,CAAC;IACrG,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,uEAAuE,CAAC;IACrG,SAAS,CACP,0BAA0B,EAC1B,4JAA4J,EAC5J,EAAE,IAAI,EAAE,UAAU,EAAE,CACrB;IACD,SAAS,CACP,uCAAuC,EACvC,4LAA4L,EAC5L,EAAE,IAAI,EAAE,UAAU,EAAE,CACrB;IACD,SAAS,CACP,uBAAuB,EACvB,kMAAkM,EAClM,MAAM,CACP;IACD;QACE,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,0DAA0D;QAChE,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;KACzG;CACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"tenancy-fixtures.js","sourceRoot":"","sources":["../../../src/check/fixtures/tenancy-fixtures.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authz-fields-by-schema.d.ts","sourceRoot":"","sources":["../../../src/check/rules/authz-fields-by-schema.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAkB7C,eAAO,MAAM,mBAAmB,EAAE,IAQjC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { inLayer } from '../support/in-layer.js';
|
|
2
|
+
import { perFile } from '../support/per-file.js';
|
|
3
|
+
/** What tells one caller from another by hand: a test on the roles, a comparison with a role, an `isAdmin`. */
|
|
4
|
+
const ROLE_TESTS = [
|
|
5
|
+
{
|
|
6
|
+
pattern: /(?<![\w$])roles\s*\.\s*(?:includes|some|every|find|indexOf)\s*\(/,
|
|
7
|
+
what: 'A test on the roles of the actor',
|
|
8
|
+
},
|
|
9
|
+
{ pattern: /(?<![\w$])role\s*[!=]==?|[!=]==?\s*(?:[\w$]+\s*\.\s*)*role(?![\w$(])/, what: 'A comparison on a role' },
|
|
10
|
+
{ pattern: /(?<![\w$])isAdmin(?![\w$])/, what: 'isAdmin' },
|
|
11
|
+
];
|
|
12
|
+
const FIX = 'Answer every field the read model holds and mark the one reserved to some callers on the response schema: withFieldAccess(schema, { internalNote: { read: { permission } } }) of @ddd-ts-kit/http. The pipeline leaves it out for an actor who may not read it, in JSON, XML and CSV alike, the contract says so, and a form described by the server shows it read-only or not at all. Which rows the actor may read at all stays the access scope of the query.';
|
|
13
|
+
export const authzFieldsBySchema = {
|
|
14
|
+
id: 'authz/fields-by-schema',
|
|
15
|
+
description: 'A query never shapes its answer by the roles of the actor: a field reserved to some callers is marked on the response schema (withFieldAccess of @ddd-ts-kit/http), not removed by hand under application/queries/.',
|
|
16
|
+
scope: 'file',
|
|
17
|
+
run(project) {
|
|
18
|
+
return perFile(project, this.id, roleShapedAnswer);
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
function roleShapedAnswer(file) {
|
|
22
|
+
const location = inLayer(file, 'application');
|
|
23
|
+
if (location?.inside[0] !== 'queries') {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
return ROLE_TESTS.flatMap(({ pattern, what }) => {
|
|
27
|
+
const match = pattern.exec(file.scan.code);
|
|
28
|
+
return match === null
|
|
29
|
+
? []
|
|
30
|
+
: [{ line: file.scan.lineAt(match.index), message: `${what} shapes the answer of a query.`, fix: FIX }];
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=authz-fields-by-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authz-fields-by-schema.js","sourceRoot":"","sources":["../../../src/check/rules/authz-fields-by-schema.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEjD,+GAA+G;AAC/G,MAAM,UAAU,GAAmE;IACjF;QACE,OAAO,EAAE,kEAAkE;QAC3E,IAAI,EAAE,kCAAkC;KACzC;IACD,EAAE,OAAO,EAAE,sEAAsE,EAAE,IAAI,EAAE,wBAAwB,EAAE;IACnH,EAAE,OAAO,EAAE,4BAA4B,EAAE,IAAI,EAAE,SAAS,EAAE;CAC3D,CAAC;AAEF,MAAM,GAAG,GACP,kcAAkc,CAAC;AAErc,MAAM,CAAC,MAAM,mBAAmB,GAAS;IACvC,EAAE,EAAE,wBAAwB;IAC5B,WAAW,EACT,qNAAqN;IACvN,KAAK,EAAE,MAAM;IACb,GAAG,CAAC,OAAO;QACT,OAAO,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;IACrD,CAAC;CACF,CAAC;AAEF,SAAS,gBAAgB,CAAC,IAAgB;IACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IAE9C,IAAI,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;QACtC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;QAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE3C,OAAO,KAAK,KAAK,IAAI;YACnB,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI,gCAAgC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;IAC5G,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { SourceFile } from '../model/source-file.js';
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* What a Knex adapter of tenant data reaches without the helpers: the executor called, chained or
|
|
4
|
+
* held, and raw SQL. A raw call whose first argument is a literal that reaches no row by itself
|
|
5
|
+
* (an aggregate in a select, a constraint of the schema: `rawReachesRows`) is not reported, since
|
|
6
|
+
* the statement it is put in is what the tenant confines; any other raw call is.
|
|
7
|
+
*/
|
|
3
8
|
export declare function knexUnscoped(file: SourceFile): readonly {
|
|
4
9
|
offset: number;
|
|
5
10
|
message: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"knex-unscoped.d.ts","sourceRoot":"","sources":["../../../src/check/tenancy/knex-unscoped.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"knex-unscoped.d.ts","sourceRoot":"","sources":["../../../src/check/tenancy/knex-unscoped.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAW1D;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,CAe7F"}
|
|
@@ -1,19 +1,32 @@
|
|
|
1
1
|
import { executorUses } from './executor-uses.js';
|
|
2
|
+
import { rawReachesRows } from './raw-reaches-rows.js';
|
|
3
|
+
import { rawSqlText } from './raw-sql-text.js';
|
|
2
4
|
/** Raw SQL, which no helper confines. */
|
|
3
5
|
const RAW = /\.raw\s*\(/g;
|
|
4
|
-
/**
|
|
6
|
+
/** A raw use of the executor: judged by what its SQL says, as any raw SQL. */
|
|
7
|
+
const RAW_STATEMENT = /^\s*\.raw\s*\(/;
|
|
8
|
+
/**
|
|
9
|
+
* What a Knex adapter of tenant data reaches without the helpers: the executor called, chained or
|
|
10
|
+
* held, and raw SQL. A raw call whose first argument is a literal that reaches no row by itself
|
|
11
|
+
* (an aggregate in a select, a constraint of the schema: `rawReachesRows`) is not reported, since
|
|
12
|
+
* the statement it is put in is what the tenant confines; any other raw call is.
|
|
13
|
+
*/
|
|
5
14
|
export function knexUnscoped(file) {
|
|
6
15
|
const { code } = file.scan;
|
|
7
16
|
const straight = executorUses(code)
|
|
8
|
-
.filter((use) => !use.handedOver)
|
|
17
|
+
.filter((use) => !use.handedOver && !RAW_STATEMENT.test(use.statement))
|
|
9
18
|
.map((use) => ({
|
|
10
19
|
offset: use.offset,
|
|
11
20
|
message: 'The executor is used straight (called, chained or held): no tenant condition confines it.',
|
|
12
21
|
}));
|
|
13
|
-
const raw = [...code.matchAll(RAW)]
|
|
14
|
-
|
|
15
|
-
message: 'Raw SQL reaches the tables with no tenant condition.'
|
|
16
|
-
}));
|
|
22
|
+
const raw = [...code.matchAll(RAW)]
|
|
23
|
+
.filter((match) => reachesRows(file, match.index + match[0].length))
|
|
24
|
+
.map((match) => ({ offset: match.index, message: 'Raw SQL reaches the tables with no tenant condition.' }));
|
|
17
25
|
return [...straight, ...raw];
|
|
18
26
|
}
|
|
27
|
+
/** True unless the first argument is a literal whose SQL reaches no row by itself. */
|
|
28
|
+
function reachesRows(file, argumentsStart) {
|
|
29
|
+
const text = rawSqlText(file, argumentsStart);
|
|
30
|
+
return text === undefined || rawReachesRows(text);
|
|
31
|
+
}
|
|
19
32
|
//# sourceMappingURL=knex-unscoped.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"knex-unscoped.js","sourceRoot":"","sources":["../../../src/check/tenancy/knex-unscoped.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"knex-unscoped.js","sourceRoot":"","sources":["../../../src/check/tenancy/knex-unscoped.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,yCAAyC;AACzC,MAAM,GAAG,GAAG,aAAa,CAAC;AAE1B,8EAA8E;AAC9E,MAAM,aAAa,GAAG,gBAAgB,CAAC;AAEvC;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,IAAgB;IAC3C,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC;IAE3B,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC;SAChC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;SACtE,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACb,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,OAAO,EAAE,2FAA2F;KACrG,CAAC,CAAC,CAAC;IAEN,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;SAChC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;SACnE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,sDAAsD,EAAE,CAAC,CAAC,CAAC;IAE9G,OAAO,CAAC,GAAG,QAAQ,EAAE,GAAG,GAAG,CAAC,CAAC;AAC/B,CAAC;AAED,sFAAsF;AACtF,SAAS,WAAW,CAAC,IAAgB,EAAE,cAAsB;IAC3D,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IAE9C,OAAO,IAAI,KAAK,SAAS,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the literal SQL of a raw call can reach rows by itself. A statement of the schema that
|
|
3
|
+
* holds no word of rows cannot; an expression can only if it holds a word that reads or writes
|
|
4
|
+
* rows, starts a statement, or calls a function outside the expressions known to work on the
|
|
5
|
+
* rows already confined (a function call may run any statement).
|
|
6
|
+
*/
|
|
7
|
+
export declare function rawReachesRows(sql: string): boolean;
|
|
8
|
+
//# sourceMappingURL=raw-reaches-rows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raw-reaches-rows.d.ts","sourceRoot":"","sources":["../../../src/check/tenancy/raw-reaches-rows.ts"],"names":[],"mappings":"AAuEA;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAYnD"}
|