chore: import async_hooks per conditional exports (#6630)

This commit is contained in:
Alex Yang
2025-12-10 13:55:24 +09:00
committed by GitHub
parent c55603ddc9
commit bf5fbd48b1
8 changed files with 60 additions and 48 deletions

View File

@@ -25,6 +25,12 @@
"./async_hooks": {
"dev-source": "./src/async_hooks/index.ts",
"types": "./dist/async_hooks/index.d.mts",
"node": "./dist/async_hooks/index.mjs",
"deno": "./dist/async_hooks/index.mjs",
"bun": "./dist/async_hooks/index.mjs",
"edge": "./dist/async_hooks/pure.index.mjs",
"workerd": "./dist/async_hooks/index.mjs",
"browser": "./dist/async_hooks/pure.index.mjs",
"default": "./dist/async_hooks/index.mjs"
},
"./context": {

View File

@@ -1,12 +0,0 @@
import { expect, test, vi } from "vitest";
vi.mock(import("node:async_hooks"), () => {
throw new Error("Doesn't work with convex");
});
test("should work with convex", async () => {
vi.stubEnv("CONVEX_CLOUD_URL", "https://convex.com");
vi.stubEnv("CONVEX_SITE_URL", "http://test.com");
const { getAsyncLocalStorage } = await import(".");
await expect(getAsyncLocalStorage()).to.resolves.toBeDefined();
});

View File

@@ -1,34 +1,7 @@
import type { AsyncLocalStorage } from "node:async_hooks";
import { env } from "../env";
export type { AsyncLocalStorage };
/**
* Due to the lack of AsyncLocalStorage in some environments (like Convex),
*
* We assume serverless functions are short-lived and single-threaded, so we can use a simple polyfill.
*/
class AsyncLocalStoragePolyfill<T> {
#current: T | undefined = undefined;
run(store: T, fn: () => unknown): unknown {
const prev = this.#current;
this.#current = store;
const result = fn();
if (result instanceof Promise) {
return result.finally(() => {
this.#current = prev;
});
}
this.#current = prev;
return result;
}
getStore(): T | undefined {
return this.#current;
}
}
const AsyncLocalStoragePromise: Promise<typeof AsyncLocalStorage | null> =
import(
/* @vite-ignore */
@@ -43,9 +16,6 @@ const AsyncLocalStoragePromise: Promise<typeof AsyncLocalStorage | null> =
if (typeof window !== "undefined") {
return null;
}
if (env["CONVEX_CLOUD_URL"] || env["CONVEX_SITE_URL"]) {
return AsyncLocalStoragePolyfill;
}
console.warn(
"[better-auth] Warning: AsyncLocalStorage is not available in this environment. Some features may not work as expected.",
);

View File

@@ -0,0 +1,46 @@
import type { AsyncLocalStorage } from "node:async_hooks";
/**
* Due to the lack of AsyncLocalStorage in some environments (like Convex),
*
* We assume serverless functions are short-lived and single-threaded, so we can use a simple polyfill.
*/
class AsyncLocalStoragePolyfill<T> {
#current: T | undefined = undefined;
run(store: T, fn: () => unknown): unknown {
const prev = this.#current;
this.#current = store;
const result = fn();
if (result instanceof Promise) {
return result.finally(() => {
this.#current = prev;
});
}
this.#current = prev;
return result;
}
getStore(): T | undefined {
return this.#current;
}
}
const AsyncLocalStoragePromise: Promise<typeof AsyncLocalStorage | null> =
Promise.resolve().then(() => {
if ("AsyncLocalStorage" in globalThis) {
return (globalThis as any).AsyncLocalStorage;
}
return AsyncLocalStoragePolyfill;
});
export async function getAsyncLocalStorage(): Promise<
typeof AsyncLocalStorage
> {
const mod = await AsyncLocalStoragePromise;
if (mod === null) {
throw new Error("getAsyncLocalStorage is only available in server code");
} else {
return mod;
}
}

View File

@@ -1,6 +1,6 @@
import type { AsyncLocalStorage } from "@better-auth/core/async_hooks";
import { getAsyncLocalStorage } from "@better-auth/core/async_hooks";
import type { EndpointContext, InputContext } from "better-call";
import type { AsyncLocalStorage } from "../async_hooks";
import { getAsyncLocalStorage } from "../async_hooks";
import type { AuthContext } from "../types";
export type AuthEndpointContext = Partial<

View File

@@ -1,5 +1,5 @@
import type { AsyncLocalStorage } from "../async_hooks";
import { getAsyncLocalStorage } from "../async_hooks";
import type { AsyncLocalStorage } from "@better-auth/core/async_hooks";
import { getAsyncLocalStorage } from "@better-auth/core/async_hooks";
export type RequestStateWeakMap = WeakMap<object, any>;

View File

@@ -1,5 +1,5 @@
import type { AsyncLocalStorage } from "../async_hooks";
import { getAsyncLocalStorage } from "../async_hooks";
import type { AsyncLocalStorage } from "@better-auth/core/async_hooks";
import { getAsyncLocalStorage } from "@better-auth/core/async_hooks";
import type { DBAdapter, DBTransactionAdapter } from "../db/adapter";
let currentAdapterAsyncStorage: AsyncLocalStorage<DBTransactionAdapter> | null =

View File

@@ -8,6 +8,7 @@ export default defineConfig({
"./src/db/index.ts",
"./src/db/adapter/index.ts",
"./src/async_hooks/index.ts",
"./src/async_hooks/pure.index.ts",
"./src/context/index.ts",
"./src/env/index.ts",
"./src/oauth2/index.ts",
@@ -16,5 +17,6 @@ export default defineConfig({
"./src/utils/index.ts",
"./src/error/index.ts",
],
external: ["@better-auth/core/async_hooks"],
clean: true,
});