jazz-tools 0.8.31 → 0.8.32
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +8 -0
- package/dist/native/coValues/coFeed.js +152 -12
- package/dist/native/coValues/coFeed.js.map +1 -1
- package/dist/native/coValues/coMap.js +49 -19
- package/dist/native/coValues/coMap.js.map +1 -1
- package/dist/native/coValues/interfaces.js.map +1 -1
- package/dist/native/coValues/schemaUnion.js +15 -21
- package/dist/native/coValues/schemaUnion.js.map +1 -1
- package/dist/web/coValues/coFeed.js +152 -12
- package/dist/web/coValues/coFeed.js.map +1 -1
- package/dist/web/coValues/coMap.js +49 -19
- package/dist/web/coValues/coMap.js.map +1 -1
- package/dist/web/coValues/interfaces.js.map +1 -1
- package/dist/web/coValues/schemaUnion.js +15 -21
- package/dist/web/coValues/schemaUnion.js.map +1 -1
- package/package.json +2 -2
- package/src/coValues/coFeed.ts +192 -12
- package/src/coValues/coMap.ts +86 -39
- package/src/coValues/interfaces.ts +12 -1
- package/src/coValues/schemaUnion.ts +15 -21
- package/src/tests/coMap.test.ts +88 -0
package/src/coValues/coFeed.ts
CHANGED
@@ -59,34 +59,92 @@ export type SingleCoFeedEntry<Item> = {
|
|
59
59
|
/** @deprecated Use CoFeed instead */
|
60
60
|
export { CoFeed as CoStream };
|
61
61
|
|
62
|
-
/**
|
63
|
-
|
62
|
+
/**
|
63
|
+
* CoFeeds are collaborative logs of data.
|
64
|
+
*
|
65
|
+
* @categoryDescription Content
|
66
|
+
* They are similar to `CoList`s, but with a few key differences:
|
67
|
+
* - They are append-only
|
68
|
+
* - They consist of several internal append-only logs, one per account session (tab, device, app instance, etc.)
|
69
|
+
* - They expose those as a per-account aggregated view (default) or a precise per-session view
|
70
|
+
*
|
71
|
+
* ```ts
|
72
|
+
* favDog.push("Poodle");
|
73
|
+
* favDog.push("Schnowzer");
|
74
|
+
* ```
|
75
|
+
*
|
76
|
+
* @category CoValues
|
77
|
+
*/
|
64
78
|
export class CoFeed<Item = any> extends CoValueBase implements CoValue {
|
79
|
+
/**
|
80
|
+
* Declare a `CoFeed` by subclassing `CoFeed.Of(...)` and passing the item schema using a `co` primitive or a `co.ref`.
|
81
|
+
*
|
82
|
+
* @example
|
83
|
+
* ```ts
|
84
|
+
* class ColorFeed extends CoFeed.Of(co.string) {}
|
85
|
+
* class AnimalFeed extends CoFeed.Of(co.ref(Animal)) {}
|
86
|
+
* ```
|
87
|
+
*
|
88
|
+
* @category Declaration
|
89
|
+
*/
|
65
90
|
static Of<Item>(item: IfCo<Item, Item>): typeof CoFeed<Item> {
|
66
91
|
return class CoFeedOf extends CoFeed<Item> {
|
67
92
|
[co.items] = item;
|
68
93
|
};
|
69
94
|
}
|
70
95
|
|
96
|
+
/**
|
97
|
+
* The ID of this `CoFeed`
|
98
|
+
* @category Content */
|
71
99
|
declare id: ID<this>;
|
100
|
+
/** @category Type Helpers */
|
72
101
|
declare _type: "CoStream";
|
73
102
|
static {
|
74
103
|
this.prototype._type = "CoStream";
|
75
104
|
}
|
105
|
+
/** @category Internals */
|
76
106
|
declare _raw: RawCoStream;
|
77
107
|
|
78
108
|
/** @internal This is only a marker type and doesn't exist at runtime */
|
79
109
|
[ItemsSym]!: Item;
|
110
|
+
/** @internal */
|
80
111
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
81
112
|
static _schema: any;
|
113
|
+
/** @internal */
|
82
114
|
get _schema(): {
|
83
115
|
[ItemsSym]: SchemaFor<Item>;
|
84
116
|
} {
|
85
117
|
return (this.constructor as typeof CoFeed)._schema;
|
86
118
|
}
|
87
119
|
|
120
|
+
/**
|
121
|
+
* The per-account view of this `CoFeed`
|
122
|
+
*
|
123
|
+
* @example
|
124
|
+
* ```ts
|
125
|
+
* // Access entries directly by account ID
|
126
|
+
* const aliceEntries = feed[aliceAccount.id];
|
127
|
+
* console.log(aliceEntries.value); // Latest value from Alice
|
128
|
+
*
|
129
|
+
* // Iterate through all accounts' entries
|
130
|
+
* for (const [accountId, entries] of Object.entries(feed)) {
|
131
|
+
* console.log(`Latest entry from ${accountId}:`, entries.value);
|
132
|
+
*
|
133
|
+
* // Access all entries from this account
|
134
|
+
* for (const entry of entries.all) {
|
135
|
+
* console.log(`Entry made at ${entry.madeAt}:`, entry.value);
|
136
|
+
* }
|
137
|
+
* }
|
138
|
+
* ```
|
139
|
+
*
|
140
|
+
* @category Content
|
141
|
+
*/
|
88
142
|
[key: ID<Account>]: CoFeedEntry<Item>;
|
89
143
|
|
144
|
+
/**
|
145
|
+
* The current account's view of this `CoFeed`
|
146
|
+
* @category Content
|
147
|
+
*/
|
90
148
|
get byMe(): CoFeedEntry<Item> | undefined {
|
91
149
|
if (this._loadedAs._type === "Account") {
|
92
150
|
return this[this._loadedAs.id];
|
@@ -94,9 +152,22 @@ export class CoFeed<Item = any> extends CoValueBase implements CoValue {
|
|
94
152
|
return undefined;
|
95
153
|
}
|
96
154
|
}
|
155
|
+
|
156
|
+
/**
|
157
|
+
* The per-session view of this `CoFeed`
|
158
|
+
* @category Content
|
159
|
+
*/
|
97
160
|
perSession!: {
|
98
161
|
[key: SessionID]: CoFeedEntry<Item>;
|
99
162
|
};
|
163
|
+
|
164
|
+
/**
|
165
|
+
* The current session's view of this `CoFeed`
|
166
|
+
*
|
167
|
+
* This is a shortcut for `this.perSession` where the session ID is the current session ID.
|
168
|
+
*
|
169
|
+
* @category Content
|
170
|
+
*/
|
100
171
|
get inCurrentSession(): CoFeedEntry<Item> | undefined {
|
101
172
|
if (this._loadedAs._type === "Account") {
|
102
173
|
return this.perSession[this._loadedAs.sessionID!];
|
@@ -125,6 +196,10 @@ export class CoFeed<Item = any> extends CoValueBase implements CoValue {
|
|
125
196
|
return new Proxy(this, CoStreamProxyHandler as ProxyHandler<this>);
|
126
197
|
}
|
127
198
|
|
199
|
+
/**
|
200
|
+
* Create a new `CoFeed`
|
201
|
+
* @category Creation
|
202
|
+
*/
|
128
203
|
static create<S extends CoFeed>(
|
129
204
|
this: CoValueClass<S>,
|
130
205
|
init: S extends CoFeed<infer Item> ? UnCo<Item>[] : never,
|
@@ -147,6 +222,26 @@ export class CoFeed<Item = any> extends CoValueBase implements CoValue {
|
|
147
222
|
return instance;
|
148
223
|
}
|
149
224
|
|
225
|
+
/**
|
226
|
+
* Push items to this `CoFeed`
|
227
|
+
*
|
228
|
+
* Items are appended to the current session's log. Each session (tab, device, app instance)
|
229
|
+
* maintains its own append-only log, which is then aggregated into the per-account view.
|
230
|
+
*
|
231
|
+
* @example
|
232
|
+
* ```ts
|
233
|
+
* // Adds items to current session's log
|
234
|
+
* feed.push("item1", "item2");
|
235
|
+
*
|
236
|
+
* // View items from current session
|
237
|
+
* console.log(feed.inCurrentSession);
|
238
|
+
*
|
239
|
+
* // View aggregated items from all sessions for current account
|
240
|
+
* console.log(feed.byMe);
|
241
|
+
* ```
|
242
|
+
*
|
243
|
+
* @category Content
|
244
|
+
*/
|
150
245
|
push(...items: Item[]) {
|
151
246
|
for (const item of items) {
|
152
247
|
this.pushItem(item);
|
@@ -165,6 +260,10 @@ export class CoFeed<Item = any> extends CoValueBase implements CoValue {
|
|
165
260
|
}
|
166
261
|
}
|
167
262
|
|
263
|
+
/**
|
264
|
+
* Get a JSON representation of the `CoFeed`
|
265
|
+
* @category
|
266
|
+
*/
|
168
267
|
toJSON(): {
|
169
268
|
id: string;
|
170
269
|
_type: "CoStream";
|
@@ -197,6 +296,7 @@ export class CoFeed<Item = any> extends CoValueBase implements CoValue {
|
|
197
296
|
};
|
198
297
|
}
|
199
298
|
|
299
|
+
/** @internal */
|
200
300
|
[inspect](): {
|
201
301
|
id: string;
|
202
302
|
_type: "CoStream";
|
@@ -206,6 +306,7 @@ export class CoFeed<Item = any> extends CoValueBase implements CoValue {
|
|
206
306
|
return this.toJSON();
|
207
307
|
}
|
208
308
|
|
309
|
+
/** @internal */
|
209
310
|
static schema<V extends CoFeed>(
|
210
311
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
211
312
|
this: { new (...args: any): V } & typeof CoFeed,
|
@@ -215,7 +316,10 @@ export class CoFeed<Item = any> extends CoValueBase implements CoValue {
|
|
215
316
|
Object.assign(this._schema, def);
|
216
317
|
}
|
217
318
|
|
218
|
-
/**
|
319
|
+
/**
|
320
|
+
* Load a `CoFeed`
|
321
|
+
* @category Subscription & Loading
|
322
|
+
*/
|
219
323
|
static load<S extends CoFeed, Depth>(
|
220
324
|
this: CoValueClass<S>,
|
221
325
|
id: ID<S>,
|
@@ -225,7 +329,10 @@ export class CoFeed<Item = any> extends CoValueBase implements CoValue {
|
|
225
329
|
return loadCoValue(this, id, as, depth);
|
226
330
|
}
|
227
331
|
|
228
|
-
/**
|
332
|
+
/**
|
333
|
+
* Subscribe to a `CoFeed`, when you have an ID but don't have a `CoFeed` instance yet
|
334
|
+
* @category Subscription & Loading
|
335
|
+
*/
|
229
336
|
static subscribe<S extends CoFeed, Depth>(
|
230
337
|
this: CoValueClass<S>,
|
231
338
|
id: ID<S>,
|
@@ -236,7 +343,13 @@ export class CoFeed<Item = any> extends CoValueBase implements CoValue {
|
|
236
343
|
return subscribeToCoValue<S, Depth>(this, id, as, depth, listener);
|
237
344
|
}
|
238
345
|
|
239
|
-
/**
|
346
|
+
/**
|
347
|
+
* Ensure a `CoFeed` is loaded to the specified depth
|
348
|
+
*
|
349
|
+
* @returns A new instance of the same CoFeed that's loaded to the specified depth,
|
350
|
+
* or undefined if it cannot be loaded that deeply
|
351
|
+
* @category Subscription & Loading
|
352
|
+
*/
|
240
353
|
ensureLoaded<S extends CoFeed, Depth>(
|
241
354
|
this: S,
|
242
355
|
depth: Depth & DepthsIn<S>,
|
@@ -244,7 +357,12 @@ export class CoFeed<Item = any> extends CoValueBase implements CoValue {
|
|
244
357
|
return ensureCoValueLoaded(this, depth);
|
245
358
|
}
|
246
359
|
|
247
|
-
/**
|
360
|
+
/**
|
361
|
+
* An instance method to subscribe to an existing `CoFeed`
|
362
|
+
*
|
363
|
+
* No need to provide an ID or Account since they're already part of the instance.
|
364
|
+
* @category Subscription & Loading
|
365
|
+
*/
|
248
366
|
subscribe<S extends CoFeed, Depth>(
|
249
367
|
this: S,
|
250
368
|
depth: Depth & DepthsIn<S>,
|
@@ -254,6 +372,10 @@ export class CoFeed<Item = any> extends CoValueBase implements CoValue {
|
|
254
372
|
}
|
255
373
|
}
|
256
374
|
|
375
|
+
/**
|
376
|
+
* Converts a raw stream entry into a formatted CoFeed entry with proper typing and accessors.
|
377
|
+
* @internal
|
378
|
+
*/
|
257
379
|
function entryFromRawEntry<Item>(
|
258
380
|
accessFrom: CoValue,
|
259
381
|
rawEntry: {
|
@@ -316,6 +438,10 @@ function entryFromRawEntry<Item>(
|
|
316
438
|
};
|
317
439
|
}
|
318
440
|
|
441
|
+
/**
|
442
|
+
* The proxy handler for `CoFeed` instances
|
443
|
+
* @internal
|
444
|
+
*/
|
319
445
|
export const CoStreamProxyHandler: ProxyHandler<CoFeed> = {
|
320
446
|
get(target, key, receiver) {
|
321
447
|
if (typeof key === "string" && key.startsWith("co_")) {
|
@@ -404,6 +530,10 @@ export const CoStreamProxyHandler: ProxyHandler<CoFeed> = {
|
|
404
530
|
},
|
405
531
|
};
|
406
532
|
|
533
|
+
/**
|
534
|
+
* The proxy handler for the per-session view of a `CoFeed`
|
535
|
+
* @internal
|
536
|
+
*/
|
407
537
|
const CoStreamPerSessionProxyHandler = (
|
408
538
|
innerTarget: CoFeed,
|
409
539
|
accessFrom: CoFeed,
|
@@ -469,13 +599,34 @@ const CoStreamPerSessionProxyHandler = (
|
|
469
599
|
},
|
470
600
|
});
|
471
601
|
|
472
|
-
/** @deprecated Use
|
602
|
+
/** @deprecated Use FileStream instead */
|
473
603
|
export { FileStream as BinaryCoStream };
|
474
604
|
|
475
|
-
/**
|
605
|
+
/**
|
606
|
+
* FileStreams are `CoFeed`s that contain binary data, collaborative versions of `Blob`s.
|
607
|
+
*
|
608
|
+
* @categoryDescription Declaration
|
609
|
+
* `FileStream` can be referenced in schemas.
|
610
|
+
*
|
611
|
+
* ```ts
|
612
|
+
* import { co, FileStream } from "jazz-tools";
|
613
|
+
*
|
614
|
+
* class MyCoMap extends CoMap {
|
615
|
+
* file = co.ref(FileStream);
|
616
|
+
* }
|
617
|
+
* ```
|
618
|
+
*
|
619
|
+
* @category CoValues
|
620
|
+
*/
|
476
621
|
export class FileStream extends CoValueBase implements CoValue {
|
622
|
+
/**
|
623
|
+
* The ID of this `FileStream`
|
624
|
+
* @category Content
|
625
|
+
*/
|
477
626
|
declare id: ID<this>;
|
627
|
+
/** @category Type Helpers */
|
478
628
|
declare _type: "BinaryCoStream";
|
629
|
+
/** @internal */
|
479
630
|
declare _raw: RawBinaryCoStream;
|
480
631
|
|
481
632
|
constructor(
|
@@ -552,6 +703,11 @@ export class FileStream extends CoValueBase implements CoValue {
|
|
552
703
|
return new Blob(chunks.chunks, { type: chunks.mimeType });
|
553
704
|
}
|
554
705
|
|
706
|
+
/**
|
707
|
+
* Load a `FileStream` as a `Blob`
|
708
|
+
*
|
709
|
+
* @category Content
|
710
|
+
*/
|
555
711
|
static async loadAsBlob(
|
556
712
|
id: ID<FileStream>,
|
557
713
|
as: Account,
|
@@ -581,6 +737,17 @@ export class FileStream extends CoValueBase implements CoValue {
|
|
581
737
|
});
|
582
738
|
}
|
583
739
|
|
740
|
+
/**
|
741
|
+
* Create a `FileStream` from a `Blob` or `File`
|
742
|
+
*
|
743
|
+
* @example
|
744
|
+
* ```ts
|
745
|
+
* import { co, FileStream } from "jazz-tools";
|
746
|
+
*
|
747
|
+
* const fileStream = await FileStream.createFromBlob(file, {owner: group})
|
748
|
+
* ```
|
749
|
+
* @category Content
|
750
|
+
*/
|
584
751
|
static async createFromBlob(
|
585
752
|
blob: Blob | File,
|
586
753
|
options: {
|
@@ -626,6 +793,10 @@ export class FileStream extends CoValueBase implements CoValue {
|
|
626
793
|
return stream;
|
627
794
|
}
|
628
795
|
|
796
|
+
/**
|
797
|
+
* Get a JSON representation of the `FileStream`
|
798
|
+
* @category Content
|
799
|
+
*/
|
629
800
|
toJSON(): {
|
630
801
|
id: string;
|
631
802
|
_type: "BinaryCoStream";
|
@@ -642,11 +813,15 @@ export class FileStream extends CoValueBase implements CoValue {
|
|
642
813
|
};
|
643
814
|
}
|
644
815
|
|
816
|
+
/** @internal */
|
645
817
|
[inspect]() {
|
646
818
|
return this.toJSON();
|
647
819
|
}
|
648
820
|
|
649
|
-
/**
|
821
|
+
/**
|
822
|
+
* Load a `FileStream`
|
823
|
+
* @category Subscription & Loading
|
824
|
+
*/
|
650
825
|
static load<B extends FileStream, Depth>(
|
651
826
|
this: CoValueClass<B>,
|
652
827
|
id: ID<B>,
|
@@ -656,7 +831,10 @@ export class FileStream extends CoValueBase implements CoValue {
|
|
656
831
|
return loadCoValue(this, id, as, depth);
|
657
832
|
}
|
658
833
|
|
659
|
-
/**
|
834
|
+
/**
|
835
|
+
* Subscribe to a `FileStream`, when you have an ID but don't have a `FileStream` instance yet
|
836
|
+
* @category Subscription & Loading
|
837
|
+
*/
|
660
838
|
static subscribe<B extends FileStream, Depth>(
|
661
839
|
this: CoValueClass<B>,
|
662
840
|
id: ID<B>,
|
@@ -667,7 +845,6 @@ export class FileStream extends CoValueBase implements CoValue {
|
|
667
845
|
return subscribeToCoValue<B, Depth>(this, id, as, depth, listener);
|
668
846
|
}
|
669
847
|
|
670
|
-
/** @category Subscription & Loading */
|
671
848
|
ensureLoaded<B extends FileStream, Depth>(
|
672
849
|
this: B,
|
673
850
|
depth: Depth & DepthsIn<B>,
|
@@ -675,7 +852,10 @@ export class FileStream extends CoValueBase implements CoValue {
|
|
675
852
|
return ensureCoValueLoaded(this, depth);
|
676
853
|
}
|
677
854
|
|
678
|
-
/**
|
855
|
+
/**
|
856
|
+
* An instance method to subscribe to an existing `FileStream`
|
857
|
+
* @category Subscription & Loading
|
858
|
+
*/
|
679
859
|
subscribe<B extends FileStream, Depth>(
|
680
860
|
this: B,
|
681
861
|
depth: Depth & DepthsIn<B>,
|
package/src/coValues/coMap.ts
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
import {
|
2
|
+
AgentID,
|
2
3
|
type CoValueUniqueness,
|
4
|
+
CojsonInternalTypes,
|
3
5
|
type JsonValue,
|
6
|
+
RawAccountID,
|
4
7
|
type RawCoMap,
|
5
8
|
cojsonInternals,
|
6
9
|
} from "cojson";
|
@@ -41,6 +44,8 @@ type CoMapEdit<V> = {
|
|
41
44
|
madeAt: Date;
|
42
45
|
};
|
43
46
|
|
47
|
+
type LastAndAllCoMapEdits<V> = CoMapEdit<V> & { all: CoMapEdit<V>[] };
|
48
|
+
|
44
49
|
export type Simplify<A> = {
|
45
50
|
[K in keyof A]: A[K];
|
46
51
|
} extends infer B
|
@@ -141,47 +146,82 @@ export class CoMap extends CoValueBase implements CoValue {
|
|
141
146
|
) as any;
|
142
147
|
}
|
143
148
|
|
149
|
+
/** @internal */
|
150
|
+
private getEditFromRaw(
|
151
|
+
target: CoMap,
|
152
|
+
rawEdit: {
|
153
|
+
by: RawAccountID | AgentID;
|
154
|
+
tx: CojsonInternalTypes.TransactionID;
|
155
|
+
at: Date;
|
156
|
+
value?: JsonValue | undefined;
|
157
|
+
},
|
158
|
+
descriptor: Schema,
|
159
|
+
key: string,
|
160
|
+
) {
|
161
|
+
return {
|
162
|
+
value:
|
163
|
+
descriptor === "json"
|
164
|
+
? rawEdit.value
|
165
|
+
: "encoded" in descriptor
|
166
|
+
? rawEdit.value === null || rawEdit.value === undefined
|
167
|
+
? rawEdit.value
|
168
|
+
: descriptor.encoded.decode(rawEdit.value)
|
169
|
+
: new Ref(
|
170
|
+
rawEdit.value as ID<CoValue>,
|
171
|
+
target._loadedAs,
|
172
|
+
descriptor,
|
173
|
+
).accessFrom(target, "_edits." + key + ".value"),
|
174
|
+
ref:
|
175
|
+
descriptor !== "json" && isRefEncoded(descriptor)
|
176
|
+
? new Ref(rawEdit.value as ID<CoValue>, target._loadedAs, descriptor)
|
177
|
+
: undefined,
|
178
|
+
by:
|
179
|
+
rawEdit.by &&
|
180
|
+
new Ref<Account>(rawEdit.by as ID<Account>, target._loadedAs, {
|
181
|
+
ref: Account,
|
182
|
+
optional: false,
|
183
|
+
}).accessFrom(target, "_edits." + key + ".by"),
|
184
|
+
madeAt: rawEdit.at,
|
185
|
+
};
|
186
|
+
}
|
187
|
+
|
144
188
|
/** @category Collaboration */
|
145
189
|
get _edits() {
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
optional: false,
|
179
|
-
}).accessFrom(target, "_edits." + key.toString() + ".by"),
|
180
|
-
madeAt: rawEdit.at,
|
181
|
-
};
|
190
|
+
const map = this;
|
191
|
+
return new Proxy(
|
192
|
+
{},
|
193
|
+
{
|
194
|
+
get(_target, key) {
|
195
|
+
const rawEdit = map._raw.lastEditAt(key as string);
|
196
|
+
if (!rawEdit) return undefined;
|
197
|
+
|
198
|
+
const descriptor = map._schema[
|
199
|
+
key as keyof typeof map._schema
|
200
|
+
] as Schema;
|
201
|
+
|
202
|
+
return {
|
203
|
+
...map.getEditFromRaw(map, rawEdit, descriptor, key as string),
|
204
|
+
get all() {
|
205
|
+
return [...map._raw.editsAt(key as string)].map((rawEdit) =>
|
206
|
+
map.getEditFromRaw(map, rawEdit, descriptor, key as string),
|
207
|
+
);
|
208
|
+
},
|
209
|
+
};
|
210
|
+
},
|
211
|
+
ownKeys(_target) {
|
212
|
+
return map._raw.keys();
|
213
|
+
},
|
214
|
+
getOwnPropertyDescriptor(target, key) {
|
215
|
+
return {
|
216
|
+
value: Reflect.get(target, key),
|
217
|
+
writable: false,
|
218
|
+
enumerable: true,
|
219
|
+
configurable: true,
|
220
|
+
};
|
221
|
+
},
|
182
222
|
},
|
183
|
-
|
184
|
-
[Key in CoKeys<this>]: IfCo<this[Key],
|
223
|
+
) as {
|
224
|
+
[Key in CoKeys<this>]: IfCo<this[Key], LastAndAllCoMapEdits<this[Key]>>;
|
185
225
|
};
|
186
226
|
}
|
187
227
|
|
@@ -251,6 +291,10 @@ export class CoMap extends CoValueBase implements CoValue {
|
|
251
291
|
return instance;
|
252
292
|
}
|
253
293
|
|
294
|
+
/**
|
295
|
+
* Return a JSON representation of the `CoMap`
|
296
|
+
* @category Content
|
297
|
+
*/
|
254
298
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
255
299
|
toJSON(_key?: string, seenAbove?: ID<CoValue>[]): any[] {
|
256
300
|
const jsonedFields = this._raw.keys().map((key) => {
|
@@ -288,7 +332,10 @@ export class CoMap extends CoValueBase implements CoValue {
|
|
288
332
|
return this.toJSON();
|
289
333
|
}
|
290
334
|
|
291
|
-
/**
|
335
|
+
/**
|
336
|
+
* Create a new `RawCoMap` from an initialization object
|
337
|
+
* @internal
|
338
|
+
*/
|
292
339
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
293
340
|
rawFromInit<Fields extends object = Record<string, any>>(
|
294
341
|
init: Simplify<CoMapInit<Fields>> | undefined,
|
@@ -58,7 +58,18 @@ export function isCoValueClass<V extends CoValue>(
|
|
58
58
|
return typeof value === "function" && value.fromRaw !== undefined;
|
59
59
|
}
|
60
60
|
|
61
|
-
/**
|
61
|
+
/**
|
62
|
+
* IDs are unique identifiers for `CoValue`s.
|
63
|
+
* Can be used with a type argument to refer to a specific `CoValue` type.
|
64
|
+
*
|
65
|
+
* @example
|
66
|
+
*
|
67
|
+
* ```ts
|
68
|
+
* type AccountID = ID<Account>;
|
69
|
+
* ```
|
70
|
+
*
|
71
|
+
* @category CoValues
|
72
|
+
*/
|
62
73
|
export type ID<T> = CojsonInternalTypes.RawCoID & IDMarker<T>;
|
63
74
|
|
64
75
|
type IDMarker<out T> = { __type(_: never): T };
|
@@ -9,10 +9,8 @@ import {
|
|
9
9
|
* SchemaUnion allows you to create union types of CoValues that can be discriminated at runtime.
|
10
10
|
*
|
11
11
|
* @categoryDescription Declaration
|
12
|
-
* Declare your union types by extending `SchemaUnion.Of(...)` and passing a discriminator function
|
13
|
-
* that determines which concrete type to use based on the raw data.
|
12
|
+
* Declare your union types by extending `SchemaUnion.Of(...)` and passing a discriminator function that determines which concrete type to use based on the raw data.
|
14
13
|
*
|
15
|
-
* @example
|
16
14
|
* ```ts
|
17
15
|
* import { SchemaUnion, CoMap } from "jazz-tools";
|
18
16
|
*
|
@@ -40,28 +38,15 @@ import {
|
|
40
38
|
* });
|
41
39
|
* ```
|
42
40
|
*
|
43
|
-
* @categoryDescription Loading
|
44
|
-
* When loading a SchemaUnion, the correct subclass will be instantiated based on the discriminator.
|
45
|
-
* You can narrow the returned instance to a subclass by using `instanceof` like so:
|
46
|
-
*
|
47
|
-
* @example
|
48
|
-
* ```ts
|
49
|
-
* const widget = await loadCoValue(WidgetUnion, id, me, {});
|
50
|
-
* if (widget instanceof ButtonWidget) {
|
51
|
-
* console.log(widget.label);
|
52
|
-
* } else if (widget instanceof SliderWidget) {
|
53
|
-
* console.log(widget.min, widget.max);
|
54
|
-
* }
|
55
|
-
* ```
|
56
|
-
*
|
57
41
|
* @category CoValues
|
58
42
|
*/
|
59
43
|
export abstract class SchemaUnion extends CoValueBase implements CoValue {
|
60
44
|
/**
|
61
45
|
* Create a new union type from a discriminator function.
|
62
46
|
*
|
63
|
-
* The discriminator function receives the raw data and should return the appropriate
|
64
|
-
*
|
47
|
+
* The discriminator function receives the raw data and should return the appropriate concrete class to use for that data.
|
48
|
+
*
|
49
|
+
* When loading a SchemaUnion, the correct subclass will be instantiated based on the discriminator.
|
65
50
|
*
|
66
51
|
* @param discriminator - Function that determines which concrete type to use
|
67
52
|
* @returns A new class that can create/load instances of the union type
|
@@ -75,10 +60,19 @@ export abstract class SchemaUnion extends CoValueBase implements CoValue {
|
|
75
60
|
* default: throw new Error("Unknown widget type");
|
76
61
|
* }
|
77
62
|
* });
|
63
|
+
*
|
64
|
+
* const widget = await loadCoValue(WidgetUnion, id, me, {});
|
65
|
+
*
|
66
|
+
* // You can narrow the returned instance to a subclass by using `instanceof`
|
67
|
+
* if (widget instanceof ButtonWidget) {
|
68
|
+
* console.log(widget.label);
|
69
|
+
* } else if (widget instanceof SliderWidget) {
|
70
|
+
* console.log(widget.min, widget.max);
|
71
|
+
* }
|
78
72
|
* ```
|
79
73
|
*
|
80
|
-
* @category
|
81
|
-
|
74
|
+
* @category Declaration
|
75
|
+
**/
|
82
76
|
static Of<V extends CoValue>(
|
83
77
|
discriminator: (raw: V["_raw"]) => CoValueClass<V> & CoValueFromRaw<V>,
|
84
78
|
): CoValueClass<V> & typeof SchemaUnion {
|