jazz-tools 0.7.0-alpha.8 → 0.7.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.
- package/.eslintrc.cjs +3 -10
- package/.prettierrc.js +9 -0
- package/.turbo/turbo-build.log +3 -19
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-test.log +140 -0
- package/CHANGELOG.md +304 -0
- package/README.md +10 -2
- package/dist/coValues/account.js +59 -41
- package/dist/coValues/account.js.map +1 -1
- package/dist/coValues/coList.js +49 -46
- package/dist/coValues/coList.js.map +1 -1
- package/dist/coValues/coMap.js +143 -44
- package/dist/coValues/coMap.js.map +1 -1
- package/dist/coValues/coStream.js +144 -35
- package/dist/coValues/coStream.js.map +1 -1
- package/dist/coValues/deepLoading.js +60 -0
- package/dist/coValues/deepLoading.js.map +1 -0
- package/dist/coValues/extensions/imageDef.js +10 -7
- package/dist/coValues/extensions/imageDef.js.map +1 -1
- package/dist/coValues/group.js +49 -13
- package/dist/coValues/group.js.map +1 -1
- package/dist/coValues/interfaces.js +70 -31
- package/dist/coValues/interfaces.js.map +1 -1
- package/dist/implementation/devtoolsFormatters.js +114 -0
- package/dist/implementation/devtoolsFormatters.js.map +1 -0
- package/dist/implementation/refs.js +58 -18
- package/dist/implementation/refs.js.map +1 -1
- package/dist/implementation/schema.js +58 -0
- package/dist/implementation/schema.js.map +1 -0
- package/dist/implementation/subscriptionScope.js +19 -1
- package/dist/implementation/subscriptionScope.js.map +1 -1
- package/dist/implementation/symbols.js +5 -0
- package/dist/implementation/symbols.js.map +1 -0
- package/dist/index.js +3 -5
- package/dist/index.js.map +1 -1
- package/dist/internal.js +5 -2
- package/dist/internal.js.map +1 -1
- package/dist/tests/coList.test.js +51 -48
- package/dist/tests/coList.test.js.map +1 -1
- package/dist/tests/coMap.test.js +131 -73
- package/dist/tests/coMap.test.js.map +1 -1
- package/dist/tests/coStream.test.js +56 -41
- package/dist/tests/coStream.test.js.map +1 -1
- package/dist/tests/deepLoading.test.js +188 -0
- package/dist/tests/deepLoading.test.js.map +1 -0
- package/dist/tests/groupsAndAccounts.test.js +83 -0
- package/dist/tests/groupsAndAccounts.test.js.map +1 -0
- package/package.json +17 -9
- package/src/coValues/account.ts +113 -125
- package/src/coValues/coList.ts +87 -103
- package/src/coValues/coMap.ts +200 -147
- package/src/coValues/coStream.ts +264 -80
- package/src/coValues/deepLoading.ts +229 -0
- package/src/coValues/extensions/imageDef.ts +17 -13
- package/src/coValues/group.ts +92 -58
- package/src/coValues/interfaces.ts +215 -115
- package/src/implementation/devtoolsFormatters.ts +110 -0
- package/src/implementation/inspect.ts +1 -1
- package/src/implementation/refs.ts +80 -28
- package/src/implementation/schema.ts +138 -0
- package/src/implementation/subscriptionScope.ts +48 -12
- package/src/implementation/symbols.ts +11 -0
- package/src/index.ts +12 -8
- package/src/internal.ts +7 -3
- package/src/tests/coList.test.ts +77 -62
- package/src/tests/coMap.test.ts +201 -113
- package/src/tests/coStream.test.ts +113 -84
- package/src/tests/deepLoading.test.ts +301 -0
- package/src/tests/groupsAndAccounts.test.ts +91 -0
- package/dist/implementation/encoding.js +0 -26
- package/dist/implementation/encoding.js.map +0 -1
- package/src/implementation/encoding.ts +0 -105
package/src/coValues/coStream.ts
CHANGED
@@ -8,16 +8,16 @@ import type {
|
|
8
8
|
RawCoStream,
|
9
9
|
SessionID,
|
10
10
|
} from "cojson";
|
11
|
-
import { cojsonInternals } from "cojson";
|
11
|
+
import { MAX_RECOMMENDED_TX_SIZE, cojsonInternals } from "cojson";
|
12
12
|
import type {
|
13
13
|
CoValue,
|
14
|
-
|
15
|
-
|
16
|
-
EncodingFor,
|
14
|
+
Schema,
|
15
|
+
SchemaFor,
|
17
16
|
Group,
|
18
17
|
ID,
|
19
|
-
|
20
|
-
|
18
|
+
IfCo,
|
19
|
+
ClassOf,
|
20
|
+
UnCo,
|
21
21
|
} from "../internal.js";
|
22
22
|
import {
|
23
23
|
ItemsSym,
|
@@ -25,46 +25,52 @@ import {
|
|
25
25
|
CoValueBase,
|
26
26
|
Ref,
|
27
27
|
inspect,
|
28
|
-
|
28
|
+
co,
|
29
29
|
InitValues,
|
30
30
|
SchemaInit,
|
31
|
+
isRefEncoded,
|
31
32
|
} from "../internal.js";
|
32
|
-
import {
|
33
|
+
import { encodeSync, decodeSync } from "@effect/schema/Schema";
|
33
34
|
|
34
|
-
export type CoStreamEntry<Item> = {
|
35
|
+
export type CoStreamEntry<Item> = SingleCoStreamEntry<Item> & {
|
36
|
+
all: IterableIterator<SingleCoStreamEntry<Item>>;
|
37
|
+
};
|
38
|
+
|
39
|
+
export type SingleCoStreamEntry<Item> = {
|
35
40
|
value: NonNullable<Item> extends CoValue ? NonNullable<Item> | null : Item;
|
36
|
-
ref
|
37
|
-
by?: Account;
|
41
|
+
ref: NonNullable<Item> extends CoValue ? Ref<NonNullable<Item>> : never;
|
42
|
+
by?: Account | null;
|
38
43
|
madeAt: Date;
|
39
44
|
tx: CojsonInternalTypes.TransactionID;
|
40
45
|
};
|
41
46
|
|
42
|
-
|
47
|
+
/** @category CoValues */
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
49
|
+
export class CoStream<Item = any>
|
43
50
|
extends CoValueBase
|
44
51
|
implements CoValue<"CoStream", RawCoStream>
|
45
52
|
{
|
46
|
-
static Of<Item
|
47
|
-
item: IsVal<Item, Item>
|
48
|
-
): typeof CoStream<Item> {
|
53
|
+
static Of<Item>(item: IfCo<Item, Item>): typeof CoStream<Item> {
|
49
54
|
return class CoStreamOf extends CoStream<Item> {
|
50
|
-
[
|
55
|
+
[co.items] = item;
|
51
56
|
};
|
52
57
|
}
|
53
58
|
|
54
|
-
id
|
55
|
-
_type
|
59
|
+
declare id: ID<this>;
|
60
|
+
declare _type: "CoStream";
|
56
61
|
static {
|
57
62
|
this.prototype._type = "CoStream";
|
58
63
|
}
|
59
|
-
_raw
|
64
|
+
declare _raw: RawCoStream;
|
60
65
|
|
61
66
|
/** @internal This is only a marker type and doesn't exist at runtime */
|
62
67
|
[ItemsSym]!: Item;
|
63
|
-
|
64
|
-
|
65
|
-
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
69
|
+
static _schema: any;
|
70
|
+
get _schema(): {
|
71
|
+
[ItemsSym]: SchemaFor<Item>;
|
66
72
|
} {
|
67
|
-
return (this.constructor as typeof CoStream).
|
73
|
+
return (this.constructor as typeof CoStream)._schema;
|
68
74
|
}
|
69
75
|
|
70
76
|
[key: ID<Account>]: CoStreamEntry<Item>;
|
@@ -76,19 +82,16 @@ export class CoStream<Item extends ValidItem<Item, "CoStream"> = any>
|
|
76
82
|
[key: SessionID]: CoStreamEntry<Item>;
|
77
83
|
};
|
78
84
|
get inCurrentSession(): CoStreamEntry<Item> | undefined {
|
79
|
-
return this.perSession[this._loadedAs.sessionID];
|
85
|
+
return this.perSession[this._loadedAs.sessionID!];
|
80
86
|
}
|
81
87
|
|
82
|
-
|
83
|
-
|
84
|
-
owner: Account | Group;
|
85
|
-
};
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
89
|
+
[InitValues]?: any;
|
86
90
|
|
87
|
-
constructor(_init: undefined, options: { fromRaw: RawCoStream });
|
88
|
-
constructor(init: Item[], options: { owner: Account | Group });
|
89
91
|
constructor(
|
90
|
-
|
91
|
-
|
92
|
+
options:
|
93
|
+
| { init: Item[]; owner: Account | Group }
|
94
|
+
| { fromRaw: RawCoStream },
|
92
95
|
) {
|
93
96
|
super();
|
94
97
|
|
@@ -102,7 +105,7 @@ export class CoStream<Item extends ValidItem<Item, "CoStream"> = any>
|
|
102
105
|
});
|
103
106
|
} else {
|
104
107
|
this[InitValues] = {
|
105
|
-
init,
|
108
|
+
init: options.init,
|
106
109
|
owner: options.owner,
|
107
110
|
};
|
108
111
|
}
|
@@ -110,6 +113,14 @@ export class CoStream<Item extends ValidItem<Item, "CoStream"> = any>
|
|
110
113
|
return new Proxy(this, CoStreamProxyHandler as ProxyHandler<this>);
|
111
114
|
}
|
112
115
|
|
116
|
+
static create<S extends CoStream>(
|
117
|
+
this: ClassOf<S>,
|
118
|
+
init: S extends CoStream<infer Item> ? UnCo<Item>[] : never,
|
119
|
+
options: { owner: Account | Group },
|
120
|
+
) {
|
121
|
+
return new this({ init, owner: options.owner });
|
122
|
+
}
|
123
|
+
|
113
124
|
push(...items: Item[]) {
|
114
125
|
for (const item of items) {
|
115
126
|
this.pushItem(item);
|
@@ -117,24 +128,24 @@ export class CoStream<Item extends ValidItem<Item, "CoStream"> = any>
|
|
117
128
|
}
|
118
129
|
|
119
130
|
private pushItem(item: Item) {
|
120
|
-
const itemDescriptor = this.
|
131
|
+
const itemDescriptor = this._schema[ItemsSym] as Schema;
|
121
132
|
|
122
133
|
if (itemDescriptor === "json") {
|
123
134
|
this._raw.push(item as JsonValue);
|
124
135
|
} else if ("encoded" in itemDescriptor) {
|
125
|
-
this._raw.push(
|
126
|
-
} else if (
|
136
|
+
this._raw.push(encodeSync(itemDescriptor.encoded)(item));
|
137
|
+
} else if (isRefEncoded(itemDescriptor)) {
|
127
138
|
this._raw.push((item as unknown as CoValue).id);
|
128
139
|
}
|
129
140
|
}
|
130
141
|
|
131
142
|
toJSON() {
|
132
|
-
const itemDescriptor = this.
|
143
|
+
const itemDescriptor = this._schema[ItemsSym] as Schema;
|
133
144
|
const mapper =
|
134
145
|
itemDescriptor === "json"
|
135
146
|
? (v: unknown) => v
|
136
147
|
: "encoded" in itemDescriptor
|
137
|
-
?
|
148
|
+
? encodeSync(itemDescriptor.encoded)
|
138
149
|
: (v: unknown) => v && (v as CoValue).id;
|
139
150
|
|
140
151
|
return {
|
@@ -144,13 +155,13 @@ export class CoStream<Item extends ValidItem<Item, "CoStream"> = any>
|
|
144
155
|
Object.entries(this).map(([account, entry]) => [
|
145
156
|
account,
|
146
157
|
mapper(entry.value),
|
147
|
-
])
|
158
|
+
]),
|
148
159
|
),
|
149
160
|
in: Object.fromEntries(
|
150
161
|
Object.entries(this.perSession).map(([session, entry]) => [
|
151
162
|
session,
|
152
163
|
mapper(entry.value),
|
153
|
-
])
|
164
|
+
]),
|
154
165
|
),
|
155
166
|
};
|
156
167
|
}
|
@@ -159,12 +170,13 @@ export class CoStream<Item extends ValidItem<Item, "CoStream"> = any>
|
|
159
170
|
return this.toJSON();
|
160
171
|
}
|
161
172
|
|
162
|
-
static
|
173
|
+
static schema<V extends CoStream>(
|
174
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
163
175
|
this: { new (...args: any): V } & typeof CoStream,
|
164
|
-
def: { [ItemsSym]: V["
|
176
|
+
def: { [ItemsSym]: V["_schema"][ItemsSym] },
|
165
177
|
) {
|
166
|
-
this.
|
167
|
-
Object.assign(this.
|
178
|
+
this._schema ||= {};
|
179
|
+
Object.assign(this._schema, def);
|
168
180
|
}
|
169
181
|
}
|
170
182
|
|
@@ -176,38 +188,64 @@ function entryFromRawEntry<Item>(
|
|
176
188
|
at: Date;
|
177
189
|
value: JsonValue;
|
178
190
|
},
|
179
|
-
loadedAs: Account
|
191
|
+
loadedAs: Account,
|
180
192
|
accountID: ID<Account> | undefined,
|
181
|
-
itemField:
|
182
|
-
) {
|
193
|
+
itemField: Schema,
|
194
|
+
): Omit<CoStreamEntry<Item>, "all"> {
|
183
195
|
return {
|
184
|
-
get value(): Item
|
196
|
+
get value(): NonNullable<Item> extends CoValue
|
197
|
+
? (CoValue & Item) | null
|
198
|
+
: Item {
|
185
199
|
if (itemField === "json") {
|
186
|
-
return rawEntry.value as Item
|
200
|
+
return rawEntry.value as NonNullable<Item> extends CoValue
|
201
|
+
? (CoValue & Item) | null
|
202
|
+
: Item;
|
187
203
|
} else if ("encoded" in itemField) {
|
188
|
-
return
|
189
|
-
} else if (
|
190
|
-
return this.ref?.accessFrom(
|
204
|
+
return decodeSync(itemField.encoded)(rawEntry.value);
|
205
|
+
} else if (isRefEncoded(itemField)) {
|
206
|
+
return this.ref?.accessFrom(
|
207
|
+
accessFrom,
|
208
|
+
rawEntry.by +
|
209
|
+
rawEntry.tx.sessionID +
|
210
|
+
rawEntry.tx.txIndex +
|
211
|
+
".value",
|
212
|
+
) as NonNullable<Item> extends CoValue
|
213
|
+
? (CoValue & Item) | null
|
214
|
+
: Item;
|
215
|
+
} else {
|
216
|
+
throw new Error("Invalid item field schema");
|
191
217
|
}
|
192
218
|
},
|
193
|
-
get ref()
|
194
|
-
|
219
|
+
get ref(): NonNullable<Item> extends CoValue
|
220
|
+
? Ref<NonNullable<Item>>
|
221
|
+
: never {
|
222
|
+
if (itemField !== "json" && isRefEncoded(itemField)) {
|
195
223
|
const rawId = rawEntry.value;
|
196
224
|
return new Ref(
|
197
225
|
rawId as unknown as ID<CoValue>,
|
198
226
|
loadedAs,
|
199
|
-
itemField
|
200
|
-
)
|
227
|
+
itemField,
|
228
|
+
) as NonNullable<Item> extends CoValue
|
229
|
+
? Ref<NonNullable<Item>>
|
230
|
+
: never;
|
231
|
+
} else {
|
232
|
+
return undefined as never;
|
201
233
|
}
|
202
234
|
},
|
203
235
|
get by() {
|
204
236
|
return (
|
205
237
|
accountID &&
|
206
|
-
new Ref(
|
238
|
+
new Ref<Account>(
|
207
239
|
accountID as unknown as ID<Account>,
|
208
240
|
loadedAs,
|
209
|
-
{ref:
|
210
|
-
)?.accessFrom(
|
241
|
+
{ ref: Account, optional: false },
|
242
|
+
)?.accessFrom(
|
243
|
+
accessFrom,
|
244
|
+
rawEntry.by +
|
245
|
+
rawEntry.tx.sessionID +
|
246
|
+
rawEntry.tx.txIndex +
|
247
|
+
".by",
|
248
|
+
)
|
211
249
|
);
|
212
250
|
},
|
213
251
|
madeAt: rawEntry.at,
|
@@ -242,15 +280,40 @@ export const CoStreamProxyHandler: ProxyHandler<CoStream> = {
|
|
242
280
|
const rawEntry = target._raw.lastItemBy(key as AccountID);
|
243
281
|
|
244
282
|
if (!rawEntry) return;
|
245
|
-
|
283
|
+
const entry = entryFromRawEntry(
|
246
284
|
receiver,
|
247
285
|
rawEntry,
|
248
286
|
target._loadedAs,
|
249
287
|
key as unknown as ID<Account>,
|
250
|
-
target.
|
288
|
+
target._schema[ItemsSym],
|
251
289
|
);
|
290
|
+
|
291
|
+
Object.defineProperty(entry, "all", {
|
292
|
+
get: () => {
|
293
|
+
const allRawEntries = target._raw.itemsBy(key as AccountID);
|
294
|
+
return (function* () {
|
295
|
+
while (true) {
|
296
|
+
const rawEntry = allRawEntries.next();
|
297
|
+
if (rawEntry.done) return;
|
298
|
+
yield entryFromRawEntry(
|
299
|
+
receiver,
|
300
|
+
rawEntry.value,
|
301
|
+
target._loadedAs,
|
302
|
+
key as unknown as ID<Account>,
|
303
|
+
target._schema[ItemsSym],
|
304
|
+
);
|
305
|
+
}
|
306
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
307
|
+
})() satisfies IterableIterator<SingleCoStreamEntry<any>>;
|
308
|
+
},
|
309
|
+
});
|
310
|
+
|
311
|
+
return entry;
|
252
312
|
} else if (key === "perSession") {
|
253
|
-
return new Proxy(
|
313
|
+
return new Proxy(
|
314
|
+
{},
|
315
|
+
CoStreamPerSessionProxyHandler(target, receiver),
|
316
|
+
);
|
254
317
|
} else {
|
255
318
|
return Reflect.get(target, key, receiver);
|
256
319
|
}
|
@@ -261,8 +324,8 @@ export const CoStreamProxyHandler: ProxyHandler<CoStream> = {
|
|
261
324
|
typeof value === "object" &&
|
262
325
|
SchemaInit in value
|
263
326
|
) {
|
264
|
-
(target.constructor as typeof CoStream).
|
265
|
-
(target.constructor as typeof CoStream).
|
327
|
+
(target.constructor as typeof CoStream)._schema ||= {};
|
328
|
+
(target.constructor as typeof CoStream)._schema[ItemsSym] =
|
266
329
|
value[SchemaInit];
|
267
330
|
init(target);
|
268
331
|
return true;
|
@@ -277,8 +340,8 @@ export const CoStreamProxyHandler: ProxyHandler<CoStream> = {
|
|
277
340
|
typeof descriptor.value === "object" &&
|
278
341
|
SchemaInit in descriptor.value
|
279
342
|
) {
|
280
|
-
(target.constructor as typeof CoStream).
|
281
|
-
(target.constructor as typeof CoStream).
|
343
|
+
(target.constructor as typeof CoStream)._schema ||= {};
|
344
|
+
(target.constructor as typeof CoStream)._schema[ItemsSym] =
|
282
345
|
descriptor.value[SchemaInit];
|
283
346
|
init(target);
|
284
347
|
return true;
|
@@ -308,46 +371,88 @@ export const CoStreamProxyHandler: ProxyHandler<CoStream> = {
|
|
308
371
|
},
|
309
372
|
};
|
310
373
|
|
311
|
-
const CoStreamPerSessionProxyHandler
|
312
|
-
|
374
|
+
const CoStreamPerSessionProxyHandler = (
|
375
|
+
innerTarget: CoStream,
|
376
|
+
accessFrom: CoStream,
|
377
|
+
): ProxyHandler<Record<string, never>> => ({
|
378
|
+
get(_target, key, receiver) {
|
313
379
|
if (typeof key === "string" && key.includes("session")) {
|
314
380
|
const sessionID = key as SessionID;
|
315
|
-
const rawEntry =
|
381
|
+
const rawEntry = innerTarget._raw.lastItemIn(sessionID);
|
316
382
|
|
317
383
|
if (!rawEntry) return;
|
318
384
|
const by = cojsonInternals.accountOrAgentIDfromSessionID(sessionID);
|
319
|
-
|
320
|
-
|
385
|
+
|
386
|
+
const entry = entryFromRawEntry(
|
387
|
+
accessFrom,
|
321
388
|
rawEntry,
|
322
|
-
|
389
|
+
innerTarget._loadedAs,
|
323
390
|
cojsonInternals.isAccountID(by)
|
324
391
|
? (by as unknown as ID<Account>)
|
325
392
|
: undefined,
|
326
|
-
|
393
|
+
innerTarget._schema[ItemsSym],
|
327
394
|
);
|
395
|
+
|
396
|
+
Object.defineProperty(entry, "all", {
|
397
|
+
get: () => {
|
398
|
+
const allRawEntries = innerTarget._raw.itemsIn(sessionID);
|
399
|
+
return (function* () {
|
400
|
+
while (true) {
|
401
|
+
const rawEntry = allRawEntries.next();
|
402
|
+
if (rawEntry.done) return;
|
403
|
+
yield entryFromRawEntry(
|
404
|
+
accessFrom,
|
405
|
+
rawEntry.value,
|
406
|
+
innerTarget._loadedAs,
|
407
|
+
cojsonInternals.isAccountID(by)
|
408
|
+
? (by as unknown as ID<Account>)
|
409
|
+
: undefined,
|
410
|
+
innerTarget._schema[ItemsSym],
|
411
|
+
);
|
412
|
+
}
|
413
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
414
|
+
})() satisfies IterableIterator<SingleCoStreamEntry<any>>;
|
415
|
+
},
|
416
|
+
});
|
417
|
+
|
418
|
+
return entry;
|
328
419
|
} else {
|
329
|
-
return Reflect.get(
|
420
|
+
return Reflect.get(innerTarget, key, receiver);
|
330
421
|
}
|
331
422
|
},
|
332
|
-
|
423
|
+
ownKeys() {
|
424
|
+
return innerTarget._raw.sessions();
|
425
|
+
},
|
426
|
+
getOwnPropertyDescriptor(target, key) {
|
427
|
+
if (typeof key === "string" && key.startsWith("co_")) {
|
428
|
+
return {
|
429
|
+
configurable: true,
|
430
|
+
enumerable: true,
|
431
|
+
writable: false,
|
432
|
+
};
|
433
|
+
} else {
|
434
|
+
return Reflect.getOwnPropertyDescriptor(target, key);
|
435
|
+
}
|
436
|
+
},
|
437
|
+
});
|
333
438
|
|
439
|
+
/** @category CoValues */
|
334
440
|
export class BinaryCoStream
|
335
441
|
extends CoValueBase
|
336
442
|
implements CoValue<"BinaryCoStream", RawBinaryCoStream>
|
337
443
|
{
|
338
|
-
id
|
339
|
-
_type
|
340
|
-
_raw
|
444
|
+
declare id: ID<this>;
|
445
|
+
declare _type: "BinaryCoStream";
|
446
|
+
declare _raw: RawBinaryCoStream;
|
341
447
|
|
342
448
|
constructor(
|
343
|
-
init: [] | undefined,
|
344
449
|
options:
|
345
450
|
| {
|
346
451
|
owner: Account | Group;
|
347
452
|
}
|
348
453
|
| {
|
349
454
|
fromRaw: RawBinaryCoStream;
|
350
|
-
}
|
455
|
+
},
|
351
456
|
) {
|
352
457
|
super();
|
353
458
|
|
@@ -365,10 +470,18 @@ export class BinaryCoStream
|
|
365
470
|
value: raw.id,
|
366
471
|
enumerable: false,
|
367
472
|
},
|
473
|
+
_type: { value: "BinaryCoStream", enumerable: false },
|
368
474
|
_raw: { value: raw, enumerable: false },
|
369
475
|
});
|
370
476
|
}
|
371
477
|
|
478
|
+
static create<S extends BinaryCoStream>(
|
479
|
+
this: ClassOf<S>,
|
480
|
+
options: { owner: Account | Group },
|
481
|
+
) {
|
482
|
+
return new this(options);
|
483
|
+
}
|
484
|
+
|
372
485
|
getChunks(options?: {
|
373
486
|
allowUnfinished?: boolean;
|
374
487
|
}):
|
@@ -389,6 +502,77 @@ export class BinaryCoStream
|
|
389
502
|
this._raw.endBinaryStream();
|
390
503
|
}
|
391
504
|
|
505
|
+
toBlob(options?: { allowUnfinished?: boolean }): Blob | undefined {
|
506
|
+
const chunks = this.getChunks({
|
507
|
+
allowUnfinished: options?.allowUnfinished,
|
508
|
+
});
|
509
|
+
|
510
|
+
if (!chunks) {
|
511
|
+
return undefined;
|
512
|
+
}
|
513
|
+
|
514
|
+
return new Blob(chunks.chunks, { type: chunks.mimeType });
|
515
|
+
}
|
516
|
+
|
517
|
+
static async loadAsBlob(
|
518
|
+
id: ID<BinaryCoStream>,
|
519
|
+
as: Account,
|
520
|
+
options?: {
|
521
|
+
allowUnfinished?: boolean;
|
522
|
+
},
|
523
|
+
): Promise<Blob | undefined> {
|
524
|
+
const stream = await this.load(id, as, []);
|
525
|
+
|
526
|
+
return stream?.toBlob({
|
527
|
+
allowUnfinished: options?.allowUnfinished,
|
528
|
+
});
|
529
|
+
}
|
530
|
+
|
531
|
+
static async createFromBlob(
|
532
|
+
blob: Blob | File,
|
533
|
+
options: {
|
534
|
+
owner: Group | Account;
|
535
|
+
onProgress?: (progress: number) => void;
|
536
|
+
},
|
537
|
+
): Promise<BinaryCoStream> {
|
538
|
+
const stream = this.create({ owner: options.owner });
|
539
|
+
|
540
|
+
const start = Date.now();
|
541
|
+
|
542
|
+
const data = new Uint8Array(await blob.arrayBuffer());
|
543
|
+
stream.start({
|
544
|
+
mimeType: blob.type,
|
545
|
+
totalSizeBytes: blob.size,
|
546
|
+
fileName: blob instanceof File ? blob.name : undefined,
|
547
|
+
});
|
548
|
+
const chunkSize = MAX_RECOMMENDED_TX_SIZE;
|
549
|
+
|
550
|
+
let lastProgressUpdate = Date.now();
|
551
|
+
|
552
|
+
for (let idx = 0; idx < data.length; idx += chunkSize) {
|
553
|
+
stream.push(data.slice(idx, idx + chunkSize));
|
554
|
+
|
555
|
+
if (Date.now() - lastProgressUpdate > 100) {
|
556
|
+
options.onProgress?.(idx / data.length);
|
557
|
+
lastProgressUpdate = Date.now();
|
558
|
+
}
|
559
|
+
|
560
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
561
|
+
}
|
562
|
+
stream.end();
|
563
|
+
const end = Date.now();
|
564
|
+
|
565
|
+
console.debug(
|
566
|
+
"Finished creating binary stream in",
|
567
|
+
(end - start) / 1000,
|
568
|
+
"s - Throughput in MB/s",
|
569
|
+
(1000 * (blob.size / (end - start))) / (1024 * 1024),
|
570
|
+
);
|
571
|
+
options.onProgress?.(1);
|
572
|
+
|
573
|
+
return stream;
|
574
|
+
}
|
575
|
+
|
392
576
|
toJSON() {
|
393
577
|
return {
|
394
578
|
id: this.id,
|