ddd-ts-kit 0.14.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 +28 -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/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/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 +11 -1
- package/dist/commands/init.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/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/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/write-adr.js +3 -6
- package/dist/generate/kinds/write-adr.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 +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/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/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/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
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { AggregateRoot } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { OrganisationOpened } from '{{alias.context}}/domain/events/organisation-opened.event{{alias.ext}}';
|
|
3
|
+
import type { OrganisationName } from '{{alias.context}}/domain/value-objects/organisation-name.vo{{alias.ext}}';
|
|
4
|
+
import type { OrganisationSlug } from '{{alias.context}}/domain/value-objects/organisation-slug.vo{{alias.ext}}';
|
|
5
|
+
|
|
6
|
+
export interface OrganisationState {
|
|
7
|
+
readonly name: OrganisationName;
|
|
8
|
+
readonly openedBy: string;
|
|
9
|
+
readonly openedAt: Date;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A group of accounts that work together: a company, a clinic, a school. Its slug is its identity,
|
|
14
|
+
* and the tenant of its data when the project keeps the data of each organisation apart.
|
|
15
|
+
*/
|
|
16
|
+
export class Organisation extends AggregateRoot<string> {
|
|
17
|
+
private constructor(
|
|
18
|
+
id: string,
|
|
19
|
+
private readonly state: OrganisationState,
|
|
20
|
+
) {
|
|
21
|
+
super(id);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Opened by an account, which becomes its first owner (see `OpenOrganisationHandler`). */
|
|
25
|
+
static open(slug: OrganisationSlug, terms: Pick<OrganisationState, 'name' | 'openedBy'>, now: Date): Organisation {
|
|
26
|
+
const opened = new Organisation(slug.value, { ...terms, openedAt: now });
|
|
27
|
+
|
|
28
|
+
opened.record(new OrganisationOpened(slug.value, now, { name: terms.name.value, openedBy: terms.openedBy }));
|
|
29
|
+
|
|
30
|
+
return opened;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static rehydrate(id: string, state: OrganisationState): Organisation {
|
|
34
|
+
return new Organisation(id, state);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get name(): OrganisationName {
|
|
38
|
+
return this.state.name;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get openedBy(): string {
|
|
42
|
+
return this.state.openedBy;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get openedAt(): Date {
|
|
46
|
+
return this.state.openedAt;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
toState(): OrganisationState {
|
|
50
|
+
return { ...this.state };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ConceptError } from '@ddd-ts-kit/kernel';
|
|
2
|
+
|
|
3
|
+
/** What the accounts refuse: an account is the application's view of one person the identity provider authenticates. */
|
|
4
|
+
export class AccountError extends ConceptError {
|
|
5
|
+
static notFound(accountId: string) {
|
|
6
|
+
return AccountError.refusal(
|
|
7
|
+
'ACCOUNT_NOT_FOUND',
|
|
8
|
+
`No account ${accountId}: the person signs in once before acting.`,
|
|
9
|
+
{ accountId },
|
|
10
|
+
).exposing('accountId');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
static deactivated(accountId: string) {
|
|
14
|
+
return AccountError.refusal('ACCOUNT_DEACTIVATED', `The account ${accountId} is deactivated.`, { accountId });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static alreadyDeactivated(accountId: string) {
|
|
18
|
+
return AccountError.refusal('ACCOUNT_ALREADY_DEACTIVATED', `The account ${accountId} is already deactivated.`, {
|
|
19
|
+
accountId,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static emailNotVerified(accountId: string) {
|
|
24
|
+
return AccountError.refusal(
|
|
25
|
+
'EMAIL_NOT_VERIFIED',
|
|
26
|
+
'The identity provider has not verified the email address of this person: they verify it, then sign in again.',
|
|
27
|
+
{ accountId },
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static invalidEmailAddress(raw: string) {
|
|
32
|
+
return AccountError.refusal('INVALID_EMAIL_ADDRESS', 'An email address is a local part, an @ and a domain.', {
|
|
33
|
+
raw,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static invalidDisplayName(raw: string) {
|
|
38
|
+
return AccountError.refusal('INVALID_DISPLAY_NAME', 'A display name holds between 1 and 100 characters.', { raw });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ConceptError } from '@ddd-ts-kit/kernel';
|
|
2
|
+
|
|
3
|
+
/** What the delegations refuse: a member lends some of their rights to another, for a bounded time. */
|
|
4
|
+
export class DelegationError extends ConceptError {
|
|
5
|
+
static notFound(delegationId: string) {
|
|
6
|
+
return DelegationError.refusal('DELEGATION_NOT_FOUND', `No delegation ${delegationId}.`, {
|
|
7
|
+
delegationId,
|
|
8
|
+
}).exposing('delegationId');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
static notActive(delegationId: string) {
|
|
12
|
+
return DelegationError.refusal('DELEGATION_NOT_ACTIVE', `The delegation ${delegationId} already ended.`, {
|
|
13
|
+
delegationId,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static toOneself(accountId: string) {
|
|
18
|
+
return DelegationError.refusal('DELEGATION_TO_ONESELF', 'A member delegates to another member.', { accountId });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static withoutRights() {
|
|
22
|
+
return DelegationError.refusal('DELEGATION_WITHOUT_RIGHTS', 'A delegation lends at least one right.');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static beyondRights(right: string) {
|
|
26
|
+
return DelegationError.refusal('DELEGATION_BEYOND_RIGHTS', `A member lends only the rights they hold: ${right}.`, {
|
|
27
|
+
right,
|
|
28
|
+
}).exposing('right');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static periodInverted(startsAt: Date, endsAt: Date) {
|
|
32
|
+
return DelegationError.refusal('DELEGATION_PERIOD_INVERTED', 'A delegation ends after it starts.', {
|
|
33
|
+
startsAt,
|
|
34
|
+
endsAt,
|
|
35
|
+
}).exposing('startsAt', 'endsAt');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static tooLong(longestDays: number) {
|
|
39
|
+
return DelegationError.refusal(
|
|
40
|
+
'DELEGATION_TOO_LONG',
|
|
41
|
+
`A delegation lasts ${longestDays} days at most: a longer one is a role.`,
|
|
42
|
+
{ longestDays },
|
|
43
|
+
).exposing('longestDays');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ConceptError } from '@ddd-ts-kit/kernel';
|
|
2
|
+
|
|
3
|
+
/** What the invitations refuse. The token of an invitation is never a fact of a refusal. */
|
|
4
|
+
export class InvitationError extends ConceptError {
|
|
5
|
+
static notFound() {
|
|
6
|
+
return InvitationError.refusal('INVITATION_NOT_FOUND', 'No invitation answers this token or this identifier.');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
static expired(invitationId: string, expiresAt: Date) {
|
|
10
|
+
return InvitationError.refusal('INVITATION_EXPIRED', `The invitation ${invitationId} expired.`, {
|
|
11
|
+
invitationId,
|
|
12
|
+
expiresAt,
|
|
13
|
+
}).exposing('expiresAt');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static notPending(invitationId: string, status: string) {
|
|
17
|
+
return InvitationError.refusal('INVITATION_NOT_PENDING', `The invitation ${invitationId} is already ${status}.`, {
|
|
18
|
+
invitationId,
|
|
19
|
+
status,
|
|
20
|
+
}).exposing('status');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static addressedToAnother(invitationId: string) {
|
|
24
|
+
return InvitationError.refusal(
|
|
25
|
+
'INVITATION_ADDRESSED_TO_ANOTHER',
|
|
26
|
+
`The invitation ${invitationId} is addressed to another email address than the account's.`,
|
|
27
|
+
{ invitationId },
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ConceptError } from '@ddd-ts-kit/kernel';
|
|
2
|
+
|
|
3
|
+
/** What the members of an organisation refuse. */
|
|
4
|
+
export class MemberError extends ConceptError {
|
|
5
|
+
static notFound(organisationId: string, accountId: string) {
|
|
6
|
+
return MemberError.refusal('MEMBER_NOT_FOUND', `The account ${accountId} is not a member of ${organisationId}.`, {
|
|
7
|
+
organisationId,
|
|
8
|
+
accountId,
|
|
9
|
+
}).exposing('organisationId', 'accountId');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
static alreadyMember(organisationId: string, accountId: string) {
|
|
13
|
+
return MemberError.refusal('ALREADY_MEMBER', `The account ${accountId} is already a member of ${organisationId}.`, {
|
|
14
|
+
organisationId,
|
|
15
|
+
accountId,
|
|
16
|
+
}).exposing('organisationId', 'accountId');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static lastOwner(organisationId: string) {
|
|
20
|
+
return MemberError.refusal('LAST_OWNER', `${organisationId} keeps at least one owner.`, {
|
|
21
|
+
organisationId,
|
|
22
|
+
}).exposing('organisationId');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static ownersOnly(organisationId: string) {
|
|
26
|
+
return MemberError.refusal('OWNERS_ONLY', `Only an owner of ${organisationId} appoints or changes an owner.`, {
|
|
27
|
+
organisationId,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static ownRole(organisationId: string) {
|
|
32
|
+
return MemberError.refusal(
|
|
33
|
+
'OWN_ROLE',
|
|
34
|
+
`A member of ${organisationId} does not change their own role: another member does.`,
|
|
35
|
+
{
|
|
36
|
+
organisationId,
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static aboveOwnRole(organisationId: string) {
|
|
42
|
+
return MemberError.refusal(
|
|
43
|
+
'ABOVE_OWN_ROLE',
|
|
44
|
+
`A member of ${organisationId} appoints, changes or removes no one above their own role.`,
|
|
45
|
+
{
|
|
46
|
+
organisationId,
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ConceptError } from '@ddd-ts-kit/kernel';
|
|
2
|
+
|
|
3
|
+
/** What the organisations refuse: an organisation is a group of accounts, and the tenant of its data when the project has tenants. */
|
|
4
|
+
export class OrganisationError extends ConceptError {
|
|
5
|
+
static notFound(organisationId: string) {
|
|
6
|
+
return OrganisationError.refusal('ORGANISATION_NOT_FOUND', `No organisation ${organisationId}.`, {
|
|
7
|
+
organisationId,
|
|
8
|
+
}).exposing('organisationId');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
static slugTaken(slug: string) {
|
|
12
|
+
return OrganisationError.refusal('ORGANISATION_SLUG_TAKEN', `An organisation is already named ${slug}.`, {
|
|
13
|
+
slug,
|
|
14
|
+
}).exposing('slug');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static invalidOrganisationName(raw: string) {
|
|
18
|
+
return OrganisationError.refusal(
|
|
19
|
+
'INVALID_ORGANISATION_NAME',
|
|
20
|
+
'The name of an organisation holds between 1 and 100 characters.',
|
|
21
|
+
{ raw },
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static invalidOrganisationSlug(raw: string) {
|
|
26
|
+
return OrganisationError.refusal(
|
|
27
|
+
'INVALID_ORGANISATION_SLUG',
|
|
28
|
+
'A slug is 2 to 63 lower-case letters, digits and hyphens, starting with a letter or a digit.',
|
|
29
|
+
{ raw },
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DomainEvent } from '@ddd-ts-kit/kernel';
|
|
2
|
+
|
|
3
|
+
/** An account was deactivated: its person signs in no more. */
|
|
4
|
+
export class AccountDeactivated implements DomainEvent {
|
|
5
|
+
static readonly eventName = '{{context.kebab}}.account.deactivated';
|
|
6
|
+
|
|
7
|
+
readonly name = AccountDeactivated.eventName;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
readonly aggregateId: string,
|
|
11
|
+
readonly occurredAt: Date,
|
|
12
|
+
) {}
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DomainEvent } from '@ddd-ts-kit/kernel';
|
|
2
|
+
|
|
3
|
+
/** An account was provisioned at the first sign-in of its person. */
|
|
4
|
+
export class AccountProvisioned implements DomainEvent {
|
|
5
|
+
static readonly eventName = '{{context.kebab}}.account.provisioned';
|
|
6
|
+
|
|
7
|
+
readonly name = AccountProvisioned.eventName;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
readonly aggregateId: string,
|
|
11
|
+
readonly occurredAt: Date,
|
|
12
|
+
readonly facts: {
|
|
13
|
+
readonly email: string;
|
|
14
|
+
readonly displayName: string;
|
|
15
|
+
},
|
|
16
|
+
) {}
|
|
17
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DomainEvent } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import type { MemberRight } from '{{alias.context}}/domain/vocabularies/member-right.vocabulary{{alias.ext}}';
|
|
3
|
+
|
|
4
|
+
/** A member lent some of their rights to another, for a period. */
|
|
5
|
+
export class DelegationGranted implements DomainEvent {
|
|
6
|
+
static readonly eventName = '{{context.kebab}}.delegation.granted';
|
|
7
|
+
|
|
8
|
+
readonly name = DelegationGranted.eventName;
|
|
9
|
+
|
|
10
|
+
constructor(
|
|
11
|
+
readonly aggregateId: string,
|
|
12
|
+
readonly occurredAt: Date,
|
|
13
|
+
readonly facts: {
|
|
14
|
+
readonly organisationId: string;
|
|
15
|
+
readonly delegatorId: string;
|
|
16
|
+
readonly delegateId: string;
|
|
17
|
+
readonly rights: readonly MemberRight[];
|
|
18
|
+
readonly startsAt: Date;
|
|
19
|
+
readonly endsAt: Date;
|
|
20
|
+
},
|
|
21
|
+
) {}
|
|
22
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DomainEvent } from '@ddd-ts-kit/kernel';
|
|
2
|
+
|
|
3
|
+
/** A delegation ended before its period: revoked, or its delegator lost the standing it was granted with. */
|
|
4
|
+
export class DelegationRevoked implements DomainEvent {
|
|
5
|
+
static readonly eventName = '{{context.kebab}}.delegation.revoked';
|
|
6
|
+
|
|
7
|
+
readonly name = DelegationRevoked.eventName;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
readonly aggregateId: string,
|
|
11
|
+
readonly occurredAt: Date,
|
|
12
|
+
readonly facts: {
|
|
13
|
+
readonly organisationId: string;
|
|
14
|
+
readonly delegatorId: string;
|
|
15
|
+
readonly delegateId: string;
|
|
16
|
+
},
|
|
17
|
+
) {}
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DomainEvent } from '@ddd-ts-kit/kernel';
|
|
2
|
+
|
|
3
|
+
/** The person an invitation was addressed to accepted it. */
|
|
4
|
+
export class InvitationAccepted implements DomainEvent {
|
|
5
|
+
static readonly eventName = '{{context.kebab}}.invitation.accepted';
|
|
6
|
+
|
|
7
|
+
readonly name = InvitationAccepted.eventName;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
readonly aggregateId: string,
|
|
11
|
+
readonly occurredAt: Date,
|
|
12
|
+
readonly facts: {
|
|
13
|
+
readonly organisationId: string;
|
|
14
|
+
readonly accountId: string;
|
|
15
|
+
},
|
|
16
|
+
) {}
|
|
17
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DomainEvent } from '@ddd-ts-kit/kernel';
|
|
2
|
+
|
|
3
|
+
/** The person an invitation was addressed to declined it. */
|
|
4
|
+
export class InvitationDeclined implements DomainEvent {
|
|
5
|
+
static readonly eventName = '{{context.kebab}}.invitation.declined';
|
|
6
|
+
|
|
7
|
+
readonly name = InvitationDeclined.eventName;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
readonly aggregateId: string,
|
|
11
|
+
readonly occurredAt: Date,
|
|
12
|
+
readonly facts: {
|
|
13
|
+
readonly organisationId: string;
|
|
14
|
+
},
|
|
15
|
+
) {}
|
|
16
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DomainEvent } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import type { MemberRole } from '{{alias.context}}/domain/vocabularies/member-role.vocabulary{{alias.ext}}';
|
|
3
|
+
|
|
4
|
+
/** An invitation was issued to an email address. */
|
|
5
|
+
export class InvitationIssued implements DomainEvent {
|
|
6
|
+
static readonly eventName = '{{context.kebab}}.invitation.issued';
|
|
7
|
+
|
|
8
|
+
readonly name = InvitationIssued.eventName;
|
|
9
|
+
|
|
10
|
+
constructor(
|
|
11
|
+
readonly aggregateId: string,
|
|
12
|
+
readonly occurredAt: Date,
|
|
13
|
+
readonly facts: {
|
|
14
|
+
readonly organisationId: string;
|
|
15
|
+
readonly email: string;
|
|
16
|
+
readonly role: MemberRole;
|
|
17
|
+
readonly expiresAt: Date;
|
|
18
|
+
/** The delegation that lent the right to invite, when the role of the inviter did not grant it. */
|
|
19
|
+
readonly delegationId?: string;
|
|
20
|
+
},
|
|
21
|
+
) {}
|
|
22
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DomainEvent } from '@ddd-ts-kit/kernel';
|
|
2
|
+
|
|
3
|
+
/** The organisation took an invitation back before it was answered. */
|
|
4
|
+
export class InvitationRevoked implements DomainEvent {
|
|
5
|
+
static readonly eventName = '{{context.kebab}}.invitation.revoked';
|
|
6
|
+
|
|
7
|
+
readonly name = InvitationRevoked.eventName;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
readonly aggregateId: string,
|
|
11
|
+
readonly occurredAt: Date,
|
|
12
|
+
readonly facts: {
|
|
13
|
+
readonly organisationId: string;
|
|
14
|
+
},
|
|
15
|
+
) {}
|
|
16
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DomainEvent } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import type { MemberRole } from '{{alias.context}}/domain/vocabularies/member-role.vocabulary{{alias.ext}}';
|
|
3
|
+
|
|
4
|
+
/** An account became a member of an organisation, in a role. */
|
|
5
|
+
export class MemberJoined implements DomainEvent {
|
|
6
|
+
static readonly eventName = '{{context.kebab}}.member.joined';
|
|
7
|
+
|
|
8
|
+
readonly name = MemberJoined.eventName;
|
|
9
|
+
|
|
10
|
+
constructor(
|
|
11
|
+
readonly aggregateId: string,
|
|
12
|
+
readonly occurredAt: Date,
|
|
13
|
+
readonly facts: {
|
|
14
|
+
readonly organisationId: string;
|
|
15
|
+
readonly accountId: string;
|
|
16
|
+
readonly role: MemberRole;
|
|
17
|
+
},
|
|
18
|
+
) {}
|
|
19
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DomainEvent } from '@ddd-ts-kit/kernel';
|
|
2
|
+
|
|
3
|
+
/** A member left an organisation, or was removed from it. */
|
|
4
|
+
export class MemberRemoved implements DomainEvent {
|
|
5
|
+
static readonly eventName = '{{context.kebab}}.member.removed';
|
|
6
|
+
|
|
7
|
+
readonly name = MemberRemoved.eventName;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
readonly aggregateId: string,
|
|
11
|
+
readonly occurredAt: Date,
|
|
12
|
+
readonly facts: {
|
|
13
|
+
readonly organisationId: string;
|
|
14
|
+
readonly accountId: string;
|
|
15
|
+
/** The delegation that lent the right to decide it, when the role of who decided did not grant it. */
|
|
16
|
+
readonly delegationId?: string;
|
|
17
|
+
},
|
|
18
|
+
) {}
|
|
19
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DomainEvent } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import type { MemberRole } from '{{alias.context}}/domain/vocabularies/member-role.vocabulary{{alias.ext}}';
|
|
3
|
+
|
|
4
|
+
/** A member holds another role: what they may do in the organisation follows from it from now on. */
|
|
5
|
+
export class MemberRoleChanged implements DomainEvent {
|
|
6
|
+
static readonly eventName = '{{context.kebab}}.member.role-changed';
|
|
7
|
+
|
|
8
|
+
readonly name = MemberRoleChanged.eventName;
|
|
9
|
+
|
|
10
|
+
constructor(
|
|
11
|
+
readonly aggregateId: string,
|
|
12
|
+
readonly occurredAt: Date,
|
|
13
|
+
readonly facts: {
|
|
14
|
+
readonly organisationId: string;
|
|
15
|
+
readonly accountId: string;
|
|
16
|
+
readonly from: MemberRole;
|
|
17
|
+
readonly to: MemberRole;
|
|
18
|
+
/** The delegation that lent the right to decide it, when the role of who decided did not grant it. */
|
|
19
|
+
readonly delegationId?: string;
|
|
20
|
+
},
|
|
21
|
+
) {}
|
|
22
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DomainEvent } from '@ddd-ts-kit/kernel';
|
|
2
|
+
|
|
3
|
+
/** An organisation was opened, its opener its first owner. */
|
|
4
|
+
export class OrganisationOpened implements DomainEvent {
|
|
5
|
+
static readonly eventName = '{{context.kebab}}.organisation.opened';
|
|
6
|
+
|
|
7
|
+
readonly name = OrganisationOpened.eventName;
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
readonly aggregateId: string,
|
|
11
|
+
readonly occurredAt: Date,
|
|
12
|
+
readonly facts: {
|
|
13
|
+
readonly name: string;
|
|
14
|
+
readonly openedBy: string;
|
|
15
|
+
},
|
|
16
|
+
) {}
|
|
17
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Repository } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import type { Account } from '{{alias.context}}/domain/aggregates/account.aggregate{{alias.ext}}';
|
|
3
|
+
|
|
4
|
+
/** The accounts, by the subject the identity provider gives each person. */
|
|
5
|
+
export abstract class AccountRepository extends Repository<Account> {}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Repository } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import type { Delegation } from '{{alias.context}}/domain/aggregates/delegation.aggregate{{alias.ext}}';
|
|
3
|
+
|
|
4
|
+
export abstract class DelegationRepository extends Repository<Delegation> {
|
|
5
|
+
/** The delegations not ended yet that lend rights to this member of the organisation, started or not. */
|
|
6
|
+
abstract findUnendedTo(organisationId: string, delegateId: string): Promise<readonly Delegation[]>;
|
|
7
|
+
|
|
8
|
+
/** The delegations not ended yet that this member of the organisation gave or received. */
|
|
9
|
+
abstract findUnendedInvolving(organisationId: string, accountId: string): Promise<readonly Delegation[]>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Repository } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import type { Invitation } from '{{alias.context}}/domain/aggregates/invitation.aggregate{{alias.ext}}';
|
|
3
|
+
|
|
4
|
+
export abstract class InvitationRepository extends Repository<Invitation> {
|
|
5
|
+
/** The invitation whose token has this digest. */
|
|
6
|
+
abstract findByTokenHash(tokenHash: string): Promise<Invitation | undefined>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Repository } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import type { Member } from '{{alias.context}}/domain/aggregates/member.aggregate{{alias.ext}}';
|
|
3
|
+
|
|
4
|
+
export abstract class MemberRepository extends Repository<Member> {
|
|
5
|
+
/** The current membership of an account in an organisation: there is at most one. */
|
|
6
|
+
abstract findOf(organisationId: string, accountId: string): Promise<Member | undefined>;
|
|
7
|
+
|
|
8
|
+
/** The current memberships of an account, in every organisation. */
|
|
9
|
+
abstract searchCurrentOf(accountId: string): Promise<readonly Member[]>;
|
|
10
|
+
|
|
11
|
+
/** How many current members of the organisation are owners. */
|
|
12
|
+
abstract countOwners(organisationId: string): Promise<number>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Repository } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import type { Organisation } from '{{alias.context}}/domain/aggregates/organisation.aggregate{{alias.ext}}';
|
|
3
|
+
|
|
4
|
+
/** The organisations, by their slug. */
|
|
5
|
+
export abstract class OrganisationRepository extends Repository<Organisation> {}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Delegation } from '{{alias.context}}/domain/aggregates/delegation.aggregate{{alias.ext}}';
|
|
2
|
+
import type { Member } from '{{alias.context}}/domain/aggregates/member.aggregate{{alias.ext}}';
|
|
3
|
+
import { OrganisationRights } from '{{alias.context}}/domain/value-objects/organisation-rights.vo{{alias.ext}}';
|
|
4
|
+
import { MemberRight } from '{{alias.context}}/domain/vocabularies/member-right.vocabulary{{alias.ext}}';
|
|
5
|
+
import { MemberRole } from '{{alias.context}}/domain/vocabularies/member-role.vocabulary{{alias.ext}}';
|
|
6
|
+
|
|
7
|
+
/** What each role grants. Changing a role here changes what every member of that role may do. */
|
|
8
|
+
const GRANTED: Readonly<Record<MemberRole, readonly MemberRight[]>> = {
|
|
9
|
+
[MemberRole.Owner]: [
|
|
10
|
+
MemberRight.ReadMembers,
|
|
11
|
+
MemberRight.InviteMembers,
|
|
12
|
+
MemberRight.ManageMembers,
|
|
13
|
+
MemberRight.GrantDelegations,
|
|
14
|
+
],
|
|
15
|
+
[MemberRole.Admin]: [MemberRight.ReadMembers, MemberRight.InviteMembers, MemberRight.ManageMembers],
|
|
16
|
+
[MemberRole.Member]: [MemberRight.ReadMembers],
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/** What an account holds in an organisation at an instant: its membership, the delegations lent to it. */
|
|
20
|
+
export interface HeldRights {
|
|
21
|
+
readonly member: Member | undefined;
|
|
22
|
+
readonly lent: readonly Delegation[];
|
|
23
|
+
readonly now: Date;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** The rights of the roles, and what an account may do in an organisation once its delegations are counted. */
|
|
27
|
+
export class RoleRightsService {
|
|
28
|
+
rightsOf(role: MemberRole): readonly MemberRight[] {
|
|
29
|
+
return GRANTED[role];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The rights of an account in an organisation at `now`: none without a current membership (a
|
|
34
|
+
* member removed, or whose account was deactivated, which ends its memberships), those of its
|
|
35
|
+
* role otherwise, plus those every delegation active at `now` lends it there.
|
|
36
|
+
*/
|
|
37
|
+
rightsIn(organisationId: string, accountId: string, held: HeldRights): OrganisationRights {
|
|
38
|
+
if (!held.member?.isActive) {
|
|
39
|
+
return OrganisationRights.of(organisationId, accountId, []);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const lent = activeAt(held).flatMap((given) => given.rights);
|
|
43
|
+
|
|
44
|
+
return OrganisationRights.of(organisationId, accountId, [...GRANTED[held.member.role], ...lent]);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** The delegation `right` is used under, when the role of the member does not grant it: what the facts it leads to name. */
|
|
48
|
+
delegationUsedFor(right: MemberRight, held: HeldRights): string | undefined {
|
|
49
|
+
if (held.member === undefined || GRANTED[held.member.role].includes(right)) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return activeAt(held).find((given) => given.rights.includes(right))?.id;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function activeAt(held: HeldRights): readonly Delegation[] {
|
|
58
|
+
return held.lent.filter((delegation) => delegation.isActiveAt(held.now));
|
|
59
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ValueObject } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { DelegationError } from '{{alias.context}}/domain/errors/delegation.error{{alias.ext}}';
|
|
3
|
+
|
|
4
|
+
/** A delegation is a stand-in for an absence: past this, the right belongs in a role. */
|
|
5
|
+
const LONGEST_DAYS = 90;
|
|
6
|
+
const DAY_MS = 86_400_000;
|
|
7
|
+
|
|
8
|
+
export type DelegationPeriodProps = {
|
|
9
|
+
readonly startsAt: Date;
|
|
10
|
+
readonly endsAt: Date;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/** When a delegation holds: from its start, included, to its end, excluded, for at most ninety days. */
|
|
14
|
+
export class DelegationPeriod extends ValueObject<DelegationPeriodProps> {
|
|
15
|
+
private constructor(props: DelegationPeriodProps) {
|
|
16
|
+
super(props);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static create(startsAt: Date, endsAt: Date): DelegationPeriod {
|
|
20
|
+
if (endsAt.getTime() <= startsAt.getTime()) {
|
|
21
|
+
throw DelegationError.periodInverted(startsAt, endsAt);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (endsAt.getTime() - startsAt.getTime() > LONGEST_DAYS * DAY_MS) {
|
|
25
|
+
throw DelegationError.tooLong(LONGEST_DAYS);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return new DelegationPeriod({ startsAt, endsAt });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
includes(instant: Date): boolean {
|
|
32
|
+
return this.props.startsAt.getTime() <= instant.getTime() && instant.getTime() < this.props.endsAt.getTime();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get startsAt(): Date {
|
|
36
|
+
return this.props.startsAt;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get endsAt(): Date {
|
|
40
|
+
return this.props.endsAt;
|
|
41
|
+
}
|
|
42
|
+
}
|