jazz-tools 0.11.5 → 0.11.6
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/.turbo/turbo-build.log +5 -5
- package/CHANGELOG.md +8 -0
- package/dist/{chunk-IOK4K3XC.js → chunk-2LO7CLFD.js} +13 -9
- package/dist/{chunk-IOK4K3XC.js.map → chunk-2LO7CLFD.js.map} +1 -1
- package/dist/coValues/extensions/imageDef.d.ts +1 -0
- package/dist/coValues/extensions/imageDef.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/testing.js +1 -1
- package/dist/tests/imageDef.test.d.ts +2 -0
- package/dist/tests/imageDef.test.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/coValues/extensions/imageDef.ts +22 -15
- package/src/tests/coFeed.test.ts +32 -0
- package/src/tests/imageDef.test.ts +269 -0
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"imageDef.d.ts","sourceRoot":"","sources":["../../../src/coValues/extensions/imageDef.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAuB,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,sBAAsB;AACtB,qBAAa,eAAgB,SAAQ,KAAK;IACxC,YAAY,uBAA+B;IAC3C,kBAAkB,CAAC,yBAAa;IAEhC,CAAC,EAAE,CAAC,KAAK,CAAC,wBAAsB;IAChC,CAAC,GAAG,EAAE,GAAG,MAAM,IAAI,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAEpD,mBAAmB,CAAC,OAAO,CAAC,EAAE;QAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;
|
1
|
+
{"version":3,"file":"imageDef.d.ts","sourceRoot":"","sources":["../../../src/coValues/extensions/imageDef.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAuB,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEpC,sBAAsB;AACtB,qBAAa,eAAgB,SAAQ,KAAK;IACxC,YAAY,uBAA+B;IAC3C,kBAAkB,CAAC,yBAAa;IAEhC,CAAC,EAAE,CAAC,KAAK,CAAC,wBAAsB;IAChC,CAAC,GAAG,EAAE,GAAG,MAAM,IAAI,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAEpD,mBAAmB,CAAC,OAAO,CAAC,EAAE;QAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,GAAG;QAAE,GAAG,EAAE,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,GAAG,SAAS;CA+CnE"}
|
package/dist/index.js
CHANGED
package/dist/testing.js
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"imageDef.test.d.ts","sourceRoot":"","sources":["../../src/tests/imageDef.test.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
@@ -17,11 +17,11 @@
|
|
17
17
|
},
|
18
18
|
"type": "module",
|
19
19
|
"license": "MIT",
|
20
|
-
"version": "0.11.
|
20
|
+
"version": "0.11.6",
|
21
21
|
"dependencies": {
|
22
22
|
"@scure/bip39": "^1.3.0",
|
23
23
|
"fast-myers-diff": "^3.2.0",
|
24
|
-
"cojson": "0.11.
|
24
|
+
"cojson": "0.11.6"
|
25
25
|
},
|
26
26
|
"devDependencies": {
|
27
27
|
"tsup": "8.3.5",
|
@@ -12,6 +12,7 @@ export class ImageDefinition extends CoMap {
|
|
12
12
|
|
13
13
|
highestResAvailable(options?: {
|
14
14
|
maxWidth?: number;
|
15
|
+
targetWidth?: number;
|
15
16
|
}): { res: `${number}x${number}`; stream: FileStream } | undefined {
|
16
17
|
if (!subscriptionsScopes.get(this)) {
|
17
18
|
console.warn(
|
@@ -19,33 +20,39 @@ export class ImageDefinition extends CoMap {
|
|
19
20
|
);
|
20
21
|
}
|
21
22
|
|
22
|
-
const resolutions = Object.keys(this).filter(
|
23
|
-
(
|
24
|
-
key.match(/^\d+x\d+$/) &&
|
25
|
-
(options?.maxWidth === undefined ||
|
26
|
-
Number(key.split("x")[0]) <= options.maxWidth),
|
23
|
+
const resolutions = Object.keys(this).filter((key) =>
|
24
|
+
key.match(/^\d+x\d+$/),
|
27
25
|
) as `${number}x${number}`[];
|
28
26
|
|
29
|
-
|
27
|
+
let maxWidth = options?.maxWidth;
|
28
|
+
|
29
|
+
if (options?.targetWidth) {
|
30
|
+
const targetWidth = options.targetWidth;
|
31
|
+
const widths = resolutions.map((res) => Number(res.split("x")[0]));
|
32
|
+
|
33
|
+
maxWidth = Math.min(...widths.filter((w) => w >= targetWidth));
|
34
|
+
}
|
35
|
+
|
36
|
+
const validResolutions = resolutions.filter(
|
37
|
+
(key) => maxWidth === undefined || Number(key.split("x")[0]) <= maxWidth,
|
38
|
+
) as `${number}x${number}`[];
|
39
|
+
|
40
|
+
// Sort the resolutions by width, smallest to largest
|
41
|
+
validResolutions.sort((a, b) => {
|
30
42
|
const aWidth = Number(a.split("x")[0]);
|
31
43
|
const bWidth = Number(b.split("x")[0]);
|
32
|
-
return aWidth - bWidth;
|
44
|
+
return aWidth - bWidth; // Sort smallest to largest
|
33
45
|
});
|
34
46
|
|
35
47
|
let highestAvailableResolution: `${number}x${number}` | undefined;
|
36
48
|
|
37
|
-
for (const resolution of
|
49
|
+
for (const resolution of validResolutions) {
|
38
50
|
if (this[resolution] && this[resolution]?.getChunks()) {
|
39
51
|
highestAvailableResolution = resolution;
|
40
|
-
} else {
|
41
|
-
return (
|
42
|
-
highestAvailableResolution && {
|
43
|
-
res: highestAvailableResolution,
|
44
|
-
stream: this[highestAvailableResolution]!,
|
45
|
-
}
|
46
|
-
);
|
47
52
|
}
|
48
53
|
}
|
54
|
+
|
55
|
+
// Return the highest complete resolution if we found one
|
49
56
|
return (
|
50
57
|
highestAvailableResolution && {
|
51
58
|
res: highestAvailableResolution,
|
package/src/tests/coFeed.test.ts
CHANGED
@@ -470,6 +470,38 @@ describe("FileStream.loadAsBlob", async () => {
|
|
470
470
|
});
|
471
471
|
});
|
472
472
|
|
473
|
+
describe("FileStream progress tracking", async () => {
|
474
|
+
test("createFromBlob should report upload progress correctly", async () => {
|
475
|
+
// Create 5MB test blob
|
476
|
+
const testData = new Uint8Array(5 * 1024 * 1024); // 5MB instead of 500KB
|
477
|
+
for (let i = 0; i < testData.length; i++) testData[i] = i % 256;
|
478
|
+
const testBlob = new Blob([testData]);
|
479
|
+
|
480
|
+
// Collect progress updates
|
481
|
+
const progressUpdates: number[] = [];
|
482
|
+
await FileStream.createFromBlob(testBlob, {
|
483
|
+
onProgress: (progress) => progressUpdates.push(progress),
|
484
|
+
});
|
485
|
+
|
486
|
+
// Verify progress reporting
|
487
|
+
expect(progressUpdates.length).toBeGreaterThan(1);
|
488
|
+
|
489
|
+
// Check values between 0-1, increasing, with final=1
|
490
|
+
progressUpdates.forEach((p) => {
|
491
|
+
expect(p).toBeGreaterThanOrEqual(0);
|
492
|
+
expect(p).toBeLessThanOrEqual(1);
|
493
|
+
});
|
494
|
+
|
495
|
+
for (let i = 1; i < progressUpdates.length; i++) {
|
496
|
+
expect(progressUpdates[i]!).toBeGreaterThanOrEqual(
|
497
|
+
progressUpdates[i - 1]!,
|
498
|
+
);
|
499
|
+
}
|
500
|
+
|
501
|
+
expect(progressUpdates[progressUpdates.length - 1]).toBe(1);
|
502
|
+
});
|
503
|
+
});
|
504
|
+
|
473
505
|
describe("waitForSync", async () => {
|
474
506
|
test("CoFeed: should resolve when the value is uploaded", async () => {
|
475
507
|
class TestStream extends CoFeed.Of(co.string) {}
|
@@ -0,0 +1,269 @@
|
|
1
|
+
import { WasmCrypto } from "cojson/crypto/WasmCrypto";
|
2
|
+
import { describe, expect, test } from "vitest";
|
3
|
+
import { Account, FileStream, ImageDefinition, co } from "../exports.js";
|
4
|
+
|
5
|
+
const Crypto = await WasmCrypto.create();
|
6
|
+
|
7
|
+
describe("ImageDefinition", async () => {
|
8
|
+
const me = await Account.create({
|
9
|
+
creationProps: { name: "Test User" },
|
10
|
+
crypto: Crypto,
|
11
|
+
});
|
12
|
+
|
13
|
+
test("Construction with basic properties", () => {
|
14
|
+
const imageDef = ImageDefinition.create(
|
15
|
+
{
|
16
|
+
originalSize: [1920, 1080],
|
17
|
+
placeholderDataURL: "data:image/jpeg;base64,...",
|
18
|
+
},
|
19
|
+
{ owner: me },
|
20
|
+
);
|
21
|
+
|
22
|
+
expect(imageDef.originalSize).toEqual([1920, 1080]);
|
23
|
+
expect(imageDef.placeholderDataURL).toBe("data:image/jpeg;base64,...");
|
24
|
+
});
|
25
|
+
|
26
|
+
test("highestResAvailable with no resolutions", () => {
|
27
|
+
const imageDef = ImageDefinition.create(
|
28
|
+
{
|
29
|
+
originalSize: [1920, 1080],
|
30
|
+
},
|
31
|
+
{ owner: me },
|
32
|
+
);
|
33
|
+
|
34
|
+
const result = imageDef.highestResAvailable();
|
35
|
+
expect(result).toBeUndefined();
|
36
|
+
});
|
37
|
+
|
38
|
+
test("highestResAvailable with single resolution", () => {
|
39
|
+
const imageDef = ImageDefinition.create(
|
40
|
+
{
|
41
|
+
originalSize: [1920, 1080],
|
42
|
+
},
|
43
|
+
{ owner: me },
|
44
|
+
);
|
45
|
+
|
46
|
+
const stream = FileStream.create({ owner: me });
|
47
|
+
stream.start({ mimeType: "image/jpeg" });
|
48
|
+
stream.push(new Uint8Array([1, 2, 3]));
|
49
|
+
stream.end();
|
50
|
+
|
51
|
+
imageDef["1920x1080"] = stream;
|
52
|
+
|
53
|
+
const result = imageDef.highestResAvailable();
|
54
|
+
expect(result).toBeDefined();
|
55
|
+
expect(result?.res).toBe("1920x1080");
|
56
|
+
expect(result?.stream).toStrictEqual(stream);
|
57
|
+
});
|
58
|
+
|
59
|
+
test("highestResAvailable with multiple resolutions", () => {
|
60
|
+
const imageDef = ImageDefinition.create(
|
61
|
+
{
|
62
|
+
originalSize: [1920, 1080],
|
63
|
+
},
|
64
|
+
{ owner: me },
|
65
|
+
);
|
66
|
+
|
67
|
+
const stream1 = FileStream.create({ owner: me });
|
68
|
+
stream1.start({ mimeType: "image/jpeg" });
|
69
|
+
stream1.push(new Uint8Array([1, 2, 3]));
|
70
|
+
stream1.end();
|
71
|
+
|
72
|
+
const stream2 = FileStream.create({ owner: me });
|
73
|
+
stream2.start({ mimeType: "image/jpeg" });
|
74
|
+
stream2.push(new Uint8Array([4, 5, 6]));
|
75
|
+
stream2.end();
|
76
|
+
|
77
|
+
imageDef["1920x1080"] = stream1;
|
78
|
+
imageDef["1280x720"] = stream2;
|
79
|
+
|
80
|
+
const result = imageDef.highestResAvailable();
|
81
|
+
expect(result).toBeDefined();
|
82
|
+
expect(result?.res).toBe("1920x1080");
|
83
|
+
expect(result?.stream).toStrictEqual(stream1);
|
84
|
+
});
|
85
|
+
|
86
|
+
test("highestResAvailable with maxWidth option", () => {
|
87
|
+
const imageDef = ImageDefinition.create(
|
88
|
+
{
|
89
|
+
originalSize: [1920, 1080],
|
90
|
+
},
|
91
|
+
{ owner: me },
|
92
|
+
);
|
93
|
+
|
94
|
+
const stream1 = FileStream.create({ owner: me });
|
95
|
+
stream1.start({ mimeType: "image/jpeg" });
|
96
|
+
stream1.push(new Uint8Array([1, 2, 3]));
|
97
|
+
stream1.end();
|
98
|
+
|
99
|
+
const stream2 = FileStream.create({ owner: me });
|
100
|
+
stream2.start({ mimeType: "image/jpeg" });
|
101
|
+
stream2.push(new Uint8Array([4, 5, 6]));
|
102
|
+
stream2.end();
|
103
|
+
|
104
|
+
imageDef["1920x1080"] = stream1;
|
105
|
+
imageDef["1280x720"] = stream2;
|
106
|
+
|
107
|
+
const result = imageDef.highestResAvailable({ maxWidth: 1500 });
|
108
|
+
expect(result).toBeDefined();
|
109
|
+
expect(result?.res).toBe("1280x720");
|
110
|
+
expect(result?.stream).toStrictEqual(stream2);
|
111
|
+
});
|
112
|
+
|
113
|
+
test("highestResAvailable with missing chunks", () => {
|
114
|
+
const imageDef = ImageDefinition.create(
|
115
|
+
{
|
116
|
+
originalSize: [1920, 1080],
|
117
|
+
},
|
118
|
+
{ owner: me },
|
119
|
+
);
|
120
|
+
|
121
|
+
const stream1 = FileStream.create({ owner: me });
|
122
|
+
stream1.start({ mimeType: "image/jpeg" });
|
123
|
+
stream1.push(new Uint8Array([1, 2, 3]));
|
124
|
+
stream1.end();
|
125
|
+
|
126
|
+
const stream2 = FileStream.create({ owner: me });
|
127
|
+
stream2.start({ mimeType: "image/jpeg" });
|
128
|
+
// Don't end stream2, so it has no chunks
|
129
|
+
|
130
|
+
imageDef["1920x1080"] = stream1;
|
131
|
+
imageDef["1280x720"] = stream2;
|
132
|
+
|
133
|
+
const result = imageDef.highestResAvailable();
|
134
|
+
expect(result).toBeDefined();
|
135
|
+
expect(result?.res).toBe("1920x1080");
|
136
|
+
expect(result?.stream).toStrictEqual(stream1);
|
137
|
+
});
|
138
|
+
|
139
|
+
test("highestResAvailable with missing chunks in middle stream", () => {
|
140
|
+
const imageDef = ImageDefinition.create(
|
141
|
+
{
|
142
|
+
originalSize: [1920, 1080],
|
143
|
+
},
|
144
|
+
{ owner: me },
|
145
|
+
);
|
146
|
+
|
147
|
+
const stream1 = FileStream.create({ owner: me });
|
148
|
+
stream1.start({ mimeType: "image/jpeg" });
|
149
|
+
stream1.push(new Uint8Array([1, 2, 3]));
|
150
|
+
stream1.end();
|
151
|
+
|
152
|
+
const stream2 = FileStream.create({ owner: me });
|
153
|
+
stream2.start({ mimeType: "image/jpeg" });
|
154
|
+
// Don't end stream2, so it has no chunks
|
155
|
+
|
156
|
+
const stream3 = FileStream.create({ owner: me });
|
157
|
+
stream3.start({ mimeType: "image/jpeg" });
|
158
|
+
stream3.push(new Uint8Array([7, 8, 9]));
|
159
|
+
stream3.end();
|
160
|
+
|
161
|
+
imageDef["1920x1080"] = stream1;
|
162
|
+
imageDef["1280x720"] = stream2;
|
163
|
+
imageDef["1024x576"] = stream3;
|
164
|
+
|
165
|
+
const result = imageDef.highestResAvailable();
|
166
|
+
expect(result).toBeDefined();
|
167
|
+
expect(result?.res).toBe("1920x1080");
|
168
|
+
expect(result?.stream).toStrictEqual(stream1);
|
169
|
+
});
|
170
|
+
|
171
|
+
test("highestResAvailable with non-resolution keys", () => {
|
172
|
+
const imageDef = ImageDefinition.create(
|
173
|
+
{
|
174
|
+
originalSize: [1920, 1080],
|
175
|
+
},
|
176
|
+
{ owner: me },
|
177
|
+
);
|
178
|
+
|
179
|
+
const stream = FileStream.create({ owner: me });
|
180
|
+
stream.start({ mimeType: "image/jpeg" });
|
181
|
+
stream.push(new Uint8Array([1, 2, 3]));
|
182
|
+
stream.end();
|
183
|
+
|
184
|
+
// @ts-expect-error - Testing invalid key
|
185
|
+
imageDef["invalid-key"] = stream;
|
186
|
+
|
187
|
+
const result = imageDef.highestResAvailable();
|
188
|
+
expect(result).toBeUndefined();
|
189
|
+
});
|
190
|
+
|
191
|
+
test("highestResAvailable with targetWidth option", () => {
|
192
|
+
const imageDef = ImageDefinition.create(
|
193
|
+
{
|
194
|
+
originalSize: [1920, 1080],
|
195
|
+
},
|
196
|
+
{ owner: me },
|
197
|
+
);
|
198
|
+
|
199
|
+
const stream1 = FileStream.create({ owner: me });
|
200
|
+
stream1.start({ mimeType: "image/jpeg" });
|
201
|
+
stream1.push(new Uint8Array([1, 2, 3]));
|
202
|
+
stream1.end();
|
203
|
+
|
204
|
+
const stream2 = FileStream.create({ owner: me });
|
205
|
+
stream2.start({ mimeType: "image/jpeg" });
|
206
|
+
stream2.push(new Uint8Array([4, 5, 6]));
|
207
|
+
stream2.end();
|
208
|
+
|
209
|
+
const stream3 = FileStream.create({ owner: me });
|
210
|
+
stream3.start({ mimeType: "image/jpeg" });
|
211
|
+
stream3.push(new Uint8Array([7, 8, 9]));
|
212
|
+
stream3.end();
|
213
|
+
|
214
|
+
imageDef["1920x1080"] = stream1;
|
215
|
+
imageDef["1280x720"] = stream2;
|
216
|
+
imageDef["800x450"] = stream3;
|
217
|
+
|
218
|
+
// Should return 1280x720 as it's the smallest resolution >= 1000px
|
219
|
+
const result1 = imageDef.highestResAvailable({ targetWidth: 1000 });
|
220
|
+
expect(result1).toBeDefined();
|
221
|
+
expect(result1?.res).toBe("1280x720");
|
222
|
+
expect(result1?.stream).toStrictEqual(stream2);
|
223
|
+
|
224
|
+
// Should return 800x450 as it's the smallest resolution >= 700px
|
225
|
+
const result2 = imageDef.highestResAvailable({ targetWidth: 700 });
|
226
|
+
expect(result2).toBeDefined();
|
227
|
+
expect(result2?.res).toBe("800x450");
|
228
|
+
expect(result2?.stream).toStrictEqual(stream3);
|
229
|
+
|
230
|
+
// Should return 1920x1080 as it's the smallest resolution >= 1500px
|
231
|
+
const result3 = imageDef.highestResAvailable({ targetWidth: 1500 });
|
232
|
+
expect(result3).toBeDefined();
|
233
|
+
expect(result3?.res).toBe("1920x1080");
|
234
|
+
expect(result3?.stream).toStrictEqual(stream1);
|
235
|
+
});
|
236
|
+
|
237
|
+
test("highestResAvailable with targetWidth and incomplete streams", () => {
|
238
|
+
const imageDef = ImageDefinition.create(
|
239
|
+
{
|
240
|
+
originalSize: [1920, 1080],
|
241
|
+
},
|
242
|
+
{ owner: me },
|
243
|
+
);
|
244
|
+
|
245
|
+
const stream1 = FileStream.create({ owner: me });
|
246
|
+
stream1.start({ mimeType: "image/jpeg" });
|
247
|
+
stream1.push(new Uint8Array([1, 2, 3]));
|
248
|
+
stream1.end();
|
249
|
+
|
250
|
+
const stream2 = FileStream.create({ owner: me });
|
251
|
+
stream2.start({ mimeType: "image/jpeg" });
|
252
|
+
// Don't end stream2, so it has no chunks
|
253
|
+
|
254
|
+
const stream3 = FileStream.create({ owner: me });
|
255
|
+
stream3.start({ mimeType: "image/jpeg" });
|
256
|
+
stream3.push(new Uint8Array([7, 8, 9]));
|
257
|
+
stream3.end();
|
258
|
+
|
259
|
+
imageDef["1920x1080"] = stream1;
|
260
|
+
imageDef["1280x720"] = stream2;
|
261
|
+
imageDef["800x450"] = stream3;
|
262
|
+
|
263
|
+
// Should skip 1280x720 as it's incomplete and return 1920x1080
|
264
|
+
const result = imageDef.highestResAvailable({ targetWidth: 1000 });
|
265
|
+
expect(result).toBeDefined();
|
266
|
+
expect(result?.res).toBe("800x450");
|
267
|
+
expect(result?.stream).toStrictEqual(stream1);
|
268
|
+
});
|
269
|
+
});
|