@bquery/bquery 1.9.0 → 1.10.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/README.md +181 -25
- package/dist/{a11y-_9X-kt-_.js → a11y-DG2i4iZN.js} +3 -3
- package/dist/{a11y-_9X-kt-_.js.map → a11y-DG2i4iZN.js.map} +1 -1
- package/dist/a11y.es.mjs +1 -1
- package/dist/{component-L3-JfOFz.js → component-DRotf1hl.js} +19 -18
- package/dist/{component-L3-JfOFz.js.map → component-DRotf1hl.js.map} +1 -1
- package/dist/component.es.mjs +1 -1
- package/dist/concurrency/errors.d.ts +29 -0
- package/dist/concurrency/errors.d.ts.map +1 -0
- package/dist/concurrency/high-level.d.ts +85 -0
- package/dist/concurrency/high-level.d.ts.map +1 -0
- package/dist/concurrency/index.d.ts +19 -0
- package/dist/concurrency/index.d.ts.map +1 -0
- package/dist/concurrency/internal.d.ts +26 -0
- package/dist/concurrency/internal.d.ts.map +1 -0
- package/dist/concurrency/pipeline.d.ts +30 -0
- package/dist/concurrency/pipeline.d.ts.map +1 -0
- package/dist/concurrency/pool.d.ts +48 -0
- package/dist/concurrency/pool.d.ts.map +1 -0
- package/dist/concurrency/reactive.d.ts +107 -0
- package/dist/concurrency/reactive.d.ts.map +1 -0
- package/dist/concurrency/rpc.d.ts +46 -0
- package/dist/concurrency/rpc.d.ts.map +1 -0
- package/dist/concurrency/support.d.ts +23 -0
- package/dist/concurrency/support.d.ts.map +1 -0
- package/dist/concurrency/task.d.ts +31 -0
- package/dist/concurrency/task.d.ts.map +1 -0
- package/dist/concurrency/types.d.ts +343 -0
- package/dist/concurrency/types.d.ts.map +1 -0
- package/dist/concurrency-BU1wPEsZ.js +826 -0
- package/dist/concurrency-BU1wPEsZ.js.map +1 -0
- package/dist/concurrency.es.mjs +29 -0
- package/dist/{constraints-D5RHQLmP.js → constraints-CqjhmpZC.js} +1 -1
- package/dist/{constraints-D5RHQLmP.js.map → constraints-CqjhmpZC.js.map} +1 -1
- package/dist/core-CongXJuo.js +87 -0
- package/dist/core-CongXJuo.js.map +1 -0
- package/dist/{custom-directives-Dr4C5lVV.js → custom-directives-BjFzFhuf.js} +1 -1
- package/dist/{custom-directives-Dr4C5lVV.js.map → custom-directives-BjFzFhuf.js.map} +1 -1
- package/dist/{devtools-BhB2iDPT.js → devtools-C5FExMwv.js} +2 -2
- package/dist/{devtools-BhB2iDPT.js.map → devtools-C5FExMwv.js.map} +1 -1
- package/dist/devtools.es.mjs +1 -1
- package/dist/{dnd-NwZBYh4l.js → dnd-BAqzPlSo.js} +1 -1
- package/dist/{dnd-NwZBYh4l.js.map → dnd-BAqzPlSo.js.map} +1 -1
- package/dist/dnd.es.mjs +1 -1
- package/dist/effect-Cc51IH91.js +87 -0
- package/dist/effect-Cc51IH91.js.map +1 -0
- package/dist/{env-CTdvLaH2.js → env-PvwYHnJq.js} +1 -1
- package/dist/{env-CTdvLaH2.js.map → env-PvwYHnJq.js.map} +1 -1
- package/dist/{forms-UhAeJEoO.js → forms-Dx1Scvh0.js} +41 -40
- package/dist/{forms-UhAeJEoO.js.map → forms-Dx1Scvh0.js.map} +1 -1
- package/dist/forms.es.mjs +1 -1
- package/dist/full.d.ts +2 -0
- package/dist/full.d.ts.map +1 -1
- package/dist/full.es.mjs +243 -214
- package/dist/full.iife.js +117 -33
- package/dist/full.iife.js.map +1 -1
- package/dist/full.umd.js +117 -33
- package/dist/full.umd.js.map +1 -1
- package/dist/{i18n-kuF6Ekj6.js → i18n-Cazyk9RD.js} +3 -3
- package/dist/{i18n-kuF6Ekj6.js.map → i18n-Cazyk9RD.js.map} +1 -1
- package/dist/i18n.es.mjs +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.mjs +270 -241
- package/dist/media/observers.d.ts.map +1 -1
- package/dist/{media-D4zLj9t-.js → media-dAKIGPk3.js} +3 -3
- package/dist/{media-D4zLj9t-.js.map → media-dAKIGPk3.js.map} +1 -1
- package/dist/media.es.mjs +1 -1
- package/dist/{motion-BJsAuULb.js → motion-BBMso9Ir.js} +1 -1
- package/dist/{motion-BJsAuULb.js.map → motion-BBMso9Ir.js.map} +1 -1
- package/dist/motion.es.mjs +1 -1
- package/dist/{mount-B-JvH6Y0.js → mount-C8O2vXkQ.js} +10 -9
- package/dist/{mount-B-JvH6Y0.js.map → mount-C8O2vXkQ.js.map} +1 -1
- package/dist/{platform-Dw2gE3zI.js → platform-BPHIXbw8.js} +17 -16
- package/dist/{platform-Dw2gE3zI.js.map → platform-BPHIXbw8.js.map} +1 -1
- package/dist/platform.es.mjs +1 -1
- package/dist/{plugin-C2WuC8SF.js → plugin-DjTqWg-P.js} +2 -2
- package/dist/{plugin-C2WuC8SF.js.map → plugin-DjTqWg-P.js.map} +1 -1
- package/dist/plugin.es.mjs +1 -1
- package/dist/reactive/watch.d.ts.map +1 -1
- package/dist/reactive/websocket.d.ts +6 -3
- package/dist/reactive/websocket.d.ts.map +1 -1
- package/dist/{reactive-BjpLkclt.js → reactive-BAd2hfl8.js} +436 -449
- package/dist/reactive-BAd2hfl8.js.map +1 -0
- package/dist/reactive.es.mjs +42 -40
- package/dist/readonly-C0ZwS1Tf.js +35 -0
- package/dist/readonly-C0ZwS1Tf.js.map +1 -0
- package/dist/{registry-B08iilIh.js → registry-Cr6VH8CR.js} +1 -1
- package/dist/{registry-B08iilIh.js.map → registry-Cr6VH8CR.js.map} +1 -1
- package/dist/{router-BieVwgci.js → router-CCepRMpC.js} +29 -28
- package/dist/{router-BieVwgci.js.map → router-CCepRMpC.js.map} +1 -1
- package/dist/router.es.mjs +1 -1
- package/dist/{ssr-CrGSJySz.js → ssr-D-1IPcfw.js} +4 -4
- package/dist/{ssr-CrGSJySz.js.map → ssr-D-1IPcfw.js.map} +1 -1
- package/dist/ssr.es.mjs +1 -1
- package/dist/{store-CY6sjTW3.js → store-CjmEeX9-.js} +6 -6
- package/dist/{store-CY6sjTW3.js.map → store-CjmEeX9-.js.map} +1 -1
- package/dist/store.es.mjs +2 -2
- package/dist/{testing-UjAtu9aQ.js → testing-TdfaL7VE.js} +7 -7
- package/dist/{testing-UjAtu9aQ.js.map → testing-TdfaL7VE.js.map} +1 -1
- package/dist/testing.es.mjs +1 -1
- package/dist/{untrack-D0fnO5k2.js → untrack-bjWDNdyE.js} +11 -10
- package/dist/{untrack-D0fnO5k2.js.map → untrack-bjWDNdyE.js.map} +1 -1
- package/dist/view.es.mjs +12 -11
- package/package.json +17 -13
- package/src/concurrency/errors.ts +57 -0
- package/src/concurrency/high-level.ts +387 -0
- package/src/concurrency/index.ts +63 -0
- package/src/concurrency/internal.ts +100 -0
- package/src/concurrency/pipeline.ts +133 -0
- package/src/concurrency/pool.ts +450 -0
- package/src/concurrency/reactive.ts +339 -0
- package/src/concurrency/rpc.ts +380 -0
- package/src/concurrency/support.ts +44 -0
- package/src/concurrency/task.ts +318 -0
- package/src/concurrency/types.ts +431 -0
- package/src/full.ts +65 -0
- package/src/index.ts +3 -0
- package/src/media/observers.ts +5 -8
- package/src/reactive/watch.ts +10 -9
- package/src/reactive/websocket.ts +31 -8
- package/dist/core-DdtZHzsS.js +0 -168
- package/dist/core-DdtZHzsS.js.map +0 -1
- package/dist/reactive-BjpLkclt.js.map +0 -1
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for the concurrency module.
|
|
3
|
+
*
|
|
4
|
+
* @module bquery/concurrency
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ReadonlySignalHandle } from '../reactive/index';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Standalone task handler executed inside a Web Worker.
|
|
11
|
+
*
|
|
12
|
+
* The function must be self-contained because it is stringified and evaluated
|
|
13
|
+
* in the worker context without access to outer closures.
|
|
14
|
+
*
|
|
15
|
+
* The bivariance wrapper is intentional: TypeScript checks plain function
|
|
16
|
+
* parameter types contravariantly under `strictFunctionTypes`, but method
|
|
17
|
+
* signatures remain bivariant. Modeling the public handler as a method-shaped
|
|
18
|
+
* signature keeps object-literal task and RPC handlers ergonomic in strict
|
|
19
|
+
* typechecks, including the repository's dedicated test typecheck. In practice
|
|
20
|
+
* this allows narrower inline handler parameter annotations in object literals;
|
|
21
|
+
* the trade-off is that assignability here is intentionally a little less strict
|
|
22
|
+
* than a plain function-type alias would be.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const square = (value: number) => value * value;
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export type WorkerTaskHandler<TInput = void, TResult = unknown> = {
|
|
30
|
+
bivarianceHack(input: TInput): TResult | Promise<TResult>;
|
|
31
|
+
}['bivarianceHack'];
|
|
32
|
+
|
|
33
|
+
/** Lifecycle state of a reusable task worker. */
|
|
34
|
+
export type TaskWorkerState = 'idle' | 'running' | 'terminated';
|
|
35
|
+
|
|
36
|
+
/** Structured error codes emitted by the concurrency module. */
|
|
37
|
+
export type TaskWorkerErrorCode =
|
|
38
|
+
| 'ABORT'
|
|
39
|
+
| 'BUSY'
|
|
40
|
+
| 'METHOD_NOT_FOUND'
|
|
41
|
+
| 'QUEUE_CLEARED'
|
|
42
|
+
| 'QUEUE_FULL'
|
|
43
|
+
| 'SERIALIZATION'
|
|
44
|
+
| 'TERMINATED'
|
|
45
|
+
| 'TIMEOUT'
|
|
46
|
+
| 'UNSUPPORTED'
|
|
47
|
+
| 'WORKER';
|
|
48
|
+
|
|
49
|
+
/** Per-run options for worker task execution. */
|
|
50
|
+
export interface TaskRunOptions {
|
|
51
|
+
/**
|
|
52
|
+
* AbortSignal used to cancel the current run.
|
|
53
|
+
* Cancellation terminates the active worker run so later runs start cleanly.
|
|
54
|
+
*/
|
|
55
|
+
signal?: AbortSignal;
|
|
56
|
+
/**
|
|
57
|
+
* Optional timeout in milliseconds.
|
|
58
|
+
* Non-finite or non-positive values disable timeout handling.
|
|
59
|
+
*/
|
|
60
|
+
timeout?: number;
|
|
61
|
+
/**
|
|
62
|
+
* Transferable values passed together with the task payload.
|
|
63
|
+
* Use this for large `ArrayBuffer`-backed payloads when appropriate.
|
|
64
|
+
*/
|
|
65
|
+
transfer?: Transferable[];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Options for creating a reusable task worker. */
|
|
69
|
+
export interface CreateTaskWorkerOptions {
|
|
70
|
+
/** Optional worker name shown in browser tooling where supported. */
|
|
71
|
+
name?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Default timeout applied to `run()` calls when the run itself does not
|
|
74
|
+
* override it.
|
|
75
|
+
*/
|
|
76
|
+
timeout?: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Options accepted by the one-off `runTask()` helper. */
|
|
80
|
+
export interface RunTaskOptions extends CreateTaskWorkerOptions, TaskRunOptions {}
|
|
81
|
+
|
|
82
|
+
/** Options for creating a reusable RPC worker. */
|
|
83
|
+
export type CreateRpcWorkerOptions = CreateTaskWorkerOptions;
|
|
84
|
+
|
|
85
|
+
/** Options accepted by the one-off RPC method helper. */
|
|
86
|
+
export interface CallWorkerMethodOptions extends CreateRpcWorkerOptions, TaskRunOptions {}
|
|
87
|
+
|
|
88
|
+
/** Options for creating a reusable task worker pool. */
|
|
89
|
+
export interface CreateTaskPoolOptions extends CreateTaskWorkerOptions {
|
|
90
|
+
/** Maximum number of workers executing tasks in parallel (default: 4). */
|
|
91
|
+
concurrency?: number;
|
|
92
|
+
/**
|
|
93
|
+
* Maximum number of not-yet-started tasks kept in the queue.
|
|
94
|
+
* Use `0` to disable queueing or `Infinity` for an unbounded queue.
|
|
95
|
+
*/
|
|
96
|
+
maxQueue?: number;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Options for creating a reusable RPC worker pool. */
|
|
100
|
+
export interface CreateRpcPoolOptions extends CreateRpcWorkerOptions {
|
|
101
|
+
/** Maximum number of workers executing calls in parallel (default: 4). */
|
|
102
|
+
concurrency?: number;
|
|
103
|
+
/**
|
|
104
|
+
* Maximum number of not-yet-started calls kept in the queue.
|
|
105
|
+
* Use `0` to disable queueing or `Infinity` for an unbounded queue.
|
|
106
|
+
*/
|
|
107
|
+
maxQueue?: number;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Standalone task descriptor for `parallel()` / `batchTasks()`. */
|
|
111
|
+
export interface ParallelTask<TInput = unknown, TResult = unknown> {
|
|
112
|
+
/** Standalone handler revived inside a worker context. */
|
|
113
|
+
handler: WorkerTaskHandler<TInput, TResult>;
|
|
114
|
+
/** Serializable payload for the handler. */
|
|
115
|
+
input: TInput;
|
|
116
|
+
/** Optional per-task timeout, abort, and transfer options. */
|
|
117
|
+
options?: TaskRunOptions;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Shared pool options for high-level parallel task helpers. */
|
|
121
|
+
export type ParallelOptions = CreateTaskPoolOptions;
|
|
122
|
+
|
|
123
|
+
/** Shared options for chunked collection helpers such as `map()` and `filter()`. */
|
|
124
|
+
export interface ParallelCollectionOptions extends CreateTaskPoolOptions {
|
|
125
|
+
/**
|
|
126
|
+
* Number of array items grouped into each worker run.
|
|
127
|
+
* Defaults to `1`.
|
|
128
|
+
*/
|
|
129
|
+
batchSize?: number;
|
|
130
|
+
/** AbortSignal shared across all queued or running chunks. */
|
|
131
|
+
signal?: AbortSignal;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Callback signature used by `map()` for parallel array processing. */
|
|
135
|
+
export type ParallelMapHandler<TInput, TResult> = (
|
|
136
|
+
value: TInput,
|
|
137
|
+
index: number
|
|
138
|
+
) => TResult | Promise<TResult>;
|
|
139
|
+
|
|
140
|
+
/** Callback signature used by predicate-style helpers such as `filter()`. */
|
|
141
|
+
export type ParallelPredicateHandler<TInput> = (
|
|
142
|
+
value: TInput,
|
|
143
|
+
index: number
|
|
144
|
+
) => boolean | Promise<boolean>;
|
|
145
|
+
|
|
146
|
+
/** Callback signature used by `reduce()` for sequential accumulation inside a worker. */
|
|
147
|
+
export type ParallelReduceHandler<TAccumulator, TInput> = (
|
|
148
|
+
accumulator: TAccumulator,
|
|
149
|
+
value: TInput,
|
|
150
|
+
index: number
|
|
151
|
+
) => TAccumulator | Promise<TAccumulator>;
|
|
152
|
+
|
|
153
|
+
/** Options for `map()` chunking and cancellation behavior. */
|
|
154
|
+
export type ParallelMapOptions = ParallelCollectionOptions;
|
|
155
|
+
|
|
156
|
+
/** Shared defaults for the optional fluent concurrency pipeline. */
|
|
157
|
+
export type ConcurrencyPipelineOptions = ParallelCollectionOptions;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Optional fluent pipeline over the existing explicit collection helpers.
|
|
161
|
+
*
|
|
162
|
+
* The pipeline is immutable: each transforming stage returns a new pipeline
|
|
163
|
+
* instead of mutating the previous one in place.
|
|
164
|
+
*/
|
|
165
|
+
export interface ConcurrencyPipeline<TValue> {
|
|
166
|
+
/**
|
|
167
|
+
* Maps the current array value through the existing worker-backed `map()` helper.
|
|
168
|
+
*/
|
|
169
|
+
map<TResult>(
|
|
170
|
+
mapper: ParallelMapHandler<TValue, TResult>,
|
|
171
|
+
options?: ParallelCollectionOptions
|
|
172
|
+
): ConcurrencyPipeline<TResult>;
|
|
173
|
+
/**
|
|
174
|
+
* Filters the current array value through the existing worker-backed `filter()` helper.
|
|
175
|
+
*/
|
|
176
|
+
filter(
|
|
177
|
+
predicate: ParallelPredicateHandler<TValue>,
|
|
178
|
+
options?: ParallelCollectionOptions
|
|
179
|
+
): ConcurrencyPipeline<TValue>;
|
|
180
|
+
/**
|
|
181
|
+
* Resolves the pipeline to a materialized array.
|
|
182
|
+
*/
|
|
183
|
+
toArray(): Promise<TValue[]>;
|
|
184
|
+
/**
|
|
185
|
+
* Evaluates whether at least one item matches via the existing `some()` helper.
|
|
186
|
+
*/
|
|
187
|
+
some(
|
|
188
|
+
predicate: ParallelPredicateHandler<TValue>,
|
|
189
|
+
options?: ParallelCollectionOptions
|
|
190
|
+
): Promise<boolean>;
|
|
191
|
+
/**
|
|
192
|
+
* Evaluates whether every item matches via the existing `every()` helper.
|
|
193
|
+
*/
|
|
194
|
+
every(
|
|
195
|
+
predicate: ParallelPredicateHandler<TValue>,
|
|
196
|
+
options?: ParallelCollectionOptions
|
|
197
|
+
): Promise<boolean>;
|
|
198
|
+
/**
|
|
199
|
+
* Finds the first matching item via the existing `find()` helper.
|
|
200
|
+
*/
|
|
201
|
+
find(
|
|
202
|
+
predicate: ParallelPredicateHandler<TValue>,
|
|
203
|
+
options?: ParallelCollectionOptions
|
|
204
|
+
): Promise<TValue | undefined>;
|
|
205
|
+
/**
|
|
206
|
+
* Reduces the current array value via the existing `reduce()` helper.
|
|
207
|
+
*/
|
|
208
|
+
reduce<TAccumulator>(
|
|
209
|
+
reducer: ParallelReduceHandler<TAccumulator, TValue>,
|
|
210
|
+
initialValue: TAccumulator,
|
|
211
|
+
options?: TaskRunOptions
|
|
212
|
+
): Promise<TAccumulator>;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Result tuple inferred from a `parallel()` or `batchTasks()` task list. */
|
|
216
|
+
export type ParallelResults<TTasks extends readonly ParallelTask<unknown, unknown>[]> = {
|
|
217
|
+
[TIndex in keyof TTasks]: TTasks[TIndex] extends ParallelTask<unknown, infer TResult>
|
|
218
|
+
? Awaited<TResult>
|
|
219
|
+
: never;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
/** Feature-detection snapshot for the browser concurrency runtime. */
|
|
223
|
+
export interface ConcurrencySupport {
|
|
224
|
+
/** `Worker` constructor availability. */
|
|
225
|
+
worker: boolean;
|
|
226
|
+
/** `Blob` availability for zero-build inline worker scripts. */
|
|
227
|
+
blob: boolean;
|
|
228
|
+
/** `URL.createObjectURL()` and `URL.revokeObjectURL()` availability. */
|
|
229
|
+
objectUrl: boolean;
|
|
230
|
+
/** `AbortController` availability for cancellation ergonomics. */
|
|
231
|
+
abortController: boolean;
|
|
232
|
+
/** Whether the minimum browser primitives for this module are present. */
|
|
233
|
+
supported: boolean;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Reusable worker-task handle.
|
|
238
|
+
*
|
|
239
|
+
* A task worker runs one task at a time. Queueing and pooling live in the
|
|
240
|
+
* separate `TaskPool` / `RpcPool` APIs so the worker handle itself stays explicit.
|
|
241
|
+
*/
|
|
242
|
+
export interface TaskWorker<TInput = void, TResult = unknown> {
|
|
243
|
+
/** Current lifecycle state. */
|
|
244
|
+
readonly state: TaskWorkerState;
|
|
245
|
+
/** Whether a task is currently running. */
|
|
246
|
+
readonly busy: boolean;
|
|
247
|
+
/**
|
|
248
|
+
* Execute one task in the backing worker.
|
|
249
|
+
*
|
|
250
|
+
* @param input - Serializable input passed to the task handler
|
|
251
|
+
* @param options - Per-run timeout, abort, and transfer options
|
|
252
|
+
*/
|
|
253
|
+
run(input: TInput, options?: TaskRunOptions): Promise<TResult>;
|
|
254
|
+
/**
|
|
255
|
+
* Permanently terminate the backing worker.
|
|
256
|
+
* Any in-flight task is rejected with a termination error.
|
|
257
|
+
*/
|
|
258
|
+
terminate(): void;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Reactive wrapper around a reusable task worker.
|
|
263
|
+
*
|
|
264
|
+
* Extends the standard {@link TaskWorker} API with readonly signals so UI code
|
|
265
|
+
* can observe worker lifecycle changes without polling getters manually.
|
|
266
|
+
*/
|
|
267
|
+
export interface ReactiveTaskWorker<TInput = void, TResult = unknown> extends TaskWorker<
|
|
268
|
+
TInput,
|
|
269
|
+
TResult
|
|
270
|
+
> {
|
|
271
|
+
/** Reactive mirror of {@link TaskWorker.state}. */
|
|
272
|
+
readonly state$: ReadonlySignalHandle<TaskWorkerState>;
|
|
273
|
+
/** Reactive mirror of {@link TaskWorker.busy}. */
|
|
274
|
+
readonly busy$: ReadonlySignalHandle<boolean>;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** Standalone named RPC handler executed inside a Web Worker. */
|
|
278
|
+
export type WorkerRpcHandler<TInput = void, TResult = unknown> = WorkerTaskHandler<TInput, TResult>;
|
|
279
|
+
|
|
280
|
+
/** Explicit map of named worker RPC handlers. */
|
|
281
|
+
export type WorkerRpcHandlers = Record<string, WorkerRpcHandler<unknown, unknown>>;
|
|
282
|
+
|
|
283
|
+
/** Reusable RPC-style worker handle with named method dispatch. */
|
|
284
|
+
export interface RpcWorker<TRoutes extends WorkerRpcHandlers = WorkerRpcHandlers> {
|
|
285
|
+
/** Current lifecycle state. */
|
|
286
|
+
readonly state: TaskWorkerState;
|
|
287
|
+
/** Whether a method call is currently in progress. */
|
|
288
|
+
readonly busy: boolean;
|
|
289
|
+
/**
|
|
290
|
+
* Call one named RPC method in the backing worker.
|
|
291
|
+
*
|
|
292
|
+
* @param method - Method name from the provided RPC handler map
|
|
293
|
+
* @param input - Serializable payload for the selected method
|
|
294
|
+
* @param options - Per-call timeout, abort, and transfer options
|
|
295
|
+
*/
|
|
296
|
+
call<TMethod extends keyof TRoutes & string>(
|
|
297
|
+
method: TMethod,
|
|
298
|
+
input: Parameters<TRoutes[TMethod]>[0],
|
|
299
|
+
options?: TaskRunOptions
|
|
300
|
+
): Promise<Awaited<ReturnType<TRoutes[TMethod]>>>;
|
|
301
|
+
/**
|
|
302
|
+
* Permanently terminate the backing worker.
|
|
303
|
+
* Any in-flight call is rejected with a termination error.
|
|
304
|
+
*/
|
|
305
|
+
terminate(): void;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Reactive wrapper around a reusable RPC worker.
|
|
310
|
+
*
|
|
311
|
+
* Extends the standard {@link RpcWorker} API with readonly signals so UI code
|
|
312
|
+
* can observe worker lifecycle changes without polling getters manually.
|
|
313
|
+
*/
|
|
314
|
+
export interface ReactiveRpcWorker<
|
|
315
|
+
TRoutes extends WorkerRpcHandlers = WorkerRpcHandlers,
|
|
316
|
+
> extends RpcWorker<TRoutes> {
|
|
317
|
+
/** Reactive mirror of {@link RpcWorker.state}. */
|
|
318
|
+
readonly state$: ReadonlySignalHandle<TaskWorkerState>;
|
|
319
|
+
/** Reactive mirror of {@link RpcWorker.busy}. */
|
|
320
|
+
readonly busy$: ReadonlySignalHandle<boolean>;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/** Reusable pool of task workers with bounded concurrency and queueing. */
|
|
324
|
+
export interface TaskPool<TInput = void, TResult = unknown> {
|
|
325
|
+
/** Current lifecycle state. */
|
|
326
|
+
readonly state: TaskWorkerState;
|
|
327
|
+
/** Whether the pool has active or queued tasks. */
|
|
328
|
+
readonly busy: boolean;
|
|
329
|
+
/** Maximum number of parallel worker runs. */
|
|
330
|
+
readonly concurrency: number;
|
|
331
|
+
/** Number of tasks currently running. */
|
|
332
|
+
readonly pending: number;
|
|
333
|
+
/** Number of tasks currently waiting in the queue. */
|
|
334
|
+
readonly size: number;
|
|
335
|
+
/**
|
|
336
|
+
* Queue or immediately execute one task in the pool.
|
|
337
|
+
*
|
|
338
|
+
* @param input - Serializable task input
|
|
339
|
+
* @param options - Per-run timeout, abort, and transfer options
|
|
340
|
+
*/
|
|
341
|
+
run(input: TInput, options?: TaskRunOptions): Promise<TResult>;
|
|
342
|
+
/**
|
|
343
|
+
* Remove queued tasks that have not started yet.
|
|
344
|
+
* Active tasks continue running.
|
|
345
|
+
*/
|
|
346
|
+
clear(): void;
|
|
347
|
+
/**
|
|
348
|
+
* Permanently terminate the pool and all backing workers.
|
|
349
|
+
* Active and queued tasks reject with termination errors.
|
|
350
|
+
*/
|
|
351
|
+
terminate(): void;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Reactive wrapper around a reusable task pool.
|
|
356
|
+
*
|
|
357
|
+
* Extends the standard {@link TaskPool} API with readonly signals for pool
|
|
358
|
+
* state, queue pressure, and configured concurrency.
|
|
359
|
+
*/
|
|
360
|
+
export interface ReactiveTaskPool<TInput = void, TResult = unknown> extends TaskPool<
|
|
361
|
+
TInput,
|
|
362
|
+
TResult
|
|
363
|
+
> {
|
|
364
|
+
/** Reactive mirror of {@link TaskPool.state}. */
|
|
365
|
+
readonly state$: ReadonlySignalHandle<TaskWorkerState>;
|
|
366
|
+
/** Reactive mirror of {@link TaskPool.busy}. */
|
|
367
|
+
readonly busy$: ReadonlySignalHandle<boolean>;
|
|
368
|
+
/** Reactive mirror of {@link TaskPool.concurrency}. */
|
|
369
|
+
readonly concurrency$: ReadonlySignalHandle<number>;
|
|
370
|
+
/** Reactive mirror of {@link TaskPool.pending}. */
|
|
371
|
+
readonly pending$: ReadonlySignalHandle<number>;
|
|
372
|
+
/** Reactive mirror of {@link TaskPool.size}. */
|
|
373
|
+
readonly size$: ReadonlySignalHandle<number>;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/** Reusable pool of RPC workers with bounded concurrency and queueing. */
|
|
377
|
+
export interface RpcPool<TRoutes extends WorkerRpcHandlers = WorkerRpcHandlers> {
|
|
378
|
+
/** Current lifecycle state. */
|
|
379
|
+
readonly state: TaskWorkerState;
|
|
380
|
+
/** Whether the pool has active or queued calls. */
|
|
381
|
+
readonly busy: boolean;
|
|
382
|
+
/** Maximum number of parallel worker calls. */
|
|
383
|
+
readonly concurrency: number;
|
|
384
|
+
/** Number of calls currently running. */
|
|
385
|
+
readonly pending: number;
|
|
386
|
+
/** Number of calls currently waiting in the queue. */
|
|
387
|
+
readonly size: number;
|
|
388
|
+
/**
|
|
389
|
+
* Queue or immediately execute one RPC call in the pool.
|
|
390
|
+
*
|
|
391
|
+
* @param method - Method name from the provided RPC handler map
|
|
392
|
+
* @param input - Serializable payload for the selected method
|
|
393
|
+
* @param options - Per-call timeout, abort, and transfer options
|
|
394
|
+
*/
|
|
395
|
+
call<TMethod extends keyof TRoutes & string>(
|
|
396
|
+
method: TMethod,
|
|
397
|
+
input: Parameters<TRoutes[TMethod]>[0],
|
|
398
|
+
options?: TaskRunOptions
|
|
399
|
+
): Promise<Awaited<ReturnType<TRoutes[TMethod]>>>;
|
|
400
|
+
/**
|
|
401
|
+
* Remove queued calls that have not started yet.
|
|
402
|
+
* Active calls continue running.
|
|
403
|
+
*/
|
|
404
|
+
clear(): void;
|
|
405
|
+
/**
|
|
406
|
+
* Permanently terminate the pool and all backing workers.
|
|
407
|
+
* Active and queued calls reject with termination errors.
|
|
408
|
+
*/
|
|
409
|
+
terminate(): void;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Reactive wrapper around a reusable RPC pool.
|
|
414
|
+
*
|
|
415
|
+
* Extends the standard {@link RpcPool} API with readonly signals for pool
|
|
416
|
+
* state, queue pressure, and configured concurrency.
|
|
417
|
+
*/
|
|
418
|
+
export interface ReactiveRpcPool<
|
|
419
|
+
TRoutes extends WorkerRpcHandlers = WorkerRpcHandlers,
|
|
420
|
+
> extends RpcPool<TRoutes> {
|
|
421
|
+
/** Reactive mirror of {@link RpcPool.state}. */
|
|
422
|
+
readonly state$: ReadonlySignalHandle<TaskWorkerState>;
|
|
423
|
+
/** Reactive mirror of {@link RpcPool.busy}. */
|
|
424
|
+
readonly busy$: ReadonlySignalHandle<boolean>;
|
|
425
|
+
/** Reactive mirror of {@link RpcPool.concurrency}. */
|
|
426
|
+
readonly concurrency$: ReadonlySignalHandle<number>;
|
|
427
|
+
/** Reactive mirror of {@link RpcPool.pending}. */
|
|
428
|
+
readonly pending$: ReadonlySignalHandle<number>;
|
|
429
|
+
/** Reactive mirror of {@link RpcPool.size}. */
|
|
430
|
+
readonly size$: ReadonlySignalHandle<number>;
|
|
431
|
+
}
|
package/src/full.ts
CHANGED
|
@@ -138,6 +138,71 @@ export type {
|
|
|
138
138
|
WebSocketStatus,
|
|
139
139
|
} from './reactive/index';
|
|
140
140
|
|
|
141
|
+
// ============================================================================
|
|
142
|
+
// Concurrency Module: Zero-build worker task helpers
|
|
143
|
+
// ============================================================================
|
|
144
|
+
export {
|
|
145
|
+
batchTasks,
|
|
146
|
+
callWorkerMethod,
|
|
147
|
+
createReactiveRpcPool,
|
|
148
|
+
createReactiveRpcWorker,
|
|
149
|
+
createReactiveTaskPool,
|
|
150
|
+
createReactiveTaskWorker,
|
|
151
|
+
createRpcPool,
|
|
152
|
+
createRpcWorker,
|
|
153
|
+
createTaskPool,
|
|
154
|
+
createTaskWorker,
|
|
155
|
+
every,
|
|
156
|
+
filter,
|
|
157
|
+
find,
|
|
158
|
+
getConcurrencySupport,
|
|
159
|
+
isConcurrencySupported,
|
|
160
|
+
map,
|
|
161
|
+
parallel,
|
|
162
|
+
pipeline,
|
|
163
|
+
reduce,
|
|
164
|
+
runTask,
|
|
165
|
+
some,
|
|
166
|
+
TaskWorkerAbortError,
|
|
167
|
+
TaskWorkerError,
|
|
168
|
+
TaskWorkerSerializationError,
|
|
169
|
+
TaskWorkerTimeoutError,
|
|
170
|
+
TaskWorkerUnsupportedError,
|
|
171
|
+
} from './concurrency/index';
|
|
172
|
+
export type {
|
|
173
|
+
CallWorkerMethodOptions,
|
|
174
|
+
ConcurrencyPipeline,
|
|
175
|
+
ConcurrencyPipelineOptions,
|
|
176
|
+
ConcurrencySupport,
|
|
177
|
+
CreateRpcPoolOptions,
|
|
178
|
+
CreateRpcWorkerOptions,
|
|
179
|
+
CreateTaskPoolOptions,
|
|
180
|
+
CreateTaskWorkerOptions,
|
|
181
|
+
ParallelCollectionOptions,
|
|
182
|
+
ParallelMapHandler,
|
|
183
|
+
ParallelMapOptions,
|
|
184
|
+
ParallelOptions,
|
|
185
|
+
ParallelPredicateHandler,
|
|
186
|
+
ParallelReduceHandler,
|
|
187
|
+
ParallelResults,
|
|
188
|
+
ParallelTask,
|
|
189
|
+
ReactiveRpcPool,
|
|
190
|
+
ReactiveRpcWorker,
|
|
191
|
+
ReactiveTaskPool,
|
|
192
|
+
ReactiveTaskWorker,
|
|
193
|
+
RpcPool,
|
|
194
|
+
RpcWorker,
|
|
195
|
+
RunTaskOptions,
|
|
196
|
+
TaskPool,
|
|
197
|
+
TaskRunOptions,
|
|
198
|
+
TaskWorker,
|
|
199
|
+
TaskWorkerErrorCode,
|
|
200
|
+
TaskWorkerState,
|
|
201
|
+
WorkerRpcHandler,
|
|
202
|
+
WorkerRpcHandlers,
|
|
203
|
+
WorkerTaskHandler,
|
|
204
|
+
} from './concurrency/index';
|
|
205
|
+
|
|
141
206
|
// ============================================================================
|
|
142
207
|
// Component Module: Web Components helper with Shadow DOM
|
|
143
208
|
// ============================================================================
|
package/src/index.ts
CHANGED
|
@@ -14,6 +14,9 @@ export * from './core/index';
|
|
|
14
14
|
// Reactive module: signals, computed, effects, binding
|
|
15
15
|
export * from './reactive/index';
|
|
16
16
|
|
|
17
|
+
// Concurrency module: zero-build worker task helpers
|
|
18
|
+
export * from './concurrency/index';
|
|
19
|
+
|
|
17
20
|
// Component module: Web Components helper
|
|
18
21
|
export * from './component/index';
|
|
19
22
|
|
package/src/media/observers.ts
CHANGED
|
@@ -29,10 +29,7 @@ const getResizeDimensions = (
|
|
|
29
29
|
entry: ResizeObserverEntry,
|
|
30
30
|
box: ResizeObserverBoxOptions
|
|
31
31
|
): Pick<ResizeObserverState, 'width' | 'height'> => {
|
|
32
|
-
let boxSize:
|
|
33
|
-
| ResizeObserverBoxSizeLike
|
|
34
|
-
| readonly ResizeObserverBoxSizeLike[]
|
|
35
|
-
| undefined;
|
|
32
|
+
let boxSize: ResizeObserverBoxSizeLike | readonly ResizeObserverBoxSizeLike[] | undefined;
|
|
36
33
|
|
|
37
34
|
if (box === 'border-box') {
|
|
38
35
|
boxSize = entry.borderBoxSize;
|
|
@@ -100,7 +97,7 @@ const getResizeDimensions = (
|
|
|
100
97
|
*/
|
|
101
98
|
export const useIntersectionObserver = (
|
|
102
99
|
target?: Element | Element[] | null,
|
|
103
|
-
options?: IntersectionObserverOptions
|
|
100
|
+
options?: IntersectionObserverOptions
|
|
104
101
|
): IntersectionObserverSignal => {
|
|
105
102
|
const initial: IntersectionObserverState = {
|
|
106
103
|
isIntersecting: false,
|
|
@@ -130,7 +127,7 @@ export const useIntersectionObserver = (
|
|
|
130
127
|
root: options?.root ?? null,
|
|
131
128
|
rootMargin: options?.rootMargin ?? '0px',
|
|
132
129
|
threshold: options?.threshold ?? 0,
|
|
133
|
-
}
|
|
130
|
+
}
|
|
134
131
|
);
|
|
135
132
|
|
|
136
133
|
// Observe initial targets
|
|
@@ -216,7 +213,7 @@ export const useIntersectionObserver = (
|
|
|
216
213
|
*/
|
|
217
214
|
export const useResizeObserver = (
|
|
218
215
|
target?: Element | Element[] | null,
|
|
219
|
-
options?: ResizeObserverOptions
|
|
216
|
+
options?: ResizeObserverOptions
|
|
220
217
|
): ResizeObserverSignal => {
|
|
221
218
|
const initial: ResizeObserverState = {
|
|
222
219
|
width: 0,
|
|
@@ -326,7 +323,7 @@ export const useResizeObserver = (
|
|
|
326
323
|
*/
|
|
327
324
|
export const useMutationObserver = (
|
|
328
325
|
target?: Node | null,
|
|
329
|
-
options?: MutationObserverOptions
|
|
326
|
+
options?: MutationObserverOptions
|
|
330
327
|
): MutationObserverSignal => {
|
|
331
328
|
const initial: MutationObserverState = {
|
|
332
329
|
mutations: [],
|
package/src/reactive/watch.ts
CHANGED
|
@@ -188,20 +188,21 @@ export const watchThrottle = <T>(
|
|
|
188
188
|
): CleanupFn => {
|
|
189
189
|
const { immediate = false, equals = Object.is } = options;
|
|
190
190
|
const normalizedIntervalMs = Number.isFinite(intervalMs) ? Math.max(0, intervalMs) : 0;
|
|
191
|
-
const notify = throttle(
|
|
192
|
-
(newValue
|
|
193
|
-
|
|
194
|
-
},
|
|
195
|
-
normalizedIntervalMs
|
|
196
|
-
);
|
|
191
|
+
const notify = throttle((newValue: T, oldValue: T | undefined) => {
|
|
192
|
+
callback(newValue, oldValue);
|
|
193
|
+
}, normalizedIntervalMs);
|
|
197
194
|
|
|
198
195
|
if (immediate) {
|
|
199
196
|
notify(source.peek(), undefined);
|
|
200
197
|
}
|
|
201
198
|
|
|
202
|
-
const cleanup = watch(
|
|
203
|
-
|
|
204
|
-
|
|
199
|
+
const cleanup = watch(
|
|
200
|
+
source,
|
|
201
|
+
(newValue, oldValue) => {
|
|
202
|
+
notify(newValue, oldValue);
|
|
203
|
+
},
|
|
204
|
+
{ equals }
|
|
205
|
+
);
|
|
205
206
|
|
|
206
207
|
return () => {
|
|
207
208
|
cleanup();
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
import { computed } from './computed';
|
|
9
9
|
import { Signal, signal } from './core';
|
|
10
10
|
|
|
11
|
+
/** @internal */
|
|
12
|
+
type WebSocketSendData = string | Blob | ArrayBufferLike | ArrayBufferView;
|
|
13
|
+
|
|
11
14
|
// ---------------------------------------------------------------------------
|
|
12
15
|
// Types
|
|
13
16
|
// ---------------------------------------------------------------------------
|
|
@@ -40,7 +43,7 @@ export type EventSourceReconnectConfig = Pick<
|
|
|
40
43
|
/** Configuration for keep-alive heartbeats. */
|
|
41
44
|
export interface WebSocketHeartbeatConfig {
|
|
42
45
|
/** Outgoing ping message (default: `'ping'`). */
|
|
43
|
-
message?:
|
|
46
|
+
message?: WebSocketSendData;
|
|
44
47
|
/** Interval in ms between heartbeat pings (default: 30 000). */
|
|
45
48
|
interval?: number;
|
|
46
49
|
/** Time in ms to wait for a pong before assuming the connection is dead (default: 10 000). */
|
|
@@ -52,7 +55,7 @@ export interface WebSocketHeartbeatConfig {
|
|
|
52
55
|
/** Serializer/deserializer for typed messaging. */
|
|
53
56
|
export interface WebSocketSerializer<TSend = unknown, TReceive = unknown> {
|
|
54
57
|
/** Serialize a value before sending over the wire. Default: `JSON.stringify`. */
|
|
55
|
-
serialize?: (data: TSend) =>
|
|
58
|
+
serialize?: (data: TSend) => WebSocketSendData;
|
|
56
59
|
/** Deserialize an incoming message. Default: `JSON.parse`. */
|
|
57
60
|
deserialize?: (event: MessageEvent) => TReceive;
|
|
58
61
|
}
|
|
@@ -115,7 +118,7 @@ export interface UseWebSocketReturn<TSend = unknown, TReceive = unknown> {
|
|
|
115
118
|
* Uses the same queuing behavior as {@link send}: data is queued when the
|
|
116
119
|
* socket is not `OPEN` and flushed once a connection is (re)established.
|
|
117
120
|
*/
|
|
118
|
-
sendRaw: (data:
|
|
121
|
+
sendRaw: (data: WebSocketSendData) => void;
|
|
119
122
|
/** Manually open / reconnect the WebSocket. */
|
|
120
123
|
open: () => void;
|
|
121
124
|
/** Gracefully close the connection. */
|
|
@@ -162,6 +165,26 @@ const computeDelay = (attempt: number, config: WebSocketReconnectConfig): number
|
|
|
162
165
|
return Math.min(base * factor ** attempt, max);
|
|
163
166
|
};
|
|
164
167
|
|
|
168
|
+
/** @internal */
|
|
169
|
+
const sendSocketData = (socket: WebSocket, data: WebSocketSendData): void => {
|
|
170
|
+
if (typeof data === 'string' || data instanceof Blob || data instanceof ArrayBuffer) {
|
|
171
|
+
socket.send(data);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (ArrayBuffer.isView(data)) {
|
|
176
|
+
socket.send(data as BufferSource);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (typeof SharedArrayBuffer !== 'undefined' && data instanceof SharedArrayBuffer) {
|
|
181
|
+
socket.send(data as unknown as BufferSource);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
throw new TypeError('Unsupported WebSocket payload type.');
|
|
186
|
+
};
|
|
187
|
+
|
|
165
188
|
// ---------------------------------------------------------------------------
|
|
166
189
|
// useWebSocket
|
|
167
190
|
// ---------------------------------------------------------------------------
|
|
@@ -249,7 +272,7 @@ export const useWebSocket = <TSend = string, TReceive = string>(
|
|
|
249
272
|
let internalReconnectCount = 0;
|
|
250
273
|
let isAutoReconnecting = false;
|
|
251
274
|
let pingSentAt = 0;
|
|
252
|
-
const sendQueue:
|
|
275
|
+
const sendQueue: WebSocketSendData[] = [];
|
|
253
276
|
|
|
254
277
|
const reconnectConfig = resolveReconnect(options.autoReconnect);
|
|
255
278
|
const heartbeatConfig = resolveHeartbeat(options.heartbeat);
|
|
@@ -265,7 +288,7 @@ export const useWebSocket = <TSend = string, TReceive = string>(
|
|
|
265
288
|
heartbeatTimer = setInterval(() => {
|
|
266
289
|
if (ws?.readyState === WebSocket.OPEN) {
|
|
267
290
|
pingSentAt = Date.now();
|
|
268
|
-
ws
|
|
291
|
+
sendSocketData(ws, pingMsg);
|
|
269
292
|
if (pongTimer !== undefined) {
|
|
270
293
|
clearTimeout(pongTimer);
|
|
271
294
|
}
|
|
@@ -341,7 +364,7 @@ export const useWebSocket = <TSend = string, TReceive = string>(
|
|
|
341
364
|
if (ws.readyState !== WebSocket.OPEN) {
|
|
342
365
|
break;
|
|
343
366
|
}
|
|
344
|
-
ws
|
|
367
|
+
sendSocketData(ws, sendQueue[index]);
|
|
345
368
|
}
|
|
346
369
|
|
|
347
370
|
if (index > 0) {
|
|
@@ -460,10 +483,10 @@ export const useWebSocket = <TSend = string, TReceive = string>(
|
|
|
460
483
|
sendRaw(serialized);
|
|
461
484
|
};
|
|
462
485
|
|
|
463
|
-
const sendRaw = (raw:
|
|
486
|
+
const sendRaw = (raw: WebSocketSendData): void => {
|
|
464
487
|
if (disposed) return;
|
|
465
488
|
if (ws?.readyState === WebSocket.OPEN) {
|
|
466
|
-
ws
|
|
489
|
+
sendSocketData(ws, raw);
|
|
467
490
|
} else {
|
|
468
491
|
sendQueue.push(raw);
|
|
469
492
|
}
|