jazz-tools 0.17.4 → 0.17.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/.turbo/turbo-build.log +44 -44
  2. package/CHANGELOG.md +21 -0
  3. package/dist/{chunk-NPXI4XAS.js → chunk-SJHXI5AB.js} +103 -14
  4. package/dist/chunk-SJHXI5AB.js.map +1 -0
  5. package/dist/index.js +1 -1
  6. package/dist/media/{chunk-JBLT443O.js → chunk-E5J3WLQW.js} +2 -2
  7. package/dist/media/{chunk-JBLT443O.js.map → chunk-E5J3WLQW.js.map} +1 -1
  8. package/dist/media/index.browser.js +1 -1
  9. package/dist/media/index.js +1 -1
  10. package/dist/media/index.native.js +1 -1
  11. package/dist/media/utils.d.ts.map +1 -1
  12. package/dist/react/index.js.map +1 -1
  13. package/dist/testing.js +9 -1
  14. package/dist/testing.js.map +1 -1
  15. package/dist/tools/coValues/coList.d.ts +43 -1
  16. package/dist/tools/coValues/coList.d.ts.map +1 -1
  17. package/dist/tools/implementation/schema.d.ts.map +1 -1
  18. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +15 -1
  19. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -1
  20. package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts +11 -0
  21. package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts.map +1 -1
  22. package/dist/tools/testing.d.ts +9 -0
  23. package/dist/tools/testing.d.ts.map +1 -1
  24. package/package.json +4 -4
  25. package/src/media/utils.test.ts +3 -2
  26. package/src/media/utils.ts +5 -1
  27. package/src/tools/coValues/coList.ts +124 -4
  28. package/src/tools/implementation/schema.ts +3 -1
  29. package/src/tools/implementation/zodSchema/schemaTypes/CoListSchema.ts +44 -1
  30. package/src/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.ts +25 -0
  31. package/src/tools/testing.ts +18 -0
  32. package/src/tools/tests/coList.test.ts +167 -0
  33. package/src/tools/tests/coMap.record.test.ts +104 -0
  34. package/src/tools/tests/coMap.test.ts +19 -1
  35. package/dist/chunk-NPXI4XAS.js.map +0 -1
@@ -863,6 +863,173 @@ describe("CoList subscription", async () => {
863
863
  });
864
864
  });
865
865
 
866
+ describe("CoList unique methods", () => {
867
+ test("loadUnique returns existing list", async () => {
868
+ const ItemList = co.list(z.string());
869
+ const group = Group.create();
870
+
871
+ const originalList = ItemList.create(["item1", "item2", "item3"], {
872
+ owner: group,
873
+ unique: "test-list",
874
+ });
875
+
876
+ const foundList = await ItemList.loadUnique("test-list", group.id);
877
+ expect(foundList).toEqual(originalList);
878
+ expect(foundList?.length).toBe(3);
879
+ expect(foundList?.[0]).toBe("item1");
880
+ });
881
+
882
+ test("loadUnique returns null for non-existent list", async () => {
883
+ const ItemList = co.list(z.string());
884
+ const group = Group.create();
885
+
886
+ const foundList = await ItemList.loadUnique("non-existent", group.id);
887
+ expect(foundList).toBeNull();
888
+ });
889
+
890
+ test("upsertUnique creates new list when none exists", async () => {
891
+ const ItemList = co.list(z.string());
892
+ const group = Group.create();
893
+
894
+ const sourceData = ["item1", "item2", "item3"];
895
+
896
+ const result = await ItemList.upsertUnique({
897
+ value: sourceData,
898
+ unique: "new-list",
899
+ owner: group,
900
+ });
901
+
902
+ expect(result).not.toBeNull();
903
+ expect(result?.length).toBe(3);
904
+ expect(result?.[0]).toBe("item1");
905
+ expect(result?.[1]).toBe("item2");
906
+ expect(result?.[2]).toBe("item3");
907
+ });
908
+
909
+ test("upsertUnique updates existing list", async () => {
910
+ const ItemList = co.list(z.string());
911
+ const group = Group.create();
912
+
913
+ // Create initial list
914
+ const originalList = ItemList.create(["original1", "original2"], {
915
+ owner: group,
916
+ unique: "update-list",
917
+ });
918
+
919
+ // Upsert with new data
920
+ const updatedList = await ItemList.upsertUnique({
921
+ value: ["updated1", "updated2", "updated3"],
922
+ unique: "update-list",
923
+ owner: group,
924
+ });
925
+
926
+ expect(updatedList).toEqual(originalList); // Should be the same instance
927
+ expect(updatedList?.length).toBe(3);
928
+ expect(updatedList?.[0]).toBe("updated1");
929
+ expect(updatedList?.[1]).toBe("updated2");
930
+ expect(updatedList?.[2]).toBe("updated3");
931
+ });
932
+
933
+ test("upsertUnique with CoValue items", async () => {
934
+ const Item = co.map({
935
+ name: z.string(),
936
+ value: z.number(),
937
+ });
938
+ const ItemList = co.list(Item);
939
+ const group = Group.create();
940
+
941
+ const items = [
942
+ Item.create({ name: "First", value: 1 }, group),
943
+ Item.create({ name: "Second", value: 2 }, group),
944
+ ];
945
+
946
+ const result = await ItemList.upsertUnique({
947
+ value: items,
948
+ unique: "item-list",
949
+ owner: group,
950
+ resolve: { $each: true },
951
+ });
952
+
953
+ expect(result).not.toBeNull();
954
+ expect(result?.length).toBe(2);
955
+ expect(result?.[0]?.name).toBe("First");
956
+ expect(result?.[1]?.name).toBe("Second");
957
+ });
958
+
959
+ test("upsertUnique updates list with CoValue items", async () => {
960
+ const Item = co.map({
961
+ name: z.string(),
962
+ value: z.number(),
963
+ });
964
+ const ItemList = co.list(Item);
965
+ const group = Group.create();
966
+
967
+ // Create initial list
968
+ const initialItems = [Item.create({ name: "Initial", value: 0 }, group)];
969
+ const originalList = ItemList.create(initialItems, {
970
+ owner: group,
971
+ unique: "updateable-item-list",
972
+ });
973
+
974
+ // Upsert with new items
975
+ const newItems = [
976
+ Item.create({ name: "Updated", value: 1 }, group),
977
+ Item.create({ name: "Added", value: 2 }, group),
978
+ ];
979
+
980
+ const updatedList = await ItemList.upsertUnique({
981
+ value: newItems,
982
+ unique: "updateable-item-list",
983
+ owner: group,
984
+ resolve: { $each: true },
985
+ });
986
+
987
+ expect(updatedList).toEqual(originalList); // Should be the same instance
988
+ expect(updatedList?.length).toBe(2);
989
+ expect(updatedList?.[0]?.name).toBe("Updated");
990
+ expect(updatedList?.[1]?.name).toBe("Added");
991
+ });
992
+
993
+ test("findUnique returns correct ID", async () => {
994
+ const ItemList = co.list(z.string());
995
+ const group = Group.create();
996
+
997
+ const originalList = ItemList.create(["test"], {
998
+ owner: group,
999
+ unique: "find-test",
1000
+ });
1001
+
1002
+ const foundId = ItemList.findUnique("find-test", group.id);
1003
+ expect(foundId).toBe(originalList.id);
1004
+ });
1005
+
1006
+ test("upsertUnique with resolve options", async () => {
1007
+ const Category = co.map({ title: z.string() });
1008
+ const Item = co.map({
1009
+ name: z.string(),
1010
+ category: Category,
1011
+ });
1012
+ const ItemList = co.list(Item);
1013
+ const group = Group.create();
1014
+
1015
+ const category = Category.create({ title: "Category 1" }, group);
1016
+
1017
+ const items = [Item.create({ name: "Item 1", category }, group)];
1018
+
1019
+ const result = await ItemList.upsertUnique({
1020
+ value: items,
1021
+ unique: "resolved-list",
1022
+ owner: group,
1023
+ resolve: { $each: { category: true } },
1024
+ });
1025
+
1026
+ expect(result).not.toBeNull();
1027
+ expect(result?.length).toBe(1);
1028
+ expect(result?.[0]?.name).toBe("Item 1");
1029
+ expect(result?.[0]?.category?.title).toBe("Category 1");
1030
+ });
1031
+ });
1032
+
866
1033
  describe("co.list schema", () => {
867
1034
  test("can access the inner schema of a co.list", () => {
868
1035
  const Keywords = co.list(co.plainText());
@@ -460,3 +460,107 @@ describe("CoMap.Record", async () => {
460
460
  }
461
461
  });
462
462
  });
463
+
464
+ describe("CoRecord unique methods", () => {
465
+ test("loadUnique returns existing record", async () => {
466
+ const ItemRecord = co.record(z.string(), z.number());
467
+ const group = Group.create();
468
+
469
+ const originalRecord = ItemRecord.create(
470
+ { item1: 1, item2: 2, item3: 3 },
471
+ { owner: group, unique: "test-record" },
472
+ );
473
+
474
+ const foundRecord = await ItemRecord.loadUnique("test-record", group.id);
475
+ expect(foundRecord).toEqual(originalRecord);
476
+ expect(foundRecord?.item1).toBe(1);
477
+ expect(foundRecord?.item2).toBe(2);
478
+ });
479
+
480
+ test("loadUnique returns null for non-existent record", async () => {
481
+ const ItemRecord = co.record(z.string(), z.number());
482
+ const group = Group.create();
483
+
484
+ const foundRecord = await ItemRecord.loadUnique("non-existent", group.id);
485
+ expect(foundRecord).toBeNull();
486
+ });
487
+
488
+ test("upsertUnique creates new record when none exists", async () => {
489
+ const ItemRecord = co.record(z.string(), z.number());
490
+ const group = Group.create();
491
+
492
+ const sourceData = { item1: 1, item2: 2, item3: 3 };
493
+
494
+ const result = await ItemRecord.upsertUnique({
495
+ value: sourceData,
496
+ unique: "new-record",
497
+ owner: group,
498
+ });
499
+
500
+ expect(result).not.toBeNull();
501
+ expect(result?.item1).toBe(1);
502
+ expect(result?.item2).toBe(2);
503
+ expect(result?.item3).toBe(3);
504
+ });
505
+
506
+ test("upsertUnique updates existing record", async () => {
507
+ const ItemRecord = co.record(z.string(), z.number());
508
+ const group = Group.create();
509
+
510
+ // Create initial record
511
+ const originalRecord = ItemRecord.create(
512
+ { original1: 1, original2: 2 },
513
+ { owner: group, unique: "update-record" },
514
+ );
515
+
516
+ // Upsert with new data
517
+ const updatedRecord = await ItemRecord.upsertUnique({
518
+ value: { updated1: 10, updated2: 20, updated3: 30 },
519
+ unique: "update-record",
520
+ owner: group,
521
+ });
522
+
523
+ expect(updatedRecord).toEqual(originalRecord); // Should be the same instance
524
+ expect(updatedRecord?.updated1).toBe(10);
525
+ expect(updatedRecord?.updated2).toBe(20);
526
+ expect(updatedRecord?.updated3).toBe(30);
527
+ });
528
+
529
+ test("upsertUnique with CoValue items", async () => {
530
+ const Item = co.map({
531
+ name: z.string(),
532
+ value: z.number(),
533
+ });
534
+ const ItemRecord = co.record(z.string(), Item);
535
+ const group = Group.create();
536
+
537
+ const items = {
538
+ first: Item.create({ name: "First", value: 1 }, group),
539
+ second: Item.create({ name: "Second", value: 2 }, group),
540
+ };
541
+
542
+ const result = await ItemRecord.upsertUnique({
543
+ value: items,
544
+ unique: "item-record",
545
+ owner: group,
546
+ resolve: { first: true, second: true },
547
+ });
548
+
549
+ expect(result).not.toBeNull();
550
+ expect(result?.first?.name).toBe("First");
551
+ expect(result?.second?.name).toBe("Second");
552
+ });
553
+
554
+ test("findUnique returns correct ID", async () => {
555
+ const ItemRecord = co.record(z.string(), z.string());
556
+ const group = Group.create();
557
+
558
+ const originalRecord = ItemRecord.create(
559
+ { test: "value" },
560
+ { owner: group, unique: "find-test" },
561
+ );
562
+
563
+ const foundId = ItemRecord.findUnique("find-test", group.id);
564
+ expect(foundId).toBe(originalRecord.id);
565
+ });
566
+ });
@@ -12,10 +12,15 @@ import {
12
12
  } from "vitest";
13
13
  import { Group, co, subscribeToCoValue, z } from "../exports.js";
14
14
  import { Account } from "../index.js";
15
- import { Loaded, coValueClassFromCoValueClassOrSchema } from "../internal.js";
15
+ import {
16
+ Loaded,
17
+ activeAccountContext,
18
+ coValueClassFromCoValueClassOrSchema,
19
+ } from "../internal.js";
16
20
  import {
17
21
  createJazzTestAccount,
18
22
  getPeerConnectedToTestSyncServer,
23
+ runWithoutActiveAccount,
19
24
  setupJazzTestSync,
20
25
  } from "../testing.js";
21
26
  import { setupTwoNodes, waitFor } from "./utils.js";
@@ -214,6 +219,19 @@ describe("CoMap", async () => {
214
219
  const map = Schema.create({ text: "" });
215
220
  expect(map.text.toString()).toBe("");
216
221
  });
222
+
223
+ it("creates a group for the new CoValue when there is no active account", () => {
224
+ const Schema = co.map({ text: co.plainText() });
225
+
226
+ const parentGroup = Group.create();
227
+ runWithoutActiveAccount(() => {
228
+ const map = Schema.create({ text: "Hello" }, parentGroup);
229
+
230
+ expect(
231
+ map.text._owner.getParentGroups().map((group: Group) => group.id),
232
+ ).toContain(parentGroup.id);
233
+ });
234
+ });
217
235
  });
218
236
 
219
237
  test("CoMap with self reference", () => {