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
@@ -8,10 +8,12 @@ import {
8
8
  type RawCoMap,
9
9
  cojsonInternals,
10
10
  } from "cojson";
11
- import type {
11
+ import {
12
12
  AnonymousJazzAgent,
13
+ CoFieldInit,
13
14
  CoValue,
14
15
  CoValueClass,
16
+ getCoValueOwner,
15
17
  Group,
16
18
  ID,
17
19
  PartialOnUndefined,
@@ -24,10 +26,12 @@ import type {
24
26
  Simplify,
25
27
  SubscribeListenerOptions,
26
28
  SubscribeRestArgs,
29
+ TypeSym,
27
30
  } from "../internal.js";
28
31
  import {
29
32
  Account,
30
33
  CoValueBase,
34
+ CoValueJazzApi,
31
35
  ItemsSym,
32
36
  Ref,
33
37
  RegisteredSchemas,
@@ -57,6 +61,14 @@ type CoMapEdit<V> = {
57
61
 
58
62
  type LastAndAllCoMapEdits<V> = CoMapEdit<V> & { all: CoMapEdit<V>[] };
59
63
 
64
+ type CoMapEdits<M extends CoMap> = {
65
+ [Key in CoKeys<M>]?: LastAndAllCoMapEdits<M[Key]>;
66
+ };
67
+
68
+ type CoMapFieldSchema = {
69
+ [key: string]: Schema;
70
+ } & { [ItemsSym]?: Schema };
71
+
60
72
  /**
61
73
  * CoMaps are collaborative versions of plain objects, mapping string-like keys to values.
62
74
  *
@@ -91,196 +103,44 @@ type LastAndAllCoMapEdits<V> = CoMapEdit<V> & { all: CoMapEdit<V>[] };
91
103
  * @category CoValues
92
104
  * */
93
105
  export class CoMap extends CoValueBase implements CoValue {
94
- /**
95
- * The ID of this `CoMap`
96
- * @category Content */
97
- declare id: ID<this>;
98
106
  /** @category Type Helpers */
99
- declare _type: "CoMap";
107
+ declare [TypeSym]: "CoMap";
100
108
  static {
101
- this.prototype._type = "CoMap";
102
- }
103
- /** @category Internals */
104
- declare _raw: RawCoMap;
105
-
106
- /** @internal */
107
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
108
- static _schema: any;
109
- /** @internal */
110
- get _schema() {
111
- return (this.constructor as typeof CoMap)._schema as {
112
- [key: string]: Schema;
113
- } & { [ItemsSym]?: Schema };
109
+ this.prototype[TypeSym] = "CoMap";
114
110
  }
115
111
 
116
112
  /**
117
- * The timestamp of the creation time of the CoMap
118
- */
119
- get _createdAt() {
120
- return this._raw.earliestTxMadeAt ?? Number.MAX_SAFE_INTEGER;
121
- }
122
-
123
- /**
124
- * The timestamp of the last updated time of the CoMap
125
- */
126
- get _lastUpdatedAt() {
127
- return this._raw.latestTxMadeAt;
128
- }
129
-
130
- /**
131
- * If property `prop` is a `coField.ref(...)`, you can use `coMaps._refs.prop` to access
132
- * the `Ref` instead of the potentially loaded/null value.
133
- *
134
- * This allows you to always get the ID or load the value manually.
135
- *
136
- * @example
137
- * ```ts
138
- * person._refs.pet.id; // => ID<Animal>
139
- * person._refs.pet.value;
140
- * // => Animal | null
141
- * const pet = await person._refs.pet.load();
142
- * ```
113
+ * Jazz methods for CoMaps are inside this property.
143
114
  *
144
- * @category Content
145
- **/
146
- get _refs(): Simplify<
147
- {
148
- [Key in CoKeys<this> as NonNullable<this[Key]> extends CoValue
149
- ? Key
150
- : never]?: RefIfCoValue<this[Key]>;
151
- } & {
152
- [Key in CoKeys<this> as this[Key] extends undefined
153
- ? never
154
- : this[Key] extends CoValue
155
- ? Key
156
- : never]: RefIfCoValue<this[Key]>;
157
- }
158
- > {
159
- return makeRefs<CoKeys<this>>(
160
- this,
161
- (key) => this._raw.get(key as string) as unknown as ID<CoValue>,
162
- () => {
163
- const keys = this._raw.keys().filter((key) => {
164
- const descriptor = this.getDescriptor(key as string);
165
- return (
166
- descriptor && descriptor !== "json" && isRefEncoded(descriptor)
167
- );
168
- }) as CoKeys<this>[];
169
-
170
- return keys;
171
- },
172
- this._loadedAs,
173
- (key) => this.getDescriptor(key as string) as RefEncoded<CoValue>,
174
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
175
- ) as any;
176
- }
115
+ * This allows CoMaps to be used as plain objects while still having
116
+ * access to Jazz methods, and also doesn't limit which key names can be
117
+ * used inside CoMaps.
118
+ */
119
+ declare $jazz: CoMapJazzApi<this>;
177
120
 
178
121
  /** @internal */
179
- public getEditFromRaw(
180
- target: CoMap,
181
- rawEdit: {
182
- by: RawAccountID | AgentID;
183
- tx: CojsonInternalTypes.TransactionID;
184
- at: Date;
185
- value?: JsonValue | undefined;
186
- },
187
- descriptor: Schema,
188
- key: string,
189
- ) {
190
- return {
191
- value:
192
- descriptor === "json"
193
- ? rawEdit.value
194
- : "encoded" in descriptor
195
- ? rawEdit.value === null || rawEdit.value === undefined
196
- ? rawEdit.value
197
- : descriptor.encoded.decode(rawEdit.value)
198
- : accessChildById(target, rawEdit.value as string, descriptor),
199
- ref:
200
- descriptor !== "json" && isRefEncoded(descriptor)
201
- ? new Ref(
202
- rawEdit.value as ID<CoValue>,
203
- target._loadedAs,
204
- descriptor,
205
- target,
206
- )
207
- : undefined,
208
- get by() {
209
- return (
210
- rawEdit.by &&
211
- accessChildById(target, rawEdit.by, {
212
- ref: Account,
213
- optional: false,
214
- })
215
- );
216
- },
217
- madeAt: rawEdit.at,
218
- key,
219
- };
220
- }
221
-
222
- /** @category Collaboration */
223
- get _edits() {
224
- const map = this;
225
- return new Proxy(
226
- {},
227
- {
228
- get(_target, key) {
229
- const rawEdit = map._raw.lastEditAt(key as string);
230
- if (!rawEdit) return undefined;
231
-
232
- const descriptor = map.getDescriptor(key as string);
233
-
234
- if (!descriptor) return undefined;
235
-
236
- return {
237
- ...map.getEditFromRaw(map, rawEdit, descriptor, key as string),
238
- get all() {
239
- return [...map._raw.editsAt(key as string)].map((rawEdit) =>
240
- map.getEditFromRaw(map, rawEdit, descriptor, key as string),
241
- );
242
- },
243
- };
244
- },
245
- ownKeys(_target) {
246
- return map._raw.keys();
247
- },
248
- getOwnPropertyDescriptor(target, key) {
249
- return {
250
- value: Reflect.get(target, key),
251
- writable: false,
252
- enumerable: true,
253
- configurable: true,
254
- };
255
- },
256
- },
257
- ) as {
258
- [Key in CoKeys<this>]?: LastAndAllCoMapEdits<this[Key]>;
259
- };
260
- }
122
+ static _schema: CoMapFieldSchema;
261
123
 
262
124
  /** @internal */
263
- constructor(
264
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
265
- options: { fromRaw: RawCoMap } | undefined,
266
- ) {
125
+ constructor(options: { fromRaw: RawCoMap } | undefined) {
267
126
  super();
268
127
 
128
+ const proxy = new Proxy(this, CoMapProxyHandler as ProxyHandler<this>);
129
+
269
130
  if (options) {
270
131
  if ("fromRaw" in options) {
271
132
  Object.defineProperties(this, {
272
- id: {
273
- value: options.fromRaw.id as unknown as ID<this>,
133
+ $jazz: {
134
+ value: new CoMapJazzApi(proxy, () => options.fromRaw),
274
135
  enumerable: false,
275
136
  },
276
- _raw: { value: options.fromRaw, enumerable: false },
277
137
  });
278
138
  } else {
279
139
  throw new Error("Invalid CoMap constructor arguments");
280
140
  }
281
141
  }
282
142
 
283
- return new Proxy(this, CoMapProxyHandler as ProxyHandler<this>);
143
+ return proxy;
284
144
  }
285
145
 
286
146
  /**
@@ -300,13 +160,15 @@ export class CoMap extends CoValueBase implements CoValue {
300
160
  * ```
301
161
  *
302
162
  * @category Creation
163
+ *
164
+ * @deprecated Use `co.map(...).create`.
303
165
  **/
304
166
  static create<M extends CoMap>(
305
167
  this: CoValueClass<M>,
306
- init: Simplify<CoMapInit<M>>,
168
+ init: Simplify<CoMapInit_DEPRECATED<M>>,
307
169
  options?:
308
170
  | {
309
- owner: Account | Group;
171
+ owner?: Account | Group;
310
172
  unique?: CoValueUniqueness["uniqueness"];
311
173
  }
312
174
  | Account
@@ -314,7 +176,7 @@ export class CoMap extends CoValueBase implements CoValue {
314
176
  ) {
315
177
  const instance = new this();
316
178
 
317
- return instance._createCoMap(init, options);
179
+ return CoMap._createCoMap(instance, init, options);
318
180
  }
319
181
 
320
182
  /**
@@ -323,25 +185,22 @@ export class CoMap extends CoValueBase implements CoValue {
323
185
  */
324
186
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
325
187
  toJSON(_key?: string, processedValues?: ID<CoValue>[]): any {
326
- const result = {
327
- id: this.id,
328
- _type: this._type,
329
- } as Record<string, any>;
188
+ const result = {} as Record<string, any>;
330
189
 
331
- for (const key of this._raw.keys()) {
190
+ for (const key of this.$jazz.raw.keys()) {
332
191
  const tKey = key as CoKeys<this>;
333
- const descriptor = this.getDescriptor(tKey);
192
+ const descriptor = this.$jazz.getDescriptor(tKey);
334
193
 
335
194
  if (!descriptor) {
336
195
  continue;
337
196
  }
338
197
 
339
198
  if (descriptor == "json" || "encoded" in descriptor) {
340
- result[key] = this._raw.get(key);
199
+ result[key] = this.$jazz.raw.get(key);
341
200
  } else if (isRefEncoded(descriptor)) {
342
- const id = this._raw.get(key) as ID<CoValue>;
201
+ const id = this.$jazz.raw.get(key) as ID<CoValue>;
343
202
 
344
- if (processedValues?.includes(id) || id === this.id) {
203
+ if (processedValues?.includes(id) || id === this.$jazz.id) {
345
204
  result[key] = { _circular: id };
346
205
  continue;
347
206
  }
@@ -356,7 +215,7 @@ export class CoMap extends CoValueBase implements CoValue {
356
215
  ) {
357
216
  const jsonedRef = ref.toJSON(tKey, [
358
217
  ...(processedValues || []),
359
- this.id,
218
+ this.$jazz.id,
360
219
  ]);
361
220
  result[key] = jsonedRef;
362
221
  }
@@ -372,41 +231,45 @@ export class CoMap extends CoValueBase implements CoValue {
372
231
  return this.toJSON();
373
232
  }
374
233
 
375
- _createCoMap(
376
- init: Simplify<CoMapInit<typeof this>>,
234
+ /**
235
+ * @internal
236
+ */
237
+ static _createCoMap<M extends CoMap>(
238
+ instance: M,
239
+ init: Simplify<CoMapInit_DEPRECATED<M>>,
377
240
  options?:
378
241
  | {
379
- owner: Account | Group;
242
+ owner?: Account | Group;
380
243
  unique?: CoValueUniqueness["uniqueness"];
381
244
  }
382
245
  | Account
383
246
  | Group,
384
- ): typeof this {
247
+ ): M {
385
248
  const { owner, uniqueness } = parseCoValueCreateOptions(options);
386
- const raw = this.rawFromInit(init, owner, uniqueness);
387
249
 
388
- Object.defineProperties(this, {
389
- id: {
390
- value: raw.id,
250
+ Object.defineProperties(instance, {
251
+ $jazz: {
252
+ value: new CoMapJazzApi(instance, () => raw),
391
253
  enumerable: false,
392
254
  },
393
- _raw: { value: raw, enumerable: false },
394
255
  });
395
256
 
396
- return this;
257
+ const raw = CoMap.rawFromInit(instance, init, owner, uniqueness);
258
+
259
+ return instance;
397
260
  }
398
261
 
399
262
  /**
400
263
  * Create a new `RawCoMap` from an initialization object
401
264
  * @internal
402
265
  */
403
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
404
- rawFromInit<Fields extends object = Record<string, any>>(
405
- init: Simplify<CoMapInit<Fields>> | undefined,
406
- owner: Account | Group,
266
+ static rawFromInit<M extends CoMap, Fields extends object>(
267
+ instance: M,
268
+ init: Simplify<CoMapInit_DEPRECATED<Fields>> | undefined,
269
+ owner: Group,
407
270
  uniqueness?: CoValueUniqueness,
408
271
  ) {
409
- const rawOwner = owner._raw;
272
+ const rawOwner = owner.$jazz.raw;
410
273
 
411
274
  const rawInit = {} as {
412
275
  [key in keyof Fields]: JsonValue | undefined;
@@ -416,7 +279,7 @@ export class CoMap extends CoValueBase implements CoValue {
416
279
  for (const key of Object.keys(init) as (keyof Fields)[]) {
417
280
  const initValue = init[key as keyof typeof init];
418
281
 
419
- const descriptor = this.getDescriptor(key as string);
282
+ const descriptor = instance.$jazz.getDescriptor(key as string);
420
283
 
421
284
  if (!descriptor) {
422
285
  continue;
@@ -426,14 +289,14 @@ export class CoMap extends CoValueBase implements CoValue {
426
289
  rawInit[key] = initValue as JsonValue;
427
290
  } else if (isRefEncoded(descriptor)) {
428
291
  if (initValue != null) {
429
- let refId = (initValue as unknown as CoValue).id;
292
+ let refId = (initValue as unknown as CoValue).$jazz?.id;
430
293
  if (!refId) {
431
294
  const coValue = instantiateRefEncodedWithInit(
432
295
  descriptor,
433
296
  initValue,
434
297
  owner,
435
298
  );
436
- refId = coValue.id;
299
+ refId = coValue.$jazz.id;
437
300
  }
438
301
  rawInit[key] = refId;
439
302
  }
@@ -448,10 +311,6 @@ export class CoMap extends CoValueBase implements CoValue {
448
311
  return rawOwner.createMap(rawInit, null, "private", uniqueness);
449
312
  }
450
313
 
451
- getDescriptor(key: string) {
452
- return this._schema?.[key] || this._schema?.[ItemsSym];
453
- }
454
-
455
314
  /**
456
315
  * Declare a Record-like CoMap schema, by extending `CoMap.Record(...)` and passing the value schema using `co`. Keys are always `string`.
457
316
  *
@@ -500,6 +359,8 @@ export class CoMap extends CoValueBase implements CoValue {
500
359
  * ```
501
360
  *
502
361
  * @category Subscription & Loading
362
+ *
363
+ * @deprecated Use `co.map(...).load` instead.
503
364
  */
504
365
  static load<M extends CoMap, const R extends RefsToResolve<M> = true>(
505
366
  this: CoValueClass<M>,
@@ -539,6 +400,8 @@ export class CoMap extends CoValueBase implements CoValue {
539
400
  * ```
540
401
  *
541
402
  * @category Subscription & Loading
403
+ *
404
+ * @deprecated Use `co.map(...).subscribe` instead.
542
405
  */
543
406
  static subscribe<M extends CoMap, const R extends RefsToResolve<M> = true>(
544
407
  this: CoValueClass<M>,
@@ -589,7 +452,7 @@ export class CoMap extends CoValueBase implements CoValue {
589
452
  uniqueness: unique,
590
453
  };
591
454
  const crypto =
592
- as._type === "Anonymous" ? as.node.crypto : as._raw.core.node.crypto;
455
+ as[TypeSym] === "Anonymous" ? as.node.crypto : as.$jazz.localNode.crypto;
593
456
  return cojsonInternals.idforHeader(header, crypto) as ID<M>;
594
457
  }
595
458
 
@@ -615,6 +478,8 @@ export class CoMap extends CoValueBase implements CoValue {
615
478
  * @param options The options for creating or loading the CoMap. This includes the intended state of the CoMap, its unique identifier, its owner, and the references to resolve.
616
479
  * @returns Either an existing & modified CoMap, or a new initialised CoMap if none exists.
617
480
  * @category Subscription & Loading
481
+ *
482
+ * @deprecated Use `co.map(...).upsertUnique` instead.
618
483
  */
619
484
  static async upsertUnique<
620
485
  M extends CoMap,
@@ -622,7 +487,7 @@ export class CoMap extends CoValueBase implements CoValue {
622
487
  >(
623
488
  this: CoValueClass<M>,
624
489
  options: {
625
- value: Simplify<CoMapInit<M>>;
490
+ value: Simplify<CoMapInit_DEPRECATED<M>>;
626
491
  unique: CoValueUniqueness["uniqueness"];
627
492
  owner: Account | Group;
628
493
  resolve?: RefsToResolveStrict<M, R>;
@@ -630,27 +495,29 @@ export class CoMap extends CoValueBase implements CoValue {
630
495
  ): Promise<Resolved<M, R> | null> {
631
496
  const mapId = CoMap._findUnique(
632
497
  options.unique,
633
- options.owner.id,
634
- options.owner._loadedAs,
498
+ options.owner.$jazz.id,
499
+ options.owner.$jazz.loadedAs,
635
500
  );
636
501
  let map: Resolved<M, R> | null = await loadCoValueWithoutMe(this, mapId, {
637
502
  ...options,
638
- loadAs: options.owner._loadedAs,
503
+ loadAs: options.owner.$jazz.loadedAs,
639
504
  skipRetry: true,
640
505
  });
641
506
  if (!map) {
642
507
  const instance = new this();
643
- map = instance._createCoMap(options.value, {
508
+ map = CoMap._createCoMap(instance, options.value, {
644
509
  owner: options.owner,
645
510
  unique: options.unique,
646
511
  }) as Resolved<M, R>;
647
512
  } else {
648
- (map as M).applyDiff(options.value as Partial<CoMapInit<M>>);
513
+ (map as M).$jazz.applyDiff(
514
+ options.value as unknown as Partial<CoMapInit<M>>,
515
+ );
649
516
  }
650
517
 
651
518
  return await loadCoValueWithoutMe(this, mapId, {
652
519
  ...options,
653
- loadAs: options.owner._loadedAs,
520
+ loadAs: options.owner.$jazz.loadedAs,
654
521
  skipRetry: true,
655
522
  });
656
523
  }
@@ -661,6 +528,8 @@ export class CoMap extends CoValueBase implements CoValue {
661
528
  * @param ownerID The ID of the owner of the CoMap.
662
529
  * @param options Additional options for loading the CoMap.
663
530
  * @returns The loaded CoMap, or null if unavailable.
531
+ *
532
+ * @deprecated Use `co.map(...).loadUnique` instead.
664
533
  */
665
534
  static loadUnique<M extends CoMap, const R extends RefsToResolve<M> = true>(
666
535
  this: CoValueClass<M>,
@@ -677,48 +546,100 @@ export class CoMap extends CoValueBase implements CoValue {
677
546
  { ...options, skipRetry: true },
678
547
  );
679
548
  }
549
+ }
550
+
551
+ /**
552
+ * Contains CoMap Jazz methods that are part of the {@link CoMap.$jazz`} property.
553
+ */
554
+ class CoMapJazzApi<M extends CoMap> extends CoValueJazzApi<M> {
555
+ constructor(
556
+ private coMap: M,
557
+ private getRaw: () => RawCoMap,
558
+ ) {
559
+ super(coMap);
560
+ }
680
561
 
681
562
  /**
682
- * Given an already loaded `CoMap`, ensure that the specified fields are loaded to the specified depth.
563
+ * The ID of this `CoMap`
564
+ * @category Content
565
+ */
566
+ get id(): ID<M> {
567
+ return this.raw.id;
568
+ }
569
+
570
+ get owner(): Group {
571
+ return getCoValueOwner(this.coMap);
572
+ }
573
+
574
+ /**
575
+ * Set a value on the CoMap
683
576
  *
684
- * Works like `CoMap.load()`, but you don't need to pass the ID or the account to load as again.
577
+ * @param key The key to set
578
+ * @param value The value to set
685
579
  *
686
- * @category Subscription & Loading
580
+ * @category Content
687
581
  */
688
- ensureLoaded<M extends CoMap, const R extends RefsToResolve<M>>(
689
- this: M,
690
- options: { resolve: RefsToResolveStrict<M, R> },
691
- ): Promise<Resolved<M, R>> {
692
- return ensureCoValueLoaded(this, options);
582
+ set<K extends CoKeys<M>>(key: K, value: CoFieldInit<M[K]>): void {
583
+ const descriptor = this.getDescriptor(key as string);
584
+
585
+ if (!descriptor) {
586
+ throw Error(`Cannot set unknown key ${key}`);
587
+ }
588
+
589
+ let refId = (value as CoValue)?.$jazz?.id;
590
+ if (descriptor === "json") {
591
+ this.raw.set(key, value as JsonValue | undefined);
592
+ } else if ("encoded" in descriptor) {
593
+ this.raw.set(key, descriptor.encoded.encode(value));
594
+ } else if (isRefEncoded(descriptor)) {
595
+ if (value === undefined) {
596
+ if (!descriptor.optional) {
597
+ throw Error(`Cannot set required reference ${key} to undefined`);
598
+ }
599
+ this.raw.set(key, null);
600
+ } else {
601
+ if (!refId) {
602
+ const coValue = instantiateRefEncodedWithInit(
603
+ descriptor,
604
+ value,
605
+ this.owner,
606
+ );
607
+ refId = coValue.$jazz.id;
608
+ }
609
+ this.raw.set(key, refId);
610
+ }
611
+ }
693
612
  }
694
613
 
695
614
  /**
696
- * Given an already loaded `CoMap`, subscribe to updates to the `CoMap` and ensure that the specified fields are loaded to the specified depth.
615
+ * Delete a value from a CoMap.
697
616
  *
698
- * Works like `CoMap.subscribe()`, but you don't need to pass the ID or the account to load as again.
617
+ * For record-like CoMaps (created with `co.record`), any string key can be deleted.
618
+ * For struct-like CoMaps (created with `co.map`), only optional properties can be deleted.
699
619
  *
700
- * Returns an unsubscribe function that you should call when you no longer need updates.
620
+ * @param key The key to delete
701
621
  *
702
- * @category Subscription & Loading
703
- **/
704
- subscribe<M extends CoMap, const R extends RefsToResolve<M> = true>(
705
- this: M,
706
- listener: (value: Resolved<M, R>, unsubscribe: () => void) => void,
707
- ): () => void;
708
- subscribe<M extends CoMap, const R extends RefsToResolve<M> = true>(
709
- this: M,
710
- options: { resolve?: RefsToResolveStrict<M, R> },
711
- listener: (value: Resolved<M, R>, unsubscribe: () => void) => void,
712
- ): () => void;
713
- subscribe<M extends CoMap, const R extends RefsToResolve<M>>(
714
- this: M,
715
- ...args: SubscribeRestArgs<M, R>
716
- ): () => void {
717
- const { options, listener } = parseSubscribeRestArgs(args);
718
- return subscribeToExistingCoValue<M, R>(this, options, listener);
622
+ * @category Content
623
+ */
624
+ delete(
625
+ key: OptionalCoKeys<M> | (string extends keyof M ? string : never),
626
+ ): void {
627
+ this.raw.delete(key);
719
628
  }
720
629
 
721
- applyDiff<N extends Partial<CoMapInit<this>>>(newValues: N) {
630
+ /**
631
+ * Modify the `CoMap` to match another map.
632
+ *
633
+ * The new values are assigned to the CoMap, overwriting existing values
634
+ * when the property already exists.
635
+ *
636
+ * @param newValues - The new values to apply to the CoMap. For collaborative values,
637
+ * both CoValues and JSON values are supported.
638
+ * @returns The modified CoMap.
639
+ *
640
+ * @category Content
641
+ */
642
+ applyDiff(newValues: Partial<CoMapInit<M>>): M {
722
643
  for (const key in newValues) {
723
644
  if (Object.prototype.hasOwnProperty.call(newValues, key)) {
724
645
  const tKey = key as keyof typeof newValues & keyof this;
@@ -727,24 +648,64 @@ export class CoMap extends CoValueBase implements CoValue {
727
648
  if (!descriptor) continue;
728
649
 
729
650
  const newValue = newValues[tKey];
730
- const currentValue = (this as unknown as N)[tKey];
651
+ const currentValue = this.coMap[tKey];
731
652
 
732
653
  if (descriptor === "json" || "encoded" in descriptor) {
733
654
  if (currentValue !== newValue) {
734
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
735
- (this as any)[tKey] = newValue;
655
+ this.set(tKey as any, newValue as CoFieldInit<M[keyof M]>);
736
656
  }
737
657
  } else if (isRefEncoded(descriptor)) {
738
- const currentId = (currentValue as CoValue | undefined)?.id;
739
- const newId = (newValue as CoValue | undefined)?.id;
658
+ const currentId = (currentValue as CoValue | undefined)?.$jazz.id;
659
+ let newId = (newValue as CoValue | undefined)?.$jazz?.id;
740
660
  if (currentId !== newId) {
741
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
742
- (this as any)[tKey] = newValue;
661
+ this.set(tKey as any, newValue as CoFieldInit<M[keyof M]>);
743
662
  }
744
663
  }
745
664
  }
746
665
  }
747
- return this;
666
+ return this.coMap;
667
+ }
668
+
669
+ /**
670
+ * Given an already loaded `CoMap`, ensure that the specified fields are loaded to the specified depth.
671
+ *
672
+ * Works like `CoMap.load()`, but you don't need to pass the ID or the account to load as again.
673
+ *
674
+ * @category Subscription & Loading
675
+ */
676
+ ensureLoaded<Map extends CoMap, const R extends RefsToResolve<Map>>(
677
+ this: CoMapJazzApi<Map>,
678
+ options: {
679
+ resolve: RefsToResolveStrict<Map, R>;
680
+ },
681
+ ): Promise<Resolved<Map, R>> {
682
+ return ensureCoValueLoaded(this.coMap, options);
683
+ }
684
+
685
+ /**
686
+ * Given an already loaded `CoMap`, subscribe to updates to the `CoMap` and ensure that the specified fields are loaded to the specified depth.
687
+ *
688
+ * Works like `CoMap.subscribe()`, but you don't need to pass the ID or the account to load as again.
689
+ *
690
+ * Returns an unsubscribe function that you should call when you no longer need updates.
691
+ *
692
+ * @category Subscription & Loading
693
+ **/
694
+ subscribe<Map extends CoMap, const R extends RefsToResolve<Map> = true>(
695
+ this: CoMapJazzApi<Map>,
696
+ listener: (value: Resolved<Map, R>, unsubscribe: () => void) => void,
697
+ ): () => void;
698
+ subscribe<Map extends CoMap, const R extends RefsToResolve<Map> = true>(
699
+ this: CoMapJazzApi<Map>,
700
+ options: { resolve?: RefsToResolveStrict<Map, R> },
701
+ listener: (value: Resolved<Map, R>, unsubscribe: () => void) => void,
702
+ ): () => void;
703
+ subscribe<Map extends CoMap, const R extends RefsToResolve<Map>>(
704
+ this: CoMapJazzApi<Map>,
705
+ ...args: SubscribeRestArgs<Map, R>
706
+ ): () => void {
707
+ const { options, listener } = parseSubscribeRestArgs(args);
708
+ return subscribeToExistingCoValue(this.coMap, options, listener);
748
709
  }
749
710
 
750
711
  /**
@@ -752,8 +713,134 @@ export class CoMap extends CoValueBase implements CoValue {
752
713
  *
753
714
  * @category Subscription & Loading
754
715
  */
755
- waitForSync(options?: { timeout?: number }) {
756
- return this._raw.core.waitForSync(options);
716
+ async waitForSync(options?: { timeout?: number }): Promise<void> {
717
+ await this.raw.core.waitForSync(options);
718
+ }
719
+
720
+ /**
721
+ * Get the descriptor for a given key
722
+ * @internal
723
+ */
724
+ getDescriptor(key: string): Schema | undefined {
725
+ return this.schema?.[key] || this.schema?.[ItemsSym];
726
+ }
727
+
728
+ /**
729
+ * If property `prop` is a `coField.ref(...)`, you can use `coMap.$jazz.refs.prop` to access
730
+ * the `Ref` instead of the potentially loaded/null value.
731
+ *
732
+ * This allows you to always get the ID or load the value manually.
733
+ *
734
+ * @example
735
+ * ```ts
736
+ * person.$jazz.refs.pet.id; // => ID<Animal>
737
+ * person.$jazz.refs.pet.value;
738
+ * // => Animal | null
739
+ * const pet = await person.$jazz.refs.pet.load();
740
+ * ```
741
+ *
742
+ * @category Content
743
+ **/
744
+ get refs(): Simplify<
745
+ {
746
+ [Key in CoKeys<M> as NonNullable<M[Key]> extends CoValue
747
+ ? Key
748
+ : never]?: RefIfCoValue<M[Key]>;
749
+ } & {
750
+ [Key in CoKeys<M> as M[Key] extends undefined
751
+ ? never
752
+ : M[Key] extends CoValue
753
+ ? Key
754
+ : never]: RefIfCoValue<M[Key]>;
755
+ }
756
+ > {
757
+ return makeRefs<CoKeys<this>>(
758
+ this.coMap,
759
+ (key) => this.raw.get(key as string) as unknown as ID<CoValue>,
760
+ () => {
761
+ const keys = this.raw.keys().filter((key) => {
762
+ const descriptor = this.getDescriptor(key as string);
763
+ return (
764
+ descriptor && descriptor !== "json" && isRefEncoded(descriptor)
765
+ );
766
+ }) as CoKeys<this>[];
767
+
768
+ return keys;
769
+ },
770
+ this.loadedAs,
771
+ (key) => this.getDescriptor(key as string) as RefEncoded<CoValue>,
772
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
773
+ ) as any;
774
+ }
775
+
776
+ /**
777
+ * Get the edits made to the CoMap.
778
+ *
779
+ * @category Collaboration
780
+ */
781
+ getEdits(): CoMapEdits<M> {
782
+ const map = this.coMap;
783
+ return new Proxy(
784
+ {},
785
+ {
786
+ get(_target, key) {
787
+ const rawEdit = map.$jazz.raw.lastEditAt(key as string);
788
+ if (!rawEdit) return undefined;
789
+
790
+ const descriptor = map.$jazz.getDescriptor(key as string);
791
+
792
+ if (!descriptor) return undefined;
793
+
794
+ return {
795
+ ...getEditFromRaw(map, rawEdit, descriptor, key as string),
796
+ get all() {
797
+ return [...map.$jazz.raw.editsAt(key as string)].map((rawEdit) =>
798
+ getEditFromRaw(map, rawEdit, descriptor, key as string),
799
+ );
800
+ },
801
+ };
802
+ },
803
+ ownKeys(_target) {
804
+ return map.$jazz.raw.keys();
805
+ },
806
+ getOwnPropertyDescriptor(target, key) {
807
+ return {
808
+ value: Reflect.get(target, key),
809
+ writable: false,
810
+ enumerable: true,
811
+ configurable: true,
812
+ };
813
+ },
814
+ },
815
+ );
816
+ }
817
+
818
+ /** @internal */
819
+ override get raw() {
820
+ return this.getRaw();
821
+ }
822
+
823
+ /**
824
+ * The timestamp of the creation time of the CoMap
825
+ *
826
+ * @category Content
827
+ */
828
+ get createdAt(): number {
829
+ return this.raw.earliestTxMadeAt ?? Number.MAX_SAFE_INTEGER;
830
+ }
831
+
832
+ /**
833
+ * The timestamp of the last updated time of the CoMap
834
+ *
835
+ * @category Content
836
+ */
837
+ get lastUpdatedAt(): number {
838
+ return this.raw.latestTxMadeAt;
839
+ }
840
+
841
+ /** @internal */
842
+ get schema(): CoMapFieldSchema {
843
+ return (this.coMap.constructor as typeof CoMap)._schema;
757
844
  }
758
845
  }
759
846
 
@@ -762,6 +849,20 @@ export type CoKeys<Map extends object> = Exclude<
762
849
  keyof CoMap
763
850
  >;
764
851
 
852
+ /**
853
+ * Extract keys of properties that are required
854
+ */
855
+ export type RequiredCoKeys<Map extends object> = {
856
+ [K in CoKeys<Map>]: undefined extends Map[K] ? never : K;
857
+ }[CoKeys<Map>];
858
+
859
+ /**
860
+ * Extract keys of properties that can be undefined
861
+ */
862
+ export type OptionalCoKeys<Map extends object> = {
863
+ [K in CoKeys<Map>]: undefined extends Map[K] ? K : never;
864
+ }[CoKeys<Map>];
865
+
765
866
  /**
766
867
  * Force required ref fields to be non nullable
767
868
  *
@@ -793,10 +894,16 @@ type ForceRequiredRef<V> = V extends InstanceType<CoValueClass> | null
793
894
  ? V | null
794
895
  : V;
795
896
 
796
- export type CoMapInit<Map extends object> = PartialOnUndefined<{
897
+ export type CoMapInit_DEPRECATED<Map extends object> = PartialOnUndefined<{
797
898
  [Key in CoKeys<Map>]: ForceRequiredRef<Map[Key]>;
798
899
  }>;
799
900
 
901
+ export type CoMapInit<Map extends object> = {
902
+ [K in RequiredCoKeys<Map>]: CoFieldInit<Map[K]>;
903
+ } & {
904
+ [K in OptionalCoKeys<Map>]?: CoFieldInit<Map[K]> | undefined;
905
+ };
906
+
800
907
  // TODO: cache handlers per descriptor for performance?
801
908
  const CoMapProxyHandler: ProxyHandler<CoMap> = {
802
909
  get(target, key, receiver) {
@@ -809,13 +916,13 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
809
916
  return undefined;
810
917
  }
811
918
 
812
- const descriptor = target.getDescriptor(key as string);
919
+ const descriptor = target.$jazz.getDescriptor(key as string);
813
920
 
814
921
  if (!descriptor) {
815
922
  return undefined;
816
923
  }
817
924
 
818
- const raw = target._raw.get(key);
925
+ const raw = target.$jazz.raw.get(key);
819
926
 
820
927
  if (descriptor === "json") {
821
928
  return raw;
@@ -830,7 +937,7 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
830
937
  },
831
938
  set(target, key, value, receiver) {
832
939
  if (
833
- (typeof key === "string" || ItemsSym) &&
940
+ typeof key === "string" &&
834
941
  typeof value === "object" &&
835
942
  value !== null &&
836
943
  SchemaInit in value
@@ -840,33 +947,12 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
840
947
  return true;
841
948
  }
842
949
 
843
- const descriptor = target.getDescriptor(key as string);
950
+ const descriptor = target.$jazz.getDescriptor(key as string);
844
951
 
845
952
  if (!descriptor) return false;
846
953
 
847
954
  if (typeof key === "string") {
848
- if (descriptor === "json") {
849
- target._raw.set(key, value);
850
- } else if ("encoded" in descriptor) {
851
- target._raw.set(key, descriptor.encoded.encode(value));
852
- } else if (isRefEncoded(descriptor)) {
853
- if (value === undefined) {
854
- if (descriptor.optional) {
855
- target._raw.set(key, null);
856
- } else {
857
- throw new Error(
858
- `Cannot set required reference ${key} to undefined`,
859
- );
860
- }
861
- } else if (value?.id) {
862
- target._raw.set(key, value.id);
863
- } else {
864
- throw new Error(
865
- `Cannot set reference ${key} to a non-CoValue. Got ${value}`,
866
- );
867
- }
868
- }
869
- return true;
955
+ throw Error("Cannot update a CoMap directly. Use `$jazz.set` instead.");
870
956
  } else {
871
957
  return Reflect.set(target, key, value, receiver);
872
958
  }
@@ -888,7 +974,7 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
888
974
  ownKeys(target) {
889
975
  const keys = Reflect.ownKeys(target).filter((k) => k !== ItemsSym);
890
976
 
891
- for (const key of target._raw.keys()) {
977
+ for (const key of target.$jazz.raw.keys()) {
892
978
  if (!keys.includes(key)) {
893
979
  keys.push(key);
894
980
  }
@@ -900,9 +986,9 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
900
986
  if (key in target) {
901
987
  return Reflect.getOwnPropertyDescriptor(target, key);
902
988
  } else {
903
- const descriptor = target.getDescriptor(key as string);
989
+ const descriptor = target.$jazz.getDescriptor(key as string);
904
990
 
905
- if (descriptor || key in target._raw.latest) {
991
+ if (descriptor || key in target.$jazz.raw.latest) {
906
992
  return {
907
993
  enumerable: true,
908
994
  configurable: true,
@@ -912,20 +998,24 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
912
998
  }
913
999
  },
914
1000
  has(target, key) {
915
- const descriptor = target.getDescriptor(key as string);
1001
+ // The `has` trap can be called when defining properties during CoMap creation
1002
+ // when using the class-based syntax. In that case, $jazz may not yet be initialized,
1003
+ // as it's defined afterwards in the create method.
1004
+ const descriptor = target.$jazz?.getDescriptor(key as string);
916
1005
 
917
- if (target._raw && typeof key === "string" && descriptor) {
918
- return target._raw.get(key) !== undefined;
1006
+ if (target.$jazz?.raw && typeof key === "string" && descriptor) {
1007
+ return target.$jazz.raw.get(key) !== undefined;
919
1008
  } else {
920
1009
  return Reflect.has(target, key);
921
1010
  }
922
1011
  },
923
1012
  deleteProperty(target, key) {
924
- const descriptor = target.getDescriptor(key as string);
1013
+ const descriptor = target.$jazz.getDescriptor(key as string);
925
1014
 
926
1015
  if (typeof key === "string" && descriptor) {
927
- target._raw.delete(key);
928
- return true;
1016
+ throw Error(
1017
+ "Cannot delete a CoMap property directly. Use `$jazz.delete` instead.",
1018
+ );
929
1019
  } else {
930
1020
  return Reflect.deleteProperty(target, key);
931
1021
  }
@@ -933,3 +1023,47 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
933
1023
  };
934
1024
 
935
1025
  RegisteredSchemas["CoMap"] = CoMap;
1026
+
1027
+ /** @internal */
1028
+ function getEditFromRaw(
1029
+ target: CoMap,
1030
+ rawEdit: {
1031
+ by: RawAccountID | AgentID;
1032
+ tx: CojsonInternalTypes.TransactionID;
1033
+ at: Date;
1034
+ value?: JsonValue | undefined;
1035
+ },
1036
+ descriptor: Schema,
1037
+ key: string,
1038
+ ) {
1039
+ return {
1040
+ value:
1041
+ descriptor === "json"
1042
+ ? rawEdit.value
1043
+ : "encoded" in descriptor
1044
+ ? rawEdit.value === null || rawEdit.value === undefined
1045
+ ? rawEdit.value
1046
+ : descriptor.encoded.decode(rawEdit.value)
1047
+ : accessChildById(target, rawEdit.value as string, descriptor),
1048
+ ref:
1049
+ descriptor !== "json" && isRefEncoded(descriptor)
1050
+ ? new Ref(
1051
+ rawEdit.value as ID<CoValue>,
1052
+ target.$jazz.loadedAs,
1053
+ descriptor,
1054
+ target,
1055
+ )
1056
+ : undefined,
1057
+ get by() {
1058
+ return (
1059
+ rawEdit.by &&
1060
+ accessChildById(target, rawEdit.by, {
1061
+ ref: Account,
1062
+ optional: false,
1063
+ })
1064
+ );
1065
+ },
1066
+ madeAt: rawEdit.at,
1067
+ key,
1068
+ };
1069
+ }