jazz-tools 0.17.14 → 0.18.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 (250) 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 +60 -46
  10. package/CHANGELOG.md +41 -0
  11. package/dist/better-auth/auth/client.d.ts +29 -0
  12. package/dist/better-auth/auth/client.d.ts.map +1 -0
  13. package/dist/better-auth/auth/client.js +127 -0
  14. package/dist/better-auth/auth/client.js.map +1 -0
  15. package/dist/better-auth/auth/react.d.ts +2170 -0
  16. package/dist/better-auth/auth/react.d.ts.map +1 -0
  17. package/dist/better-auth/auth/react.js +40 -0
  18. package/dist/better-auth/auth/react.js.map +1 -0
  19. package/dist/better-auth/auth/server.d.ts +14 -0
  20. package/dist/better-auth/auth/server.d.ts.map +1 -0
  21. package/dist/better-auth/auth/server.js +198 -0
  22. package/dist/better-auth/auth/server.js.map +1 -0
  23. package/dist/better-auth/auth/tests/client.test.d.ts +2 -0
  24. package/dist/better-auth/auth/tests/client.test.d.ts.map +1 -0
  25. package/dist/better-auth/auth/tests/server.test.d.ts +2 -0
  26. package/dist/better-auth/auth/tests/server.test.d.ts.map +1 -0
  27. package/dist/browser/index.js +2 -2
  28. package/dist/browser/index.js.map +1 -1
  29. package/dist/{chunk-LZOF6WP5.js → chunk-IERUTUXB.js} +1336 -1017
  30. package/dist/chunk-IERUTUXB.js.map +1 -0
  31. package/dist/index.js +18 -18
  32. package/dist/index.js.map +1 -1
  33. package/dist/inspector/{custom-element-ZSNTCECD.js → custom-element-WCY6D3QJ.js} +3 -3
  34. package/dist/inspector/{custom-element-ZSNTCECD.js.map → custom-element-WCY6D3QJ.js.map} +1 -1
  35. package/dist/inspector/index.js +1 -1
  36. package/dist/inspector/index.js.map +1 -1
  37. package/dist/inspector/register-custom-element.js +1 -1
  38. package/dist/media/{chunk-E5J3WLQW.js → chunk-KR2V6X2N.js} +14 -9
  39. package/dist/media/chunk-KR2V6X2N.js.map +1 -0
  40. package/dist/media/create-image.d.ts +6 -6
  41. package/dist/media/index.browser.d.ts +6 -6
  42. package/dist/media/index.browser.js +1 -1
  43. package/dist/media/index.d.ts +1 -1
  44. package/dist/media/index.js +1 -1
  45. package/dist/media/index.native.d.ts +6 -6
  46. package/dist/media/index.native.js +1 -1
  47. package/dist/media/utils.d.ts.map +1 -1
  48. package/dist/prosemirror/index.js +2 -2
  49. package/dist/prosemirror/index.js.map +1 -1
  50. package/dist/react/index.js +7 -5
  51. package/dist/react/index.js.map +1 -1
  52. package/dist/react-core/hooks.d.ts.map +1 -1
  53. package/dist/react-core/index.js +4675 -23
  54. package/dist/react-core/index.js.map +1 -1
  55. package/dist/react-native-core/index.js +1 -1
  56. package/dist/react-native-core/index.js.map +1 -1
  57. package/dist/svelte/jazz.class.svelte.js +1 -1
  58. package/dist/svelte/media/image.svelte +3 -9
  59. package/dist/svelte/media/image.svelte.d.ts +1 -6
  60. package/dist/svelte/media/image.svelte.d.ts.map +1 -1
  61. package/dist/svelte/media/image.types.d.ts +7 -0
  62. package/dist/svelte/media/image.types.d.ts.map +1 -0
  63. package/dist/svelte/media/image.types.js +1 -0
  64. package/dist/svelte/tests/media/image.svelte.test.js +31 -31
  65. package/dist/testing.js +18 -14
  66. package/dist/testing.js.map +1 -1
  67. package/dist/tools/coValues/CoFieldInit.d.ts +13 -0
  68. package/dist/tools/coValues/CoFieldInit.d.ts.map +1 -0
  69. package/dist/tools/coValues/CoValueBase.d.ts +18 -15
  70. package/dist/tools/coValues/CoValueBase.d.ts.map +1 -1
  71. package/dist/tools/coValues/account.d.ts +101 -46
  72. package/dist/tools/coValues/account.d.ts.map +1 -1
  73. package/dist/tools/coValues/coFeed.d.ts +78 -62
  74. package/dist/tools/coValues/coFeed.d.ts.map +1 -1
  75. package/dist/tools/coValues/coList.d.ts +212 -99
  76. package/dist/tools/coValues/coList.d.ts.map +1 -1
  77. package/dist/tools/coValues/coMap.d.ts +210 -192
  78. package/dist/tools/coValues/coMap.d.ts.map +1 -1
  79. package/dist/tools/coValues/coPlainText.d.ts +30 -22
  80. package/dist/tools/coValues/coPlainText.d.ts.map +1 -1
  81. package/dist/tools/coValues/deepLoading.d.ts +13 -13
  82. package/dist/tools/coValues/deepLoading.d.ts.map +1 -1
  83. package/dist/tools/coValues/extensions/imageDef.d.ts +1 -1
  84. package/dist/tools/coValues/group.d.ts +32 -32
  85. package/dist/tools/coValues/group.d.ts.map +1 -1
  86. package/dist/tools/coValues/inbox.d.ts.map +1 -1
  87. package/dist/tools/coValues/interfaces.d.ts +18 -17
  88. package/dist/tools/coValues/interfaces.d.ts.map +1 -1
  89. package/dist/tools/coValues/profile.d.ts +6 -5
  90. package/dist/tools/coValues/profile.d.ts.map +1 -1
  91. package/dist/tools/coValues/schemaUnion.d.ts +3 -3
  92. package/dist/tools/coValues/schemaUnion.d.ts.map +1 -1
  93. package/dist/tools/exports.d.ts +1 -1
  94. package/dist/tools/exports.d.ts.map +1 -1
  95. package/dist/tools/implementation/anonymousJazzAgent.d.ts +2 -1
  96. package/dist/tools/implementation/anonymousJazzAgent.d.ts.map +1 -1
  97. package/dist/tools/implementation/schema.d.ts +5 -5
  98. package/dist/tools/implementation/schema.d.ts.map +1 -1
  99. package/dist/tools/implementation/symbols.d.ts +2 -0
  100. package/dist/tools/implementation/symbols.d.ts.map +1 -1
  101. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts +2 -2
  102. package/dist/tools/implementation/zodSchema/schemaTypes/AccountSchema.d.ts.map +1 -1
  103. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts +6 -2
  104. package/dist/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.d.ts.map +1 -1
  105. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts +8 -3
  106. package/dist/tools/implementation/zodSchema/schemaTypes/CoListSchema.d.ts.map +1 -1
  107. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts +12 -7
  108. package/dist/tools/implementation/zodSchema/schemaTypes/CoMapSchema.d.ts.map +1 -1
  109. package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts +13 -7
  110. package/dist/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.d.ts.map +1 -1
  111. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts +11 -2
  112. package/dist/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.d.ts.map +1 -1
  113. package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts +4 -0
  114. package/dist/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.d.ts.map +1 -1
  115. package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts +4 -0
  116. package/dist/tools/implementation/zodSchema/schemaTypes/RichTextSchema.d.ts.map +1 -1
  117. package/dist/tools/implementation/zodSchema/typeConverters/{CoFieldInit.d.ts → CoFieldSchemaInit.d.ts} +7 -7
  118. package/dist/tools/implementation/zodSchema/typeConverters/CoFieldSchemaInit.d.ts.map +1 -0
  119. package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchema.d.ts +4 -4
  120. package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchema.d.ts.map +1 -1
  121. package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.d.ts +4 -4
  122. package/dist/tools/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.d.ts.map +1 -1
  123. package/dist/tools/implementation/zodSchema/zodCo.d.ts +3 -3
  124. package/dist/tools/implementation/zodSchema/zodCo.d.ts.map +1 -1
  125. package/dist/tools/internal.d.ts +2 -1
  126. package/dist/tools/internal.d.ts.map +1 -1
  127. package/dist/tools/lib/migration.d.ts +1 -1
  128. package/dist/tools/lib/migration.d.ts.map +1 -1
  129. package/dist/tools/subscribe/SubscriptionScope.d.ts.map +1 -1
  130. package/dist/tools/subscribe/index.d.ts +1 -1
  131. package/dist/tools/subscribe/index.d.ts.map +1 -1
  132. package/dist/tools/subscribe/utils.d.ts +2 -2
  133. package/dist/tools/subscribe/utils.d.ts.map +1 -1
  134. package/dist/tools/testing.d.ts.map +1 -1
  135. package/dist/tools/tests/utils.d.ts +2 -6
  136. package/dist/tools/tests/utils.d.ts.map +1 -1
  137. package/dist/worker/index.js +3 -3
  138. package/dist/worker/index.js.map +1 -1
  139. package/package.json +23 -4
  140. package/src/better-auth/auth/client.ts +169 -0
  141. package/src/better-auth/auth/react.tsx +105 -0
  142. package/src/better-auth/auth/server.ts +250 -0
  143. package/src/better-auth/auth/tests/client.test.ts +249 -0
  144. package/src/better-auth/auth/tests/server.test.ts +226 -0
  145. package/src/browser/auth/PasskeyAuth.ts +2 -2
  146. package/src/browser/createBrowserContext.ts +2 -2
  147. package/src/browser/tests/PasskeyAuth.test.ts +2 -2
  148. package/src/inspector/custom-element.tsx +2 -2
  149. package/src/inspector/viewer/new-app.tsx +1 -1
  150. package/src/media/create-image.test.ts +7 -7
  151. package/src/media/create-image.ts +5 -3
  152. package/src/media/index.ts +1 -1
  153. package/src/media/utils.test.ts +72 -66
  154. package/src/media/utils.ts +9 -6
  155. package/src/prosemirror/lib/plugin.ts +1 -1
  156. package/src/prosemirror/lib/sync.ts +1 -1
  157. package/src/prosemirror/tests/plugin.test.ts +4 -4
  158. package/src/react/media/image.tsx +2 -2
  159. package/src/react/tests/media/image.test.tsx +52 -32
  160. package/src/react-core/hooks.ts +11 -5
  161. package/src/react-core/tests/useAccount.test.ts +16 -22
  162. package/src/react-core/tests/useCoState.test.ts +19 -19
  163. package/src/react-core/tests/useInboxSender.test.ts +5 -2
  164. package/src/react-core/tests/usePassPhraseAuth.test.ts +6 -6
  165. package/src/react-native-core/media/image.tsx +1 -1
  166. package/src/svelte/jazz.class.svelte.ts +1 -1
  167. package/src/svelte/media/image.svelte +3 -9
  168. package/src/svelte/media/image.types.ts +7 -0
  169. package/src/svelte/tests/media/image.svelte.test.ts +34 -32
  170. package/src/tools/auth/DemoAuth.ts +2 -2
  171. package/src/tools/auth/PassphraseAuth.ts +2 -2
  172. package/src/tools/auth/clerk/index.ts +2 -2
  173. package/src/tools/auth/clerk/tests/JazzClerkAuth.test.ts +1 -1
  174. package/src/tools/coValues/CoFieldInit.ts +20 -0
  175. package/src/tools/coValues/CoValueBase.ts +40 -60
  176. package/src/tools/coValues/account.ts +311 -232
  177. package/src/tools/coValues/coFeed.ts +185 -153
  178. package/src/tools/coValues/coList.ts +507 -334
  179. package/src/tools/coValues/coMap.ts +434 -286
  180. package/src/tools/coValues/coPlainText.ts +94 -110
  181. package/src/tools/coValues/deepLoading.ts +13 -13
  182. package/src/tools/coValues/group.ts +100 -114
  183. package/src/tools/coValues/inbox.ts +16 -14
  184. package/src/tools/coValues/interfaces.ts +49 -31
  185. package/src/tools/coValues/profile.ts +8 -6
  186. package/src/tools/coValues/request.ts +9 -9
  187. package/src/tools/coValues/schemaUnion.ts +11 -5
  188. package/src/tools/exports.ts +1 -1
  189. package/src/tools/implementation/ContextManager.ts +4 -4
  190. package/src/tools/implementation/anonymousJazzAgent.ts +2 -1
  191. package/src/tools/implementation/createContext.ts +1 -1
  192. package/src/tools/implementation/devtoolsFormatters.ts +9 -9
  193. package/src/tools/implementation/invites.ts +2 -2
  194. package/src/tools/implementation/schema.ts +7 -7
  195. package/src/tools/implementation/symbols.ts +3 -0
  196. package/src/tools/implementation/zodSchema/schemaTypes/AccountSchema.ts +2 -2
  197. package/src/tools/implementation/zodSchema/schemaTypes/CoFeedSchema.ts +11 -2
  198. package/src/tools/implementation/zodSchema/schemaTypes/CoListSchema.ts +18 -7
  199. package/src/tools/implementation/zodSchema/schemaTypes/CoMapSchema.ts +17 -7
  200. package/src/tools/implementation/zodSchema/schemaTypes/CoRecordSchema.ts +20 -11
  201. package/src/tools/implementation/zodSchema/schemaTypes/FileStreamSchema.ts +19 -2
  202. package/src/tools/implementation/zodSchema/schemaTypes/PlainTextSchema.ts +6 -0
  203. package/src/tools/implementation/zodSchema/schemaTypes/RichTextSchema.ts +6 -0
  204. package/src/tools/implementation/zodSchema/typeConverters/{CoFieldInit.ts → CoFieldSchemaInit.ts} +11 -11
  205. package/src/tools/implementation/zodSchema/typeConverters/InstanceOfSchema.ts +4 -4
  206. package/src/tools/implementation/zodSchema/typeConverters/InstanceOfSchemaCoValuesNullable.ts +4 -4
  207. package/src/tools/implementation/zodSchema/zodCo.ts +3 -3
  208. package/src/tools/internal.ts +2 -1
  209. package/src/tools/lib/migration.ts +5 -5
  210. package/src/tools/subscribe/SubscriptionScope.ts +32 -24
  211. package/src/tools/subscribe/index.ts +4 -4
  212. package/src/tools/subscribe/utils.ts +11 -11
  213. package/src/tools/testing.ts +17 -13
  214. package/src/tools/tests/ContextManager.test.ts +70 -59
  215. package/src/tools/tests/PassphraseAuth.test.ts +2 -2
  216. package/src/tools/tests/account.test.ts +188 -67
  217. package/src/tools/tests/coDiscriminatedUnion.test-d.ts +12 -6
  218. package/src/tools/tests/coDiscriminatedUnion.test.ts +26 -17
  219. package/src/tools/tests/coFeed.test-d.ts +18 -17
  220. package/src/tools/tests/coFeed.test.ts +108 -97
  221. package/src/tools/tests/coList.test-d.ts +18 -23
  222. package/src/tools/tests/coList.test.ts +350 -165
  223. package/src/tools/tests/coMap.record.test-d.ts +9 -13
  224. package/src/tools/tests/coMap.record.test.ts +37 -23
  225. package/src/tools/tests/coMap.test-d.ts +43 -21
  226. package/src/tools/tests/coMap.test.ts +459 -182
  227. package/src/tools/tests/coOptional.test.ts +28 -13
  228. package/src/tools/tests/coPlainText.test.ts +15 -15
  229. package/src/tools/tests/createContext.test.ts +14 -14
  230. package/src/tools/tests/deepLoading.test.ts +95 -94
  231. package/src/tools/tests/exportImport.test.ts +61 -41
  232. package/src/tools/tests/groupsAndAccounts.test.ts +333 -116
  233. package/src/tools/tests/inbox.test.ts +22 -17
  234. package/src/tools/tests/interfaces.test.ts +12 -11
  235. package/src/tools/tests/invites.test.ts +6 -4
  236. package/src/tools/tests/load.test.ts +20 -18
  237. package/src/tools/tests/patterns/notifications.test.ts +7 -7
  238. package/src/tools/tests/patterns/quest.test.ts +3 -3
  239. package/src/tools/tests/patterns/requestToJoin.test.ts +22 -22
  240. package/src/tools/tests/request.test.ts +38 -39
  241. package/src/tools/tests/schemaUnion.test.ts +64 -10
  242. package/src/tools/tests/subscribe.test.ts +64 -64
  243. package/src/tools/tests/testing.test.ts +7 -11
  244. package/src/tools/tests/utils.ts +3 -3
  245. package/src/tools/tests/zod.test.ts +3 -3
  246. package/src/worker/index.ts +3 -3
  247. package/tsup.config.ts +9 -0
  248. package/dist/chunk-LZOF6WP5.js.map +0 -1
  249. package/dist/media/chunk-E5J3WLQW.js.map +0 -1
  250. 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"]);
491
519
  });
492
520
 
493
- test("update a reference", () => {
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");
566
+ });
567
+
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,17 +729,120 @@ 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
  });
551
746
 
747
+ describe("has", () => {
748
+ test("should return true if the key is defined", () => {
749
+ const Person = co.map({
750
+ name: z.string(),
751
+ age: z.number().optional(),
752
+ });
753
+
754
+ const person = Person.create({ name: "John", age: 20 });
755
+
756
+ expect(person.$jazz.has("name")).toBe(true);
757
+ expect(person.$jazz.has("age")).toBe(true);
758
+ });
759
+
760
+ test("should return true if the key was set to undefined", () => {
761
+ const Person = co.map({
762
+ name: z.string(),
763
+ age: z.number().optional(),
764
+ });
765
+
766
+ const person = Person.create({ name: "John" });
767
+
768
+ person.$jazz.set("age", undefined);
769
+
770
+ expect(person.$jazz.has("age")).toBe(true);
771
+ });
772
+
773
+ test("should return false if the key is not defined", () => {
774
+ const Person = co.map({
775
+ name: z.string(),
776
+ age: z.number().optional(),
777
+ });
778
+
779
+ const person = Person.create({ name: "John" });
780
+
781
+ expect(person.$jazz.has("age")).toBe(false);
782
+ });
783
+
784
+ test("should return false if the key was deleted", () => {
785
+ const Person = co.map({
786
+ name: z.string(),
787
+ age: z.number().optional(),
788
+ });
789
+
790
+ const person = Person.create({ name: "John", age: 20 });
791
+
792
+ person.$jazz.delete("age");
793
+
794
+ expect(person.$jazz.has("age")).toBe(false);
795
+ });
796
+
797
+ test("should not load the referenced CoValue", async () => {
798
+ const Person = co.map({
799
+ name: co.plainText(),
800
+ });
801
+
802
+ const { clientAccount, serverAccount } = await setupTwoNodes();
803
+
804
+ const person = Person.create(
805
+ {
806
+ name: "John",
807
+ },
808
+ { owner: Group.create(serverAccount).makePublic() },
809
+ );
810
+
811
+ const loadedPerson = await Person.load(person.$jazz.id, {
812
+ resolve: true,
813
+ loadAs: clientAccount,
814
+ });
815
+
816
+ assert(loadedPerson);
817
+ expect(loadedPerson.$jazz.has("name")).toBe(true);
818
+ expect(loadedPerson.name).toBeNull();
819
+ });
820
+
821
+ test("should return true even if the viewer doesn't have access to the referenced CoValue", async () => {
822
+ const Person = co.map({
823
+ name: co.plainText(),
824
+ });
825
+
826
+ const person = Person.create(
827
+ // UserB has no access to name
828
+ { name: co.plainText().create("John", Group.create()) },
829
+ // UserB has access to person
830
+ { owner: Group.create().makePublic() },
831
+ );
832
+
833
+ const userB = await createJazzTestAccount();
834
+
835
+ const loadedPerson = await Person.load(person.$jazz.id, {
836
+ resolve: true,
837
+ loadAs: userB,
838
+ });
839
+
840
+ assert(loadedPerson);
841
+ expect(loadedPerson.$jazz.has("name")).toBe(true);
842
+ expect(loadedPerson.name).toBeNull();
843
+ });
844
+ });
845
+
552
846
  test("Enum of maps", () => {
553
847
  const ChildA = co.map({
554
848
  type: z.literal("a"),
@@ -576,7 +870,7 @@ describe("CoMap", async () => {
576
870
  expect(mapWithEnum.name).toEqual("enum");
577
871
  expect(mapWithEnum.child?.type).toEqual("a");
578
872
  expect(mapWithEnum.child?.value).toEqual(5);
579
- expect(mapWithEnum.child?.id).toBeDefined();
873
+ expect(mapWithEnum.child?.$jazz.id).toBeDefined();
580
874
 
581
875
  // TODO: properly support narrowing once we get rid of the coField marker
582
876
  // if (mapWithEnum.child?.type === "a") {
@@ -604,7 +898,7 @@ describe("CoMap resolution", async () => {
604
898
  dog: Dog.create({ name: "Rex", breed: "Labrador" }),
605
899
  });
606
900
 
607
- const loadedPerson = await Person.load(person.id, {
901
+ const loadedPerson = await Person.load(person.$jazz.id, {
608
902
  resolve: {
609
903
  dog: true,
610
904
  },
@@ -632,7 +926,7 @@ describe("CoMap resolution", async () => {
632
926
  dog: Dog.create({ name: "Rex", breed: "Labrador" }),
633
927
  });
634
928
 
635
- const loadedPerson = await Person.load(person.id);
929
+ const loadedPerson = await Person.load(person.$jazz.id);
636
930
 
637
931
  assert(loadedPerson);
638
932
  expect(loadedPerson.dog?.name).toEqual("Rex");
@@ -664,7 +958,7 @@ describe("CoMap resolution", async () => {
664
958
 
665
959
  const userB = await createJazzTestAccount();
666
960
 
667
- const loadedPerson = await Person.load(person.id, {
961
+ const loadedPerson = await Person.load(person.$jazz.id, {
668
962
  resolve: {
669
963
  dog: true,
670
964
  },
@@ -700,7 +994,7 @@ describe("CoMap resolution", async () => {
700
994
  );
701
995
 
702
996
  const userB = await createJazzTestAccount();
703
- const loadedPerson = await Person.load(person.id, {
997
+ const loadedPerson = await Person.load(person.$jazz.id, {
704
998
  loadAs: userB,
705
999
  });
706
1000
 
@@ -726,8 +1020,8 @@ describe("CoMap resolution", async () => {
726
1020
  const currentAccount = Account.getMe();
727
1021
 
728
1022
  // Disconnect the current account
729
- currentAccount._raw.core.node.syncManager
730
- .getServerPeers(currentAccount._raw.id)
1023
+ currentAccount.$jazz.localNode.syncManager
1024
+ .getServerPeers(currentAccount.$jazz.raw.id)
731
1025
  .forEach((peer) => {
732
1026
  peer.gracefulShutdown();
733
1027
  });
@@ -747,7 +1041,7 @@ describe("CoMap resolution", async () => {
747
1041
  const userB = await createJazzTestAccount();
748
1042
 
749
1043
  // We expect that the test doesn't hang here and immediately returns null
750
- const loadedPerson = await Person.load(person.id, {
1044
+ const loadedPerson = await Person.load(person.$jazz.id, {
751
1045
  loadAs: userB,
752
1046
  skipRetry: true,
753
1047
  });
@@ -773,8 +1067,8 @@ describe("CoMap resolution", async () => {
773
1067
  const currentAccount = Account.getMe();
774
1068
 
775
1069
  // Disconnect the current account
776
- currentAccount._raw.core.node.syncManager
777
- .getServerPeers(currentAccount._raw.id)
1070
+ currentAccount.$jazz.localNode.syncManager
1071
+ .getServerPeers(currentAccount.$jazz.raw.id)
778
1072
  .forEach((peer) => {
779
1073
  peer.gracefulShutdown();
780
1074
  });
@@ -793,7 +1087,7 @@ describe("CoMap resolution", async () => {
793
1087
 
794
1088
  const userB = await createJazzTestAccount();
795
1089
  let resolved = false;
796
- const promise = Person.load(person.id, {
1090
+ const promise = Person.load(person.$jazz.id, {
797
1091
  loadAs: userB,
798
1092
  skipRetry: false,
799
1093
  });
@@ -806,7 +1100,7 @@ describe("CoMap resolution", async () => {
806
1100
  expect(resolved).toBe(false);
807
1101
 
808
1102
  // Reconnect the current account
809
- currentAccount._raw.core.node.syncManager.addPeer(
1103
+ currentAccount.$jazz.localNode.syncManager.addPeer(
810
1104
  getPeerConnectedToTestSyncServer(),
811
1105
  );
812
1106
 
@@ -842,15 +1136,15 @@ describe("CoMap resolution", async () => {
842
1136
  );
843
1137
 
844
1138
  const userB = await createJazzTestAccount();
845
- const loadedPerson = await Person.load(person.id, {
1139
+ const loadedPerson = await Person.load(person.$jazz.id, {
846
1140
  loadAs: userB,
847
1141
  });
848
1142
 
849
1143
  assert(loadedPerson);
850
1144
 
851
- expect(loadedPerson._refs.dog?.id).toBe(person.dog!.id);
1145
+ expect(loadedPerson.$jazz.refs.dog?.id).toBe(person.dog!.$jazz.id);
852
1146
 
853
- const dog = await loadedPerson._refs.dog?.load();
1147
+ const dog = await loadedPerson.$jazz.refs.dog?.load();
854
1148
 
855
1149
  assert(dog);
856
1150
 
@@ -879,7 +1173,7 @@ describe("CoMap resolution", async () => {
879
1173
  const spy = vi.fn((person) => updates.push(person));
880
1174
 
881
1175
  Person.subscribe(
882
- person.id,
1176
+ person.$jazz.id,
883
1177
  {
884
1178
  resolve: {
885
1179
  dog: true,
@@ -896,7 +1190,7 @@ describe("CoMap resolution", async () => {
896
1190
 
897
1191
  expect(updates[0]?.dog.name).toEqual("Rex");
898
1192
 
899
- person.dog!.name = "Fido";
1193
+ person.dog!.$jazz.set("name", "Fido");
900
1194
 
901
1195
  await waitFor(() => expect(spy).toHaveBeenCalledTimes(2));
902
1196
 
@@ -926,7 +1220,7 @@ describe("CoMap resolution", async () => {
926
1220
  const updates: Loaded<typeof Person>[] = [];
927
1221
  const spy = vi.fn((person) => updates.push(person));
928
1222
 
929
- Person.subscribe(person.id, {}, spy);
1223
+ Person.subscribe(person.$jazz.id, {}, spy);
930
1224
 
931
1225
  expect(spy).not.toHaveBeenCalled();
932
1226
 
@@ -936,7 +1230,7 @@ describe("CoMap resolution", async () => {
936
1230
 
937
1231
  expect(updates[0]?.dog?.name).toEqual("Rex");
938
1232
 
939
- person.dog!.name = "Fido";
1233
+ person.dog!.$jazz.set("name", "Fido");
940
1234
 
941
1235
  await waitFor(() => expect(spy).toHaveBeenCalledTimes(2));
942
1236
 
@@ -968,7 +1262,7 @@ describe("CoMap resolution", async () => {
968
1262
 
969
1263
  subscribeToCoValue(
970
1264
  coValueClassFromCoValueClassOrSchema(Person), // TODO: we should get rid of the conversion in the future
971
- person.id,
1265
+ person.$jazz.id,
972
1266
  {
973
1267
  syncResolution: true,
974
1268
  loadAs: Account.getMe(),
@@ -983,7 +1277,7 @@ describe("CoMap resolution", async () => {
983
1277
 
984
1278
  expect(spy).toHaveBeenCalledTimes(1);
985
1279
 
986
- person.dog!.name = "Fido";
1280
+ person.dog!.$jazz.set("name", "Fido");
987
1281
 
988
1282
  expect(spy).toHaveBeenCalledTimes(2);
989
1283
 
@@ -1022,7 +1316,7 @@ describe("CoMap resolution", async () => {
1022
1316
  const spy = vi.fn((person) => updates.push(person));
1023
1317
 
1024
1318
  Person.subscribe(
1025
- person.id,
1319
+ person.$jazz.id,
1026
1320
  {
1027
1321
  resolve: {
1028
1322
  dog: true,
@@ -1040,7 +1334,7 @@ describe("CoMap resolution", async () => {
1040
1334
 
1041
1335
  expect(updates[0]?.dog.name).toEqual("Rex");
1042
1336
 
1043
- person.dog!.name = "Fido";
1337
+ person.dog!.$jazz.set("name", "Fido");
1044
1338
 
1045
1339
  await waitFor(() => expect(spy).toHaveBeenCalledTimes(2));
1046
1340
 
@@ -1079,7 +1373,7 @@ describe("CoMap resolution", async () => {
1079
1373
  const userB = await createJazzTestAccount();
1080
1374
 
1081
1375
  Person.subscribe(
1082
- person.id,
1376
+ person.$jazz.id,
1083
1377
  {
1084
1378
  loadAs: userB,
1085
1379
  },
@@ -1094,7 +1388,7 @@ describe("CoMap resolution", async () => {
1094
1388
 
1095
1389
  expect(updates[0]?.dog?.name).toEqual("Rex");
1096
1390
 
1097
- person.dog!.name = "Fido";
1391
+ person.dog!.$jazz.set("name", "Fido");
1098
1392
 
1099
1393
  await waitFor(() => expect(spy).toHaveBeenCalledTimes(2));
1100
1394
 
@@ -1125,7 +1419,7 @@ describe("CoMap resolution", async () => {
1125
1419
  const spy = vi.fn((person) => updates.push(person));
1126
1420
 
1127
1421
  Person.subscribe(
1128
- person.id,
1422
+ person.$jazz.id,
1129
1423
  {
1130
1424
  resolve: {
1131
1425
  dog: true,
@@ -1142,7 +1436,7 @@ describe("CoMap resolution", async () => {
1142
1436
 
1143
1437
  expect(updates[0]?.dog.name).toEqual("Rex");
1144
1438
 
1145
- person.dog!.name = "Fido";
1439
+ person.dog!.$jazz.set("name", "Fido");
1146
1440
 
1147
1441
  await waitFor(() => expect(spy).toHaveBeenCalledTimes(2));
1148
1442
 
@@ -1190,7 +1484,7 @@ describe("CoMap applyDiff", async () => {
1190
1484
  isActive: false,
1191
1485
  };
1192
1486
 
1193
- map.applyDiff(newValues);
1487
+ map.$jazz.applyDiff(newValues);
1194
1488
 
1195
1489
  expect(map.name).toEqual("Bob");
1196
1490
  expect(map.age).toEqual(35);
@@ -1200,13 +1494,17 @@ describe("CoMap applyDiff", async () => {
1200
1494
  });
1201
1495
 
1202
1496
  test("applyDiff with nested changes", () => {
1497
+ const originalNestedMap = NestedMap.create(
1498
+ { value: "original" },
1499
+ { owner: me },
1500
+ );
1203
1501
  const map = TestMap.create(
1204
1502
  {
1205
1503
  name: "Charlie",
1206
1504
  age: 25,
1207
1505
  isActive: true,
1208
1506
  birthday: new Date("1995-01-01"),
1209
- nested: NestedMap.create({ value: "original" }, { owner: me }),
1507
+ nested: originalNestedMap,
1210
1508
  },
1211
1509
  { owner: me },
1212
1510
  );
@@ -1216,11 +1514,13 @@ describe("CoMap applyDiff", async () => {
1216
1514
  nested: NestedMap.create({ value: "updated" }, { owner: me }),
1217
1515
  };
1218
1516
 
1219
- map.applyDiff(newValues);
1517
+ map.$jazz.applyDiff(newValues);
1220
1518
 
1221
1519
  expect(map.name).toEqual("David");
1222
1520
  expect(map.age).toEqual(25);
1223
1521
  expect(map.nested?.value).toEqual("updated");
1522
+ // A new nested CoMap is created
1523
+ expect(map.nested.$jazz.id).not.toBe(originalNestedMap.$jazz.id);
1224
1524
  });
1225
1525
 
1226
1526
  test("applyDiff with encoded fields", () => {
@@ -1239,7 +1539,7 @@ describe("CoMap applyDiff", async () => {
1239
1539
  birthday: new Date("1993-06-15"),
1240
1540
  };
1241
1541
 
1242
- map.applyDiff(newValues);
1542
+ map.$jazz.applyDiff(newValues);
1243
1543
 
1244
1544
  expect(map.birthday).toEqual(new Date("1993-06-15"));
1245
1545
  });
@@ -1260,11 +1560,11 @@ describe("CoMap applyDiff", async () => {
1260
1560
  optionalField: "New optional value",
1261
1561
  };
1262
1562
 
1263
- map.applyDiff(newValues);
1563
+ map.$jazz.applyDiff(newValues);
1264
1564
 
1265
1565
  expect(map.optionalField).toEqual("New optional value");
1266
1566
 
1267
- map.applyDiff({ optionalField: undefined });
1567
+ map.$jazz.applyDiff({ optionalField: undefined });
1268
1568
 
1269
1569
  expect(map.optionalField).toBeUndefined();
1270
1570
  });
@@ -1283,7 +1583,7 @@ describe("CoMap applyDiff", async () => {
1283
1583
 
1284
1584
  const originalJSON = map.toJSON();
1285
1585
 
1286
- map.applyDiff({});
1586
+ map.$jazz.applyDiff({});
1287
1587
 
1288
1588
  expect(map.toJSON()).toEqual(originalJSON);
1289
1589
  });
@@ -1304,8 +1604,7 @@ describe("CoMap applyDiff", async () => {
1304
1604
  name: "Ian",
1305
1605
  invalidField: "This should be ignored",
1306
1606
  };
1307
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1308
- map.applyDiff(newValues as any);
1607
+ map.$jazz.applyDiff(newValues);
1309
1608
 
1310
1609
  expect(map.name).toEqual("Ian");
1311
1610
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -1329,7 +1628,7 @@ describe("CoMap applyDiff", async () => {
1329
1628
  optionalNested: undefined,
1330
1629
  };
1331
1630
 
1332
- map.applyDiff(newValues);
1631
+ map.$jazz.applyDiff(newValues);
1333
1632
 
1334
1633
  expect(map.optionalNested).toBeUndefined();
1335
1634
  });
@@ -1350,10 +1649,31 @@ describe("CoMap applyDiff", async () => {
1350
1649
  nested: undefined,
1351
1650
  };
1352
1651
 
1353
- expect(() => map.applyDiff(newValues)).toThrowError(
1652
+ expect(() => map.$jazz.applyDiff(newValues)).toThrowError(
1354
1653
  "Cannot set required reference nested to undefined",
1355
1654
  );
1356
1655
  });
1656
+
1657
+ test("applyDiff from JSON", () => {
1658
+ const map = TestMap.create({
1659
+ name: "Alice",
1660
+ age: 30,
1661
+ isActive: true,
1662
+ birthday: new Date("1990-01-01"),
1663
+ nested: NestedMap.create({ value: "original" }),
1664
+ });
1665
+ const originalNestedMap = map.nested;
1666
+
1667
+ const newValues = {
1668
+ nested: { value: "updated" },
1669
+ };
1670
+
1671
+ map.$jazz.applyDiff(newValues);
1672
+
1673
+ expect(map.nested?.value).toEqual("updated");
1674
+ // A new nested CoMap is created
1675
+ expect(map.nested.$jazz.id).not.toBe(originalNestedMap.$jazz.id);
1676
+ });
1357
1677
  });
1358
1678
 
1359
1679
  describe("CoMap Typescript validation", async () => {
@@ -1373,9 +1693,9 @@ describe("CoMap Typescript validation", async () => {
1373
1693
  });
1374
1694
 
1375
1695
  expectTypeOf<typeof TestMap.create>().toBeCallableWith(
1696
+ // @ts-expect-error null can't be passed to a non-optional field
1376
1697
  {
1377
1698
  optional: NestedMap.create({ value: "" }, { owner: me }),
1378
- // @ts-expect-error null can't be passed to a non-optional field
1379
1699
  required: null,
1380
1700
  },
1381
1701
  { owner: me },
@@ -1439,12 +1759,12 @@ describe("CoMap Typescript validation", async () => {
1439
1759
  { owner: clientAccount },
1440
1760
  );
1441
1761
 
1442
- await map.waitForSync({ timeout: 1000 });
1762
+ await map.$jazz.waitForSync({ timeout: 1000 });
1443
1763
 
1444
1764
  // Killing the client node so the serverNode can't load the map from it
1445
1765
  clientNode.gracefulShutdown();
1446
1766
 
1447
- const loadedMap = await serverNode.load(map._raw.id);
1767
+ const loadedMap = await serverNode.load(map.$jazz.raw.id);
1448
1768
 
1449
1769
  expect(loadedMap).not.toBe("unavailable");
1450
1770
  });
@@ -1471,7 +1791,10 @@ describe("Creating and finding unique CoMaps", async () => {
1471
1791
  { owner: group, unique: { name: "Alice" } },
1472
1792
  );
1473
1793
 
1474
- const foundAlice = await Person.loadUnique({ name: "Alice" }, group.id);
1794
+ const foundAlice = await Person.loadUnique(
1795
+ { name: "Alice" },
1796
+ group.$jazz.id,
1797
+ );
1475
1798
  expect(foundAlice).toEqual(alice);
1476
1799
  });
1477
1800
 
@@ -1494,7 +1817,7 @@ describe("Creating and finding unique CoMaps", async () => {
1494
1817
  // Pattern
1495
1818
  let activeEvent = await Event.loadUnique(
1496
1819
  { identifier: sourceData.identifier },
1497
- workspace.id,
1820
+ workspace.$jazz.id,
1498
1821
  );
1499
1822
  if (!activeEvent) {
1500
1823
  activeEvent = Event.create(
@@ -1506,7 +1829,7 @@ describe("Creating and finding unique CoMaps", async () => {
1506
1829
  workspace,
1507
1830
  );
1508
1831
  } else {
1509
- activeEvent.applyDiff({
1832
+ activeEvent.$jazz.applyDiff({
1510
1833
  title: sourceData.title,
1511
1834
  identifier: sourceData.identifier,
1512
1835
  external_id: sourceData._id,
@@ -1589,7 +1912,7 @@ describe("Creating and finding unique CoMaps", async () => {
1589
1912
 
1590
1913
  assert(activeEvent);
1591
1914
 
1592
- expect(activeEvent._owner).toEqual(account);
1915
+ expect(activeEvent.$jazz.owner).toEqual(account);
1593
1916
  });
1594
1917
 
1595
1918
  test("upserting an existing value", async () => {
@@ -1767,12 +2090,14 @@ describe("Creating and finding unique CoMaps", async () => {
1767
2090
  isCurrentActiveAccount: true,
1768
2091
  });
1769
2092
 
1770
- const shallowProjectList = await co.list(Project).load(fullProjectList.id, {
1771
- loadAs: account,
1772
- });
2093
+ const shallowProjectList = await co
2094
+ .list(Project)
2095
+ .load(fullProjectList.$jazz.id, {
2096
+ loadAs: account,
2097
+ });
1773
2098
  assert(shallowProjectList);
1774
2099
 
1775
- const publicAccessAsNewAccount = await Group.load(publicAccess.id, {
2100
+ const publicAccessAsNewAccount = await Group.load(publicAccess.$jazz.id, {
1776
2101
  loadAs: account,
1777
2102
  });
1778
2103
  assert(publicAccessAsNewAccount);
@@ -1793,7 +2118,7 @@ describe("Creating and finding unique CoMaps", async () => {
1793
2118
 
1794
2119
  assert(updatedOrg);
1795
2120
 
1796
- expect(updatedOrg.projects.id).toEqual(fullProjectList.id);
2121
+ expect(updatedOrg.projects.$jazz.id).toEqual(fullProjectList.$jazz.id);
1797
2122
  expect(updatedOrg.projects.length).toBe(1);
1798
2123
  expect(updatedOrg.projects.at(0)?.name).toEqual("My project");
1799
2124
  });
@@ -1843,12 +2168,14 @@ describe("Creating and finding unique CoMaps", async () => {
1843
2168
  isCurrentActiveAccount: true,
1844
2169
  });
1845
2170
 
1846
- const shallowProjectList = await co.list(Project).load(fullProjectList.id, {
1847
- loadAs: account,
1848
- });
2171
+ const shallowProjectList = await co
2172
+ .list(Project)
2173
+ .load(fullProjectList.$jazz.id, {
2174
+ loadAs: account,
2175
+ });
1849
2176
  assert(shallowProjectList);
1850
2177
 
1851
- const publicAccessAsNewAccount = await Group.load(publicAccess.id, {
2178
+ const publicAccessAsNewAccount = await Group.load(publicAccess.$jazz.id, {
1852
2179
  loadAs: account,
1853
2180
  });
1854
2181
  assert(publicAccessAsNewAccount);
@@ -1869,10 +2196,10 @@ describe("Creating and finding unique CoMaps", async () => {
1869
2196
 
1870
2197
  assert(updatedOrg);
1871
2198
 
1872
- expect(updatedOrg.projects.id).toEqual(fullProjectList.id);
2199
+ expect(updatedOrg.projects.$jazz.id).toEqual(fullProjectList.$jazz.id);
1873
2200
  expect(updatedOrg.projects.length).toBe(1);
1874
2201
  expect(updatedOrg.projects.at(0)?.name).toEqual("My project");
1875
- expect(updatedOrg.id).toEqual(myOrg.id);
2202
+ expect(updatedOrg.$jazz.id).toEqual(myOrg.$jazz.id);
1876
2203
  });
1877
2204
 
1878
2205
  test("complex discriminated union", () => {
@@ -2031,58 +2358,6 @@ describe("Creating and finding unique CoMaps", async () => {
2031
2358
  });
2032
2359
  });
2033
2360
 
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
2361
  describe("CoMap migration", () => {
2087
2362
  test("should run on load", async () => {
2088
2363
  const PersonV1 = co.map({
@@ -2098,8 +2373,8 @@ describe("CoMap migration", () => {
2098
2373
  })
2099
2374
  .withMigration((person) => {
2100
2375
  if (person.version === 1) {
2101
- person.age = 20;
2102
- person.version = 2;
2376
+ person.$jazz.set("age", 20);
2377
+ person.$jazz.set("version", 2);
2103
2378
  }
2104
2379
  });
2105
2380
 
@@ -2111,7 +2386,7 @@ describe("CoMap migration", () => {
2111
2386
  expect(person?.name).toEqual("Bob");
2112
2387
  expect(person?.version).toEqual(1);
2113
2388
 
2114
- const loadedPerson = await Person.load(person.id);
2389
+ const loadedPerson = await Person.load(person.$jazz.id);
2115
2390
 
2116
2391
  expect(loadedPerson?.name).toEqual("Bob");
2117
2392
  expect(loadedPerson?.age).toEqual(20);
@@ -2126,9 +2401,9 @@ describe("CoMap migration", () => {
2126
2401
  })
2127
2402
  .withMigration((person) => {
2128
2403
  if (person.version === 1) {
2129
- person.version = 2;
2404
+ person.$jazz.set("version", 2);
2130
2405
 
2131
- person._owner.castAs(Group).addMember("everyone", "reader");
2406
+ person.$jazz.owner.addMember("everyone", "reader");
2132
2407
  }
2133
2408
  });
2134
2409
 
@@ -2140,14 +2415,14 @@ describe("CoMap migration", () => {
2140
2415
  expect(person?.name).toEqual("Bob");
2141
2416
  expect(person?.version).toEqual(1);
2142
2417
 
2143
- const loadedPerson = await Person.load(person.id);
2418
+ const loadedPerson = await Person.load(person.$jazz.id);
2144
2419
 
2145
2420
  expect(loadedPerson?.name).toEqual("Bob");
2146
2421
  expect(loadedPerson?.version).toEqual(2);
2147
2422
 
2148
2423
  const anotherAccount = await createJazzTestAccount();
2149
2424
 
2150
- const loadedPersonFromAnotherAccount = await Person.load(person.id, {
2425
+ const loadedPersonFromAnotherAccount = await Person.load(person.$jazz.id, {
2151
2426
  loadAs: anotherAccount,
2152
2427
  });
2153
2428
 
@@ -2168,7 +2443,7 @@ describe("CoMap migration", () => {
2168
2443
  version: 1,
2169
2444
  });
2170
2445
 
2171
- await expect(Person.load(person.id)).rejects.toThrow(
2446
+ await expect(Person.load(person.$jazz.id)).rejects.toThrow(
2172
2447
  "Migration function cannot be async",
2173
2448
  );
2174
2449
  });
@@ -2189,8 +2464,8 @@ describe("CoMap migration", () => {
2189
2464
  version: 1,
2190
2465
  });
2191
2466
 
2192
- await Person.load(person.id);
2193
- await Person.load(person.id);
2467
+ await Person.load(person.$jazz.id);
2468
+ await Person.load(person.$jazz.id);
2194
2469
  expect(spy).toHaveBeenCalledTimes(1);
2195
2470
  });
2196
2471
 
@@ -2214,8 +2489,8 @@ describe("CoMap migration", () => {
2214
2489
  })
2215
2490
  .withMigration((person) => {
2216
2491
  if (person.version === 1) {
2217
- person.age = 20;
2218
- person.version = 2;
2492
+ person.$jazz.set("age", 20);
2493
+ person.$jazz.set("version", 2);
2219
2494
  }
2220
2495
  });
2221
2496
 
@@ -2230,7 +2505,7 @@ describe("CoMap migration", () => {
2230
2505
  friend: charlie,
2231
2506
  });
2232
2507
 
2233
- const loaded = await Person.load(bob.id, {
2508
+ const loaded = await Person.load(bob.$jazz.id, {
2234
2509
  resolve: {
2235
2510
  friend: true,
2236
2511
  },
@@ -2249,7 +2524,7 @@ describe("createdAt & lastUpdatedAt", () => {
2249
2524
  test("empty map created time", () => {
2250
2525
  const emptyMap = co.map({}).create({});
2251
2526
 
2252
- expect(emptyMap._lastUpdatedAt).toEqual(emptyMap._createdAt);
2527
+ expect(emptyMap.$jazz.lastUpdatedAt).toEqual(emptyMap.$jazz.createdAt);
2253
2528
  });
2254
2529
 
2255
2530
  test("created time and last updated time", async () => {
@@ -2259,14 +2534,14 @@ describe("createdAt & lastUpdatedAt", () => {
2259
2534
 
2260
2535
  const person = Person.create({ name: "John" });
2261
2536
 
2262
- const createdAt = person._createdAt;
2263
- expect(person._lastUpdatedAt).toEqual(createdAt);
2537
+ const createdAt = person.$jazz.createdAt;
2538
+ expect(person.$jazz.lastUpdatedAt).toEqual(createdAt);
2264
2539
 
2265
2540
  await new Promise((r) => setTimeout(r, 10));
2266
- person.name = "Jane";
2541
+ person.$jazz.set("name", "Jane");
2267
2542
 
2268
- expect(person._createdAt).toEqual(createdAt);
2269
- expect(person._lastUpdatedAt).not.toEqual(createdAt);
2543
+ expect(person.$jazz.createdAt).toEqual(createdAt);
2544
+ expect(person.$jazz.lastUpdatedAt).not.toEqual(createdAt);
2270
2545
  });
2271
2546
  });
2272
2547
 
@@ -2343,10 +2618,10 @@ describe("co.map schema", () => {
2343
2618
  expect(draftPerson.age).toBeUndefined();
2344
2619
  expect(draftPerson.pet).toBeUndefined();
2345
2620
 
2346
- draftPerson.name = "John";
2347
- draftPerson.age = 20;
2621
+ draftPerson.$jazz.set("name", "John");
2622
+ draftPerson.$jazz.set("age", 20);
2348
2623
  const rex = Dog.create({ name: "Rex", breed: "Labrador" });
2349
- draftPerson.pet = rex;
2624
+ draftPerson.$jazz.set("pet", rex);
2350
2625
 
2351
2626
  expect(draftPerson.name).toEqual("John");
2352
2627
  expect(draftPerson.age).toEqual(20);
@@ -2364,7 +2639,7 @@ describe("co.map schema", () => {
2364
2639
  const DraftPerson = Person.partial();
2365
2640
 
2366
2641
  const draftPerson = DraftPerson.create({});
2367
- draftPerson.extraField = "extra";
2642
+ draftPerson.$jazz.set("extraField", "extra");
2368
2643
 
2369
2644
  expect(draftPerson.extraField).toEqual("extra");
2370
2645
  });
@@ -2431,7 +2706,7 @@ describe("Updating a nested reference", () => {
2431
2706
  group.addMember(player1Account, "reader");
2432
2707
 
2433
2708
  // Load the game to verify the assignment worked
2434
- const loadedGame = await Game.load(game.id, {
2709
+ const loadedGame = await Game.load(game.$jazz.id, {
2435
2710
  resolve: {
2436
2711
  player1: {
2437
2712
  account: true,
@@ -2450,7 +2725,7 @@ describe("Updating a nested reference", () => {
2450
2725
  const playSelection = PlaySelection.create({ value: "rock", group }, group);
2451
2726
 
2452
2727
  // Assign the play selection to player1 (similar to the route logic)
2453
- loadedGame.player1.playSelection = playSelection;
2728
+ loadedGame.player1.$jazz.set("playSelection", playSelection);
2454
2729
 
2455
2730
  // Verify that the playSelection is not null and has the expected value
2456
2731
  expect(loadedGame.player1.playSelection).not.toBeNull();
@@ -2499,7 +2774,7 @@ describe("Updating a nested reference", () => {
2499
2774
  });
2500
2775
 
2501
2776
  // Load the game to verify the assignment worked
2502
- const loadedGame = await Game.load(game.id, {
2777
+ const loadedGame = await Game.load(game.$jazz.id, {
2503
2778
  resolve: {
2504
2779
  player1: {
2505
2780
  account: true,
@@ -2518,10 +2793,12 @@ describe("Updating a nested reference", () => {
2518
2793
  const playSelection = PlaySelection.create({ value: "scissors" });
2519
2794
 
2520
2795
  // Assign the play selection to player1 (similar to the route logic)
2521
- loadedGame.player1.playSelection = playSelection;
2796
+ loadedGame.player1.$jazz.set("playSelection", playSelection);
2522
2797
 
2523
2798
  // Verify that the playSelection is not null and has the expected value
2524
- expect(loadedGame.player1.playSelection.id).toBe(playSelection.id);
2799
+ expect(loadedGame.player1.playSelection.$jazz.id).toBe(
2800
+ playSelection.$jazz.id,
2801
+ );
2525
2802
  expect(loadedGame.player1.playSelection.value).toEqual("scissors");
2526
2803
  });
2527
2804
  });