jazz-tools 0.19.22 → 0.20.0

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 (201) hide show
  1. package/.svelte-kit/__package__/react.d.ts.map +1 -1
  2. package/.svelte-kit/__package__/react.tsx +5 -2
  3. package/.turbo/turbo-build.log +71 -83
  4. package/CHANGELOG.md +69 -0
  5. package/dist/better-auth/auth/react.d.ts.map +1 -1
  6. package/dist/better-auth/auth/react.js +5 -2
  7. package/dist/better-auth/auth/react.js.map +1 -1
  8. package/dist/browser/createBrowserContext.d.ts +1 -2
  9. package/dist/browser/createBrowserContext.d.ts.map +1 -1
  10. package/dist/browser/index.js +1 -8
  11. package/dist/browser/index.js.map +1 -1
  12. package/dist/browser/provideBrowserLockSession/SessionIDStorage.d.ts +1 -1
  13. package/dist/{chunk-QCTQH5RS.js → chunk-3CAPPS2F.js} +234 -101
  14. package/dist/chunk-3CAPPS2F.js.map +1 -0
  15. package/dist/{chunk-M2HGBOXS.js → chunk-K4D7IMFM.js} +3 -3
  16. package/dist/chunk-K4D7IMFM.js.map +1 -0
  17. package/dist/expo/auth/clerk/index.d.ts.map +1 -1
  18. package/dist/expo/index.js +5 -2
  19. package/dist/expo/index.js.map +1 -1
  20. package/dist/index.js +4 -2
  21. package/dist/index.js.map +1 -1
  22. package/dist/inspector/{chunk-YQNK5Y7B.js → chunk-MCTB5ZJC.js} +1 -1
  23. package/dist/inspector/chunk-MCTB5ZJC.js.map +1 -0
  24. package/dist/inspector/contexts/node.d.ts.map +1 -1
  25. package/dist/inspector/{custom-element-KYV64IOC.js → custom-element-5YWVZBWA.js} +1 -1
  26. package/dist/inspector/{custom-element-KYV64IOC.js.map → custom-element-5YWVZBWA.js.map} +1 -1
  27. package/dist/inspector/index.js +3 -3
  28. package/dist/inspector/index.js.map +1 -1
  29. package/dist/inspector/register-custom-element.js +1 -1
  30. package/dist/inspector/standalone.js +1 -1
  31. package/dist/react/auth/Clerk.d.ts.map +1 -1
  32. package/dist/react/hooks.d.ts +1 -1
  33. package/dist/react/hooks.d.ts.map +1 -1
  34. package/dist/react/index.js +61 -47
  35. package/dist/react/index.js.map +1 -1
  36. package/dist/react/provider.d.ts.map +1 -1
  37. package/dist/react/ssr.js +2 -2
  38. package/dist/react/ssr.js.map +1 -1
  39. package/dist/react-core/chunk-UOYH6JFJ.js +10 -0
  40. package/dist/react-core/chunk-UOYH6JFJ.js.map +1 -0
  41. package/dist/react-core/hooks.d.ts +3 -3
  42. package/dist/react-core/hooks.d.ts.map +1 -1
  43. package/dist/react-core/index.js +27 -25
  44. package/dist/react-core/index.js.map +1 -1
  45. package/dist/react-core/provider.d.ts +2 -3
  46. package/dist/react-core/provider.d.ts.map +1 -1
  47. package/dist/react-core/testing.d.ts.map +1 -1
  48. package/dist/react-core/testing.js +4 -10
  49. package/dist/react-core/testing.js.map +1 -1
  50. package/dist/react-native/index.js +61 -53
  51. package/dist/react-native/index.js.map +1 -1
  52. package/dist/react-native-core/ReactNativeContextManager.d.ts +0 -1
  53. package/dist/react-native-core/ReactNativeContextManager.d.ts.map +1 -1
  54. package/dist/react-native-core/hooks.d.ts +1 -1
  55. package/dist/react-native-core/hooks.d.ts.map +1 -1
  56. package/dist/react-native-core/index.js +58 -50
  57. package/dist/react-native-core/index.js.map +1 -1
  58. package/dist/react-native-core/platform.d.ts +0 -4
  59. package/dist/react-native-core/platform.d.ts.map +1 -1
  60. package/dist/react-native-core/provider.d.ts +2 -1
  61. package/dist/react-native-core/provider.d.ts.map +1 -1
  62. package/dist/svelte/jazz.class.svelte.d.ts.map +1 -1
  63. package/dist/svelte/jazz.class.svelte.js +2 -8
  64. package/dist/svelte/tests/AccountCoState.svelte.test.d.ts +2 -0
  65. package/dist/svelte/tests/AccountCoState.svelte.test.d.ts.map +1 -0
  66. package/dist/svelte/tests/AccountCoState.svelte.test.js +59 -0
  67. package/dist/svelte/tests/CoState.svelte.test.js +23 -0
  68. package/dist/svelte/tests/TestAccountCoStateWrapper.svelte +24 -0
  69. package/dist/svelte/tests/TestAccountCoStateWrapper.svelte.d.ts +11 -0
  70. package/dist/svelte/tests/TestAccountCoStateWrapper.svelte.d.ts.map +1 -0
  71. package/dist/testing.js +6 -6
  72. package/dist/testing.js.map +1 -1
  73. package/dist/tools/coValues/coList.d.ts +2 -2
  74. package/dist/tools/coValues/coList.d.ts.map +1 -1
  75. package/dist/tools/coValues/coMap.d.ts +2 -2
  76. package/dist/tools/coValues/deepLoading.d.ts +2 -2
  77. package/dist/tools/coValues/deepLoading.d.ts.map +1 -1
  78. package/dist/tools/coValues/interfaces.d.ts +32 -0
  79. package/dist/tools/coValues/interfaces.d.ts.map +1 -1
  80. package/dist/tools/exports.d.ts +1 -1
  81. package/dist/tools/exports.d.ts.map +1 -1
  82. package/dist/tools/implementation/ContextManager.d.ts.map +1 -1
  83. package/dist/tools/implementation/createContext.d.ts.map +1 -1
  84. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts +3 -2
  85. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -1
  86. package/dist/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.d.ts +3 -2
  87. package/dist/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.d.ts.map +1 -1
  88. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts +3 -3
  89. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts.map +1 -1
  90. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +3 -2
  91. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -1
  92. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts +5 -2
  93. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts.map +1 -1
  94. package/dist/tools/implementation/zodSchema/zodCo.d.ts.map +1 -1
  95. package/dist/tools/ssr.js +1 -1
  96. package/dist/tools/subscribe/JazzError.d.ts +3 -3
  97. package/dist/tools/subscribe/JazzError.d.ts.map +1 -1
  98. package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
  99. package/dist/tools/subscribe/types.d.ts +5 -1
  100. package/dist/tools/subscribe/types.d.ts.map +1 -1
  101. package/dist/tools/testing.d.ts +3 -3
  102. package/dist/tools/testing.d.ts.map +1 -1
  103. package/dist/tools/tests/deleteCoValues.test.d.ts +2 -0
  104. package/dist/tools/tests/deleteCoValues.test.d.ts.map +1 -0
  105. package/dist/tools/tests/deletedState.test.d.ts +2 -0
  106. package/dist/tools/tests/deletedState.test.d.ts.map +1 -0
  107. package/dist/worker/edge-wasm.js +2 -1
  108. package/dist/worker/edge-wasm.js.map +1 -1
  109. package/dist/worker/wasm.d.ts +2 -0
  110. package/dist/worker/wasm.d.ts.map +1 -0
  111. package/package.json +9 -28
  112. package/src/better-auth/auth/react.tsx +5 -2
  113. package/src/browser/createBrowserContext.ts +2 -5
  114. package/src/expo/auth/clerk/index.tsx +5 -2
  115. package/src/inspector/contexts/node.tsx +1 -2
  116. package/src/inspector/index.tsx +2 -2
  117. package/src/react/auth/Clerk.tsx +5 -2
  118. package/src/react/auth/PasskeyAuth.tsx +2 -2
  119. package/src/react/hooks.tsx +3 -2
  120. package/src/react/provider.tsx +45 -41
  121. package/src/react-core/auth/DemoAuth.tsx +2 -2
  122. package/src/react-core/auth/PassphraseAuth.tsx +2 -2
  123. package/src/react-core/hooks.ts +26 -27
  124. package/src/react-core/provider.tsx +1 -5
  125. package/src/react-core/testing.tsx +3 -11
  126. package/src/react-core/tests/useAccount.selector.test.ts +2 -3
  127. package/src/react-core/tests/useAccount.test.ts +57 -7
  128. package/src/react-core/tests/useCoState.test.ts +37 -0
  129. package/src/react-core/tests/useInboxSender.test.ts +2 -5
  130. package/src/react-core/tests/useSuspenseAccount.test.tsx +68 -0
  131. package/src/react-core/tests/useSuspenseCoState.test.tsx +44 -0
  132. package/src/react-native-core/ReactNativeContextManager.ts +0 -3
  133. package/src/react-native-core/auth/usePasskeyAuth.tsx +2 -2
  134. package/src/react-native-core/hooks.tsx +3 -3
  135. package/src/react-native-core/platform.ts +2 -6
  136. package/src/react-native-core/provider.tsx +47 -43
  137. package/src/svelte/jazz.class.svelte.ts +2 -8
  138. package/src/svelte/tests/AccountCoState.svelte.test.ts +79 -0
  139. package/src/svelte/tests/CoState.svelte.test.ts +36 -0
  140. package/src/svelte/tests/TestAccountCoStateWrapper.svelte +24 -0
  141. package/src/tools/coValues/deepLoading.ts +2 -0
  142. package/src/tools/coValues/interfaces.ts +170 -32
  143. package/src/tools/exports.ts +1 -0
  144. package/src/tools/implementation/ContextManager.ts +2 -2
  145. package/src/tools/implementation/createContext.ts +4 -0
  146. package/src/tools/implementation/zodSchema/schemaTypes/AccountSchema.ts +30 -6
  147. package/src/tools/implementation/zodSchema/schemaTypes/CoDiscriminatedUnionSchema.ts +55 -7
  148. package/src/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.ts +33 -14
  149. package/src/tools/implementation/zodSchema/schemaTypes/CoListSchema.ts +35 -6
  150. package/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts +35 -14
  151. package/src/tools/ssr/ssr.ts +2 -2
  152. package/src/tools/subscribe/CoValueCoreSubscription.ts +1 -0
  153. package/src/tools/subscribe/JazzError.ts +4 -1
  154. package/src/tools/subscribe/SubscriptionScope.ts +23 -0
  155. package/src/tools/subscribe/types.ts +5 -0
  156. package/src/tools/testing.ts +5 -5
  157. package/src/tools/tests/PassphraseAuth.test.ts +5 -5
  158. package/src/tools/tests/deleteCoValues.test.ts +231 -0
  159. package/src/tools/tests/deletedState.test.ts +110 -0
  160. package/src/tools/tests/request.test.ts +15 -2
  161. package/src/worker/edge-wasm.ts +2 -1
  162. package/src/worker/wasm.ts +1 -0
  163. package/tsup.config.ts +0 -4
  164. package/dist/browser/storageOptions.d.ts +0 -8
  165. package/dist/browser/storageOptions.d.ts.map +0 -1
  166. package/dist/browser/tests/storageOptions.test.d.ts +0 -2
  167. package/dist/browser/tests/storageOptions.test.d.ts.map +0 -1
  168. package/dist/chunk-M2HGBOXS.js.map +0 -1
  169. package/dist/chunk-QCTQH5RS.js.map +0 -1
  170. package/dist/expo/crypto.d.ts +0 -2
  171. package/dist/expo/crypto.d.ts.map +0 -1
  172. package/dist/expo/crypto.js +0 -6
  173. package/dist/expo/crypto.js.map +0 -1
  174. package/dist/inspector/chunk-YQNK5Y7B.js.map +0 -1
  175. package/dist/react-core/chunk-7DYMJ74I.js +0 -12
  176. package/dist/react-core/chunk-7DYMJ74I.js.map +0 -1
  177. package/dist/react-native/chunk-DGUM43GV.js +0 -11
  178. package/dist/react-native/chunk-DGUM43GV.js.map +0 -1
  179. package/dist/react-native/crypto.d.ts +0 -2
  180. package/dist/react-native/crypto.d.ts.map +0 -1
  181. package/dist/react-native/crypto.js +0 -8
  182. package/dist/react-native/crypto.js.map +0 -1
  183. package/dist/react-native-core/chunk-DGUM43GV.js +0 -11
  184. package/dist/react-native-core/chunk-DGUM43GV.js.map +0 -1
  185. package/dist/react-native-core/crypto/RNCrypto.d.ts +0 -2
  186. package/dist/react-native-core/crypto/RNCrypto.d.ts.map +0 -1
  187. package/dist/react-native-core/crypto/RNCrypto.js +0 -3
  188. package/dist/react-native-core/crypto/RNCrypto.js.map +0 -1
  189. package/dist/react-native-core/crypto/RNQuickCrypto.d.ts +0 -17
  190. package/dist/react-native-core/crypto/RNQuickCrypto.d.ts.map +0 -1
  191. package/dist/react-native-core/crypto/index.d.ts +0 -2
  192. package/dist/react-native-core/crypto/index.d.ts.map +0 -1
  193. package/dist/react-native-core/crypto.js +0 -89
  194. package/dist/react-native-core/crypto.js.map +0 -1
  195. package/src/browser/storageOptions.ts +0 -17
  196. package/src/browser/tests/storageOptions.test.ts +0 -33
  197. package/src/expo/crypto.ts +0 -1
  198. package/src/react-native/crypto.ts +0 -1
  199. package/src/react-native-core/crypto/RNCrypto.ts +0 -1
  200. package/src/react-native-core/crypto/RNQuickCrypto.ts +0 -122
  201. package/src/react-native-core/crypto/index.ts +0 -1
@@ -1,10 +1,10 @@
1
1
  import { WebSocketPeerWithReconnection } from "cojson-transport-ws";
2
- import { PureJSCrypto } from "cojson/dist/crypto/PureJSCrypto";
2
+ import { WasmCrypto } from "cojson/crypto/WasmCrypto";
3
3
  import { createAnonymousJazzContext } from "jazz-tools";
4
4
 
5
5
  export function createSSRJazzAgent(opts: { peer: string }) {
6
6
  const ssrNode = createAnonymousJazzContext({
7
- crypto: new PureJSCrypto(),
7
+ crypto: WasmCrypto.createSync(),
8
8
  peers: [],
9
9
  });
10
10
 
@@ -223,6 +223,7 @@ export class CoValueCoreSubscription {
223
223
  */
224
224
  function isCompletelyDownloaded(value: RawCoValue) {
225
225
  return (
226
+ value.core.isDeleted ||
226
227
  value.core.verified?.header.meta?.type === "binary" ||
227
228
  value.core.isCompletelyDownloaded()
228
229
  );
@@ -6,6 +6,7 @@ export class JazzError {
6
6
  public id: ID<CoValue> | undefined,
7
7
  public type:
8
8
  | typeof CoValueLoadingState.UNAVAILABLE
9
+ | typeof CoValueLoadingState.DELETED
9
10
  | typeof CoValueLoadingState.UNAUTHORIZED,
10
11
  public issues: JazzErrorIssue[],
11
12
  ) {}
@@ -49,8 +50,10 @@ export class JazzError {
49
50
  export type JazzErrorIssue = {
50
51
  code:
51
52
  | typeof CoValueLoadingState.UNAVAILABLE
53
+ | typeof CoValueLoadingState.DELETED
52
54
  | typeof CoValueLoadingState.UNAUTHORIZED
53
- | "validationError";
55
+ | "validationError"
56
+ | "deleteError";
54
57
  message: string;
55
58
  params: Record<string, any>;
56
59
  path: string[];
@@ -171,6 +171,25 @@ export class SubscriptionScope<D extends CoValue> {
171
171
  return;
172
172
  }
173
173
 
174
+ if (update.core.isDeleted) {
175
+ if (this.value.type !== CoValueLoadingState.DELETED) {
176
+ const error = new JazzError(this.id, CoValueLoadingState.DELETED, [
177
+ {
178
+ code: CoValueLoadingState.DELETED,
179
+ message: `Jazz Deleted Error: ${this.id} has been deleted`,
180
+ params: {
181
+ id: this.id,
182
+ },
183
+ path: [],
184
+ },
185
+ ]);
186
+
187
+ this.updateValue(error);
188
+ this.triggerUpdate();
189
+ }
190
+ return;
191
+ }
192
+
174
193
  if (!hasAccessToCoValue(update)) {
175
194
  if (this.value.type !== CoValueLoadingState.UNAUTHORIZED) {
176
195
  const message = `Jazz Authorization Error: The current user (${this.node.getCurrentAgent().id}) is not authorized to access ${this.id}`;
@@ -279,6 +298,7 @@ export class SubscriptionScope<D extends CoValue> {
279
298
 
280
299
  if (
281
300
  value.type === CoValueLoadingState.UNAVAILABLE ||
301
+ value.type === CoValueLoadingState.DELETED ||
282
302
  value.type === CoValueLoadingState.UNAUTHORIZED
283
303
  ) {
284
304
  this.childErrors.set(id, value.prependPath(key ?? id));
@@ -414,6 +434,7 @@ export class SubscriptionScope<D extends CoValue> {
414
434
 
415
435
  if (
416
436
  rawValue === CoValueLoadingState.UNAUTHORIZED ||
437
+ rawValue === CoValueLoadingState.DELETED ||
417
438
  rawValue === CoValueLoadingState.UNAVAILABLE ||
418
439
  rawValue === CoValueLoadingState.LOADING
419
440
  ) {
@@ -427,6 +448,7 @@ export class SubscriptionScope<D extends CoValue> {
427
448
  private getCurrentRawValue(): D | NotLoadedCoValueState {
428
449
  if (
429
450
  this.value.type === CoValueLoadingState.UNAUTHORIZED ||
451
+ this.value.type === CoValueLoadingState.DELETED ||
430
452
  this.value.type === CoValueLoadingState.UNAVAILABLE
431
453
  ) {
432
454
  return this.value.type;
@@ -481,6 +503,7 @@ export class SubscriptionScope<D extends CoValue> {
481
503
  private getError() {
482
504
  if (
483
505
  this.value.type === CoValueLoadingState.UNAUTHORIZED ||
506
+ this.value.type === CoValueLoadingState.DELETED ||
484
507
  this.value.type === CoValueLoadingState.UNAVAILABLE
485
508
  ) {
486
509
  return this.value;
@@ -16,6 +16,10 @@ export const CoValueLoadingState = {
16
16
  * The coValue is being loaded.
17
17
  */
18
18
  LOADING: "loading",
19
+ /**
20
+ * The coValue existed but has been deleted (tombstoned).
21
+ */
22
+ DELETED: "deleted",
19
23
  /**
20
24
  * The coValue was loaded but the account is not authorized to access it.
21
25
  */
@@ -31,6 +35,7 @@ export type CoValueLoadingState =
31
35
 
32
36
  export type CoValueErrorState =
33
37
  | typeof CoValueLoadingState.UNAVAILABLE
38
+ | typeof CoValueLoadingState.DELETED
34
39
  | typeof CoValueLoadingState.UNAUTHORIZED;
35
40
 
36
41
  export type NotLoadedCoValueState =
@@ -1,6 +1,5 @@
1
1
  import { LocalNode } from "cojson";
2
2
  import { cojsonInternals } from "cojson";
3
- import { PureJSCrypto } from "cojson/dist/crypto/PureJSCrypto";
4
3
  import {
5
4
  Account,
6
5
  AccountClass,
@@ -18,6 +17,7 @@ import {
18
17
  createJazzContext,
19
18
  MockSessionProvider,
20
19
  } from "./internal.js";
20
+ import { WasmCrypto } from "cojson/crypto/WasmCrypto";
21
21
 
22
22
  const randomSessionProvider = new MockSessionProvider();
23
23
 
@@ -28,11 +28,11 @@ const syncServer: { current: LocalNode | null; asyncPeers: boolean } = {
28
28
  asyncPeers: false,
29
29
  };
30
30
 
31
- export class TestJSCrypto extends PureJSCrypto {
31
+ export class TestJSCrypto extends WasmCrypto {
32
32
  static async create() {
33
33
  if ("navigator" in globalThis && navigator.userAgent?.includes("jsdom")) {
34
34
  // Mocking crypto seal & encrypt to make it work with JSDom. Getting "Error: Uint8Array expected" there
35
- const crypto = new PureJSCrypto();
35
+ const crypto = await WasmCrypto.create();
36
36
 
37
37
  crypto.seal = (options) =>
38
38
  `sealed_U${cojsonInternals.stableStringify(options.message)}` as any;
@@ -47,7 +47,7 @@ export class TestJSCrypto extends PureJSCrypto {
47
47
  }
48
48
 
49
49
  // For non-jsdom environments, we use the real crypto
50
- return new PureJSCrypto();
50
+ return await WasmCrypto.create();
51
51
  }
52
52
  }
53
53
 
@@ -188,7 +188,7 @@ export function runWithoutActiveAccount<Result>(
188
188
 
189
189
  export async function createJazzTestGuest() {
190
190
  const ctx = await createAnonymousJazzContext({
191
- crypto: await PureJSCrypto.create(),
191
+ crypto: await WasmCrypto.create(),
192
192
  peers: [],
193
193
  });
194
194
 
@@ -1,7 +1,6 @@
1
1
  // @vitest-environment happy-dom
2
2
 
3
3
  import { AgentSecret } from "cojson";
4
- import { PureJSCrypto } from "cojson/crypto/PureJSCrypto";
5
4
  import { assert, beforeEach, describe, expect, it, vi } from "vitest";
6
5
  import { PassphraseAuth } from "../auth/PassphraseAuth";
7
6
  import {
@@ -17,6 +16,7 @@ import {
17
16
  setupJazzTestSync,
18
17
  } from "../testing";
19
18
  import { testWordlist } from "./fixtures";
19
+ import { WasmCrypto } from "cojson/crypto/WasmCrypto";
20
20
 
21
21
  // Initialize KV store for tests
22
22
  KvStoreContext.getInstance().initialize(new InMemoryKVStore());
@@ -26,7 +26,7 @@ beforeEach(async () => {
26
26
  });
27
27
 
28
28
  describe("PassphraseAuth", () => {
29
- let crypto: PureJSCrypto;
29
+ let crypto: WasmCrypto;
30
30
  let mockAuthenticate: any;
31
31
  let mockRegister: any;
32
32
  let authSecretStorage: AuthSecretStorage;
@@ -38,7 +38,7 @@ describe("PassphraseAuth", () => {
38
38
  KvStoreContext.getInstance().getStorage().clearAll();
39
39
 
40
40
  // Set up crypto and mocks
41
- crypto = await PureJSCrypto.create();
41
+ crypto = await WasmCrypto.create();
42
42
  mockAuthenticate = vi.fn();
43
43
  mockRegister = vi.fn();
44
44
  authSecretStorage = new AuthSecretStorage();
@@ -201,7 +201,7 @@ describe("PassphraseAuth", () => {
201
201
  KvStoreContext.getInstance().initialize(new InMemoryKVStore());
202
202
 
203
203
  describe("PassphraseAuth with TestJazzContextManager", () => {
204
- let crypto: PureJSCrypto;
204
+ let crypto: WasmCrypto;
205
205
  let contextManager: TestJazzContextManager<any>;
206
206
  let authSecretStorage: AuthSecretStorage;
207
207
  let passphraseAuth: PassphraseAuth;
@@ -215,7 +215,7 @@ describe("PassphraseAuth with TestJazzContextManager", () => {
215
215
  });
216
216
 
217
217
  // Set up crypto and context manager
218
- crypto = await PureJSCrypto.create();
218
+ crypto = await WasmCrypto.create();
219
219
  contextManager = TestJazzContextManager.fromAccountOrGuest(account);
220
220
  authSecretStorage = contextManager.getAuthSecretStorage();
221
221
 
@@ -0,0 +1,231 @@
1
+ import { beforeEach, describe, expect, test } from "vitest";
2
+ import {
3
+ Account,
4
+ CoValueLoadingState,
5
+ Group,
6
+ co,
7
+ deleteCoValues,
8
+ z,
9
+ } from "../exports.js";
10
+ import { createJazzTestAccount, setupJazzTestSync } from "../testing.js";
11
+ import { assertLoaded, waitFor } from "./utils.js";
12
+
13
+ beforeEach(async () => {
14
+ await setupJazzTestSync();
15
+ await createJazzTestAccount({
16
+ isCurrentActiveAccount: true,
17
+ });
18
+ });
19
+
20
+ describe("deleteCoValues", () => {
21
+ test("deletes a resolved graph (tombstones) and loads as DELETED", async () => {
22
+ const Meta = co.map({
23
+ tag: z.string(),
24
+ });
25
+
26
+ const Note = co.map({
27
+ text: co.plainText(),
28
+ meta: Meta,
29
+ });
30
+
31
+ const owner = Account.getMe();
32
+ const group = Group.create(owner).makePublic("reader");
33
+
34
+ const note = Note.create(
35
+ {
36
+ text: "hello",
37
+ meta: { tag: "t1" },
38
+ },
39
+ group,
40
+ );
41
+
42
+ const text = note.text;
43
+ const meta = note.meta;
44
+
45
+ await note.$jazz.raw.core.waitForSync();
46
+
47
+ await deleteCoValues(Note, note.$jazz.id, {
48
+ loadAs: owner,
49
+ resolve: { text: true, meta: true },
50
+ });
51
+
52
+ expect(note.$jazz.raw.core.isDeleted).toBe(true);
53
+ expect(text.$jazz.raw.core.isDeleted).toBe(true);
54
+ expect(meta.$jazz.raw.core.isDeleted).toBe(true);
55
+
56
+ const viewer = await createJazzTestAccount();
57
+ const loaded = await Note.load(note.$jazz.id, {
58
+ loadAs: viewer,
59
+ skipRetry: true,
60
+ });
61
+
62
+ expect(loaded.$isLoaded).toBe(false);
63
+ expect(loaded.$jazz.loadingState).toBe(CoValueLoadingState.DELETED);
64
+ });
65
+
66
+ test("rejects deletion for non-admin on a group-owned value", async () => {
67
+ const Meta = co.map({
68
+ tag: z.string(),
69
+ });
70
+
71
+ const Note = co.map({
72
+ meta: Meta,
73
+ });
74
+
75
+ const owner = Account.getMe();
76
+ const writer = await createJazzTestAccount();
77
+
78
+ const group = Group.create(owner);
79
+ group.addMember(writer, "writer");
80
+
81
+ const note = Note.create({ meta: { tag: "t1" } }, group);
82
+ await note.$jazz.raw.core.waitForSync();
83
+
84
+ await expect(
85
+ deleteCoValues(Note, note.$jazz.id, {
86
+ loadAs: writer,
87
+ resolve: { meta: true },
88
+ }),
89
+ ).rejects.toThrow(/admin permissions/i);
90
+
91
+ expect(note.$jazz.raw.core.isDeleted).toBe(false);
92
+ });
93
+
94
+ test("rejects deletion when a resolved child is not deletable (error includes path)", async () => {
95
+ const Child = co.map({
96
+ value: z.string(),
97
+ });
98
+
99
+ const Root = co.map({
100
+ child: Child,
101
+ });
102
+
103
+ const owner = Account.getMe();
104
+ const otherOwner = await createJazzTestAccount();
105
+
106
+ const groupA = Group.create(owner).makePublic("reader");
107
+ const groupB = Group.create({ owner: otherOwner }).makePublic("reader");
108
+
109
+ const child = Child.create({ value: "child" }, groupB);
110
+ await child.$jazz.raw.core.waitForSync();
111
+
112
+ const root = Root.create({ child }, groupA);
113
+ await root.$jazz.raw.core.waitForSync();
114
+
115
+ await expect(
116
+ deleteCoValues(Root, root.$jazz.id, {
117
+ loadAs: owner,
118
+ resolve: { child: true },
119
+ }),
120
+ ).rejects.toThrow(
121
+ new RegExp(
122
+ `Subscription starts from ${root.$jazz.id}.*path ${child.$jazz.id}`,
123
+ ),
124
+ );
125
+
126
+ expect(root.$jazz.raw.core.isDeleted).toBe(false);
127
+ expect(child.$jazz.raw.core.isDeleted).toBe(false);
128
+ });
129
+
130
+ test("rejects deletion when the value cannot be loaded", async () => {
131
+ const Root = co.map({
132
+ value: z.string(),
133
+ });
134
+
135
+ const owner = Account.getMe();
136
+ const otherOwner = await createJazzTestAccount();
137
+ const root = Root.create(
138
+ { value: "root" },
139
+ Group.create({ owner: otherOwner }),
140
+ );
141
+ await root.$jazz.raw.core.waitForSync();
142
+
143
+ await expect(
144
+ deleteCoValues(Root, root.$jazz.id, {
145
+ loadAs: owner,
146
+ }),
147
+ ).rejects.toThrow(new RegExp(`Jazz Authorization Error`));
148
+
149
+ expect(root.$jazz.raw.core.isDeleted).toBe(false);
150
+ });
151
+
152
+ test("rejects deletion when a child could not be loaded", async () => {
153
+ const Child = co.map({
154
+ value: z.string(),
155
+ });
156
+
157
+ const Root = co.map({
158
+ child: Child,
159
+ });
160
+
161
+ const owner = Account.getMe();
162
+ const otherOwner = await createJazzTestAccount();
163
+
164
+ const groupA = Group.create(owner).makePublic("reader");
165
+ const groupB = Group.create({ owner: otherOwner });
166
+
167
+ const child = Child.create({ value: "child" }, groupB);
168
+ await child.$jazz.raw.core.waitForSync();
169
+
170
+ const root = Root.create({ child }, groupA);
171
+ await root.$jazz.raw.core.waitForSync();
172
+
173
+ await expect(
174
+ deleteCoValues(Root, root.$jazz.id, {
175
+ loadAs: owner,
176
+ resolve: { child: true },
177
+ }),
178
+ ).rejects.toThrow(new RegExp(`Jazz Authorization Error`));
179
+
180
+ expect(root.$jazz.raw.core.isDeleted).toBe(false);
181
+ expect(child.$jazz.raw.core.isDeleted).toBe(false);
182
+ });
183
+
184
+ test("delete the CoValue when the child cannot be loaded but is marked with $onError", async () => {
185
+ const Child = co.map({
186
+ value: z.string(),
187
+ });
188
+
189
+ const Root = co.map({
190
+ child: Child,
191
+ });
192
+
193
+ const owner = Account.getMe();
194
+ const otherOwner = await createJazzTestAccount();
195
+
196
+ const groupA = Group.create(owner).makePublic("reader");
197
+ const groupB = Group.create({ owner: otherOwner });
198
+
199
+ const child = Child.create({ value: "child" }, groupB);
200
+ await child.$jazz.raw.core.waitForSync();
201
+
202
+ const root = Root.create({ child }, groupA);
203
+ await root.$jazz.raw.core.waitForSync();
204
+
205
+ await deleteCoValues(Root, root.$jazz.id, {
206
+ loadAs: owner,
207
+ resolve: { child: { $onError: "catch" } },
208
+ });
209
+
210
+ expect(root.$jazz.raw.core.isDeleted).toBe(true);
211
+ expect(child.$jazz.raw.core.isDeleted).toBe(false);
212
+ });
213
+
214
+ test("skips Account and Group CoValues", async () => {
215
+ const me = Account.getMe();
216
+
217
+ await deleteCoValues(Account, me.$jazz.id, {
218
+ loadAs: me,
219
+ });
220
+
221
+ expect(me.$jazz.raw.core.isDeleted).toBe(false);
222
+
223
+ const group = Group.create(me).makePublic("reader");
224
+
225
+ await deleteCoValues(Group, group.$jazz.id, {
226
+ loadAs: me,
227
+ });
228
+
229
+ expect(group.$jazz.raw.core.isDeleted).toBe(false);
230
+ });
231
+ });
@@ -0,0 +1,110 @@
1
+ import { beforeEach, describe, expect, it, onTestFinished, vi } from "vitest";
2
+ import { cojsonInternals } from "cojson";
3
+
4
+ import { Account, Group, z } from "../index.js";
5
+ import {
6
+ CoValueLoadingState,
7
+ co,
8
+ coValueClassFromCoValueClassOrSchema,
9
+ subscribeToCoValue,
10
+ } from "../internal.js";
11
+ import { loadCoValue } from "../exports.js";
12
+ import { createJazzTestAccount, setupJazzTestSync } from "../testing.js";
13
+ import { setupAccount, waitFor } from "./utils.js";
14
+
15
+ cojsonInternals.setCoValueLoadingRetryDelay(50);
16
+
17
+ describe("deleted loading state", () => {
18
+ beforeEach(() => {
19
+ // Keep these tests snappy and deterministic.
20
+ cojsonInternals.CO_VALUE_LOADING_CONFIG.MAX_RETRIES = 1;
21
+ cojsonInternals.CO_VALUE_LOADING_CONFIG.TIMEOUT = 50;
22
+ });
23
+
24
+ it("subscribeToCoValue calls onError and stops emitting loaded updates", async () => {
25
+ const TestMap = co.map({
26
+ value: z.string(),
27
+ });
28
+
29
+ const { me, meOnSecondPeer } = await setupAccount();
30
+
31
+ const map = TestMap.create({ value: "hello" }, me);
32
+
33
+ const onLoaded = vi.fn();
34
+ const onError = vi.fn();
35
+ const onUnavailable = vi.fn();
36
+ const onUnauthorized = vi.fn();
37
+
38
+ const unsubscribe = subscribeToCoValue(
39
+ coValueClassFromCoValueClassOrSchema(TestMap),
40
+ map.$jazz.id,
41
+ {
42
+ loadAs: meOnSecondPeer,
43
+ onError,
44
+ onUnavailable,
45
+ onUnauthorized,
46
+ },
47
+ onLoaded,
48
+ );
49
+
50
+ onTestFinished(unsubscribe);
51
+
52
+ await waitFor(() => {
53
+ expect(onLoaded).toHaveBeenCalled();
54
+ });
55
+
56
+ const loadedCallCountBeforeDelete = onLoaded.mock.calls.length;
57
+
58
+ map.$jazz.raw.core.deleteCoValue();
59
+ await map.$jazz.raw.core.waitForSync();
60
+
61
+ await waitFor(() => {
62
+ expect(onError).toHaveBeenCalled();
63
+ });
64
+
65
+ const deletedValue = onError.mock.calls[0]?.[0];
66
+ expect(deletedValue?.$isLoaded).toBe(false);
67
+ expect(deletedValue?.$jazz.loadingState).toBe(CoValueLoadingState.DELETED);
68
+
69
+ // Give the system a moment; we should not emit additional loaded updates after deletion.
70
+ await new Promise((resolve) => setTimeout(resolve, 50));
71
+ expect(onLoaded).toHaveBeenCalledTimes(loadedCallCountBeforeDelete);
72
+ expect(onUnavailable).not.toHaveBeenCalled();
73
+ expect(onUnauthorized).not.toHaveBeenCalled();
74
+ });
75
+
76
+ it("loadCoValue resolves a NotLoaded(DELETED) value for deleted coValues", async () => {
77
+ await setupJazzTestSync();
78
+
79
+ const TestMap = co.map({
80
+ value: z.string(),
81
+ });
82
+
83
+ const owner = await createJazzTestAccount({
84
+ isCurrentActiveAccount: true,
85
+ });
86
+
87
+ const group = Group.create(owner).makePublic("reader");
88
+ const map = TestMap.create({ value: "hello" }, group);
89
+
90
+ // Ensure the value exists on storage/peers before deleting.
91
+ await map.$jazz.raw.core.waitForSync();
92
+
93
+ map.$jazz.raw.core.deleteCoValue();
94
+ await map.$jazz.raw.core.waitForSync();
95
+
96
+ const viewer = await createJazzTestAccount();
97
+
98
+ const loaded = await loadCoValue(
99
+ coValueClassFromCoValueClassOrSchema(TestMap),
100
+ map.$jazz.id,
101
+ {
102
+ loadAs: viewer,
103
+ skipRetry: true,
104
+ },
105
+ );
106
+
107
+ expect(loaded.$isLoaded).toBe(false);
108
+ expect(loaded.$jazz.loadingState).toBe(CoValueLoadingState.DELETED);
109
+ });
110
+ });
@@ -20,7 +20,18 @@ import { createJazzTestAccount, linkAccounts } from "../testing.js";
20
20
 
21
21
  const server = setupServer();
22
22
 
23
- beforeAll(() => server.listen());
23
+ const ignoreWasmRequests = (request: Request, print: any) => {
24
+ if (request.url.includes("application/wasm")) {
25
+ return;
26
+ }
27
+ print.warning();
28
+ };
29
+
30
+ beforeAll(() =>
31
+ server.listen({
32
+ onUnhandledRequest: ignoreWasmRequests,
33
+ }),
34
+ );
24
35
  afterEach(() => server.resetHandlers());
25
36
  afterEach(() => vi.restoreAllMocks());
26
37
  afterAll(() => server.close());
@@ -877,7 +888,9 @@ describe("JazzRequestError handling", () => {
877
888
  ),
878
889
  ).rejects.toThrow("fetch failed");
879
890
 
880
- server.listen();
891
+ server.listen({
892
+ onUnhandledRequest: ignoreWasmRequests,
893
+ });
881
894
  });
882
895
  });
883
896
 
@@ -1,5 +1,6 @@
1
1
  // InitWasm allow to load the wasm code in edge runtimes (ex. cloudflare worker and vercel edge functions)
2
- import { init as InitWasm } from "cojson/crypto/WasmCrypto/edge";
2
+ import { init as InitWasm, initSync } from "cojson/crypto/WasmCrypto/edge";
3
3
  import { WasmCrypto } from "cojson/crypto/WasmCrypto";
4
4
 
5
5
  WasmCrypto.setInit(InitWasm);
6
+ WasmCrypto.setInitSync(initSync);
@@ -0,0 +1 @@
1
+ export { initWasmCrypto as initWasm } from "cojson/crypto/WasmCrypto";
package/tsup.config.ts CHANGED
@@ -42,7 +42,6 @@ export default defineConfig([
42
42
  entry: {
43
43
  index: "src/expo/index.ts",
44
44
  testing: "src/expo/testing.ts",
45
- crypto: "src/expo/crypto.ts",
46
45
  polyfills: "src/react-native-core/polyfills/index.js",
47
46
  },
48
47
  outDir: "dist/expo",
@@ -115,7 +114,6 @@ export default defineConfig([
115
114
  entry: {
116
115
  index: "src/react-native/index.ts",
117
116
  testing: "src/react-native/testing.ts",
118
- crypto: "src/react-native/crypto.ts",
119
117
  polyfills: "src/react-native-core/polyfills/index.js",
120
118
  },
121
119
  outDir: "dist/react-native",
@@ -132,8 +130,6 @@ export default defineConfig([
132
130
  entry: {
133
131
  index: "src/react-native-core/index.ts",
134
132
  testing: "src/react-native-core/testing.tsx",
135
- crypto: "src/react-native-core/crypto/index.ts",
136
- "crypto/RNCrypto": "src/react-native-core/crypto/RNCrypto.ts",
137
133
  },
138
134
  outDir: "dist/react-native-core",
139
135
  },
@@ -1,8 +0,0 @@
1
- type StorageOption = "indexedDB";
2
- type CombinedStorageOption = ["indexedDB"];
3
- export type StorageConfig = StorageOption | CombinedStorageOption | [StorageOption];
4
- export declare function getStorageOptions(storage?: StorageConfig): {
5
- useIndexedDB: boolean;
6
- };
7
- export {};
8
- //# sourceMappingURL=storageOptions.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"storageOptions.d.ts","sourceRoot":"","sources":["../../src/browser/storageOptions.ts"],"names":[],"mappings":"AAAA,KAAK,aAAa,GAAG,WAAW,CAAC;AACjC,KAAK,qBAAqB,GAAG,CAAC,WAAW,CAAC,CAAC;AAC3C,MAAM,MAAM,aAAa,GACrB,aAAa,GACb,qBAAqB,GACrB,CAAC,aAAa,CAAC,CAAC;AAEpB,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG;IAC1D,YAAY,EAAE,OAAO,CAAC;CACvB,CAOA"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=storageOptions.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"storageOptions.test.d.ts","sourceRoot":"","sources":["../../../src/browser/tests/storageOptions.test.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/tools/ssr/ssr.ts"],"sourcesContent":["import { WebSocketPeerWithReconnection } from \"cojson-transport-ws\";\nimport { PureJSCrypto } from \"cojson/dist/crypto/PureJSCrypto\";\nimport { createAnonymousJazzContext } from \"jazz-tools\";\n\nexport function createSSRJazzAgent(opts: { peer: string }) {\n const ssrNode = createAnonymousJazzContext({\n crypto: new PureJSCrypto(),\n peers: [],\n });\n\n const wsPeer = new WebSocketPeerWithReconnection({\n peer: opts.peer,\n reconnectionTimeout: 100,\n addPeer: (peer) => {\n ssrNode.agent.node.syncManager.addPeer(peer);\n },\n removePeer: () => {},\n });\n\n wsPeer.enable();\n\n return ssrNode.agent;\n}\n"],"mappings":";AAAA,SAAS,qCAAqC;AAC9C,SAAS,oBAAoB;AAC7B,SAAS,kCAAkC;AAEpC,SAAS,mBAAmB,MAAwB;AACzD,QAAM,UAAU,2BAA2B;AAAA,IACzC,QAAQ,IAAI,aAAa;AAAA,IACzB,OAAO,CAAC;AAAA,EACV,CAAC;AAED,QAAM,SAAS,IAAI,8BAA8B;AAAA,IAC/C,MAAM,KAAK;AAAA,IACX,qBAAqB;AAAA,IACrB,SAAS,CAAC,SAAS;AACjB,cAAQ,MAAM,KAAK,YAAY,QAAQ,IAAI;AAAA,IAC7C;AAAA,IACA,YAAY,MAAM;AAAA,IAAC;AAAA,EACrB,CAAC;AAED,SAAO,OAAO;AAEd,SAAO,QAAQ;AACjB;","names":[]}