jazz-tools 0.8.19 → 0.8.23
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.
- package/CHANGELOG.md +19 -0
- package/dist/native/coValues/account.js +15 -17
- package/dist/native/coValues/account.js.map +1 -1
- package/dist/native/coValues/{coStream.js → coFeed.js} +21 -14
- package/dist/native/coValues/coFeed.js.map +1 -0
- package/dist/native/coValues/coList.js +16 -13
- package/dist/native/coValues/coList.js.map +1 -1
- package/dist/native/coValues/coMap.js +14 -10
- package/dist/native/coValues/coMap.js.map +1 -1
- package/dist/native/coValues/deepLoading.js.map +1 -1
- package/dist/native/coValues/extensions/imageDef.js +9 -4
- package/dist/native/coValues/extensions/imageDef.js.map +1 -1
- package/dist/native/coValues/group.js +23 -20
- package/dist/native/coValues/group.js.map +1 -1
- package/dist/native/coValues/schemaUnion.js +93 -0
- package/dist/native/coValues/schemaUnion.js.map +1 -0
- package/dist/native/exports.js +1 -1
- package/dist/native/exports.js.map +1 -1
- package/dist/native/implementation/createContext.js +1 -2
- package/dist/native/implementation/createContext.js.map +1 -1
- package/dist/native/implementation/refs.js +0 -3
- package/dist/native/implementation/refs.js.map +1 -1
- package/dist/native/implementation/subscriptionScope.js +5 -8
- package/dist/native/implementation/subscriptionScope.js.map +1 -1
- package/dist/native/internal.js +2 -1
- package/dist/native/internal.js.map +1 -1
- package/dist/web/coValues/account.js +15 -17
- package/dist/web/coValues/account.js.map +1 -1
- package/dist/web/coValues/{coStream.js → coFeed.js} +21 -14
- package/dist/web/coValues/coFeed.js.map +1 -0
- package/dist/web/coValues/coList.js +16 -13
- package/dist/web/coValues/coList.js.map +1 -1
- package/dist/web/coValues/coMap.js +14 -10
- package/dist/web/coValues/coMap.js.map +1 -1
- package/dist/web/coValues/deepLoading.js.map +1 -1
- package/dist/web/coValues/extensions/imageDef.js +9 -4
- package/dist/web/coValues/extensions/imageDef.js.map +1 -1
- package/dist/web/coValues/group.js +23 -20
- package/dist/web/coValues/group.js.map +1 -1
- package/dist/web/coValues/schemaUnion.js +93 -0
- package/dist/web/coValues/schemaUnion.js.map +1 -0
- package/dist/web/exports.js +1 -1
- package/dist/web/exports.js.map +1 -1
- package/dist/web/implementation/createContext.js +1 -2
- package/dist/web/implementation/createContext.js.map +1 -1
- package/dist/web/implementation/refs.js +0 -3
- package/dist/web/implementation/refs.js.map +1 -1
- package/dist/web/implementation/subscriptionScope.js +5 -8
- package/dist/web/implementation/subscriptionScope.js.map +1 -1
- package/dist/web/internal.js +2 -1
- package/dist/web/internal.js.map +1 -1
- package/package.json +2 -2
- package/src/coValues/{coStream.ts → coFeed.ts} +50 -38
- package/src/coValues/coList.ts +2 -2
- package/src/coValues/coMap.ts +2 -2
- package/src/coValues/deepLoading.ts +6 -6
- package/src/coValues/extensions/imageDef.ts +4 -9
- package/src/coValues/schemaUnion.ts +106 -0
- package/src/exports.ts +3 -0
- package/src/internal.ts +2 -1
- package/src/tests/{coStream.test.ts → coFeed.test.ts} +21 -30
- package/src/tests/deepLoading.test.ts +2 -2
- package/src/tests/schemaUnion.test.ts +118 -0
- package/src/tests/subscribe.test.ts +4 -4
- package/tsconfig.json +1 -1
- package/dist/native/coValues/coStream.js.map +0 -1
- package/dist/web/coValues/coStream.js.map +0 -1
@@ -38,11 +38,17 @@ import {
|
|
38
38
|
subscribeToExistingCoValue,
|
39
39
|
} from "../internal.js";
|
40
40
|
|
41
|
-
|
42
|
-
|
41
|
+
/** @deprecated Use CoFeedEntry instead */
|
42
|
+
export type CoStreamEntry<Item> = CoFeedEntry<Item>;
|
43
|
+
|
44
|
+
export type CoFeedEntry<Item> = SingleCoFeedEntry<Item> & {
|
45
|
+
all: IterableIterator<SingleCoFeedEntry<Item>>;
|
43
46
|
};
|
44
47
|
|
45
|
-
|
48
|
+
/** @deprecated Use SingleCoFeedEntry instead */
|
49
|
+
export type SingleCoStreamEntry<Item> = SingleCoFeedEntry<Item>;
|
50
|
+
|
51
|
+
export type SingleCoFeedEntry<Item> = {
|
46
52
|
value: NonNullable<Item> extends CoValue ? NonNullable<Item> | null : Item;
|
47
53
|
ref: NonNullable<Item> extends CoValue ? Ref<NonNullable<Item>> : never;
|
48
54
|
by?: Account | null;
|
@@ -50,11 +56,14 @@ export type SingleCoStreamEntry<Item> = {
|
|
50
56
|
tx: CojsonInternalTypes.TransactionID;
|
51
57
|
};
|
52
58
|
|
59
|
+
/** @deprecated Use CoFeed instead */
|
60
|
+
export { CoFeed as CoStream };
|
61
|
+
|
53
62
|
/** @category CoValues */
|
54
63
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
55
|
-
export class
|
56
|
-
static Of<Item>(item: IfCo<Item, Item>): typeof
|
57
|
-
return class
|
64
|
+
export class CoFeed<Item = any> extends CoValueBase implements CoValue {
|
65
|
+
static Of<Item>(item: IfCo<Item, Item>): typeof CoFeed<Item> {
|
66
|
+
return class CoFeedOf extends CoFeed<Item> {
|
58
67
|
[co.items] = item;
|
59
68
|
};
|
60
69
|
}
|
@@ -73,12 +82,12 @@ export class CoStream<Item = any> extends CoValueBase implements CoValue {
|
|
73
82
|
get _schema(): {
|
74
83
|
[ItemsSym]: SchemaFor<Item>;
|
75
84
|
} {
|
76
|
-
return (this.constructor as typeof
|
85
|
+
return (this.constructor as typeof CoFeed)._schema;
|
77
86
|
}
|
78
87
|
|
79
|
-
[key: ID<Account>]:
|
88
|
+
[key: ID<Account>]: CoFeedEntry<Item>;
|
80
89
|
|
81
|
-
get byMe():
|
90
|
+
get byMe(): CoFeedEntry<Item> | undefined {
|
82
91
|
if (this._loadedAs._type === "Account") {
|
83
92
|
return this[this._loadedAs.id];
|
84
93
|
} else {
|
@@ -86,9 +95,9 @@ export class CoStream<Item = any> extends CoValueBase implements CoValue {
|
|
86
95
|
}
|
87
96
|
}
|
88
97
|
perSession!: {
|
89
|
-
[key: SessionID]:
|
98
|
+
[key: SessionID]: CoFeedEntry<Item>;
|
90
99
|
};
|
91
|
-
get inCurrentSession():
|
100
|
+
get inCurrentSession(): CoFeedEntry<Item> | undefined {
|
92
101
|
if (this._loadedAs._type === "Account") {
|
93
102
|
return this.perSession[this._loadedAs.sessionID!];
|
94
103
|
} else {
|
@@ -116,9 +125,9 @@ export class CoStream<Item = any> extends CoValueBase implements CoValue {
|
|
116
125
|
return new Proxy(this, CoStreamProxyHandler as ProxyHandler<this>);
|
117
126
|
}
|
118
127
|
|
119
|
-
static create<S extends
|
128
|
+
static create<S extends CoFeed>(
|
120
129
|
this: CoValueClass<S>,
|
121
|
-
init: S extends
|
130
|
+
init: S extends CoFeed<infer Item> ? UnCo<Item>[] : never,
|
122
131
|
options: { owner: Account | Group },
|
123
132
|
) {
|
124
133
|
const instance = new this({ init, owner: options.owner });
|
@@ -197,9 +206,9 @@ export class CoStream<Item = any> extends CoValueBase implements CoValue {
|
|
197
206
|
return this.toJSON();
|
198
207
|
}
|
199
208
|
|
200
|
-
static schema<V extends
|
209
|
+
static schema<V extends CoFeed>(
|
201
210
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
202
|
-
this: { new (...args: any): V } & typeof
|
211
|
+
this: { new (...args: any): V } & typeof CoFeed,
|
203
212
|
def: { [ItemsSym]: V["_schema"][ItemsSym] },
|
204
213
|
) {
|
205
214
|
this._schema ||= {};
|
@@ -207,7 +216,7 @@ export class CoStream<Item = any> extends CoValueBase implements CoValue {
|
|
207
216
|
}
|
208
217
|
|
209
218
|
/** @category Subscription & Loading */
|
210
|
-
static load<S extends
|
219
|
+
static load<S extends CoFeed, Depth>(
|
211
220
|
this: CoValueClass<S>,
|
212
221
|
id: ID<S>,
|
213
222
|
as: Account,
|
@@ -217,7 +226,7 @@ export class CoStream<Item = any> extends CoValueBase implements CoValue {
|
|
217
226
|
}
|
218
227
|
|
219
228
|
/** @category Subscription & Loading */
|
220
|
-
static subscribe<S extends
|
229
|
+
static subscribe<S extends CoFeed, Depth>(
|
221
230
|
this: CoValueClass<S>,
|
222
231
|
id: ID<S>,
|
223
232
|
as: Account,
|
@@ -228,7 +237,7 @@ export class CoStream<Item = any> extends CoValueBase implements CoValue {
|
|
228
237
|
}
|
229
238
|
|
230
239
|
/** @category Subscription & Loading */
|
231
|
-
ensureLoaded<S extends
|
240
|
+
ensureLoaded<S extends CoFeed, Depth>(
|
232
241
|
this: S,
|
233
242
|
depth: Depth & DepthsIn<S>,
|
234
243
|
): Promise<DeeplyLoaded<S, Depth> | undefined> {
|
@@ -236,7 +245,7 @@ export class CoStream<Item = any> extends CoValueBase implements CoValue {
|
|
236
245
|
}
|
237
246
|
|
238
247
|
/** @category Subscription & Loading */
|
239
|
-
subscribe<S extends
|
248
|
+
subscribe<S extends CoFeed, Depth>(
|
240
249
|
this: S,
|
241
250
|
depth: Depth & DepthsIn<S>,
|
242
251
|
listener: (value: DeeplyLoaded<S, Depth>) => void,
|
@@ -256,7 +265,7 @@ function entryFromRawEntry<Item>(
|
|
256
265
|
loadedAs: Account | AnonymousJazzAgent,
|
257
266
|
accountID: ID<Account> | undefined,
|
258
267
|
itemField: Schema,
|
259
|
-
): Omit<
|
268
|
+
): Omit<CoFeedEntry<Item>, "all"> {
|
260
269
|
return {
|
261
270
|
get value(): NonNullable<Item> extends CoValue
|
262
271
|
? (CoValue & Item) | null
|
@@ -307,7 +316,7 @@ function entryFromRawEntry<Item>(
|
|
307
316
|
};
|
308
317
|
}
|
309
318
|
|
310
|
-
export const CoStreamProxyHandler: ProxyHandler<
|
319
|
+
export const CoStreamProxyHandler: ProxyHandler<CoFeed> = {
|
311
320
|
get(target, key, receiver) {
|
312
321
|
if (typeof key === "string" && key.startsWith("co_")) {
|
313
322
|
const rawEntry = target._raw.lastItemBy(key as RawAccountID);
|
@@ -337,7 +346,7 @@ export const CoStreamProxyHandler: ProxyHandler<CoStream> = {
|
|
337
346
|
);
|
338
347
|
}
|
339
348
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
340
|
-
})() satisfies IterableIterator<
|
349
|
+
})() satisfies IterableIterator<SingleCoFeedEntry<any>>;
|
341
350
|
},
|
342
351
|
});
|
343
352
|
|
@@ -350,8 +359,8 @@ export const CoStreamProxyHandler: ProxyHandler<CoStream> = {
|
|
350
359
|
},
|
351
360
|
set(target, key, value, receiver) {
|
352
361
|
if (key === ItemsSym && typeof value === "object" && SchemaInit in value) {
|
353
|
-
(target.constructor as typeof
|
354
|
-
(target.constructor as typeof
|
362
|
+
(target.constructor as typeof CoFeed)._schema ||= {};
|
363
|
+
(target.constructor as typeof CoFeed)._schema[ItemsSym] =
|
355
364
|
value[SchemaInit];
|
356
365
|
return true;
|
357
366
|
} else {
|
@@ -365,8 +374,8 @@ export const CoStreamProxyHandler: ProxyHandler<CoStream> = {
|
|
365
374
|
typeof descriptor.value === "object" &&
|
366
375
|
SchemaInit in descriptor.value
|
367
376
|
) {
|
368
|
-
(target.constructor as typeof
|
369
|
-
(target.constructor as typeof
|
377
|
+
(target.constructor as typeof CoFeed)._schema ||= {};
|
378
|
+
(target.constructor as typeof CoFeed)._schema[ItemsSym] =
|
370
379
|
descriptor.value[SchemaInit];
|
371
380
|
return true;
|
372
381
|
} else {
|
@@ -396,8 +405,8 @@ export const CoStreamProxyHandler: ProxyHandler<CoStream> = {
|
|
396
405
|
};
|
397
406
|
|
398
407
|
const CoStreamPerSessionProxyHandler = (
|
399
|
-
innerTarget:
|
400
|
-
accessFrom:
|
408
|
+
innerTarget: CoFeed,
|
409
|
+
accessFrom: CoFeed,
|
401
410
|
): ProxyHandler<Record<string, never>> => ({
|
402
411
|
get(_target, key, receiver) {
|
403
412
|
if (typeof key === "string" && key.includes("session")) {
|
@@ -435,7 +444,7 @@ const CoStreamPerSessionProxyHandler = (
|
|
435
444
|
);
|
436
445
|
}
|
437
446
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
438
|
-
})() satisfies IterableIterator<
|
447
|
+
})() satisfies IterableIterator<SingleCoFeedEntry<any>>;
|
439
448
|
},
|
440
449
|
});
|
441
450
|
|
@@ -460,8 +469,11 @@ const CoStreamPerSessionProxyHandler = (
|
|
460
469
|
},
|
461
470
|
});
|
462
471
|
|
472
|
+
/** @deprecated Use CoFeed instead */
|
473
|
+
export { FileStream as BinaryCoStream };
|
474
|
+
|
463
475
|
/** @category CoValues */
|
464
|
-
export class
|
476
|
+
export class FileStream extends CoValueBase implements CoValue {
|
465
477
|
declare id: ID<this>;
|
466
478
|
declare _type: "BinaryCoStream";
|
467
479
|
declare _raw: RawBinaryCoStream;
|
@@ -496,7 +508,7 @@ export class BinaryCoStream extends CoValueBase implements CoValue {
|
|
496
508
|
});
|
497
509
|
}
|
498
510
|
|
499
|
-
static create<S extends
|
511
|
+
static create<S extends FileStream>(
|
500
512
|
this: CoValueClass<S>,
|
501
513
|
options: { owner: Account | Group },
|
502
514
|
) {
|
@@ -541,7 +553,7 @@ export class BinaryCoStream extends CoValueBase implements CoValue {
|
|
541
553
|
}
|
542
554
|
|
543
555
|
static async loadAsBlob(
|
544
|
-
id: ID<
|
556
|
+
id: ID<FileStream>,
|
545
557
|
as: Account,
|
546
558
|
options?: {
|
547
559
|
allowUnfinished?: boolean;
|
@@ -554,7 +566,7 @@ export class BinaryCoStream extends CoValueBase implements CoValue {
|
|
554
566
|
* stream isn't complete wait for the stream download before progressing
|
555
567
|
*/
|
556
568
|
if (!options?.allowUnfinished && !stream?.isBinaryStreamEnded()) {
|
557
|
-
stream = await new Promise<
|
569
|
+
stream = await new Promise<FileStream>((resolve) => {
|
558
570
|
const unsubscribe = subscribeToCoValue(this, id, as, [], (value) => {
|
559
571
|
if (value.isBinaryStreamEnded()) {
|
560
572
|
unsubscribe();
|
@@ -575,7 +587,7 @@ export class BinaryCoStream extends CoValueBase implements CoValue {
|
|
575
587
|
owner: Group | Account;
|
576
588
|
onProgress?: (progress: number) => void;
|
577
589
|
},
|
578
|
-
): Promise<
|
590
|
+
): Promise<FileStream> {
|
579
591
|
const stream = this.create({ owner: options.owner });
|
580
592
|
|
581
593
|
const start = Date.now();
|
@@ -635,7 +647,7 @@ export class BinaryCoStream extends CoValueBase implements CoValue {
|
|
635
647
|
}
|
636
648
|
|
637
649
|
/** @category Subscription & Loading */
|
638
|
-
static load<B extends
|
650
|
+
static load<B extends FileStream, Depth>(
|
639
651
|
this: CoValueClass<B>,
|
640
652
|
id: ID<B>,
|
641
653
|
as: Account,
|
@@ -645,7 +657,7 @@ export class BinaryCoStream extends CoValueBase implements CoValue {
|
|
645
657
|
}
|
646
658
|
|
647
659
|
/** @category Subscription & Loading */
|
648
|
-
static subscribe<B extends
|
660
|
+
static subscribe<B extends FileStream, Depth>(
|
649
661
|
this: CoValueClass<B>,
|
650
662
|
id: ID<B>,
|
651
663
|
as: Account,
|
@@ -656,7 +668,7 @@ export class BinaryCoStream extends CoValueBase implements CoValue {
|
|
656
668
|
}
|
657
669
|
|
658
670
|
/** @category Subscription & Loading */
|
659
|
-
ensureLoaded<B extends
|
671
|
+
ensureLoaded<B extends FileStream, Depth>(
|
660
672
|
this: B,
|
661
673
|
depth: Depth & DepthsIn<B>,
|
662
674
|
): Promise<DeeplyLoaded<B, Depth> | undefined> {
|
@@ -664,7 +676,7 @@ export class BinaryCoStream extends CoValueBase implements CoValue {
|
|
664
676
|
}
|
665
677
|
|
666
678
|
/** @category Subscription & Loading */
|
667
|
-
subscribe<B extends
|
679
|
+
subscribe<B extends FileStream, Depth>(
|
668
680
|
this: B,
|
669
681
|
depth: Depth & DepthsIn<B>,
|
670
682
|
listener: (value: DeeplyLoaded<B, Depth>) => void,
|
package/src/coValues/coList.ts
CHANGED
@@ -339,7 +339,7 @@ export class CoList<Item = any> extends Array<Item> implements CoValue {
|
|
339
339
|
*
|
340
340
|
* You can pass `[]` or for shallowly loading only this CoList, or `[itemDepth]` for recursively loading referenced CoValues.
|
341
341
|
*
|
342
|
-
* Check out the `load` methods on `CoMap`/`CoList`/`
|
342
|
+
* Check out the `load` methods on `CoMap`/`CoList`/`CoFeed`/`Group`/`Account` to see which depth structures are valid to nest.
|
343
343
|
*
|
344
344
|
* @example
|
345
345
|
* ```ts
|
@@ -372,7 +372,7 @@ export class CoList<Item = any> extends Array<Item> implements CoValue {
|
|
372
372
|
*
|
373
373
|
* You can pass `[]` or for shallowly loading only this CoList, or `[itemDepth]` for recursively loading referenced CoValues.
|
374
374
|
*
|
375
|
-
* Check out the `load` methods on `CoMap`/`CoList`/`
|
375
|
+
* Check out the `load` methods on `CoMap`/`CoList`/`CoFeed`/`Group`/`Account` to see which depth structures are valid to nest.
|
376
376
|
*
|
377
377
|
* Returns an unsubscribe function that you should call when you no longer need updates.
|
378
378
|
*
|
package/src/coValues/coMap.ts
CHANGED
@@ -366,7 +366,7 @@ export class CoMap extends CoValueBase implements CoValue {
|
|
366
366
|
*
|
367
367
|
* You can pass `[]` or `{}` for shallowly loading only this CoMap, or `{ fieldA: depthA, fieldB: depthB }` for recursively loading referenced CoValues.
|
368
368
|
*
|
369
|
-
* Check out the `load` methods on `CoMap`/`CoList`/`
|
369
|
+
* Check out the `load` methods on `CoMap`/`CoList`/`CoFeed`/`Group`/`Account` to see which depth structures are valid to nest.
|
370
370
|
*
|
371
371
|
* @example
|
372
372
|
* ```ts
|
@@ -398,7 +398,7 @@ export class CoMap extends CoValueBase implements CoValue {
|
|
398
398
|
*
|
399
399
|
* You can pass `[]` or `{}` for shallowly loading only this CoMap, or `{ fieldA: depthA, fieldB: depthB }` for recursively loading referenced CoValues.
|
400
400
|
*
|
401
|
-
* Check out the `load` methods on `CoMap`/`CoList`/`
|
401
|
+
* Check out the `load` methods on `CoMap`/`CoList`/`CoFeed`/`Group`/`Account` to see which depth structures are valid to nest.
|
402
402
|
*
|
403
403
|
* Returns an unsubscribe function that you should call when you no longer need updates.
|
404
404
|
*
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import { SessionID } from "cojson";
|
2
2
|
import {
|
3
3
|
Account,
|
4
|
+
CoFeed,
|
5
|
+
CoFeedEntry,
|
4
6
|
CoList,
|
5
|
-
CoStream,
|
6
|
-
CoStreamEntry,
|
7
7
|
ItemsSym,
|
8
8
|
Ref,
|
9
9
|
RefEncoded,
|
@@ -66,10 +66,10 @@ export function fulfillsDepth(depth: any, value: CoValue): boolean {
|
|
66
66
|
return true;
|
67
67
|
} else {
|
68
68
|
const itemDepth = depth[0];
|
69
|
-
return Object.values((value as
|
69
|
+
return Object.values((value as CoFeed).perSession).every((entry) =>
|
70
70
|
entry.ref
|
71
71
|
? entry.value && fulfillsDepth(itemDepth, entry.value)
|
72
|
-
: ((value as
|
72
|
+
: ((value as CoFeed)._schema[ItemsSym] as RefEncoded<CoValue>)
|
73
73
|
.optional,
|
74
74
|
);
|
75
75
|
}
|
@@ -121,7 +121,7 @@ export type DepthsIn<
|
|
121
121
|
| never[]
|
122
122
|
: V extends {
|
123
123
|
_type: "CoStream";
|
124
|
-
byMe:
|
124
|
+
byMe: CoFeedEntry<infer Item> | undefined;
|
125
125
|
}
|
126
126
|
?
|
127
127
|
| [
|
@@ -192,7 +192,7 @@ export type DeeplyLoaded<
|
|
192
192
|
: [V] extends [
|
193
193
|
{
|
194
194
|
_type: "CoStream";
|
195
|
-
byMe:
|
195
|
+
byMe: CoFeedEntry<infer Item> | undefined;
|
196
196
|
},
|
197
197
|
]
|
198
198
|
? Depth extends never[]
|
@@ -1,21 +1,16 @@
|
|
1
|
-
import {
|
2
|
-
BinaryCoStream,
|
3
|
-
CoMap,
|
4
|
-
co,
|
5
|
-
subscriptionsScopes,
|
6
|
-
} from "../../internal.js";
|
1
|
+
import { CoMap, FileStream, co, subscriptionsScopes } from "../../internal.js";
|
7
2
|
|
8
3
|
/** @category Media */
|
9
4
|
export class ImageDefinition extends CoMap {
|
10
5
|
originalSize = co.json<[number, number]>();
|
11
6
|
placeholderDataURL? = co.string;
|
12
7
|
|
13
|
-
[co.items] = co.ref(
|
14
|
-
[res: `${number}x${number}`]: co<
|
8
|
+
[co.items] = co.ref(FileStream);
|
9
|
+
[res: `${number}x${number}`]: co<FileStream | null>;
|
15
10
|
|
16
11
|
highestResAvailable(options?: {
|
17
12
|
maxWidth?: number;
|
18
|
-
}): { res: `${number}x${number}`; stream:
|
13
|
+
}): { res: `${number}x${number}`; stream: FileStream } | undefined {
|
19
14
|
if (!subscriptionsScopes.get(this)) {
|
20
15
|
console.warn(
|
21
16
|
"highestResAvailable() only makes sense when used within a subscription.",
|
@@ -0,0 +1,106 @@
|
|
1
|
+
import {
|
2
|
+
CoValue,
|
3
|
+
CoValueBase,
|
4
|
+
CoValueClass,
|
5
|
+
CoValueFromRaw,
|
6
|
+
} from "../internal.js";
|
7
|
+
|
8
|
+
/**
|
9
|
+
* SchemaUnion allows you to create union types of CoValues that can be discriminated at runtime.
|
10
|
+
*
|
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.
|
14
|
+
*
|
15
|
+
* ```ts
|
16
|
+
* import { SchemaUnion, CoMap } from "jazz-tools";
|
17
|
+
*
|
18
|
+
* class BaseWidget extends CoMap {
|
19
|
+
* type = co.string;
|
20
|
+
* }
|
21
|
+
*
|
22
|
+
* class ButtonWidget extends BaseWidget {
|
23
|
+
* type = co.literal("button");
|
24
|
+
* label = co.string;
|
25
|
+
* }
|
26
|
+
*
|
27
|
+
* class SliderWidget extends BaseWidget {
|
28
|
+
* type = co.literal("slider");
|
29
|
+
* min = co.number;
|
30
|
+
* max = co.number;
|
31
|
+
* }
|
32
|
+
*
|
33
|
+
* const WidgetUnion = SchemaUnion.Of<BaseWidget>((raw) => {
|
34
|
+
* switch (raw.get("type")) {
|
35
|
+
* case "button": return ButtonWidget;
|
36
|
+
* case "slider": return SliderWidget;
|
37
|
+
* default: throw new Error("Unknown widget type");
|
38
|
+
* }
|
39
|
+
* });
|
40
|
+
* ```
|
41
|
+
*
|
42
|
+
* @categoryDescription Loading
|
43
|
+
* When loading a SchemaUnion, the correct subclass will be instantiated based on the discriminator.
|
44
|
+
* You can narrow the returned instance to a subclass by using `instanceof` like so:
|
45
|
+
*
|
46
|
+
* ```ts
|
47
|
+
* const widget = await WidgetUnion.load(id, me, {});
|
48
|
+
* if (widget instanceof ButtonWidget) {
|
49
|
+
* console.log(widget.label);
|
50
|
+
* } else if (widget instanceof SliderWidget) {
|
51
|
+
* console.log(widget.min, widget.max);
|
52
|
+
* }
|
53
|
+
* ```
|
54
|
+
*
|
55
|
+
* @category CoValues
|
56
|
+
*/
|
57
|
+
export abstract class SchemaUnion extends CoValueBase implements CoValue {
|
58
|
+
/**
|
59
|
+
* Create a new union type from a discriminator function.
|
60
|
+
*
|
61
|
+
* The discriminator function receives the raw data and should return the appropriate
|
62
|
+
* concrete class to use for that data.
|
63
|
+
*
|
64
|
+
* @param discriminator - Function that determines which concrete type to use
|
65
|
+
* @returns A new class that can create/load instances of the union type
|
66
|
+
*
|
67
|
+
* @example
|
68
|
+
* ```ts
|
69
|
+
* const WidgetUnion = SchemaUnion.Of<BaseWidget>((raw) => {
|
70
|
+
* switch (raw.get("type")) {
|
71
|
+
* case "button": return ButtonWidget;
|
72
|
+
* case "slider": return SliderWidget;
|
73
|
+
* default: throw new Error("Unknown widget type");
|
74
|
+
* }
|
75
|
+
* });
|
76
|
+
* ```
|
77
|
+
*
|
78
|
+
* @category Creation
|
79
|
+
*/
|
80
|
+
static Of<V extends CoValue>(
|
81
|
+
discriminator: (raw: V["_raw"]) => CoValueClass<V> & CoValueFromRaw<V>,
|
82
|
+
): CoValueClass<V> & typeof SchemaUnion {
|
83
|
+
return class SchemaUnionClass extends SchemaUnion {
|
84
|
+
static override fromRaw<T extends CoValue>(
|
85
|
+
this: CoValueClass<T> & CoValueFromRaw<T>,
|
86
|
+
raw: T["_raw"],
|
87
|
+
): T {
|
88
|
+
const ResolvedClass = discriminator(
|
89
|
+
raw as V["_raw"],
|
90
|
+
) as unknown as CoValueClass<T> & CoValueFromRaw<T>;
|
91
|
+
return ResolvedClass.fromRaw(raw);
|
92
|
+
}
|
93
|
+
} as unknown as CoValueClass<V> & typeof SchemaUnion;
|
94
|
+
}
|
95
|
+
|
96
|
+
/**
|
97
|
+
* Create an instance from raw data. This is called internally and should not be used directly.
|
98
|
+
* Use {@link SchemaUnion.Of} to create a union type instead.
|
99
|
+
*
|
100
|
+
* @internal
|
101
|
+
*/
|
102
|
+
// @ts-ignore
|
103
|
+
static fromRaw<V extends CoValue>(this: CoValueClass<V>, raw: V["_raw"]): V {
|
104
|
+
throw new Error("Not implemented");
|
105
|
+
}
|
106
|
+
}
|
package/src/exports.ts
CHANGED
@@ -14,15 +14,18 @@ export { Encoders, co } from "./internal.js";
|
|
14
14
|
|
15
15
|
export {
|
16
16
|
Account,
|
17
|
+
FileStream,
|
17
18
|
BinaryCoStream,
|
18
19
|
CoList,
|
19
20
|
CoMap,
|
21
|
+
CoFeed,
|
20
22
|
CoStream,
|
21
23
|
CoValueBase,
|
22
24
|
Group,
|
23
25
|
ImageDefinition,
|
24
26
|
Profile,
|
25
27
|
isControlledAccount,
|
28
|
+
SchemaUnion,
|
26
29
|
type AccountClass,
|
27
30
|
type CoMapInit,
|
28
31
|
type CoValueClass,
|
package/src/internal.ts
CHANGED
@@ -5,7 +5,8 @@ export * from "./coValues/interfaces.js";
|
|
5
5
|
export * from "./coValues/coMap.js";
|
6
6
|
export * from "./coValues/account.js";
|
7
7
|
export * from "./coValues/coList.js";
|
8
|
-
export * from "./coValues/
|
8
|
+
export * from "./coValues/coFeed.js";
|
9
|
+
export * from "./coValues/schemaUnion.js";
|
9
10
|
export * from "./coValues/group.js";
|
10
11
|
|
11
12
|
export * from "./implementation/errors.js";
|
@@ -2,8 +2,8 @@ import { connectedPeers } from "cojson/src/streamUtils.ts";
|
|
2
2
|
import { describe, expect, test } from "vitest";
|
3
3
|
import {
|
4
4
|
Account,
|
5
|
-
|
6
|
-
|
5
|
+
CoFeed,
|
6
|
+
FileStream,
|
7
7
|
ID,
|
8
8
|
WasmCrypto,
|
9
9
|
co,
|
@@ -16,7 +16,7 @@ import { randomSessionProvider } from "../internal.js";
|
|
16
16
|
|
17
17
|
const Crypto = await WasmCrypto.create();
|
18
18
|
|
19
|
-
describe("Simple
|
19
|
+
describe("Simple CoFeed operations", async () => {
|
20
20
|
const me = await Account.create({
|
21
21
|
creationProps: { name: "Hermes Puggington" },
|
22
22
|
crypto: Crypto,
|
@@ -24,7 +24,7 @@ describe("Simple CoStream operations", async () => {
|
|
24
24
|
if (!isControlledAccount(me)) {
|
25
25
|
throw "me is not a controlled account";
|
26
26
|
}
|
27
|
-
class TestStream extends
|
27
|
+
class TestStream extends CoFeed.Of(co.string) {}
|
28
28
|
|
29
29
|
const stream = TestStream.create(["milk"], { owner: me });
|
30
30
|
|
@@ -46,16 +46,16 @@ describe("Simple CoStream operations", async () => {
|
|
46
46
|
});
|
47
47
|
});
|
48
48
|
|
49
|
-
describe("
|
50
|
-
class TwiceNestedStream extends
|
49
|
+
describe("CoFeed resolution", async () => {
|
50
|
+
class TwiceNestedStream extends CoFeed.Of(co.string) {
|
51
51
|
fancyValueOf(account: ID<Account>) {
|
52
52
|
return "Sir " + this[account]?.value;
|
53
53
|
}
|
54
54
|
}
|
55
55
|
|
56
|
-
class NestedStream extends
|
56
|
+
class NestedStream extends CoFeed.Of(co.ref(TwiceNestedStream)) {}
|
57
57
|
|
58
|
-
class TestStream extends
|
58
|
+
class TestStream extends CoFeed.Of(co.ref(NestedStream)) {}
|
59
59
|
|
60
60
|
const initNodeAndStream = async () => {
|
61
61
|
const me = await Account.create({
|
@@ -242,13 +242,13 @@ describe("CoStream resolution", async () => {
|
|
242
242
|
});
|
243
243
|
});
|
244
244
|
|
245
|
-
describe("Simple
|
245
|
+
describe("Simple FileStream operations", async () => {
|
246
246
|
const me = await Account.create({
|
247
247
|
creationProps: { name: "Hermes Puggington" },
|
248
248
|
crypto: Crypto,
|
249
249
|
});
|
250
250
|
|
251
|
-
const stream =
|
251
|
+
const stream = FileStream.create({ owner: me });
|
252
252
|
|
253
253
|
test("Construction", () => {
|
254
254
|
expect(stream.getChunks()).toBe(undefined);
|
@@ -270,14 +270,14 @@ describe("Simple BinaryCoStream operations", async () => {
|
|
270
270
|
});
|
271
271
|
});
|
272
272
|
|
273
|
-
describe("
|
273
|
+
describe("FileStream loading & Subscription", async () => {
|
274
274
|
const initNodeAndStream = async () => {
|
275
275
|
const me = await Account.create({
|
276
276
|
creationProps: { name: "Hermes Puggington" },
|
277
277
|
crypto: Crypto,
|
278
278
|
});
|
279
279
|
|
280
|
-
const stream =
|
280
|
+
const stream = FileStream.create({ owner: me });
|
281
281
|
|
282
282
|
stream.start({ mimeType: "text/plain" });
|
283
283
|
stream.push(new Uint8Array([1, 2, 3]));
|
@@ -316,11 +316,7 @@ describe("BinaryCoStream loading & Subscription", async () => {
|
|
316
316
|
crypto: Crypto,
|
317
317
|
});
|
318
318
|
|
319
|
-
const loadedStream = await
|
320
|
-
stream.id,
|
321
|
-
meOnSecondPeer,
|
322
|
-
[],
|
323
|
-
);
|
319
|
+
const loadedStream = await FileStream.load(stream.id, meOnSecondPeer, []);
|
324
320
|
|
325
321
|
expect(loadedStream?.getChunks()).toEqual({
|
326
322
|
mimeType: "text/plain",
|
@@ -331,7 +327,7 @@ describe("BinaryCoStream loading & Subscription", async () => {
|
|
331
327
|
|
332
328
|
test("Subscription", async () => {
|
333
329
|
const { me } = await initNodeAndStream();
|
334
|
-
const stream =
|
330
|
+
const stream = FileStream.create({ owner: me });
|
335
331
|
|
336
332
|
const [initialAsPeer, secondAsPeer] = connectedPeers("initial", "second", {
|
337
333
|
peer1role: "server",
|
@@ -353,14 +349,9 @@ describe("BinaryCoStream loading & Subscription", async () => {
|
|
353
349
|
|
354
350
|
const queue = new cojsonInternals.Channel();
|
355
351
|
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
[],
|
360
|
-
(subscribedStream) => {
|
361
|
-
void queue.push(subscribedStream);
|
362
|
-
},
|
363
|
-
);
|
352
|
+
FileStream.subscribe(stream.id, meOnSecondPeer, [], (subscribedStream) => {
|
353
|
+
void queue.push(subscribedStream);
|
354
|
+
});
|
364
355
|
|
365
356
|
const update1 = (await queue.next()).value;
|
366
357
|
expect(update1.getChunks()).toBe(undefined);
|
@@ -411,14 +402,14 @@ describe("BinaryCoStream loading & Subscription", async () => {
|
|
411
402
|
});
|
412
403
|
});
|
413
404
|
|
414
|
-
describe("
|
405
|
+
describe("FileStream.loadAsBlob", async () => {
|
415
406
|
async function setup() {
|
416
407
|
const me = await Account.create({
|
417
408
|
creationProps: { name: "Hermes Puggington" },
|
418
409
|
crypto: Crypto,
|
419
410
|
});
|
420
411
|
|
421
|
-
const stream =
|
412
|
+
const stream = FileStream.create({ owner: me });
|
422
413
|
|
423
414
|
stream.start({ mimeType: "text/plain" });
|
424
415
|
|
@@ -429,7 +420,7 @@ describe("BinaryCoStream.loadAsBlob", async () => {
|
|
429
420
|
const { stream, me } = await setup();
|
430
421
|
stream.push(new Uint8Array([1]));
|
431
422
|
|
432
|
-
const promise =
|
423
|
+
const promise = FileStream.loadAsBlob(stream.id, me);
|
433
424
|
|
434
425
|
await stream.ensureLoaded([]);
|
435
426
|
|
@@ -447,7 +438,7 @@ describe("BinaryCoStream.loadAsBlob", async () => {
|
|
447
438
|
const { stream, me } = await setup();
|
448
439
|
stream.push(new Uint8Array([1]));
|
449
440
|
|
450
|
-
const promise =
|
441
|
+
const promise = FileStream.loadAsBlob(stream.id, me, {
|
451
442
|
allowUnfinished: true,
|
452
443
|
});
|
453
444
|
|