@webiny/api-core 6.4.11 → 6.6.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ApiCoreFeature.d.ts +2 -2
- package/ApiCoreFeature.js +29 -5
- package/ApiCoreFeature.js.map +1 -1
- package/exports/api/security/api-key.d.ts +1 -0
- package/exports/api/security/api-key.js +1 -0
- package/exports/api.d.ts +3 -1
- package/exports/api.js +2 -1
- package/features/ai/Ai.d.ts +3 -3
- package/features/ai/Ai.js +60 -23
- package/features/ai/Ai.js.map +1 -1
- package/features/ai/AnthropicSdkFactory.js +12 -0
- package/features/ai/AnthropicSdkFactory.js.map +1 -1
- package/features/ai/OpenAiSdkFactory.js +16 -0
- package/features/ai/OpenAiSdkFactory.js.map +1 -1
- package/features/ai/TextExtractor/DefaultTextExtractor.d.ts +9 -0
- package/features/ai/TextExtractor/DefaultTextExtractor.js +28 -0
- package/features/ai/TextExtractor/DefaultTextExtractor.js.map +1 -0
- package/features/ai/TextExtractor/abstractions.d.ts +12 -0
- package/features/ai/TextExtractor/abstractions.js +5 -0
- package/features/ai/TextExtractor/abstractions.js.map +1 -0
- package/features/ai/TextExtractor/index.d.ts +3 -0
- package/features/ai/TextExtractor/index.js +2 -0
- package/features/ai/TextExtractor/parsers/docxParser.d.ts +1 -0
- package/features/ai/TextExtractor/parsers/docxParser.js +111 -0
- package/features/ai/TextExtractor/parsers/docxParser.js.map +1 -0
- package/features/ai/abstractions.d.ts +18 -7
- package/features/ai/abstractions.js +1 -2
- package/features/ai/abstractions.js.map +1 -1
- package/features/ai/events.d.ts +59 -0
- package/features/ai/events.js +41 -0
- package/features/ai/events.js.map +1 -0
- package/features/ai/feature.js +6 -2
- package/features/ai/feature.js.map +1 -1
- package/features/ai/index.d.ts +8 -2
- package/features/ai/index.js +4 -1
- package/features/ai/toolPipeline/AiOutputToolRegistry.d.ts +11 -0
- package/features/ai/toolPipeline/AiOutputToolRegistry.js +31 -0
- package/features/ai/toolPipeline/AiOutputToolRegistry.js.map +1 -0
- package/features/ai/toolPipeline/AiToolPipelineRunner.d.ts +10 -0
- package/features/ai/toolPipeline/AiToolPipelineRunner.js +36 -0
- package/features/ai/toolPipeline/AiToolPipelineRunner.js.map +1 -0
- package/features/ai/toolPipeline/abstractions.d.ts +23 -0
- package/features/ai/toolPipeline/abstractions.js +7 -0
- package/features/ai/toolPipeline/abstractions.js.map +1 -0
- package/features/ai/toolPipeline/index.d.ts +2 -0
- package/features/ai/toolPipeline/index.js +1 -0
- package/features/dateFormatter/DefaultDateFormatter.d.ts +15 -0
- package/features/dateFormatter/DefaultDateFormatter.js +20 -0
- package/features/dateFormatter/DefaultDateFormatter.js.map +1 -0
- package/features/dateFormatter/abstractions.d.ts +13 -0
- package/features/dateFormatter/abstractions.js +5 -0
- package/features/dateFormatter/abstractions.js.map +1 -0
- package/features/dateFormatter/feature.d.ts +4 -0
- package/features/dateFormatter/feature.js +11 -0
- package/features/dateFormatter/feature.js.map +1 -0
- package/features/dateFormatter/index.d.ts +3 -0
- package/features/dateFormatter/index.js +2 -0
- package/features/featureFlags/decorators/FeatureFlagsWithLicenseDecorator.d.ts +13 -0
- package/features/featureFlags/decorators/FeatureFlagsWithLicenseDecorator.js +49 -0
- package/features/featureFlags/decorators/FeatureFlagsWithLicenseDecorator.js.map +1 -0
- package/features/hashing/ScryptHasher.d.ts +11 -0
- package/features/hashing/ScryptHasher.js +74 -0
- package/features/hashing/ScryptHasher.js.map +1 -0
- package/features/hashing/abstractions.d.ts +18 -0
- package/features/hashing/abstractions.js +5 -0
- package/features/hashing/abstractions.js.map +1 -0
- package/features/hashing/feature.d.ts +4 -0
- package/features/hashing/feature.js +11 -0
- package/features/hashing/feature.js.map +1 -0
- package/features/hashing/index.d.ts +2 -0
- package/features/hashing/index.js +1 -0
- package/features/requestContext/RawAuthToken.d.ts +14 -0
- package/features/requestContext/RawAuthToken.js +19 -0
- package/features/requestContext/RawAuthToken.js.map +1 -0
- package/features/requestContext/RawTenantId.d.ts +14 -0
- package/features/requestContext/RawTenantId.js +19 -0
- package/features/requestContext/RawTenantId.js.map +1 -0
- package/features/requestContext/RequestIdentityLoader.d.ts +19 -0
- package/features/requestContext/RequestIdentityLoader.js +26 -0
- package/features/requestContext/RequestIdentityLoader.js.map +1 -0
- package/features/requestContext/RequestTenantLoader.d.ts +18 -0
- package/features/requestContext/RequestTenantLoader.js +52 -0
- package/features/requestContext/RequestTenantLoader.js.map +1 -0
- package/features/requestContext/abstractions.d.ts +53 -0
- package/features/requestContext/abstractions.js +8 -0
- package/features/requestContext/abstractions.js.map +1 -0
- package/features/requestContext/feature.d.ts +11 -0
- package/features/requestContext/feature.js +17 -0
- package/features/requestContext/feature.js.map +1 -0
- package/features/requestContext/index.d.ts +2 -0
- package/features/requestContext/index.js +2 -0
- package/features/security/IdentityContext/IdentityContext.d.ts +3 -3
- package/features/security/IdentityContext/IdentityContext.js +6 -6
- package/features/security/IdentityContext/IdentityContext.js.map +1 -1
- package/features/security/apiKeys/ApiKeyAuthenticator.d.ts +14 -0
- package/features/security/apiKeys/ApiKeyAuthenticator.js +36 -0
- package/features/security/apiKeys/ApiKeyAuthenticator.js.map +1 -0
- package/features/security/apiKeys/ApiKeyAuthorizer.d.ts +10 -0
- package/features/security/apiKeys/ApiKeyAuthorizer.js +15 -0
- package/features/security/apiKeys/ApiKeyAuthorizer.js.map +1 -0
- package/features/security/apiKeys/CreateApiKey/CreateApiKeyUseCase.js +11 -6
- package/features/security/apiKeys/CreateApiKey/CreateApiKeyUseCase.js.map +1 -1
- package/features/security/apiKeys/GetApiKey/GetApiKeyUseCase.d.ts +1 -1
- package/features/security/apiKeys/GetApiKey/GetApiKeyUseCase.js.map +1 -1
- package/features/security/apiKeys/GetApiKeyBySlug/GetApiKeyBySlugUseCase.d.ts +1 -3
- package/features/security/apiKeys/GetApiKeyBySlug/GetApiKeyBySlugUseCase.js.map +1 -1
- package/features/security/apiKeys/GetApiKeyBySlug/abstractions.d.ts +1 -1
- package/features/security/apiKeys/GetApiKeyBySlug/abstractions.js.map +1 -1
- package/features/security/apiKeys/GetApiKeyByToken/GetApiKeyByTokenUseCase.d.ts +1 -3
- package/features/security/apiKeys/GetApiKeyByToken/GetApiKeyByTokenUseCase.js.map +1 -1
- package/features/security/apiKeys/GetApiKeyByToken/abstractions.d.ts +1 -1
- package/features/security/apiKeys/GetApiKeyByToken/abstractions.js.map +1 -1
- package/features/security/apiKeys/UpdateApiKey/UpdateApiKeyUseCase.js +9 -3
- package/features/security/apiKeys/UpdateApiKey/UpdateApiKeyUseCase.js.map +1 -1
- package/features/security/apiKeys/feature.js +11 -2
- package/features/security/apiKeys/feature.js.map +1 -1
- package/features/security/apiKeys/shared/ApiKeyProvider.d.ts +3 -5
- package/features/security/apiKeys/shared/ApiKeyProvider.js +6 -21
- package/features/security/apiKeys/shared/ApiKeyProvider.js.map +1 -1
- package/features/security/apiKeys/shared/ApiKeysRepository.d.ts +1 -0
- package/features/security/apiKeys/shared/ApiKeysRepository.js +19 -4
- package/features/security/apiKeys/shared/ApiKeysRepository.js.map +1 -1
- package/features/security/apiKeys/shared/generateToken.d.ts +1 -1
- package/features/security/apiKeys/shared/generateToken.js.map +1 -1
- package/features/security/apiKeys/shared/schemas.d.ts +2 -2
- package/features/security/apiKeys/shared/schemas.js +2 -2
- package/features/security/apiKeys/shared/schemas.js.map +1 -1
- package/features/security/apiKeys/shared/types.d.ts +1 -1
- package/features/security/authorization/GroupsTeamsAuthorizer/GetPermissionsFromIdentity.d.ts +4 -4
- package/features/security/authorization/GroupsTeamsAuthorizer/GetPermissionsFromIdentity.js +5 -5
- package/features/security/authorization/GroupsTeamsAuthorizer/GetPermissionsFromIdentity.js.map +1 -1
- package/features/security/roles/CreateRole/CreateRoleUseCase.js +11 -6
- package/features/security/roles/CreateRole/CreateRoleUseCase.js.map +1 -1
- package/features/security/roles/CreateRole/schema.d.ts +1 -1
- package/features/security/roles/CreateRole/schema.js +1 -1
- package/features/security/roles/CreateRole/schema.js.map +1 -1
- package/features/security/roles/Installer/RolesInstaller.js +0 -1
- package/features/security/roles/Installer/RolesInstaller.js.map +1 -1
- package/features/security/roles/UpdateRole/UpdateRoleUseCase.js +9 -3
- package/features/security/roles/UpdateRole/UpdateRoleUseCase.js.map +1 -1
- package/features/security/roles/UpdateRole/schema.d.ts +1 -1
- package/features/security/roles/UpdateRole/schema.js +1 -1
- package/features/security/roles/UpdateRole/schema.js.map +1 -1
- package/features/security/shared/description.d.ts +4 -0
- package/features/security/shared/description.js +7 -0
- package/features/security/shared/description.js.map +1 -0
- package/features/security/shared/index.d.ts +1 -0
- package/features/security/shared/index.js +1 -0
- package/features/security/teams/CreateTeam/CreateTeamUseCase.d.ts +3 -1
- package/features/security/teams/CreateTeam/CreateTeamUseCase.js +20 -8
- package/features/security/teams/CreateTeam/CreateTeamUseCase.js.map +1 -1
- package/features/security/teams/CreateTeam/schema.d.ts +1 -1
- package/features/security/teams/CreateTeam/schema.js +1 -1
- package/features/security/teams/CreateTeam/schema.js.map +1 -1
- package/features/security/teams/UpdateTeam/UpdateTeamUseCase.d.ts +3 -1
- package/features/security/teams/UpdateTeam/UpdateTeamUseCase.js +20 -5
- package/features/security/teams/UpdateTeam/UpdateTeamUseCase.js.map +1 -1
- package/features/security/teams/UpdateTeam/schema.d.ts +1 -1
- package/features/security/teams/UpdateTeam/schema.js +1 -1
- package/features/security/teams/UpdateTeam/schema.js.map +1 -1
- package/features/security/teams/shared/resolveRoleIdentifiers.d.ts +17 -0
- package/features/security/teams/shared/resolveRoleIdentifiers.js +32 -0
- package/features/security/teams/shared/resolveRoleIdentifiers.js.map +1 -0
- package/features/security/utils/getPermissionsFromRoles.d.ts +1 -1
- package/features/serviceDiscovery/ServiceDiscovery.d.ts +17 -0
- package/features/serviceDiscovery/ServiceDiscovery.js +22 -0
- package/features/serviceDiscovery/ServiceDiscovery.js.map +1 -0
- package/features/serviceDiscovery/__tests__/ServiceDiscovery.test.d.ts +1 -0
- package/features/serviceDiscovery/__tests__/ServiceDiscovery.test.js +111 -0
- package/features/serviceDiscovery/__tests__/ServiceDiscovery.test.js.map +1 -0
- package/features/serviceDiscovery/index.d.ts +3 -0
- package/features/serviceDiscovery/index.js +1 -0
- package/features/slugify/DefaultSlugify.d.ts +8 -0
- package/features/slugify/DefaultSlugify.js +20 -0
- package/features/slugify/DefaultSlugify.js.map +1 -0
- package/features/slugify/abstractions.d.ts +12 -0
- package/features/slugify/abstractions.js +5 -0
- package/features/slugify/abstractions.js.map +1 -0
- package/features/slugify/feature.d.ts +4 -0
- package/features/slugify/feature.js +11 -0
- package/features/slugify/feature.js.map +1 -0
- package/features/slugify/index.d.ts +3 -0
- package/features/slugify/index.js +2 -0
- package/features/storageOperations/abstractions.d.ts +21 -0
- package/features/storageOperations/abstractions.js +10 -0
- package/features/storageOperations/abstractions.js.map +1 -0
- package/features/stringFormatter/DefaultStringFormatter.d.ts +17 -0
- package/features/stringFormatter/DefaultStringFormatter.js +19 -0
- package/features/stringFormatter/DefaultStringFormatter.js.map +1 -0
- package/features/stringFormatter/abstractions.d.ts +11 -0
- package/features/stringFormatter/abstractions.js +5 -0
- package/features/stringFormatter/abstractions.js.map +1 -0
- package/features/stringFormatter/feature.d.ts +4 -0
- package/features/stringFormatter/feature.js +13 -0
- package/features/stringFormatter/feature.js.map +1 -0
- package/features/stringFormatter/index.d.ts +3 -0
- package/features/stringFormatter/index.js +2 -0
- package/features/task/TaskDefinition/abstractions.d.ts +76 -4
- package/features/task/TaskDefinition/abstractions.js +2 -1
- package/features/task/TaskDefinition/abstractions.js.map +1 -1
- package/features/tenancy/CreateTenant/CreateTenantUseCase.d.ts +1 -1
- package/features/tenancy/InstallTenant/InstallTenantUseCase.d.ts +1 -1
- package/features/tenancy/UpdateTenant/UpdateTenantUseCase.d.ts +2 -2
- package/features/users/CreateUser/decorators/CreateUserWithWcpIncrement.d.ts +1 -1
- package/features/wcp/WcpContext/WcpContext.d.ts +10 -5
- package/features/wcp/WcpContext/WcpContext.js +23 -2
- package/features/wcp/WcpContext/WcpContext.js.map +1 -1
- package/features/wcp/WcpContext/decorators/WcpContextWithFeatureFlagsDecorator.d.ts +25 -7
- package/features/wcp/WcpContext/decorators/WcpContextWithFeatureFlagsDecorator.js +57 -25
- package/features/wcp/WcpContext/decorators/WcpContextWithFeatureFlagsDecorator.js.map +1 -1
- package/features/wcp/WcpContext/feature.d.ts +1 -2
- package/features/wcp/WcpContext/feature.js +2 -2
- package/features/wcp/WcpContext/feature.js.map +1 -1
- package/features/wcp/WcpContext/index.d.ts +0 -1
- package/features/wcp/WcpContext/types.d.ts +0 -4
- package/features/wcp/WcpFeature.d.ts +1 -1
- package/features/wcp/WcpFeature.js +7 -2
- package/features/wcp/WcpFeature.js.map +1 -1
- package/features/wcp/WcpLicenseLoader.d.ts +25 -0
- package/features/wcp/WcpLicenseLoader.js +58 -0
- package/features/wcp/WcpLicenseLoader.js.map +1 -0
- package/features/wcp/WcpLicenseProvider.d.ts +21 -0
- package/features/wcp/WcpLicenseProvider.js +14 -0
- package/features/wcp/WcpLicenseProvider.js.map +1 -0
- package/features/wcp/resolveWcpProjectEnvironment.d.ts +9 -0
- package/features/wcp/resolveWcpProjectEnvironment.js +23 -0
- package/features/wcp/resolveWcpProjectEnvironment.js.map +1 -0
- package/graphql/ApiCoreSchemaFactory.d.ts +15 -0
- package/graphql/ApiCoreSchemaFactory.js +52 -0
- package/graphql/ApiCoreSchemaFactory.js.map +1 -0
- package/graphql/featureFlags/FeatureFlagsSchemaFactory.d.ts +9 -0
- package/graphql/featureFlags/FeatureFlagsSchemaFactory.js +49 -0
- package/graphql/featureFlags/FeatureFlagsSchemaFactory.js.map +1 -0
- package/graphql/security/NotAuthorizedResponse.d.ts +1 -1
- package/graphql/security/NotAuthorizedResponse.js +1 -1
- package/graphql/security/NotAuthorizedResponse.js.map +1 -1
- package/graphql/security/SecuritySchemaFactory.d.ts +14 -0
- package/graphql/security/SecuritySchemaFactory.js +23 -0
- package/graphql/security/SecuritySchemaFactory.js.map +1 -0
- package/graphql/security/addApiKeySchema.d.ts +2 -0
- package/graphql/security/{apiKey.gql.js → addApiKeySchema.js} +45 -27
- package/graphql/security/addApiKeySchema.js.map +1 -0
- package/graphql/security/addIdentitySchema.d.ts +2 -0
- package/graphql/security/{identity.gql.js → addIdentitySchema.js} +52 -35
- package/graphql/security/addIdentitySchema.js.map +1 -0
- package/graphql/security/addRoleSchema.d.ts +2 -0
- package/graphql/security/addRoleSchema.js +137 -0
- package/graphql/security/addRoleSchema.js.map +1 -0
- package/graphql/security/addSecurityBaseSchema.d.ts +2 -0
- package/graphql/security/{base.gql.js → addSecurityBaseSchema.js} +14 -16
- package/graphql/security/addSecurityBaseSchema.js.map +1 -0
- package/graphql/security/addTeamSchema.d.ts +2 -0
- package/graphql/security/addTeamSchema.js +157 -0
- package/graphql/security/addTeamSchema.js.map +1 -0
- package/graphql/system/SystemSchemaFactory.d.ts +9 -0
- package/graphql/system/SystemSchemaFactory.js +66 -0
- package/graphql/system/SystemSchemaFactory.js.map +1 -0
- package/graphql/users/UsersSchemaFactory.d.ts +9 -0
- package/graphql/users/UsersSchemaFactory.js +191 -0
- package/graphql/users/UsersSchemaFactory.js.map +1 -0
- package/graphql/wcp/WcpSchemaFactory.d.ts +9 -0
- package/graphql/wcp/{graphql.js → WcpSchemaFactory.js} +28 -18
- package/graphql/wcp/WcpSchemaFactory.js.map +1 -0
- package/index.d.ts +3 -1
- package/index.js +3 -1
- package/package.json +21 -24
- package/testing/environment.d.ts +14 -0
- package/testing/environment.js +18 -0
- package/testing/environment.js.map +1 -0
- package/types/core.d.ts +17 -5
- package/types/security.d.ts +1 -7
- package/types/tenancy.d.ts +0 -17
- package/types/users.d.ts +0 -13
- package/createApiCore.d.ts +0 -7
- package/createApiCore.js +0 -22
- package/createApiCore.js.map +0 -1
- package/features/ai/AiModelRegistry.d.ts +0 -12
- package/features/ai/AiModelRegistry.js +0 -28
- package/features/ai/AiModelRegistry.js.map +0 -1
- package/graphql/security/apiKey.gql.d.ts +0 -4
- package/graphql/security/apiKey.gql.js.map +0 -1
- package/graphql/security/base.gql.d.ts +0 -4
- package/graphql/security/base.gql.js.map +0 -1
- package/graphql/security/identity.gql.d.ts +0 -4
- package/graphql/security/identity.gql.js.map +0 -1
- package/graphql/security/index.d.ts +0 -1
- package/graphql/security/index.js +0 -15
- package/graphql/security/index.js.map +0 -1
- package/graphql/security/role.gql.d.ts +0 -4
- package/graphql/security/role.gql.js +0 -106
- package/graphql/security/role.gql.js.map +0 -1
- package/graphql/security/team.gql.d.ts +0 -4
- package/graphql/security/team.gql.js +0 -119
- package/graphql/security/team.gql.js.map +0 -1
- package/graphql/system/createSystemGraphQL.d.ts +0 -2
- package/graphql/system/createSystemGraphQL.js +0 -54
- package/graphql/system/createSystemGraphQL.js.map +0 -1
- package/graphql/users/user.gql.d.ts +0 -3
- package/graphql/users/user.gql.js +0 -167
- package/graphql/users/user.gql.js.map +0 -1
- package/graphql/wcp/graphql.d.ts +0 -2
- package/graphql/wcp/graphql.js.map +0 -1
- package/legacy/security/LegacyContext.d.ts +0 -36
- package/legacy/security/LegacyContext.js +0 -152
- package/legacy/security/LegacyContext.js.map +0 -1
- package/legacy/security/createSecurityContext.d.ts +0 -3
- package/legacy/security/createSecurityContext.js +0 -10
- package/legacy/security/createSecurityContext.js.map +0 -1
- package/legacy/security/plugins/apiKeyAuthentication.d.ts +0 -7
- package/legacy/security/plugins/apiKeyAuthentication.js +0 -20
- package/legacy/security/plugins/apiKeyAuthentication.js.map +0 -1
- package/legacy/security/plugins/apiKeyAuthorization.d.ts +0 -6
- package/legacy/security/plugins/apiKeyAuthorization.js +0 -13
- package/legacy/security/plugins/apiKeyAuthorization.js.map +0 -1
- package/legacy/security/plugins/authenticateUsingCookie.d.ts +0 -5
- package/legacy/security/plugins/authenticateUsingCookie.js +0 -23
- package/legacy/security/plugins/authenticateUsingCookie.js.map +0 -1
- package/legacy/security/plugins/authenticateUsingHttpHeader.d.ts +0 -5
- package/legacy/security/plugins/authenticateUsingHttpHeader.js +0 -20
- package/legacy/security/plugins/authenticateUsingHttpHeader.js.map +0 -1
- package/legacy/security/plugins/secureHeaders.d.ts +0 -1
- package/legacy/security/plugins/secureHeaders.js +0 -30
- package/legacy/security/plugins/secureHeaders.js.map +0 -1
- package/legacy/tenancy/LegacyContext.d.ts +0 -15
- package/legacy/tenancy/LegacyContext.js +0 -57
- package/legacy/tenancy/LegacyContext.js.map +0 -1
- package/legacy/tenancy/createTenancyContext.d.ts +0 -3
- package/legacy/tenancy/createTenancyContext.js +0 -31
- package/legacy/tenancy/createTenancyContext.js.map +0 -1
- package/legacy/users/LegacyContext.d.ts +0 -13
- package/legacy/users/LegacyContext.js +0 -55
- package/legacy/users/LegacyContext.js.map +0 -1
- package/legacy/users/createAdminUsersContext.d.ts +0 -3
- package/legacy/users/createAdminUsersContext.js +0 -12
- package/legacy/users/createAdminUsersContext.js.map +0 -1
- package/legacy/wcp/LegacyWcpContext.d.ts +0 -33
- package/legacy/wcp/LegacyWcpContext.js +0 -84
- package/legacy/wcp/LegacyWcpContext.js.map +0 -1
- package/legacy/wcp/context.d.ts +0 -5
- package/legacy/wcp/context.js +0 -46
- package/legacy/wcp/context.js.map +0 -1
|
@@ -3,15 +3,19 @@ import { Result, createImplementation } from "@webiny/feature/api";
|
|
|
3
3
|
import { EventPublisher } from "../../../eventPublisher/index.js";
|
|
4
4
|
import { CreateTeam } from "./abstractions.js";
|
|
5
5
|
import { TeamsRepository } from "../shared/abstractions.js";
|
|
6
|
+
import { RolesRepository } from "../../roles/shared/abstractions.js";
|
|
6
7
|
import { IdentityContext } from "../../IdentityContext/abstractions.js";
|
|
7
8
|
import { createTeamValidation } from "./schema.js";
|
|
8
9
|
import { TeamAfterCreateEvent, TeamBeforeCreateEvent } from "./events.js";
|
|
9
10
|
import { NotAuthorizedError, TeamExistsError, TeamValidationError } from "../shared/errors.js";
|
|
11
|
+
import { descriptionOnCreate } from "../../shared/description.js";
|
|
12
|
+
import { resolveRoleIdentifiers } from "../shared/resolveRoleIdentifiers.js";
|
|
10
13
|
class CreateTeamUseCase {
|
|
11
|
-
constructor(identityContext, eventPublisher, repository){
|
|
14
|
+
constructor(identityContext, eventPublisher, repository, rolesRepository){
|
|
12
15
|
this.identityContext = identityContext;
|
|
13
16
|
this.eventPublisher = eventPublisher;
|
|
14
17
|
this.repository = repository;
|
|
18
|
+
this.rolesRepository = rolesRepository;
|
|
15
19
|
}
|
|
16
20
|
async execute(input) {
|
|
17
21
|
const hasPermission = await this.identityContext.getPermission("security.team");
|
|
@@ -24,12 +28,19 @@ class CreateTeamUseCase {
|
|
|
24
28
|
slug: data.slug
|
|
25
29
|
});
|
|
26
30
|
if (existingTeamResult.isOk()) return Result.fail(new TeamExistsError(data.slug));
|
|
31
|
+
const roleIdsResult = await resolveRoleIdentifiers(this.rolesRepository, data.roles);
|
|
32
|
+
if (roleIdsResult.isFail()) return Result.fail(roleIdsResult.error);
|
|
33
|
+
const createInput = {
|
|
34
|
+
...data,
|
|
35
|
+
description: descriptionOnCreate(data.description),
|
|
36
|
+
roles: roleIdsResult.value
|
|
37
|
+
};
|
|
27
38
|
const team = {
|
|
28
39
|
id: mdbid(),
|
|
29
|
-
name:
|
|
30
|
-
slug:
|
|
31
|
-
description:
|
|
32
|
-
roles:
|
|
40
|
+
name: createInput.name,
|
|
41
|
+
slug: createInput.slug,
|
|
42
|
+
description: descriptionOnCreate(createInput.description),
|
|
43
|
+
roles: createInput.roles,
|
|
33
44
|
system: input.system || false,
|
|
34
45
|
createdOn: new Date().toISOString(),
|
|
35
46
|
createdBy: {
|
|
@@ -41,13 +52,13 @@ class CreateTeamUseCase {
|
|
|
41
52
|
};
|
|
42
53
|
await this.eventPublisher.publish(new TeamBeforeCreateEvent({
|
|
43
54
|
team,
|
|
44
|
-
input:
|
|
55
|
+
input: createInput
|
|
45
56
|
}));
|
|
46
57
|
const result = await this.repository.create(team);
|
|
47
58
|
if (result.isFail()) return Result.fail(result.error);
|
|
48
59
|
await this.eventPublisher.publish(new TeamAfterCreateEvent({
|
|
49
60
|
team,
|
|
50
|
-
input:
|
|
61
|
+
input: createInput
|
|
51
62
|
}));
|
|
52
63
|
return Result.ok(team);
|
|
53
64
|
}
|
|
@@ -58,7 +69,8 @@ const CreateTeamUseCaseImpl = createImplementation({
|
|
|
58
69
|
dependencies: [
|
|
59
70
|
IdentityContext,
|
|
60
71
|
EventPublisher,
|
|
61
|
-
TeamsRepository
|
|
72
|
+
TeamsRepository,
|
|
73
|
+
RolesRepository
|
|
62
74
|
]
|
|
63
75
|
});
|
|
64
76
|
export { CreateTeamUseCase, CreateTeamUseCaseImpl };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/security/teams/CreateTeam/CreateTeamUseCase.js","sources":["../../../../../src/features/security/teams/CreateTeam/CreateTeamUseCase.ts"],"sourcesContent":["import { mdbid } from \"@webiny/utils\";\nimport { createImplementation } from \"@webiny/feature/api\";\nimport { Result } from \"@webiny/feature/api\";\nimport { EventPublisher } from \"~/features/eventPublisher/index.js\";\nimport { CreateTeam } from \"./abstractions.js\";\nimport { TeamsRepository } from \"../shared/abstractions.js\";\nimport { IdentityContext } from \"../../IdentityContext/abstractions.js\";\nimport { createTeamValidation } from \"./schema.js\";\nimport { TeamBeforeCreateEvent, TeamAfterCreateEvent } from \"./events.js\";\nimport type { Team, CreateTeamInput } from \"../shared/types.js\";\nimport { NotAuthorizedError, TeamExistsError, TeamValidationError } from \"../shared/errors.js\";\n\nexport class CreateTeamUseCase implements CreateTeam.Interface {\n constructor(\n private identityContext: IdentityContext.Interface,\n private eventPublisher: EventPublisher.Interface,\n private repository: TeamsRepository.Interface\n ) {}\n\n async execute(input: CreateTeamInput): Promise<Result<Team, CreateTeam.Error>> {\n const hasPermission = await this.identityContext.getPermission(\"security.team\");\n\n if (!hasPermission) {\n return Result.fail(new NotAuthorizedError());\n }\n\n const validation = createTeamValidation.safeParse(input);\n if (!validation.success) {\n return Result.fail(new TeamValidationError(validation.error.issues[0].message));\n }\n\n const identity = this.identityContext.getIdentity();\n const data = validation.data;\n\n // Check if team with same slug already exists\n const existingTeamResult = await this.repository.get({ slug: data.slug });\n if (existingTeamResult.isOk()) {\n return Result.fail(new TeamExistsError(data.slug));\n }\n\n const team: Team = {\n id: mdbid(),\n name:
|
|
1
|
+
{"version":3,"file":"features/security/teams/CreateTeam/CreateTeamUseCase.js","sources":["../../../../../src/features/security/teams/CreateTeam/CreateTeamUseCase.ts"],"sourcesContent":["import { mdbid } from \"@webiny/utils\";\nimport { createImplementation } from \"@webiny/feature/api\";\nimport { Result } from \"@webiny/feature/api\";\nimport { EventPublisher } from \"~/features/eventPublisher/index.js\";\nimport { CreateTeam } from \"./abstractions.js\";\nimport { TeamsRepository } from \"../shared/abstractions.js\";\nimport { RolesRepository } from \"../../roles/shared/abstractions.js\";\nimport { IdentityContext } from \"../../IdentityContext/abstractions.js\";\nimport { createTeamValidation } from \"./schema.js\";\nimport { TeamBeforeCreateEvent, TeamAfterCreateEvent } from \"./events.js\";\nimport type { Team, CreateTeamInput } from \"../shared/types.js\";\nimport { NotAuthorizedError, TeamExistsError, TeamValidationError } from \"../shared/errors.js\";\nimport { descriptionOnCreate } from \"../../shared/description.js\";\nimport { resolveRoleIdentifiers } from \"../shared/resolveRoleIdentifiers.js\";\n\nexport class CreateTeamUseCase implements CreateTeam.Interface {\n constructor(\n private identityContext: IdentityContext.Interface,\n private eventPublisher: EventPublisher.Interface,\n private repository: TeamsRepository.Interface,\n private rolesRepository: RolesRepository.Interface\n ) {}\n\n async execute(input: CreateTeamInput): Promise<Result<Team, CreateTeam.Error>> {\n const hasPermission = await this.identityContext.getPermission(\"security.team\");\n\n if (!hasPermission) {\n return Result.fail(new NotAuthorizedError());\n }\n\n const validation = createTeamValidation.safeParse(input);\n if (!validation.success) {\n return Result.fail(new TeamValidationError(validation.error.issues[0].message));\n }\n\n const identity = this.identityContext.getIdentity();\n const data = validation.data;\n\n // Check if team with same slug already exists\n const existingTeamResult = await this.repository.get({ slug: data.slug });\n if (existingTeamResult.isOk()) {\n return Result.fail(new TeamExistsError(data.slug));\n }\n\n // A slug here would be stored verbatim and then match no role, leaving a team that grants\n // nothing. Resolved before the entity is built so the events carry the stored IDs.\n const roleIdsResult = await resolveRoleIdentifiers(this.rolesRepository, data.roles);\n\n if (roleIdsResult.isFail()) {\n return Result.fail(roleIdsResult.error);\n }\n\n // Normalised up front so that null reaches neither the entity nor the published events.\n const createInput: CreateTeamInput = {\n ...data,\n description: descriptionOnCreate(data.description),\n roles: roleIdsResult.value\n };\n\n const team: Team = {\n id: mdbid(),\n name: createInput.name,\n slug: createInput.slug,\n description: descriptionOnCreate(createInput.description),\n roles: createInput.roles,\n system: input.system || false,\n createdOn: new Date().toISOString(),\n createdBy: {\n id: identity.id,\n displayName: identity.displayName,\n type: identity.type\n },\n plugin: false\n };\n\n await this.eventPublisher.publish(new TeamBeforeCreateEvent({ team, input: createInput }));\n\n const result = await this.repository.create(team);\n\n if (result.isFail()) {\n return Result.fail(result.error);\n }\n\n await this.eventPublisher.publish(new TeamAfterCreateEvent({ team, input: createInput }));\n\n return Result.ok(team);\n }\n}\n\nexport const CreateTeamUseCaseImpl = createImplementation({\n abstraction: CreateTeam,\n implementation: CreateTeamUseCase,\n dependencies: [IdentityContext, EventPublisher, TeamsRepository, RolesRepository]\n});\n"],"names":["CreateTeamUseCase","identityContext","eventPublisher","repository","rolesRepository","input","hasPermission","Result","NotAuthorizedError","validation","createTeamValidation","TeamValidationError","identity","data","existingTeamResult","TeamExistsError","roleIdsResult","resolveRoleIdentifiers","createInput","descriptionOnCreate","team","mdbid","Date","TeamBeforeCreateEvent","result","TeamAfterCreateEvent","CreateTeamUseCaseImpl","createImplementation","CreateTeam","IdentityContext","EventPublisher","TeamsRepository","RolesRepository"],"mappings":";;;;;;;;;;;;AAeO,MAAMA;IACT,YACYC,eAA0C,EAC1CC,cAAwC,EACxCC,UAAqC,EACrCC,eAA0C,CACpD;aAJUH,eAAe,GAAfA;aACAC,cAAc,GAAdA;aACAC,UAAU,GAAVA;aACAC,eAAe,GAAfA;IACT;IAEH,MAAM,QAAQC,KAAsB,EAA2C;QAC3E,MAAMC,gBAAgB,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC;QAE/D,IAAI,CAACA,eACD,OAAOC,OAAO,IAAI,CAAC,IAAIC;QAG3B,MAAMC,aAAaC,qBAAqB,SAAS,CAACL;QAClD,IAAI,CAACI,WAAW,OAAO,EACnB,OAAOF,OAAO,IAAI,CAAC,IAAII,oBAAoBF,WAAW,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO;QAGjF,MAAMG,WAAW,IAAI,CAAC,eAAe,CAAC,WAAW;QACjD,MAAMC,OAAOJ,WAAW,IAAI;QAG5B,MAAMK,qBAAqB,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,MAAMD,KAAK,IAAI;QAAC;QACvE,IAAIC,mBAAmB,IAAI,IACvB,OAAOP,OAAO,IAAI,CAAC,IAAIQ,gBAAgBF,KAAK,IAAI;QAKpD,MAAMG,gBAAgB,MAAMC,uBAAuB,IAAI,CAAC,eAAe,EAAEJ,KAAK,KAAK;QAEnF,IAAIG,cAAc,MAAM,IACpB,OAAOT,OAAO,IAAI,CAACS,cAAc,KAAK;QAI1C,MAAME,cAA+B;YACjC,GAAGL,IAAI;YACP,aAAaM,oBAAoBN,KAAK,WAAW;YACjD,OAAOG,cAAc,KAAK;QAC9B;QAEA,MAAMI,OAAa;YACf,IAAIC;YACJ,MAAMH,YAAY,IAAI;YACtB,MAAMA,YAAY,IAAI;YACtB,aAAaC,oBAAoBD,YAAY,WAAW;YACxD,OAAOA,YAAY,KAAK;YACxB,QAAQb,MAAM,MAAM,IAAI;YACxB,WAAW,IAAIiB,OAAO,WAAW;YACjC,WAAW;gBACP,IAAIV,SAAS,EAAE;gBACf,aAAaA,SAAS,WAAW;gBACjC,MAAMA,SAAS,IAAI;YACvB;YACA,QAAQ;QACZ;QAEA,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,IAAIW,sBAAsB;YAAEH;YAAM,OAAOF;QAAY;QAEvF,MAAMM,SAAS,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAACJ;QAE5C,IAAII,OAAO,MAAM,IACb,OAAOjB,OAAO,IAAI,CAACiB,OAAO,KAAK;QAGnC,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,IAAIC,qBAAqB;YAAEL;YAAM,OAAOF;QAAY;QAEtF,OAAOX,OAAO,EAAE,CAACa;IACrB;AACJ;AAEO,MAAMM,wBAAwBC,qBAAqB;IACtD,aAAaC;IACb,gBAAgB5B;IAChB,cAAc;QAAC6B;QAAiBC;QAAgBC;QAAiBC;KAAgB;AACrF"}
|
|
@@ -2,6 +2,6 @@ import { z } from "zod";
|
|
|
2
2
|
export declare const createTeamValidation: z.ZodObject<{
|
|
3
3
|
name: z.ZodString;
|
|
4
4
|
slug: z.ZodString;
|
|
5
|
-
description: z.
|
|
5
|
+
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
6
6
|
roles: z.ZodArray<z.ZodString>;
|
|
7
7
|
}, z.core.$strip>;
|
|
@@ -2,7 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
const createTeamValidation = z.object({
|
|
3
3
|
name: z.string().min(3),
|
|
4
4
|
slug: z.string().min(3),
|
|
5
|
-
description: z.string().max(500).
|
|
5
|
+
description: z.string().max(500).nullish(),
|
|
6
6
|
roles: z.array(z.string())
|
|
7
7
|
});
|
|
8
8
|
export { createTeamValidation };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/security/teams/CreateTeam/schema.js","sources":["../../../../../src/features/security/teams/CreateTeam/schema.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const createTeamValidation = z.object({\n name: z.string().min(3),\n slug: z.string().min(3),\n description: z.string().max(500).
|
|
1
|
+
{"version":3,"file":"features/security/teams/CreateTeam/schema.js","sources":["../../../../../src/features/security/teams/CreateTeam/schema.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const createTeamValidation = z.object({\n name: z.string().min(3),\n slug: z.string().min(3),\n // Nullable in the GraphQL schema - see `descriptionOnCreate` for why this is `.nullish()`.\n description: z.string().max(500).nullish(),\n roles: z.array(z.string())\n});\n"],"names":["createTeamValidation","z"],"mappings":";AAEO,MAAMA,uBAAuBC,EAAE,MAAM,CAAC;IACzC,MAAMA,EAAE,MAAM,GAAG,GAAG,CAAC;IACrB,MAAMA,EAAE,MAAM,GAAG,GAAG,CAAC;IAErB,aAAaA,EAAE,MAAM,GAAG,GAAG,CAAC,KAAK,OAAO;IACxC,OAAOA,EAAE,KAAK,CAACA,EAAE,MAAM;AAC3B"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Result } from "@webiny/feature/api";
|
|
2
2
|
import { UpdateTeam } from "./abstractions.js";
|
|
3
3
|
import { TeamsRepository } from "../shared/abstractions.js";
|
|
4
|
+
import { RolesRepository } from "../../roles/shared/abstractions.js";
|
|
4
5
|
import { IdentityContext } from "../../IdentityContext/abstractions.js";
|
|
5
6
|
import { EventPublisher } from "../../../../features/eventPublisher/index.js";
|
|
6
7
|
import type { Team, UpdateTeamInput } from "../shared/types.js";
|
|
@@ -8,7 +9,8 @@ export declare class UpdateTeamUseCase {
|
|
|
8
9
|
private repository;
|
|
9
10
|
private identityContext;
|
|
10
11
|
private eventPublisher;
|
|
11
|
-
|
|
12
|
+
private rolesRepository;
|
|
13
|
+
constructor(repository: TeamsRepository.Interface, identityContext: IdentityContext.Interface, eventPublisher: EventPublisher.Interface, rolesRepository: RolesRepository.Interface);
|
|
12
14
|
execute(id: string, input: UpdateTeamInput): Promise<Result<Team, UpdateTeam.Error>>;
|
|
13
15
|
}
|
|
14
16
|
export declare const UpdateTeamUseCaseImpl: import("@webiny/di").Implementation<typeof UpdateTeamUseCase>;
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { Result, createImplementation } from "@webiny/feature/api";
|
|
2
2
|
import { UpdateTeam } from "./abstractions.js";
|
|
3
3
|
import { TeamsRepository } from "../shared/abstractions.js";
|
|
4
|
+
import { RolesRepository } from "../../roles/shared/abstractions.js";
|
|
4
5
|
import { IdentityContext } from "../../IdentityContext/abstractions.js";
|
|
5
6
|
import { EventPublisher } from "../../../eventPublisher/index.js";
|
|
6
7
|
import { updateTeamValidation } from "./schema.js";
|
|
7
8
|
import { TeamAfterUpdateEvent, TeamBeforeUpdateEvent } from "./events.js";
|
|
9
|
+
import { descriptionOnUpdate } from "../../shared/description.js";
|
|
10
|
+
import { resolveRoleIdentifiers } from "../shared/resolveRoleIdentifiers.js";
|
|
8
11
|
import { CannotUpdatePluginTeamsError, CannotUpdateSystemTeamsError, NotAuthorizedError, TeamValidationError } from "../shared/errors.js";
|
|
9
12
|
class UpdateTeamUseCase {
|
|
10
|
-
constructor(repository, identityContext, eventPublisher){
|
|
13
|
+
constructor(repository, identityContext, eventPublisher, rolesRepository){
|
|
11
14
|
this.repository = repository;
|
|
12
15
|
this.identityContext = identityContext;
|
|
13
16
|
this.eventPublisher = eventPublisher;
|
|
17
|
+
this.rolesRepository = rolesRepository;
|
|
14
18
|
}
|
|
15
19
|
async execute(id, input) {
|
|
16
20
|
const hasPermission = await this.identityContext.getPermission("security.team");
|
|
@@ -24,21 +28,31 @@ class UpdateTeamUseCase {
|
|
|
24
28
|
const existingTeam = existingResult.value;
|
|
25
29
|
if (existingTeam.system) return Result.fail(new CannotUpdateSystemTeamsError());
|
|
26
30
|
if (existingTeam.plugin) return Result.fail(new CannotUpdatePluginTeamsError());
|
|
31
|
+
const { description, ...rest } = validation.data;
|
|
32
|
+
const changes = {
|
|
33
|
+
...rest,
|
|
34
|
+
...descriptionOnUpdate(description)
|
|
35
|
+
};
|
|
36
|
+
if (changes.roles) {
|
|
37
|
+
const roleIdsResult = await resolveRoleIdentifiers(this.rolesRepository, changes.roles);
|
|
38
|
+
if (roleIdsResult.isFail()) return Result.fail(roleIdsResult.error);
|
|
39
|
+
changes.roles = roleIdsResult.value;
|
|
40
|
+
}
|
|
27
41
|
const updatedTeam = {
|
|
28
42
|
...existingTeam,
|
|
29
|
-
...
|
|
43
|
+
...changes
|
|
30
44
|
};
|
|
31
45
|
await this.eventPublisher.publish(new TeamBeforeUpdateEvent({
|
|
32
46
|
original: existingTeam,
|
|
33
47
|
updated: updatedTeam,
|
|
34
|
-
input:
|
|
48
|
+
input: changes
|
|
35
49
|
}));
|
|
36
50
|
const result = await this.repository.update(updatedTeam);
|
|
37
51
|
if (result.isFail()) return Result.fail(result.error);
|
|
38
52
|
await this.eventPublisher.publish(new TeamAfterUpdateEvent({
|
|
39
53
|
original: existingTeam,
|
|
40
54
|
updated: updatedTeam,
|
|
41
|
-
input:
|
|
55
|
+
input: changes
|
|
42
56
|
}));
|
|
43
57
|
return Result.ok(updatedTeam);
|
|
44
58
|
}
|
|
@@ -49,7 +63,8 @@ const UpdateTeamUseCaseImpl = createImplementation({
|
|
|
49
63
|
dependencies: [
|
|
50
64
|
TeamsRepository,
|
|
51
65
|
IdentityContext,
|
|
52
|
-
EventPublisher
|
|
66
|
+
EventPublisher,
|
|
67
|
+
RolesRepository
|
|
53
68
|
]
|
|
54
69
|
});
|
|
55
70
|
export { UpdateTeamUseCase, UpdateTeamUseCaseImpl };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/security/teams/UpdateTeam/UpdateTeamUseCase.js","sources":["../../../../../src/features/security/teams/UpdateTeam/UpdateTeamUseCase.ts"],"sourcesContent":["import { createImplementation } from \"@webiny/feature/api\";\nimport { Result } from \"@webiny/feature/api\";\nimport { UpdateTeam } from \"./abstractions.js\";\nimport { TeamsRepository } from \"../shared/abstractions.js\";\nimport { IdentityContext } from \"../../IdentityContext/abstractions.js\";\nimport { EventPublisher } from \"~/features/eventPublisher/index.js\";\nimport { updateTeamValidation } from \"./schema.js\";\nimport { TeamBeforeUpdateEvent, TeamAfterUpdateEvent } from \"./events.js\";\nimport type { Team, UpdateTeamInput } from \"../shared/types.js\";\nimport {\n NotAuthorizedError,\n CannotUpdatePluginTeamsError,\n CannotUpdateSystemTeamsError,\n TeamValidationError\n} from \"../shared/errors.js\";\n\nexport class UpdateTeamUseCase {\n private repository: TeamsRepository.Interface;\n private identityContext: IdentityContext.Interface;\n private eventPublisher: EventPublisher.Interface;\n\n constructor(\n repository: TeamsRepository.Interface,\n identityContext: IdentityContext.Interface,\n eventPublisher: EventPublisher.Interface\n ) {\n this.repository = repository;\n this.identityContext = identityContext;\n this.eventPublisher = eventPublisher;\n }\n\n async execute(id: string, input: UpdateTeamInput): Promise<Result<Team, UpdateTeam.Error>> {\n const hasPermission = await this.identityContext.getPermission(\"security.team\");\n if (!hasPermission) {\n return Result.fail(new NotAuthorizedError());\n }\n\n const validation = updateTeamValidation.safeParse(input);\n if (!validation.success) {\n return Result.fail(new TeamValidationError(validation.error.issues[0].message));\n }\n\n const existingResult = await this.repository.get({ id });\n if (existingResult.isFail()) {\n return Result.fail(existingResult.error);\n }\n\n const existingTeam = existingResult.value;\n\n // Check if team is system team\n if (existingTeam.system) {\n return Result.fail(new CannotUpdateSystemTeamsError());\n }\n\n // Check if team is created via plugin\n if (existingTeam.plugin) {\n return Result.fail(new CannotUpdatePluginTeamsError());\n }\n\n const updatedTeam: Team = {\n ...existingTeam,\n ...
|
|
1
|
+
{"version":3,"file":"features/security/teams/UpdateTeam/UpdateTeamUseCase.js","sources":["../../../../../src/features/security/teams/UpdateTeam/UpdateTeamUseCase.ts"],"sourcesContent":["import { createImplementation } from \"@webiny/feature/api\";\nimport { Result } from \"@webiny/feature/api\";\nimport { UpdateTeam } from \"./abstractions.js\";\nimport { TeamsRepository } from \"../shared/abstractions.js\";\nimport { RolesRepository } from \"../../roles/shared/abstractions.js\";\nimport { IdentityContext } from \"../../IdentityContext/abstractions.js\";\nimport { EventPublisher } from \"~/features/eventPublisher/index.js\";\nimport { updateTeamValidation } from \"./schema.js\";\nimport { TeamBeforeUpdateEvent, TeamAfterUpdateEvent } from \"./events.js\";\nimport type { Team, UpdateTeamInput } from \"../shared/types.js\";\nimport { descriptionOnUpdate } from \"../../shared/description.js\";\nimport { resolveRoleIdentifiers } from \"../shared/resolveRoleIdentifiers.js\";\nimport {\n NotAuthorizedError,\n CannotUpdatePluginTeamsError,\n CannotUpdateSystemTeamsError,\n TeamValidationError\n} from \"../shared/errors.js\";\n\nexport class UpdateTeamUseCase {\n private repository: TeamsRepository.Interface;\n private identityContext: IdentityContext.Interface;\n private eventPublisher: EventPublisher.Interface;\n private rolesRepository: RolesRepository.Interface;\n\n constructor(\n repository: TeamsRepository.Interface,\n identityContext: IdentityContext.Interface,\n eventPublisher: EventPublisher.Interface,\n rolesRepository: RolesRepository.Interface\n ) {\n this.repository = repository;\n this.identityContext = identityContext;\n this.eventPublisher = eventPublisher;\n this.rolesRepository = rolesRepository;\n }\n\n async execute(id: string, input: UpdateTeamInput): Promise<Result<Team, UpdateTeam.Error>> {\n const hasPermission = await this.identityContext.getPermission(\"security.team\");\n if (!hasPermission) {\n return Result.fail(new NotAuthorizedError());\n }\n\n const validation = updateTeamValidation.safeParse(input);\n if (!validation.success) {\n return Result.fail(new TeamValidationError(validation.error.issues[0].message));\n }\n\n const existingResult = await this.repository.get({ id });\n if (existingResult.isFail()) {\n return Result.fail(existingResult.error);\n }\n\n const existingTeam = existingResult.value;\n\n // Check if team is system team\n if (existingTeam.system) {\n return Result.fail(new CannotUpdateSystemTeamsError());\n }\n\n // Check if team is created via plugin\n if (existingTeam.plugin) {\n return Result.fail(new CannotUpdatePluginTeamsError());\n }\n\n // `description` is pulled out of the spread because it is the one field that accepts null.\n // Normalising it here keeps null out of both the entity and the published events, whose\n // input type declares `description?: string`.\n const { description, ...rest } = validation.data;\n\n const changes: UpdateTeamInput = {\n ...rest,\n ...descriptionOnUpdate(description)\n };\n\n /*\n * Only when the update mentions roles. An update that omits them must leave the stored ones\n * alone, and resolving an absent list would cost a read and write an empty array.\n */\n if (changes.roles) {\n const roleIdsResult = await resolveRoleIdentifiers(this.rolesRepository, changes.roles);\n\n if (roleIdsResult.isFail()) {\n return Result.fail(roleIdsResult.error);\n }\n\n changes.roles = roleIdsResult.value;\n }\n\n const updatedTeam: Team = {\n ...existingTeam,\n ...changes\n };\n\n await this.eventPublisher.publish(\n new TeamBeforeUpdateEvent({\n original: existingTeam,\n updated: updatedTeam,\n input: changes\n })\n );\n\n const result = await this.repository.update(updatedTeam);\n\n if (result.isFail()) {\n return Result.fail(result.error);\n }\n\n await this.eventPublisher.publish(\n new TeamAfterUpdateEvent({\n original: existingTeam,\n updated: updatedTeam,\n input: changes\n })\n );\n\n return Result.ok(updatedTeam);\n }\n}\n\nexport const UpdateTeamUseCaseImpl = createImplementation({\n abstraction: UpdateTeam,\n implementation: UpdateTeamUseCase,\n dependencies: [TeamsRepository, IdentityContext, EventPublisher, RolesRepository]\n});\n"],"names":["UpdateTeamUseCase","repository","identityContext","eventPublisher","rolesRepository","id","input","hasPermission","Result","NotAuthorizedError","validation","updateTeamValidation","TeamValidationError","existingResult","existingTeam","CannotUpdateSystemTeamsError","CannotUpdatePluginTeamsError","description","rest","changes","descriptionOnUpdate","roleIdsResult","resolveRoleIdentifiers","updatedTeam","TeamBeforeUpdateEvent","result","TeamAfterUpdateEvent","UpdateTeamUseCaseImpl","createImplementation","UpdateTeam","TeamsRepository","IdentityContext","EventPublisher","RolesRepository"],"mappings":";;;;;;;;;;;AAmBO,MAAMA;IAMT,YACIC,UAAqC,EACrCC,eAA0C,EAC1CC,cAAwC,EACxCC,eAA0C,CAC5C;QACE,IAAI,CAAC,UAAU,GAAGH;QAClB,IAAI,CAAC,eAAe,GAAGC;QACvB,IAAI,CAAC,cAAc,GAAGC;QACtB,IAAI,CAAC,eAAe,GAAGC;IAC3B;IAEA,MAAM,QAAQC,EAAU,EAAEC,KAAsB,EAA2C;QACvF,MAAMC,gBAAgB,MAAM,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC;QAC/D,IAAI,CAACA,eACD,OAAOC,OAAO,IAAI,CAAC,IAAIC;QAG3B,MAAMC,aAAaC,qBAAqB,SAAS,CAACL;QAClD,IAAI,CAACI,WAAW,OAAO,EACnB,OAAOF,OAAO,IAAI,CAAC,IAAII,oBAAoBF,WAAW,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO;QAGjF,MAAMG,iBAAiB,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAER;QAAG;QACtD,IAAIQ,eAAe,MAAM,IACrB,OAAOL,OAAO,IAAI,CAACK,eAAe,KAAK;QAG3C,MAAMC,eAAeD,eAAe,KAAK;QAGzC,IAAIC,aAAa,MAAM,EACnB,OAAON,OAAO,IAAI,CAAC,IAAIO;QAI3B,IAAID,aAAa,MAAM,EACnB,OAAON,OAAO,IAAI,CAAC,IAAIQ;QAM3B,MAAM,EAAEC,WAAW,EAAE,GAAGC,MAAM,GAAGR,WAAW,IAAI;QAEhD,MAAMS,UAA2B;YAC7B,GAAGD,IAAI;YACP,GAAGE,oBAAoBH,YAAY;QACvC;QAMA,IAAIE,QAAQ,KAAK,EAAE;YACf,MAAME,gBAAgB,MAAMC,uBAAuB,IAAI,CAAC,eAAe,EAAEH,QAAQ,KAAK;YAEtF,IAAIE,cAAc,MAAM,IACpB,OAAOb,OAAO,IAAI,CAACa,cAAc,KAAK;YAG1CF,QAAQ,KAAK,GAAGE,cAAc,KAAK;QACvC;QAEA,MAAME,cAAoB;YACtB,GAAGT,YAAY;YACf,GAAGK,OAAO;QACd;QAEA,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAC7B,IAAIK,sBAAsB;YACtB,UAAUV;YACV,SAASS;YACT,OAAOJ;QACX;QAGJ,MAAMM,SAAS,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAACF;QAE5C,IAAIE,OAAO,MAAM,IACb,OAAOjB,OAAO,IAAI,CAACiB,OAAO,KAAK;QAGnC,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAC7B,IAAIC,qBAAqB;YACrB,UAAUZ;YACV,SAASS;YACT,OAAOJ;QACX;QAGJ,OAAOX,OAAO,EAAE,CAACe;IACrB;AACJ;AAEO,MAAMI,wBAAwBC,qBAAqB;IACtD,aAAaC;IACb,gBAAgB7B;IAChB,cAAc;QAAC8B;QAAiBC;QAAiBC;QAAgBC;KAAgB;AACrF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export declare const updateTeamValidation: z.ZodObject<{
|
|
3
3
|
name: z.ZodOptional<z.ZodString>;
|
|
4
|
-
description: z.ZodOptional<z.ZodString
|
|
4
|
+
description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
5
5
|
roles: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
6
6
|
}, z.core.$strip>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
const updateTeamValidation = z.object({
|
|
3
3
|
name: z.string().min(3).optional(),
|
|
4
|
-
description: z.string().max(500).
|
|
4
|
+
description: z.string().max(500).nullish(),
|
|
5
5
|
roles: z.array(z.string()).optional()
|
|
6
6
|
});
|
|
7
7
|
export { updateTeamValidation };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/security/teams/UpdateTeam/schema.js","sources":["../../../../../src/features/security/teams/UpdateTeam/schema.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const updateTeamValidation = z.object({\n name: z.string().min(3).optional(),\n description: z.string().max(500).
|
|
1
|
+
{"version":3,"file":"features/security/teams/UpdateTeam/schema.js","sources":["../../../../../src/features/security/teams/UpdateTeam/schema.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const updateTeamValidation = z.object({\n name: z.string().min(3).optional(),\n // Nullable in the GraphQL schema - see `descriptionOnUpdate` for why this is `.nullish()` and\n // must not carry a `.transform()`.\n description: z.string().max(500).nullish(),\n roles: z.array(z.string()).optional()\n});\n"],"names":["updateTeamValidation","z"],"mappings":";AAEO,MAAMA,uBAAuBC,EAAE,MAAM,CAAC;IACzC,MAAMA,EAAE,MAAM,GAAG,GAAG,CAAC,GAAG,QAAQ;IAGhC,aAAaA,EAAE,MAAM,GAAG,GAAG,CAAC,KAAK,OAAO;IACxC,OAAOA,EAAE,KAAK,CAACA,EAAE,MAAM,IAAI,QAAQ;AACvC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Result } from "@webiny/feature/api";
|
|
2
|
+
import { RolesRepository } from "../../roles/shared/abstractions.js";
|
|
3
|
+
import { TeamValidationError } from "./errors.js";
|
|
4
|
+
/**
|
|
5
|
+
* Maps whatever a caller used to name a role onto the role IDs a team stores.
|
|
6
|
+
*
|
|
7
|
+
* `team.roles` holds IDs and only IDs: GetPermissionsFromIdentity resolves them with `id_in` against
|
|
8
|
+
* the roles repository. A slug stored here matches nothing, so the team is created, reads correctly
|
|
9
|
+
* in the admin UI, and grants no permissions at all. Nothing previously caught that, because the
|
|
10
|
+
* field is typed `string[]` and the use case wrote it through untouched.
|
|
11
|
+
*
|
|
12
|
+
* Accepting both forms rather than rejecting slugs: which identifier a given field wants is not
|
|
13
|
+
* guessable from the outside, and a few lines away in the same area a team is identified by SLUG
|
|
14
|
+
* (folder permission targets are `team:<slug>`). An identifier that is neither is a genuine mistake
|
|
15
|
+
* and is reported.
|
|
16
|
+
*/
|
|
17
|
+
export declare const resolveRoleIdentifiers: (rolesRepository: RolesRepository.Interface, identifiers: string[]) => Promise<Result<string[], TeamValidationError>>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Result } from "@webiny/feature/api";
|
|
2
|
+
import { TeamValidationError } from "./errors.js";
|
|
3
|
+
const resolveRoleIdentifiers = async (rolesRepository, identifiers)=>{
|
|
4
|
+
if (0 === identifiers.length) return Result.ok([]);
|
|
5
|
+
const rolesResult = await rolesRepository.list({});
|
|
6
|
+
if (rolesResult.isFail()) return Result.fail(new TeamValidationError(`Could not load roles: ${rolesResult.error}`));
|
|
7
|
+
const byId = new Map(rolesResult.value.map((role)=>[
|
|
8
|
+
role.id,
|
|
9
|
+
role.id
|
|
10
|
+
]));
|
|
11
|
+
const bySlug = new Map(rolesResult.value.map((role)=>[
|
|
12
|
+
role.slug,
|
|
13
|
+
role.id
|
|
14
|
+
]));
|
|
15
|
+
const unknown = [];
|
|
16
|
+
const roleIds = identifiers.map((identifier)=>{
|
|
17
|
+
const resolved = byId.get(identifier) ?? bySlug.get(identifier);
|
|
18
|
+
if (!resolved) {
|
|
19
|
+
unknown.push(identifier);
|
|
20
|
+
return identifier;
|
|
21
|
+
}
|
|
22
|
+
return resolved;
|
|
23
|
+
});
|
|
24
|
+
if (unknown.length > 0) {
|
|
25
|
+
const names = unknown.map((identifier)=>`"${identifier}"`).join(", ");
|
|
26
|
+
return Result.fail(new TeamValidationError(`Not a known role id or slug: ${names}.`));
|
|
27
|
+
}
|
|
28
|
+
return Result.ok(roleIds);
|
|
29
|
+
};
|
|
30
|
+
export { resolveRoleIdentifiers };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=resolveRoleIdentifiers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/security/teams/shared/resolveRoleIdentifiers.js","sources":["../../../../../src/features/security/teams/shared/resolveRoleIdentifiers.ts"],"sourcesContent":["import { Result } from \"@webiny/feature/api\";\nimport { RolesRepository } from \"../../roles/shared/abstractions.js\";\nimport { TeamValidationError } from \"./errors.js\";\n\n/**\n * Maps whatever a caller used to name a role onto the role IDs a team stores.\n *\n * `team.roles` holds IDs and only IDs: GetPermissionsFromIdentity resolves them with `id_in` against\n * the roles repository. A slug stored here matches nothing, so the team is created, reads correctly\n * in the admin UI, and grants no permissions at all. Nothing previously caught that, because the\n * field is typed `string[]` and the use case wrote it through untouched.\n *\n * Accepting both forms rather than rejecting slugs: which identifier a given field wants is not\n * guessable from the outside, and a few lines away in the same area a team is identified by SLUG\n * (folder permission targets are `team:<slug>`). An identifier that is neither is a genuine mistake\n * and is reported.\n */\nexport const resolveRoleIdentifiers = async (\n rolesRepository: RolesRepository.Interface,\n identifiers: string[]\n): Promise<Result<string[], TeamValidationError>> => {\n if (identifiers.length === 0) {\n return Result.ok([]);\n }\n\n /*\n * Every role, in one read. `id_in` and `slug_in` are ANDed by the repository, so they cannot\n * express \"either of these\", and a project has few enough roles for the distinction not to\n * matter. Plugin-defined roles are included, which a filtered query would also have to cover.\n */\n const rolesResult = await rolesRepository.list({});\n\n if (rolesResult.isFail()) {\n return Result.fail(new TeamValidationError(`Could not load roles: ${rolesResult.error}`));\n }\n\n const byId = new Map(rolesResult.value.map(role => [role.id, role.id]));\n const bySlug = new Map(rolesResult.value.map(role => [role.slug, role.id]));\n\n const unknown: string[] = [];\n\n // ID first, so a slug that happens to equal another role's ID cannot shadow it.\n const roleIds = identifiers.map(identifier => {\n const resolved = byId.get(identifier) ?? bySlug.get(identifier);\n\n if (!resolved) {\n unknown.push(identifier);\n return identifier;\n }\n\n return resolved;\n });\n\n if (unknown.length > 0) {\n const names = unknown.map(identifier => `\"${identifier}\"`).join(\", \");\n return Result.fail(new TeamValidationError(`Not a known role id or slug: ${names}.`));\n }\n\n return Result.ok(roleIds);\n};\n"],"names":["resolveRoleIdentifiers","rolesRepository","identifiers","Result","rolesResult","TeamValidationError","byId","Map","role","bySlug","unknown","roleIds","identifier","resolved","names"],"mappings":";;AAiBO,MAAMA,yBAAyB,OAClCC,iBACAC;IAEA,IAAIA,AAAuB,MAAvBA,YAAY,MAAM,EAClB,OAAOC,OAAO,EAAE,CAAC,EAAE;IAQvB,MAAMC,cAAc,MAAMH,gBAAgB,IAAI,CAAC,CAAC;IAEhD,IAAIG,YAAY,MAAM,IAClB,OAAOD,OAAO,IAAI,CAAC,IAAIE,oBAAoB,CAAC,sBAAsB,EAAED,YAAY,KAAK,EAAE;IAG3F,MAAME,OAAO,IAAIC,IAAIH,YAAY,KAAK,CAAC,GAAG,CAACI,CAAAA,OAAQ;YAACA,KAAK,EAAE;YAAEA,KAAK,EAAE;SAAC;IACrE,MAAMC,SAAS,IAAIF,IAAIH,YAAY,KAAK,CAAC,GAAG,CAACI,CAAAA,OAAQ;YAACA,KAAK,IAAI;YAAEA,KAAK,EAAE;SAAC;IAEzE,MAAME,UAAoB,EAAE;IAG5B,MAAMC,UAAUT,YAAY,GAAG,CAACU,CAAAA;QAC5B,MAAMC,WAAWP,KAAK,GAAG,CAACM,eAAeH,OAAO,GAAG,CAACG;QAEpD,IAAI,CAACC,UAAU;YACXH,QAAQ,IAAI,CAACE;YACb,OAAOA;QACX;QAEA,OAAOC;IACX;IAEA,IAAIH,QAAQ,MAAM,GAAG,GAAG;QACpB,MAAMI,QAAQJ,QAAQ,GAAG,CAACE,CAAAA,aAAc,CAAC,CAAC,EAAEA,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC;QAChE,OAAOT,OAAO,IAAI,CAAC,IAAIE,oBAAoB,CAAC,6BAA6B,EAAES,MAAM,CAAC,CAAC;IACvF;IAEA,OAAOX,OAAO,EAAE,CAACQ;AACrB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { GenericRecord } from "@webiny/api/types.js";
|
|
2
|
+
export interface IServiceManifest {
|
|
3
|
+
name: string;
|
|
4
|
+
manifest: GenericRecord<string>;
|
|
5
|
+
}
|
|
6
|
+
export interface IServiceManifestLoader {
|
|
7
|
+
load(): Promise<IServiceManifest[] | undefined>;
|
|
8
|
+
}
|
|
9
|
+
type Manifest = GenericRecord<string>;
|
|
10
|
+
export declare class ServiceDiscovery {
|
|
11
|
+
private static loader;
|
|
12
|
+
private static manifest;
|
|
13
|
+
static setLoader(loader: IServiceManifestLoader): void;
|
|
14
|
+
static load(): Promise<Manifest | undefined>;
|
|
15
|
+
static clear(): void;
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class ServiceDiscovery {
|
|
2
|
+
static setLoader(loader) {
|
|
3
|
+
this.loader = loader;
|
|
4
|
+
}
|
|
5
|
+
static async load() {
|
|
6
|
+
if (this.manifest) return this.manifest;
|
|
7
|
+
if (!this.loader) throw new Error("ServiceDiscovery loader not configured. Call ServiceDiscovery.setLoader() before loading manifests.");
|
|
8
|
+
const manifests = await this.loader.load();
|
|
9
|
+
if (!manifests) return;
|
|
10
|
+
this.manifest = manifests.reduce((acc, item)=>({
|
|
11
|
+
...acc,
|
|
12
|
+
[item.name]: item.manifest
|
|
13
|
+
}), {});
|
|
14
|
+
return this.manifest;
|
|
15
|
+
}
|
|
16
|
+
static clear() {
|
|
17
|
+
this.manifest = void 0;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export { ServiceDiscovery };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=ServiceDiscovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/serviceDiscovery/ServiceDiscovery.js","sources":["../../../src/features/serviceDiscovery/ServiceDiscovery.ts"],"sourcesContent":["import type { GenericRecord } from \"@webiny/api/types.js\";\n\nexport interface IServiceManifest {\n name: string;\n manifest: GenericRecord<string>;\n}\n\nexport interface IServiceManifestLoader {\n load(): Promise<IServiceManifest[] | undefined>;\n}\n\ntype Manifest = GenericRecord<string>;\n\nexport class ServiceDiscovery {\n private static loader: IServiceManifestLoader | undefined;\n private static manifest: Manifest | undefined;\n\n static setLoader(loader: IServiceManifestLoader): void {\n this.loader = loader;\n }\n\n static async load(): Promise<Manifest | undefined> {\n if (this.manifest) {\n return this.manifest;\n }\n\n if (!this.loader) {\n throw new Error(\n \"ServiceDiscovery loader not configured. Call ServiceDiscovery.setLoader() before loading manifests.\"\n );\n }\n\n const manifests = await this.loader.load();\n\n if (!manifests) {\n return undefined;\n }\n\n this.manifest = manifests.reduce<Manifest>((acc, item) => {\n return { ...acc, [item.name]: item.manifest };\n }, {});\n\n return this.manifest;\n }\n\n static clear(): void {\n this.manifest = undefined;\n }\n}\n"],"names":["ServiceDiscovery","loader","Error","manifests","acc","item","undefined"],"mappings":"AAaO,MAAMA;IAIT,OAAO,UAAUC,MAA8B,EAAQ;QACnD,IAAI,CAAC,MAAM,GAAGA;IAClB;IAEA,aAAa,OAAsC;QAC/C,IAAI,IAAI,CAAC,QAAQ,EACb,OAAO,IAAI,CAAC,QAAQ;QAGxB,IAAI,CAAC,IAAI,CAAC,MAAM,EACZ,MAAM,IAAIC,MACN;QAIR,MAAMC,YAAY,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI;QAExC,IAAI,CAACA,WACD;QAGJ,IAAI,CAAC,QAAQ,GAAGA,UAAU,MAAM,CAAW,CAACC,KAAKC,OACtC;gBAAE,GAAGD,GAAG;gBAAE,CAACC,KAAK,IAAI,CAAC,EAAEA,KAAK,QAAQ;YAAC,IAC7C,CAAC;QAEJ,OAAO,IAAI,CAAC,QAAQ;IACxB;IAEA,OAAO,QAAc;QACjB,IAAI,CAAC,QAAQ,GAAGC;IACpB;AACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it } from "vitest";
|
|
2
|
+
import { ServiceDiscovery } from "../ServiceDiscovery.js";
|
|
3
|
+
describe("ServiceDiscovery", ()=>{
|
|
4
|
+
beforeEach(()=>{
|
|
5
|
+
ServiceDiscovery.clear();
|
|
6
|
+
});
|
|
7
|
+
it("should throw if no loader is set", async ()=>{
|
|
8
|
+
ServiceDiscovery.loader = void 0;
|
|
9
|
+
await expect(ServiceDiscovery.load()).rejects.toThrow("ServiceDiscovery loader not configured");
|
|
10
|
+
});
|
|
11
|
+
it("should load manifests and combine them by name", async ()=>{
|
|
12
|
+
const loader = {
|
|
13
|
+
async load () {
|
|
14
|
+
return [
|
|
15
|
+
{
|
|
16
|
+
name: "api",
|
|
17
|
+
manifest: {
|
|
18
|
+
cloudfront: {
|
|
19
|
+
distributionId: "123"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: "core",
|
|
25
|
+
manifest: {
|
|
26
|
+
bucket: {
|
|
27
|
+
name: "my-bucket"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
ServiceDiscovery.setLoader(loader);
|
|
35
|
+
const result = await ServiceDiscovery.load();
|
|
36
|
+
expect(result).toEqual({
|
|
37
|
+
api: {
|
|
38
|
+
cloudfront: {
|
|
39
|
+
distributionId: "123"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
core: {
|
|
43
|
+
bucket: {
|
|
44
|
+
name: "my-bucket"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
it("should cache the result and not call loader again", async ()=>{
|
|
50
|
+
let callCount = 0;
|
|
51
|
+
const loader = {
|
|
52
|
+
async load () {
|
|
53
|
+
callCount++;
|
|
54
|
+
return [
|
|
55
|
+
{
|
|
56
|
+
name: "api",
|
|
57
|
+
manifest: {
|
|
58
|
+
url: "https://example.com"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
ServiceDiscovery.setLoader(loader);
|
|
65
|
+
await ServiceDiscovery.load();
|
|
66
|
+
await ServiceDiscovery.load();
|
|
67
|
+
await ServiceDiscovery.load();
|
|
68
|
+
expect(callCount).toBe(1);
|
|
69
|
+
});
|
|
70
|
+
it("should return undefined when loader returns undefined", async ()=>{
|
|
71
|
+
const loader = {
|
|
72
|
+
async load () {}
|
|
73
|
+
};
|
|
74
|
+
ServiceDiscovery.setLoader(loader);
|
|
75
|
+
const result = await ServiceDiscovery.load();
|
|
76
|
+
expect(result).toBeUndefined();
|
|
77
|
+
});
|
|
78
|
+
it("should reload after clear()", async ()=>{
|
|
79
|
+
let callCount = 0;
|
|
80
|
+
const loader = {
|
|
81
|
+
async load () {
|
|
82
|
+
callCount++;
|
|
83
|
+
return [
|
|
84
|
+
{
|
|
85
|
+
name: "api",
|
|
86
|
+
manifest: {
|
|
87
|
+
version: callCount
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
ServiceDiscovery.setLoader(loader);
|
|
94
|
+
const first = await ServiceDiscovery.load();
|
|
95
|
+
expect(first).toEqual({
|
|
96
|
+
api: {
|
|
97
|
+
version: 1
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
ServiceDiscovery.clear();
|
|
101
|
+
const second = await ServiceDiscovery.load();
|
|
102
|
+
expect(second).toEqual({
|
|
103
|
+
api: {
|
|
104
|
+
version: 2
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
expect(callCount).toBe(2);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
//# sourceMappingURL=ServiceDiscovery.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/serviceDiscovery/__tests__/ServiceDiscovery.test.js","sources":["../../../../src/features/serviceDiscovery/__tests__/ServiceDiscovery.test.ts"],"sourcesContent":["import { describe, it, expect, beforeEach } from \"vitest\";\nimport { ServiceDiscovery } from \"../ServiceDiscovery.js\";\nimport type { IServiceManifestLoader } from \"../ServiceDiscovery.js\";\n\ndescribe(\"ServiceDiscovery\", () => {\n beforeEach(() => {\n ServiceDiscovery.clear();\n });\n\n it(\"should throw if no loader is set\", async () => {\n (ServiceDiscovery as any).loader = undefined;\n\n await expect(ServiceDiscovery.load()).rejects.toThrow(\n \"ServiceDiscovery loader not configured\"\n );\n });\n\n it(\"should load manifests and combine them by name\", async () => {\n const loader: IServiceManifestLoader = {\n async load() {\n return [\n { name: \"api\", manifest: { cloudfront: { distributionId: \"123\" } } },\n { name: \"core\", manifest: { bucket: { name: \"my-bucket\" } } }\n ];\n }\n };\n\n ServiceDiscovery.setLoader(loader);\n\n const result = await ServiceDiscovery.load();\n\n expect(result).toEqual({\n api: { cloudfront: { distributionId: \"123\" } },\n core: { bucket: { name: \"my-bucket\" } }\n });\n });\n\n it(\"should cache the result and not call loader again\", async () => {\n let callCount = 0;\n const loader: IServiceManifestLoader = {\n async load() {\n callCount++;\n return [{ name: \"api\", manifest: { url: \"https://example.com\" } }];\n }\n };\n\n ServiceDiscovery.setLoader(loader);\n\n await ServiceDiscovery.load();\n await ServiceDiscovery.load();\n await ServiceDiscovery.load();\n\n expect(callCount).toBe(1);\n });\n\n it(\"should return undefined when loader returns undefined\", async () => {\n const loader: IServiceManifestLoader = {\n async load() {\n return undefined;\n }\n };\n\n ServiceDiscovery.setLoader(loader);\n\n const result = await ServiceDiscovery.load();\n expect(result).toBeUndefined();\n });\n\n it(\"should reload after clear()\", async () => {\n let callCount = 0;\n const loader: IServiceManifestLoader = {\n async load() {\n callCount++;\n return [{ name: \"api\", manifest: { version: callCount } }];\n }\n };\n\n ServiceDiscovery.setLoader(loader);\n\n const first = await ServiceDiscovery.load();\n expect(first).toEqual({ api: { version: 1 } });\n\n ServiceDiscovery.clear();\n\n const second = await ServiceDiscovery.load();\n expect(second).toEqual({ api: { version: 2 } });\n expect(callCount).toBe(2);\n });\n});\n"],"names":["describe","beforeEach","ServiceDiscovery","it","undefined","expect","loader","result","callCount","first","second"],"mappings":";;AAIAA,SAAS,oBAAoB;IACzBC,WAAW;QACPC,iBAAiB,KAAK;IAC1B;IAEAC,GAAG,oCAAoC;QAClCD,iBAAAA,MAA+B,GAAGE;QAEnC,MAAMC,OAAOH,iBAAiB,IAAI,IAAI,OAAO,CAAC,OAAO,CACjD;IAER;IAEAC,GAAG,kDAAkD;QACjD,MAAMG,SAAiC;YACnC,MAAM;gBACF,OAAO;oBACH;wBAAE,MAAM;wBAAO,UAAU;4BAAE,YAAY;gCAAE,gBAAgB;4BAAM;wBAAE;oBAAE;oBACnE;wBAAE,MAAM;wBAAQ,UAAU;4BAAE,QAAQ;gCAAE,MAAM;4BAAY;wBAAE;oBAAE;iBAC/D;YACL;QACJ;QAEAJ,iBAAiB,SAAS,CAACI;QAE3B,MAAMC,SAAS,MAAML,iBAAiB,IAAI;QAE1CG,OAAOE,QAAQ,OAAO,CAAC;YACnB,KAAK;gBAAE,YAAY;oBAAE,gBAAgB;gBAAM;YAAE;YAC7C,MAAM;gBAAE,QAAQ;oBAAE,MAAM;gBAAY;YAAE;QAC1C;IACJ;IAEAJ,GAAG,qDAAqD;QACpD,IAAIK,YAAY;QAChB,MAAMF,SAAiC;YACnC,MAAM;gBACFE;gBACA,OAAO;oBAAC;wBAAE,MAAM;wBAAO,UAAU;4BAAE,KAAK;wBAAsB;oBAAE;iBAAE;YACtE;QACJ;QAEAN,iBAAiB,SAAS,CAACI;QAE3B,MAAMJ,iBAAiB,IAAI;QAC3B,MAAMA,iBAAiB,IAAI;QAC3B,MAAMA,iBAAiB,IAAI;QAE3BG,OAAOG,WAAW,IAAI,CAAC;IAC3B;IAEAL,GAAG,yDAAyD;QACxD,MAAMG,SAAiC;YACnC,MAAM,SAEN;QACJ;QAEAJ,iBAAiB,SAAS,CAACI;QAE3B,MAAMC,SAAS,MAAML,iBAAiB,IAAI;QAC1CG,OAAOE,QAAQ,aAAa;IAChC;IAEAJ,GAAG,+BAA+B;QAC9B,IAAIK,YAAY;QAChB,MAAMF,SAAiC;YACnC,MAAM;gBACFE;gBACA,OAAO;oBAAC;wBAAE,MAAM;wBAAO,UAAU;4BAAE,SAASA;wBAAU;oBAAE;iBAAE;YAC9D;QACJ;QAEAN,iBAAiB,SAAS,CAACI;QAE3B,MAAMG,QAAQ,MAAMP,iBAAiB,IAAI;QACzCG,OAAOI,OAAO,OAAO,CAAC;YAAE,KAAK;gBAAE,SAAS;YAAE;QAAE;QAE5CP,iBAAiB,KAAK;QAEtB,MAAMQ,SAAS,MAAMR,iBAAiB,IAAI;QAC1CG,OAAOK,QAAQ,OAAO,CAAC;YAAE,KAAK;gBAAE,SAAS;YAAE;QAAE;QAC7CL,OAAOG,WAAW,IAAI,CAAC;IAC3B;AACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ServiceDiscovery } from "./ServiceDiscovery.js";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Slugify } from "./abstractions.js";
|
|
2
|
+
declare class DefaultSlugifyImpl implements Slugify.Interface {
|
|
3
|
+
execute(value: string): string;
|
|
4
|
+
}
|
|
5
|
+
export declare const DefaultSlugify: typeof DefaultSlugifyImpl & {
|
|
6
|
+
__abstraction: import("@webiny/di").Abstraction<import("./abstractions.js").ISlugify>;
|
|
7
|
+
};
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import slugify from "slugify";
|
|
2
|
+
import { Slugify } from "./abstractions.js";
|
|
3
|
+
const DEFAULT_OPTIONS = {
|
|
4
|
+
replacement: "-",
|
|
5
|
+
lower: true,
|
|
6
|
+
remove: /[*#?<>_{}[\]+~.()'"!:;@]/g,
|
|
7
|
+
trim: false
|
|
8
|
+
};
|
|
9
|
+
class DefaultSlugifyImpl {
|
|
10
|
+
execute(value) {
|
|
11
|
+
return slugify(value, DEFAULT_OPTIONS);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const DefaultSlugify = Slugify.createImplementation({
|
|
15
|
+
implementation: DefaultSlugifyImpl,
|
|
16
|
+
dependencies: []
|
|
17
|
+
});
|
|
18
|
+
export { DefaultSlugify };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=DefaultSlugify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/slugify/DefaultSlugify.js","sources":["../../../src/features/slugify/DefaultSlugify.ts"],"sourcesContent":["import baseSlugify from \"slugify\";\nimport { Slugify } from \"./abstractions.js\";\n\n/**\n * Webiny's canonical slug options. These were previously duplicated at every call site; keeping them\n * in one private place means projects can change slug generation everywhere at once by decorating\n * Slugify — not by passing per-call options, so the abstraction stays independent of this library.\n */\nconst DEFAULT_OPTIONS = {\n replacement: \"-\",\n lower: true,\n remove: /[*#?<>_{}[\\]+~.()'\"!:;@]/g,\n trim: false\n};\n\nclass DefaultSlugifyImpl implements Slugify.Interface {\n execute(value: string): string {\n return baseSlugify(value, DEFAULT_OPTIONS);\n }\n}\n\nexport const DefaultSlugify = Slugify.createImplementation({\n implementation: DefaultSlugifyImpl,\n dependencies: []\n});\n"],"names":["DEFAULT_OPTIONS","DefaultSlugifyImpl","value","baseSlugify","DefaultSlugify","Slugify"],"mappings":";;AAQA,MAAMA,kBAAkB;IACpB,aAAa;IACb,OAAO;IACP,QAAQ;IACR,MAAM;AACV;AAEA,MAAMC;IACF,QAAQC,KAAa,EAAU;QAC3B,OAAOC,QAAYD,OAAOF;IAC9B;AACJ;AAEO,MAAMI,iBAAiBC,QAAQ,oBAAoB,CAAC;IACvD,gBAAgBJ;IAChB,cAAc,EAAE;AACpB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface ISlugify {
|
|
2
|
+
/**
|
|
3
|
+
* Turns a value into a URL-friendly slug using Webiny's canonical options. This is the
|
|
4
|
+
* fine-grained seam behind `StringFormatter.slugify()` — decorate `Slugify` alone to change slug
|
|
5
|
+
* logic without touching the rest of the string formatter.
|
|
6
|
+
*/
|
|
7
|
+
execute(value: string): string;
|
|
8
|
+
}
|
|
9
|
+
export declare const Slugify: import("@webiny/di").Abstraction<ISlugify>;
|
|
10
|
+
export declare namespace Slugify {
|
|
11
|
+
type Interface = ISlugify;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/slugify/abstractions.js","sources":["../../../src/features/slugify/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/api\";\n\nexport interface ISlugify {\n /**\n * Turns a value into a URL-friendly slug using Webiny's canonical options. This is the\n * fine-grained seam behind `StringFormatter.slugify()` — decorate `Slugify` alone to change slug\n * logic without touching the rest of the string formatter.\n */\n execute(value: string): string;\n}\n\nexport const Slugify = createAbstraction<ISlugify>(\"Slugify\");\n\nexport namespace Slugify {\n export type Interface = ISlugify;\n}\n"],"names":["Slugify","createAbstraction"],"mappings":";AAWO,MAAMA,UAAUC,kBAA4B"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createFeature } from "@webiny/feature/api";
|
|
2
|
+
import { DefaultSlugify } from "./DefaultSlugify.js";
|
|
3
|
+
const SlugifyFeature = createFeature({
|
|
4
|
+
name: "SlugifyFeature",
|
|
5
|
+
register (container) {
|
|
6
|
+
container.register(DefaultSlugify);
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
export { SlugifyFeature };
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=feature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/slugify/feature.js","sources":["../../../src/features/slugify/feature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport { DefaultSlugify } from \"./DefaultSlugify.js\";\n\nexport const SlugifyFeature = createFeature({\n name: \"SlugifyFeature\",\n register(container) {\n container.register(DefaultSlugify);\n }\n});\n"],"names":["SlugifyFeature","createFeature","container","DefaultSlugify"],"mappings":";;AAGO,MAAMA,iBAAiBC,cAAc;IACxC,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC;IACvB;AACJ"}
|