@vielzeug/familiar 26.10.14 → 26.10.16
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/_pool-core.cjs.map +1 -1
- package/dist/_pool-core.js +171 -1
- package/dist/_pool-core.js.map +1 -1
- package/dist/_pool.cjs.map +1 -1
- package/dist/_pool.js +111 -1
- package/dist/_pool.js.map +1 -1
- package/dist/_stream-pool.cjs.map +1 -1
- package/dist/_stream-pool.js +77 -1
- package/dist/_stream-pool.js.map +1 -1
- package/dist/_timers.cjs.map +1 -1
- package/dist/_timers.js +7 -1
- package/dist/_timers.js.map +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.js +23 -1
- package/dist/errors.js.map +1 -1
- package/dist/familiar.cjs +1 -1
- package/dist/familiar.cjs.map +1 -1
- package/dist/familiar.iife.js +1 -1
- package/dist/familiar.iife.js.map +1 -1
- package/dist/familiar.js +528 -1
- package/dist/familiar.js.map +1 -1
- package/dist/index.js +4 -1
- package/dist/protocol.cjs.map +1 -1
- package/dist/protocol.js +78 -1
- package/dist/protocol.js.map +1 -1
- package/dist/testing/testing.cjs.map +1 -1
- package/dist/testing/testing.js +75 -1
- package/dist/testing/testing.js.map +1 -1
- package/dist/testing.js +3 -1
- package/dist/worker.cjs +1 -1
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.js +166 -1
- package/dist/worker.js.map +1 -1
- package/package.json +5 -5
package/dist/familiar.js
CHANGED
|
@@ -1,2 +1,529 @@
|
|
|
1
|
-
import{abortError as e,tapper as t}from"@vielzeug/arsenal";function unrefTimer(e){typeof e==`object`&&e&&`unref`in e&&e.unref()}var FamiliarError=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},FamiliarInvalidOptionsError=class extends FamiliarError{},FamiliarQueueFullError=class extends FamiliarError{maxQueue;constructor(e){super(`Queue is full (maxQueue=${e})`),this.maxQueue=e}},FamiliarTaskError=class extends FamiliarError{},FamiliarTerminatedError=class extends FamiliarError{constructor(e=`Worker was terminated`){super(e)}},FamiliarTimeoutError=class extends FamiliarError{timeoutMs;constructor(e,t=`Task`){super(`${t} timed out after ${e}ms`),this.timeoutMs=e}},FamiliarRuntimeError=class extends FamiliarError{},n=2147483647;function validatePriority(e){if(!Number.isFinite(e))throw new FamiliarInvalidOptionsError("`priority` must be a finite number");return e}function validateTimeout(e,t=`timeout`){if(e!==void 0&&(!Number.isInteger(e)||e<1||e>2147483647))throw new FamiliarInvalidOptionsError(`\`${t}\` must be an integer from 1 through ${n}`);return e}function createPoolCore(n,r){let i=[...n],a=[],o=[],s=[],c=t(),l=new AbortController,u=0,d=0,f=0,p=0,m=0,h,g=!1;function isIdle(){return i.length===n.length&&a.length===0}function settleIdle(){if(isIdle())for(let e of o.splice(0))e.timer&&clearTimeout(e.timer),e.resolve()}function waitForIdle(e){return isIdle()?Promise.resolve():new Promise((t,n)=>{let r={reject:n,resolve:t};e.timeout!==void 0&&(r.timer=setTimeout(()=>{let t=o.indexOf(r);t!==-1&&o.splice(t,1),n(new FamiliarTimeoutError(e.timeout,`Drain`))},e.timeout),unrefTimer(r.timer)),o.push(r)})}function releaseCapacity(){s.shift()?.resolve()}function rejectCapacity(e){for(let t of s.splice(0))t.reject(e)}function waitForCapacity(t,n){return t?.aborted?Promise.reject(e(t)):new Promise((r,i)=>{let a=!1,o={cleanup(){t?.removeEventListener(`abort`,onAbort)},priority:n,reject(e){if(a)return;a=!0,o.cleanup();let t=s.indexOf(o);t!==-1&&s.splice(t,1),i(e)},resolve(){a||(a=!0,o.cleanup(),r())},sequence:f++},onAbort=()=>o.reject(e(t));t?.addEventListener(`abort`,onAbort,{once:!0}),s.push(o),s.sort((e,t)=>t.priority-e.priority||e.sequence-t.sequence)})}function acquire(t,n){let{priority:i,signal:o}=t;return o?.aborted?Promise.reject(e(o)):(async()=>{for(;;){if(g)throw new FamiliarTerminatedError;if(h)throw new FamiliarTerminatedError(`Worker is draining`);if(r.maxQueue===void 0||a.length<r.maxQueue)return admit(t,n??(e=>e));if(r.onFull===`reject`)throw new FamiliarQueueFullError(r.maxQueue);if(await waitForCapacity(o,i),o?.aborted)throw releaseCapacity(),e(o)}})()}function admit(t,n){let{priority:r,signal:o}=t,s=i.pop();if(s)try{return Promise.resolve(n(s))}catch(e){return release(s),settleIdle(),Promise.reject(e)}return new Promise((t,i)=>{let s={cleanup(){s.signal?.removeEventListener(`abort`,onAbort)},priority:r,reject(e){s.cleanup();let t=a.indexOf(s);t!==-1&&(a.splice(t,1),releaseCapacity()),i(e),settleIdle()},sequence:d++,signal:o,start(e){s.cleanup();try{t(n(e))}catch(t){release(e),settleIdle(),i(t)}}},onAbort=()=>s.reject(e(s.signal));s.signal?.addEventListener(`abort`,onAbort,{once:!0}),a.push(s),a.sort((e,t)=>t.priority-e.priority||e.sequence-t.sequence)})}function release(e){let t=a.shift();t?(t.start(e),releaseCapacity()):i.push(e)}function dispose(){if(!g){g=!0,l.abort();for(let e of n)e.terminate();for(let e of a.splice(0))e.reject(new FamiliarTerminatedError);rejectCapacity(new FamiliarTerminatedError),settleIdle(),c.emit({type:`dispose`}),c.clear()}}function drain(e={}){if(g)return Promise.resolve();try{validateTimeout(e.timeout,`drain.timeout`)}catch(e){return Promise.reject(e)}return h||(rejectCapacity(new FamiliarTerminatedError(`Worker is draining`)),h=waitForIdle(e).then(()=>dispose(),e=>{throw dispose(),e}),h)}return{acquire,disposalSignal:l.signal,dispose,get disposed(){return g},drain,get drainPromise(){return h},emitTap(e){c.emit(e)},release,settleIdle,stats(){return{active:u,completed:p,failed:m,queued:a.length+s.length}},status(){return g?`terminated`:u===0?`idle`:`running`},tap(e,t){return g?()=>void 0:c.tap(e,t)},trackActive(e){u+=e},trackCompleted(){p+=1},trackFailed(){m+=1}}}function createPool(t,n){let r=createPoolCore(t,n);for(let e of t)e.notify=e=>r.emitTap({error:e,type:`worker-error`});function run(t,i={}){let a,o,s;try{a=validatePriority(i.priority??0),o=validateTimeout(i.timeout)??n.defaultTimeout,s=[...i.transferables??[]]}catch(e){return Promise.reject(e)}return r.acquire({priority:a,signal:i.signal},n=>{r.trackActive(1);let onAbort=()=>n.cancel(e(i.signal));i.signal?.addEventListener(`abort`,onAbort,{once:!0});let finish=async()=>{try{let e=await n.run(t,s,o);return r.trackCompleted(),e}catch(e){throw!i.signal?.aborted&&!(e instanceof FamiliarTerminatedError)&&r.trackFailed(),e}finally{i.signal?.removeEventListener(`abort`,onAbort),r.trackActive(-1),r.release(n),r.settleIdle()}};return finish()})}return{get disposalSignal(){return r.disposalSignal},dispose:r.dispose,get disposed(){return r.disposed},drain:r.drain,run,get stats(){return r.stats()},get status(){return r.status()},tap:r.tap,[Symbol.asyncDispose]:()=>r.drain({}),[Symbol.dispose]:r.dispose}}function runBatch(t,n,r={}){let i,iterate=async function*(i){let a=[],onAbort=()=>i.abort(r.signal?.reason);r.signal?.aborted?i.abort(r.signal.reason):r.signal?.addEventListener(`abort`,onAbort,{once:!0});try{for(let[e,o]of n.entries()){let n=t.run(o,{priority:r.priority,signal:i.signal,timeout:r.timeout,transferables:r.getTransferables?.(o,e)}).catch(e=>{throw i.abort(e),e});n.catch(()=>void 0),a.push(n)}if(a.length===0&&i.signal.aborted)throw e(i.signal);for(let t of a){if(i.signal.aborted)throw e(i.signal);let n=await t;if(i.signal.aborted)throw e(i.signal);yield n}}catch(e){throw i.abort(e),e}finally{r.signal?.removeEventListener(`abort`,onAbort),i.abort(new DOMException(`Batch consumer stopped`,`AbortError`)),await Promise.allSettled(a)}};return{[Symbol.asyncIterator](){let e={},t=new AbortController,n,start=()=>{if(i??=e,i===e)return n??=iterate(t),n};return{next:()=>start()?.next()??Promise.reject(new FamiliarRuntimeError(`Worker batches can only be consumed once`)),return:async r=>!i||i!==e?{done:!0,value:r}:(t.abort(new FamiliarTerminatedError(`Batch consumer stopped`)),n?.return(r)??{done:!0,value:r}),throw:async e=>{let n=start();if(!n)throw new FamiliarRuntimeError(`Worker batches can only be consumed once`);return t.abort(e),n.throw(e)}}}}}function createStreamPool(t,n){let r=createPoolCore(t,n);for(let e of t)e.notify=e=>r.emitTap({error:e,type:`worker-error`});function runStream(t,i={}){let a=validatePriority(i.priority??0),o=validateTimeout(i.timeout)??n.defaultTimeout,s=[...i.transferables??[]],c,iterate=async function*(n){let onAbort=()=>n.abort(i.signal?.reason),c,onCancel;i.signal?.aborted?n.abort(i.signal.reason):i.signal?.addEventListener(`abort`,onAbort,{once:!0});try{let i=await r.acquire({priority:a,signal:n.signal},i=>(c=i,r.trackActive(1),onCancel=()=>c?.cancel(e(n.signal)),n.signal.addEventListener(`abort`,onCancel,{once:!0}),i.stream(t,{priority:a,signal:n.signal,timeout:o,transferables:s})));for await(let e of i.iterable)yield e;await i.done,r.trackCompleted()}catch(e){throw c&&!n.signal.aborted&&!(e instanceof FamiliarTerminatedError)&&r.trackFailed(),e}finally{i.signal?.removeEventListener(`abort`,onAbort),c&&(onCancel&&n.signal.removeEventListener(`abort`,onCancel),r.trackActive(-1),r.release(c),r.settleIdle())}};return{[Symbol.asyncIterator](){let e={},t=new AbortController,n,start=()=>{if(c??=e,c===e)return n??=iterate(t),n};return{next:()=>start()?.next()??Promise.reject(new FamiliarRuntimeError(`Worker streams can only be consumed once`)),return:async r=>!c||c!==e?{done:!0,value:r}:(t.abort(new FamiliarTerminatedError(`Stream consumer stopped`)),n?.return(r)??{done:!0,value:r}),throw:async e=>{let n=start();if(!n)throw new FamiliarRuntimeError(`Worker streams can only be consumed once`);return t.abort(e),n.throw(e)}}}}}return{get disposalSignal(){return r.disposalSignal},dispose:r.dispose,get disposed(){return r.disposed},drain:r.drain,runStream,get stats(){return r.stats()},get status(){return r.status()},tap:r.tap,[Symbol.asyncDispose]:()=>r.drain({}),[Symbol.dispose]:r.dispose}}function resolveOptions(e={}){let{concurrency:t=1,maxQueue:n,onFull:r=`reject`,timeout:i}=e,a=t===`auto`?Math.min(512,Math.max(1,globalThis.navigator?.hardwareConcurrency??1)):t;if(!Number.isInteger(a)||a<1||a>512)throw new FamiliarInvalidOptionsError('`concurrency` must be a positive integer ≤ 512 or "auto"');if(n!==void 0&&(!Number.isInteger(n)||n<1))throw new FamiliarInvalidOptionsError("`maxQueue` must be a positive integer");if(r!==`reject`&&r!==`wait`)throw new FamiliarInvalidOptionsError('`onFull` must be "reject" or "wait"');return validateTimeout(i),{concurrency:a,maxQueue:n,onFull:r,timeout:i}}function isWorkerResponse(e){if(typeof e!=`object`||!e)return!1;let t=e;return t.version!==1||typeof t.id!=`number`||!Number.isSafeInteger(t.id)||t.id<0?!1:t.kind===`chunk`||t.kind===`result`?`value`in t:t.kind!==`error`||typeof t.error!=`object`||t.error===null?!1:(t.error.category===void 0||t.error.category===`protocol`)&&typeof t.error.message==`string`&&typeof t.error.name==`string`&&(t.error.stack===void 0||typeof t.error.stack==`string`)}function responseError(e){let t=Error(e.message);return t.name=e.name,t.stack=e.stack,e.category===`protocol`?new FamiliarRuntimeError(e.message,{cause:t}):new FamiliarTaskError(e.message,{cause:t})}var Slot=class{#e;#t=!1;#n;#r=0;#i;notify=void 0;constructor(e){this.#e=e}cancel(e){this.#n&&(this.#s(),this.#u(`reject`,e))}run(e,t,n){return this.#a(e,t,n,`run`)}stream(e,t){let stop=()=>this.cancel(new FamiliarTerminatedError(`Stream consumer stopped`)),n=[],r=[],i=!1,a,emit=e=>{let t=r.shift();t?t({done:!1,value:e}):n.push(e)},finish=e=>{for(i=!0,a=e;r.length>0;)r.shift()(e===void 0?{done:!0,value:void 0}:Promise.reject(e))};return{done:this.#a(e,[...t.transferables??[]],t.timeout,`stream`,emit).then(()=>finish(),e=>finish(e)),iterable:{[Symbol.asyncIterator]:()=>({async next(){if(n.length>0)return{done:!1,value:n.shift()};if(a!==void 0)throw a;return i?{done:!0,value:void 0}:new Promise((e,t)=>{r.push(n=>{n instanceof Promise?n.then(e,t):e(n)})})},async return(){return stop(),{done:!0,value:void 0}}})}}}terminate(){this.#t=!0,this.#s(),this.#u(`reject`,new FamiliarTerminatedError)}#a(e,t,n,r,i){if(this.#t)return Promise.reject(new FamiliarTerminatedError);if(this.#n)return Promise.reject(new FamiliarRuntimeError(`Worker slot is already busy`));try{let a=this.#o(),o=this.#r;return this.#r=o===2**53-1?0:o+1,new Promise((s,c)=>{let l={emit:i,id:o,kind:r,reject:c,resolve:s};this.#n=l,n!==void 0&&(l.timer=setTimeout(()=>this.cancel(new FamiliarTimeoutError(n)),n),unrefTimer(l.timer));try{a.postMessage({id:o,input:e,kind:r,version:1},t)}catch(e){this.cancel(new FamiliarRuntimeError(`Failed to post message to worker`,{cause:e}))}})}catch(e){return Promise.reject(e)}}#o(){if(this.#i)return this.#i;if(typeof Worker>`u`)throw new FamiliarRuntimeError(`Worker API is unavailable in this runtime`);try{let e=new Worker(this.#e,{type:`module`});return e.onmessage=t=>{this.#i===e&&this.#l(t.data)},e.onerror=t=>this.#c(e,new FamiliarRuntimeError(t.message||`Worker failed`)),e.onmessageerror=()=>this.#c(e,new FamiliarRuntimeError(`Worker response could not be deserialized`)),this.#i=e,e}catch(e){throw new FamiliarRuntimeError(`Failed to create Worker`,{cause:e})}}#s(){let e=this.#i;this.#i=void 0,e&&(e.onmessage=null,e.onerror=null,e.onmessageerror=null,e.terminate())}#c(e,t){this.#i===e&&(this.#s(),this.#u(`reject`,t),this.notify?.(t))}#l(e){if(this.#n){if(!isWorkerResponse(e)||e.id!==this.#n.id||this.#n.kind===`run`&&e.kind===`chunk`){this.cancel(new FamiliarRuntimeError(`Worker returned an incompatible protocol response`));return}if(e.kind===`chunk`){this.#n.emit?.(e.value);return}if(e.kind===`error`){this.#u(`reject`,responseError(e.error));return}this.#u(`resolve`,e.value)}}#u(e,t){let n=this.#n;n&&(this.#n=void 0,n.timer&&clearTimeout(n.timer),e===`resolve`?n.resolve(t):n.reject(t))}};function slots(e,t){let n=typeof e==`string`?e:e.href;return Array.from({length:t.concurrency},()=>new Slot(n))}function createWorker(e,t={}){let n=resolveOptions(t);return createPool(slots(e,n),{defaultTimeout:n.timeout,maxQueue:n.maxQueue,onFull:n.onFull})}function createStreamWorker(e,t={}){let n=resolveOptions(t);return createStreamPool(slots(e,n),{defaultTimeout:n.timeout,maxQueue:n.maxQueue,onFull:n.onFull})}export{FamiliarError,FamiliarInvalidOptionsError,FamiliarQueueFullError,FamiliarRuntimeError,FamiliarTaskError,FamiliarTerminatedError,FamiliarTimeoutError,createStreamWorker,createWorker,runBatch};
|
|
1
|
+
import { abortError as e, tapper as t } from "@vielzeug/arsenal";
|
|
2
|
+
//#region src/_timers.ts
|
|
3
|
+
function unrefTimer(e) {
|
|
4
|
+
typeof e == "object" && e && "unref" in e && e.unref();
|
|
5
|
+
}
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/errors.ts
|
|
8
|
+
var FamiliarError = class extends Error {
|
|
9
|
+
constructor(e, t) {
|
|
10
|
+
super(e, t), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
|
|
11
|
+
}
|
|
12
|
+
}, FamiliarInvalidOptionsError = class extends FamiliarError {}, FamiliarQueueFullError = class extends FamiliarError {
|
|
13
|
+
maxQueue;
|
|
14
|
+
constructor(e) {
|
|
15
|
+
super(`Queue is full (maxQueue=${e})`), this.maxQueue = e;
|
|
16
|
+
}
|
|
17
|
+
}, FamiliarTaskError = class extends FamiliarError {}, FamiliarTerminatedError = class extends FamiliarError {
|
|
18
|
+
constructor(e = "Worker was terminated") {
|
|
19
|
+
super(e);
|
|
20
|
+
}
|
|
21
|
+
}, FamiliarTimeoutError = class extends FamiliarError {
|
|
22
|
+
timeoutMs;
|
|
23
|
+
constructor(e, t = "Task") {
|
|
24
|
+
super(`${t} timed out after ${e}ms`), this.timeoutMs = e;
|
|
25
|
+
}
|
|
26
|
+
}, FamiliarRuntimeError = class extends FamiliarError {}, n = 2147483647;
|
|
27
|
+
function validatePriority(e) {
|
|
28
|
+
if (!Number.isFinite(e)) throw new FamiliarInvalidOptionsError("`priority` must be a finite number");
|
|
29
|
+
return e;
|
|
30
|
+
}
|
|
31
|
+
function validateTimeout(e, t = "timeout") {
|
|
32
|
+
if (e !== void 0 && (!Number.isInteger(e) || e < 1 || e > 2147483647)) throw new FamiliarInvalidOptionsError(`\`${t}\` must be an integer from 1 through ${n}`);
|
|
33
|
+
return e;
|
|
34
|
+
}
|
|
35
|
+
function createPoolCore(n, r) {
|
|
36
|
+
let i = [...n], a = [], o = [], s = [], c = t(), l = new AbortController(), u = 0, d = 0, f = 0, p = 0, m = 0, h, g = !1;
|
|
37
|
+
function isIdle() {
|
|
38
|
+
return i.length === n.length && a.length === 0;
|
|
39
|
+
}
|
|
40
|
+
function settleIdle() {
|
|
41
|
+
if (isIdle()) for (let e of o.splice(0)) e.timer && clearTimeout(e.timer), e.resolve();
|
|
42
|
+
}
|
|
43
|
+
function waitForIdle(e) {
|
|
44
|
+
return isIdle() ? Promise.resolve() : new Promise((t, n) => {
|
|
45
|
+
let r = {
|
|
46
|
+
reject: n,
|
|
47
|
+
resolve: t
|
|
48
|
+
};
|
|
49
|
+
e.timeout !== void 0 && (r.timer = setTimeout(() => {
|
|
50
|
+
let t = o.indexOf(r);
|
|
51
|
+
t !== -1 && o.splice(t, 1), n(new FamiliarTimeoutError(e.timeout, "Drain"));
|
|
52
|
+
}, e.timeout), unrefTimer(r.timer)), o.push(r);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function releaseCapacity() {
|
|
56
|
+
s.shift()?.resolve();
|
|
57
|
+
}
|
|
58
|
+
function rejectCapacity(e) {
|
|
59
|
+
for (let t of s.splice(0)) t.reject(e);
|
|
60
|
+
}
|
|
61
|
+
function waitForCapacity(t, n) {
|
|
62
|
+
return t?.aborted ? Promise.reject(e(t)) : new Promise((r, i) => {
|
|
63
|
+
let a = !1, o = {
|
|
64
|
+
cleanup() {
|
|
65
|
+
t?.removeEventListener("abort", onAbort);
|
|
66
|
+
},
|
|
67
|
+
priority: n,
|
|
68
|
+
reject(e) {
|
|
69
|
+
if (a) return;
|
|
70
|
+
a = !0, o.cleanup();
|
|
71
|
+
let t = s.indexOf(o);
|
|
72
|
+
t !== -1 && s.splice(t, 1), i(e);
|
|
73
|
+
},
|
|
74
|
+
resolve() {
|
|
75
|
+
a || (a = !0, o.cleanup(), r());
|
|
76
|
+
},
|
|
77
|
+
sequence: f++
|
|
78
|
+
}, onAbort = () => o.reject(e(t));
|
|
79
|
+
t?.addEventListener("abort", onAbort, { once: !0 }), s.push(o), s.sort((e, t) => t.priority - e.priority || e.sequence - t.sequence);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function acquire(t, n) {
|
|
83
|
+
let { priority: i, signal: o } = t;
|
|
84
|
+
return o?.aborted ? Promise.reject(e(o)) : (async () => {
|
|
85
|
+
for (;;) {
|
|
86
|
+
if (g) throw new FamiliarTerminatedError();
|
|
87
|
+
if (h) throw new FamiliarTerminatedError("Worker is draining");
|
|
88
|
+
if (r.maxQueue === void 0 || a.length < r.maxQueue) return admit(t, n ?? ((e) => e));
|
|
89
|
+
if (r.onFull === "reject") throw new FamiliarQueueFullError(r.maxQueue);
|
|
90
|
+
if (await waitForCapacity(o, i), o?.aborted) throw releaseCapacity(), e(o);
|
|
91
|
+
}
|
|
92
|
+
})();
|
|
93
|
+
}
|
|
94
|
+
function admit(t, n) {
|
|
95
|
+
let { priority: r, signal: o } = t, s = i.pop();
|
|
96
|
+
if (s) try {
|
|
97
|
+
return Promise.resolve(n(s));
|
|
98
|
+
} catch (e) {
|
|
99
|
+
return release(s), settleIdle(), Promise.reject(e);
|
|
100
|
+
}
|
|
101
|
+
return new Promise((t, i) => {
|
|
102
|
+
let s = {
|
|
103
|
+
cleanup() {
|
|
104
|
+
s.signal?.removeEventListener("abort", onAbort);
|
|
105
|
+
},
|
|
106
|
+
priority: r,
|
|
107
|
+
reject(e) {
|
|
108
|
+
s.cleanup();
|
|
109
|
+
let t = a.indexOf(s);
|
|
110
|
+
t !== -1 && (a.splice(t, 1), releaseCapacity()), i(e), settleIdle();
|
|
111
|
+
},
|
|
112
|
+
sequence: d++,
|
|
113
|
+
signal: o,
|
|
114
|
+
start(e) {
|
|
115
|
+
s.cleanup();
|
|
116
|
+
try {
|
|
117
|
+
t(n(e));
|
|
118
|
+
} catch (t) {
|
|
119
|
+
release(e), settleIdle(), i(t);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}, onAbort = () => s.reject(e(s.signal));
|
|
123
|
+
s.signal?.addEventListener("abort", onAbort, { once: !0 }), a.push(s), a.sort((e, t) => t.priority - e.priority || e.sequence - t.sequence);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function release(e) {
|
|
127
|
+
let t = a.shift();
|
|
128
|
+
t ? (t.start(e), releaseCapacity()) : i.push(e);
|
|
129
|
+
}
|
|
130
|
+
function dispose() {
|
|
131
|
+
if (!g) {
|
|
132
|
+
g = !0, l.abort();
|
|
133
|
+
for (let e of n) e.terminate();
|
|
134
|
+
for (let e of a.splice(0)) e.reject(new FamiliarTerminatedError());
|
|
135
|
+
rejectCapacity(new FamiliarTerminatedError()), settleIdle(), c.emit({ type: "dispose" }), c.clear();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function drain(e = {}) {
|
|
139
|
+
if (g) return Promise.resolve();
|
|
140
|
+
try {
|
|
141
|
+
validateTimeout(e.timeout, "drain.timeout");
|
|
142
|
+
} catch (e) {
|
|
143
|
+
return Promise.reject(e);
|
|
144
|
+
}
|
|
145
|
+
return h || (rejectCapacity(new FamiliarTerminatedError("Worker is draining")), h = waitForIdle(e).then(() => dispose(), (e) => {
|
|
146
|
+
throw dispose(), e;
|
|
147
|
+
}), h);
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
acquire,
|
|
151
|
+
disposalSignal: l.signal,
|
|
152
|
+
dispose,
|
|
153
|
+
get disposed() {
|
|
154
|
+
return g;
|
|
155
|
+
},
|
|
156
|
+
drain,
|
|
157
|
+
get drainPromise() {
|
|
158
|
+
return h;
|
|
159
|
+
},
|
|
160
|
+
emitTap(e) {
|
|
161
|
+
c.emit(e);
|
|
162
|
+
},
|
|
163
|
+
release,
|
|
164
|
+
settleIdle,
|
|
165
|
+
stats() {
|
|
166
|
+
return {
|
|
167
|
+
active: u,
|
|
168
|
+
completed: p,
|
|
169
|
+
failed: m,
|
|
170
|
+
queued: a.length + s.length
|
|
171
|
+
};
|
|
172
|
+
},
|
|
173
|
+
status() {
|
|
174
|
+
return g ? "terminated" : u === 0 ? "idle" : "running";
|
|
175
|
+
},
|
|
176
|
+
tap(e, t) {
|
|
177
|
+
return g ? () => void 0 : c.tap(e, t);
|
|
178
|
+
},
|
|
179
|
+
trackActive(e) {
|
|
180
|
+
u += e;
|
|
181
|
+
},
|
|
182
|
+
trackCompleted() {
|
|
183
|
+
p += 1;
|
|
184
|
+
},
|
|
185
|
+
trackFailed() {
|
|
186
|
+
m += 1;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region src/_pool.ts
|
|
192
|
+
function createPool(t, n) {
|
|
193
|
+
let r = createPoolCore(t, n);
|
|
194
|
+
for (let e of t) e.notify = (e) => r.emitTap({
|
|
195
|
+
error: e,
|
|
196
|
+
type: "worker-error"
|
|
197
|
+
});
|
|
198
|
+
function run(t, i = {}) {
|
|
199
|
+
let a, o, s;
|
|
200
|
+
try {
|
|
201
|
+
a = validatePriority(i.priority ?? 0), o = validateTimeout(i.timeout) ?? n.defaultTimeout, s = [...i.transferables ?? []];
|
|
202
|
+
} catch (e) {
|
|
203
|
+
return Promise.reject(e);
|
|
204
|
+
}
|
|
205
|
+
return r.acquire({
|
|
206
|
+
priority: a,
|
|
207
|
+
signal: i.signal
|
|
208
|
+
}, (n) => {
|
|
209
|
+
r.trackActive(1);
|
|
210
|
+
let onAbort = () => n.cancel(e(i.signal));
|
|
211
|
+
i.signal?.addEventListener("abort", onAbort, { once: !0 });
|
|
212
|
+
let finish = async () => {
|
|
213
|
+
try {
|
|
214
|
+
let e = await n.run(t, s, o);
|
|
215
|
+
return r.trackCompleted(), e;
|
|
216
|
+
} catch (e) {
|
|
217
|
+
throw !i.signal?.aborted && !(e instanceof FamiliarTerminatedError) && r.trackFailed(), e;
|
|
218
|
+
} finally {
|
|
219
|
+
i.signal?.removeEventListener("abort", onAbort), r.trackActive(-1), r.release(n), r.settleIdle();
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
return finish();
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
get disposalSignal() {
|
|
227
|
+
return r.disposalSignal;
|
|
228
|
+
},
|
|
229
|
+
dispose: r.dispose,
|
|
230
|
+
get disposed() {
|
|
231
|
+
return r.disposed;
|
|
232
|
+
},
|
|
233
|
+
drain: r.drain,
|
|
234
|
+
run,
|
|
235
|
+
get stats() {
|
|
236
|
+
return r.stats();
|
|
237
|
+
},
|
|
238
|
+
get status() {
|
|
239
|
+
return r.status();
|
|
240
|
+
},
|
|
241
|
+
tap: r.tap,
|
|
242
|
+
[Symbol.asyncDispose]: () => r.drain({}),
|
|
243
|
+
[Symbol.dispose]: r.dispose
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function runBatch(t, n, r = {}) {
|
|
247
|
+
let i, iterate = async function* (i) {
|
|
248
|
+
let a = [], onAbort = () => i.abort(r.signal?.reason);
|
|
249
|
+
r.signal?.aborted ? i.abort(r.signal.reason) : r.signal?.addEventListener("abort", onAbort, { once: !0 });
|
|
250
|
+
try {
|
|
251
|
+
for (let [e, o] of n.entries()) {
|
|
252
|
+
let n = t.run(o, {
|
|
253
|
+
priority: r.priority,
|
|
254
|
+
signal: i.signal,
|
|
255
|
+
timeout: r.timeout,
|
|
256
|
+
transferables: r.getTransferables?.(o, e)
|
|
257
|
+
}).catch((e) => {
|
|
258
|
+
throw i.abort(e), e;
|
|
259
|
+
});
|
|
260
|
+
n.catch(() => void 0), a.push(n);
|
|
261
|
+
}
|
|
262
|
+
if (a.length === 0 && i.signal.aborted) throw e(i.signal);
|
|
263
|
+
for (let t of a) {
|
|
264
|
+
if (i.signal.aborted) throw e(i.signal);
|
|
265
|
+
let n = await t;
|
|
266
|
+
if (i.signal.aborted) throw e(i.signal);
|
|
267
|
+
yield n;
|
|
268
|
+
}
|
|
269
|
+
} catch (e) {
|
|
270
|
+
throw i.abort(e), e;
|
|
271
|
+
} finally {
|
|
272
|
+
r.signal?.removeEventListener("abort", onAbort), i.abort(new DOMException("Batch consumer stopped", "AbortError")), await Promise.allSettled(a);
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
return { [Symbol.asyncIterator]() {
|
|
276
|
+
let e = {}, t = new AbortController(), n, start = () => {
|
|
277
|
+
if (i ??= e, i === e) return n ??= iterate(t), n;
|
|
278
|
+
};
|
|
279
|
+
return {
|
|
280
|
+
next: () => start()?.next() ?? Promise.reject(new FamiliarRuntimeError("Worker batches can only be consumed once")),
|
|
281
|
+
return: async (r) => !i || i !== e ? {
|
|
282
|
+
done: !0,
|
|
283
|
+
value: r
|
|
284
|
+
} : (t.abort(new FamiliarTerminatedError("Batch consumer stopped")), n?.return(r) ?? {
|
|
285
|
+
done: !0,
|
|
286
|
+
value: r
|
|
287
|
+
}),
|
|
288
|
+
throw: async (e) => {
|
|
289
|
+
let n = start();
|
|
290
|
+
if (!n) throw new FamiliarRuntimeError("Worker batches can only be consumed once");
|
|
291
|
+
return t.abort(e), n.throw(e);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
} };
|
|
295
|
+
}
|
|
296
|
+
//#endregion
|
|
297
|
+
//#region src/_stream-pool.ts
|
|
298
|
+
function createStreamPool(t, n) {
|
|
299
|
+
let r = createPoolCore(t, n);
|
|
300
|
+
for (let e of t) e.notify = (e) => r.emitTap({
|
|
301
|
+
error: e,
|
|
302
|
+
type: "worker-error"
|
|
303
|
+
});
|
|
304
|
+
function runStream(t, i = {}) {
|
|
305
|
+
let a = validatePriority(i.priority ?? 0), o = validateTimeout(i.timeout) ?? n.defaultTimeout, s = [...i.transferables ?? []], c, iterate = async function* (n) {
|
|
306
|
+
let onAbort = () => n.abort(i.signal?.reason), c, onCancel;
|
|
307
|
+
i.signal?.aborted ? n.abort(i.signal.reason) : i.signal?.addEventListener("abort", onAbort, { once: !0 });
|
|
308
|
+
try {
|
|
309
|
+
let i = await r.acquire({
|
|
310
|
+
priority: a,
|
|
311
|
+
signal: n.signal
|
|
312
|
+
}, (i) => (c = i, r.trackActive(1), onCancel = () => c?.cancel(e(n.signal)), n.signal.addEventListener("abort", onCancel, { once: !0 }), i.stream(t, {
|
|
313
|
+
priority: a,
|
|
314
|
+
signal: n.signal,
|
|
315
|
+
timeout: o,
|
|
316
|
+
transferables: s
|
|
317
|
+
})));
|
|
318
|
+
for await (let e of i.iterable) yield e;
|
|
319
|
+
await i.done, r.trackCompleted();
|
|
320
|
+
} catch (e) {
|
|
321
|
+
throw c && !n.signal.aborted && !(e instanceof FamiliarTerminatedError) && r.trackFailed(), e;
|
|
322
|
+
} finally {
|
|
323
|
+
i.signal?.removeEventListener("abort", onAbort), c && (onCancel && n.signal.removeEventListener("abort", onCancel), r.trackActive(-1), r.release(c), r.settleIdle());
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
return { [Symbol.asyncIterator]() {
|
|
327
|
+
let e = {}, t = new AbortController(), n, start = () => {
|
|
328
|
+
if (c ??= e, c === e) return n ??= iterate(t), n;
|
|
329
|
+
};
|
|
330
|
+
return {
|
|
331
|
+
next: () => start()?.next() ?? Promise.reject(new FamiliarRuntimeError("Worker streams can only be consumed once")),
|
|
332
|
+
return: async (r) => !c || c !== e ? {
|
|
333
|
+
done: !0,
|
|
334
|
+
value: r
|
|
335
|
+
} : (t.abort(new FamiliarTerminatedError("Stream consumer stopped")), n?.return(r) ?? {
|
|
336
|
+
done: !0,
|
|
337
|
+
value: r
|
|
338
|
+
}),
|
|
339
|
+
throw: async (e) => {
|
|
340
|
+
let n = start();
|
|
341
|
+
if (!n) throw new FamiliarRuntimeError("Worker streams can only be consumed once");
|
|
342
|
+
return t.abort(e), n.throw(e);
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
} };
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
get disposalSignal() {
|
|
349
|
+
return r.disposalSignal;
|
|
350
|
+
},
|
|
351
|
+
dispose: r.dispose,
|
|
352
|
+
get disposed() {
|
|
353
|
+
return r.disposed;
|
|
354
|
+
},
|
|
355
|
+
drain: r.drain,
|
|
356
|
+
runStream,
|
|
357
|
+
get stats() {
|
|
358
|
+
return r.stats();
|
|
359
|
+
},
|
|
360
|
+
get status() {
|
|
361
|
+
return r.status();
|
|
362
|
+
},
|
|
363
|
+
tap: r.tap,
|
|
364
|
+
[Symbol.asyncDispose]: () => r.drain({}),
|
|
365
|
+
[Symbol.dispose]: r.dispose
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
//#endregion
|
|
369
|
+
//#region src/worker.ts
|
|
370
|
+
function resolveOptions(e = {}) {
|
|
371
|
+
let { concurrency: t = 1, maxQueue: n, onFull: r = "reject", timeout: i } = e, a = t === "auto" ? Math.min(512, Math.max(1, globalThis.navigator?.hardwareConcurrency ?? 1)) : t;
|
|
372
|
+
if (!Number.isInteger(a) || a < 1 || a > 512) throw new FamiliarInvalidOptionsError("`concurrency` must be a positive integer ≤ 512 or \"auto\"");
|
|
373
|
+
if (n !== void 0 && (!Number.isInteger(n) || n < 1)) throw new FamiliarInvalidOptionsError("`maxQueue` must be a positive integer");
|
|
374
|
+
if (r !== "reject" && r !== "wait") throw new FamiliarInvalidOptionsError("`onFull` must be \"reject\" or \"wait\"");
|
|
375
|
+
return validateTimeout(i), {
|
|
376
|
+
concurrency: a,
|
|
377
|
+
maxQueue: n,
|
|
378
|
+
onFull: r,
|
|
379
|
+
timeout: i
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
function isWorkerResponse(e) {
|
|
383
|
+
if (typeof e != "object" || !e) return !1;
|
|
384
|
+
let t = e;
|
|
385
|
+
return t.version !== 1 || typeof t.id != "number" || !Number.isSafeInteger(t.id) || t.id < 0 ? !1 : t.kind === "chunk" || t.kind === "result" ? "value" in t : t.kind !== "error" || typeof t.error != "object" || t.error === null ? !1 : (t.error.category === void 0 || t.error.category === "protocol") && typeof t.error.message == "string" && typeof t.error.name == "string" && (t.error.stack === void 0 || typeof t.error.stack == "string");
|
|
386
|
+
}
|
|
387
|
+
function responseError(e) {
|
|
388
|
+
let t = Error(e.message);
|
|
389
|
+
return t.name = e.name, t.stack = e.stack, e.category === "protocol" ? new FamiliarRuntimeError(e.message, { cause: t }) : new FamiliarTaskError(e.message, { cause: t });
|
|
390
|
+
}
|
|
391
|
+
var Slot = class {
|
|
392
|
+
#e;
|
|
393
|
+
#t = !1;
|
|
394
|
+
#n;
|
|
395
|
+
#r = 0;
|
|
396
|
+
#i;
|
|
397
|
+
notify = void 0;
|
|
398
|
+
constructor(e) {
|
|
399
|
+
this.#e = e;
|
|
400
|
+
}
|
|
401
|
+
cancel(e) {
|
|
402
|
+
this.#n && (this.#s(), this.#u("reject", e));
|
|
403
|
+
}
|
|
404
|
+
run(e, t, n) {
|
|
405
|
+
return this.#a(e, t, n, "run");
|
|
406
|
+
}
|
|
407
|
+
stream(e, t) {
|
|
408
|
+
let stop = () => this.cancel(new FamiliarTerminatedError("Stream consumer stopped")), n = [], r = [], i = !1, a, emit = (e) => {
|
|
409
|
+
let t = r.shift();
|
|
410
|
+
t ? t({
|
|
411
|
+
done: !1,
|
|
412
|
+
value: e
|
|
413
|
+
}) : n.push(e);
|
|
414
|
+
}, finish = (e) => {
|
|
415
|
+
for (i = !0, a = e; r.length > 0;) r.shift()(e === void 0 ? {
|
|
416
|
+
done: !0,
|
|
417
|
+
value: void 0
|
|
418
|
+
} : Promise.reject(e));
|
|
419
|
+
};
|
|
420
|
+
return {
|
|
421
|
+
done: this.#a(e, [...t.transferables ?? []], t.timeout, "stream", emit).then(() => finish(), (e) => finish(e)),
|
|
422
|
+
iterable: { [Symbol.asyncIterator]: () => ({
|
|
423
|
+
async next() {
|
|
424
|
+
if (n.length > 0) return {
|
|
425
|
+
done: !1,
|
|
426
|
+
value: n.shift()
|
|
427
|
+
};
|
|
428
|
+
if (a !== void 0) throw a;
|
|
429
|
+
return i ? {
|
|
430
|
+
done: !0,
|
|
431
|
+
value: void 0
|
|
432
|
+
} : new Promise((e, t) => {
|
|
433
|
+
r.push((n) => {
|
|
434
|
+
n instanceof Promise ? n.then(e, t) : e(n);
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
},
|
|
438
|
+
async return() {
|
|
439
|
+
return stop(), {
|
|
440
|
+
done: !0,
|
|
441
|
+
value: void 0
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
}) }
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
terminate() {
|
|
448
|
+
this.#t = !0, this.#s(), this.#u("reject", new FamiliarTerminatedError());
|
|
449
|
+
}
|
|
450
|
+
#a(e, t, n, r, i) {
|
|
451
|
+
if (this.#t) return Promise.reject(new FamiliarTerminatedError());
|
|
452
|
+
if (this.#n) return Promise.reject(new FamiliarRuntimeError("Worker slot is already busy"));
|
|
453
|
+
try {
|
|
454
|
+
let a = this.#o(), o = this.#r;
|
|
455
|
+
return this.#r = o === 2 ** 53 - 1 ? 0 : o + 1, new Promise((s, c) => {
|
|
456
|
+
let l = {
|
|
457
|
+
emit: i,
|
|
458
|
+
id: o,
|
|
459
|
+
kind: r,
|
|
460
|
+
reject: c,
|
|
461
|
+
resolve: s
|
|
462
|
+
};
|
|
463
|
+
this.#n = l, n !== void 0 && (l.timer = setTimeout(() => this.cancel(new FamiliarTimeoutError(n)), n), unrefTimer(l.timer));
|
|
464
|
+
try {
|
|
465
|
+
a.postMessage({
|
|
466
|
+
id: o,
|
|
467
|
+
input: e,
|
|
468
|
+
kind: r,
|
|
469
|
+
version: 1
|
|
470
|
+
}, t);
|
|
471
|
+
} catch (e) {
|
|
472
|
+
this.cancel(new FamiliarRuntimeError("Failed to post message to worker", { cause: e }));
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
} catch (e) {
|
|
476
|
+
return Promise.reject(e);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
#o() {
|
|
480
|
+
if (this.#i) return this.#i;
|
|
481
|
+
if (typeof Worker > "u") throw new FamiliarRuntimeError("Worker API is unavailable in this runtime");
|
|
482
|
+
try {
|
|
483
|
+
let e = new Worker(this.#e, { type: "module" });
|
|
484
|
+
return e.onmessage = (t) => {
|
|
485
|
+
this.#i === e && this.#l(t.data);
|
|
486
|
+
}, e.onerror = (t) => this.#c(e, new FamiliarRuntimeError(t.message || "Worker failed")), e.onmessageerror = () => this.#c(e, new FamiliarRuntimeError("Worker response could not be deserialized")), this.#i = e, e;
|
|
487
|
+
} catch (e) {
|
|
488
|
+
throw new FamiliarRuntimeError("Failed to create Worker", { cause: e });
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
#s() {
|
|
492
|
+
let e = this.#i;
|
|
493
|
+
this.#i = void 0, e && (e.onmessage = null, e.onerror = null, e.onmessageerror = null, e.terminate());
|
|
494
|
+
}
|
|
495
|
+
#c(e, t) {
|
|
496
|
+
this.#i === e && (this.#s(), this.#u("reject", t), this.notify?.(t));
|
|
497
|
+
}
|
|
498
|
+
#l(e) {
|
|
499
|
+
this.#n && (!isWorkerResponse(e) || e.id !== this.#n.id || this.#n.kind === "run" && e.kind === "chunk" ? this.cancel(new FamiliarRuntimeError("Worker returned an incompatible protocol response")) : e.kind === "chunk" ? this.#n.emit?.(e.value) : e.kind === "error" ? this.#u("reject", responseError(e.error)) : this.#u("resolve", e.value));
|
|
500
|
+
}
|
|
501
|
+
#u(e, t) {
|
|
502
|
+
let n = this.#n;
|
|
503
|
+
n && (this.#n = void 0, n.timer && clearTimeout(n.timer), e === "resolve" ? n.resolve(t) : n.reject(t));
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
function slots(e, t) {
|
|
507
|
+
let n = typeof e == "string" ? e : e.href;
|
|
508
|
+
return Array.from({ length: t.concurrency }, () => new Slot(n));
|
|
509
|
+
}
|
|
510
|
+
function createWorker(e, t = {}) {
|
|
511
|
+
let n = resolveOptions(t);
|
|
512
|
+
return createPool(slots(e, n), {
|
|
513
|
+
defaultTimeout: n.timeout,
|
|
514
|
+
maxQueue: n.maxQueue,
|
|
515
|
+
onFull: n.onFull
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
function createStreamWorker(e, t = {}) {
|
|
519
|
+
let n = resolveOptions(t);
|
|
520
|
+
return createStreamPool(slots(e, n), {
|
|
521
|
+
defaultTimeout: n.timeout,
|
|
522
|
+
maxQueue: n.maxQueue,
|
|
523
|
+
onFull: n.onFull
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
//#endregion
|
|
527
|
+
export { FamiliarError, FamiliarInvalidOptionsError, FamiliarQueueFullError, FamiliarRuntimeError, FamiliarTaskError, FamiliarTerminatedError, FamiliarTimeoutError, createStreamWorker, createWorker, runBatch };
|
|
528
|
+
|
|
2
529
|
//# sourceMappingURL=familiar.js.map
|