jazz-tools 0.11.7 → 0.12.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 (62) hide show
  1. package/.turbo/turbo-build.log +7 -7
  2. package/CHANGELOG.md +23 -0
  3. package/dist/auth/DemoAuth.d.ts.map +1 -1
  4. package/dist/auth/PassphraseAuth.d.ts.map +1 -1
  5. package/dist/{chunk-HH3Z4JSB.js → chunk-QJNU65NK.js} +414 -275
  6. package/dist/chunk-QJNU65NK.js.map +1 -0
  7. package/dist/coValues/account.d.ts +15 -17
  8. package/dist/coValues/account.d.ts.map +1 -1
  9. package/dist/coValues/coFeed.d.ts +23 -18
  10. package/dist/coValues/coFeed.d.ts.map +1 -1
  11. package/dist/coValues/coList.d.ts +14 -7
  12. package/dist/coValues/coList.d.ts.map +1 -1
  13. package/dist/coValues/coMap.d.ts +36 -33
  14. package/dist/coValues/coMap.d.ts.map +1 -1
  15. package/dist/coValues/coPlainText.d.ts +7 -5
  16. package/dist/coValues/coPlainText.d.ts.map +1 -1
  17. package/dist/coValues/deepLoading.d.ts +36 -19
  18. package/dist/coValues/deepLoading.d.ts.map +1 -1
  19. package/dist/coValues/group.d.ts +14 -7
  20. package/dist/coValues/group.d.ts.map +1 -1
  21. package/dist/coValues/inbox.d.ts.map +1 -1
  22. package/dist/coValues/interfaces.d.ts +45 -11
  23. package/dist/coValues/interfaces.d.ts.map +1 -1
  24. package/dist/exports.d.ts +1 -1
  25. package/dist/exports.d.ts.map +1 -1
  26. package/dist/implementation/refs.d.ts +3 -0
  27. package/dist/implementation/refs.d.ts.map +1 -1
  28. package/dist/index.js +1 -1
  29. package/dist/testing.d.ts +1 -1
  30. package/dist/testing.d.ts.map +1 -1
  31. package/dist/testing.js +4 -2
  32. package/dist/testing.js.map +1 -1
  33. package/package.json +2 -2
  34. package/src/auth/DemoAuth.ts +3 -1
  35. package/src/auth/PassphraseAuth.ts +3 -1
  36. package/src/coValues/account.ts +43 -49
  37. package/src/coValues/coFeed.ts +74 -146
  38. package/src/coValues/coList.ts +47 -54
  39. package/src/coValues/coMap.ts +47 -54
  40. package/src/coValues/coPlainText.ts +23 -40
  41. package/src/coValues/deepLoading.ts +233 -102
  42. package/src/coValues/group.ts +44 -54
  43. package/src/coValues/inbox.ts +3 -6
  44. package/src/coValues/interfaces.ts +216 -105
  45. package/src/exports.ts +7 -1
  46. package/src/implementation/refs.ts +45 -7
  47. package/src/testing.ts +4 -1
  48. package/src/tests/ContextManager.test.ts +20 -6
  49. package/src/tests/PassphraseAuth.test.ts +3 -1
  50. package/src/tests/account.test.ts +26 -2
  51. package/src/tests/coFeed.test.ts +26 -19
  52. package/src/tests/coList.test.ts +18 -18
  53. package/src/tests/coMap.test.ts +67 -19
  54. package/src/tests/coPlainText.test.ts +8 -4
  55. package/src/tests/coRichText.test.ts +10 -8
  56. package/src/tests/deepLoading.test.ts +321 -80
  57. package/src/tests/groupsAndAccounts.test.ts +10 -12
  58. package/src/tests/inbox.test.ts +1 -1
  59. package/src/tests/schemaUnion.test.ts +8 -18
  60. package/src/tests/subscribe.test.ts +52 -33
  61. package/src/tests/testing.test.ts +1 -1
  62. package/dist/chunk-HH3Z4JSB.js.map +0 -1
@@ -6,7 +6,6 @@ import type {
6
6
  import { RawAccount } from "cojson";
7
7
  import { activeAccountContext } from "../implementation/activeAccountContext.js";
8
8
  import { AnonymousJazzAgent } from "../implementation/anonymousJazzAgent.js";
9
- import type { DeeplyLoaded, DepthsIn } from "../internal.js";
10
9
  import {
11
10
  Ref,
12
11
  SubscriptionScope,
@@ -15,7 +14,12 @@ import {
15
14
  } from "../internal.js";
16
15
  import { coValuesCache } from "../lib/cache.js";
17
16
  import { type Account } from "./account.js";
18
- import { fulfillsDepth } from "./deepLoading.js";
17
+ import {
18
+ RefsToResolve,
19
+ RefsToResolveStrict,
20
+ Resolved,
21
+ fulfillsDepth,
22
+ } from "./deepLoading.js";
19
23
  import { type Group } from "./group.js";
20
24
  import { RegisteredSchemas } from "./registeredSchemas.js";
21
25
 
@@ -155,56 +159,70 @@ export class CoValueBase implements CoValue {
155
159
  }
156
160
  }
157
161
 
158
- export function loadCoValueWithoutMe<V extends CoValue, Depth>(
162
+ export function loadCoValueWithoutMe<
163
+ V extends CoValue,
164
+ const R extends RefsToResolve<V>,
165
+ >(
159
166
  cls: CoValueClass<V>,
160
167
  id: ID<CoValue>,
161
- asOrDepth: Account | AnonymousJazzAgent | (Depth & DepthsIn<V>),
162
- depth?: Depth & DepthsIn<V>,
163
- ): Promise<DeeplyLoaded<V, Depth> | undefined> {
164
- if (isAccountInstance(asOrDepth) || isAnonymousAgentInstance(asOrDepth)) {
165
- if (!depth) {
166
- throw new Error(
167
- "Depth is required when loading a CoValue as an Account or AnonymousJazzAgent",
168
- );
169
- }
170
- return loadCoValue(cls, id, asOrDepth, depth);
171
- }
172
-
173
- return loadCoValue(cls, id, activeAccountContext.get(), asOrDepth);
168
+ options?: {
169
+ resolve?: RefsToResolveStrict<V, R>;
170
+ loadAs?: Account | AnonymousJazzAgent;
171
+ },
172
+ ): Promise<Resolved<V, R> | null> {
173
+ return loadCoValue(cls, id, {
174
+ ...options,
175
+ loadAs: options?.loadAs ?? activeAccountContext.get(),
176
+ });
174
177
  }
175
178
 
176
- export function loadCoValue<V extends CoValue, Depth>(
179
+ export function loadCoValue<
180
+ V extends CoValue,
181
+ const R extends RefsToResolve<V>,
182
+ >(
177
183
  cls: CoValueClass<V>,
178
184
  id: ID<CoValue>,
179
- as: Account | AnonymousJazzAgent,
180
- depth: Depth & DepthsIn<V>,
181
- ): Promise<DeeplyLoaded<V, Depth> | undefined> {
185
+ options: {
186
+ resolve?: RefsToResolveStrict<V, R>;
187
+ loadAs: Account | AnonymousJazzAgent;
188
+ },
189
+ ): Promise<Resolved<V, R> | null> {
182
190
  return new Promise((resolve) => {
183
- subscribeToCoValue(
191
+ subscribeToCoValue<V, R>(
184
192
  cls,
185
193
  id,
186
- as,
187
- depth,
194
+ {
195
+ resolve: options.resolve,
196
+ loadAs: options.loadAs,
197
+ onUnavailable: () => {
198
+ resolve(null);
199
+ },
200
+ onUnauthorized: () => {
201
+ resolve(null);
202
+ },
203
+ },
188
204
  (value, unsubscribe) => {
189
205
  resolve(value);
190
206
  unsubscribe();
191
207
  },
192
- () => {
193
- resolve(undefined);
194
- },
195
208
  );
196
209
  });
197
210
  }
198
211
 
199
- export async function ensureCoValueLoaded<V extends CoValue, Depth>(
212
+ export async function ensureCoValueLoaded<
213
+ V extends CoValue,
214
+ const R extends RefsToResolve<V>,
215
+ >(
200
216
  existing: V,
201
- depth: Depth & DepthsIn<V>,
202
- ): Promise<DeeplyLoaded<V, Depth>> {
217
+ options?: { resolve?: RefsToResolveStrict<V, R> } | undefined,
218
+ ): Promise<Resolved<V, R>> {
203
219
  const response = await loadCoValue(
204
220
  existing.constructor as CoValueClass<V>,
205
221
  existing.id,
206
- existing._loadedAs,
207
- depth,
222
+ {
223
+ loadAs: existing._loadedAs,
224
+ resolve: options?.resolve,
225
+ },
208
226
  );
209
227
 
210
228
  if (!response) {
@@ -214,81 +232,146 @@ export async function ensureCoValueLoaded<V extends CoValue, Depth>(
214
232
  return response;
215
233
  }
216
234
 
217
- export function subscribeToCoValueWithoutMe<V extends CoValue, Depth>(
218
- cls: CoValueClass<V>,
219
- id: ID<CoValue>,
220
- asOrDepth: Account | AnonymousJazzAgent | (Depth & DepthsIn<V>),
221
- depthOrListener:
222
- | (Depth & DepthsIn<V>)
223
- | ((value: DeeplyLoaded<V, Depth>) => void),
224
- listener?: (value: DeeplyLoaded<V, Depth>) => void,
225
- ) {
226
- if (isAccountInstance(asOrDepth) || isAnonymousAgentInstance(asOrDepth)) {
227
- if (typeof depthOrListener !== "function") {
228
- return subscribeToCoValue<V, Depth>(
229
- cls,
230
- id,
231
- asOrDepth,
232
- depthOrListener,
233
- listener!,
234
- );
235
+ type SubscribeListener<V extends CoValue, R extends RefsToResolve<V>> = (
236
+ value: Resolved<V, R>,
237
+ unsubscribe: () => void,
238
+ ) => void;
239
+
240
+ export type SubscribeListenerOptions<
241
+ V extends CoValue,
242
+ R extends RefsToResolve<V>,
243
+ > = {
244
+ resolve?: RefsToResolveStrict<V, R>;
245
+ loadAs?: Account | AnonymousJazzAgent;
246
+ onUnauthorized?: () => void;
247
+ onUnavailable?: () => void;
248
+ };
249
+
250
+ export type SubscribeRestArgs<V extends CoValue, R extends RefsToResolve<V>> =
251
+ | [options: SubscribeListenerOptions<V, R>, listener: SubscribeListener<V, R>]
252
+ | [listener: SubscribeListener<V, R>];
253
+
254
+ export function parseSubscribeRestArgs<
255
+ V extends CoValue,
256
+ R extends RefsToResolve<V>,
257
+ >(
258
+ args: SubscribeRestArgs<V, R>,
259
+ ): {
260
+ options: SubscribeListenerOptions<V, R>;
261
+ listener: SubscribeListener<V, R>;
262
+ } {
263
+ if (args.length === 2) {
264
+ if (
265
+ typeof args[0] === "object" &&
266
+ args[0] &&
267
+ typeof args[1] === "function"
268
+ ) {
269
+ return {
270
+ options: {
271
+ resolve: args[0].resolve,
272
+ loadAs: args[0].loadAs,
273
+ onUnauthorized: args[0].onUnauthorized,
274
+ onUnavailable: args[0].onUnavailable,
275
+ },
276
+ listener: args[1],
277
+ };
278
+ } else {
279
+ throw new Error("Invalid arguments");
280
+ }
281
+ } else {
282
+ if (typeof args[0] === "function") {
283
+ return { options: {}, listener: args[0] };
284
+ } else {
285
+ throw new Error("Invalid arguments");
235
286
  }
236
- throw new Error("Invalid arguments");
237
- }
238
-
239
- if (typeof depthOrListener !== "function") {
240
- throw new Error("Invalid arguments");
241
287
  }
288
+ }
242
289
 
243
- return subscribeToCoValue<V, Depth>(
290
+ export function subscribeToCoValueWithoutMe<
291
+ V extends CoValue,
292
+ const R extends RefsToResolve<V>,
293
+ >(
294
+ cls: CoValueClass<V>,
295
+ id: ID<CoValue>,
296
+ options: SubscribeListenerOptions<V, R>,
297
+ listener: SubscribeListener<V, R>,
298
+ ) {
299
+ return subscribeToCoValue(
244
300
  cls,
245
301
  id,
246
- activeAccountContext.get(),
247
- asOrDepth,
248
- depthOrListener,
302
+ {
303
+ ...options,
304
+ loadAs: options.loadAs ?? activeAccountContext.get(),
305
+ },
306
+ listener,
249
307
  );
250
308
  }
251
309
 
252
- export function subscribeToCoValue<V extends CoValue, Depth>(
310
+ export function subscribeToCoValue<
311
+ V extends CoValue,
312
+ const R extends RefsToResolve<V>,
313
+ >(
253
314
  cls: CoValueClass<V>,
254
315
  id: ID<CoValue>,
255
- as: Account | AnonymousJazzAgent,
256
- depth: Depth & DepthsIn<V>,
257
- listener: (value: DeeplyLoaded<V, Depth>, unsubscribe: () => void) => void,
258
- onUnavailable?: () => void,
259
- syncResolution?: boolean,
316
+ options: {
317
+ resolve?: RefsToResolveStrict<V, R>;
318
+ loadAs: Account | AnonymousJazzAgent;
319
+ onUnavailable?: () => void;
320
+ onUnauthorized?: () => void;
321
+ syncResolution?: boolean;
322
+ },
323
+ listener: SubscribeListener<V, R>,
260
324
  ): () => void {
261
- const ref = new Ref(id, as, { ref: cls, optional: false });
325
+ const ref = new Ref(id, options.loadAs, { ref: cls, optional: false });
262
326
 
263
327
  let unsubscribed = false;
264
328
  let unsubscribe: (() => void) | undefined;
265
329
 
266
- function subscribe(value: CoValue | undefined) {
330
+ function subscribe() {
331
+ const value = ref.getValueWithoutAccessCheck();
332
+
267
333
  if (!value) {
268
- onUnavailable && onUnavailable();
334
+ options.onUnavailable?.();
269
335
  return;
270
336
  }
337
+
271
338
  if (unsubscribed) return;
272
339
 
273
340
  const subscription = new SubscriptionScope(
274
341
  value,
275
342
  cls as CoValueClass<V> & CoValueFromRaw<V>,
276
343
  (update, subscription) => {
277
- // fullfillsDepth may trigger a syncronous update while accessing values
278
- // we want to discard those to avoid invalid updates
279
- if (subscription.syncResolution) return false;
280
-
281
- // Enabling syncResolution during fullfillsDepth access to block any
282
- // unnecessery update triggers related to in-memory values
283
- subscription.syncResolution = true;
284
- const isLoaded = fulfillsDepth(depth, update);
285
- subscription.syncResolution = false;
286
-
287
- if (isLoaded) {
288
- listener(
289
- update as DeeplyLoaded<V, Depth>,
290
- subscription.unsubscribeAll,
344
+ if (subscription.syncResolution) return;
345
+
346
+ if (!ref.hasReadAccess()) {
347
+ options.onUnauthorized?.();
348
+ return;
349
+ }
350
+
351
+ let result;
352
+
353
+ try {
354
+ subscription.syncResolution = true;
355
+ result = fulfillsDepth(options.resolve, update);
356
+ } catch (e) {
357
+ console.error(
358
+ "Failed to load / subscribe to CoValue",
359
+ e,
360
+ e instanceof Error ? e.stack : undefined,
291
361
  );
362
+ options.onUnavailable?.();
363
+ return;
364
+ } finally {
365
+ subscription.syncResolution = false;
366
+ }
367
+
368
+ if (result === "unauthorized") {
369
+ options.onUnauthorized?.();
370
+ return;
371
+ }
372
+
373
+ if (result === "fulfilled") {
374
+ listener(update as Resolved<V, R>, subscription.unsubscribeAll);
292
375
  }
293
376
  },
294
377
  );
@@ -296,17 +379,21 @@ export function subscribeToCoValue<V extends CoValue, Depth>(
296
379
  unsubscribe = subscription.unsubscribeAll;
297
380
  }
298
381
 
299
- const sync = syncResolution ? ref.syncLoad() : undefined;
382
+ const sync = options.syncResolution ? ref.syncLoad() : undefined;
300
383
 
301
384
  if (sync) {
302
- subscribe(sync);
385
+ subscribe();
303
386
  } else {
304
387
  ref
305
388
  .load()
306
- .then((value) => subscribe(value))
389
+ .then(() => subscribe())
307
390
  .catch((e) => {
308
- console.error("Failed to load / subscribe to CoValue", e);
309
- onUnavailable?.();
391
+ console.error(
392
+ "Failed to load / subscribe to CoValue",
393
+ e,
394
+ e instanceof Error ? e.stack : undefined,
395
+ );
396
+ options.onUnavailable?.();
310
397
  });
311
398
  }
312
399
 
@@ -316,36 +403,47 @@ export function subscribeToCoValue<V extends CoValue, Depth>(
316
403
  };
317
404
  }
318
405
 
319
- export function createCoValueObservable<V extends CoValue, Depth>(options?: {
320
- syncResolution?: boolean;
321
- }) {
322
- let currentValue: DeeplyLoaded<V, Depth> | undefined | null = undefined;
406
+ export function createCoValueObservable<
407
+ V extends CoValue,
408
+ const R extends RefsToResolve<V>,
409
+ >() {
410
+ let currentValue: Resolved<V, R> | undefined | null = undefined;
323
411
  let subscriberCount = 0;
324
412
 
325
413
  function subscribe(
326
414
  cls: CoValueClass<V>,
327
415
  id: ID<CoValue>,
328
- as: Account | AnonymousJazzAgent,
329
- depth: Depth & DepthsIn<V>,
416
+ options: {
417
+ loadAs: Account | AnonymousJazzAgent;
418
+ resolve?: RefsToResolveStrict<V, R>;
419
+ onUnavailable?: () => void;
420
+ onUnauthorized?: () => void;
421
+ syncResolution?: boolean;
422
+ },
330
423
  listener: () => void,
331
- onUnavailable?: () => void,
332
424
  ) {
333
425
  subscriberCount++;
334
426
 
335
427
  const unsubscribe = subscribeToCoValue(
336
428
  cls,
337
429
  id,
338
- as,
339
- depth,
430
+ {
431
+ loadAs: options.loadAs,
432
+ resolve: options.resolve,
433
+ onUnavailable: () => {
434
+ currentValue = null;
435
+ options.onUnavailable?.();
436
+ },
437
+ onUnauthorized: () => {
438
+ currentValue = null;
439
+ options.onUnauthorized?.();
440
+ },
441
+ syncResolution: options.syncResolution,
442
+ },
340
443
  (value) => {
341
444
  currentValue = value;
342
445
  listener();
343
446
  },
344
- () => {
345
- currentValue = null;
346
- onUnavailable?.();
347
- },
348
- options?.syncResolution,
349
447
  );
350
448
 
351
449
  return () => {
@@ -365,16 +463,29 @@ export function createCoValueObservable<V extends CoValue, Depth>(options?: {
365
463
  return observable;
366
464
  }
367
465
 
368
- export function subscribeToExistingCoValue<V extends CoValue, Depth>(
466
+ export function subscribeToExistingCoValue<
467
+ V extends CoValue,
468
+ const R extends RefsToResolve<V>,
469
+ >(
369
470
  existing: V,
370
- depth: Depth & DepthsIn<V>,
371
- listener: (value: DeeplyLoaded<V, Depth>) => void,
471
+ options:
472
+ | {
473
+ resolve?: RefsToResolveStrict<V, R>;
474
+ onUnavailable?: () => void;
475
+ onUnauthorized?: () => void;
476
+ }
477
+ | undefined,
478
+ listener: SubscribeListener<V, R>,
372
479
  ): () => void {
373
480
  return subscribeToCoValue(
374
481
  existing.constructor as CoValueClass<V>,
375
482
  existing.id,
376
- existing._loadedAs,
377
- depth,
483
+ {
484
+ loadAs: existing._loadedAs,
485
+ resolve: options?.resolve,
486
+ onUnavailable: options?.onUnavailable,
487
+ onUnauthorized: options?.onUnauthorized,
488
+ },
378
489
  listener,
379
490
  );
380
491
  }
package/src/exports.ts CHANGED
@@ -43,7 +43,13 @@ export { CoValueBase } from "./coValues/interfaces.js";
43
43
  export { Profile } from "./coValues/profile.js";
44
44
  export { SchemaUnion } from "./coValues/schemaUnion.js";
45
45
 
46
- export type { CoValueClass, DeeplyLoaded, DepthsIn } from "./internal.js";
46
+ export type {
47
+ CoValueClass,
48
+ DeeplyLoaded,
49
+ Resolved,
50
+ RefsToResolve,
51
+ RefsToResolveStrict,
52
+ } from "./internal.js";
47
53
 
48
54
  export {
49
55
  createCoValueObservable,
@@ -1,4 +1,4 @@
1
- import type { CoID, RawCoValue } from "cojson";
1
+ import { type CoID, RawAccount, type RawCoValue, RawGroup } from "cojson";
2
2
  import { type Account } from "../coValues/account.js";
3
3
  import type {
4
4
  AnonymousJazzAgent,
@@ -27,12 +27,42 @@ export class Ref<out V extends CoValue> {
27
27
  }
28
28
  }
29
29
 
30
- get value() {
31
- const node =
32
- "node" in this.controlledAccount
33
- ? this.controlledAccount.node
34
- : this.controlledAccount._raw.core.node;
30
+ private getNode() {
31
+ return "node" in this.controlledAccount
32
+ ? this.controlledAccount.node
33
+ : this.controlledAccount._raw.core.node;
34
+ }
35
+
36
+ hasReadAccess() {
37
+ const node = this.getNode();
38
+
35
39
  const raw = node.getLoaded(this.id as unknown as CoID<RawCoValue>);
40
+
41
+ if (!raw) {
42
+ return true;
43
+ }
44
+
45
+ if (raw instanceof RawAccount || raw instanceof RawGroup) {
46
+ return true;
47
+ }
48
+
49
+ const group = raw.core.getGroup();
50
+
51
+ if (group instanceof RawAccount) {
52
+ if (node.account.id !== group.id) {
53
+ return false;
54
+ }
55
+ } else if (group.myRole() === undefined) {
56
+ return false;
57
+ }
58
+
59
+ return true;
60
+ }
61
+
62
+ getValueWithoutAccessCheck() {
63
+ const node = this.getNode();
64
+ const raw = node.getLoaded(this.id as unknown as CoID<RawCoValue>);
65
+
36
66
  if (raw) {
37
67
  return coValuesCache.get(raw, () =>
38
68
  instantiateRefEncoded(this.schema, raw),
@@ -42,6 +72,14 @@ export class Ref<out V extends CoValue> {
42
72
  }
43
73
  }
44
74
 
75
+ get value() {
76
+ if (!this.hasReadAccess()) {
77
+ return null;
78
+ }
79
+
80
+ return this.getValueWithoutAccessCheck();
81
+ }
82
+
45
83
  private async loadHelper(): Promise<V | "unavailable"> {
46
84
  const node =
47
85
  "node" in this.controlledAccount
@@ -100,7 +138,7 @@ export class Ref<out V extends CoValue> {
100
138
  } else if (this.value !== null) {
101
139
  const freshValueInstance = instantiateRefEncoded(
102
140
  this.schema,
103
- this.value?._raw,
141
+ this.value._raw,
104
142
  );
105
143
  TRACE_ACCESSES && console.log("freshValueInstance", freshValueInstance);
106
144
  subScope.cachedValues[this.id] = freshValueInstance;
package/src/testing.ts CHANGED
@@ -271,7 +271,7 @@ export class TestJazzContextManager<
271
271
  }
272
272
  }
273
273
 
274
- export function linkAccounts(
274
+ export async function linkAccounts(
275
275
  a: Account,
276
276
  b: Account,
277
277
  aRole: "server" | "client" = "server",
@@ -284,6 +284,9 @@ export function linkAccounts(
284
284
 
285
285
  a._raw.core.node.syncManager.addPeer(aPeer);
286
286
  b._raw.core.node.syncManager.addPeer(bPeer);
287
+
288
+ await a.waitForAllCoValuesSync();
289
+ await b.waitForAllCoValuesSync();
287
290
  }
288
291
 
289
292
  export async function setupJazzTestSync() {
@@ -247,7 +247,9 @@ describe("ContextManager", () => {
247
247
  provider: "test",
248
248
  });
249
249
 
250
- const me = await CustomAccount.getMe().ensureLoaded({ root: {} });
250
+ const me = await CustomAccount.getMe().ensureLoaded({
251
+ resolve: { root: true },
252
+ });
251
253
 
252
254
  expect(me.root.id).toBe(lastRootId);
253
255
  });
@@ -266,7 +268,7 @@ describe("ContextManager", () => {
266
268
  value: 1,
267
269
  });
268
270
  } else {
269
- const { root } = await this.ensureLoaded({ root: {} });
271
+ const { root } = await this.ensureLoaded({ resolve: { root: true } });
270
272
 
271
273
  root.value = 2;
272
274
  }
@@ -289,7 +291,9 @@ describe("ContextManager", () => {
289
291
  provider: "test",
290
292
  });
291
293
 
292
- const me = await CustomAccount.getMe().ensureLoaded({ root: {} });
294
+ const me = await CustomAccount.getMe().ensureLoaded({
295
+ resolve: { root: true },
296
+ });
293
297
 
294
298
  expect(me.root.value).toBe(2);
295
299
  });
@@ -316,10 +320,16 @@ describe("ContextManager", () => {
316
320
  anonymousAccount: CustomAccount,
317
321
  ) => {
318
322
  const anonymousAccountWithRoot = await anonymousAccount.ensureLoaded({
319
- root: {},
323
+ resolve: {
324
+ root: true,
325
+ },
320
326
  });
321
327
 
322
- const meWithRoot = await CustomAccount.getMe().ensureLoaded({ root: {} });
328
+ const meWithRoot = await CustomAccount.getMe().ensureLoaded({
329
+ resolve: {
330
+ root: true,
331
+ },
332
+ });
323
333
 
324
334
  const rootToTransfer = anonymousAccountWithRoot.root;
325
335
 
@@ -347,7 +357,11 @@ describe("ContextManager", () => {
347
357
  provider: "test",
348
358
  });
349
359
 
350
- const me = await CustomAccount.getMe().ensureLoaded({ root: {} });
360
+ const me = await CustomAccount.getMe().ensureLoaded({
361
+ resolve: {
362
+ root: true,
363
+ },
364
+ });
351
365
 
352
366
  expect(me.root.transferredRoot?.value).toBe("Hello");
353
367
  });
@@ -152,7 +152,9 @@ describe("PassphraseAuth", () => {
152
152
 
153
153
  // Verify the account name was set
154
154
  const { profile } = await account.ensureLoaded({
155
- profile: {},
155
+ resolve: {
156
+ profile: true,
157
+ },
156
158
  });
157
159
  expect(profile.name).toBe(testName);
158
160
 
@@ -1,6 +1,10 @@
1
1
  import { expect, test } from "vitest";
2
- import { Account, CoMap, co } from "../exports.js";
3
- import { createJazzTestAccount, setActiveAccount } from "../testing.js";
2
+ import { Account, CoMap, Group, co } from "../exports.js";
3
+ import {
4
+ createJazzTestAccount,
5
+ linkAccounts,
6
+ setActiveAccount,
7
+ } from "../testing.js";
4
8
  import { setupTwoNodes } from "./utils.js";
5
9
 
6
10
  test("waitForAllCoValuesSync should resolve when all the values are synced", async () => {
@@ -74,3 +78,23 @@ test("Me gets updated correctly when creating a new account as active", async ()
74
78
  expect(newMe.isMe).toBe(true);
75
79
  expect(oldMe.isMe).toBe(false);
76
80
  });
81
+
82
+ test("accounts should sync correctly", async () => {
83
+ const account = await createJazzTestAccount({ isCurrentActiveAccount: true });
84
+ account.profile!.name = "test 1";
85
+ const otherAccount = await createJazzTestAccount({
86
+ isCurrentActiveAccount: true,
87
+ });
88
+ otherAccount.profile!.name = "test 2";
89
+
90
+ await linkAccounts(account, otherAccount);
91
+
92
+ const group = Group.create({ owner: account });
93
+
94
+ group.addMember(otherAccount, "writer");
95
+
96
+ const { members } = group;
97
+
98
+ expect(members[0]?.account.profile!.name).toBe("test 1");
99
+ expect(members[1]?.account.profile!.name).toBe("test 2");
100
+ });