jazz-tools 0.19.15 → 0.19.16
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/.turbo/turbo-build.log +40 -40
- package/CHANGELOG.md +10 -0
- package/dist/index.js +21 -13
- package/dist/index.js.map +1 -1
- package/dist/tools/auth/clerk/index.d.ts +1 -0
- package/dist/tools/auth/clerk/index.d.ts.map +1 -1
- package/dist/tools/auth/clerk/tests/isClerkAuthStateEqual.test.d.ts +2 -0
- package/dist/tools/auth/clerk/tests/isClerkAuthStateEqual.test.d.ts.map +1 -0
- package/dist/tools/auth/clerk/types.d.ts +2 -2
- package/dist/tools/auth/clerk/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/tools/auth/clerk/index.ts +21 -11
- package/src/tools/auth/clerk/tests/JazzClerkAuth.test.ts +77 -0
- package/src/tools/auth/clerk/tests/isClerkAuthStateEqual.test.ts +124 -0
- package/src/tools/auth/clerk/types.ts +23 -6
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> jazz-tools@0.19.
|
|
2
|
+
> jazz-tools@0.19.16 build /home/runner/_work/jazz/jazz/packages/jazz-tools
|
|
3
3
|
> tsup && pnpm types && pnpm build:svelte
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: {"index":"src/index.ts","testing":"src/testing.ts","tools/ssr":"src/tools/ssr/index.ts"}
|
|
@@ -109,21 +109,21 @@
|
|
|
109
109
|
[34mESM[39m Build start
|
|
110
110
|
[32mESM[39m [1mdist/tiptap/index.js [22m[32m564.00 B[39m
|
|
111
111
|
[32mESM[39m [1mdist/tiptap/index.js.map [22m[32m1.21 KB[39m
|
|
112
|
-
[32mESM[39m ⚡️ Build success in
|
|
112
|
+
[32mESM[39m ⚡️ Build success in 63ms
|
|
113
|
+
[32mESM[39m [1mdist/better-auth/auth/client.js [22m[32m4.50 KB[39m
|
|
114
|
+
[32mESM[39m [1mdist/better-auth/auth/react.js [22m[32m799.00 B[39m
|
|
115
|
+
[32mESM[39m [1mdist/better-auth/auth/server.js [22m[32m8.36 KB[39m
|
|
116
|
+
[32mESM[39m [1mdist/better-auth/auth/client.js.map [22m[32m8.32 KB[39m
|
|
117
|
+
[32mESM[39m [1mdist/better-auth/auth/react.js.map [22m[32m2.04 KB[39m
|
|
118
|
+
[32mESM[39m [1mdist/better-auth/auth/server.js.map [22m[32m15.31 KB[39m
|
|
119
|
+
[32mESM[39m ⚡️ Build success in 49ms
|
|
113
120
|
[32mESM[39m [1mdist/worker/index.js [22m[32m3.19 KB[39m
|
|
114
121
|
[32mESM[39m [1mdist/worker/edge-wasm.js [22m[32m215.00 B[39m
|
|
115
122
|
[32mESM[39m [1mdist/worker/napi-crypto.js [22m[32m110.00 B[39m
|
|
116
|
-
[32mESM[39m [1mdist/worker/edge-wasm.js.map [22m[32m434.00 B[39m
|
|
117
123
|
[32mESM[39m [1mdist/worker/index.js.map [22m[32m6.26 KB[39m
|
|
124
|
+
[32mESM[39m [1mdist/worker/edge-wasm.js.map [22m[32m434.00 B[39m
|
|
118
125
|
[32mESM[39m [1mdist/worker/napi-crypto.js.map [22m[32m162.00 B[39m
|
|
119
|
-
[32mESM[39m ⚡️ Build success in
|
|
120
|
-
[32mESM[39m [1mdist/better-auth/auth/client.js [22m[32m4.50 KB[39m
|
|
121
|
-
[32mESM[39m [1mdist/better-auth/auth/server.js [22m[32m8.36 KB[39m
|
|
122
|
-
[32mESM[39m [1mdist/better-auth/auth/react.js [22m[32m799.00 B[39m
|
|
123
|
-
[32mESM[39m [1mdist/better-auth/auth/client.js.map [22m[32m8.32 KB[39m
|
|
124
|
-
[32mESM[39m [1mdist/better-auth/auth/server.js.map [22m[32m15.31 KB[39m
|
|
125
|
-
[32mESM[39m [1mdist/better-auth/auth/react.js.map [22m[32m2.04 KB[39m
|
|
126
|
-
[32mESM[39m ⚡️ Build success in 74ms
|
|
126
|
+
[32mESM[39m ⚡️ Build success in 62ms
|
|
127
127
|
[32mESM[39m [1mdist/media/index.js [22m[32m236.00 B[39m
|
|
128
128
|
[32mESM[39m [1mdist/media/index.browser.js [22m[32m2.79 KB[39m
|
|
129
129
|
[32mESM[39m [1mdist/media/index.native.js [22m[32m4.01 KB[39m
|
|
@@ -134,32 +134,26 @@
|
|
|
134
134
|
[32mESM[39m [1mdist/media/index.native.js.map [22m[32m8.10 KB[39m
|
|
135
135
|
[32mESM[39m [1mdist/media/index.server.js.map [22m[32m6.37 KB[39m
|
|
136
136
|
[32mESM[39m [1mdist/media/chunk-3LKBM3G3.js.map [22m[32m16.99 KB[39m
|
|
137
|
-
[32mESM[39m ⚡️ Build success in
|
|
137
|
+
[32mESM[39m ⚡️ Build success in 78ms
|
|
138
138
|
[32mESM[39m [1mdist/expo/index.js [22m[32m4.68 KB[39m
|
|
139
|
-
[32mESM[39m [1mdist/expo/crypto.js [22m[32m153.00 B[39m
|
|
140
139
|
[32mESM[39m [1mdist/expo/testing.js [22m[32m112.00 B[39m
|
|
140
|
+
[32mESM[39m [1mdist/expo/crypto.js [22m[32m153.00 B[39m
|
|
141
141
|
[32mESM[39m [1mdist/expo/polyfills.js [22m[32m858.00 B[39m
|
|
142
142
|
[32mESM[39m [1mdist/expo/index.js.map [22m[32m10.23 KB[39m
|
|
143
|
-
[32mESM[39m [1mdist/expo/crypto.js.map [22m[32m189.00 B[39m
|
|
144
143
|
[32mESM[39m [1mdist/expo/testing.js.map [22m[32m168.00 B[39m
|
|
144
|
+
[32mESM[39m [1mdist/expo/crypto.js.map [22m[32m189.00 B[39m
|
|
145
145
|
[32mESM[39m [1mdist/expo/polyfills.js.map [22m[32m1.61 KB[39m
|
|
146
|
-
[32mESM[39m ⚡️ Build success in
|
|
147
|
-
[32mESM[39m [1mdist/prosemirror/index.js [22m[32m77.76 KB[39m
|
|
148
|
-
[32mESM[39m [1mdist/prosemirror/index.js.map [22m[32m307.20 KB[39m
|
|
149
|
-
[32mESM[39m ⚡️ Build success in 117ms
|
|
146
|
+
[32mESM[39m ⚡️ Build success in 76ms
|
|
150
147
|
[32mESM[39m [1mdist/react-core/index.js [22m[32m17.05 KB[39m
|
|
151
148
|
[32mESM[39m [1mdist/react-core/testing.js [22m[32m1.22 KB[39m
|
|
152
149
|
[32mESM[39m [1mdist/react-core/chunk-7DYMJ74I.js [22m[32m279.00 B[39m
|
|
153
150
|
[32mESM[39m [1mdist/react-core/index.js.map [22m[32m49.77 KB[39m
|
|
154
151
|
[32mESM[39m [1mdist/react-core/testing.js.map [22m[32m1.86 KB[39m
|
|
155
152
|
[32mESM[39m [1mdist/react-core/chunk-7DYMJ74I.js.map [22m[32m533.00 B[39m
|
|
156
|
-
[32mESM[39m ⚡️ Build success in
|
|
157
|
-
[32mESM[39m [1mdist/better-auth/database-adapter/index.js [22m[32m26.65 KB[39m
|
|
158
|
-
[32mESM[39m [1mdist/better-auth/database-adapter/index.js.map [22m[32m58.26 KB[39m
|
|
159
|
-
[32mESM[39m ⚡️ Build success in 111ms
|
|
153
|
+
[32mESM[39m ⚡️ Build success in 98ms
|
|
160
154
|
[32mESM[39m [1mdist/browser/index.js [22m[32m16.14 KB[39m
|
|
161
155
|
[32mESM[39m [1mdist/browser/index.js.map [22m[32m34.66 KB[39m
|
|
162
|
-
[32mESM[39m ⚡️ Build success in
|
|
156
|
+
[32mESM[39m ⚡️ Build success in 111ms
|
|
163
157
|
[32mESM[39m [1mdist/react-native-core/index.js [22m[32m20.57 KB[39m
|
|
164
158
|
[32mESM[39m [1mdist/react-native-core/testing.js [22m[32m119.00 B[39m
|
|
165
159
|
[32mESM[39m [1mdist/react-native-core/crypto.js [22m[32m2.58 KB[39m
|
|
@@ -168,14 +162,20 @@
|
|
|
168
162
|
[32mESM[39m [1mdist/react-native-core/testing.js.map [22m[32m175.00 B[39m
|
|
169
163
|
[32mESM[39m [1mdist/react-native-core/crypto.js.map [22m[32m5.25 KB[39m
|
|
170
164
|
[32mESM[39m [1mdist/react-native-core/crypto/RNCrypto.js.map [22m[32m178.00 B[39m
|
|
171
|
-
[32mESM[39m ⚡️ Build success in
|
|
165
|
+
[32mESM[39m ⚡️ Build success in 124ms
|
|
166
|
+
[32mESM[39m [1mdist/prosemirror/index.js [22m[32m77.76 KB[39m
|
|
167
|
+
[32mESM[39m [1mdist/prosemirror/index.js.map [22m[32m307.20 KB[39m
|
|
168
|
+
[32mESM[39m ⚡️ Build success in 138ms
|
|
172
169
|
[32mESM[39m [1mdist/react/index.js [22m[32m25.96 KB[39m
|
|
173
170
|
[32mESM[39m [1mdist/react/testing.js [22m[32m122.00 B[39m
|
|
174
171
|
[32mESM[39m [1mdist/react/ssr.js [22m[32m697.00 B[39m
|
|
175
172
|
[32mESM[39m [1mdist/react/index.js.map [22m[32m55.44 KB[39m
|
|
176
173
|
[32mESM[39m [1mdist/react/testing.js.map [22m[32m165.00 B[39m
|
|
177
174
|
[32mESM[39m [1mdist/react/ssr.js.map [22m[32m1.11 KB[39m
|
|
178
|
-
[32mESM[39m ⚡️ Build success in
|
|
175
|
+
[32mESM[39m ⚡️ Build success in 122ms
|
|
176
|
+
[32mESM[39m [1mdist/better-auth/database-adapter/index.js [22m[32m26.65 KB[39m
|
|
177
|
+
[32mESM[39m [1mdist/better-auth/database-adapter/index.js.map [22m[32m58.26 KB[39m
|
|
178
|
+
[32mESM[39m ⚡️ Build success in 124ms
|
|
179
179
|
[32mESM[39m [1mdist/react-native/index.js [22m[32m23.11 KB[39m
|
|
180
180
|
[32mESM[39m [1mdist/react-native/testing.js [22m[32m120.00 B[39m
|
|
181
181
|
[32mESM[39m [1mdist/react-native/crypto.js [22m[32m161.00 B[39m
|
|
@@ -184,38 +184,38 @@
|
|
|
184
184
|
[32mESM[39m [1mdist/react-native/testing.js.map [22m[32m176.00 B[39m
|
|
185
185
|
[32mESM[39m [1mdist/react-native/crypto.js.map [22m[32m197.00 B[39m
|
|
186
186
|
[32mESM[39m [1mdist/react-native/polyfills.js.map [22m[32m1.61 KB[39m
|
|
187
|
-
[32mESM[39m ⚡️ Build success in
|
|
187
|
+
[32mESM[39m ⚡️ Build success in 144ms
|
|
188
188
|
[32mESM[39m [1mdist/inspector/index.js [22m[32m6.29 KB[39m
|
|
189
189
|
[32mESM[39m [1mdist/inspector/standalone.js [22m[32m12.61 KB[39m
|
|
190
190
|
[32mESM[39m [1mdist/inspector/chunk-YQNK5Y7B.js [22m[32m127.21 KB[39m
|
|
191
191
|
[32mESM[39m [1mdist/inspector/index.js.map [22m[32m9.65 KB[39m
|
|
192
192
|
[32mESM[39m [1mdist/inspector/standalone.js.map [22m[32m20.11 KB[39m
|
|
193
193
|
[32mESM[39m [1mdist/inspector/chunk-YQNK5Y7B.js.map [22m[32m221.30 KB[39m
|
|
194
|
-
[32mESM[39m ⚡️ Build success in
|
|
195
|
-
[32mESM[39m [1mdist/
|
|
196
|
-
[32mESM[39m [1mdist/inspector/register-custom-element.js.map [22m[32m314.00 B[39m
|
|
197
|
-
[32mESM[39m [1mdist/inspector/custom-element-KYV64IOC.js [22m[32m1.60 MB[39m
|
|
198
|
-
[32mESM[39m [1mdist/inspector/custom-element-KYV64IOC.js.map [22m[32m2.47 MB[39m
|
|
199
|
-
[32mESM[39m ⚡️ Build success in 251ms
|
|
200
|
-
[32mESM[39m [1mdist/index.js [22m[32m29.82 KB[39m
|
|
194
|
+
[32mESM[39m ⚡️ Build success in 163ms
|
|
195
|
+
[32mESM[39m [1mdist/index.js [22m[32m30.20 KB[39m
|
|
201
196
|
[32mESM[39m [1mdist/testing.js [22m[32m8.56 KB[39m
|
|
202
|
-
[32mESM[39m [1mdist/chunk-
|
|
197
|
+
[32mESM[39m [1mdist/chunk-R3KIZG4P.js [22m[32m226.01 KB[39m
|
|
203
198
|
[32mESM[39m [1mdist/tools/ssr.js [22m[32m156.00 B[39m
|
|
199
|
+
[32mESM[39m [1mdist/chunk-M2HGBOXS.js [22m[32m694.00 B[39m
|
|
204
200
|
[32mESM[39m [1mdist/chunk-PZ5AY32C.js [22m[32m233.00 B[39m
|
|
205
|
-
[32mESM[39m [1mdist/
|
|
201
|
+
[32mESM[39m [1mdist/index.js.map [22m[32m61.58 KB[39m
|
|
206
202
|
[32mESM[39m [1mdist/testing.js.map [22m[32m16.21 KB[39m
|
|
207
|
-
[32mESM[39m [1mdist/index.js.map [22m[32m60.59 KB[39m
|
|
208
|
-
[32mESM[39m [1mdist/chunk-M2HGBOXS.js.map [22m[32m1.10 KB[39m
|
|
209
203
|
[32mESM[39m [1mdist/tools/ssr.js.map [22m[32m71.00 B[39m
|
|
204
|
+
[32mESM[39m [1mdist/chunk-M2HGBOXS.js.map [22m[32m1.10 KB[39m
|
|
210
205
|
[32mESM[39m [1mdist/chunk-PZ5AY32C.js.map [22m[32m71.00 B[39m
|
|
211
206
|
[32mESM[39m [1mdist/chunk-R3KIZG4P.js.map [22m[32m531.93 KB[39m
|
|
212
|
-
[32mESM[39m ⚡️ Build success in
|
|
207
|
+
[32mESM[39m ⚡️ Build success in 227ms
|
|
208
|
+
[32mESM[39m [1mdist/inspector/register-custom-element.js [22m[32m218.00 B[39m
|
|
209
|
+
[32mESM[39m [1mdist/inspector/custom-element-KYV64IOC.js [22m[32m1.60 MB[39m
|
|
210
|
+
[32mESM[39m [1mdist/inspector/register-custom-element.js.map [22m[32m314.00 B[39m
|
|
211
|
+
[32mESM[39m [1mdist/inspector/custom-element-KYV64IOC.js.map [22m[32m2.47 MB[39m
|
|
212
|
+
[32mESM[39m ⚡️ Build success in 244ms
|
|
213
213
|
|
|
214
|
-
> jazz-tools@0.19.
|
|
214
|
+
> jazz-tools@0.19.16 types /home/runner/_work/jazz/jazz/packages/jazz-tools
|
|
215
215
|
> tsc --outDir dist
|
|
216
216
|
|
|
217
217
|
|
|
218
|
-
> jazz-tools@0.19.
|
|
218
|
+
> jazz-tools@0.19.16 build:svelte /home/runner/_work/jazz/jazz/packages/jazz-tools
|
|
219
219
|
> rm -rf dist/svelte && svelte-package -i src/svelte -o dist/svelte --tsconfig tsconfig.svelte.json
|
|
220
220
|
|
|
221
221
|
src/svelte -> dist/svelte
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# jazz-tools
|
|
2
2
|
|
|
3
|
+
## 0.19.16
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 25268bf: Bugfix: fixed a race condition in Clerk auth where the signup flow could trigger a duplicate login attempt
|
|
8
|
+
- Updated dependencies [265d0e9]
|
|
9
|
+
- cojson@0.19.16
|
|
10
|
+
- cojson-storage-indexeddb@0.19.16
|
|
11
|
+
- cojson-transport-ws@0.19.16
|
|
12
|
+
|
|
3
13
|
## 0.19.15
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -95,9 +95,12 @@ function isClerkAuthStateEqual(previousUser, newUser) {
|
|
|
95
95
|
if (Boolean(previousUser) !== Boolean(newUser)) {
|
|
96
96
|
return false;
|
|
97
97
|
}
|
|
98
|
-
const previousCredentials = isClerkCredentials(previousUser?.unsafeMetadata);
|
|
99
|
-
const newCredentials = isClerkCredentials(newUser?.unsafeMetadata);
|
|
100
|
-
|
|
98
|
+
const previousCredentials = isClerkCredentials(previousUser?.unsafeMetadata) ? previousUser?.unsafeMetadata : null;
|
|
99
|
+
const newCredentials = isClerkCredentials(newUser?.unsafeMetadata) ? newUser?.unsafeMetadata : null;
|
|
100
|
+
if (!previousCredentials || !newCredentials) {
|
|
101
|
+
return previousCredentials === newCredentials;
|
|
102
|
+
}
|
|
103
|
+
return previousCredentials.jazzAccountID === newCredentials.jazzAccountID;
|
|
101
104
|
}
|
|
102
105
|
|
|
103
106
|
// src/tools/auth/clerk/index.ts
|
|
@@ -107,6 +110,7 @@ var JazzClerkAuth = class _JazzClerkAuth {
|
|
|
107
110
|
this.logOut = logOut;
|
|
108
111
|
this.authSecretStorage = authSecretStorage;
|
|
109
112
|
this.isFirstCall = true;
|
|
113
|
+
this.previousUser = null;
|
|
110
114
|
this.onClerkUserChange = async (clerkClient) => {
|
|
111
115
|
const isAuthenticated = this.authSecretStorage.isAuthenticated;
|
|
112
116
|
if (!clerkClient.user) {
|
|
@@ -154,13 +158,17 @@ var JazzClerkAuth = class _JazzClerkAuth {
|
|
|
154
158
|
throw new Error("No credentials found");
|
|
155
159
|
}
|
|
156
160
|
const jazzAccountSeed = credentials.secretSeed ? Array.from(credentials.secretSeed) : void 0;
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
const clerkCredentials = {
|
|
162
|
+
jazzAccountID: credentials.accountID,
|
|
163
|
+
jazzAccountSecret: credentials.accountSecret,
|
|
164
|
+
jazzAccountSeed
|
|
165
|
+
};
|
|
166
|
+
this.previousUser = { unsafeMetadata: clerkCredentials };
|
|
167
|
+
if (clerkClient.user) {
|
|
168
|
+
await clerkClient.user.update({
|
|
169
|
+
unsafeMetadata: clerkCredentials
|
|
170
|
+
});
|
|
171
|
+
}
|
|
164
172
|
const currentAccount = await Account2.getMe().$jazz.ensureLoaded({
|
|
165
173
|
resolve: {
|
|
166
174
|
profile: true
|
|
@@ -202,12 +210,12 @@ var JazzClerkAuth = class _JazzClerkAuth {
|
|
|
202
210
|
);
|
|
203
211
|
}
|
|
204
212
|
registerListener(clerkClient) {
|
|
205
|
-
|
|
213
|
+
this.previousUser = clerkClient.user ?? null;
|
|
206
214
|
return clerkClient.addListener((event) => {
|
|
207
215
|
const user = event.user ?? null;
|
|
208
|
-
if (!isClerkAuthStateEqual(previousUser, user) || this.isFirstCall) {
|
|
216
|
+
if (!isClerkAuthStateEqual(this.previousUser, user) || this.isFirstCall) {
|
|
217
|
+
this.previousUser = user;
|
|
209
218
|
this.onClerkUserChange({ user });
|
|
210
|
-
previousUser = user;
|
|
211
219
|
this.isFirstCall = false;
|
|
212
220
|
}
|
|
213
221
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tools/auth/clerk/index.ts","../src/tools/auth/clerk/getClerkUsername.ts","../src/tools/auth/clerk/types.ts","../src/tools/auth/DemoAuth.ts","../src/tools/auth/PassphraseAuth.ts","../src/tools/implementation/invites.ts","../src/tools/coValues/request.ts","../src/tools/config.ts","../src/tools/index.ts"],"sourcesContent":["import {\n Account,\n AuthCredentials,\n AuthSecretStorage,\n AuthenticateAccountFunction,\n} from \"jazz-tools\";\nimport { getClerkUsername } from \"./getClerkUsername.js\";\nimport {\n ClerkCredentials,\n MinimalClerkClient,\n isClerkAuthStateEqual,\n isClerkCredentials,\n} from \"./types.js\";\n\nexport type { MinimalClerkClient };\nexport { isClerkCredentials };\n\nexport class JazzClerkAuth {\n constructor(\n private authenticate: AuthenticateAccountFunction,\n private logOut: () => Promise<void> | void,\n private authSecretStorage: AuthSecretStorage,\n ) {}\n\n /**\n * Loads the Jazz auth data from the Clerk user and sets it in the auth secret storage.\n */\n static loadClerkAuthData(\n credentials: ClerkCredentials,\n storage: AuthSecretStorage,\n ) {\n return storage.set({\n accountID: credentials.jazzAccountID,\n accountSecret: credentials.jazzAccountSecret,\n secretSeed: credentials.jazzAccountSeed\n ? Uint8Array.from(credentials.jazzAccountSeed)\n : undefined,\n provider: \"clerk\",\n });\n }\n\n static async initializeAuth(clerk: MinimalClerkClient) {\n const secretStorage = new AuthSecretStorage();\n\n if (!isClerkCredentials(clerk.user?.unsafeMetadata)) {\n return;\n }\n\n await JazzClerkAuth.loadClerkAuthData(\n clerk.user.unsafeMetadata,\n secretStorage,\n );\n }\n\n private isFirstCall = true;\n\n registerListener(clerkClient: MinimalClerkClient) {\n let previousUser: MinimalClerkClient[\"user\"] | null =\n clerkClient.user ?? null;\n\n // Need to use addListener because the clerk user object is not updated when the user logs in\n return clerkClient.addListener((event) => {\n const user = (event as Pick<MinimalClerkClient, \"user\">).user ?? null;\n\n if (!isClerkAuthStateEqual(previousUser, user) || this.isFirstCall) {\n this.onClerkUserChange({ user });\n previousUser = user;\n this.isFirstCall = false;\n }\n });\n }\n\n onClerkUserChange = async (clerkClient: Pick<MinimalClerkClient, \"user\">) => {\n const isAuthenticated = this.authSecretStorage.isAuthenticated;\n\n // LogOut is driven by Clerk. The framework adapters will need to pass `logOutReplacement` to the `JazzProvider`\n // to make the logOut work correctly.\n if (!clerkClient.user) {\n if (isAuthenticated) {\n this.authSecretStorage.clear();\n await this.logOut();\n }\n return;\n }\n\n if (isAuthenticated) return;\n\n const clerkCredentials = clerkClient.user\n .unsafeMetadata as ClerkCredentials;\n\n if (!clerkCredentials.jazzAccountID) {\n await this.signIn(clerkClient);\n } else {\n await this.logIn(clerkClient);\n }\n };\n\n logIn = async (clerkClient: Pick<MinimalClerkClient, \"user\">) => {\n if (!clerkClient.user) {\n throw new Error(\"Not signed in on Clerk\");\n }\n\n const clerkCredentials = clerkClient.user.unsafeMetadata;\n if (!isClerkCredentials(clerkCredentials)) {\n throw new Error(\"No credentials found on Clerk\");\n }\n\n const credentials = {\n accountID: clerkCredentials.jazzAccountID,\n accountSecret: clerkCredentials.jazzAccountSecret,\n secretSeed: clerkCredentials.jazzAccountSeed\n ? Uint8Array.from(clerkCredentials.jazzAccountSeed)\n : undefined,\n provider: \"clerk\",\n } satisfies AuthCredentials;\n\n await this.authenticate(credentials);\n\n await JazzClerkAuth.loadClerkAuthData(\n {\n jazzAccountID: credentials.accountID,\n jazzAccountSecret: credentials.accountSecret,\n jazzAccountSeed: clerkCredentials.jazzAccountSeed,\n },\n this.authSecretStorage,\n );\n };\n\n signIn = async (clerkClient: Pick<MinimalClerkClient, \"user\">) => {\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials) {\n throw new Error(\"No credentials found\");\n }\n\n const jazzAccountSeed = credentials.secretSeed\n ? Array.from(credentials.secretSeed)\n : undefined;\n\n await clerkClient.user?.update({\n unsafeMetadata: {\n jazzAccountID: credentials.accountID,\n jazzAccountSecret: credentials.accountSecret,\n jazzAccountSeed,\n } satisfies ClerkCredentials,\n });\n\n const currentAccount = await Account.getMe().$jazz.ensureLoaded({\n resolve: {\n profile: true,\n },\n });\n\n const username = getClerkUsername(clerkClient);\n\n if (username) {\n currentAccount.profile.$jazz.set(\"name\", username);\n }\n\n await JazzClerkAuth.loadClerkAuthData(\n {\n jazzAccountID: credentials.accountID,\n jazzAccountSecret: credentials.accountSecret,\n jazzAccountSeed,\n },\n this.authSecretStorage,\n );\n };\n}\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace BrowserClerkAuth {\n export interface Driver {\n onError: (error: string | Error) => void;\n }\n}\n","import type { MinimalClerkClient } from \"./types.js\";\n\nexport function getClerkUsername(\n clerkClient: Pick<MinimalClerkClient, \"user\">,\n) {\n if (!clerkClient.user) {\n return null;\n }\n\n if (clerkClient.user.fullName) {\n return clerkClient.user.fullName;\n }\n\n if (clerkClient.user.firstName) {\n if (clerkClient.user.lastName) {\n return `${clerkClient.user.firstName} ${clerkClient.user.lastName}`;\n }\n\n return clerkClient.user.firstName;\n }\n\n if (clerkClient.user.username) {\n return clerkClient.user.username;\n }\n\n if (clerkClient.user.primaryEmailAddress?.emailAddress) {\n const emailUsername =\n clerkClient.user.primaryEmailAddress.emailAddress.split(\"@\")[0];\n\n if (emailUsername) {\n return emailUsername;\n }\n }\n\n return clerkClient.user.id;\n}\n","import { AgentSecret } from \"cojson\";\nimport { Account, ID } from \"jazz-tools\";\n\nexport type MinimalClerkClient = {\n user:\n | {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n unsafeMetadata: Record<string, any>;\n fullName: string | null;\n username: string | null;\n firstName: string | null;\n lastName: string | null;\n id: string;\n primaryEmailAddress: {\n emailAddress: string | null;\n } | null;\n update: (args: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n unsafeMetadata: Record<string, any>;\n }) => Promise<unknown>;\n }\n | null\n | undefined;\n signOut: () => Promise<void>;\n addListener: (listener: (data: unknown) => void) => void;\n};\n\nexport type ClerkCredentials = {\n jazzAccountID: ID<Account>;\n jazzAccountSecret: AgentSecret;\n jazzAccountSeed?: number[];\n};\n\n/**\n * Checks if the Clerk user metadata contains the necessary credentials for Jazz auth.\n * **Note**: It does not validate the credentials, only checks if the necessary fields are present in the metadata object.\n */\nexport function isClerkCredentials(\n data: NonNullable<MinimalClerkClient[\"user\"]>[\"unsafeMetadata\"] | undefined,\n): data is ClerkCredentials {\n return !!data && \"jazzAccountID\" in data && \"jazzAccountSecret\" in data;\n}\n\nexport function isClerkAuthStateEqual(\n previousUser: MinimalClerkClient[\"user\"] | null | undefined,\n newUser: MinimalClerkClient[\"user\"] | null | undefined,\n) {\n if (Boolean(previousUser) !== Boolean(newUser)) {\n return false;\n }\n\n const previousCredentials = isClerkCredentials(previousUser?.unsafeMetadata);\n const newCredentials = isClerkCredentials(newUser?.unsafeMetadata);\n\n return previousCredentials === newCredentials;\n}\n","import { AgentSecret } from \"cojson\";\nimport { Account, ID } from \"../internal.js\";\nimport { AuthenticateAccountFunction } from \"../types.js\";\nimport { AuthSecretStorage } from \"./AuthSecretStorage.js\";\nimport { KvStore, KvStoreContext } from \"./KvStoreContext.js\";\n\ntype StorageData = {\n accountID: ID<Account>;\n accountSecret: AgentSecret;\n secretSeed?: number[];\n};\n\n/**\n * `DemoAuth` provides a `JazzAuth` object for demo authentication.\n *\n * Demo authentication is useful for quickly testing your app, as it allows you to create new accounts and log in as existing ones.\n *\n * ```\n * import { DemoAuth } from \"jazz-tools\";\n *\n * const auth = new DemoAuth(jazzContext.authenticate, new AuthSecretStorage());\n * ```\n *\n * @category Auth Providers\n */\nexport class DemoAuth {\n constructor(\n private authenticate: AuthenticateAccountFunction,\n private authSecretStorage: AuthSecretStorage,\n ) {}\n\n logIn = async (username: string) => {\n const existingUsers = await this.getExisitingUsersWithData();\n const storageData = existingUsers[username];\n\n if (!storageData?.accountID) {\n throw new Error(\"User not found\");\n }\n\n await this.authenticate({\n accountID: storageData.accountID,\n accountSecret: storageData.accountSecret,\n });\n\n await this.authSecretStorage.set({\n accountID: storageData.accountID,\n accountSecret: storageData.accountSecret,\n secretSeed: storageData.secretSeed\n ? new Uint8Array(storageData.secretSeed)\n : undefined,\n provider: \"demo\",\n });\n };\n\n signUp = async (username: string) => {\n const existingUsers = await this.getExistingUsers();\n if (existingUsers.includes(username)) {\n throw new Error(\"User already registered\");\n }\n\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials) {\n throw new Error(\"No credentials found\");\n }\n\n const currentAccount = await Account.getMe().$jazz.ensureLoaded({\n resolve: {\n profile: true,\n },\n });\n\n currentAccount.profile.$jazz.set(\"name\", username);\n\n await this.authSecretStorage.set({\n accountID: credentials.accountID,\n accountSecret: credentials.accountSecret,\n secretSeed: credentials.secretSeed\n ? new Uint8Array(credentials.secretSeed)\n : undefined,\n provider: \"demo\",\n });\n\n await this.addToExistingUsers(username, {\n accountID: credentials.accountID,\n accountSecret: credentials.accountSecret,\n secretSeed: credentials.secretSeed\n ? Array.from(credentials.secretSeed)\n : undefined,\n });\n };\n\n private async addToExistingUsers(username: string, data: StorageData) {\n const existingUsers = await this.getExisitingUsersWithData();\n\n if (existingUsers[username]) {\n return;\n }\n\n existingUsers[username] = data;\n\n const kvStore = KvStoreContext.getInstance().getStorage();\n await kvStore.set(\"demo-auth-users\", JSON.stringify(existingUsers));\n }\n\n private async getExisitingUsersWithData() {\n const kvStore = KvStoreContext.getInstance().getStorage();\n await migrateExistingUsers(kvStore);\n\n const existingUsers = await kvStore.get(\"demo-auth-users\");\n return existingUsers ? JSON.parse(existingUsers) : {};\n }\n\n getExistingUsers = async () => {\n return Object.keys(await this.getExisitingUsersWithData());\n };\n}\n\nexport function encodeUsername(username: string) {\n return btoa(username)\n .replace(/=/g, \"-\")\n .replace(/\\+/g, \"_\")\n .replace(/\\//g, \".\");\n}\n\nasync function getStorageVersion(kvStore: KvStore) {\n try {\n const version = await kvStore.get(\"demo-auth-storage-version\");\n return version ? parseInt(version) : 1;\n } catch (error) {\n return 1;\n }\n}\n\nasync function setStorageVersion(kvStore: KvStore, version: number) {\n await kvStore.set(\"demo-auth-storage-version\", version.toString());\n}\n\nasync function getExistingUsersList(kvStore: KvStore) {\n const existingUsers = await kvStore.get(\"demo-auth-existing-users\");\n return existingUsers ? existingUsers.split(\",\") : [];\n}\n\n/**\n * Migrates existing users keys to work with any storage.\n */\nasync function migrateExistingUsers(kvStore: KvStore) {\n if ((await getStorageVersion(kvStore)) < 2) {\n const existingUsers = await getExistingUsersList(kvStore);\n\n for (const username of existingUsers) {\n const legacyKey = `demo-auth-existing-users-${username}`;\n const storageData = await kvStore.get(legacyKey);\n if (storageData) {\n await kvStore.set(\n `demo-auth-existing-users-${encodeUsername(username)}`,\n storageData,\n );\n await kvStore.delete(legacyKey);\n }\n }\n\n await setStorageVersion(kvStore, 2);\n }\n\n if ((await getStorageVersion(kvStore)) < 3) {\n const existingUsersList = await getExistingUsersList(kvStore);\n\n const existingUsers: Record<string, StorageData> = {};\n const keysToDelete: string[] = [\"demo-auth-existing-users\"];\n\n for (const username of existingUsersList) {\n const key = `demo-auth-existing-users-${encodeUsername(username)}`;\n const storageData = await kvStore.get(key);\n if (storageData) {\n existingUsers[username] = JSON.parse(storageData);\n keysToDelete.push(key);\n }\n }\n\n await kvStore.set(\"demo-auth-users\", JSON.stringify(existingUsers));\n\n for (const key of keysToDelete) {\n await kvStore.delete(key);\n }\n\n await setStorageVersion(kvStore, 3);\n }\n}\n","import * as bip39 from \"@scure/bip39\";\nimport { entropyToMnemonic } from \"@scure/bip39\";\nimport { CryptoProvider, cojsonInternals } from \"cojson\";\nimport type { ID } from \"../internal.js\";\nimport { Account } from \"../internal.js\";\nimport type {\n AuthenticateAccountFunction,\n RegisterAccountFunction,\n} from \"../types.js\";\nimport { AuthSecretStorage } from \"./AuthSecretStorage.js\";\n\n/**\n * `PassphraseAuth` provides a `JazzAuth` object for passphrase authentication.\n *\n * ```ts\n * import { PassphraseAuth } from \"jazz-tools\";\n *\n * const auth = new PassphraseAuth(crypto, jazzContext.authenticate, new AuthSecretStorage(), wordlist);\n * ```\n *\n * @category Auth Providers\n */\nexport class PassphraseAuth {\n passphrase: string = \"\";\n\n constructor(\n private crypto: CryptoProvider,\n private authenticate: AuthenticateAccountFunction,\n private register: RegisterAccountFunction,\n private authSecretStorage: AuthSecretStorage,\n public wordlist: string[],\n ) {}\n\n logIn = async (passphrase: string) => {\n const { crypto, authenticate } = this;\n\n let secretSeed;\n\n try {\n secretSeed = bip39.mnemonicToEntropy(passphrase, this.wordlist);\n } catch (e) {\n throw new Error(\"Invalid passphrase\");\n }\n\n const accountSecret = crypto.agentSecretFromSecretSeed(secretSeed);\n\n const accountID = cojsonInternals.idforHeader(\n cojsonInternals.accountHeaderForInitialAgentSecret(accountSecret, crypto),\n crypto,\n ) as ID<Account>;\n\n await authenticate({\n accountID,\n accountSecret,\n });\n\n await this.authSecretStorage.set({\n accountID,\n secretSeed,\n accountSecret,\n provider: \"passphrase\",\n });\n\n this.passphrase = passphrase;\n this.notify();\n };\n\n signUp = async (name?: string) => {\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials || !credentials.secretSeed) {\n throw new Error(\"No credentials found\");\n }\n\n const passphrase = entropyToMnemonic(credentials.secretSeed, this.wordlist);\n\n await this.authSecretStorage.set({\n accountID: credentials.accountID,\n secretSeed: credentials.secretSeed,\n accountSecret: credentials.accountSecret,\n provider: \"passphrase\",\n });\n\n if (name?.trim()) {\n const currentAccount = await Account.getMe().$jazz.ensureLoaded({\n resolve: {\n profile: true,\n },\n });\n\n currentAccount.profile.$jazz.set(\"name\", name);\n }\n\n return passphrase;\n };\n\n registerNewAccount = async (passphrase: string, name: string) => {\n const secretSeed = bip39.mnemonicToEntropy(passphrase, this.wordlist);\n const accountSecret = this.crypto.agentSecretFromSecretSeed(secretSeed);\n const accountID = await this.register(accountSecret, { name });\n\n await this.authSecretStorage.set({\n accountID,\n secretSeed,\n accountSecret,\n provider: \"passphrase\",\n });\n\n return accountID;\n };\n\n getCurrentAccountPassphrase = async () => {\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials || !credentials.secretSeed) {\n throw new Error(\"No credentials found\");\n }\n\n return entropyToMnemonic(credentials.secretSeed, this.wordlist);\n };\n\n generateRandomPassphrase = () => {\n return entropyToMnemonic(this.crypto.newRandomSecretSeed(), this.wordlist);\n };\n\n loadCurrentAccountPassphrase = async () => {\n const passphrase = await this.getCurrentAccountPassphrase();\n this.passphrase = passphrase;\n this.notify();\n };\n\n listeners = new Set<() => void>();\n subscribe = (callback: () => void) => {\n this.listeners.add(callback);\n\n return () => {\n this.listeners.delete(callback);\n };\n };\n\n notify() {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n","import { AccountRole, type InviteSecret, cojsonInternals } from \"cojson\";\nimport { Account } from \"../coValues/account.js\";\nimport type { CoValue, CoValueClassOrSchema } from \"../internal.js\";\n\n/** @category Invite Links */\nexport function createInviteLink<C extends CoValue>(\n value: C,\n role: AccountRole,\n baseURL: string,\n valueHint?: string,\n): string {\n const coValueCore = value.$jazz.raw.core;\n let currentCoValue = coValueCore;\n\n while (currentCoValue.verified.header.ruleset.type === \"ownedByGroup\") {\n currentCoValue = currentCoValue.getGroup().core;\n }\n\n const { ruleset, meta } = currentCoValue.verified.header;\n\n if (ruleset.type !== \"group\" || meta?.type === \"account\") {\n throw new Error(\"Can't create invite link for object without group\");\n }\n\n const group = cojsonInternals.expectGroup(currentCoValue.getCurrentContent());\n const inviteSecret = group.createInvite(role);\n\n return `${baseURL}#/invite/${valueHint ? valueHint + \"/\" : \"\"}${\n value.$jazz.id\n }/${inviteSecret}`;\n}\n\n/** @category Invite Links */\nexport function parseInviteLink(inviteURL: string):\n | {\n valueID: string;\n valueHint?: string;\n inviteSecret: InviteSecret;\n }\n | undefined {\n const url = new URL(inviteURL);\n const parts = url.hash.split(\"/\");\n\n let valueHint: string | undefined;\n let valueID: string | undefined;\n let inviteSecret: InviteSecret | undefined;\n\n if (parts[0] === \"#\" && parts[1] === \"invite\") {\n if (parts.length === 5) {\n valueHint = parts[2];\n valueID = parts[3];\n inviteSecret = parts[4] as InviteSecret;\n } else if (parts.length === 4) {\n valueID = parts[2];\n inviteSecret = parts[3] as InviteSecret;\n }\n\n if (!valueID || !inviteSecret) {\n return undefined;\n }\n return { valueID, inviteSecret, valueHint };\n }\n}\n\n/** @category Invite Links */\nexport function consumeInviteLink<S extends CoValueClassOrSchema>({\n inviteURL,\n as = Account.getMe(),\n forValueHint,\n invitedObjectSchema,\n}: {\n inviteURL: string;\n as?: Account;\n forValueHint?: string;\n invitedObjectSchema: S;\n}): Promise<\n | {\n valueID: string;\n valueHint?: string;\n inviteSecret: InviteSecret;\n }\n | undefined\n> {\n return new Promise((resolve, reject) => {\n const result = parseInviteLink(inviteURL);\n\n if (result && result.valueHint === forValueHint) {\n as.acceptInvite(result.valueID, result.inviteSecret, invitedObjectSchema)\n .then(() => {\n resolve(result);\n })\n .catch(reject);\n } else {\n resolve(undefined);\n }\n });\n}\n","import {\n CoValueCore,\n CojsonInternalTypes,\n CryptoProvider,\n RawAccount,\n RawCoMap,\n cojsonInternals,\n} from \"cojson\";\nimport z from \"zod/v4\";\nimport {\n AnyZodOrCoValueSchema,\n CoMap,\n CoMapSchema,\n CoMapSchemaInit,\n CoValueClass,\n CoreCoMapSchema,\n Group,\n Loaded,\n ResolveQuery,\n ResolveQueryStrict,\n Simplify,\n coMapDefiner,\n coValueClassFromCoValueClassOrSchema,\n exportCoValue,\n importContentPieces,\n loadCoValue,\n} from \"../internal.js\";\nimport { isCoValueId } from \"../lib/utils.js\";\nimport { Account } from \"./account.js\";\n\ntype MessageShape = Record<string, AnyZodOrCoValueSchema>;\n\ntype RequestSchemaDefinition<\n S extends MessageShape,\n R extends ResolveQuery<CoMapSchema<S>> = true,\n> =\n | S\n | {\n schema: S;\n resolve?: R;\n };\n\n/**\n * Configuration options for defining HTTP request/response schemas in Jazz.\n *\n * This interface defines the structure for creating typed HTTP routes with\n * request and response validation using CoMap schemas.\n *\n * @template RequestShape - The shape of the request message schema (must extend MessageShape)\n * @template RequestResolve - The resolve query type for the request CoMap schema\n * @template ResponseShape - The shape of the response message schema (must extend MessageShape)\n * @template ResponseResolve - The resolve query type for the response CoMap schema\n */\ninterface RequestOptions<\n RequestShape extends MessageShape,\n RequestResolve extends ResolveQuery<CoMapSchema<RequestShape>>,\n ResponseShape extends MessageShape,\n ResponseResolve extends ResolveQuery<CoMapSchema<ResponseShape>>,\n> {\n /**\n * The URL endpoint for the HTTP route.\n * This is used by the client to send requests to the server.\n */\n url: string;\n\n /**\n * The id of the worker Account or Group.\n */\n workerId: string;\n\n /**\n * Schema definition for the request payload.\n * Can be either a direct schema object or an object with schema and optional resolve properties.\n * The schema defines the structure and validation rules for incoming requests.\n */\n request: RequestSchemaDefinition<\n RequestShape,\n ResolveQueryStrict<CoMapSchema<RequestShape>, RequestResolve>\n >;\n\n /**\n * Schema definition for the response payload.\n * Can be either a direct schema object or an object with schema and optional resolve properties.\n * The schema defines the structure and validation rules for outgoing responses.\n */\n response: RequestSchemaDefinition<\n ResponseShape,\n ResolveQueryStrict<CoMapSchema<ResponseShape>, ResponseResolve>\n >;\n}\n\ntype AsNullablePayload<T extends MessageShape> = T extends Record<string, never>\n ? undefined\n : never;\ntype MessageValuePayload<T extends MessageShape> =\n | Simplify<CoMapSchemaInit<T>>\n | AsNullablePayload<T>;\n\nfunction createMessageEnvelope<S extends MessageShape>(\n schema: CoreCoMapSchema,\n value: MessageValuePayload<S>,\n owner: Account,\n sharedWith: Account | Group,\n type: \"request\" | \"response\",\n): Loaded<CoMapSchema<S>> {\n const group = Group.create({ owner });\n\n if (type === \"request\") {\n group.addMember(sharedWith, \"writer\");\n } else {\n group.addMember(sharedWith, \"reader\");\n }\n\n // @ts-expect-error - CoreCoMapSchema doesn't have static methods\n return schema.create(value ?? {}, group);\n}\n\n/**\n * Function that exports the input CoValue in a serializable format and prepares the information\n * required for the other side to safely verify the identity of the sender.\n */\nasync function serializeMessagePayload({\n type,\n schema,\n resolve,\n value,\n owner,\n target,\n}: {\n // Skipping type validation here to avoid excessive type complexity that affects the typecheck performance\n type: \"request\" | \"response\";\n schema: CoreCoMapSchema;\n resolve: any;\n value: any;\n owner: Account;\n target: Account | Group;\n}) {\n const me = owner ?? Account.getMe();\n const node = me.$jazz.localNode;\n const crypto = node.crypto;\n\n const agent = node.getCurrentAgent();\n const signerID = agent.currentSignerID();\n const signerSecret = agent.currentSignerSecret();\n\n const envelope = createMessageEnvelope(schema, value, me, target, type);\n\n const contentPieces =\n (await exportCoValue(schema, envelope.$jazz.id, {\n resolve,\n loadAs: me,\n bestEffortResolution: true,\n })) ?? [];\n\n const createdAt = Date.now();\n\n const signPayload = crypto.secureHash({\n contentPieces,\n id: envelope.$jazz.id,\n createdAt,\n signerID,\n });\n\n const authToken = crypto.sign(signerSecret, signPayload);\n\n return {\n contentPieces,\n id: envelope.$jazz.id,\n createdAt,\n authToken,\n signerID,\n };\n}\n\nconst coIdSchema = z.custom<`co_z${string}`>(isCoValueId);\nconst signatureSchema = z.custom<`signature_z${string}`>(\n (value) => typeof value === \"string\" && value.startsWith(\"signature_z\"),\n);\n\nconst requestSchema = z.object({\n contentPieces: z.array(z.json()),\n id: coIdSchema,\n createdAt: z.number(),\n authToken: signatureSchema,\n signerID: z.custom<`signer_z${string}`>(\n (value) => typeof value === \"string\" && value.startsWith(\"signer_z\"),\n ),\n});\n\n/**\n * Function that parses the message payload, verifies the identity of the sender and loads the data.\n *\n * @returns The data from the message.\n */\nasync function handleMessagePayload({\n type,\n schema,\n resolve,\n request,\n loadAs,\n}: {\n type: \"request\" | \"response\";\n // Skipping type validation here to avoid excessive type complexity that affects the typecheck performance\n schema: CoreCoMapSchema;\n resolve: any;\n request: unknown;\n loadAs: Account;\n}) {\n const node = loadAs.$jazz.localNode;\n const crypto = node.crypto;\n\n const requestParsed = requestSchema.safeParse(request);\n\n if (!requestParsed.success) {\n throw new JazzRequestError(\n \"Request payload is not valid\",\n 400,\n requestParsed.error,\n );\n }\n\n const requestData = requestParsed.data;\n\n if (type === \"request\") {\n const core = await node.loadCoValueCore(requestData.id, undefined, true);\n\n // Check if the message has already been handled to prevent replay attacks\n if (core.isAvailable()) {\n const content = core.getCurrentContent() as RawCoMap;\n\n if (content.get(\"$handled\") === loadAs.$jazz.id) {\n throw new JazzRequestError(\"Request payload is already handled\", 400);\n }\n }\n\n // Check if the message is expired as extra protection\n if (requestData.createdAt + 1000 * 60 < Date.now()) {\n throw new JazzRequestError(\"Authentication token is expired\", 401);\n }\n }\n\n // Verify the signature of the message to prevent tampering\n const signPayload = crypto.secureHash({\n contentPieces: requestData.contentPieces,\n id: requestData.id,\n createdAt: requestData.createdAt,\n signerID: requestData.signerID,\n });\n\n if (\n !safeVerifySignature(\n crypto,\n signPayload,\n requestData.signerID,\n requestData.authToken,\n )\n ) {\n throw new JazzRequestError(\"Invalid signature\", 401);\n }\n\n let contentPieces =\n requestData.contentPieces as CojsonInternalTypes.NewContentMessage[];\n\n if (type === \"request\") {\n const coValueContent = contentPieces.find(\n (piece) => piece.id === requestData.id,\n );\n\n if (coValueContent && coValueContent.header) {\n const validValues = cojsonInternals.getDependedOnCoValues(\n coValueContent.header,\n coValueContent,\n );\n validValues.add(requestData.id);\n contentPieces = contentPieces.filter((piece) =>\n validValues.has(piece.id),\n );\n } else {\n contentPieces = [];\n }\n }\n\n importContentPieces(contentPieces, loadAs);\n\n const coValue = await node.loadCoValueCore(requestData.id);\n const accountId = getCoValueCreatorAccountId(coValue);\n\n const madeBy = await Account.load(accountId, {\n loadAs,\n });\n\n if (!madeBy.$isLoaded) {\n throw new JazzRequestError(\"Creator account not found\", 400);\n }\n\n const coSchema = coValueClassFromCoValueClassOrSchema(\n schema,\n ) as CoValueClass<CoMap>;\n const value = await loadCoValue<CoMap, true>(coSchema, requestData.id, {\n resolve,\n loadAs,\n });\n\n if (!value.$isLoaded) {\n throw new JazzRequestError(\"Value not found\", 400);\n }\n\n if (type === \"request\") {\n value.$jazz.raw.set(\"$handled\", loadAs.$jazz.id);\n }\n\n return {\n value: value as unknown,\n madeBy,\n };\n}\n\nfunction parseSchemaAndResolve<\n S extends MessageShape,\n R extends ResolveQuery<CoMapSchema<S>>,\n>(options: RequestSchemaDefinition<S, R>) {\n if (\"schema\" in options) {\n return {\n // Using a type cast to reduce the type complexity\n schema: coMapDefiner(options.schema) as CoreCoMapSchema,\n resolve: options.resolve as any,\n };\n }\n\n return {\n schema: coMapDefiner(options) as CoreCoMapSchema,\n resolve: true as any,\n };\n}\n\nexport class HttpRoute<\n RequestShape extends MessageShape = z.core.$ZodLooseShape,\n RequestResolve extends ResolveQuery<CoMapSchema<RequestShape>> = any,\n ResponseShape extends MessageShape = z.core.$ZodLooseShape,\n ResponseResolve extends ResolveQuery<CoMapSchema<ResponseShape>> = any,\n> {\n private requestDefinition: {\n schema: CoreCoMapSchema;\n resolve: any;\n };\n private responseDefinition: {\n schema: CoreCoMapSchema;\n resolve: any;\n };\n private url: string;\n private workerId: string;\n\n constructor(\n params: RequestOptions<\n RequestShape,\n RequestResolve,\n ResponseShape,\n ResponseResolve\n >,\n ) {\n this.requestDefinition = parseSchemaAndResolve(params.request);\n this.responseDefinition = parseSchemaAndResolve(params.response);\n this.url = params.url;\n this.workerId = params.workerId;\n\n if (params.workerId === undefined) {\n throw new TypeError(\"Worker ID is required\");\n }\n }\n\n async send(\n values: MessageValuePayload<RequestShape>,\n options?: { owner?: Account },\n ): Promise<Loaded<CoMapSchema<ResponseShape>, ResponseResolve>> {\n const as = options?.owner ?? Account.getMe();\n\n const target = await loadWorkerAccountOrGroup(this.workerId, as);\n\n const response = await fetch(this.url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(\n await serializeMessagePayload({\n type: \"request\",\n schema: this.requestDefinition.schema,\n resolve: true, // export only the envelope\n value: values,\n owner: as,\n target,\n }),\n ),\n });\n\n if (!response.ok) {\n if (response.headers.has(\"X-Jazz-Request-Error\")) {\n const error = await response.json();\n throw new JazzRequestError(error.message, error.code, error.details);\n }\n\n throw new JazzRequestError(\"Request failed\", response.status);\n }\n\n const responseBody = await response.json();\n\n const responseParsed = z\n .object({\n type: z.literal(\"success\"),\n payload: z.any(),\n })\n .safeParse(responseBody);\n\n if (!responseParsed.success) {\n throw new JazzRequestError(\n \"Response payload is not valid\",\n 400,\n responseParsed.error,\n );\n }\n\n const data = await handleMessagePayload({\n type: \"response\",\n schema: this.responseDefinition.schema,\n resolve: this.responseDefinition.resolve,\n request: responseParsed.data.payload,\n loadAs: as,\n });\n\n return data.value as Loaded<CoMapSchema<ResponseShape>, ResponseResolve>;\n }\n\n handle = async (\n request: Request,\n as: Account,\n callback: (\n value: Loaded<CoMapSchema<RequestShape>, RequestResolve>,\n madeBy: Account,\n ) =>\n | Promise<MessageValuePayload<ResponseShape>>\n | MessageValuePayload<ResponseShape>,\n ): Promise<Response> => {\n try {\n const response = await this.executeHandleRequest(request, as, callback);\n return response;\n } catch (error) {\n // Serialize the error to make it possible to handle it on the client side\n if (isJazzRequestError(error)) {\n return new Response(JSON.stringify(error.toJSON()), {\n status: error.code,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Jazz-Request-Error\": \"true\",\n },\n });\n }\n\n throw error;\n }\n };\n\n executeHandleRequest = async (\n request: Request,\n as: Account,\n callback: (\n value: Loaded<CoMapSchema<RequestShape>, RequestResolve>,\n madeBy: Account,\n ) =>\n | Promise<MessageValuePayload<ResponseShape>>\n | MessageValuePayload<ResponseShape>,\n ): Promise<Response> => {\n const node = as.$jazz.localNode;\n const body = await request.json();\n const data = await handleMessagePayload({\n type: \"request\",\n schema: this.requestDefinition.schema,\n resolve: this.requestDefinition.resolve,\n request: body,\n loadAs: as,\n });\n\n const tracking = node.syncManager.trackDirtyCoValues();\n\n const responseValue = await callback(\n data.value as Loaded<CoMapSchema<RequestShape>, RequestResolve>,\n data.madeBy,\n );\n\n const responsePayload = await serializeMessagePayload({\n type: \"response\",\n schema: this.responseDefinition.schema,\n resolve: this.responseDefinition.resolve,\n value: responseValue,\n owner: as,\n target: data.madeBy,\n });\n\n const responseBody = JSON.stringify({\n type: \"success\",\n payload: responsePayload,\n });\n\n // TODO: Detect the defer support from the environment\n await Promise.all(\n Array.from(tracking.done(), (id) => node.syncManager.waitForSync(id)),\n );\n\n return new Response(responseBody, {\n status: 200,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n });\n };\n\n get requestSchema(): CoMapSchema<RequestShape> {\n return this.requestDefinition.schema as CoMapSchema<RequestShape>;\n }\n\n get responseSchema() {\n return this.responseDefinition.schema as CoMapSchema<ResponseShape>;\n }\n}\n\n/**\n * Define a request route.\n *\n * @param params - The parameters for the request route.\n * @returns The request route.\n *\n * @see {@link https://jazz.tools/docs/react/server-side/http-requests}\n */\nexport function experimental_defineRequest<\n RequestShape extends MessageShape,\n RequestResolve extends ResolveQuery<CoMapSchema<RequestShape>>,\n ResponseShape extends MessageShape,\n ResponseResolve extends ResolveQuery<CoMapSchema<ResponseShape>>,\n>(\n params: RequestOptions<\n RequestShape,\n RequestResolve,\n ResponseShape,\n ResponseResolve\n >,\n) {\n return new HttpRoute(params);\n}\n\nfunction getCoValueCreatorAccountId(coValue: CoValueCore) {\n if (!coValue.isAvailable()) {\n throw new Error(\"Unable to load the request payload\");\n }\n\n const creatorSessionId = coValue.getValidSortedTransactions().at(0)\n ?.txID.sessionID;\n\n if (!creatorSessionId) {\n throw new JazzRequestError(\n \"Request payload is not valid, creator session ID not found\",\n 400,\n );\n }\n\n const accountId =\n cojsonInternals.accountOrAgentIDfromSessionID(creatorSessionId);\n\n if (!isCoValueId(accountId)) {\n throw new JazzRequestError(\n \"Request payload is not valid, the creator is not a valid account\",\n 400,\n );\n }\n\n return accountId;\n}\n\nexport class JazzRequestError {\n public readonly isJazzRequestError = true;\n\n constructor(\n public readonly message: string,\n public readonly code: number,\n public readonly details?: unknown,\n ) {}\n\n toJSON() {\n return { message: this.message, code: this.code, details: this.details };\n }\n}\n\nexport function isJazzRequestError(error: unknown): error is JazzRequestError {\n return (\n error instanceof JazzRequestError ||\n (typeof error === \"object\" &&\n error !== null &&\n \"isJazzRequestError\" in error &&\n Boolean(error.isJazzRequestError))\n );\n}\n\nfunction safeVerifySignature(\n crypto: CryptoProvider,\n signPayload: `hash_z${string}`,\n signerID: `signer_z${string}`,\n authToken: `signature_z${string}`,\n) {\n try {\n return crypto.verify(authToken, signPayload, signerID);\n } catch (error) {\n return false;\n }\n}\n\nasync function loadWorkerAccountOrGroup(id: string, loadAs: Account) {\n const node = loadAs.$jazz.localNode;\n const coValue = await node.loadCoValueCore(id as `co_z${string}`);\n\n if (!coValue.isAvailable()) {\n throw new JazzRequestError(\"Worker account not found\", 400);\n }\n\n const content = coValue.getCurrentContent();\n\n if (content instanceof RawAccount) {\n const account = await Account.load(content.id, {\n loadAs,\n });\n if (!account.$isLoaded) {\n throw new JazzRequestError(\"Worker account not found\", 400);\n }\n return account;\n }\n\n const group = await Group.load(content.id, {\n loadAs,\n });\n\n if (!group.$isLoaded) {\n throw new JazzRequestError(\"Worker group not found\", 400);\n }\n return group;\n}\n\nfunction defaultGetToken(request: Request) {\n const headerValue = request.headers.get(\"Authorization\");\n if (headerValue?.startsWith(\"Jazz \")) {\n return headerValue.replace(\"Jazz \", \"\");\n }\n\n if (headerValue) {\n console.warn(\n \"An Authorization header was found, but it did not start with 'Jazz '. If this is intentional, you can specify the location of the token using the `getToken` option.\",\n );\n }\n\n return undefined;\n}\n\n/**\n * Authenticates a Request by verifying a signed authentication token.\n *\n * - If a token is not provided, the returned account is `undefined` and no error is returned.\n * - If a valid token is provided, the signer account is returned.\n * - If an invalid token is provided, an error is returned detailing the validation error, and the returned account is `undefined`.\n *\n * @see {@link generateAuthToken} for generating a token.\n *\n * Note: This function does not perform any authorization checks, it only verifies if - **when provided** - a token is valid. It is up to the caller to perform any additional authorization checks, if needed.\n *\n * @param request - The request to authenticate.\n * @param options - The options for the authentication.\n * @param options.expiration - The expiration time of the token in milliseconds, defaults to 1 minute.\n * @param options.loadAs - The account to load the token from, defaults to the current active account.\n * @param options.getToken - If specified, this function will be used to get the token from the request. By default the token is expected to be in the `Authorization` header in the form of `Jazz <token>`.\n * @returns The account if it is valid, otherwise an error.\n *\n * @example\n * ```ts\n * const { account, error } = await authenticateRequest(request);\n * if (error) {\n * return new Response(JSON.stringify(error), { status: 401 });\n * }\n * ```\n */\nexport async function authenticateRequest(\n request: Request,\n options?: {\n expiration?: number;\n loadAs?: Account;\n getToken?: (request: Request) => string | undefined | null;\n },\n): Promise<\n | {\n account?: Account;\n error?: never;\n }\n | {\n account?: never;\n error: { message: string; details?: unknown };\n }\n> {\n const token = options?.getToken?.(request) ?? defaultGetToken(request);\n\n if (!token) {\n return {};\n }\n\n const { account, error } = await parseAuthToken(token, {\n loadAs: options?.loadAs,\n expiration: options?.expiration ?? 1000 * 60,\n });\n\n if (error) {\n return { error };\n }\n\n return { account, error };\n}\n\n/**\n * Generates an authentication token for a given account. This token can be used to authenticate a request. See {@link authenticateRequest} for more details.\n *\n * @param as - The account to generate the token for, defaults to the current active account.\n * @returns The authentication token.\n *\n * @example Make a fetch request with the token\n * ```ts\n * const token = generateAuthToken();\n * const response = await fetch(url, {\n * headers: {\n * Authorization: `Jazz ${token}`,\n * },\n * });\n * ```\n */\n\nexport function generateAuthToken(as?: Account) {\n const account = as ?? Account.getMe();\n const node = account.$jazz.localNode;\n const crypto = node.crypto;\n\n const agent = node.getCurrentAgent();\n const signerSecret = agent.currentSignerSecret();\n\n const createdAt = Date.now();\n\n const signPayload = crypto.secureHash({\n id: account.$jazz.id,\n createdAt,\n });\n\n const authToken = crypto.sign(signerSecret, signPayload);\n\n return `${authToken}~${account.$jazz.id}~${createdAt}`;\n}\n\nexport async function parseAuthToken(\n authToken: string,\n options?: { loadAs?: Account; expiration?: number },\n): Promise<\n | { account: Account; error?: never }\n | { account?: never; error: { message: string; details?: unknown } }\n> {\n const expiration = options?.expiration ?? 1_000 * 60; // 1 minute\n\n const parsed = z\n .tuple([signatureSchema, coIdSchema, z.string().transform(Number)])\n .safeParse(authToken.split(\"~\"));\n\n if (!parsed.success) {\n return {\n error: {\n message: \"Invalid token\",\n details: parsed.error,\n },\n };\n }\n\n const [signature, id, createdAt] = parsed.data;\n\n if (createdAt + expiration < Date.now()) {\n return {\n error: {\n message: \"Token expired\",\n },\n };\n }\n\n const account = await Account.load(id, { loadAs: options?.loadAs });\n\n if (!account.$isLoaded) {\n return {\n error: {\n message: \"Failed to load account\",\n details: { id },\n },\n };\n }\n\n const node = account.$jazz.localNode;\n const crypto = node.crypto;\n\n // Verify the signature of the message to prevent tampering\n const signPayload = crypto.secureHash({\n id: account.$jazz.id,\n createdAt: Number(createdAt),\n });\n\n const agentID = account.$jazz.raw.currentAgentID();\n const signerID = crypto.getAgentSignerID(agentID);\n\n if (!crypto.verify(signature, signPayload, signerID)) {\n return {\n error: {\n message: \"Invalid signature\",\n },\n };\n }\n\n return {\n account,\n };\n}\n","export {\n setCustomErrorReporter,\n enableCaptureErrorCause,\n} from \"./subscribe/errorReporting.js\";\n\nexport {\n logger,\n LogLevel,\n} from \"cojson\";\n","export * from \"./exports.js\";\n\nexport {\n cojsonInternals,\n logger,\n LogLevel,\n} from \"cojson\";\n"],"mappings":"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","names":["Account","AuthSecretStorage","Account","AuthSecretStorage","cojsonInternals","cojsonInternals","cojsonInternals","cojsonInternals","cojsonInternals","logger","LogLevel"]}
|
|
1
|
+
{"version":3,"sources":["../src/tools/auth/clerk/index.ts","../src/tools/auth/clerk/getClerkUsername.ts","../src/tools/auth/clerk/types.ts","../src/tools/auth/DemoAuth.ts","../src/tools/auth/PassphraseAuth.ts","../src/tools/implementation/invites.ts","../src/tools/coValues/request.ts","../src/tools/config.ts","../src/tools/index.ts"],"sourcesContent":["import {\n Account,\n AuthCredentials,\n AuthSecretStorage,\n AuthenticateAccountFunction,\n} from \"jazz-tools\";\nimport { getClerkUsername } from \"./getClerkUsername.js\";\nimport {\n ClerkCredentials,\n MinimalClerkClient,\n isClerkAuthStateEqual,\n isClerkCredentials,\n} from \"./types.js\";\n\nexport type { MinimalClerkClient };\nexport { isClerkCredentials };\n\nexport class JazzClerkAuth {\n constructor(\n private authenticate: AuthenticateAccountFunction,\n private logOut: () => Promise<void> | void,\n private authSecretStorage: AuthSecretStorage,\n ) {}\n\n /**\n * Loads the Jazz auth data from the Clerk user and sets it in the auth secret storage.\n */\n static loadClerkAuthData(\n credentials: ClerkCredentials,\n storage: AuthSecretStorage,\n ) {\n return storage.set({\n accountID: credentials.jazzAccountID,\n accountSecret: credentials.jazzAccountSecret,\n secretSeed: credentials.jazzAccountSeed\n ? Uint8Array.from(credentials.jazzAccountSeed)\n : undefined,\n provider: \"clerk\",\n });\n }\n\n static async initializeAuth(clerk: MinimalClerkClient) {\n const secretStorage = new AuthSecretStorage();\n\n if (!isClerkCredentials(clerk.user?.unsafeMetadata)) {\n return;\n }\n\n await JazzClerkAuth.loadClerkAuthData(\n clerk.user.unsafeMetadata,\n secretStorage,\n );\n }\n\n private isFirstCall = true;\n private previousUser: Pick<\n NonNullable<MinimalClerkClient[\"user\"]>,\n \"unsafeMetadata\"\n > | null = null;\n\n registerListener(clerkClient: MinimalClerkClient) {\n this.previousUser = clerkClient.user ?? null;\n\n // Need to use addListener because the clerk user object is not updated when the user logs in\n return clerkClient.addListener((event) => {\n const user = (event as Pick<MinimalClerkClient, \"user\">).user ?? null;\n\n if (!isClerkAuthStateEqual(this.previousUser, user) || this.isFirstCall) {\n this.previousUser = user;\n this.onClerkUserChange({ user });\n this.isFirstCall = false;\n }\n });\n }\n\n onClerkUserChange = async (clerkClient: Pick<MinimalClerkClient, \"user\">) => {\n const isAuthenticated = this.authSecretStorage.isAuthenticated;\n\n // LogOut is driven by Clerk. The framework adapters will need to pass `logOutReplacement` to the `JazzProvider`\n // to make the logOut work correctly.\n if (!clerkClient.user) {\n if (isAuthenticated) {\n this.authSecretStorage.clear();\n await this.logOut();\n }\n return;\n }\n\n if (isAuthenticated) return;\n\n const clerkCredentials = clerkClient.user\n .unsafeMetadata as ClerkCredentials;\n\n if (!clerkCredentials.jazzAccountID) {\n await this.signIn(clerkClient);\n } else {\n await this.logIn(clerkClient);\n }\n };\n\n logIn = async (clerkClient: Pick<MinimalClerkClient, \"user\">) => {\n if (!clerkClient.user) {\n throw new Error(\"Not signed in on Clerk\");\n }\n\n const clerkCredentials = clerkClient.user.unsafeMetadata;\n if (!isClerkCredentials(clerkCredentials)) {\n throw new Error(\"No credentials found on Clerk\");\n }\n\n const credentials = {\n accountID: clerkCredentials.jazzAccountID,\n accountSecret: clerkCredentials.jazzAccountSecret,\n secretSeed: clerkCredentials.jazzAccountSeed\n ? Uint8Array.from(clerkCredentials.jazzAccountSeed)\n : undefined,\n provider: \"clerk\",\n } satisfies AuthCredentials;\n\n await this.authenticate(credentials);\n\n await JazzClerkAuth.loadClerkAuthData(\n {\n jazzAccountID: credentials.accountID,\n jazzAccountSecret: credentials.accountSecret,\n jazzAccountSeed: clerkCredentials.jazzAccountSeed,\n },\n this.authSecretStorage,\n );\n };\n\n signIn = async (clerkClient: Pick<MinimalClerkClient, \"user\">) => {\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials) {\n throw new Error(\"No credentials found\");\n }\n\n const jazzAccountSeed = credentials.secretSeed\n ? Array.from(credentials.secretSeed)\n : undefined;\n\n const clerkCredentials = {\n jazzAccountID: credentials.accountID,\n jazzAccountSecret: credentials.accountSecret,\n jazzAccountSeed,\n };\n // user.update will cause the Clerk user change listener to fire; updating this.previousUser beforehand\n // ensures the listener sees the new credentials and does not trigger an unnecessary logIn operation\n this.previousUser = { unsafeMetadata: clerkCredentials };\n\n if (clerkClient.user) {\n await clerkClient.user.update({\n unsafeMetadata: clerkCredentials,\n });\n }\n\n const currentAccount = await Account.getMe().$jazz.ensureLoaded({\n resolve: {\n profile: true,\n },\n });\n\n const username = getClerkUsername(clerkClient);\n\n if (username) {\n currentAccount.profile.$jazz.set(\"name\", username);\n }\n\n await JazzClerkAuth.loadClerkAuthData(\n {\n jazzAccountID: credentials.accountID,\n jazzAccountSecret: credentials.accountSecret,\n jazzAccountSeed,\n },\n this.authSecretStorage,\n );\n };\n}\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace BrowserClerkAuth {\n export interface Driver {\n onError: (error: string | Error) => void;\n }\n}\n","import type { MinimalClerkClient } from \"./types.js\";\n\nexport function getClerkUsername(\n clerkClient: Pick<MinimalClerkClient, \"user\">,\n) {\n if (!clerkClient.user) {\n return null;\n }\n\n if (clerkClient.user.fullName) {\n return clerkClient.user.fullName;\n }\n\n if (clerkClient.user.firstName) {\n if (clerkClient.user.lastName) {\n return `${clerkClient.user.firstName} ${clerkClient.user.lastName}`;\n }\n\n return clerkClient.user.firstName;\n }\n\n if (clerkClient.user.username) {\n return clerkClient.user.username;\n }\n\n if (clerkClient.user.primaryEmailAddress?.emailAddress) {\n const emailUsername =\n clerkClient.user.primaryEmailAddress.emailAddress.split(\"@\")[0];\n\n if (emailUsername) {\n return emailUsername;\n }\n }\n\n return clerkClient.user.id;\n}\n","import { AgentSecret } from \"cojson\";\nimport { Account, ID } from \"jazz-tools\";\n\nexport type MinimalClerkClient = {\n user:\n | {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n unsafeMetadata: Record<string, any>;\n fullName: string | null;\n username: string | null;\n firstName: string | null;\n lastName: string | null;\n id: string;\n primaryEmailAddress: {\n emailAddress: string | null;\n } | null;\n update: (args: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n unsafeMetadata: Record<string, any>;\n }) => Promise<unknown>;\n }\n | null\n | undefined;\n signOut: () => Promise<void>;\n addListener: (listener: (data: unknown) => void) => void;\n};\n\nexport type ClerkCredentials = {\n jazzAccountID: ID<Account>;\n jazzAccountSecret: AgentSecret;\n jazzAccountSeed?: number[];\n};\n\n/**\n * Checks if the Clerk user metadata contains the necessary credentials for Jazz auth.\n * **Note**: It does not validate the credentials, only checks if the necessary fields are present in the metadata object.\n */\nexport function isClerkCredentials(\n data:\n | NonNullable<MinimalClerkClient[\"user\"]>[\"unsafeMetadata\"]\n | null\n | undefined,\n): data is ClerkCredentials {\n return !!data && \"jazzAccountID\" in data && \"jazzAccountSecret\" in data;\n}\n\nexport function isClerkAuthStateEqual(\n previousUser:\n | Pick<NonNullable<MinimalClerkClient[\"user\"]>, \"unsafeMetadata\">\n | null\n | undefined,\n newUser:\n | Pick<NonNullable<MinimalClerkClient[\"user\"]>, \"unsafeMetadata\">\n | null\n | undefined,\n) {\n if (Boolean(previousUser) !== Boolean(newUser)) {\n return false;\n }\n\n const previousCredentials = isClerkCredentials(previousUser?.unsafeMetadata)\n ? previousUser?.unsafeMetadata\n : null;\n const newCredentials = isClerkCredentials(newUser?.unsafeMetadata)\n ? newUser?.unsafeMetadata\n : null;\n\n if (!previousCredentials || !newCredentials) {\n return previousCredentials === newCredentials;\n }\n\n return previousCredentials.jazzAccountID === newCredentials.jazzAccountID;\n}\n","import { AgentSecret } from \"cojson\";\nimport { Account, ID } from \"../internal.js\";\nimport { AuthenticateAccountFunction } from \"../types.js\";\nimport { AuthSecretStorage } from \"./AuthSecretStorage.js\";\nimport { KvStore, KvStoreContext } from \"./KvStoreContext.js\";\n\ntype StorageData = {\n accountID: ID<Account>;\n accountSecret: AgentSecret;\n secretSeed?: number[];\n};\n\n/**\n * `DemoAuth` provides a `JazzAuth` object for demo authentication.\n *\n * Demo authentication is useful for quickly testing your app, as it allows you to create new accounts and log in as existing ones.\n *\n * ```\n * import { DemoAuth } from \"jazz-tools\";\n *\n * const auth = new DemoAuth(jazzContext.authenticate, new AuthSecretStorage());\n * ```\n *\n * @category Auth Providers\n */\nexport class DemoAuth {\n constructor(\n private authenticate: AuthenticateAccountFunction,\n private authSecretStorage: AuthSecretStorage,\n ) {}\n\n logIn = async (username: string) => {\n const existingUsers = await this.getExisitingUsersWithData();\n const storageData = existingUsers[username];\n\n if (!storageData?.accountID) {\n throw new Error(\"User not found\");\n }\n\n await this.authenticate({\n accountID: storageData.accountID,\n accountSecret: storageData.accountSecret,\n });\n\n await this.authSecretStorage.set({\n accountID: storageData.accountID,\n accountSecret: storageData.accountSecret,\n secretSeed: storageData.secretSeed\n ? new Uint8Array(storageData.secretSeed)\n : undefined,\n provider: \"demo\",\n });\n };\n\n signUp = async (username: string) => {\n const existingUsers = await this.getExistingUsers();\n if (existingUsers.includes(username)) {\n throw new Error(\"User already registered\");\n }\n\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials) {\n throw new Error(\"No credentials found\");\n }\n\n const currentAccount = await Account.getMe().$jazz.ensureLoaded({\n resolve: {\n profile: true,\n },\n });\n\n currentAccount.profile.$jazz.set(\"name\", username);\n\n await this.authSecretStorage.set({\n accountID: credentials.accountID,\n accountSecret: credentials.accountSecret,\n secretSeed: credentials.secretSeed\n ? new Uint8Array(credentials.secretSeed)\n : undefined,\n provider: \"demo\",\n });\n\n await this.addToExistingUsers(username, {\n accountID: credentials.accountID,\n accountSecret: credentials.accountSecret,\n secretSeed: credentials.secretSeed\n ? Array.from(credentials.secretSeed)\n : undefined,\n });\n };\n\n private async addToExistingUsers(username: string, data: StorageData) {\n const existingUsers = await this.getExisitingUsersWithData();\n\n if (existingUsers[username]) {\n return;\n }\n\n existingUsers[username] = data;\n\n const kvStore = KvStoreContext.getInstance().getStorage();\n await kvStore.set(\"demo-auth-users\", JSON.stringify(existingUsers));\n }\n\n private async getExisitingUsersWithData() {\n const kvStore = KvStoreContext.getInstance().getStorage();\n await migrateExistingUsers(kvStore);\n\n const existingUsers = await kvStore.get(\"demo-auth-users\");\n return existingUsers ? JSON.parse(existingUsers) : {};\n }\n\n getExistingUsers = async () => {\n return Object.keys(await this.getExisitingUsersWithData());\n };\n}\n\nexport function encodeUsername(username: string) {\n return btoa(username)\n .replace(/=/g, \"-\")\n .replace(/\\+/g, \"_\")\n .replace(/\\//g, \".\");\n}\n\nasync function getStorageVersion(kvStore: KvStore) {\n try {\n const version = await kvStore.get(\"demo-auth-storage-version\");\n return version ? parseInt(version) : 1;\n } catch (error) {\n return 1;\n }\n}\n\nasync function setStorageVersion(kvStore: KvStore, version: number) {\n await kvStore.set(\"demo-auth-storage-version\", version.toString());\n}\n\nasync function getExistingUsersList(kvStore: KvStore) {\n const existingUsers = await kvStore.get(\"demo-auth-existing-users\");\n return existingUsers ? existingUsers.split(\",\") : [];\n}\n\n/**\n * Migrates existing users keys to work with any storage.\n */\nasync function migrateExistingUsers(kvStore: KvStore) {\n if ((await getStorageVersion(kvStore)) < 2) {\n const existingUsers = await getExistingUsersList(kvStore);\n\n for (const username of existingUsers) {\n const legacyKey = `demo-auth-existing-users-${username}`;\n const storageData = await kvStore.get(legacyKey);\n if (storageData) {\n await kvStore.set(\n `demo-auth-existing-users-${encodeUsername(username)}`,\n storageData,\n );\n await kvStore.delete(legacyKey);\n }\n }\n\n await setStorageVersion(kvStore, 2);\n }\n\n if ((await getStorageVersion(kvStore)) < 3) {\n const existingUsersList = await getExistingUsersList(kvStore);\n\n const existingUsers: Record<string, StorageData> = {};\n const keysToDelete: string[] = [\"demo-auth-existing-users\"];\n\n for (const username of existingUsersList) {\n const key = `demo-auth-existing-users-${encodeUsername(username)}`;\n const storageData = await kvStore.get(key);\n if (storageData) {\n existingUsers[username] = JSON.parse(storageData);\n keysToDelete.push(key);\n }\n }\n\n await kvStore.set(\"demo-auth-users\", JSON.stringify(existingUsers));\n\n for (const key of keysToDelete) {\n await kvStore.delete(key);\n }\n\n await setStorageVersion(kvStore, 3);\n }\n}\n","import * as bip39 from \"@scure/bip39\";\nimport { entropyToMnemonic } from \"@scure/bip39\";\nimport { CryptoProvider, cojsonInternals } from \"cojson\";\nimport type { ID } from \"../internal.js\";\nimport { Account } from \"../internal.js\";\nimport type {\n AuthenticateAccountFunction,\n RegisterAccountFunction,\n} from \"../types.js\";\nimport { AuthSecretStorage } from \"./AuthSecretStorage.js\";\n\n/**\n * `PassphraseAuth` provides a `JazzAuth` object for passphrase authentication.\n *\n * ```ts\n * import { PassphraseAuth } from \"jazz-tools\";\n *\n * const auth = new PassphraseAuth(crypto, jazzContext.authenticate, new AuthSecretStorage(), wordlist);\n * ```\n *\n * @category Auth Providers\n */\nexport class PassphraseAuth {\n passphrase: string = \"\";\n\n constructor(\n private crypto: CryptoProvider,\n private authenticate: AuthenticateAccountFunction,\n private register: RegisterAccountFunction,\n private authSecretStorage: AuthSecretStorage,\n public wordlist: string[],\n ) {}\n\n logIn = async (passphrase: string) => {\n const { crypto, authenticate } = this;\n\n let secretSeed;\n\n try {\n secretSeed = bip39.mnemonicToEntropy(passphrase, this.wordlist);\n } catch (e) {\n throw new Error(\"Invalid passphrase\");\n }\n\n const accountSecret = crypto.agentSecretFromSecretSeed(secretSeed);\n\n const accountID = cojsonInternals.idforHeader(\n cojsonInternals.accountHeaderForInitialAgentSecret(accountSecret, crypto),\n crypto,\n ) as ID<Account>;\n\n await authenticate({\n accountID,\n accountSecret,\n });\n\n await this.authSecretStorage.set({\n accountID,\n secretSeed,\n accountSecret,\n provider: \"passphrase\",\n });\n\n this.passphrase = passphrase;\n this.notify();\n };\n\n signUp = async (name?: string) => {\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials || !credentials.secretSeed) {\n throw new Error(\"No credentials found\");\n }\n\n const passphrase = entropyToMnemonic(credentials.secretSeed, this.wordlist);\n\n await this.authSecretStorage.set({\n accountID: credentials.accountID,\n secretSeed: credentials.secretSeed,\n accountSecret: credentials.accountSecret,\n provider: \"passphrase\",\n });\n\n if (name?.trim()) {\n const currentAccount = await Account.getMe().$jazz.ensureLoaded({\n resolve: {\n profile: true,\n },\n });\n\n currentAccount.profile.$jazz.set(\"name\", name);\n }\n\n return passphrase;\n };\n\n registerNewAccount = async (passphrase: string, name: string) => {\n const secretSeed = bip39.mnemonicToEntropy(passphrase, this.wordlist);\n const accountSecret = this.crypto.agentSecretFromSecretSeed(secretSeed);\n const accountID = await this.register(accountSecret, { name });\n\n await this.authSecretStorage.set({\n accountID,\n secretSeed,\n accountSecret,\n provider: \"passphrase\",\n });\n\n return accountID;\n };\n\n getCurrentAccountPassphrase = async () => {\n const credentials = await this.authSecretStorage.get();\n\n if (!credentials || !credentials.secretSeed) {\n throw new Error(\"No credentials found\");\n }\n\n return entropyToMnemonic(credentials.secretSeed, this.wordlist);\n };\n\n generateRandomPassphrase = () => {\n return entropyToMnemonic(this.crypto.newRandomSecretSeed(), this.wordlist);\n };\n\n loadCurrentAccountPassphrase = async () => {\n const passphrase = await this.getCurrentAccountPassphrase();\n this.passphrase = passphrase;\n this.notify();\n };\n\n listeners = new Set<() => void>();\n subscribe = (callback: () => void) => {\n this.listeners.add(callback);\n\n return () => {\n this.listeners.delete(callback);\n };\n };\n\n notify() {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n","import { AccountRole, type InviteSecret, cojsonInternals } from \"cojson\";\nimport { Account } from \"../coValues/account.js\";\nimport type { CoValue, CoValueClassOrSchema } from \"../internal.js\";\n\n/** @category Invite Links */\nexport function createInviteLink<C extends CoValue>(\n value: C,\n role: AccountRole,\n baseURL: string,\n valueHint?: string,\n): string {\n const coValueCore = value.$jazz.raw.core;\n let currentCoValue = coValueCore;\n\n while (currentCoValue.verified.header.ruleset.type === \"ownedByGroup\") {\n currentCoValue = currentCoValue.getGroup().core;\n }\n\n const { ruleset, meta } = currentCoValue.verified.header;\n\n if (ruleset.type !== \"group\" || meta?.type === \"account\") {\n throw new Error(\"Can't create invite link for object without group\");\n }\n\n const group = cojsonInternals.expectGroup(currentCoValue.getCurrentContent());\n const inviteSecret = group.createInvite(role);\n\n return `${baseURL}#/invite/${valueHint ? valueHint + \"/\" : \"\"}${\n value.$jazz.id\n }/${inviteSecret}`;\n}\n\n/** @category Invite Links */\nexport function parseInviteLink(inviteURL: string):\n | {\n valueID: string;\n valueHint?: string;\n inviteSecret: InviteSecret;\n }\n | undefined {\n const url = new URL(inviteURL);\n const parts = url.hash.split(\"/\");\n\n let valueHint: string | undefined;\n let valueID: string | undefined;\n let inviteSecret: InviteSecret | undefined;\n\n if (parts[0] === \"#\" && parts[1] === \"invite\") {\n if (parts.length === 5) {\n valueHint = parts[2];\n valueID = parts[3];\n inviteSecret = parts[4] as InviteSecret;\n } else if (parts.length === 4) {\n valueID = parts[2];\n inviteSecret = parts[3] as InviteSecret;\n }\n\n if (!valueID || !inviteSecret) {\n return undefined;\n }\n return { valueID, inviteSecret, valueHint };\n }\n}\n\n/** @category Invite Links */\nexport function consumeInviteLink<S extends CoValueClassOrSchema>({\n inviteURL,\n as = Account.getMe(),\n forValueHint,\n invitedObjectSchema,\n}: {\n inviteURL: string;\n as?: Account;\n forValueHint?: string;\n invitedObjectSchema: S;\n}): Promise<\n | {\n valueID: string;\n valueHint?: string;\n inviteSecret: InviteSecret;\n }\n | undefined\n> {\n return new Promise((resolve, reject) => {\n const result = parseInviteLink(inviteURL);\n\n if (result && result.valueHint === forValueHint) {\n as.acceptInvite(result.valueID, result.inviteSecret, invitedObjectSchema)\n .then(() => {\n resolve(result);\n })\n .catch(reject);\n } else {\n resolve(undefined);\n }\n });\n}\n","import {\n CoValueCore,\n CojsonInternalTypes,\n CryptoProvider,\n RawAccount,\n RawCoMap,\n cojsonInternals,\n} from \"cojson\";\nimport z from \"zod/v4\";\nimport {\n AnyZodOrCoValueSchema,\n CoMap,\n CoMapSchema,\n CoMapSchemaInit,\n CoValueClass,\n CoreCoMapSchema,\n Group,\n Loaded,\n ResolveQuery,\n ResolveQueryStrict,\n Simplify,\n coMapDefiner,\n coValueClassFromCoValueClassOrSchema,\n exportCoValue,\n importContentPieces,\n loadCoValue,\n} from \"../internal.js\";\nimport { isCoValueId } from \"../lib/utils.js\";\nimport { Account } from \"./account.js\";\n\ntype MessageShape = Record<string, AnyZodOrCoValueSchema>;\n\ntype RequestSchemaDefinition<\n S extends MessageShape,\n R extends ResolveQuery<CoMapSchema<S>> = true,\n> =\n | S\n | {\n schema: S;\n resolve?: R;\n };\n\n/**\n * Configuration options for defining HTTP request/response schemas in Jazz.\n *\n * This interface defines the structure for creating typed HTTP routes with\n * request and response validation using CoMap schemas.\n *\n * @template RequestShape - The shape of the request message schema (must extend MessageShape)\n * @template RequestResolve - The resolve query type for the request CoMap schema\n * @template ResponseShape - The shape of the response message schema (must extend MessageShape)\n * @template ResponseResolve - The resolve query type for the response CoMap schema\n */\ninterface RequestOptions<\n RequestShape extends MessageShape,\n RequestResolve extends ResolveQuery<CoMapSchema<RequestShape>>,\n ResponseShape extends MessageShape,\n ResponseResolve extends ResolveQuery<CoMapSchema<ResponseShape>>,\n> {\n /**\n * The URL endpoint for the HTTP route.\n * This is used by the client to send requests to the server.\n */\n url: string;\n\n /**\n * The id of the worker Account or Group.\n */\n workerId: string;\n\n /**\n * Schema definition for the request payload.\n * Can be either a direct schema object or an object with schema and optional resolve properties.\n * The schema defines the structure and validation rules for incoming requests.\n */\n request: RequestSchemaDefinition<\n RequestShape,\n ResolveQueryStrict<CoMapSchema<RequestShape>, RequestResolve>\n >;\n\n /**\n * Schema definition for the response payload.\n * Can be either a direct schema object or an object with schema and optional resolve properties.\n * The schema defines the structure and validation rules for outgoing responses.\n */\n response: RequestSchemaDefinition<\n ResponseShape,\n ResolveQueryStrict<CoMapSchema<ResponseShape>, ResponseResolve>\n >;\n}\n\ntype AsNullablePayload<T extends MessageShape> = T extends Record<string, never>\n ? undefined\n : never;\ntype MessageValuePayload<T extends MessageShape> =\n | Simplify<CoMapSchemaInit<T>>\n | AsNullablePayload<T>;\n\nfunction createMessageEnvelope<S extends MessageShape>(\n schema: CoreCoMapSchema,\n value: MessageValuePayload<S>,\n owner: Account,\n sharedWith: Account | Group,\n type: \"request\" | \"response\",\n): Loaded<CoMapSchema<S>> {\n const group = Group.create({ owner });\n\n if (type === \"request\") {\n group.addMember(sharedWith, \"writer\");\n } else {\n group.addMember(sharedWith, \"reader\");\n }\n\n // @ts-expect-error - CoreCoMapSchema doesn't have static methods\n return schema.create(value ?? {}, group);\n}\n\n/**\n * Function that exports the input CoValue in a serializable format and prepares the information\n * required for the other side to safely verify the identity of the sender.\n */\nasync function serializeMessagePayload({\n type,\n schema,\n resolve,\n value,\n owner,\n target,\n}: {\n // Skipping type validation here to avoid excessive type complexity that affects the typecheck performance\n type: \"request\" | \"response\";\n schema: CoreCoMapSchema;\n resolve: any;\n value: any;\n owner: Account;\n target: Account | Group;\n}) {\n const me = owner ?? Account.getMe();\n const node = me.$jazz.localNode;\n const crypto = node.crypto;\n\n const agent = node.getCurrentAgent();\n const signerID = agent.currentSignerID();\n const signerSecret = agent.currentSignerSecret();\n\n const envelope = createMessageEnvelope(schema, value, me, target, type);\n\n const contentPieces =\n (await exportCoValue(schema, envelope.$jazz.id, {\n resolve,\n loadAs: me,\n bestEffortResolution: true,\n })) ?? [];\n\n const createdAt = Date.now();\n\n const signPayload = crypto.secureHash({\n contentPieces,\n id: envelope.$jazz.id,\n createdAt,\n signerID,\n });\n\n const authToken = crypto.sign(signerSecret, signPayload);\n\n return {\n contentPieces,\n id: envelope.$jazz.id,\n createdAt,\n authToken,\n signerID,\n };\n}\n\nconst coIdSchema = z.custom<`co_z${string}`>(isCoValueId);\nconst signatureSchema = z.custom<`signature_z${string}`>(\n (value) => typeof value === \"string\" && value.startsWith(\"signature_z\"),\n);\n\nconst requestSchema = z.object({\n contentPieces: z.array(z.json()),\n id: coIdSchema,\n createdAt: z.number(),\n authToken: signatureSchema,\n signerID: z.custom<`signer_z${string}`>(\n (value) => typeof value === \"string\" && value.startsWith(\"signer_z\"),\n ),\n});\n\n/**\n * Function that parses the message payload, verifies the identity of the sender and loads the data.\n *\n * @returns The data from the message.\n */\nasync function handleMessagePayload({\n type,\n schema,\n resolve,\n request,\n loadAs,\n}: {\n type: \"request\" | \"response\";\n // Skipping type validation here to avoid excessive type complexity that affects the typecheck performance\n schema: CoreCoMapSchema;\n resolve: any;\n request: unknown;\n loadAs: Account;\n}) {\n const node = loadAs.$jazz.localNode;\n const crypto = node.crypto;\n\n const requestParsed = requestSchema.safeParse(request);\n\n if (!requestParsed.success) {\n throw new JazzRequestError(\n \"Request payload is not valid\",\n 400,\n requestParsed.error,\n );\n }\n\n const requestData = requestParsed.data;\n\n if (type === \"request\") {\n const core = await node.loadCoValueCore(requestData.id, undefined, true);\n\n // Check if the message has already been handled to prevent replay attacks\n if (core.isAvailable()) {\n const content = core.getCurrentContent() as RawCoMap;\n\n if (content.get(\"$handled\") === loadAs.$jazz.id) {\n throw new JazzRequestError(\"Request payload is already handled\", 400);\n }\n }\n\n // Check if the message is expired as extra protection\n if (requestData.createdAt + 1000 * 60 < Date.now()) {\n throw new JazzRequestError(\"Authentication token is expired\", 401);\n }\n }\n\n // Verify the signature of the message to prevent tampering\n const signPayload = crypto.secureHash({\n contentPieces: requestData.contentPieces,\n id: requestData.id,\n createdAt: requestData.createdAt,\n signerID: requestData.signerID,\n });\n\n if (\n !safeVerifySignature(\n crypto,\n signPayload,\n requestData.signerID,\n requestData.authToken,\n )\n ) {\n throw new JazzRequestError(\"Invalid signature\", 401);\n }\n\n let contentPieces =\n requestData.contentPieces as CojsonInternalTypes.NewContentMessage[];\n\n if (type === \"request\") {\n const coValueContent = contentPieces.find(\n (piece) => piece.id === requestData.id,\n );\n\n if (coValueContent && coValueContent.header) {\n const validValues = cojsonInternals.getDependedOnCoValues(\n coValueContent.header,\n coValueContent,\n );\n validValues.add(requestData.id);\n contentPieces = contentPieces.filter((piece) =>\n validValues.has(piece.id),\n );\n } else {\n contentPieces = [];\n }\n }\n\n importContentPieces(contentPieces, loadAs);\n\n const coValue = await node.loadCoValueCore(requestData.id);\n const accountId = getCoValueCreatorAccountId(coValue);\n\n const madeBy = await Account.load(accountId, {\n loadAs,\n });\n\n if (!madeBy.$isLoaded) {\n throw new JazzRequestError(\"Creator account not found\", 400);\n }\n\n const coSchema = coValueClassFromCoValueClassOrSchema(\n schema,\n ) as CoValueClass<CoMap>;\n const value = await loadCoValue<CoMap, true>(coSchema, requestData.id, {\n resolve,\n loadAs,\n });\n\n if (!value.$isLoaded) {\n throw new JazzRequestError(\"Value not found\", 400);\n }\n\n if (type === \"request\") {\n value.$jazz.raw.set(\"$handled\", loadAs.$jazz.id);\n }\n\n return {\n value: value as unknown,\n madeBy,\n };\n}\n\nfunction parseSchemaAndResolve<\n S extends MessageShape,\n R extends ResolveQuery<CoMapSchema<S>>,\n>(options: RequestSchemaDefinition<S, R>) {\n if (\"schema\" in options) {\n return {\n // Using a type cast to reduce the type complexity\n schema: coMapDefiner(options.schema) as CoreCoMapSchema,\n resolve: options.resolve as any,\n };\n }\n\n return {\n schema: coMapDefiner(options) as CoreCoMapSchema,\n resolve: true as any,\n };\n}\n\nexport class HttpRoute<\n RequestShape extends MessageShape = z.core.$ZodLooseShape,\n RequestResolve extends ResolveQuery<CoMapSchema<RequestShape>> = any,\n ResponseShape extends MessageShape = z.core.$ZodLooseShape,\n ResponseResolve extends ResolveQuery<CoMapSchema<ResponseShape>> = any,\n> {\n private requestDefinition: {\n schema: CoreCoMapSchema;\n resolve: any;\n };\n private responseDefinition: {\n schema: CoreCoMapSchema;\n resolve: any;\n };\n private url: string;\n private workerId: string;\n\n constructor(\n params: RequestOptions<\n RequestShape,\n RequestResolve,\n ResponseShape,\n ResponseResolve\n >,\n ) {\n this.requestDefinition = parseSchemaAndResolve(params.request);\n this.responseDefinition = parseSchemaAndResolve(params.response);\n this.url = params.url;\n this.workerId = params.workerId;\n\n if (params.workerId === undefined) {\n throw new TypeError(\"Worker ID is required\");\n }\n }\n\n async send(\n values: MessageValuePayload<RequestShape>,\n options?: { owner?: Account },\n ): Promise<Loaded<CoMapSchema<ResponseShape>, ResponseResolve>> {\n const as = options?.owner ?? Account.getMe();\n\n const target = await loadWorkerAccountOrGroup(this.workerId, as);\n\n const response = await fetch(this.url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(\n await serializeMessagePayload({\n type: \"request\",\n schema: this.requestDefinition.schema,\n resolve: true, // export only the envelope\n value: values,\n owner: as,\n target,\n }),\n ),\n });\n\n if (!response.ok) {\n if (response.headers.has(\"X-Jazz-Request-Error\")) {\n const error = await response.json();\n throw new JazzRequestError(error.message, error.code, error.details);\n }\n\n throw new JazzRequestError(\"Request failed\", response.status);\n }\n\n const responseBody = await response.json();\n\n const responseParsed = z\n .object({\n type: z.literal(\"success\"),\n payload: z.any(),\n })\n .safeParse(responseBody);\n\n if (!responseParsed.success) {\n throw new JazzRequestError(\n \"Response payload is not valid\",\n 400,\n responseParsed.error,\n );\n }\n\n const data = await handleMessagePayload({\n type: \"response\",\n schema: this.responseDefinition.schema,\n resolve: this.responseDefinition.resolve,\n request: responseParsed.data.payload,\n loadAs: as,\n });\n\n return data.value as Loaded<CoMapSchema<ResponseShape>, ResponseResolve>;\n }\n\n handle = async (\n request: Request,\n as: Account,\n callback: (\n value: Loaded<CoMapSchema<RequestShape>, RequestResolve>,\n madeBy: Account,\n ) =>\n | Promise<MessageValuePayload<ResponseShape>>\n | MessageValuePayload<ResponseShape>,\n ): Promise<Response> => {\n try {\n const response = await this.executeHandleRequest(request, as, callback);\n return response;\n } catch (error) {\n // Serialize the error to make it possible to handle it on the client side\n if (isJazzRequestError(error)) {\n return new Response(JSON.stringify(error.toJSON()), {\n status: error.code,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Jazz-Request-Error\": \"true\",\n },\n });\n }\n\n throw error;\n }\n };\n\n executeHandleRequest = async (\n request: Request,\n as: Account,\n callback: (\n value: Loaded<CoMapSchema<RequestShape>, RequestResolve>,\n madeBy: Account,\n ) =>\n | Promise<MessageValuePayload<ResponseShape>>\n | MessageValuePayload<ResponseShape>,\n ): Promise<Response> => {\n const node = as.$jazz.localNode;\n const body = await request.json();\n const data = await handleMessagePayload({\n type: \"request\",\n schema: this.requestDefinition.schema,\n resolve: this.requestDefinition.resolve,\n request: body,\n loadAs: as,\n });\n\n const tracking = node.syncManager.trackDirtyCoValues();\n\n const responseValue = await callback(\n data.value as Loaded<CoMapSchema<RequestShape>, RequestResolve>,\n data.madeBy,\n );\n\n const responsePayload = await serializeMessagePayload({\n type: \"response\",\n schema: this.responseDefinition.schema,\n resolve: this.responseDefinition.resolve,\n value: responseValue,\n owner: as,\n target: data.madeBy,\n });\n\n const responseBody = JSON.stringify({\n type: \"success\",\n payload: responsePayload,\n });\n\n // TODO: Detect the defer support from the environment\n await Promise.all(\n Array.from(tracking.done(), (id) => node.syncManager.waitForSync(id)),\n );\n\n return new Response(responseBody, {\n status: 200,\n headers: {\n \"Content-Type\": \"application/json\",\n },\n });\n };\n\n get requestSchema(): CoMapSchema<RequestShape> {\n return this.requestDefinition.schema as CoMapSchema<RequestShape>;\n }\n\n get responseSchema() {\n return this.responseDefinition.schema as CoMapSchema<ResponseShape>;\n }\n}\n\n/**\n * Define a request route.\n *\n * @param params - The parameters for the request route.\n * @returns The request route.\n *\n * @see {@link https://jazz.tools/docs/react/server-side/http-requests}\n */\nexport function experimental_defineRequest<\n RequestShape extends MessageShape,\n RequestResolve extends ResolveQuery<CoMapSchema<RequestShape>>,\n ResponseShape extends MessageShape,\n ResponseResolve extends ResolveQuery<CoMapSchema<ResponseShape>>,\n>(\n params: RequestOptions<\n RequestShape,\n RequestResolve,\n ResponseShape,\n ResponseResolve\n >,\n) {\n return new HttpRoute(params);\n}\n\nfunction getCoValueCreatorAccountId(coValue: CoValueCore) {\n if (!coValue.isAvailable()) {\n throw new Error(\"Unable to load the request payload\");\n }\n\n const creatorSessionId = coValue.getValidSortedTransactions().at(0)\n ?.txID.sessionID;\n\n if (!creatorSessionId) {\n throw new JazzRequestError(\n \"Request payload is not valid, creator session ID not found\",\n 400,\n );\n }\n\n const accountId =\n cojsonInternals.accountOrAgentIDfromSessionID(creatorSessionId);\n\n if (!isCoValueId(accountId)) {\n throw new JazzRequestError(\n \"Request payload is not valid, the creator is not a valid account\",\n 400,\n );\n }\n\n return accountId;\n}\n\nexport class JazzRequestError {\n public readonly isJazzRequestError = true;\n\n constructor(\n public readonly message: string,\n public readonly code: number,\n public readonly details?: unknown,\n ) {}\n\n toJSON() {\n return { message: this.message, code: this.code, details: this.details };\n }\n}\n\nexport function isJazzRequestError(error: unknown): error is JazzRequestError {\n return (\n error instanceof JazzRequestError ||\n (typeof error === \"object\" &&\n error !== null &&\n \"isJazzRequestError\" in error &&\n Boolean(error.isJazzRequestError))\n );\n}\n\nfunction safeVerifySignature(\n crypto: CryptoProvider,\n signPayload: `hash_z${string}`,\n signerID: `signer_z${string}`,\n authToken: `signature_z${string}`,\n) {\n try {\n return crypto.verify(authToken, signPayload, signerID);\n } catch (error) {\n return false;\n }\n}\n\nasync function loadWorkerAccountOrGroup(id: string, loadAs: Account) {\n const node = loadAs.$jazz.localNode;\n const coValue = await node.loadCoValueCore(id as `co_z${string}`);\n\n if (!coValue.isAvailable()) {\n throw new JazzRequestError(\"Worker account not found\", 400);\n }\n\n const content = coValue.getCurrentContent();\n\n if (content instanceof RawAccount) {\n const account = await Account.load(content.id, {\n loadAs,\n });\n if (!account.$isLoaded) {\n throw new JazzRequestError(\"Worker account not found\", 400);\n }\n return account;\n }\n\n const group = await Group.load(content.id, {\n loadAs,\n });\n\n if (!group.$isLoaded) {\n throw new JazzRequestError(\"Worker group not found\", 400);\n }\n return group;\n}\n\nfunction defaultGetToken(request: Request) {\n const headerValue = request.headers.get(\"Authorization\");\n if (headerValue?.startsWith(\"Jazz \")) {\n return headerValue.replace(\"Jazz \", \"\");\n }\n\n if (headerValue) {\n console.warn(\n \"An Authorization header was found, but it did not start with 'Jazz '. If this is intentional, you can specify the location of the token using the `getToken` option.\",\n );\n }\n\n return undefined;\n}\n\n/**\n * Authenticates a Request by verifying a signed authentication token.\n *\n * - If a token is not provided, the returned account is `undefined` and no error is returned.\n * - If a valid token is provided, the signer account is returned.\n * - If an invalid token is provided, an error is returned detailing the validation error, and the returned account is `undefined`.\n *\n * @see {@link generateAuthToken} for generating a token.\n *\n * Note: This function does not perform any authorization checks, it only verifies if - **when provided** - a token is valid. It is up to the caller to perform any additional authorization checks, if needed.\n *\n * @param request - The request to authenticate.\n * @param options - The options for the authentication.\n * @param options.expiration - The expiration time of the token in milliseconds, defaults to 1 minute.\n * @param options.loadAs - The account to load the token from, defaults to the current active account.\n * @param options.getToken - If specified, this function will be used to get the token from the request. By default the token is expected to be in the `Authorization` header in the form of `Jazz <token>`.\n * @returns The account if it is valid, otherwise an error.\n *\n * @example\n * ```ts\n * const { account, error } = await authenticateRequest(request);\n * if (error) {\n * return new Response(JSON.stringify(error), { status: 401 });\n * }\n * ```\n */\nexport async function authenticateRequest(\n request: Request,\n options?: {\n expiration?: number;\n loadAs?: Account;\n getToken?: (request: Request) => string | undefined | null;\n },\n): Promise<\n | {\n account?: Account;\n error?: never;\n }\n | {\n account?: never;\n error: { message: string; details?: unknown };\n }\n> {\n const token = options?.getToken?.(request) ?? defaultGetToken(request);\n\n if (!token) {\n return {};\n }\n\n const { account, error } = await parseAuthToken(token, {\n loadAs: options?.loadAs,\n expiration: options?.expiration ?? 1000 * 60,\n });\n\n if (error) {\n return { error };\n }\n\n return { account, error };\n}\n\n/**\n * Generates an authentication token for a given account. This token can be used to authenticate a request. See {@link authenticateRequest} for more details.\n *\n * @param as - The account to generate the token for, defaults to the current active account.\n * @returns The authentication token.\n *\n * @example Make a fetch request with the token\n * ```ts\n * const token = generateAuthToken();\n * const response = await fetch(url, {\n * headers: {\n * Authorization: `Jazz ${token}`,\n * },\n * });\n * ```\n */\n\nexport function generateAuthToken(as?: Account) {\n const account = as ?? Account.getMe();\n const node = account.$jazz.localNode;\n const crypto = node.crypto;\n\n const agent = node.getCurrentAgent();\n const signerSecret = agent.currentSignerSecret();\n\n const createdAt = Date.now();\n\n const signPayload = crypto.secureHash({\n id: account.$jazz.id,\n createdAt,\n });\n\n const authToken = crypto.sign(signerSecret, signPayload);\n\n return `${authToken}~${account.$jazz.id}~${createdAt}`;\n}\n\nexport async function parseAuthToken(\n authToken: string,\n options?: { loadAs?: Account; expiration?: number },\n): Promise<\n | { account: Account; error?: never }\n | { account?: never; error: { message: string; details?: unknown } }\n> {\n const expiration = options?.expiration ?? 1_000 * 60; // 1 minute\n\n const parsed = z\n .tuple([signatureSchema, coIdSchema, z.string().transform(Number)])\n .safeParse(authToken.split(\"~\"));\n\n if (!parsed.success) {\n return {\n error: {\n message: \"Invalid token\",\n details: parsed.error,\n },\n };\n }\n\n const [signature, id, createdAt] = parsed.data;\n\n if (createdAt + expiration < Date.now()) {\n return {\n error: {\n message: \"Token expired\",\n },\n };\n }\n\n const account = await Account.load(id, { loadAs: options?.loadAs });\n\n if (!account.$isLoaded) {\n return {\n error: {\n message: \"Failed to load account\",\n details: { id },\n },\n };\n }\n\n const node = account.$jazz.localNode;\n const crypto = node.crypto;\n\n // Verify the signature of the message to prevent tampering\n const signPayload = crypto.secureHash({\n id: account.$jazz.id,\n createdAt: Number(createdAt),\n });\n\n const agentID = account.$jazz.raw.currentAgentID();\n const signerID = crypto.getAgentSignerID(agentID);\n\n if (!crypto.verify(signature, signPayload, signerID)) {\n return {\n error: {\n message: \"Invalid signature\",\n },\n };\n }\n\n return {\n account,\n };\n}\n","export {\n setCustomErrorReporter,\n enableCaptureErrorCause,\n} from \"./subscribe/errorReporting.js\";\n\nexport {\n logger,\n LogLevel,\n} from \"cojson\";\n","export * from \"./exports.js\";\n\nexport {\n cojsonInternals,\n logger,\n LogLevel,\n} from \"cojson\";\n"],"mappings":"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","names":["Account","AuthSecretStorage","Account","AuthSecretStorage","cojsonInternals","cojsonInternals","cojsonInternals","cojsonInternals","cojsonInternals","logger","LogLevel"]}
|
|
@@ -13,6 +13,7 @@ export declare class JazzClerkAuth {
|
|
|
13
13
|
static loadClerkAuthData(credentials: ClerkCredentials, storage: AuthSecretStorage): Promise<void>;
|
|
14
14
|
static initializeAuth(clerk: MinimalClerkClient): Promise<void>;
|
|
15
15
|
private isFirstCall;
|
|
16
|
+
private previousUser;
|
|
16
17
|
registerListener(clerkClient: MinimalClerkClient): void;
|
|
17
18
|
onClerkUserChange: (clerkClient: Pick<MinimalClerkClient, "user">) => Promise<void>;
|
|
18
19
|
logIn: (clerkClient: Pick<MinimalClerkClient, "user">) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/tools/auth/clerk/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,iBAAiB,EACjB,2BAA2B,EAC5B,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAElB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,kBAAkB,EAAE,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAE9B,qBAAa,aAAa;IAEtB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,iBAAiB;gBAFjB,YAAY,EAAE,2BAA2B,EACzC,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,EAClC,iBAAiB,EAAE,iBAAiB;IAG9C;;OAEG;IACH,MAAM,CAAC,iBAAiB,CACtB,WAAW,EAAE,gBAAgB,EAC7B,OAAO,EAAE,iBAAiB;WAYf,cAAc,CAAC,KAAK,EAAE,kBAAkB;IAarD,OAAO,CAAC,WAAW,CAAQ;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/tools/auth/clerk/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,iBAAiB,EACjB,2BAA2B,EAC5B,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAElB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,kBAAkB,EAAE,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAE9B,qBAAa,aAAa;IAEtB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,iBAAiB;gBAFjB,YAAY,EAAE,2BAA2B,EACzC,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,EAClC,iBAAiB,EAAE,iBAAiB;IAG9C;;OAEG;IACH,MAAM,CAAC,iBAAiB,CACtB,WAAW,EAAE,gBAAgB,EAC7B,OAAO,EAAE,iBAAiB;WAYf,cAAc,CAAC,KAAK,EAAE,kBAAkB;IAarD,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,YAAY,CAGJ;IAEhB,gBAAgB,CAAC,WAAW,EAAE,kBAAkB;IAehD,iBAAiB,gBAAuB,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,mBAuBtE;IAEF,KAAK,gBAAuB,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,mBA6B1D;IAEF,MAAM,gBAAuB,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,mBA8C3D;CACH;AAGD,yBAAiB,gBAAgB,CAAC;IAChC,UAAiB,MAAM;QACrB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,KAAK,IAAI,CAAC;KAC1C;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isClerkAuthStateEqual.test.d.ts","sourceRoot":"","sources":["../../../../../src/tools/auth/clerk/tests/isClerkAuthStateEqual.test.ts"],"names":[],"mappings":""}
|
|
@@ -27,6 +27,6 @@ export type ClerkCredentials = {
|
|
|
27
27
|
* Checks if the Clerk user metadata contains the necessary credentials for Jazz auth.
|
|
28
28
|
* **Note**: It does not validate the credentials, only checks if the necessary fields are present in the metadata object.
|
|
29
29
|
*/
|
|
30
|
-
export declare function isClerkCredentials(data: NonNullable<MinimalClerkClient["user"]>["unsafeMetadata"] | undefined): data is ClerkCredentials;
|
|
31
|
-
export declare function isClerkAuthStateEqual(previousUser: MinimalClerkClient["user"] | null | undefined, newUser: MinimalClerkClient["user"] | null | undefined): boolean;
|
|
30
|
+
export declare function isClerkCredentials(data: NonNullable<MinimalClerkClient["user"]>["unsafeMetadata"] | null | undefined): data is ClerkCredentials;
|
|
31
|
+
export declare function isClerkAuthStateEqual(previousUser: Pick<NonNullable<MinimalClerkClient["user"]>, "unsafeMetadata"> | null | undefined, newUser: Pick<NonNullable<MinimalClerkClient["user"]>, "unsafeMetadata"> | null | undefined): boolean;
|
|
32
32
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/tools/auth/clerk/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EACA;QAEE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACpC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,EAAE,EAAE,MAAM,CAAC;QACX,mBAAmB,EAAE;YACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;SAC7B,GAAG,IAAI,CAAC;QACT,MAAM,EAAE,CAAC,IAAI,EAAE;YAEb,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;SACrC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;KACxB,GACD,IAAI,GACJ,SAAS,CAAC;IACd,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,KAAK,IAAI,CAAC;CAC1D,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,aAAa,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;IAC3B,iBAAiB,EAAE,WAAW,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/tools/auth/clerk/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EACA;QAEE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACpC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QACxB,EAAE,EAAE,MAAM,CAAC;QACX,mBAAmB,EAAE;YACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;SAC7B,GAAG,IAAI,CAAC;QACT,MAAM,EAAE,CAAC,IAAI,EAAE;YAEb,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;SACrC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;KACxB,GACD,IAAI,GACJ,SAAS,CAAC;IACd,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,KAAK,IAAI,CAAC;CAC1D,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,aAAa,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;IAC3B,iBAAiB,EAAE,WAAW,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EACA,WAAW,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,GACzD,IAAI,GACJ,SAAS,GACZ,IAAI,IAAI,gBAAgB,CAE1B;AAED,wBAAgB,qBAAqB,CACnC,YAAY,EACR,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAC/D,IAAI,GACJ,SAAS,EACb,OAAO,EACH,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAC/D,IAAI,GACJ,SAAS,WAkBd"}
|
package/package.json
CHANGED
|
@@ -205,7 +205,7 @@
|
|
|
205
205
|
},
|
|
206
206
|
"type": "module",
|
|
207
207
|
"license": "MIT",
|
|
208
|
-
"version": "0.19.
|
|
208
|
+
"version": "0.19.16",
|
|
209
209
|
"dependencies": {
|
|
210
210
|
"@manuscripts/prosemirror-recreate-steps": "^0.1.4",
|
|
211
211
|
"@scure/base": "1.2.1",
|
|
@@ -222,9 +222,9 @@
|
|
|
222
222
|
"prosemirror-transform": "^1.9.0",
|
|
223
223
|
"use-sync-external-store": "^1.5.0",
|
|
224
224
|
"zod": "4.1.11",
|
|
225
|
-
"cojson": "0.19.
|
|
226
|
-
"cojson-storage-indexeddb": "0.19.
|
|
227
|
-
"cojson-transport-ws": "0.19.
|
|
225
|
+
"cojson": "0.19.16",
|
|
226
|
+
"cojson-storage-indexeddb": "0.19.16",
|
|
227
|
+
"cojson-transport-ws": "0.19.16"
|
|
228
228
|
},
|
|
229
229
|
"devDependencies": {
|
|
230
230
|
"@scure/bip39": "^1.3.0",
|
|
@@ -53,18 +53,21 @@ export class JazzClerkAuth {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
private isFirstCall = true;
|
|
56
|
+
private previousUser: Pick<
|
|
57
|
+
NonNullable<MinimalClerkClient["user"]>,
|
|
58
|
+
"unsafeMetadata"
|
|
59
|
+
> | null = null;
|
|
56
60
|
|
|
57
61
|
registerListener(clerkClient: MinimalClerkClient) {
|
|
58
|
-
|
|
59
|
-
clerkClient.user ?? null;
|
|
62
|
+
this.previousUser = clerkClient.user ?? null;
|
|
60
63
|
|
|
61
64
|
// Need to use addListener because the clerk user object is not updated when the user logs in
|
|
62
65
|
return clerkClient.addListener((event) => {
|
|
63
66
|
const user = (event as Pick<MinimalClerkClient, "user">).user ?? null;
|
|
64
67
|
|
|
65
|
-
if (!isClerkAuthStateEqual(previousUser, user) || this.isFirstCall) {
|
|
68
|
+
if (!isClerkAuthStateEqual(this.previousUser, user) || this.isFirstCall) {
|
|
69
|
+
this.previousUser = user;
|
|
66
70
|
this.onClerkUserChange({ user });
|
|
67
|
-
previousUser = user;
|
|
68
71
|
this.isFirstCall = false;
|
|
69
72
|
}
|
|
70
73
|
});
|
|
@@ -137,13 +140,20 @@ export class JazzClerkAuth {
|
|
|
137
140
|
? Array.from(credentials.secretSeed)
|
|
138
141
|
: undefined;
|
|
139
142
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
const clerkCredentials = {
|
|
144
|
+
jazzAccountID: credentials.accountID,
|
|
145
|
+
jazzAccountSecret: credentials.accountSecret,
|
|
146
|
+
jazzAccountSeed,
|
|
147
|
+
};
|
|
148
|
+
// user.update will cause the Clerk user change listener to fire; updating this.previousUser beforehand
|
|
149
|
+
// ensures the listener sees the new credentials and does not trigger an unnecessary logIn operation
|
|
150
|
+
this.previousUser = { unsafeMetadata: clerkCredentials };
|
|
151
|
+
|
|
152
|
+
if (clerkClient.user) {
|
|
153
|
+
await clerkClient.user.update({
|
|
154
|
+
unsafeMetadata: clerkCredentials,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
147
157
|
|
|
148
158
|
const currentAccount = await Account.getMe().$jazz.ensureLoaded({
|
|
149
159
|
resolve: {
|
|
@@ -282,6 +282,83 @@ describe("JazzClerkAuth", () => {
|
|
|
282
282
|
|
|
283
283
|
expect(onClerkUserChangeSpy).toHaveBeenCalledTimes(1);
|
|
284
284
|
});
|
|
285
|
+
|
|
286
|
+
it("should complete signup flow when new Clerk user is detected", async () => {
|
|
287
|
+
// 1. Setup local credentials (simulating anonymous user)
|
|
288
|
+
await authSecretStorage.set({
|
|
289
|
+
accountID: "test-account-id" as ID<Account>,
|
|
290
|
+
secretSeed: new Uint8Array([1, 2, 3]),
|
|
291
|
+
accountSecret: "test-secret" as AgentSecret,
|
|
292
|
+
provider: "anonymous",
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const { client, triggerUserChange } = setupMockClerk(null);
|
|
296
|
+
|
|
297
|
+
const auth = new JazzClerkAuth(
|
|
298
|
+
mockAuthenticate,
|
|
299
|
+
mockLogOut,
|
|
300
|
+
authSecretStorage,
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
// 2. Register listener with null user (no one logged in yet)
|
|
304
|
+
auth.registerListener(client);
|
|
305
|
+
|
|
306
|
+
// Initial trigger with no user
|
|
307
|
+
triggerUserChange(null);
|
|
308
|
+
|
|
309
|
+
// 3. Trigger event with new Clerk user (no Jazz credentials yet)
|
|
310
|
+
const mockUserUpdate = vi.fn((data) => {
|
|
311
|
+
triggerUserChange(data);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
const signInSpy = vi.spyOn(auth, "signIn");
|
|
315
|
+
const logInSpy = vi.spyOn(auth, "logIn");
|
|
316
|
+
|
|
317
|
+
const newClerkUser = {
|
|
318
|
+
fullName: "Test User",
|
|
319
|
+
firstName: "Test",
|
|
320
|
+
lastName: "User",
|
|
321
|
+
username: "testuser",
|
|
322
|
+
id: "clerk-user-123",
|
|
323
|
+
primaryEmailAddress: { emailAddress: "test@example.com" },
|
|
324
|
+
unsafeMetadata: {}, // No Jazz credentials yet
|
|
325
|
+
update: mockUserUpdate,
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
triggerUserChange(newClerkUser);
|
|
329
|
+
|
|
330
|
+
// Wait for async operations to complete
|
|
331
|
+
await vi.waitFor(() => {
|
|
332
|
+
expect(mockUserUpdate).toHaveBeenCalled();
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
// 4. Verify credentials synced to Clerk
|
|
336
|
+
expect(mockUserUpdate).toHaveBeenCalledWith({
|
|
337
|
+
unsafeMetadata: {
|
|
338
|
+
jazzAccountID: "test-account-id",
|
|
339
|
+
jazzAccountSecret: "test-secret",
|
|
340
|
+
jazzAccountSeed: [1, 2, 3],
|
|
341
|
+
},
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
// Verify profile name was updated from Clerk username
|
|
345
|
+
const me = await Account.getMe().$jazz.ensureLoaded({
|
|
346
|
+
resolve: { profile: true },
|
|
347
|
+
});
|
|
348
|
+
expect(me.profile.name).toBe("Test User");
|
|
349
|
+
|
|
350
|
+
// Verify authSecretStorage is updated with provider "clerk"
|
|
351
|
+
const storedCredentials = await authSecretStorage.get();
|
|
352
|
+
expect(storedCredentials).toEqual({
|
|
353
|
+
accountID: "test-account-id",
|
|
354
|
+
accountSecret: "test-secret",
|
|
355
|
+
secretSeed: new Uint8Array([1, 2, 3]),
|
|
356
|
+
provider: "clerk",
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
expect(signInSpy).toHaveBeenCalled();
|
|
360
|
+
expect(logInSpy).not.toHaveBeenCalled();
|
|
361
|
+
});
|
|
285
362
|
});
|
|
286
363
|
|
|
287
364
|
describe("initializeAuth", () => {
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { isClerkAuthStateEqual } from "../types";
|
|
3
|
+
|
|
4
|
+
describe("isClerkAuthStateEqual", () => {
|
|
5
|
+
const validCredentials = {
|
|
6
|
+
jazzAccountID: "account-123",
|
|
7
|
+
jazzAccountSecret: "secret-123",
|
|
8
|
+
jazzAccountSeed: [1, 2, 3],
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const differentCredentials = {
|
|
12
|
+
jazzAccountID: "account-456",
|
|
13
|
+
jazzAccountSecret: "secret-456",
|
|
14
|
+
jazzAccountSeed: [4, 5, 6],
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
describe("both users null/undefined", () => {
|
|
18
|
+
it.each([
|
|
19
|
+
{ previous: null, next: null, description: "both null" },
|
|
20
|
+
{ previous: undefined, next: undefined, description: "both undefined" },
|
|
21
|
+
{ previous: null, next: undefined, description: "null and undefined" },
|
|
22
|
+
{ previous: undefined, next: null, description: "undefined and null" },
|
|
23
|
+
])("returns true when $description", ({ previous, next }) => {
|
|
24
|
+
expect(isClerkAuthStateEqual(previous, next)).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe("one user null, other exists", () => {
|
|
29
|
+
it.each([
|
|
30
|
+
{
|
|
31
|
+
previous: null,
|
|
32
|
+
next: { unsafeMetadata: validCredentials },
|
|
33
|
+
description: "previous null, next exists",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
previous: { unsafeMetadata: validCredentials },
|
|
37
|
+
next: null,
|
|
38
|
+
description: "previous exists, next null",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
previous: undefined,
|
|
42
|
+
next: { unsafeMetadata: validCredentials },
|
|
43
|
+
description: "previous undefined, next exists",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
previous: { unsafeMetadata: validCredentials },
|
|
47
|
+
next: undefined,
|
|
48
|
+
description: "previous exists, next undefined",
|
|
49
|
+
},
|
|
50
|
+
])("returns false when $description", ({ previous, next }) => {
|
|
51
|
+
expect(isClerkAuthStateEqual(previous, next)).toBe(false);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe("same jazzAccountID", () => {
|
|
56
|
+
it("returns true when both users have the same jazzAccountID", () => {
|
|
57
|
+
const previous = { unsafeMetadata: validCredentials };
|
|
58
|
+
const next = {
|
|
59
|
+
unsafeMetadata: {
|
|
60
|
+
...validCredentials,
|
|
61
|
+
jazzAccountSecret: "different-secret",
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
expect(isClerkAuthStateEqual(previous, next)).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe("different jazzAccountID", () => {
|
|
69
|
+
it("returns false when users have different jazzAccountID", () => {
|
|
70
|
+
const previous = { unsafeMetadata: validCredentials };
|
|
71
|
+
const next = { unsafeMetadata: differentCredentials };
|
|
72
|
+
expect(isClerkAuthStateEqual(previous, next)).toBe(false);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe("neither user has valid credentials", () => {
|
|
77
|
+
it.each([
|
|
78
|
+
{
|
|
79
|
+
previous: { unsafeMetadata: {} },
|
|
80
|
+
next: { unsafeMetadata: {} },
|
|
81
|
+
description: "both have empty metadata",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
previous: { unsafeMetadata: { someOtherField: "value" } },
|
|
85
|
+
next: { unsafeMetadata: { anotherField: "value" } },
|
|
86
|
+
description: "both have non-credential metadata",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
previous: { unsafeMetadata: { jazzAccountID: "123" } },
|
|
90
|
+
next: { unsafeMetadata: { jazzAccountSecret: "456" } },
|
|
91
|
+
description: "both have incomplete credentials",
|
|
92
|
+
},
|
|
93
|
+
])("returns true when $description", ({ previous, next }) => {
|
|
94
|
+
expect(isClerkAuthStateEqual(previous, next)).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe("one has credentials, other doesn't", () => {
|
|
99
|
+
it.each([
|
|
100
|
+
{
|
|
101
|
+
previous: { unsafeMetadata: validCredentials },
|
|
102
|
+
next: { unsafeMetadata: {} },
|
|
103
|
+
description: "previous has credentials, next empty",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
previous: { unsafeMetadata: {} },
|
|
107
|
+
next: { unsafeMetadata: validCredentials },
|
|
108
|
+
description: "previous empty, next has credentials",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
previous: { unsafeMetadata: validCredentials },
|
|
112
|
+
next: { unsafeMetadata: { jazzAccountID: "123" } },
|
|
113
|
+
description: "previous has credentials, next has incomplete",
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
previous: { unsafeMetadata: { jazzAccountSecret: "456" } },
|
|
117
|
+
next: { unsafeMetadata: validCredentials },
|
|
118
|
+
description: "previous has incomplete, next has credentials",
|
|
119
|
+
},
|
|
120
|
+
])("returns false when $description", ({ previous, next }) => {
|
|
121
|
+
expect(isClerkAuthStateEqual(previous, next)).toBe(false);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|
|
@@ -36,21 +36,38 @@ export type ClerkCredentials = {
|
|
|
36
36
|
* **Note**: It does not validate the credentials, only checks if the necessary fields are present in the metadata object.
|
|
37
37
|
*/
|
|
38
38
|
export function isClerkCredentials(
|
|
39
|
-
data:
|
|
39
|
+
data:
|
|
40
|
+
| NonNullable<MinimalClerkClient["user"]>["unsafeMetadata"]
|
|
41
|
+
| null
|
|
42
|
+
| undefined,
|
|
40
43
|
): data is ClerkCredentials {
|
|
41
44
|
return !!data && "jazzAccountID" in data && "jazzAccountSecret" in data;
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
export function isClerkAuthStateEqual(
|
|
45
|
-
previousUser:
|
|
46
|
-
|
|
48
|
+
previousUser:
|
|
49
|
+
| Pick<NonNullable<MinimalClerkClient["user"]>, "unsafeMetadata">
|
|
50
|
+
| null
|
|
51
|
+
| undefined,
|
|
52
|
+
newUser:
|
|
53
|
+
| Pick<NonNullable<MinimalClerkClient["user"]>, "unsafeMetadata">
|
|
54
|
+
| null
|
|
55
|
+
| undefined,
|
|
47
56
|
) {
|
|
48
57
|
if (Boolean(previousUser) !== Boolean(newUser)) {
|
|
49
58
|
return false;
|
|
50
59
|
}
|
|
51
60
|
|
|
52
|
-
const previousCredentials = isClerkCredentials(previousUser?.unsafeMetadata)
|
|
53
|
-
|
|
61
|
+
const previousCredentials = isClerkCredentials(previousUser?.unsafeMetadata)
|
|
62
|
+
? previousUser?.unsafeMetadata
|
|
63
|
+
: null;
|
|
64
|
+
const newCredentials = isClerkCredentials(newUser?.unsafeMetadata)
|
|
65
|
+
? newUser?.unsafeMetadata
|
|
66
|
+
: null;
|
|
67
|
+
|
|
68
|
+
if (!previousCredentials || !newCredentials) {
|
|
69
|
+
return previousCredentials === newCredentials;
|
|
70
|
+
}
|
|
54
71
|
|
|
55
|
-
return previousCredentials === newCredentials;
|
|
72
|
+
return previousCredentials.jazzAccountID === newCredentials.jazzAccountID;
|
|
56
73
|
}
|