@gatwech/core 0.0.11 → 1.0.0-beta.18
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/dist/api/index.d.mts +2 -2
- package/dist/context/index.d.mts +2 -2
- package/dist/db/adapter/index.d.mts +2 -2
- package/dist/db/index.d.mts +2 -2
- package/dist/env/index.d.mts +1 -1
- package/dist/env/index.mjs +1 -1
- package/dist/{env-JMSMESs1.mjs → env-4_Lym7sj.mjs} +7 -7
- package/dist/index-65G5U5DB.d.mts +3002 -0
- package/dist/{index-DLP-K0uY.d.mts → index-CmdhhvA2.d.mts} +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/oauth2/index.d.mts +2 -2
- package/dist/social-providers/index.d.mts +3 -3
- package/dist/social-providers/index.mjs +71 -2412
- package/dist/src/api/index.d.ts +119 -0
- package/dist/src/async_hooks/index.d.ts +6 -0
- package/dist/src/context/endpoint-context.d.ts +14 -0
- package/dist/src/context/index.d.ts +3 -0
- package/dist/src/context/request-state.d.ts +13 -0
- package/dist/src/context/transaction.d.ts +11 -0
- package/dist/src/db/adapter/index.d.ts +401 -0
- package/{src/db/index.ts → dist/src/db/index.d.ts} +2 -18
- package/dist/src/db/plugin.d.ts +10 -0
- package/dist/src/db/schema/account.d.ts +22 -0
- package/dist/src/db/schema/rate-limit.d.ts +10 -0
- package/dist/src/db/schema/session.d.ts +17 -0
- package/dist/src/db/schema/shared.d.ts +6 -0
- package/dist/src/db/schema/user.d.ts +16 -0
- package/{src/db/schema/verification.ts → dist/src/db/schema/verification.d.ts} +8 -8
- package/dist/src/db/type.d.ts +159 -0
- package/dist/src/env/color-depth.d.ts +1 -0
- package/dist/src/env/env-impl.d.ts +29 -0
- package/dist/src/env/index.d.ts +3 -0
- package/dist/src/env/logger.d.ts +50 -0
- package/dist/src/error/codes.d.ts +27 -0
- package/dist/src/error/index.d.ts +4 -0
- package/dist/src/oauth2/client-credentials-token.d.ts +21 -0
- package/dist/src/oauth2/create-authorization-url.d.ts +21 -0
- package/dist/src/oauth2/index.d.ts +6 -0
- package/dist/src/oauth2/oauth-provider.d.ts +178 -0
- package/dist/src/oauth2/refresh-access-token.d.ts +20 -0
- package/dist/src/oauth2/utils.d.ts +3 -0
- package/dist/src/oauth2/validate-authorization-code.d.ts +28 -0
- package/dist/src/social-providers/github.d.ts +89 -0
- package/dist/src/social-providers/google.d.ts +82 -0
- package/dist/src/social-providers/index.d.ts +93 -0
- package/dist/src/types/context.d.ts +177 -0
- package/dist/src/types/cookie.d.ts +15 -0
- package/dist/src/types/helper.d.ts +9 -0
- package/dist/src/types/index.d.ts +7 -0
- package/dist/src/types/init-options.d.ts +1140 -0
- package/dist/src/types/plugin-client.d.ts +88 -0
- package/dist/src/types/plugin.d.ts +120 -0
- package/dist/src/utils/error-codes.d.ts +9 -0
- package/package.json +11 -5
- package/.turbo/turbo-build.log +0 -42
- package/dist/index-DjrJweYn.d.mts +0 -7312
- package/src/api/index.ts +0 -57
- package/src/async_hooks/index.ts +0 -35
- package/src/context/endpoint-context.ts +0 -48
- package/src/context/index.ts +0 -21
- package/src/context/request-state.test.ts +0 -346
- package/src/context/request-state.ts +0 -75
- package/src/context/transaction.ts +0 -72
- package/src/db/adapter/index.ts +0 -466
- package/src/db/plugin.ts +0 -11
- package/src/db/schema/account.ts +0 -34
- package/src/db/schema/rate-limit.ts +0 -21
- package/src/db/schema/session.ts +0 -17
- package/src/db/schema/shared.ts +0 -7
- package/src/db/schema/user.ts +0 -16
- package/src/db/type.ts +0 -180
- package/src/env/color-depth.ts +0 -172
- package/src/env/env-impl.ts +0 -124
- package/src/env/index.ts +0 -23
- package/src/env/logger.test.ts +0 -33
- package/src/env/logger.ts +0 -145
- package/src/error/codes.ts +0 -31
- package/src/error/index.ts +0 -11
- package/src/oauth2/client-credentials-token.ts +0 -102
- package/src/oauth2/create-authorization-url.ts +0 -85
- package/src/oauth2/index.ts +0 -21
- package/src/oauth2/oauth-provider.ts +0 -211
- package/src/oauth2/refresh-access-token.ts +0 -124
- package/src/oauth2/utils.ts +0 -36
- package/src/oauth2/validate-authorization-code.ts +0 -154
- package/src/social-providers/apple.ts +0 -213
- package/src/social-providers/atlassian.ts +0 -132
- package/src/social-providers/cognito.ts +0 -269
- package/src/social-providers/discord.ts +0 -169
- package/src/social-providers/dropbox.ts +0 -112
- package/src/social-providers/facebook.ts +0 -204
- package/src/social-providers/figma.ts +0 -115
- package/src/social-providers/github.ts +0 -154
- package/src/social-providers/gitlab.ts +0 -152
- package/src/social-providers/google.ts +0 -171
- package/src/social-providers/huggingface.ts +0 -118
- package/src/social-providers/index.ts +0 -124
- package/src/social-providers/kakao.ts +0 -178
- package/src/social-providers/kick.ts +0 -92
- package/src/social-providers/line.ts +0 -169
- package/src/social-providers/linear.ts +0 -120
- package/src/social-providers/linkedin.ts +0 -110
- package/src/social-providers/microsoft-entra-id.ts +0 -245
- package/src/social-providers/naver.ts +0 -112
- package/src/social-providers/notion.ts +0 -108
- package/src/social-providers/paybin.ts +0 -122
- package/src/social-providers/paypal.ts +0 -263
- package/src/social-providers/polar.ts +0 -107
- package/src/social-providers/reddit.ts +0 -122
- package/src/social-providers/roblox.ts +0 -110
- package/src/social-providers/salesforce.ts +0 -159
- package/src/social-providers/slack.ts +0 -111
- package/src/social-providers/spotify.ts +0 -93
- package/src/social-providers/tiktok.ts +0 -210
- package/src/social-providers/twitch.ts +0 -111
- package/src/social-providers/twitter.ts +0 -198
- package/src/social-providers/vk.ts +0 -126
- package/src/social-providers/zoom.ts +0 -217
- package/src/types/context.ts +0 -269
- package/src/types/cookie.ts +0 -7
- package/src/types/helper.ts +0 -6
- package/src/types/index.ts +0 -21
- package/src/types/init-options.ts +0 -1346
- package/src/types/plugin-client.ts +0 -100
- package/src/types/plugin.ts +0 -158
- package/src/utils/error-codes.ts +0 -51
- package/tsconfig.json +0 -7
- package/tsdown.config.ts +0 -20
- /package/{src/index.ts → dist/src/index.d.ts} +0 -0
- /package/{src/utils/index.ts → dist/src/utils/index.d.ts} +0 -0
package/src/api/index.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createEndpoint,
|
|
3
|
-
createMiddleware,
|
|
4
|
-
type EndpointContext,
|
|
5
|
-
type EndpointOptions,
|
|
6
|
-
} from "better-call";
|
|
7
|
-
import { runWithEndpointContext } from "../context";
|
|
8
|
-
import type { AuthContext } from "../types";
|
|
9
|
-
|
|
10
|
-
export const optionsMiddleware = createMiddleware(async () => {
|
|
11
|
-
/**
|
|
12
|
-
* This will be passed on the instance of
|
|
13
|
-
* the context. Used to infer the type
|
|
14
|
-
* here.
|
|
15
|
-
*/
|
|
16
|
-
return {} as AuthContext;
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
export const createAuthMiddleware = createMiddleware.create({
|
|
20
|
-
use: [
|
|
21
|
-
optionsMiddleware,
|
|
22
|
-
/**
|
|
23
|
-
* Only use for post hooks
|
|
24
|
-
*/
|
|
25
|
-
createMiddleware(async () => {
|
|
26
|
-
return {} as {
|
|
27
|
-
returned?: unknown | undefined;
|
|
28
|
-
responseHeaders?: Headers | undefined;
|
|
29
|
-
};
|
|
30
|
-
}),
|
|
31
|
-
],
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
const use = [optionsMiddleware];
|
|
35
|
-
|
|
36
|
-
export const createAuthEndpoint = <
|
|
37
|
-
Path extends string,
|
|
38
|
-
Opts extends EndpointOptions,
|
|
39
|
-
R,
|
|
40
|
-
>(
|
|
41
|
-
path: Path,
|
|
42
|
-
options: Opts,
|
|
43
|
-
handler: (ctx: EndpointContext<Path, Opts, AuthContext>) => Promise<R>,
|
|
44
|
-
) => {
|
|
45
|
-
return createEndpoint(
|
|
46
|
-
path,
|
|
47
|
-
{
|
|
48
|
-
...options,
|
|
49
|
-
use: [...(options?.use || []), ...use],
|
|
50
|
-
},
|
|
51
|
-
// todo: prettify the code, we want to call `runWithEndpointContext` to top level
|
|
52
|
-
async (ctx) => runWithEndpointContext(ctx as any, () => handler(ctx)),
|
|
53
|
-
);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
export type AuthEndpoint = ReturnType<typeof createAuthEndpoint>;
|
|
57
|
-
export type AuthMiddleware = ReturnType<typeof createAuthMiddleware>;
|
package/src/async_hooks/index.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AsyncLocalStorage will be import directly in 1.5.x
|
|
3
|
-
*/
|
|
4
|
-
import type { AsyncLocalStorage } from "node:async_hooks";
|
|
5
|
-
|
|
6
|
-
// We only export the type here to avoid issues in environments where AsyncLocalStorage is not available.
|
|
7
|
-
export type { AsyncLocalStorage };
|
|
8
|
-
|
|
9
|
-
const AsyncLocalStoragePromise: Promise<typeof AsyncLocalStorage> = import(
|
|
10
|
-
/* @vite-ignore */
|
|
11
|
-
/* webpackIgnore: true */
|
|
12
|
-
"node:async_hooks"
|
|
13
|
-
)
|
|
14
|
-
.then((mod) => mod.AsyncLocalStorage)
|
|
15
|
-
.catch((err) => {
|
|
16
|
-
if ("AsyncLocalStorage" in globalThis) {
|
|
17
|
-
return (globalThis as any).AsyncLocalStorage;
|
|
18
|
-
}
|
|
19
|
-
console.warn(
|
|
20
|
-
"[payvo-auth] Warning: AsyncLocalStorage is not available in this environment. Some features may not work as expected."
|
|
21
|
-
);
|
|
22
|
-
console.warn(
|
|
23
|
-
"[payvo-auth] Please read more about this warning at https://payvo-auth.com/docs/installation#mount-handler"
|
|
24
|
-
);
|
|
25
|
-
console.warn(
|
|
26
|
-
"[payvo-auth] If you are using Cloudflare Workers, please see: https://developers.cloudflare.com/workers/configuration/compatibility-flags/#nodejs-compatibility-flag"
|
|
27
|
-
);
|
|
28
|
-
throw err;
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
export async function getAsyncLocalStorage(): Promise<
|
|
32
|
-
typeof AsyncLocalStorage
|
|
33
|
-
> {
|
|
34
|
-
return AsyncLocalStoragePromise;
|
|
35
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type { EndpointContext, InputContext } from "better-call";
|
|
2
|
-
import { type AsyncLocalStorage, getAsyncLocalStorage } from "../async_hooks";
|
|
3
|
-
import type { AuthContext } from "../types";
|
|
4
|
-
|
|
5
|
-
export type AuthEndpointContext = Partial<
|
|
6
|
-
InputContext<string, any> & EndpointContext<string, any>
|
|
7
|
-
> & {
|
|
8
|
-
context: AuthContext;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
let currentContextAsyncStorage: AsyncLocalStorage<AuthEndpointContext> | null =
|
|
12
|
-
null;
|
|
13
|
-
|
|
14
|
-
const ensureAsyncStorage = async () => {
|
|
15
|
-
if (!currentContextAsyncStorage) {
|
|
16
|
-
const AsyncLocalStorage = await getAsyncLocalStorage();
|
|
17
|
-
currentContextAsyncStorage = new AsyncLocalStorage();
|
|
18
|
-
}
|
|
19
|
-
return currentContextAsyncStorage;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* This is for internal use only. Most users should use `getCurrentAuthContext` instead.
|
|
24
|
-
*
|
|
25
|
-
* It is exposed for advanced use cases where you need direct access to the AsyncLocalStorage instance.
|
|
26
|
-
*/
|
|
27
|
-
export async function getCurrentAuthContextAsyncLocalStorage() {
|
|
28
|
-
return ensureAsyncStorage();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export async function getCurrentAuthContext(): Promise<AuthEndpointContext> {
|
|
32
|
-
const als = await ensureAsyncStorage();
|
|
33
|
-
const context = als.getStore();
|
|
34
|
-
if (!context) {
|
|
35
|
-
throw new Error(
|
|
36
|
-
"No auth context found. Please make sure you are calling this function within a `runWithEndpointContext` callback.",
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
return context;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export async function runWithEndpointContext<T>(
|
|
43
|
-
context: AuthEndpointContext,
|
|
44
|
-
fn: () => T,
|
|
45
|
-
): Promise<T> {
|
|
46
|
-
const als = await ensureAsyncStorage();
|
|
47
|
-
return als.run(context, fn);
|
|
48
|
-
}
|
package/src/context/index.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export {
|
|
2
|
-
type AuthEndpointContext,
|
|
3
|
-
getCurrentAuthContext,
|
|
4
|
-
getCurrentAuthContextAsyncLocalStorage,
|
|
5
|
-
runWithEndpointContext,
|
|
6
|
-
} from "./endpoint-context";
|
|
7
|
-
export {
|
|
8
|
-
defineRequestState,
|
|
9
|
-
getCurrentRequestState,
|
|
10
|
-
getRequestStateAsyncLocalStorage,
|
|
11
|
-
hasRequestState,
|
|
12
|
-
type RequestState,
|
|
13
|
-
type RequestStateWeakMap,
|
|
14
|
-
runWithRequestState,
|
|
15
|
-
} from "./request-state";
|
|
16
|
-
export {
|
|
17
|
-
getCurrentAdapter,
|
|
18
|
-
getCurrentDBAdapterAsyncLocalStorage,
|
|
19
|
-
runWithAdapter,
|
|
20
|
-
runWithTransaction,
|
|
21
|
-
} from "./transaction";
|
|
@@ -1,346 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import z from "zod";
|
|
3
|
-
import {
|
|
4
|
-
defineRequestState,
|
|
5
|
-
getCurrentRequestState,
|
|
6
|
-
hasRequestState,
|
|
7
|
-
type RequestStateWeakMap,
|
|
8
|
-
runWithRequestState,
|
|
9
|
-
} from "./request-state";
|
|
10
|
-
|
|
11
|
-
describe("request-state", () => {
|
|
12
|
-
describe("runWithRequestState", () => {
|
|
13
|
-
it("should execute function within request state context", async () => {
|
|
14
|
-
const store: RequestStateWeakMap = new WeakMap();
|
|
15
|
-
const result = await runWithRequestState(store, async () => {
|
|
16
|
-
const hasStore = await hasRequestState();
|
|
17
|
-
expect(hasStore).toBe(true);
|
|
18
|
-
return "success";
|
|
19
|
-
});
|
|
20
|
-
expect(result).toBe("success");
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it("should isolate request states between concurrent requests", async () => {
|
|
24
|
-
const store1: RequestStateWeakMap = new WeakMap();
|
|
25
|
-
const store2: RequestStateWeakMap = new WeakMap();
|
|
26
|
-
|
|
27
|
-
const schema = z.object({ id: z.string() });
|
|
28
|
-
const { get, set } = defineRequestState(schema);
|
|
29
|
-
|
|
30
|
-
const [result1, result2] = await Promise.all([
|
|
31
|
-
runWithRequestState(store1, async () => {
|
|
32
|
-
await set({ id: "store1" });
|
|
33
|
-
// Simulate some async work
|
|
34
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
35
|
-
return await get();
|
|
36
|
-
}),
|
|
37
|
-
runWithRequestState(store2, async () => {
|
|
38
|
-
await set({ id: "store2" });
|
|
39
|
-
// Simulate some async work
|
|
40
|
-
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
41
|
-
return await get();
|
|
42
|
-
}),
|
|
43
|
-
]);
|
|
44
|
-
|
|
45
|
-
expect(result1).toEqual({ id: "store1" });
|
|
46
|
-
expect(result2).toEqual({ id: "store2" });
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("should support nested async operations", async () => {
|
|
50
|
-
const store: RequestStateWeakMap = new WeakMap();
|
|
51
|
-
const schema = z.object({ value: z.number() });
|
|
52
|
-
const { get, set } = defineRequestState(schema);
|
|
53
|
-
|
|
54
|
-
await runWithRequestState(store, async () => {
|
|
55
|
-
await set({ value: 1 });
|
|
56
|
-
|
|
57
|
-
const nestedResult = await (async () => {
|
|
58
|
-
const current = await get();
|
|
59
|
-
await set({ value: (current?.value || 0) + 1 });
|
|
60
|
-
return await get();
|
|
61
|
-
})();
|
|
62
|
-
|
|
63
|
-
expect(nestedResult).toEqual({ value: 2 });
|
|
64
|
-
expect(await get()).toEqual({ value: 2 });
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
describe("hasRequestState", () => {
|
|
70
|
-
it("should return false when not in request state context", async () => {
|
|
71
|
-
const hasStore = await hasRequestState();
|
|
72
|
-
expect(hasStore).toBe(false);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it("should return true when in request state context", async () => {
|
|
76
|
-
const store: RequestStateWeakMap = new WeakMap();
|
|
77
|
-
await runWithRequestState(store, async () => {
|
|
78
|
-
const hasStore = await hasRequestState();
|
|
79
|
-
expect(hasStore).toBe(true);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
describe("getCurrentRequestState", () => {
|
|
85
|
-
it("should throw error when not in request state context", async () => {
|
|
86
|
-
await expect(getCurrentRequestState()).rejects.toThrow(
|
|
87
|
-
"No request state found",
|
|
88
|
-
);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it("should return the current store when in context", async () => {
|
|
92
|
-
const store: RequestStateWeakMap = new WeakMap();
|
|
93
|
-
await runWithRequestState(store, async () => {
|
|
94
|
-
const currentStore = await getCurrentRequestState();
|
|
95
|
-
expect(currentStore).toBe(store);
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
describe("defineRequestState", () => {
|
|
101
|
-
it("should create a request state with get and set methods", async () => {
|
|
102
|
-
const schema = z.object({ name: z.string() });
|
|
103
|
-
const store = defineRequestState(schema);
|
|
104
|
-
|
|
105
|
-
expect(store).toHaveProperty("get");
|
|
106
|
-
expect(store).toHaveProperty("set");
|
|
107
|
-
expect(typeof store.get).toBe("function");
|
|
108
|
-
expect(typeof store.set).toBe("function");
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it("should store and retrieve values using schema as key", async () => {
|
|
112
|
-
const requestState: RequestStateWeakMap = new WeakMap();
|
|
113
|
-
const schema = z.object({ name: z.string(), age: z.number() });
|
|
114
|
-
const { get, set } = defineRequestState(schema);
|
|
115
|
-
|
|
116
|
-
await runWithRequestState(requestState, async () => {
|
|
117
|
-
await set({ name: "John", age: 30 });
|
|
118
|
-
const value = await get();
|
|
119
|
-
expect(value).toEqual({ name: "John", age: 30 });
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it("should return undefined for unset values", async () => {
|
|
124
|
-
const requestState: RequestStateWeakMap = new WeakMap();
|
|
125
|
-
const schema = z.object({ value: z.string() });
|
|
126
|
-
const { get } = defineRequestState(schema);
|
|
127
|
-
|
|
128
|
-
await runWithRequestState(requestState, async () => {
|
|
129
|
-
const value = await get();
|
|
130
|
-
expect(value).toBeUndefined();
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it("should handle multiple stores with different schemas independently", async () => {
|
|
135
|
-
const requestState: RequestStateWeakMap = new WeakMap();
|
|
136
|
-
const schema1 = z.object({ type: z.literal("user") });
|
|
137
|
-
const schema2 = z.object({ type: z.literal("session") });
|
|
138
|
-
|
|
139
|
-
const store1 = defineRequestState(schema1);
|
|
140
|
-
const store2 = defineRequestState(schema2);
|
|
141
|
-
|
|
142
|
-
await runWithRequestState(requestState, async () => {
|
|
143
|
-
await store1.set({ type: "user" });
|
|
144
|
-
await store2.set({ type: "session" });
|
|
145
|
-
|
|
146
|
-
expect(await store1.get()).toEqual({ type: "user" });
|
|
147
|
-
expect(await store2.get()).toEqual({ type: "session" });
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it("should overwrite existing values", async () => {
|
|
152
|
-
const requestState: RequestStateWeakMap = new WeakMap();
|
|
153
|
-
const schema = z.object({ count: z.number() });
|
|
154
|
-
const { get, set } = defineRequestState(schema);
|
|
155
|
-
|
|
156
|
-
await runWithRequestState(requestState, async () => {
|
|
157
|
-
await set({ count: 1 });
|
|
158
|
-
expect(await get()).toEqual({ count: 1 });
|
|
159
|
-
|
|
160
|
-
await set({ count: 2 });
|
|
161
|
-
expect(await get()).toEqual({ count: 2 });
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
it("should handle complex nested objects", async () => {
|
|
166
|
-
const requestState: RequestStateWeakMap = new WeakMap();
|
|
167
|
-
const schema = z.object({
|
|
168
|
-
user: z.object({
|
|
169
|
-
id: z.string(),
|
|
170
|
-
profile: z.object({
|
|
171
|
-
name: z.string(),
|
|
172
|
-
settings: z.object({
|
|
173
|
-
theme: z.string(),
|
|
174
|
-
}),
|
|
175
|
-
}),
|
|
176
|
-
}),
|
|
177
|
-
});
|
|
178
|
-
const { get, set } = defineRequestState(schema);
|
|
179
|
-
|
|
180
|
-
await runWithRequestState(requestState, async () => {
|
|
181
|
-
const value = {
|
|
182
|
-
user: {
|
|
183
|
-
id: "123",
|
|
184
|
-
profile: {
|
|
185
|
-
name: "John",
|
|
186
|
-
settings: {
|
|
187
|
-
theme: "dark",
|
|
188
|
-
},
|
|
189
|
-
},
|
|
190
|
-
},
|
|
191
|
-
};
|
|
192
|
-
await set(value);
|
|
193
|
-
expect(await get()).toEqual(value);
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it("should handle arrays in schema", async () => {
|
|
198
|
-
const requestState: RequestStateWeakMap = new WeakMap();
|
|
199
|
-
const schema = z.object({
|
|
200
|
-
tags: z.array(z.string()),
|
|
201
|
-
scores: z.array(z.number()),
|
|
202
|
-
});
|
|
203
|
-
const { get, set } = defineRequestState(schema);
|
|
204
|
-
|
|
205
|
-
await runWithRequestState(requestState, async () => {
|
|
206
|
-
await set({ tags: ["auth", "oauth"], scores: [1, 2, 3] });
|
|
207
|
-
const value = await get();
|
|
208
|
-
expect(value).toEqual({ tags: ["auth", "oauth"], scores: [1, 2, 3] });
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
it("should throw error when accessing outside request state context", async () => {
|
|
213
|
-
const schema = z.object({ value: z.string() });
|
|
214
|
-
const { get, set } = defineRequestState(schema);
|
|
215
|
-
|
|
216
|
-
await expect(get()).rejects.toThrow("No request state found");
|
|
217
|
-
await expect(set({ value: "test" })).rejects.toThrow(
|
|
218
|
-
"No request state found",
|
|
219
|
-
);
|
|
220
|
-
});
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
describe("type inference", () => {
|
|
224
|
-
it("should infer types from schema", async () => {
|
|
225
|
-
const requestState: RequestStateWeakMap = new WeakMap();
|
|
226
|
-
const schema = z.object({
|
|
227
|
-
id: z.string(),
|
|
228
|
-
count: z.number(),
|
|
229
|
-
active: z.boolean(),
|
|
230
|
-
});
|
|
231
|
-
const { get, set } = defineRequestState(schema);
|
|
232
|
-
|
|
233
|
-
await runWithRequestState(requestState, async () => {
|
|
234
|
-
// TypeScript should infer the correct types here
|
|
235
|
-
await set({ id: "123", count: 42, active: true });
|
|
236
|
-
const value = await get();
|
|
237
|
-
|
|
238
|
-
if (value) {
|
|
239
|
-
// These should all be properly typed
|
|
240
|
-
const id: string = value.id;
|
|
241
|
-
const count: number = value.count;
|
|
242
|
-
const active: boolean = value.active;
|
|
243
|
-
|
|
244
|
-
expect(id).toBe("123");
|
|
245
|
-
expect(count).toBe(42);
|
|
246
|
-
expect(active).toBe(true);
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
});
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
describe("error handling", () => {
|
|
253
|
-
it("should handle errors thrown within runWithRequestState", async () => {
|
|
254
|
-
const store: RequestStateWeakMap = new WeakMap();
|
|
255
|
-
|
|
256
|
-
await expect(
|
|
257
|
-
runWithRequestState(store, async () => {
|
|
258
|
-
throw new Error("Test error");
|
|
259
|
-
}),
|
|
260
|
-
).rejects.toThrow("Test error");
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
it("should clean up context after error", async () => {
|
|
264
|
-
const store: RequestStateWeakMap = new WeakMap();
|
|
265
|
-
|
|
266
|
-
try {
|
|
267
|
-
await runWithRequestState(store, async () => {
|
|
268
|
-
throw new Error("Test error");
|
|
269
|
-
});
|
|
270
|
-
} catch (e) {
|
|
271
|
-
// Error is expected
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// Should not have a store context after the error
|
|
275
|
-
const hasStore = await hasRequestState();
|
|
276
|
-
expect(hasStore).toBe(false);
|
|
277
|
-
});
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
describe("WeakMap behavior", () => {
|
|
281
|
-
it("should use schema objects as keys in WeakMap", async () => {
|
|
282
|
-
const store: RequestStateWeakMap = new WeakMap();
|
|
283
|
-
const schema1 = z.object({ value: z.string() });
|
|
284
|
-
const schema2 = z.object({ value: z.string() }); // Same structure, different instance
|
|
285
|
-
|
|
286
|
-
const store1 = defineRequestState(schema1);
|
|
287
|
-
const store2 = defineRequestState(schema2);
|
|
288
|
-
|
|
289
|
-
await runWithRequestState(store, async () => {
|
|
290
|
-
await store1.set({ value: "first" });
|
|
291
|
-
await store2.set({ value: "second" });
|
|
292
|
-
|
|
293
|
-
// Different schema instances should have different values
|
|
294
|
-
expect(await store1.get()).toEqual({ value: "first" });
|
|
295
|
-
expect(await store2.get()).toEqual({ value: "second" });
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
describe("concurrent request isolation", () => {
|
|
301
|
-
it("should maintain separate stores for 10 concurrent requests", async () => {
|
|
302
|
-
const schema = z.object({ requestId: z.number() });
|
|
303
|
-
const { get, set } = defineRequestState(schema);
|
|
304
|
-
|
|
305
|
-
const promises = Array.from({ length: 10 }, (_, i) => {
|
|
306
|
-
const store: RequestStateWeakMap = new WeakMap();
|
|
307
|
-
return runWithRequestState(store, async () => {
|
|
308
|
-
await set({ requestId: i });
|
|
309
|
-
// Simulate async work with varying delays
|
|
310
|
-
await new Promise((resolve) =>
|
|
311
|
-
setTimeout(resolve, Math.random() * 20),
|
|
312
|
-
);
|
|
313
|
-
const value = await get();
|
|
314
|
-
return value;
|
|
315
|
-
});
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
const results = await Promise.all(promises);
|
|
319
|
-
|
|
320
|
-
// Each request should have its own unique ID
|
|
321
|
-
results.forEach((result, index) => {
|
|
322
|
-
expect(result).toEqual({ requestId: index });
|
|
323
|
-
});
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
it("should handle rapid consecutive requests", async () => {
|
|
327
|
-
const schema = z.object({ counter: z.number() });
|
|
328
|
-
const { get, set } = defineRequestState(schema);
|
|
329
|
-
|
|
330
|
-
const results = await Promise.all(
|
|
331
|
-
Array.from({ length: 100 }, async (_, i) => {
|
|
332
|
-
const store: RequestStateWeakMap = new WeakMap();
|
|
333
|
-
return runWithRequestState(store, async () => {
|
|
334
|
-
await set({ counter: i });
|
|
335
|
-
return await get();
|
|
336
|
-
});
|
|
337
|
-
}),
|
|
338
|
-
);
|
|
339
|
-
|
|
340
|
-
// Each request should have its own counter value
|
|
341
|
-
results.forEach((result, index) => {
|
|
342
|
-
expect(result).toEqual({ counter: index });
|
|
343
|
-
});
|
|
344
|
-
});
|
|
345
|
-
});
|
|
346
|
-
});
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
2
|
-
import z from "zod";
|
|
3
|
-
import { type AsyncLocalStorage, getAsyncLocalStorage } from "../async_hooks";
|
|
4
|
-
|
|
5
|
-
export type RequestStateWeakMap = WeakMap<StandardSchemaV1, any>;
|
|
6
|
-
|
|
7
|
-
let requestStateAsyncStorage: AsyncLocalStorage<RequestStateWeakMap> | null =
|
|
8
|
-
null;
|
|
9
|
-
|
|
10
|
-
const ensureAsyncStorage = async () => {
|
|
11
|
-
if (!requestStateAsyncStorage) {
|
|
12
|
-
const AsyncLocalStorage = await getAsyncLocalStorage();
|
|
13
|
-
requestStateAsyncStorage = new AsyncLocalStorage();
|
|
14
|
-
}
|
|
15
|
-
return requestStateAsyncStorage;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export async function getRequestStateAsyncLocalStorage() {
|
|
19
|
-
return ensureAsyncStorage();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export async function hasRequestState() {
|
|
23
|
-
const als = await ensureAsyncStorage();
|
|
24
|
-
return als.getStore() !== undefined;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export async function getCurrentRequestState(): Promise<RequestStateWeakMap> {
|
|
28
|
-
const als = await ensureAsyncStorage();
|
|
29
|
-
const store = als.getStore();
|
|
30
|
-
if (!store) {
|
|
31
|
-
throw new Error(
|
|
32
|
-
"No request state found. Please make sure you are calling this function within a `runWithRequestState` callback.",
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
return store;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export async function runWithRequestState<T>(
|
|
39
|
-
store: RequestStateWeakMap,
|
|
40
|
-
fn: () => T,
|
|
41
|
-
): Promise<T> {
|
|
42
|
-
const als = await ensureAsyncStorage();
|
|
43
|
-
return als.run(store, fn);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface RequestState<T> {
|
|
47
|
-
get<S>(): Promise<S & T>;
|
|
48
|
-
set(value: T): Promise<void>;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function defineRequestState<T>(
|
|
52
|
-
schema?: StandardSchemaV1<T>,
|
|
53
|
-
): RequestState<T>;
|
|
54
|
-
export function defineRequestState<Schema extends StandardSchemaV1>(
|
|
55
|
-
schema?: Schema,
|
|
56
|
-
): RequestState<StandardSchemaV1.InferInput<Schema>>;
|
|
57
|
-
export function defineRequestState(
|
|
58
|
-
schema: StandardSchemaV1 = z.any(),
|
|
59
|
-
): RequestState<any> {
|
|
60
|
-
return {
|
|
61
|
-
async get() {
|
|
62
|
-
const store = await getCurrentRequestState();
|
|
63
|
-
return store.get(schema);
|
|
64
|
-
},
|
|
65
|
-
|
|
66
|
-
async set(value) {
|
|
67
|
-
const store = await getCurrentRequestState();
|
|
68
|
-
const parsedValue = await schema["~standard"].validate(value);
|
|
69
|
-
if (parsedValue.issues) {
|
|
70
|
-
throw new Error(`Invalid value: ${JSON.stringify(parsedValue.issues)}`);
|
|
71
|
-
}
|
|
72
|
-
store.set(schema, parsedValue.value);
|
|
73
|
-
},
|
|
74
|
-
};
|
|
75
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { type AsyncLocalStorage, getAsyncLocalStorage } from "../async_hooks";
|
|
2
|
-
import type { DBAdapter, DBTransactionAdapter } from "../db/adapter";
|
|
3
|
-
|
|
4
|
-
let currentAdapterAsyncStorage: AsyncLocalStorage<DBTransactionAdapter> | null =
|
|
5
|
-
null;
|
|
6
|
-
|
|
7
|
-
const ensureAsyncStorage = async () => {
|
|
8
|
-
if (!currentAdapterAsyncStorage) {
|
|
9
|
-
const AsyncLocalStorage = await getAsyncLocalStorage();
|
|
10
|
-
currentAdapterAsyncStorage = new AsyncLocalStorage();
|
|
11
|
-
}
|
|
12
|
-
return currentAdapterAsyncStorage;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* This is for internal use only. Most users should use `getCurrentAdapter` instead.
|
|
17
|
-
*
|
|
18
|
-
* It is exposed for advanced use cases where you need direct access to the AsyncLocalStorage instance.
|
|
19
|
-
*/
|
|
20
|
-
export const getCurrentDBAdapterAsyncLocalStorage = async () => {
|
|
21
|
-
return ensureAsyncStorage();
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export const getCurrentAdapter = async (
|
|
25
|
-
fallback: DBTransactionAdapter,
|
|
26
|
-
): Promise<DBTransactionAdapter> => {
|
|
27
|
-
return ensureAsyncStorage()
|
|
28
|
-
.then((als) => {
|
|
29
|
-
return als.getStore() || fallback;
|
|
30
|
-
})
|
|
31
|
-
.catch(() => {
|
|
32
|
-
return fallback;
|
|
33
|
-
});
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export const runWithAdapter = async <R>(
|
|
37
|
-
adapter: DBAdapter,
|
|
38
|
-
fn: () => R,
|
|
39
|
-
): Promise<R> => {
|
|
40
|
-
let called = true;
|
|
41
|
-
return ensureAsyncStorage()
|
|
42
|
-
.then((als) => {
|
|
43
|
-
called = true;
|
|
44
|
-
return als.run(adapter, fn);
|
|
45
|
-
})
|
|
46
|
-
.catch((err) => {
|
|
47
|
-
if (!called) {
|
|
48
|
-
return fn();
|
|
49
|
-
}
|
|
50
|
-
throw err;
|
|
51
|
-
});
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export const runWithTransaction = async <R>(
|
|
55
|
-
adapter: DBAdapter,
|
|
56
|
-
fn: () => R,
|
|
57
|
-
): Promise<R> => {
|
|
58
|
-
let called = true;
|
|
59
|
-
return ensureAsyncStorage()
|
|
60
|
-
.then((als) => {
|
|
61
|
-
called = true;
|
|
62
|
-
return adapter.transaction(async (trx) => {
|
|
63
|
-
return als.run(trx, fn);
|
|
64
|
-
});
|
|
65
|
-
})
|
|
66
|
-
.catch((err) => {
|
|
67
|
-
if (!called) {
|
|
68
|
-
return fn();
|
|
69
|
-
}
|
|
70
|
-
throw err;
|
|
71
|
-
});
|
|
72
|
-
};
|