jazz-tools 0.19.5 → 0.19.7

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 (54) hide show
  1. package/.turbo/turbo-build.log +56 -56
  2. package/CHANGELOG.md +24 -0
  3. package/dist/{chunk-DFFRRRRF.js → chunk-CUS6O5NE.js} +73 -19
  4. package/dist/chunk-CUS6O5NE.js.map +1 -0
  5. package/dist/index.js +1 -1
  6. package/dist/inspector/index.d.ts +1 -1
  7. package/dist/inspector/index.d.ts.map +1 -1
  8. package/dist/inspector/index.js +8 -1
  9. package/dist/inspector/index.js.map +1 -1
  10. package/dist/react-core/hooks.d.ts +2 -1
  11. package/dist/react-core/hooks.d.ts.map +1 -1
  12. package/dist/react-core/index.js +39 -15
  13. package/dist/react-core/index.js.map +1 -1
  14. package/dist/react-native-core/crypto/RNQuickCrypto.d.ts +3 -1
  15. package/dist/react-native-core/crypto/RNQuickCrypto.d.ts.map +1 -1
  16. package/dist/react-native-core/crypto.js +23 -1
  17. package/dist/react-native-core/crypto.js.map +1 -1
  18. package/dist/testing.js +1 -1
  19. package/dist/tools/coValues/CoValueBase.d.ts +2 -1
  20. package/dist/tools/coValues/CoValueBase.d.ts.map +1 -1
  21. package/dist/tools/coValues/account.d.ts +3 -2
  22. package/dist/tools/coValues/account.d.ts.map +1 -1
  23. package/dist/tools/coValues/interfaces.d.ts +8 -0
  24. package/dist/tools/coValues/interfaces.d.ts.map +1 -1
  25. package/dist/tools/exports.d.ts +1 -1
  26. package/dist/tools/exports.d.ts.map +1 -1
  27. package/dist/tools/implementation/anonymousJazzAgent.d.ts +5 -0
  28. package/dist/tools/implementation/anonymousJazzAgent.d.ts.map +1 -1
  29. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts +3 -3
  30. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -1
  31. package/dist/tools/implementation/zodSchema/zodCo.d.ts.map +1 -1
  32. package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
  33. package/dist/tools/testing.d.ts.map +1 -1
  34. package/dist/tools/tests/utils.d.ts +6 -1
  35. package/dist/tools/tests/utils.d.ts.map +1 -1
  36. package/package.json +5 -5
  37. package/src/inspector/index.tsx +10 -1
  38. package/src/react-core/hooks.ts +65 -21
  39. package/src/react-core/tests/useCoState.test.ts +102 -2
  40. package/src/react-native-core/crypto/RNQuickCrypto.ts +32 -2
  41. package/src/tools/coValues/CoValueBase.ts +11 -1
  42. package/src/tools/coValues/account.ts +30 -6
  43. package/src/tools/coValues/interfaces.ts +25 -1
  44. package/src/tools/exports.ts +1 -0
  45. package/src/tools/implementation/anonymousJazzAgent.ts +21 -1
  46. package/src/tools/implementation/zodSchema/schemaTypes/AccountSchema.ts +9 -4
  47. package/src/tools/subscribe/SubscriptionScope.ts +16 -9
  48. package/src/tools/tests/account.test.ts +65 -0
  49. package/src/tools/tests/coDiscriminatedUnion.test.ts +69 -2
  50. package/src/tools/tests/exportImport.test.ts +78 -0
  51. package/src/tools/tests/groupsAndAccounts.test.ts +21 -20
  52. package/src/tools/tests/schema.resolved.test.ts +26 -19
  53. package/src/tools/tests/utils.ts +27 -0
  54. package/dist/chunk-DFFRRRRF.js.map +0 -1
@@ -93,15 +93,20 @@ export class AccountSchema<
93
93
  );
94
94
  }
95
95
 
96
- /** @internal */
96
+ // Create an account via worker, useful to generate controlled accounts from the server
97
97
  createAs(
98
- as: Account,
98
+ worker: Account,
99
99
  options: {
100
100
  creationProps: { name: string };
101
+ onCreate?: (
102
+ account: AccountInstance<Shape>,
103
+ worker: Account,
104
+ ) => Promise<void>;
101
105
  },
102
- ): Promise<AccountInstance<Shape>> {
106
+ // @ts-expect-error we can't statically enforce the schema's resolve query is a valid resolve query, but in practice it is
107
+ ): Promise<Loaded<AccountSchema<Shape>, DefaultResolveQuery>> {
103
108
  // @ts-expect-error
104
- return this.coValueClass.createAs(as, options);
109
+ return this.coValueClass.createAs(worker, options);
105
110
  }
106
111
 
107
112
  unstable_merge<
@@ -91,7 +91,11 @@ export class SubscriptionScope<D extends CoValue> {
91
91
  // - Run the migration only once
92
92
  // - Skip all the updates until the migration is done
93
93
  // - Trigger handleUpdate only with the final value
94
- if (!this.migrated && value !== CoValueLoadingState.UNAVAILABLE) {
94
+ if (
95
+ !this.migrated &&
96
+ value !== CoValueLoadingState.UNAVAILABLE &&
97
+ hasAccessToCoValue(value)
98
+ ) {
95
99
  if (this.migrating) {
96
100
  return;
97
101
  }
@@ -139,14 +143,7 @@ export class SubscriptionScope<D extends CoValue> {
139
143
  return;
140
144
  }
141
145
 
142
- const ruleset = update.core.verified.header.ruleset;
143
-
144
- // Groups and accounts are accessible by everyone, for the other coValues we use the role to check access
145
- const hasAccess =
146
- ruleset.type !== "ownedByGroup" ||
147
- myRoleForRawValue(update) !== undefined;
148
-
149
- if (!hasAccess) {
146
+ if (!hasAccessToCoValue(update)) {
150
147
  if (this.value.type !== CoValueLoadingState.UNAUTHORIZED) {
151
148
  this.updateValue(
152
149
  new JazzError(this.id, CoValueLoadingState.UNAUTHORIZED, [
@@ -759,3 +756,13 @@ export class SubscriptionScope<D extends CoValue> {
759
756
  this.childNodes.forEach((child) => child.destroy());
760
757
  }
761
758
  }
759
+
760
+ function hasAccessToCoValue(rawCoValue: RawCoValue): boolean {
761
+ const ruleset = rawCoValue.core.verified.header.ruleset;
762
+
763
+ // Groups and accounts are accessible by everyone, for the other coValues we use the role to check access
764
+ return (
765
+ ruleset.type !== "ownedByGroup" ||
766
+ myRoleForRawValue(rawCoValue) !== undefined
767
+ );
768
+ }
@@ -435,3 +435,68 @@ describe("accepting invites", () => {
435
435
  expect(group.getRoleOf(newAccount.$jazz.id)).toBe("reader");
436
436
  });
437
437
  });
438
+
439
+ describe("createAs", () => {
440
+ test("migration is executed before onCreate and onCreate can set root from worker", async () => {
441
+ const executionOrder: string[] = [];
442
+
443
+ const CustomRoot = co.map({
444
+ value: z.string(),
445
+ });
446
+
447
+ const CustomAccount = co
448
+ .account({
449
+ profile: co.profile({
450
+ name: z.string(),
451
+ }),
452
+ root: CustomRoot,
453
+ })
454
+ .withMigration((me) => {
455
+ executionOrder.push("migration");
456
+ if (me.root === undefined) {
457
+ me.$jazz.set("root", { value: "migration-set" });
458
+ }
459
+ });
460
+
461
+ const worker = await createJazzTestAccount({
462
+ isCurrentActiveAccount: true,
463
+ });
464
+
465
+ const workerRoot = CustomRoot.create(
466
+ { value: "worker-root" },
467
+ { owner: worker },
468
+ );
469
+
470
+ const createdAccount = await CustomAccount.createAs(worker, {
471
+ creationProps: { name: "Test Account" },
472
+ onCreate: async (account, loadedWorker) => {
473
+ executionOrder.push("onCreate");
474
+
475
+ // Verify migration ran before onCreate
476
+ expect(executionOrder).toEqual(["migration", "onCreate"]);
477
+
478
+ // Verify migration set the root
479
+ assertLoaded(account.root);
480
+ expect(account.root.value).toBe("migration-set");
481
+
482
+ // It should be possible to add the worker as a member of the root
483
+ account.root.$jazz.owner.addMember(loadedWorker, "writer");
484
+ expect(account.root.$jazz.owner.getRoleOf(loadedWorker.$jazz.id)).toBe(
485
+ "writer",
486
+ );
487
+
488
+ // Set root from worker in onCreate
489
+ account.$jazz.set("root", workerRoot);
490
+ },
491
+ });
492
+
493
+ assertLoaded(createdAccount);
494
+ assertLoaded(createdAccount.root);
495
+
496
+ // Verify onCreate was called and root was set from worker
497
+ expect(createdAccount.root.value).toBe("worker-root");
498
+
499
+ // Verify execution order
500
+ expect(executionOrder).toEqual(["migration", "onCreate"]);
501
+ });
502
+ });
@@ -1,5 +1,13 @@
1
- import { beforeEach, describe, expect, test, vi } from "vitest";
2
- import { CoPlainText, Group, Loaded, co, loadCoValue, z } from "../exports.js";
1
+ import { assert, beforeEach, describe, expect, test, vi } from "vitest";
2
+ import {
3
+ CoPlainText,
4
+ CoValueLoadingState,
5
+ Group,
6
+ Loaded,
7
+ co,
8
+ loadCoValue,
9
+ z,
10
+ } from "../exports.js";
3
11
  import { createJazzTestAccount, setupJazzTestSync } from "../testing.js";
4
12
  import { assertLoaded, waitFor } from "./utils.js";
5
13
  import type { Account } from "jazz-tools";
@@ -713,4 +721,63 @@ describe("co.discriminatedUnion", () => {
713
721
  }
714
722
  });
715
723
  });
724
+
725
+ test("cannot create a co.discriminatedUnion member if it has no matching discriminator value", async () => {
726
+ const Dog = co.map({
727
+ type: z.literal("dog"),
728
+ name: z.string(),
729
+ });
730
+ const Cat = co.map({
731
+ type: z.literal("cat"),
732
+ name: z.string(),
733
+ });
734
+ const Parrot = co.map({
735
+ type2: z.literal("parrot"),
736
+ name: z.string(),
737
+ });
738
+ const Pet = co.discriminatedUnion("type", [Dog, Cat, Parrot]);
739
+ const Pets = co.list(Pet);
740
+
741
+ expect(() => Pets.create([{ type2: "parrot", name: "Polly" }])).toThrow(
742
+ "co.discriminatedUnion() of collaborative types with no matching discriminator value found",
743
+ );
744
+ });
745
+
746
+ test("can load a discriminated union CoList even if some elements are not accessible", async () => {
747
+ const Dog = co.map({
748
+ type: z.literal("dog"),
749
+ name: z.string(),
750
+ });
751
+ const Cat = co.map({
752
+ type: z.literal("cat"),
753
+ name: z.string(),
754
+ });
755
+ const Pet = co.discriminatedUnion("type", [Dog, Cat]);
756
+ const Pets = co.list(Pet);
757
+
758
+ const publicGroup = Group.create().makePublic();
759
+ const privateGroup = Group.create();
760
+ const pets = Pets.create(
761
+ [
762
+ Dog.create({ type: "dog", name: "Rex" }, publicGroup),
763
+ Cat.create({ type: "cat", name: "Whiskers" }, privateGroup),
764
+ ],
765
+ { owner: publicGroup },
766
+ );
767
+
768
+ const anotherAccount = await createJazzTestAccount();
769
+ const loadedPets = await Pets.load(pets.$jazz.id, {
770
+ resolve: { $each: { $onError: "catch" } },
771
+ loadAs: anotherAccount,
772
+ });
773
+
774
+ assertLoaded(loadedPets);
775
+ expect(loadedPets.length).toEqual(2);
776
+ assert(loadedPets[0]);
777
+ assertLoaded(loadedPets[0]);
778
+ expect(loadedPets[0].type).toEqual("dog");
779
+ expect(loadedPets[1]?.$jazz.loadingState).toEqual(
780
+ CoValueLoadingState.UNAUTHORIZED,
781
+ );
782
+ });
716
783
  });
@@ -5,6 +5,7 @@ import { Account, CoPlainText, Group, co, z } from "../exports.js";
5
5
  import {
6
6
  createJazzTestAccount,
7
7
  createJazzTestGuest,
8
+ disableJazzTestSync,
8
9
  setupJazzTestSync,
9
10
  } from "../testing.js";
10
11
  import { assertLoaded } from "./utils.js";
@@ -262,6 +263,83 @@ describe("exportCoValue", () => {
262
263
  });
263
264
  });
264
265
 
266
+ describe("value.$jazz.export", () => {
267
+ test("exports a CoValue returned by create", async () => {
268
+ disableJazzTestSync();
269
+
270
+ const Person = co.map({
271
+ name: z.string(),
272
+ age: z.number(),
273
+ });
274
+
275
+ const group = Group.create();
276
+ group.addMember("everyone", "reader");
277
+
278
+ const person = Person.create({ name: "Jane", age: 28 }, group);
279
+
280
+ const exported = person.$jazz.export();
281
+
282
+ expect(exported.id).toBe(person.$jazz.id);
283
+
284
+ const bob = await createJazzTestAccount();
285
+ importContentPieces(exported.contentPieces, bob);
286
+
287
+ const loadedPerson = await Person.load(person.$jazz.id, { loadAs: bob });
288
+ assertLoaded(loadedPerson);
289
+
290
+ expect(loadedPerson.name).toBe("Jane");
291
+ expect(loadedPerson.age).toBe(28);
292
+ });
293
+
294
+ test("exports a nested CoValue loaded with load", async () => {
295
+ disableJazzTestSync();
296
+
297
+ const Address = co.map({
298
+ street: z.string(),
299
+ city: z.string(),
300
+ });
301
+
302
+ const Person = co.map({
303
+ name: z.string(),
304
+ address: Address,
305
+ });
306
+
307
+ const alice = await createJazzTestAccount();
308
+
309
+ const group = Group.create(alice);
310
+ group.addMember("everyone", "reader");
311
+
312
+ const address = Address.create(
313
+ { street: "123 Main St", city: "New York" },
314
+ group,
315
+ );
316
+ const person = Person.create({ name: "John", address }, group);
317
+
318
+ const loadedPerson = await Person.load(person.$jazz.id, {
319
+ resolve: { address: true },
320
+ loadAs: alice,
321
+ });
322
+
323
+ assertLoaded(loadedPerson);
324
+ assertLoaded(loadedPerson.address);
325
+
326
+ const exported = loadedPerson.$jazz.export();
327
+
328
+ const bob = await createJazzTestAccount();
329
+
330
+ importContentPieces(exported.contentPieces, bob);
331
+
332
+ const importedPerson = await Person.load(person.$jazz.id, {
333
+ resolve: { address: true },
334
+ loadAs: bob,
335
+ });
336
+
337
+ assertLoaded(importedPerson);
338
+ expect(importedPerson.address.street).toBe("123 Main St");
339
+ expect(importedPerson.address.city).toBe("New York");
340
+ });
341
+ });
342
+
265
343
  describe("importContentPieces", () => {
266
344
  test("imports content pieces successfully", async () => {
267
345
  const Person = co.map({
@@ -12,6 +12,7 @@ import {
12
12
  import { createJazzTestAccount, setupJazzTestSync } from "../testing.js";
13
13
  import {
14
14
  assertLoaded,
15
+ createAccountAs,
15
16
  loadCoValueOrFail,
16
17
  setupTwoNodes,
17
18
  waitFor,
@@ -100,7 +101,7 @@ describe("Group inheritance", () => {
100
101
 
101
102
  group.addMember(parentGroup);
102
103
 
103
- const reader = await co.account().createAs(me, {
104
+ const reader = await createAccountAs(co.account(), me, {
104
105
  creationProps: { name: "Reader" },
105
106
  });
106
107
 
@@ -141,7 +142,7 @@ describe("Group inheritance", () => {
141
142
  group.addMember(parentGroup);
142
143
  parentGroup.addMember(grandParentGroup);
143
144
 
144
- const reader = await co.account().createAs(me, {
145
+ const reader = await createAccountAs(co.account(), me, {
145
146
  creationProps: { name: "Reader" },
146
147
  });
147
148
 
@@ -359,7 +360,7 @@ describe("Group inheritance", () => {
359
360
 
360
361
  test("nested CoValues inherit permissions from the referencing CoValue", async () => {
361
362
  const me = co.account().getMe();
362
- const reader = await co.account().createAs(me, {
363
+ const reader = await createAccountAs(co.account(), me, {
363
364
  creationProps: { name: "Reader" },
364
365
  });
365
366
 
@@ -504,16 +505,16 @@ describe("Account permissions", () => {
504
505
  const group = Group.create({ owner: admin });
505
506
  const testObject = CoMap.create({}, { owner: group });
506
507
 
507
- const manager = await co.account().createAs(admin, {
508
+ const manager = await createAccountAs(co.account(), admin, {
508
509
  creationProps: { name: "Manager" },
509
510
  });
510
- const writer = await co.account().createAs(admin, {
511
+ const writer = await createAccountAs(co.account(), admin, {
511
512
  creationProps: { name: "Writer" },
512
513
  });
513
- const reader = await co.account().createAs(admin, {
514
+ const reader = await createAccountAs(co.account(), admin, {
514
515
  creationProps: { name: "Reader" },
515
516
  });
516
- const writeOnly = await co.account().createAs(admin, {
517
+ const writeOnly = await createAccountAs(co.account(), admin, {
517
518
  creationProps: { name: "WriteOnly" },
518
519
  });
519
520
 
@@ -541,16 +542,16 @@ describe("Account permissions", () => {
541
542
  const group = Group.create({ owner: admin });
542
543
  const testObject = CoMap.create({}, { owner: group });
543
544
 
544
- const manager = await co.account().createAs(admin, {
545
+ const manager = await createAccountAs(co.account(), admin, {
545
546
  creationProps: { name: "Manager" },
546
547
  });
547
- const writer = await co.account().createAs(admin, {
548
+ const writer = await createAccountAs(co.account(), admin, {
548
549
  creationProps: { name: "Writer" },
549
550
  });
550
- const reader = await co.account().createAs(admin, {
551
+ const reader = await createAccountAs(co.account(), admin, {
551
552
  creationProps: { name: "Reader" },
552
553
  });
553
- const writeOnly = await co.account().createAs(admin, {
554
+ const writeOnly = await createAccountAs(co.account(), admin, {
554
555
  creationProps: { name: "WriteOnly" },
555
556
  });
556
557
 
@@ -578,17 +579,17 @@ describe("Account permissions", () => {
578
579
  const group = Group.create({ owner: admin });
579
580
  const testObject = CoMap.create({}, { owner: group });
580
581
 
581
- const manager = await co.account().createAs(admin, {
582
+ const manager = await createAccountAs(co.account(), admin, {
582
583
  creationProps: { name: "Admin" },
583
584
  });
584
585
 
585
- const writer = await co.account().createAs(admin, {
586
+ const writer = await createAccountAs(co.account(), admin, {
586
587
  creationProps: { name: "Writer" },
587
588
  });
588
- const reader = await co.account().createAs(admin, {
589
+ const reader = await createAccountAs(co.account(), admin, {
589
590
  creationProps: { name: "Reader" },
590
591
  });
591
- const writeOnly = await co.account().createAs(admin, {
592
+ const writeOnly = await createAccountAs(co.account(), admin, {
592
593
  creationProps: { name: "WriteOnly" },
593
594
  });
594
595
 
@@ -616,17 +617,17 @@ describe("Account permissions", () => {
616
617
  const group = Group.create({ owner: admin });
617
618
  const testObject = CoMap.create({}, { owner: group });
618
619
 
619
- const manager = await co.account().createAs(admin, {
620
+ const manager = await createAccountAs(co.account(), admin, {
620
621
  creationProps: { name: "Admin" },
621
622
  });
622
623
 
623
- const writer = await co.account().createAs(admin, {
624
+ const writer = await createAccountAs(co.account(), admin, {
624
625
  creationProps: { name: "Writer" },
625
626
  });
626
- const reader = await co.account().createAs(admin, {
627
+ const reader = await createAccountAs(co.account(), admin, {
627
628
  creationProps: { name: "Reader" },
628
629
  });
629
- const writeOnly = await co.account().createAs(admin, {
630
+ const writeOnly = await createAccountAs(co.account(), admin, {
630
631
  creationProps: { name: "WriteOnly" },
631
632
  });
632
633
 
@@ -653,7 +654,7 @@ describe("Account permissions", () => {
653
654
  const group = Group.create({ owner: admin });
654
655
  const testObject = CoMap.create({}, { owner: group });
655
656
 
656
- const nonMember = await co.account().createAs(admin, {
657
+ const nonMember = await createAccountAs(co.account(), admin, {
657
658
  creationProps: { name: "NonMember" },
658
659
  });
659
660
 
@@ -248,11 +248,13 @@ describe("Schema.resolved()", () => {
248
248
 
249
249
  const account = await AccountWithProfile.createAs(serverAccount, {
250
250
  creationProps: { name: "Hermes Puggington" },
251
+ onCreate: async (account) => {
252
+ account.$jazz.set(
253
+ "profile",
254
+ co.profile().create({ name: "Hermes Puggington" }, publicGroup),
255
+ );
256
+ },
251
257
  });
252
- account.$jazz.set(
253
- "profile",
254
- co.profile().create({ name: "Hermes Puggington" }, publicGroup),
255
- );
256
258
 
257
259
  const loadedAccount = await AccountWithProfile.load(account.$jazz.id, {
258
260
  loadAs: clientAccount,
@@ -405,11 +407,13 @@ describe("Schema.resolved()", () => {
405
407
 
406
408
  const account = await AccountWithProfile.createAs(serverAccount, {
407
409
  creationProps: { name: "Hermes Puggington" },
410
+ onCreate: async (account) => {
411
+ account.$jazz.set(
412
+ "profile",
413
+ co.profile().create({ name: "Hermes Puggington" }, publicGroup),
414
+ );
415
+ },
408
416
  });
409
- account.$jazz.set(
410
- "profile",
411
- co.profile().create({ name: "Hermes Puggington" }, publicGroup),
412
- );
413
417
 
414
418
  const updates: co.loaded<typeof AccountWithProfile>[] = [];
415
419
  AccountWithProfile.subscribe(
@@ -559,18 +563,21 @@ describe("Schema.resolved()", () => {
559
563
 
560
564
  const account = await TestAccount.createAs(serverAccount, {
561
565
  creationProps: { name: "Hermes Puggington" },
566
+ onCreate: async (account) => {
567
+ account.$jazz.set(
568
+ "profile",
569
+ TestAccount.shape.profile.create(
570
+ { name: "Hermes Puggington" },
571
+ publicGroup,
572
+ ),
573
+ );
574
+ account.$jazz.set(
575
+ "root",
576
+ TestAccount.shape.root.create({ text: "Test" }, publicGroup),
577
+ );
578
+ },
562
579
  });
563
- account.$jazz.set(
564
- "profile",
565
- TestAccount.shape.profile.create(
566
- { name: "Hermes Puggington" },
567
- publicGroup,
568
- ),
569
- );
570
- account.$jazz.set(
571
- "root",
572
- TestAccount.shape.root.create({ text: "Test" }, publicGroup),
573
- );
580
+
574
581
  const accountList = AccountList.create([account], publicGroup);
575
582
 
576
583
  const branchAccountList = await AccountList.load(accountList.$jazz.id, {
@@ -15,6 +15,7 @@ import {
15
15
  CoValueLoadingState,
16
16
  MaybeLoaded,
17
17
  LoadedAndRequired,
18
+ AccountSchema,
18
19
  } from "../internal";
19
20
 
20
21
  const Crypto = await WasmCrypto.create();
@@ -151,3 +152,29 @@ export function assertLoaded<T extends MaybeLoaded<CoValue>>(
151
152
  ): asserts coValue is LoadedAndRequired<T> {
152
153
  assert(coValue.$isLoaded, "CoValue is not loaded");
153
154
  }
155
+
156
+ export async function createAccountAs<S extends AccountSchema<any, any>>(
157
+ schema: S,
158
+ as: Account,
159
+ options: {
160
+ creationProps: { name: string };
161
+ },
162
+ ) {
163
+ const connectedPeers = cojsonInternals.connectedPeers(
164
+ "creatingAccount",
165
+ "createdAccount",
166
+ { peer1role: "server", peer2role: "client" },
167
+ );
168
+
169
+ as.$jazz.localNode.syncManager.addPeer(connectedPeers[1]);
170
+
171
+ const account = await schema.create({
172
+ creationProps: options.creationProps,
173
+ crypto: as.$jazz.localNode.crypto,
174
+ peers: [connectedPeers[0]],
175
+ });
176
+
177
+ await account.$jazz.waitForAllCoValuesSync();
178
+
179
+ return account;
180
+ }