@intlayer/backend 7.5.12 → 7.5.14
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/dist/assets/utils/AI/askDocQuestion/embeddings/blog/en/per-component_vs_centralized_i18n.json +6158 -0
- package/dist/assets/utils/AI/askDocQuestion/embeddings/frequent_questions/en/error-vite-env-only.json +2054 -0
- package/dist/esm/controllers/ai.controller.mjs.map +1 -1
- package/dist/esm/controllers/bitbucket.controller.mjs.map +1 -1
- package/dist/esm/controllers/dictionary.controller.mjs.map +1 -1
- package/dist/esm/controllers/eventListener.controller.mjs.map +1 -1
- package/dist/esm/controllers/github.controller.mjs.map +1 -1
- package/dist/esm/controllers/gitlab.controller.mjs.map +1 -1
- package/dist/esm/controllers/project.controller.mjs.map +1 -1
- package/dist/esm/controllers/stripe.controller.mjs.map +1 -1
- package/dist/esm/controllers/tag.controller.mjs.map +1 -1
- package/dist/esm/controllers/user.controller.mjs.map +1 -1
- package/dist/esm/emails/InviteUserEmail.mjs.map +1 -1
- package/dist/esm/emails/MagicLinkEmail.mjs.map +1 -1
- package/dist/esm/emails/OAuthTokenCreatedEmail.mjs.map +1 -1
- package/dist/esm/emails/PasswordChangeConfirmation.mjs.map +1 -1
- package/dist/esm/emails/ResetUserPassword.mjs.map +1 -1
- package/dist/esm/emails/SubscriptionPaymentCancellation.mjs.map +1 -1
- package/dist/esm/emails/SubscriptionPaymentError.mjs.map +1 -1
- package/dist/esm/emails/SubscriptionPaymentSuccess.mjs.map +1 -1
- package/dist/esm/emails/ValidateUserEmail.mjs.map +1 -1
- package/dist/esm/emails/Welcome.mjs.map +1 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/services/bitbucket.service.mjs.map +1 -1
- package/dist/esm/services/github.service.mjs.map +1 -1
- package/dist/esm/services/gitlab.service.mjs.map +1 -1
- package/dist/esm/services/oAuth2.service.mjs.map +1 -1
- package/dist/esm/services/projectAccessKey.service.mjs.map +1 -1
- package/dist/esm/services/subscription.service.mjs.map +1 -1
- package/dist/esm/services/user.service.mjs.map +1 -1
- package/dist/esm/services/webhook.service.mjs.map +1 -1
- package/dist/esm/utils/AI/askDocQuestion/askDocQuestion.mjs.map +1 -1
- package/dist/esm/utils/AI/askDocQuestion/embeddings/blog/en/per-component_vs_centralized_i18n.json +6158 -0
- package/dist/esm/utils/AI/askDocQuestion/embeddings/frequent_questions/en/error-vite-env-only.json +2054 -0
- package/dist/esm/utils/AI/askDocQuestion/indexMarkdownFiles.mjs.map +1 -1
- package/dist/esm/utils/AI/auditDictionary/index.mjs.map +1 -1
- package/dist/esm/utils/AI/auditDictionaryField/index.mjs.map +1 -1
- package/dist/esm/utils/AI/auditDictionaryMetadata/index.mjs.map +1 -1
- package/dist/esm/utils/AI/auditTag/index.mjs.map +1 -1
- package/dist/esm/utils/AI/autocomplete/index.mjs.map +1 -1
- package/dist/esm/utils/AI/customQuery/index.mjs.map +1 -1
- package/dist/esm/utils/AI/translateJSON/index.mjs.map +1 -1
- package/dist/esm/utils/accessControl.mjs.map +1 -1
- package/dist/esm/utils/auth/getAuth.mjs.map +1 -1
- package/dist/esm/utils/cors.mjs.map +1 -1
- package/dist/esm/utils/ensureArrayQueryFilter.mjs.map +1 -1
- package/dist/esm/utils/ensureMongoDocumentToObject.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getDictionaryFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getDiscussionFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getOrganizationFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getProjectFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getTagFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/filtersAndPagination/getUserFiltersAndPagination.mjs.map +1 -1
- package/dist/esm/utils/mongoDB/connectDB.mjs.map +1 -1
- package/dist/esm/utils/oAuth2.mjs.map +1 -1
- package/dist/esm/utils/permissions.mjs.map +1 -1
- package/dist/esm/utils/plan.mjs.map +1 -1
- package/dist/esm/utils/rateLimiter.mjs.map +1 -1
- package/dist/esm/utils/validation/validateArray.mjs.map +1 -1
- package/dist/esm/utils/validation/validateDictionary.mjs.map +1 -1
- package/dist/esm/utils/validation/validateOrganization.mjs.map +1 -1
- package/dist/esm/utils/validation/validateProject.mjs.map +1 -1
- package/dist/esm/utils/validation/validateString.mjs.map +1 -1
- package/dist/esm/utils/validation/validateTag.mjs.map +1 -1
- package/dist/esm/utils/validation/validateUser.mjs.map +1 -1
- package/dist/esm/webhooks/stripe.webhook.mjs.map +1 -1
- package/dist/types/controllers/ai.controller.d.ts.map +1 -1
- package/dist/types/controllers/gitlab.controller.d.ts.map +1 -1
- package/dist/types/emails/InviteUserEmail.d.ts +4 -4
- package/dist/types/emails/InviteUserEmail.d.ts.map +1 -1
- package/dist/types/emails/MagicLinkEmail.d.ts +4 -4
- package/dist/types/emails/OAuthTokenCreatedEmail.d.ts +4 -4
- package/dist/types/emails/PasswordChangeConfirmation.d.ts +4 -4
- package/dist/types/emails/ResetUserPassword.d.ts +4 -4
- package/dist/types/emails/SubscriptionPaymentCancellation.d.ts +4 -4
- package/dist/types/emails/SubscriptionPaymentError.d.ts +4 -4
- package/dist/types/emails/SubscriptionPaymentError.d.ts.map +1 -1
- package/dist/types/emails/SubscriptionPaymentSuccess.d.ts +4 -4
- package/dist/types/emails/ValidateUserEmail.d.ts +4 -4
- package/dist/types/emails/Welcome.d.ts +4 -4
- package/dist/types/models/dictionary.model.d.ts +4 -4
- package/dist/types/models/discussion.model.d.ts +3 -3
- package/dist/types/models/oAuth2.model.d.ts +3 -3
- package/dist/types/schemas/dictionary.schema.d.ts +6 -6
- package/dist/types/schemas/discussion.schema.d.ts +6 -6
- package/dist/types/schemas/oAuth2.schema.d.ts +5 -5
- package/dist/types/schemas/organization.schema.d.ts +6 -6
- package/dist/types/schemas/plans.schema.d.ts +6 -6
- package/dist/types/schemas/plans.schema.d.ts.map +1 -1
- package/dist/types/schemas/project.schema.d.ts +6 -6
- package/dist/types/schemas/project.schema.d.ts.map +1 -1
- package/dist/types/schemas/session.schema.d.ts +6 -6
- package/dist/types/schemas/tag.schema.d.ts +6 -6
- package/dist/types/schemas/user.schema.d.ts +6 -6
- package/dist/types/schemas/user.schema.d.ts.map +1 -1
- package/dist/types/utils/filtersAndPagination/getDictionaryFiltersAndPagination.d.ts +2 -2
- package/dist/types/utils/filtersAndPagination/getDiscussionFiltersAndPagination.d.ts +2 -2
- package/dist/types/utils/filtersAndPagination/getOrganizationFiltersAndPagination.d.ts +2 -2
- package/dist/types/utils/filtersAndPagination/getTagFiltersAndPagination.d.ts +2 -2
- package/package.json +20 -20
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.mjs","names":["roles: Roles[]","rolesCheck: any"],"sources":["../../../src/utils/permissions.ts"],"sourcesContent":["import type { Dictionary, DictionaryAPI } from '@/types/dictionary.types';\nimport type { Organization, OrganizationAPI } from '@/types/organization.types';\nimport type { Project, ProjectAPI } from '@/types/project.types';\nimport type { SessionContext } from '@/types/session.types';\nimport type { Tag, TagAPI } from '@/types/tag.types';\nimport type { User, UserAPI } from '@/types/user.types';\n\n/**\n * A named grouping of privileges (e.g. `\"org_admin\"`).\n * Users are *granted* one or more Roles.\n */\nexport type Roles =\n | 'user'\n | 'admin'\n | 'org_admin'\n | 'org_user'\n | 'project_admin'\n | 'project_user'\n | 'project_reviewer';\n\n/**\n * An atomic operation that can be performed on a resource.\n * - **read**: view or list\n * - **write**: create or update\n * - **admin**: delete or change permissions\n */\nexport type Action = 'read' | 'write' | 'admin';\n\n/**\n * A first‑class entity in your domain model that you want to protect.\n */\nexport type Resource = {\n organization: Organization;\n project: Project;\n dictionary: Dictionary;\n tag: Tag;\n user: User;\n};\n\n/**\n * A literal string combining a Resource and an Action, e.g. `\"project:write\"`.\n * This is the *unit* checked at runtime in your middleware.\n */\nexport type Permission = `${keyof Resource}:${Action}`;\n\ntype CheckPrivilege = (\n args: any\n) => boolean | undefined | Promise<boolean> | Promise<undefined>;\n\ntype RolePolicy = Record<Roles, Partial<Record<Permission, CheckPrivilege>>>;\n\nexport const ROLE_POLICY = {\n admin: {\n 'organization:read': () => true,\n 'organization:write': () => true,\n 'organization:admin': () => true,\n 'project:read': () => true,\n 'project:write': () => true,\n 'project:admin': () => true,\n 'dictionary:read': () => true,\n 'dictionary:write': () => true,\n 'dictionary:admin': () => true,\n 'tag:read': () => true,\n 'tag:write': () => true,\n 'tag:admin': () => true,\n 'user:read': () => true,\n 'user:write': () => true,\n 'user:admin': () => true,\n },\n user: {\n 'user:read': ({\n user,\n targetUsers,\n }: SessionContext & { targetUsers: (User | UserAPI)[] }) =>\n targetUsers.every(\n (targetUser) =>\n String(targetUser.id) === String(user?.id) &&\n targetUser.email === user?.email\n ),\n 'user:write': ({\n user,\n targetUsers,\n }: SessionContext & { targetUsers: (User | UserAPI)[] }) =>\n targetUsers.every(\n (targetUser) =>\n String(targetUser.id) === String(user?.id) &&\n targetUser.email === user?.email\n ),\n 'user:admin': ({\n user,\n targetUsers,\n }: SessionContext & { targetUsers: (User | UserAPI)[] }) =>\n targetUsers.every(\n (targetUser) =>\n String(targetUser.id) === String(user?.id) &&\n targetUser.email === user?.email\n ),\n 'organization:read': ({\n user,\n targetOrganizations,\n }: SessionContext & {\n targetOrganizations: (Organization | OrganizationAPI)[];\n }) =>\n targetOrganizations.every((organization) =>\n organization?.membersIds?.map(String).includes(String(user?.id))\n ),\n },\n org_admin: {\n 'organization:read': ({\n organization,\n targetOrganizations,\n }: SessionContext & {\n targetOrganizations: (Organization | OrganizationAPI)[];\n }) =>\n targetOrganizations.every(\n (targetOrg) => String(targetOrg.id) === String(organization?.id)\n ),\n 'organization:write': ({\n organization,\n targetOrganizations,\n }: SessionContext & {\n targetOrganizations: (Organization | OrganizationAPI)[];\n }) =>\n targetOrganizations.every(\n (targetOrg) => String(targetOrg.id) === String(organization?.id)\n ),\n 'organization:admin': ({\n organization,\n targetOrganizations,\n }: SessionContext & {\n targetOrganizations: (Organization | OrganizationAPI)[];\n }) =>\n targetOrganizations.every(\n (targetOrg) => String(targetOrg.id) === String(organization?.id)\n ),\n\n 'project:read': ({ organization, project }: SessionContext) =>\n String(project?.organizationId) === String(organization?.id),\n 'project:write': ({ organization, project }: SessionContext) =>\n String(project?.organizationId) === String(organization?.id),\n 'project:admin': ({ organization, project }: SessionContext) =>\n String(project?.organizationId) === String(organization?.id),\n\n 'tag:read': ({ organization, project }: SessionContext) =>\n String(project?.organizationId) === String(organization?.id),\n 'tag:write': ({ organization, project }: SessionContext) =>\n String(project?.organizationId) === String(organization?.id),\n 'tag:admin': ({ organization, project }: SessionContext) =>\n String(project?.organizationId) === String(organization?.id),\n\n 'user:write': ({\n organization,\n targetUsers,\n }: SessionContext & { targetUsers: (User | UserAPI)[] }) =>\n targetUsers.every((targetUser) =>\n organization?.membersIds?.map(String).includes(String(targetUser?.id))\n ),\n },\n org_user: {\n 'organization:read': ({\n organization,\n targetOrganizations,\n }: SessionContext & {\n targetOrganizations: (Organization | OrganizationAPI)[];\n }) =>\n targetOrganizations.every(\n (targetOrg) => String(targetOrg.id) === String(organization?.id)\n ),\n\n 'project:read': ({\n user,\n targetProjects,\n }: SessionContext & {\n targetProjects: (Project | ProjectAPI)[];\n }) =>\n targetProjects?.every((project) =>\n project?.membersIds?.map(String).includes(String(user?.id))\n ),\n\n 'user:read': ({\n organization,\n targetUsers,\n }: SessionContext & { targetUsers: (User | UserAPI)[] }) =>\n targetUsers.every((targetUser) =>\n organization?.membersIds?.map(String).includes(String(targetUser?.id))\n ),\n },\n project_admin: {\n 'project:read': ({\n project,\n targetProjectIds,\n }: SessionContext & {\n targetProjectIds?: (Project | ProjectAPI)['id'][];\n }) =>\n targetProjectIds?.every(\n (projectId) => String(project?.id) === String(projectId)\n ),\n 'project:write': ({\n project,\n targetProjectIds,\n }: SessionContext & {\n targetProjectIds?: (Project | ProjectAPI)['id'][];\n }) =>\n targetProjectIds?.every(\n (projectId) => String(project?.id) === String(projectId)\n ),\n 'project:admin': ({\n project,\n targetProjectIds,\n }: SessionContext & {\n targetProjectIds?: (Project | ProjectAPI)['id'][];\n }) =>\n targetProjectIds?.every(\n (projectId) => String(project?.id) === String(projectId)\n ),\n\n 'tag:read': ({\n project,\n targetTags,\n }: SessionContext & { targetTags: (Tag | TagAPI)[] }) =>\n targetTags.every((tag) => String(project?.id) === String(tag?.projectId)),\n 'tag:write': ({\n project,\n targetTags,\n }: SessionContext & { targetTags: (Tag | TagAPI)[] }) =>\n targetTags.every((tag) => String(project?.id) === String(tag?.projectId)),\n 'tag:admin': ({\n project,\n targetTags,\n }: SessionContext & { targetTags: (Tag | TagAPI)[] }) =>\n targetTags.every((tag) => String(project?.id) === String(tag?.projectId)),\n\n 'user:write': ({\n project,\n targetUsers,\n }: SessionContext & { targetUsers: (User | UserAPI)[] }) =>\n targetUsers.every((targetUser) =>\n project?.membersIds?.map(String).includes(String(targetUser?.id))\n ),\n\n 'dictionary:read': ({ project, user }: SessionContext) =>\n project?.adminsIds?.map(String).includes(String(user?.id)),\n 'dictionary:write': ({ project, user }: SessionContext) =>\n project?.adminsIds?.map(String).includes(String(user?.id)),\n 'dictionary:admin': ({ project, user }: SessionContext) =>\n project?.adminsIds?.map(String).includes(String(user?.id)),\n },\n project_user: {\n 'project:read': ({ user, organization, project }: SessionContext) =>\n String(organization?.id) === String(project?.organizationId) &&\n organization?.membersIds?.map(String).includes(String(user?.id)) &&\n project?.membersIds?.map(String).includes(String(user?.id)),\n\n 'dictionary:read': ({\n user,\n project,\n targetDictionaries,\n }: SessionContext & {\n targetDictionaries: (Dictionary | DictionaryAPI)[];\n }) =>\n project?.membersIds?.map(String).includes(String(user?.id)) &&\n targetDictionaries.every((dictionary) =>\n dictionary?.projectIds?.map(String).includes(String(project?.id))\n ),\n 'dictionary:write': ({ user, project }: SessionContext) =>\n project?.adminsIds?.map(String).includes(String(user?.id)),\n\n 'tag:read': ({\n project,\n targetTags,\n user,\n }: SessionContext & {\n targetTags: (Tag | TagAPI)[];\n }) =>\n project?.membersIds?.map(String).includes(String(user?.id)) &&\n targetTags.every((tag) => String(project?.id) === String(tag?.projectId)),\n 'tag:write': ({\n project,\n targetTags,\n user,\n }: SessionContext & {\n targetTags: (Tag | TagAPI)[];\n }) =>\n project?.membersIds?.map(String).includes(String(user?.id)) &&\n targetTags.every((tag) => String(project?.id) === String(tag?.projectId)),\n 'tag:admin': ({\n user,\n project,\n targetTags,\n }: SessionContext & {\n targetTags: (Tag | TagAPI)[];\n }) =>\n project?.adminsIds?.map(String).includes(String(user?.id)) &&\n targetTags.every((tag) => String(project?.id) === String(tag?.projectId)),\n\n 'user:read': ({\n project,\n targetUsers,\n }: SessionContext & { targetUsers: (User | UserAPI)[] }) =>\n targetUsers.every((targetUser) =>\n project?.membersIds?.map(String).includes(String(targetUser?.id))\n ),\n },\n project_reviewer: {\n 'dictionary:read': ({ user, project }: SessionContext) =>\n project?.membersIds?.map(String).includes(String(user?.id)),\n 'dictionary:write': ({ user, project }: SessionContext) =>\n project?.membersIds?.map(String).includes(String(user?.id)),\n\n 'tag:read': () => true,\n },\n} as const satisfies RolePolicy;\n\nexport const getSessionRoles = ({\n user,\n organization,\n project,\n}: SessionContext): Roles[] => {\n const roles: Roles[] = [];\n\n if (!user) {\n return roles;\n }\n\n roles.push('user');\n\n const isUserAdmin = user.role === 'admin';\n\n if (isUserAdmin) {\n roles.push('admin');\n }\n\n if (!organization) {\n return roles;\n }\n\n const isOrganizationAdmin = organization.adminsIds\n ?.map(String)\n .includes(String(user?.id));\n\n if (isOrganizationAdmin) {\n roles.push('org_admin');\n }\n\n const isOrganizationMember = organization.membersIds\n ?.map(String)\n .includes(String(user?.id));\n\n if (isOrganizationMember) {\n roles.push('org_user');\n }\n\n if (!project) {\n return roles;\n }\n\n const isProjectAdmin = project.adminsIds\n ?.map(String)\n .includes(String(user?.id));\n\n if (isProjectAdmin) {\n roles.push('project_admin');\n }\n\n const isProjectMember = project?.membersIds\n ?.map(String)\n .includes(String(user?.id));\n\n if (isProjectMember) {\n roles.push('project_user');\n }\n\n // const isProjectReviewer =\n // session.project?.reviewersIds?.includes(session.user!.id);\n\n // if (isProjectReviewer) {\n // roles.push('project_reviewer');\n // }\n\n return roles;\n};\n\nexport const computeEffectivePermission = (roles: Roles[]): Permission[] =>\n Array.from(\n new Set(\n roles.flatMap((role) => Object.keys(ROLE_POLICY[role]) as Permission[])\n )\n );\n\n/**\n * Intersect two permission lists\n * @param permissionList1 - The first permission list\n * @param permissionList2 - The second permission list\n * @returns The intersection of the two permission lists (only permissions present in both)\n */\nexport const intersectPermissions = (\n permissions1: Permission[],\n permissions2: Permission[]\n): Permission[] =>\n permissions1.filter((permission) => permissions2.includes(permission));\n\ntype PermissionResult<\n R extends Roles,\n P extends Permission,\n> = (typeof ROLE_POLICY)[R] extends infer RolePerms\n ? RolePerms extends Record<string, (args: any) => any>\n ? P extends keyof RolePerms\n ? RolePerms[P] extends undefined\n ? never\n : RolePerms[P]\n : never\n : never\n : never;\n\nexport const hasPermission = <P extends Permission>(\n roles: Roles[],\n permission: P\n): PermissionResult<Roles, P> => {\n const rolesCheck: any = roles.map(\n (role) =>\n ROLE_POLICY[role]?.[\n permission as keyof (typeof ROLE_POLICY)[typeof role]\n ] ?? (() => false)\n ) as unknown as PermissionResult<Roles, P>[];\n\n return ((args: any) => rolesCheck.some((check: any) => check(args))) as any;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"permissions.mjs","names":[],"sources":["../../../src/utils/permissions.ts"],"sourcesContent":["import type { Dictionary, DictionaryAPI } from '@/types/dictionary.types';\nimport type { Organization, OrganizationAPI } from '@/types/organization.types';\nimport type { Project, ProjectAPI } from '@/types/project.types';\nimport type { SessionContext } from '@/types/session.types';\nimport type { Tag, TagAPI } from '@/types/tag.types';\nimport type { User, UserAPI } from '@/types/user.types';\n\n/**\n * A named grouping of privileges (e.g. `\"org_admin\"`).\n * Users are *granted* one or more Roles.\n */\nexport type Roles =\n | 'user'\n | 'admin'\n | 'org_admin'\n | 'org_user'\n | 'project_admin'\n | 'project_user'\n | 'project_reviewer';\n\n/**\n * An atomic operation that can be performed on a resource.\n * - **read**: view or list\n * - **write**: create or update\n * - **admin**: delete or change permissions\n */\nexport type Action = 'read' | 'write' | 'admin';\n\n/**\n * A first‑class entity in your domain model that you want to protect.\n */\nexport type Resource = {\n organization: Organization;\n project: Project;\n dictionary: Dictionary;\n tag: Tag;\n user: User;\n};\n\n/**\n * A literal string combining a Resource and an Action, e.g. `\"project:write\"`.\n * This is the *unit* checked at runtime in your middleware.\n */\nexport type Permission = `${keyof Resource}:${Action}`;\n\ntype CheckPrivilege = (\n args: any\n) => boolean | undefined | Promise<boolean> | Promise<undefined>;\n\ntype RolePolicy = Record<Roles, Partial<Record<Permission, CheckPrivilege>>>;\n\nexport const ROLE_POLICY = {\n admin: {\n 'organization:read': () => true,\n 'organization:write': () => true,\n 'organization:admin': () => true,\n 'project:read': () => true,\n 'project:write': () => true,\n 'project:admin': () => true,\n 'dictionary:read': () => true,\n 'dictionary:write': () => true,\n 'dictionary:admin': () => true,\n 'tag:read': () => true,\n 'tag:write': () => true,\n 'tag:admin': () => true,\n 'user:read': () => true,\n 'user:write': () => true,\n 'user:admin': () => true,\n },\n user: {\n 'user:read': ({\n user,\n targetUsers,\n }: SessionContext & { targetUsers: (User | UserAPI)[] }) =>\n targetUsers.every(\n (targetUser) =>\n String(targetUser.id) === String(user?.id) &&\n targetUser.email === user?.email\n ),\n 'user:write': ({\n user,\n targetUsers,\n }: SessionContext & { targetUsers: (User | UserAPI)[] }) =>\n targetUsers.every(\n (targetUser) =>\n String(targetUser.id) === String(user?.id) &&\n targetUser.email === user?.email\n ),\n 'user:admin': ({\n user,\n targetUsers,\n }: SessionContext & { targetUsers: (User | UserAPI)[] }) =>\n targetUsers.every(\n (targetUser) =>\n String(targetUser.id) === String(user?.id) &&\n targetUser.email === user?.email\n ),\n 'organization:read': ({\n user,\n targetOrganizations,\n }: SessionContext & {\n targetOrganizations: (Organization | OrganizationAPI)[];\n }) =>\n targetOrganizations.every((organization) =>\n organization?.membersIds?.map(String).includes(String(user?.id))\n ),\n },\n org_admin: {\n 'organization:read': ({\n organization,\n targetOrganizations,\n }: SessionContext & {\n targetOrganizations: (Organization | OrganizationAPI)[];\n }) =>\n targetOrganizations.every(\n (targetOrg) => String(targetOrg.id) === String(organization?.id)\n ),\n 'organization:write': ({\n organization,\n targetOrganizations,\n }: SessionContext & {\n targetOrganizations: (Organization | OrganizationAPI)[];\n }) =>\n targetOrganizations.every(\n (targetOrg) => String(targetOrg.id) === String(organization?.id)\n ),\n 'organization:admin': ({\n organization,\n targetOrganizations,\n }: SessionContext & {\n targetOrganizations: (Organization | OrganizationAPI)[];\n }) =>\n targetOrganizations.every(\n (targetOrg) => String(targetOrg.id) === String(organization?.id)\n ),\n\n 'project:read': ({ organization, project }: SessionContext) =>\n String(project?.organizationId) === String(organization?.id),\n 'project:write': ({ organization, project }: SessionContext) =>\n String(project?.organizationId) === String(organization?.id),\n 'project:admin': ({ organization, project }: SessionContext) =>\n String(project?.organizationId) === String(organization?.id),\n\n 'tag:read': ({ organization, project }: SessionContext) =>\n String(project?.organizationId) === String(organization?.id),\n 'tag:write': ({ organization, project }: SessionContext) =>\n String(project?.organizationId) === String(organization?.id),\n 'tag:admin': ({ organization, project }: SessionContext) =>\n String(project?.organizationId) === String(organization?.id),\n\n 'user:write': ({\n organization,\n targetUsers,\n }: SessionContext & { targetUsers: (User | UserAPI)[] }) =>\n targetUsers.every((targetUser) =>\n organization?.membersIds?.map(String).includes(String(targetUser?.id))\n ),\n },\n org_user: {\n 'organization:read': ({\n organization,\n targetOrganizations,\n }: SessionContext & {\n targetOrganizations: (Organization | OrganizationAPI)[];\n }) =>\n targetOrganizations.every(\n (targetOrg) => String(targetOrg.id) === String(organization?.id)\n ),\n\n 'project:read': ({\n user,\n targetProjects,\n }: SessionContext & {\n targetProjects: (Project | ProjectAPI)[];\n }) =>\n targetProjects?.every((project) =>\n project?.membersIds?.map(String).includes(String(user?.id))\n ),\n\n 'user:read': ({\n organization,\n targetUsers,\n }: SessionContext & { targetUsers: (User | UserAPI)[] }) =>\n targetUsers.every((targetUser) =>\n organization?.membersIds?.map(String).includes(String(targetUser?.id))\n ),\n },\n project_admin: {\n 'project:read': ({\n project,\n targetProjectIds,\n }: SessionContext & {\n targetProjectIds?: (Project | ProjectAPI)['id'][];\n }) =>\n targetProjectIds?.every(\n (projectId) => String(project?.id) === String(projectId)\n ),\n 'project:write': ({\n project,\n targetProjectIds,\n }: SessionContext & {\n targetProjectIds?: (Project | ProjectAPI)['id'][];\n }) =>\n targetProjectIds?.every(\n (projectId) => String(project?.id) === String(projectId)\n ),\n 'project:admin': ({\n project,\n targetProjectIds,\n }: SessionContext & {\n targetProjectIds?: (Project | ProjectAPI)['id'][];\n }) =>\n targetProjectIds?.every(\n (projectId) => String(project?.id) === String(projectId)\n ),\n\n 'tag:read': ({\n project,\n targetTags,\n }: SessionContext & { targetTags: (Tag | TagAPI)[] }) =>\n targetTags.every((tag) => String(project?.id) === String(tag?.projectId)),\n 'tag:write': ({\n project,\n targetTags,\n }: SessionContext & { targetTags: (Tag | TagAPI)[] }) =>\n targetTags.every((tag) => String(project?.id) === String(tag?.projectId)),\n 'tag:admin': ({\n project,\n targetTags,\n }: SessionContext & { targetTags: (Tag | TagAPI)[] }) =>\n targetTags.every((tag) => String(project?.id) === String(tag?.projectId)),\n\n 'user:write': ({\n project,\n targetUsers,\n }: SessionContext & { targetUsers: (User | UserAPI)[] }) =>\n targetUsers.every((targetUser) =>\n project?.membersIds?.map(String).includes(String(targetUser?.id))\n ),\n\n 'dictionary:read': ({ project, user }: SessionContext) =>\n project?.adminsIds?.map(String).includes(String(user?.id)),\n 'dictionary:write': ({ project, user }: SessionContext) =>\n project?.adminsIds?.map(String).includes(String(user?.id)),\n 'dictionary:admin': ({ project, user }: SessionContext) =>\n project?.adminsIds?.map(String).includes(String(user?.id)),\n },\n project_user: {\n 'project:read': ({ user, organization, project }: SessionContext) =>\n String(organization?.id) === String(project?.organizationId) &&\n organization?.membersIds?.map(String).includes(String(user?.id)) &&\n project?.membersIds?.map(String).includes(String(user?.id)),\n\n 'dictionary:read': ({\n user,\n project,\n targetDictionaries,\n }: SessionContext & {\n targetDictionaries: (Dictionary | DictionaryAPI)[];\n }) =>\n project?.membersIds?.map(String).includes(String(user?.id)) &&\n targetDictionaries.every((dictionary) =>\n dictionary?.projectIds?.map(String).includes(String(project?.id))\n ),\n 'dictionary:write': ({ user, project }: SessionContext) =>\n project?.adminsIds?.map(String).includes(String(user?.id)),\n\n 'tag:read': ({\n project,\n targetTags,\n user,\n }: SessionContext & {\n targetTags: (Tag | TagAPI)[];\n }) =>\n project?.membersIds?.map(String).includes(String(user?.id)) &&\n targetTags.every((tag) => String(project?.id) === String(tag?.projectId)),\n 'tag:write': ({\n project,\n targetTags,\n user,\n }: SessionContext & {\n targetTags: (Tag | TagAPI)[];\n }) =>\n project?.membersIds?.map(String).includes(String(user?.id)) &&\n targetTags.every((tag) => String(project?.id) === String(tag?.projectId)),\n 'tag:admin': ({\n user,\n project,\n targetTags,\n }: SessionContext & {\n targetTags: (Tag | TagAPI)[];\n }) =>\n project?.adminsIds?.map(String).includes(String(user?.id)) &&\n targetTags.every((tag) => String(project?.id) === String(tag?.projectId)),\n\n 'user:read': ({\n project,\n targetUsers,\n }: SessionContext & { targetUsers: (User | UserAPI)[] }) =>\n targetUsers.every((targetUser) =>\n project?.membersIds?.map(String).includes(String(targetUser?.id))\n ),\n },\n project_reviewer: {\n 'dictionary:read': ({ user, project }: SessionContext) =>\n project?.membersIds?.map(String).includes(String(user?.id)),\n 'dictionary:write': ({ user, project }: SessionContext) =>\n project?.membersIds?.map(String).includes(String(user?.id)),\n\n 'tag:read': () => true,\n },\n} as const satisfies RolePolicy;\n\nexport const getSessionRoles = ({\n user,\n organization,\n project,\n}: SessionContext): Roles[] => {\n const roles: Roles[] = [];\n\n if (!user) {\n return roles;\n }\n\n roles.push('user');\n\n const isUserAdmin = user.role === 'admin';\n\n if (isUserAdmin) {\n roles.push('admin');\n }\n\n if (!organization) {\n return roles;\n }\n\n const isOrganizationAdmin = organization.adminsIds\n ?.map(String)\n .includes(String(user?.id));\n\n if (isOrganizationAdmin) {\n roles.push('org_admin');\n }\n\n const isOrganizationMember = organization.membersIds\n ?.map(String)\n .includes(String(user?.id));\n\n if (isOrganizationMember) {\n roles.push('org_user');\n }\n\n if (!project) {\n return roles;\n }\n\n const isProjectAdmin = project.adminsIds\n ?.map(String)\n .includes(String(user?.id));\n\n if (isProjectAdmin) {\n roles.push('project_admin');\n }\n\n const isProjectMember = project?.membersIds\n ?.map(String)\n .includes(String(user?.id));\n\n if (isProjectMember) {\n roles.push('project_user');\n }\n\n // const isProjectReviewer =\n // session.project?.reviewersIds?.includes(session.user!.id);\n\n // if (isProjectReviewer) {\n // roles.push('project_reviewer');\n // }\n\n return roles;\n};\n\nexport const computeEffectivePermission = (roles: Roles[]): Permission[] =>\n Array.from(\n new Set(\n roles.flatMap((role) => Object.keys(ROLE_POLICY[role]) as Permission[])\n )\n );\n\n/**\n * Intersect two permission lists\n * @param permissionList1 - The first permission list\n * @param permissionList2 - The second permission list\n * @returns The intersection of the two permission lists (only permissions present in both)\n */\nexport const intersectPermissions = (\n permissions1: Permission[],\n permissions2: Permission[]\n): Permission[] =>\n permissions1.filter((permission) => permissions2.includes(permission));\n\ntype PermissionResult<\n R extends Roles,\n P extends Permission,\n> = (typeof ROLE_POLICY)[R] extends infer RolePerms\n ? RolePerms extends Record<string, (args: any) => any>\n ? P extends keyof RolePerms\n ? RolePerms[P] extends undefined\n ? never\n : RolePerms[P]\n : never\n : never\n : never;\n\nexport const hasPermission = <P extends Permission>(\n roles: Roles[],\n permission: P\n): PermissionResult<Roles, P> => {\n const rolesCheck: any = roles.map(\n (role) =>\n ROLE_POLICY[role]?.[\n permission as keyof (typeof ROLE_POLICY)[typeof role]\n ] ?? (() => false)\n ) as unknown as PermissionResult<Roles, P>[];\n\n return ((args: any) => rolesCheck.some((check: any) => check(args))) as any;\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan.mjs","names":[
|
|
1
|
+
{"version":3,"file":"plan.mjs","names":[],"sources":["../../../src/utils/plan.ts"],"sourcesContent":["import type { Plan } from '@/types/plan.types';\n\n/**\n * Retrieves the plan type based on the price ID.\n * @param priceId - The price ID to retrieve the plan type from.\n * @returns The plan type and period.\n */\nexport const retrievePlanInformation = (\n priceId: string\n): Pick<Plan, 'period' | 'type'> => {\n switch (priceId) {\n case process.env.STRIPE_PREMIUM_YEARLY_PRICE_ID!:\n return { period: 'YEARLY', type: 'PREMIUM' };\n case process.env.STRIPE_PREMIUM_MONTHLY_PRICE_ID!:\n return { period: 'MONTHLY', type: 'PREMIUM' };\n case process.env.STRIPE_ENTERPRISE_YEARLY_PRICE_ID!:\n return { period: 'YEARLY', type: 'ENTERPRISE' };\n case process.env.STRIPE_ENTERPRISE_MONTHLY_PRICE_ID!:\n return { period: 'MONTHLY', type: 'ENTERPRISE' };\n default:\n return { period: undefined, type: 'FREE' };\n }\n};\n\ntype PlanDetails = {\n numberOfOrganizationUsers?: number;\n numberOfProjects?: number;\n totalStorage?: number;\n SeoAI: boolean;\n contentAI: boolean;\n};\n\nconst planDetails: Record<Plan['type'], PlanDetails> = {\n FREE: {\n numberOfOrganizationUsers: 1,\n numberOfProjects: 1,\n totalStorage: 100, // 100 MB\n SeoAI: false,\n contentAI: false,\n },\n PREMIUM: {\n numberOfOrganizationUsers: 20,\n numberOfProjects: 10,\n totalStorage: 500, // 500 MB\n SeoAI: false,\n contentAI: true,\n },\n ENTERPRISE: {\n numberOfOrganizationUsers: undefined,\n numberOfProjects: undefined,\n totalStorage: undefined,\n SeoAI: true,\n contentAI: true,\n },\n};\n\nexport const getPlanDetails = (plan?: Plan): PlanDetails => {\n if (plan?.status !== 'active') {\n return planDetails.FREE;\n }\n\n return planDetails[plan.type];\n};\n"],"mappings":";;;;;;AAOA,MAAa,2BACX,YACkC;AAClC,SAAQ,SAAR;EACE,KAAK,QAAQ,IAAI,+BACf,QAAO;GAAE,QAAQ;GAAU,MAAM;GAAW;EAC9C,KAAK,QAAQ,IAAI,gCACf,QAAO;GAAE,QAAQ;GAAW,MAAM;GAAW;EAC/C,KAAK,QAAQ,IAAI,kCACf,QAAO;GAAE,QAAQ;GAAU,MAAM;GAAc;EACjD,KAAK,QAAQ,IAAI,mCACf,QAAO;GAAE,QAAQ;GAAW,MAAM;GAAc;EAClD,QACE,QAAO;GAAE,QAAQ;GAAW,MAAM;GAAQ;;;AAYhD,MAAM,cAAiD;CACrD,MAAM;EACJ,2BAA2B;EAC3B,kBAAkB;EAClB,cAAc;EACd,OAAO;EACP,WAAW;EACZ;CACD,SAAS;EACP,2BAA2B;EAC3B,kBAAkB;EAClB,cAAc;EACd,OAAO;EACP,WAAW;EACZ;CACD,YAAY;EACV,2BAA2B;EAC3B,kBAAkB;EAClB,cAAc;EACd,OAAO;EACP,WAAW;EACZ;CACF;AAED,MAAa,kBAAkB,SAA6B;AAC1D,KAAI,MAAM,WAAW,SACnB,QAAO,YAAY;AAGrB,QAAO,YAAY,KAAK"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rateLimiter.mjs","names":[
|
|
1
|
+
{"version":3,"file":"rateLimiter.mjs","names":[],"sources":["../../../src/utils/rateLimiter.ts"],"sourcesContent":["import type { RateLimitOptions } from '@fastify/rate-limit';\nimport type { FastifyRequest } from 'fastify';\nimport { ErrorHandler } from './errors';\n\n// Helper function to normalize IP addresses (similar to express-rate-limit's ipKeyGenerator)\nconst normalizeIP = (ip: string | undefined): string => {\n if (!ip) return 'unknown';\n // Normalize IPv6 mapped IPv4 addresses\n if (ip.startsWith('::ffff:')) {\n return ip.substring(7);\n }\n return ip;\n};\n\n// -------------------------------------------------------------\n// Create the rate-limiter instances once at module load-time so\n// that the hit counters are shared across every incoming request.\n// -------------------------------------------------------------\n\nexport const ipLimiter: RateLimitOptions = {\n max: 500, // 500 requests\n timeWindow: 60 * 1000, // 1-minute window\n enableDraftSpec: true,\n // Use a custom key generator that handles proxy headers securely\n keyGenerator: (request: FastifyRequest) => {\n const ip =\n request.ip ??\n request.socket?.remoteAddress ??\n request.headers['x-forwarded-for'] ??\n 'unknown';\n return normalizeIP(typeof ip === 'string' ? ip : ip[0]);\n },\n errorResponseBuilder: (_request: FastifyRequest, context) => {\n // context.ttl is already the remaining time in milliseconds\n const retryAfter = Math.ceil(context.ttl / 1000);\n const errorResponse = ErrorHandler.formatGenericErrorResponse(\n 'RATE_LIMIT_EXCEEDED',\n {\n limit: `${context.max} per minute`,\n retryAfter,\n }\n );\n return {\n statusCode: errorResponse.status,\n ...errorResponse,\n };\n },\n};\n\nexport const unauthenticatedChatBotLimiter: RateLimitOptions = {\n max: 3, // 3 requests\n timeWindow: 60 * 60 * 1000, // 1-hour window\n enableDraftSpec: true,\n // Skip rate limiting if user is authenticated (allowList returns true to skip)\n allowList: (request: FastifyRequest) => {\n return Boolean((request as any).locals?.user);\n },\n // Use a custom key generator that handles proxy headers securely\n keyGenerator: (request: FastifyRequest) => {\n const ip =\n request.ip ??\n request.socket?.remoteAddress ??\n request.headers['x-forwarded-for'] ??\n 'unknown';\n return normalizeIP(typeof ip === 'string' ? ip : ip[0]);\n },\n errorResponseBuilder: (_request: FastifyRequest, context) => {\n // context.ttl is already the remaining time in milliseconds\n const retryAfter = Math.ceil(context.ttl / 1000);\n const errorResponse = ErrorHandler.formatGenericErrorResponse(\n 'RATE_LIMIT_EXCEEDED_UNAUTHENTICATED',\n {\n limit: `${context.max} per hour`,\n retryAfter,\n }\n );\n return {\n statusCode: errorResponse.status,\n ...errorResponse,\n };\n },\n};\n"],"mappings":";;;AAKA,MAAM,eAAe,OAAmC;AACtD,KAAI,CAAC,GAAI,QAAO;AAEhB,KAAI,GAAG,WAAW,UAAU,CAC1B,QAAO,GAAG,UAAU,EAAE;AAExB,QAAO;;AAQT,MAAa,YAA8B;CACzC,KAAK;CACL,YAAY,KAAK;CACjB,iBAAiB;CAEjB,eAAe,YAA4B;EACzC,MAAM,KACJ,QAAQ,MACR,QAAQ,QAAQ,iBAChB,QAAQ,QAAQ,sBAChB;AACF,SAAO,YAAY,OAAO,OAAO,WAAW,KAAK,GAAG,GAAG;;CAEzD,uBAAuB,UAA0B,YAAY;EAE3D,MAAM,aAAa,KAAK,KAAK,QAAQ,MAAM,IAAK;EAChD,MAAM,gBAAgB,aAAa,2BACjC,uBACA;GACE,OAAO,GAAG,QAAQ,IAAI;GACtB;GACD,CACF;AACD,SAAO;GACL,YAAY,cAAc;GAC1B,GAAG;GACJ;;CAEJ;AAED,MAAa,gCAAkD;CAC7D,KAAK;CACL,YAAY,OAAU;CACtB,iBAAiB;CAEjB,YAAY,YAA4B;AACtC,SAAO,QAAS,QAAgB,QAAQ,KAAK;;CAG/C,eAAe,YAA4B;EACzC,MAAM,KACJ,QAAQ,MACR,QAAQ,QAAQ,iBAChB,QAAQ,QAAQ,sBAChB;AACF,SAAO,YAAY,OAAO,OAAO,WAAW,KAAK,GAAG,GAAG;;CAEzD,uBAAuB,UAA0B,YAAY;EAE3D,MAAM,aAAa,KAAK,KAAK,QAAQ,MAAM,IAAK;EAChD,MAAM,gBAAgB,aAAa,2BACjC,uCACA;GACE,OAAO,GAAG,QAAQ,IAAI;GACtB;GACD,CACF;AACD,SAAO;GACL,YAAY,cAAc;GAC1B,GAAG;GACJ;;CAEJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateArray.mjs","names":[
|
|
1
|
+
{"version":3,"file":"validateArray.mjs","names":[],"sources":["../../../../src/utils/validation/validateArray.ts"],"sourcesContent":["type ElementType = 'string' | 'number' | 'boolean' | 'object' | 'array';\ntype ElementValidator<T> = (value: T) => boolean | string[];\n\n/**\n * Validates a email field.\n * @param value The value to validate.\n * @param entityName The name of the entity being validated.\n * @param minLength The minimum length of the string.\n * @param maxLength The maximum length of the string.\n * @returns An array of validation errors.\n */\nexport const validateArray = <T = unknown>(\n value: T[],\n entityName = 'Array',\n elementType?: ElementType,\n elementValidator?: ElementValidator<T>,\n minLength = 0,\n maxLength = undefined\n): string[] => {\n const errors: string[] = [];\n\n if (!Array.isArray(value)) {\n errors.push(`${entityName} must be an array.`);\n } else if (minLength && value.length < minLength) {\n errors.push(`${entityName} must be at least ${minLength} items long.`);\n } else if (maxLength && value.length > maxLength) {\n errors.push(`${entityName} must be at most ${maxLength} items long.`);\n } else if (elementType) {\n const isValid = value.every((element) => {\n return typeof element === elementType;\n });\n\n if (!isValid) {\n errors.push(`${entityName} must contain only ${elementType} elements.`);\n }\n } else if (elementValidator) {\n const isValidOrErrorList = value.every(elementValidator);\n\n if (Array.isArray(isValidOrErrorList)) {\n const isValid = isValidOrErrorList.length > 0;\n\n if (!isValid) {\n errors.push(...isValidOrErrorList);\n }\n } else {\n const isValid = isValidOrErrorList;\n\n if (!isValid) {\n errors.push(`${entityName} must contain valid elements.`);\n }\n }\n }\n\n return errors;\n};\n"],"mappings":";;;;;;;;;AAWA,MAAa,iBACX,OACA,aAAa,SACb,aACA,kBACA,YAAY,GACZ,YAAY,WACC;CACb,MAAM,SAAmB,EAAE;AAE3B,KAAI,CAAC,MAAM,QAAQ,MAAM,CACvB,QAAO,KAAK,GAAG,WAAW,oBAAoB;UACrC,aAAa,MAAM,SAAS,UACrC,QAAO,KAAK,GAAG,WAAW,oBAAoB,UAAU,cAAc;UAC7D,aAAa,MAAM,SAAS,UACrC,QAAO,KAAK,GAAG,WAAW,mBAAmB,UAAU,cAAc;UAC5D,aAKT;MAAI,CAJY,MAAM,OAAO,YAAY;AACvC,UAAO,OAAO,YAAY;IAC1B,CAGA,QAAO,KAAK,GAAG,WAAW,qBAAqB,YAAY,YAAY;YAEhE,kBAAkB;EAC3B,MAAM,qBAAqB,MAAM,MAAM,iBAAiB;AAExD,MAAI,MAAM,QAAQ,mBAAmB,EAGnC;OAAI,EAFY,mBAAmB,SAAS,GAG1C,QAAO,KAAK,GAAG,mBAAmB;aAKhC,CAFY,mBAGd,QAAO,KAAK,GAAG,WAAW,+BAA+B;;AAK/D,QAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateDictionary.mjs","names":["
|
|
1
|
+
{"version":3,"file":"validateDictionary.mjs","names":["value"],"sources":["../../../../src/utils/validation/validateDictionary.ts"],"sourcesContent":["import { findProjects } from '@services/project.service';\nimport type { Dictionary } from '@/types/dictionary.types';\nimport { validateArray } from './validateArray';\n\nexport type DictionaryFields = (keyof Dictionary)[];\n\nconst defaultFieldsToCheck: DictionaryFields = ['projectIds'];\n\ntype FieldsToCheck = (typeof defaultFieldsToCheck)[number];\ntype ValidationErrors = Partial<\n Record<(typeof defaultFieldsToCheck)[number], string[]>\n>;\n\n/**\n * Validates an dictionary object.\n * @param dictionary The dictionary object to validate.\n * @returns An object containing the validation errors for each field.\n */\nexport const validateDictionary = async (\n dictionary: Partial<Dictionary>,\n fieldsToCheck = defaultFieldsToCheck\n): Promise<ValidationErrors> => {\n const errors: ValidationErrors = {};\n\n // Define the fields to validate\n const fieldsToValidate = new Set<FieldsToCheck>(fieldsToCheck);\n\n const dictionaryJSON = JSON.parse(JSON.stringify(dictionary));\n\n const projects = await findProjects({\n _id: dictionary.projectIds as unknown as string[],\n });\n\n // Validate each field\n for (const field of fieldsToValidate) {\n const value = dictionaryJSON[field];\n\n // Initialize error array for the field\n errors[field] = [];\n\n if (field === 'projectIds') {\n const projectsErrors: string[] = validateArray<string>(\n value as unknown as string[],\n 'Project',\n 'string',\n (value) => {\n const projectErrors: string[] = [];\n\n if (typeof value !== 'string') {\n projectErrors.push('Project id must be a string');\n }\n\n if (!value) {\n projectErrors.push('Project id is required');\n }\n\n if (!projects) {\n projectErrors.push('Project not found');\n }\n\n return projectsErrors;\n }\n );\n }\n\n // Remove the error field if there are no errors\n if (errors[field].length === 0) {\n delete errors[field];\n }\n }\n\n return errors;\n};\n"],"mappings":";;;;AAMA,MAAM,uBAAyC,CAAC,aAAa;;;;;;AAY7D,MAAa,qBAAqB,OAChC,YACA,gBAAgB,yBACc;CAC9B,MAAM,SAA2B,EAAE;CAGnC,MAAM,mBAAmB,IAAI,IAAmB,cAAc;CAE9D,MAAM,iBAAiB,KAAK,MAAM,KAAK,UAAU,WAAW,CAAC;CAE7D,MAAM,WAAW,MAAM,aAAa,EAClC,KAAK,WAAW,YACjB,CAAC;AAGF,MAAK,MAAM,SAAS,kBAAkB;EACpC,MAAM,QAAQ,eAAe;AAG7B,SAAO,SAAS,EAAE;AAElB,MAAI,UAAU,cAAc;GAC1B,MAAM,iBAA2B,cAC/B,OACA,WACA,WACC,YAAU;IACT,MAAM,gBAA0B,EAAE;AAElC,QAAI,OAAOA,YAAU,SACnB,eAAc,KAAK,8BAA8B;AAGnD,QAAI,CAACA,QACH,eAAc,KAAK,yBAAyB;AAG9C,QAAI,CAAC,SACH,eAAc,KAAK,oBAAoB;AAGzC,WAAO;KAEV;;AAIH,MAAI,OAAO,OAAO,WAAW,EAC3B,QAAO,OAAO;;AAIlB,QAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateOrganization.mjs","names":[
|
|
1
|
+
{"version":3,"file":"validateOrganization.mjs","names":[],"sources":["../../../../src/utils/validation/validateOrganization.ts"],"sourcesContent":["import type { Organization, OrganizationAPI } from '@/types/organization.types';\nimport { validateArray } from './validateArray';\nimport { validateString } from './validateString';\n\nexport type OrganizationFields = (keyof Organization)[];\n\nconst defaultFieldsToCheck: OrganizationFields = [\n 'name',\n 'membersIds',\n 'adminsIds',\n];\n\ntype FieldsToCheck = (typeof defaultFieldsToCheck)[number];\ntype ValidationErrors = Partial<\n Record<(typeof defaultFieldsToCheck)[number], string[]>\n>;\n\nexport const NAME_MIN_LENGTH = 4;\nexport const NAME_MAX_LENGTH = 100;\n\nexport const MEMBERS_MIN_LENGTH = 1;\n\n/**\n * Validates an organization object.\n * @param organization The organization object to validate.\n * @returns An object containing the validation errors for each field.\n */\nexport const validateOrganization = (\n organization: Partial<Organization | OrganizationAPI>,\n fieldsToCheck = defaultFieldsToCheck\n): ValidationErrors => {\n const errors: ValidationErrors = {};\n\n const organizationObject = JSON.parse(JSON.stringify(organization));\n\n // Define the fields to validate\n const fieldsToValidate = new Set<FieldsToCheck>(fieldsToCheck);\n\n // Validate each field\n for (const field of fieldsToValidate) {\n const value = organizationObject[field];\n\n // Initialize error array for the field\n errors[field] = [];\n\n // Check for name validity\n if (field === 'name') {\n const nameErrors = validateString(\n value,\n 'Name',\n NAME_MIN_LENGTH,\n NAME_MAX_LENGTH\n );\n\n if (nameErrors.length > 0) {\n errors[field] = nameErrors;\n }\n }\n\n if (field === 'membersIds' || field === 'adminsIds') {\n const membersErrors = validateArray<string>(\n value as unknown as string[],\n 'Members',\n 'string',\n undefined,\n MEMBERS_MIN_LENGTH\n );\n\n if (membersErrors.length > 0) {\n errors[field] = membersErrors;\n }\n }\n\n // Remove the error field if there are no errors\n if (errors[field].length === 0) {\n delete errors[field];\n }\n }\n\n return errors;\n};\n"],"mappings":";;;;AAMA,MAAM,uBAA2C;CAC/C;CACA;CACA;CACD;AAOD,MAAa,kBAAkB;AAC/B,MAAa,kBAAkB;AAE/B,MAAa,qBAAqB;;;;;;AAOlC,MAAa,wBACX,cACA,gBAAgB,yBACK;CACrB,MAAM,SAA2B,EAAE;CAEnC,MAAM,qBAAqB,KAAK,MAAM,KAAK,UAAU,aAAa,CAAC;CAGnE,MAAM,mBAAmB,IAAI,IAAmB,cAAc;AAG9D,MAAK,MAAM,SAAS,kBAAkB;EACpC,MAAM,QAAQ,mBAAmB;AAGjC,SAAO,SAAS,EAAE;AAGlB,MAAI,UAAU,QAAQ;GACpB,MAAM,aAAa,eACjB,OACA,QACA,iBACA,gBACD;AAED,OAAI,WAAW,SAAS,EACtB,QAAO,SAAS;;AAIpB,MAAI,UAAU,gBAAgB,UAAU,aAAa;GACnD,MAAM,gBAAgB,cACpB,OACA,WACA,UACA,QACA,mBACD;AAED,OAAI,cAAc,SAAS,EACzB,QAAO,SAAS;;AAKpB,MAAI,OAAO,OAAO,WAAW,EAC3B,QAAO,OAAO;;AAIlB,QAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateProject.mjs","names":[
|
|
1
|
+
{"version":3,"file":"validateProject.mjs","names":[],"sources":["../../../../src/utils/validation/validateProject.ts"],"sourcesContent":["import { getOrganizationById } from '@services/organization.service';\nimport type { Project, ProjectAPI } from '@/types/project.types';\nimport { validateArray } from './validateArray';\nimport { validateString } from './validateString';\n\nexport type ProjectFields = (keyof Project)[];\n\nconst defaultFieldsToCheck: ProjectFields = [\n 'name',\n 'membersIds',\n 'adminsIds',\n 'organizationId',\n];\n\ntype FieldsToCheck = (typeof defaultFieldsToCheck)[number];\ntype ValidationErrors = Partial<\n Record<(typeof defaultFieldsToCheck)[number], string[]>\n>;\n\nexport const NAME_MIN_LENGTH = 4;\nexport const NAME_MAX_LENGTH = 100;\n\nexport const MEMBERS_MIN_LENGTH = 1;\n\n/**\n * Validates an project object.\n * @param project The project object to validate.\n * @returns An object containing the validation errors for each field.\n */\nexport const validateProject = async (\n project: Partial<Project | ProjectAPI>,\n fieldsToCheck = defaultFieldsToCheck\n): Promise<ValidationErrors> => {\n const errors: ValidationErrors = {};\n\n // Define the fields to validate\n const fieldsToValidate = new Set<FieldsToCheck>(fieldsToCheck);\n\n const projectJson = JSON.parse(JSON.stringify(project));\n\n // Validate each field\n for (const field of fieldsToValidate) {\n const value = projectJson[field];\n\n // Initialize error array for the field\n errors[field] = [];\n\n // Check for name validity\n if (field === 'name') {\n const nameErrors = validateString(\n value,\n 'Name',\n NAME_MIN_LENGTH,\n NAME_MAX_LENGTH\n );\n\n if (nameErrors.length > 0) {\n errors[field] = nameErrors;\n }\n }\n\n if (field === 'organizationId') {\n const organization = await getOrganizationById(field);\n const organizationErrors: string[] = [];\n\n if (typeof value !== 'string') {\n organizationErrors.push('Organization id must be a string');\n }\n\n if (!value) {\n organizationErrors.push('Organization id is required');\n }\n\n if (!organization) {\n organizationErrors.push('Organization not found');\n }\n\n if (organizationErrors.length > 0) {\n errors[field] = organizationErrors;\n }\n }\n\n if (field === 'membersIds' || field === 'adminsIds') {\n if (!project.organizationId) {\n errors[field] = [\n 'Organization id is required to validate project members',\n ];\n } else {\n const organization = await getOrganizationById(project.organizationId);\n const membersErrors = validateArray<string>(\n value as unknown as string[],\n 'Members',\n 'string',\n (item) =>\n (organization?.membersIds as unknown as string[]).includes(item),\n MEMBERS_MIN_LENGTH\n );\n\n if (membersErrors.length > 0) {\n errors[field] = membersErrors;\n }\n }\n }\n\n // Remove the error field if there are no errors\n if (errors[field].length === 0) {\n delete errors[field];\n }\n }\n\n return errors;\n};\n"],"mappings":";;;;;AAOA,MAAM,uBAAsC;CAC1C;CACA;CACA;CACA;CACD;AAOD,MAAa,kBAAkB;AAC/B,MAAa,kBAAkB;AAE/B,MAAa,qBAAqB;;;;;;AAOlC,MAAa,kBAAkB,OAC7B,SACA,gBAAgB,yBACc;CAC9B,MAAM,SAA2B,EAAE;CAGnC,MAAM,mBAAmB,IAAI,IAAmB,cAAc;CAE9D,MAAM,cAAc,KAAK,MAAM,KAAK,UAAU,QAAQ,CAAC;AAGvD,MAAK,MAAM,SAAS,kBAAkB;EACpC,MAAM,QAAQ,YAAY;AAG1B,SAAO,SAAS,EAAE;AAGlB,MAAI,UAAU,QAAQ;GACpB,MAAM,aAAa,eACjB,OACA,QACA,iBACA,gBACD;AAED,OAAI,WAAW,SAAS,EACtB,QAAO,SAAS;;AAIpB,MAAI,UAAU,kBAAkB;GAC9B,MAAM,eAAe,MAAM,oBAAoB,MAAM;GACrD,MAAM,qBAA+B,EAAE;AAEvC,OAAI,OAAO,UAAU,SACnB,oBAAmB,KAAK,mCAAmC;AAG7D,OAAI,CAAC,MACH,oBAAmB,KAAK,8BAA8B;AAGxD,OAAI,CAAC,aACH,oBAAmB,KAAK,yBAAyB;AAGnD,OAAI,mBAAmB,SAAS,EAC9B,QAAO,SAAS;;AAIpB,MAAI,UAAU,gBAAgB,UAAU,YACtC,KAAI,CAAC,QAAQ,eACX,QAAO,SAAS,CACd,0DACD;OACI;GACL,MAAM,eAAe,MAAM,oBAAoB,QAAQ,eAAe;GACtE,MAAM,gBAAgB,cACpB,OACA,WACA,WACC,UACE,cAAc,YAAmC,SAAS,KAAK,EAClE,mBACD;AAED,OAAI,cAAc,SAAS,EACzB,QAAO,SAAS;;AAMtB,MAAI,OAAO,OAAO,WAAW,EAC3B,QAAO,OAAO;;AAIlB,QAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateString.mjs","names":[
|
|
1
|
+
{"version":3,"file":"validateString.mjs","names":[],"sources":["../../../../src/utils/validation/validateString.ts"],"sourcesContent":["/**\n * Validates a string field.\n * @param value The value to validate.\n * @param entityName The name of the entity being validated.\n * @param minLength The minimum length of the string.\n * @param maxLength The maximum length of the string.\n * @returns An array of validation errors.\n */\nexport const validateString = (\n value: unknown,\n entityName: string,\n minLength?: number,\n maxLength?: number\n): string[] => {\n const errors: string[] = [];\n\n if (typeof value !== 'string') {\n errors.push(`${entityName} must be a string.`);\n } else if (minLength && value.length < minLength) {\n errors.push(`${entityName} must be at least ${minLength} characters long.`);\n } else if (maxLength && value.length > maxLength) {\n errors.push(`${entityName} must be at most ${maxLength} characters long.`);\n }\n\n return errors;\n};\n"],"mappings":";;;;;;;;;AAQA,MAAa,kBACX,OACA,YACA,WACA,cACa;CACb,MAAM,SAAmB,EAAE;AAE3B,KAAI,OAAO,UAAU,SACnB,QAAO,KAAK,GAAG,WAAW,oBAAoB;UACrC,aAAa,MAAM,SAAS,UACrC,QAAO,KAAK,GAAG,WAAW,oBAAoB,UAAU,mBAAmB;UAClE,aAAa,MAAM,SAAS,UACrC,QAAO,KAAK,GAAG,WAAW,mBAAmB,UAAU,mBAAmB;AAG5E,QAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateTag.mjs","names":[
|
|
1
|
+
{"version":3,"file":"validateTag.mjs","names":[],"sources":["../../../../src/utils/validation/validateTag.ts"],"sourcesContent":["import { getOrganizationById } from '@services/organization.service';\nimport type { Tag } from '@/types/tag.types';\nimport { validateString } from './validateString';\n\nexport type TagFields = (keyof Tag)[];\n\nconst defaultFieldsToCheck: TagFields = ['name'];\n\ntype FieldsToCheck = (typeof defaultFieldsToCheck)[number];\ntype ValidationErrors = Partial<\n Record<(typeof defaultFieldsToCheck)[number], string[]>\n>;\n\nexport const KEY_MIN_LENGTH = 4;\nexport const KEY_MAX_LENGTH = 20;\n\nexport const NAME_MIN_LENGTH = 4;\nexport const NAME_MAX_LENGTH = 50;\n\n/**\n * Validates an tag object.\n * @param tag The tag object to validate.\n * @returns An object containing the validation errors for each field.\n */\nexport const validateTag = async (\n tag: Partial<Tag>,\n fieldsToCheck = defaultFieldsToCheck\n): Promise<ValidationErrors> => {\n const errors: ValidationErrors = {};\n\n // Define the fields to validate\n const fieldsToValidate = new Set<FieldsToCheck>(fieldsToCheck);\n\n // Validate each field\n for (const field of fieldsToValidate) {\n const value = tag[field];\n\n // Initialize error array for the field\n errors[field] = [];\n\n // Check for name validity\n if (field === 'key') {\n const nameErrors = validateString(\n value,\n 'Key',\n KEY_MIN_LENGTH,\n KEY_MAX_LENGTH\n );\n\n if (nameErrors.length > 0) {\n errors[field] = nameErrors;\n }\n }\n\n // Check for name validity\n if (field === 'name') {\n const nameErrors = validateString(\n value,\n 'Name',\n NAME_MIN_LENGTH,\n NAME_MAX_LENGTH\n );\n\n if (nameErrors.length > 0) {\n errors[field] = nameErrors;\n }\n }\n\n if (field === 'organizationId') {\n const organizationErrors: string[] = [];\n\n if (typeof value !== 'string') {\n organizationErrors.push('Organization id must be a string');\n }\n\n if (!value) {\n organizationErrors.push('Organization id is required');\n }\n\n const organization = await getOrganizationById(field);\n if (!organization) {\n organizationErrors.push('Organization not found');\n }\n\n if (organizationErrors.length > 0) {\n errors[field] = organizationErrors;\n }\n }\n\n // Remove the error field if there are no errors\n if (errors[field].length === 0) {\n delete errors[field];\n }\n }\n\n return errors;\n};\n"],"mappings":";;;;AAMA,MAAM,uBAAkC,CAAC,OAAO;AAOhD,MAAa,iBAAiB;AAC9B,MAAa,iBAAiB;AAE9B,MAAa,kBAAkB;AAC/B,MAAa,kBAAkB;;;;;;AAO/B,MAAa,cAAc,OACzB,KACA,gBAAgB,yBACc;CAC9B,MAAM,SAA2B,EAAE;CAGnC,MAAM,mBAAmB,IAAI,IAAmB,cAAc;AAG9D,MAAK,MAAM,SAAS,kBAAkB;EACpC,MAAM,QAAQ,IAAI;AAGlB,SAAO,SAAS,EAAE;AAGlB,MAAI,UAAU,OAAO;GACnB,MAAM,aAAa,eACjB,OACA,OACA,gBACA,eACD;AAED,OAAI,WAAW,SAAS,EACtB,QAAO,SAAS;;AAKpB,MAAI,UAAU,QAAQ;GACpB,MAAM,aAAa,eACjB,OACA,QACA,iBACA,gBACD;AAED,OAAI,WAAW,SAAS,EACtB,QAAO,SAAS;;AAIpB,MAAI,UAAU,kBAAkB;GAC9B,MAAM,qBAA+B,EAAE;AAEvC,OAAI,OAAO,UAAU,SACnB,oBAAmB,KAAK,mCAAmC;AAG7D,OAAI,CAAC,MACH,oBAAmB,KAAK,8BAA8B;AAIxD,OAAI,CADiB,MAAM,oBAAoB,MAAM,CAEnD,oBAAmB,KAAK,yBAAyB;AAGnD,OAAI,mBAAmB,SAAS,EAC9B,QAAO,SAAS;;AAKpB,MAAI,OAAO,OAAO,WAAW,EAC3B,QAAO,OAAO;;AAIlB,QAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateUser.mjs","names":[
|
|
1
|
+
{"version":3,"file":"validateUser.mjs","names":[],"sources":["../../../../src/utils/validation/validateUser.ts"],"sourcesContent":["import type { User, UserAPI } from '@/types/user.types';\nimport { validateEmail } from './validateEmail';\nimport { validatePhone } from './validatePhone';\nimport { validateString } from './validateString';\n\nexport type UserFields = (keyof User)[];\n\nconst defaultFieldsToCheck: UserFields = ['name', 'phone', 'email', 'phone'];\n\nexport type FieldsToCheck = (typeof defaultFieldsToCheck)[number];\ntype ValidationErrors = Partial<\n Record<(typeof defaultFieldsToCheck)[number], string[]>\n>;\nexport const NAMES_MIN_LENGTH = 4;\nexport const NAMES_MAX_LENGTH = 100;\n\n/**\n * Validates an user object.\n * @param user The user object to validate.\n * @returns An object containing the validation errors for each field.\n */\nexport const validateUser = (\n user: Partial<User | UserAPI>,\n fieldsToCheck = defaultFieldsToCheck\n): ValidationErrors => {\n const errors: ValidationErrors = {};\n\n // Define the fields to validate\n const fieldsToValidate = new Set<FieldsToCheck>(fieldsToCheck);\n\n const userJson = JSON.parse(JSON.stringify(user));\n\n // Validate each field\n for (const field of fieldsToValidate) {\n const value = userJson[field];\n\n // Initialize error array for the field\n errors[field] = [];\n\n // Check for name validity\n if (field === 'name') {\n const nameErrors = validateString(\n value,\n `User ${field}`,\n NAMES_MIN_LENGTH,\n NAMES_MAX_LENGTH\n );\n\n if (nameErrors.length > 0) {\n errors[field] = nameErrors;\n }\n }\n\n // Check for email validity\n if (field === 'email') {\n const emailErrors = validateEmail(value, 'User Email');\n\n if (emailErrors.length > 0) {\n errors[field] = emailErrors;\n }\n }\n\n if (field === 'phone') {\n const phoneErrors = validatePhone(value, 'User Phone', 8, 20);\n\n if (phoneErrors.length > 0) {\n errors[field] = phoneErrors;\n }\n }\n\n // Remove the error field if there are no errors\n if (errors[field].length === 0) {\n delete errors[field];\n }\n }\n\n return errors;\n};\n"],"mappings":";;;;;AAOA,MAAM,uBAAmC;CAAC;CAAQ;CAAS;CAAS;CAAQ;AAM5E,MAAa,mBAAmB;AAChC,MAAa,mBAAmB;;;;;;AAOhC,MAAa,gBACX,MACA,gBAAgB,yBACK;CACrB,MAAM,SAA2B,EAAE;CAGnC,MAAM,mBAAmB,IAAI,IAAmB,cAAc;CAE9D,MAAM,WAAW,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC;AAGjD,MAAK,MAAM,SAAS,kBAAkB;EACpC,MAAM,QAAQ,SAAS;AAGvB,SAAO,SAAS,EAAE;AAGlB,MAAI,UAAU,QAAQ;GACpB,MAAM,aAAa,eACjB,OACA,QAAQ,SACR,kBACA,iBACD;AAED,OAAI,WAAW,SAAS,EACtB,QAAO,SAAS;;AAKpB,MAAI,UAAU,SAAS;GACrB,MAAM,cAAc,cAAc,OAAO,aAAa;AAEtD,OAAI,YAAY,SAAS,EACvB,QAAO,SAAS;;AAIpB,MAAI,UAAU,SAAS;GACrB,MAAM,cAAc,cAAc,OAAO,cAAc,GAAG,GAAG;AAE7D,OAAI,YAAY,SAAS,EACvB,QAAO,SAAS;;AAKpB,MAAI,OAAO,OAAO,WAAW,EAC3B,QAAO,OAAO;;AAIlB,QAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stripe.webhook.mjs","names":["event: Stripe.Event","emailService.sendEmail"],"sources":["../../../src/webhooks/stripe.webhook.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types';\nimport { logger } from '@logger';\nimport * as emailService from '@services/email.service';\nimport { getOrganizationById } from '@services/organization.service';\nimport {\n addOrUpdateSubscription,\n cancelSubscription,\n changeSubscriptionStatus,\n} from '@services/subscription.service';\nimport { getUserById } from '@services/user.service';\nimport { GenericError } from '@utils/errors';\nimport type { Request, Response } from 'express';\nimport { Stripe } from 'stripe';\nimport type { Plan } from '@/types/plan.types';\n\ntype SubscriptionMetadata = {\n locale: Locale; // Localization setting (e.g., 'en', 'fr', 'es')\n userId: string; // ID of the user associated with the subscription\n organizationId: string; // ID of the organization associated with the subscription\n};\n\n/**\n * Stripe webhook handler for processing subscription and invoice events.\n * @param req - Express request object.\n * @param res - Express response object.\n */\nexport const stripeWebhook = async (req: Request, res: Response) => {\n // Initialize the Stripe client with the secret key\n const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);\n\n const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET!; // Webhook secret for verifying event signatures\n const sig = req.headers['stripe-signature']!; // Retrieve the signature from the webhook request headers\n\n let event: Stripe.Event;\n\n // Verify the webhook signature to ensure the request is authentic\n try {\n event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);\n } catch (err) {\n // Respond with a 400 status code if the signature verification fails\n res.status(400).send(`Webhook Error: ${(err as Error).message}`);\n return;\n }\n\n // Utility function to extract metadata from a Stripe customer\n const extractMetadata = async (customerId: string) => {\n const customer = await stripe.customers.retrieve(customerId); // Retrieve customer details from Stripe\n return (customer as Stripe.Customer).metadata as SubscriptionMetadata; // Return the metadata object\n };\n\n // Handles subscription-related events (creation, update, deletion)\n const handleSubscriptionEvent = async (\n subscription: Stripe.Subscription,\n statusOverride?: Plan['status'] // Optionally override the subscription status\n ) => {\n const { id: subscriptionId, customer } = subscription;\n const priceId = subscription.items.data[0]?.price?.id; // Extract the price ID from subscription items\n\n if (!customer) {\n throw new GenericError('STRIPE_SUBSCRIPTION_NO_CUSTOMER');\n }\n\n const customerId = customer as string;\n const { locale, userId, organizationId } =\n await extractMetadata(customerId); // Extract metadata from the customer\n\n // Set localization in response locals if available\n if (locale) {\n res.locals.locales = locale;\n }\n\n const organization = await getOrganizationById(organizationId); // Fetch organization details by ID\n\n if (!organization) {\n throw new GenericError('ORGANIZATION_NOT_FOUND');\n }\n\n const user = await getUserById(userId);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND');\n }\n\n const status = statusOverride ?? subscription.status; // Use the provided status override or the subscription's status\n\n // Update or create a subscription record in the database\n await addOrUpdateSubscription(\n subscriptionId,\n priceId!,\n customerId,\n userId,\n organization,\n status\n );\n\n if (status === 'active') {\n await emailService.sendEmail({\n type: 'subscriptionPaymentSuccess',\n to: user.email,\n email: user.email,\n subscriptionStartDate: new Date().toLocaleDateString(),\n manageSubscriptionLink: `${process.env.APP_URL}/organization`,\n username: user.name,\n organizationName: organization.name,\n planName: organization.plan?.type ?? 'Unknown',\n });\n }\n if (status === 'canceled') {\n await emailService.sendEmail({\n type: 'subscriptionPaymentCancellation',\n to: user.email,\n email: user.email,\n cancellationDate: new Date(\n (subscription as any).current_period_end * 1000\n ).toLocaleDateString(),\n reactivateLink: `${process.env.APP_URL}/pricing`,\n username: user.name,\n organizationName: organization.name,\n planName: organization.plan?.type ?? 'Unknown',\n });\n }\n };\n\n // Handles invoice-related events (payment success or failure)\n const handleInvoiceEvent = async (\n invoice: Stripe.Invoice,\n status: 'active' | 'incomplete'\n ) => {\n const subscriptionId =\n typeof (invoice as any).subscription === 'string'\n ? (invoice as any).subscription\n : (invoice as any).subscription?.id; // Extract the subscription ID from the invoice\n if (!subscriptionId) {\n logger.warn('Subscription ID is undefined in invoice.');\n return;\n }\n\n // Retrieve the subscription details from Stripe\n const subscription = await stripe.subscriptions.retrieve(subscriptionId);\n const organization = await getOrganizationById(\n subscription.metadata.organizationId\n );\n\n // Prevent duplicate subscriptions by canceling conflicting subscriptions\n if (\n organization.plan?.subscriptionId &&\n organization.plan.subscriptionId !== subscriptionId\n ) {\n await stripe.subscriptions.cancel(subscriptionId);\n }\n\n const customerId = invoice.customer as string;\n const { locale, userId, organizationId } =\n await extractMetadata(customerId);\n\n // Set localization in response locals if available\n if (locale) {\n res.locals.locales = locale;\n }\n\n // Update the subscription status in the database\n await changeSubscriptionStatus(\n subscriptionId,\n status,\n userId,\n organizationId\n );\n };\n\n try {\n // Log the event type for debugging and monitoring\n logger.info(`Triggered event type ${event.type}`);\n\n // Handle specific event types\n switch (event.type) {\n case 'customer.subscription.created': {\n logger.info(`Handled event type ${event.type}`);\n // Process a new subscription creation event\n await handleSubscriptionEvent(event.data.object as Stripe.Subscription);\n break;\n }\n case 'customer.subscription.updated': {\n logger.info(`Handled event type ${event.type}`);\n // Process a subscription update event\n await handleSubscriptionEvent(event.data.object as Stripe.Subscription);\n break;\n }\n case 'customer.subscription.deleted': {\n logger.info(`Handled event type ${event.type}`);\n const subscription = event.data\n .object as unknown as Stripe.Subscription;\n const customerId = subscription.customer as string;\n const { locale, organizationId } = await extractMetadata(customerId);\n\n // Set localization in response locals if available\n if (locale) {\n res.locals.locales = locale;\n }\n\n // Handle subscription deletion by canceling it in the database\n await cancelSubscription(subscription.id, organizationId);\n break;\n }\n case 'invoice.payment_succeeded': {\n logger.info(`Handled event type ${event.type}`);\n // Handle successful invoice payment\n await handleInvoiceEvent(event.data.object as Stripe.Invoice, 'active');\n break;\n }\n case 'invoice.payment_failed': {\n logger.info(`Handled event type ${event.type}`);\n // Handle failed invoice payment\n await handleInvoiceEvent(\n event.data.object as Stripe.Invoice,\n 'incomplete'\n );\n break;\n }\n default:\n // Log unhandled event types for visibility\n logger.info(`Unhandled event type ${event.type}`);\n }\n\n // Respond to Stripe to confirm the event was processed successfully\n res.send();\n } catch (error) {\n // Log errors for debugging and respond with a 500 status code\n logger.error(\n `Error handling event ${event.type}: ${(error as Error).message}`\n );\n res.status(500).send('Server Error');\n }\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stripe.webhook.mjs","names":["emailService.sendEmail"],"sources":["../../../src/webhooks/stripe.webhook.ts"],"sourcesContent":["import type { Locale } from '@intlayer/types';\nimport { logger } from '@logger';\nimport * as emailService from '@services/email.service';\nimport { getOrganizationById } from '@services/organization.service';\nimport {\n addOrUpdateSubscription,\n cancelSubscription,\n changeSubscriptionStatus,\n} from '@services/subscription.service';\nimport { getUserById } from '@services/user.service';\nimport { GenericError } from '@utils/errors';\nimport type { Request, Response } from 'express';\nimport { Stripe } from 'stripe';\nimport type { Plan } from '@/types/plan.types';\n\ntype SubscriptionMetadata = {\n locale: Locale; // Localization setting (e.g., 'en', 'fr', 'es')\n userId: string; // ID of the user associated with the subscription\n organizationId: string; // ID of the organization associated with the subscription\n};\n\n/**\n * Stripe webhook handler for processing subscription and invoice events.\n * @param req - Express request object.\n * @param res - Express response object.\n */\nexport const stripeWebhook = async (req: Request, res: Response) => {\n // Initialize the Stripe client with the secret key\n const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);\n\n const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET!; // Webhook secret for verifying event signatures\n const sig = req.headers['stripe-signature']!; // Retrieve the signature from the webhook request headers\n\n let event: Stripe.Event;\n\n // Verify the webhook signature to ensure the request is authentic\n try {\n event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);\n } catch (err) {\n // Respond with a 400 status code if the signature verification fails\n res.status(400).send(`Webhook Error: ${(err as Error).message}`);\n return;\n }\n\n // Utility function to extract metadata from a Stripe customer\n const extractMetadata = async (customerId: string) => {\n const customer = await stripe.customers.retrieve(customerId); // Retrieve customer details from Stripe\n return (customer as Stripe.Customer).metadata as SubscriptionMetadata; // Return the metadata object\n };\n\n // Handles subscription-related events (creation, update, deletion)\n const handleSubscriptionEvent = async (\n subscription: Stripe.Subscription,\n statusOverride?: Plan['status'] // Optionally override the subscription status\n ) => {\n const { id: subscriptionId, customer } = subscription;\n const priceId = subscription.items.data[0]?.price?.id; // Extract the price ID from subscription items\n\n if (!customer) {\n throw new GenericError('STRIPE_SUBSCRIPTION_NO_CUSTOMER');\n }\n\n const customerId = customer as string;\n const { locale, userId, organizationId } =\n await extractMetadata(customerId); // Extract metadata from the customer\n\n // Set localization in response locals if available\n if (locale) {\n res.locals.locales = locale;\n }\n\n const organization = await getOrganizationById(organizationId); // Fetch organization details by ID\n\n if (!organization) {\n throw new GenericError('ORGANIZATION_NOT_FOUND');\n }\n\n const user = await getUserById(userId);\n\n if (!user) {\n throw new GenericError('USER_NOT_FOUND');\n }\n\n const status = statusOverride ?? subscription.status; // Use the provided status override or the subscription's status\n\n // Update or create a subscription record in the database\n await addOrUpdateSubscription(\n subscriptionId,\n priceId!,\n customerId,\n userId,\n organization,\n status\n );\n\n if (status === 'active') {\n await emailService.sendEmail({\n type: 'subscriptionPaymentSuccess',\n to: user.email,\n email: user.email,\n subscriptionStartDate: new Date().toLocaleDateString(),\n manageSubscriptionLink: `${process.env.APP_URL}/organization`,\n username: user.name,\n organizationName: organization.name,\n planName: organization.plan?.type ?? 'Unknown',\n });\n }\n if (status === 'canceled') {\n await emailService.sendEmail({\n type: 'subscriptionPaymentCancellation',\n to: user.email,\n email: user.email,\n cancellationDate: new Date(\n (subscription as any).current_period_end * 1000\n ).toLocaleDateString(),\n reactivateLink: `${process.env.APP_URL}/pricing`,\n username: user.name,\n organizationName: organization.name,\n planName: organization.plan?.type ?? 'Unknown',\n });\n }\n };\n\n // Handles invoice-related events (payment success or failure)\n const handleInvoiceEvent = async (\n invoice: Stripe.Invoice,\n status: 'active' | 'incomplete'\n ) => {\n const subscriptionId =\n typeof (invoice as any).subscription === 'string'\n ? (invoice as any).subscription\n : (invoice as any).subscription?.id; // Extract the subscription ID from the invoice\n if (!subscriptionId) {\n logger.warn('Subscription ID is undefined in invoice.');\n return;\n }\n\n // Retrieve the subscription details from Stripe\n const subscription = await stripe.subscriptions.retrieve(subscriptionId);\n const organization = await getOrganizationById(\n subscription.metadata.organizationId\n );\n\n // Prevent duplicate subscriptions by canceling conflicting subscriptions\n if (\n organization.plan?.subscriptionId &&\n organization.plan.subscriptionId !== subscriptionId\n ) {\n await stripe.subscriptions.cancel(subscriptionId);\n }\n\n const customerId = invoice.customer as string;\n const { locale, userId, organizationId } =\n await extractMetadata(customerId);\n\n // Set localization in response locals if available\n if (locale) {\n res.locals.locales = locale;\n }\n\n // Update the subscription status in the database\n await changeSubscriptionStatus(\n subscriptionId,\n status,\n userId,\n organizationId\n );\n };\n\n try {\n // Log the event type for debugging and monitoring\n logger.info(`Triggered event type ${event.type}`);\n\n // Handle specific event types\n switch (event.type) {\n case 'customer.subscription.created': {\n logger.info(`Handled event type ${event.type}`);\n // Process a new subscription creation event\n await handleSubscriptionEvent(event.data.object as Stripe.Subscription);\n break;\n }\n case 'customer.subscription.updated': {\n logger.info(`Handled event type ${event.type}`);\n // Process a subscription update event\n await handleSubscriptionEvent(event.data.object as Stripe.Subscription);\n break;\n }\n case 'customer.subscription.deleted': {\n logger.info(`Handled event type ${event.type}`);\n const subscription = event.data\n .object as unknown as Stripe.Subscription;\n const customerId = subscription.customer as string;\n const { locale, organizationId } = await extractMetadata(customerId);\n\n // Set localization in response locals if available\n if (locale) {\n res.locals.locales = locale;\n }\n\n // Handle subscription deletion by canceling it in the database\n await cancelSubscription(subscription.id, organizationId);\n break;\n }\n case 'invoice.payment_succeeded': {\n logger.info(`Handled event type ${event.type}`);\n // Handle successful invoice payment\n await handleInvoiceEvent(event.data.object as Stripe.Invoice, 'active');\n break;\n }\n case 'invoice.payment_failed': {\n logger.info(`Handled event type ${event.type}`);\n // Handle failed invoice payment\n await handleInvoiceEvent(\n event.data.object as Stripe.Invoice,\n 'incomplete'\n );\n break;\n }\n default:\n // Log unhandled event types for visibility\n logger.info(`Unhandled event type ${event.type}`);\n }\n\n // Respond to Stripe to confirm the event was processed successfully\n res.send();\n } catch (error) {\n // Log errors for debugging and respond with a 500 status code\n logger.error(\n `Error handling event ${event.type}: ${(error as Error).message}`\n );\n res.status(500).send('Server Error');\n }\n};\n"],"mappings":";;;;;;;;;;;;;;AA0BA,MAAa,gBAAgB,OAAO,KAAc,QAAkB;CAElE,MAAM,SAAS,IAAI,OAAO,QAAQ,IAAI,kBAAmB;CAEzD,MAAM,iBAAiB,QAAQ,IAAI;CACnC,MAAM,MAAM,IAAI,QAAQ;CAExB,IAAI;AAGJ,KAAI;AACF,UAAQ,OAAO,SAAS,eAAe,IAAI,MAAM,KAAK,eAAe;UAC9D,KAAK;AAEZ,MAAI,OAAO,IAAI,CAAC,KAAK,kBAAmB,IAAc,UAAU;AAChE;;CAIF,MAAM,kBAAkB,OAAO,eAAuB;AAEpD,UADiB,MAAM,OAAO,UAAU,SAAS,WAAW,EACvB;;CAIvC,MAAM,0BAA0B,OAC9B,cACA,mBACG;EACH,MAAM,EAAE,IAAI,gBAAgB,aAAa;EACzC,MAAM,UAAU,aAAa,MAAM,KAAK,IAAI,OAAO;AAEnD,MAAI,CAAC,SACH,OAAM,IAAI,aAAa,kCAAkC;EAG3D,MAAM,aAAa;EACnB,MAAM,EAAE,QAAQ,QAAQ,mBACtB,MAAM,gBAAgB,WAAW;AAGnC,MAAI,OACF,KAAI,OAAO,UAAU;EAGvB,MAAM,eAAe,MAAM,oBAAoB,eAAe;AAE9D,MAAI,CAAC,aACH,OAAM,IAAI,aAAa,yBAAyB;EAGlD,MAAM,OAAO,MAAM,YAAY,OAAO;AAEtC,MAAI,CAAC,KACH,OAAM,IAAI,aAAa,iBAAiB;EAG1C,MAAM,SAAS,kBAAkB,aAAa;AAG9C,QAAM,wBACJ,gBACA,SACA,YACA,QACA,cACA,OACD;AAED,MAAI,WAAW,SACb,OAAMA,UAAuB;GAC3B,MAAM;GACN,IAAI,KAAK;GACT,OAAO,KAAK;GACZ,wCAAuB,IAAI,MAAM,EAAC,oBAAoB;GACtD,wBAAwB,GAAG,QAAQ,IAAI,QAAQ;GAC/C,UAAU,KAAK;GACf,kBAAkB,aAAa;GAC/B,UAAU,aAAa,MAAM,QAAQ;GACtC,CAAC;AAEJ,MAAI,WAAW,WACb,OAAMA,UAAuB;GAC3B,MAAM;GACN,IAAI,KAAK;GACT,OAAO,KAAK;GACZ,mCAAkB,IAAI,KACnB,aAAqB,qBAAqB,IAC5C,EAAC,oBAAoB;GACtB,gBAAgB,GAAG,QAAQ,IAAI,QAAQ;GACvC,UAAU,KAAK;GACf,kBAAkB,aAAa;GAC/B,UAAU,aAAa,MAAM,QAAQ;GACtC,CAAC;;CAKN,MAAM,qBAAqB,OACzB,SACA,WACG;EACH,MAAM,iBACJ,OAAQ,QAAgB,iBAAiB,WACpC,QAAgB,eAChB,QAAgB,cAAc;AACrC,MAAI,CAAC,gBAAgB;AACnB,UAAO,KAAK,2CAA2C;AACvD;;EAKF,MAAM,eAAe,MAAM,qBADN,MAAM,OAAO,cAAc,SAAS,eAAe,EAEzD,SAAS,eACvB;AAGD,MACE,aAAa,MAAM,kBACnB,aAAa,KAAK,mBAAmB,eAErC,OAAM,OAAO,cAAc,OAAO,eAAe;EAGnD,MAAM,aAAa,QAAQ;EAC3B,MAAM,EAAE,QAAQ,QAAQ,mBACtB,MAAM,gBAAgB,WAAW;AAGnC,MAAI,OACF,KAAI,OAAO,UAAU;AAIvB,QAAM,yBACJ,gBACA,QACA,QACA,eACD;;AAGH,KAAI;AAEF,SAAO,KAAK,wBAAwB,MAAM,OAAO;AAGjD,UAAQ,MAAM,MAAd;GACE,KAAK;AACH,WAAO,KAAK,sBAAsB,MAAM,OAAO;AAE/C,UAAM,wBAAwB,MAAM,KAAK,OAA8B;AACvE;GAEF,KAAK;AACH,WAAO,KAAK,sBAAsB,MAAM,OAAO;AAE/C,UAAM,wBAAwB,MAAM,KAAK,OAA8B;AACvE;GAEF,KAAK,iCAAiC;AACpC,WAAO,KAAK,sBAAsB,MAAM,OAAO;IAC/C,MAAM,eAAe,MAAM,KACxB;IACH,MAAM,aAAa,aAAa;IAChC,MAAM,EAAE,QAAQ,mBAAmB,MAAM,gBAAgB,WAAW;AAGpE,QAAI,OACF,KAAI,OAAO,UAAU;AAIvB,UAAM,mBAAmB,aAAa,IAAI,eAAe;AACzD;;GAEF,KAAK;AACH,WAAO,KAAK,sBAAsB,MAAM,OAAO;AAE/C,UAAM,mBAAmB,MAAM,KAAK,QAA0B,SAAS;AACvE;GAEF,KAAK;AACH,WAAO,KAAK,sBAAsB,MAAM,OAAO;AAE/C,UAAM,mBACJ,MAAM,KAAK,QACX,aACD;AACD;GAEF,QAEE,QAAO,KAAK,wBAAwB,MAAM,OAAO;;AAIrD,MAAI,MAAM;UACH,OAAO;AAEd,SAAO,MACL,wBAAwB,MAAM,KAAK,IAAK,MAAgB,UACzD;AACD,MAAI,OAAO,IAAI,CAAC,KAAK,eAAe"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai.controller.d.ts","names":[],"sources":["../../../src/controllers/ai.controller.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;KAoCK,8BAA8B,KAAK;cAC1B;AAHuC,CAAA;AAEb,KAI5B,eAAA,GACV,wBALsC,CAKb,kBALa,CAAA,GAAA;EAAL,QAAA,CAAA,EAAA,MAAA,EAAA;EACrB,kBAAA,CAAA,EAAA,MAAA;CAAS;AAGX,KAKA,iBAAA,GACV,YALyB,CAKZ,qBALW,CAAA;AAId,cAGC,WAHgB,EAAA,CAAA,OACd,EAGJ,cAHI,
|
|
1
|
+
{"version":3,"file":"ai.controller.d.ts","names":[],"sources":["../../../src/controllers/ai.controller.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitlab.controller.d.ts","names":[],"sources":["../../../src/controllers/gitlab.controller.ts"],"sourcesContent":[],"mappings":";;;;;KAMY,2BAAA;;EAAA,WAAA,CAAA,EAAA,MAAA;EAMA,KAAA,CAAA,EAAA,MAAA;AAIZ,CAAA;AACyC,KAL7B,sBAAA,GAAyB,YAKI,CAAA;EAA9B,OAAA,EAAA,MAAA;CACF,CAAA;AACN,cAHU,UAGV,EAAA,CAAA,OAAA,EAFQ,cAER,CAAA;EAAO,WAAA,EAF+B,2BAE/B;AAyBV,CAAA,CAAA,EAAY,KAAA,EA1BH,YA0BG,EAAA,GAzBT,OAyB+B,CAAA,IAAA,CAAA;AAMtB,KANA,sBAAA,GAMwB;EAIvB,IAAA,EAAA,MAAA;EACqB,WAAA,EAAA,MAAA;EAAvB,WAAA,CAAA,EAAA,MAAA;CACF;AACN,KAPS,wBAAA,GAA2B,YAOpC,CAAA;EAAO,KAAA,EAAA,MAAA;AAyBV,CAAA,CAAA;AAKY,cAjCC,YAiCuB,EAAA,CAAA,
|
|
1
|
+
{"version":3,"file":"gitlab.controller.d.ts","names":[],"sources":["../../../src/controllers/gitlab.controller.ts"],"sourcesContent":[],"mappings":";;;;;KAMY,2BAAA;;EAAA,WAAA,CAAA,EAAA,MAAA;EAMA,KAAA,CAAA,EAAA,MAAA;AAIZ,CAAA;AACyC,KAL7B,sBAAA,GAAyB,YAKI,CAAA;EAA9B,OAAA,EAAA,MAAA;CACF,CAAA;AACN,cAHU,UAGV,EAAA,CAAA,OAAA,EAFQ,cAER,CAAA;EAAO,WAAA,EAF+B,2BAE/B;AAyBV,CAAA,CAAA,EAAY,KAAA,EA1BH,YA0BG,EAAA,GAzBT,OAyB+B,CAAA,IAAA,CAAA;AAMtB,KANA,sBAAA,GAMwB;EAIvB,IAAA,EAAA,MAAA;EACqB,WAAA,EAAA,MAAA;EAAvB,WAAA,CAAA,EAAA,MAAA;CACF;AACN,KAPS,wBAAA,GAA2B,YAOpC,CAAA;EAAO,KAAA,EAAA,MAAA;AAyBV,CAAA,CAAA;AAKY,cAjCC,YAiCuB,EAAA,CAAA,OAClC,EAjCS,cAgC4B,CAAA;EAI1B,IAAA,EApCqB,sBAoEjC;CA/BwC,CAAA,EAAA,KAAA,EApChC,YAoCgC,EAAA,GAnCtC,OAmCsC,CAAA,IAAA,CAAA;AAA9B,KAVC,6BAAA,GAUD;EACF,KAAA,CAAA,EAAA,MAAA;EACN,WAAA,CAAA,EAAA,MAAA;CAAO;AA+BE,KAtCA,wBAAA,GAA2B,YAsCN,CArC/B,aAqC+B,EAAA,CAAA;AAOrB,cAzCC,YAyCsB,EAAA,CAAA,OAAG,EAxC3B,cAwCuC,CAAA;EAQrC,WAAA,EAhD4B,6BA0FxC;CAzCiC,CAAA,EAAA,KAAA,EAhDzB,YAgDyB,EAAA,GA/C/B,OA+C+B,CAAA,IAAA,CAAA;AAAvB,KAhBC,qBAAA,GAgBD;EACF,KAAA,CAAA,EAAA,MAAA;EACN,SAAA,EAAA,MAAA;EAAO,MAAA,CAAA,EAAA,MAAA;EAyCE,WAAA,CAAA,EAAA,MAAA;AAQZ,CAAA;AAIa,KAhED,uBAAA,GAA0B,YAkHrC,CAAA;EAjDiC,SAAA,EAAA,OAAA;EAAvB,WAAA,EAAA,MAAA,EAAA;CACF,CAAA;;;;cA1DI,uBACF;QAAuB;WACzB,iBACN;KAyCS,uBAAA;;;;;;;KAQA,yBAAA,GAA4B;;;cAI3B,yBACF;QAAuB;WACzB,iBACN"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime5 from "react/jsx-runtime";
|
|
2
2
|
|
|
3
3
|
//#region src/emails/InviteUserEmail.d.ts
|
|
4
4
|
type InviteUserEmailProps = {
|
|
@@ -19,7 +19,7 @@ declare const InviteUserEmailEN: {
|
|
|
19
19
|
inviteLink,
|
|
20
20
|
inviteFromIp,
|
|
21
21
|
inviteFromLocation
|
|
22
|
-
}: InviteUserEmailProps):
|
|
22
|
+
}: InviteUserEmailProps): react_jsx_runtime5.JSX.Element;
|
|
23
23
|
PreviewProps: InviteUserEmailProps;
|
|
24
24
|
};
|
|
25
25
|
declare const InviteUserEmailFR: {
|
|
@@ -31,7 +31,7 @@ declare const InviteUserEmailFR: {
|
|
|
31
31
|
inviteLink,
|
|
32
32
|
inviteFromIp,
|
|
33
33
|
inviteFromLocation
|
|
34
|
-
}: InviteUserEmailProps):
|
|
34
|
+
}: InviteUserEmailProps): react_jsx_runtime5.JSX.Element;
|
|
35
35
|
PreviewProps: InviteUserEmailProps;
|
|
36
36
|
};
|
|
37
37
|
declare const InviteUserEmailES: {
|
|
@@ -43,7 +43,7 @@ declare const InviteUserEmailES: {
|
|
|
43
43
|
inviteLink,
|
|
44
44
|
inviteFromIp,
|
|
45
45
|
inviteFromLocation
|
|
46
|
-
}: InviteUserEmailProps):
|
|
46
|
+
}: InviteUserEmailProps): react_jsx_runtime5.JSX.Element;
|
|
47
47
|
PreviewProps: InviteUserEmailProps;
|
|
48
48
|
};
|
|
49
49
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InviteUserEmail.d.ts","names":[],"sources":["../../../src/emails/InviteUserEmail.tsx"],"sourcesContent":[],"mappings":";;;KAgBY,oBAAA;;;EAAA,cAAA,EAAA,MAAA;EAUC,gBAAA,EAAA,MAmFZ;;;;;cAnFY;;;;;;;;;KAQV,uBAAoB,
|
|
1
|
+
{"version":3,"file":"InviteUserEmail.d.ts","names":[],"sources":["../../../src/emails/InviteUserEmail.tsx"],"sourcesContent":[],"mappings":";;;KAgBY,oBAAA;;;EAAA,cAAA,EAAA,MAAA;EAUC,gBAAA,EAAA,MAmFZ;;;;;cAnFY;;;;;;;;;KAQV,uBAAoB,kBAAA,CAAA,GAAA,CAAA;;CAApB;AAAoB,cA6EV,iBA7EU,EAAA;;;;;;;;;KAqFpB,uBAAoB,kBAAA,CAAA,GAAA,CAAA;;AARvB,CAAA;cAqFa;;;;;;;;;KAQV,uBAAoB,kBAAA,CAAA,GAAA,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime2 from "react/jsx-runtime";
|
|
2
2
|
|
|
3
3
|
//#region src/emails/MagicLinkEmail.d.ts
|
|
4
4
|
type MagicLinkEmailProps = {
|
|
@@ -9,21 +9,21 @@ declare const MagicLinkEmailEN: {
|
|
|
9
9
|
({
|
|
10
10
|
username,
|
|
11
11
|
magicLink
|
|
12
|
-
}: MagicLinkEmailProps):
|
|
12
|
+
}: MagicLinkEmailProps): react_jsx_runtime2.JSX.Element;
|
|
13
13
|
PreviewProps: MagicLinkEmailProps;
|
|
14
14
|
};
|
|
15
15
|
declare const MagicLinkEmailFR: {
|
|
16
16
|
({
|
|
17
17
|
username,
|
|
18
18
|
magicLink
|
|
19
|
-
}: MagicLinkEmailProps):
|
|
19
|
+
}: MagicLinkEmailProps): react_jsx_runtime2.JSX.Element;
|
|
20
20
|
PreviewProps: MagicLinkEmailProps;
|
|
21
21
|
};
|
|
22
22
|
declare const MagicLinkEmailES: {
|
|
23
23
|
({
|
|
24
24
|
username,
|
|
25
25
|
magicLink
|
|
26
|
-
}: MagicLinkEmailProps):
|
|
26
|
+
}: MagicLinkEmailProps): react_jsx_runtime2.JSX.Element;
|
|
27
27
|
PreviewProps: MagicLinkEmailProps;
|
|
28
28
|
};
|
|
29
29
|
//#endregion
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime8 from "react/jsx-runtime";
|
|
2
2
|
|
|
3
3
|
//#region src/emails/OAuthTokenCreatedEmail.d.ts
|
|
4
4
|
type OAuthTokenCreatedEmailProps = {
|
|
@@ -17,7 +17,7 @@ declare const OAuthTokenCreatedEmailEN: {
|
|
|
17
17
|
tokenDetailsUrl,
|
|
18
18
|
securityLogUrl,
|
|
19
19
|
supportUrl
|
|
20
|
-
}: OAuthTokenCreatedEmailProps):
|
|
20
|
+
}: OAuthTokenCreatedEmailProps): react_jsx_runtime8.JSX.Element;
|
|
21
21
|
PreviewProps: OAuthTokenCreatedEmailProps;
|
|
22
22
|
};
|
|
23
23
|
declare const OAuthTokenCreatedEmailFR: {
|
|
@@ -28,7 +28,7 @@ declare const OAuthTokenCreatedEmailFR: {
|
|
|
28
28
|
tokenDetailsUrl,
|
|
29
29
|
securityLogUrl,
|
|
30
30
|
supportUrl
|
|
31
|
-
}: OAuthTokenCreatedEmailProps):
|
|
31
|
+
}: OAuthTokenCreatedEmailProps): react_jsx_runtime8.JSX.Element;
|
|
32
32
|
PreviewProps: OAuthTokenCreatedEmailProps;
|
|
33
33
|
};
|
|
34
34
|
declare const OAuthTokenCreatedEmailES: {
|
|
@@ -39,7 +39,7 @@ declare const OAuthTokenCreatedEmailES: {
|
|
|
39
39
|
tokenDetailsUrl,
|
|
40
40
|
securityLogUrl,
|
|
41
41
|
supportUrl
|
|
42
|
-
}: OAuthTokenCreatedEmailProps):
|
|
42
|
+
}: OAuthTokenCreatedEmailProps): react_jsx_runtime8.JSX.Element;
|
|
43
43
|
PreviewProps: OAuthTokenCreatedEmailProps;
|
|
44
44
|
};
|
|
45
45
|
//#endregion
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime11 from "react/jsx-runtime";
|
|
2
2
|
|
|
3
3
|
//#region src/emails/PasswordChangeConfirmation.d.ts
|
|
4
4
|
type PasswordChangeConfirmationEmailProps = {
|
|
@@ -7,19 +7,19 @@ type PasswordChangeConfirmationEmailProps = {
|
|
|
7
7
|
declare const PasswordChangeConfirmationEmailEN: {
|
|
8
8
|
({
|
|
9
9
|
username
|
|
10
|
-
}: PasswordChangeConfirmationEmailProps):
|
|
10
|
+
}: PasswordChangeConfirmationEmailProps): react_jsx_runtime11.JSX.Element;
|
|
11
11
|
PreviewProps: PasswordChangeConfirmationEmailProps;
|
|
12
12
|
};
|
|
13
13
|
declare const PasswordChangeConfirmationEmailFR: {
|
|
14
14
|
({
|
|
15
15
|
username
|
|
16
|
-
}: PasswordChangeConfirmationEmailProps):
|
|
16
|
+
}: PasswordChangeConfirmationEmailProps): react_jsx_runtime11.JSX.Element;
|
|
17
17
|
PreviewProps: PasswordChangeConfirmationEmailProps;
|
|
18
18
|
};
|
|
19
19
|
declare const PasswordChangeConfirmationEmailES: {
|
|
20
20
|
({
|
|
21
21
|
username
|
|
22
|
-
}: PasswordChangeConfirmationEmailProps):
|
|
22
|
+
}: PasswordChangeConfirmationEmailProps): react_jsx_runtime11.JSX.Element;
|
|
23
23
|
PreviewProps: PasswordChangeConfirmationEmailProps;
|
|
24
24
|
};
|
|
25
25
|
//#endregion
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime14 from "react/jsx-runtime";
|
|
2
2
|
|
|
3
3
|
//#region src/emails/ResetUserPassword.d.ts
|
|
4
4
|
type ResetPasswordEmailProps = {
|
|
@@ -9,21 +9,21 @@ declare const ResetPasswordEmailEN: {
|
|
|
9
9
|
({
|
|
10
10
|
username,
|
|
11
11
|
resetLink
|
|
12
|
-
}: ResetPasswordEmailProps):
|
|
12
|
+
}: ResetPasswordEmailProps): react_jsx_runtime14.JSX.Element;
|
|
13
13
|
PreviewProps: ResetPasswordEmailProps;
|
|
14
14
|
};
|
|
15
15
|
declare const ResetPasswordEmailFR: {
|
|
16
16
|
({
|
|
17
17
|
username,
|
|
18
18
|
resetLink
|
|
19
|
-
}: ResetPasswordEmailProps):
|
|
19
|
+
}: ResetPasswordEmailProps): react_jsx_runtime14.JSX.Element;
|
|
20
20
|
PreviewProps: ResetPasswordEmailProps;
|
|
21
21
|
};
|
|
22
22
|
declare const ResetPasswordEmailES: {
|
|
23
23
|
({
|
|
24
24
|
username,
|
|
25
25
|
resetLink
|
|
26
|
-
}: ResetPasswordEmailProps):
|
|
26
|
+
}: ResetPasswordEmailProps): react_jsx_runtime14.JSX.Element;
|
|
27
27
|
PreviewProps: ResetPasswordEmailProps;
|
|
28
28
|
};
|
|
29
29
|
//#endregion
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime23 from "react/jsx-runtime";
|
|
2
2
|
|
|
3
3
|
//#region src/emails/SubscriptionPaymentCancellation.d.ts
|
|
4
4
|
type SubscriptionPaymentCancellationProps = {
|
|
@@ -16,7 +16,7 @@ declare const SubscriptionPaymentCancellationEN: {
|
|
|
16
16
|
organizationName,
|
|
17
17
|
cancellationDate,
|
|
18
18
|
reactivateLink
|
|
19
|
-
}: SubscriptionPaymentCancellationProps):
|
|
19
|
+
}: SubscriptionPaymentCancellationProps): react_jsx_runtime23.JSX.Element;
|
|
20
20
|
PreviewProps: SubscriptionPaymentCancellationProps;
|
|
21
21
|
};
|
|
22
22
|
declare const SubscriptionPaymentCancellationFR: {
|
|
@@ -26,7 +26,7 @@ declare const SubscriptionPaymentCancellationFR: {
|
|
|
26
26
|
organizationName,
|
|
27
27
|
cancellationDate,
|
|
28
28
|
reactivateLink
|
|
29
|
-
}: SubscriptionPaymentCancellationProps):
|
|
29
|
+
}: SubscriptionPaymentCancellationProps): react_jsx_runtime23.JSX.Element;
|
|
30
30
|
PreviewProps: SubscriptionPaymentCancellationProps;
|
|
31
31
|
};
|
|
32
32
|
declare const SubscriptionPaymentCancellationES: {
|
|
@@ -36,7 +36,7 @@ declare const SubscriptionPaymentCancellationES: {
|
|
|
36
36
|
organizationName,
|
|
37
37
|
cancellationDate,
|
|
38
38
|
reactivateLink
|
|
39
|
-
}: SubscriptionPaymentCancellationProps):
|
|
39
|
+
}: SubscriptionPaymentCancellationProps): react_jsx_runtime23.JSX.Element;
|
|
40
40
|
PreviewProps: SubscriptionPaymentCancellationProps;
|
|
41
41
|
};
|
|
42
42
|
//#endregion
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime17 from "react/jsx-runtime";
|
|
2
2
|
|
|
3
3
|
//#region src/emails/SubscriptionPaymentError.d.ts
|
|
4
4
|
type SubscriptionPaymentErrorProps = {
|
|
@@ -16,7 +16,7 @@ declare const SubscriptionPaymentErrorEN: {
|
|
|
16
16
|
organizationName,
|
|
17
17
|
errorDate,
|
|
18
18
|
retryPaymentLink
|
|
19
|
-
}: SubscriptionPaymentErrorProps):
|
|
19
|
+
}: SubscriptionPaymentErrorProps): react_jsx_runtime17.JSX.Element;
|
|
20
20
|
PreviewProps: SubscriptionPaymentErrorProps;
|
|
21
21
|
};
|
|
22
22
|
declare const SubscriptionPaymentErrorFR: {
|
|
@@ -26,7 +26,7 @@ declare const SubscriptionPaymentErrorFR: {
|
|
|
26
26
|
organizationName,
|
|
27
27
|
errorDate,
|
|
28
28
|
retryPaymentLink
|
|
29
|
-
}: SubscriptionPaymentErrorProps):
|
|
29
|
+
}: SubscriptionPaymentErrorProps): react_jsx_runtime17.JSX.Element;
|
|
30
30
|
PreviewProps: SubscriptionPaymentErrorProps;
|
|
31
31
|
};
|
|
32
32
|
declare const SubscriptionPaymentErrorES: {
|
|
@@ -36,7 +36,7 @@ declare const SubscriptionPaymentErrorES: {
|
|
|
36
36
|
organizationName,
|
|
37
37
|
errorDate,
|
|
38
38
|
retryPaymentLink
|
|
39
|
-
}: SubscriptionPaymentErrorProps):
|
|
39
|
+
}: SubscriptionPaymentErrorProps): react_jsx_runtime17.JSX.Element;
|
|
40
40
|
PreviewProps: SubscriptionPaymentErrorProps;
|
|
41
41
|
};
|
|
42
42
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SubscriptionPaymentError.d.ts","names":[],"sources":["../../../src/emails/SubscriptionPaymentError.tsx"],"sourcesContent":[],"mappings":";;;KAcY,6BAAA;;;EAAA,QAAA,EAAA,MAAA;EAUC,gBAAA,EAAA,MAAA;;;;cAAA;;;;;;;KAMV,gCAA6B,
|
|
1
|
+
{"version":3,"file":"SubscriptionPaymentError.d.ts","names":[],"sources":["../../../src/emails/SubscriptionPaymentError.tsx"],"sourcesContent":[],"mappings":";;;KAcY,6BAAA;;;EAAA,QAAA,EAAA,MAAA;EAUC,gBAAA,EAAA,MAAA;;;;cAAA;;;;;;;KAMV,gCAA6B,mBAAA,CAAA,GAAA,CAAA;EAA7B,YAAA,+BAAA;CAA6B;cAkDnB;;;;;;;KAMV,gCAA6B,mBAAA,CAAA,GAAA,CAAA;EANnB,YAAA,+BAsDZ;;cAGY;;;;;;;KAMV,gCAA6B,mBAAA,CAAA,GAAA,CAAA"}
|