jazz-tools 0.18.4 → 0.18.6

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.
Files changed (80) hide show
  1. package/.turbo/turbo-build.log +54 -54
  2. package/CHANGELOG.md +28 -0
  3. package/dist/better-auth/auth/client.d.ts.map +1 -1
  4. package/dist/better-auth/auth/client.js +7 -1
  5. package/dist/better-auth/auth/client.js.map +1 -1
  6. package/dist/better-auth/auth/react.d.ts +0 -2142
  7. package/dist/better-auth/auth/react.d.ts.map +1 -1
  8. package/dist/better-auth/auth/react.js +2 -14
  9. package/dist/better-auth/auth/react.js.map +1 -1
  10. package/dist/better-auth/auth/server.d.ts +21 -1
  11. package/dist/better-auth/auth/server.d.ts.map +1 -1
  12. package/dist/better-auth/auth/server.js +83 -27
  13. package/dist/better-auth/auth/server.js.map +1 -1
  14. package/dist/better-auth/auth/tests/react.test.d.ts +2 -0
  15. package/dist/better-auth/auth/tests/react.test.d.ts.map +1 -0
  16. package/dist/browser/createBrowserContext.d.ts.map +1 -1
  17. package/dist/browser/index.js +7 -0
  18. package/dist/browser/index.js.map +1 -1
  19. package/dist/{chunk-LHQQZH7I.js → chunk-45VKEOXG.js} +123 -81
  20. package/dist/chunk-45VKEOXG.js.map +1 -0
  21. package/dist/index.js +1 -1
  22. package/dist/inspector/{custom-element-WCY6D3QJ.js → custom-element-IBHKHN27.js} +19 -69
  23. package/dist/inspector/custom-element-IBHKHN27.js.map +1 -0
  24. package/dist/inspector/index.d.ts +5 -1
  25. package/dist/inspector/index.d.ts.map +1 -1
  26. package/dist/inspector/index.js +18 -17
  27. package/dist/inspector/index.js.map +1 -1
  28. package/dist/inspector/register-custom-element.js +1 -1
  29. package/dist/inspector/viewer/new-app.d.ts +0 -3
  30. package/dist/inspector/viewer/new-app.d.ts.map +1 -1
  31. package/dist/react-core/index.js +3 -1
  32. package/dist/react-core/index.js.map +1 -1
  33. package/dist/testing.js +2 -2
  34. package/dist/testing.js.map +1 -1
  35. package/dist/tools/coValues/inbox.d.ts +5 -5
  36. package/dist/tools/coValues/inbox.d.ts.map +1 -1
  37. package/dist/tools/implementation/anonymousJazzAgent.d.ts +1 -1
  38. package/dist/tools/implementation/anonymousJazzAgent.d.ts.map +1 -1
  39. package/dist/tools/implementation/zodSchema/coExport.d.ts +2 -0
  40. package/dist/tools/implementation/zodSchema/coExport.d.ts.map +1 -1
  41. package/dist/tools/implementation/zodSchema/typeConverters/CoFieldSchemaInit.d.ts +4 -0
  42. package/dist/tools/implementation/zodSchema/typeConverters/CoFieldSchemaInit.d.ts.map +1 -1
  43. package/dist/tools/implementation/zodSchema/typeConverters/TypeOfZodSchema.d.ts.map +1 -1
  44. package/dist/tools/implementation/zodSchema/unionUtils.d.ts.map +1 -1
  45. package/dist/worker/index.d.ts +8 -2
  46. package/dist/worker/index.d.ts.map +1 -1
  47. package/dist/worker/index.js +7 -3
  48. package/dist/worker/index.js.map +1 -1
  49. package/package.json +5 -4
  50. package/src/better-auth/auth/client.ts +8 -2
  51. package/src/better-auth/auth/react.tsx +2 -51
  52. package/src/better-auth/auth/server.ts +132 -31
  53. package/src/better-auth/auth/tests/client.test.ts +92 -4
  54. package/src/better-auth/auth/tests/react.test.tsx +43 -0
  55. package/src/better-auth/auth/tests/server.test.ts +317 -51
  56. package/src/browser/createBrowserContext.ts +8 -0
  57. package/src/inspector/custom-element.tsx +1 -1
  58. package/src/inspector/index.tsx +44 -0
  59. package/src/inspector/viewer/new-app.tsx +0 -18
  60. package/src/tools/coValues/inbox.ts +190 -108
  61. package/src/tools/implementation/anonymousJazzAgent.ts +1 -1
  62. package/src/tools/implementation/zodSchema/coExport.ts +2 -0
  63. package/src/tools/implementation/zodSchema/typeConverters/CoFieldSchemaInit.ts +8 -1
  64. package/src/tools/implementation/zodSchema/typeConverters/TypeOfZodSchema.ts +0 -1
  65. package/src/tools/implementation/zodSchema/unionUtils.ts +0 -1
  66. package/src/tools/testing.ts +1 -1
  67. package/src/tools/tests/coFeed.test.ts +33 -22
  68. package/src/tools/tests/coList.test-d.ts +17 -0
  69. package/src/tools/tests/coList.test.ts +6 -4
  70. package/src/tools/tests/coMap.record.test-d.ts +18 -0
  71. package/src/tools/tests/coMap.test-d.ts +15 -0
  72. package/src/tools/tests/coMap.test.ts +13 -5
  73. package/src/tools/tests/exportImport.test.ts +3 -1
  74. package/src/tools/tests/groupsAndAccounts.test.ts +56 -44
  75. package/src/tools/tests/inbox.test.ts +293 -31
  76. package/src/worker/index.ts +15 -5
  77. package/tsup.config.ts +1 -1
  78. package/dist/chunk-LHQQZH7I.js.map +0 -1
  79. package/dist/inspector/custom-element-WCY6D3QJ.js.map +0 -1
  80. package/src/inspector/index.ts +0 -23
@@ -1,55 +1,55 @@
1
1
  import { betterAuth } from "better-auth";
2
2
  import { memoryAdapter } from "better-auth/adapters/memory";
3
- import { beforeEach, describe, expect, it, vi, type Mock } from "vitest";
3
+ import {
4
+ afterAll,
5
+ beforeAll,
6
+ beforeEach,
7
+ describe,
8
+ expect,
9
+ it,
10
+ vi,
11
+ type Mock,
12
+ } from "vitest";
13
+ import { OAuth2Server } from "oauth2-mock-server";
4
14
  import { jazzPlugin } from "../server.js";
15
+ import { emailOTP, genericOAuth } from "better-auth/plugins";
5
16
 
6
- describe("Better Auth - Signup and Login Tests", () => {
7
- let auth: ReturnType<typeof betterAuth>;
8
- let accountCreationSpy: Mock;
9
- let verificationCreationSpy: Mock;
10
-
11
- beforeEach(() => {
12
- accountCreationSpy = vi.fn();
13
- verificationCreationSpy = vi.fn();
14
-
15
- // Create auth instance with in-memory database
16
- auth = betterAuth({
17
- database: memoryAdapter({
18
- user: [],
19
- session: [],
20
- verification: [],
21
- account: [],
22
- }),
23
- plugins: [jazzPlugin()],
24
- emailAndPassword: {
25
- enabled: true,
26
- requireEmailVerification: false, // Disable for testing
27
- },
28
- socialProviders: {
29
- github: {
30
- clientId: "123",
31
- clientSecret: "123",
32
- },
33
- },
34
- databaseHooks: {
35
- user: {
36
- create: {
37
- after: accountCreationSpy,
38
- },
17
+ describe("Better-Auth server plugin", async () => {
18
+ describe("Email & Password", () => {
19
+ let auth: ReturnType<
20
+ typeof betterAuth<{
21
+ plugins: ReturnType<typeof jazzPlugin>[];
22
+ }>
23
+ >;
24
+
25
+ let accountCreationSpy: Mock;
26
+
27
+ beforeEach(() => {
28
+ accountCreationSpy = vi.fn();
29
+
30
+ // Create auth instance with in-memory database
31
+ auth = betterAuth({
32
+ database: memoryAdapter({
33
+ user: [],
34
+ session: [],
35
+ verification: [],
36
+ account: [],
37
+ }),
38
+ plugins: [jazzPlugin()],
39
+ emailAndPassword: {
40
+ enabled: true,
41
+ requireEmailVerification: false, // Disable for testing
39
42
  },
40
- verification: {
41
- create: {
42
- after: verificationCreationSpy,
43
+ databaseHooks: {
44
+ user: {
45
+ create: {
46
+ after: accountCreationSpy,
47
+ },
43
48
  },
44
49
  },
45
- },
46
- session: {
47
- expiresIn: 60 * 60 * 24 * 7, // 7 days
48
- },
50
+ });
49
51
  });
50
- });
51
52
 
52
- describe("User Registration (Signup)", () => {
53
53
  it("should successfully register a new user with email and password", async () => {
54
54
  const userData = {
55
55
  name: "test",
@@ -147,9 +147,7 @@ describe("Better Auth - Signup and Login Tests", () => {
147
147
  expect.any(Object),
148
148
  );
149
149
  });
150
- });
151
150
 
152
- describe("User login (Signin)", () => {
153
151
  it("should successfully login a new user with email and password", async () => {
154
152
  const userData = {
155
153
  name: "test",
@@ -194,7 +192,90 @@ describe("Better Auth - Signup and Login Tests", () => {
194
192
  });
195
193
  });
196
194
 
197
- describe("Social Login", () => {
195
+ describe("OAuth/Social plugin", async () => {
196
+ const providerId = "test";
197
+ const clientId = "test-client-id";
198
+ const clientSecret = "test-client-secret";
199
+ const server = new OAuth2Server();
200
+ await server.start();
201
+ const oauthPort = Number(server.issuer.url?.split(":")[2]!);
202
+
203
+ let auth: ReturnType<
204
+ typeof betterAuth<{
205
+ plugins: ReturnType<typeof jazzPlugin | typeof genericOAuth>[];
206
+ }>
207
+ >;
208
+ let accountCreationSpy: Mock;
209
+ let verificationCreationSpy: Mock;
210
+
211
+ beforeAll(async () => {
212
+ await server.issuer.keys.generate("RS256");
213
+
214
+ server.service.on("beforeUserinfo", (userInfoResponse) => {
215
+ userInfoResponse.body = {
216
+ email: "oauth2@test.com",
217
+ name: "OAuth2 Test",
218
+ sub: "oauth2",
219
+ picture: "https://test.com/picture.png",
220
+ email_verified: true,
221
+ };
222
+ userInfoResponse.statusCode = 200;
223
+ });
224
+ });
225
+
226
+ afterAll(async () => {
227
+ await server.stop();
228
+ });
229
+
230
+ beforeEach(() => {
231
+ accountCreationSpy = vi.fn();
232
+ verificationCreationSpy = vi.fn();
233
+
234
+ // Create auth instance with in-memory database
235
+ auth = betterAuth({
236
+ database: memoryAdapter({
237
+ user: [],
238
+ session: [],
239
+ verification: [],
240
+ account: [],
241
+ }),
242
+ baseURL: "http://localhost:3000",
243
+ plugins: [
244
+ jazzPlugin(),
245
+ genericOAuth({
246
+ config: [
247
+ {
248
+ providerId,
249
+ discoveryUrl: `http://localhost:${oauthPort}/.well-known/openid-configuration`,
250
+ authorizationUrl: `http://localhost:${oauthPort}/authorize`,
251
+ clientId: clientId,
252
+ clientSecret: clientSecret,
253
+ pkce: true,
254
+ },
255
+ ],
256
+ }),
257
+ ],
258
+ socialProviders: {
259
+ github: {
260
+ clientId: "123",
261
+ clientSecret: "123",
262
+ },
263
+ },
264
+ databaseHooks: {
265
+ user: {
266
+ create: {
267
+ after: accountCreationSpy,
268
+ },
269
+ },
270
+ verification: {
271
+ create: {
272
+ after: verificationCreationSpy,
273
+ },
274
+ },
275
+ },
276
+ });
277
+ });
278
+
198
279
  it("should store jazzAuth in verification table when using social provider", async () => {
199
280
  await auth.api.signInSocial({
200
281
  body: {
@@ -210,17 +291,202 @@ describe("Better Auth - Signup and Login Tests", () => {
210
291
  },
211
292
  });
212
293
 
213
- expect(verificationCreationSpy).toHaveBeenCalledTimes(1);
214
- expect(verificationCreationSpy).toHaveBeenCalledWith(
294
+ expect(verificationCreationSpy).toHaveBeenCalledTimes(2);
295
+ expect(verificationCreationSpy.mock.calls[1]?.[0]).toMatchObject({
296
+ identifier: expect.stringMatching("-jazz-auth"),
297
+ value: expect.stringContaining('"accountID":"123"'),
298
+ });
299
+ });
300
+
301
+ it("should create a new account with jazz auth when using social provider", async () => {
302
+ const response = await auth.api.signInSocial({
303
+ body: {
304
+ provider: providerId,
305
+ callbackURL: "http://localhost:3000/api/auth/sign-in/social/callback",
306
+ newUserCallbackURL:
307
+ "http://localhost:3000/api/auth/sign-in/social/callback",
308
+ },
309
+ headers: {
310
+ "x-jazz-auth": JSON.stringify({
311
+ accountID: "123",
312
+ secretSeed: [1, 2, 3],
313
+ accountSecret: "123",
314
+ }),
315
+ },
316
+ });
317
+
318
+ const oauthres = await fetch(response.url as string, {
319
+ redirect: "manual",
320
+ });
321
+
322
+ const resURL = new URL(oauthres.headers.get("Location") as string);
323
+
324
+ const callbackRes = await auth.handler(new Request(resURL));
325
+
326
+ expect(callbackRes.headers.getSetCookie()[0]).toMatch(
327
+ "better-auth.session_token=",
328
+ );
329
+
330
+ expect(accountCreationSpy).toHaveBeenCalledTimes(1);
331
+ expect(accountCreationSpy).toHaveBeenCalledWith(
332
+ expect.objectContaining({ accountID: "123" }),
333
+ expect.any(Object),
334
+ );
335
+ });
336
+ });
337
+
338
+ describe("Email OTP plugin", () => {
339
+ let auth: ReturnType<
340
+ typeof betterAuth<{
341
+ plugins: ReturnType<typeof jazzPlugin | typeof emailOTP>[];
342
+ }>
343
+ >;
344
+
345
+ let accountCreationSpy: Mock;
346
+ let verificationCreationSpy: Mock;
347
+ let sendVerificationOTPSpy: Mock;
348
+
349
+ beforeEach(() => {
350
+ accountCreationSpy = vi.fn();
351
+ verificationCreationSpy = vi.fn();
352
+ sendVerificationOTPSpy = vi.fn();
353
+ // Create auth instance with in-memory database
354
+ auth = betterAuth({
355
+ database: memoryAdapter({
356
+ user: [],
357
+ session: [],
358
+ verification: [],
359
+ account: [],
360
+ }),
361
+ plugins: [
362
+ jazzPlugin(),
363
+ emailOTP({
364
+ allowedAttempts: 5,
365
+ otpLength: 6,
366
+ expiresIn: 600,
367
+ sendVerificationOTP: sendVerificationOTPSpy,
368
+ }),
369
+ ],
370
+ emailAndPassword: {
371
+ enabled: true,
372
+ requireEmailVerification: false, // Disable for testing
373
+ },
374
+ databaseHooks: {
375
+ user: {
376
+ create: {
377
+ after: accountCreationSpy,
378
+ },
379
+ },
380
+ verification: {
381
+ create: {
382
+ after: verificationCreationSpy,
383
+ },
384
+ },
385
+ },
386
+ });
387
+ });
388
+
389
+ it("should create a new account with jazz auth when using email OTP", async () => {
390
+ let OTP: string = "";
391
+
392
+ sendVerificationOTPSpy.mockImplementationOnce(({ otp }) => {
393
+ OTP = otp;
394
+ });
395
+
396
+ await auth.api.sendVerificationOTP({
397
+ headers: {
398
+ "x-jazz-auth": JSON.stringify({
399
+ accountID: "123",
400
+ secretSeed: [1, 2, 3],
401
+ accountSecret: "123",
402
+ }),
403
+ },
404
+ body: {
405
+ email: "email@email.it",
406
+ type: "sign-in",
407
+ },
408
+ });
409
+
410
+ expect(accountCreationSpy).toHaveBeenCalledTimes(0);
411
+ expect(sendVerificationOTPSpy).toHaveBeenCalledTimes(1);
412
+ expect(verificationCreationSpy).toHaveBeenCalledTimes(2);
413
+ expect(verificationCreationSpy.mock.calls[0]?.[0]).toMatchObject(
215
414
  expect.objectContaining({
415
+ identifier: "sign-in-otp-email@email.it-jazz-auth",
216
416
  value: expect.stringContaining('"accountID":"123"'),
217
417
  }),
418
+ );
419
+
420
+ await auth.api.signInEmailOTP({
421
+ body: {
422
+ email: "email@email.it",
423
+ otp: OTP,
424
+ },
425
+ });
426
+
427
+ expect(accountCreationSpy).toHaveBeenCalledTimes(1);
428
+ expect(accountCreationSpy).toHaveBeenCalledWith(
429
+ expect.objectContaining({ accountID: "123" }),
218
430
  expect.any(Object),
219
431
  );
220
432
  });
221
433
 
222
- it.todo(
223
- "should create a new account with jazz auth when using social provider",
224
- );
434
+ it("should not expect Jazz's credentials using Email OTP for sign-in an already registered user", async () => {
435
+ // 1. User registration
436
+ const userData = {
437
+ name: "test",
438
+ email: "test@example.com",
439
+ password: "securePassword123",
440
+ };
441
+
442
+ const jazzAuth = {
443
+ accountID: "123",
444
+ secretSeed: [1, 2, 3],
445
+ accountSecret: "123",
446
+ provider: "better-auth",
447
+ };
448
+
449
+ await auth.api.signUpEmail({
450
+ body: userData,
451
+ headers: {
452
+ "x-jazz-auth": JSON.stringify(jazzAuth),
453
+ },
454
+ });
455
+
456
+ expect(accountCreationSpy).toHaveBeenCalledTimes(1);
457
+
458
+ // 2. Try to sign-in with OTP
459
+ let OTP: string = "";
460
+
461
+ sendVerificationOTPSpy.mockImplementationOnce(({ otp }) => {
462
+ OTP = otp;
463
+ });
464
+
465
+ await auth.api.sendVerificationOTP({
466
+ body: {
467
+ email: "test@example.com",
468
+ type: "sign-in",
469
+ },
470
+ });
471
+
472
+ expect(sendVerificationOTPSpy).toHaveBeenCalledTimes(1);
473
+ expect(verificationCreationSpy).toHaveBeenCalledTimes(1);
474
+
475
+ const result = await auth.api.signInEmailOTP({
476
+ body: {
477
+ email: "test@example.com",
478
+ otp: OTP,
479
+ },
480
+ });
481
+
482
+ expect(accountCreationSpy).toHaveBeenCalledTimes(1); // still only 1
483
+ expect(result).toMatchObject({
484
+ user: {
485
+ id: expect.any(String),
486
+ email: "test@example.com",
487
+ name: "test",
488
+ },
489
+ });
490
+ });
225
491
  });
226
492
  });
@@ -214,6 +214,14 @@ export function provideBrowserLockSession(
214
214
  accountID: ID<Account> | AgentID,
215
215
  crypto: CryptoProvider,
216
216
  ) {
217
+ if (typeof navigator === "undefined" || !navigator.locks?.request) {
218
+ // Fallback to random session ID for each tab session
219
+ return Promise.resolve({
220
+ sessionID: crypto.newRandomSessionID(accountID as RawAccountID | AgentID),
221
+ sessionDone: () => {},
222
+ });
223
+ }
224
+
217
225
  let sessionDone!: () => void;
218
226
  const donePromise = new Promise<void>((resolve) => {
219
227
  sessionDone = resolve;
@@ -1,6 +1,6 @@
1
1
  import { Account } from "jazz-tools";
2
2
  import { createRoot } from "react-dom/client";
3
- import { JazzInspectorInternal } from "./index.js";
3
+ import { JazzInspectorInternal } from "./viewer/new-app.js";
4
4
 
5
5
  export class JazzInspectorElement extends HTMLElement {
6
6
  private root: ReturnType<typeof createRoot> | null = null;
@@ -0,0 +1,44 @@
1
+ import React from "react";
2
+
3
+ export { JazzInspectorInternal } from "./viewer/new-app.js";
4
+ export { PageStack } from "./viewer/page-stack.js";
5
+ export { Breadcrumbs } from "./viewer/breadcrumbs.js";
6
+ export { AccountOrGroupText } from "./viewer/account-or-group-text.js";
7
+
8
+ export { Button } from "./ui/button.js";
9
+ export { Input } from "./ui/input.js";
10
+ export { Select } from "./ui/select.js";
11
+ export { Icon } from "./ui/icon.js";
12
+ export { GlobalStyles } from "./ui/global-styles.js";
13
+
14
+ export {
15
+ resolveCoValue,
16
+ useResolvedCoValue,
17
+ } from "./viewer/use-resolve-covalue.js";
18
+
19
+ export type { PageInfo } from "./viewer/types.js";
20
+
21
+ import { setup } from "goober";
22
+ import { useJazzContext } from "jazz-tools/react-core";
23
+ import { Account } from "jazz-tools";
24
+
25
+ import { JazzInspectorInternal } from "./viewer/new-app.js";
26
+ import { Position } from "./viewer/inpsector-button.js";
27
+
28
+ export function JazzInspector({ position = "right" }: { position?: Position }) {
29
+ const context = useJazzContext<Account>();
30
+ const localNode = context.node;
31
+ const me = "me" in context ? context.me : undefined;
32
+
33
+ if (process.env.NODE_ENV !== "development") return null;
34
+
35
+ return (
36
+ <JazzInspectorInternal
37
+ position={position}
38
+ localNode={localNode}
39
+ accountId={me?.$jazz.raw.id}
40
+ />
41
+ );
42
+ }
43
+
44
+ setup(React.createElement);
@@ -1,6 +1,5 @@
1
1
  import { CoID, LocalNode, RawAccount, RawCoValue } from "cojson";
2
2
  import { styled } from "goober";
3
- import { useJazzContext } from "jazz-tools/react-core";
4
3
  import React, { useState } from "react";
5
4
  import { Button } from "../ui/button.js";
6
5
  import { Input } from "../ui/input.js";
@@ -8,7 +7,6 @@ import { Breadcrumbs } from "./breadcrumbs.js";
8
7
  import { PageStack } from "./page-stack.js";
9
8
  import { usePagePath } from "./use-page-path.js";
10
9
 
11
- import { Account } from "jazz-tools";
12
10
  import { GlobalStyles } from "../ui/global-styles.js";
13
11
  import { Heading } from "../ui/heading.js";
14
12
  import { InspectorButton, type Position } from "./inpsector-button.js";
@@ -61,22 +59,6 @@ const OrText = styled("p")`
61
59
  text-align: center;
62
60
  `;
63
61
 
64
- export function JazzInspector({ position = "right" }: { position?: Position }) {
65
- const context = useJazzContext<Account>();
66
- const localNode = context.node;
67
- const me = "me" in context ? context.me : undefined;
68
-
69
- if (process.env.NODE_ENV !== "development") return null;
70
-
71
- return (
72
- <JazzInspectorInternal
73
- position={position}
74
- localNode={localNode}
75
- accountId={me?.$jazz.raw.id}
76
- />
77
- );
78
- }
79
-
80
62
  export function JazzInspectorInternal({
81
63
  position = "right",
82
64
  localNode,