@fest-lib/uniform 0.1.11 → 0.1.13
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 +31 -369
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,384 +1,46 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Uniform.TS
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`@fest-lib/uniform` — cross-context channels for fest-lib. One API over dedicated workers, SharedWorker, Service Worker, MessagePort, BroadcastChannel, WebSocket, Chrome extension ports, SharedArrayBuffer/Atomics, and WebRTC data channels.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Canonical runtime: `UnifiedChannel` / `createUnifiedChannel`. Invoker (`Requestor` / `Responder`) gives request/response across those transports. Legacy `createWorkerChannel` helpers remain under `src/original` and `src/newer/next/utils`.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- **Automatic Serialization**: Handles complex data types and transferables
|
|
9
|
-
- **Optimized Protocol**: Batching, timeouts, and error recovery
|
|
10
|
-
- **Type Safety**: Full TypeScript support with reflection
|
|
11
|
-
- **Performance**: Efficient message passing with minimal overhead
|
|
7
|
+
## Install
|
|
12
8
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
### Basic Usage
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
import { createWorkerChannel } from 'fest/uniform';
|
|
19
|
-
|
|
20
|
-
// Create a worker channel
|
|
21
|
-
const worker = await createWorkerChannel({
|
|
22
|
-
name: 'my-worker',
|
|
23
|
-
script: './my-worker.uniform.worker.ts'
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
// Call worker functions seamlessly
|
|
27
|
-
const result = await worker.request('processData', { data: 'hello' });
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### Queued Channels (Recommended)
|
|
31
|
-
|
|
32
|
-
```typescript
|
|
33
|
-
import { createQueuedWorkerChannel } from 'fest/uniform';
|
|
34
|
-
|
|
35
|
-
// Create queued channel - operations queue until worker is ready
|
|
36
|
-
const worker = new QueuedWorkerChannel({
|
|
37
|
-
name: 'my-worker',
|
|
38
|
-
script: './my-worker.uniform.worker.ts'
|
|
39
|
-
}, (channel) => {
|
|
40
|
-
console.log('Worker channel ready!');
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
// Operations will queue until the channel connects
|
|
44
|
-
const result = await worker.request('processData', { data: 'hello' });
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### Optimized Protocol
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
import { createOptimizedWorkerChannel } from 'fest/uniform';
|
|
51
|
-
|
|
52
|
-
// Create optimized channel with advanced features
|
|
53
|
-
const worker = await createOptimizedWorkerChannel({
|
|
54
|
-
name: 'my-worker',
|
|
55
|
-
script: './my-worker.uniform.worker.ts'
|
|
56
|
-
}, {
|
|
57
|
-
timeout: 10000,
|
|
58
|
-
retries: 3,
|
|
59
|
-
batching: true,
|
|
60
|
-
compression: false
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// Request with automatic batching and retry
|
|
64
|
-
const result = await worker.request('processData', { data: 'hello' });
|
|
65
|
-
|
|
66
|
-
// Fire-and-forget notifications
|
|
67
|
-
worker.notify('logMessage', 'Processing complete');
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### Queued Optimized Channels
|
|
71
|
-
|
|
72
|
-
```typescript
|
|
73
|
-
import { createQueuedOptimizedWorkerChannel } from 'fest/uniform';
|
|
74
|
-
|
|
75
|
-
// Best of both worlds: queuing + optimization
|
|
76
|
-
const worker = createQueuedOptimizedWorkerChannel({
|
|
77
|
-
name: 'my-worker',
|
|
78
|
-
script: './my-worker.uniform.worker.ts'
|
|
79
|
-
}, {
|
|
80
|
-
timeout: 10000,
|
|
81
|
-
retries: 3,
|
|
82
|
-
batching: true
|
|
83
|
-
}, (channel) => {
|
|
84
|
-
console.log('Optimized worker channel ready!');
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// Operations queue until ready, then use optimized protocol
|
|
88
|
-
const result = await worker.request('processData', { data: 'hello' });
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### Context-Specific Usage
|
|
92
|
-
|
|
93
|
-
#### Service Worker Context
|
|
94
|
-
```typescript
|
|
95
|
-
import { detectExecutionContext, createServiceWorkerChannel } from 'fest/uniform';
|
|
96
|
-
|
|
97
|
-
if (detectExecutionContext() === 'service-worker') {
|
|
98
|
-
// In service worker, use BroadcastChannel communication
|
|
99
|
-
const channel = await createServiceWorkerChannel({
|
|
100
|
-
name: 'sw-cache-worker',
|
|
101
|
-
script: './cache-worker.js'
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
// Communicate through BroadcastChannel
|
|
105
|
-
const result = await channel.request('cacheData', { data: 'important' });
|
|
106
|
-
}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
#### Chrome Extension Context
|
|
110
|
-
```typescript
|
|
111
|
-
import { createChromeExtensionChannel } from 'fest/uniform';
|
|
112
|
-
|
|
113
|
-
const worker = await createChromeExtensionChannel({
|
|
114
|
-
name: 'extension-worker',
|
|
115
|
-
script: 'workers/processor.js' // Will be resolved with chrome.runtime.getURL()
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
// Automatic extension URL resolution
|
|
119
|
-
const result = await worker.request('processExtensionData', data);
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
## Worker Implementation
|
|
123
|
-
|
|
124
|
-
### Basic Worker
|
|
125
|
-
|
|
126
|
-
```typescript
|
|
127
|
-
// my-worker.uniform.worker.ts
|
|
128
|
-
import { registerWorkerAPI } from 'fest/uniform';
|
|
129
|
-
|
|
130
|
-
const workerAPI = {
|
|
131
|
-
async processData(payload: { data: string }) {
|
|
132
|
-
// Process the data
|
|
133
|
-
return payload.data.toUpperCase();
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
async logMessage(message: string) {
|
|
137
|
-
console.log('[Worker]', message);
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
registerWorkerAPI(workerAPI);
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### Advanced Worker with Optimized Protocol
|
|
145
|
-
|
|
146
|
-
```typescript
|
|
147
|
-
// my-worker.uniform.worker.ts
|
|
148
|
-
import { registerWorkerAPI } from 'fest/uniform';
|
|
149
|
-
import { MessageEnvelope } from 'fest/uniform/src/optimized-protocol';
|
|
150
|
-
|
|
151
|
-
const workerAPI = {
|
|
152
|
-
async processData(payload: { data: string }) {
|
|
153
|
-
return payload.data.toUpperCase();
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
// Handle optimized protocol messages
|
|
158
|
-
const processMessage = async (envelope: MessageEnvelope) => {
|
|
159
|
-
if (envelope.type === 'batch') {
|
|
160
|
-
const results = [];
|
|
161
|
-
for (const msg of envelope.payload) {
|
|
162
|
-
results.push(await processSingleMessage(msg));
|
|
163
|
-
}
|
|
164
|
-
return results;
|
|
165
|
-
}
|
|
166
|
-
return await processSingleMessage(envelope);
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
const processSingleMessage = async (envelope: MessageEnvelope) => {
|
|
170
|
-
const handler = workerAPI[envelope.type as keyof typeof workerAPI];
|
|
171
|
-
if (!handler) {
|
|
172
|
-
throw new Error(`Unknown message type: ${envelope.type}`);
|
|
173
|
-
}
|
|
174
|
-
return await handler(envelope.payload);
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
// Register API and message processor
|
|
178
|
-
registerWorkerAPI(workerAPI);
|
|
179
|
-
(globalThis as any).processMessage = processMessage;
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
## API Reference
|
|
183
|
-
|
|
184
|
-
### Core Functions
|
|
185
|
-
|
|
186
|
-
#### `createWorkerChannel(config: WorkerConfig): Promise<WorkerChannel>`
|
|
187
|
-
|
|
188
|
-
Creates a basic worker channel.
|
|
189
|
-
|
|
190
|
-
**Parameters:**
|
|
191
|
-
- `config.name`: Unique channel name
|
|
192
|
-
- `config.script`: Path to worker script
|
|
193
|
-
- `config.options`: Worker options
|
|
194
|
-
|
|
195
|
-
#### `createOptimizedWorkerChannel(config: WorkerConfig, options?: ProtocolOptions): Promise<OptimizedWorkerChannel>`
|
|
196
|
-
|
|
197
|
-
Creates an optimized worker channel with advanced features.
|
|
198
|
-
|
|
199
|
-
**Protocol Options:**
|
|
200
|
-
- `timeout`: Request timeout in milliseconds (default: 30000)
|
|
201
|
-
- `retries`: Number of retry attempts (default: 3)
|
|
202
|
-
- `batching`: Enable message batching (default: true)
|
|
203
|
-
- `compression`: Enable payload compression (default: false)
|
|
204
|
-
|
|
205
|
-
### WorkerChannel Methods
|
|
206
|
-
|
|
207
|
-
#### `request(method: string, args: any[]): Promise<any>`
|
|
208
|
-
|
|
209
|
-
Call a worker method and wait for response.
|
|
210
|
-
|
|
211
|
-
#### `close(): void`
|
|
212
|
-
|
|
213
|
-
Close the worker channel.
|
|
214
|
-
|
|
215
|
-
### OptimizedWorkerChannel Methods
|
|
216
|
-
|
|
217
|
-
#### `request(type: string, payload: any, options?: Partial<ProtocolOptions>): Promise<any>`
|
|
218
|
-
|
|
219
|
-
Send request with optimization features.
|
|
220
|
-
|
|
221
|
-
#### `notify(type: string, payload: any): void`
|
|
222
|
-
|
|
223
|
-
Send fire-and-forget message.
|
|
224
|
-
|
|
225
|
-
#### `stream(type: string, data: any[]): AsyncGenerator<any>`
|
|
226
|
-
|
|
227
|
-
Stream data with backpressure handling.
|
|
228
|
-
|
|
229
|
-
## Advanced Features
|
|
230
|
-
|
|
231
|
-
### Message Batching
|
|
232
|
-
|
|
233
|
-
Automatically batches multiple messages to reduce overhead:
|
|
234
|
-
|
|
235
|
-
```typescript
|
|
236
|
-
const worker = await createOptimizedWorkerChannel(config, { batching: true });
|
|
237
|
-
|
|
238
|
-
// These calls will be batched automatically
|
|
239
|
-
await Promise.all([
|
|
240
|
-
worker.request('method1', data1),
|
|
241
|
-
worker.request('method2', data2),
|
|
242
|
-
worker.request('method3', data3)
|
|
243
|
-
]);
|
|
9
|
+
```bash
|
|
10
|
+
npm install @fest-lib/uniform
|
|
244
11
|
```
|
|
245
12
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
});
|
|
13
|
+
```ts
|
|
14
|
+
import {
|
|
15
|
+
createUnifiedChannel,
|
|
16
|
+
createInvoker,
|
|
17
|
+
detectContextType
|
|
18
|
+
} from "@fest-lib/uniform";
|
|
253
19
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
} catch (error) {
|
|
257
|
-
console.error('All retries failed:', error);
|
|
258
|
-
}
|
|
20
|
+
const channel = createUnifiedChannel({ name: "opfs" });
|
|
21
|
+
const invoker = createInvoker(channel);
|
|
259
22
|
```
|
|
260
23
|
|
|
261
|
-
|
|
24
|
+
Worker-style (queued until ready):
|
|
262
25
|
|
|
263
|
-
```
|
|
264
|
-
|
|
26
|
+
```ts
|
|
27
|
+
import { createQueuedWorkerChannel } from "@fest-lib/uniform";
|
|
265
28
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
29
|
+
const worker = createQueuedWorkerChannel(
|
|
30
|
+
{ name: "my-worker", script: "./my-worker.uniform.worker.ts" },
|
|
31
|
+
() => { /* connected */ }
|
|
32
|
+
);
|
|
33
|
+
const result = await worker.request("processData", { data: "hello" });
|
|
270
34
|
```
|
|
271
35
|
|
|
272
|
-
##
|
|
273
|
-
|
|
274
|
-
### OPFS Worker (Real Example)
|
|
275
|
-
|
|
276
|
-
```typescript
|
|
277
|
-
// From fest/lure OPFS implementation
|
|
278
|
-
import { createOptimizedWorkerChannel } from 'fest/uniform';
|
|
279
|
-
|
|
280
|
-
const workerChannel = await createOptimizedWorkerChannel({
|
|
281
|
-
name: "opfs-worker",
|
|
282
|
-
script: "./OPFS.uniform.worker.ts"
|
|
283
|
-
}, {
|
|
284
|
-
timeout: 10000,
|
|
285
|
-
batching: true
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
// Use like a regular function call
|
|
289
|
-
const result = await workerChannel.request('readFile', {
|
|
290
|
-
rootId: 'user',
|
|
291
|
-
path: '/data.json'
|
|
292
|
-
});
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
## Performance Benefits
|
|
296
|
-
|
|
297
|
-
- **Reduced Latency**: Message batching minimizes round trips
|
|
298
|
-
- **Better Throughput**: Optimized serialization and transfer handling
|
|
299
|
-
- **Automatic Retry**: Built-in error recovery
|
|
300
|
-
- **Memory Efficient**: Proper transferable object handling
|
|
301
|
-
- **Type Safe**: Full TypeScript support across worker boundaries
|
|
302
|
-
|
|
303
|
-
## Migration from postMessage
|
|
304
|
-
|
|
305
|
-
### Before (Traditional)
|
|
306
|
-
|
|
307
|
-
```typescript
|
|
308
|
-
const worker = new Worker('./worker.js');
|
|
309
|
-
|
|
310
|
-
worker.postMessage({ type: 'process', data });
|
|
311
|
-
|
|
312
|
-
worker.onmessage = (e) => {
|
|
313
|
-
const { result, error } = e.data;
|
|
314
|
-
if (error) handleError(error);
|
|
315
|
-
else handleResult(result);
|
|
316
|
-
};
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
### After (Uniform)
|
|
320
|
-
|
|
321
|
-
```typescript
|
|
322
|
-
const worker = await createWorkerChannel({
|
|
323
|
-
name: 'my-worker',
|
|
324
|
-
script: './worker.uniform.worker.ts'
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
try {
|
|
328
|
-
const result = await worker.request('process', data);
|
|
329
|
-
handleResult(result);
|
|
330
|
-
} catch (error) {
|
|
331
|
-
handleError(error);
|
|
332
|
-
}
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
## Execution Context Support
|
|
336
|
-
|
|
337
|
-
Fest/Uniform automatically adapts to different JavaScript execution contexts:
|
|
338
|
-
|
|
339
|
-
### Main Thread Context
|
|
340
|
-
- Full dedicated worker support
|
|
341
|
-
- MessageChannel communication
|
|
342
|
-
- All optimization features available
|
|
343
|
-
|
|
344
|
-
### Service Worker Context
|
|
345
|
-
- BroadcastChannel-based communication
|
|
346
|
-
- No dedicated worker creation (not supported)
|
|
347
|
-
- Queued operations with fallback handling
|
|
348
|
-
|
|
349
|
-
### Chrome Extension Context
|
|
350
|
-
- Dedicated worker support with extension URL resolution
|
|
351
|
-
- Automatic detection of extension environment
|
|
352
|
-
- Fallback communication patterns
|
|
353
|
-
|
|
354
|
-
### Context Detection
|
|
355
|
-
```typescript
|
|
356
|
-
import { detectExecutionContext, supportsDedicatedWorkers } from 'fest/uniform';
|
|
357
|
-
|
|
358
|
-
const context = detectExecutionContext(); // 'main' | 'service-worker' | 'chrome-extension' | 'unknown'
|
|
359
|
-
const hasWorkers = supportsDedicatedWorkers(); // boolean
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
## Browser Support
|
|
363
|
-
|
|
364
|
-
Requires modern browsers with:
|
|
365
|
-
- ES2020 modules
|
|
366
|
-
- MessageChannel API (main thread)
|
|
367
|
-
- BroadcastChannel API (service workers)
|
|
368
|
-
- Proxy API
|
|
369
|
-
- WeakRef (optional)
|
|
370
|
-
|
|
371
|
-
Compatible with all Chromium-based browsers and modern Firefox/Safari.
|
|
372
|
-
|
|
373
|
-
## Examples
|
|
374
|
-
|
|
375
|
-
- [Service Worker Integration](./examples/service-worker-integration.ts) - Using uniform channels in service worker context
|
|
376
|
-
- [Chrome Extension Integration](./examples/chrome-extension-integration.ts) - Chrome extension worker communication
|
|
377
|
-
|
|
378
|
-
## Contributing
|
|
379
|
-
|
|
380
|
-
This library is experimental and evolving. Contributions welcome!
|
|
36
|
+
## Layout
|
|
381
37
|
|
|
382
|
-
|
|
38
|
+
| Path | Role |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| `src/newer/next/channel/UnifiedChannel.ts` | primary channel |
|
|
41
|
+
| `src/newer/next/proxy/Invoker.ts` | request/response |
|
|
42
|
+
| `src/newer/core/TransportCore.ts` | transport factory |
|
|
43
|
+
| `src/newer/messaging/*` | queues / protocol |
|
|
44
|
+
| `src/original/*` | older worker helpers |
|
|
383
45
|
|
|
384
|
-
|
|
46
|
+
Peer: `@fest-lib/core`. Build: `npm run build`. Publish: `npm run publish`.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fest-lib/uniform",
|
|
3
|
-
"description": "
|
|
4
|
-
"version": "0.1.
|
|
3
|
+
"description": "fest-lib UnifiedChannel: workers, ports, BroadcastChannel, Chrome, Atomics, WebRTC",
|
|
4
|
+
"version": "0.1.13",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"sideEffects": true,
|