@intlayer/backend 8.7.12 → 8.7.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -1
- package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/benchmark/solid.json +4990 -0
- package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/benchmark/svelte.json +4987 -0
- package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/benchmark/vue.json +4975 -0
- package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/intlayer_with_astro_lit.json +9936 -8930
- package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/intlayer_with_astro_vanilla.json +7963 -6949
- package/dist/assets/utils/AI/askDocQuestion/embeddings/docs/en/readme.json +12908 -12288
- package/dist/esm/controllers/oAuth2.controller.mjs +21 -1
- package/dist/esm/controllers/oAuth2.controller.mjs.map +1 -1
- package/dist/esm/controllers/stripe.controller.mjs +86 -2
- package/dist/esm/controllers/stripe.controller.mjs.map +1 -1
- package/dist/esm/controllers/translation.controller.mjs +2 -0
- package/dist/esm/controllers/translation.controller.mjs.map +1 -1
- package/dist/esm/emails/InviteUserEmail.mjs +1541 -1
- package/dist/esm/emails/InviteUserEmail.mjs.map +1 -1
- package/dist/esm/emails/MagicLinkEmail.mjs +1128 -1
- package/dist/esm/emails/MagicLinkEmail.mjs.map +1 -1
- package/dist/esm/emails/OAuthTokenCreatedEmail.mjs +1389 -1
- package/dist/esm/emails/OAuthTokenCreatedEmail.mjs.map +1 -1
- package/dist/esm/emails/PasswordChangeConfirmation.mjs +814 -1
- package/dist/esm/emails/PasswordChangeConfirmation.mjs.map +1 -1
- package/dist/esm/emails/ResetUserPassword.mjs +1132 -1
- package/dist/esm/emails/ResetUserPassword.mjs.map +1 -1
- package/dist/esm/emails/SubscriptionPaymentCancellation.mjs +913 -1
- package/dist/esm/emails/SubscriptionPaymentCancellation.mjs.map +1 -1
- package/dist/esm/emails/SubscriptionPaymentError.mjs +908 -1
- package/dist/esm/emails/SubscriptionPaymentError.mjs.map +1 -1
- package/dist/esm/emails/SubscriptionPaymentSuccess.mjs +935 -1
- package/dist/esm/emails/SubscriptionPaymentSuccess.mjs.map +1 -1
- package/dist/esm/emails/ValidateUserEmail.mjs +1111 -1
- package/dist/esm/emails/ValidateUserEmail.mjs.map +1 -1
- package/dist/esm/emails/Welcome.mjs +1004 -1
- package/dist/esm/emails/Welcome.mjs.map +1 -1
- package/dist/esm/emails/index.mjs +7 -7
- package/dist/esm/index.mjs +8 -2
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/middlewares/oAuth2.middleware.mjs +2 -2
- package/dist/esm/middlewares/oAuth2.middleware.mjs.map +1 -1
- package/dist/esm/routes/audit.routes.mjs +5 -4
- package/dist/esm/routes/audit.routes.mjs.map +1 -1
- package/dist/esm/routes/dictionary.routes.mjs +4 -3
- package/dist/esm/routes/dictionary.routes.mjs.map +1 -1
- package/dist/esm/routes/organization.routes.mjs +3 -2
- package/dist/esm/routes/organization.routes.mjs.map +1 -1
- package/dist/esm/routes/paramsSchemas.mjs +67 -0
- package/dist/esm/routes/paramsSchemas.mjs.map +1 -0
- package/dist/esm/routes/project.routes.mjs +2 -1
- package/dist/esm/routes/project.routes.mjs.map +1 -1
- package/dist/esm/routes/showcaseProject.routes.mjs +5 -4
- package/dist/esm/routes/showcaseProject.routes.mjs.map +1 -1
- package/dist/esm/routes/stripe.routes.mjs +19 -1
- package/dist/esm/routes/stripe.routes.mjs.map +1 -1
- package/dist/esm/routes/tags.routes.mjs +3 -2
- package/dist/esm/routes/tags.routes.mjs.map +1 -1
- package/dist/esm/routes/translate.routes.mjs +6 -5
- package/dist/esm/routes/translate.routes.mjs.map +1 -1
- package/dist/esm/routes/user.routes.mjs +5 -4
- package/dist/esm/routes/user.routes.mjs.map +1 -1
- package/dist/esm/schemas/oAuth2.schema.mjs +1 -1
- package/dist/esm/schemas/oAuth2.schema.mjs.map +1 -1
- package/dist/esm/services/email.service.mjs +338 -38
- package/dist/esm/services/email.service.mjs.map +1 -1
- package/dist/esm/services/oAuth2.service.mjs +20 -2
- package/dist/esm/services/oAuth2.service.mjs.map +1 -1
- package/dist/esm/services/subscription.service.mjs +5 -2
- package/dist/esm/services/subscription.service.mjs.map +1 -1
- package/dist/esm/utils/AI/askDocQuestion/embeddings/docs/en/benchmark/solid.json +4990 -0
- package/dist/esm/utils/AI/askDocQuestion/embeddings/docs/en/benchmark/svelte.json +4987 -0
- package/dist/esm/utils/AI/askDocQuestion/embeddings/docs/en/benchmark/vue.json +4975 -0
- package/dist/esm/utils/AI/askDocQuestion/embeddings/docs/en/intlayer_with_astro_lit.json +9936 -8930
- package/dist/esm/utils/AI/askDocQuestion/embeddings/docs/en/intlayer_with_astro_vanilla.json +7963 -6949
- package/dist/esm/utils/AI/askDocQuestion/embeddings/docs/en/readme.json +12908 -12288
- package/dist/esm/utils/auth/getAuth.mjs +6 -0
- package/dist/esm/utils/auth/getAuth.mjs.map +1 -1
- package/dist/esm/utils/errors/errorCodes.mjs +3917 -287
- package/dist/esm/utils/errors/errorCodes.mjs.map +1 -1
- package/dist/esm/utils/mongoDB/connectDB.mjs +5 -0
- package/dist/esm/utils/mongoDB/connectDB.mjs.map +1 -1
- package/dist/esm/utils/oAuth2.mjs +6 -2
- package/dist/esm/utils/oAuth2.mjs.map +1 -1
- package/dist/esm/utils/plan.mjs +13 -1
- package/dist/esm/utils/plan.mjs.map +1 -1
- package/dist/types/controllers/oAuth2.controller.d.ts +11 -1
- package/dist/types/controllers/oAuth2.controller.d.ts.map +1 -1
- package/dist/types/controllers/stripe.controller.d.ts +22 -2
- package/dist/types/controllers/stripe.controller.d.ts.map +1 -1
- package/dist/types/controllers/translation.controller.d.ts.map +1 -1
- package/dist/types/emails/InviteUserEmail.d.ts +181 -1
- package/dist/types/emails/InviteUserEmail.d.ts.map +1 -1
- package/dist/types/emails/MagicLinkEmail.d.ts +106 -1
- package/dist/types/emails/MagicLinkEmail.d.ts.map +1 -1
- package/dist/types/emails/OAuthTokenCreatedEmail.d.ts +166 -1
- package/dist/types/emails/OAuthTokenCreatedEmail.d.ts.map +1 -1
- package/dist/types/emails/PasswordChangeConfirmation.d.ts +91 -1
- package/dist/types/emails/PasswordChangeConfirmation.d.ts.map +1 -1
- package/dist/types/emails/ResetUserPassword.d.ts +106 -1
- package/dist/types/emails/ResetUserPassword.d.ts.map +1 -1
- package/dist/types/emails/SubscriptionPaymentCancellation.d.ts +151 -1
- package/dist/types/emails/SubscriptionPaymentCancellation.d.ts.map +1 -1
- package/dist/types/emails/SubscriptionPaymentError.d.ts +151 -1
- package/dist/types/emails/SubscriptionPaymentError.d.ts.map +1 -1
- package/dist/types/emails/SubscriptionPaymentSuccess.d.ts +151 -1
- package/dist/types/emails/SubscriptionPaymentSuccess.d.ts.map +1 -1
- package/dist/types/emails/ValidateUserEmail.d.ts +106 -1
- package/dist/types/emails/ValidateUserEmail.d.ts.map +1 -1
- package/dist/types/emails/Welcome.d.ts +106 -1
- package/dist/types/emails/Welcome.d.ts.map +1 -1
- package/dist/types/emails/index.d.ts +7 -7
- package/dist/types/export.d.ts +3 -3
- package/dist/types/middlewares/oAuth2.middleware.d.ts.map +1 -1
- package/dist/types/routes/audit.routes.d.ts.map +1 -1
- package/dist/types/routes/dictionary.routes.d.ts.map +1 -1
- package/dist/types/routes/organization.routes.d.ts.map +1 -1
- package/dist/types/routes/paramsSchemas.d.ts +102 -0
- package/dist/types/routes/paramsSchemas.d.ts.map +1 -0
- package/dist/types/routes/project.routes.d.ts.map +1 -1
- package/dist/types/routes/showcaseProject.routes.d.ts.map +1 -1
- package/dist/types/routes/stripe.routes.d.ts +15 -0
- package/dist/types/routes/stripe.routes.d.ts.map +1 -1
- package/dist/types/routes/tags.routes.d.ts.map +1 -1
- package/dist/types/routes/translate.routes.d.ts.map +1 -1
- package/dist/types/routes/user.routes.d.ts.map +1 -1
- package/dist/types/schemas/dictionary.schema.d.ts +8 -8
- package/dist/types/schemas/discussion.schema.d.ts +8 -8
- package/dist/types/schemas/organization.schema.d.ts +5 -5
- package/dist/types/schemas/plans.schema.d.ts +7 -7
- package/dist/types/schemas/project.schema.d.ts +9 -9
- package/dist/types/schemas/session.schema.d.ts +7 -7
- package/dist/types/schemas/showcaseProject.schema.d.ts +18 -18
- package/dist/types/schemas/tag.schema.d.ts +7 -7
- package/dist/types/services/email.service.d.ts.map +1 -1
- package/dist/types/services/oAuth2.service.d.ts +6 -1
- package/dist/types/services/oAuth2.service.d.ts.map +1 -1
- package/dist/types/types/plan.types.d.ts +2 -2
- package/dist/types/utils/errors/errorCodes.d.ts +3634 -4
- package/dist/types/utils/errors/errorCodes.d.ts.map +1 -1
- package/dist/types/utils/mongoDB/connectDB.d.ts.map +1 -1
- package/dist/types/utils/oAuth2.d.ts +3 -1
- package/dist/types/utils/oAuth2.d.ts.map +1 -1
- package/dist/types/utils/plan.d.ts +2 -1
- package/dist/types/utils/plan.d.ts.map +1 -1
- package/package.json +13 -12
|
@@ -96,6 +96,12 @@ const getAuth = (dbClient) => {
|
|
|
96
96
|
session: {
|
|
97
97
|
modelName: "sessions",
|
|
98
98
|
id: "id",
|
|
99
|
+
expiresIn: 3600 * 24 * 30,
|
|
100
|
+
updateAge: 3600 * 24,
|
|
101
|
+
cookieCache: {
|
|
102
|
+
enabled: false,
|
|
103
|
+
maxAge: 300
|
|
104
|
+
},
|
|
99
105
|
additionalFields: {
|
|
100
106
|
activeOrganizationId: {
|
|
101
107
|
type: "string",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getAuth.mjs","names":[],"sources":["../../../../src/utils/auth/getAuth.ts"],"sourcesContent":["import { passkey } from '@better-auth/passkey';\nimport { sso } from '@better-auth/sso';\nimport { sendVerificationUpdate } from '@controllers/user.controller';\nimport { logger } from '@logger';\nimport { sendEmail } from '@services/email.service';\nimport { getOrganizationById } from '@services/organization.service';\nimport { getProjectById } from '@services/project.service';\nimport { getUserById } from '@services/user.service';\nimport { mapOrganizationToAPI } from '@utils/mapper/organization';\nimport { mapProjectToAPI } from '@utils/mapper/project';\nimport { mapSessionToAPI } from '@utils/mapper/session';\nimport { mapUserToAPI } from '@utils/mapper/user';\nimport type { OmitId } from '@utils/mongoDB/types';\nimport {\n computeEffectivePermission,\n getSessionRoles,\n intersectPermissions,\n} from '@utils/permissions';\nimport { betterAuth } from 'better-auth';\nimport { mongodbAdapter } from 'better-auth/adapters/mongodb';\nimport { createAuthMiddleware } from 'better-auth/api';\nimport { customSession, lastLoginMethod, twoFactor } from 'better-auth/plugins';\nimport { magicLink } from 'better-auth/plugins/magic-link';\nimport type { MongoClient } from 'mongodb';\nimport type { OrganizationAPI } from '@/types/organization.types';\nimport type { ProjectAPI } from '@/types/project.types';\nimport type {\n Session,\n SessionContext,\n SessionDataApi,\n} from '@/types/session.types';\nimport type { User, UserAPI } from '@/types/user.types';\n\nexport type Auth = ReturnType<typeof betterAuth>;\n\n// Check if we are in production based on the domain or NODE_ENV\nconst isProd = process.env.DOMAIN !== 'localhost';\n\nexport const formatSession = (session: SessionContext): OmitId<Session> => {\n const roles = getSessionRoles(session);\n let permissions = computeEffectivePermission(roles);\n\n // Intersect in the case a Access Token try to override the permissions\n if (session.permissions) {\n permissions = intersectPermissions(permissions, session.permissions);\n }\n\n const resultSession = {\n session: session.session,\n user: session.user,\n organization: session.organization,\n project: session.project,\n authType: 'session',\n permissions,\n roles,\n } as OmitId<Session>;\n\n return resultSession;\n};\n\nexport const getAuth = (dbClient: MongoClient): Auth => {\n if (!dbClient) {\n throw new Error('MongoDB connection not established');\n }\n\n const auth = betterAuth({\n appName: 'Intlayer',\n\n baseURL: process.env.BACKEND_URL,\n\n database: mongodbAdapter(dbClient.db()),\n\n /**\n * User model\n */\n user: {\n modelName: 'users',\n },\n\n databaseHooks: {\n user: {\n create: {\n // Runs once, immediately after the INSERT\n after: async (user) => {\n if (!user?.emailVerified) return;\n\n await sendEmail({\n type: 'welcome',\n to: user.email,\n username: user.name ?? user.email.split('@')[0],\n loginLink: `${process.env.APP_URL}/auth/login`,\n locale: (user as any).lang,\n });\n logger.info('Welcome e‑mail delivered', {\n email: user.email,\n });\n },\n },\n },\n },\n\n hooks: {\n after: createAuthMiddleware(async (ctx) => {\n const { path, context } = ctx;\n\n const newUser = context.newSession?.user;\n const existingUser = context.session?.user;\n const user = newUser ?? existingUser;\n\n if (!user) return;\n\n if (path.includes('/verify-email')) {\n sendVerificationUpdate(user as unknown as User);\n logger.info('SSE verification update sent', {\n email: user.email,\n userId: user.id,\n });\n\n await sendEmail({\n type: 'welcome',\n to: user.email,\n username: user.name ?? user.email.split('@')[0],\n loginLink: `${process.env.APP_URL}/auth/login`,\n locale: (user as any).lang,\n });\n logger.info('Welcome e‑mail delivered', {\n email: user.email,\n });\n }\n }),\n },\n\n advanced: {\n crossSubDomainCookies: {\n enabled: isProd,\n domain: isProd ? process.env.DOMAIN : undefined,\n additionalCookies: ['session_token'],\n },\n cookiePrefix: 'intlayer',\n cookies: {\n session_token: {\n name: 'session_token',\n attributes: {\n httpOnly: true,\n secure: isProd,\n sameSite: 'lax',\n },\n },\n },\n },\n\n secret: process.env.BETTER_AUTH_SECRET as string,\n session: {\n modelName: 'sessions',\n id: 'id',\n\n additionalFields: {\n activeOrganizationId: { type: 'string', nullable: true, input: false },\n activeProjectId: { type: 'string', nullable: true, input: false },\n },\n },\n\n plugins: [\n customSession(async ({ session }) => {\n const typedSession = session as unknown as SessionDataApi;\n\n let userAPI: UserAPI | null = null;\n let organizationAPI: OrganizationAPI | null = null;\n let projectAPI: ProjectAPI | null = null;\n\n if (typedSession.userId) {\n const userData = await getUserById(typedSession.userId);\n\n if (userData) {\n userAPI = mapUserToAPI(userData);\n }\n }\n\n if (typedSession.activeOrganizationId) {\n // activeOrganizationId may be stored as a BSON ObjectId in MongoDB\n // (legacy data), so we normalize it to a string before querying.\n const rawOrgId = typedSession.activeOrganizationId as any;\n const orgIdStr: string | null =\n typeof rawOrgId === 'string'\n ? rawOrgId\n : rawOrgId.buffer instanceof Uint8Array\n ? Buffer.from(rawOrgId.buffer).toString('hex')\n : null;\n\n if (!orgIdStr) {\n typedSession.activeOrganizationId = undefined;\n typedSession.activeProjectId = undefined;\n }\n\n const orgData = orgIdStr ? await getOrganizationById(orgIdStr) : null;\n\n if (orgData) {\n organizationAPI = mapOrganizationToAPI(orgData);\n } else {\n // Organization ID is present in session but not found in DB (Zombie session)\n // We detach the organization to prevent login errors\n await dbClient\n .db()\n .collection('sessions')\n .updateOne(\n { id: typedSession.id },\n {\n $set: { activeOrganizationId: null, activeProjectId: null },\n }\n );\n\n // Clear it locally so the current request proceeds without error\n typedSession.activeOrganizationId = undefined;\n typedSession.activeProjectId = undefined;\n }\n }\n if (typedSession.activeProjectId) {\n const rawProjectId = typedSession.activeProjectId as any;\n const projectIdStr: string | null =\n typeof rawProjectId === 'string'\n ? rawProjectId\n : rawProjectId.buffer instanceof Uint8Array\n ? Buffer.from(rawProjectId.buffer).toString('hex')\n : null;\n const projectData = projectIdStr\n ? await getProjectById(projectIdStr)\n : null;\n\n if (projectData) {\n projectAPI = mapProjectToAPI(projectData);\n } else {\n // Organization ID is present in session but not found in DB (Zombie session)\n // We detach the organization to prevent login errors\n await dbClient\n .db()\n .collection('sessions')\n .updateOne(\n { id: typedSession.id },\n {\n $set: { activeProjectId: null },\n }\n );\n\n // Clear it locally so the current request proceeds without error\n typedSession.activeProjectId = undefined;\n }\n }\n\n const sessionWithNoPermission: SessionContext = {\n session: typedSession,\n user: userAPI!,\n organization: organizationAPI ?? null,\n project: projectAPI ?? null,\n authType: 'session',\n };\n\n const formattedSession = formatSession(sessionWithNoPermission);\n\n return mapSessionToAPI(formattedSession);\n }),\n lastLoginMethod({\n storeInDatabase: true, // adds user.lastLoginMethod in DB and session\n schema: {\n user: {\n lastLoginMethod: 'lastLoginMethod', // Custom field name\n },\n },\n customResolveMethod: (context) => {\n // When user clicks the magic link\n if (context.path === '/magic-link/verify') {\n return 'magic-link';\n }\n\n // Fallback to default behavior for everything else\n return null;\n },\n }),\n passkey({\n rpID: process.env.DOMAIN,\n rpName: 'Intlayer',\n }),\n twoFactor(),\n magicLink({\n sendMagicLink: async ({ email, url }) => {\n logger.info('sending magic link', { email, url });\n await sendEmail({\n type: 'magicLink',\n to: email,\n username: email.split('@')[0],\n magicLink: url,\n });\n },\n }),\n sso({\n organizationProvisioning: {},\n }),\n ],\n\n emailAndPassword: {\n enabled: true,\n disableSignUp: false,\n requireEmailVerification: true,\n minPasswordLength: 8,\n maxPasswordLength: 128,\n autoSignIn: true,\n sendResetPassword: async ({ user, token }) => {\n logger.info('sending reset password email', { email: user.email });\n await sendEmail({\n type: 'resetPassword',\n to: user.email,\n username: user.name ?? user.email.split('@')[0],\n resetLink: `${process.env.APP_URL}/auth/password/reset?token=${token}`,\n });\n },\n resetPasswordTokenExpiresIn: 3600,\n },\n\n emailVerification: {\n autoSignInAfterVerification: true,\n sendOnSignIn: true,\n sendVerificationEmail: async ({ user, url }) => {\n logger.info('sending verification email', { email: user.email });\n await sendEmail({\n type: 'validate',\n to: user.email,\n username: user.name ?? user.email.split('@')[0],\n validationLink: url,\n });\n },\n },\n\n trustedOrigins: [\n process.env.WEBSITE_URL,\n process.env.APP_URL,\n process.env.SHOWCASE_URL,\n ].filter(Boolean) as string[],\n\n accountLinking: {\n enabled: true, // allow linking in general\n trustedProviders: [\n 'google',\n 'github',\n 'linkedin',\n 'gitlab',\n 'atlassian',\n 'microsoft',\n 'email-password',\n 'magic-link',\n 'passkey',\n ],\n },\n socialProviders: {\n google: {\n clientId: process.env.GOOGLE_CLIENT_ID as string,\n clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,\n },\n github: {\n clientId: process.env.GITHUB_CLIENT_ID as string,\n clientSecret: process.env.GITHUB_CLIENT_SECRET as string,\n },\n atlassian: {\n clientId: process.env.ATLASSIAN_CLIENT_ID as string,\n clientSecret: process.env.ATLASSIAN_CLIENT_SECRET as string,\n },\n gitlab: {\n clientId: process.env.GITLAB_CLIENT_ID as string,\n clientSecret: process.env.GITLAB_CLIENT_SECRET as string,\n },\n linkedin: {\n clientId: process.env.LINKEDIN_CLIENT_ID as string,\n clientSecret: process.env.LINKEDIN_CLIENT_SECRET as string,\n },\n microsoft: {\n clientId: process.env.MICROSOFT_CLIENT_ID as string,\n clientSecret: process.env.MICROSOFT_CLIENT_SECRET as string,\n },\n // socialProviders: {\n // apple: {\n // clientId: process.env.APPLE_CLIENT_ID as string,\n // clientSecret: process.env.APPLE_CLIENT_SECRET as string,\n // // Optional\n // appBundleIdentifier: process.env\n // .APPLE_APP_BUNDLE_IDENTIFIER as string,\n // },\n // },\n // // Add appleid.apple.com to trustedOrigins for Sign In with Apple flows\n // trustedOrigins: ['https://appleid.apple.com'],\n },\n\n logger: {\n log: (level, message, ...args) => logger[level](message, ...args),\n },\n });\n\n return auth;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"getAuth.mjs","names":[],"sources":["../../../../src/utils/auth/getAuth.ts"],"sourcesContent":["import { passkey } from '@better-auth/passkey';\nimport { sso } from '@better-auth/sso';\nimport { sendVerificationUpdate } from '@controllers/user.controller';\nimport { logger } from '@logger';\nimport { sendEmail } from '@services/email.service';\nimport { getOrganizationById } from '@services/organization.service';\nimport { getProjectById } from '@services/project.service';\nimport { getUserById } from '@services/user.service';\nimport { mapOrganizationToAPI } from '@utils/mapper/organization';\nimport { mapProjectToAPI } from '@utils/mapper/project';\nimport { mapSessionToAPI } from '@utils/mapper/session';\nimport { mapUserToAPI } from '@utils/mapper/user';\nimport type { OmitId } from '@utils/mongoDB/types';\nimport {\n computeEffectivePermission,\n getSessionRoles,\n intersectPermissions,\n} from '@utils/permissions';\nimport { betterAuth } from 'better-auth';\nimport { mongodbAdapter } from 'better-auth/adapters/mongodb';\nimport { createAuthMiddleware } from 'better-auth/api';\nimport { customSession, lastLoginMethod, twoFactor } from 'better-auth/plugins';\nimport { magicLink } from 'better-auth/plugins/magic-link';\nimport type { MongoClient } from 'mongodb';\nimport type { OrganizationAPI } from '@/types/organization.types';\nimport type { ProjectAPI } from '@/types/project.types';\nimport type {\n Session,\n SessionContext,\n SessionDataApi,\n} from '@/types/session.types';\nimport type { User, UserAPI } from '@/types/user.types';\n\nexport type Auth = ReturnType<typeof betterAuth>;\n\n// Check if we are in production based on the domain or NODE_ENV\nconst isProd = process.env.DOMAIN !== 'localhost';\n\nexport const formatSession = (session: SessionContext): OmitId<Session> => {\n const roles = getSessionRoles(session);\n let permissions = computeEffectivePermission(roles);\n\n // Intersect in the case a Access Token try to override the permissions\n if (session.permissions) {\n permissions = intersectPermissions(permissions, session.permissions);\n }\n\n const resultSession = {\n session: session.session,\n user: session.user,\n organization: session.organization,\n project: session.project,\n authType: 'session',\n permissions,\n roles,\n } as OmitId<Session>;\n\n return resultSession;\n};\n\nexport const getAuth = (dbClient: MongoClient): Auth => {\n if (!dbClient) {\n throw new Error('MongoDB connection not established');\n }\n\n const auth = betterAuth({\n appName: 'Intlayer',\n\n baseURL: process.env.BACKEND_URL,\n\n database: mongodbAdapter(dbClient.db()),\n\n /**\n * User model\n */\n user: {\n modelName: 'users',\n },\n\n databaseHooks: {\n user: {\n create: {\n // Runs once, immediately after the INSERT\n after: async (user) => {\n if (!user?.emailVerified) return;\n\n await sendEmail({\n type: 'welcome',\n to: user.email,\n username: user.name ?? user.email.split('@')[0],\n loginLink: `${process.env.APP_URL}/auth/login`,\n locale: (user as any).lang,\n });\n logger.info('Welcome e‑mail delivered', {\n email: user.email,\n });\n },\n },\n },\n },\n\n hooks: {\n after: createAuthMiddleware(async (ctx) => {\n const { path, context } = ctx;\n\n const newUser = context.newSession?.user;\n const existingUser = context.session?.user;\n const user = newUser ?? existingUser;\n\n if (!user) return;\n\n if (path.includes('/verify-email')) {\n sendVerificationUpdate(user as unknown as User);\n logger.info('SSE verification update sent', {\n email: user.email,\n userId: user.id,\n });\n\n await sendEmail({\n type: 'welcome',\n to: user.email,\n username: user.name ?? user.email.split('@')[0],\n loginLink: `${process.env.APP_URL}/auth/login`,\n locale: (user as any).lang,\n });\n logger.info('Welcome e‑mail delivered', {\n email: user.email,\n });\n }\n }),\n },\n\n advanced: {\n crossSubDomainCookies: {\n enabled: isProd,\n domain: isProd ? process.env.DOMAIN : undefined,\n additionalCookies: ['session_token'],\n },\n cookiePrefix: 'intlayer',\n cookies: {\n session_token: {\n name: 'session_token',\n attributes: {\n httpOnly: true,\n secure: isProd,\n sameSite: 'lax',\n },\n },\n },\n },\n\n secret: process.env.BETTER_AUTH_SECRET as string,\n session: {\n modelName: 'sessions',\n id: 'id',\n\n // Session lives for 30 days; each access made more than 1 day after the\n // last refresh slides the expiry forward, so an active user effectively\n // stays signed in indefinitely.\n expiresIn: 60 * 60 * 24 * 30,\n updateAge: 60 * 60 * 24,\n\n // Cache the session in a signed cookie for 5 minutes to avoid hitting\n // Mongo on every request while still picking up updateAge refreshes.\n cookieCache: {\n enabled: false,\n maxAge: 5 * 60,\n },\n\n additionalFields: {\n activeOrganizationId: { type: 'string', nullable: true, input: false },\n activeProjectId: { type: 'string', nullable: true, input: false },\n },\n },\n\n plugins: [\n customSession(async ({ session }) => {\n const typedSession = session as unknown as SessionDataApi;\n\n let userAPI: UserAPI | null = null;\n let organizationAPI: OrganizationAPI | null = null;\n let projectAPI: ProjectAPI | null = null;\n\n if (typedSession.userId) {\n const userData = await getUserById(typedSession.userId);\n\n if (userData) {\n userAPI = mapUserToAPI(userData);\n }\n }\n\n if (typedSession.activeOrganizationId) {\n // activeOrganizationId may be stored as a BSON ObjectId in MongoDB\n // (legacy data), so we normalize it to a string before querying.\n const rawOrgId = typedSession.activeOrganizationId as any;\n const orgIdStr: string | null =\n typeof rawOrgId === 'string'\n ? rawOrgId\n : rawOrgId.buffer instanceof Uint8Array\n ? Buffer.from(rawOrgId.buffer).toString('hex')\n : null;\n\n if (!orgIdStr) {\n typedSession.activeOrganizationId = undefined;\n typedSession.activeProjectId = undefined;\n }\n\n const orgData = orgIdStr ? await getOrganizationById(orgIdStr) : null;\n\n if (orgData) {\n organizationAPI = mapOrganizationToAPI(orgData);\n } else {\n // Organization ID is present in session but not found in DB (Zombie session)\n // We detach the organization to prevent login errors\n await dbClient\n .db()\n .collection('sessions')\n .updateOne(\n { id: typedSession.id },\n {\n $set: { activeOrganizationId: null, activeProjectId: null },\n }\n );\n\n // Clear it locally so the current request proceeds without error\n typedSession.activeOrganizationId = undefined;\n typedSession.activeProjectId = undefined;\n }\n }\n if (typedSession.activeProjectId) {\n const rawProjectId = typedSession.activeProjectId as any;\n const projectIdStr: string | null =\n typeof rawProjectId === 'string'\n ? rawProjectId\n : rawProjectId.buffer instanceof Uint8Array\n ? Buffer.from(rawProjectId.buffer).toString('hex')\n : null;\n const projectData = projectIdStr\n ? await getProjectById(projectIdStr)\n : null;\n\n if (projectData) {\n projectAPI = mapProjectToAPI(projectData);\n } else {\n // Organization ID is present in session but not found in DB (Zombie session)\n // We detach the organization to prevent login errors\n await dbClient\n .db()\n .collection('sessions')\n .updateOne(\n { id: typedSession.id },\n {\n $set: { activeProjectId: null },\n }\n );\n\n // Clear it locally so the current request proceeds without error\n typedSession.activeProjectId = undefined;\n }\n }\n\n const sessionWithNoPermission: SessionContext = {\n session: typedSession,\n user: userAPI!,\n organization: organizationAPI ?? null,\n project: projectAPI ?? null,\n authType: 'session',\n };\n\n const formattedSession = formatSession(sessionWithNoPermission);\n\n return mapSessionToAPI(formattedSession);\n }),\n lastLoginMethod({\n storeInDatabase: true, // adds user.lastLoginMethod in DB and session\n schema: {\n user: {\n lastLoginMethod: 'lastLoginMethod', // Custom field name\n },\n },\n customResolveMethod: (context) => {\n // When user clicks the magic link\n if (context.path === '/magic-link/verify') {\n return 'magic-link';\n }\n\n // Fallback to default behavior for everything else\n return null;\n },\n }),\n passkey({\n rpID: process.env.DOMAIN,\n rpName: 'Intlayer',\n }),\n twoFactor(),\n magicLink({\n sendMagicLink: async ({ email, url }) => {\n logger.info('sending magic link', { email, url });\n await sendEmail({\n type: 'magicLink',\n to: email,\n username: email.split('@')[0],\n magicLink: url,\n });\n },\n }),\n sso({\n organizationProvisioning: {},\n }),\n ],\n\n emailAndPassword: {\n enabled: true,\n disableSignUp: false,\n requireEmailVerification: true,\n minPasswordLength: 8,\n maxPasswordLength: 128,\n autoSignIn: true,\n sendResetPassword: async ({ user, token }) => {\n logger.info('sending reset password email', { email: user.email });\n await sendEmail({\n type: 'resetPassword',\n to: user.email,\n username: user.name ?? user.email.split('@')[0],\n resetLink: `${process.env.APP_URL}/auth/password/reset?token=${token}`,\n });\n },\n resetPasswordTokenExpiresIn: 3600,\n },\n\n emailVerification: {\n autoSignInAfterVerification: true,\n sendOnSignIn: true,\n sendVerificationEmail: async ({ user, url }) => {\n logger.info('sending verification email', { email: user.email });\n await sendEmail({\n type: 'validate',\n to: user.email,\n username: user.name ?? user.email.split('@')[0],\n validationLink: url,\n });\n },\n },\n\n trustedOrigins: [\n process.env.WEBSITE_URL,\n process.env.APP_URL,\n process.env.SHOWCASE_URL,\n ].filter(Boolean) as string[],\n\n accountLinking: {\n enabled: true, // allow linking in general\n trustedProviders: [\n 'google',\n 'github',\n 'linkedin',\n 'gitlab',\n 'atlassian',\n 'microsoft',\n 'email-password',\n 'magic-link',\n 'passkey',\n ],\n },\n socialProviders: {\n google: {\n clientId: process.env.GOOGLE_CLIENT_ID as string,\n clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,\n },\n github: {\n clientId: process.env.GITHUB_CLIENT_ID as string,\n clientSecret: process.env.GITHUB_CLIENT_SECRET as string,\n },\n atlassian: {\n clientId: process.env.ATLASSIAN_CLIENT_ID as string,\n clientSecret: process.env.ATLASSIAN_CLIENT_SECRET as string,\n },\n gitlab: {\n clientId: process.env.GITLAB_CLIENT_ID as string,\n clientSecret: process.env.GITLAB_CLIENT_SECRET as string,\n },\n linkedin: {\n clientId: process.env.LINKEDIN_CLIENT_ID as string,\n clientSecret: process.env.LINKEDIN_CLIENT_SECRET as string,\n },\n microsoft: {\n clientId: process.env.MICROSOFT_CLIENT_ID as string,\n clientSecret: process.env.MICROSOFT_CLIENT_SECRET as string,\n },\n // socialProviders: {\n // apple: {\n // clientId: process.env.APPLE_CLIENT_ID as string,\n // clientSecret: process.env.APPLE_CLIENT_SECRET as string,\n // // Optional\n // appBundleIdentifier: process.env\n // .APPLE_APP_BUNDLE_IDENTIFIER as string,\n // },\n // },\n // // Add appleid.apple.com to trustedOrigins for Sign In with Apple flows\n // trustedOrigins: ['https://appleid.apple.com'],\n },\n\n logger: {\n log: (level, message, ...args) => logger[level](message, ...args),\n },\n });\n\n return auth;\n};\n"],"mappings":"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"}
|