{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/test-utils/index.ts"],"sourcesContent":["import type { BetterAuthOptions, BetterAuthPlugin } from \"@better-auth/core\";\nimport {\n\tcreateGetAuthHeaders,\n\tcreateGetCookies,\n\tcreateLogin,\n} from \"./auth-helpers\";\nimport {\n\tcreateAddMember,\n\tcreateDeleteOrganization,\n\tcreateDeleteUser,\n\tcreateSaveOrganization,\n\tcreateSaveUser,\n} from \"./db-helpers\";\nimport { createOrganizationFactory, createUserFactory } from \"./factories\";\nimport { createOTPStore } from \"./otp-sink\";\nimport type { TestHelpers, TestUtilsOptions } from \"./types\";\n\nexport type {\n\tLoginResult,\n\tTestCookie,\n\tTestHelpers,\n\tTestUtilsOptions,\n} from \"./types\";\n\ndeclare module \"@better-auth/core\" {\n\tinterface BetterAuthPluginRegistry<AuthOptions, Options> {\n\t\t\"test-utils\": {\n\t\t\tcreator: typeof testUtils;\n\t\t};\n\t}\n}\n\n/**\n * Test utilities plugin for Better Auth.\n *\n * Provides helpers for integration and E2E testing including:\n * - User/Organization factories (creates objects without DB writes)\n * - Database helpers (save, delete)\n * - Auth helpers (login, getAuthHeaders, getCookies)\n * - OTP capture (when captureOTP: true)\n *\n * @example\n * ```ts\n * import { betterAuth } from \"better-auth\";\n * import { testUtils } from \"better-auth/plugins\";\n *\n * export const auth = betterAuth({\n *   plugins: [\n *     testUtils({ captureOTP: true }),\n *   ],\n * });\n *\n * // In tests, access helpers via context:\n * const ctx = await auth.$context;\n * const test = ctx.test;\n *\n * const user = test.createUser({ email: \"test@example.com\" });\n * const savedUser = await test.saveUser(user);\n * const { headers, cookies } = await test.login({ userId: user.id });\n * ```\n */\nexport const testUtils = (options: TestUtilsOptions = {}) => {\n\treturn {\n\t\tid: \"test-utils\",\n\t\tinit(ctx) {\n\t\t\t// Check if organization plugin is present\n\t\t\tconst hasOrgPlugin = ctx.hasPlugin(\"organization\");\n\n\t\t\t// Build core helpers\n\t\t\tconst helpers: TestHelpers = {\n\t\t\t\t// Factories\n\t\t\t\tcreateUser: createUserFactory(ctx),\n\n\t\t\t\t// Database helpers\n\t\t\t\tsaveUser: createSaveUser(ctx),\n\t\t\t\tdeleteUser: createDeleteUser(ctx),\n\n\t\t\t\t// Auth helpers\n\t\t\t\tlogin: createLogin(ctx),\n\t\t\t\tgetAuthHeaders: createGetAuthHeaders(ctx),\n\t\t\t\tgetCookies: createGetCookies(ctx),\n\t\t\t};\n\n\t\t\t// Add organization helpers if plugin is present\n\t\t\tif (hasOrgPlugin) {\n\t\t\t\thelpers.createOrganization = createOrganizationFactory(ctx);\n\t\t\t\thelpers.saveOrganization = createSaveOrganization(ctx);\n\t\t\t\thelpers.deleteOrganization = createDeleteOrganization(ctx);\n\t\t\t\thelpers.addMember = createAddMember(ctx);\n\t\t\t}\n\n\t\t\t// Instance-scoped OTP store\n\t\t\tconst otpStore = createOTPStore();\n\n\t\t\t// Add OTP helpers if enabled\n\t\t\tif (options.captureOTP) {\n\t\t\t\thelpers.getOTP = otpStore.get;\n\t\t\t\thelpers.clearOTPs = otpStore.clear;\n\t\t\t}\n\n\t\t\t// Build database hooks for OTP capture if enabled\n\t\t\tconst databaseHooks = options.captureOTP\n\t\t\t\t? ({\n\t\t\t\t\t\tverification: {\n\t\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\t\tasync after(\n\t\t\t\t\t\t\t\t\tverification: {\n\t\t\t\t\t\t\t\t\t\tidentifier: string;\n\t\t\t\t\t\t\t\t\t\tvalue: string;\n\t\t\t\t\t\t\t\t\t} | null,\n\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\tif (verification?.value && verification?.identifier) {\n\t\t\t\t\t\t\t\t\t\t// Extract the actual OTP (before any encoding)\n\t\t\t\t\t\t\t\t\t\t// The format is typically \"otp:retryCount\" or just \"otp\"\n\t\t\t\t\t\t\t\t\t\tconst otpPart = verification.value.split(\":\")[0];\n\t\t\t\t\t\t\t\t\t\tif (otpPart) {\n\t\t\t\t\t\t\t\t\t\t\t// Extract base identifier (remove prefix like \"email-verification-otp-\")\n\t\t\t\t\t\t\t\t\t\t\tlet identifier = verification.identifier;\n\t\t\t\t\t\t\t\t\t\t\tconst prefixes = [\n\t\t\t\t\t\t\t\t\t\t\t\t\"email-verification-otp-\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"sign-in-otp-\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"forget-password-otp-\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"phone-verification-otp-\",\n\t\t\t\t\t\t\t\t\t\t\t];\n\t\t\t\t\t\t\t\t\t\t\tfor (const prefix of prefixes) {\n\t\t\t\t\t\t\t\t\t\t\t\tif (identifier.startsWith(prefix)) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tidentifier = identifier.slice(prefix.length);\n\t\t\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\totpStore.capture(identifier, otpPart);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t} satisfies BetterAuthOptions[\"databaseHooks\"])\n\t\t\t\t: null;\n\n\t\t\treturn {\n\t\t\t\tcontext: {\n\t\t\t\t\ttest: helpers,\n\t\t\t\t},\n\t\t\t\toptions: databaseHooks ? { databaseHooks } : undefined,\n\t\t\t};\n\t\t},\n\t\toptions,\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6DA,MAAa,aAAa,UAA4B,EAAE,KAAK;AAC5D,QAAO;EACN,IAAI;EACJ,KAAK,KAAK;GAET,MAAM,eAAe,IAAI,UAAU,eAAe;GAGlD,MAAM,UAAuB;IAE5B,YAAY,kBAAkB,IAAI;IAGlC,UAAU,eAAe,IAAI;IAC7B,YAAY,iBAAiB,IAAI;IAGjC,OAAO,YAAY,IAAI;IACvB,gBAAgB,qBAAqB,IAAI;IACzC,YAAY,iBAAiB,IAAI;IACjC;AAGD,OAAI,cAAc;AACjB,YAAQ,qBAAqB,0BAA0B,IAAI;AAC3D,YAAQ,mBAAmB,uBAAuB,IAAI;AACtD,YAAQ,qBAAqB,yBAAyB,IAAI;AAC1D,YAAQ,YAAY,gBAAgB,IAAI;;GAIzC,MAAM,WAAW,gBAAgB;AAGjC,OAAI,QAAQ,YAAY;AACvB,YAAQ,SAAS,SAAS;AAC1B,YAAQ,YAAY,SAAS;;GAI9B,MAAM,gBAAgB,QAAQ,aAC1B,EACD,cAAc,EACb,QAAQ,EACP,MAAM,MACL,cAIC;AACD,QAAI,cAAc,SAAS,cAAc,YAAY;KAGpD,MAAM,UAAU,aAAa,MAAM,MAAM,IAAI,CAAC;AAC9C,SAAI,SAAS;MAEZ,IAAI,aAAa,aAAa;AAO9B,WAAK,MAAM,UANM;OAChB;OACA;OACA;OACA;OACA,CAEA,KAAI,WAAW,WAAW,OAAO,EAAE;AAClC,oBAAa,WAAW,MAAM,OAAO,OAAO;AAC5C;;AAGF,eAAS,QAAQ,YAAY,QAAQ;;;MAIxC,EACD,EACD,GACA;AAEH,UAAO;IACN,SAAS,EACR,MAAM,SACN;IACD,SAAS,gBAAgB,EAAE,eAAe,GAAG;IAC7C;;EAEF;EACA"}