arkos 2.0.0-next.29 → 2.0.0-next.30

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.
Files changed (132) hide show
  1. package/dist/esm/app.js +2 -0
  2. package/dist/esm/app.js.map +1 -1
  3. package/dist/esm/components/arkos-gateway/arkos-gateway.js +22 -5
  4. package/dist/esm/components/arkos-gateway/arkos-gateway.js.map +1 -1
  5. package/dist/esm/components/arkos-gateway/types.js.map +1 -1
  6. package/dist/esm/components/arkos-route-hook/index.js +9 -3
  7. package/dist/esm/components/arkos-route-hook/index.js.map +1 -1
  8. package/dist/esm/components/arkos-route-hook/reader.js.map +1 -1
  9. package/dist/esm/components/arkos-route-hook/types.js.map +1 -1
  10. package/dist/esm/exports/file-upload.js +2 -0
  11. package/dist/esm/exports/file-upload.js.map +1 -0
  12. package/dist/esm/exports/index.js.map +1 -1
  13. package/dist/esm/exports/websockets.js.map +1 -1
  14. package/dist/esm/generated.js.map +1 -1
  15. package/dist/esm/modules/auth/auth.controller.js +84 -141
  16. package/dist/esm/modules/auth/auth.controller.js.map +1 -1
  17. package/dist/esm/modules/auth/auth.router.js +1 -1
  18. package/dist/esm/modules/auth/auth.router.js.map +1 -1
  19. package/dist/esm/modules/auth/auth.service.js +93 -15
  20. package/dist/esm/modules/auth/auth.service.js.map +1 -1
  21. package/dist/esm/modules/auth/auth.types.js +2 -0
  22. package/dist/esm/modules/auth/auth.types.js.map +1 -0
  23. package/dist/esm/modules/auth/utils/helpers/auth.controller.helpers.js +1 -0
  24. package/dist/esm/modules/auth/utils/helpers/auth.controller.helpers.js.map +1 -1
  25. package/dist/esm/modules/auth/utils/token-extraction.js +57 -0
  26. package/dist/esm/modules/auth/utils/token-extraction.js.map +1 -0
  27. package/dist/esm/modules/base/base.controller.js +5 -0
  28. package/dist/esm/modules/base/base.controller.js.map +1 -1
  29. package/dist/esm/modules/base/base.middlewares.js +4 -4
  30. package/dist/esm/modules/base/base.middlewares.js.map +1 -1
  31. package/dist/esm/modules/base/utils/error-prettifier.js +64 -0
  32. package/dist/esm/modules/base/utils/error-prettifier.js.map +1 -1
  33. package/dist/esm/modules/error-handler/utils/error-handler.helpers.js +52 -8
  34. package/dist/esm/modules/error-handler/utils/error-handler.helpers.js.map +1 -1
  35. package/dist/esm/modules/error-handler/utils/get-handled-error.js +5 -0
  36. package/dist/esm/modules/error-handler/utils/get-handled-error.js.map +1 -1
  37. package/dist/esm/modules/file-upload/file-upload.controller.js +25 -7
  38. package/dist/esm/modules/file-upload/file-upload.controller.js.map +1 -1
  39. package/dist/esm/modules/file-upload/file-upload.router.js +21 -5
  40. package/dist/esm/modules/file-upload/file-upload.router.js.map +1 -1
  41. package/dist/esm/modules/file-upload/file-upload.service.js +28 -18
  42. package/dist/esm/modules/file-upload/file-upload.service.js.map +1 -1
  43. package/dist/esm/modules/file-upload/utils/file-upload-json-schema-generator.js +37 -12
  44. package/dist/esm/modules/file-upload/utils/file-upload-json-schema-generator.js.map +1 -1
  45. package/dist/esm/modules/file-upload/utils/helpers/file-upload.helpers.js +73 -35
  46. package/dist/esm/modules/file-upload/utils/helpers/file-upload.helpers.js.map +1 -1
  47. package/dist/esm/modules/file-upload/utils/helpers/serve-upload-dir.js +206 -0
  48. package/dist/esm/modules/file-upload/utils/helpers/serve-upload-dir.js.map +1 -0
  49. package/dist/esm/modules/file-upload/utils/helpers/upload-path.helper.js +103 -0
  50. package/dist/esm/modules/file-upload/utils/helpers/upload-path.helper.js.map +1 -0
  51. package/dist/esm/modules/file-upload/utils/helpers/upload-serving-validation.js +212 -0
  52. package/dist/esm/modules/file-upload/utils/helpers/upload-serving-validation.js.map +1 -0
  53. package/dist/esm/modules/file-upload/utils/helpers/upload-serving.registry.js +30 -0
  54. package/dist/esm/modules/file-upload/utils/helpers/upload-serving.registry.js.map +1 -0
  55. package/dist/esm/modules/swagger/utils/helpers/get-swagger-default-configs.js +1 -1
  56. package/dist/esm/modules/swagger/utils/helpers/get-swagger-default-configs.js.map +1 -1
  57. package/dist/esm/modules/swagger/utils/helpers/openapi-schema-converter.js +7 -8
  58. package/dist/esm/modules/swagger/utils/helpers/openapi-schema-converter.js.map +1 -1
  59. package/dist/esm/types/index.js.map +1 -1
  60. package/dist/esm/types/internal.js +2 -0
  61. package/dist/esm/types/internal.js.map +1 -0
  62. package/dist/esm/types/new-arkos-config.js.map +1 -1
  63. package/dist/esm/types/upload.js.map +1 -1
  64. package/dist/esm/types/validation/validation-manager.js +18 -10
  65. package/dist/esm/types/validation/validation-manager.js.map +1 -1
  66. package/dist/esm/types/validation/validator.js.map +1 -1
  67. package/dist/esm/utils/arkos-router/arkos-router-openapi-manager.js.map +1 -1
  68. package/dist/esm/utils/arkos-router/index.js +2 -11
  69. package/dist/esm/utils/arkos-router/index.js.map +1 -1
  70. package/dist/esm/utils/arkos-router/route-config-validator.js +11 -10
  71. package/dist/esm/utils/arkos-router/route-config-validator.js.map +1 -1
  72. package/dist/esm/utils/arkos-router/types/index.js.map +1 -1
  73. package/dist/esm/utils/arkos-router/types/upload-config.js.map +1 -1
  74. package/dist/esm/utils/arkos-router/utils/helpers/index.js +1 -0
  75. package/dist/esm/utils/arkos-router/utils/helpers/index.js.map +1 -1
  76. package/dist/esm/utils/arkos-router/utils/helpers/upload-manager.js +326 -37
  77. package/dist/esm/utils/arkos-router/utils/helpers/upload-manager.js.map +1 -1
  78. package/dist/esm/utils/cli/dev.js +15 -2
  79. package/dist/esm/utils/cli/dev.js.map +1 -1
  80. package/dist/esm/utils/cli/generate.js +8 -3
  81. package/dist/esm/utils/cli/generate.js.map +1 -1
  82. package/dist/esm/utils/cli/index.js +21 -20
  83. package/dist/esm/utils/cli/index.js.map +1 -1
  84. package/dist/esm/utils/cli/prisma-generate.js +24 -5
  85. package/dist/esm/utils/cli/prisma-generate.js.map +1 -1
  86. package/dist/esm/utils/cli/start.js +2 -0
  87. package/dist/esm/utils/cli/start.js.map +1 -1
  88. package/dist/esm/utils/cli/utils/cli.helpers.js +1 -1
  89. package/dist/esm/utils/cli/utils/dependency-version-check.js +39 -0
  90. package/dist/esm/utils/cli/utils/dependency-version-check.js.map +1 -0
  91. package/dist/esm/utils/cli/utils/template-generator/templates/router-template.js.map +1 -1
  92. package/dist/esm/utils/define-config.js +1 -0
  93. package/dist/esm/utils/define-config.js.map +1 -1
  94. package/dist/esm/utils/initialize-app.js +2 -0
  95. package/dist/esm/utils/initialize-app.js.map +1 -1
  96. package/dist/types/app.d.ts +5 -2
  97. package/dist/types/components/arkos-gateway/arkos-gateway.d.ts +19 -7
  98. package/dist/types/components/arkos-gateway/types.d.ts +19 -2
  99. package/dist/types/components/arkos-route-hook/index.d.ts +4 -3
  100. package/dist/types/components/arkos-route-hook/reader.d.ts +1 -1
  101. package/dist/types/components/arkos-route-hook/types.d.ts +4 -1
  102. package/dist/types/exports/file-upload.d.ts +1 -0
  103. package/dist/types/exports/index.d.ts +1 -2
  104. package/dist/types/exports/websockets.d.ts +1 -1
  105. package/dist/types/modules/auth/auth.controller.d.ts +10 -3
  106. package/dist/types/modules/auth/auth.service.d.ts +90 -0
  107. package/dist/types/modules/auth/auth.types.d.ts +72 -0
  108. package/dist/types/modules/auth/utils/helpers/auth.controller.helpers.d.ts +1 -0
  109. package/dist/types/modules/auth/utils/token-extraction.d.ts +53 -0
  110. package/dist/types/modules/base/base.controller.d.ts +1 -0
  111. package/dist/types/modules/base/utils/error-prettifier.d.ts +8 -0
  112. package/dist/types/modules/error-handler/utils/error-handler.helpers.d.ts +1 -0
  113. package/dist/types/modules/file-upload/file-upload.service.d.ts +2 -6
  114. package/dist/types/modules/file-upload/utils/helpers/file-upload.helpers.d.ts +21 -1
  115. package/dist/types/modules/file-upload/utils/helpers/serve-upload-dir.d.ts +43 -0
  116. package/dist/types/modules/file-upload/utils/helpers/upload-path.helper.d.ts +14 -0
  117. package/dist/types/modules/file-upload/utils/helpers/upload-serving-validation.d.ts +5 -0
  118. package/dist/types/modules/file-upload/utils/helpers/upload-serving.registry.d.ts +31 -0
  119. package/dist/types/modules/swagger/utils/helpers/openapi-schema-converter.d.ts +1 -1
  120. package/dist/types/types/index.d.ts +5 -0
  121. package/dist/types/types/internal.d.ts +25 -0
  122. package/dist/types/types/new-arkos-config.d.ts +24 -2
  123. package/dist/types/types/upload.d.ts +35 -0
  124. package/dist/types/types/validation/validation-manager.d.ts +6 -8
  125. package/dist/types/types/validation/validator.d.ts +2 -2
  126. package/dist/types/utils/arkos-router/types/index.d.ts +3 -2
  127. package/dist/types/utils/arkos-router/types/upload-config.d.ts +102 -11
  128. package/dist/types/utils/arkos-router/utils/helpers/upload-manager.d.ts +20 -0
  129. package/dist/types/utils/cli/utils/dependency-version-check.d.ts +15 -0
  130. package/dist/types/utils/define-config.d.ts +56 -2
  131. package/dist/types/utils/helpers/prisma.helpers.d.ts +1 -1
  132. package/package.json +15 -38
@@ -1 +1 @@
1
- {"version":3,"file":"auth.service.js","sourceRoot":"","sources":["../../../../src/modules/auth/auth.service.ts"],"names":[],"mappings":"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","sourcesContent":["import jwt, { SignOptions } from 'jsonwebtoken';\nimport bcrypt from 'bcryptjs';\nimport { User } from '../../types';\nimport catchAsync from '../error-handler/utils/catch-async';\nimport AppError from '../error-handler/utils/app-error';\nimport arkosEnv from '../../utils/arkos-env';\nimport { getPrismaInstance } from '../../utils/helpers/prisma.helpers';\nimport {\n ArkosRequest,\n ArkosResponse,\n ArkosNextFunction,\n ArkosRequestHandler,\n} from '../../types';\nimport {\n AuthJwtPayload,\n AccessAction,\n AccessControlConfig,\n AccessControlRules,\n DetailedAccessControlRule,\n} from '../../types/auth';\nimport { MsDuration, toMs } from './utils/helpers/auth.controller.helpers';\nimport {\n invaliAuthTokenError,\n loginRequiredError,\n} from './utils/auth-error-objects';\nimport authActionService from './utils/services/auth-action.service';\nimport {\n getArkosConfig,\n isAuthenticationEnabled,\n isUsingAuthentication,\n} from '../../utils/helpers/arkos-config.helpers';\nimport { CookieOptions } from 'express';\nimport { getUserFileExtension } from '../../utils/helpers/fs.helpers';\nimport { authenticationDocsLinks } from './utils/docs-links';\nimport authHookManager from './utils/auth-hooks-manager';\nimport { ArkosSocket } from '../../components/arkos-gateway/types';\n\n/**\n * Handles various authentication-related tasks such as JWT signing, password hashing, and verifying user credentials.\n */\nexport class AuthService {\n /**\n * Object containing a combination of actions per resource, tracked by each set of calls of `authService.handleAccessControl`, this can be accessed through the `authService` object or through the endpoint\n */\n actionsPerResource: Record<string, Set<string>> = {};\n\n /**\n * Signs a JWT token for the user.\n *\n * @param {number | string} id - The unique identifier of the user to generate the token for.\n * @param {string | number} [expiresIn] - The expiration time for the token. Defaults to environment variable `JWT_EXPIRES_IN`.\n * @param {string} [secret] - The secret key used to sign the token. Defaults to environment variable `JWT_SECRET`.\n * @returns {string} The signed JWT token.\n */\n signJwtToken(\n id: number | string,\n expiresIn?: MsDuration | number,\n secret?: string,\n ): string {\n const { authentication: configs } = getArkosConfig();\n\n if (\n process.env.ARKOS_BUILD === 'true' &&\n !process.env.JWT_SECRET &&\n !configs?.jwt?.secret\n )\n throw new AppError(\n 'Missing JWT secret on production!',\n 500,\n 'MissingJWTOnProduction',\n );\n\n secret =\n secret ||\n configs?.jwt?.secret ||\n process.env.JWT_SECRET ||\n arkosEnv.JWT_SECRET;\n\n expiresIn = (expiresIn ||\n configs?.jwt?.expiresIn ||\n process.env.JWT_EXPIRES_IN ||\n arkosEnv.JWT_EXPIRES_IN) as keyof SignOptions['expiresIn'];\n\n return jwt.sign({ id }, secret, {\n expiresIn: expiresIn as MsDuration,\n });\n }\n\n /**\n * Retrieves cookie configuration options for JWT authentication.\n *\n * Merges configuration from multiple sources in order of precedence:\n * 1. Arkos configuration file\n * 2. Environment variables\n * 3. Request properties (for secure flag)\n * 4. Default fallback values\n *\n * @param req - ArkosRequest object used to determine if the connection is secure\n * @returns Cookie options object with expires, httpOnly, secure, and sameSite properties\n *\n * @example\n * ```typescript\n * const cookieOptions = authService.getJwtCookieOptions(req);\n * res.cookie('jwt', token, cookieOptions);\n * ```\n */\n getJwtCookieOptions(req: ArkosRequest) {\n const arkosConfig = getArkosConfig();\n const authConfigs = arkosConfig?.authentication;\n\n if (!req)\n throw new Error('Missing req object in order get jwt cookie options');\n\n const sameSite =\n authConfigs?.jwt?.cookie?.sameSite ||\n (process.env.JWT_COOKIE_SAME_SITE as\n 'none' | 'lax' | 'strict' | undefined) ||\n 'lax';\n\n return {\n expires: new Date(\n Date.now() +\n Number(\n toMs(\n authConfigs?.jwt?.expiresIn ||\n (process.env.JWT_EXPIRES_IN as MsDuration) ||\n (arkosEnv.JWT_EXPIRES_IN as MsDuration),\n ),\n ),\n ),\n httpOnly:\n authConfigs?.jwt?.cookie?.httpOnly ??\n (process.env.JWT_COOKIE_HTTP_ONLY !== undefined\n ? process.env.JWT_COOKIE_HTTP_ONLY === 'true'\n : undefined) ??\n true,\n secure: (() => {\n if (authConfigs?.jwt?.cookie?.secure !== undefined)\n return authConfigs?.jwt?.cookie?.secure;\n else if (process.env.JWT_COOKIE_SECURE !== undefined)\n return process.env.JWT_COOKIE_SECURE === 'true';\n else return req.secure || req.headers['x-forwarded-proto'] === 'https';\n })(),\n sameSite,\n domain: authConfigs?.jwt?.cookie?.domain || process.env.JWT_COOKIE_DOMAIN,\n ...arkosConfig?.authentication?.jwt?.cookie,\n } as CookieOptions;\n }\n\n /**\n * Is used by default internally by Arkos under `ArkosPrismaService` class to check if the password is already hashed.\n *\n * This was just added to prevent unwanted errors when someone just forgets that the `ArkosPrismaService` class will automatically hash the password field using `authService.hashPassword` by default.\n *\n * So now before `ArkosPrismaService` hashes it will test it.\n *\n *\n * @param password The password to be tested if is hashed\n * @returns\n */\n isPasswordHashed(password: string) {\n return !Number.isNaN(bcrypt.getRounds(password) * 1);\n }\n\n /**\n * Compares a candidate password with the stored user password to check if they match.\n *\n * @param {string} candidatePassword - The password provided by the user during login.\n * @param {string} userPassword - The password stored in the database.\n * @returns {Promise<boolean>} Returns true if the passwords match, otherwise false.\n */\n async isCorrectPassword(\n candidatePassword: string,\n userPassword: string,\n ): Promise<boolean> {\n return await bcrypt.compare(candidatePassword, userPassword);\n }\n\n /**\n * Hashes a plain text password using bcrypt.\n *\n * @param {string} password - The password to be hashed.\n * @returns {Promise<string>} Returns the hashed password.\n */\n async hashPassword(password: string): Promise<string> {\n return await bcrypt.hash(password, 12);\n }\n\n /**\n * Checks if a user has changed their password after the JWT was issued.\n *\n * @param {User} user - The user object containing the passwordChangedAt field.\n * @param {number} JWTTimestamp - The timestamp when the JWT was issued.\n * @returns {boolean} Returns true if the user changed their password after the JWT was issued, otherwise false.\n */\n userChangedPasswordAfter(user: User, JWTTimestamp: number): boolean {\n if (user.passwordChangedAt) {\n const convertedTimestamp = parseInt(\n String(new Date(user.passwordChangedAt).getTime() / 1000),\n 10,\n );\n\n return JWTTimestamp < convertedTimestamp;\n }\n return false;\n }\n\n /**\n * Verifies the authenticity of a JWT token.\n *\n * @param {string} token - The JWT token to verify.\n * @param {string} [secret] - The secret key used to verify the token. Defaults to environment variable `JWT_SECRET`.\n * @returns {Promise<AuthJwtPayload>} Returns the decoded JWT payload if the token is valid.\n * @throws {Error} Throws an error if the token is invalid or expired.\n */\n async verifyJwtToken(\n token: string,\n secret?: string,\n ): Promise<AuthJwtPayload> {\n const { authentication: configs } = getArkosConfig();\n\n if (\n process.env.ARKOS_BUILD === 'true' &&\n !process.env.JWT_SECRET &&\n !configs?.jwt?.secret\n )\n throw new AppError(\n 'Missing JWT secret in production',\n 500,\n 'MissingJWTSecretInProduction',\n );\n\n secret =\n secret ||\n configs?.jwt?.secret ||\n process.env.JWT_SECRET ||\n arkosEnv.JWT_SECRET;\n\n try {\n const decoded = (await new Promise((resolve, reject) => {\n jwt.verify(token, secret, (err, decoded) => {\n if (err) reject(err);\n else resolve(decoded as AuthJwtPayload);\n });\n })) as AuthJwtPayload;\n\n if (!decoded?.id) throw invaliAuthTokenError;\n\n return decoded;\n } catch (err) {\n throw invaliAuthTokenError;\n }\n }\n\n private isWildcardAccess(config: AccessControlConfig): config is '*' {\n return config === '*';\n }\n\n private isRoleList(config: AccessControlConfig): config is string[] {\n return Array.isArray(config);\n }\n\n private isAccessRules(\n config: AccessControlConfig,\n ): config is Partial<AccessControlRules> {\n return (\n typeof config === 'object' && config !== null && !Array.isArray(config)\n );\n }\n\n private normalizeRuleToRoles(\n rule: string[] | DetailedAccessControlRule | '*' | undefined,\n ): string[] {\n if (!rule) return [];\n if (rule === '*') return ['*'];\n if (Array.isArray(rule)) return rule;\n return rule.roles === '*' ? ['*'] : (rule.roles ?? []);\n }\n\n private resolveAuthorizedRoles(\n action: AccessAction,\n accessControl: AccessControlConfig,\n ): string[] {\n if (this.isWildcardAccess(accessControl)) return ['*'];\n if (this.isRoleList(accessControl)) return accessControl;\n if (this.isAccessRules(accessControl))\n return this.normalizeRuleToRoles(accessControl[action]);\n return [];\n }\n\n /**\n * Checks if a user has permission for a specific action using static access control rules.\n * Validates user roles against predefined access control configuration.\n *\n * @param user - The user object containing role or roles field\n * @param action - The action being performed\n * @param accessControl - Access control configuration (array of roles or object with action-role mappings)\n * @returns True if user has permission, false otherwise\n * @throws Error if user doesn't have role/roles field\n */\n checkStaticAccessControl(\n user: User,\n action: string,\n accessControl: AccessControlConfig,\n ) {\n if (!user?.role && !user.roles)\n throw Error(\n 'Validation Error: In order to use static authentication user needs at least role field or roles for multiple roles.',\n );\n\n let authorizedRoles = this.resolveAuthorizedRoles(action, accessControl);\n\n const userRoles = Array.isArray(user?.roles) ? user.roles : [user.role];\n\n return (\n authorizedRoles?.[0] === '*' ||\n !!userRoles.some((role: string) => authorizedRoles.includes(role))\n );\n }\n\n /**\n * Checks if a user has permission for a specific action and resource using dynamic access control.\n * Queries the database to verify user's role permissions.\n *\n * @param userId - The unique identifier of the user\n * @param action - The action being performed\n * @param resource - The resource being accessed\n * @returns Promise resolving to true if user has permission, false otherwise\n */\n async checkDynamicAccessControl(\n userId: string,\n action: string,\n resource: string,\n ) {\n const prisma = getPrismaInstance();\n\n const [userPermission, hasRolePermission] = await Promise.all([\n prisma.userPermission\n ? prisma.userPermission.findFirst({\n where: { userId, permission: { resource, action } },\n select: { effect: true },\n })\n : Promise.resolve(null),\n\n prisma.userRole.findFirst({\n where: {\n userId,\n role: {\n permissions: {\n some: { resource, action },\n },\n },\n },\n select: { id: true },\n }),\n ]);\n\n if (userPermission) return userPermission.effect === 'Allow';\n return !!hasRolePermission;\n }\n\n private extractRequestToken(\n req: ArkosRequest,\n cookie: 'arkos_access_token' = 'arkos_access_token',\n ) {\n let token: string | null = null;\n\n if (\n req?.headers?.authorization &&\n req?.headers?.authorization.startsWith('Bearer') &&\n req?.headers?.authorization.split?.(' ')?.[1]\n )\n token = req?.headers?.authorization.split(' ')[1];\n\n if (\n !token &&\n req?.cookies?.arkos_access_token !== 'no-token' &&\n req.cookies\n )\n token = req?.cookies?.[cookie];\n\n return token;\n }\n\n private extractSocketToken(socket: ArkosSocket, key: 'token' = 'token') {\n return (\n socket.handshake.auth?.[key] ||\n socket.handshake.headers?.authorization?.replace('Bearer ', '')\n );\n }\n\n async validateDecodedUser(\n decoded: AuthJwtPayload,\n action: 'logout' | 'default' = 'default',\n ): Promise<User> {\n const prisma = getPrismaInstance();\n const user = await (prisma as any).user.findUnique({\n where: { id: decoded.id },\n });\n\n if (!user)\n throw new AppError(\n 'The user belonging to this token no longer exists',\n 401,\n 'UserNoLongerExists',\n );\n\n if (\n action !== 'logout' &&\n this.userChangedPasswordAfter(user, decoded.iat!)\n )\n throw new AppError(\n 'User recently changed password! Please log in again.',\n 401,\n 'PasswordChanged',\n );\n\n return user;\n }\n\n /**\n * Processes the cookies or authoriation token and returns the user.\n *\n * @param ctx | socket\n * @returns {Promise<User | null>} - if authentication is turned off in arkosConfig it returns null\n * @throws {AppError} Throws an error if the token is invalid or the user is not logged in.\n */\n async getAuthenticatedUser(\n ctx: ArkosRequest | ArkosSocket,\n action: 'logout' | 'default' = 'default',\n ): Promise<User | null> {\n if (!isAuthenticationEnabled())\n throw Error(\n `Trying to call authService.getAuthenticatedUser without setting up authentication in arkos.config.${getUserFileExtension()}, see ${authenticationDocsLinks.setup}`,\n );\n\n let token: string | null = null;\n\n if ('headers' in ctx) token = this.extractRequestToken(ctx);\n else if ('join' in ctx) token = this.extractSocketToken(ctx);\n\n if (!token) return null;\n\n const decoded = await this.verifyJwtToken(token);\n ctx.accessToken = token;\n\n return this.validateDecodedUser(decoded, action);\n }\n\n /**\n * Middleware to authenticate the request by extracting and verifying the JWT token and setting `req.user`.\n *\n * Runs `authentication.hooks.authenticate` before/after the authentication logic.\n *\n * Hook execution flow:\n * - `before` hooks run first — call `ctx.skip()` to bypass core logic and jump to `after` hooks,\n * call `ctx.next()` to stop the chain early, or return without calling anything to continue.\n * - Core logic runs — extracts and verifies the JWT token, sets `req.user`.\n * - `after` hooks run — call `ctx.next(err)` to abort or return without calling anything to continue.\n * - `onError` hooks run if core logic throws — call `ctx.skip()` to suppress the error and jump to\n * `after` hooks, or call `ctx.next(err)` to forward it to the global error handler.\n *\n * On custom routes, hooks defined in `arkosConfig` still apply since they are baked into this method.\n *\n * @example\n * ```ts\n * // custom route - hooks still run\n * router.get(\"/custom\", authService.authenticate, handler);\n * ```\n *\n * @example\n * ```ts\n * // skip built-in auth from a before hook\n * before: (ctx) => {\n * ctx.req.user = myCustomAuth(ctx.req);\n * ctx.skip();\n * }\n * ```\n *\n * @see {@link https://www.arkosjs.com/docs/core-concepts/authentication/hooks}\n */\n authenticate = catchAsync(\n async (req: ArkosRequest, _: ArkosResponse, next: ArkosNextFunction) => {\n await authHookManager.runAuthenticate(\n { context: req, done: next },\n async (req): Promise<any> => {\n if (!isAuthenticationEnabled()) return null;\n const user = (await this.getAuthenticatedUser(\n req,\n req.path.includes('logout') ? 'logout' : 'default',\n )) as User;\n if (!user) throw loginRequiredError;\n return user;\n },\n );\n },\n );\n\n /**\n * Middleware to authorize the authenticated user for a given action on a resource.\n *\n * Runs `authentication.hooks.authorize` before/after the authorization logic.\n *\n * Hook execution flow:\n * - `before` hooks run first — call `ctx.skip()` to bypass core logic and jump to `after` hooks,\n * call `ctx.next()` to stop the chain early, or return without calling anything to continue.\n * - Core logic runs — checks user role/permissions against the access control rules.\n * - `after` hooks run — call `ctx.next(err)` to abort or return without calling anything to continue.\n * - `onError` hooks run if authorization fails — call `ctx.skip()` to suppress the error and jump to\n * `after` hooks, or call `ctx.next(err)` to forward it to the global error handler.\n *\n * @param resource - The resource being accessed, in kebabCase (e.g. `\"product\"`, `\"cart-item\"`)\n * @param action - The action being performed (e.g. `\"View\"`, `\"Create\"`, `\"Delete\"`)\n * @param rule - Access control rules for this action. Accepts a role list, a wildcard, or a `DetailedAccessControlRule`.\n *\n * @example\n * ```ts\n * router.delete(\"/products/:id\",\n * authService.authenticate,\n * authService.authorize(\"product\", \"Delete\", [\"admin\"]),\n * handler\n * );\n * ```\n *\n * @example\n * ```ts\n * // skip built-in authorization from a before hook\n * before: (ctx) => {\n * ctx.req.user.role = myCustomRoleResolver(ctx.req);\n * ctx.skip();\n * }\n * ```\n *\n * @see {@link https://www.arkosjs.com/docs/core-concepts/authentication/hooks#authorize}\n * @since v1.6.0-beta\n */\n authorize(\n action: AccessAction,\n resource: string,\n rule?: string[] | DetailedAccessControlRule | '*',\n ): ArkosRequestHandler {\n const authAction = authActionService.add(action, resource, {\n [action]: rule,\n });\n\n return catchAsync(\n async (req: ArkosRequest, _: ArkosResponse, next: ArkosNextFunction) => {\n await authHookManager.runAuthorize(\n { context: req, done: next },\n authAction,\n );\n },\n );\n }\n\n /**\n * Creates a permission checker function for a specific action and resource.\n *\n * PS: This method should be called during application initialization to build permission validators.\n *\n * @see {@link https://www.arkosjs.com/docs/advanced-guide/fine-grained-access-control}\n *\n * @param action - The action to check permission for (e.g., 'View', 'Create', 'Delete')\n * @param resource - The resource being accessed, must be in kebabCase (e.g., 'user', 'cart-item', 'order')\n * @param accessControl - Access control rules (required for static authentication mode), and it is automatically loaded for known modules such as all prisma models, auth and file-upload.\n * @returns A function that takes a user object and returns a boolean indicating permission status\n *\n * @example\n * ```typescript\n * const hasViewProductPermission = await authService.permission('View', 'product');\n *\n * // Later in handler:\n * const canAccess = await hasViewProductPermission(user);\n * if (canAccess) {\n * // User has permission\n * }\n * ```\n */\n permission(\n action: string,\n resource: string,\n accessControl?: AccessControlConfig,\n ) {\n // Check if called during request handling (deep call stack indicates handler execution)\n const stack = new Error().stack;\n\n if (stack?.includes('node_modules/express/lib/router/index.js'))\n throw new Error(\n 'authService.permission() should be called during application initialization level.',\n );\n\n authActionService.add(action, resource, accessControl);\n\n return async (user: User | undefined): Promise<boolean> => {\n // getArkosConfig must not be called the same time as arkos()\n const configs = getArkosConfig();\n\n if (!isUsingAuthentication())\n throw Error(\n 'Validation Error: Trying to use authService.permission without setting up authentication.',\n );\n\n if (!isAuthenticationEnabled()) return false;\n if (!user) throw loginRequiredError;\n if (user?.isSuperUser) return true;\n\n if (configs?.authentication?.mode === 'dynamic') {\n return await this.checkDynamicAccessControl(user?.id, action, resource);\n } else if (configs?.authentication?.mode === 'static') {\n return (\n !!accessControl &&\n this.checkStaticAccessControl(user as any, action, accessControl)\n );\n }\n return false;\n };\n }\n}\n\n/**\n * Handles various authentication-related tasks such as JWT signing, password hashing, and verifying user credentials.\n */\nconst authService = new AuthService();\n\nexport default authService;\n\n"]}
1
+ {"version":3,"file":"auth.service.js","sourceRoot":"","sources":["../../../../src/modules/auth/auth.service.ts"],"names":[],"mappings":"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","sourcesContent":["import jwt, { SignOptions } from 'jsonwebtoken';\nimport bcrypt from 'bcryptjs';\nimport { User } from '../../types';\nimport catchAsync from '../error-handler/utils/catch-async';\nimport AppError from '../error-handler/utils/app-error';\nimport arkosEnv from '../../utils/arkos-env';\nimport { getPrismaInstance } from '../../utils/helpers/prisma.helpers';\nimport {\n ArkosRequest,\n ArkosResponse,\n ArkosNextFunction,\n ArkosRequestHandler,\n} from '../../types';\nimport {\n AuthJwtPayload,\n AccessAction,\n AccessControlConfig,\n AccessControlRules,\n DetailedAccessControlRule,\n} from '../../types/auth';\nimport {\n MsDuration,\n toMs,\n createPrismaWhereClause,\n getDefaultUsernameField,\n} from './utils/helpers/auth.controller.helpers';\nimport { ArkosPrismaService } from '../base/base.service';\nimport {\n AuthUser,\n DeleteMeOptions,\n GetMeOptions,\n LoginInput,\n LoginOptions,\n SignupDto,\n SignupOptions,\n UpdateMeDto,\n UpdateMeOptions,\n UpdatePasswordInput,\n} from './auth.types';\nimport {\n invaliAuthTokenError,\n loginRequiredError,\n} from './utils/auth-error-objects';\nimport authActionService from './utils/services/auth-action.service';\nimport {\n getArkosConfig,\n isAuthenticationEnabled,\n isUsingAuthentication,\n} from '../../utils/helpers/arkos-config.helpers';\nimport { CookieOptions } from 'express';\nimport { getUserFileExtension } from '../../utils/helpers/fs.helpers';\nimport { authenticationDocsLinks } from './utils/docs-links';\nimport authHookManager from './utils/auth-hooks-manager';\nimport { ArkosSocket } from '../../components/arkos-gateway/types';\nimport {\n resolveRequestToken,\n resolveSocketToken,\n} from './utils/token-extraction';\nimport {\n BadRequestError,\n UnauthorizedError,\n} from '../error-handler/utils/errors';\n\n/**\n * Handles various authentication-related tasks such as JWT signing, password hashing, and verifying user credentials.\n */\nexport class AuthService {\n /**\n * Object containing a combination of actions per resource, tracked by each set of calls of `authService.handleAccessControl`, this can be accessed through the `authService` object or through the endpoint\n */\n actionsPerResource: Record<string, Set<string>> = {};\n\n private _userService?: ArkosPrismaService<'user'>;\n\n protected get userService(): ArkosPrismaService<'user'> {\n if (!this._userService) this._userService = new ArkosPrismaService('user');\n return this._userService;\n }\n\n /**\n * Signs a JWT token for the user.\n *\n * @param {number | string} id - The unique identifier of the user to generate the token for.\n * @param {string | number} [expiresIn] - The expiration time for the token. Defaults to environment variable `JWT_EXPIRES_IN`.\n * @param {string} [secret] - The secret key used to sign the token. Defaults to environment variable `JWT_SECRET`.\n * @returns {string} The signed JWT token.\n */\n signJwtToken(\n id: number | string,\n expiresIn?: MsDuration | number,\n secret?: string,\n ): string {\n const { authentication: configs } = getArkosConfig();\n\n if (\n process.env.ARKOS_BUILD === 'true' &&\n !process.env.JWT_SECRET &&\n !configs?.jwt?.secret\n )\n throw new AppError(\n 'Missing JWT secret on production!',\n 500,\n 'MissingJWTOnProduction',\n );\n\n secret =\n secret ||\n configs?.jwt?.secret ||\n process.env.JWT_SECRET ||\n arkosEnv.JWT_SECRET;\n\n expiresIn = (expiresIn ||\n configs?.jwt?.expiresIn ||\n process.env.JWT_EXPIRES_IN ||\n arkosEnv.JWT_EXPIRES_IN) as keyof SignOptions['expiresIn'];\n\n return jwt.sign({ id }, secret, {\n expiresIn: expiresIn as MsDuration,\n });\n }\n\n /**\n * Retrieves cookie configuration options for JWT authentication.\n *\n * Merges configuration from multiple sources in order of precedence:\n * 1. Arkos configuration file\n * 2. Environment variables\n * 3. Request properties (for secure flag)\n * 4. Default fallback values\n *\n * @param req - ArkosRequest object used to determine if the connection is secure\n * @returns Cookie options object with expires, httpOnly, secure, and sameSite properties\n *\n * @example\n * ```typescript\n * const cookieOptions = authService.getJwtCookieOptions(req);\n * res.cookie('jwt', token, cookieOptions);\n * ```\n */\n getJwtCookieOptions(req: ArkosRequest) {\n const arkosConfig = getArkosConfig();\n const authConfigs = arkosConfig?.authentication;\n\n if (!req)\n throw new Error('Missing req object in order get jwt cookie options');\n\n const sameSite =\n authConfigs?.jwt?.cookie?.sameSite ||\n (process.env.JWT_COOKIE_SAME_SITE as\n 'none' | 'lax' | 'strict' | undefined) ||\n 'lax';\n\n return {\n expires: new Date(\n Date.now() +\n Number(\n toMs(\n authConfigs?.jwt?.expiresIn ||\n (process.env.JWT_EXPIRES_IN as MsDuration) ||\n (arkosEnv.JWT_EXPIRES_IN as MsDuration),\n ),\n ),\n ),\n httpOnly:\n authConfigs?.jwt?.cookie?.httpOnly ??\n (process.env.JWT_COOKIE_HTTP_ONLY !== undefined\n ? process.env.JWT_COOKIE_HTTP_ONLY === 'true'\n : undefined) ??\n true,\n secure: (() => {\n if (authConfigs?.jwt?.cookie?.secure !== undefined)\n return authConfigs?.jwt?.cookie?.secure;\n else if (process.env.JWT_COOKIE_SECURE !== undefined)\n return process.env.JWT_COOKIE_SECURE === 'true';\n else return req.secure || req.headers['x-forwarded-proto'] === 'https';\n })(),\n sameSite,\n domain: authConfigs?.jwt?.cookie?.domain || process.env.JWT_COOKIE_DOMAIN,\n ...arkosConfig?.authentication?.jwt?.cookie,\n } as CookieOptions;\n }\n\n /**\n * Is used by default internally by Arkos under `ArkosPrismaService` class to check if the password is already hashed.\n *\n * This was just added to prevent unwanted errors when someone just forgets that the `ArkosPrismaService` class will automatically hash the password field using `authService.hashPassword` by default.\n *\n * So now before `ArkosPrismaService` hashes it will test it.\n *\n *\n * @param password The password to be tested if is hashed\n * @returns\n */\n isPasswordHashed(password: string) {\n return !Number.isNaN(bcrypt.getRounds(password) * 1);\n }\n\n /**\n * Compares a candidate password with the stored user password to check if they match.\n *\n * @param {string} candidatePassword - The password provided by the user during login.\n * @param {string} userPassword - The password stored in the database.\n * @returns {Promise<boolean>} Returns true if the passwords match, otherwise false.\n */\n async isCorrectPassword(\n candidatePassword: string,\n userPassword: string,\n ): Promise<boolean> {\n return await bcrypt.compare(candidatePassword, userPassword);\n }\n\n /**\n * Hashes a plain text password using bcrypt.\n *\n * @param {string} password - The password to be hashed.\n * @returns {Promise<string>} Returns the hashed password.\n */\n async hashPassword(password: string): Promise<string> {\n return await bcrypt.hash(password, 12);\n }\n\n /**\n * Checks if a user has changed their password after the JWT was issued.\n *\n * @param {User} user - The user object containing the passwordChangedAt field.\n * @param {number} JWTTimestamp - The timestamp when the JWT was issued.\n * @returns {boolean} Returns true if the user changed their password after the JWT was issued, otherwise false.\n */\n userChangedPasswordAfter(user: User, JWTTimestamp: number): boolean {\n if (user.passwordChangedAt) {\n const convertedTimestamp = parseInt(\n String(new Date(user.passwordChangedAt).getTime() / 1000),\n 10,\n );\n\n return JWTTimestamp < convertedTimestamp;\n }\n return false;\n }\n\n /**\n * Verifies the authenticity of a JWT token.\n *\n * @param {string} token - The JWT token to verify.\n * @param {string} [secret] - The secret key used to verify the token. Defaults to environment variable `JWT_SECRET`.\n * @returns {Promise<AuthJwtPayload>} Returns the decoded JWT payload if the token is valid.\n * @throws {Error} Throws an error if the token is invalid or expired.\n */\n async verifyJwtToken(\n token: string,\n secret?: string,\n ): Promise<AuthJwtPayload> {\n const { authentication: configs } = getArkosConfig();\n\n if (\n process.env.ARKOS_BUILD === 'true' &&\n !process.env.JWT_SECRET &&\n !configs?.jwt?.secret\n )\n throw new AppError(\n 'Missing JWT secret in production',\n 500,\n 'MissingJWTSecretInProduction',\n );\n\n secret =\n secret ||\n configs?.jwt?.secret ||\n process.env.JWT_SECRET ||\n arkosEnv.JWT_SECRET;\n\n try {\n const decoded = (await new Promise((resolve, reject) => {\n jwt.verify(token, secret, (err, decoded) => {\n if (err) reject(err);\n else resolve(decoded as AuthJwtPayload);\n });\n })) as AuthJwtPayload;\n\n if (!decoded?.id) throw invaliAuthTokenError;\n\n return decoded;\n } catch (err) {\n throw invaliAuthTokenError;\n }\n }\n\n private isWildcardAccess(config: AccessControlConfig): config is '*' {\n return config === '*';\n }\n\n private isRoleList(config: AccessControlConfig): config is string[] {\n return Array.isArray(config);\n }\n\n private isAccessRules(\n config: AccessControlConfig,\n ): config is Partial<AccessControlRules> {\n return (\n typeof config === 'object' && config !== null && !Array.isArray(config)\n );\n }\n\n private normalizeRuleToRoles(\n rule: string[] | DetailedAccessControlRule | '*' | undefined,\n ): string[] {\n if (!rule) return [];\n if (rule === '*') return ['*'];\n if (Array.isArray(rule)) return rule;\n return rule.roles === '*' ? ['*'] : (rule.roles ?? []);\n }\n\n private resolveAuthorizedRoles(\n action: AccessAction,\n accessControl: AccessControlConfig,\n ): string[] {\n if (this.isWildcardAccess(accessControl)) return ['*'];\n if (this.isRoleList(accessControl)) return accessControl;\n if (this.isAccessRules(accessControl))\n return this.normalizeRuleToRoles(accessControl[action]);\n return [];\n }\n\n /**\n * Checks if a user has permission for a specific action using static access control rules.\n * Validates user roles against predefined access control configuration.\n *\n * @param user - The user object containing role or roles field\n * @param action - The action being performed\n * @param accessControl - Access control configuration (array of roles or object with action-role mappings)\n * @returns True if user has permission, false otherwise\n * @throws Error if user doesn't have role/roles field\n */\n checkStaticAccessControl(\n user: User,\n action: string,\n accessControl: AccessControlConfig,\n ) {\n if (!user?.role && !user.roles)\n throw Error(\n 'Validation Error: In order to use static authentication user needs at least role field or roles for multiple roles.',\n );\n\n let authorizedRoles = this.resolveAuthorizedRoles(action, accessControl);\n\n const userRoles = Array.isArray(user?.roles) ? user.roles : [user.role];\n\n return (\n authorizedRoles?.[0] === '*' ||\n !!userRoles.some((role: string) => authorizedRoles.includes(role))\n );\n }\n\n /**\n * Checks if a user has permission for a specific action and resource using dynamic access control.\n * Queries the database to verify user's role permissions.\n *\n * @param userId - The unique identifier of the user\n * @param action - The action being performed\n * @param resource - The resource being accessed\n * @returns Promise resolving to true if user has permission, false otherwise\n */\n async checkDynamicAccessControl(\n userId: string,\n action: string,\n resource: string,\n ) {\n const prisma = getPrismaInstance();\n\n const [userPermission, hasRolePermission] = await Promise.all([\n prisma.userPermission\n ? prisma.userPermission.findFirst({\n where: { userId, permission: { resource, action } },\n select: { effect: true },\n })\n : Promise.resolve(null),\n\n prisma.userRole.findFirst({\n where: {\n userId,\n role: {\n permissions: {\n some: { resource, action },\n },\n },\n },\n select: { id: true },\n }),\n ]);\n\n if (userPermission) return userPermission.effect === 'Allow';\n return !!hasRolePermission;\n }\n\n private sanitizeUser(user: Record<string, any>): AuthUser {\n const { password: _password, ...sanitized } = user;\n return sanitized as AuthUser;\n }\n\n private withPasswordIncluded<T extends Record<string, any>>(\n queryOptions?: T,\n ): Record<string, any> {\n const options: Record<string, any> = { ...(queryOptions || {}) };\n\n if (options.select) options.select = { ...options.select, password: true };\n\n if (options.omit) {\n const { password: _password, ...omit } = options.omit;\n options.omit = omit;\n }\n\n return options;\n }\n\n /**\n * Retrieves the authenticated user by id without the password field.\n *\n * Can be overridden through `ArkosRouteHook(\"auth\", { service })`.\n *\n * @param userId - The id of the authenticated user\n * @param queryOptions - Optional Prisma query options (select, include, etc.)\n * @since 1.8.0-rc\n */\n async getMe(\n userId: User[\"id\"],\n queryOptions?: GetMeOptions,\n ): Promise<AuthUser | null> {\n const user = await this.userService.findOne(\n { id: userId },\n queryOptions || {},\n );\n\n return user ? this.sanitizeUser(user) : null;\n }\n\n /**\n * Updates the authenticated user without the password field in the result.\n * Password changes are rejected, use `updatePassword` instead.\n *\n * Can be overridden through `ArkosRouteHook(\"auth\", { service })`.\n *\n * @param userId - The id of the authenticated user\n * @param data - The fields to update\n * @param queryOptions - Optional Prisma query options (select, include, etc.)\n * @since 1.8.0-rc\n */\n async updateMe(\n userId: User[\"id\"],\n data: UpdateMeDto,\n queryOptions?: UpdateMeOptions,\n ): Promise<AuthUser> {\n if (\"password\" in (data as Record<string, any>))\n throw new BadRequestError(\n \"In order to update password use the update-password endpoint.\",\n \"InvalidFieldPassword\",\n );\n\n const user = await this.userService.updateOne(\n { id: userId },\n data,\n queryOptions || {},\n );\n\n return this.sanitizeUser(user);\n }\n\n /**\n * Creates a new user account without the password field in the result.\n *\n * Can be overridden through `ArkosRouteHook(\"auth\", { service })`.\n *\n * @param data - The user data, the password is hashed automatically\n * @param queryOptions - Optional Prisma query options (select, include, etc.)\n * @since 1.8.0-rc\n */\n async signup(\n data: SignupDto,\n queryOptions?: SignupOptions,\n ): Promise<AuthUser> {\n const user = await this.userService.createOne(data, queryOptions || {});\n\n return this.sanitizeUser(user);\n }\n\n /**\n * Marks the authenticated user's account as self-deleted by setting\n * `deletedSelfAccountAt`, the result never includes the password field.\n *\n * Can be overridden through `ArkosRouteHook(\"auth\", { service })`.\n *\n * @param userId - The id of the authenticated user\n * @param queryOptions - Optional Prisma query options (select, include, etc.)\n * @since 1.8.0-rc\n */\n async deleteMe(\n userId: User[\"id\"],\n queryOptions?: DeleteMeOptions,\n ): Promise<AuthUser> {\n const user = await this.userService.updateOne(\n { id: userId },\n { deletedSelfAccountAt: new Date().toISOString() },\n queryOptions || {},\n );\n\n return this.sanitizeUser(user);\n }\n\n /**\n * Authenticates a user with the given username field and password.\n *\n * The username field is inferred from the username key present in `input`\n * (the only key besides `password`), can be overridden explicitly with\n * `usernameField` for nested paths such as `\"profile.nickname\"`, and falls\n * back to `authentication.login.allowedUsernames[0] || \"username\"`. When\n * `authentication.login.allowedUsernames` is configured, the resolved field\n * must be one of its entries. The password is always loaded for the\n * comparison and never returned.\n *\n * Can be overridden through `ArkosRouteHook(\"auth\", { service })`.\n *\n * @param input - Its username key and the password\n * @param queryOptions - Optional Prisma query options (select, include, etc.)\n * @returns The sanitized user and a signed access token\n * @since 1.8.0-rc\n */\n async login(\n input: LoginInput,\n queryOptions?: LoginOptions,\n ): Promise<{ user: AuthUser; accessToken: string }> {\n const { password } = input as { password: string };\n const usernameField =\n (input as { usernameField?: string }).usernameField ||\n Object.keys(input).find(\n (key) => key !== \"password\" && key !== \"usernameField\",\n ) ||\n getDefaultUsernameField();\n\n const allowedUsernames =\n getArkosConfig()?.authentication?.login?.allowedUsernames;\n\n if (allowedUsernames?.length && !allowedUsernames.includes(usernameField))\n throw new BadRequestError(\n `Invalid username field, expected one of: ${allowedUsernames.join(\", \")}`,\n \"InvalidUsernameField\",\n );\n\n const lastField = usernameField.split(\".\").pop()!;\n const username = (input as Record<string, any>)[lastField];\n\n if (!username || !password)\n throw new BadRequestError(\n `Please provide both ${lastField} and password`,\n `MissingCredentialFields`,\n );\n\n const user = (await this.userService.findOne(\n createPrismaWhereClause(usernameField, username),\n this.withPasswordIncluded(queryOptions),\n )) as Record<string, any> | null;\n\n if (!user || !(await this.isCorrectPassword(password, user.password)))\n throw new UnauthorizedError(\n `Incorrect ${lastField} or password`,\n `IncorrectCredentials`,\n );\n\n return {\n user: this.sanitizeUser(user),\n accessToken: this.signJwtToken(user.id),\n };\n }\n\n /**\n * Updates the password of the given user after validating the current one.\n *\n * Can be overridden through `ArkosRouteHook(\"auth\", { service })`.\n *\n * @param userId - The id of the authenticated user\n * @param input - The current and the new password\n * @returns A fresh access token valid after the password change\n * @since 1.8.0-rc\n */\n async updatePassword(\n userId: User[\"id\"],\n input: UpdatePasswordInput,\n ): Promise<{ accessToken: string }> {\n const { currentPassword, newPassword } = input;\n\n if (!currentPassword || !newPassword)\n throw new AppError(\n \"currentPassword and newPassword are required\",\n 400,\n \"SameCurrentAndNewPassword\",\n );\n\n const user = (await this.userService.findOne(\n { id: userId },\n this.withPasswordIncluded(),\n )) as Record<string, any> | null;\n\n if (!user || user.isActive === false || user.deletedSelfAccountAt)\n throw new AppError(\"User not found!\", 404);\n\n if (\n !(await this.isCorrectPassword(\n String(currentPassword),\n String(user.password),\n ))\n )\n throw new AppError(\n \"Current password is incorrect\",\n 400,\n \"IncorrentCurrentPassword\",\n );\n\n await this.userService.updateOne(\n { id: userId },\n {\n password: await this.hashPassword(String(newPassword)),\n passwordChangedAt: new Date(Date.now()).toISOString(),\n },\n );\n\n return { accessToken: this.signJwtToken(userId) };\n }\n\n /**\n * Runs on logout. Override through `ArkosRouteHook(\"auth\", { service })`.\n *\n * @since 1.8.0-rc\n */\n async logout(_userId: User[\"id\"], _accessToken: string): Promise<void> {}\n\n private extractRequestToken(\n req: ArkosRequest,\n cookie: \"arkos_access_token\" = \"arkos_access_token\",\n ) {\n return resolveRequestToken({\n authorization: req?.headers?.authorization,\n cookies: req?.cookies,\n cookieName: cookie,\n });\n }\n\n private extractSocketToken(socket: ArkosSocket, key: \"token\" = \"token\") {\n const requestCookie = (socket.request as any)?.headers?.cookie;\n\n return resolveSocketToken({\n auth: socket.handshake?.auth,\n key,\n headers: socket.handshake?.headers,\n cookies: socket.handshake?.cookies,\n cookieHeader: requestCookie,\n });\n }\n\n async validateDecodedUser(\n decoded: AuthJwtPayload,\n action: 'logout' | 'default' = 'default',\n ): Promise<User> {\n const prisma = getPrismaInstance();\n const user = await prisma.user.findUnique({\n where: { id: decoded.id },\n });\n\n if (!user)\n throw new AppError(\n 'The user belonging to this token no longer exists',\n 401,\n 'UserNoLongerExists',\n );\n\n if (\n action !== 'logout' &&\n this.userChangedPasswordAfter(user, decoded.iat!)\n )\n throw new AppError(\n 'User recently changed password! Please log in again.',\n 401,\n 'PasswordChanged',\n );\n\n return user;\n }\n\n /**\n * Processes the cookies or authoriation token and returns the user.\n *\n * @param ctx | socket\n * @returns {Promise<User | null>} - if authentication is turned off in arkosConfig it returns null\n * @throws {AppError} Throws an error if the token is invalid or the user is not logged in.\n */\n async getAuthenticatedUser(\n ctx: ArkosRequest | ArkosSocket,\n action: 'logout' | 'default' = 'default',\n ): Promise<User | null> {\n if (!isAuthenticationEnabled())\n throw Error(\n `Trying to call authService.getAuthenticatedUser without setting up authentication in arkos.config.${getUserFileExtension()}, see ${authenticationDocsLinks.setup}`,\n );\n\n let token: string | null = null;\n\n if ('headers' in ctx) token = this.extractRequestToken(ctx);\n else if ('join' in ctx) token = this.extractSocketToken(ctx);\n\n if (!token) return null;\n\n const decoded = await this.verifyJwtToken(token);\n ctx.accessToken = token;\n\n return this.validateDecodedUser(decoded, action);\n }\n\n /**\n * Middleware to authenticate the request by extracting and verifying the JWT token and setting `req.user`.\n *\n * Runs `authentication.hooks.authenticate` before/after the authentication logic.\n *\n * Hook execution flow:\n * - `before` hooks run first — call `ctx.skip()` to bypass core logic and jump to `after` hooks,\n * call `ctx.next()` to stop the chain early, or return without calling anything to continue.\n * - Core logic runs — extracts and verifies the JWT token, sets `req.user`.\n * - `after` hooks run — call `ctx.next(err)` to abort or return without calling anything to continue.\n * - `onError` hooks run if core logic throws — call `ctx.skip()` to suppress the error and jump to\n * `after` hooks, or call `ctx.next(err)` to forward it to the global error handler.\n *\n * On custom routes, hooks defined in `arkosConfig` still apply since they are baked into this method.\n *\n * @example\n * ```ts\n * // custom route - hooks still run\n * router.get(\"/custom\", authService.authenticate, handler);\n * ```\n *\n * @example\n * ```ts\n * // skip built-in auth from a before hook\n * before: (ctx) => {\n * ctx.req.user = myCustomAuth(ctx.req);\n * ctx.skip();\n * }\n * ```\n *\n * @see {@link https://www.arkosjs.com/docs/core-concepts/authentication/hooks}\n */\n authenticate = catchAsync(\n async (req: ArkosRequest, _: ArkosResponse, next: ArkosNextFunction) => {\n await authHookManager.runAuthenticate(\n { context: req, done: next },\n async (req): Promise<any> => {\n if (!isAuthenticationEnabled()) return null;\n const user = (await this.getAuthenticatedUser(\n req,\n req.path.includes('logout') ? 'logout' : 'default',\n )) as User;\n if (!user) throw loginRequiredError;\n return user;\n },\n );\n },\n );\n\n /**\n * Middleware to authorize the authenticated user for a given action on a resource.\n *\n * Runs `authentication.hooks.authorize` before/after the authorization logic.\n *\n * Hook execution flow:\n * - `before` hooks run first — call `ctx.skip()` to bypass core logic and jump to `after` hooks,\n * call `ctx.next()` to stop the chain early, or return without calling anything to continue.\n * - Core logic runs — checks user role/permissions against the access control rules.\n * - `after` hooks run — call `ctx.next(err)` to abort or return without calling anything to continue.\n * - `onError` hooks run if authorization fails — call `ctx.skip()` to suppress the error and jump to\n * `after` hooks, or call `ctx.next(err)` to forward it to the global error handler.\n *\n * @param resource - The resource being accessed, in kebabCase (e.g. `\"product\"`, `\"cart-item\"`)\n * @param action - The action being performed (e.g. `\"View\"`, `\"Create\"`, `\"Delete\"`)\n * @param rule - Access control rules for this action. Accepts a role list, a wildcard, or a `DetailedAccessControlRule`.\n *\n * @example\n * ```ts\n * router.delete(\"/products/:id\",\n * authService.authenticate,\n * authService.authorize(\"product\", \"Delete\", [\"admin\"]),\n * handler\n * );\n * ```\n *\n * @example\n * ```ts\n * // skip built-in authorization from a before hook\n * before: (ctx) => {\n * ctx.req.user.role = myCustomRoleResolver(ctx.req);\n * ctx.skip();\n * }\n * ```\n *\n * @see {@link https://www.arkosjs.com/docs/core-concepts/authentication/hooks#authorize}\n * @since v1.6.0-beta\n */\n authorize(\n action: AccessAction,\n resource: string,\n rule?: string[] | DetailedAccessControlRule | '*',\n ): ArkosRequestHandler {\n const authAction = authActionService.add(action, resource, {\n [action]: rule,\n });\n\n return catchAsync(\n async (req: ArkosRequest, _: ArkosResponse, next: ArkosNextFunction) => {\n await authHookManager.runAuthorize(\n { context: req, done: next },\n authAction,\n );\n },\n );\n }\n\n /**\n * Creates a permission checker function for a specific action and resource.\n *\n * PS: This method should be called during application initialization to build permission validators.\n *\n * @see {@link https://www.arkosjs.com/docs/advanced-guide/fine-grained-access-control}\n *\n * @param action - The action to check permission for (e.g., 'View', 'Create', 'Delete')\n * @param resource - The resource being accessed, must be in kebabCase (e.g., 'user', 'cart-item', 'order')\n * @param accessControl - Access control rules (required for static authentication mode), and it is automatically loaded for known modules such as all prisma models, auth and file-upload.\n * @returns A function that takes a user object and returns a boolean indicating permission status\n *\n * @example\n * ```typescript\n * const hasViewProductPermission = await authService.permission('View', 'product');\n *\n * // Later in handler:\n * const canAccess = await hasViewProductPermission(user);\n * if (canAccess) {\n * // User has permission\n * }\n * ```\n */\n permission(\n action: string,\n resource: string,\n accessControl?: AccessControlConfig,\n ) {\n // Check if called during request handling (deep call stack indicates handler execution)\n const stack = new Error().stack;\n\n if (stack?.includes('node_modules/express/lib/router/index.js'))\n throw new Error(\n 'authService.permission() should be called during application initialization level.',\n );\n\n authActionService.add(action, resource, accessControl);\n\n return async (user: User | undefined): Promise<boolean> => {\n // getArkosConfig must not be called the same time as arkos()\n const configs = getArkosConfig();\n\n if (!isUsingAuthentication())\n throw Error(\n 'Validation Error: Trying to use authService.permission without setting up authentication.',\n );\n\n if (!isAuthenticationEnabled()) return false;\n if (!user) throw loginRequiredError;\n if (user?.isSuperUser) return true;\n\n if (configs?.authentication?.mode === 'dynamic') {\n return await this.checkDynamicAccessControl(user?.id, action, resource);\n } else if (configs?.authentication?.mode === 'static') {\n return (\n !!accessControl &&\n this.checkStaticAccessControl(user, action, accessControl)\n );\n }\n return false;\n };\n }\n}\n\n/**\n * Handles various authentication-related tasks such as JWT signing, password hashing, and verifying user credentials.\n */\nconst authService = new AuthService();\n\nexport default authService;\n\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=auth.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.types.js","sourceRoot":"","sources":["../../../../src/modules/auth/auth.types.ts"],"names":[],"mappings":"","sourcesContent":["import {\n ExtractPrismaData,\n ExtractPrismaQueryOptions,\n PrismaModels,\n RuntimeArkosConfig,\n} from \"../../generated\";\nimport { ArkosPrismaInput } from \"../../types/arkos-prisma-input\";\nimport { User } from \"../../types\";\n\ntype UserModel = PrismaModels<any>[\"user\"];\n\nexport type AuthUser = Omit<User, \"password\">;\n\nexport type GetMeOptions = ExtractPrismaQueryOptions<\n UserModel[\"FindFirstArgs\"],\n \"where\"\n>;\nexport type LoginOptions = GetMeOptions;\nexport type UpdateMeOptions = ExtractPrismaQueryOptions<\n UserModel[\"UpdateArgs\"],\n \"where\" | \"data\"\n>;\nexport type DeleteMeOptions = UpdateMeOptions;\nexport type SignupOptions = ExtractPrismaQueryOptions<\n UserModel[\"CreateArgs\"],\n \"data\"\n>;\n\nexport type SignupDto =\n | ExtractPrismaData<UserModel[\"CreateArgs\"]>\n | ArkosPrismaInput<ExtractPrismaData<UserModel[\"CreateArgs\"]>>;\n\nexport type UpdateMeDto =\n | ExtractPrismaData<UserModel[\"UpdateArgs\"]>\n | ArkosPrismaInput<ExtractPrismaData<UserModel[\"UpdateArgs\"]>>;\n\nexport type OverridableAuthMethod =\n | \"getMe\"\n | \"updateMe\"\n | \"signup\"\n | \"deleteMe\"\n | \"login\"\n | \"updatePassword\"\n | \"logout\";\n\nexport interface UpdatePasswordInput {\n currentPassword: string;\n newPassword: string;\n}\n\ntype ListOperator = \"some\" | \"every\" | \"none\";\n\ntype LastSegment<P extends string> = P extends `${string}.${infer R}`\n ? LastSegment<R>\n : P;\n\ntype PathSelect<P extends string> = P extends `${infer H}.${infer T}`\n ? H extends ListOperator\n ? PathSelect<T>\n : { [K in H]: { select: PathSelect<T> } }\n : { [K in P]: true };\n\ntype ElementOf<T> = T extends readonly (infer E)[] ? E : T;\n\ntype PathValue<T, P extends string> = P extends `${infer H}.${infer R}`\n ? H extends ListOperator\n ? PathValue<T, R>\n : H extends keyof T\n ? PathValue<ElementOf<NonNullable<T[H]>>, R>\n : never\n : P extends keyof T\n ? T[P]\n : never;\n\n/**\n * The username fields accepted by the built-in login, derived from\n * `authentication.login.allowedUsernames` in the user's `arkos.config`.\n *\n * The generated `RuntimeArkosConfig` is a literal-typed view of the config;\n * when `allowedUsernames` is not configured it falls back to the runtime\n * default, `\"username\"` (see `getDefaultUsernameField`).\n */\nexport type LoginUsernames = RuntimeArkosConfig extends {\n authentication: {\n login: { allowedUsernames: readonly (infer U extends string)[] };\n };\n}\n ? U\n : \"username\";\n\n/**\n * The union of fields accepted as the login username.\n *\n * @deprecated Use `LoginUsernames`.\n */\nexport type LoginUsernameField = LoginUsernames;\n\ntype LoginUsernameValue<F extends string> = NonNullable<\n PathValue<PrismaModels<{ select: PathSelect<F> }>[\"user\"][\"GetPayload\"], F>\n>;\n\ntype LoginInputFor<F extends string> = {\n password: string;\n} & (F extends `${string}.${string}`\n ? {\n /** Required for nested paths so the full dot-path is queried. */\n usernameField: F;\n }\n : {\n /** Only needed for nested paths; otherwise inferred from the username key. */\n usernameField?: F;\n }) & {\n [K in LastSegment<F>]: LoginUsernameValue<F>;\n};\n\ntype DistributiveLoginInput<F extends string> = F extends any\n ? LoginInputFor<F>\n : never;\n\n/**\n * Login payload for the configured username fields. Every entry in\n * `authentication.login.allowedUsernames` is accepted as an alternative, and the\n * key holding the username is the last segment of the field path, typed from the\n * Prisma schema.\n */\nexport type LoginInput = DistributiveLoginInput<LoginUsernames>;\n\n"]}
@@ -1,5 +1,6 @@
1
1
  import { getArkosConfig } from "../../../../server.js";
2
2
  import AppError from "../../../error-handler/utils/app-error.js";
3
+ export const getDefaultUsernameField = () => getArkosConfig()?.authentication?.login?.allowedUsernames?.[0] || "username";
3
4
  export const determineUsernameField = (req) => {
4
5
  const authConfigs = getArkosConfig()?.authentication;
5
6
  if (req.query?.usernameField &&
@@ -1 +1 @@
1
- {"version":3,"file":"auth.controller.helpers.js","sourceRoot":"","sources":["../../../../../../src/modules/auth/utils/helpers/auth.controller.helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import { getArkosConfig } from \"../../../../server\";\nimport { ArkosRequest } from \"../../../../types\";\nimport AppError from \"../../../error-handler/utils/app-error\";\n\n/**\n * Determines the username field to use for authentication and supports nested paths\n * Priority:\n * 1. req.query.usernameField\n * 2. config setting\n * 3. default \"username\"\n *\n * Supports dot notation for nested fields and array queries (e.g., \"profile.nickname\", \"phones.some.number\")\n *\n * @param req - The request object\n * @returns The field name to use for username identification\n */\nexport const determineUsernameField = (req: ArkosRequest): string => {\n const authConfigs = getArkosConfig()?.authentication;\n\n if (\n req.query?.usernameField &&\n typeof req.query?.usernameField === \"string\" &&\n authConfigs?.login?.allowedUsernames?.includes?.(req.query.usernameField)\n )\n return req.query.usernameField;\n else if (req.query?.usernameField)\n throw new AppError(\n \"Invalid usernameField parameter, it is not allowed!\",\n 400\n );\n\n return authConfigs?.login?.allowedUsernames?.[0] || \"username\";\n};\n\n/**\n * Creates a Prisma-compatible where clause from a path using dot notation\n * Handles nested objects and array queries with \"some\" operator\n * Example: createPrismaWhereClause(\"profile.nickname\", \"john\") or createPrismaWhereClause(\"phones.some.number\", \"1234567890\")\n *\n * @param path - The dot notation path (e.g., \"profile.nickname\" or \"phones.some.number\")\n * @param value - The value to search for\n * @returns A nested object suitable for Prisma's where clause\n */\nexport const createPrismaWhereClause = (\n path: string,\n value: any\n): Record<string, any> => {\n if (!path) return {};\n\n const parts = path.split(\".\");\n const whereClause: Record<string, any> = {};\n\n // Handle simple field case\n if (parts.length === 1) {\n whereClause[parts[0]] = value;\n return whereClause;\n }\n\n // Handle nested fields\n let current = whereClause;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n current[part] = {};\n current = current[part];\n }\n\n current[parts[parts.length - 1]] = value;\n\n return whereClause;\n};\n\n/**\n * Access a value from a simple object based on a dot notation path\n * The object will only contain a single property that matches the last part of the path\n * Example: getNestedValue({nickname: \"john\"}, \"profile.nickname\") => \"john\"\n *\n * @param obj - The object containing the value (simple key-value pair)\n * @param path - The dot notation path (only the last part is used to access the object)\n * @returns The value from the object if the key matches the last part of the path, or undefined\n */\nexport const getNestedValue = (obj: any, path: string): any => {\n if (!obj || !path) return undefined;\n\n const properties = path.split(\".\");\n const lastProperty = properties[properties.length - 1];\n\n // If the last property exists in the object, return its value\n if (lastProperty in obj) {\n return obj[lastProperty];\n }\n\n return undefined;\n};\n\n/**\n * MsDuration type allows specific units for durations\n *\n * **For example**: 90d, 10ms, 50s.\n *\n * **Available metrics**: ms, s, m, h, d, w, y.\n * */\nexport type MsDuration =\n | number\n | `${number}`\n | `${number}${\"ms\" | \"s\" | \"m\" | \"h\" | \"d\" | \"w\" | \"y\"}`; // Short format (e.g., \"1y\")\n\n// Normalize function to convert long units to short ones\nfunction normalizeDuration(input: string): string {\n return input\n .toLowerCase()\n .replace(/years?|yr|year/g, \"y\")\n .replace(/minutes?|min/g, \"m\")\n .replace(/seconds?|sec|secs/g, \"s\")\n .replace(/hours?|hr/g, \"h\")\n .replace(/days?/g, \"d\")\n .replace(/weeks?/g, \"w\")\n .replace(/milliseconds?/g, \"ms\");\n}\n\nexport function toMs(input: number | MsDuration): number {\n if (typeof input === \"number\") return input * 1000; // If it's a number, assume it's in seconds\n\n // Normalize the string input\n const normalizedInput = normalizeDuration(input.trim());\n\n // Type assertion: we assert that normalizedInput will now match the MsDuration format\n const regex = /^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d|w|y)$/i;\n const match = normalizedInput.match(regex);\n\n if (!match) throw new Error(`Invalid time format: ${input}`);\n\n const value = parseFloat(match[1]);\n const unit = match[2].toLowerCase() as\n | \"ms\"\n | \"s\"\n | \"m\"\n | \"h\"\n | \"d\"\n | \"w\"\n | \"y\";\n\n const multipliers: Record<\"ms\" | \"s\" | \"m\" | \"h\" | \"d\" | \"w\" | \"y\", number> =\n {\n ms: 1,\n s: 1000,\n m: 60000,\n h: 3600000,\n d: 86400000,\n w: 604800000,\n y: 31557600000, // 365.25 days in ms\n };\n\n return value * multipliers[unit];\n}\n"]}
1
+ {"version":3,"file":"auth.controller.helpers.js","sourceRoot":"","sources":["../../../../../../src/modules/auth/utils/helpers/auth.controller.helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import { getArkosConfig } from \"../../../../server\";\nimport { ArkosRequest } from \"../../../../types\";\nimport AppError from \"../../../error-handler/utils/app-error\";\n\nexport const getDefaultUsernameField = (): string =>\n getArkosConfig()?.authentication?.login?.allowedUsernames?.[0] || \"username\";\n\n/**\n * Determines the username field to use for authentication and supports nested paths\n * Priority:\n * 1. req.query.usernameField\n * 2. config setting\n * 3. default \"username\"\n *\n * Supports dot notation for nested fields and array queries (e.g., \"profile.nickname\", \"phones.some.number\")\n *\n * @param req - The request object\n * @returns The field name to use for username identification\n */\nexport const determineUsernameField = (req: ArkosRequest): string => {\n const authConfigs = getArkosConfig()?.authentication;\n\n if (\n req.query?.usernameField &&\n typeof req.query?.usernameField === \"string\" &&\n authConfigs?.login?.allowedUsernames?.includes?.(req.query.usernameField)\n )\n return req.query.usernameField;\n else if (req.query?.usernameField)\n throw new AppError(\n \"Invalid usernameField parameter, it is not allowed!\",\n 400\n );\n\n return authConfigs?.login?.allowedUsernames?.[0] || \"username\";\n};\n\n/**\n * Creates a Prisma-compatible where clause from a path using dot notation\n * Handles nested objects and array queries with \"some\" operator\n * Example: createPrismaWhereClause(\"profile.nickname\", \"john\") or createPrismaWhereClause(\"phones.some.number\", \"1234567890\")\n *\n * @param path - The dot notation path (e.g., \"profile.nickname\" or \"phones.some.number\")\n * @param value - The value to search for\n * @returns A nested object suitable for Prisma's where clause\n */\nexport const createPrismaWhereClause = (\n path: string,\n value: any\n): Record<string, any> => {\n if (!path) return {};\n\n const parts = path.split(\".\");\n const whereClause: Record<string, any> = {};\n\n // Handle simple field case\n if (parts.length === 1) {\n whereClause[parts[0]] = value;\n return whereClause;\n }\n\n // Handle nested fields\n let current = whereClause;\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n current[part] = {};\n current = current[part];\n }\n\n current[parts[parts.length - 1]] = value;\n\n return whereClause;\n};\n\n/**\n * Access a value from a simple object based on a dot notation path\n * The object will only contain a single property that matches the last part of the path\n * Example: getNestedValue({nickname: \"john\"}, \"profile.nickname\") => \"john\"\n *\n * @param obj - The object containing the value (simple key-value pair)\n * @param path - The dot notation path (only the last part is used to access the object)\n * @returns The value from the object if the key matches the last part of the path, or undefined\n */\nexport const getNestedValue = (obj: any, path: string): any => {\n if (!obj || !path) return undefined;\n\n const properties = path.split(\".\");\n const lastProperty = properties[properties.length - 1];\n\n // If the last property exists in the object, return its value\n if (lastProperty in obj) {\n return obj[lastProperty];\n }\n\n return undefined;\n};\n\n/**\n * MsDuration type allows specific units for durations\n *\n * **For example**: 90d, 10ms, 50s.\n *\n * **Available metrics**: ms, s, m, h, d, w, y.\n * */\nexport type MsDuration =\n | number\n | `${number}`\n | `${number}${\"ms\" | \"s\" | \"m\" | \"h\" | \"d\" | \"w\" | \"y\"}`; // Short format (e.g., \"1y\")\n\n// Normalize function to convert long units to short ones\nfunction normalizeDuration(input: string): string {\n return input\n .toLowerCase()\n .replace(/years?|yr|year/g, \"y\")\n .replace(/minutes?|min/g, \"m\")\n .replace(/seconds?|sec|secs/g, \"s\")\n .replace(/hours?|hr/g, \"h\")\n .replace(/days?/g, \"d\")\n .replace(/weeks?/g, \"w\")\n .replace(/milliseconds?/g, \"ms\");\n}\n\nexport function toMs(input: number | MsDuration): number {\n if (typeof input === \"number\") return input * 1000; // If it's a number, assume it's in seconds\n\n // Normalize the string input\n const normalizedInput = normalizeDuration(input.trim());\n\n // Type assertion: we assert that normalizedInput will now match the MsDuration format\n const regex = /^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d|w|y)$/i;\n const match = normalizedInput.match(regex);\n\n if (!match) throw new Error(`Invalid time format: ${input}`);\n\n const value = parseFloat(match[1]);\n const unit = match[2].toLowerCase() as\n | \"ms\"\n | \"s\"\n | \"m\"\n | \"h\"\n | \"d\"\n | \"w\"\n | \"y\";\n\n const multipliers: Record<\"ms\" | \"s\" | \"m\" | \"h\" | \"d\" | \"w\" | \"y\", number> =\n {\n ms: 1,\n s: 1000,\n m: 60000,\n h: 3600000,\n d: 86400000,\n w: 604800000,\n y: 31557600000, // 365.25 days in ms\n };\n\n return value * multipliers[unit];\n}\n"]}
@@ -0,0 +1,57 @@
1
+ export const ACCESS_TOKEN_COOKIE_NAME = "arkos_access_token";
2
+ export const NO_TOKEN_SENTINEL = "no-token";
3
+ export function normalizeToken(value) {
4
+ if (typeof value !== "string")
5
+ return null;
6
+ const token = value.trim();
7
+ return token || null;
8
+ }
9
+ export function getCookieToken(cookies, cookieName = ACCESS_TOKEN_COOKIE_NAME) {
10
+ if (!cookies)
11
+ return null;
12
+ const token = normalizeToken(cookies[cookieName]);
13
+ return token === NO_TOKEN_SENTINEL ? null : token;
14
+ }
15
+ export function parseCookieHeader(cookieHeader) {
16
+ const cookies = {};
17
+ if (!cookieHeader || typeof cookieHeader !== "string")
18
+ return cookies;
19
+ for (const pair of cookieHeader.split(";")) {
20
+ const separator = pair.indexOf("=");
21
+ if (separator < 1)
22
+ continue;
23
+ const key = pair.slice(0, separator).trim();
24
+ if (!key)
25
+ continue;
26
+ let value;
27
+ try {
28
+ value = decodeURIComponent(pair.slice(separator + 1).trim());
29
+ }
30
+ catch {
31
+ continue;
32
+ }
33
+ cookies[key] = value;
34
+ }
35
+ return cookies;
36
+ }
37
+ export function extractBearerToken(authorization, { caseInsensitive = true } = {}) {
38
+ if (!authorization || typeof authorization !== "string")
39
+ return null;
40
+ if (!caseInsensitive) {
41
+ if (!authorization.startsWith("Bearer"))
42
+ return null;
43
+ return normalizeToken(authorization.split(" ")[1]);
44
+ }
45
+ const match = /^Bearer\s*(.*)$/i.exec(authorization.trim());
46
+ return match ? normalizeToken(match[1]) : null;
47
+ }
48
+ export function resolveRequestToken({ authorization, cookies, cookieName = ACCESS_TOKEN_COOKIE_NAME, }) {
49
+ return (extractBearerToken(authorization, { caseInsensitive: false }) ??
50
+ getCookieToken(cookies, cookieName));
51
+ }
52
+ export function resolveSocketToken({ auth, key = "token", headers, cookies, cookieHeader, cookieName = ACCESS_TOKEN_COOKIE_NAME, }) {
53
+ return (normalizeToken(auth?.[key]) ??
54
+ extractBearerToken(headers?.authorization) ??
55
+ getCookieToken(cookies ?? parseCookieHeader(cookieHeader ?? headers?.cookie), cookieName));
56
+ }
57
+ //# sourceMappingURL=token-extraction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-extraction.js","sourceRoot":"","sources":["../../../../../src/modules/auth/utils/token-extraction.ts"],"names":[],"mappings":"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","sourcesContent":["export const ACCESS_TOKEN_COOKIE_NAME = \"arkos_access_token\";\nexport const NO_TOKEN_SENTINEL = \"no-token\";\n\nexport type CookieMap = Record<string, string>;\n\n/** Returns the trimmed token if it is non-empty, otherwise `null`. */\nexport function normalizeToken(value: unknown): string | null {\n if (typeof value !== \"string\") return null;\n\n const token = value.trim();\n return token || null;\n}\n\n/**\n * Reads a token from an already-parsed cookie map (e.g. Express's `req.cookies`).\n * Arkos writes the `no-token` sentinel on logout, so it counts as absent.\n */\nexport function getCookieToken(\n cookies: Record<string, unknown> | undefined,\n cookieName: string = ACCESS_TOKEN_COOKIE_NAME,\n): string | null {\n if (!cookies) return null;\n\n const token = normalizeToken(cookies[cookieName]);\n return token === NO_TOKEN_SENTINEL ? null : token;\n}\n\n/**\n * Parses a raw `Cookie` header without requiring cookie-parser.\n * Values may contain `=`; malformed pairs are skipped.\n */\nexport function parseCookieHeader(\n cookieHeader?: string | null,\n): CookieMap {\n const cookies: CookieMap = {};\n\n if (!cookieHeader || typeof cookieHeader !== \"string\") return cookies;\n\n for (const pair of cookieHeader.split(\";\")) {\n const separator = pair.indexOf(\"=\");\n if (separator < 1) continue;\n\n const key = pair.slice(0, separator).trim();\n if (!key) continue;\n\n let value: string;\n try {\n value = decodeURIComponent(pair.slice(separator + 1).trim());\n } catch {\n continue;\n }\n\n cookies[key] = value;\n }\n\n return cookies;\n}\n\n/**\n * Extracts a bearer token from an `Authorization` header.\n *\n * The default mode is case-insensitive and tolerates a missing space after\n * `Bearer`. Pass `{ caseInsensitive: false }` to preserve the legacy HTTP\n * behavior exactly.\n */\nexport function extractBearerToken(\n authorization?: string | null,\n { caseInsensitive = true }: { caseInsensitive?: boolean } = {},\n): string | null {\n if (!authorization || typeof authorization !== \"string\") return null;\n\n if (!caseInsensitive) {\n if (!authorization.startsWith(\"Bearer\")) return null;\n return normalizeToken(authorization.split(\" \")[1]);\n }\n\n const match = /^Bearer\\s*(.*)$/i.exec(authorization.trim());\n return match ? normalizeToken(match[1]) : null;\n}\n\nexport interface RequestTokenSources {\n authorization?: string;\n cookies?: Record<string, unknown>;\n cookieName?: string;\n}\n\n/**\n * Resolves the token for an HTTP request-like object.\n * Precedence: `Authorization` header, then the access-token cookie.\n */\nexport function resolveRequestToken({\n authorization,\n cookies,\n cookieName = ACCESS_TOKEN_COOKIE_NAME,\n}: RequestTokenSources): string | null {\n return (\n extractBearerToken(authorization, { caseInsensitive: false }) ??\n getCookieToken(cookies, cookieName)\n );\n}\n\nexport interface SocketTokenSources {\n auth?: Record<string, unknown>;\n key?: string;\n headers?: {\n authorization?: string;\n cookie?: string;\n };\n /** Pre-parsed cookies, when available. */\n cookies?: CookieMap;\n /** Raw `Cookie` header, used when `cookies` is not provided. */\n cookieHeader?: string;\n cookieName?: string;\n}\n\n/**\n * Resolves the token for a Socket.IO connection.\n * Precedence: `handshake.auth.token`, `Authorization` header, access-token cookie.\n */\nexport function resolveSocketToken({\n auth,\n key = \"token\",\n headers,\n cookies,\n cookieHeader,\n cookieName = ACCESS_TOKEN_COOKIE_NAME,\n}: SocketTokenSources): string | null {\n return (\n normalizeToken(auth?.[key]) ??\n extractBearerToken(headers?.authorization) ??\n getCookieToken(\n cookies ?? parseCookieHeader(cookieHeader ?? headers?.cookie),\n cookieName,\n )\n );\n}\n"]}
@@ -10,6 +10,9 @@ import { routeHookReader } from '../../components/arkos-route-hook/reader.js';
10
10
  export class BaseController {
11
11
  service;
12
12
  modelName;
13
+ get hasCustomService() {
14
+ return !!this.getRouteHook()?._configs.service;
15
+ }
13
16
  constructor(modelName) {
14
17
  this.modelName = kebabCase(modelName);
15
18
  this.service = new ArkosPrismaService(modelName);
@@ -64,6 +67,8 @@ export class BaseController {
64
67
  ? routeHook._configs.service[config.serviceMethod]
65
68
  : this.service[config.serviceMethod]);
66
69
  let result = await serviceMethod.apply(isRouteHookMethod ? routeHook._configs.service : this.service, serviceArgs);
70
+ if (this.hasCustomService && result === undefined)
71
+ throw new Error(`Custom service method ${config.serviceMethod} didn't return the required data`);
67
72
  if (config.hooks?.afterService)
68
73
  result = await config.hooks.afterService(result, req);
69
74
  let data = result;
@@ -1 +1 @@
1
- {"version":3,"file":"base.controller.js","sourceRoot":"","sources":["../../../../src/modules/base/base.controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { ArkosRequest, ArkosResponse, ArkosNextFunction } from '../../types';\nimport catchAsync from '../error-handler/utils/catch-async';\nimport { ArkosPrismaService } from './base.service';\nimport AppError from '../error-handler/utils/app-error';\nimport { kebabCase, pascalCase } from '../../utils/helpers/change-case.helpers';\nimport pluralize from 'pluralize';\nimport { APIFeatures } from '../../exports/utils';\nimport deepmerge from '../../utils/helpers/deepmerge.helper';\nimport loadableRegistry from '../../components/arkos-loadable-registry';\nimport { routeHookReader } from '../../components/arkos-route-hook/reader';\nimport { PrismaModels } from '../../generated';\nimport { ArkosRouteHookInstance } from '../../components/arkos-route-hook/types';\n\nexport interface OperationHooks {\n beforeQuery?: (req: ArkosRequest) => void | Promise<void>;\n afterQuery?: (\n queryData: { where: any; queryOptions: any },\n req: ArkosRequest,\n ) => void | Promise<void>;\n beforeService?: (args: any[], req: ArkosRequest) => any[] | Promise<any[]>;\n afterService?: (data: any, req: ArkosRequest) => any | Promise<any>;\n beforeResponse?: (responseData: any, req: ArkosRequest) => any | Promise<any>;\n}\n\ninterface OperationConfig {\n operationType:\n | keyof Omit<ArkosRouteHookInstance<any>, '__type' | 'moduleName'>\n | 'batchUpdate'\n | 'batchDelete';\n serviceMethod: string;\n successStatus: number;\n queryFeatures: ('filter' | 'sort' | 'limitFields' | 'paginate')[];\n requiresQueryForBulk?: boolean;\n preventORFilter?: boolean;\n responseBuilder?: (data: any, additionalData?: any) => any;\n errorHandler?: (\n data: any,\n req: ArkosRequest,\n modelName: string,\n ) => AppError | null;\n usesRequestParams?: boolean;\n usesRequestBody?: boolean;\n hooks?: OperationHooks;\n}\n\n/**\n * The `BaseController` class provides standardized RESTful API endpoints\n * for any Prisma model based on its name. It supports automatic integration\n * with Prisma services and dynamic middleware hooks for extending behaviors.\n *\n * This controller includes:\n * - `createOne` / `createMany`\n * - `findOne` / `findMany`\n * - `updateOne` / `updateMany`\n * - `deleteOne` / `deleteMany`\n *\n * It handles:\n * - Prisma query options\n * - APIFeatures: filtering, sorting, pagination, field limiting\n * - Middleware hooks: `afterCreateOne`, `afterUpdateMany`, etc.\n *\n * @class BaseController\n *\n * @param {string} modelName - The Prisma model name this controller handles.\n *\n * @see {@link https://www.arkosjs.com/docs/reference/base-controller}\n *--\n * **See about how Arkos handles routers**\n * @see {@link https://www.arkosjs.com/docs/core-concepts/routing/setup}\n */\nexport class BaseController<TModuleName extends keyof PrismaModels<any>> {\n /**\n * Service instance to handle business logic operations\n * @public\n */\n service: ArkosPrismaService<TModuleName>;\n\n /**\n * Name of the model this controller handles\n * @private\n */\n private modelName: string;\n\n /**\n * Creates a new BaseController instance\n * @param {string} modelName - The name of the model for which this controller will handle operations\n */\n constructor(modelName: TModuleName) {\n this.modelName = kebabCase(modelName);\n this.service = new ArkosPrismaService(modelName);\n }\n\n private getRouteHook() {\n return loadableRegistry.getItem(\n 'ArkosRouteHook',\n kebabCase(kebabCase(this.modelName)),\n ) as ArkosRouteHookInstance<TModuleName> | null;\n }\n\n private executeOperation = (config: OperationConfig) => {\n return catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction,\n ) => {\n if (config.hooks?.beforeQuery) await config.hooks.beforeQuery(req);\n\n if (config.requiresQueryForBulk) {\n if (\n Object.keys(req.query).every((key) =>\n ['filterMode', 'prismaQueryOptions'].includes(key),\n )\n ) {\n return next(\n new AppError(\n `Filter criteria not provided for bulk ${config.operationType.replace(/Many$/, '')}.`,\n 400,\n 'MissingRequestQueryParameters',\n ),\n );\n }\n }\n\n if (config.preventORFilter && req.query.filterMode === 'OR') {\n throw new AppError(\n `req.query.filterMode === OR is not valid for ${config.operationType} operation`,\n 400,\n );\n }\n\n if (config.preventORFilter) req.query.filterMode = 'AND';\n\n let apiFeatures = new APIFeatures(req, this.modelName);\n\n config.queryFeatures.forEach((feature) => {\n switch (feature) {\n case 'filter':\n apiFeatures = apiFeatures.filter();\n break;\n case 'sort':\n apiFeatures = apiFeatures.sort();\n break;\n case 'limitFields':\n apiFeatures = apiFeatures.limitFields();\n break;\n case 'paginate':\n apiFeatures = apiFeatures.paginate();\n break;\n }\n });\n\n const { where, ...queryOptions } = apiFeatures.filters;\n\n if (config.hooks?.afterQuery)\n await config.hooks.afterQuery({ where, queryOptions }, req);\n\n let serviceArgs = this.buildServiceArgs(\n config,\n req,\n where,\n queryOptions,\n );\n\n if (config.hooks?.beforeService)\n serviceArgs = await config.hooks.beforeService(serviceArgs, req);\n\n const routeHook = this.getRouteHook();\n\n const isRouteHookMethod =\n routeHook &&\n routeHook._configs.service &&\n routeHook._configs.service[\n config.serviceMethod as keyof ArkosPrismaService<any>\n ]\n ? true\n : false;\n\n const serviceMethod = (\n isRouteHookMethod\n ? routeHook!._configs.service![\n config.serviceMethod as keyof ArkosPrismaService<any>\n ]\n : this.service[\n config.serviceMethod as keyof ArkosPrismaService<any>\n ]\n ) as Function;\n\n let result = await serviceMethod.apply(\n isRouteHookMethod ? routeHook!._configs.service : this.service,\n serviceArgs,\n );\n\n if (config.hooks?.afterService)\n result = await config.hooks.afterService(result, req);\n\n let data = result;\n let additionalData: any = null;\n\n if (config.operationType === 'findMany') {\n const [records, total] = await Promise.all([\n result,\n this.service.count(where, {\n user: req?.user!,\n accessToken: req?.accessToken,\n }),\n ]);\n\n const take = serviceArgs[1]?.take ?? null;\n const skip = serviceArgs[1]?.skip ?? 0;\n\n const limit = take ?? total;\n const currentPage = limit > 0 ? Math.floor(skip / limit) + 1 : 1;\n const totalPages = limit > 0 ? Math.ceil(total / limit) : 1;\n\n data = records;\n additionalData = {\n total,\n results: records.length,\n page: currentPage,\n pages: totalPages,\n limit,\n hasNextPage: currentPage < totalPages,\n hasPrevPage: currentPage > 1,\n };\n }\n\n const error = config.errorHandler\n ? config.errorHandler(data, req, this.modelName)\n : this.defaultErrorHandler(data, req, config.operationType);\n\n if (error) return next(error);\n\n let responseData = config.responseBuilder\n ? config.responseBuilder(data, additionalData)\n : this.defaultResponseBuilder(\n data,\n additionalData,\n config.operationType,\n );\n\n if (config.hooks?.beforeResponse)\n responseData = await config.hooks.beforeResponse(responseData, req);\n\n if (\n routeHook &&\n routeHookReader.getHooks(this.modelName, config.operationType as any)\n ?.after\n ) {\n this.setResponseData(req, res, responseData, config.successStatus);\n next();\n return;\n }\n\n if (config.operationType === 'deleteOne') {\n res.status(config.successStatus).send();\n return;\n }\n\n res.status(config.successStatus).json(responseData);\n },\n );\n };\n\n /**\n * Sets response data for both legacy (req.responseData) and modern (res.locals) support\n */\n private setResponseData(\n req: ArkosRequest,\n res: ArkosResponse,\n data: any,\n status: number,\n ): void {\n (res as any).originalData = data;\n req.responseData = data;\n res.locals.data = data;\n (res as any).originalStatus = status;\n req.responseStatus = status;\n res.locals.status = status;\n\n // Special handling for deleteOne\n if (status === 204) {\n req.additionalData = data;\n res.locals.additionalData = data;\n (res as any).originalAdditionalData = data;\n }\n }\n\n /**\n * Builds service method arguments based on operation configuration\n */\n private buildServiceArgs(\n config: OperationConfig,\n req: ArkosRequest,\n where: any,\n queryOptions: any,\n ): any[] {\n const context = { user: req?.user, accessToken: req?.accessToken };\n const mergedOptions = deepmerge(req.prismaQueryOptions || {}, queryOptions);\n\n switch (config.operationType) {\n case 'createOne':\n case 'createMany':\n return [req.body, mergedOptions, context];\n\n case 'findMany':\n return [where, queryOptions, context];\n\n case 'findOne':\n return [{ ...req.params, ...where }, mergedOptions, context];\n\n case 'updateOne':\n return [{ ...req.params, ...where }, req.body, mergedOptions, context];\n\n case 'updateMany':\n // Remove include for bulk operations\n delete queryOptions.include;\n return [where, req.body, queryOptions, context];\n\n case 'batchUpdate':\n return [req.body, mergedOptions, context];\n\n case 'deleteOne':\n return [{ ...req.params, ...where }, context];\n\n case 'deleteMany':\n return [where, context];\n\n case 'batchDelete':\n return [req.body, context];\n\n default:\n throw new Error(`Unknown operation type: ${config.operationType}`);\n }\n }\n\n /**\n * Default error handler for operations\n */\n private defaultErrorHandler(\n data: any,\n req: ArkosRequest,\n operationType: string,\n ): AppError | null {\n if (!data || (Array.isArray(data) && data.length === 0)) {\n // Handle different error scenarios\n if (operationType.includes('create') || operationType.includes('batch')) {\n return new AppError(\n 'Failed to create the resources. Please check your input.',\n 400,\n { body: req.body },\n );\n }\n\n if (\n operationType === 'findOne' ||\n operationType === 'updateOne' ||\n operationType === 'deleteOne'\n ) {\n if (\n Object.keys(req.params).length === 1 &&\n 'id' in req.params &&\n req.params.id !== 'me'\n ) {\n return new AppError(\n `${pascalCase(String(this.modelName))} with ID ${req.params?.id} not found`,\n 404,\n {},\n 'NotFound',\n );\n } else {\n return new AppError(\n `${pascalCase(String(this.modelName))} not found`,\n 404,\n {},\n 'NotFound',\n );\n }\n }\n\n if (operationType === 'updateMany' || operationType === 'deleteMany') {\n const isUpdate = operationType === 'updateMany';\n return new AppError(\n isUpdate\n ? `${pluralize(pascalCase(String(this.modelName)))} not found`\n : `No records found to delete`,\n 404,\n {},\n 'NotFound',\n );\n }\n }\n\n // Special handling for operations that return count\n if (\n data &&\n typeof data === 'object' &&\n 'count' in data &&\n data.count === 0\n ) {\n return new AppError(\n operationType === 'updateMany'\n ? `${pluralize(pascalCase(String(this.modelName)))} not found`\n : `No records found to delete`,\n 404,\n {},\n 'NotFound',\n );\n }\n\n return null;\n }\n\n /**\n * Default response builder for operations\n */\n private defaultResponseBuilder(\n data: any,\n additionalData: any,\n operationType: string,\n ): any {\n if (operationType === 'findMany' && additionalData)\n return {\n ...additionalData,\n data,\n };\n\n if (\n operationType.includes('Many') &&\n data &&\n typeof data === 'object' &&\n 'count' in data\n )\n return { results: data.count, data };\n\n if (operationType.includes('batch') && Array.isArray(data))\n return { results: data.length, data };\n\n return { data };\n }\n\n /**\n * Creates a single resource\n */\n createOne = this.executeOperation({\n operationType: 'createOne',\n serviceMethod: 'createOne',\n successStatus: 201,\n queryFeatures: ['limitFields'],\n usesRequestBody: true,\n });\n\n /**\n * Creates multiple resources in a single operation\n */\n createMany = this.executeOperation({\n operationType: 'createMany',\n serviceMethod: 'createMany',\n successStatus: 201,\n queryFeatures: ['limitFields'],\n usesRequestBody: true,\n hooks: {\n async beforeQuery(req) {\n if (!req.body || (Array.isArray(req.body) && req.body.length === 0))\n throw new AppError(\n 'Expected request body array to contain at least on item but received none',\n 400,\n { body: req.body },\n 'MissingArrayRequestBody',\n );\n },\n },\n });\n\n /**\n * Retrieves multiple resources with filtering, sorting, pagination, and field selection\n */\n findMany = this.executeOperation({\n operationType: 'findMany',\n serviceMethod: 'findMany',\n successStatus: 200,\n queryFeatures: ['filter', 'sort', 'limitFields', 'paginate'],\n });\n\n /**\n * Retrieves a single resource by its identifier\n */\n findOne = this.executeOperation({\n operationType: 'findOne',\n serviceMethod: 'findOne',\n successStatus: 200,\n queryFeatures: ['limitFields', 'filter'],\n usesRequestParams: true,\n });\n\n /**\n * Updates a single resource by its identifier\n */\n updateOne = this.executeOperation({\n operationType: 'updateOne',\n serviceMethod: 'updateOne',\n successStatus: 200,\n queryFeatures: ['limitFields', 'filter'],\n usesRequestParams: true,\n usesRequestBody: true,\n });\n\n /**\n * Updates multiple resources that match specified criteria\n */\n updateMany = this.executeOperation({\n operationType: 'updateMany',\n serviceMethod: 'updateMany',\n successStatus: 200,\n queryFeatures: ['filter', 'limitFields'],\n requiresQueryForBulk: true,\n preventORFilter: true,\n usesRequestBody: true,\n });\n\n /**\n * Updates multiple resources with different data in a single transaction\n */\n batchUpdate = this.executeOperation({\n operationType: 'batchUpdate',\n serviceMethod: 'batchUpdate',\n successStatus: 200,\n queryFeatures: ['limitFields', 'filter'],\n usesRequestBody: true,\n });\n\n /**\n * Deletes a single resource by its identifier\n */\n deleteOne = this.executeOperation({\n operationType: 'deleteOne',\n serviceMethod: 'deleteOne',\n successStatus: 204,\n queryFeatures: ['filter'],\n usesRequestParams: true,\n });\n\n /**\n * Deletes multiple resources that match specified criteria\n */\n deleteMany = this.executeOperation({\n operationType: 'deleteMany',\n serviceMethod: 'deleteMany',\n successStatus: 200,\n queryFeatures: ['filter'],\n requiresQueryForBulk: true,\n preventORFilter: true,\n });\n\n /**\n * Deletes multiple resources with different filters in a single transaction\n */\n batchDelete = this.executeOperation({\n operationType: 'batchDelete',\n serviceMethod: 'batchDelete',\n successStatus: 200,\n queryFeatures: ['filter'],\n usesRequestBody: true,\n });\n}\n\n"]}
1
+ {"version":3,"file":"base.controller.js","sourceRoot":"","sources":["../../../../src/modules/base/base.controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { ArkosRequest, ArkosResponse, ArkosNextFunction } from '../../types';\nimport catchAsync from '../error-handler/utils/catch-async';\nimport { ArkosPrismaService } from './base.service';\nimport AppError from '../error-handler/utils/app-error';\nimport { kebabCase, pascalCase } from '../../utils/helpers/change-case.helpers';\nimport pluralize from 'pluralize';\nimport { APIFeatures } from '../../exports/utils';\nimport deepmerge from '../../utils/helpers/deepmerge.helper';\nimport loadableRegistry from '../../components/arkos-loadable-registry';\nimport { routeHookReader } from '../../components/arkos-route-hook/reader';\nimport { PrismaModels } from '../../generated';\nimport { ArkosRouteHookInstance } from '../../components/arkos-route-hook/types';\n\nexport interface OperationHooks {\n beforeQuery?: (req: ArkosRequest) => void | Promise<void>;\n afterQuery?: (\n queryData: { where: any; queryOptions: any },\n req: ArkosRequest,\n ) => void | Promise<void>;\n beforeService?: (args: any[], req: ArkosRequest) => any[] | Promise<any[]>;\n afterService?: (data: any, req: ArkosRequest) => any | Promise<any>;\n beforeResponse?: (responseData: any, req: ArkosRequest) => any | Promise<any>;\n}\n\ninterface OperationConfig {\n operationType:\n | keyof Omit<ArkosRouteHookInstance<any>, '__type' | 'moduleName'>\n | 'batchUpdate'\n | 'batchDelete';\n serviceMethod: string;\n successStatus: number;\n queryFeatures: ('filter' | 'sort' | 'limitFields' | 'paginate')[];\n requiresQueryForBulk?: boolean;\n preventORFilter?: boolean;\n responseBuilder?: (data: any, additionalData?: any) => any;\n errorHandler?: (\n data: any,\n req: ArkosRequest,\n modelName: string,\n ) => AppError | null;\n usesRequestParams?: boolean;\n usesRequestBody?: boolean;\n hooks?: OperationHooks;\n}\n\n/**\n * The `BaseController` class provides standardized RESTful API endpoints\n * for any Prisma model based on its name. It supports automatic integration\n * with Prisma services and dynamic middleware hooks for extending behaviors.\n *\n * This controller includes:\n * - `createOne` / `createMany`\n * - `findOne` / `findMany`\n * - `updateOne` / `updateMany`\n * - `deleteOne` / `deleteMany`\n *\n * It handles:\n * - Prisma query options\n * - APIFeatures: filtering, sorting, pagination, field limiting\n * - Middleware hooks: `afterCreateOne`, `afterUpdateMany`, etc.\n *\n * @class BaseController\n *\n * @param {string} modelName - The Prisma model name this controller handles.\n *\n * @see {@link https://www.arkosjs.com/docs/reference/base-controller}\n *--\n * **See about how Arkos handles routers**\n * @see {@link https://www.arkosjs.com/docs/core-concepts/routing/setup}\n */\nexport class BaseController<TModuleName extends keyof PrismaModels<any>> {\n /**\n * Service instance to handle business logic operations\n * @public\n */\n service: ArkosPrismaService<TModuleName>;\n\n /**\n * Name of the model this controller handles\n * @private\n */\n private modelName: string;\n\n private get hasCustomService() {\n return !!this.getRouteHook()?._configs.service;\n }\n\n /**\n * Creates a new BaseController instance\n * @param {string} modelName - The name of the model for which this controller will handle operations\n */\n constructor(modelName: TModuleName) {\n this.modelName = kebabCase(modelName);\n this.service = new ArkosPrismaService(modelName);\n }\n\n private getRouteHook() {\n return loadableRegistry.getItem(\n 'ArkosRouteHook',\n kebabCase(kebabCase(this.modelName)),\n ) as ArkosRouteHookInstance<TModuleName> | null;\n }\n\n private executeOperation = (config: OperationConfig) => {\n return catchAsync(\n async (\n req: ArkosRequest,\n res: ArkosResponse,\n next: ArkosNextFunction,\n ) => {\n if (config.hooks?.beforeQuery) await config.hooks.beforeQuery(req);\n\n if (config.requiresQueryForBulk) {\n if (\n Object.keys(req.query).every((key) =>\n ['filterMode', 'prismaQueryOptions'].includes(key),\n )\n ) {\n return next(\n new AppError(\n `Filter criteria not provided for bulk ${config.operationType.replace(/Many$/, '')}.`,\n 400,\n 'MissingRequestQueryParameters',\n ),\n );\n }\n }\n\n if (config.preventORFilter && req.query.filterMode === 'OR') {\n throw new AppError(\n `req.query.filterMode === OR is not valid for ${config.operationType} operation`,\n 400,\n );\n }\n\n if (config.preventORFilter) req.query.filterMode = 'AND';\n\n let apiFeatures = new APIFeatures(req, this.modelName);\n\n config.queryFeatures.forEach((feature) => {\n switch (feature) {\n case 'filter':\n apiFeatures = apiFeatures.filter();\n break;\n case 'sort':\n apiFeatures = apiFeatures.sort();\n break;\n case 'limitFields':\n apiFeatures = apiFeatures.limitFields();\n break;\n case 'paginate':\n apiFeatures = apiFeatures.paginate();\n break;\n }\n });\n\n const { where, ...queryOptions } = apiFeatures.filters;\n\n if (config.hooks?.afterQuery)\n await config.hooks.afterQuery({ where, queryOptions }, req);\n\n let serviceArgs = this.buildServiceArgs(\n config,\n req,\n where,\n queryOptions,\n );\n\n if (config.hooks?.beforeService)\n serviceArgs = await config.hooks.beforeService(serviceArgs, req);\n\n const routeHook = this.getRouteHook();\n\n const isRouteHookMethod =\n routeHook &&\n routeHook._configs.service &&\n routeHook._configs.service[\n config.serviceMethod as keyof ArkosPrismaService<any>\n ]\n ? true\n : false;\n\n const serviceMethod = (\n isRouteHookMethod\n ? routeHook!._configs.service![\n config.serviceMethod as keyof ArkosPrismaService<any>\n ]\n : this.service[\n config.serviceMethod as keyof ArkosPrismaService<any>\n ]\n ) as Function;\n\n let result = await serviceMethod.apply(\n isRouteHookMethod ? routeHook!._configs.service : this.service,\n serviceArgs,\n );\n\n if (this.hasCustomService && result === undefined)\n throw new Error(\n `Custom service method ${config.serviceMethod} didn't return the required data`,\n );\n\n if (config.hooks?.afterService)\n result = await config.hooks.afterService(result, req);\n\n let data = result;\n let additionalData: any = null;\n\n if (config.operationType === 'findMany') {\n const [records, total] = await Promise.all([\n result,\n this.service.count(where, {\n user: req?.user!,\n accessToken: req?.accessToken,\n }),\n ]);\n\n const take = serviceArgs[1]?.take ?? null;\n const skip = serviceArgs[1]?.skip ?? 0;\n\n const limit = take ?? total;\n const currentPage = limit > 0 ? Math.floor(skip / limit) + 1 : 1;\n const totalPages = limit > 0 ? Math.ceil(total / limit) : 1;\n\n data = records;\n additionalData = {\n total,\n results: records.length,\n page: currentPage,\n pages: totalPages,\n limit,\n hasNextPage: currentPage < totalPages,\n hasPrevPage: currentPage > 1,\n };\n }\n\n const error = config.errorHandler\n ? config.errorHandler(data, req, this.modelName)\n : this.defaultErrorHandler(data, req, config.operationType);\n\n if (error) return next(error);\n\n let responseData = config.responseBuilder\n ? config.responseBuilder(data, additionalData)\n : this.defaultResponseBuilder(\n data,\n additionalData,\n config.operationType,\n );\n\n if (config.hooks?.beforeResponse)\n responseData = await config.hooks.beforeResponse(responseData, req);\n\n if (\n routeHook &&\n routeHookReader.getHooks(this.modelName, config.operationType as any)\n ?.after\n ) {\n this.setResponseData(req, res, responseData, config.successStatus);\n next();\n return;\n }\n\n if (config.operationType === 'deleteOne') {\n res.status(config.successStatus).send();\n return;\n }\n\n res.status(config.successStatus).json(responseData);\n },\n );\n };\n\n /**\n * Sets response data for both legacy (req.responseData) and modern (res.locals) support\n */\n private setResponseData(\n req: ArkosRequest,\n res: ArkosResponse,\n data: any,\n status: number,\n ): void {\n (res as any).originalData = data;\n req.responseData = data;\n res.locals.data = data;\n (res as any).originalStatus = status;\n req.responseStatus = status;\n res.locals.status = status;\n\n // Special handling for deleteOne\n if (status === 204) {\n req.additionalData = data;\n res.locals.additionalData = data;\n (res as any).originalAdditionalData = data;\n }\n }\n\n /**\n * Builds service method arguments based on operation configuration\n */\n private buildServiceArgs(\n config: OperationConfig,\n req: ArkosRequest,\n where: any,\n queryOptions: any,\n ): any[] {\n const context = { user: req?.user, accessToken: req?.accessToken };\n const mergedOptions = deepmerge(req.prismaQueryOptions || {}, queryOptions);\n\n switch (config.operationType) {\n case 'createOne':\n case 'createMany':\n return [req.body, mergedOptions, context];\n\n case 'findMany':\n return [where, queryOptions, context];\n\n case 'findOne':\n return [{ ...req.params, ...where }, mergedOptions, context];\n\n case 'updateOne':\n return [{ ...req.params, ...where }, req.body, mergedOptions, context];\n\n case 'updateMany':\n // Remove include for bulk operations\n delete queryOptions.include;\n return [where, req.body, queryOptions, context];\n\n case 'batchUpdate':\n return [req.body, mergedOptions, context];\n\n case 'deleteOne':\n return [{ ...req.params, ...where }, context];\n\n case 'deleteMany':\n return [where, context];\n\n case 'batchDelete':\n return [req.body, context];\n\n default:\n throw new Error(`Unknown operation type: ${config.operationType}`);\n }\n }\n\n /**\n * Default error handler for operations\n */\n private defaultErrorHandler(\n data: any,\n req: ArkosRequest,\n operationType: string,\n ): AppError | null {\n if (!data || (Array.isArray(data) && data.length === 0)) {\n // Handle different error scenarios\n if (operationType.includes('create') || operationType.includes('batch')) {\n return new AppError(\n 'Failed to create the resources. Please check your input.',\n 400,\n { body: req.body },\n );\n }\n\n if (\n operationType === 'findOne' ||\n operationType === 'updateOne' ||\n operationType === 'deleteOne'\n ) {\n if (\n Object.keys(req.params).length === 1 &&\n 'id' in req.params &&\n req.params.id !== 'me'\n ) {\n return new AppError(\n `${pascalCase(String(this.modelName))} with ID ${req.params?.id} not found`,\n 404,\n {},\n 'NotFound',\n );\n } else {\n return new AppError(\n `${pascalCase(String(this.modelName))} not found`,\n 404,\n {},\n 'NotFound',\n );\n }\n }\n\n if (operationType === 'updateMany' || operationType === 'deleteMany') {\n const isUpdate = operationType === 'updateMany';\n return new AppError(\n isUpdate\n ? `${pluralize(pascalCase(String(this.modelName)))} not found`\n : `No records found to delete`,\n 404,\n {},\n 'NotFound',\n );\n }\n }\n\n // Special handling for operations that return count\n if (\n data &&\n typeof data === 'object' &&\n 'count' in data &&\n data.count === 0\n ) {\n return new AppError(\n operationType === 'updateMany'\n ? `${pluralize(pascalCase(String(this.modelName)))} not found`\n : `No records found to delete`,\n 404,\n {},\n 'NotFound',\n );\n }\n\n return null;\n }\n\n /**\n * Default response builder for operations\n */\n private defaultResponseBuilder(\n data: any,\n additionalData: any,\n operationType: string,\n ): any {\n if (operationType === 'findMany' && additionalData)\n return {\n ...additionalData,\n data,\n };\n\n if (\n operationType.includes('Many') &&\n data &&\n typeof data === 'object' &&\n 'count' in data\n )\n return { results: data.count, data };\n\n if (operationType.includes('batch') && Array.isArray(data))\n return { results: data.length, data };\n\n return { data };\n }\n\n /**\n * Creates a single resource\n */\n createOne = this.executeOperation({\n operationType: 'createOne',\n serviceMethod: 'createOne',\n successStatus: 201,\n queryFeatures: ['limitFields'],\n usesRequestBody: true,\n });\n\n /**\n * Creates multiple resources in a single operation\n */\n createMany = this.executeOperation({\n operationType: 'createMany',\n serviceMethod: 'createMany',\n successStatus: 201,\n queryFeatures: ['limitFields'],\n usesRequestBody: true,\n hooks: {\n async beforeQuery(req) {\n if (!req.body || (Array.isArray(req.body) && req.body.length === 0))\n throw new AppError(\n 'Expected request body array to contain at least on item but received none',\n 400,\n { body: req.body },\n 'MissingArrayRequestBody',\n );\n },\n },\n });\n\n /**\n * Retrieves multiple resources with filtering, sorting, pagination, and field selection\n */\n findMany = this.executeOperation({\n operationType: 'findMany',\n serviceMethod: 'findMany',\n successStatus: 200,\n queryFeatures: ['filter', 'sort', 'limitFields', 'paginate'],\n });\n\n /**\n * Retrieves a single resource by its identifier\n */\n findOne = this.executeOperation({\n operationType: 'findOne',\n serviceMethod: 'findOne',\n successStatus: 200,\n queryFeatures: ['limitFields', 'filter'],\n usesRequestParams: true,\n });\n\n /**\n * Updates a single resource by its identifier\n */\n updateOne = this.executeOperation({\n operationType: 'updateOne',\n serviceMethod: 'updateOne',\n successStatus: 200,\n queryFeatures: ['limitFields', 'filter'],\n usesRequestParams: true,\n usesRequestBody: true,\n });\n\n /**\n * Updates multiple resources that match specified criteria\n */\n updateMany = this.executeOperation({\n operationType: 'updateMany',\n serviceMethod: 'updateMany',\n successStatus: 200,\n queryFeatures: ['filter', 'limitFields'],\n requiresQueryForBulk: true,\n preventORFilter: true,\n usesRequestBody: true,\n });\n\n /**\n * Updates multiple resources with different data in a single transaction\n */\n batchUpdate = this.executeOperation({\n operationType: 'batchUpdate',\n serviceMethod: 'batchUpdate',\n successStatus: 200,\n queryFeatures: ['limitFields', 'filter'],\n usesRequestBody: true,\n });\n\n /**\n * Deletes a single resource by its identifier\n */\n deleteOne = this.executeOperation({\n operationType: 'deleteOne',\n serviceMethod: 'deleteOne',\n successStatus: 204,\n queryFeatures: ['filter'],\n usesRequestParams: true,\n });\n\n /**\n * Deletes multiple resources that match specified criteria\n */\n deleteMany = this.executeOperation({\n operationType: 'deleteMany',\n serviceMethod: 'deleteMany',\n successStatus: 200,\n queryFeatures: ['filter'],\n requiresQueryForBulk: true,\n preventORFilter: true,\n });\n\n /**\n * Deletes multiple resources with different filters in a single transaction\n */\n batchDelete = this.executeOperation({\n operationType: 'batchDelete',\n serviceMethod: 'batchDelete',\n successStatus: 200,\n queryFeatures: ['filter'],\n usesRequestBody: true,\n });\n}\n\n"]}
@@ -1,4 +1,5 @@
1
1
  import { getArkosConfig } from '../../server.js';
2
+ import { isZodSchema } from '../../utils/dynamic-loader.js';
2
3
  import deepmerge from '../../utils/helpers/deepmerge.helper.js';
3
4
  import { AppError, BadRequestError, catchAsync, } from '../../exports/error-handler/index.js';
4
5
  import { resolvePrismaQueryOptions } from './utils/helpers/base.middlewares.helpers.js';
@@ -190,11 +191,10 @@ Read more about strict validation at https://www.arkosjs.com/docs/guides/validat
190
191
  });
191
192
  }
192
193
  catch (err) {
193
- const resolver = validationConfig?.resolver;
194
- const isZod = validationConfig?.resolver === 'zod';
195
- const prettifiedError = errorPrettifier.prettify(resolver, err);
194
+ const isZod = isZodSchema(validator);
195
+ const prettifiedError = errorPrettifier.prettify(isZod ? 'zod' : 'class-validator', err);
196
196
  const error = prettifiedError[0];
197
- throw new AppError(error.message, 400, `InvalidRequest${pascalCase(key)}`, isZod ? err.format() : err);
197
+ throw new AppError(error?.message || err?.message || `Request ${key} is invalid`, 400, `InvalidRequest${pascalCase(key)}`, isZod && typeof err?.format === 'function' ? err.format() : err);
198
198
  }
199
199
  }
200
200
  next();