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
@@ -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 };
114
- }
115
-
116
- /**
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;
109
+ this.prototype[TypeSym] = "CoMap";
128
110
  }
129
111
 
130
112
  /**
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,114 @@ 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
+ * Check if a key is defined in 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
+ * This check does not load the referenced value or validate permissions.
685
578
  *
686
- * @category Subscription & Loading
579
+ * @param key The key to check
580
+ * @returns True if the key is defined, false otherwise
581
+ * @category Content
687
582
  */
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);
583
+ has(key: CoKeys<M>): boolean {
584
+ const entry = this.raw.getRaw(key);
585
+ return entry?.change !== undefined && entry.change.op !== "del";
693
586
  }
694
587
 
695
588
  /**
696
- * Given an already loaded `CoMap`, subscribe to updates to the `CoMap` and ensure that the specified fields are loaded to the specified depth.
589
+ * Set a value on the CoMap
697
590
  *
698
- * Works like `CoMap.subscribe()`, but you don't need to pass the ID or the account to load as again.
591
+ * @param key The key to set
592
+ * @param value The value to set
699
593
  *
700
- * Returns an unsubscribe function that you should call when you no longer need updates.
594
+ * @category Content
595
+ */
596
+ set<K extends CoKeys<M>>(key: K, value: CoFieldInit<M[K]>): void {
597
+ const descriptor = this.getDescriptor(key as string);
598
+
599
+ if (!descriptor) {
600
+ throw Error(`Cannot set unknown key ${key}`);
601
+ }
602
+
603
+ let refId = (value as CoValue)?.$jazz?.id;
604
+ if (descriptor === "json") {
605
+ this.raw.set(key, value as JsonValue | undefined);
606
+ } else if ("encoded" in descriptor) {
607
+ this.raw.set(key, descriptor.encoded.encode(value));
608
+ } else if (isRefEncoded(descriptor)) {
609
+ if (value === undefined) {
610
+ if (!descriptor.optional) {
611
+ throw Error(`Cannot set required reference ${key} to undefined`);
612
+ }
613
+ this.raw.set(key, null);
614
+ } else {
615
+ if (!refId) {
616
+ const coValue = instantiateRefEncodedWithInit(
617
+ descriptor,
618
+ value,
619
+ this.owner,
620
+ );
621
+ refId = coValue.$jazz.id;
622
+ }
623
+ this.raw.set(key, refId);
624
+ }
625
+ }
626
+ }
627
+
628
+ /**
629
+ * Delete a value from a CoMap.
701
630
  *
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);
631
+ * For record-like CoMaps (created with `co.record`), any string key can be deleted.
632
+ * For struct-like CoMaps (created with `co.map`), only optional properties can be deleted.
633
+ *
634
+ * @param key The key to delete
635
+ *
636
+ * @category Content
637
+ */
638
+ delete(
639
+ key: OptionalCoKeys<M> | (string extends keyof M ? string : never),
640
+ ): void {
641
+ this.raw.delete(key);
719
642
  }
720
643
 
721
- applyDiff<N extends Partial<CoMapInit<this>>>(newValues: N) {
644
+ /**
645
+ * Modify the `CoMap` to match another map.
646
+ *
647
+ * The new values are assigned to the CoMap, overwriting existing values
648
+ * when the property already exists.
649
+ *
650
+ * @param newValues - The new values to apply to the CoMap. For collaborative values,
651
+ * both CoValues and JSON values are supported.
652
+ * @returns The modified CoMap.
653
+ *
654
+ * @category Content
655
+ */
656
+ applyDiff(newValues: Partial<CoMapInit<M>>): M {
722
657
  for (const key in newValues) {
723
658
  if (Object.prototype.hasOwnProperty.call(newValues, key)) {
724
659
  const tKey = key as keyof typeof newValues & keyof this;
@@ -727,24 +662,64 @@ export class CoMap extends CoValueBase implements CoValue {
727
662
  if (!descriptor) continue;
728
663
 
729
664
  const newValue = newValues[tKey];
730
- const currentValue = (this as unknown as N)[tKey];
665
+ const currentValue = this.coMap[tKey];
731
666
 
732
667
  if (descriptor === "json" || "encoded" in descriptor) {
733
668
  if (currentValue !== newValue) {
734
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
735
- (this as any)[tKey] = newValue;
669
+ this.set(tKey as any, newValue as CoFieldInit<M[keyof M]>);
736
670
  }
737
671
  } else if (isRefEncoded(descriptor)) {
738
- const currentId = (currentValue as CoValue | undefined)?.id;
739
- const newId = (newValue as CoValue | undefined)?.id;
672
+ const currentId = (currentValue as CoValue | undefined)?.$jazz.id;
673
+ let newId = (newValue as CoValue | undefined)?.$jazz?.id;
740
674
  if (currentId !== newId) {
741
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
742
- (this as any)[tKey] = newValue;
675
+ this.set(tKey as any, newValue as CoFieldInit<M[keyof M]>);
743
676
  }
744
677
  }
745
678
  }
746
679
  }
747
- return this;
680
+ return this.coMap;
681
+ }
682
+
683
+ /**
684
+ * Given an already loaded `CoMap`, ensure that the specified fields are loaded to the specified depth.
685
+ *
686
+ * Works like `CoMap.load()`, but you don't need to pass the ID or the account to load as again.
687
+ *
688
+ * @category Subscription & Loading
689
+ */
690
+ ensureLoaded<Map extends CoMap, const R extends RefsToResolve<Map>>(
691
+ this: CoMapJazzApi<Map>,
692
+ options: {
693
+ resolve: RefsToResolveStrict<Map, R>;
694
+ },
695
+ ): Promise<Resolved<Map, R>> {
696
+ return ensureCoValueLoaded(this.coMap, options);
697
+ }
698
+
699
+ /**
700
+ * Given an already loaded `CoMap`, subscribe to updates to the `CoMap` and ensure that the specified fields are loaded to the specified depth.
701
+ *
702
+ * Works like `CoMap.subscribe()`, but you don't need to pass the ID or the account to load as again.
703
+ *
704
+ * Returns an unsubscribe function that you should call when you no longer need updates.
705
+ *
706
+ * @category Subscription & Loading
707
+ **/
708
+ subscribe<Map extends CoMap, const R extends RefsToResolve<Map> = true>(
709
+ this: CoMapJazzApi<Map>,
710
+ listener: (value: Resolved<Map, R>, unsubscribe: () => void) => void,
711
+ ): () => void;
712
+ subscribe<Map extends CoMap, const R extends RefsToResolve<Map> = true>(
713
+ this: CoMapJazzApi<Map>,
714
+ options: { resolve?: RefsToResolveStrict<Map, R> },
715
+ listener: (value: Resolved<Map, R>, unsubscribe: () => void) => void,
716
+ ): () => void;
717
+ subscribe<Map extends CoMap, const R extends RefsToResolve<Map>>(
718
+ this: CoMapJazzApi<Map>,
719
+ ...args: SubscribeRestArgs<Map, R>
720
+ ): () => void {
721
+ const { options, listener } = parseSubscribeRestArgs(args);
722
+ return subscribeToExistingCoValue(this.coMap, options, listener);
748
723
  }
749
724
 
750
725
  /**
@@ -752,8 +727,134 @@ export class CoMap extends CoValueBase implements CoValue {
752
727
  *
753
728
  * @category Subscription & Loading
754
729
  */
755
- waitForSync(options?: { timeout?: number }) {
756
- return this._raw.core.waitForSync(options);
730
+ async waitForSync(options?: { timeout?: number }): Promise<void> {
731
+ await this.raw.core.waitForSync(options);
732
+ }
733
+
734
+ /**
735
+ * Get the descriptor for a given key
736
+ * @internal
737
+ */
738
+ getDescriptor(key: string): Schema | undefined {
739
+ return this.schema?.[key] || this.schema?.[ItemsSym];
740
+ }
741
+
742
+ /**
743
+ * If property `prop` is a `coField.ref(...)`, you can use `coMap.$jazz.refs.prop` to access
744
+ * the `Ref` instead of the potentially loaded/null value.
745
+ *
746
+ * This allows you to always get the ID or load the value manually.
747
+ *
748
+ * @example
749
+ * ```ts
750
+ * person.$jazz.refs.pet.id; // => ID<Animal>
751
+ * person.$jazz.refs.pet.value;
752
+ * // => Animal | null
753
+ * const pet = await person.$jazz.refs.pet.load();
754
+ * ```
755
+ *
756
+ * @category Content
757
+ **/
758
+ get refs(): Simplify<
759
+ {
760
+ [Key in CoKeys<M> as NonNullable<M[Key]> extends CoValue
761
+ ? Key
762
+ : never]?: RefIfCoValue<M[Key]>;
763
+ } & {
764
+ [Key in CoKeys<M> as M[Key] extends undefined
765
+ ? never
766
+ : M[Key] extends CoValue
767
+ ? Key
768
+ : never]: RefIfCoValue<M[Key]>;
769
+ }
770
+ > {
771
+ return makeRefs<CoKeys<this>>(
772
+ this.coMap,
773
+ (key) => this.raw.get(key as string) as unknown as ID<CoValue>,
774
+ () => {
775
+ const keys = this.raw.keys().filter((key) => {
776
+ const descriptor = this.getDescriptor(key as string);
777
+ return (
778
+ descriptor && descriptor !== "json" && isRefEncoded(descriptor)
779
+ );
780
+ }) as CoKeys<this>[];
781
+
782
+ return keys;
783
+ },
784
+ this.loadedAs,
785
+ (key) => this.getDescriptor(key as string) as RefEncoded<CoValue>,
786
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
787
+ ) as any;
788
+ }
789
+
790
+ /**
791
+ * Get the edits made to the CoMap.
792
+ *
793
+ * @category Collaboration
794
+ */
795
+ getEdits(): CoMapEdits<M> {
796
+ const map = this.coMap;
797
+ return new Proxy(
798
+ {},
799
+ {
800
+ get(_target, key) {
801
+ const rawEdit = map.$jazz.raw.lastEditAt(key as string);
802
+ if (!rawEdit) return undefined;
803
+
804
+ const descriptor = map.$jazz.getDescriptor(key as string);
805
+
806
+ if (!descriptor) return undefined;
807
+
808
+ return {
809
+ ...getEditFromRaw(map, rawEdit, descriptor, key as string),
810
+ get all() {
811
+ return [...map.$jazz.raw.editsAt(key as string)].map((rawEdit) =>
812
+ getEditFromRaw(map, rawEdit, descriptor, key as string),
813
+ );
814
+ },
815
+ };
816
+ },
817
+ ownKeys(_target) {
818
+ return map.$jazz.raw.keys();
819
+ },
820
+ getOwnPropertyDescriptor(target, key) {
821
+ return {
822
+ value: Reflect.get(target, key),
823
+ writable: false,
824
+ enumerable: true,
825
+ configurable: true,
826
+ };
827
+ },
828
+ },
829
+ );
830
+ }
831
+
832
+ /** @internal */
833
+ override get raw() {
834
+ return this.getRaw();
835
+ }
836
+
837
+ /**
838
+ * The timestamp of the creation time of the CoMap
839
+ *
840
+ * @category Content
841
+ */
842
+ get createdAt(): number {
843
+ return this.raw.earliestTxMadeAt ?? Number.MAX_SAFE_INTEGER;
844
+ }
845
+
846
+ /**
847
+ * The timestamp of the last updated time of the CoMap
848
+ *
849
+ * @category Content
850
+ */
851
+ get lastUpdatedAt(): number {
852
+ return this.raw.latestTxMadeAt;
853
+ }
854
+
855
+ /** @internal */
856
+ get schema(): CoMapFieldSchema {
857
+ return (this.coMap.constructor as typeof CoMap)._schema;
757
858
  }
758
859
  }
759
860
 
@@ -762,6 +863,20 @@ export type CoKeys<Map extends object> = Exclude<
762
863
  keyof CoMap
763
864
  >;
764
865
 
866
+ /**
867
+ * Extract keys of properties that are required
868
+ */
869
+ export type RequiredCoKeys<Map extends object> = {
870
+ [K in CoKeys<Map>]: undefined extends Map[K] ? never : K;
871
+ }[CoKeys<Map>];
872
+
873
+ /**
874
+ * Extract keys of properties that can be undefined
875
+ */
876
+ export type OptionalCoKeys<Map extends object> = {
877
+ [K in CoKeys<Map>]: undefined extends Map[K] ? K : never;
878
+ }[CoKeys<Map>];
879
+
765
880
  /**
766
881
  * Force required ref fields to be non nullable
767
882
  *
@@ -793,10 +908,16 @@ type ForceRequiredRef<V> = V extends InstanceType<CoValueClass> | null
793
908
  ? V | null
794
909
  : V;
795
910
 
796
- export type CoMapInit<Map extends object> = PartialOnUndefined<{
911
+ export type CoMapInit_DEPRECATED<Map extends object> = PartialOnUndefined<{
797
912
  [Key in CoKeys<Map>]: ForceRequiredRef<Map[Key]>;
798
913
  }>;
799
914
 
915
+ export type CoMapInit<Map extends object> = {
916
+ [K in RequiredCoKeys<Map>]: CoFieldInit<Map[K]>;
917
+ } & {
918
+ [K in OptionalCoKeys<Map>]?: CoFieldInit<Map[K]> | undefined;
919
+ };
920
+
800
921
  // TODO: cache handlers per descriptor for performance?
801
922
  const CoMapProxyHandler: ProxyHandler<CoMap> = {
802
923
  get(target, key, receiver) {
@@ -809,13 +930,13 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
809
930
  return undefined;
810
931
  }
811
932
 
812
- const descriptor = target.getDescriptor(key as string);
933
+ const descriptor = target.$jazz.getDescriptor(key as string);
813
934
 
814
935
  if (!descriptor) {
815
936
  return undefined;
816
937
  }
817
938
 
818
- const raw = target._raw.get(key);
939
+ const raw = target.$jazz.raw.get(key);
819
940
 
820
941
  if (descriptor === "json") {
821
942
  return raw;
@@ -830,7 +951,7 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
830
951
  },
831
952
  set(target, key, value, receiver) {
832
953
  if (
833
- (typeof key === "string" || ItemsSym) &&
954
+ typeof key === "string" &&
834
955
  typeof value === "object" &&
835
956
  value !== null &&
836
957
  SchemaInit in value
@@ -840,33 +961,12 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
840
961
  return true;
841
962
  }
842
963
 
843
- const descriptor = target.getDescriptor(key as string);
964
+ const descriptor = target.$jazz.getDescriptor(key as string);
844
965
 
845
966
  if (!descriptor) return false;
846
967
 
847
968
  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;
969
+ throw Error("Cannot update a CoMap directly. Use `$jazz.set` instead.");
870
970
  } else {
871
971
  return Reflect.set(target, key, value, receiver);
872
972
  }
@@ -888,7 +988,7 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
888
988
  ownKeys(target) {
889
989
  const keys = Reflect.ownKeys(target).filter((k) => k !== ItemsSym);
890
990
 
891
- for (const key of target._raw.keys()) {
991
+ for (const key of target.$jazz.raw.keys()) {
892
992
  if (!keys.includes(key)) {
893
993
  keys.push(key);
894
994
  }
@@ -900,9 +1000,9 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
900
1000
  if (key in target) {
901
1001
  return Reflect.getOwnPropertyDescriptor(target, key);
902
1002
  } else {
903
- const descriptor = target.getDescriptor(key as string);
1003
+ const descriptor = target.$jazz.getDescriptor(key as string);
904
1004
 
905
- if (descriptor || key in target._raw.latest) {
1005
+ if (descriptor || key in target.$jazz.raw.latest) {
906
1006
  return {
907
1007
  enumerable: true,
908
1008
  configurable: true,
@@ -912,20 +1012,24 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
912
1012
  }
913
1013
  },
914
1014
  has(target, key) {
915
- const descriptor = target.getDescriptor(key as string);
1015
+ // The `has` trap can be called when defining properties during CoMap creation
1016
+ // when using the class-based syntax. In that case, $jazz may not yet be initialized,
1017
+ // as it's defined afterwards in the create method.
1018
+ const descriptor = target.$jazz?.getDescriptor(key as string);
916
1019
 
917
- if (target._raw && typeof key === "string" && descriptor) {
918
- return target._raw.get(key) !== undefined;
1020
+ if (target.$jazz?.raw && typeof key === "string" && descriptor) {
1021
+ return target.$jazz.raw.get(key) !== undefined;
919
1022
  } else {
920
1023
  return Reflect.has(target, key);
921
1024
  }
922
1025
  },
923
1026
  deleteProperty(target, key) {
924
- const descriptor = target.getDescriptor(key as string);
1027
+ const descriptor = target.$jazz.getDescriptor(key as string);
925
1028
 
926
1029
  if (typeof key === "string" && descriptor) {
927
- target._raw.delete(key);
928
- return true;
1030
+ throw Error(
1031
+ "Cannot delete a CoMap property directly. Use `$jazz.delete` instead.",
1032
+ );
929
1033
  } else {
930
1034
  return Reflect.deleteProperty(target, key);
931
1035
  }
@@ -933,3 +1037,47 @@ const CoMapProxyHandler: ProxyHandler<CoMap> = {
933
1037
  };
934
1038
 
935
1039
  RegisteredSchemas["CoMap"] = CoMap;
1040
+
1041
+ /** @internal */
1042
+ function getEditFromRaw(
1043
+ target: CoMap,
1044
+ rawEdit: {
1045
+ by: RawAccountID | AgentID;
1046
+ tx: CojsonInternalTypes.TransactionID;
1047
+ at: Date;
1048
+ value?: JsonValue | undefined;
1049
+ },
1050
+ descriptor: Schema,
1051
+ key: string,
1052
+ ) {
1053
+ return {
1054
+ value:
1055
+ descriptor === "json"
1056
+ ? rawEdit.value
1057
+ : "encoded" in descriptor
1058
+ ? rawEdit.value === null || rawEdit.value === undefined
1059
+ ? rawEdit.value
1060
+ : descriptor.encoded.decode(rawEdit.value)
1061
+ : accessChildById(target, rawEdit.value as string, descriptor),
1062
+ ref:
1063
+ descriptor !== "json" && isRefEncoded(descriptor)
1064
+ ? new Ref(
1065
+ rawEdit.value as ID<CoValue>,
1066
+ target.$jazz.loadedAs,
1067
+ descriptor,
1068
+ target,
1069
+ )
1070
+ : undefined,
1071
+ get by() {
1072
+ return (
1073
+ rawEdit.by &&
1074
+ accessChildById(target, rawEdit.by, {
1075
+ ref: Account,
1076
+ optional: false,
1077
+ })
1078
+ );
1079
+ },
1080
+ madeAt: rawEdit.at,
1081
+ key,
1082
+ };
1083
+ }