jazz-tools 0.19.18 → 0.19.19
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/.svelte-kit/__package__/client.d.ts +29 -0
- package/.svelte-kit/__package__/client.d.ts.map +1 -0
- package/.svelte-kit/__package__/client.js +138 -0
- package/.svelte-kit/__package__/react.d.ts +28 -0
- package/.svelte-kit/__package__/react.d.ts.map +1 -0
- package/.svelte-kit/__package__/react.tsx +56 -0
- package/.svelte-kit/__package__/server.d.ts +34 -0
- package/.svelte-kit/__package__/server.d.ts.map +1 -0
- package/.svelte-kit/__package__/server.js +269 -0
- package/.svelte-kit/__package__/svelte.svelte +47 -0
- package/.svelte-kit/__package__/svelte.svelte.d.ts +693 -0
- package/.svelte-kit/__package__/svelte.svelte.d.ts.map +1 -0
- package/.svelte-kit/__package__/tests/TestAuthProviderWrapper.svelte +23 -0
- package/.svelte-kit/__package__/tests/TestAuthProviderWrapper.svelte.d.ts +691 -0
- package/.svelte-kit/__package__/tests/TestAuthProviderWrapper.svelte.d.ts.map +1 -0
- package/.svelte-kit/__package__/tests/client.test.d.ts +2 -0
- package/.svelte-kit/__package__/tests/client.test.d.ts.map +1 -0
- package/.svelte-kit/__package__/tests/client.test.js +404 -0
- package/.svelte-kit/__package__/tests/react.test.d.ts +2 -0
- package/.svelte-kit/__package__/tests/react.test.d.ts.map +1 -0
- package/.svelte-kit/__package__/tests/react.test.tsx +43 -0
- package/.svelte-kit/__package__/tests/server.test.d.ts +2 -0
- package/.svelte-kit/__package__/tests/server.test.d.ts.map +1 -0
- package/.svelte-kit/__package__/tests/server.test.js +417 -0
- package/.svelte-kit/__package__/tests/svelte.test.d.ts +2 -0
- package/.svelte-kit/__package__/tests/svelte.test.d.ts.map +1 -0
- package/.svelte-kit/__package__/tests/svelte.test.js +31 -0
- package/.turbo/turbo-build.log +63 -58
- package/CHANGELOG.md +15 -0
- package/dist/better-auth/auth/svelte.d.ts +693 -0
- package/dist/better-auth/auth/svelte.svelte +47 -0
- package/dist/better-auth/auth/tests/svelte.test.d.ts +2 -0
- package/dist/better-auth/auth/tests/svelte.test.d.ts.map +1 -0
- package/dist/browser/BrowserContextManager.d.ts +4 -4
- package/dist/browser/createBrowserContext.d.ts +4 -4
- package/dist/browser/createBrowserContext.d.ts.map +1 -1
- package/dist/browser/index.js +6 -0
- package/dist/browser/index.js.map +1 -1
- package/dist/{chunk-OH2GW5WP.js → chunk-PEHQ7TN2.js} +55 -23
- package/dist/chunk-PEHQ7TN2.js.map +1 -0
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/react-native/index.js +6 -0
- package/dist/react-native/index.js.map +1 -1
- package/dist/react-native-core/ReactNativeContextManager.d.ts +4 -4
- package/dist/react-native-core/index.js +6 -0
- package/dist/react-native-core/index.js.map +1 -1
- package/dist/react-native-core/platform.d.ts +4 -4
- package/dist/react-native-core/platform.d.ts.map +1 -1
- package/dist/testing.js +1 -1
- package/dist/tools/auth/clerk/types.d.ts +4 -4
- package/dist/tools/exports.d.ts +1 -1
- package/dist/tools/exports.d.ts.map +1 -1
- package/dist/tools/implementation/ContextManager.d.ts +3 -1
- package/dist/tools/implementation/ContextManager.d.ts.map +1 -1
- package/dist/tools/implementation/createContext.d.ts +8 -4
- package/dist/tools/implementation/createContext.d.ts.map +1 -1
- package/dist/tools/internal.d.ts +1 -0
- package/dist/tools/internal.d.ts.map +1 -1
- package/dist/tools/subscribe/JazzError.d.ts +9 -1
- package/dist/tools/subscribe/JazzError.d.ts.map +1 -1
- package/dist/tools/subscribe/SubscriptionScope.d.ts +2 -1
- package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
- package/dist/tools/types.d.ts +8 -1
- package/dist/tools/types.d.ts.map +1 -1
- package/package.json +13 -6
- package/src/better-auth/auth/svelte.svelte +47 -0
- package/src/better-auth/auth/tests/TestAuthProviderWrapper.svelte +23 -0
- package/src/better-auth/auth/tests/svelte.test.ts +35 -0
- package/src/browser/createBrowserContext.ts +6 -0
- package/src/react-core/tests/useSuspenseAccount.test.tsx +10 -5
- package/src/react-core/tests/useSuspenseCoState.test.tsx +17 -13
- package/src/react-native-core/platform.ts +6 -0
- package/src/tools/auth/clerk/tests/JazzClerkAuth.test.ts +33 -0
- package/src/tools/auth/clerk/types.ts +1 -1
- package/src/tools/exports.ts +1 -0
- package/src/tools/implementation/ContextManager.ts +21 -1
- package/src/tools/implementation/createContext.ts +18 -5
- package/src/tools/internal.ts +2 -0
- package/src/tools/subscribe/JazzError.ts +37 -1
- package/src/tools/subscribe/SubscriptionScope.ts +23 -20
- package/src/tools/tests/ContextManager.test.ts +75 -16
- package/src/tools/tests/createContext.test.ts +34 -1
- package/src/tools/types.ts +9 -0
- package/vitest.config.ts +15 -2
- package/.svelte-kit/__package__/Provider.svelte +0 -71
- package/.svelte-kit/__package__/Provider.svelte.d.ts +0 -19
- package/.svelte-kit/__package__/Provider.svelte.d.ts.map +0 -1
- package/.svelte-kit/__package__/auth/PasskeyAuth.svelte.d.ts +0 -11
- package/.svelte-kit/__package__/auth/PasskeyAuth.svelte.d.ts.map +0 -1
- package/.svelte-kit/__package__/auth/PasskeyAuth.svelte.js +0 -20
- package/.svelte-kit/__package__/auth/PasskeyAuthBasicUI.svelte +0 -81
- package/.svelte-kit/__package__/auth/PasskeyAuthBasicUI.svelte.d.ts +0 -9
- package/.svelte-kit/__package__/auth/PasskeyAuthBasicUI.svelte.d.ts.map +0 -1
- package/.svelte-kit/__package__/auth/PassphraseAuth.svelte.d.ts +0 -12
- package/.svelte-kit/__package__/auth/PassphraseAuth.svelte.d.ts.map +0 -1
- package/.svelte-kit/__package__/auth/PassphraseAuth.svelte.js +0 -30
- package/.svelte-kit/__package__/auth/index.d.ts +0 -4
- package/.svelte-kit/__package__/auth/index.d.ts.map +0 -1
- package/.svelte-kit/__package__/auth/index.js +0 -3
- package/.svelte-kit/__package__/auth/useIsAuthenticated.svelte.d.ts +0 -6
- package/.svelte-kit/__package__/auth/useIsAuthenticated.svelte.d.ts.map +0 -1
- package/.svelte-kit/__package__/auth/useIsAuthenticated.svelte.js +0 -22
- package/.svelte-kit/__package__/index.d.ts +0 -7
- package/.svelte-kit/__package__/index.d.ts.map +0 -1
- package/.svelte-kit/__package__/index.js +0 -6
- package/.svelte-kit/__package__/jazz.class.svelte.d.ts +0 -52
- package/.svelte-kit/__package__/jazz.class.svelte.d.ts.map +0 -1
- package/.svelte-kit/__package__/jazz.class.svelte.js +0 -185
- package/.svelte-kit/__package__/jazz.svelte.d.ts +0 -39
- package/.svelte-kit/__package__/jazz.svelte.d.ts.map +0 -1
- package/.svelte-kit/__package__/jazz.svelte.js +0 -63
- package/.svelte-kit/__package__/media/image.svelte +0 -135
- package/.svelte-kit/__package__/media/image.svelte.d.ts +0 -5
- package/.svelte-kit/__package__/media/image.svelte.d.ts.map +0 -1
- package/.svelte-kit/__package__/media/image.types.d.ts +0 -8
- package/.svelte-kit/__package__/media/image.types.d.ts.map +0 -1
- package/.svelte-kit/__package__/media/image.types.js +0 -1
- package/.svelte-kit/__package__/media/index.d.ts +0 -2
- package/.svelte-kit/__package__/media/index.d.ts.map +0 -1
- package/.svelte-kit/__package__/media/index.js +0 -1
- package/.svelte-kit/__package__/testing.d.ts +0 -10
- package/.svelte-kit/__package__/testing.d.ts.map +0 -1
- package/.svelte-kit/__package__/testing.js +0 -23
- package/.svelte-kit/__package__/tests/AccountCoState.svelte.test-d.d.ts +0 -2
- package/.svelte-kit/__package__/tests/AccountCoState.svelte.test-d.d.ts.map +0 -1
- package/.svelte-kit/__package__/tests/AccountCoState.svelte.test-d.js +0 -19
- package/.svelte-kit/__package__/tests/CoState.svelte.test-d.d.ts +0 -2
- package/.svelte-kit/__package__/tests/CoState.svelte.test-d.d.ts.map +0 -1
- package/.svelte-kit/__package__/tests/CoState.svelte.test-d.js +0 -16
- package/.svelte-kit/__package__/tests/CoState.svelte.test.d.ts +0 -2
- package/.svelte-kit/__package__/tests/CoState.svelte.test.d.ts.map +0 -1
- package/.svelte-kit/__package__/tests/CoState.svelte.test.js +0 -42
- package/.svelte-kit/__package__/tests/TestCoStateWrapper.svelte +0 -23
- package/.svelte-kit/__package__/tests/TestCoStateWrapper.svelte.d.ts +0 -12
- package/.svelte-kit/__package__/tests/TestCoStateWrapper.svelte.d.ts.map +0 -1
- package/.svelte-kit/__package__/tests/TestConnectionStatus.svelte +0 -8
- package/.svelte-kit/__package__/tests/TestConnectionStatus.svelte.d.ts +0 -27
- package/.svelte-kit/__package__/tests/TestConnectionStatus.svelte.d.ts.map +0 -1
- package/.svelte-kit/__package__/tests/media/image.svelte.test.d.ts +0 -2
- package/.svelte-kit/__package__/tests/media/image.svelte.test.d.ts.map +0 -1
- package/.svelte-kit/__package__/tests/media/image.svelte.test.js +0 -510
- package/.svelte-kit/__package__/tests/sync-connection-status.svelte.test.d.ts +0 -2
- package/.svelte-kit/__package__/tests/sync-connection-status.svelte.test.d.ts.map +0 -1
- package/.svelte-kit/__package__/tests/sync-connection-status.svelte.test.js +0 -47
- package/.svelte-kit/__package__/tests/testUtils.d.ts +0 -11
- package/.svelte-kit/__package__/tests/testUtils.d.ts.map +0 -1
- package/.svelte-kit/__package__/tests/testUtils.js +0 -17
- package/.svelte-kit/__package__/tests/types.d.ts +0 -3
- package/dist/chunk-OH2GW5WP.js.map +0 -1
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Account, AuthSecretStorage, JazzContextType } from "jazz-tools";
|
|
2
|
+
import type { jazzPlugin } from "./server.js";
|
|
3
|
+
/**
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* const auth = betterAuth({
|
|
7
|
+
* plugins: [jazzPluginClient()],
|
|
8
|
+
* });
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export declare const jazzPluginClient: () => {
|
|
12
|
+
id: "jazz-plugin";
|
|
13
|
+
$InferServerPlugin: ReturnType<typeof jazzPlugin>;
|
|
14
|
+
getActions: ($fetch: import("@better-fetch/fetch").BetterFetch, $store: import("better-auth").ClientStore) => {
|
|
15
|
+
jazz: {
|
|
16
|
+
setJazzContext: (context: JazzContextType<Account>) => void;
|
|
17
|
+
setAuthSecretStorage: (storage: AuthSecretStorage) => void;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
fetchPlugins: {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
hooks: {
|
|
24
|
+
onRequest<T extends Record<string, any>>(context: import("@better-fetch/fetch").RequestContext<T>): Promise<void>;
|
|
25
|
+
onSuccess(context: import("@better-fetch/fetch").SuccessContext<any>): Promise<void>;
|
|
26
|
+
};
|
|
27
|
+
}[];
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/better-auth/auth/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,OAAO,EACP,iBAAiB,EAEjB,eAAe,EAChB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAS9C;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB;;wBAmBC,UAAU,CAAC,OAAO,UAAU,CAAC;;;sCAIvB,eAAe,CAAC,OAAO,CAAC;4CAGlB,iBAAiB;;;;;;;;;;;CA6H1D,CAAC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
const SIGNUP_URLS = [
|
|
2
|
+
"/sign-up",
|
|
3
|
+
"/sign-in/social",
|
|
4
|
+
"/sign-in/oauth2",
|
|
5
|
+
"/email-otp/send-verification-otp",
|
|
6
|
+
];
|
|
7
|
+
/**
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const auth = betterAuth({
|
|
11
|
+
* plugins: [jazzPluginClient()],
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export const jazzPluginClient = () => {
|
|
16
|
+
let jazzContext;
|
|
17
|
+
let authSecretStorage;
|
|
18
|
+
let signOutUnsubscription;
|
|
19
|
+
const authenticateOnJazz = async (jazzAuth) => {
|
|
20
|
+
const parsedJazzAuth = {
|
|
21
|
+
...jazzAuth,
|
|
22
|
+
secretSeed: jazzAuth.secretSeed
|
|
23
|
+
? Uint8Array.from(jazzAuth.secretSeed)
|
|
24
|
+
: undefined,
|
|
25
|
+
};
|
|
26
|
+
await jazzContext.authenticate(parsedJazzAuth);
|
|
27
|
+
await authSecretStorage.set(parsedJazzAuth);
|
|
28
|
+
};
|
|
29
|
+
return {
|
|
30
|
+
id: "jazz-plugin",
|
|
31
|
+
$InferServerPlugin: {},
|
|
32
|
+
getActions: ($fetch, $store) => {
|
|
33
|
+
return {
|
|
34
|
+
jazz: {
|
|
35
|
+
setJazzContext: (context) => {
|
|
36
|
+
jazzContext = context;
|
|
37
|
+
},
|
|
38
|
+
setAuthSecretStorage: (storage) => {
|
|
39
|
+
authSecretStorage = storage;
|
|
40
|
+
if (signOutUnsubscription)
|
|
41
|
+
signOutUnsubscription();
|
|
42
|
+
// This is a workaround to logout from Better Auth when user logs out directly from Jazz
|
|
43
|
+
signOutUnsubscription = authSecretStorage.onUpdate((isAuthenticated) => {
|
|
44
|
+
if (isAuthenticated === false) {
|
|
45
|
+
const session = $store.atoms.session?.get();
|
|
46
|
+
if (!session)
|
|
47
|
+
return;
|
|
48
|
+
// if the user logs out from Better Auth, the get session is immediately called
|
|
49
|
+
// so we must wait the next fetched session to understand if we need to call sign-out
|
|
50
|
+
if (session.isPending || session.isRefetching) {
|
|
51
|
+
// listen once for next session's data
|
|
52
|
+
const unsub = $store.atoms.session?.listen((session) => {
|
|
53
|
+
unsub?.();
|
|
54
|
+
// if the session is null, user has been already logged out from Better Auth
|
|
55
|
+
if (session.data !== null) {
|
|
56
|
+
$fetch("/sign-out", { method: "POST" });
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
// if the session is not pending, it means user logged out from Jazz only
|
|
61
|
+
// so we call the sign-out api
|
|
62
|
+
else {
|
|
63
|
+
$fetch("/sign-out", { method: "POST" });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
fetchPlugins: [
|
|
72
|
+
{
|
|
73
|
+
id: "jazz-plugin",
|
|
74
|
+
name: "jazz-plugin",
|
|
75
|
+
hooks: {
|
|
76
|
+
async onRequest(context) {
|
|
77
|
+
if (SIGNUP_URLS.some((url) => context.url.toString().includes(url))) {
|
|
78
|
+
const credentials = await authSecretStorage.get();
|
|
79
|
+
if (!credentials) {
|
|
80
|
+
throw new Error("Jazz credentials not found");
|
|
81
|
+
}
|
|
82
|
+
context.headers.set("x-jazz-auth", JSON.stringify({
|
|
83
|
+
accountID: credentials.accountID,
|
|
84
|
+
secretSeed: credentials.secretSeed,
|
|
85
|
+
accountSecret: credentials.accountSecret,
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
async onSuccess(context) {
|
|
90
|
+
if (context.request.url.toString().includes("/sign-up")) {
|
|
91
|
+
await authenticateOnJazz(context.data.jazzAuth);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (context.request.url.toString().includes("/sign-in/email")) {
|
|
95
|
+
await authenticateOnJazz(context.data.jazzAuth);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (context.request.url.toString().includes("/get-session")) {
|
|
99
|
+
if (context.data === null) {
|
|
100
|
+
if (authSecretStorage.isAuthenticated === true) {
|
|
101
|
+
console.info("Jazz is authenticated, but the session is null. Logging out");
|
|
102
|
+
await jazzContext.logOut();
|
|
103
|
+
}
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (!context.data?.user) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (authSecretStorage.isAuthenticated === false) {
|
|
110
|
+
console.info("Jazz is not authenticated, using Better Auth stored credentials");
|
|
111
|
+
await authenticateOnJazz(context.data.jazzAuth);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const sessionAccountID = context.data.user.accountID;
|
|
115
|
+
const credentials = await authSecretStorage.get();
|
|
116
|
+
if (!credentials) {
|
|
117
|
+
throw new Error("Jazz credentials not found");
|
|
118
|
+
}
|
|
119
|
+
if (credentials.accountID !== sessionAccountID) {
|
|
120
|
+
console.info("Jazz credentials mismatch, using Better Auth stored credentials");
|
|
121
|
+
await authenticateOnJazz(context.data.jazzAuth);
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (context.request.url.toString().includes("/sign-out")) {
|
|
126
|
+
await jazzContext.logOut();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (context.request.url.toString().includes("/delete-user")) {
|
|
130
|
+
await jazzContext.logOut();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
};
|
|
138
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createAuthClient } from "better-auth/client";
|
|
2
|
+
import { type PropsWithChildren } from "react";
|
|
3
|
+
import { jazzPluginClient } from "./client.js";
|
|
4
|
+
type AuthClient = ReturnType<typeof createAuthClient<{
|
|
5
|
+
plugins: [ReturnType<typeof jazzPluginClient>];
|
|
6
|
+
}>>;
|
|
7
|
+
/**
|
|
8
|
+
* @param props.children - The children to render.
|
|
9
|
+
* @param props.betterAuthClient - The BetterAuth client with the Jazz plugin.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const betterAuthClient = createAuthClient({
|
|
14
|
+
* plugins: [
|
|
15
|
+
* jazzPluginClient(),
|
|
16
|
+
* ],
|
|
17
|
+
* });
|
|
18
|
+
*
|
|
19
|
+
* <AuthProvider betterAuthClient={betterAuthClient}>
|
|
20
|
+
* <App />
|
|
21
|
+
* </AuthProvider>
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function AuthProvider({ children, betterAuthClient, }: PropsWithChildren<{
|
|
25
|
+
betterAuthClient: AuthClient;
|
|
26
|
+
}>): import("react").ReactNode;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../../src/better-auth/auth/react.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,KAAK,UAAU,GAAG,UAAU,CAC1B,OAAO,gBAAgB,CAAC;IACtB,OAAO,EAAE,CAAC,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC,CAAC;CAChD,CAAC,CACH,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,gBAAgB,GACjB,EAAE,iBAAiB,CAAC;IACnB,gBAAgB,EAAE,UAAU,CAAC;CAC9B,CAAC,6BAmBD"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { createAuthClient } from "better-auth/client";
|
|
4
|
+
import { useAuthSecretStorage, useJazzContext } from "jazz-tools/react-core";
|
|
5
|
+
import { useEffect } from "react";
|
|
6
|
+
import { type PropsWithChildren } from "react";
|
|
7
|
+
import { jazzPluginClient } from "./client.js";
|
|
8
|
+
|
|
9
|
+
type AuthClient = ReturnType<
|
|
10
|
+
typeof createAuthClient<{
|
|
11
|
+
plugins: [ReturnType<typeof jazzPluginClient>];
|
|
12
|
+
}>
|
|
13
|
+
>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param props.children - The children to render.
|
|
17
|
+
* @param props.betterAuthClient - The BetterAuth client with the Jazz plugin.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const betterAuthClient = createAuthClient({
|
|
22
|
+
* plugins: [
|
|
23
|
+
* jazzPluginClient(),
|
|
24
|
+
* ],
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* <AuthProvider betterAuthClient={betterAuthClient}>
|
|
28
|
+
* <App />
|
|
29
|
+
* </AuthProvider>
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function AuthProvider({
|
|
33
|
+
children,
|
|
34
|
+
betterAuthClient,
|
|
35
|
+
}: PropsWithChildren<{
|
|
36
|
+
betterAuthClient: AuthClient;
|
|
37
|
+
}>) {
|
|
38
|
+
const context = useJazzContext();
|
|
39
|
+
const authSecretStorage = useAuthSecretStorage();
|
|
40
|
+
|
|
41
|
+
if (betterAuthClient.jazz === undefined) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
"Better Auth client has been initialized without the jazzPluginClient",
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
betterAuthClient.jazz.setJazzContext(context);
|
|
49
|
+
betterAuthClient.jazz.setAuthSecretStorage(authSecretStorage);
|
|
50
|
+
|
|
51
|
+
// We need to subscribe to the session to let the plugin keep sync Jazz's and BetterAuth's session
|
|
52
|
+
return betterAuthClient.useSession.subscribe(() => {});
|
|
53
|
+
}, [betterAuthClient, context, authSecretStorage]);
|
|
54
|
+
|
|
55
|
+
return children;
|
|
56
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type BetterAuthPlugin } from "better-auth";
|
|
2
|
+
type JazzPlugin = BetterAuthPlugin & {
|
|
3
|
+
schema: {
|
|
4
|
+
user: {
|
|
5
|
+
fields: {
|
|
6
|
+
accountID: {
|
|
7
|
+
type: "string";
|
|
8
|
+
required: false;
|
|
9
|
+
input: false;
|
|
10
|
+
};
|
|
11
|
+
encryptedCredentials: {
|
|
12
|
+
type: "string";
|
|
13
|
+
required: false;
|
|
14
|
+
input: false;
|
|
15
|
+
returned: false;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* @returns The BetterAuth server plugin.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const auth = betterAuth({
|
|
27
|
+
* plugins: [jazzPlugin()],
|
|
28
|
+
* // ... other BetterAuth options
|
|
29
|
+
* });
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare const jazzPlugin: () => JazzPlugin;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/better-auth/auth/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EAGtB,MAAM,aAAa,CAAC;AASrB,KAAK,UAAU,GAAG,gBAAgB,GAAG;IACnC,MAAM,EAAE;QACN,IAAI,EAAE;YACJ,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT,IAAI,EAAE,QAAQ,CAAC;oBACf,QAAQ,EAAE,KAAK,CAAC;oBAChB,KAAK,EAAE,KAAK,CAAC;iBACd,CAAC;gBACF,oBAAoB,EAAE;oBACpB,IAAI,EAAE,QAAQ,CAAC;oBACf,QAAQ,EAAE,KAAK,CAAC;oBAChB,KAAK,EAAE,KAAK,CAAC;oBACb,QAAQ,EAAE,KAAK,CAAC;iBACjB,CAAC;aACH,CAAC;SACH,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,UA0Q9B,CAAC"}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { APIError } from "better-auth/api";
|
|
2
|
+
import { symmetricDecrypt, symmetricEncrypt } from "better-auth/crypto";
|
|
3
|
+
import { createAuthMiddleware } from "better-auth/plugins";
|
|
4
|
+
/**
|
|
5
|
+
* @returns The BetterAuth server plugin.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* const auth = betterAuth({
|
|
10
|
+
* plugins: [jazzPlugin()],
|
|
11
|
+
* // ... other BetterAuth options
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export const jazzPlugin = () => {
|
|
16
|
+
return {
|
|
17
|
+
id: "jazz-plugin",
|
|
18
|
+
schema: {
|
|
19
|
+
user: {
|
|
20
|
+
fields: {
|
|
21
|
+
accountID: {
|
|
22
|
+
type: "string",
|
|
23
|
+
required: false,
|
|
24
|
+
input: false,
|
|
25
|
+
},
|
|
26
|
+
encryptedCredentials: {
|
|
27
|
+
type: "string",
|
|
28
|
+
required: false,
|
|
29
|
+
input: false,
|
|
30
|
+
returned: false,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
init() {
|
|
36
|
+
return {
|
|
37
|
+
options: {
|
|
38
|
+
databaseHooks: {
|
|
39
|
+
user: {
|
|
40
|
+
create: {
|
|
41
|
+
before: async (user, context) => {
|
|
42
|
+
// If the user is created without a jazzAuth, it will throw an error.
|
|
43
|
+
if (!contextContainsJazzAuth(context)) {
|
|
44
|
+
throw new APIError(422, {
|
|
45
|
+
message: "JazzAuth is required on user creation",
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
// Decorate the user with the jazz's credentials.
|
|
49
|
+
return {
|
|
50
|
+
data: {
|
|
51
|
+
accountID: context.jazzAuth.accountID,
|
|
52
|
+
encryptedCredentials: context.jazzAuth.encryptedCredentials,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
verification: {
|
|
59
|
+
create: {
|
|
60
|
+
after: async (verification, context) => {
|
|
61
|
+
/**
|
|
62
|
+
* For: Email OTP plugin
|
|
63
|
+
* After a verification is created, if it is from the EmailOTP plugin,
|
|
64
|
+
* create a new verification value with the jazzAuth with the same expiration.
|
|
65
|
+
*/
|
|
66
|
+
if (contextContainsJazzAuth(context) &&
|
|
67
|
+
verification.identifier.startsWith("sign-in-otp-")) {
|
|
68
|
+
const identifier = `jazz-auth-${verification.identifier}`;
|
|
69
|
+
await context.context.internalAdapter.deleteVerificationByIdentifier(identifier);
|
|
70
|
+
await context.context.internalAdapter.createVerificationValue({
|
|
71
|
+
value: JSON.stringify({ jazzAuth: context.jazzAuth }),
|
|
72
|
+
identifier: identifier,
|
|
73
|
+
expiresAt: verification.expiresAt,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
hooks: {
|
|
84
|
+
before: [
|
|
85
|
+
/**
|
|
86
|
+
* If the client sends a x-jazz-auth header,
|
|
87
|
+
* we encrypt the credentials and inject them into the context.
|
|
88
|
+
*/
|
|
89
|
+
{
|
|
90
|
+
matcher: (context) => {
|
|
91
|
+
return !!context.headers?.get("x-jazz-auth");
|
|
92
|
+
},
|
|
93
|
+
handler: createAuthMiddleware(async (ctx) => {
|
|
94
|
+
const jazzAuth = JSON.parse(ctx.headers?.get("x-jazz-auth"));
|
|
95
|
+
const credentials = {
|
|
96
|
+
accountID: jazzAuth.accountID,
|
|
97
|
+
secretSeed: jazzAuth.secretSeed,
|
|
98
|
+
accountSecret: jazzAuth.accountSecret,
|
|
99
|
+
// If the provider remains 'anonymous', Jazz will not consider us authenticated later.
|
|
100
|
+
provider: "better-auth",
|
|
101
|
+
};
|
|
102
|
+
const encryptedCredentials = await symmetricEncrypt({
|
|
103
|
+
key: ctx.context.secret,
|
|
104
|
+
data: JSON.stringify(credentials),
|
|
105
|
+
});
|
|
106
|
+
return {
|
|
107
|
+
context: {
|
|
108
|
+
...ctx,
|
|
109
|
+
jazzAuth: {
|
|
110
|
+
accountID: jazzAuth.accountID,
|
|
111
|
+
encryptedCredentials: encryptedCredentials,
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}),
|
|
116
|
+
},
|
|
117
|
+
/**
|
|
118
|
+
* For: Social / OAuth2 plugin
|
|
119
|
+
* /callback is the endpoint that BetterAuth uses to authenticate the user coming from a social provider.
|
|
120
|
+
* 1. Catch the state
|
|
121
|
+
* 2. Find the verification value
|
|
122
|
+
* 3. If the verification value contains a jazzAuth, inject into the context to have it in case of registration.
|
|
123
|
+
*/
|
|
124
|
+
{
|
|
125
|
+
matcher: (context) => {
|
|
126
|
+
return (context.path.startsWith("/callback") ||
|
|
127
|
+
context.path.startsWith("/oauth2/callback"));
|
|
128
|
+
},
|
|
129
|
+
handler: createAuthMiddleware(async (ctx) => {
|
|
130
|
+
const state = ctx.query?.state || ctx.body?.state;
|
|
131
|
+
const identifier = `jazz-auth-${state}`;
|
|
132
|
+
const data = await ctx.context.internalAdapter.findVerificationValue(identifier);
|
|
133
|
+
// if not found, the social plugin will throw later anyway
|
|
134
|
+
if (!data) {
|
|
135
|
+
throw new APIError(404, {
|
|
136
|
+
message: "Verification not found",
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
const parsed = JSON.parse(data.value);
|
|
140
|
+
if (parsed && "jazzAuth" in parsed) {
|
|
141
|
+
return {
|
|
142
|
+
context: {
|
|
143
|
+
...ctx,
|
|
144
|
+
jazzAuth: parsed.jazzAuth,
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
throw new APIError(404, {
|
|
150
|
+
message: "JazzAuth not found in verification value",
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}),
|
|
154
|
+
},
|
|
155
|
+
/**
|
|
156
|
+
* For: Email OTP plugin
|
|
157
|
+
* When the user sends an OTP, we try to find the jazzAuth.
|
|
158
|
+
* If it isn't a sign-up, we expect to not find a verification value.
|
|
159
|
+
*/
|
|
160
|
+
{
|
|
161
|
+
matcher: (context) => {
|
|
162
|
+
return context.path.startsWith("/sign-in/email-otp");
|
|
163
|
+
},
|
|
164
|
+
handler: createAuthMiddleware(async (ctx) => {
|
|
165
|
+
const email = ctx.body.email;
|
|
166
|
+
const identifier = `jazz-auth-sign-in-otp-${email}`;
|
|
167
|
+
const data = await ctx.context.internalAdapter.findVerificationValue(identifier);
|
|
168
|
+
// if not found, it isn't a sign-up
|
|
169
|
+
if (!data || data.expiresAt < new Date()) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const parsed = JSON.parse(data.value);
|
|
173
|
+
if (parsed && "jazzAuth" in parsed) {
|
|
174
|
+
return {
|
|
175
|
+
context: {
|
|
176
|
+
...ctx,
|
|
177
|
+
jazzAuth: parsed.jazzAuth,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
throw new APIError(500, {
|
|
183
|
+
message: "JazzAuth not found in verification value",
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
}),
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
after: [
|
|
190
|
+
/**
|
|
191
|
+
* This middleware is used to extract the jazzAuth from the user and return it in the response.
|
|
192
|
+
* It is used in the following endpoints that return the user:
|
|
193
|
+
* - /sign-up/email
|
|
194
|
+
* - /sign-in/email
|
|
195
|
+
* - /get-session
|
|
196
|
+
*/
|
|
197
|
+
{
|
|
198
|
+
matcher: (context) => {
|
|
199
|
+
return (context.path.startsWith("/sign-up") ||
|
|
200
|
+
context.path.startsWith("/sign-in") ||
|
|
201
|
+
context.path.startsWith("/get-session"));
|
|
202
|
+
},
|
|
203
|
+
handler: createAuthMiddleware({}, async (ctx) => {
|
|
204
|
+
const returned = ctx.context.returned;
|
|
205
|
+
if (!returned?.user?.id) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const jazzAuth = await extractJazzAuth(returned.user.id, ctx);
|
|
209
|
+
return ctx.json({
|
|
210
|
+
...returned,
|
|
211
|
+
jazzAuth: jazzAuth,
|
|
212
|
+
});
|
|
213
|
+
}),
|
|
214
|
+
},
|
|
215
|
+
/**
|
|
216
|
+
* For: Social / OAuth2 plugin
|
|
217
|
+
* When the user sign-in via social, we create a verification value with the jazzAuth.
|
|
218
|
+
*/
|
|
219
|
+
{
|
|
220
|
+
matcher: (context) => {
|
|
221
|
+
return context.path.startsWith("/sign-in/social");
|
|
222
|
+
},
|
|
223
|
+
handler: createAuthMiddleware(async (ctx) => {
|
|
224
|
+
if (!contextContainsJazzAuth(ctx)) {
|
|
225
|
+
throw new APIError(500, {
|
|
226
|
+
message: "JazzAuth not found in context",
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
const returned = ctx.context.returned;
|
|
230
|
+
const url = new URL(returned.url);
|
|
231
|
+
const state = url.searchParams.get("state");
|
|
232
|
+
const value = JSON.stringify({ jazzAuth: ctx.jazzAuth });
|
|
233
|
+
const expiresAt = new Date();
|
|
234
|
+
expiresAt.setMinutes(expiresAt.getMinutes() + 10);
|
|
235
|
+
await ctx.context.internalAdapter.createVerificationValue({
|
|
236
|
+
value,
|
|
237
|
+
identifier: `jazz-auth-${state}`,
|
|
238
|
+
expiresAt,
|
|
239
|
+
});
|
|
240
|
+
}),
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
};
|
|
246
|
+
function contextContainsJazzAuth(ctx) {
|
|
247
|
+
return !!ctx && typeof ctx === "object" && "jazzAuth" in ctx;
|
|
248
|
+
}
|
|
249
|
+
async function extractJazzAuth(userId, ctx) {
|
|
250
|
+
const user = await ctx.context.adapter.findOne({
|
|
251
|
+
model: ctx.context.tables.user.modelName,
|
|
252
|
+
where: [
|
|
253
|
+
{
|
|
254
|
+
field: "id",
|
|
255
|
+
operator: "eq",
|
|
256
|
+
value: userId,
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
select: ["accountID", "encryptedCredentials"],
|
|
260
|
+
});
|
|
261
|
+
if (!user) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const jazzAuth = JSON.parse(await symmetricDecrypt({
|
|
265
|
+
key: ctx.context.secret,
|
|
266
|
+
data: user.encryptedCredentials,
|
|
267
|
+
}));
|
|
268
|
+
return jazzAuth;
|
|
269
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import { createAuthClient } from "better-auth/client";
|
|
4
|
+
import { getAuthSecretStorage, getJazzContext } from "jazz-tools/svelte";
|
|
5
|
+
import { jazzPluginClient } from "./client.js";
|
|
6
|
+
|
|
7
|
+
type AuthClient = ReturnType<
|
|
8
|
+
typeof createAuthClient<{
|
|
9
|
+
plugins: [ReturnType<typeof jazzPluginClient>];
|
|
10
|
+
}>
|
|
11
|
+
>;
|
|
12
|
+
|
|
13
|
+
let {
|
|
14
|
+
betterAuthClient,
|
|
15
|
+
children,
|
|
16
|
+
}: {
|
|
17
|
+
betterAuthClient: AuthClient;
|
|
18
|
+
children?: Snippet;
|
|
19
|
+
} = $props();
|
|
20
|
+
|
|
21
|
+
const context = getJazzContext();
|
|
22
|
+
const authSecretStorage = getAuthSecretStorage();
|
|
23
|
+
|
|
24
|
+
if (betterAuthClient.jazz === undefined) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
"Better Auth client has been initialized without the jazzPluginClient",
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
$effect(() => {
|
|
31
|
+
// Register reactive dependencies
|
|
32
|
+
context.current;
|
|
33
|
+
authSecretStorage;
|
|
34
|
+
betterAuthClient;
|
|
35
|
+
|
|
36
|
+
// The plugin installs itself on the client under the `jazz` key:
|
|
37
|
+
betterAuthClient.jazz.setJazzContext(context.current);
|
|
38
|
+
betterAuthClient.jazz.setAuthSecretStorage(authSecretStorage);
|
|
39
|
+
|
|
40
|
+
// If we don't subscribe, then the plugin won't keep the states synced, but we don't need to actually do anything in the callback.
|
|
41
|
+
return betterAuthClient.useSession.subscribe(() => {});
|
|
42
|
+
});
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
{#if children}
|
|
46
|
+
{@render children()}
|
|
47
|
+
{/if}
|