@computekit/core 0.1.2 → 0.2.0
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/dist/index.cjs +80 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +138 -14
- package/dist/index.d.ts +138 -14
- package/dist/index.js +80 -8
- package/dist/index.js.map +1 -1
- package/dist/types-BNUPDwV-.d.cts +363 -0
- package/dist/types-BNUPDwV-.d.ts +363 -0
- package/dist/worker.cjs +54 -2
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.cts +1 -1
- package/dist/worker.d.ts +1 -1
- package/dist/worker.js +54 -2
- package/dist/worker.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +154 -28
- package/src/pool.ts +9 -1
- package/src/registry.ts +132 -0
- package/src/types.ts +222 -0
- package/src/utils.ts +74 -0
- package/src/worker/runtime.ts +8 -1
- package/dist/types-2XRPtzH9.d.cts +0 -145
- package/dist/types-2XRPtzH9.d.ts +0 -145
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ComputeKit Core Types
|
|
3
|
+
* Type definitions for the WASM + Worker toolkit
|
|
4
|
+
*/
|
|
5
|
+
/** Configuration options for ComputeKit */
|
|
6
|
+
interface ComputeKitOptions {
|
|
7
|
+
/** Maximum number of workers in the pool (default: navigator.hardwareConcurrency || 4) */
|
|
8
|
+
maxWorkers?: number;
|
|
9
|
+
/** Timeout for compute operations in milliseconds (default: 30000) */
|
|
10
|
+
timeout?: number;
|
|
11
|
+
/** Enable debug logging (default: false) */
|
|
12
|
+
debug?: boolean;
|
|
13
|
+
/** Custom path to worker script */
|
|
14
|
+
workerPath?: string;
|
|
15
|
+
/** Whether to use SharedArrayBuffer when available (default: true) */
|
|
16
|
+
useSharedMemory?: boolean;
|
|
17
|
+
/** Remote scripts to load in workers via importScripts */
|
|
18
|
+
remoteDependencies?: string[];
|
|
19
|
+
}
|
|
20
|
+
/** Options for individual compute operations */
|
|
21
|
+
interface ComputeOptions {
|
|
22
|
+
/** Timeout for this specific operation (overrides global) */
|
|
23
|
+
timeout?: number;
|
|
24
|
+
/** Transfer these ArrayBuffers to the worker (improves performance) */
|
|
25
|
+
transfer?: ArrayBuffer[];
|
|
26
|
+
/** Priority level for scheduling (0-10, higher = more priority) */
|
|
27
|
+
priority?: number;
|
|
28
|
+
/** Abort signal to cancel the operation */
|
|
29
|
+
signal?: AbortSignal;
|
|
30
|
+
/** Progress callback for long-running operations */
|
|
31
|
+
onProgress?: (progress: ComputeProgress) => void;
|
|
32
|
+
}
|
|
33
|
+
/** Progress information for compute operations */
|
|
34
|
+
interface ComputeProgress {
|
|
35
|
+
/** Progress percentage (0-100) */
|
|
36
|
+
percent: number;
|
|
37
|
+
/** Current step/phase name */
|
|
38
|
+
phase?: string;
|
|
39
|
+
/** Estimated time remaining in milliseconds */
|
|
40
|
+
estimatedTimeRemaining?: number;
|
|
41
|
+
/** Any additional data from the compute function */
|
|
42
|
+
data?: unknown;
|
|
43
|
+
}
|
|
44
|
+
/** Result wrapper with metadata */
|
|
45
|
+
interface ComputeResult<T> {
|
|
46
|
+
/** The computed result */
|
|
47
|
+
data: T;
|
|
48
|
+
/** Time taken in milliseconds */
|
|
49
|
+
duration: number;
|
|
50
|
+
/** Whether the result came from cache */
|
|
51
|
+
cached: boolean;
|
|
52
|
+
/** Worker ID that processed this */
|
|
53
|
+
workerId: string;
|
|
54
|
+
/** Size of input data in bytes (available in debug mode) */
|
|
55
|
+
inputSize?: number;
|
|
56
|
+
/** Size of output data in bytes (available in debug mode) */
|
|
57
|
+
outputSize?: number;
|
|
58
|
+
}
|
|
59
|
+
/** Function definition for registration */
|
|
60
|
+
interface ComputeFunction<TInput = unknown, TOutput = unknown> {
|
|
61
|
+
/** The compute function implementation */
|
|
62
|
+
fn: (input: TInput) => TOutput | Promise<TOutput>;
|
|
63
|
+
/** Optional WASM module to load */
|
|
64
|
+
wasmModule?: WebAssembly.Module | ArrayBuffer | string;
|
|
65
|
+
/** Whether this function supports progress reporting */
|
|
66
|
+
supportsProgress?: boolean;
|
|
67
|
+
}
|
|
68
|
+
/** WASM module configuration */
|
|
69
|
+
interface WasmModuleConfig {
|
|
70
|
+
/** Path to the WASM file or base64 encoded WASM */
|
|
71
|
+
source: string | ArrayBuffer;
|
|
72
|
+
/** Imports to provide to the WASM module */
|
|
73
|
+
imports?: WebAssembly.Imports;
|
|
74
|
+
/** Memory configuration */
|
|
75
|
+
memory?: {
|
|
76
|
+
initial: number;
|
|
77
|
+
maximum?: number;
|
|
78
|
+
shared?: boolean;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/** Worker state */
|
|
82
|
+
type WorkerState = 'idle' | 'busy' | 'error' | 'terminated';
|
|
83
|
+
/** Worker info */
|
|
84
|
+
interface WorkerInfo {
|
|
85
|
+
id: string;
|
|
86
|
+
state: WorkerState;
|
|
87
|
+
currentTask?: string;
|
|
88
|
+
tasksCompleted: number;
|
|
89
|
+
errors: number;
|
|
90
|
+
createdAt: number;
|
|
91
|
+
lastActiveAt: number;
|
|
92
|
+
}
|
|
93
|
+
/** Pool statistics */
|
|
94
|
+
interface PoolStats {
|
|
95
|
+
workers: WorkerInfo[];
|
|
96
|
+
totalWorkers: number;
|
|
97
|
+
activeWorkers: number;
|
|
98
|
+
idleWorkers: number;
|
|
99
|
+
queueLength: number;
|
|
100
|
+
tasksCompleted: number;
|
|
101
|
+
tasksFailed: number;
|
|
102
|
+
averageTaskDuration: number;
|
|
103
|
+
}
|
|
104
|
+
/** Event data for worker:created */
|
|
105
|
+
interface WorkerCreatedEvent {
|
|
106
|
+
info: WorkerInfo;
|
|
107
|
+
}
|
|
108
|
+
/** Event data for worker:terminated */
|
|
109
|
+
interface WorkerTerminatedEvent {
|
|
110
|
+
info: WorkerInfo;
|
|
111
|
+
}
|
|
112
|
+
/** Event data for worker:error */
|
|
113
|
+
interface WorkerErrorEvent {
|
|
114
|
+
error: Error;
|
|
115
|
+
info: WorkerInfo;
|
|
116
|
+
}
|
|
117
|
+
/** Event data for task:start */
|
|
118
|
+
interface TaskStartEvent {
|
|
119
|
+
taskId: string;
|
|
120
|
+
functionName: string;
|
|
121
|
+
}
|
|
122
|
+
/** Event data for task:complete */
|
|
123
|
+
interface TaskCompleteEvent {
|
|
124
|
+
taskId: string;
|
|
125
|
+
duration: number;
|
|
126
|
+
}
|
|
127
|
+
/** Event data for task:error */
|
|
128
|
+
interface TaskErrorEvent {
|
|
129
|
+
taskId: string;
|
|
130
|
+
error: Error;
|
|
131
|
+
}
|
|
132
|
+
/** Event data for task:progress */
|
|
133
|
+
interface TaskProgressEvent {
|
|
134
|
+
taskId: string;
|
|
135
|
+
progress: ComputeProgress;
|
|
136
|
+
}
|
|
137
|
+
/** Events emitted by ComputeKit */
|
|
138
|
+
type ComputeKitEvents = {
|
|
139
|
+
'worker:created': WorkerCreatedEvent;
|
|
140
|
+
'worker:terminated': WorkerTerminatedEvent;
|
|
141
|
+
'worker:error': WorkerErrorEvent;
|
|
142
|
+
'task:start': TaskStartEvent;
|
|
143
|
+
'task:complete': TaskCompleteEvent;
|
|
144
|
+
'task:error': TaskErrorEvent;
|
|
145
|
+
'task:progress': TaskProgressEvent;
|
|
146
|
+
[key: string]: unknown;
|
|
147
|
+
};
|
|
148
|
+
/** Status of a pipeline stage */
|
|
149
|
+
type StageStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped';
|
|
150
|
+
/** Detailed information about a single pipeline stage */
|
|
151
|
+
interface StageInfo<TInput = unknown, TOutput = unknown> {
|
|
152
|
+
/** Unique identifier for the stage */
|
|
153
|
+
id: string;
|
|
154
|
+
/** Display name for the stage */
|
|
155
|
+
name: string;
|
|
156
|
+
/** Name of the registered compute function to execute */
|
|
157
|
+
functionName: string;
|
|
158
|
+
/** Current status of this stage */
|
|
159
|
+
status: StageStatus;
|
|
160
|
+
/** Input data for this stage (set when stage starts) */
|
|
161
|
+
input?: TInput;
|
|
162
|
+
/** Output data from this stage (set when stage completes) */
|
|
163
|
+
output?: TOutput;
|
|
164
|
+
/** Error if stage failed */
|
|
165
|
+
error?: Error;
|
|
166
|
+
/** Start timestamp (ms since epoch) */
|
|
167
|
+
startedAt?: number;
|
|
168
|
+
/** End timestamp (ms since epoch) */
|
|
169
|
+
completedAt?: number;
|
|
170
|
+
/** Duration in milliseconds */
|
|
171
|
+
duration?: number;
|
|
172
|
+
/** Progress within this stage (0-100) */
|
|
173
|
+
progress?: number;
|
|
174
|
+
/** Number of retry attempts */
|
|
175
|
+
retryCount: number;
|
|
176
|
+
/** Compute options specific to this stage */
|
|
177
|
+
options?: ComputeOptions;
|
|
178
|
+
}
|
|
179
|
+
/** Pipeline execution mode */
|
|
180
|
+
type PipelineMode = 'sequential' | 'parallel';
|
|
181
|
+
/** Configuration for a pipeline stage */
|
|
182
|
+
interface StageConfig<TInput = unknown, TOutput = unknown> {
|
|
183
|
+
/** Unique identifier for the stage */
|
|
184
|
+
id: string;
|
|
185
|
+
/** Display name for the stage */
|
|
186
|
+
name: string;
|
|
187
|
+
/** Name of the registered compute function */
|
|
188
|
+
functionName: string;
|
|
189
|
+
/** Transform input before passing to compute function */
|
|
190
|
+
transformInput?: (input: TInput, previousResults: unknown[]) => unknown;
|
|
191
|
+
/** Transform output after compute function returns */
|
|
192
|
+
transformOutput?: (output: unknown) => TOutput;
|
|
193
|
+
/** Whether to skip this stage based on previous results */
|
|
194
|
+
shouldSkip?: (input: TInput, previousResults: unknown[]) => boolean;
|
|
195
|
+
/** Maximum retry attempts on failure (default: 0) */
|
|
196
|
+
maxRetries?: number;
|
|
197
|
+
/** Delay between retries in ms (default: 1000) */
|
|
198
|
+
retryDelay?: number;
|
|
199
|
+
/** Compute options for this stage */
|
|
200
|
+
options?: ComputeOptions;
|
|
201
|
+
}
|
|
202
|
+
/** Overall pipeline status */
|
|
203
|
+
type PipelineStatus = 'idle' | 'running' | 'paused' | 'completed' | 'failed' | 'cancelled';
|
|
204
|
+
/** Comprehensive pipeline state for debugging */
|
|
205
|
+
interface PipelineState<TInput = unknown, TOutput = unknown> {
|
|
206
|
+
/** Overall pipeline status */
|
|
207
|
+
status: PipelineStatus;
|
|
208
|
+
/** All stage information */
|
|
209
|
+
stages: StageInfo[];
|
|
210
|
+
/** Index of currently executing stage (-1 if not running) */
|
|
211
|
+
currentStageIndex: number;
|
|
212
|
+
/** Current stage info (convenience) */
|
|
213
|
+
currentStage: StageInfo | null;
|
|
214
|
+
/** Overall progress percentage (0-100) */
|
|
215
|
+
progress: number;
|
|
216
|
+
/** Final output from the last stage */
|
|
217
|
+
output: TOutput | null;
|
|
218
|
+
/** Initial input that started the pipeline */
|
|
219
|
+
input: TInput | null;
|
|
220
|
+
/** Error that caused pipeline failure */
|
|
221
|
+
error: Error | null;
|
|
222
|
+
/** Pipeline start timestamp */
|
|
223
|
+
startedAt: number | null;
|
|
224
|
+
/** Pipeline completion timestamp */
|
|
225
|
+
completedAt: number | null;
|
|
226
|
+
/** Total duration in milliseconds */
|
|
227
|
+
totalDuration: number | null;
|
|
228
|
+
/** Results from each completed stage */
|
|
229
|
+
stageResults: unknown[];
|
|
230
|
+
/** Execution metrics for debugging */
|
|
231
|
+
metrics: PipelineMetrics;
|
|
232
|
+
}
|
|
233
|
+
/** Metrics for pipeline debugging and reporting */
|
|
234
|
+
interface PipelineMetrics {
|
|
235
|
+
/** Total stages in pipeline */
|
|
236
|
+
totalStages: number;
|
|
237
|
+
/** Number of completed stages */
|
|
238
|
+
completedStages: number;
|
|
239
|
+
/** Number of failed stages */
|
|
240
|
+
failedStages: number;
|
|
241
|
+
/** Number of skipped stages */
|
|
242
|
+
skippedStages: number;
|
|
243
|
+
/** Total retry attempts across all stages */
|
|
244
|
+
totalRetries: number;
|
|
245
|
+
/** Slowest stage info */
|
|
246
|
+
slowestStage: {
|
|
247
|
+
id: string;
|
|
248
|
+
name: string;
|
|
249
|
+
duration: number;
|
|
250
|
+
} | null;
|
|
251
|
+
/** Fastest stage info */
|
|
252
|
+
fastestStage: {
|
|
253
|
+
id: string;
|
|
254
|
+
name: string;
|
|
255
|
+
duration: number;
|
|
256
|
+
} | null;
|
|
257
|
+
/** Average stage duration */
|
|
258
|
+
averageStageDuration: number;
|
|
259
|
+
/** Timestamp of each stage transition for timeline view */
|
|
260
|
+
timeline: Array<{
|
|
261
|
+
stageId: string;
|
|
262
|
+
stageName: string;
|
|
263
|
+
event: 'started' | 'completed' | 'failed' | 'skipped' | 'retry';
|
|
264
|
+
timestamp: number;
|
|
265
|
+
duration?: number;
|
|
266
|
+
error?: string;
|
|
267
|
+
}>;
|
|
268
|
+
}
|
|
269
|
+
/** Pipeline configuration options */
|
|
270
|
+
interface PipelineOptions {
|
|
271
|
+
/** Execution mode (default: 'sequential') */
|
|
272
|
+
mode?: PipelineMode;
|
|
273
|
+
/** Stop pipeline on first stage failure (default: true) */
|
|
274
|
+
stopOnError?: boolean;
|
|
275
|
+
/** Global timeout for entire pipeline in ms */
|
|
276
|
+
timeout?: number;
|
|
277
|
+
/** Enable detailed timeline tracking (default: true) */
|
|
278
|
+
trackTimeline?: boolean;
|
|
279
|
+
/** Called when pipeline state changes */
|
|
280
|
+
onStateChange?: (state: PipelineState) => void;
|
|
281
|
+
/** Called when a stage starts */
|
|
282
|
+
onStageStart?: (stage: StageInfo) => void;
|
|
283
|
+
/** Called when a stage completes */
|
|
284
|
+
onStageComplete?: (stage: StageInfo) => void;
|
|
285
|
+
/** Called when a stage fails */
|
|
286
|
+
onStageError?: (stage: StageInfo, error: Error) => void;
|
|
287
|
+
/** Called when a stage is retried */
|
|
288
|
+
onStageRetry?: (stage: StageInfo, attempt: number) => void;
|
|
289
|
+
}
|
|
290
|
+
/** Events emitted by Pipeline */
|
|
291
|
+
interface PipelineEvents {
|
|
292
|
+
'pipeline:start': {
|
|
293
|
+
input: unknown;
|
|
294
|
+
};
|
|
295
|
+
'pipeline:complete': {
|
|
296
|
+
output: unknown;
|
|
297
|
+
duration: number;
|
|
298
|
+
};
|
|
299
|
+
'pipeline:error': {
|
|
300
|
+
error: Error;
|
|
301
|
+
stageId: string;
|
|
302
|
+
};
|
|
303
|
+
'pipeline:cancel': {
|
|
304
|
+
stageId: string;
|
|
305
|
+
};
|
|
306
|
+
'stage:start': StageInfo;
|
|
307
|
+
'stage:progress': {
|
|
308
|
+
stageId: string;
|
|
309
|
+
progress: number;
|
|
310
|
+
};
|
|
311
|
+
'stage:complete': StageInfo;
|
|
312
|
+
'stage:error': {
|
|
313
|
+
stage: StageInfo;
|
|
314
|
+
error: Error;
|
|
315
|
+
};
|
|
316
|
+
'stage:skip': StageInfo;
|
|
317
|
+
'stage:retry': {
|
|
318
|
+
stage: StageInfo;
|
|
319
|
+
attempt: number;
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
/** Configuration for parallel batch processing */
|
|
323
|
+
interface ParallelBatchConfig<TItem = unknown> {
|
|
324
|
+
/** Items to process in parallel */
|
|
325
|
+
items: TItem[];
|
|
326
|
+
/** Name of the registered compute function */
|
|
327
|
+
functionName: string;
|
|
328
|
+
/** Maximum concurrent executions (default: all) */
|
|
329
|
+
concurrency?: number;
|
|
330
|
+
/** Compute options for batch items */
|
|
331
|
+
options?: ComputeOptions;
|
|
332
|
+
}
|
|
333
|
+
/** Result of a single item in parallel batch */
|
|
334
|
+
interface BatchItemResult<TOutput = unknown> {
|
|
335
|
+
/** Index of the item in original array */
|
|
336
|
+
index: number;
|
|
337
|
+
/** Whether this item succeeded */
|
|
338
|
+
success: boolean;
|
|
339
|
+
/** Result if successful */
|
|
340
|
+
data?: TOutput;
|
|
341
|
+
/** Error if failed */
|
|
342
|
+
error?: Error;
|
|
343
|
+
/** Duration in ms */
|
|
344
|
+
duration: number;
|
|
345
|
+
}
|
|
346
|
+
/** Aggregate result of parallel batch processing */
|
|
347
|
+
interface ParallelBatchResult<TOutput = unknown> {
|
|
348
|
+
/** All individual results */
|
|
349
|
+
results: BatchItemResult<TOutput>[];
|
|
350
|
+
/** Successfully processed items */
|
|
351
|
+
successful: TOutput[];
|
|
352
|
+
/** Failed items with their errors */
|
|
353
|
+
failed: Array<{
|
|
354
|
+
index: number;
|
|
355
|
+
error: Error;
|
|
356
|
+
}>;
|
|
357
|
+
/** Total duration */
|
|
358
|
+
totalDuration: number;
|
|
359
|
+
/** Success rate (0-1) */
|
|
360
|
+
successRate: number;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export type { BatchItemResult as B, ComputeKitOptions as C, PoolStats as P, StageStatus as S, WasmModuleConfig as W, ComputeOptions as a, ComputeKitEvents as b, ComputeResult as c, ComputeProgress as d, ComputeFunction as e, WorkerInfo as f, StageInfo as g, StageConfig as h, PipelineMode as i, PipelineStatus as j, PipelineState as k, PipelineMetrics as l, PipelineOptions as m, PipelineEvents as n, ParallelBatchConfig as o, ParallelBatchResult as p };
|
package/dist/worker.cjs
CHANGED
|
@@ -51,6 +51,53 @@ function findTransferables(data) {
|
|
|
51
51
|
traverse(data);
|
|
52
52
|
return transferables;
|
|
53
53
|
}
|
|
54
|
+
function estimatePayloadSize(value) {
|
|
55
|
+
if (value === null || value === void 0) return 0;
|
|
56
|
+
if (typeof value === "boolean") return 4;
|
|
57
|
+
if (typeof value === "number") return 8;
|
|
58
|
+
if (typeof value === "string") return value.length * 2;
|
|
59
|
+
if (value instanceof ArrayBuffer) return value.byteLength;
|
|
60
|
+
if (ArrayBuffer.isView(value)) return value.byteLength;
|
|
61
|
+
if (value instanceof Blob) return value.size;
|
|
62
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
63
|
+
function traverse(obj) {
|
|
64
|
+
if (obj === null || typeof obj !== "object") {
|
|
65
|
+
if (typeof obj === "boolean") return 4;
|
|
66
|
+
if (typeof obj === "number") return 8;
|
|
67
|
+
if (typeof obj === "string") return obj.length * 2;
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
70
|
+
if (seen.has(obj)) return 0;
|
|
71
|
+
seen.add(obj);
|
|
72
|
+
if (obj instanceof ArrayBuffer) return obj.byteLength;
|
|
73
|
+
if (ArrayBuffer.isView(obj)) return obj.byteLength;
|
|
74
|
+
if (obj instanceof Blob) return obj.size;
|
|
75
|
+
if (obj instanceof Date) return 8;
|
|
76
|
+
if (obj instanceof RegExp) return obj.source.length * 2;
|
|
77
|
+
if (Array.isArray(obj)) {
|
|
78
|
+
return obj.reduce((sum, item) => sum + traverse(item), 0);
|
|
79
|
+
}
|
|
80
|
+
if (obj instanceof Map) {
|
|
81
|
+
let size = 0;
|
|
82
|
+
obj.forEach((val, key) => {
|
|
83
|
+
size += traverse(key) + traverse(val);
|
|
84
|
+
});
|
|
85
|
+
return size;
|
|
86
|
+
}
|
|
87
|
+
if (obj instanceof Set) {
|
|
88
|
+
let size = 0;
|
|
89
|
+
obj.forEach((val) => {
|
|
90
|
+
size += traverse(val);
|
|
91
|
+
});
|
|
92
|
+
return size;
|
|
93
|
+
}
|
|
94
|
+
return Object.entries(obj).reduce(
|
|
95
|
+
(sum, [key, val]) => sum + key.length * 2 + traverse(val),
|
|
96
|
+
0
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return traverse(value);
|
|
100
|
+
}
|
|
54
101
|
|
|
55
102
|
// src/worker/runtime.ts
|
|
56
103
|
var functionRegistry = /* @__PURE__ */ new Map();
|
|
@@ -96,24 +143,29 @@ async function handleMessage(event) {
|
|
|
96
143
|
const result = await executeFunction(functionName, input);
|
|
97
144
|
const duration = performance.now() - startTime;
|
|
98
145
|
const transfer = findTransferables(result);
|
|
146
|
+
const outputSize = estimatePayloadSize(result);
|
|
99
147
|
const response = {
|
|
100
148
|
id,
|
|
101
149
|
type: "result",
|
|
102
150
|
payload: {
|
|
103
151
|
data: result,
|
|
104
|
-
duration
|
|
152
|
+
duration,
|
|
153
|
+
outputSize
|
|
105
154
|
},
|
|
106
155
|
timestamp: Date.now()
|
|
107
156
|
};
|
|
108
157
|
self.postMessage(response, transfer);
|
|
109
158
|
} catch (err) {
|
|
110
159
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
160
|
+
const duration = performance.now() - startTime;
|
|
111
161
|
const response = {
|
|
112
162
|
id,
|
|
113
163
|
type: "error",
|
|
114
164
|
payload: {
|
|
115
165
|
message: error.message,
|
|
116
|
-
stack: error.stack
|
|
166
|
+
stack: error.stack,
|
|
167
|
+
functionName,
|
|
168
|
+
duration
|
|
117
169
|
},
|
|
118
170
|
timestamp: Date.now()
|
|
119
171
|
};
|
package/dist/worker.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils.ts","../src/worker/runtime.ts"],"names":[],"mappings":"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","file":"worker.cjs","sourcesContent":["/**\n * ComputeKit Utilities\n * Helper functions for the WASM + Worker toolkit\n */\n\n/**\n * Generate a unique ID\n */\nexport function generateId(): string {\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 11)}`;\n}\n\n/**\n * Check if running in a Web Worker context\n */\nexport function isWorkerContext(): boolean {\n return (\n typeof self !== 'undefined' &&\n typeof Window === 'undefined' &&\n typeof self.postMessage === 'function'\n );\n}\n\n/**\n * Check if running in a browser context\n */\nexport function isBrowserContext(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Check if SharedArrayBuffer is available\n */\nexport function isSharedArrayBufferAvailable(): boolean {\n try {\n return typeof SharedArrayBuffer !== 'undefined';\n } catch {\n return false;\n }\n}\n\n/**\n * Check if WASM is supported\n */\nexport function isWasmSupported(): boolean {\n try {\n if (typeof WebAssembly === 'object') {\n const module = new WebAssembly.Module(\n Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)\n );\n return module instanceof WebAssembly.Module;\n }\n } catch {\n // WASM not supported\n }\n return false;\n}\n\n/**\n * Get the number of logical processors\n */\nexport function getHardwareConcurrency(): number {\n if (typeof navigator !== 'undefined' && navigator.hardwareConcurrency) {\n return navigator.hardwareConcurrency;\n }\n return 4; // Reasonable default\n}\n\n/**\n * Create a deferred promise\n */\nexport interface Deferred<T> {\n promise: Promise<T>;\n resolve: (value: T | PromiseLike<T>) => void;\n reject: (reason?: unknown) => void;\n}\n\nexport function createDeferred<T>(): Deferred<T> {\n let resolve!: (value: T | PromiseLike<T>) => void;\n let reject!: (reason?: unknown) => void;\n\n const promise = new Promise<T>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n return { promise, resolve, reject };\n}\n\n/**\n * Create a timeout promise\n */\nexport function createTimeout(ms: number, message?: string): Promise<never> {\n return new Promise((_, reject) => {\n setTimeout(() => {\n reject(new Error(message || `Operation timed out after ${ms}ms`));\n }, ms);\n });\n}\n\n/**\n * Race a promise against a timeout\n */\nexport async function withTimeout<T>(\n promise: Promise<T>,\n ms: number,\n message?: string\n): Promise<T> {\n return Promise.race([promise, createTimeout(ms, message)]);\n}\n\n/**\n * Detect transferable objects in data\n */\nexport function findTransferables(data: unknown): Transferable[] {\n const transferables: Transferable[] = [];\n const seen = new WeakSet();\n\n function traverse(obj: unknown): void {\n if (obj === null || typeof obj !== 'object') return;\n if (seen.has(obj as object)) return;\n seen.add(obj as object);\n\n if (obj instanceof ArrayBuffer) {\n transferables.push(obj);\n return;\n }\n\n if (ArrayBuffer.isView(obj)) {\n transferables.push(obj.buffer);\n return;\n }\n\n if (obj instanceof MessagePort) {\n transferables.push(obj);\n return;\n }\n\n if (typeof ImageBitmap !== 'undefined' && obj instanceof ImageBitmap) {\n transferables.push(obj);\n return;\n }\n\n if (typeof OffscreenCanvas !== 'undefined' && obj instanceof OffscreenCanvas) {\n transferables.push(obj);\n return;\n }\n\n if (Array.isArray(obj)) {\n obj.forEach(traverse);\n return;\n }\n\n if (obj instanceof Map) {\n obj.forEach((value, key) => {\n traverse(key);\n traverse(value);\n });\n return;\n }\n\n if (obj instanceof Set) {\n obj.forEach(traverse);\n return;\n }\n\n Object.values(obj).forEach(traverse);\n }\n\n traverse(data);\n return transferables;\n}\n\n/**\n * Clone data, detaching transferables\n */\nexport function cloneForTransfer<T>(data: T): { data: T; transfer: Transferable[] } {\n const transfer = findTransferables(data);\n return { data, transfer };\n}\n\n/**\n * Create a typed event emitter\n */\nexport type EventHandler<T = unknown> = (data: T) => void;\n\nexport class EventEmitter<TEvents extends Record<string, unknown>> {\n private handlers = new Map<keyof TEvents, Set<EventHandler>>();\n\n on<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): () => void {\n if (!this.handlers.has(event)) {\n this.handlers.set(event, new Set());\n }\n this.handlers.get(event)!.add(handler as EventHandler);\n\n // Return unsubscribe function\n return () => this.off(event, handler);\n }\n\n off<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): void {\n this.handlers.get(event)?.delete(handler as EventHandler);\n }\n\n emit<K extends keyof TEvents>(event: K, data: TEvents[K]): void {\n this.handlers.get(event)?.forEach((handler) => {\n try {\n handler(data);\n } catch (err) {\n console.error(`Error in event handler for ${String(event)}:`, err);\n }\n });\n }\n\n removeAllListeners(event?: keyof TEvents): void {\n if (event) {\n this.handlers.delete(event);\n } else {\n this.handlers.clear();\n }\n }\n}\n\n/**\n * Simple LRU cache\n */\nexport class LRUCache<K, V> {\n private cache = new Map<K, V>();\n private maxSize: number;\n\n constructor(maxSize: number = 100) {\n this.maxSize = maxSize;\n }\n\n get(key: K): V | undefined {\n const value = this.cache.get(key);\n if (value !== undefined) {\n // Move to end (most recently used)\n this.cache.delete(key);\n this.cache.set(key, value);\n }\n return value;\n }\n\n set(key: K, value: V): void {\n if (this.cache.has(key)) {\n this.cache.delete(key);\n } else if (this.cache.size >= this.maxSize) {\n // Delete oldest (first) entry\n const firstKey = this.cache.keys().next().value;\n if (firstKey !== undefined) {\n this.cache.delete(firstKey);\n }\n }\n this.cache.set(key, value);\n }\n\n has(key: K): boolean {\n return this.cache.has(key);\n }\n\n delete(key: K): boolean {\n return this.cache.delete(key);\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n get size(): number {\n return this.cache.size;\n }\n}\n\n/**\n * Serialize function to string for worker\n */\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\nexport function serializeFunction(fn: Function): string {\n return fn.toString();\n}\n\n/**\n * Logger utility\n */\nexport interface Logger {\n debug(...args: unknown[]): void;\n info(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n}\n\nexport function createLogger(prefix: string, enabled: boolean = false): Logger {\n const noop = () => {};\n const log = (level: string) =>\n enabled ? (...args: unknown[]) => console.log(`[${prefix}:${level}]`, ...args) : noop;\n\n return {\n debug: log('debug'),\n info: log('info'),\n warn: enabled\n ? (...args: unknown[]) => console.warn(`[${prefix}:warn]`, ...args)\n : noop,\n error: (...args: unknown[]) => console.error(`[${prefix}:error]`, ...args),\n };\n}\n","/**\n * ComputeKit Worker Runtime\n * Code that runs inside Web Workers\n */\n\nimport type {\n WorkerMessage,\n ExecutePayload,\n ResultPayload,\n ErrorPayload,\n ComputeProgress,\n} from '../types';\n\nimport { generateId, findTransferables } from '../utils';\n\n/** Registry of compute functions available in the worker */\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\nconst functionRegistry = new Map<string, Function>();\n\n/** Current task context for progress reporting */\nlet currentTaskId: string | null = null;\n\n/**\n * Report progress from within a compute function\n */\nexport function reportProgress(progress: Partial<ComputeProgress>): void {\n if (!currentTaskId) {\n console.warn('reportProgress called outside of compute function');\n return;\n }\n\n const message: WorkerMessage = {\n id: generateId(),\n type: 'progress',\n payload: {\n taskId: currentTaskId,\n progress: {\n percent: progress.percent ?? 0,\n phase: progress.phase,\n estimatedTimeRemaining: progress.estimatedTimeRemaining,\n data: progress.data,\n },\n },\n timestamp: Date.now(),\n };\n\n self.postMessage(message);\n}\n\n/**\n * Register a compute function in the worker\n */\nexport function registerFunction(\n name: string,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n fn: Function\n): void {\n functionRegistry.set(name, fn);\n}\n\n/**\n * Execute a registered function\n */\nasync function executeFunction(functionName: string, input: unknown): Promise<unknown> {\n const fn = functionRegistry.get(functionName);\n\n if (!fn) {\n throw new Error(`Function \"${functionName}\" not found in worker`);\n }\n\n return fn(input);\n}\n\n/**\n * Handle incoming messages from the main thread\n */\nasync function handleMessage(event: MessageEvent<WorkerMessage>): Promise<void> {\n const { id, type, payload } = event.data;\n\n if (type === 'execute') {\n const { functionName, input } = payload as ExecutePayload;\n const startTime = performance.now();\n\n // Set current task for progress reporting\n currentTaskId = id;\n\n try {\n const result = await executeFunction(functionName, input);\n const duration = performance.now() - startTime;\n\n // Find transferable objects in result\n const transfer = findTransferables(result);\n\n const response: WorkerMessage<ResultPayload> = {\n id,\n type: 'result',\n payload: {\n data: result,\n duration,\n },\n timestamp: Date.now(),\n };\n\n self.postMessage(response, transfer as Transferable[]);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n\n const response: WorkerMessage<ErrorPayload> = {\n id,\n type: 'error',\n payload: {\n message: error.message,\n stack: error.stack,\n },\n timestamp: Date.now(),\n };\n\n self.postMessage(response);\n } finally {\n currentTaskId = null;\n }\n } else if (type === 'init') {\n // Handle initialization if needed\n const response: WorkerMessage = {\n id,\n type: 'ready',\n timestamp: Date.now(),\n };\n self.postMessage(response);\n }\n}\n\n/**\n * Initialize the worker runtime\n */\nexport function initWorkerRuntime(): void {\n self.onmessage = handleMessage;\n\n // Signal that worker is ready\n const readyMessage: WorkerMessage = {\n id: generateId(),\n type: 'ready',\n timestamp: Date.now(),\n };\n self.postMessage(readyMessage);\n}\n\n// Export for use in worker entry point\nexport { functionRegistry };\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts","../src/worker/runtime.ts"],"names":[],"mappings":"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","file":"worker.cjs","sourcesContent":["/**\n * ComputeKit Utilities\n * Helper functions for the WASM + Worker toolkit\n */\n\n/**\n * Generate a unique ID\n */\nexport function generateId(): string {\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 11)}`;\n}\n\n/**\n * Check if running in a Web Worker context\n */\nexport function isWorkerContext(): boolean {\n return (\n typeof self !== 'undefined' &&\n typeof Window === 'undefined' &&\n typeof self.postMessage === 'function'\n );\n}\n\n/**\n * Check if running in a browser context\n */\nexport function isBrowserContext(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\n/**\n * Check if SharedArrayBuffer is available\n */\nexport function isSharedArrayBufferAvailable(): boolean {\n try {\n return typeof SharedArrayBuffer !== 'undefined';\n } catch {\n return false;\n }\n}\n\n/**\n * Check if WASM is supported\n */\nexport function isWasmSupported(): boolean {\n try {\n if (typeof WebAssembly === 'object') {\n const module = new WebAssembly.Module(\n Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)\n );\n return module instanceof WebAssembly.Module;\n }\n } catch {\n // WASM not supported\n }\n return false;\n}\n\n/**\n * Get the number of logical processors\n */\nexport function getHardwareConcurrency(): number {\n if (typeof navigator !== 'undefined' && navigator.hardwareConcurrency) {\n return navigator.hardwareConcurrency;\n }\n return 4; // Reasonable default\n}\n\n/**\n * Create a deferred promise\n */\nexport interface Deferred<T> {\n promise: Promise<T>;\n resolve: (value: T | PromiseLike<T>) => void;\n reject: (reason?: unknown) => void;\n}\n\nexport function createDeferred<T>(): Deferred<T> {\n let resolve!: (value: T | PromiseLike<T>) => void;\n let reject!: (reason?: unknown) => void;\n\n const promise = new Promise<T>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n return { promise, resolve, reject };\n}\n\n/**\n * Create a timeout promise\n */\nexport function createTimeout(ms: number, message?: string): Promise<never> {\n return new Promise((_, reject) => {\n setTimeout(() => {\n reject(new Error(message || `Operation timed out after ${ms}ms`));\n }, ms);\n });\n}\n\n/**\n * Race a promise against a timeout\n */\nexport async function withTimeout<T>(\n promise: Promise<T>,\n ms: number,\n message?: string\n): Promise<T> {\n return Promise.race([promise, createTimeout(ms, message)]);\n}\n\n/**\n * Detect transferable objects in data\n */\nexport function findTransferables(data: unknown): Transferable[] {\n const transferables: Transferable[] = [];\n const seen = new WeakSet();\n\n function traverse(obj: unknown): void {\n if (obj === null || typeof obj !== 'object') return;\n if (seen.has(obj as object)) return;\n seen.add(obj as object);\n\n if (obj instanceof ArrayBuffer) {\n transferables.push(obj);\n return;\n }\n\n if (ArrayBuffer.isView(obj)) {\n transferables.push(obj.buffer);\n return;\n }\n\n if (obj instanceof MessagePort) {\n transferables.push(obj);\n return;\n }\n\n if (typeof ImageBitmap !== 'undefined' && obj instanceof ImageBitmap) {\n transferables.push(obj);\n return;\n }\n\n if (typeof OffscreenCanvas !== 'undefined' && obj instanceof OffscreenCanvas) {\n transferables.push(obj);\n return;\n }\n\n if (Array.isArray(obj)) {\n obj.forEach(traverse);\n return;\n }\n\n if (obj instanceof Map) {\n obj.forEach((value, key) => {\n traverse(key);\n traverse(value);\n });\n return;\n }\n\n if (obj instanceof Set) {\n obj.forEach(traverse);\n return;\n }\n\n Object.values(obj).forEach(traverse);\n }\n\n traverse(data);\n return transferables;\n}\n\n/**\n * Clone data, detaching transferables\n */\nexport function cloneForTransfer<T>(data: T): { data: T; transfer: Transferable[] } {\n const transfer = findTransferables(data);\n return { data, transfer };\n}\n\n/**\n * Create a typed event emitter\n */\nexport type EventHandler<T = unknown> = (data: T) => void;\n\nexport class EventEmitter<TEvents extends Record<string, unknown>> {\n private handlers = new Map<keyof TEvents, Set<EventHandler>>();\n\n on<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): () => void {\n if (!this.handlers.has(event)) {\n this.handlers.set(event, new Set());\n }\n this.handlers.get(event)!.add(handler as EventHandler);\n\n // Return unsubscribe function\n return () => this.off(event, handler);\n }\n\n off<K extends keyof TEvents>(event: K, handler: EventHandler<TEvents[K]>): void {\n this.handlers.get(event)?.delete(handler as EventHandler);\n }\n\n emit<K extends keyof TEvents>(event: K, data: TEvents[K]): void {\n this.handlers.get(event)?.forEach((handler) => {\n try {\n handler(data);\n } catch (err) {\n console.error(`Error in event handler for ${String(event)}:`, err);\n }\n });\n }\n\n removeAllListeners(event?: keyof TEvents): void {\n if (event) {\n this.handlers.delete(event);\n } else {\n this.handlers.clear();\n }\n }\n}\n\n/**\n * Simple LRU cache\n */\nexport class LRUCache<K, V> {\n private cache = new Map<K, V>();\n private maxSize: number;\n\n constructor(maxSize: number = 100) {\n this.maxSize = maxSize;\n }\n\n get(key: K): V | undefined {\n const value = this.cache.get(key);\n if (value !== undefined) {\n // Move to end (most recently used)\n this.cache.delete(key);\n this.cache.set(key, value);\n }\n return value;\n }\n\n set(key: K, value: V): void {\n if (this.cache.has(key)) {\n this.cache.delete(key);\n } else if (this.cache.size >= this.maxSize) {\n // Delete oldest (first) entry\n const firstKey = this.cache.keys().next().value;\n if (firstKey !== undefined) {\n this.cache.delete(firstKey);\n }\n }\n this.cache.set(key, value);\n }\n\n has(key: K): boolean {\n return this.cache.has(key);\n }\n\n delete(key: K): boolean {\n return this.cache.delete(key);\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n get size(): number {\n return this.cache.size;\n }\n}\n\n/**\n * Serialize function to string for worker\n */\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\nexport function serializeFunction(fn: Function): string {\n return fn.toString();\n}\n\n/**\n * Estimate the byte size of a value for structured cloning.\n * This is an approximation useful for debugging and performance monitoring.\n */\nexport function estimatePayloadSize(value: unknown): number {\n if (value === null || value === undefined) return 0;\n if (typeof value === 'boolean') return 4;\n if (typeof value === 'number') return 8;\n if (typeof value === 'string') return value.length * 2; // UTF-16\n\n if (value instanceof ArrayBuffer) return value.byteLength;\n if (ArrayBuffer.isView(value)) return value.byteLength;\n if (value instanceof Blob) return value.size;\n\n const seen = new WeakSet<object>();\n\n function traverse(obj: unknown): number {\n if (obj === null || typeof obj !== 'object') {\n if (typeof obj === 'boolean') return 4;\n if (typeof obj === 'number') return 8;\n if (typeof obj === 'string') return (obj as string).length * 2;\n return 0;\n }\n\n if (seen.has(obj)) return 0; // Avoid infinite loops\n seen.add(obj);\n\n if (obj instanceof ArrayBuffer) return obj.byteLength;\n if (ArrayBuffer.isView(obj)) return obj.byteLength;\n if (obj instanceof Blob) return obj.size;\n if (obj instanceof Date) return 8;\n if (obj instanceof RegExp) return obj.source.length * 2;\n\n if (Array.isArray(obj)) {\n return obj.reduce((sum, item) => sum + traverse(item), 0);\n }\n\n if (obj instanceof Map) {\n let size = 0;\n obj.forEach((val, key) => {\n size += traverse(key) + traverse(val);\n });\n return size;\n }\n\n if (obj instanceof Set) {\n let size = 0;\n obj.forEach((val) => {\n size += traverse(val);\n });\n return size;\n }\n\n // Plain object\n return Object.entries(obj).reduce(\n (sum, [key, val]) => sum + key.length * 2 + traverse(val),\n 0\n );\n }\n\n return traverse(value);\n}\n\n/**\n * Format bytes to human-readable string\n */\nexport function formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B';\n const k = 1024;\n const sizes = ['B', 'KB', 'MB', 'GB'];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${(bytes / Math.pow(k, i)).toFixed(i > 0 ? 1 : 0)} ${sizes[i]}`;\n}\n\n/**\n * Logger utility\n */\nexport interface Logger {\n debug(...args: unknown[]): void;\n info(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n}\n\nexport function createLogger(prefix: string, enabled: boolean = false): Logger {\n const noop = () => {};\n const log = (level: string) =>\n enabled ? (...args: unknown[]) => console.log(`[${prefix}:${level}]`, ...args) : noop;\n\n return {\n debug: log('debug'),\n info: log('info'),\n warn: enabled\n ? (...args: unknown[]) => console.warn(`[${prefix}:warn]`, ...args)\n : noop,\n error: (...args: unknown[]) => console.error(`[${prefix}:error]`, ...args),\n };\n}\n","/**\n * ComputeKit Worker Runtime\n * Code that runs inside Web Workers\n */\n\nimport type {\n WorkerMessage,\n ExecutePayload,\n ResultPayload,\n ErrorPayload,\n ComputeProgress,\n} from '../types';\n\nimport { generateId, findTransferables, estimatePayloadSize } from '../utils';\n\n/** Registry of compute functions available in the worker */\n// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\nconst functionRegistry = new Map<string, Function>();\n\n/** Current task context for progress reporting */\nlet currentTaskId: string | null = null;\n\n/**\n * Report progress from within a compute function\n */\nexport function reportProgress(progress: Partial<ComputeProgress>): void {\n if (!currentTaskId) {\n console.warn('reportProgress called outside of compute function');\n return;\n }\n\n const message: WorkerMessage = {\n id: generateId(),\n type: 'progress',\n payload: {\n taskId: currentTaskId,\n progress: {\n percent: progress.percent ?? 0,\n phase: progress.phase,\n estimatedTimeRemaining: progress.estimatedTimeRemaining,\n data: progress.data,\n },\n },\n timestamp: Date.now(),\n };\n\n self.postMessage(message);\n}\n\n/**\n * Register a compute function in the worker\n */\nexport function registerFunction(\n name: string,\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n fn: Function\n): void {\n functionRegistry.set(name, fn);\n}\n\n/**\n * Execute a registered function\n */\nasync function executeFunction(functionName: string, input: unknown): Promise<unknown> {\n const fn = functionRegistry.get(functionName);\n\n if (!fn) {\n throw new Error(`Function \"${functionName}\" not found in worker`);\n }\n\n return fn(input);\n}\n\n/**\n * Handle incoming messages from the main thread\n */\nasync function handleMessage(event: MessageEvent<WorkerMessage>): Promise<void> {\n const { id, type, payload } = event.data;\n\n if (type === 'execute') {\n const { functionName, input } = payload as ExecutePayload;\n const startTime = performance.now();\n\n // Set current task for progress reporting\n currentTaskId = id;\n\n try {\n const result = await executeFunction(functionName, input);\n const duration = performance.now() - startTime;\n\n // Find transferable objects in result\n const transfer = findTransferables(result);\n\n // Estimate output size for debugging\n const outputSize = estimatePayloadSize(result);\n\n const response: WorkerMessage<ResultPayload> = {\n id,\n type: 'result',\n payload: {\n data: result,\n duration,\n outputSize,\n },\n timestamp: Date.now(),\n };\n\n self.postMessage(response, transfer as Transferable[]);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n const duration = performance.now() - startTime;\n\n const response: WorkerMessage<ErrorPayload> = {\n id,\n type: 'error',\n payload: {\n message: error.message,\n stack: error.stack,\n functionName,\n duration,\n },\n timestamp: Date.now(),\n };\n\n self.postMessage(response);\n } finally {\n currentTaskId = null;\n }\n } else if (type === 'init') {\n // Handle initialization if needed\n const response: WorkerMessage = {\n id,\n type: 'ready',\n timestamp: Date.now(),\n };\n self.postMessage(response);\n }\n}\n\n/**\n * Initialize the worker runtime\n */\nexport function initWorkerRuntime(): void {\n self.onmessage = handleMessage;\n\n // Signal that worker is ready\n const readyMessage: WorkerMessage = {\n id: generateId(),\n type: 'ready',\n timestamp: Date.now(),\n };\n self.postMessage(readyMessage);\n}\n\n// Export for use in worker entry point\nexport { functionRegistry };\n"]}
|
package/dist/worker.d.cts
CHANGED
package/dist/worker.d.ts
CHANGED
package/dist/worker.js
CHANGED
|
@@ -49,6 +49,53 @@ function findTransferables(data) {
|
|
|
49
49
|
traverse(data);
|
|
50
50
|
return transferables;
|
|
51
51
|
}
|
|
52
|
+
function estimatePayloadSize(value) {
|
|
53
|
+
if (value === null || value === void 0) return 0;
|
|
54
|
+
if (typeof value === "boolean") return 4;
|
|
55
|
+
if (typeof value === "number") return 8;
|
|
56
|
+
if (typeof value === "string") return value.length * 2;
|
|
57
|
+
if (value instanceof ArrayBuffer) return value.byteLength;
|
|
58
|
+
if (ArrayBuffer.isView(value)) return value.byteLength;
|
|
59
|
+
if (value instanceof Blob) return value.size;
|
|
60
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
61
|
+
function traverse(obj) {
|
|
62
|
+
if (obj === null || typeof obj !== "object") {
|
|
63
|
+
if (typeof obj === "boolean") return 4;
|
|
64
|
+
if (typeof obj === "number") return 8;
|
|
65
|
+
if (typeof obj === "string") return obj.length * 2;
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
if (seen.has(obj)) return 0;
|
|
69
|
+
seen.add(obj);
|
|
70
|
+
if (obj instanceof ArrayBuffer) return obj.byteLength;
|
|
71
|
+
if (ArrayBuffer.isView(obj)) return obj.byteLength;
|
|
72
|
+
if (obj instanceof Blob) return obj.size;
|
|
73
|
+
if (obj instanceof Date) return 8;
|
|
74
|
+
if (obj instanceof RegExp) return obj.source.length * 2;
|
|
75
|
+
if (Array.isArray(obj)) {
|
|
76
|
+
return obj.reduce((sum, item) => sum + traverse(item), 0);
|
|
77
|
+
}
|
|
78
|
+
if (obj instanceof Map) {
|
|
79
|
+
let size = 0;
|
|
80
|
+
obj.forEach((val, key) => {
|
|
81
|
+
size += traverse(key) + traverse(val);
|
|
82
|
+
});
|
|
83
|
+
return size;
|
|
84
|
+
}
|
|
85
|
+
if (obj instanceof Set) {
|
|
86
|
+
let size = 0;
|
|
87
|
+
obj.forEach((val) => {
|
|
88
|
+
size += traverse(val);
|
|
89
|
+
});
|
|
90
|
+
return size;
|
|
91
|
+
}
|
|
92
|
+
return Object.entries(obj).reduce(
|
|
93
|
+
(sum, [key, val]) => sum + key.length * 2 + traverse(val),
|
|
94
|
+
0
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
return traverse(value);
|
|
98
|
+
}
|
|
52
99
|
|
|
53
100
|
// src/worker/runtime.ts
|
|
54
101
|
var functionRegistry = /* @__PURE__ */ new Map();
|
|
@@ -94,24 +141,29 @@ async function handleMessage(event) {
|
|
|
94
141
|
const result = await executeFunction(functionName, input);
|
|
95
142
|
const duration = performance.now() - startTime;
|
|
96
143
|
const transfer = findTransferables(result);
|
|
144
|
+
const outputSize = estimatePayloadSize(result);
|
|
97
145
|
const response = {
|
|
98
146
|
id,
|
|
99
147
|
type: "result",
|
|
100
148
|
payload: {
|
|
101
149
|
data: result,
|
|
102
|
-
duration
|
|
150
|
+
duration,
|
|
151
|
+
outputSize
|
|
103
152
|
},
|
|
104
153
|
timestamp: Date.now()
|
|
105
154
|
};
|
|
106
155
|
self.postMessage(response, transfer);
|
|
107
156
|
} catch (err) {
|
|
108
157
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
158
|
+
const duration = performance.now() - startTime;
|
|
109
159
|
const response = {
|
|
110
160
|
id,
|
|
111
161
|
type: "error",
|
|
112
162
|
payload: {
|
|
113
163
|
message: error.message,
|
|
114
|
-
stack: error.stack
|
|
164
|
+
stack: error.stack,
|
|
165
|
+
functionName,
|
|
166
|
+
duration
|
|
115
167
|
},
|
|
116
168
|
timestamp: Date.now()
|
|
117
169
|
};
|