@squoosh-kit/webp 0.0.3 → 0.0.5
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/README.md +197 -28
- package/dist/bridge.browser.mjs +4 -0
- package/dist/bridge.browser.mjs.map +13 -0
- package/dist/bridge.bun.js +5 -0
- package/dist/bridge.bun.js.map +13 -0
- package/dist/bridge.d.ts +3 -1
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.node.cjs +3 -0
- package/dist/bridge.node.cjs.map +13 -0
- package/dist/bridge.node.mjs +4 -0
- package/dist/bridge.node.mjs.map +13 -0
- package/dist/chunk-djaabg7r.js +3 -0
- package/dist/chunk-djaabg7r.js.map +9 -0
- package/dist/index.browser.mjs +3 -0
- package/dist/index.browser.mjs.map +10 -0
- package/dist/index.bun.js +4 -0
- package/dist/index.bun.js.map +10 -0
- package/dist/index.d.ts +39 -7
- package/dist/index.d.ts.map +1 -0
- package/dist/index.node.cjs +3 -0
- package/dist/index.node.cjs.map +10 -0
- package/dist/index.node.mjs +3 -0
- package/dist/index.node.mjs.map +10 -0
- package/dist/types.browser.mjs +2 -0
- package/dist/types.browser.mjs.map +9 -0
- package/dist/types.bun.js +3 -0
- package/dist/types.bun.js.map +9 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.node.cjs +3 -0
- package/dist/types.node.cjs.map +9 -0
- package/dist/types.node.mjs +2 -0
- package/dist/types.node.mjs.map +9 -0
- package/dist/webp.worker.browser.mjs +28 -0
- package/dist/webp.worker.browser.mjs.map +13 -0
- package/dist/webp.worker.bun.js +29 -0
- package/dist/webp.worker.bun.js.map +13 -0
- package/dist/webp.worker.d.ts +3 -2
- package/dist/webp.worker.d.ts.map +1 -0
- package/dist/webp.worker.node.cjs +27 -0
- package/dist/webp.worker.node.cjs.map +13 -0
- package/dist/webp.worker.node.mjs +28 -0
- package/dist/webp.worker.node.mjs.map +13 -0
- package/package.json +13 -5
- package/dist/index.js +0 -5
- package/dist/index.js.map +0 -12
- package/dist/wasm/webp/webp_enc.d.ts +0 -42
- package/dist/wasm/webp/webp_enc.js +0 -16
- package/dist/wasm/webp/webp_enc.wasm +0 -0
- package/dist/wasm/webp-dec/webp_dec.d.ts +0 -7
- package/dist/wasm/webp-dec/webp_dec.js +0 -16
- package/dist/wasm/webp-dec/webp_dec.wasm +0 -0
- package/dist/webp.worker.js +0 -6
- package/dist/webp.worker.js.map +0 -10
package/README.md
CHANGED
|
@@ -28,25 +28,37 @@ import type { ImageInput } from '@squoosh-kit/webp';
|
|
|
28
28
|
const imageData: ImageInput = {
|
|
29
29
|
data: imageBuffer,
|
|
30
30
|
width: 1920,
|
|
31
|
-
height: 1080
|
|
31
|
+
height: 1080,
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
//
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
imageData,
|
|
38
|
-
{ quality: 85 }
|
|
39
|
-
);
|
|
34
|
+
// With cancellation support
|
|
35
|
+
const controller = new AbortController();
|
|
36
|
+
const webpBuffer = await encode(imageData, { quality: 85 }, controller.signal);
|
|
40
37
|
|
|
41
38
|
// For multiple images, create a persistent encoder
|
|
42
39
|
const encoder = createWebpEncoder('worker');
|
|
43
40
|
const optimized = await encoder(
|
|
44
|
-
new AbortController().signal,
|
|
45
41
|
imageData,
|
|
46
|
-
{ quality: 90, lossless: false }
|
|
42
|
+
{ quality: 90, lossless: false },
|
|
43
|
+
new AbortController().signal
|
|
47
44
|
);
|
|
45
|
+
|
|
46
|
+
// Without cancellation (operation cannot be stopped once started)
|
|
47
|
+
const simple = await encode(imageData, { quality: 85 });
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
+
## Public API
|
|
51
|
+
|
|
52
|
+
Only the following exports are part of the public API and guaranteed to be stable across versions:
|
|
53
|
+
|
|
54
|
+
- `encode(imageData, options?, signal?)` - Encode an image to WebP format
|
|
55
|
+
- `createWebpEncoder(mode?)` - Create a reusable encoder function
|
|
56
|
+
- `ImageInput` type - Input image data structure
|
|
57
|
+
- `WebpOptions` type - WebP encoding configuration options
|
|
58
|
+
- `WebpEncoderFactory` type - Type for reusable encoder functions
|
|
59
|
+
|
|
60
|
+
Internal implementation details (such as `webpEncodeClient`) are not part of the public API and may change without notice.
|
|
61
|
+
|
|
50
62
|
## How It Works
|
|
51
63
|
|
|
52
64
|
Under the hood, this package leverages Google's Squoosh WebP encoder compiled to WebAssembly. The heavy processing happens in a Web Worker by default, so your main thread stays free for user interactions.
|
|
@@ -55,32 +67,45 @@ You get the same quality and performance as the original Squoosh tool, but wrapp
|
|
|
55
67
|
|
|
56
68
|
## Real-World Examples
|
|
57
69
|
|
|
58
|
-
**Image Upload Processing**
|
|
70
|
+
**Image Upload Processing with Timeout**
|
|
71
|
+
|
|
59
72
|
```typescript
|
|
60
73
|
// In your upload handler
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
74
|
+
const controller = new AbortController();
|
|
75
|
+
|
|
76
|
+
// Set a 30-second timeout
|
|
77
|
+
const timeout = setTimeout(() => controller.abort(), 30000);
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const processedImage = await encode(
|
|
81
|
+
uploadedImage,
|
|
82
|
+
{
|
|
83
|
+
quality: 85,
|
|
84
|
+
lossless: false, // Perfect for photos
|
|
85
|
+
},
|
|
86
|
+
controller.signal
|
|
87
|
+
);
|
|
69
88
|
|
|
70
|
-
await saveToStorage('optimized.webp', processedImage);
|
|
89
|
+
await saveToStorage('optimized.webp', processedImage);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if (error.name === 'AbortError') {
|
|
92
|
+
console.log('Encoding timed out');
|
|
93
|
+
} else {
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
} finally {
|
|
97
|
+
clearTimeout(timeout);
|
|
98
|
+
}
|
|
71
99
|
```
|
|
72
100
|
|
|
73
101
|
**Batch Conversion Service**
|
|
102
|
+
|
|
74
103
|
```typescript
|
|
75
104
|
const encoder = createWebpEncoder('client'); // Direct encoding, no worker
|
|
76
105
|
|
|
77
106
|
for (const imagePath of imageFiles) {
|
|
78
107
|
const imageData = await loadImage(imagePath);
|
|
79
|
-
const webpData = await encoder(
|
|
80
|
-
new AbortController().signal,
|
|
81
|
-
imageData,
|
|
82
|
-
{ quality: 75 }
|
|
83
|
-
);
|
|
108
|
+
const webpData = await encoder(imageData, { quality: 75 });
|
|
84
109
|
|
|
85
110
|
await writeFile(`${imagePath}.webp`, webpData);
|
|
86
111
|
}
|
|
@@ -88,13 +113,13 @@ for (const imagePath of imageFiles) {
|
|
|
88
113
|
|
|
89
114
|
## API Reference
|
|
90
115
|
|
|
91
|
-
### `encode(
|
|
116
|
+
### `encode(imageData, options?, signal?)`
|
|
92
117
|
|
|
93
118
|
The main encoding function. Handles everything automatically and returns a Promise.
|
|
94
119
|
|
|
95
|
-
- `signal` - `AbortSignal` to cancel long-running operations
|
|
96
120
|
- `imageData` - `ImageInput` object with your pixel data
|
|
97
121
|
- `options` - (optional) `WebpOptions` for quality and format settings
|
|
122
|
+
- `signal` - (optional) `AbortSignal` to cancel long-running operations. If provided, you can cancel by calling `controller.abort()` on the associated `AbortController`. If not provided, the operation cannot be cancelled.
|
|
98
123
|
- **Returns** - `Promise<Uint8Array>` with your encoded WebP data
|
|
99
124
|
|
|
100
125
|
### `createWebpEncoder(mode?)`
|
|
@@ -104,14 +129,158 @@ Creates a reusable encoder function. More efficient for processing multiple imag
|
|
|
104
129
|
- `mode` - (optional) `'worker'` or `'client'`, defaults to `'worker'`
|
|
105
130
|
- **Returns** - A function with the same signature as `encode()`
|
|
106
131
|
|
|
132
|
+
## Cancellation Support
|
|
133
|
+
|
|
134
|
+
To cancel an encoding operation in progress, pass an `AbortSignal`:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
const controller = new AbortController();
|
|
138
|
+
|
|
139
|
+
// Start encoding
|
|
140
|
+
const encodePromise = encode(imageData, { quality: 85 }, controller.signal);
|
|
141
|
+
|
|
142
|
+
// Cancel after 5 seconds if still running
|
|
143
|
+
setTimeout(() => controller.abort(), 5000);
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
const result = await encodePromise;
|
|
147
|
+
} catch (error) {
|
|
148
|
+
if (error.name === 'AbortError') {
|
|
149
|
+
console.log('Encoding was cancelled');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Important**: If no signal is provided, the encoding operation cannot be cancelled. It will run to completion.
|
|
155
|
+
|
|
156
|
+
## Input Validation
|
|
157
|
+
|
|
158
|
+
All inputs are automatically validated before processing to provide clear error messages:
|
|
159
|
+
|
|
160
|
+
### Image Validation
|
|
161
|
+
|
|
162
|
+
The `ImageInput` must contain valid image data:
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// Valid image data
|
|
166
|
+
const validImage: ImageInput = {
|
|
167
|
+
data: new Uint8Array(4096), // or Uint8ClampedArray
|
|
168
|
+
width: 32,
|
|
169
|
+
height: 32,
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// Will throw TypeError: image must be an object
|
|
173
|
+
await encode(null, { quality: 85 });
|
|
174
|
+
|
|
175
|
+
// Will throw TypeError: image.data is required
|
|
176
|
+
await encode({ width: 32, height: 32 }, { quality: 85 });
|
|
177
|
+
|
|
178
|
+
// Will throw TypeError: image.data must be Uint8Array or Uint8ClampedArray
|
|
179
|
+
await encode({ data: [0, 0, 0, 255], width: 32, height: 32 }, { quality: 85 });
|
|
180
|
+
|
|
181
|
+
// Will throw RangeError: image.width must be a positive integer
|
|
182
|
+
await encode(
|
|
183
|
+
{ data: new Uint8Array(100), width: 0, height: 32 },
|
|
184
|
+
{ quality: 85 }
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
// Will throw RangeError: image.data too small
|
|
188
|
+
// (needs 32 * 32 * 4 = 4096 bytes, but only 100 provided)
|
|
189
|
+
await encode(
|
|
190
|
+
{ data: new Uint8Array(100), width: 32, height: 32 },
|
|
191
|
+
{ quality: 85 }
|
|
192
|
+
);
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Options Validation
|
|
196
|
+
|
|
197
|
+
All encoding options are validated for correctness:
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
// Will throw RangeError: options.quality must be an integer between 0 and 100
|
|
201
|
+
await encode(validImage, { quality: 150 });
|
|
202
|
+
|
|
203
|
+
// Will throw TypeError: options.lossless must be boolean
|
|
204
|
+
await encode(validImage, { lossless: 1 });
|
|
205
|
+
|
|
206
|
+
// Will throw TypeError: options.nearLossless must be boolean
|
|
207
|
+
await encode(validImage, { nearLossless: 'true' });
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Why Validation Matters
|
|
211
|
+
|
|
212
|
+
Input validation prevents:
|
|
213
|
+
|
|
214
|
+
- **Cryptic WASM errors** - Clear messages instead of "undefined behavior"
|
|
215
|
+
- **Out-of-bounds buffer access** - Catches undersized buffers early
|
|
216
|
+
- **Silent failures** - Invalid options are caught immediately
|
|
217
|
+
- **Type confusion** - Ensures data is in the correct format
|
|
218
|
+
|
|
219
|
+
All validation happens synchronously before WASM processing, so you get errors immediately without starting an async operation.
|
|
220
|
+
|
|
221
|
+
### Package Size
|
|
222
|
+
|
|
223
|
+
This package includes WebAssembly binaries (~30-40KB gzipped) for the WebP encoder. These enable fast processing through Web Workers and are essential for optimal performance.
|
|
224
|
+
|
|
225
|
+
**Size breakdown:**
|
|
226
|
+
|
|
227
|
+
- JavaScript code: ~5-8KB gzipped
|
|
228
|
+
- TypeScript definitions: ~3KB
|
|
229
|
+
- WASM binaries: ~30-40KB gzipped (required for encoding)
|
|
230
|
+
|
|
231
|
+
If you're using client mode only and want to reduce package size, you can safely remove the WASM files:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
rm -rf node_modules/@squoosh-kit/webp/dist/wasm/
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Note**: This will cause worker mode to fail. Only remove if using client mode exclusively.
|
|
238
|
+
|
|
239
|
+
### Worker Cleanup
|
|
240
|
+
|
|
241
|
+
When using worker mode (`createWebpEncoder('worker')`), always clean up the worker when you're done to prevent memory leaks:
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
const encoder = createWebpEncoder('worker');
|
|
245
|
+
|
|
246
|
+
try {
|
|
247
|
+
const webpData = await encoder(imageData, { quality: 85 });
|
|
248
|
+
// Use the encoded data...
|
|
249
|
+
} finally {
|
|
250
|
+
// Clean up the worker to free resources
|
|
251
|
+
await encoder.terminate();
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
For batch operations, keep the encoder alive throughout processing:
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
const encoder = createWebpEncoder('worker');
|
|
259
|
+
|
|
260
|
+
try {
|
|
261
|
+
const webpImages = await Promise.all([
|
|
262
|
+
encoder(image1, { quality: 85 }),
|
|
263
|
+
encoder(image2, { quality: 85 }),
|
|
264
|
+
encoder(image3, { quality: 85 }),
|
|
265
|
+
]);
|
|
266
|
+
|
|
267
|
+
// Save encoded images...
|
|
268
|
+
} finally {
|
|
269
|
+
// Clean up when all operations are complete
|
|
270
|
+
await encoder.terminate();
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Note**: In client mode (`createWebpEncoder('client')`), calling `terminate()` is a no-op since there are no worker resources to clean up. It's always safe to call for consistency.
|
|
275
|
+
|
|
107
276
|
### `WebpOptions`
|
|
108
277
|
|
|
109
278
|
Fine-tune your encoding:
|
|
110
279
|
|
|
111
280
|
```typescript
|
|
112
281
|
type WebpOptions = {
|
|
113
|
-
quality?: number;
|
|
114
|
-
lossless?: boolean;
|
|
282
|
+
quality?: number; // 0-100, controls file size vs quality (default: 82)
|
|
283
|
+
lossless?: boolean; // Lossless compression, larger files (default: false)
|
|
115
284
|
nearLossless?: boolean; // Near-lossless mode, best of both worlds (default: false)
|
|
116
285
|
};
|
|
117
286
|
```
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{b as A,c as B,d as E}from"./webp.worker.browser.mjs";function N(){return typeof Bun<"u"}var T=0;async function S(G,J,K,Y,H){return new Promise((X,Q)=>{let Z=++T;if(Y?.aborted){Q(new DOMException("Aborted","AbortError"));return}let V=(D)=>{let _=D.data;if(_.id!==Z)return;if($(),_.ok&&_.data!==void 0)X(_.data);else Q(Error(_.error||"Unknown worker error"))},O=(D)=>{$(),Q(Error(`Worker error: ${D.message}`))},x=()=>{$(),Q(new DOMException("Aborted","AbortError"))},$=()=>{G.removeEventListener("message",V),G.removeEventListener("error",O),Y?.removeEventListener("abort",x)};G.addEventListener("message",V),G.addEventListener("error",O),Y?.addEventListener("abort",x);let L={type:J,id:Z,payload:K};if(H&&H.length>0)G.postMessage(L,H);else G.postMessage(L)})}function q(G){let J=G.endsWith(".js")?G:`${G}.js`;if(typeof window<"u"){let Q={"webp.worker.js":"/dist/features/webp/webp.worker.browser.mjs","resize.worker.js":"/dist/features/resize/resize.worker.browser.mjs"}[J];if(Q)return new URL(Q,window.location.href)}let K=N()?".bun.js":".node.mjs",H={"webp.worker.js":`../../webp/dist/webp.worker${K}`,"resize.worker.js":`../../resize/dist/resize.worker${K}`}[J];if(H)return new URL(H,import.meta.url);return new URL(J,import.meta.url)}function z(G){let J=q(G);try{return new Worker(J.href,{type:"module"})}catch(K){let Y=K instanceof Error?K.message:String(K);throw Error(`Failed to create worker from ${J}: ${Y}. Ensure the worker file exists at the expected location. Expected worker file: ${G}${G.endsWith(".js")?"":".js"}`)}}function U(G,J=1e4){return new Promise((K,Y)=>{let H=setTimeout(()=>{Y(Error(`Worker initialization timeout after ${J}ms. Worker file: ${G}`))},J),X;try{X=z(G)}catch(Z){clearTimeout(H),Y(Z);return}let Q=(Z)=>{if(Z.data?.type==="worker:ready")clearTimeout(H),X.removeEventListener("message",Q),K(X)};X.addEventListener("message",Q),X.postMessage({type:"worker:ping"})})}class P{async encode(G,J,K){return E(G,J,K)}async terminate(){}}class I{worker=null;workerReady=null;async getWorker(){if(!this.worker){if(!this.workerReady)this.workerReady=this.createWorker();this.worker=await this.workerReady}return this.worker}async createWorker(){return U("webp.worker")}async encode(G,J,K){let Y=await this.getWorker();if(!G||typeof G!=="object")throw TypeError("image must be an object");let H=G;if(!H.data)throw TypeError("image.data is required");if(H.width===void 0||H.height===void 0)throw TypeError("image.width and image.height are required");let X={data:H.data,width:H.width,height:H.height};B(X);let Q=X.data.buffer;return A(Q),S(Y,"webp:encode",{image:X,options:J},K,[Q])}async terminate(){if(this.worker)this.worker.terminate(),this.worker=null,this.workerReady=null}}function v(G){return G==="client"?new P:new I}export{v as createBridge};
|
|
2
|
+
export{v as a};
|
|
3
|
+
|
|
4
|
+
//# debugId=A53D8DE6F4ECB82364756E2164756E21
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../runtime/src/env.ts", "../../runtime/src/worker-call.ts", "../../runtime/src/worker-helper.ts", "../src/bridge.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Runtime environment detection utilities\n */\n\n/**\n * Detect if running in a Web Worker context\n */\nexport function isWorker(): boolean {\n return (\n typeof self !== 'undefined' &&\n typeof (globalThis as unknown as { DedicatedWorkerGlobalScope?: unknown })\n .DedicatedWorkerGlobalScope !== 'undefined'\n );\n}\n\n/**\n * Detect if running in a browser context\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Detect if running in Bun\n */\nexport function isBun(): boolean {\n return typeof Bun !== 'undefined';\n}\n\n/**\n * Detect if running in Node.js\n */\nexport function isNode(): boolean {\n return (\n typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null\n );\n}\n\n/**\n * Check if ImageData is available in the current environment\n */\nexport function hasImageData(): boolean {\n return typeof ImageData !== 'undefined';\n}\n",
|
|
6
|
+
"/**\n * Generic worker communication helper with support for transferables and AbortSignal\n */\n\nexport interface WorkerRequest<T = unknown> {\n type: string;\n id: number;\n payload: T;\n}\n\nexport interface WorkerResponse<T = unknown> {\n id: number;\n ok: boolean;\n data?: T;\n error?: string;\n}\n\nlet requestId = 0;\n\n/**\n * Call a worker with a typed request and wait for response\n *\n * @param worker - The worker instance to call\n * @param type - The message type\n * @param payload - The payload to send\n * @param signal - Optional AbortSignal to cancel the operation\n * @param transfer - Optional list of Transferable objects to transfer\n * @returns Promise that resolves with the worker's response data\n */\nexport async function callWorker<TPayload, TResponse>(\n worker: Worker,\n type: string,\n payload: TPayload,\n signal?: AbortSignal,\n transfer?: Transferable[]\n): Promise<TResponse> {\n return new Promise<TResponse>((resolve, reject) => {\n const id = ++requestId;\n\n // Check if already aborted\n if (signal?.aborted) {\n reject(new DOMException('Aborted', 'AbortError'));\n return;\n }\n\n const handleMessage = (event: MessageEvent) => {\n const response = event.data as WorkerResponse<TResponse>;\n if (response.id !== id) return;\n\n cleanup();\n\n if (response.ok && response.data !== undefined) {\n resolve(response.data);\n } else {\n reject(new Error(response.error || 'Unknown worker error'));\n }\n };\n\n const handleError = (error: ErrorEvent) => {\n cleanup();\n reject(new Error(`Worker error: ${error.message}`));\n };\n\n const handleAbort = () => {\n cleanup();\n reject(new DOMException('Aborted', 'AbortError'));\n };\n\n const cleanup = () => {\n worker.removeEventListener('message', handleMessage);\n worker.removeEventListener('error', handleError);\n signal?.removeEventListener('abort', handleAbort);\n };\n\n // Set up listeners\n worker.addEventListener('message', handleMessage);\n worker.addEventListener('error', handleError);\n signal?.addEventListener('abort', handleAbort);\n\n // Send the request\n const request: WorkerRequest<TPayload> = { type, id, payload };\n\n if (transfer && transfer.length > 0) {\n worker.postMessage(request, transfer);\n } else {\n worker.postMessage(request);\n }\n });\n}\n",
|
|
7
|
+
"/**\n * Worker helper utilities for creating and managing Web Workers\n *\n * This module provides centralized logic for locating and creating worker files\n * in different environments (development, npm package, bundled, etc.)\n */\n\nimport { isBun } from './env';\n\n/**\n * Get the URL for a worker file\n *\n * This helper abstracts away the complexity of locating worker files\n * in different environments (development, npm package, bundled, etc.)\n *\n * @param workerFilename - The name of the worker file (with or without .js extension)\n * @returns URL object pointing to the worker file\n */\nexport function getWorkerURL(workerFilename: string): URL {\n // Ensure filename has correct format\n const normalizedName = workerFilename.endsWith('.js')\n ? workerFilename\n : `${workerFilename}.js`;\n\n // In browser contexts, use absolute paths from the server root\n // The server will route these to the correct locations\n if (typeof window !== 'undefined') {\n // Browser environment - use absolute paths with platform-specific extension\n const workerPathMap: Record<string, string> = {\n 'webp.worker.js': '/dist/features/webp/webp.worker.browser.mjs',\n 'resize.worker.js': '/dist/features/resize/resize.worker.browser.mjs',\n };\n\n const browserPath = workerPathMap[normalizedName];\n if (browserPath) {\n return new URL(browserPath, window.location.href);\n }\n }\n\n // Node.js/Bun: use relative path from runtime package location\n // Determine which platform variant to use\n const platformExt = isBun() ? '.bun.js' : '.node.mjs';\n\n const nodePathMap: Record<string, string> = {\n 'webp.worker.js': `../../webp/dist/webp.worker${platformExt}`,\n 'resize.worker.js': `../../resize/dist/resize.worker${platformExt}`,\n };\n\n const nodePath = nodePathMap[normalizedName];\n if (nodePath) {\n return new URL(nodePath, import.meta.url);\n }\n\n // Fallback: assume worker is in same directory as this module\n return new URL(normalizedName, import.meta.url);\n}\n\n/**\n * Create a Web Worker for a specific codec\n *\n * Handles environment-specific worker creation logic and provides\n * clear error messages when worker creation fails.\n *\n * @param workerFilename - The name of the worker file (e.g., 'resize.worker' or 'webp.worker')\n * @returns Worker instance\n * @throws Error if worker creation fails with detailed error message\n */\nexport function createCodecWorker(workerFilename: string): Worker {\n const workerURL = getWorkerURL(workerFilename);\n\n try {\n return new Worker(workerURL.href, { type: 'module' });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to create worker from ${workerURL}: ${errorMessage}. ` +\n `Ensure the worker file exists at the expected location. ` +\n `Expected worker file: ${workerFilename}${workerFilename.endsWith('.js') ? '' : '.js'}`\n );\n }\n}\n\n/**\n * Create a worker with initialization timeout and ready signal handling\n *\n * This is a higher-level function that creates a worker and waits for it\n * to signal that it's ready to receive messages.\n *\n * @param workerFilename - The name of the worker file\n * @param timeoutMs - Timeout in milliseconds (default: 10000)\n * @returns Promise that resolves to a ready Worker instance\n * @throws Error if worker creation fails or times out\n */\nexport function createReadyWorker(\n workerFilename: string,\n timeoutMs: number = 10000\n): Promise<Worker> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(\n `Worker initialization timeout after ${timeoutMs}ms. Worker file: ${workerFilename}`\n )\n );\n }, timeoutMs);\n\n let worker: Worker;\n try {\n worker = createCodecWorker(workerFilename);\n } catch (error) {\n clearTimeout(timeout);\n reject(error);\n return;\n }\n\n const handleMessage = (event: MessageEvent) => {\n if (event.data?.type === 'worker:ready') {\n clearTimeout(timeout);\n worker.removeEventListener('message', handleMessage);\n resolve(worker);\n }\n };\n\n worker.addEventListener('message', handleMessage);\n worker.postMessage({ type: 'worker:ping' });\n });\n}\n",
|
|
8
|
+
"/**\n * Bridge implementation for the WebP package, handling worker and client modes.\n */\n\nimport {\n callWorker,\n createReadyWorker,\n type ImageInput,\n} from '@squoosh-kit/runtime';\nimport { validateArrayBuffer, validateImageInput } from '@squoosh-kit/runtime';\nimport { webpEncodeClient } from './webp.worker.js';\nimport type { WebpOptions } from './types.js';\n\ninterface WebPBridge {\n encode(\n image: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n ): Promise<Uint8Array>;\n terminate(): Promise<void>;\n}\n\nclass WebpClientBridge implements WebPBridge {\n async encode(\n image: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n ): Promise<Uint8Array> {\n return webpEncodeClient(image, options, signal);\n }\n\n async terminate(): Promise<void> {\n // Client mode has nothing to terminate\n }\n}\n\nclass WebpWorkerBridge implements WebPBridge {\n private worker: Worker | null = null;\n private workerReady: Promise<Worker> | null = null;\n\n private async getWorker(): Promise<Worker> {\n if (!this.worker) {\n if (!this.workerReady) {\n this.workerReady = this.createWorker();\n }\n this.worker = await this.workerReady;\n }\n return this.worker;\n }\n\n private async createWorker(): Promise<Worker> {\n // Use the centralized worker helper for robust path resolution\n return createReadyWorker('webp.worker');\n }\n\n async encode(\n image: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n ): Promise<Uint8Array> {\n const worker = await this.getWorker();\n\n // Validate and normalize image - ensure all required properties exist\n if (!image || typeof image !== 'object') {\n throw new TypeError('image must be an object');\n }\n\n const imageRecord = image as Record<string, unknown>;\n if (!imageRecord.data) {\n throw new TypeError('image.data is required');\n }\n if (imageRecord.width === undefined || imageRecord.height === undefined) {\n throw new TypeError('image.width and image.height are required');\n }\n\n const normalizedImage: ImageInput = {\n data: imageRecord.data as Uint8Array | Uint8ClampedArray,\n width: imageRecord.width as number,\n height: imageRecord.height as number,\n };\n\n validateImageInput(normalizedImage);\n const buffer = normalizedImage.data.buffer;\n validateArrayBuffer(buffer);\n return callWorker(\n worker,\n 'webp:encode',\n { image: normalizedImage, options },\n signal,\n [buffer]\n );\n }\n\n async terminate(): Promise<void> {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.workerReady = null;\n }\n }\n}\n\nexport function createBridge(mode: 'worker' | 'client'): WebPBridge {\n return mode === 'client' ? new WebpClientBridge() : new WebpWorkerBridge();\n}\n"
|
|
9
|
+
],
|
|
10
|
+
"mappings": "4DAyBO,SAAS,CAAK,EAAY,CAC/B,OAAO,OAAO,IAAQ,ICTxB,IAAI,EAAY,EAYhB,eAAsB,CAA+B,CACnD,EACA,EACA,EACA,EACA,EACoB,CACpB,OAAO,IAAI,QAAmB,CAAC,EAAS,IAAW,CACjD,IAAM,EAAK,EAAE,EAGb,GAAI,GAAQ,QAAS,CACnB,EAAO,IAAI,aAAa,UAAW,YAAY,CAAC,EAChD,OAGF,IAAM,EAAgB,CAAC,IAAwB,CAC7C,IAAM,EAAW,EAAM,KACvB,GAAI,EAAS,KAAO,EAAI,OAIxB,GAFA,EAAQ,EAEJ,EAAS,IAAM,EAAS,OAAS,OACnC,EAAQ,EAAS,IAAI,EAErB,OAAW,MAAM,EAAS,OAAS,sBAAsB,CAAC,GAIxD,EAAc,CAAC,IAAsB,CACzC,EAAQ,EACR,EAAW,MAAM,iBAAiB,EAAM,SAAS,CAAC,GAG9C,EAAc,IAAM,CACxB,EAAQ,EACR,EAAO,IAAI,aAAa,UAAW,YAAY,CAAC,GAG5C,EAAU,IAAM,CACpB,EAAO,oBAAoB,UAAW,CAAa,EACnD,EAAO,oBAAoB,QAAS,CAAW,EAC/C,GAAQ,oBAAoB,QAAS,CAAW,GAIlD,EAAO,iBAAiB,UAAW,CAAa,EAChD,EAAO,iBAAiB,QAAS,CAAW,EAC5C,GAAQ,iBAAiB,QAAS,CAAW,EAG7C,IAAM,EAAmC,CAAE,OAAM,KAAI,SAAQ,EAE7D,GAAI,GAAY,EAAS,OAAS,EAChC,EAAO,YAAY,EAAS,CAAQ,EAEpC,OAAO,YAAY,CAAO,EAE7B,ECrEI,SAAS,CAAY,CAAC,EAA6B,CAExD,IAAM,EAAiB,EAAe,SAAS,KAAK,EAChD,EACA,GAAG,OAIP,GAAI,OAAO,OAAW,IAAa,CAOjC,IAAM,EALwC,CAC5C,iBAAkB,8CAClB,mBAAoB,iDACtB,EAEkC,GAClC,GAAI,EACF,OAAO,IAAI,IAAI,EAAa,OAAO,SAAS,IAAI,EAMpD,IAAM,EAAc,EAAM,EAAI,UAAY,YAOpC,EALsC,CAC1C,iBAAkB,8BAA8B,IAChD,mBAAoB,kCAAkC,GACxD,EAE6B,GAC7B,GAAI,EACF,OAAO,IAAI,IAAI,EAAU,YAAY,GAAG,EAI1C,OAAO,IAAI,IAAI,EAAgB,YAAY,GAAG,EAazC,SAAS,CAAiB,CAAC,EAAgC,CAChE,IAAM,EAAY,EAAa,CAAc,EAE7C,GAAI,CACF,OAAO,IAAI,OAAO,EAAU,KAAM,CAAE,KAAM,QAAS,CAAC,EACpD,MAAO,EAAO,CACd,IAAM,EAAe,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EAC1E,MAAU,MACR,gCAAgC,MAAc,oFAEnB,IAAiB,EAAe,SAAS,KAAK,EAAI,GAAK,OACpF,GAeG,SAAS,CAAiB,CAC/B,EACA,EAAoB,IACH,CACjB,OAAO,IAAI,QAAQ,CAAC,EAAS,IAAW,CACtC,IAAM,EAAU,WAAW,IAAM,CAC/B,EACM,MACF,uCAAuC,qBAA6B,GACtE,CACF,GACC,CAAS,EAER,EACJ,GAAI,CACF,EAAS,EAAkB,CAAc,EACzC,MAAO,EAAO,CACd,aAAa,CAAO,EACpB,EAAO,CAAK,EACZ,OAGF,IAAM,EAAgB,CAAC,IAAwB,CAC7C,GAAI,EAAM,MAAM,OAAS,eACvB,aAAa,CAAO,EACpB,EAAO,oBAAoB,UAAW,CAAa,EACnD,EAAQ,CAAM,GAIlB,EAAO,iBAAiB,UAAW,CAAa,EAChD,EAAO,YAAY,CAAE,KAAM,aAAc,CAAC,EAC3C,ECvGH,MAAM,CAAuC,MACrC,OAAM,CACV,EACA,EACA,EACqB,CACrB,OAAO,EAAiB,EAAO,EAAS,CAAM,OAG1C,UAAS,EAAkB,EAGnC,CAEA,MAAM,CAAuC,CACnC,OAAwB,KACxB,YAAsC,UAEhC,UAAS,EAAoB,CACzC,GAAI,CAAC,KAAK,OAAQ,CAChB,GAAI,CAAC,KAAK,YACR,KAAK,YAAc,KAAK,aAAa,EAEvC,KAAK,OAAS,MAAM,KAAK,YAE3B,OAAO,KAAK,YAGA,aAAY,EAAoB,CAE5C,OAAO,EAAkB,aAAa,OAGlC,OAAM,CACV,EACA,EACA,EACqB,CACrB,IAAM,EAAS,MAAM,KAAK,UAAU,EAGpC,GAAI,CAAC,GAAS,OAAO,IAAU,SAC7B,MAAU,UAAU,yBAAyB,EAG/C,IAAM,EAAc,EACpB,GAAI,CAAC,EAAY,KACf,MAAU,UAAU,wBAAwB,EAE9C,GAAI,EAAY,QAAU,QAAa,EAAY,SAAW,OAC5D,MAAU,UAAU,2CAA2C,EAGjE,IAAM,EAA8B,CAClC,KAAM,EAAY,KAClB,MAAO,EAAY,MACnB,OAAQ,EAAY,MACtB,EAEA,EAAmB,CAAe,EAClC,IAAM,EAAS,EAAgB,KAAK,OAEpC,OADA,EAAoB,CAAM,EACnB,EACL,EACA,cACA,CAAE,MAAO,EAAiB,SAAQ,EAClC,EACA,CAAC,CAAM,CACT,OAGI,UAAS,EAAkB,CAC/B,GAAI,KAAK,OACP,KAAK,OAAO,UAAU,EACtB,KAAK,OAAS,KACd,KAAK,YAAc,KAGzB,CAEO,SAAS,CAAY,CAAC,EAAuC,CAClE,OAAO,IAAS,SAAW,IAAI,EAAqB,IAAI",
|
|
11
|
+
"debugId": "A53D8DE6F4ECB82364756E2164756E21",
|
|
12
|
+
"names": []
|
|
13
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{b as A,c as B,d as E}from"./webp.worker.bun.js";function N(){return typeof Bun<"u"}var T=0;async function S(G,J,K,Y,H){return new Promise((X,Q)=>{let Z=++T;if(Y?.aborted){Q(new DOMException("Aborted","AbortError"));return}let V=(D)=>{let _=D.data;if(_.id!==Z)return;if($(),_.ok&&_.data!==void 0)X(_.data);else Q(Error(_.error||"Unknown worker error"))},O=(D)=>{$(),Q(Error(`Worker error: ${D.message}`))},x=()=>{$(),Q(new DOMException("Aborted","AbortError"))},$=()=>{G.removeEventListener("message",V),G.removeEventListener("error",O),Y?.removeEventListener("abort",x)};G.addEventListener("message",V),G.addEventListener("error",O),Y?.addEventListener("abort",x);let L={type:J,id:Z,payload:K};if(H&&H.length>0)G.postMessage(L,H);else G.postMessage(L)})}function q(G){let J=G.endsWith(".js")?G:`${G}.js`;if(typeof window<"u"){let Q={"webp.worker.js":"/dist/features/webp/webp.worker.browser.mjs","resize.worker.js":"/dist/features/resize/resize.worker.browser.mjs"}[J];if(Q)return new URL(Q,window.location.href)}let K=N()?".bun.js":".node.mjs",H={"webp.worker.js":`../../webp/dist/webp.worker${K}`,"resize.worker.js":`../../resize/dist/resize.worker${K}`}[J];if(H)return new URL(H,import.meta.url);return new URL(J,import.meta.url)}function z(G){let J=q(G);try{return new Worker(J.href,{type:"module"})}catch(K){let Y=K instanceof Error?K.message:String(K);throw Error(`Failed to create worker from ${J}: ${Y}. Ensure the worker file exists at the expected location. Expected worker file: ${G}${G.endsWith(".js")?"":".js"}`)}}function U(G,J=1e4){return new Promise((K,Y)=>{let H=setTimeout(()=>{Y(Error(`Worker initialization timeout after ${J}ms. Worker file: ${G}`))},J),X;try{X=z(G)}catch(Z){clearTimeout(H),Y(Z);return}let Q=(Z)=>{if(Z.data?.type==="worker:ready")clearTimeout(H),X.removeEventListener("message",Q),K(X)};X.addEventListener("message",Q),X.postMessage({type:"worker:ping"})})}class P{async encode(G,J,K){return E(G,J,K)}async terminate(){}}class I{worker=null;workerReady=null;async getWorker(){if(!this.worker){if(!this.workerReady)this.workerReady=this.createWorker();this.worker=await this.workerReady}return this.worker}async createWorker(){return U("webp.worker")}async encode(G,J,K){let Y=await this.getWorker();if(!G||typeof G!=="object")throw TypeError("image must be an object");let H=G;if(!H.data)throw TypeError("image.data is required");if(H.width===void 0||H.height===void 0)throw TypeError("image.width and image.height are required");let X={data:H.data,width:H.width,height:H.height};B(X);let Q=X.data.buffer;return A(Q),S(Y,"webp:encode",{image:X,options:J},K,[Q])}async terminate(){if(this.worker)this.worker.terminate(),this.worker=null,this.workerReady=null}}function v(G){return G==="client"?new P:new I}export{v as createBridge};
|
|
3
|
+
export{v as a};
|
|
4
|
+
|
|
5
|
+
//# debugId=480F678DC127BB6164756E2164756E21
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../runtime/src/env.ts", "../../runtime/src/worker-call.ts", "../../runtime/src/worker-helper.ts", "../src/bridge.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Runtime environment detection utilities\n */\n\n/**\n * Detect if running in a Web Worker context\n */\nexport function isWorker(): boolean {\n return (\n typeof self !== 'undefined' &&\n typeof (globalThis as unknown as { DedicatedWorkerGlobalScope?: unknown })\n .DedicatedWorkerGlobalScope !== 'undefined'\n );\n}\n\n/**\n * Detect if running in a browser context\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Detect if running in Bun\n */\nexport function isBun(): boolean {\n return typeof Bun !== 'undefined';\n}\n\n/**\n * Detect if running in Node.js\n */\nexport function isNode(): boolean {\n return (\n typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null\n );\n}\n\n/**\n * Check if ImageData is available in the current environment\n */\nexport function hasImageData(): boolean {\n return typeof ImageData !== 'undefined';\n}\n",
|
|
6
|
+
"/**\n * Generic worker communication helper with support for transferables and AbortSignal\n */\n\nexport interface WorkerRequest<T = unknown> {\n type: string;\n id: number;\n payload: T;\n}\n\nexport interface WorkerResponse<T = unknown> {\n id: number;\n ok: boolean;\n data?: T;\n error?: string;\n}\n\nlet requestId = 0;\n\n/**\n * Call a worker with a typed request and wait for response\n *\n * @param worker - The worker instance to call\n * @param type - The message type\n * @param payload - The payload to send\n * @param signal - Optional AbortSignal to cancel the operation\n * @param transfer - Optional list of Transferable objects to transfer\n * @returns Promise that resolves with the worker's response data\n */\nexport async function callWorker<TPayload, TResponse>(\n worker: Worker,\n type: string,\n payload: TPayload,\n signal?: AbortSignal,\n transfer?: Transferable[]\n): Promise<TResponse> {\n return new Promise<TResponse>((resolve, reject) => {\n const id = ++requestId;\n\n // Check if already aborted\n if (signal?.aborted) {\n reject(new DOMException('Aborted', 'AbortError'));\n return;\n }\n\n const handleMessage = (event: MessageEvent) => {\n const response = event.data as WorkerResponse<TResponse>;\n if (response.id !== id) return;\n\n cleanup();\n\n if (response.ok && response.data !== undefined) {\n resolve(response.data);\n } else {\n reject(new Error(response.error || 'Unknown worker error'));\n }\n };\n\n const handleError = (error: ErrorEvent) => {\n cleanup();\n reject(new Error(`Worker error: ${error.message}`));\n };\n\n const handleAbort = () => {\n cleanup();\n reject(new DOMException('Aborted', 'AbortError'));\n };\n\n const cleanup = () => {\n worker.removeEventListener('message', handleMessage);\n worker.removeEventListener('error', handleError);\n signal?.removeEventListener('abort', handleAbort);\n };\n\n // Set up listeners\n worker.addEventListener('message', handleMessage);\n worker.addEventListener('error', handleError);\n signal?.addEventListener('abort', handleAbort);\n\n // Send the request\n const request: WorkerRequest<TPayload> = { type, id, payload };\n\n if (transfer && transfer.length > 0) {\n worker.postMessage(request, transfer);\n } else {\n worker.postMessage(request);\n }\n });\n}\n",
|
|
7
|
+
"/**\n * Worker helper utilities for creating and managing Web Workers\n *\n * This module provides centralized logic for locating and creating worker files\n * in different environments (development, npm package, bundled, etc.)\n */\n\nimport { isBun } from './env';\n\n/**\n * Get the URL for a worker file\n *\n * This helper abstracts away the complexity of locating worker files\n * in different environments (development, npm package, bundled, etc.)\n *\n * @param workerFilename - The name of the worker file (with or without .js extension)\n * @returns URL object pointing to the worker file\n */\nexport function getWorkerURL(workerFilename: string): URL {\n // Ensure filename has correct format\n const normalizedName = workerFilename.endsWith('.js')\n ? workerFilename\n : `${workerFilename}.js`;\n\n // In browser contexts, use absolute paths from the server root\n // The server will route these to the correct locations\n if (typeof window !== 'undefined') {\n // Browser environment - use absolute paths with platform-specific extension\n const workerPathMap: Record<string, string> = {\n 'webp.worker.js': '/dist/features/webp/webp.worker.browser.mjs',\n 'resize.worker.js': '/dist/features/resize/resize.worker.browser.mjs',\n };\n\n const browserPath = workerPathMap[normalizedName];\n if (browserPath) {\n return new URL(browserPath, window.location.href);\n }\n }\n\n // Node.js/Bun: use relative path from runtime package location\n // Determine which platform variant to use\n const platformExt = isBun() ? '.bun.js' : '.node.mjs';\n\n const nodePathMap: Record<string, string> = {\n 'webp.worker.js': `../../webp/dist/webp.worker${platformExt}`,\n 'resize.worker.js': `../../resize/dist/resize.worker${platformExt}`,\n };\n\n const nodePath = nodePathMap[normalizedName];\n if (nodePath) {\n return new URL(nodePath, import.meta.url);\n }\n\n // Fallback: assume worker is in same directory as this module\n return new URL(normalizedName, import.meta.url);\n}\n\n/**\n * Create a Web Worker for a specific codec\n *\n * Handles environment-specific worker creation logic and provides\n * clear error messages when worker creation fails.\n *\n * @param workerFilename - The name of the worker file (e.g., 'resize.worker' or 'webp.worker')\n * @returns Worker instance\n * @throws Error if worker creation fails with detailed error message\n */\nexport function createCodecWorker(workerFilename: string): Worker {\n const workerURL = getWorkerURL(workerFilename);\n\n try {\n return new Worker(workerURL.href, { type: 'module' });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to create worker from ${workerURL}: ${errorMessage}. ` +\n `Ensure the worker file exists at the expected location. ` +\n `Expected worker file: ${workerFilename}${workerFilename.endsWith('.js') ? '' : '.js'}`\n );\n }\n}\n\n/**\n * Create a worker with initialization timeout and ready signal handling\n *\n * This is a higher-level function that creates a worker and waits for it\n * to signal that it's ready to receive messages.\n *\n * @param workerFilename - The name of the worker file\n * @param timeoutMs - Timeout in milliseconds (default: 10000)\n * @returns Promise that resolves to a ready Worker instance\n * @throws Error if worker creation fails or times out\n */\nexport function createReadyWorker(\n workerFilename: string,\n timeoutMs: number = 10000\n): Promise<Worker> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(\n `Worker initialization timeout after ${timeoutMs}ms. Worker file: ${workerFilename}`\n )\n );\n }, timeoutMs);\n\n let worker: Worker;\n try {\n worker = createCodecWorker(workerFilename);\n } catch (error) {\n clearTimeout(timeout);\n reject(error);\n return;\n }\n\n const handleMessage = (event: MessageEvent) => {\n if (event.data?.type === 'worker:ready') {\n clearTimeout(timeout);\n worker.removeEventListener('message', handleMessage);\n resolve(worker);\n }\n };\n\n worker.addEventListener('message', handleMessage);\n worker.postMessage({ type: 'worker:ping' });\n });\n}\n",
|
|
8
|
+
"/**\n * Bridge implementation for the WebP package, handling worker and client modes.\n */\n\nimport {\n callWorker,\n createReadyWorker,\n type ImageInput,\n} from '@squoosh-kit/runtime';\nimport { validateArrayBuffer, validateImageInput } from '@squoosh-kit/runtime';\nimport { webpEncodeClient } from './webp.worker.js';\nimport type { WebpOptions } from './types.js';\n\ninterface WebPBridge {\n encode(\n image: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n ): Promise<Uint8Array>;\n terminate(): Promise<void>;\n}\n\nclass WebpClientBridge implements WebPBridge {\n async encode(\n image: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n ): Promise<Uint8Array> {\n return webpEncodeClient(image, options, signal);\n }\n\n async terminate(): Promise<void> {\n // Client mode has nothing to terminate\n }\n}\n\nclass WebpWorkerBridge implements WebPBridge {\n private worker: Worker | null = null;\n private workerReady: Promise<Worker> | null = null;\n\n private async getWorker(): Promise<Worker> {\n if (!this.worker) {\n if (!this.workerReady) {\n this.workerReady = this.createWorker();\n }\n this.worker = await this.workerReady;\n }\n return this.worker;\n }\n\n private async createWorker(): Promise<Worker> {\n // Use the centralized worker helper for robust path resolution\n return createReadyWorker('webp.worker');\n }\n\n async encode(\n image: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n ): Promise<Uint8Array> {\n const worker = await this.getWorker();\n\n // Validate and normalize image - ensure all required properties exist\n if (!image || typeof image !== 'object') {\n throw new TypeError('image must be an object');\n }\n\n const imageRecord = image as Record<string, unknown>;\n if (!imageRecord.data) {\n throw new TypeError('image.data is required');\n }\n if (imageRecord.width === undefined || imageRecord.height === undefined) {\n throw new TypeError('image.width and image.height are required');\n }\n\n const normalizedImage: ImageInput = {\n data: imageRecord.data as Uint8Array | Uint8ClampedArray,\n width: imageRecord.width as number,\n height: imageRecord.height as number,\n };\n\n validateImageInput(normalizedImage);\n const buffer = normalizedImage.data.buffer;\n validateArrayBuffer(buffer);\n return callWorker(\n worker,\n 'webp:encode',\n { image: normalizedImage, options },\n signal,\n [buffer]\n );\n }\n\n async terminate(): Promise<void> {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.workerReady = null;\n }\n }\n}\n\nexport function createBridge(mode: 'worker' | 'client'): WebPBridge {\n return mode === 'client' ? new WebpClientBridge() : new WebpWorkerBridge();\n}\n"
|
|
9
|
+
],
|
|
10
|
+
"mappings": "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",
|
|
11
|
+
"debugId": "480F678DC127BB6164756E2164756E21",
|
|
12
|
+
"names": []
|
|
13
|
+
}
|
package/dist/bridge.d.ts
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
import { type ImageInput } from '@squoosh-kit/runtime';
|
|
5
5
|
import type { WebpOptions } from './types.js';
|
|
6
6
|
interface WebPBridge {
|
|
7
|
-
encode(
|
|
7
|
+
encode(image: ImageInput, options?: WebpOptions, signal?: AbortSignal): Promise<Uint8Array>;
|
|
8
|
+
terminate(): Promise<void>;
|
|
8
9
|
}
|
|
9
10
|
export declare function createBridge(mode: 'worker' | 'client'): WebPBridge;
|
|
10
11
|
export {};
|
|
12
|
+
//# sourceMappingURL=bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,UAAU,UAAU;IAClB,MAAM,CACJ,KAAK,EAAE,UAAU,EACjB,OAAO,CAAC,EAAE,WAAW,EACrB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CAAC;IACvB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAkFD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAElE"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var W={};M(W,{createBridge:()=>R});module.exports=C(W);function N(){return typeof Bun<"u"}var T=0;async function S(G,J,K,Y,H){return new Promise((X,Q)=>{let Z=++T;if(Y?.aborted){Q(new DOMException("Aborted","AbortError"));return}let V=(D)=>{let _=D.data;if(_.id!==Z)return;if($(),_.ok&&_.data!==void 0)X(_.data);else Q(Error(_.error||"Unknown worker error"))},O=(D)=>{$(),Q(Error(`Worker error: ${D.message}`))},x=()=>{$(),Q(new DOMException("Aborted","AbortError"))},$=()=>{G.removeEventListener("message",V),G.removeEventListener("error",O),Y?.removeEventListener("abort",x)};G.addEventListener("message",V),G.addEventListener("error",O),Y?.addEventListener("abort",x);let L={type:J,id:Z,payload:K};if(H&&H.length>0)G.postMessage(L,H);else G.postMessage(L)})}function q(G){let J=G.endsWith(".js")?G:`${G}.js`;if(typeof window<"u"){let Q={"webp.worker.js":"/dist/features/webp/webp.worker.browser.mjs","resize.worker.js":"/dist/features/resize/resize.worker.browser.mjs"}[J];if(Q)return new URL(Q,window.location.href)}let K=N()?".bun.js":".node.mjs",H={"webp.worker.js":`../../webp/dist/webp.worker${K}`,"resize.worker.js":`../../resize/dist/resize.worker${K}`}[J];if(H)return new URL(H,"file:///home/bnowak/repos/squoosh-lite/packages/runtime/src/worker-helper.ts");return new URL(J,"file:///home/bnowak/repos/squoosh-lite/packages/runtime/src/worker-helper.ts")}function z(G){let J=q(G);try{return new Worker(J.href,{type:"module"})}catch(K){let Y=K instanceof Error?K.message:String(K);throw Error(`Failed to create worker from ${J}: ${Y}. Ensure the worker file exists at the expected location. Expected worker file: ${G}${G.endsWith(".js")?"":".js"}`)}}function U(G,J=1e4){return new Promise((K,Y)=>{let H=setTimeout(()=>{Y(Error(`Worker initialization timeout after ${J}ms. Worker file: ${G}`))},J),X;try{X=z(G)}catch(Z){clearTimeout(H),Y(Z);return}let Q=(Z)=>{if(Z.data?.type==="worker:ready")clearTimeout(H),X.removeEventListener("message",Q),K(X)};X.addEventListener("message",Q),X.postMessage({type:"worker:ping"})})}class P{async encode(G,J,K){return E(G,J,K)}async terminate(){}}class I{worker=null;workerReady=null;async getWorker(){if(!this.worker){if(!this.workerReady)this.workerReady=this.createWorker();this.worker=await this.workerReady}return this.worker}async createWorker(){return U("webp.worker")}async encode(G,J,K){let Y=await this.getWorker();if(!G||typeof G!=="object")throw TypeError("image must be an object");let H=G;if(!H.data)throw TypeError("image.data is required");if(H.width===void 0||H.height===void 0)throw TypeError("image.width and image.height are required");let X={data:H.data,width:H.width,height:H.height};B(X);let Q=X.data.buffer;return A(Q),S(Y,"webp:encode",{image:X,options:J},K,[Q])}async terminate(){if(this.worker)this.worker.terminate(),this.worker=null,this.workerReady=null}}function R(G){return G==="client"?new P:new I}
|
|
2
|
+
|
|
3
|
+
//# debugId=0D11351578D67A2764756E2164756E21
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../runtime/src/env.ts", "../../runtime/src/worker-call.ts", "../../runtime/src/worker-helper.ts", "../src/bridge.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Runtime environment detection utilities\n */\n\n/**\n * Detect if running in a Web Worker context\n */\nexport function isWorker(): boolean {\n return (\n typeof self !== 'undefined' &&\n typeof (globalThis as unknown as { DedicatedWorkerGlobalScope?: unknown })\n .DedicatedWorkerGlobalScope !== 'undefined'\n );\n}\n\n/**\n * Detect if running in a browser context\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Detect if running in Bun\n */\nexport function isBun(): boolean {\n return typeof Bun !== 'undefined';\n}\n\n/**\n * Detect if running in Node.js\n */\nexport function isNode(): boolean {\n return (\n typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null\n );\n}\n\n/**\n * Check if ImageData is available in the current environment\n */\nexport function hasImageData(): boolean {\n return typeof ImageData !== 'undefined';\n}\n",
|
|
6
|
+
"/**\n * Generic worker communication helper with support for transferables and AbortSignal\n */\n\nexport interface WorkerRequest<T = unknown> {\n type: string;\n id: number;\n payload: T;\n}\n\nexport interface WorkerResponse<T = unknown> {\n id: number;\n ok: boolean;\n data?: T;\n error?: string;\n}\n\nlet requestId = 0;\n\n/**\n * Call a worker with a typed request and wait for response\n *\n * @param worker - The worker instance to call\n * @param type - The message type\n * @param payload - The payload to send\n * @param signal - Optional AbortSignal to cancel the operation\n * @param transfer - Optional list of Transferable objects to transfer\n * @returns Promise that resolves with the worker's response data\n */\nexport async function callWorker<TPayload, TResponse>(\n worker: Worker,\n type: string,\n payload: TPayload,\n signal?: AbortSignal,\n transfer?: Transferable[]\n): Promise<TResponse> {\n return new Promise<TResponse>((resolve, reject) => {\n const id = ++requestId;\n\n // Check if already aborted\n if (signal?.aborted) {\n reject(new DOMException('Aborted', 'AbortError'));\n return;\n }\n\n const handleMessage = (event: MessageEvent) => {\n const response = event.data as WorkerResponse<TResponse>;\n if (response.id !== id) return;\n\n cleanup();\n\n if (response.ok && response.data !== undefined) {\n resolve(response.data);\n } else {\n reject(new Error(response.error || 'Unknown worker error'));\n }\n };\n\n const handleError = (error: ErrorEvent) => {\n cleanup();\n reject(new Error(`Worker error: ${error.message}`));\n };\n\n const handleAbort = () => {\n cleanup();\n reject(new DOMException('Aborted', 'AbortError'));\n };\n\n const cleanup = () => {\n worker.removeEventListener('message', handleMessage);\n worker.removeEventListener('error', handleError);\n signal?.removeEventListener('abort', handleAbort);\n };\n\n // Set up listeners\n worker.addEventListener('message', handleMessage);\n worker.addEventListener('error', handleError);\n signal?.addEventListener('abort', handleAbort);\n\n // Send the request\n const request: WorkerRequest<TPayload> = { type, id, payload };\n\n if (transfer && transfer.length > 0) {\n worker.postMessage(request, transfer);\n } else {\n worker.postMessage(request);\n }\n });\n}\n",
|
|
7
|
+
"/**\n * Worker helper utilities for creating and managing Web Workers\n *\n * This module provides centralized logic for locating and creating worker files\n * in different environments (development, npm package, bundled, etc.)\n */\n\nimport { isBun } from './env';\n\n/**\n * Get the URL for a worker file\n *\n * This helper abstracts away the complexity of locating worker files\n * in different environments (development, npm package, bundled, etc.)\n *\n * @param workerFilename - The name of the worker file (with or without .js extension)\n * @returns URL object pointing to the worker file\n */\nexport function getWorkerURL(workerFilename: string): URL {\n // Ensure filename has correct format\n const normalizedName = workerFilename.endsWith('.js')\n ? workerFilename\n : `${workerFilename}.js`;\n\n // In browser contexts, use absolute paths from the server root\n // The server will route these to the correct locations\n if (typeof window !== 'undefined') {\n // Browser environment - use absolute paths with platform-specific extension\n const workerPathMap: Record<string, string> = {\n 'webp.worker.js': '/dist/features/webp/webp.worker.browser.mjs',\n 'resize.worker.js': '/dist/features/resize/resize.worker.browser.mjs',\n };\n\n const browserPath = workerPathMap[normalizedName];\n if (browserPath) {\n return new URL(browserPath, window.location.href);\n }\n }\n\n // Node.js/Bun: use relative path from runtime package location\n // Determine which platform variant to use\n const platformExt = isBun() ? '.bun.js' : '.node.mjs';\n\n const nodePathMap: Record<string, string> = {\n 'webp.worker.js': `../../webp/dist/webp.worker${platformExt}`,\n 'resize.worker.js': `../../resize/dist/resize.worker${platformExt}`,\n };\n\n const nodePath = nodePathMap[normalizedName];\n if (nodePath) {\n return new URL(nodePath, import.meta.url);\n }\n\n // Fallback: assume worker is in same directory as this module\n return new URL(normalizedName, import.meta.url);\n}\n\n/**\n * Create a Web Worker for a specific codec\n *\n * Handles environment-specific worker creation logic and provides\n * clear error messages when worker creation fails.\n *\n * @param workerFilename - The name of the worker file (e.g., 'resize.worker' or 'webp.worker')\n * @returns Worker instance\n * @throws Error if worker creation fails with detailed error message\n */\nexport function createCodecWorker(workerFilename: string): Worker {\n const workerURL = getWorkerURL(workerFilename);\n\n try {\n return new Worker(workerURL.href, { type: 'module' });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to create worker from ${workerURL}: ${errorMessage}. ` +\n `Ensure the worker file exists at the expected location. ` +\n `Expected worker file: ${workerFilename}${workerFilename.endsWith('.js') ? '' : '.js'}`\n );\n }\n}\n\n/**\n * Create a worker with initialization timeout and ready signal handling\n *\n * This is a higher-level function that creates a worker and waits for it\n * to signal that it's ready to receive messages.\n *\n * @param workerFilename - The name of the worker file\n * @param timeoutMs - Timeout in milliseconds (default: 10000)\n * @returns Promise that resolves to a ready Worker instance\n * @throws Error if worker creation fails or times out\n */\nexport function createReadyWorker(\n workerFilename: string,\n timeoutMs: number = 10000\n): Promise<Worker> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(\n `Worker initialization timeout after ${timeoutMs}ms. Worker file: ${workerFilename}`\n )\n );\n }, timeoutMs);\n\n let worker: Worker;\n try {\n worker = createCodecWorker(workerFilename);\n } catch (error) {\n clearTimeout(timeout);\n reject(error);\n return;\n }\n\n const handleMessage = (event: MessageEvent) => {\n if (event.data?.type === 'worker:ready') {\n clearTimeout(timeout);\n worker.removeEventListener('message', handleMessage);\n resolve(worker);\n }\n };\n\n worker.addEventListener('message', handleMessage);\n worker.postMessage({ type: 'worker:ping' });\n });\n}\n",
|
|
8
|
+
"/**\n * Bridge implementation for the WebP package, handling worker and client modes.\n */\n\nimport {\n callWorker,\n createReadyWorker,\n type ImageInput,\n} from '@squoosh-kit/runtime';\nimport { validateArrayBuffer, validateImageInput } from '@squoosh-kit/runtime';\nimport { webpEncodeClient } from './webp.worker.js';\nimport type { WebpOptions } from './types.js';\n\ninterface WebPBridge {\n encode(\n image: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n ): Promise<Uint8Array>;\n terminate(): Promise<void>;\n}\n\nclass WebpClientBridge implements WebPBridge {\n async encode(\n image: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n ): Promise<Uint8Array> {\n return webpEncodeClient(image, options, signal);\n }\n\n async terminate(): Promise<void> {\n // Client mode has nothing to terminate\n }\n}\n\nclass WebpWorkerBridge implements WebPBridge {\n private worker: Worker | null = null;\n private workerReady: Promise<Worker> | null = null;\n\n private async getWorker(): Promise<Worker> {\n if (!this.worker) {\n if (!this.workerReady) {\n this.workerReady = this.createWorker();\n }\n this.worker = await this.workerReady;\n }\n return this.worker;\n }\n\n private async createWorker(): Promise<Worker> {\n // Use the centralized worker helper for robust path resolution\n return createReadyWorker('webp.worker');\n }\n\n async encode(\n image: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n ): Promise<Uint8Array> {\n const worker = await this.getWorker();\n\n // Validate and normalize image - ensure all required properties exist\n if (!image || typeof image !== 'object') {\n throw new TypeError('image must be an object');\n }\n\n const imageRecord = image as Record<string, unknown>;\n if (!imageRecord.data) {\n throw new TypeError('image.data is required');\n }\n if (imageRecord.width === undefined || imageRecord.height === undefined) {\n throw new TypeError('image.width and image.height are required');\n }\n\n const normalizedImage: ImageInput = {\n data: imageRecord.data as Uint8Array | Uint8ClampedArray,\n width: imageRecord.width as number,\n height: imageRecord.height as number,\n };\n\n validateImageInput(normalizedImage);\n const buffer = normalizedImage.data.buffer;\n validateArrayBuffer(buffer);\n return callWorker(\n worker,\n 'webp:encode',\n { image: normalizedImage, options },\n signal,\n [buffer]\n );\n }\n\n async terminate(): Promise<void> {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.workerReady = null;\n }\n }\n}\n\nexport function createBridge(mode: 'worker' | 'client'): WebPBridge {\n return mode === 'client' ? new WebpClientBridge() : new WebpWorkerBridge();\n}\n"
|
|
9
|
+
],
|
|
10
|
+
"mappings": "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",
|
|
11
|
+
"debugId": "0D11351578D67A2764756E2164756E21",
|
|
12
|
+
"names": []
|
|
13
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{b as A,c as B,d as E}from"./webp.worker.node.mjs";function N(){return typeof Bun<"u"}var T=0;async function S(G,J,K,Y,H){return new Promise((X,Q)=>{let Z=++T;if(Y?.aborted){Q(new DOMException("Aborted","AbortError"));return}let V=(D)=>{let _=D.data;if(_.id!==Z)return;if($(),_.ok&&_.data!==void 0)X(_.data);else Q(Error(_.error||"Unknown worker error"))},O=(D)=>{$(),Q(Error(`Worker error: ${D.message}`))},x=()=>{$(),Q(new DOMException("Aborted","AbortError"))},$=()=>{G.removeEventListener("message",V),G.removeEventListener("error",O),Y?.removeEventListener("abort",x)};G.addEventListener("message",V),G.addEventListener("error",O),Y?.addEventListener("abort",x);let L={type:J,id:Z,payload:K};if(H&&H.length>0)G.postMessage(L,H);else G.postMessage(L)})}function q(G){let J=G.endsWith(".js")?G:`${G}.js`;if(typeof window<"u"){let Q={"webp.worker.js":"/dist/features/webp/webp.worker.browser.mjs","resize.worker.js":"/dist/features/resize/resize.worker.browser.mjs"}[J];if(Q)return new URL(Q,window.location.href)}let K=N()?".bun.js":".node.mjs",H={"webp.worker.js":`../../webp/dist/webp.worker${K}`,"resize.worker.js":`../../resize/dist/resize.worker${K}`}[J];if(H)return new URL(H,import.meta.url);return new URL(J,import.meta.url)}function z(G){let J=q(G);try{return new Worker(J.href,{type:"module"})}catch(K){let Y=K instanceof Error?K.message:String(K);throw Error(`Failed to create worker from ${J}: ${Y}. Ensure the worker file exists at the expected location. Expected worker file: ${G}${G.endsWith(".js")?"":".js"}`)}}function U(G,J=1e4){return new Promise((K,Y)=>{let H=setTimeout(()=>{Y(Error(`Worker initialization timeout after ${J}ms. Worker file: ${G}`))},J),X;try{X=z(G)}catch(Z){clearTimeout(H),Y(Z);return}let Q=(Z)=>{if(Z.data?.type==="worker:ready")clearTimeout(H),X.removeEventListener("message",Q),K(X)};X.addEventListener("message",Q),X.postMessage({type:"worker:ping"})})}class P{async encode(G,J,K){return E(G,J,K)}async terminate(){}}class I{worker=null;workerReady=null;async getWorker(){if(!this.worker){if(!this.workerReady)this.workerReady=this.createWorker();this.worker=await this.workerReady}return this.worker}async createWorker(){return U("webp.worker")}async encode(G,J,K){let Y=await this.getWorker();if(!G||typeof G!=="object")throw TypeError("image must be an object");let H=G;if(!H.data)throw TypeError("image.data is required");if(H.width===void 0||H.height===void 0)throw TypeError("image.width and image.height are required");let X={data:H.data,width:H.width,height:H.height};B(X);let Q=X.data.buffer;return A(Q),S(Y,"webp:encode",{image:X,options:J},K,[Q])}async terminate(){if(this.worker)this.worker.terminate(),this.worker=null,this.workerReady=null}}function v(G){return G==="client"?new P:new I}export{v as createBridge};
|
|
2
|
+
export{v as a};
|
|
3
|
+
|
|
4
|
+
//# debugId=5071F7E57E5AA63164756E2164756E21
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../runtime/src/env.ts", "../../runtime/src/worker-call.ts", "../../runtime/src/worker-helper.ts", "../src/bridge.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * Runtime environment detection utilities\n */\n\n/**\n * Detect if running in a Web Worker context\n */\nexport function isWorker(): boolean {\n return (\n typeof self !== 'undefined' &&\n typeof (globalThis as unknown as { DedicatedWorkerGlobalScope?: unknown })\n .DedicatedWorkerGlobalScope !== 'undefined'\n );\n}\n\n/**\n * Detect if running in a browser context\n */\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Detect if running in Bun\n */\nexport function isBun(): boolean {\n return typeof Bun !== 'undefined';\n}\n\n/**\n * Detect if running in Node.js\n */\nexport function isNode(): boolean {\n return (\n typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null\n );\n}\n\n/**\n * Check if ImageData is available in the current environment\n */\nexport function hasImageData(): boolean {\n return typeof ImageData !== 'undefined';\n}\n",
|
|
6
|
+
"/**\n * Generic worker communication helper with support for transferables and AbortSignal\n */\n\nexport interface WorkerRequest<T = unknown> {\n type: string;\n id: number;\n payload: T;\n}\n\nexport interface WorkerResponse<T = unknown> {\n id: number;\n ok: boolean;\n data?: T;\n error?: string;\n}\n\nlet requestId = 0;\n\n/**\n * Call a worker with a typed request and wait for response\n *\n * @param worker - The worker instance to call\n * @param type - The message type\n * @param payload - The payload to send\n * @param signal - Optional AbortSignal to cancel the operation\n * @param transfer - Optional list of Transferable objects to transfer\n * @returns Promise that resolves with the worker's response data\n */\nexport async function callWorker<TPayload, TResponse>(\n worker: Worker,\n type: string,\n payload: TPayload,\n signal?: AbortSignal,\n transfer?: Transferable[]\n): Promise<TResponse> {\n return new Promise<TResponse>((resolve, reject) => {\n const id = ++requestId;\n\n // Check if already aborted\n if (signal?.aborted) {\n reject(new DOMException('Aborted', 'AbortError'));\n return;\n }\n\n const handleMessage = (event: MessageEvent) => {\n const response = event.data as WorkerResponse<TResponse>;\n if (response.id !== id) return;\n\n cleanup();\n\n if (response.ok && response.data !== undefined) {\n resolve(response.data);\n } else {\n reject(new Error(response.error || 'Unknown worker error'));\n }\n };\n\n const handleError = (error: ErrorEvent) => {\n cleanup();\n reject(new Error(`Worker error: ${error.message}`));\n };\n\n const handleAbort = () => {\n cleanup();\n reject(new DOMException('Aborted', 'AbortError'));\n };\n\n const cleanup = () => {\n worker.removeEventListener('message', handleMessage);\n worker.removeEventListener('error', handleError);\n signal?.removeEventListener('abort', handleAbort);\n };\n\n // Set up listeners\n worker.addEventListener('message', handleMessage);\n worker.addEventListener('error', handleError);\n signal?.addEventListener('abort', handleAbort);\n\n // Send the request\n const request: WorkerRequest<TPayload> = { type, id, payload };\n\n if (transfer && transfer.length > 0) {\n worker.postMessage(request, transfer);\n } else {\n worker.postMessage(request);\n }\n });\n}\n",
|
|
7
|
+
"/**\n * Worker helper utilities for creating and managing Web Workers\n *\n * This module provides centralized logic for locating and creating worker files\n * in different environments (development, npm package, bundled, etc.)\n */\n\nimport { isBun } from './env';\n\n/**\n * Get the URL for a worker file\n *\n * This helper abstracts away the complexity of locating worker files\n * in different environments (development, npm package, bundled, etc.)\n *\n * @param workerFilename - The name of the worker file (with or without .js extension)\n * @returns URL object pointing to the worker file\n */\nexport function getWorkerURL(workerFilename: string): URL {\n // Ensure filename has correct format\n const normalizedName = workerFilename.endsWith('.js')\n ? workerFilename\n : `${workerFilename}.js`;\n\n // In browser contexts, use absolute paths from the server root\n // The server will route these to the correct locations\n if (typeof window !== 'undefined') {\n // Browser environment - use absolute paths with platform-specific extension\n const workerPathMap: Record<string, string> = {\n 'webp.worker.js': '/dist/features/webp/webp.worker.browser.mjs',\n 'resize.worker.js': '/dist/features/resize/resize.worker.browser.mjs',\n };\n\n const browserPath = workerPathMap[normalizedName];\n if (browserPath) {\n return new URL(browserPath, window.location.href);\n }\n }\n\n // Node.js/Bun: use relative path from runtime package location\n // Determine which platform variant to use\n const platformExt = isBun() ? '.bun.js' : '.node.mjs';\n\n const nodePathMap: Record<string, string> = {\n 'webp.worker.js': `../../webp/dist/webp.worker${platformExt}`,\n 'resize.worker.js': `../../resize/dist/resize.worker${platformExt}`,\n };\n\n const nodePath = nodePathMap[normalizedName];\n if (nodePath) {\n return new URL(nodePath, import.meta.url);\n }\n\n // Fallback: assume worker is in same directory as this module\n return new URL(normalizedName, import.meta.url);\n}\n\n/**\n * Create a Web Worker for a specific codec\n *\n * Handles environment-specific worker creation logic and provides\n * clear error messages when worker creation fails.\n *\n * @param workerFilename - The name of the worker file (e.g., 'resize.worker' or 'webp.worker')\n * @returns Worker instance\n * @throws Error if worker creation fails with detailed error message\n */\nexport function createCodecWorker(workerFilename: string): Worker {\n const workerURL = getWorkerURL(workerFilename);\n\n try {\n return new Worker(workerURL.href, { type: 'module' });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to create worker from ${workerURL}: ${errorMessage}. ` +\n `Ensure the worker file exists at the expected location. ` +\n `Expected worker file: ${workerFilename}${workerFilename.endsWith('.js') ? '' : '.js'}`\n );\n }\n}\n\n/**\n * Create a worker with initialization timeout and ready signal handling\n *\n * This is a higher-level function that creates a worker and waits for it\n * to signal that it's ready to receive messages.\n *\n * @param workerFilename - The name of the worker file\n * @param timeoutMs - Timeout in milliseconds (default: 10000)\n * @returns Promise that resolves to a ready Worker instance\n * @throws Error if worker creation fails or times out\n */\nexport function createReadyWorker(\n workerFilename: string,\n timeoutMs: number = 10000\n): Promise<Worker> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(\n new Error(\n `Worker initialization timeout after ${timeoutMs}ms. Worker file: ${workerFilename}`\n )\n );\n }, timeoutMs);\n\n let worker: Worker;\n try {\n worker = createCodecWorker(workerFilename);\n } catch (error) {\n clearTimeout(timeout);\n reject(error);\n return;\n }\n\n const handleMessage = (event: MessageEvent) => {\n if (event.data?.type === 'worker:ready') {\n clearTimeout(timeout);\n worker.removeEventListener('message', handleMessage);\n resolve(worker);\n }\n };\n\n worker.addEventListener('message', handleMessage);\n worker.postMessage({ type: 'worker:ping' });\n });\n}\n",
|
|
8
|
+
"/**\n * Bridge implementation for the WebP package, handling worker and client modes.\n */\n\nimport {\n callWorker,\n createReadyWorker,\n type ImageInput,\n} from '@squoosh-kit/runtime';\nimport { validateArrayBuffer, validateImageInput } from '@squoosh-kit/runtime';\nimport { webpEncodeClient } from './webp.worker.js';\nimport type { WebpOptions } from './types.js';\n\ninterface WebPBridge {\n encode(\n image: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n ): Promise<Uint8Array>;\n terminate(): Promise<void>;\n}\n\nclass WebpClientBridge implements WebPBridge {\n async encode(\n image: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n ): Promise<Uint8Array> {\n return webpEncodeClient(image, options, signal);\n }\n\n async terminate(): Promise<void> {\n // Client mode has nothing to terminate\n }\n}\n\nclass WebpWorkerBridge implements WebPBridge {\n private worker: Worker | null = null;\n private workerReady: Promise<Worker> | null = null;\n\n private async getWorker(): Promise<Worker> {\n if (!this.worker) {\n if (!this.workerReady) {\n this.workerReady = this.createWorker();\n }\n this.worker = await this.workerReady;\n }\n return this.worker;\n }\n\n private async createWorker(): Promise<Worker> {\n // Use the centralized worker helper for robust path resolution\n return createReadyWorker('webp.worker');\n }\n\n async encode(\n image: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n ): Promise<Uint8Array> {\n const worker = await this.getWorker();\n\n // Validate and normalize image - ensure all required properties exist\n if (!image || typeof image !== 'object') {\n throw new TypeError('image must be an object');\n }\n\n const imageRecord = image as Record<string, unknown>;\n if (!imageRecord.data) {\n throw new TypeError('image.data is required');\n }\n if (imageRecord.width === undefined || imageRecord.height === undefined) {\n throw new TypeError('image.width and image.height are required');\n }\n\n const normalizedImage: ImageInput = {\n data: imageRecord.data as Uint8Array | Uint8ClampedArray,\n width: imageRecord.width as number,\n height: imageRecord.height as number,\n };\n\n validateImageInput(normalizedImage);\n const buffer = normalizedImage.data.buffer;\n validateArrayBuffer(buffer);\n return callWorker(\n worker,\n 'webp:encode',\n { image: normalizedImage, options },\n signal,\n [buffer]\n );\n }\n\n async terminate(): Promise<void> {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n this.workerReady = null;\n }\n }\n}\n\nexport function createBridge(mode: 'worker' | 'client'): WebPBridge {\n return mode === 'client' ? new WebpClientBridge() : new WebpWorkerBridge();\n}\n"
|
|
9
|
+
],
|
|
10
|
+
"mappings": "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",
|
|
11
|
+
"debugId": "5071F7E57E5AA63164756E2164756E21",
|
|
12
|
+
"names": []
|
|
13
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var j=Object.create;var{getPrototypeOf:k,defineProperty:e,getOwnPropertyNames:h,getOwnPropertyDescriptor:l}=Object,i=Object.prototype.hasOwnProperty;var m=(a,b,c)=>{c=a!=null?j(k(a)):{};let d=b||!a||!a.__esModule?e(c,"default",{value:a,enumerable:!0}):c;for(let f of h(a))if(!i.call(d,f))e(d,f,{get:()=>a[f],enumerable:!0});return d},g=new WeakMap,n=(a)=>{var b=g.get(a),c;if(b)return b;if(b=e({},"__esModule",{value:!0}),a&&typeof a==="object"||typeof a==="function")h(a).map((d)=>!i.call(b,d)&&e(b,d,{get:()=>a[d],enumerable:!(c=l(a,d))||c.enumerable}));return g.set(a,b),b};var o=(a,b)=>{for(var c in b)e(a,c,{get:b[c],enumerable:!0,configurable:!0,set:(d)=>b[c]=()=>d})};
|
|
2
|
+
|
|
3
|
+
//# debugId=13132CCCB2E09AB364756E2164756E21
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{a as E}from"./bridge.browser.mjs";import"./webp.worker.browser.mjs";var z=null;async function J(y,j,q){if(!z)z=E("worker");return z.encode(y,j,q)}function K(y="worker"){let j=E(y),q=(F,G,H)=>{return j.encode(F,G,H)};return q.terminate=async()=>{await j.terminate()},q}export{J as encode,K as createWebpEncoder};
|
|
2
|
+
|
|
3
|
+
//# debugId=56B5D79F936C056264756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * @squoosh-kit/webp public API\n */\n\nimport type { ImageInput } from '@squoosh-kit/runtime';\nimport { createBridge } from './bridge';\nimport type { WebpOptions } from './types';\n\nexport type { ImageInput, WebpOptions };\n\n// Global bridge instance for reuse\nlet globalClientBridge: ReturnType<typeof createBridge> | null = null;\n\n/**\n * A WebP image encoder that can be reused for multiple operations.\n * Can be terminated to clean up associated resources (especially workers).\n */\nexport type WebpEncoderFactory = ((\n imageData: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n) => Promise<Uint8Array>) & {\n /**\n * Terminates the encoder and cleans up resources.\n * Important for worker mode to prevent memory leaks.\n *\n * @example\n * const encoder = createWebpEncoder('worker');\n * try {\n * const result = await encoder(imageData, options);\n * } finally {\n * await encoder.terminate();\n * }\n */\n terminate(): Promise<void>;\n};\n\n/**\n * Encodes an image to WebP format. Uses worker mode for UI responsiveness.\n *\n * @param imageData - The image data to encode.\n * @param options - WebP encoding options.\n * @param signal - (Optional) AbortSignal to cancel the encoding operation.\n * If provided, you can cancel the operation by calling\n * `controller.abort()` on the associated AbortController.\n * If not provided, the operation cannot be cancelled.\n * @returns A Promise resolving to the encoded WebP data as a Uint8Array.\n *\n * @example\n * // With cancellation support\n * const controller = new AbortController();\n * const result = await encode(imageData, { quality: 85 }, controller.signal);\n * setTimeout(() => controller.abort(), 5000);\n *\n * @example\n * // Without cancellation (operation cannot be stopped)\n * const result = await encode(imageData, { quality: 85 });\n */\nexport async function encode(\n imageData: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n): Promise<Uint8Array> {\n // Use worker mode for UI responsiveness - prevents blocking the main thread\n if (!globalClientBridge) {\n globalClientBridge = createBridge('worker');\n }\n\n return globalClientBridge.encode(imageData, options, signal);\n}\n\n/**\n * Creates a reusable WebP encoder function for a specific execution mode.\n * This is useful for processing multiple images without the overhead of\n * creating a new worker or client instance each time.\n *\n * @param mode - The execution mode, either 'worker' or 'client'.\n * @returns A function that encodes an image to WebP format with optional AbortSignal.\n */\nexport function createWebpEncoder(\n mode: 'worker' | 'client' = 'worker'\n): WebpEncoderFactory {\n const bridge = createBridge(mode);\n\n const encoder = (\n imageData: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n ) => {\n return bridge.encode(imageData, options, signal);\n };\n\n encoder.terminate = async () => {\n await bridge.terminate();\n };\n\n return encoder as WebpEncoderFactory;\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "2EAWA,IAAI,EAA6D,KA+CjE,eAAsB,CAAM,CAC1B,EACA,EACA,EACqB,CAErB,GAAI,CAAC,EACH,EAAqB,EAAa,QAAQ,EAG5C,OAAO,EAAmB,OAAO,EAAW,EAAS,CAAM,EAWtD,SAAS,CAAiB,CAC/B,EAA4B,SACR,CACpB,IAAM,EAAS,EAAa,CAAI,EAE1B,EAAU,CACd,EACA,EACA,IACG,CACH,OAAO,EAAO,OAAO,EAAW,EAAS,CAAM,GAOjD,OAJA,EAAQ,UAAY,SAAY,CAC9B,MAAM,EAAO,UAAU,GAGlB",
|
|
8
|
+
"debugId": "56B5D79F936C056264756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{a as E}from"./bridge.bun.js";import"./webp.worker.bun.js";var z=null;async function J(y,j,q){if(!z)z=E("worker");return z.encode(y,j,q)}function K(y="worker"){let j=E(y),q=(F,G,H)=>{return j.encode(F,G,H)};return q.terminate=async()=>{await j.terminate()},q}export{J as encode,K as createWebpEncoder};
|
|
3
|
+
|
|
4
|
+
//# debugId=F933FA0AE193052664756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"/**\n * @squoosh-kit/webp public API\n */\n\nimport type { ImageInput } from '@squoosh-kit/runtime';\nimport { createBridge } from './bridge';\nimport type { WebpOptions } from './types';\n\nexport type { ImageInput, WebpOptions };\n\n// Global bridge instance for reuse\nlet globalClientBridge: ReturnType<typeof createBridge> | null = null;\n\n/**\n * A WebP image encoder that can be reused for multiple operations.\n * Can be terminated to clean up associated resources (especially workers).\n */\nexport type WebpEncoderFactory = ((\n imageData: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n) => Promise<Uint8Array>) & {\n /**\n * Terminates the encoder and cleans up resources.\n * Important for worker mode to prevent memory leaks.\n *\n * @example\n * const encoder = createWebpEncoder('worker');\n * try {\n * const result = await encoder(imageData, options);\n * } finally {\n * await encoder.terminate();\n * }\n */\n terminate(): Promise<void>;\n};\n\n/**\n * Encodes an image to WebP format. Uses worker mode for UI responsiveness.\n *\n * @param imageData - The image data to encode.\n * @param options - WebP encoding options.\n * @param signal - (Optional) AbortSignal to cancel the encoding operation.\n * If provided, you can cancel the operation by calling\n * `controller.abort()` on the associated AbortController.\n * If not provided, the operation cannot be cancelled.\n * @returns A Promise resolving to the encoded WebP data as a Uint8Array.\n *\n * @example\n * // With cancellation support\n * const controller = new AbortController();\n * const result = await encode(imageData, { quality: 85 }, controller.signal);\n * setTimeout(() => controller.abort(), 5000);\n *\n * @example\n * // Without cancellation (operation cannot be stopped)\n * const result = await encode(imageData, { quality: 85 });\n */\nexport async function encode(\n imageData: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n): Promise<Uint8Array> {\n // Use worker mode for UI responsiveness - prevents blocking the main thread\n if (!globalClientBridge) {\n globalClientBridge = createBridge('worker');\n }\n\n return globalClientBridge.encode(imageData, options, signal);\n}\n\n/**\n * Creates a reusable WebP encoder function for a specific execution mode.\n * This is useful for processing multiple images without the overhead of\n * creating a new worker or client instance each time.\n *\n * @param mode - The execution mode, either 'worker' or 'client'.\n * @returns A function that encodes an image to WebP format with optional AbortSignal.\n */\nexport function createWebpEncoder(\n mode: 'worker' | 'client' = 'worker'\n): WebpEncoderFactory {\n const bridge = createBridge(mode);\n\n const encoder = (\n imageData: ImageInput,\n options?: WebpOptions,\n signal?: AbortSignal\n ) => {\n return bridge.encode(imageData, options, signal);\n };\n\n encoder.terminate = async () => {\n await bridge.terminate();\n };\n\n return encoder as WebpEncoderFactory;\n}\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";sEAWA,DAAI,EAA6D,KA+CjE,eAAsB,CAAM,CAC1B,EACA,EACA,EACqB,CAErB,GAAI,CAAC,EACH,EAAqB,EAAa,QAAQ,EAG5C,OAAO,EAAmB,OAAO,EAAW,EAAS,CAAM,EAWtD,SAAS,CAAiB,CAC/B,EAA4B,SACR,CACpB,IAAM,EAAS,EAAa,CAAI,EAE1B,EAAU,CACd,EACA,EACA,IACG,CACH,OAAO,EAAO,OAAO,EAAW,EAAS,CAAM,GAOjD,OAJA,EAAQ,UAAY,SAAY,CAC9B,MAAM,EAAO,UAAU,GAGlB",
|
|
8
|
+
"debugId": "F933FA0AE193052664756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|