jazz-tools 0.19.7 → 0.19.10

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 (167) hide show
  1. package/.turbo/turbo-build.log +65 -59
  2. package/CHANGELOG.md +34 -3
  3. package/dist/{chunk-CUS6O5NE.js → chunk-FFEEPZEG.js} +454 -122
  4. package/dist/chunk-FFEEPZEG.js.map +1 -0
  5. package/dist/expo/polyfills.js +22 -0
  6. package/dist/expo/polyfills.js.map +1 -0
  7. package/dist/index.js +26 -6
  8. package/dist/index.js.map +1 -1
  9. package/dist/react/hooks.d.ts +1 -1
  10. package/dist/react/hooks.d.ts.map +1 -1
  11. package/dist/react/index.d.ts +1 -1
  12. package/dist/react/index.d.ts.map +1 -1
  13. package/dist/react/index.js +5 -1
  14. package/dist/react/index.js.map +1 -1
  15. package/dist/react-core/hooks.d.ts +59 -0
  16. package/dist/react-core/hooks.d.ts.map +1 -1
  17. package/dist/react-core/index.js +133 -34
  18. package/dist/react-core/index.js.map +1 -1
  19. package/dist/react-core/tests/testUtils.d.ts +1 -0
  20. package/dist/react-core/tests/testUtils.d.ts.map +1 -1
  21. package/dist/react-core/tests/useSuspenseAccount.test.d.ts +2 -0
  22. package/dist/react-core/tests/useSuspenseAccount.test.d.ts.map +1 -0
  23. package/dist/react-core/tests/useSuspenseCoState.test.d.ts +2 -0
  24. package/dist/react-core/tests/useSuspenseCoState.test.d.ts.map +1 -0
  25. package/dist/react-core/use.d.ts +3 -0
  26. package/dist/react-core/use.d.ts.map +1 -0
  27. package/dist/react-native/index.d.ts +1 -1
  28. package/dist/react-native/index.d.ts.map +1 -1
  29. package/dist/react-native/index.js +717 -9
  30. package/dist/react-native/index.js.map +1 -1
  31. package/dist/react-native/polyfills.js +22 -0
  32. package/dist/react-native/polyfills.js.map +1 -0
  33. package/dist/react-native-core/crypto/RNCrypto.d.ts +2 -0
  34. package/dist/react-native-core/crypto/RNCrypto.d.ts.map +1 -0
  35. package/dist/react-native-core/crypto/RNCrypto.js +3 -0
  36. package/dist/react-native-core/crypto/RNCrypto.js.map +1 -0
  37. package/dist/react-native-core/hooks.d.ts +1 -1
  38. package/dist/react-native-core/hooks.d.ts.map +1 -1
  39. package/dist/react-native-core/index.d.ts.map +1 -1
  40. package/dist/react-native-core/index.js +5 -1
  41. package/dist/react-native-core/index.js.map +1 -1
  42. package/dist/react-native-core/platform.d.ts +2 -1
  43. package/dist/react-native-core/platform.d.ts.map +1 -1
  44. package/dist/testing.js +1 -1
  45. package/dist/testing.js.map +1 -1
  46. package/dist/tools/coValues/account.d.ts +3 -3
  47. package/dist/tools/coValues/account.d.ts.map +1 -1
  48. package/dist/tools/coValues/coFeed.d.ts +3 -3
  49. package/dist/tools/coValues/coFeed.d.ts.map +1 -1
  50. package/dist/tools/coValues/coList.d.ts +4 -4
  51. package/dist/tools/coValues/coList.d.ts.map +1 -1
  52. package/dist/tools/coValues/coMap.d.ts +7 -7
  53. package/dist/tools/coValues/coMap.d.ts.map +1 -1
  54. package/dist/tools/coValues/coPlainText.d.ts +2 -2
  55. package/dist/tools/coValues/coPlainText.d.ts.map +1 -1
  56. package/dist/tools/coValues/coVector.d.ts +2 -2
  57. package/dist/tools/coValues/coVector.d.ts.map +1 -1
  58. package/dist/tools/coValues/deepLoading.d.ts +24 -0
  59. package/dist/tools/coValues/deepLoading.d.ts.map +1 -1
  60. package/dist/tools/coValues/group.d.ts +2 -2
  61. package/dist/tools/coValues/group.d.ts.map +1 -1
  62. package/dist/tools/coValues/interfaces.d.ts +7 -7
  63. package/dist/tools/coValues/interfaces.d.ts.map +1 -1
  64. package/dist/tools/coValues/schemaUnion.d.ts +2 -2
  65. package/dist/tools/coValues/schemaUnion.d.ts.map +1 -1
  66. package/dist/tools/config.d.ts +3 -0
  67. package/dist/tools/config.d.ts.map +1 -0
  68. package/dist/tools/exports.d.ts +2 -0
  69. package/dist/tools/exports.d.ts.map +1 -1
  70. package/dist/tools/implementation/ContextManager.d.ts +3 -0
  71. package/dist/tools/implementation/ContextManager.d.ts.map +1 -1
  72. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts +2 -2
  73. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -1
  74. package/dist/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.d.ts +2 -2
  75. package/dist/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.d.ts.map +1 -1
  76. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts +2 -2
  77. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts.map +1 -1
  78. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +4 -4
  79. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -1
  80. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts +4 -4
  81. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts.map +1 -1
  82. package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts +4 -4
  83. package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts.map +1 -1
  84. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts +2 -2
  85. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts.map +1 -1
  86. package/dist/tools/implementation/zodSchema/schemaTypes/GroupSchema.d.ts +2 -2
  87. package/dist/tools/implementation/zodSchema/schemaTypes/GroupSchema.d.ts.map +1 -1
  88. package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts +2 -2
  89. package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts.map +1 -1
  90. package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts +2 -2
  91. package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts.map +1 -1
  92. package/dist/tools/implementation/zodSchema/zodCo.d.ts.map +1 -1
  93. package/dist/tools/subscribe/CoValueCoreSubscription.d.ts +8 -22
  94. package/dist/tools/subscribe/CoValueCoreSubscription.d.ts.map +1 -1
  95. package/dist/tools/subscribe/JazzError.d.ts.map +1 -1
  96. package/dist/tools/subscribe/SubscriptionCache.d.ts +51 -0
  97. package/dist/tools/subscribe/SubscriptionCache.d.ts.map +1 -0
  98. package/dist/tools/subscribe/SubscriptionScope.d.ts +27 -2
  99. package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
  100. package/dist/tools/subscribe/errorReporting.d.ts +31 -0
  101. package/dist/tools/subscribe/errorReporting.d.ts.map +1 -0
  102. package/dist/tools/subscribe/utils.d.ts +9 -1
  103. package/dist/tools/subscribe/utils.d.ts.map +1 -1
  104. package/dist/tools/testing.d.ts +2 -2
  105. package/dist/tools/testing.d.ts.map +1 -1
  106. package/dist/tools/tests/SubscriptionCache.test.d.ts +2 -0
  107. package/dist/tools/tests/SubscriptionCache.test.d.ts.map +1 -0
  108. package/dist/tools/tests/errorReporting.test.d.ts +2 -0
  109. package/dist/tools/tests/errorReporting.test.d.ts.map +1 -0
  110. package/package.json +22 -7
  111. package/src/react/hooks.tsx +2 -0
  112. package/src/react/index.ts +1 -14
  113. package/src/react-core/hooks.ts +181 -16
  114. package/src/react-core/tests/createCoValueSubscriptionContext.test.tsx +18 -8
  115. package/src/react-core/tests/testUtils.tsx +67 -5
  116. package/src/react-core/tests/useCoState.test.ts +3 -7
  117. package/src/react-core/tests/useSubscriptionSelector.test.ts +3 -7
  118. package/src/react-core/tests/useSuspenseAccount.test.tsx +343 -0
  119. package/src/react-core/tests/useSuspenseCoState.test.tsx +1182 -0
  120. package/src/react-core/use.ts +46 -0
  121. package/src/react-native/index.ts +1 -1
  122. package/src/react-native-core/crypto/RNCrypto.ts +1 -0
  123. package/src/react-native-core/hooks.tsx +2 -0
  124. package/src/react-native-core/index.ts +2 -0
  125. package/src/react-native-core/platform.ts +2 -1
  126. package/src/react-native-core/polyfills/index.js +28 -0
  127. package/src/tools/coValues/account.ts +3 -4
  128. package/src/tools/coValues/coFeed.ts +3 -2
  129. package/src/tools/coValues/coList.ts +4 -4
  130. package/src/tools/coValues/coMap.ts +4 -4
  131. package/src/tools/coValues/coPlainText.ts +2 -2
  132. package/src/tools/coValues/coVector.ts +2 -2
  133. package/src/tools/coValues/deepLoading.ts +31 -0
  134. package/src/tools/coValues/group.ts +2 -2
  135. package/src/tools/coValues/interfaces.ts +21 -26
  136. package/src/tools/coValues/schemaUnion.ts +2 -2
  137. package/src/tools/config.ts +9 -0
  138. package/src/tools/exports.ts +4 -0
  139. package/src/tools/implementation/ContextManager.ts +13 -0
  140. package/src/tools/implementation/zodSchema/schemaTypes/AccountSchema.ts +2 -2
  141. package/src/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.ts +2 -2
  142. package/src/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.ts +2 -2
  143. package/src/tools/implementation/zodSchema/schemaTypes/CoListSchema.ts +4 -4
  144. package/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts +4 -4
  145. package/src/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.ts +4 -10
  146. package/src/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.ts +2 -2
  147. package/src/tools/implementation/zodSchema/schemaTypes/GroupSchema.ts +2 -2
  148. package/src/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.ts +2 -2
  149. package/src/tools/implementation/zodSchema/schemaTypes/RichTextSchema.ts +2 -2
  150. package/src/tools/subscribe/CoValueCoreSubscription.ts +71 -100
  151. package/src/tools/subscribe/JazzError.ts +9 -6
  152. package/src/tools/subscribe/SubscriptionCache.ts +272 -0
  153. package/src/tools/subscribe/SubscriptionScope.ts +218 -29
  154. package/src/tools/subscribe/errorReporting.ts +67 -0
  155. package/src/tools/subscribe/utils.ts +77 -0
  156. package/src/tools/testing.ts +0 -3
  157. package/src/tools/tests/CoValueCoreSubscription.test.ts +46 -12
  158. package/src/tools/tests/ContextManager.test.ts +85 -0
  159. package/src/tools/tests/SubscriptionCache.test.ts +237 -0
  160. package/src/tools/tests/coMap.test.ts +5 -7
  161. package/src/tools/tests/deepLoading.test.ts +47 -47
  162. package/src/tools/tests/errorReporting.test.ts +103 -0
  163. package/src/tools/tests/load.test.ts +21 -1
  164. package/src/tools/tests/request.test.ts +2 -1
  165. package/src/tools/tests/subscribe.test.ts +44 -0
  166. package/tsup.config.ts +17 -0
  167. package/dist/chunk-CUS6O5NE.js.map +0 -1
@@ -1,6 +1,14 @@
1
1
  import { cojsonInternals } from "cojson";
2
2
  import { WasmCrypto } from "cojson/crypto/WasmCrypto";
3
- import { assert, describe, expect, expectTypeOf, test, vi } from "vitest";
3
+ import {
4
+ assert,
5
+ beforeEach,
6
+ describe,
7
+ expect,
8
+ expectTypeOf,
9
+ test,
10
+ vi,
11
+ } from "vitest";
4
12
  import {
5
13
  Group,
6
14
  ID,
@@ -11,17 +19,17 @@ import {
11
19
  } from "../index.js";
12
20
  import {
13
21
  Account,
14
- CoList,
15
22
  Loaded,
16
23
  MaybeLoaded,
17
- NotLoaded,
24
+ Settled,
18
25
  co,
19
26
  randomSessionProvider,
20
27
  CoValueLoadingState,
21
- NotLoadedCoValueState,
28
+ CoValueErrorState,
22
29
  } from "../internal.js";
23
30
  import { createJazzTestAccount, linkAccounts } from "../testing.js";
24
31
  import { assertLoaded, waitFor } from "./utils.js";
32
+ import { setCustomErrorReporter } from "../config.js";
25
33
 
26
34
  const Crypto = await WasmCrypto.create();
27
35
  const { connectedPeers } = cojsonInternals;
@@ -43,6 +51,15 @@ const TestMap = co.map({
43
51
  optionalRef: co.optional(InnermostMap),
44
52
  });
45
53
 
54
+ let lastError: Error | undefined;
55
+
56
+ beforeEach(() => {
57
+ lastError = undefined;
58
+ setCustomErrorReporter((error) => {
59
+ lastError = error;
60
+ });
61
+ });
62
+
46
63
  describe("Deep loading with depth arg", async () => {
47
64
  const me = await Account.create({
48
65
  creationProps: { name: "Hermes Puggington" },
@@ -345,7 +362,7 @@ test("Deep loading a record-like coMap", async () => {
345
362
  },
346
363
  });
347
364
  expectTypeOf(recordLoaded).branded.toEqualTypeOf<
348
- MaybeLoaded<
365
+ Settled<
349
366
  Loaded<typeof RecordLike> & {
350
367
  readonly [key: string]: Loaded<typeof TestMap> & {
351
368
  readonly list: Loaded<typeof TestList> &
@@ -494,17 +511,14 @@ describe("Deep loading with unauthorized account", async () => {
494
511
  CoValueLoadingState.UNAUTHORIZED,
495
512
  );
496
513
 
497
- expect(errorSpy).toHaveBeenCalledWith(
498
- `The current user (${alice.$jazz.id}) is not authorized to access this value from ${map.$jazz.id}`,
514
+ expect(lastError?.message).toBe(
515
+ `Jazz Authorization Error: The current user (${alice.$jazz.id}) is not authorized to access ${map.$jazz.id}`,
499
516
  );
500
-
501
- errorSpy.mockReset();
502
517
  });
503
518
 
504
519
  test("unaccessible list", async () => {
505
- const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
506
-
507
- const map = TestMap.create({ list: TestList.create([], onlyBob) }, group);
520
+ const innerList = TestList.create([], onlyBob);
521
+ const map = TestMap.create({ list: innerList }, group);
508
522
 
509
523
  const mapOnAlice = await TestMap.load(map.$jazz.id, { loadAs: alice });
510
524
  expect(mapOnAlice).toBeTruthy();
@@ -518,16 +532,12 @@ describe("Deep loading with unauthorized account", async () => {
518
532
  CoValueLoadingState.UNAUTHORIZED,
519
533
  );
520
534
 
521
- expect(errorSpy).toHaveBeenCalledWith(
522
- `The current user (${alice.$jazz.id}) is not authorized to access this value from ${map.$jazz.id} on path list`,
535
+ expect(lastError?.message).toBe(
536
+ `Jazz Authorization Error: The current user (${alice.$jazz.id}) is not authorized to access ${innerList.$jazz.id}. Subscription starts from ${map.$jazz.id} and the value is on path list`,
523
537
  );
524
-
525
- errorSpy.mockReset();
526
538
  });
527
539
 
528
540
  test("unaccessible list element", async () => {
529
- const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
530
-
531
541
  const map = TestMap.create(
532
542
  {
533
543
  list: TestList.create(
@@ -554,16 +564,12 @@ describe("Deep loading with unauthorized account", async () => {
554
564
  CoValueLoadingState.UNAUTHORIZED,
555
565
  );
556
566
 
557
- expect(errorSpy).toHaveBeenCalledWith(
558
- `The current user (${alice.$jazz.id}) is not authorized to access this value from ${map.$jazz.id} on path list.0`,
567
+ expect(lastError?.message).toBe(
568
+ `Jazz Authorization Error: The current user (${alice.$jazz.id}) is not authorized to access ${map.list[0]!.$jazz.id}. Subscription starts from ${map.$jazz.id} and the value is on path list.0`,
559
569
  );
560
-
561
- errorSpy.mockReset();
562
570
  });
563
571
 
564
572
  test("unaccessible optional element", async () => {
565
- const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
566
-
567
573
  const map = TestMap.create(
568
574
  {
569
575
  list: TestList.create([], group),
@@ -579,11 +585,9 @@ describe("Deep loading with unauthorized account", async () => {
579
585
  expect(mapOnAlice.$jazz.loadingState).toBe(
580
586
  CoValueLoadingState.UNAUTHORIZED,
581
587
  );
582
- expect(errorSpy).toHaveBeenCalledWith(
583
- `The current user (${alice.$jazz.id}) is not authorized to access this value from ${map.$jazz.id} on path optionalRef`,
588
+ expect(lastError?.message).toBe(
589
+ `Jazz Authorization Error: The current user (${alice.$jazz.id}) is not authorized to access ${map.optionalRef!.$jazz.id}. Subscription starts from ${map.$jazz.id} and the value is on path optionalRef`,
584
590
  );
585
-
586
- errorSpy.mockReset();
587
591
  });
588
592
 
589
593
  test("unaccessible optional element via autoload", async () => {
@@ -611,17 +615,20 @@ describe("Deep loading with unauthorized account", async () => {
611
615
  });
612
616
 
613
617
  expect(result?.$jazz.loadingState).toBe(CoValueLoadingState.UNAUTHORIZED);
618
+ expect(lastError?.message).toBe(
619
+ `Jazz Authorization Error: The current user (${alice.$jazz.id}) is not authorized to access ${map.optionalRef!.$jazz.id}`,
620
+ );
614
621
  });
615
622
 
616
623
  test("unaccessible stream", async () => {
617
- const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
624
+ const stream = TestFeed.create([], onlyBob);
618
625
  const map = TestMap.create(
619
626
  {
620
627
  list: TestList.create(
621
628
  [
622
629
  InnerMap.create(
623
630
  {
624
- stream: TestFeed.create([], onlyBob),
631
+ stream,
625
632
  },
626
633
  group,
627
634
  ),
@@ -641,16 +648,12 @@ describe("Deep loading with unauthorized account", async () => {
641
648
  CoValueLoadingState.UNAUTHORIZED,
642
649
  );
643
650
 
644
- expect(errorSpy).toHaveBeenCalledWith(
645
- `The current user (${alice.$jazz.id}) is not authorized to access this value from ${map.$jazz.id} on path list.0.stream`,
651
+ expect(lastError?.message).toBe(
652
+ `Jazz Authorization Error: The current user (${alice.$jazz.id}) is not authorized to access ${stream.$jazz.id}. Subscription starts from ${map.$jazz.id} and the value is on path list.0.stream`,
646
653
  );
647
-
648
- errorSpy.mockReset();
649
654
  });
650
655
 
651
656
  test("unaccessible stream element", async () => {
652
- const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
653
-
654
657
  const value = InnermostMap.create({ value: "hello" }, onlyBob);
655
658
 
656
659
  const map = TestMap.create(
@@ -679,11 +682,9 @@ describe("Deep loading with unauthorized account", async () => {
679
682
  CoValueLoadingState.UNAUTHORIZED,
680
683
  );
681
684
 
682
- expect(errorSpy).toHaveBeenCalledWith(
683
- `The current user (${alice.$jazz.id}) is not authorized to access this value from ${map.$jazz.id} on path list.0.stream.${value.$jazz.id}`,
685
+ expect(lastError?.message).toBe(
686
+ `Jazz Authorization Error: The current user (${alice.$jazz.id}) is not authorized to access ${value.$jazz.id}. Subscription starts from ${map.$jazz.id} and the value is on path list.0.stream.${value.$jazz.id}`,
684
687
  );
685
-
686
- errorSpy.mockReset();
687
688
  });
688
689
 
689
690
  test("setting undefined via proxy", async () => {
@@ -1229,7 +1230,7 @@ describe("$isLoaded", async () => {
1229
1230
 
1230
1231
  const map = TestMap.create({ list: [] }, { owner: me });
1231
1232
 
1232
- test("$isLoaded narrows MaybeLoaded to loaded CoValue", async () => {
1233
+ test("$isLoaded narrows a maybe-loaded CoValue to a loaded CoValue", async () => {
1233
1234
  const maybeLoadedMap = await TestMap.load(map.$jazz.id, {
1234
1235
  loadAs: me,
1235
1236
  });
@@ -1244,19 +1245,18 @@ describe("$isLoaded", async () => {
1244
1245
  } else {
1245
1246
  expectTypeOf(
1246
1247
  maybeLoadedMap.$jazz.loadingState,
1247
- ).toEqualTypeOf<NotLoadedCoValueState>();
1248
+ ).toEqualTypeOf<CoValueErrorState>();
1248
1249
  }
1249
1250
  });
1250
1251
 
1251
- test("$isLoaded narrows MaybeLoaded to not loaded CoValue", async () => {
1252
+ test("$isLoaded narrows a maybe-loaded CoValue to a not loaded CoValue", async () => {
1252
1253
  const otherAccount = await Account.create({
1253
1254
  creationProps: { name: "Other Account" },
1254
1255
  crypto: Crypto,
1255
1256
  });
1256
- const unloadedMap: MaybeLoaded<Loaded<typeof TestMap>> = await TestMap.load(
1257
- map.$jazz.id,
1258
- { loadAs: otherAccount },
1259
- );
1257
+ const unloadedMap = await TestMap.load(map.$jazz.id, {
1258
+ loadAs: otherAccount,
1259
+ });
1260
1260
 
1261
1261
  expect(unloadedMap.$isLoaded).toBe(false);
1262
1262
  if (!unloadedMap.$isLoaded) {
@@ -0,0 +1,103 @@
1
+ import { beforeEach, describe, expect, test, vi } from "vitest";
2
+ import { Group, z } from "../index.js";
3
+ import { setCustomErrorReporter } from "../config.js";
4
+ import { CoValueLoadingState } from "../internal.js";
5
+ import { createJazzTestAccount, linkAccounts } from "../testing.js";
6
+ import { co } from "../exports.js";
7
+
8
+ const TestMap = co.map({
9
+ value: z.string(),
10
+ });
11
+
12
+ describe("Custom error reporter", () => {
13
+ beforeEach(() => {
14
+ // Clean up error reporter before each test
15
+ setCustomErrorReporter(undefined);
16
+ });
17
+
18
+ test("with custom error reporter enabled, console.error is not called", async () => {
19
+ const bob = await createJazzTestAccount({
20
+ creationProps: { name: "Bob" },
21
+ });
22
+
23
+ const alice = await createJazzTestAccount({
24
+ creationProps: { name: "Alice" },
25
+ });
26
+
27
+ linkAccounts(bob, alice);
28
+
29
+ await alice.$jazz.waitForAllCoValuesSync();
30
+
31
+ const onlyBob = bob;
32
+ const group = Group.create(bob);
33
+
34
+ group.addMember(alice, "reader");
35
+
36
+ let capturedError: Error | undefined;
37
+ let capturedProps: { jazzError: any } | undefined;
38
+
39
+ setCustomErrorReporter((error, props) => {
40
+ capturedError = error;
41
+ capturedProps = props;
42
+ });
43
+
44
+ const consoleErrorSpy = vi
45
+ .spyOn(console, "error")
46
+ .mockImplementation(() => {});
47
+
48
+ const map = TestMap.create({ value: "hello" }, onlyBob);
49
+
50
+ const mapOnAlice = await TestMap.load(map.$jazz.id, { loadAs: alice });
51
+
52
+ // Access the value to trigger error logging
53
+ expect(mapOnAlice.$jazz.loadingState).toBe(
54
+ CoValueLoadingState.UNAUTHORIZED,
55
+ );
56
+
57
+ expect(consoleErrorSpy).not.toHaveBeenCalled();
58
+ expect(capturedError).toBeDefined();
59
+ expect(capturedProps).toBeDefined();
60
+ expect(capturedProps?.jazzError).toBeDefined();
61
+
62
+ consoleErrorSpy.mockRestore();
63
+ });
64
+
65
+ test("without custom error reporter, console.error is called", async () => {
66
+ const bob = await createJazzTestAccount({
67
+ creationProps: { name: "Bob" },
68
+ });
69
+
70
+ const alice = await createJazzTestAccount({
71
+ creationProps: { name: "Alice" },
72
+ });
73
+
74
+ linkAccounts(bob, alice);
75
+
76
+ await alice.$jazz.waitForAllCoValuesSync();
77
+
78
+ const onlyBob = bob;
79
+ const group = Group.create(bob);
80
+
81
+ group.addMember(alice, "reader");
82
+
83
+ // Ensure no custom error reporter is set
84
+ setCustomErrorReporter(undefined);
85
+
86
+ const consoleErrorSpy = vi
87
+ .spyOn(console, "error")
88
+ .mockImplementation(() => {});
89
+
90
+ const map = TestMap.create({ value: "hello" }, onlyBob);
91
+
92
+ const mapOnAlice = await TestMap.load(map.$jazz.id, { loadAs: alice });
93
+
94
+ // Access the value to trigger error logging
95
+ expect(mapOnAlice.$jazz.loadingState).toBe(
96
+ CoValueLoadingState.UNAUTHORIZED,
97
+ );
98
+
99
+ expect(consoleErrorSpy).toHaveBeenCalled();
100
+
101
+ consoleErrorSpy.mockRestore();
102
+ });
103
+ });
@@ -1,6 +1,13 @@
1
1
  import { cojsonInternals, emptyKnownState } from "cojson";
2
2
  import { assert, beforeEach, expect, test } from "vitest";
3
- import { Account, Group, co, exportCoValue, z } from "../exports.js";
3
+ import {
4
+ Account,
5
+ Group,
6
+ co,
7
+ exportCoValue,
8
+ jazzConfig,
9
+ z,
10
+ } from "../exports.js";
4
11
  import { CoValueLoadingState } from "../internal.js";
5
12
  import {
6
13
  createJazzTestAccount,
@@ -12,6 +19,13 @@ import { assertLoaded, waitFor } from "./utils.js";
12
19
 
13
20
  cojsonInternals.CO_VALUE_LOADING_CONFIG.RETRY_DELAY = 10;
14
21
 
22
+ let lastError: Error | undefined;
23
+ beforeEach(() => {
24
+ lastError = undefined;
25
+ jazzConfig.setCustomErrorReporter((error) => {
26
+ lastError = error;
27
+ });
28
+ });
15
29
  beforeEach(async () => {
16
30
  await setupJazzTestSync();
17
31
  await createJazzTestAccount({
@@ -42,6 +56,9 @@ test("return 'unavailable' if id is invalid", async () => {
42
56
 
43
57
  const john = await Person.load("test");
44
58
  expect(john.$jazz.loadingState).toBe(CoValueLoadingState.UNAVAILABLE);
59
+ expect(lastError?.message).toBe(
60
+ "Jazz Unavailable Error: unable to load test",
61
+ );
45
62
  });
46
63
 
47
64
  test("load a missing optional value (co.optional)", async () => {
@@ -185,6 +202,9 @@ test("returns 'unavailable' if the value is unavailable after retries", async ()
185
202
  const john = await Person.load(map.$jazz.id, { loadAs: alice });
186
203
 
187
204
  expect(john.$jazz.loadingState).toBe(CoValueLoadingState.UNAVAILABLE);
205
+ expect(lastError?.message).toBe(
206
+ "Jazz Unavailable Error: unable to load " + map.$jazz.id,
207
+ );
188
208
  });
189
209
 
190
210
  test("load works even when the coValue access is granted after the creation", async () => {
@@ -14,6 +14,7 @@ import {
14
14
  CoValueLoadingState,
15
15
  exportCoValue,
16
16
  importContentPieces,
17
+ Inaccessible,
17
18
  } from "../internal.js";
18
19
  import { createJazzTestAccount, linkAccounts } from "../testing.js";
19
20
 
@@ -663,7 +664,7 @@ describe("JazzRequestError handling", () => {
663
664
  createUnloadedCoValue(
664
665
  "some-covalue-id",
665
666
  CoValueLoadingState.UNAVAILABLE,
666
- ),
667
+ ) as Inaccessible<Account>,
667
668
  );
668
669
 
669
670
  return userRequest.handle(request, worker, async () => {
@@ -1297,6 +1297,50 @@ describe("subscribeToCoValue", () => {
1297
1297
  expect(result.data[chunks]).toBe("new entry");
1298
1298
  });
1299
1299
 
1300
+ it("should emit not emit when the content doesn't bring real changes", async () => {
1301
+ const alice = await createJazzTestAccount();
1302
+
1303
+ const Person = co.map({
1304
+ name: z.string(),
1305
+ });
1306
+ const PersonList = co.list(Person);
1307
+
1308
+ const group = Group.create(alice);
1309
+
1310
+ const person1 = Person.create({ name: "John" }, group);
1311
+ const person2 = Person.create({ name: "Jane" }, group);
1312
+
1313
+ const personList = PersonList.create([person1, person2], group);
1314
+
1315
+ const spy = vi.fn();
1316
+ // Test subscribing to the large coValue
1317
+ const unsubscribe = subscribeToCoValue(
1318
+ coValueClassFromCoValueClassOrSchema(PersonList),
1319
+ personList.$jazz.id,
1320
+ {
1321
+ loadAs: alice,
1322
+ resolve: {
1323
+ $each: true,
1324
+ },
1325
+ syncResolution: true,
1326
+ },
1327
+ spy,
1328
+ );
1329
+
1330
+ onTestFinished(unsubscribe);
1331
+
1332
+ expect(spy).toHaveBeenCalledTimes(1);
1333
+
1334
+ // Test that updates to the large coValue are properly subscribed
1335
+ spy.mockClear();
1336
+
1337
+ group.addMember("everyone", "reader");
1338
+
1339
+ await new Promise((resolve) => setTimeout(resolve, 5));
1340
+
1341
+ expect(spy).not.toHaveBeenCalled();
1342
+ });
1343
+
1300
1344
  it.fails(
1301
1345
  "should return the latest loaded state when a deeply loaded child becomes not accessible",
1302
1346
  async () => {
package/tsup.config.ts CHANGED
@@ -43,8 +43,16 @@ export default defineConfig([
43
43
  index: "src/expo/index.ts",
44
44
  testing: "src/expo/testing.ts",
45
45
  crypto: "src/expo/crypto.ts",
46
+ polyfills: "src/react-native-core/polyfills/index.js",
46
47
  },
47
48
  outDir: "dist/expo",
49
+ external: [
50
+ "jazz-tools",
51
+ "readable-stream",
52
+ "@azure/core-asynciterator-polyfill",
53
+ "react-native-get-random-values",
54
+ "react-native-fast-encoder",
55
+ ],
48
56
  },
49
57
  {
50
58
  ...cfg,
@@ -107,8 +115,16 @@ export default defineConfig([
107
115
  index: "src/react-native/index.ts",
108
116
  testing: "src/react-native/testing.ts",
109
117
  crypto: "src/react-native/crypto.ts",
118
+ polyfills: "src/react-native-core/polyfills/index.js",
110
119
  },
111
120
  outDir: "dist/react-native",
121
+ external: [
122
+ "jazz-tools",
123
+ "readable-stream",
124
+ "@azure/core-asynciterator-polyfill",
125
+ "react-native-get-random-values",
126
+ "react-native-fast-encoder",
127
+ ],
112
128
  },
113
129
  {
114
130
  ...cfg,
@@ -116,6 +132,7 @@ export default defineConfig([
116
132
  index: "src/react-native-core/index.ts",
117
133
  testing: "src/react-native-core/testing.tsx",
118
134
  crypto: "src/react-native-core/crypto/index.ts",
135
+ "crypto/RNCrypto": "src/react-native-core/crypto/RNCrypto.ts",
119
136
  },
120
137
  outDir: "dist/react-native-core",
121
138
  },