jazz-tools 0.20.11 → 0.20.12

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.
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/better-auth/auth/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EAGtB,MAAM,aAAa,CAAC;AASrB,KAAK,UAAU,GAAG,gBAAgB,GAAG;IACnC,MAAM,EAAE;QACN,IAAI,EAAE;YACJ,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT,IAAI,EAAE,QAAQ,CAAC;oBACf,QAAQ,EAAE,KAAK,CAAC;oBAChB,KAAK,EAAE,KAAK,CAAC;iBACd,CAAC;gBACF,oBAAoB,EAAE;oBACpB,IAAI,EAAE,QAAQ,CAAC;oBACf,QAAQ,EAAE,KAAK,CAAC;oBAChB,KAAK,EAAE,KAAK,CAAC;oBACb,QAAQ,EAAE,KAAK,CAAC;iBACjB,CAAC;aACH,CAAC;SACH,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,UA4Q9B,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/better-auth/auth/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EAGtB,MAAM,aAAa,CAAC;AASrB,KAAK,UAAU,GAAG,gBAAgB,GAAG;IACnC,MAAM,EAAE;QACN,IAAI,EAAE;YACJ,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT,IAAI,EAAE,QAAQ,CAAC;oBACf,QAAQ,EAAE,KAAK,CAAC;oBAChB,KAAK,EAAE,KAAK,CAAC;iBACd,CAAC;gBACF,oBAAoB,EAAE;oBACpB,IAAI,EAAE,QAAQ,CAAC;oBACf,QAAQ,EAAE,KAAK,CAAC;oBAChB,KAAK,EAAE,KAAK,CAAC;oBACb,QAAQ,EAAE,KAAK,CAAC;iBACjB,CAAC;aACH,CAAC;SACH,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,UA6Q9B,CAAC"}
@@ -163,7 +163,8 @@ export const jazzPlugin = () => {
163
163
  return context.path?.startsWith("/sign-in/email-otp") || false;
164
164
  },
165
165
  handler: createAuthMiddleware(async (ctx) => {
166
- const email = ctx.body.email;
166
+ // lowercase the email as done in https://github.com/better-auth/better-auth/blob/40a80b070bbabf2d6886e8a3ad1bc068c8d570cb/packages/better-auth/src/plugins/email-otp/routes.ts#L641
167
+ const email = ctx.body.email.toLowerCase();
167
168
  const identifier = `jazz-auth-sign-in-otp-${email}`;
168
169
  const data = await ctx.context.internalAdapter.findVerificationValue(identifier);
169
170
  // if not found, it isn't a sign-up
@@ -365,6 +365,40 @@ describe("Better-Auth server plugin", async () => {
365
365
  expect(accountCreationSpy).toHaveBeenCalledTimes(1);
366
366
  expect(accountCreationSpy).toHaveBeenCalledWith(expect.objectContaining({ accountID: "123" }), expect.any(Object));
367
367
  });
368
+ it("should be case-insensitive for email", async () => {
369
+ let OTP = "";
370
+ sendVerificationOTPSpy.mockImplementationOnce(({ otp }) => {
371
+ OTP = otp;
372
+ });
373
+ await auth.api.sendVerificationOTP({
374
+ headers: {
375
+ "x-jazz-auth": JSON.stringify({
376
+ accountID: "123",
377
+ secretSeed: [1, 2, 3],
378
+ accountSecret: "123",
379
+ }),
380
+ },
381
+ body: {
382
+ email: "EMAIL@email.it",
383
+ type: "sign-in",
384
+ },
385
+ });
386
+ expect(accountCreationSpy).toHaveBeenCalledTimes(0);
387
+ expect(sendVerificationOTPSpy).toHaveBeenCalledTimes(1);
388
+ expect(verificationCreationSpy).toHaveBeenCalledTimes(2);
389
+ expect(verificationCreationSpy.mock.calls[0]?.[0]).toMatchObject(expect.objectContaining({
390
+ identifier: "jazz-auth-sign-in-otp-email@email.it",
391
+ value: expect.stringContaining('"accountID":"123"'),
392
+ }));
393
+ await auth.api.signInEmailOTP({
394
+ body: {
395
+ email: "EMAIL@email.it",
396
+ otp: OTP,
397
+ },
398
+ });
399
+ expect(accountCreationSpy).toHaveBeenCalledTimes(1);
400
+ expect(accountCreationSpy).toHaveBeenCalledWith(expect.objectContaining({ accountID: "123" }), expect.any(Object));
401
+ });
368
402
  it("should not expect Jazz's credentials using Email OTP for sign-in an already registered user", async () => {
369
403
  // 1. User registration
370
404
  const userData = {
@@ -1,5 +1,5 @@
1
1
 
2
- > jazz-tools@0.20.11 build /home/runner/_work/jazz/jazz/packages/jazz-tools
2
+ > jazz-tools@0.20.12 build /home/runner/_work/jazz/jazz/packages/jazz-tools
3
3
  > tsup && pnpm types && pnpm build:svelte && pnpm build:better-auth-svelte
4
4
 
5
5
  CLI Building entry: {"index":"src/index.ts","testing":"src/testing.ts","tools/ssr":"src/tools/ssr/index.ts"}
@@ -109,81 +109,81 @@
109
109
  ESM Build start
110
110
  ESM dist/tiptap/index.js 564.00 B
111
111
  ESM dist/tiptap/index.js.map 1.21 KB
112
- ESM ⚡️ Build success in 39ms
112
+ ESM ⚡️ Build success in 38ms
113
113
  ESM dist/worker/index.js 3.45 KB
114
114
  ESM dist/worker/edge-wasm.js 259.00 B
115
115
  ESM dist/worker/napi-crypto.js 110.00 B
116
116
  ESM dist/worker/index.js.map 6.97 KB
117
117
  ESM dist/worker/edge-wasm.js.map 505.00 B
118
118
  ESM dist/worker/napi-crypto.js.map 162.00 B
119
- ESM ⚡️ Build success in 38ms
119
+ ESM ⚡️ Build success in 36ms
120
120
  ESM dist/better-auth/auth/client.js 4.54 KB
121
- ESM dist/better-auth/auth/server.js 8.40 KB
121
+ ESM dist/better-auth/auth/server.js 8.42 KB
122
122
  ESM dist/better-auth/auth/react.js 813.00 B
123
123
  ESM dist/better-auth/auth/client.js.map 8.44 KB
124
- ESM dist/better-auth/auth/server.js.map 15.40 KB
124
+ ESM dist/better-auth/auth/server.js.map 15.61 KB
125
125
  ESM dist/better-auth/auth/react.js.map 2.07 KB
126
- ESM ⚡️ Build success in 33ms
126
+ ESM ⚡️ Build success in 34ms
127
127
  ESM dist/media/index.js 236.00 B
128
128
  ESM dist/media/index.browser.js 2.79 KB
129
- ESM dist/media/index.server.js 2.95 KB
130
129
  ESM dist/media/index.native.js 4.02 KB
130
+ ESM dist/media/index.server.js 2.95 KB
131
131
  ESM dist/media/chunk-IRL3KNPO.js 6.70 KB
132
132
  ESM dist/media/index.js.map 71.00 B
133
133
  ESM dist/media/index.browser.js.map 6.15 KB
134
- ESM dist/media/index.server.js.map 6.37 KB
135
134
  ESM dist/media/index.native.js.map 8.13 KB
135
+ ESM dist/media/index.server.js.map 6.37 KB
136
136
  ESM dist/media/chunk-IRL3KNPO.js.map 17.00 KB
137
- ESM ⚡️ Build success in 60ms
138
- ESM dist/browser/index.js 15.96 KB
139
- ESM dist/browser/index.js.map 34.06 KB
140
- ESM ⚡️ Build success in 62ms
141
- ESM dist/react-core/index.js 17.87 KB
137
+ ESM ⚡️ Build success in 43ms
142
138
  ESM dist/react-core/testing.js 904.00 B
143
139
  ESM dist/react-core/chunk-UOYH6JFJ.js 189.00 B
144
- ESM dist/react-core/index.js.map 58.59 KB
140
+ ESM dist/react-core/index.js 17.87 KB
145
141
  ESM dist/react-core/testing.js.map 1.34 KB
146
142
  ESM dist/react-core/chunk-UOYH6JFJ.js.map 363.00 B
147
- ESM ⚡️ Build success in 58ms
148
- ESM dist/better-auth/database-adapter/index.js 26.86 KB
149
- ESM dist/better-auth/database-adapter/index.js.map 58.67 KB
150
- ESM ⚡️ Build success in 52ms
143
+ ESM dist/react-core/index.js.map 58.59 KB
144
+ ESM ⚡️ Build success in 56ms
151
145
  ESM dist/expo/index.js 5.65 KB
152
146
  ESM dist/expo/testing.js 112.00 B
153
147
  ESM dist/expo/polyfills.js 858.00 B
154
148
  ESM dist/expo/index.js.map 11.85 KB
155
149
  ESM dist/expo/testing.js.map 168.00 B
156
150
  ESM dist/expo/polyfills.js.map 1.61 KB
157
- ESM ⚡️ Build success in 60ms
158
- ESM dist/prosemirror/index.js 78.48 KB
159
- ESM dist/prosemirror/index.js.map 309.11 KB
160
- ESM ⚡️ Build success in 66ms
151
+ ESM ⚡️ Build success in 53ms
152
+ ESM dist/browser/index.js 15.96 KB
153
+ ESM dist/browser/index.js.map 34.06 KB
154
+ ESM ⚡️ Build success in 71ms
155
+ ESM dist/react/testing.js 122.00 B
161
156
  ESM dist/react/index.js 26.02 KB
162
157
  ESM dist/react/ssr.js 693.00 B
163
- ESM dist/react/testing.js 122.00 B
164
- ESM dist/react/ssr.js.map 1.10 KB
165
- ESM dist/react/index.js.map 55.45 KB
166
158
  ESM dist/react/testing.js.map 165.00 B
167
- ESM ⚡️ Build success in 68ms
159
+ ESM dist/react/index.js.map 55.45 KB
160
+ ESM dist/react/ssr.js.map 1.10 KB
161
+ ESM ⚡️ Build success in 63ms
162
+ ESM dist/better-auth/database-adapter/index.js 26.86 KB
163
+ ESM dist/better-auth/database-adapter/index.js.map 58.67 KB
164
+ ESM ⚡️ Build success in 61ms
165
+ ESM dist/prosemirror/index.js 78.48 KB
166
+ ESM dist/prosemirror/index.js.map 309.11 KB
167
+ ESM ⚡️ Build success in 84ms
168
+ ESM dist/react-native-core/index.js 34.47 KB
169
+ ESM dist/react-native-core/testing.js 119.00 B
170
+ ESM dist/react-native-core/index.js.map 69.10 KB
171
+ ESM dist/react-native-core/testing.js.map 175.00 B
172
+ ESM ⚡️ Build success in 83ms
168
173
  ESM dist/react-native/index.js 38.21 KB
169
- ESM dist/react-native/polyfills.js 858.00 B
170
174
  ESM dist/react-native/testing.js 120.00 B
171
- ESM dist/react-native/polyfills.js.map 1.61 KB
175
+ ESM dist/react-native/polyfills.js 858.00 B
172
176
  ESM dist/react-native/testing.js.map 176.00 B
177
+ ESM dist/react-native/polyfills.js.map 1.61 KB
173
178
  ESM dist/react-native/index.js.map 76.75 KB
174
- ESM ⚡️ Build success in 80ms
175
- ESM dist/react-native-core/testing.js 119.00 B
176
- ESM dist/react-native-core/index.js 34.47 KB
177
- ESM dist/react-native-core/testing.js.map 175.00 B
178
- ESM dist/react-native-core/index.js.map 69.10 KB
179
- ESM ⚡️ Build success in 79ms
179
+ ESM ⚡️ Build success in 88ms
180
180
  ESM dist/inspector/index.js 37.49 KB
181
181
  ESM dist/inspector/standalone.js 12.61 KB
182
182
  ESM dist/inspector/chunk-ORKZSKZF.js 128.83 KB
183
- ESM dist/inspector/index.js.map 63.80 KB
184
183
  ESM dist/inspector/standalone.js.map 20.11 KB
184
+ ESM dist/inspector/index.js.map 63.80 KB
185
185
  ESM dist/inspector/chunk-ORKZSKZF.js.map 222.34 KB
186
- ESM ⚡️ Build success in 95ms
186
+ ESM ⚡️ Build success in 122ms
187
187
  ESM dist/testing.js 8.56 KB
188
188
  ESM dist/index.js 32.18 KB
189
189
  ESM dist/tools/ssr.js 156.00 B
@@ -191,28 +191,28 @@
191
191
  ESM dist/chunk-ZQWSQH6L.js 945.00 B
192
192
  ESM dist/chunk-KGV2CJMG.js 262.16 KB
193
193
  ESM dist/testing.js.map 16.22 KB
194
- ESM dist/index.js.map 65.34 KB
195
- ESM dist/tools/ssr.js.map 71.00 B
196
194
  ESM dist/chunk-K4D7IMFM.js.map 1.10 KB
195
+ ESM dist/tools/ssr.js.map 71.00 B
196
+ ESM dist/index.js.map 65.34 KB
197
197
  ESM dist/chunk-ZQWSQH6L.js.map 71.00 B
198
198
  ESM dist/chunk-KGV2CJMG.js.map 604.30 KB
199
- ESM ⚡️ Build success in 127ms
199
+ ESM ⚡️ Build success in 139ms
200
200
  ESM dist/inspector/register-custom-element.js 305.00 B
201
201
  ESM dist/inspector/register-custom-element.js.map 445.00 B
202
202
  ESM dist/inspector/custom-element-7G7IZVLL.js 1.64 MB
203
203
  ESM dist/inspector/custom-element-7G7IZVLL.js.map 2.52 MB
204
- ESM ⚡️ Build success in 157ms
204
+ ESM ⚡️ Build success in 171ms
205
205
 
206
- > jazz-tools@0.20.11 types /home/runner/_work/jazz/jazz/packages/jazz-tools
206
+ > jazz-tools@0.20.12 types /home/runner/_work/jazz/jazz/packages/jazz-tools
207
207
  > tsc --outDir dist
208
208
 
209
209
 
210
- > jazz-tools@0.20.11 build:svelte /home/runner/_work/jazz/jazz/packages/jazz-tools
210
+ > jazz-tools@0.20.12 build:svelte /home/runner/_work/jazz/jazz/packages/jazz-tools
211
211
  > rm -rf dist/svelte && svelte-package -i src/svelte -o dist/svelte --tsconfig tsconfig.svelte.json
212
212
 
213
213
  src/svelte -> dist/svelte
214
214
 
215
- > jazz-tools@0.20.11 build:better-auth-svelte /home/runner/_work/jazz/jazz/packages/jazz-tools
215
+ > jazz-tools@0.20.12 build:better-auth-svelte /home/runner/_work/jazz/jazz/packages/jazz-tools
216
216
  > mkdir -p dist/better-auth/auth && svelte-package -i src/better-auth/auth -o dist/better-auth/auth-temp --tsconfig tsconfig.svelte.json && cp dist/better-auth/auth-temp/svelte.svelte dist/better-auth/auth/svelte.svelte && cp dist/better-auth/auth-temp/svelte.svelte.d.ts dist/better-auth/auth/svelte.d.ts && rm -rf dist/better-auth/auth-temp
217
217
 
218
218
  src/better-auth/auth -> dist/better-auth/auth-temp
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # jazz-tools
2
2
 
3
+ ## 0.20.12
4
+
5
+ ### Patch Changes
6
+
7
+ - 9a43096: Fixed Better Auth email OTP sign-in to handle email addresses case-insensitively.
8
+ - cojson@0.20.12
9
+ - cojson-storage-indexeddb@0.20.12
10
+ - cojson-transport-ws@0.20.12
11
+
3
12
  ## 0.20.11
4
13
 
5
14
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/better-auth/auth/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EAGtB,MAAM,aAAa,CAAC;AASrB,KAAK,UAAU,GAAG,gBAAgB,GAAG;IACnC,MAAM,EAAE;QACN,IAAI,EAAE;YACJ,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT,IAAI,EAAE,QAAQ,CAAC;oBACf,QAAQ,EAAE,KAAK,CAAC;oBAChB,KAAK,EAAE,KAAK,CAAC;iBACd,CAAC;gBACF,oBAAoB,EAAE;oBACpB,IAAI,EAAE,QAAQ,CAAC;oBACf,QAAQ,EAAE,KAAK,CAAC;oBAChB,KAAK,EAAE,KAAK,CAAC;oBACb,QAAQ,EAAE,KAAK,CAAC;iBACjB,CAAC;aACH,CAAC;SACH,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,UA4Q9B,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/better-auth/auth/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EAGtB,MAAM,aAAa,CAAC;AASrB,KAAK,UAAU,GAAG,gBAAgB,GAAG;IACnC,MAAM,EAAE;QACN,IAAI,EAAE;YACJ,MAAM,EAAE;gBACN,SAAS,EAAE;oBACT,IAAI,EAAE,QAAQ,CAAC;oBACf,QAAQ,EAAE,KAAK,CAAC;oBAChB,KAAK,EAAE,KAAK,CAAC;iBACd,CAAC;gBACF,oBAAoB,EAAE;oBACpB,IAAI,EAAE,QAAQ,CAAC;oBACf,QAAQ,EAAE,KAAK,CAAC;oBAChB,KAAK,EAAE,KAAK,CAAC;oBACb,QAAQ,EAAE,KAAK,CAAC;iBACjB,CAAC;aACH,CAAC;SACH,CAAC;KACH,CAAC;CACH,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,EAAE,MAAM,UA6Q9B,CAAC"}
@@ -147,7 +147,7 @@ var jazzPlugin = () => {
147
147
  return context.path?.startsWith("/sign-in/email-otp") || false;
148
148
  },
149
149
  handler: createAuthMiddleware(async (ctx) => {
150
- const email = ctx.body.email;
150
+ const email = ctx.body.email.toLowerCase();
151
151
  const identifier = `jazz-auth-sign-in-otp-${email}`;
152
152
  const data = await ctx.context.internalAdapter.findVerificationValue(
153
153
  identifier
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/better-auth/auth/server.ts"],"sourcesContent":["import {\n AuthContext,\n type BetterAuthPlugin,\n MiddlewareContext,\n MiddlewareOptions,\n} from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\nimport { symmetricDecrypt, symmetricEncrypt } from \"better-auth/crypto\";\nimport { createAuthMiddleware } from \"better-auth/plugins\";\nimport type { Account, AuthCredentials, ID } from \"jazz-tools\";\n\n// Define a type to have user fields mapped in the better-auth instance\n// It should be automatic, but it needs an hard reference to BetterAuthPlugin type\n// in order to be exported as library.\ntype JazzPlugin = BetterAuthPlugin & {\n schema: {\n user: {\n fields: {\n accountID: {\n type: \"string\";\n required: false;\n input: false;\n };\n encryptedCredentials: {\n type: \"string\";\n required: false;\n input: false;\n returned: false;\n };\n };\n };\n };\n};\n\n/**\n * @returns The BetterAuth server plugin.\n *\n * @example\n * ```ts\n * const auth = betterAuth({\n * plugins: [jazzPlugin()],\n * // ... other BetterAuth options\n * });\n * ```\n */\nexport const jazzPlugin: () => JazzPlugin = () => {\n return {\n id: \"jazz-plugin\",\n schema: {\n user: {\n fields: {\n accountID: {\n type: \"string\",\n required: false,\n input: false,\n },\n encryptedCredentials: {\n type: \"string\",\n required: false,\n input: false,\n returned: false,\n },\n },\n },\n },\n\n init() {\n return {\n options: {\n databaseHooks: {\n user: {\n create: {\n before: async (user, context) => {\n // If the user is created without a jazzAuth, it will throw an error.\n if (!contextContainsJazzAuth(context)) {\n throw new APIError(422, {\n message: \"JazzAuth is required on user creation\",\n });\n }\n // Decorate the user with the jazz's credentials.\n return {\n data: {\n accountID: context.jazzAuth.accountID,\n encryptedCredentials:\n context.jazzAuth.encryptedCredentials,\n },\n };\n },\n },\n },\n verification: {\n create: {\n after: async (verification, context) => {\n /**\n * For: Email OTP plugin\n * After a verification is created, if it is from the EmailOTP plugin,\n * create a new verification value with the jazzAuth with the same expiration.\n */\n if (\n contextContainsJazzAuth(context) &&\n verification.identifier.startsWith(\"sign-in-otp-\")\n ) {\n const identifier = `jazz-auth-${verification.identifier}`;\n await context.context.internalAdapter.deleteVerificationByIdentifier(\n identifier,\n );\n await context.context.internalAdapter.createVerificationValue(\n {\n value: JSON.stringify({ jazzAuth: context.jazzAuth }),\n identifier: identifier,\n expiresAt: verification.expiresAt,\n },\n );\n }\n },\n },\n },\n },\n },\n };\n },\n\n hooks: {\n before: [\n /**\n * If the client sends a x-jazz-auth header,\n * we encrypt the credentials and inject them into the context.\n */\n {\n matcher: (context) => {\n return !!context.headers?.get(\"x-jazz-auth\");\n },\n handler: createAuthMiddleware(async (ctx) => {\n const jazzAuth = JSON.parse(ctx.headers?.get(\"x-jazz-auth\")!);\n\n const credentials: AuthCredentials = {\n accountID: jazzAuth.accountID as ID<Account>,\n secretSeed: jazzAuth.secretSeed,\n accountSecret: jazzAuth.accountSecret as any,\n // If the provider remains 'anonymous', Jazz will not consider us authenticated later.\n provider: \"better-auth\",\n };\n\n const encryptedCredentials = await symmetricEncrypt({\n key: ctx.context.secret,\n data: JSON.stringify(credentials),\n });\n\n return {\n context: {\n ...ctx,\n jazzAuth: {\n accountID: jazzAuth.accountID,\n encryptedCredentials: encryptedCredentials,\n },\n },\n };\n }),\n },\n\n /**\n * For: Social / OAuth2 plugin\n * /callback is the endpoint that BetterAuth uses to authenticate the user coming from a social provider.\n * 1. Catch the state\n * 2. Find the verification value\n * 3. If the verification value contains a jazzAuth, inject into the context to have it in case of registration.\n */\n {\n matcher: (context) => {\n return (\n context.path?.startsWith(\"/callback\") ||\n context.path?.startsWith(\"/oauth2/callback\") ||\n false\n );\n },\n handler: createAuthMiddleware(async (ctx) => {\n const state = ctx.query?.state || ctx.body?.state;\n\n const identifier = `jazz-auth-${state}`;\n\n const data =\n await ctx.context.internalAdapter.findVerificationValue(\n identifier,\n );\n\n // if not found, the social plugin will throw later anyway\n if (!data) {\n throw new APIError(404, {\n message: \"Verification not found\",\n });\n }\n\n const parsed = JSON.parse(data.value);\n\n if (parsed && \"jazzAuth\" in parsed) {\n return {\n context: {\n ...ctx,\n jazzAuth: parsed.jazzAuth,\n },\n };\n } else {\n throw new APIError(404, {\n message: \"JazzAuth not found in verification value\",\n });\n }\n }),\n },\n /**\n * For: Email OTP plugin\n * When the user sends an OTP, we try to find the jazzAuth.\n * If it isn't a sign-up, we expect to not find a verification value.\n */\n {\n matcher: (context) => {\n return context.path?.startsWith(\"/sign-in/email-otp\") || false;\n },\n handler: createAuthMiddleware(async (ctx) => {\n const email = ctx.body.email;\n const identifier = `jazz-auth-sign-in-otp-${email}`;\n\n const data =\n await ctx.context.internalAdapter.findVerificationValue(\n identifier,\n );\n\n // if not found, it isn't a sign-up\n if (!data || data.expiresAt < new Date()) {\n return;\n }\n\n const parsed = JSON.parse(data.value);\n\n if (parsed && \"jazzAuth\" in parsed) {\n return {\n context: {\n ...ctx,\n jazzAuth: parsed.jazzAuth,\n },\n };\n } else {\n throw new APIError(500, {\n message: \"JazzAuth not found in verification value\",\n });\n }\n }),\n },\n ],\n after: [\n /**\n * This middleware is used to extract the jazzAuth from the user and return it in the response.\n * It is used in the following endpoints that return the user:\n * - /sign-up/email\n * - /sign-in/email\n * - /get-session\n */\n {\n matcher: (context) => {\n return (\n context.path?.startsWith(\"/sign-up\") ||\n context.path?.startsWith(\"/sign-in\") ||\n context.path?.startsWith(\"/get-session\") ||\n false\n );\n },\n handler: createAuthMiddleware({}, async (ctx) => {\n const returned = ctx.context.returned as any;\n if (!returned?.user?.id) {\n return;\n }\n const jazzAuth = await extractJazzAuth(returned.user.id, ctx);\n\n return ctx.json({\n ...returned,\n jazzAuth: jazzAuth,\n });\n }),\n },\n\n /**\n * For: Social / OAuth2 plugin\n * When the user sign-in via social, we create a verification value with the jazzAuth.\n */\n {\n matcher: (context) => {\n return context.path?.startsWith(\"/sign-in/social\") || false;\n },\n handler: createAuthMiddleware(async (ctx) => {\n if (!contextContainsJazzAuth(ctx)) {\n throw new APIError(500, {\n message: \"JazzAuth not found in context\",\n });\n }\n\n const returned = ctx.context.returned as { url: string };\n\n const url = new URL(returned.url);\n const state = url.searchParams.get(\"state\");\n\n const value = JSON.stringify({ jazzAuth: ctx.jazzAuth });\n const expiresAt = new Date();\n expiresAt.setMinutes(expiresAt.getMinutes() + 10);\n\n await ctx.context.internalAdapter.createVerificationValue({\n value,\n identifier: `jazz-auth-${state}`,\n expiresAt,\n });\n }),\n },\n ],\n },\n } satisfies JazzPlugin;\n};\n\nfunction contextContainsJazzAuth(ctx: unknown): ctx is {\n jazzAuth: {\n accountID: string;\n encryptedCredentials: string;\n };\n} {\n return !!ctx && typeof ctx === \"object\" && \"jazzAuth\" in ctx;\n}\n\nasync function extractJazzAuth(\n userId: string,\n ctx: MiddlewareContext<\n MiddlewareOptions,\n AuthContext & {\n returned?: unknown;\n responseHeaders?: Headers;\n }\n >,\n) {\n const user = await ctx.context.adapter.findOne<{\n accountID: string;\n encryptedCredentials: string;\n }>({\n model: ctx.context.tables.user!.modelName,\n where: [\n {\n field: \"id\",\n operator: \"eq\",\n value: userId,\n },\n ],\n select: [\"accountID\", \"encryptedCredentials\"],\n });\n\n if (!user) {\n return;\n }\n\n const jazzAuth = JSON.parse(\n await symmetricDecrypt({\n key: ctx.context.secret,\n data: user.encryptedCredentials,\n }),\n );\n\n return jazzAuth;\n}\n"],"mappings":";AAMA,SAAS,gBAAgB;AACzB,SAAS,kBAAkB,wBAAwB;AACnD,SAAS,4BAA4B;AAqC9B,IAAM,aAA+B,MAAM;AAChD,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,QAAQ;AAAA,MACN,MAAM;AAAA,QACJ,QAAQ;AAAA,UACN,WAAW;AAAA,YACT,MAAM;AAAA,YACN,UAAU;AAAA,YACV,OAAO;AAAA,UACT;AAAA,UACA,sBAAsB;AAAA,YACpB,MAAM;AAAA,YACN,UAAU;AAAA,YACV,OAAO;AAAA,YACP,UAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,OAAO;AACL,aAAO;AAAA,QACL,SAAS;AAAA,UACP,eAAe;AAAA,YACb,MAAM;AAAA,cACJ,QAAQ;AAAA,gBACN,QAAQ,OAAO,MAAM,YAAY;AAE/B,sBAAI,CAAC,wBAAwB,OAAO,GAAG;AACrC,0BAAM,IAAI,SAAS,KAAK;AAAA,sBACtB,SAAS;AAAA,oBACX,CAAC;AAAA,kBACH;AAEA,yBAAO;AAAA,oBACL,MAAM;AAAA,sBACJ,WAAW,QAAQ,SAAS;AAAA,sBAC5B,sBACE,QAAQ,SAAS;AAAA,oBACrB;AAAA,kBACF;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,YACA,cAAc;AAAA,cACZ,QAAQ;AAAA,gBACN,OAAO,OAAO,cAAc,YAAY;AAMtC,sBACE,wBAAwB,OAAO,KAC/B,aAAa,WAAW,WAAW,cAAc,GACjD;AACA,0BAAM,aAAa,aAAa,aAAa,UAAU;AACvD,0BAAM,QAAQ,QAAQ,gBAAgB;AAAA,sBACpC;AAAA,oBACF;AACA,0BAAM,QAAQ,QAAQ,gBAAgB;AAAA,sBACpC;AAAA,wBACE,OAAO,KAAK,UAAU,EAAE,UAAU,QAAQ,SAAS,CAAC;AAAA,wBACpD;AAAA,wBACA,WAAW,aAAa;AAAA,sBAC1B;AAAA,oBACF;AAAA,kBACF;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,OAAO;AAAA,MACL,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,QAKN;AAAA,UACE,SAAS,CAAC,YAAY;AACpB,mBAAO,CAAC,CAAC,QAAQ,SAAS,IAAI,aAAa;AAAA,UAC7C;AAAA,UACA,SAAS,qBAAqB,OAAO,QAAQ;AAC3C,kBAAM,WAAW,KAAK,MAAM,IAAI,SAAS,IAAI,aAAa,CAAE;AAE5D,kBAAM,cAA+B;AAAA,cACnC,WAAW,SAAS;AAAA,cACpB,YAAY,SAAS;AAAA,cACrB,eAAe,SAAS;AAAA;AAAA,cAExB,UAAU;AAAA,YACZ;AAEA,kBAAM,uBAAuB,MAAM,iBAAiB;AAAA,cAClD,KAAK,IAAI,QAAQ;AAAA,cACjB,MAAM,KAAK,UAAU,WAAW;AAAA,YAClC,CAAC;AAED,mBAAO;AAAA,cACL,SAAS;AAAA,gBACP,GAAG;AAAA,gBACH,UAAU;AAAA,kBACR,WAAW,SAAS;AAAA,kBACpB;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QASA;AAAA,UACE,SAAS,CAAC,YAAY;AACpB,mBACE,QAAQ,MAAM,WAAW,WAAW,KACpC,QAAQ,MAAM,WAAW,kBAAkB,KAC3C;AAAA,UAEJ;AAAA,UACA,SAAS,qBAAqB,OAAO,QAAQ;AAC3C,kBAAM,QAAQ,IAAI,OAAO,SAAS,IAAI,MAAM;AAE5C,kBAAM,aAAa,aAAa,KAAK;AAErC,kBAAM,OACJ,MAAM,IAAI,QAAQ,gBAAgB;AAAA,cAChC;AAAA,YACF;AAGF,gBAAI,CAAC,MAAM;AACT,oBAAM,IAAI,SAAS,KAAK;AAAA,gBACtB,SAAS;AAAA,cACX,CAAC;AAAA,YACH;AAEA,kBAAM,SAAS,KAAK,MAAM,KAAK,KAAK;AAEpC,gBAAI,UAAU,cAAc,QAAQ;AAClC,qBAAO;AAAA,gBACL,SAAS;AAAA,kBACP,GAAG;AAAA,kBACH,UAAU,OAAO;AAAA,gBACnB;AAAA,cACF;AAAA,YACF,OAAO;AACL,oBAAM,IAAI,SAAS,KAAK;AAAA,gBACtB,SAAS;AAAA,cACX,CAAC;AAAA,YACH;AAAA,UACF,CAAC;AAAA,QACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMA;AAAA,UACE,SAAS,CAAC,YAAY;AACpB,mBAAO,QAAQ,MAAM,WAAW,oBAAoB,KAAK;AAAA,UAC3D;AAAA,UACA,SAAS,qBAAqB,OAAO,QAAQ;AAC3C,kBAAM,QAAQ,IAAI,KAAK;AACvB,kBAAM,aAAa,yBAAyB,KAAK;AAEjD,kBAAM,OACJ,MAAM,IAAI,QAAQ,gBAAgB;AAAA,cAChC;AAAA,YACF;AAGF,gBAAI,CAAC,QAAQ,KAAK,YAAY,oBAAI,KAAK,GAAG;AACxC;AAAA,YACF;AAEA,kBAAM,SAAS,KAAK,MAAM,KAAK,KAAK;AAEpC,gBAAI,UAAU,cAAc,QAAQ;AAClC,qBAAO;AAAA,gBACL,SAAS;AAAA,kBACP,GAAG;AAAA,kBACH,UAAU,OAAO;AAAA,gBACnB;AAAA,cACF;AAAA,YACF,OAAO;AACL,oBAAM,IAAI,SAAS,KAAK;AAAA,gBACtB,SAAS;AAAA,cACX,CAAC;AAAA,YACH;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,MACA,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAQL;AAAA,UACE,SAAS,CAAC,YAAY;AACpB,mBACE,QAAQ,MAAM,WAAW,UAAU,KACnC,QAAQ,MAAM,WAAW,UAAU,KACnC,QAAQ,MAAM,WAAW,cAAc,KACvC;AAAA,UAEJ;AAAA,UACA,SAAS,qBAAqB,CAAC,GAAG,OAAO,QAAQ;AAC/C,kBAAM,WAAW,IAAI,QAAQ;AAC7B,gBAAI,CAAC,UAAU,MAAM,IAAI;AACvB;AAAA,YACF;AACA,kBAAM,WAAW,MAAM,gBAAgB,SAAS,KAAK,IAAI,GAAG;AAE5D,mBAAO,IAAI,KAAK;AAAA,cACd,GAAG;AAAA,cACH;AAAA,YACF,CAAC;AAAA,UACH,CAAC;AAAA,QACH;AAAA;AAAA;AAAA;AAAA;AAAA,QAMA;AAAA,UACE,SAAS,CAAC,YAAY;AACpB,mBAAO,QAAQ,MAAM,WAAW,iBAAiB,KAAK;AAAA,UACxD;AAAA,UACA,SAAS,qBAAqB,OAAO,QAAQ;AAC3C,gBAAI,CAAC,wBAAwB,GAAG,GAAG;AACjC,oBAAM,IAAI,SAAS,KAAK;AAAA,gBACtB,SAAS;AAAA,cACX,CAAC;AAAA,YACH;AAEA,kBAAM,WAAW,IAAI,QAAQ;AAE7B,kBAAM,MAAM,IAAI,IAAI,SAAS,GAAG;AAChC,kBAAM,QAAQ,IAAI,aAAa,IAAI,OAAO;AAE1C,kBAAM,QAAQ,KAAK,UAAU,EAAE,UAAU,IAAI,SAAS,CAAC;AACvD,kBAAM,YAAY,oBAAI,KAAK;AAC3B,sBAAU,WAAW,UAAU,WAAW,IAAI,EAAE;AAEhD,kBAAM,IAAI,QAAQ,gBAAgB,wBAAwB;AAAA,cACxD;AAAA,cACA,YAAY,aAAa,KAAK;AAAA,cAC9B;AAAA,YACF,CAAC;AAAA,UACH,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,wBAAwB,KAK/B;AACA,SAAO,CAAC,CAAC,OAAO,OAAO,QAAQ,YAAY,cAAc;AAC3D;AAEA,eAAe,gBACb,QACA,KAOA;AACA,QAAM,OAAO,MAAM,IAAI,QAAQ,QAAQ,QAGpC;AAAA,IACD,OAAO,IAAI,QAAQ,OAAO,KAAM;AAAA,IAChC,OAAO;AAAA,MACL;AAAA,QACE,OAAO;AAAA,QACP,UAAU;AAAA,QACV,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,QAAQ,CAAC,aAAa,sBAAsB;AAAA,EAC9C,CAAC;AAED,MAAI,CAAC,MAAM;AACT;AAAA,EACF;AAEA,QAAM,WAAW,KAAK;AAAA,IACpB,MAAM,iBAAiB;AAAA,MACrB,KAAK,IAAI,QAAQ;AAAA,MACjB,MAAM,KAAK;AAAA,IACb,CAAC;AAAA,EACH;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../../src/better-auth/auth/server.ts"],"sourcesContent":["import {\n AuthContext,\n type BetterAuthPlugin,\n MiddlewareContext,\n MiddlewareOptions,\n} from \"better-auth\";\nimport { APIError } from \"better-auth/api\";\nimport { symmetricDecrypt, symmetricEncrypt } from \"better-auth/crypto\";\nimport { createAuthMiddleware } from \"better-auth/plugins\";\nimport type { Account, AuthCredentials, ID } from \"jazz-tools\";\n\n// Define a type to have user fields mapped in the better-auth instance\n// It should be automatic, but it needs an hard reference to BetterAuthPlugin type\n// in order to be exported as library.\ntype JazzPlugin = BetterAuthPlugin & {\n schema: {\n user: {\n fields: {\n accountID: {\n type: \"string\";\n required: false;\n input: false;\n };\n encryptedCredentials: {\n type: \"string\";\n required: false;\n input: false;\n returned: false;\n };\n };\n };\n };\n};\n\n/**\n * @returns The BetterAuth server plugin.\n *\n * @example\n * ```ts\n * const auth = betterAuth({\n * plugins: [jazzPlugin()],\n * // ... other BetterAuth options\n * });\n * ```\n */\nexport const jazzPlugin: () => JazzPlugin = () => {\n return {\n id: \"jazz-plugin\",\n schema: {\n user: {\n fields: {\n accountID: {\n type: \"string\",\n required: false,\n input: false,\n },\n encryptedCredentials: {\n type: \"string\",\n required: false,\n input: false,\n returned: false,\n },\n },\n },\n },\n\n init() {\n return {\n options: {\n databaseHooks: {\n user: {\n create: {\n before: async (user, context) => {\n // If the user is created without a jazzAuth, it will throw an error.\n if (!contextContainsJazzAuth(context)) {\n throw new APIError(422, {\n message: \"JazzAuth is required on user creation\",\n });\n }\n // Decorate the user with the jazz's credentials.\n return {\n data: {\n accountID: context.jazzAuth.accountID,\n encryptedCredentials:\n context.jazzAuth.encryptedCredentials,\n },\n };\n },\n },\n },\n verification: {\n create: {\n after: async (verification, context) => {\n /**\n * For: Email OTP plugin\n * After a verification is created, if it is from the EmailOTP plugin,\n * create a new verification value with the jazzAuth with the same expiration.\n */\n if (\n contextContainsJazzAuth(context) &&\n verification.identifier.startsWith(\"sign-in-otp-\")\n ) {\n const identifier = `jazz-auth-${verification.identifier}`;\n await context.context.internalAdapter.deleteVerificationByIdentifier(\n identifier,\n );\n await context.context.internalAdapter.createVerificationValue(\n {\n value: JSON.stringify({ jazzAuth: context.jazzAuth }),\n identifier: identifier,\n expiresAt: verification.expiresAt,\n },\n );\n }\n },\n },\n },\n },\n },\n };\n },\n\n hooks: {\n before: [\n /**\n * If the client sends a x-jazz-auth header,\n * we encrypt the credentials and inject them into the context.\n */\n {\n matcher: (context) => {\n return !!context.headers?.get(\"x-jazz-auth\");\n },\n handler: createAuthMiddleware(async (ctx) => {\n const jazzAuth = JSON.parse(ctx.headers?.get(\"x-jazz-auth\")!);\n\n const credentials: AuthCredentials = {\n accountID: jazzAuth.accountID as ID<Account>,\n secretSeed: jazzAuth.secretSeed,\n accountSecret: jazzAuth.accountSecret as any,\n // If the provider remains 'anonymous', Jazz will not consider us authenticated later.\n provider: \"better-auth\",\n };\n\n const encryptedCredentials = await symmetricEncrypt({\n key: ctx.context.secret,\n data: JSON.stringify(credentials),\n });\n\n return {\n context: {\n ...ctx,\n jazzAuth: {\n accountID: jazzAuth.accountID,\n encryptedCredentials: encryptedCredentials,\n },\n },\n };\n }),\n },\n\n /**\n * For: Social / OAuth2 plugin\n * /callback is the endpoint that BetterAuth uses to authenticate the user coming from a social provider.\n * 1. Catch the state\n * 2. Find the verification value\n * 3. If the verification value contains a jazzAuth, inject into the context to have it in case of registration.\n */\n {\n matcher: (context) => {\n return (\n context.path?.startsWith(\"/callback\") ||\n context.path?.startsWith(\"/oauth2/callback\") ||\n false\n );\n },\n handler: createAuthMiddleware(async (ctx) => {\n const state = ctx.query?.state || ctx.body?.state;\n\n const identifier = `jazz-auth-${state}`;\n\n const data =\n await ctx.context.internalAdapter.findVerificationValue(\n identifier,\n );\n\n // if not found, the social plugin will throw later anyway\n if (!data) {\n throw new APIError(404, {\n message: \"Verification not found\",\n });\n }\n\n const parsed = JSON.parse(data.value);\n\n if (parsed && \"jazzAuth\" in parsed) {\n return {\n context: {\n ...ctx,\n jazzAuth: parsed.jazzAuth,\n },\n };\n } else {\n throw new APIError(404, {\n message: \"JazzAuth not found in verification value\",\n });\n }\n }),\n },\n /**\n * For: Email OTP plugin\n * When the user sends an OTP, we try to find the jazzAuth.\n * If it isn't a sign-up, we expect to not find a verification value.\n */\n {\n matcher: (context) => {\n return context.path?.startsWith(\"/sign-in/email-otp\") || false;\n },\n handler: createAuthMiddleware(async (ctx) => {\n // lowercase the email as done in https://github.com/better-auth/better-auth/blob/40a80b070bbabf2d6886e8a3ad1bc068c8d570cb/packages/better-auth/src/plugins/email-otp/routes.ts#L641\n const email = ctx.body.email.toLowerCase();\n const identifier = `jazz-auth-sign-in-otp-${email}`;\n\n const data =\n await ctx.context.internalAdapter.findVerificationValue(\n identifier,\n );\n\n // if not found, it isn't a sign-up\n if (!data || data.expiresAt < new Date()) {\n return;\n }\n\n const parsed = JSON.parse(data.value);\n\n if (parsed && \"jazzAuth\" in parsed) {\n return {\n context: {\n ...ctx,\n jazzAuth: parsed.jazzAuth,\n },\n };\n } else {\n throw new APIError(500, {\n message: \"JazzAuth not found in verification value\",\n });\n }\n }),\n },\n ],\n after: [\n /**\n * This middleware is used to extract the jazzAuth from the user and return it in the response.\n * It is used in the following endpoints that return the user:\n * - /sign-up/email\n * - /sign-in/email\n * - /get-session\n */\n {\n matcher: (context) => {\n return (\n context.path?.startsWith(\"/sign-up\") ||\n context.path?.startsWith(\"/sign-in\") ||\n context.path?.startsWith(\"/get-session\") ||\n false\n );\n },\n handler: createAuthMiddleware({}, async (ctx) => {\n const returned = ctx.context.returned as any;\n if (!returned?.user?.id) {\n return;\n }\n const jazzAuth = await extractJazzAuth(returned.user.id, ctx);\n\n return ctx.json({\n ...returned,\n jazzAuth: jazzAuth,\n });\n }),\n },\n\n /**\n * For: Social / OAuth2 plugin\n * When the user sign-in via social, we create a verification value with the jazzAuth.\n */\n {\n matcher: (context) => {\n return context.path?.startsWith(\"/sign-in/social\") || false;\n },\n handler: createAuthMiddleware(async (ctx) => {\n if (!contextContainsJazzAuth(ctx)) {\n throw new APIError(500, {\n message: \"JazzAuth not found in context\",\n });\n }\n\n const returned = ctx.context.returned as { url: string };\n\n const url = new URL(returned.url);\n const state = url.searchParams.get(\"state\");\n\n const value = JSON.stringify({ jazzAuth: ctx.jazzAuth });\n const expiresAt = new Date();\n expiresAt.setMinutes(expiresAt.getMinutes() + 10);\n\n await ctx.context.internalAdapter.createVerificationValue({\n value,\n identifier: `jazz-auth-${state}`,\n expiresAt,\n });\n }),\n },\n ],\n },\n } satisfies JazzPlugin;\n};\n\nfunction contextContainsJazzAuth(ctx: unknown): ctx is {\n jazzAuth: {\n accountID: string;\n encryptedCredentials: string;\n };\n} {\n return !!ctx && typeof ctx === \"object\" && \"jazzAuth\" in ctx;\n}\n\nasync function extractJazzAuth(\n userId: string,\n ctx: MiddlewareContext<\n MiddlewareOptions,\n AuthContext & {\n returned?: unknown;\n responseHeaders?: Headers;\n }\n >,\n) {\n const user = await ctx.context.adapter.findOne<{\n accountID: string;\n encryptedCredentials: string;\n }>({\n model: ctx.context.tables.user!.modelName,\n where: [\n {\n field: \"id\",\n operator: \"eq\",\n value: userId,\n },\n ],\n select: [\"accountID\", \"encryptedCredentials\"],\n });\n\n if (!user) {\n return;\n }\n\n const jazzAuth = JSON.parse(\n await symmetricDecrypt({\n key: ctx.context.secret,\n data: user.encryptedCredentials,\n }),\n );\n\n return jazzAuth;\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -196,7 +196,7 @@
196
196
  },
197
197
  "type": "module",
198
198
  "license": "MIT",
199
- "version": "0.20.11",
199
+ "version": "0.20.12",
200
200
  "dependencies": {
201
201
  "@scure/base": "1.2.1",
202
202
  "@scure/bip39": "^1.3.0",
@@ -212,9 +212,9 @@
212
212
  "prosemirror-transform": "^1.9.0",
213
213
  "use-sync-external-store": "^1.5.0",
214
214
  "zod": "4.1.11",
215
- "cojson": "0.20.11",
216
- "cojson-storage-indexeddb": "0.20.11",
217
- "cojson-transport-ws": "0.20.11"
215
+ "cojson": "0.20.12",
216
+ "cojson-storage-indexeddb": "0.20.12",
217
+ "cojson-transport-ws": "0.20.12"
218
218
  },
219
219
  "devDependencies": {
220
220
  "@scure/bip39": "^1.3.0",
@@ -216,7 +216,8 @@ export const jazzPlugin: () => JazzPlugin = () => {
216
216
  return context.path?.startsWith("/sign-in/email-otp") || false;
217
217
  },
218
218
  handler: createAuthMiddleware(async (ctx) => {
219
- const email = ctx.body.email;
219
+ // lowercase the email as done in https://github.com/better-auth/better-auth/blob/40a80b070bbabf2d6886e8a3ad1bc068c8d570cb/packages/better-auth/src/plugins/email-otp/routes.ts#L641
220
+ const email = ctx.body.email.toLowerCase();
220
221
  const identifier = `jazz-auth-sign-in-otp-${email}`;
221
222
 
222
223
  const data =
@@ -453,6 +453,51 @@ describe("Better-Auth server plugin", async () => {
453
453
  );
454
454
  });
455
455
 
456
+ it("should be case-insensitive for email", async () => {
457
+ let OTP: string = "";
458
+
459
+ sendVerificationOTPSpy.mockImplementationOnce(({ otp }) => {
460
+ OTP = otp;
461
+ });
462
+
463
+ await auth.api.sendVerificationOTP({
464
+ headers: {
465
+ "x-jazz-auth": JSON.stringify({
466
+ accountID: "123",
467
+ secretSeed: [1, 2, 3],
468
+ accountSecret: "123",
469
+ }),
470
+ },
471
+ body: {
472
+ email: "EMAIL@email.it",
473
+ type: "sign-in",
474
+ },
475
+ });
476
+
477
+ expect(accountCreationSpy).toHaveBeenCalledTimes(0);
478
+ expect(sendVerificationOTPSpy).toHaveBeenCalledTimes(1);
479
+ expect(verificationCreationSpy).toHaveBeenCalledTimes(2);
480
+ expect(verificationCreationSpy.mock.calls[0]?.[0]).toMatchObject(
481
+ expect.objectContaining({
482
+ identifier: "jazz-auth-sign-in-otp-email@email.it",
483
+ value: expect.stringContaining('"accountID":"123"'),
484
+ }),
485
+ );
486
+
487
+ await auth.api.signInEmailOTP({
488
+ body: {
489
+ email: "EMAIL@email.it",
490
+ otp: OTP,
491
+ },
492
+ });
493
+
494
+ expect(accountCreationSpy).toHaveBeenCalledTimes(1);
495
+ expect(accountCreationSpy).toHaveBeenCalledWith(
496
+ expect.objectContaining({ accountID: "123" }),
497
+ expect.any(Object),
498
+ );
499
+ });
500
+
456
501
  it("should not expect Jazz's credentials using Email OTP for sign-in an already registered user", async () => {
457
502
  // 1. User registration
458
503
  const userData = {