jazz-tools 0.14.19 → 0.14.21

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 (60) hide show
  1. package/.turbo/turbo-build.log +5 -5
  2. package/CHANGELOG.md +19 -0
  3. package/dist/{chunk-AA3SCYKI.js → chunk-DAOCWHIV.js} +248 -125
  4. package/dist/chunk-DAOCWHIV.js.map +1 -0
  5. package/dist/coValues/CoValueBase.d.ts +14 -3
  6. package/dist/coValues/CoValueBase.d.ts.map +1 -1
  7. package/dist/coValues/coMap.d.ts +27 -1
  8. package/dist/coValues/coMap.d.ts.map +1 -1
  9. package/dist/coValues/group.d.ts +8 -0
  10. package/dist/coValues/group.d.ts.map +1 -1
  11. package/dist/coValues/interfaces.d.ts +5 -0
  12. package/dist/coValues/interfaces.d.ts.map +1 -1
  13. package/dist/implementation/zodSchema/runtimeConverters/zodSchemaToCoSchema.d.ts.map +1 -1
  14. package/dist/implementation/zodSchema/schemaTypes/AccountSchema.d.ts +2 -1
  15. package/dist/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -1
  16. package/dist/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts +1 -0
  17. package/dist/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts.map +1 -1
  18. package/dist/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +1 -0
  19. package/dist/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -1
  20. package/dist/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts +2 -0
  21. package/dist/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts.map +1 -1
  22. package/dist/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts +2 -1
  23. package/dist/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts.map +1 -1
  24. package/dist/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts +1 -0
  25. package/dist/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts.map +1 -1
  26. package/dist/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts +1 -0
  27. package/dist/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts.map +1 -1
  28. package/dist/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts +1 -0
  29. package/dist/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts.map +1 -1
  30. package/dist/implementation/zodSchema/zodCo.d.ts.map +1 -1
  31. package/dist/implementation/zodSchema/zodSchema.d.ts +1 -1
  32. package/dist/implementation/zodSchema/zodSchema.d.ts.map +1 -1
  33. package/dist/index.js +1 -1
  34. package/dist/lib/migration.d.ts +3 -0
  35. package/dist/lib/migration.d.ts.map +1 -0
  36. package/dist/subscribe/SubscriptionScope.d.ts +3 -1
  37. package/dist/subscribe/SubscriptionScope.d.ts.map +1 -1
  38. package/dist/testing.js +1 -1
  39. package/package.json +2 -2
  40. package/src/coValues/CoValueBase.ts +31 -7
  41. package/src/coValues/coMap.ts +14 -1
  42. package/src/coValues/group.ts +12 -0
  43. package/src/coValues/interfaces.ts +5 -0
  44. package/src/implementation/zodSchema/runtimeConverters/zodSchemaToCoSchema.ts +12 -15
  45. package/src/implementation/zodSchema/schemaTypes/AccountSchema.ts +3 -1
  46. package/src/implementation/zodSchema/schemaTypes/CoFeedSchema.ts +2 -0
  47. package/src/implementation/zodSchema/schemaTypes/CoListSchema.ts +2 -0
  48. package/src/implementation/zodSchema/schemaTypes/CoMapSchema.ts +11 -0
  49. package/src/implementation/zodSchema/schemaTypes/CoRecordSchema.ts +2 -1
  50. package/src/implementation/zodSchema/schemaTypes/FileStreamSchema.ts +1 -0
  51. package/src/implementation/zodSchema/schemaTypes/PlainTextSchema.ts +1 -0
  52. package/src/implementation/zodSchema/schemaTypes/RichTextSchema.ts +1 -0
  53. package/src/implementation/zodSchema/zodCo.ts +214 -246
  54. package/src/implementation/zodSchema/zodSchema.ts +1 -1
  55. package/src/lib/migration.ts +23 -0
  56. package/src/subscribe/SubscriptionScope.ts +48 -3
  57. package/src/tests/coMap.test.ts +280 -1
  58. package/src/tests/groupsAndAccounts.test.ts +12 -0
  59. package/src/tests/schemaUnion.test.ts +5 -5
  60. package/dist/chunk-AA3SCYKI.js.map +0 -1
@@ -11,7 +11,7 @@ import {
11
11
  } from "vitest";
12
12
  import { Group, co, subscribeToCoValue, z } from "../exports.js";
13
13
  import { Account } from "../index.js";
14
- import { CoKeys, Loaded, zodSchemaToCoSchema } from "../internal.js";
14
+ import { Loaded, zodSchemaToCoSchema } from "../internal.js";
15
15
  import { createJazzTestAccount, setupJazzTestSync } from "../testing.js";
16
16
  import { setupTwoNodes, waitFor } from "./utils.js";
17
17
 
@@ -1356,3 +1356,282 @@ describe("Creating and finding unique CoMaps", async () => {
1356
1356
  }
1357
1357
  });
1358
1358
  });
1359
+
1360
+ describe("castAs", () => {
1361
+ test("should cast a co.map type", () => {
1362
+ const Person = co.map({
1363
+ name: z.string(),
1364
+ });
1365
+
1366
+ const PersonWithAge = co.map({
1367
+ name: z.string(),
1368
+ age: z.number().optional(),
1369
+ });
1370
+
1371
+ const person = Person.create({
1372
+ name: "Alice",
1373
+ });
1374
+
1375
+ const personWithAge = person.castAs(PersonWithAge);
1376
+
1377
+ personWithAge.age = 20;
1378
+
1379
+ expect(personWithAge.age).toEqual(20);
1380
+ });
1381
+
1382
+ test("should still be able to autoload in-memory deps", () => {
1383
+ const Dog = co.map({
1384
+ name: z.string(),
1385
+ });
1386
+
1387
+ const Person = co.map({
1388
+ name: z.string(),
1389
+ dog: Dog,
1390
+ });
1391
+
1392
+ const PersonWithAge = co.map({
1393
+ name: z.string(),
1394
+ age: z.number().optional(),
1395
+ dog: Dog,
1396
+ });
1397
+
1398
+ const person = Person.create({
1399
+ name: "Alice",
1400
+ dog: Dog.create({ name: "Rex" }),
1401
+ });
1402
+
1403
+ const personWithAge = person.castAs(PersonWithAge);
1404
+
1405
+ personWithAge.age = 20;
1406
+
1407
+ expect(personWithAge.age).toEqual(20);
1408
+ expect(personWithAge.dog?.name).toEqual("Rex");
1409
+ });
1410
+ });
1411
+
1412
+ describe("CoMap migration", () => {
1413
+ test("should run on load", async () => {
1414
+ const PersonV1 = co.map({
1415
+ name: z.string(),
1416
+ version: z.literal(1),
1417
+ });
1418
+
1419
+ const Person = co
1420
+ .map({
1421
+ name: z.string(),
1422
+ age: z.number(),
1423
+ version: z.literal([1, 2]),
1424
+ })
1425
+ .withMigration((person) => {
1426
+ if (person.version === 1) {
1427
+ person.age = 20;
1428
+ person.version = 2;
1429
+ }
1430
+ });
1431
+
1432
+ const person = PersonV1.create({
1433
+ name: "Bob",
1434
+ version: 1,
1435
+ });
1436
+
1437
+ expect(person?.name).toEqual("Bob");
1438
+ expect(person?.version).toEqual(1);
1439
+
1440
+ const loadedPerson = await Person.load(person.id);
1441
+
1442
+ expect(loadedPerson?.name).toEqual("Bob");
1443
+ expect(loadedPerson?.age).toEqual(20);
1444
+ expect(loadedPerson?.version).toEqual(2);
1445
+ });
1446
+
1447
+ test("should handle group updates", async () => {
1448
+ const Person = co
1449
+ .map({
1450
+ name: z.string(),
1451
+ version: z.literal([1, 2]),
1452
+ })
1453
+ .withMigration((person) => {
1454
+ if (person.version === 1) {
1455
+ person.version = 2;
1456
+
1457
+ person._owner.castAs(Group).addMember("everyone", "reader");
1458
+ }
1459
+ });
1460
+
1461
+ const person = Person.create({
1462
+ name: "Bob",
1463
+ version: 1,
1464
+ });
1465
+
1466
+ expect(person?.name).toEqual("Bob");
1467
+ expect(person?.version).toEqual(1);
1468
+
1469
+ const loadedPerson = await Person.load(person.id);
1470
+
1471
+ expect(loadedPerson?.name).toEqual("Bob");
1472
+ expect(loadedPerson?.version).toEqual(2);
1473
+
1474
+ const anotherAccount = await createJazzTestAccount();
1475
+
1476
+ const loadedPersonFromAnotherAccount = await Person.load(person.id, {
1477
+ loadAs: anotherAccount,
1478
+ });
1479
+
1480
+ expect(loadedPersonFromAnotherAccount?.name).toEqual("Bob");
1481
+ });
1482
+
1483
+ test("should throw an error if a migration is async", async () => {
1484
+ const Person = co
1485
+ .map({
1486
+ name: z.string(),
1487
+ version: z.number(),
1488
+ })
1489
+ // @ts-expect-error async function
1490
+ .withMigration(async () => {});
1491
+
1492
+ const person = Person.create({
1493
+ name: "Bob",
1494
+ version: 1,
1495
+ });
1496
+
1497
+ await expect(Person.load(person.id)).rejects.toThrow(
1498
+ "Migration function cannot be async",
1499
+ );
1500
+ });
1501
+
1502
+ test("should run only once", async () => {
1503
+ const spy = vi.fn();
1504
+ const Person = co
1505
+ .map({
1506
+ name: z.string(),
1507
+ version: z.number(),
1508
+ })
1509
+ .withMigration((person) => {
1510
+ spy(person);
1511
+ });
1512
+
1513
+ const person = Person.create({
1514
+ name: "Bob",
1515
+ version: 1,
1516
+ });
1517
+
1518
+ await Person.load(person.id);
1519
+ await Person.load(person.id);
1520
+ expect(spy).toHaveBeenCalledTimes(1);
1521
+ });
1522
+
1523
+ test("should not break recursive schemas", async () => {
1524
+ const PersonV1 = co.map({
1525
+ name: z.string(),
1526
+ version: z.literal(1),
1527
+ get friend() {
1528
+ return PersonV1.optional();
1529
+ },
1530
+ });
1531
+
1532
+ const Person = co
1533
+ .map({
1534
+ name: z.string(),
1535
+ age: z.number(),
1536
+ get friend() {
1537
+ return Person.optional();
1538
+ },
1539
+ version: z.literal([1, 2]),
1540
+ })
1541
+ .withMigration((person) => {
1542
+ if (person.version === 1) {
1543
+ person.age = 20;
1544
+ person.version = 2;
1545
+ }
1546
+ });
1547
+
1548
+ const charlie = PersonV1.create({
1549
+ name: "Charlie",
1550
+ version: 1,
1551
+ });
1552
+
1553
+ const bob = PersonV1.create({
1554
+ name: "Bob",
1555
+ version: 1,
1556
+ friend: charlie,
1557
+ });
1558
+
1559
+ const loaded = await Person.load(bob.id, {
1560
+ resolve: {
1561
+ friend: true,
1562
+ },
1563
+ });
1564
+
1565
+ // Migration should run on both the person and their friend
1566
+ expect(loaded?.name).toEqual("Bob");
1567
+ expect(loaded?.age).toEqual(20);
1568
+ expect(loaded?.version).toEqual(2);
1569
+ expect(loaded?.friend?.name).toEqual("Charlie");
1570
+ expect(loaded?.friend?.version).toEqual(2);
1571
+ });
1572
+ describe("Time", () => {
1573
+ test("empty map created time", () => {
1574
+ const currentTimestampInSeconds = Math.floor(Date.now() / 1000);
1575
+ const emptyMap = co.map({}).create({});
1576
+ const createdAtInSeconds = Math.floor(emptyMap._createdAt / 1000);
1577
+
1578
+ expect(createdAtInSeconds).toEqual(currentTimestampInSeconds);
1579
+ expect(emptyMap._lastUpdatedAt).toEqual(emptyMap._createdAt);
1580
+ });
1581
+
1582
+ test("created time and last updated time", async () => {
1583
+ const Person = co.map({
1584
+ name: z.string(),
1585
+ });
1586
+
1587
+ let currentTimestampInSeconds = Math.floor(Date.now() / 1000);
1588
+ const person = Person.create({ name: "John" });
1589
+
1590
+ const createdAt = person._createdAt;
1591
+ const createdAtInSeconds = Math.floor(createdAt / 1000);
1592
+ expect(createdAtInSeconds).toEqual(currentTimestampInSeconds);
1593
+ expect(person._lastUpdatedAt).toEqual(createdAt);
1594
+
1595
+ await new Promise((r) => setTimeout(r, 1000));
1596
+ currentTimestampInSeconds = Math.floor(Date.now() / 1000);
1597
+ person.name = "Jane";
1598
+
1599
+ const lastUpdatedAtInSeconds = Math.floor(person._lastUpdatedAt / 1000);
1600
+ expect(lastUpdatedAtInSeconds).toEqual(currentTimestampInSeconds);
1601
+ expect(person._createdAt).toEqual(createdAt);
1602
+ expect(person._lastUpdatedAt).not.toEqual(createdAt);
1603
+ });
1604
+
1605
+ test("comap with custom uniqueness", () => {
1606
+ const Person = co.map({
1607
+ name: z.string(),
1608
+ });
1609
+
1610
+ let currentTimestampInSeconds = Math.floor(Date.now() / 1000);
1611
+ const person = Person.create(
1612
+ { name: "John" },
1613
+ { unique: "name", owner: Account.getMe() },
1614
+ );
1615
+
1616
+ const createdAt = person._createdAt;
1617
+ const createdAtInSeconds = Math.floor(createdAt / 1000);
1618
+ expect(createdAtInSeconds).toEqual(currentTimestampInSeconds);
1619
+ });
1620
+
1621
+ test("empty comap with custom uniqueness", () => {
1622
+ const Person = co.map({
1623
+ name: z.optional(z.string()),
1624
+ });
1625
+
1626
+ let currentTimestampInSeconds = Math.floor(Date.now() / 1000);
1627
+ const person = Person.create(
1628
+ {},
1629
+ { unique: "name", owner: Account.getMe() },
1630
+ );
1631
+
1632
+ const createdAt = person._createdAt;
1633
+ const createdAtInSeconds = Math.floor(createdAt / 1000);
1634
+ expect(createdAtInSeconds).toEqual(currentTimestampInSeconds);
1635
+ });
1636
+ });
1637
+ });
@@ -242,6 +242,18 @@ describe("Group inheritance", () => {
242
242
  expect(group.getRoleOf("everyone")).toBe("writeOnly");
243
243
  });
244
244
 
245
+ test("makePublic should add everyone as a reader", () => {
246
+ const group = Group.create();
247
+ group.makePublic();
248
+ expect(group.getRoleOf("everyone")).toBe("reader");
249
+ });
250
+
251
+ test("makePublic should add everyone as a writer", () => {
252
+ const group = Group.create();
253
+ group.makePublic("writer");
254
+ expect(group.getRoleOf("everyone")).toBe("writer");
255
+ });
256
+
245
257
  test("typescript should show an error when adding a member with a non-account role", async () => {
246
258
  const account = await createJazzTestAccount({});
247
259
  await account.waitForAllCoValuesSync();
@@ -4,11 +4,11 @@ import {
4
4
  Account,
5
5
  CryptoProvider,
6
6
  Loaded,
7
+ anySchemaToCoSchema,
7
8
  co,
8
9
  loadCoValue,
9
10
  subscribeToCoValue,
10
11
  z,
11
- zodSchemaToCoSchema,
12
12
  } from "../exports.js";
13
13
 
14
14
  const RedButtonWidget = co.map({
@@ -73,21 +73,21 @@ describe("SchemaUnion", () => {
73
73
  );
74
74
 
75
75
  const loadedButtonWidget = await loadCoValue(
76
- zodSchemaToCoSchema(WidgetUnion),
76
+ anySchemaToCoSchema(WidgetUnion),
77
77
  buttonWidget.id,
78
78
  {
79
79
  loadAs: me,
80
80
  },
81
81
  );
82
82
  const loadedSliderWidget = await loadCoValue(
83
- zodSchemaToCoSchema(WidgetUnion),
83
+ anySchemaToCoSchema(WidgetUnion),
84
84
  sliderWidget.id,
85
85
  {
86
86
  loadAs: me,
87
87
  },
88
88
  );
89
89
  const loadedCheckboxWidget = await loadCoValue(
90
- zodSchemaToCoSchema(WidgetUnion),
90
+ anySchemaToCoSchema(WidgetUnion),
91
91
  checkboxWidget.id,
92
92
  { loadAs: me },
93
93
  );
@@ -104,7 +104,7 @@ describe("SchemaUnion", () => {
104
104
  );
105
105
  let currentValue = "Submit";
106
106
  const unsubscribe = subscribeToCoValue(
107
- zodSchemaToCoSchema(WidgetUnion),
107
+ anySchemaToCoSchema(WidgetUnion),
108
108
  buttonWidget.id,
109
109
  { loadAs: me, syncResolution: true },
110
110
  (value: Loaded<typeof WidgetUnion>) => {