{"version":3,"file":"transaction.mjs","names":[],"sources":["../../src/context/transaction.ts"],"sourcesContent":["import type { AsyncLocalStorage } from \"node:async_hooks\";\nimport { getAsyncLocalStorage } from \"@better-auth/core/async_hooks\";\nimport type { DBAdapter, DBTransactionAdapter } from \"../db/adapter\";\nimport { __getBetterAuthGlobal } from \"./global\";\n\ntype HookContext = {\n\tadapter: DBTransactionAdapter;\n\tpendingHooks: Array<() => Promise<void>>;\n};\n\nconst ensureAsyncStorage = async () => {\n\tconst betterAuthGlobal = __getBetterAuthGlobal();\n\tif (!betterAuthGlobal.context.adapterAsyncStorage) {\n\t\tconst AsyncLocalStorage = await getAsyncLocalStorage();\n\t\tbetterAuthGlobal.context.adapterAsyncStorage = new AsyncLocalStorage();\n\t}\n\treturn betterAuthGlobal.context\n\t\t.adapterAsyncStorage as AsyncLocalStorage<HookContext>;\n};\n\n/**\n * This is for internal use only. Most users should use `getCurrentAdapter` instead.\n *\n * It is exposed for advanced use cases where you need direct access to the AsyncLocalStorage instance.\n */\nexport const getCurrentDBAdapterAsyncLocalStorage = async () => {\n\treturn ensureAsyncStorage();\n};\n\nexport const getCurrentAdapter = async (\n\tfallback: DBTransactionAdapter,\n): Promise<DBTransactionAdapter> => {\n\treturn ensureAsyncStorage()\n\t\t.then((als) => {\n\t\t\tconst store = als.getStore();\n\t\t\treturn store?.adapter || fallback;\n\t\t})\n\t\t.catch(() => {\n\t\t\treturn fallback;\n\t\t});\n};\n\nexport const runWithAdapter = async <R>(\n\tadapter: DBAdapter,\n\tfn: () => R,\n): Promise<R> => {\n\tlet called = false;\n\treturn ensureAsyncStorage()\n\t\t.then(async (als) => {\n\t\t\tcalled = true;\n\t\t\tconst pendingHooks: Array<() => Promise<void>> = [];\n\t\t\tlet result: Awaited<R>;\n\t\t\tlet error: unknown;\n\t\t\tlet hasError = false;\n\t\t\ttry {\n\t\t\t\tresult = await als.run({ adapter, pendingHooks }, fn);\n\t\t\t} catch (err) {\n\t\t\t\terror = err;\n\t\t\t\thasError = true;\n\t\t\t}\n\t\t\t// Execute pending hooks after the function completes (even if it threw)\n\t\t\tfor (const hook of pendingHooks) {\n\t\t\t\tawait hook();\n\t\t\t}\n\t\t\tif (hasError) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn result!;\n\t\t})\n\t\t.catch((err) => {\n\t\t\tif (!called) {\n\t\t\t\treturn fn();\n\t\t\t}\n\t\t\tthrow err;\n\t\t});\n};\n\nexport const runWithTransaction = async <R>(\n\tadapter: DBAdapter,\n\tfn: () => R,\n): Promise<R> => {\n\tlet called = true;\n\treturn ensureAsyncStorage()\n\t\t.then(async (als) => {\n\t\t\tcalled = true;\n\t\t\tconst pendingHooks: Array<() => Promise<void>> = [];\n\t\t\tlet result: Awaited<R>;\n\t\t\tlet error: unknown;\n\t\t\tlet hasError = false;\n\t\t\ttry {\n\t\t\t\tresult = await adapter.transaction(async (trx) => {\n\t\t\t\t\treturn als.run({ adapter: trx, pendingHooks }, fn);\n\t\t\t\t});\n\t\t\t} catch (e) {\n\t\t\t\thasError = true;\n\t\t\t\terror = e;\n\t\t\t}\n\t\t\tfor (const hook of pendingHooks) {\n\t\t\t\tawait hook();\n\t\t\t}\n\t\t\tif (hasError) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn result!;\n\t\t})\n\t\t.catch((err) => {\n\t\t\tif (!called) {\n\t\t\t\treturn fn();\n\t\t\t}\n\t\t\tthrow err;\n\t\t});\n};\n\n/**\n * Queue a hook to be executed after the current transaction commits.\n * If not in a transaction, the hook will execute immediately.\n */\nexport const queueAfterTransactionHook = async (\n\thook: () => Promise<void>,\n): Promise<void> => {\n\treturn ensureAsyncStorage()\n\t\t.then((als) => {\n\t\t\tconst store = als.getStore();\n\t\t\tif (store) {\n\t\t\t\t// We're in a transaction context, queue the hook\n\t\t\t\tstore.pendingHooks.push(hook);\n\t\t\t} else {\n\t\t\t\t// Not in a transaction, execute immediately\n\t\t\t\treturn hook();\n\t\t\t}\n\t\t})\n\t\t.catch(() => {\n\t\t\t// No async storage available, execute immediately\n\t\t\treturn hook();\n\t\t});\n};\n"],"mappings":";;;;AAUA,MAAM,qBAAqB,YAAY;CACtC,MAAM,mBAAmB,uBAAuB;AAChD,KAAI,CAAC,iBAAiB,QAAQ,qBAAqB;EAClD,MAAM,oBAAoB,MAAM,sBAAsB;AACtD,mBAAiB,QAAQ,sBAAsB,IAAI,mBAAmB;;AAEvE,QAAO,iBAAiB,QACtB;;;;;;;AAQH,MAAa,uCAAuC,YAAY;AAC/D,QAAO,oBAAoB;;AAG5B,MAAa,oBAAoB,OAChC,aACmC;AACnC,QAAO,oBAAoB,CACzB,MAAM,QAAQ;AAEd,SADc,IAAI,UAAU,EACd,WAAW;GACxB,CACD,YAAY;AACZ,SAAO;GACN;;AAGJ,MAAa,iBAAiB,OAC7B,SACA,OACgB;CAChB,IAAI,SAAS;AACb,QAAO,oBAAoB,CACzB,KAAK,OAAO,QAAQ;AACpB,WAAS;EACT,MAAM,eAA2C,EAAE;EACnD,IAAI;EACJ,IAAI;EACJ,IAAI,WAAW;AACf,MAAI;AACH,YAAS,MAAM,IAAI,IAAI;IAAE;IAAS;IAAc,EAAE,GAAG;WAC7C,KAAK;AACb,WAAQ;AACR,cAAW;;AAGZ,OAAK,MAAM,QAAQ,aAClB,OAAM,MAAM;AAEb,MAAI,SACH,OAAM;AAEP,SAAO;GACN,CACD,OAAO,QAAQ;AACf,MAAI,CAAC,OACJ,QAAO,IAAI;AAEZ,QAAM;GACL;;AAGJ,MAAa,qBAAqB,OACjC,SACA,OACgB;CAChB,IAAI,SAAS;AACb,QAAO,oBAAoB,CACzB,KAAK,OAAO,QAAQ;AACpB,WAAS;EACT,MAAM,eAA2C,EAAE;EACnD,IAAI;EACJ,IAAI;EACJ,IAAI,WAAW;AACf,MAAI;AACH,YAAS,MAAM,QAAQ,YAAY,OAAO,QAAQ;AACjD,WAAO,IAAI,IAAI;KAAE,SAAS;KAAK;KAAc,EAAE,GAAG;KACjD;WACM,GAAG;AACX,cAAW;AACX,WAAQ;;AAET,OAAK,MAAM,QAAQ,aAClB,OAAM,MAAM;AAEb,MAAI,SACH,OAAM;AAEP,SAAO;GACN,CACD,OAAO,QAAQ;AACf,MAAI,CAAC,OACJ,QAAO,IAAI;AAEZ,QAAM;GACL;;;;;;AAOJ,MAAa,4BAA4B,OACxC,SACmB;AACnB,QAAO,oBAAoB,CACzB,MAAM,QAAQ;EACd,MAAM,QAAQ,IAAI,UAAU;AAC5B,MAAI,MAEH,OAAM,aAAa,KAAK,KAAK;MAG7B,QAAO,MAAM;GAEb,CACD,YAAY;AAEZ,SAAO,MAAM;GACZ"}