jazz-tools 0.17.13 → 0.18.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 (228) hide show
  1. package/.svelte-kit/__package__/jazz.class.svelte.js +1 -1
  2. package/.svelte-kit/__package__/media/image.svelte +3 -9
  3. package/.svelte-kit/__package__/media/image.svelte.d.ts +1 -6
  4. package/.svelte-kit/__package__/media/image.svelte.d.ts.map +1 -1
  5. package/.svelte-kit/__package__/media/image.types.d.ts +7 -0
  6. package/.svelte-kit/__package__/media/image.types.d.ts.map +1 -0
  7. package/.svelte-kit/__package__/media/image.types.js +1 -0
  8. package/.svelte-kit/__package__/tests/media/image.svelte.test.js +31 -31
  9. package/.turbo/turbo-build.log +49 -49
  10. package/CHANGELOG.md +42 -0
  11. package/dist/browser/index.js +2 -2
  12. package/dist/browser/index.js.map +1 -1
  13. package/dist/{chunk-SFP5PBPX.js → chunk-HJ3GTGY7.js} +1325 -1001
  14. package/dist/chunk-HJ3GTGY7.js.map +1 -0
  15. package/dist/index.js +18 -18
  16. package/dist/index.js.map +1 -1
  17. package/dist/inspector/{custom-element-ZSNTCECD.js → custom-element-WCY6D3QJ.js} +3 -3
  18. package/dist/inspector/{custom-element-ZSNTCECD.js.map → custom-element-WCY6D3QJ.js.map} +1 -1
  19. package/dist/inspector/index.js +1 -1
  20. package/dist/inspector/index.js.map +1 -1
  21. package/dist/inspector/register-custom-element.js +1 -1
  22. package/dist/media/{chunk-E5J3WLQW.js → chunk-KR2V6X2N.js} +14 -9
  23. package/dist/media/chunk-KR2V6X2N.js.map +1 -0
  24. package/dist/media/create-image.d.ts +6 -6
  25. package/dist/media/index.browser.d.ts +6 -6
  26. package/dist/media/index.browser.js +1 -1
  27. package/dist/media/index.d.ts +1 -1
  28. package/dist/media/index.js +1 -1
  29. package/dist/media/index.native.d.ts +6 -6
  30. package/dist/media/index.native.js +1 -1
  31. package/dist/media/utils.d.ts.map +1 -1
  32. package/dist/prosemirror/index.js +2 -2
  33. package/dist/prosemirror/index.js.map +1 -1
  34. package/dist/react/index.js +7 -5
  35. package/dist/react/index.js.map +1 -1
  36. package/dist/react-core/hooks.d.ts.map +1 -1
  37. package/dist/react-core/index.js +4658 -23
  38. package/dist/react-core/index.js.map +1 -1
  39. package/dist/react-native-core/index.js +1 -1
  40. package/dist/react-native-core/index.js.map +1 -1
  41. package/dist/svelte/jazz.class.svelte.js +1 -1
  42. package/dist/svelte/media/image.svelte +3 -9
  43. package/dist/svelte/media/image.svelte.d.ts +1 -6
  44. package/dist/svelte/media/image.svelte.d.ts.map +1 -1
  45. package/dist/svelte/media/image.types.d.ts +7 -0
  46. package/dist/svelte/media/image.types.d.ts.map +1 -0
  47. package/dist/svelte/media/image.types.js +1 -0
  48. package/dist/svelte/tests/media/image.svelte.test.js +31 -31
  49. package/dist/testing.js +18 -14
  50. package/dist/testing.js.map +1 -1
  51. package/dist/tools/coValues/CoFieldInit.d.ts +13 -0
  52. package/dist/tools/coValues/CoFieldInit.d.ts.map +1 -0
  53. package/dist/tools/coValues/CoValueBase.d.ts +18 -15
  54. package/dist/tools/coValues/CoValueBase.d.ts.map +1 -1
  55. package/dist/tools/coValues/account.d.ts +100 -46
  56. package/dist/tools/coValues/account.d.ts.map +1 -1
  57. package/dist/tools/coValues/coFeed.d.ts +78 -62
  58. package/dist/tools/coValues/coFeed.d.ts.map +1 -1
  59. package/dist/tools/coValues/coList.d.ts +212 -99
  60. package/dist/tools/coValues/coList.d.ts.map +1 -1
  61. package/dist/tools/coValues/coMap.d.ts +200 -192
  62. package/dist/tools/coValues/coMap.d.ts.map +1 -1
  63. package/dist/tools/coValues/coPlainText.d.ts +30 -22
  64. package/dist/tools/coValues/coPlainText.d.ts.map +1 -1
  65. package/dist/tools/coValues/deepLoading.d.ts +13 -13
  66. package/dist/tools/coValues/deepLoading.d.ts.map +1 -1
  67. package/dist/tools/coValues/extensions/imageDef.d.ts +1 -1
  68. package/dist/tools/coValues/group.d.ts +32 -32
  69. package/dist/tools/coValues/group.d.ts.map +1 -1
  70. package/dist/tools/coValues/inbox.d.ts.map +1 -1
  71. package/dist/tools/coValues/interfaces.d.ts +18 -17
  72. package/dist/tools/coValues/interfaces.d.ts.map +1 -1
  73. package/dist/tools/coValues/profile.d.ts +6 -5
  74. package/dist/tools/coValues/profile.d.ts.map +1 -1
  75. package/dist/tools/coValues/schemaUnion.d.ts +3 -3
  76. package/dist/tools/coValues/schemaUnion.d.ts.map +1 -1
  77. package/dist/tools/exports.d.ts +1 -1
  78. package/dist/tools/exports.d.ts.map +1 -1
  79. package/dist/tools/implementation/anonymousJazzAgent.d.ts +2 -1
  80. package/dist/tools/implementation/anonymousJazzAgent.d.ts.map +1 -1
  81. package/dist/tools/implementation/schema.d.ts +5 -5
  82. package/dist/tools/implementation/schema.d.ts.map +1 -1
  83. package/dist/tools/implementation/symbols.d.ts +2 -0
  84. package/dist/tools/implementation/symbols.d.ts.map +1 -1
  85. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts +2 -2
  86. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -1
  87. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts +6 -2
  88. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts.map +1 -1
  89. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +8 -3
  90. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -1
  91. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts +12 -7
  92. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts.map +1 -1
  93. package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts +13 -7
  94. package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts.map +1 -1
  95. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts +11 -2
  96. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts.map +1 -1
  97. package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts +4 -0
  98. package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts.map +1 -1
  99. package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts +4 -0
  100. package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts.map +1 -1
  101. package/dist/tools/implementation/zodSchema/typeConverters/{CoFieldInit.d.ts → CoFieldSchemaInit.d.ts} +7 -7
  102. package/dist/tools/implementation/zodSchema/typeConverters/CoFieldSchemaInit.d.ts.map +1 -0
  103. package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchema.d.ts +4 -4
  104. package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchema.d.ts.map +1 -1
  105. package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.d.ts +4 -4
  106. package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.d.ts.map +1 -1
  107. package/dist/tools/implementation/zodSchema/zodCo.d.ts +2 -2
  108. package/dist/tools/implementation/zodSchema/zodCo.d.ts.map +1 -1
  109. package/dist/tools/internal.d.ts +2 -1
  110. package/dist/tools/internal.d.ts.map +1 -1
  111. package/dist/tools/lib/migration.d.ts +1 -1
  112. package/dist/tools/lib/migration.d.ts.map +1 -1
  113. package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
  114. package/dist/tools/subscribe/index.d.ts +1 -1
  115. package/dist/tools/subscribe/index.d.ts.map +1 -1
  116. package/dist/tools/subscribe/utils.d.ts +2 -2
  117. package/dist/tools/subscribe/utils.d.ts.map +1 -1
  118. package/dist/tools/testing.d.ts.map +1 -1
  119. package/dist/tools/tests/utils.d.ts +2 -6
  120. package/dist/tools/tests/utils.d.ts.map +1 -1
  121. package/dist/worker/index.js +3 -3
  122. package/dist/worker/index.js.map +1 -1
  123. package/package.json +4 -4
  124. package/src/browser/auth/PasskeyAuth.ts +2 -2
  125. package/src/browser/createBrowserContext.ts +2 -2
  126. package/src/browser/tests/PasskeyAuth.test.ts +2 -2
  127. package/src/inspector/custom-element.tsx +2 -2
  128. package/src/inspector/viewer/new-app.tsx +1 -1
  129. package/src/media/create-image.test.ts +7 -7
  130. package/src/media/create-image.ts +5 -3
  131. package/src/media/index.ts +1 -1
  132. package/src/media/utils.test.ts +72 -66
  133. package/src/media/utils.ts +9 -6
  134. package/src/prosemirror/lib/plugin.ts +1 -1
  135. package/src/prosemirror/lib/sync.ts +1 -1
  136. package/src/prosemirror/tests/plugin.test.ts +4 -4
  137. package/src/react/media/image.tsx +2 -2
  138. package/src/react/tests/media/image.test.tsx +52 -32
  139. package/src/react-core/hooks.ts +11 -5
  140. package/src/react-core/tests/useAccount.test.ts +16 -22
  141. package/src/react-core/tests/useCoState.test.ts +19 -19
  142. package/src/react-core/tests/useInboxSender.test.ts +5 -2
  143. package/src/react-core/tests/usePassPhraseAuth.test.ts +6 -6
  144. package/src/react-native-core/media/image.tsx +1 -1
  145. package/src/svelte/jazz.class.svelte.ts +1 -1
  146. package/src/svelte/media/image.svelte +3 -9
  147. package/src/svelte/media/image.types.ts +7 -0
  148. package/src/svelte/tests/media/image.svelte.test.ts +34 -32
  149. package/src/tools/auth/DemoAuth.ts +2 -2
  150. package/src/tools/auth/PassphraseAuth.ts +2 -2
  151. package/src/tools/auth/clerk/index.ts +2 -2
  152. package/src/tools/auth/clerk/tests/JazzClerkAuth.test.ts +1 -1
  153. package/src/tools/coValues/CoFieldInit.ts +20 -0
  154. package/src/tools/coValues/CoValueBase.ts +40 -60
  155. package/src/tools/coValues/account.ts +306 -232
  156. package/src/tools/coValues/coFeed.ts +185 -153
  157. package/src/tools/coValues/coList.ts +507 -334
  158. package/src/tools/coValues/coMap.ts +420 -286
  159. package/src/tools/coValues/coPlainText.ts +94 -110
  160. package/src/tools/coValues/deepLoading.ts +13 -13
  161. package/src/tools/coValues/group.ts +100 -114
  162. package/src/tools/coValues/inbox.ts +16 -14
  163. package/src/tools/coValues/interfaces.ts +49 -31
  164. package/src/tools/coValues/profile.ts +8 -6
  165. package/src/tools/coValues/request.ts +9 -9
  166. package/src/tools/coValues/schemaUnion.ts +11 -5
  167. package/src/tools/exports.ts +1 -1
  168. package/src/tools/implementation/ContextManager.ts +4 -4
  169. package/src/tools/implementation/anonymousJazzAgent.ts +2 -1
  170. package/src/tools/implementation/createContext.ts +1 -1
  171. package/src/tools/implementation/devtoolsFormatters.ts +9 -9
  172. package/src/tools/implementation/invites.ts +2 -2
  173. package/src/tools/implementation/schema.ts +7 -7
  174. package/src/tools/implementation/symbols.ts +3 -0
  175. package/src/tools/implementation/zodSchema/schemaTypes/AccountSchema.ts +2 -2
  176. package/src/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.ts +11 -2
  177. package/src/tools/implementation/zodSchema/schemaTypes/CoListSchema.ts +18 -7
  178. package/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts +17 -7
  179. package/src/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.ts +20 -11
  180. package/src/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.ts +19 -2
  181. package/src/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.ts +6 -0
  182. package/src/tools/implementation/zodSchema/schemaTypes/RichTextSchema.ts +6 -0
  183. package/src/tools/implementation/zodSchema/typeConverters/{CoFieldInit.ts → CoFieldSchemaInit.ts} +11 -11
  184. package/src/tools/implementation/zodSchema/typeConverters/InstanceOfSchema.ts +4 -4
  185. package/src/tools/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.ts +4 -4
  186. package/src/tools/implementation/zodSchema/zodCo.ts +47 -10
  187. package/src/tools/internal.ts +2 -1
  188. package/src/tools/lib/migration.ts +5 -5
  189. package/src/tools/subscribe/SubscriptionScope.ts +32 -24
  190. package/src/tools/subscribe/index.ts +4 -4
  191. package/src/tools/subscribe/utils.ts +11 -11
  192. package/src/tools/testing.ts +17 -13
  193. package/src/tools/tests/ContextManager.test.ts +68 -57
  194. package/src/tools/tests/PassphraseAuth.test.ts +2 -2
  195. package/src/tools/tests/account.test.ts +154 -74
  196. package/src/tools/tests/coDiscriminatedUnion.test-d.ts +12 -6
  197. package/src/tools/tests/coDiscriminatedUnion.test.ts +26 -17
  198. package/src/tools/tests/coFeed.test-d.ts +18 -17
  199. package/src/tools/tests/coFeed.test.ts +108 -97
  200. package/src/tools/tests/coList.test-d.ts +18 -23
  201. package/src/tools/tests/coList.test.ts +350 -165
  202. package/src/tools/tests/coMap.record.test-d.ts +9 -13
  203. package/src/tools/tests/coMap.record.test.ts +37 -23
  204. package/src/tools/tests/coMap.test-d.ts +43 -21
  205. package/src/tools/tests/coMap.test.ts +368 -182
  206. package/src/tools/tests/coOptional.test.ts +28 -13
  207. package/src/tools/tests/coPlainText.test.ts +15 -15
  208. package/src/tools/tests/createContext.test.ts +14 -14
  209. package/src/tools/tests/deepLoading.test.ts +95 -94
  210. package/src/tools/tests/exportImport.test.ts +61 -41
  211. package/src/tools/tests/groupsAndAccounts.test.ts +333 -116
  212. package/src/tools/tests/inbox.test.ts +22 -17
  213. package/src/tools/tests/interfaces.test.ts +12 -11
  214. package/src/tools/tests/invites.test.ts +6 -4
  215. package/src/tools/tests/load.test.ts +20 -18
  216. package/src/tools/tests/patterns/notifications.test.ts +6 -6
  217. package/src/tools/tests/patterns/quest.test.ts +3 -3
  218. package/src/tools/tests/patterns/requestToJoin.test.ts +22 -22
  219. package/src/tools/tests/request.test.ts +38 -39
  220. package/src/tools/tests/schemaUnion.test.ts +64 -10
  221. package/src/tools/tests/subscribe.test.ts +64 -64
  222. package/src/tools/tests/testing.test.ts +5 -9
  223. package/src/tools/tests/utils.ts +3 -3
  224. package/src/tools/tests/zod.test.ts +3 -3
  225. package/src/worker/index.ts +3 -3
  226. package/dist/chunk-SFP5PBPX.js.map +0 -1
  227. package/dist/media/chunk-E5J3WLQW.js.map +0 -1
  228. package/dist/tools/implementation/zodSchema/typeConverters/CoFieldInit.d.ts.map +0 -1
@@ -14,6 +14,7 @@ import { Group, co, subscribeToCoValue, z } from "../exports.js";
14
14
  import { Account } from "../index.js";
15
15
  import {
16
16
  Loaded,
17
+ TypeSym,
17
18
  activeAccountContext,
18
19
  coValueClassFromCoValueClassOrSchema,
19
20
  } from "../internal.js";
@@ -69,7 +70,7 @@ describe("CoMap", async () => {
69
70
  expect(john.color).toEqual("red");
70
71
  expect(john._height).toEqual(10);
71
72
  expect(john.birthday).toEqual(birthday);
72
- expect(john._raw.get("birthday")).toEqual(birthday.toISOString());
73
+ expect(john.$jazz.raw.get("birthday")).toEqual(birthday.toISOString());
73
74
  expect(Object.keys(john)).toEqual([
74
75
  "color",
75
76
  "_height",
@@ -93,6 +94,17 @@ describe("CoMap", async () => {
93
94
  expect("age" in john).toEqual(false);
94
95
  });
95
96
 
97
+ test("internal properties are not enumerable", () => {
98
+ const Person = co.map({
99
+ name: z.string(),
100
+ });
101
+
102
+ const person = Person.create({ name: "John" });
103
+
104
+ expect(Object.keys(person)).toEqual(["name"]);
105
+ expect(person).toEqual({ name: "John" });
106
+ });
107
+
96
108
  test("create a CoMap with an account as owner", () => {
97
109
  const Person = co.map({
98
110
  name: z.string(),
@@ -101,7 +113,7 @@ describe("CoMap", async () => {
101
113
  const john = Person.create({ name: "John" }, Account.getMe());
102
114
 
103
115
  expect(john.name).toEqual("John");
104
- expect(john._raw.get("name")).toEqual("John");
116
+ expect(john.$jazz.raw.get("name")).toEqual("John");
105
117
  });
106
118
 
107
119
  test("create a CoMap with a group as owner", () => {
@@ -112,7 +124,7 @@ describe("CoMap", async () => {
112
124
  const john = Person.create({ name: "John" }, Group.create());
113
125
 
114
126
  expect(john.name).toEqual("John");
115
- expect(john._raw.get("name")).toEqual("John");
127
+ expect(john.$jazz.raw.get("name")).toEqual("John");
116
128
  });
117
129
 
118
130
  test("Empty schema", () => {
@@ -151,7 +163,7 @@ describe("CoMap", async () => {
151
163
  type: z.literal("cat"),
152
164
  name: z.string(),
153
165
  });
154
-
166
+ const Pet = co.discriminatedUnion("type", [Dog, Cat]);
155
167
  const Person = co.map({
156
168
  name: co.plainText(),
157
169
  bio: co.richText(),
@@ -160,7 +172,8 @@ describe("CoMap", async () => {
160
172
  return co.list(Person);
161
173
  },
162
174
  reactions: co.feed(co.plainText()),
163
- pet: co.discriminatedUnion("type", [Dog, Cat]),
175
+ pet: Pet,
176
+ pets: co.record(z.string(), Pet),
164
177
  });
165
178
 
166
179
  let person: ReturnType<typeof Person.create>;
@@ -178,10 +191,17 @@ describe("CoMap", async () => {
178
191
  friends: [],
179
192
  reactions: [],
180
193
  pet: { type: "dog", name: "Fido" },
194
+ pets: {
195
+ dog: { type: "dog", name: "Fido" },
196
+ },
181
197
  },
182
198
  ],
183
199
  reactions: ["👎", "👍"],
184
200
  pet: { type: "cat", name: "Whiskers" },
201
+ pets: {
202
+ dog: { type: "dog", name: "Rex" },
203
+ cat: { type: "cat", name: "Whiskers" },
204
+ },
185
205
  });
186
206
  });
187
207
 
@@ -198,19 +218,25 @@ describe("CoMap", async () => {
198
218
  expect(person.friends[0]?.friends.length).toEqual(0);
199
219
  expect(person.reactions.byMe?.value?.toString()).toEqual("👍");
200
220
  expect(person.pet.name).toEqual("Whiskers");
221
+ expect(person.pets.dog?.name).toEqual("Rex");
222
+ expect(person.pets.cat?.name).toEqual("Whiskers");
201
223
  });
202
224
 
203
225
  it("creates a group for each new CoValue that is a child of the referencing CoValue's owner", () => {
204
226
  for (const value of Object.values(person)) {
205
227
  expect(
206
- value._owner.getParentGroups().map((group: Group) => group.id),
207
- ).toContain(person._owner.id);
228
+ value.$jazz.owner
229
+ .getParentGroups()
230
+ .map((group: Group) => group.$jazz.id),
231
+ ).toContain(person.$jazz.owner.$jazz.id);
208
232
  }
209
233
  const friend = person.friends[0]!;
210
234
  for (const value of Object.values(friend)) {
211
235
  expect(
212
- value._owner.getParentGroups().map((group: Group) => group.id),
213
- ).toContain(friend._owner.id);
236
+ value.$jazz.owner
237
+ .getParentGroups()
238
+ .map((group: Group) => group.$jazz.id),
239
+ ).toContain(friend.$jazz.owner.$jazz.id);
214
240
  }
215
241
  });
216
242
 
@@ -228,8 +254,10 @@ describe("CoMap", async () => {
228
254
  const map = Schema.create({ text: "Hello" }, parentGroup);
229
255
 
230
256
  expect(
231
- map.text._owner.getParentGroups().map((group: Group) => group.id),
232
- ).toContain(parentGroup.id);
257
+ map.text.$jazz.owner
258
+ .getParentGroups()
259
+ .map((group: Group) => group.$jazz.id),
260
+ ).toContain(parentGroup.$jazz.id);
233
261
  });
234
262
  });
235
263
  });
@@ -253,6 +281,16 @@ describe("CoMap", async () => {
253
281
  expect(person.friend?.age).toEqual(21);
254
282
  });
255
283
 
284
+ test("JSON.stringify should not include internal properties", () => {
285
+ const Person = co.map({
286
+ name: z.string(),
287
+ });
288
+
289
+ const person = Person.create({ name: "John" });
290
+
291
+ expect(JSON.stringify(person)).toEqual('{"name":"John"}');
292
+ });
293
+
256
294
  test("toJSON should not fail when there is a key in the raw value not represented in the schema", () => {
257
295
  const Person = co.map({
258
296
  name: z.string(),
@@ -261,11 +299,9 @@ describe("CoMap", async () => {
261
299
 
262
300
  const person = Person.create({ name: "John", age: 20 });
263
301
 
264
- person._raw.set("extra", "extra");
302
+ person.$jazz.raw.set("extra", "extra");
265
303
 
266
304
  expect(person.toJSON()).toEqual({
267
- _type: "CoMap",
268
- id: person.id,
269
305
  name: "John",
270
306
  age: 20,
271
307
  });
@@ -287,13 +323,9 @@ describe("CoMap", async () => {
287
323
  });
288
324
 
289
325
  expect(person.toJSON()).toEqual({
290
- _type: "CoMap",
291
- id: person.id,
292
326
  name: "John",
293
327
  age: 20,
294
328
  friend: {
295
- _type: "CoMap",
296
- id: person.friend?.id,
297
329
  name: "Jane",
298
330
  age: 21,
299
331
  },
@@ -314,15 +346,13 @@ describe("CoMap", async () => {
314
346
  age: 20,
315
347
  });
316
348
 
317
- person.friend = person;
349
+ person.$jazz.set("friend", person);
318
350
 
319
351
  expect(person.toJSON()).toEqual({
320
- _type: "CoMap",
321
- id: person.id,
322
352
  name: "John",
323
353
  age: 20,
324
354
  friend: {
325
- _circular: person.id,
355
+ _circular: person.$jazz.id,
326
356
  },
327
357
  });
328
358
  });
@@ -346,8 +376,6 @@ describe("CoMap", async () => {
346
376
  name: "John",
347
377
  age: 20,
348
378
  birthday: birthday.toISOString(),
349
- _type: "CoMap",
350
- id: john.id,
351
379
  });
352
380
  });
353
381
 
@@ -379,8 +407,6 @@ describe("CoMap", async () => {
379
407
  const john = Person.create({ name: "John", age: 30, x: 1 });
380
408
 
381
409
  expect(john.toJSON()).toEqual({
382
- _type: "CoMap",
383
- id: john.id,
384
410
  name: "John",
385
411
  age: 30,
386
412
  });
@@ -399,9 +425,9 @@ describe("CoMap", async () => {
399
425
  expect(person.age).toEqual(20);
400
426
  expect(person.extra).toBeUndefined();
401
427
 
402
- person.name = "Jane";
403
- person.age = 28;
404
- person.extra = "extra";
428
+ person.$jazz.set("name", "Jane");
429
+ person.$jazz.set("age", 28);
430
+ person.$jazz.set("extra", "extra");
405
431
 
406
432
  expect(person.name).toEqual("Jane");
407
433
  expect(person.age).toEqual(28);
@@ -436,7 +462,7 @@ describe("CoMap", async () => {
436
462
  );
437
463
 
438
464
  const userB = await createJazzTestAccount();
439
- const loadedPersonA = await Person.load(personA.id, {
465
+ const loadedPersonA = await Person.load(personA.$jazz.id, {
440
466
  resolve: true,
441
467
  loadAs: userB,
442
468
  });
@@ -464,13 +490,13 @@ describe("CoMap", async () => {
464
490
 
465
491
  const john = Person.create({ name: "John", age: 20 });
466
492
 
467
- john.name = "Jane";
493
+ john.$jazz.set("name", "Jane");
468
494
 
469
495
  expect(john.name).toEqual("Jane");
470
496
  expect(john.age).toEqual(20);
471
497
  });
472
498
 
473
- test("delete an optional value", () => {
499
+ test("delete an optional value by setting it to undefined", () => {
474
500
  const Person = co.map({
475
501
  name: z.string(),
476
502
  age: z.number().optional(),
@@ -478,19 +504,68 @@ describe("CoMap", async () => {
478
504
 
479
505
  const john = Person.create({ name: "John", age: 20 });
480
506
 
481
- delete john.age;
507
+ john.$jazz.set("age", undefined);
482
508
 
483
509
  expect(john.name).toEqual("John");
484
510
  expect(john.age).toEqual(undefined);
485
511
 
486
512
  expect(john.toJSON()).toEqual({
487
- _type: "CoMap",
488
- id: john.id,
489
513
  name: "John",
490
514
  });
515
+ // The CoMap proxy hides the age property from the `in` operator
516
+ expect("age" in john).toEqual(false);
517
+ // The key still exists, since age === undefined
518
+ expect(Object.keys(john)).toEqual(["name", "age"]);
519
+ });
520
+
521
+ test("delete optional properties using $jazz.delete", () => {
522
+ const Dog = co.map({
523
+ name: z.string(),
524
+ });
525
+
526
+ const Person = co.map({
527
+ name: z.string(),
528
+ age: z.number().optional(),
529
+ pet: Dog.optional(),
530
+ });
531
+
532
+ const john = Person.create({
533
+ name: "John",
534
+ age: 20,
535
+ pet: { name: "Rex" },
536
+ });
537
+
538
+ john.$jazz.delete("age");
539
+ john.$jazz.delete("pet");
540
+
541
+ expect(john.age).not.toBeDefined();
542
+ expect(john.pet).not.toBeDefined();
543
+ expect(john.toJSON()).toEqual({
544
+ name: "John",
545
+ });
546
+ expect("age" in john).toEqual(false);
547
+ expect("pet" in john).toEqual(false);
548
+ expect(Object.keys(john)).toEqual(["name"]);
549
+ });
550
+
551
+ test("cannot delete required properties using $jazz.delete", () => {
552
+ const Dog = co.map({
553
+ name: z.string(),
554
+ });
555
+ const Person = co.map({
556
+ name: z.string(),
557
+ pet: Dog,
558
+ });
559
+
560
+ const john = Person.create({ name: "John", pet: { name: "Rex" } });
561
+
562
+ // @ts-expect-error - should not allow deleting required primitive properties
563
+ john.$jazz.delete("name");
564
+ // @ts-expect-error - should not allow deleting required reference properties
565
+ john.$jazz.delete("pet");
491
566
  });
492
567
 
493
- test("update a reference", () => {
568
+ test("update a reference using a CoValue", () => {
494
569
  const Dog = co.map({
495
570
  name: z.string(),
496
571
  });
@@ -507,12 +582,128 @@ describe("CoMap", async () => {
507
582
  dog: Dog.create({ name: "Rex" }),
508
583
  });
509
584
 
510
- john.dog = Dog.create({ name: "Fido" });
585
+ john.$jazz.set("dog", Dog.create({ name: "Fido" }));
511
586
 
512
587
  expect(john.dog?.name).toEqual("Fido");
513
588
  });
514
589
 
515
- test("changes should be listed in _edits", () => {
590
+ describe("update a reference using a JSON object", () => {
591
+ const Dog = co.map({
592
+ type: z.literal("dog"),
593
+ name: z.string(),
594
+ });
595
+ const Cat = co.map({
596
+ type: z.literal("cat"),
597
+ name: z.string(),
598
+ });
599
+ const Pet = co.discriminatedUnion("type", [Dog, Cat]);
600
+ const Person = co.map({
601
+ name: co.plainText(),
602
+ bio: co.richText().optional(),
603
+ dog: Dog,
604
+ get friends() {
605
+ return co.list(Person);
606
+ },
607
+ reactions: co.feed(co.plainText()),
608
+ pet: Pet,
609
+ pets: co.record(z.string(), Pet),
610
+ });
611
+
612
+ let person: ReturnType<typeof Person.create>;
613
+
614
+ beforeEach(() => {
615
+ person = Person.create({
616
+ name: "John",
617
+ bio: "I am a software engineer",
618
+ dog: { type: "dog", name: "Rex" },
619
+ friends: [
620
+ {
621
+ name: "Jane",
622
+ bio: "I am a mechanical engineer",
623
+ dog: { type: "dog", name: "Fido" },
624
+ friends: [],
625
+ reactions: [],
626
+ pet: { type: "dog", name: "Fido" },
627
+ pets: {},
628
+ },
629
+ ],
630
+ reactions: ["👎", "👍"],
631
+ pet: { type: "cat", name: "Whiskers" },
632
+ pets: {
633
+ dog: { type: "dog", name: "Rex" },
634
+ cat: { type: "cat", name: "Whiskers" },
635
+ },
636
+ });
637
+ });
638
+
639
+ test("automatically creates CoValues for plain text reference", () => {
640
+ person.$jazz.set("name", "Jack");
641
+ expect(person.name.toString()).toEqual("Jack");
642
+ });
643
+
644
+ test("automatically creates CoValues for rich text reference", () => {
645
+ person.$jazz.set("bio", "I am a lawyer");
646
+ expect(person.bio!.toString()).toEqual("I am a lawyer");
647
+ });
648
+
649
+ test("automatically creates CoValues for CoMap reference", () => {
650
+ person.$jazz.set("dog", { type: "dog", name: "Fido" });
651
+ expect(person.dog.name).toEqual("Fido");
652
+ });
653
+
654
+ test("automatically creates CoValues for CoRecord reference", () => {
655
+ person.$jazz.set("pets", {
656
+ dog: { type: "dog", name: "Fido" },
657
+ });
658
+ expect(person.pets.dog?.name).toEqual("Fido");
659
+ });
660
+
661
+ test("automatically creates CoValues for CoList reference", () => {
662
+ person.$jazz.set("friends", [
663
+ {
664
+ name: "Jane",
665
+ bio: "I am a mechanical engineer",
666
+ dog: { type: "dog", name: "Firulais" },
667
+ friends: [],
668
+ reactions: [],
669
+ pet: { type: "cat", name: "Nala" },
670
+ pets: {},
671
+ },
672
+ ]);
673
+ expect(person.friends[0]!.name.toString()).toEqual("Jane");
674
+ expect(person.friends[0]!.dog.name).toEqual("Firulais");
675
+ expect(person.friends[0]!.pet.name).toEqual("Nala");
676
+ });
677
+
678
+ test("automatically creates CoValues for CoFeed reference", () => {
679
+ person.$jazz.set("reactions", ["🧑‍🔬"]);
680
+ expect(person.reactions.byMe?.value?.toString()).toEqual("🧑‍🔬");
681
+ });
682
+
683
+ test("automatically creates CoValues for discriminated union reference", () => {
684
+ person.$jazz.set("pet", { type: "cat", name: "Salem" });
685
+ expect(person.pet.name).toEqual("Salem");
686
+ });
687
+
688
+ test("undefined properties can be ommited", () => {
689
+ person.$jazz.set("friends", [
690
+ {
691
+ name: "Jane",
692
+ // bio is omitted
693
+ dog: { type: "dog", name: "Firulais" },
694
+ friends: [],
695
+ reactions: [],
696
+ pet: { type: "cat", name: "Nala" },
697
+ pets: {},
698
+ },
699
+ ]);
700
+
701
+ expect(person.friends[0]!.name.toString()).toEqual("Jane");
702
+ expect(person.friends[0]!.bio).toBeUndefined();
703
+ });
704
+ });
705
+
706
+ test("changes should be listed in getEdits()", () => {
516
707
  const Person = co.map({
517
708
  name: z.string(),
518
709
  age: z.number(),
@@ -522,9 +713,9 @@ describe("CoMap", async () => {
522
713
 
523
714
  const me = Account.getMe();
524
715
 
525
- john.age = 21;
716
+ john.$jazz.set("age", 21);
526
717
 
527
- expect(john._edits.age?.all).toEqual([
718
+ expect(john.$jazz.getEdits().age?.all).toEqual([
528
719
  expect.objectContaining({
529
720
  value: 20,
530
721
  key: "age",
@@ -538,13 +729,17 @@ describe("CoMap", async () => {
538
729
  madeAt: expect.any(Date),
539
730
  }),
540
731
  ]);
541
- expect(john._edits.age?.all[0]?.by).toMatchObject({
542
- _type: "Account",
543
- id: me.id,
732
+ expect(john.$jazz.getEdits().age?.all[0]?.by).toMatchObject({
733
+ [TypeSym]: "Account",
734
+ $jazz: expect.objectContaining({
735
+ id: me.$jazz.id,
736
+ }),
544
737
  });
545
- expect(john._edits.age?.all[1]?.by).toMatchObject({
546
- _type: "Account",
547
- id: me.id,
738
+ expect(john.$jazz.getEdits().age?.all[1]?.by).toMatchObject({
739
+ [TypeSym]: "Account",
740
+ $jazz: expect.objectContaining({
741
+ id: me.$jazz.id,
742
+ }),
548
743
  });
549
744
  });
550
745
  });
@@ -576,7 +771,7 @@ describe("CoMap", async () => {
576
771
  expect(mapWithEnum.name).toEqual("enum");
577
772
  expect(mapWithEnum.child?.type).toEqual("a");
578
773
  expect(mapWithEnum.child?.value).toEqual(5);
579
- expect(mapWithEnum.child?.id).toBeDefined();
774
+ expect(mapWithEnum.child?.$jazz.id).toBeDefined();
580
775
 
581
776
  // TODO: properly support narrowing once we get rid of the coField marker
582
777
  // if (mapWithEnum.child?.type === "a") {
@@ -604,7 +799,7 @@ describe("CoMap resolution", async () => {
604
799
  dog: Dog.create({ name: "Rex", breed: "Labrador" }),
605
800
  });
606
801
 
607
- const loadedPerson = await Person.load(person.id, {
802
+ const loadedPerson = await Person.load(person.$jazz.id, {
608
803
  resolve: {
609
804
  dog: true,
610
805
  },
@@ -632,7 +827,7 @@ describe("CoMap resolution", async () => {
632
827
  dog: Dog.create({ name: "Rex", breed: "Labrador" }),
633
828
  });
634
829
 
635
- const loadedPerson = await Person.load(person.id);
830
+ const loadedPerson = await Person.load(person.$jazz.id);
636
831
 
637
832
  assert(loadedPerson);
638
833
  expect(loadedPerson.dog?.name).toEqual("Rex");
@@ -664,7 +859,7 @@ describe("CoMap resolution", async () => {
664
859
 
665
860
  const userB = await createJazzTestAccount();
666
861
 
667
- const loadedPerson = await Person.load(person.id, {
862
+ const loadedPerson = await Person.load(person.$jazz.id, {
668
863
  resolve: {
669
864
  dog: true,
670
865
  },
@@ -700,7 +895,7 @@ describe("CoMap resolution", async () => {
700
895
  );
701
896
 
702
897
  const userB = await createJazzTestAccount();
703
- const loadedPerson = await Person.load(person.id, {
898
+ const loadedPerson = await Person.load(person.$jazz.id, {
704
899
  loadAs: userB,
705
900
  });
706
901
 
@@ -726,8 +921,8 @@ describe("CoMap resolution", async () => {
726
921
  const currentAccount = Account.getMe();
727
922
 
728
923
  // Disconnect the current account
729
- currentAccount._raw.core.node.syncManager
730
- .getServerPeers(currentAccount._raw.id)
924
+ currentAccount.$jazz.localNode.syncManager
925
+ .getServerPeers(currentAccount.$jazz.raw.id)
731
926
  .forEach((peer) => {
732
927
  peer.gracefulShutdown();
733
928
  });
@@ -747,7 +942,7 @@ describe("CoMap resolution", async () => {
747
942
  const userB = await createJazzTestAccount();
748
943
 
749
944
  // We expect that the test doesn't hang here and immediately returns null
750
- const loadedPerson = await Person.load(person.id, {
945
+ const loadedPerson = await Person.load(person.$jazz.id, {
751
946
  loadAs: userB,
752
947
  skipRetry: true,
753
948
  });
@@ -773,8 +968,8 @@ describe("CoMap resolution", async () => {
773
968
  const currentAccount = Account.getMe();
774
969
 
775
970
  // Disconnect the current account
776
- currentAccount._raw.core.node.syncManager
777
- .getServerPeers(currentAccount._raw.id)
971
+ currentAccount.$jazz.localNode.syncManager
972
+ .getServerPeers(currentAccount.$jazz.raw.id)
778
973
  .forEach((peer) => {
779
974
  peer.gracefulShutdown();
780
975
  });
@@ -793,7 +988,7 @@ describe("CoMap resolution", async () => {
793
988
 
794
989
  const userB = await createJazzTestAccount();
795
990
  let resolved = false;
796
- const promise = Person.load(person.id, {
991
+ const promise = Person.load(person.$jazz.id, {
797
992
  loadAs: userB,
798
993
  skipRetry: false,
799
994
  });
@@ -806,7 +1001,7 @@ describe("CoMap resolution", async () => {
806
1001
  expect(resolved).toBe(false);
807
1002
 
808
1003
  // Reconnect the current account
809
- currentAccount._raw.core.node.syncManager.addPeer(
1004
+ currentAccount.$jazz.localNode.syncManager.addPeer(
810
1005
  getPeerConnectedToTestSyncServer(),
811
1006
  );
812
1007
 
@@ -842,15 +1037,15 @@ describe("CoMap resolution", async () => {
842
1037
  );
843
1038
 
844
1039
  const userB = await createJazzTestAccount();
845
- const loadedPerson = await Person.load(person.id, {
1040
+ const loadedPerson = await Person.load(person.$jazz.id, {
846
1041
  loadAs: userB,
847
1042
  });
848
1043
 
849
1044
  assert(loadedPerson);
850
1045
 
851
- expect(loadedPerson._refs.dog?.id).toBe(person.dog!.id);
1046
+ expect(loadedPerson.$jazz.refs.dog?.id).toBe(person.dog!.$jazz.id);
852
1047
 
853
- const dog = await loadedPerson._refs.dog?.load();
1048
+ const dog = await loadedPerson.$jazz.refs.dog?.load();
854
1049
 
855
1050
  assert(dog);
856
1051
 
@@ -879,7 +1074,7 @@ describe("CoMap resolution", async () => {
879
1074
  const spy = vi.fn((person) => updates.push(person));
880
1075
 
881
1076
  Person.subscribe(
882
- person.id,
1077
+ person.$jazz.id,
883
1078
  {
884
1079
  resolve: {
885
1080
  dog: true,
@@ -896,7 +1091,7 @@ describe("CoMap resolution", async () => {
896
1091
 
897
1092
  expect(updates[0]?.dog.name).toEqual("Rex");
898
1093
 
899
- person.dog!.name = "Fido";
1094
+ person.dog!.$jazz.set("name", "Fido");
900
1095
 
901
1096
  await waitFor(() => expect(spy).toHaveBeenCalledTimes(2));
902
1097
 
@@ -926,7 +1121,7 @@ describe("CoMap resolution", async () => {
926
1121
  const updates: Loaded<typeof Person>[] = [];
927
1122
  const spy = vi.fn((person) => updates.push(person));
928
1123
 
929
- Person.subscribe(person.id, {}, spy);
1124
+ Person.subscribe(person.$jazz.id, {}, spy);
930
1125
 
931
1126
  expect(spy).not.toHaveBeenCalled();
932
1127
 
@@ -936,7 +1131,7 @@ describe("CoMap resolution", async () => {
936
1131
 
937
1132
  expect(updates[0]?.dog?.name).toEqual("Rex");
938
1133
 
939
- person.dog!.name = "Fido";
1134
+ person.dog!.$jazz.set("name", "Fido");
940
1135
 
941
1136
  await waitFor(() => expect(spy).toHaveBeenCalledTimes(2));
942
1137
 
@@ -968,7 +1163,7 @@ describe("CoMap resolution", async () => {
968
1163
 
969
1164
  subscribeToCoValue(
970
1165
  coValueClassFromCoValueClassOrSchema(Person), // TODO: we should get rid of the conversion in the future
971
- person.id,
1166
+ person.$jazz.id,
972
1167
  {
973
1168
  syncResolution: true,
974
1169
  loadAs: Account.getMe(),
@@ -983,7 +1178,7 @@ describe("CoMap resolution", async () => {
983
1178
 
984
1179
  expect(spy).toHaveBeenCalledTimes(1);
985
1180
 
986
- person.dog!.name = "Fido";
1181
+ person.dog!.$jazz.set("name", "Fido");
987
1182
 
988
1183
  expect(spy).toHaveBeenCalledTimes(2);
989
1184
 
@@ -1022,7 +1217,7 @@ describe("CoMap resolution", async () => {
1022
1217
  const spy = vi.fn((person) => updates.push(person));
1023
1218
 
1024
1219
  Person.subscribe(
1025
- person.id,
1220
+ person.$jazz.id,
1026
1221
  {
1027
1222
  resolve: {
1028
1223
  dog: true,
@@ -1040,7 +1235,7 @@ describe("CoMap resolution", async () => {
1040
1235
 
1041
1236
  expect(updates[0]?.dog.name).toEqual("Rex");
1042
1237
 
1043
- person.dog!.name = "Fido";
1238
+ person.dog!.$jazz.set("name", "Fido");
1044
1239
 
1045
1240
  await waitFor(() => expect(spy).toHaveBeenCalledTimes(2));
1046
1241
 
@@ -1079,7 +1274,7 @@ describe("CoMap resolution", async () => {
1079
1274
  const userB = await createJazzTestAccount();
1080
1275
 
1081
1276
  Person.subscribe(
1082
- person.id,
1277
+ person.$jazz.id,
1083
1278
  {
1084
1279
  loadAs: userB,
1085
1280
  },
@@ -1094,7 +1289,7 @@ describe("CoMap resolution", async () => {
1094
1289
 
1095
1290
  expect(updates[0]?.dog?.name).toEqual("Rex");
1096
1291
 
1097
- person.dog!.name = "Fido";
1292
+ person.dog!.$jazz.set("name", "Fido");
1098
1293
 
1099
1294
  await waitFor(() => expect(spy).toHaveBeenCalledTimes(2));
1100
1295
 
@@ -1125,7 +1320,7 @@ describe("CoMap resolution", async () => {
1125
1320
  const spy = vi.fn((person) => updates.push(person));
1126
1321
 
1127
1322
  Person.subscribe(
1128
- person.id,
1323
+ person.$jazz.id,
1129
1324
  {
1130
1325
  resolve: {
1131
1326
  dog: true,
@@ -1142,7 +1337,7 @@ describe("CoMap resolution", async () => {
1142
1337
 
1143
1338
  expect(updates[0]?.dog.name).toEqual("Rex");
1144
1339
 
1145
- person.dog!.name = "Fido";
1340
+ person.dog!.$jazz.set("name", "Fido");
1146
1341
 
1147
1342
  await waitFor(() => expect(spy).toHaveBeenCalledTimes(2));
1148
1343
 
@@ -1190,7 +1385,7 @@ describe("CoMap applyDiff", async () => {
1190
1385
  isActive: false,
1191
1386
  };
1192
1387
 
1193
- map.applyDiff(newValues);
1388
+ map.$jazz.applyDiff(newValues);
1194
1389
 
1195
1390
  expect(map.name).toEqual("Bob");
1196
1391
  expect(map.age).toEqual(35);
@@ -1200,13 +1395,17 @@ describe("CoMap applyDiff", async () => {
1200
1395
  });
1201
1396
 
1202
1397
  test("applyDiff with nested changes", () => {
1398
+ const originalNestedMap = NestedMap.create(
1399
+ { value: "original" },
1400
+ { owner: me },
1401
+ );
1203
1402
  const map = TestMap.create(
1204
1403
  {
1205
1404
  name: "Charlie",
1206
1405
  age: 25,
1207
1406
  isActive: true,
1208
1407
  birthday: new Date("1995-01-01"),
1209
- nested: NestedMap.create({ value: "original" }, { owner: me }),
1408
+ nested: originalNestedMap,
1210
1409
  },
1211
1410
  { owner: me },
1212
1411
  );
@@ -1216,11 +1415,13 @@ describe("CoMap applyDiff", async () => {
1216
1415
  nested: NestedMap.create({ value: "updated" }, { owner: me }),
1217
1416
  };
1218
1417
 
1219
- map.applyDiff(newValues);
1418
+ map.$jazz.applyDiff(newValues);
1220
1419
 
1221
1420
  expect(map.name).toEqual("David");
1222
1421
  expect(map.age).toEqual(25);
1223
1422
  expect(map.nested?.value).toEqual("updated");
1423
+ // A new nested CoMap is created
1424
+ expect(map.nested.$jazz.id).not.toBe(originalNestedMap.$jazz.id);
1224
1425
  });
1225
1426
 
1226
1427
  test("applyDiff with encoded fields", () => {
@@ -1239,7 +1440,7 @@ describe("CoMap applyDiff", async () => {
1239
1440
  birthday: new Date("1993-06-15"),
1240
1441
  };
1241
1442
 
1242
- map.applyDiff(newValues);
1443
+ map.$jazz.applyDiff(newValues);
1243
1444
 
1244
1445
  expect(map.birthday).toEqual(new Date("1993-06-15"));
1245
1446
  });
@@ -1260,11 +1461,11 @@ describe("CoMap applyDiff", async () => {
1260
1461
  optionalField: "New optional value",
1261
1462
  };
1262
1463
 
1263
- map.applyDiff(newValues);
1464
+ map.$jazz.applyDiff(newValues);
1264
1465
 
1265
1466
  expect(map.optionalField).toEqual("New optional value");
1266
1467
 
1267
- map.applyDiff({ optionalField: undefined });
1468
+ map.$jazz.applyDiff({ optionalField: undefined });
1268
1469
 
1269
1470
  expect(map.optionalField).toBeUndefined();
1270
1471
  });
@@ -1283,7 +1484,7 @@ describe("CoMap applyDiff", async () => {
1283
1484
 
1284
1485
  const originalJSON = map.toJSON();
1285
1486
 
1286
- map.applyDiff({});
1487
+ map.$jazz.applyDiff({});
1287
1488
 
1288
1489
  expect(map.toJSON()).toEqual(originalJSON);
1289
1490
  });
@@ -1304,8 +1505,7 @@ describe("CoMap applyDiff", async () => {
1304
1505
  name: "Ian",
1305
1506
  invalidField: "This should be ignored",
1306
1507
  };
1307
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1308
- map.applyDiff(newValues as any);
1508
+ map.$jazz.applyDiff(newValues);
1309
1509
 
1310
1510
  expect(map.name).toEqual("Ian");
1311
1511
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -1329,7 +1529,7 @@ describe("CoMap applyDiff", async () => {
1329
1529
  optionalNested: undefined,
1330
1530
  };
1331
1531
 
1332
- map.applyDiff(newValues);
1532
+ map.$jazz.applyDiff(newValues);
1333
1533
 
1334
1534
  expect(map.optionalNested).toBeUndefined();
1335
1535
  });
@@ -1350,10 +1550,31 @@ describe("CoMap applyDiff", async () => {
1350
1550
  nested: undefined,
1351
1551
  };
1352
1552
 
1353
- expect(() => map.applyDiff(newValues)).toThrowError(
1553
+ expect(() => map.$jazz.applyDiff(newValues)).toThrowError(
1354
1554
  "Cannot set required reference nested to undefined",
1355
1555
  );
1356
1556
  });
1557
+
1558
+ test("applyDiff from JSON", () => {
1559
+ const map = TestMap.create({
1560
+ name: "Alice",
1561
+ age: 30,
1562
+ isActive: true,
1563
+ birthday: new Date("1990-01-01"),
1564
+ nested: NestedMap.create({ value: "original" }),
1565
+ });
1566
+ const originalNestedMap = map.nested;
1567
+
1568
+ const newValues = {
1569
+ nested: { value: "updated" },
1570
+ };
1571
+
1572
+ map.$jazz.applyDiff(newValues);
1573
+
1574
+ expect(map.nested?.value).toEqual("updated");
1575
+ // A new nested CoMap is created
1576
+ expect(map.nested.$jazz.id).not.toBe(originalNestedMap.$jazz.id);
1577
+ });
1357
1578
  });
1358
1579
 
1359
1580
  describe("CoMap Typescript validation", async () => {
@@ -1373,9 +1594,9 @@ describe("CoMap Typescript validation", async () => {
1373
1594
  });
1374
1595
 
1375
1596
  expectTypeOf<typeof TestMap.create>().toBeCallableWith(
1597
+ // @ts-expect-error null can't be passed to a non-optional field
1376
1598
  {
1377
1599
  optional: NestedMap.create({ value: "" }, { owner: me }),
1378
- // @ts-expect-error null can't be passed to a non-optional field
1379
1600
  required: null,
1380
1601
  },
1381
1602
  { owner: me },
@@ -1439,12 +1660,12 @@ describe("CoMap Typescript validation", async () => {
1439
1660
  { owner: clientAccount },
1440
1661
  );
1441
1662
 
1442
- await map.waitForSync({ timeout: 1000 });
1663
+ await map.$jazz.waitForSync({ timeout: 1000 });
1443
1664
 
1444
1665
  // Killing the client node so the serverNode can't load the map from it
1445
1666
  clientNode.gracefulShutdown();
1446
1667
 
1447
- const loadedMap = await serverNode.load(map._raw.id);
1668
+ const loadedMap = await serverNode.load(map.$jazz.raw.id);
1448
1669
 
1449
1670
  expect(loadedMap).not.toBe("unavailable");
1450
1671
  });
@@ -1471,7 +1692,10 @@ describe("Creating and finding unique CoMaps", async () => {
1471
1692
  { owner: group, unique: { name: "Alice" } },
1472
1693
  );
1473
1694
 
1474
- const foundAlice = await Person.loadUnique({ name: "Alice" }, group.id);
1695
+ const foundAlice = await Person.loadUnique(
1696
+ { name: "Alice" },
1697
+ group.$jazz.id,
1698
+ );
1475
1699
  expect(foundAlice).toEqual(alice);
1476
1700
  });
1477
1701
 
@@ -1494,7 +1718,7 @@ describe("Creating and finding unique CoMaps", async () => {
1494
1718
  // Pattern
1495
1719
  let activeEvent = await Event.loadUnique(
1496
1720
  { identifier: sourceData.identifier },
1497
- workspace.id,
1721
+ workspace.$jazz.id,
1498
1722
  );
1499
1723
  if (!activeEvent) {
1500
1724
  activeEvent = Event.create(
@@ -1506,7 +1730,7 @@ describe("Creating and finding unique CoMaps", async () => {
1506
1730
  workspace,
1507
1731
  );
1508
1732
  } else {
1509
- activeEvent.applyDiff({
1733
+ activeEvent.$jazz.applyDiff({
1510
1734
  title: sourceData.title,
1511
1735
  identifier: sourceData.identifier,
1512
1736
  external_id: sourceData._id,
@@ -1589,7 +1813,7 @@ describe("Creating and finding unique CoMaps", async () => {
1589
1813
 
1590
1814
  assert(activeEvent);
1591
1815
 
1592
- expect(activeEvent._owner).toEqual(account);
1816
+ expect(activeEvent.$jazz.owner).toEqual(account);
1593
1817
  });
1594
1818
 
1595
1819
  test("upserting an existing value", async () => {
@@ -1767,12 +1991,14 @@ describe("Creating and finding unique CoMaps", async () => {
1767
1991
  isCurrentActiveAccount: true,
1768
1992
  });
1769
1993
 
1770
- const shallowProjectList = await co.list(Project).load(fullProjectList.id, {
1771
- loadAs: account,
1772
- });
1994
+ const shallowProjectList = await co
1995
+ .list(Project)
1996
+ .load(fullProjectList.$jazz.id, {
1997
+ loadAs: account,
1998
+ });
1773
1999
  assert(shallowProjectList);
1774
2000
 
1775
- const publicAccessAsNewAccount = await Group.load(publicAccess.id, {
2001
+ const publicAccessAsNewAccount = await Group.load(publicAccess.$jazz.id, {
1776
2002
  loadAs: account,
1777
2003
  });
1778
2004
  assert(publicAccessAsNewAccount);
@@ -1793,7 +2019,7 @@ describe("Creating and finding unique CoMaps", async () => {
1793
2019
 
1794
2020
  assert(updatedOrg);
1795
2021
 
1796
- expect(updatedOrg.projects.id).toEqual(fullProjectList.id);
2022
+ expect(updatedOrg.projects.$jazz.id).toEqual(fullProjectList.$jazz.id);
1797
2023
  expect(updatedOrg.projects.length).toBe(1);
1798
2024
  expect(updatedOrg.projects.at(0)?.name).toEqual("My project");
1799
2025
  });
@@ -1843,12 +2069,14 @@ describe("Creating and finding unique CoMaps", async () => {
1843
2069
  isCurrentActiveAccount: true,
1844
2070
  });
1845
2071
 
1846
- const shallowProjectList = await co.list(Project).load(fullProjectList.id, {
1847
- loadAs: account,
1848
- });
2072
+ const shallowProjectList = await co
2073
+ .list(Project)
2074
+ .load(fullProjectList.$jazz.id, {
2075
+ loadAs: account,
2076
+ });
1849
2077
  assert(shallowProjectList);
1850
2078
 
1851
- const publicAccessAsNewAccount = await Group.load(publicAccess.id, {
2079
+ const publicAccessAsNewAccount = await Group.load(publicAccess.$jazz.id, {
1852
2080
  loadAs: account,
1853
2081
  });
1854
2082
  assert(publicAccessAsNewAccount);
@@ -1869,10 +2097,10 @@ describe("Creating and finding unique CoMaps", async () => {
1869
2097
 
1870
2098
  assert(updatedOrg);
1871
2099
 
1872
- expect(updatedOrg.projects.id).toEqual(fullProjectList.id);
2100
+ expect(updatedOrg.projects.$jazz.id).toEqual(fullProjectList.$jazz.id);
1873
2101
  expect(updatedOrg.projects.length).toBe(1);
1874
2102
  expect(updatedOrg.projects.at(0)?.name).toEqual("My project");
1875
- expect(updatedOrg.id).toEqual(myOrg.id);
2103
+ expect(updatedOrg.$jazz.id).toEqual(myOrg.$jazz.id);
1876
2104
  });
1877
2105
 
1878
2106
  test("complex discriminated union", () => {
@@ -2031,58 +2259,6 @@ describe("Creating and finding unique CoMaps", async () => {
2031
2259
  });
2032
2260
  });
2033
2261
 
2034
- describe("castAs", () => {
2035
- test("should cast a co.map type", () => {
2036
- const Person = co.map({
2037
- name: z.string(),
2038
- });
2039
-
2040
- const PersonWithAge = co.map({
2041
- name: z.string(),
2042
- age: z.number().optional(),
2043
- });
2044
-
2045
- const person = Person.create({
2046
- name: "Alice",
2047
- });
2048
-
2049
- const personWithAge = person.castAs(PersonWithAge);
2050
-
2051
- personWithAge.age = 20;
2052
-
2053
- expect(personWithAge.age).toEqual(20);
2054
- });
2055
-
2056
- test("should still be able to autoload in-memory deps", () => {
2057
- const Dog = co.map({
2058
- name: z.string(),
2059
- });
2060
-
2061
- const Person = co.map({
2062
- name: z.string(),
2063
- dog: Dog,
2064
- });
2065
-
2066
- const PersonWithAge = co.map({
2067
- name: z.string(),
2068
- age: z.number().optional(),
2069
- dog: Dog,
2070
- });
2071
-
2072
- const person = Person.create({
2073
- name: "Alice",
2074
- dog: Dog.create({ name: "Rex" }),
2075
- });
2076
-
2077
- const personWithAge = person.castAs(PersonWithAge);
2078
-
2079
- personWithAge.age = 20;
2080
-
2081
- expect(personWithAge.age).toEqual(20);
2082
- expect(personWithAge.dog?.name).toEqual("Rex");
2083
- });
2084
- });
2085
-
2086
2262
  describe("CoMap migration", () => {
2087
2263
  test("should run on load", async () => {
2088
2264
  const PersonV1 = co.map({
@@ -2098,8 +2274,8 @@ describe("CoMap migration", () => {
2098
2274
  })
2099
2275
  .withMigration((person) => {
2100
2276
  if (person.version === 1) {
2101
- person.age = 20;
2102
- person.version = 2;
2277
+ person.$jazz.set("age", 20);
2278
+ person.$jazz.set("version", 2);
2103
2279
  }
2104
2280
  });
2105
2281
 
@@ -2111,7 +2287,7 @@ describe("CoMap migration", () => {
2111
2287
  expect(person?.name).toEqual("Bob");
2112
2288
  expect(person?.version).toEqual(1);
2113
2289
 
2114
- const loadedPerson = await Person.load(person.id);
2290
+ const loadedPerson = await Person.load(person.$jazz.id);
2115
2291
 
2116
2292
  expect(loadedPerson?.name).toEqual("Bob");
2117
2293
  expect(loadedPerson?.age).toEqual(20);
@@ -2126,9 +2302,9 @@ describe("CoMap migration", () => {
2126
2302
  })
2127
2303
  .withMigration((person) => {
2128
2304
  if (person.version === 1) {
2129
- person.version = 2;
2305
+ person.$jazz.set("version", 2);
2130
2306
 
2131
- person._owner.castAs(Group).addMember("everyone", "reader");
2307
+ person.$jazz.owner.addMember("everyone", "reader");
2132
2308
  }
2133
2309
  });
2134
2310
 
@@ -2140,14 +2316,14 @@ describe("CoMap migration", () => {
2140
2316
  expect(person?.name).toEqual("Bob");
2141
2317
  expect(person?.version).toEqual(1);
2142
2318
 
2143
- const loadedPerson = await Person.load(person.id);
2319
+ const loadedPerson = await Person.load(person.$jazz.id);
2144
2320
 
2145
2321
  expect(loadedPerson?.name).toEqual("Bob");
2146
2322
  expect(loadedPerson?.version).toEqual(2);
2147
2323
 
2148
2324
  const anotherAccount = await createJazzTestAccount();
2149
2325
 
2150
- const loadedPersonFromAnotherAccount = await Person.load(person.id, {
2326
+ const loadedPersonFromAnotherAccount = await Person.load(person.$jazz.id, {
2151
2327
  loadAs: anotherAccount,
2152
2328
  });
2153
2329
 
@@ -2168,7 +2344,7 @@ describe("CoMap migration", () => {
2168
2344
  version: 1,
2169
2345
  });
2170
2346
 
2171
- await expect(Person.load(person.id)).rejects.toThrow(
2347
+ await expect(Person.load(person.$jazz.id)).rejects.toThrow(
2172
2348
  "Migration function cannot be async",
2173
2349
  );
2174
2350
  });
@@ -2189,8 +2365,8 @@ describe("CoMap migration", () => {
2189
2365
  version: 1,
2190
2366
  });
2191
2367
 
2192
- await Person.load(person.id);
2193
- await Person.load(person.id);
2368
+ await Person.load(person.$jazz.id);
2369
+ await Person.load(person.$jazz.id);
2194
2370
  expect(spy).toHaveBeenCalledTimes(1);
2195
2371
  });
2196
2372
 
@@ -2214,8 +2390,8 @@ describe("CoMap migration", () => {
2214
2390
  })
2215
2391
  .withMigration((person) => {
2216
2392
  if (person.version === 1) {
2217
- person.age = 20;
2218
- person.version = 2;
2393
+ person.$jazz.set("age", 20);
2394
+ person.$jazz.set("version", 2);
2219
2395
  }
2220
2396
  });
2221
2397
 
@@ -2230,7 +2406,7 @@ describe("CoMap migration", () => {
2230
2406
  friend: charlie,
2231
2407
  });
2232
2408
 
2233
- const loaded = await Person.load(bob.id, {
2409
+ const loaded = await Person.load(bob.$jazz.id, {
2234
2410
  resolve: {
2235
2411
  friend: true,
2236
2412
  },
@@ -2249,7 +2425,7 @@ describe("createdAt & lastUpdatedAt", () => {
2249
2425
  test("empty map created time", () => {
2250
2426
  const emptyMap = co.map({}).create({});
2251
2427
 
2252
- expect(emptyMap._lastUpdatedAt).toEqual(emptyMap._createdAt);
2428
+ expect(emptyMap.$jazz.lastUpdatedAt).toEqual(emptyMap.$jazz.createdAt);
2253
2429
  });
2254
2430
 
2255
2431
  test("created time and last updated time", async () => {
@@ -2259,14 +2435,14 @@ describe("createdAt & lastUpdatedAt", () => {
2259
2435
 
2260
2436
  const person = Person.create({ name: "John" });
2261
2437
 
2262
- const createdAt = person._createdAt;
2263
- expect(person._lastUpdatedAt).toEqual(createdAt);
2438
+ const createdAt = person.$jazz.createdAt;
2439
+ expect(person.$jazz.lastUpdatedAt).toEqual(createdAt);
2264
2440
 
2265
2441
  await new Promise((r) => setTimeout(r, 10));
2266
- person.name = "Jane";
2442
+ person.$jazz.set("name", "Jane");
2267
2443
 
2268
- expect(person._createdAt).toEqual(createdAt);
2269
- expect(person._lastUpdatedAt).not.toEqual(createdAt);
2444
+ expect(person.$jazz.createdAt).toEqual(createdAt);
2445
+ expect(person.$jazz.lastUpdatedAt).not.toEqual(createdAt);
2270
2446
  });
2271
2447
  });
2272
2448
 
@@ -2343,10 +2519,10 @@ describe("co.map schema", () => {
2343
2519
  expect(draftPerson.age).toBeUndefined();
2344
2520
  expect(draftPerson.pet).toBeUndefined();
2345
2521
 
2346
- draftPerson.name = "John";
2347
- draftPerson.age = 20;
2522
+ draftPerson.$jazz.set("name", "John");
2523
+ draftPerson.$jazz.set("age", 20);
2348
2524
  const rex = Dog.create({ name: "Rex", breed: "Labrador" });
2349
- draftPerson.pet = rex;
2525
+ draftPerson.$jazz.set("pet", rex);
2350
2526
 
2351
2527
  expect(draftPerson.name).toEqual("John");
2352
2528
  expect(draftPerson.age).toEqual(20);
@@ -2364,7 +2540,7 @@ describe("co.map schema", () => {
2364
2540
  const DraftPerson = Person.partial();
2365
2541
 
2366
2542
  const draftPerson = DraftPerson.create({});
2367
- draftPerson.extraField = "extra";
2543
+ draftPerson.$jazz.set("extraField", "extra");
2368
2544
 
2369
2545
  expect(draftPerson.extraField).toEqual("extra");
2370
2546
  });
@@ -2375,6 +2551,14 @@ describe("co.map schema", () => {
2375
2551
  "co.map() expects an object as its argument, not a CoValue schema",
2376
2552
  );
2377
2553
  });
2554
+
2555
+ test("co.map() should throw an error if its shape does not contain valid schemas", () => {
2556
+ expect(() =>
2557
+ co.map({
2558
+ field: "a string is not a valid schema",
2559
+ }),
2560
+ ).toThrow("co.map() supports only Zod v4 schemas and CoValue schemas");
2561
+ });
2378
2562
  });
2379
2563
 
2380
2564
  describe("Updating a nested reference", () => {
@@ -2423,7 +2607,7 @@ describe("Updating a nested reference", () => {
2423
2607
  group.addMember(player1Account, "reader");
2424
2608
 
2425
2609
  // Load the game to verify the assignment worked
2426
- const loadedGame = await Game.load(game.id, {
2610
+ const loadedGame = await Game.load(game.$jazz.id, {
2427
2611
  resolve: {
2428
2612
  player1: {
2429
2613
  account: true,
@@ -2442,7 +2626,7 @@ describe("Updating a nested reference", () => {
2442
2626
  const playSelection = PlaySelection.create({ value: "rock", group }, group);
2443
2627
 
2444
2628
  // Assign the play selection to player1 (similar to the route logic)
2445
- loadedGame.player1.playSelection = playSelection;
2629
+ loadedGame.player1.$jazz.set("playSelection", playSelection);
2446
2630
 
2447
2631
  // Verify that the playSelection is not null and has the expected value
2448
2632
  expect(loadedGame.player1.playSelection).not.toBeNull();
@@ -2491,7 +2675,7 @@ describe("Updating a nested reference", () => {
2491
2675
  });
2492
2676
 
2493
2677
  // Load the game to verify the assignment worked
2494
- const loadedGame = await Game.load(game.id, {
2678
+ const loadedGame = await Game.load(game.$jazz.id, {
2495
2679
  resolve: {
2496
2680
  player1: {
2497
2681
  account: true,
@@ -2510,10 +2694,12 @@ describe("Updating a nested reference", () => {
2510
2694
  const playSelection = PlaySelection.create({ value: "scissors" });
2511
2695
 
2512
2696
  // Assign the play selection to player1 (similar to the route logic)
2513
- loadedGame.player1.playSelection = playSelection;
2697
+ loadedGame.player1.$jazz.set("playSelection", playSelection);
2514
2698
 
2515
2699
  // Verify that the playSelection is not null and has the expected value
2516
- expect(loadedGame.player1.playSelection.id).toBe(playSelection.id);
2700
+ expect(loadedGame.player1.playSelection.$jazz.id).toBe(
2701
+ playSelection.$jazz.id,
2702
+ );
2517
2703
  expect(loadedGame.player1.playSelection.value).toEqual("scissors");
2518
2704
  });
2519
2705
  });