jazz-tools 0.13.31 → 0.14.1

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 (166) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/CHANGELOG.md +22 -3
  3. package/dist/auth/DemoAuth.d.ts.map +1 -1
  4. package/dist/auth/PassphraseAuth.d.ts +1 -3
  5. package/dist/auth/PassphraseAuth.d.ts.map +1 -1
  6. package/dist/{chunk-IJU4XPFS.js → chunk-WLOZKDOH.js} +3536 -3291
  7. package/dist/chunk-WLOZKDOH.js.map +1 -0
  8. package/dist/coValues/CoValueBase.d.ts +22 -0
  9. package/dist/coValues/CoValueBase.d.ts.map +1 -0
  10. package/dist/coValues/account.d.ts +12 -12
  11. package/dist/coValues/account.d.ts.map +1 -1
  12. package/dist/coValues/coFeed.d.ts +24 -25
  13. package/dist/coValues/coFeed.d.ts.map +1 -1
  14. package/dist/coValues/coList.d.ts +10 -13
  15. package/dist/coValues/coList.d.ts.map +1 -1
  16. package/dist/coValues/coMap.d.ts +32 -35
  17. package/dist/coValues/coMap.d.ts.map +1 -1
  18. package/dist/coValues/coPlainText.d.ts.map +1 -1
  19. package/dist/coValues/deepLoading.d.ts +17 -21
  20. package/dist/coValues/deepLoading.d.ts.map +1 -1
  21. package/dist/coValues/extensions/imageDef.d.ts +12 -11
  22. package/dist/coValues/extensions/imageDef.d.ts.map +1 -1
  23. package/dist/coValues/group.d.ts +5 -9
  24. package/dist/coValues/group.d.ts.map +1 -1
  25. package/dist/coValues/inbox.d.ts +2 -3
  26. package/dist/coValues/inbox.d.ts.map +1 -1
  27. package/dist/coValues/interfaces.d.ts +8 -34
  28. package/dist/coValues/interfaces.d.ts.map +1 -1
  29. package/dist/coValues/profile.d.ts +4 -14
  30. package/dist/coValues/profile.d.ts.map +1 -1
  31. package/dist/coValues/registeredSchemas.d.ts +1 -3
  32. package/dist/coValues/registeredSchemas.d.ts.map +1 -1
  33. package/dist/coValues/schemaUnion.d.ts +6 -6
  34. package/dist/exports.d.ts +12 -16
  35. package/dist/exports.d.ts.map +1 -1
  36. package/dist/implementation/ContextManager.d.ts +1 -1
  37. package/dist/implementation/ContextManager.d.ts.map +1 -1
  38. package/dist/implementation/activeAccountContext.d.ts +1 -1
  39. package/dist/implementation/activeAccountContext.d.ts.map +1 -1
  40. package/dist/implementation/createContext.d.ts +10 -10
  41. package/dist/implementation/createContext.d.ts.map +1 -1
  42. package/dist/implementation/invites.d.ts +6 -6
  43. package/dist/implementation/invites.d.ts.map +1 -1
  44. package/dist/implementation/refs.d.ts +2 -2
  45. package/dist/implementation/refs.d.ts.map +1 -1
  46. package/dist/implementation/schema.d.ts +21 -28
  47. package/dist/implementation/schema.d.ts.map +1 -1
  48. package/dist/implementation/zodSchema/runtimeConverters/zodFieldToCoFieldDef.d.ts +9 -0
  49. package/dist/implementation/zodSchema/runtimeConverters/zodFieldToCoFieldDef.d.ts.map +1 -0
  50. package/dist/implementation/zodSchema/runtimeConverters/zodSchemaToCoSchema.d.ts +28 -0
  51. package/dist/implementation/zodSchema/runtimeConverters/zodSchemaToCoSchema.d.ts.map +1 -0
  52. package/dist/implementation/zodSchema/schemaTypes/AccountSchema.d.ts +65 -0
  53. package/dist/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -0
  54. package/dist/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts +28 -0
  55. package/dist/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts.map +1 -0
  56. package/dist/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +24 -0
  57. package/dist/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -0
  58. package/dist/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts +41 -0
  59. package/dist/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts.map +1 -0
  60. package/dist/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts +35 -0
  61. package/dist/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts.map +1 -0
  62. package/dist/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts +9 -0
  63. package/dist/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts.map +1 -0
  64. package/dist/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts +20 -0
  65. package/dist/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts.map +1 -0
  66. package/dist/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts +18 -0
  67. package/dist/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts.map +1 -0
  68. package/dist/implementation/zodSchema/typeConverters/InstanceOfSchema.d.ts +24 -0
  69. package/dist/implementation/zodSchema/typeConverters/InstanceOfSchema.d.ts.map +1 -0
  70. package/dist/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.d.ts +21 -0
  71. package/dist/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.d.ts.map +1 -0
  72. package/dist/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchema.d.ts +29 -0
  73. package/dist/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchema.d.ts.map +1 -0
  74. package/dist/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchemaCoValuesNullable.d.ts +29 -0
  75. package/dist/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchemaCoValuesNullable.d.ts.map +1 -0
  76. package/dist/implementation/zodSchema/unionUtils.d.ts +6 -0
  77. package/dist/implementation/zodSchema/unionUtils.d.ts.map +1 -0
  78. package/dist/implementation/zodSchema/zodCo.d.ts +35 -0
  79. package/dist/implementation/zodSchema/zodCo.d.ts.map +1 -0
  80. package/dist/implementation/zodSchema/zodSchema.d.ts +38 -0
  81. package/dist/implementation/zodSchema/zodSchema.d.ts.map +1 -0
  82. package/dist/index.js +295 -10
  83. package/dist/index.js.map +1 -1
  84. package/dist/internal.d.ts +34 -0
  85. package/dist/internal.d.ts.map +1 -1
  86. package/dist/subscribe/SubscriptionScope.d.ts +1 -2
  87. package/dist/subscribe/SubscriptionScope.d.ts.map +1 -1
  88. package/dist/subscribe/utils.d.ts +2 -2
  89. package/dist/subscribe/utils.d.ts.map +1 -1
  90. package/dist/testing.d.ts +10 -8
  91. package/dist/testing.d.ts.map +1 -1
  92. package/dist/testing.js +1 -1
  93. package/dist/testing.js.map +1 -1
  94. package/dist/tests/utils.d.ts +6 -2
  95. package/dist/tests/utils.d.ts.map +1 -1
  96. package/dist/types.d.ts +1 -7
  97. package/dist/types.d.ts.map +1 -1
  98. package/package.json +3 -2
  99. package/src/auth/DemoAuth.ts +1 -2
  100. package/src/auth/PassphraseAuth.ts +1 -1
  101. package/src/coValues/CoValueBase.ts +88 -0
  102. package/src/coValues/account.ts +53 -43
  103. package/src/coValues/coFeed.ts +65 -83
  104. package/src/coValues/coList.ts +28 -21
  105. package/src/coValues/coMap.ts +54 -38
  106. package/src/coValues/coPlainText.ts +4 -1
  107. package/src/coValues/deepLoading.ts +35 -43
  108. package/src/coValues/extensions/imageDef.ts +21 -19
  109. package/src/coValues/group.ts +37 -38
  110. package/src/coValues/inbox.ts +24 -11
  111. package/src/coValues/interfaces.ts +29 -93
  112. package/src/coValues/profile.ts +12 -13
  113. package/src/coValues/registeredSchemas.ts +1 -3
  114. package/src/coValues/schemaUnion.ts +6 -6
  115. package/src/exports.ts +47 -25
  116. package/src/implementation/activeAccountContext.ts +1 -1
  117. package/src/implementation/createContext.ts +39 -24
  118. package/src/implementation/invites.ts +15 -12
  119. package/src/implementation/refs.ts +6 -4
  120. package/src/implementation/schema.ts +22 -34
  121. package/src/implementation/zodSchema/runtimeConverters/zodFieldToCoFieldDef.ts +101 -0
  122. package/src/implementation/zodSchema/runtimeConverters/zodSchemaToCoSchema.ts +191 -0
  123. package/src/implementation/zodSchema/schemaTypes/AccountSchema.ts +102 -0
  124. package/src/implementation/zodSchema/schemaTypes/CoFeedSchema.ts +70 -0
  125. package/src/implementation/zodSchema/schemaTypes/CoListSchema.ts +59 -0
  126. package/src/implementation/zodSchema/schemaTypes/CoMapSchema.ts +126 -0
  127. package/src/implementation/zodSchema/schemaTypes/CoRecordSchema.ts +98 -0
  128. package/src/implementation/zodSchema/schemaTypes/FileStreamSchema.ts +9 -0
  129. package/src/implementation/zodSchema/schemaTypes/PlainTextSchema.ts +27 -0
  130. package/src/implementation/zodSchema/schemaTypes/RichTextSchema.ts +25 -0
  131. package/src/implementation/zodSchema/typeConverters/InstanceOfSchema.ts +61 -0
  132. package/src/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.ts +77 -0
  133. package/src/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchema.ts +90 -0
  134. package/src/implementation/zodSchema/typeConverters/InstanceOrPrimitiveOfSchemaCoValuesNullable.ts +103 -0
  135. package/src/implementation/zodSchema/unionUtils.ts +139 -0
  136. package/src/implementation/zodSchema/zodCo.ts +409 -0
  137. package/src/implementation/zodSchema/zodSchema.ts +116 -0
  138. package/src/internal.ts +38 -0
  139. package/src/subscribe/SubscriptionScope.ts +3 -1
  140. package/src/subscribe/utils.ts +7 -2
  141. package/src/testing.ts +14 -16
  142. package/src/tests/ContextManager.test.ts +73 -47
  143. package/src/tests/DemoAuth.test.ts +1 -1
  144. package/src/tests/account.test.ts +6 -9
  145. package/src/tests/coFeed.test.ts +102 -63
  146. package/src/tests/coList.test.ts +82 -95
  147. package/src/tests/coMap.record.test.ts +53 -87
  148. package/src/tests/coMap.test.ts +297 -312
  149. package/src/tests/coPlainText.test.ts +19 -39
  150. package/src/tests/createContext.test.ts +33 -15
  151. package/src/tests/deepLoading.test.ts +196 -179
  152. package/src/tests/groupsAndAccounts.test.ts +81 -72
  153. package/src/tests/imageDef.test.ts +22 -13
  154. package/src/tests/inbox.test.ts +36 -29
  155. package/src/tests/load.test.ts +10 -10
  156. package/src/tests/patterns/requestToJoin.test.ts +31 -31
  157. package/src/tests/schema.test.ts +37 -38
  158. package/src/tests/schemaUnion.test.ts +54 -64
  159. package/src/tests/subscribe.test.ts +118 -116
  160. package/src/tests/testing.test.ts +33 -33
  161. package/src/tests/utils.ts +3 -2
  162. package/src/types.ts +1 -8
  163. package/dist/chunk-IJU4XPFS.js.map +0 -1
  164. package/dist/tests/deepLoading.test-d.d.ts +0 -2
  165. package/dist/tests/deepLoading.test-d.d.ts.map +0 -1
  166. package/src/tests/deepLoading.test-d.ts +0 -393
@@ -9,13 +9,12 @@ import {
9
9
  test,
10
10
  vi,
11
11
  } from "vitest";
12
- import { Group, Resolved, subscribeToCoValue } from "../exports.js";
13
- import { Account, CoMap, Encoders, co, cojsonInternals } from "../index.js";
12
+ import { Group, co, subscribeToCoValue, z } from "../exports.js";
13
+ import { Account } from "../index.js";
14
+ import { CoKeys, Loaded, zodSchemaToCoSchema } from "../internal.js";
14
15
  import { createJazzTestAccount, setupJazzTestSync } from "../testing.js";
15
16
  import { setupTwoNodes, waitFor } from "./utils.js";
16
17
 
17
- const { connectedPeers } = cojsonInternals;
18
-
19
18
  const Crypto = await WasmCrypto.create();
20
19
 
21
20
  beforeEach(async () => {
@@ -30,21 +29,17 @@ beforeEach(async () => {
30
29
  describe("CoMap", async () => {
31
30
  describe("init", () => {
32
31
  test("create a CoMap with basic property access", () => {
33
- class Person extends CoMap {
34
- color = co.string;
35
- _height = co.number;
36
- birthday = co.Date;
37
- name = co.string;
38
- nullable = co.optional.encoded<string | undefined>({
39
- encode: (value: string | undefined) => value || null,
40
- decode: (value: unknown) => (value as string) || undefined,
41
- });
42
- optionalDate = co.optional.Date;
43
-
44
- get roughColor() {
45
- return this.color + "ish";
46
- }
47
- }
32
+ const Person = co.map({
33
+ color: z.string(),
34
+ _height: z.number(),
35
+ birthday: z.date(),
36
+ name: z.string(),
37
+ // nullable: z.optional.encoded<string | undefined>({
38
+ // encode: (value: string | undefined) => value || null,
39
+ // decode: (value: unknown) => (value as string) || undefined,
40
+ // })
41
+ optionalDate: z.date().optional(),
42
+ });
48
43
 
49
44
  const birthday = new Date("1989-11-27");
50
45
 
@@ -56,7 +51,6 @@ describe("CoMap", async () => {
56
51
  });
57
52
 
58
53
  expect(john.color).toEqual("red");
59
- expect(john.roughColor).toEqual("redish");
60
54
  expect(john._height).toEqual(10);
61
55
  expect(john.birthday).toEqual(birthday);
62
56
  expect(john._raw.get("birthday")).toEqual(birthday.toISOString());
@@ -69,9 +63,9 @@ describe("CoMap", async () => {
69
63
  });
70
64
 
71
65
  test("property existence", () => {
72
- class Person extends CoMap {
73
- name = co.string;
74
- }
66
+ const Person = co.map({
67
+ name: z.string(),
68
+ });
75
69
 
76
70
  const john = Person.create({ name: "John" });
77
71
 
@@ -80,9 +74,9 @@ describe("CoMap", async () => {
80
74
  });
81
75
 
82
76
  test("create a CoMap with an account as owner", () => {
83
- class Person extends CoMap {
84
- name = co.string;
85
- }
77
+ const Person = co.map({
78
+ name: z.string(),
79
+ });
86
80
 
87
81
  const john = Person.create({ name: "John" }, Account.getMe());
88
82
 
@@ -91,9 +85,9 @@ describe("CoMap", async () => {
91
85
  });
92
86
 
93
87
  test("create a CoMap with a group as owner", () => {
94
- class Person extends CoMap {
95
- name = co.string;
96
- }
88
+ const Person = co.map({
89
+ name: z.string(),
90
+ });
97
91
 
98
92
  const john = Person.create({ name: "John" }, Group.create());
99
93
 
@@ -102,28 +96,24 @@ describe("CoMap", async () => {
102
96
  });
103
97
 
104
98
  test("Empty schema", () => {
105
- const emptyMap = CoMap.create({});
99
+ const emptyMap = co.map({}).create({});
106
100
 
107
101
  // @ts-expect-error
108
102
  expect(emptyMap.color).toEqual(undefined);
109
103
  });
110
104
 
111
105
  test("setting date as undefined should throw", () => {
112
- class Person extends CoMap {
113
- color = co.string;
114
- _height = co.number;
115
- birthday = co.Date;
116
- name = co.string;
117
- nullable = co.optional.encoded<string | undefined>({
118
- encode: (value: string | undefined) => value || null,
119
- decode: (value: unknown) => (value as string) || undefined,
120
- });
121
- optionalDate = co.optional.Date;
122
-
123
- get roughColor() {
124
- return this.color + "ish";
125
- }
126
- }
106
+ const Person = co.map({
107
+ color: z.string(),
108
+ _height: z.number(),
109
+ birthday: z.date(),
110
+ name: z.string(),
111
+ // nullable: z.optional.encoded<string | undefined>({
112
+ // encode: (value: string | undefined) => value || null,
113
+ // decode: (value: unknown) => (value as string) || undefined,
114
+ // });
115
+ optionalDate: z.date().optional(),
116
+ });
127
117
 
128
118
  expect(() =>
129
119
  Person.create({
@@ -136,16 +126,16 @@ describe("CoMap", async () => {
136
126
  });
137
127
 
138
128
  test("CoMap with reference", () => {
139
- class Dog extends CoMap {
140
- name = co.string;
141
- breed = co.string;
142
- }
129
+ const Dog = co.map({
130
+ name: z.string(),
131
+ breed: z.string(),
132
+ });
143
133
 
144
- class Person extends CoMap {
145
- name = co.string;
146
- age = co.number;
147
- dog = co.ref(Dog);
148
- }
134
+ const Person = co.map({
135
+ name: z.string(),
136
+ age: z.number(),
137
+ dog: Dog,
138
+ });
149
139
 
150
140
  const person = Person.create({
151
141
  name: "John",
@@ -158,11 +148,14 @@ describe("CoMap", async () => {
158
148
  });
159
149
 
160
150
  test("CoMap with self reference", () => {
161
- class Person extends CoMap {
162
- name = co.string;
163
- age = co.number;
164
- friend = co.optional.ref(Person);
165
- }
151
+ const Person = co.map({
152
+ name: z.string(),
153
+ age: z.number(),
154
+ // TODO: would be nice if this didn't need a type annotation
155
+ get friend(): z.ZodOptional<typeof Person> {
156
+ return z.optional(Person);
157
+ },
158
+ });
166
159
 
167
160
  const person = Person.create({
168
161
  name: "John",
@@ -175,10 +168,10 @@ describe("CoMap", async () => {
175
168
  });
176
169
 
177
170
  test("toJSON should not fail when there is a key in the raw value not represented in the schema", () => {
178
- class Person extends CoMap {
179
- name = co.string;
180
- age = co.number;
181
- }
171
+ const Person = co.map({
172
+ name: z.string(),
173
+ age: z.number(),
174
+ });
182
175
 
183
176
  const person = Person.create({ name: "John", age: 20 });
184
177
 
@@ -193,11 +186,13 @@ describe("CoMap", async () => {
193
186
  });
194
187
 
195
188
  test("toJSON should handle references", () => {
196
- class Person extends CoMap {
197
- name = co.string;
198
- age = co.number;
199
- friend = co.optional.ref(Person);
200
- }
189
+ const Person = co.map({
190
+ name: z.string(),
191
+ age: z.number(),
192
+ get friend(): z.ZodOptional<typeof Person> {
193
+ return z.optional(Person);
194
+ },
195
+ });
201
196
 
202
197
  const person = Person.create({
203
198
  name: "John",
@@ -220,11 +215,13 @@ describe("CoMap", async () => {
220
215
  });
221
216
 
222
217
  test("toJSON should handle circular references", () => {
223
- class Person extends CoMap {
224
- name = co.string;
225
- age = co.number;
226
- friend = co.optional.ref(Person);
227
- }
218
+ const Person = co.map({
219
+ name: z.string(),
220
+ age: z.number(),
221
+ get friend(): z.ZodOptional<typeof Person> {
222
+ return z.optional(Person);
223
+ },
224
+ });
228
225
 
229
226
  const person = Person.create({
230
227
  name: "John",
@@ -245,11 +242,11 @@ describe("CoMap", async () => {
245
242
  });
246
243
 
247
244
  test("testing toJSON on a CoMap with a Date field", () => {
248
- class Person extends CoMap {
249
- name = co.string;
250
- age = co.number;
251
- birthday = co.Date;
252
- }
245
+ const Person = co.map({
246
+ name: z.string(),
247
+ age: z.number(),
248
+ birthday: z.date(),
249
+ });
253
250
 
254
251
  const birthday = new Date();
255
252
 
@@ -269,11 +266,11 @@ describe("CoMap", async () => {
269
266
  });
270
267
 
271
268
  test("setting optional date as undefined should not throw", () => {
272
- class Person extends CoMap {
273
- name = co.string;
274
- age = co.number;
275
- birthday = co.optional.Date;
276
- }
269
+ const Person = co.map({
270
+ name: z.string(),
271
+ age: z.number(),
272
+ birthday: z.date().optional(),
273
+ });
277
274
 
278
275
  const john = Person.create({
279
276
  name: "John",
@@ -287,10 +284,10 @@ describe("CoMap", async () => {
287
284
  });
288
285
 
289
286
  it("should disallow extra properties", () => {
290
- class Person extends CoMap {
291
- name = co.string;
292
- age = co.number;
293
- }
287
+ const Person = co.map({
288
+ name: z.string(),
289
+ age: z.number(),
290
+ });
294
291
 
295
292
  // @ts-expect-error - x is not a valid property
296
293
  const john = Person.create({ name: "John", age: 30, x: 1 });
@@ -306,10 +303,10 @@ describe("CoMap", async () => {
306
303
 
307
304
  describe("Mutation", () => {
308
305
  test("change a primitive value", () => {
309
- class Person extends CoMap {
310
- name = co.string;
311
- age = co.number;
312
- }
306
+ const Person = co.map({
307
+ name: z.string(),
308
+ age: z.number(),
309
+ });
313
310
 
314
311
  const john = Person.create({ name: "John", age: 20 });
315
312
 
@@ -320,10 +317,10 @@ describe("CoMap", async () => {
320
317
  });
321
318
 
322
319
  test("delete an optional value", () => {
323
- class Person extends CoMap {
324
- name = co.string;
325
- age = co.optional.number;
326
- }
320
+ const Person = co.map({
321
+ name: z.string(),
322
+ age: z.number().optional(),
323
+ });
327
324
 
328
325
  const john = Person.create({ name: "John", age: 20 });
329
326
 
@@ -340,15 +337,15 @@ describe("CoMap", async () => {
340
337
  });
341
338
 
342
339
  test("update a reference", () => {
343
- class Dog extends CoMap {
344
- name = co.string;
345
- }
340
+ const Dog = co.map({
341
+ name: z.string(),
342
+ });
346
343
 
347
- class Person extends CoMap {
348
- name = co.string;
349
- age = co.number;
350
- dog = co.ref(Dog);
351
- }
344
+ const Person = co.map({
345
+ name: z.string(),
346
+ age: z.number(),
347
+ dog: Dog,
348
+ });
352
349
 
353
350
  const john = Person.create({
354
351
  name: "John",
@@ -362,10 +359,10 @@ describe("CoMap", async () => {
362
359
  });
363
360
 
364
361
  test("changes should be listed in _edits", () => {
365
- class Person extends CoMap {
366
- name = co.string;
367
- age = co.number;
368
- }
362
+ const Person = co.map({
363
+ name: z.string(),
364
+ age: z.number(),
365
+ });
369
366
 
370
367
  const john = Person.create({ name: "John", age: 20 });
371
368
 
@@ -373,42 +370,46 @@ describe("CoMap", async () => {
373
370
 
374
371
  john.age = 21;
375
372
 
376
- expect(john._edits.age.all).toEqual([
377
- {
378
- by: expect.objectContaining({ _type: "Account", id: me.id }),
373
+ expect(john._edits.age?.all).toEqual([
374
+ expect.objectContaining({
379
375
  value: 20,
380
376
  key: "age",
381
377
  ref: undefined,
382
378
  madeAt: expect.any(Date),
383
- },
384
- {
385
- by: expect.objectContaining({ _type: "Account", id: me.id }),
379
+ }),
380
+ expect.objectContaining({
386
381
  value: 21,
387
382
  key: "age",
388
383
  ref: undefined,
389
384
  madeAt: expect.any(Date),
390
- },
385
+ }),
391
386
  ]);
387
+ expect(john._edits.age?.all[0]?.by).toMatchObject({
388
+ _type: "Account",
389
+ id: me.id,
390
+ });
391
+ expect(john._edits.age?.all[1]?.by).toMatchObject({
392
+ _type: "Account",
393
+ id: me.id,
394
+ });
392
395
  });
393
396
  });
394
397
 
395
398
  test("Enum of maps", () => {
396
- class MapWithEnumOfMaps extends CoMap {
397
- name = co.string;
398
- child = co.ref<typeof ChildA | typeof ChildB>((raw) =>
399
- raw.get("type") === "a" ? ChildA : ChildB,
400
- );
401
- }
402
-
403
- class ChildA extends CoMap {
404
- type = co.literal("a");
405
- value = co.number;
406
- }
407
-
408
- class ChildB extends CoMap {
409
- type = co.literal("b");
410
- value = co.string;
411
- }
399
+ const ChildA = co.map({
400
+ type: z.literal("a"),
401
+ value: z.number(),
402
+ });
403
+
404
+ const ChildB = co.map({
405
+ type: z.literal("b"),
406
+ value: z.string(),
407
+ });
408
+
409
+ const MapWithEnumOfMaps = co.map({
410
+ name: z.string(),
411
+ child: z.discriminatedUnion([ChildA, ChildB]),
412
+ });
412
413
 
413
414
  const mapWithEnum = MapWithEnumOfMaps.create({
414
415
  name: "enum",
@@ -422,21 +423,26 @@ describe("CoMap", async () => {
422
423
  expect(mapWithEnum.child?.type).toEqual("a");
423
424
  expect(mapWithEnum.child?.value).toEqual(5);
424
425
  expect(mapWithEnum.child?.id).toBeDefined();
426
+
427
+ // TODO: properly support narrowing once we get rid of the coField marker
428
+ // if (mapWithEnum.child?.type === "a") {
429
+ // expectTypeOf(mapWithEnum.child).toEqualTypeOf<Loaded<typeof ChildA>>();
430
+ // }
425
431
  });
426
432
  });
427
433
 
428
434
  describe("CoMap resolution", async () => {
429
435
  test("loading a locally available map with deep resolve", async () => {
430
- class Dog extends CoMap {
431
- name = co.string;
432
- breed = co.string;
433
- }
436
+ const Dog = co.map({
437
+ name: z.string(),
438
+ breed: z.string(),
439
+ });
434
440
 
435
- class Person extends CoMap {
436
- name = co.string;
437
- age = co.number;
438
- dog = co.ref(Dog);
439
- }
441
+ const Person = co.map({
442
+ name: z.string(),
443
+ age: z.number(),
444
+ dog: Dog,
445
+ });
440
446
 
441
447
  const person = Person.create({
442
448
  name: "John",
@@ -455,16 +461,16 @@ describe("CoMap resolution", async () => {
455
461
  });
456
462
 
457
463
  test("loading a locally available map using autoload for the refs", async () => {
458
- class Dog extends CoMap {
459
- name = co.string;
460
- breed = co.string;
461
- }
464
+ const Dog = co.map({
465
+ name: z.string(),
466
+ breed: z.string(),
467
+ });
462
468
 
463
- class Person extends CoMap {
464
- name = co.string;
465
- age = co.number;
466
- dog = co.ref(Dog);
467
- }
469
+ const Person = co.map({
470
+ name: z.string(),
471
+ age: z.number(),
472
+ dog: Dog,
473
+ });
468
474
 
469
475
  const person = Person.create({
470
476
  name: "John",
@@ -479,16 +485,16 @@ describe("CoMap resolution", async () => {
479
485
  });
480
486
 
481
487
  test("loading a remotely available map with deep resolve", async () => {
482
- class Dog extends CoMap {
483
- name = co.string;
484
- breed = co.string;
485
- }
488
+ const Dog = co.map({
489
+ name: z.string(),
490
+ breed: z.string(),
491
+ });
486
492
 
487
- class Person extends CoMap {
488
- name = co.string;
489
- age = co.number;
490
- dog = co.ref(Dog);
491
- }
493
+ const Person = co.map({
494
+ name: z.string(),
495
+ age: z.number(),
496
+ dog: Dog,
497
+ });
492
498
 
493
499
  const group = Group.create();
494
500
  group.addMember("everyone", "writer");
@@ -516,16 +522,16 @@ describe("CoMap resolution", async () => {
516
522
  });
517
523
 
518
524
  test("loading a remotely available map using autoload for the refs", async () => {
519
- class Dog extends CoMap {
520
- name = co.string;
521
- breed = co.string;
522
- }
525
+ const Dog = co.map({
526
+ name: z.string(),
527
+ breed: z.string(),
528
+ });
523
529
 
524
- class Person extends CoMap {
525
- name = co.string;
526
- age = co.number;
527
- dog = co.ref(Dog);
528
- }
530
+ const Person = co.map({
531
+ name: z.string(),
532
+ age: z.number(),
533
+ dog: Dog,
534
+ });
529
535
 
530
536
  const group = Group.create();
531
537
  group.addMember("everyone", "writer");
@@ -553,16 +559,16 @@ describe("CoMap resolution", async () => {
553
559
  });
554
560
 
555
561
  test("accessing the value refs", async () => {
556
- class Dog extends CoMap {
557
- name = co.string;
558
- breed = co.string;
559
- }
562
+ const Dog = co.map({
563
+ name: z.string(),
564
+ breed: z.string(),
565
+ });
560
566
 
561
- class Person extends CoMap {
562
- name = co.string;
563
- age = co.number;
564
- dog = co.ref(Dog);
565
- }
567
+ const Person = co.map({
568
+ name: z.string(),
569
+ age: z.number(),
570
+ dog: Dog,
571
+ });
566
572
 
567
573
  const group = Group.create();
568
574
  group.addMember("everyone", "writer");
@@ -583,9 +589,9 @@ describe("CoMap resolution", async () => {
583
589
 
584
590
  assert(loadedPerson);
585
591
 
586
- expect(loadedPerson._refs.dog.id).toBe(person.dog!.id);
592
+ expect(loadedPerson._refs.dog?.id).toBe(person.dog!.id);
587
593
 
588
- const dog = await loadedPerson._refs.dog.load();
594
+ const dog = await loadedPerson._refs.dog?.load();
589
595
 
590
596
  assert(dog);
591
597
 
@@ -593,16 +599,16 @@ describe("CoMap resolution", async () => {
593
599
  });
594
600
 
595
601
  test("subscription on a locally available map with deep resolve", async () => {
596
- class Dog extends CoMap {
597
- name = co.string;
598
- breed = co.string;
599
- }
602
+ const Dog = co.map({
603
+ name: z.string(),
604
+ breed: z.string(),
605
+ });
600
606
 
601
- class Person extends CoMap {
602
- name = co.string;
603
- age = co.number;
604
- dog = co.ref(Dog);
605
- }
607
+ const Person = co.map({
608
+ name: z.string(),
609
+ age: z.number(),
610
+ dog: Dog,
611
+ });
606
612
 
607
613
  const person = Person.create({
608
614
  name: "John",
@@ -610,7 +616,7 @@ describe("CoMap resolution", async () => {
610
616
  dog: Dog.create({ name: "Rex", breed: "Labrador" }),
611
617
  });
612
618
 
613
- const updates: Resolved<Person, { dog: true }>[] = [];
619
+ const updates: Loaded<typeof Person, { dog: true }>[] = [];
614
620
  const spy = vi.fn((person) => updates.push(person));
615
621
 
616
622
  Person.subscribe(
@@ -641,16 +647,16 @@ describe("CoMap resolution", async () => {
641
647
  });
642
648
 
643
649
  test("subscription on a locally available map with autoload", async () => {
644
- class Dog extends CoMap {
645
- name = co.string;
646
- breed = co.string;
647
- }
650
+ const Dog = co.map({
651
+ name: z.string(),
652
+ breed: z.string(),
653
+ });
648
654
 
649
- class Person extends CoMap {
650
- name = co.string;
651
- age = co.number;
652
- dog = co.ref(Dog);
653
- }
655
+ const Person = co.map({
656
+ name: z.string(),
657
+ age: z.number(),
658
+ dog: Dog,
659
+ });
654
660
 
655
661
  const person = Person.create({
656
662
  name: "John",
@@ -658,7 +664,7 @@ describe("CoMap resolution", async () => {
658
664
  dog: Dog.create({ name: "Rex", breed: "Labrador" }),
659
665
  });
660
666
 
661
- const updates: Person[] = [];
667
+ const updates: Loaded<typeof Person>[] = [];
662
668
  const spy = vi.fn((person) => updates.push(person));
663
669
 
664
670
  Person.subscribe(person.id, {}, spy);
@@ -681,16 +687,16 @@ describe("CoMap resolution", async () => {
681
687
  });
682
688
 
683
689
  test("subscription on a locally available map with syncResolution", async () => {
684
- class Dog extends CoMap {
685
- name = co.string;
686
- breed = co.string;
687
- }
690
+ const Dog = co.map({
691
+ name: z.string(),
692
+ breed: z.string(),
693
+ });
688
694
 
689
- class Person extends CoMap {
690
- name = co.string;
691
- age = co.number;
692
- dog = co.ref(Dog);
693
- }
695
+ const Person = co.map({
696
+ name: z.string(),
697
+ age: z.number(),
698
+ dog: Dog,
699
+ });
694
700
 
695
701
  const person = Person.create({
696
702
  name: "John",
@@ -698,11 +704,11 @@ describe("CoMap resolution", async () => {
698
704
  dog: Dog.create({ name: "Rex", breed: "Labrador" }),
699
705
  });
700
706
 
701
- const updates: Person[] = [];
707
+ const updates: Loaded<typeof Person>[] = [];
702
708
  const spy = vi.fn((person) => updates.push(person));
703
709
 
704
710
  subscribeToCoValue(
705
- Person,
711
+ zodSchemaToCoSchema(Person), // TODO: we should get rid of the conversion in the future
706
712
  person.id,
707
713
  {
708
714
  syncResolution: true,
@@ -728,16 +734,16 @@ describe("CoMap resolution", async () => {
728
734
  });
729
735
 
730
736
  test("subscription on a remotely available map with deep resolve", async () => {
731
- class Dog extends CoMap {
732
- name = co.string;
733
- breed = co.string;
734
- }
737
+ const Dog = co.map({
738
+ name: z.string(),
739
+ breed: z.string(),
740
+ });
735
741
 
736
- class Person extends CoMap {
737
- name = co.string;
738
- age = co.number;
739
- dog = co.ref(Dog);
740
- }
742
+ const Person = co.map({
743
+ name: z.string(),
744
+ age: z.number(),
745
+ dog: Dog,
746
+ });
741
747
 
742
748
  const group = Group.create();
743
749
  group.addMember("everyone", "writer");
@@ -753,7 +759,7 @@ describe("CoMap resolution", async () => {
753
759
 
754
760
  const userB = await createJazzTestAccount();
755
761
 
756
- const updates: Resolved<Person, { dog: true }>[] = [];
762
+ const updates: Loaded<typeof Person, { dog: true }>[] = [];
757
763
  const spy = vi.fn((person) => updates.push(person));
758
764
 
759
765
  Person.subscribe(
@@ -785,16 +791,16 @@ describe("CoMap resolution", async () => {
785
791
  });
786
792
 
787
793
  test("subscription on a remotely available map with autoload", async () => {
788
- class Dog extends CoMap {
789
- name = co.string;
790
- breed = co.string;
791
- }
794
+ const Dog = co.map({
795
+ name: z.string(),
796
+ breed: z.string(),
797
+ });
792
798
 
793
- class Person extends CoMap {
794
- name = co.string;
795
- age = co.number;
796
- dog = co.ref(Dog);
797
- }
799
+ const Person = co.map({
800
+ name: z.string(),
801
+ age: z.number(),
802
+ dog: Dog,
803
+ });
798
804
 
799
805
  const group = Group.create();
800
806
  group.addMember("everyone", "writer");
@@ -808,7 +814,7 @@ describe("CoMap resolution", async () => {
808
814
  group,
809
815
  );
810
816
 
811
- const updates: Person[] = [];
817
+ const updates: Loaded<typeof Person>[] = [];
812
818
  const spy = vi.fn((person) => updates.push(person));
813
819
 
814
820
  const userB = await createJazzTestAccount();
@@ -839,16 +845,16 @@ describe("CoMap resolution", async () => {
839
845
  });
840
846
 
841
847
  test("replacing nested object triggers updates", async () => {
842
- class Dog extends CoMap {
843
- name = co.string;
844
- breed = co.string;
845
- }
848
+ const Dog = co.map({
849
+ name: z.string(),
850
+ breed: z.string(),
851
+ });
846
852
 
847
- class Person extends CoMap {
848
- name = co.string;
849
- age = co.number;
850
- dog = co.ref(Dog);
851
- }
853
+ const Person = co.map({
854
+ name: z.string(),
855
+ age: z.number(),
856
+ dog: Dog,
857
+ });
852
858
 
853
859
  const person = Person.create({
854
860
  name: "John",
@@ -856,7 +862,7 @@ describe("CoMap resolution", async () => {
856
862
  dog: Dog.create({ name: "Rex", breed: "Labrador" }),
857
863
  });
858
864
 
859
- const updates: Resolved<Person, { dog: true }>[] = [];
865
+ const updates: Loaded<typeof Person, { dog: true }>[] = [];
860
866
  const spy = vi.fn((person) => updates.push(person));
861
867
 
862
868
  Person.subscribe(
@@ -893,19 +899,19 @@ describe("CoMap applyDiff", async () => {
893
899
  crypto: Crypto,
894
900
  });
895
901
 
896
- class TestMap extends CoMap {
897
- name = co.string;
898
- age = co.number;
899
- isActive = co.boolean;
900
- birthday = co.encoded(Encoders.Date);
901
- nested = co.ref(NestedMap);
902
- optionalField = co.optional.string;
903
- optionalNested = co.optional.ref(NestedMap);
904
- }
902
+ const NestedMap = co.map({
903
+ value: z.string(),
904
+ });
905
905
 
906
- class NestedMap extends CoMap {
907
- value = co.string;
908
- }
906
+ const TestMap = co.map({
907
+ name: z.string(),
908
+ age: z.number(),
909
+ isActive: z.boolean(),
910
+ birthday: z.date(),
911
+ nested: NestedMap,
912
+ optionalField: z.string().optional(),
913
+ optionalNested: z.optional(NestedMap),
914
+ });
909
915
 
910
916
  test("Basic applyDiff", () => {
911
917
  const map = TestMap.create(
@@ -1047,7 +1053,7 @@ describe("CoMap applyDiff", async () => {
1047
1053
  expect((map as any).invalidField).toBeUndefined();
1048
1054
  });
1049
1055
 
1050
- test("applyDiff with optional reference set to null", () => {
1056
+ test("applyDiff with optional reference set to undefined", () => {
1051
1057
  const map = TestMap.create(
1052
1058
  {
1053
1059
  name: "Jack",
@@ -1061,15 +1067,15 @@ describe("CoMap applyDiff", async () => {
1061
1067
  );
1062
1068
 
1063
1069
  const newValues = {
1064
- optionalNested: null,
1070
+ optionalNested: undefined,
1065
1071
  };
1066
1072
 
1067
1073
  map.applyDiff(newValues);
1068
1074
 
1069
- expect(map.optionalNested).toBeNull();
1075
+ expect(map.optionalNested).toBeUndefined();
1070
1076
  });
1071
1077
 
1072
- test("applyDiff with required reference set to null should throw", () => {
1078
+ test("applyDiff with required reference set to undefined should throw", () => {
1073
1079
  const map = TestMap.create(
1074
1080
  {
1075
1081
  name: "Kate",
@@ -1082,12 +1088,11 @@ describe("CoMap applyDiff", async () => {
1082
1088
  );
1083
1089
 
1084
1090
  const newValues = {
1085
- nested: null,
1091
+ nested: undefined,
1086
1092
  };
1087
1093
 
1088
- // @ts-expect-error testing invalid usage
1089
1094
  expect(() => map.applyDiff(newValues)).toThrowError(
1090
- "Cannot set required reference nested to null",
1095
+ "Cannot set required reference nested to undefined",
1091
1096
  );
1092
1097
  });
1093
1098
  });
@@ -1099,16 +1104,16 @@ describe("CoMap Typescript validation", async () => {
1099
1104
  });
1100
1105
 
1101
1106
  test("Is not ok to pass null into a required ref", () => {
1102
- class TestMap extends CoMap {
1103
- required = co.ref(NestedMap);
1104
- optional = co.optional.ref(NestedMap);
1105
- }
1107
+ const NestedMap = co.map({
1108
+ value: z.string(),
1109
+ });
1106
1110
 
1107
- class NestedMap extends CoMap {
1108
- value = co.string;
1109
- }
1111
+ const TestMap = co.map({
1112
+ required: NestedMap,
1113
+ optional: NestedMap.optional(),
1114
+ });
1110
1115
 
1111
- expectTypeOf<typeof TestMap.create<TestMap>>().toBeCallableWith(
1116
+ expectTypeOf<typeof TestMap.create>().toBeCallableWith(
1112
1117
  {
1113
1118
  optional: NestedMap.create({ value: "" }, { owner: me }),
1114
1119
  // @ts-expect-error null can't be passed to a non-optional field
@@ -1119,16 +1124,16 @@ describe("CoMap Typescript validation", async () => {
1119
1124
  });
1120
1125
 
1121
1126
  test("Is not ok if a required ref is omitted", () => {
1122
- class TestMap extends CoMap {
1123
- required = co.ref(NestedMap);
1124
- optional = co.ref(NestedMap, { optional: true });
1125
- }
1127
+ const NestedMap = co.map({
1128
+ value: z.string(),
1129
+ });
1126
1130
 
1127
- class NestedMap extends CoMap {
1128
- value = co.string;
1129
- }
1131
+ const TestMap = co.map({
1132
+ required: NestedMap,
1133
+ optional: NestedMap.optional(),
1134
+ });
1130
1135
 
1131
- expectTypeOf<typeof TestMap.create<TestMap>>().toBeCallableWith(
1136
+ expectTypeOf<typeof TestMap.create>().toBeCallableWith(
1132
1137
  // @ts-expect-error non-optional fields can't be omitted
1133
1138
  {},
1134
1139
  { owner: me },
@@ -1136,55 +1141,35 @@ describe("CoMap Typescript validation", async () => {
1136
1141
  });
1137
1142
 
1138
1143
  test("Is ok to omit optional fields", () => {
1139
- class TestMap extends CoMap {
1140
- required = co.ref(NestedMap);
1141
- optional = co.ref(NestedMap, { optional: true });
1142
- }
1143
-
1144
- class NestedMap extends CoMap {
1145
- value = co.string;
1146
- }
1144
+ const NestedMap = co.map({
1145
+ value: z.string(),
1146
+ });
1147
1147
 
1148
- expectTypeOf<typeof TestMap.create<TestMap>>().toBeCallableWith(
1149
- {
1150
- required: NestedMap.create({ value: "" }, { owner: me }),
1151
- },
1152
- { owner: me },
1153
- );
1148
+ const TestMap = co.map({
1149
+ required: NestedMap,
1150
+ optional: NestedMap.optional(),
1151
+ });
1154
1152
 
1155
- expectTypeOf<typeof TestMap.create<TestMap>>().toBeCallableWith(
1153
+ expectTypeOf<typeof TestMap.create>().toBeCallableWith(
1156
1154
  {
1157
1155
  required: NestedMap.create({ value: "" }, { owner: me }),
1158
- optional: null,
1159
1156
  },
1160
1157
  { owner: me },
1161
1158
  );
1162
- });
1163
-
1164
- test("the required refs should be nullable", () => {
1165
- class TestMap extends CoMap {
1166
- required = co.ref(NestedMap);
1167
- optional = co.ref(NestedMap, { optional: true });
1168
- }
1169
-
1170
- class NestedMap extends CoMap {
1171
- value = co.string;
1172
- }
1173
1159
 
1174
- const map = TestMap.create(
1160
+ expectTypeOf<typeof TestMap.create>().toBeCallableWith(
1175
1161
  {
1176
1162
  required: NestedMap.create({ value: "" }, { owner: me }),
1163
+ optional: undefined, // TODO: should we allow null here? zod is stricter about this than we were before
1177
1164
  },
1178
1165
  { owner: me },
1179
1166
  );
1180
-
1181
- expectTypeOf(map.required).toBeNullable();
1182
1167
  });
1183
1168
 
1184
1169
  test("waitForSync should resolve when the value is uploaded", async () => {
1185
- class TestMap extends CoMap {
1186
- name = co.string;
1187
- }
1170
+ const TestMap = co.map({
1171
+ name: z.string(),
1172
+ });
1188
1173
 
1189
1174
  const { clientNode, serverNode, clientAccount } = await setupTwoNodes();
1190
1175
 
@@ -1210,12 +1195,12 @@ describe("Creating and finding unique CoMaps", async () => {
1210
1195
  test("Creating and finding unique CoMaps", async () => {
1211
1196
  const group = Group.create();
1212
1197
 
1213
- class Person extends CoMap {
1214
- name = co.string;
1215
- _height = co.number;
1216
- birthday = co.Date;
1217
- color = co.string;
1218
- }
1198
+ const Person = co.map({
1199
+ name: z.string(),
1200
+ _height: z.number(),
1201
+ birthday: z.date(),
1202
+ color: z.string(),
1203
+ });
1219
1204
 
1220
1205
  const alice = Person.create(
1221
1206
  {