@qkitt/queue 0.1.0 → 0.1.1

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 CHANGED
@@ -23,7 +23,9 @@ npm install @qkitt/queue
23
23
 
24
24
  **Requirements:** Node.js **18+** (see `engines`). **ESM only** — `"type": "module"`, no CommonJS/`require` build.
25
25
 
26
- Zero runtime dependencies (TypeScript + Vitest + tsup are dev-only). Published entry is compiled ESM + declarations under `dist/` (`import` / `types`). Tree-shaking friendly (`sideEffects: false`).
26
+ Zero runtime dependencies (TypeScript + Vitest + tsup are dev-only). Published entries are compiled ESM + declarations under `dist/` (`import` / `types`). Tree-shaking friendly (`sideEffects: false`).
27
+
28
+ Root import (everything):
27
29
 
28
30
  ```ts
29
31
  import {
@@ -44,6 +46,17 @@ import {
44
46
  } from '@qkitt/queue'
45
47
  ```
46
48
 
49
+ Area subpaths (same symbols as the root barrel for that area):
50
+
51
+ ```ts
52
+ import { buildQueue, withWorker } from '@qkitt/queue/queue'
53
+ import { pipeline, withRetry } from '@qkitt/queue/worker'
54
+ import { buildRouter } from '@qkitt/queue/router'
55
+ import { createMemoryRowStore } from '@qkitt/queue/persist'
56
+ import { defineConfig, buildFromConfig } from '@qkitt/queue/config'
57
+ import { buildEventEmitter } from '@qkitt/queue/events'
58
+ ```
59
+
47
60
  ## Quick start
48
61
 
49
62
  ```ts
@@ -648,24 +661,24 @@ queue.on('worker:idle', () => console.log('inbox empty'))
648
661
  | Events | Typed emitter; listener errors are isolated so pumps keep running |
649
662
  | Routing | MQTT/AMQP-style patterns; unmatched sink does not count as a match |
650
663
  | Config | Named stores + named queues; workers/`impl` are JS-only; JSON is data-only |
651
- | Packaging | Zero runtime deps; ESM-only npm package; `npm run build` emits ESM + `.d.ts` to `dist/` |
664
+ | Packaging | Zero runtime deps; ESM-only; root + area subpaths; `npm run build` emits ESM + `.d.ts` to `dist/` |
652
665
 
653
666
  ## Source layout
654
667
 
655
- Consumers always import `@qkitt/queue` (root only). The tree under `src/` mirrors composition layers:
668
+ Consumers import `@qkitt/queue` (root) or an area subpath (`@qkitt/queue/router`, …). The tree under `src/` mirrors composition layers:
656
669
 
657
- | Folder | Meaning |
658
- | --- | --- |
659
- | `queue/core` | FIFO queue (`buildQueue`) |
660
- | `queue/worker` | Attach a processor (`withWorker`) |
661
- | `queue/persist` | Durable queue decorators + store contracts |
662
- | `persist` | Storage backends (memory, Web Storage) |
663
- | `worker` | Processor helpers (`pipeline`, `withRetry`) — not queue decoration |
664
- | `router` | Topic routing |
665
- | `config` | Declarative system build |
666
- | `events` | Typed emitter |
670
+ | Folder | npm subpath | Meaning |
671
+ | --- | --- | --- |
672
+ | `queue/core` | `@qkitt/queue/queue` | FIFO queue (`buildQueue`) |
673
+ | `queue/worker` | `@qkitt/queue/queue` | Attach a processor (`withWorker`) |
674
+ | `queue/persist` | `@qkitt/queue/queue` | Durable queue decorators + store contracts |
675
+ | `persist` | `@qkitt/queue/persist` | Storage backends (memory, Web Storage) |
676
+ | `worker` | `@qkitt/queue/worker` | Processor helpers (`pipeline`, `withRetry`) — not queue decoration |
677
+ | `router` | `@qkitt/queue/router` | Topic routing |
678
+ | `config` | `@qkitt/queue/config` | Declarative system build |
679
+ | `events` | `@qkitt/queue/events` | Typed emitter |
667
680
 
668
- **Name disambiguation:** `src/worker` = functions that process items; `src/queue/worker` = the decorator that runs them on a queue. `src/persist` = store adapters; `src/queue/persist` = queue decorators that use those stores.
681
+ **Name disambiguation:** `src/worker` / `@qkitt/queue/worker` = functions that process items; `src/queue/worker` / `@qkitt/queue/queue` = the decorator that runs them on a queue. `src/persist` / `@qkitt/queue/persist` = store adapters; `src/queue/persist` lives under `@qkitt/queue/queue`.
669
682
 
670
683
  ## Naming convention
671
684
 
@@ -690,19 +703,18 @@ Rules:
690
703
 
691
704
  ## API map
692
705
 
693
- Public surface (via `@qkitt/queue` / `src/index.ts`):
706
+ Public surface via `@qkitt/queue` (`src/index.ts`) and matching area subpaths:
694
707
 
695
- | Area | Exports |
696
- | --- | --- |
697
- | Queue | `buildQueue`, `QueueFullError`, `Queue`, `QueueEvents`, `BuildQueueOptions` |
698
- | Worker | `withWorker`, `QueueWithWorker`, `WorkerEvents`, `WithWorkerOptions` |
699
- | Snapshot persist | `withSnapshotPersist`, `SnapshotStore`, `SnapshotPersistOptions` |
700
- | Row persist | `withRowPersist`, `RowStore`, `RowRecord`, `createId`, `RowPersistOptions` |
701
- | Worker helpers | `pipeline`, `withRetry`, `RetryExhaustedError`, `WorkerFn`, `StepFn` |
702
- | Router | `buildRouter`, `RouteMessage`, `matchTopic`, `isValidTopic`, `isValidPattern`, |
703
- | Persist stores | memory + Web Storage factories, `StorageCodecError`, `WebStorageLike` |
704
- | Config | `defineConfig`, `buildFromConfig`, `buildFromJson`, `parseSystemConfig`, `validate*`, `SystemConfig`, … |
705
- | Events | `buildEventEmitter`, `createTypedEmit`, `EventEmitter`, `MergeEventMaps` |
708
+ | Area | Subpath | Exports |
709
+ | --- | --- | --- |
710
+ | Queue + queue worker + queue persist | `@qkitt/queue/queue` | `buildQueue`, `QueueFullError`, `withWorker`, `withRowPersist`, `withSnapshotPersist`, `createId`, types… |
711
+ | Worker helpers | `@qkitt/queue/worker` | `pipeline`, `withRetry`, `RetryExhaustedError`, `WorkerFn`, `StepFn` |
712
+ | Router | `@qkitt/queue/router` | `buildRouter`, `RouteMessage`, `matchTopic`, `isValidTopic`, `isValidPattern`, … |
713
+ | Persist stores | `@qkitt/queue/persist` | memory + Web Storage factories, `StorageCodecError`, `WebStorageLike` |
714
+ | Config | `@qkitt/queue/config` | `defineConfig`, `buildFromConfig`, `buildFromJson`, `parseSystemConfig`, `validate*`, `SystemConfig`, |
715
+ | Events | `@qkitt/queue/events` | `buildEventEmitter`, `createTypedEmit`, `EventEmitter`, `MergeEventMaps` |
716
+
717
+ Root `@qkitt/queue` re-exports all of the above.
706
718
 
707
719
  Internals (`forward.util`, `hydrate-gate.util`, `write-chain.util`, `row-ids.util`, codecs) are not part of the stable public contract.
708
720
 
@@ -0,0 +1,3 @@
1
+
2
+ //# sourceMappingURL=chunk-4BUYKZS2.js.map
3
+ //# sourceMappingURL=chunk-4BUYKZS2.js.map
@@ -0,0 +1,525 @@
1
+ import { buildEventEmitter, createTypedEmit } from './chunk-TX6HHN5M.js';
2
+
3
+ // src/queue/core/queue.ts
4
+ var QueueFullError = class extends Error {
5
+ name = "QueueFullError";
6
+ maxSize;
7
+ constructor(maxSize) {
8
+ super(`Queue is full (maxSize=${maxSize})`);
9
+ this.maxSize = maxSize;
10
+ }
11
+ };
12
+ var COMPACT_HEAD_THRESHOLD = 64;
13
+ var buildQueue = (options = {}) => {
14
+ const maxSize = options.maxSize;
15
+ if (maxSize !== void 0 && (!Number.isFinite(maxSize) || maxSize < 1)) {
16
+ throw new Error("maxSize must be a finite number >= 1");
17
+ }
18
+ const items = [];
19
+ let head = 0;
20
+ const emitter = buildEventEmitter();
21
+ const liveSize = () => items.length - head;
22
+ const compactIfNeeded = () => {
23
+ if (head === 0) return;
24
+ if (head < COMPACT_HEAD_THRESHOLD && head * 2 < items.length) return;
25
+ items.splice(0, head);
26
+ head = 0;
27
+ };
28
+ const assertCapacity = (nextSize) => {
29
+ if (maxSize !== void 0 && nextSize > maxSize) {
30
+ throw new QueueFullError(maxSize);
31
+ }
32
+ };
33
+ const enqueue = (item) => {
34
+ assertCapacity(liveSize() + 1);
35
+ items.push(item);
36
+ emitter.emit("queue:enqueued", { item, size: liveSize() });
37
+ };
38
+ const dequeue = () => {
39
+ if (head >= items.length) return void 0;
40
+ const item = items[head];
41
+ head += 1;
42
+ compactIfNeeded();
43
+ const size2 = liveSize();
44
+ emitter.emit("queue:dequeued", { item, size: size2 });
45
+ if (size2 === 0) {
46
+ emitter.emit("queue:emptied", void 0);
47
+ }
48
+ return item;
49
+ };
50
+ const peek = () => {
51
+ if (head >= items.length) return void 0;
52
+ return items[head];
53
+ };
54
+ const size = () => liveSize();
55
+ const isEmpty = () => head >= items.length;
56
+ const clear = () => {
57
+ const removed = liveSize();
58
+ if (removed === 0) return;
59
+ items.length = 0;
60
+ head = 0;
61
+ emitter.emit("queue:cleared", { removed });
62
+ };
63
+ const replaceAll = (next) => {
64
+ assertCapacity(next.length);
65
+ items.length = 0;
66
+ head = 0;
67
+ for (const item of next) {
68
+ items.push(item);
69
+ }
70
+ };
71
+ const toArray = () => items.slice(head);
72
+ const api = {
73
+ enqueue,
74
+ dequeue,
75
+ peek,
76
+ size,
77
+ isEmpty,
78
+ clear,
79
+ replaceAll,
80
+ toArray,
81
+ on: emitter.on,
82
+ once: emitter.once,
83
+ off: emitter.off,
84
+ emit: emitter.emit,
85
+ expand: () => api
86
+ };
87
+ return api;
88
+ };
89
+
90
+ // src/queue/persist/create-id.util.ts
91
+ var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
92
+ var DEFAULT_SIZE = 21;
93
+ var fillRandom = (bytes) => {
94
+ const cryptoObj = globalThis.crypto;
95
+ if (typeof cryptoObj?.getRandomValues === "function") {
96
+ cryptoObj.getRandomValues(bytes);
97
+ return;
98
+ }
99
+ for (let i = 0; i < bytes.length; i += 1) {
100
+ bytes[i] = Math.floor(Math.random() * 256);
101
+ }
102
+ };
103
+ var createId = (size = DEFAULT_SIZE) => {
104
+ if (!Number.isInteger(size) || size <= 0) {
105
+ throw new RangeError(`createId size must be a positive integer, got ${size}`);
106
+ }
107
+ const bytes = new Uint8Array(size);
108
+ fillRandom(bytes);
109
+ let id = "";
110
+ for (let i = 0; i < size; i += 1) {
111
+ id += ALPHABET[bytes[i] & 63];
112
+ }
113
+ return id;
114
+ };
115
+
116
+ // src/queue/core/layers.util.ts
117
+ var WORKER_LAYER = /* @__PURE__ */ Symbol.for("qkitt:worker-layer");
118
+ var PERSIST_LAYER = /* @__PURE__ */ Symbol.for("qkitt:persist-layer");
119
+ var markQueueLayer = (queue, layer) => {
120
+ if (hasQueueLayer(queue, layer)) return queue;
121
+ Object.defineProperty(queue, layer, {
122
+ value: true,
123
+ enumerable: false,
124
+ configurable: false,
125
+ writable: false
126
+ });
127
+ return queue;
128
+ };
129
+ var hasQueueLayer = (queue, layer) => queue[layer] === true;
130
+ var copyQueueLayers = (from, to) => {
131
+ if (hasQueueLayer(from, WORKER_LAYER)) {
132
+ markQueueLayer(to, WORKER_LAYER);
133
+ }
134
+ if (hasQueueLayer(from, PERSIST_LAYER)) {
135
+ markQueueLayer(to, PERSIST_LAYER);
136
+ }
137
+ return to;
138
+ };
139
+
140
+ // src/queue/core/forward.util.ts
141
+ var forwardQueue = (queue, extra) => {
142
+ const next = {
143
+ ...queue,
144
+ ...extra
145
+ };
146
+ return copyQueueLayers(queue, next);
147
+ };
148
+
149
+ // src/queue/persist/hydrate-gate.util.ts
150
+ var createHydrateGate = () => {
151
+ let suppressing = false;
152
+ return {
153
+ isSuppressing: () => suppressing,
154
+ run: async (fn) => {
155
+ suppressing = true;
156
+ try {
157
+ return await fn();
158
+ } finally {
159
+ suppressing = false;
160
+ }
161
+ }
162
+ };
163
+ };
164
+ var assertNotHydrating = (gate) => {
165
+ if (gate.isSuppressing()) {
166
+ throw new Error(
167
+ "Cannot mutate queue while hydrate() is in progress; await hydrate() first"
168
+ );
169
+ }
170
+ };
171
+
172
+ // src/queue/persist/persist.support.ts
173
+ var assertBareQueueForPersist = (queue, wrapperName) => {
174
+ if (hasQueueLayer(queue, WORKER_LAYER)) {
175
+ throw new Error(
176
+ `${wrapperName} must wrap the bare queue before withWorker: withWorker(${wrapperName}(queue, store), worker)`
177
+ );
178
+ }
179
+ if (hasQueueLayer(queue, PERSIST_LAYER)) {
180
+ throw new Error(
181
+ `${wrapperName} cannot wrap an already-persisted queue; use a single persist layer on the bare queue`
182
+ );
183
+ }
184
+ };
185
+ var notifyQueueRestored = (queue) => {
186
+ const size = queue.size();
187
+ if (size === 0) return;
188
+ const item = queue.peek();
189
+ if (item === void 0) return;
190
+ queue.emit("queue:enqueued", { item, size });
191
+ };
192
+
193
+ // src/queue/persist/row-ids.util.ts
194
+ var COMPACT_HEAD_THRESHOLD2 = 64;
195
+ var createRowIdList = () => {
196
+ const ids = [];
197
+ let idHead = 0;
198
+ const compactIfNeeded = () => {
199
+ if (idHead === 0) return;
200
+ if (idHead < COMPACT_HEAD_THRESHOLD2 && idHead * 2 < ids.length) return;
201
+ ids.splice(0, idHead);
202
+ idHead = 0;
203
+ };
204
+ return {
205
+ push: (id) => {
206
+ ids.push(id);
207
+ },
208
+ shift: () => {
209
+ if (idHead >= ids.length) return void 0;
210
+ const id = ids[idHead];
211
+ idHead += 1;
212
+ compactIfNeeded();
213
+ return id;
214
+ },
215
+ reset: (next) => {
216
+ ids.length = 0;
217
+ idHead = 0;
218
+ for (const id of next) {
219
+ ids.push(id);
220
+ }
221
+ },
222
+ live: () => ids.slice(idHead),
223
+ liveCount: () => ids.length - idHead
224
+ };
225
+ };
226
+
227
+ // src/queue/persist/write-chain.util.ts
228
+ var createWriteChain = () => {
229
+ let chain = Promise.resolve();
230
+ const push = (op) => {
231
+ const run = chain.then(op, op);
232
+ chain = run.then(
233
+ () => void 0,
234
+ () => void 0
235
+ );
236
+ return run;
237
+ };
238
+ const flush = () => chain;
239
+ return { push, flush };
240
+ };
241
+
242
+ // src/queue/persist/with-row-persist.ts
243
+ var withRowPersist = (queue, store, options = {}) => {
244
+ assertBareQueueForPersist(queue, "withRowPersist");
245
+ const nextId = options.createId ?? createId;
246
+ const inner = queue.expand();
247
+ const emitPersist = createTypedEmit(
248
+ inner.emit
249
+ );
250
+ const gate = createHydrateGate();
251
+ const writes = createWriteChain();
252
+ const rowIdsList = createRowIdList();
253
+ let localSuppress = false;
254
+ const isSuppressing = () => gate.isSuppressing() || localSuppress;
255
+ const trackError = (operation, error, id) => {
256
+ emitPersist("persist:error", { operation, error, id });
257
+ };
258
+ const rollbackLocalById = (id) => {
259
+ const liveIds = rowIdsList.live();
260
+ const liveIndex = liveIds.indexOf(id);
261
+ if (liveIndex < 0) return;
262
+ const remainingItems = inner.toArray();
263
+ remainingItems.splice(liveIndex, 1);
264
+ liveIds.splice(liveIndex, 1);
265
+ localSuppress = true;
266
+ try {
267
+ rowIdsList.reset(liveIds);
268
+ inner.replaceAll(remainingItems);
269
+ } finally {
270
+ localSuppress = false;
271
+ }
272
+ };
273
+ const scheduleStore = (op) => {
274
+ if (isSuppressing()) return;
275
+ void writes.push(op).catch(() => {
276
+ });
277
+ };
278
+ const enqueue = (item) => {
279
+ assertNotHydrating(gate);
280
+ const id = nextId();
281
+ rowIdsList.push(id);
282
+ if (!isSuppressing()) {
283
+ scheduleStore(async () => {
284
+ try {
285
+ await store.insert({ id, item });
286
+ emitPersist("persist:inserted", { id, item });
287
+ } catch (error) {
288
+ rollbackLocalById(id);
289
+ trackError("insert", error, id);
290
+ }
291
+ });
292
+ }
293
+ inner.enqueue(item);
294
+ };
295
+ const dequeue = () => {
296
+ assertNotHydrating(gate);
297
+ const item = inner.dequeue();
298
+ if (item === void 0) return void 0;
299
+ const id = rowIdsList.shift();
300
+ if (id === void 0) return item;
301
+ if (isSuppressing()) return item;
302
+ scheduleStore(async () => {
303
+ try {
304
+ await store.remove(id);
305
+ emitPersist("persist:removed", { id, item });
306
+ } catch (error) {
307
+ trackError("remove", error, id);
308
+ }
309
+ });
310
+ return item;
311
+ };
312
+ const clear = () => {
313
+ assertNotHydrating(gate);
314
+ const removed = rowIdsList.liveCount();
315
+ if (removed === 0 && inner.isEmpty()) return;
316
+ rowIdsList.reset([]);
317
+ inner.clear();
318
+ if (isSuppressing()) return;
319
+ scheduleStore(async () => {
320
+ try {
321
+ await store.clear();
322
+ emitPersist("persist:cleared", { removed });
323
+ } catch (error) {
324
+ trackError("clear", error);
325
+ }
326
+ });
327
+ };
328
+ const replaceAll = (_items) => {
329
+ throw new Error(
330
+ "replaceAll is not supported on row-persisted queues; use hydrate() to restore from the store, or enqueue/dequeue/clear"
331
+ );
332
+ };
333
+ const hydrate = async () => {
334
+ await gate.run(async () => {
335
+ try {
336
+ await writes.flush();
337
+ const rows = await store.loadAll();
338
+ rowIdsList.reset(rows.map((row) => row.id));
339
+ inner.replaceAll(rows.map((row) => row.item));
340
+ emitPersist("persist:loaded", { size: inner.size() });
341
+ } catch (error) {
342
+ trackError("load", error);
343
+ throw error;
344
+ }
345
+ });
346
+ notifyQueueRestored({
347
+ size: inner.size,
348
+ peek: inner.peek,
349
+ emit: inner.emit
350
+ });
351
+ };
352
+ const api = markQueueLayer(
353
+ forwardQueue(inner, {
354
+ enqueue,
355
+ dequeue,
356
+ clear,
357
+ replaceAll,
358
+ expand: () => api,
359
+ hydrate,
360
+ rowIds: () => rowIdsList.live(),
361
+ flush: writes.flush
362
+ }),
363
+ PERSIST_LAYER
364
+ );
365
+ return api;
366
+ };
367
+
368
+ // src/queue/persist/with-snapshot-persist.ts
369
+ var withSnapshotPersist = (queue, store, options = {}) => {
370
+ assertBareQueueForPersist(queue, "withSnapshotPersist");
371
+ const autoSave = options.autoSave ?? true;
372
+ const inner = queue.expand();
373
+ const emitPersist = createTypedEmit(
374
+ inner.emit
375
+ );
376
+ const gate = createHydrateGate();
377
+ const writes = createWriteChain();
378
+ const persist = () => writes.push(async () => {
379
+ try {
380
+ const items = inner.toArray();
381
+ await store.save(items);
382
+ emitPersist("persist:saved", { size: items.length });
383
+ } catch (error) {
384
+ emitPersist("persist:error", { operation: "save", error });
385
+ throw error;
386
+ }
387
+ });
388
+ const scheduleSave = () => {
389
+ if (gate.isSuppressing() || !autoSave) return;
390
+ void persist().catch(() => {
391
+ });
392
+ };
393
+ const enqueue = (item) => {
394
+ assertNotHydrating(gate);
395
+ inner.enqueue(item);
396
+ scheduleSave();
397
+ };
398
+ const dequeue = () => {
399
+ assertNotHydrating(gate);
400
+ const item = inner.dequeue();
401
+ if (item !== void 0) {
402
+ scheduleSave();
403
+ }
404
+ return item;
405
+ };
406
+ const clear = () => {
407
+ assertNotHydrating(gate);
408
+ if (inner.isEmpty()) return;
409
+ inner.clear();
410
+ scheduleSave();
411
+ };
412
+ const replaceAll = (items) => {
413
+ assertNotHydrating(gate);
414
+ inner.replaceAll(items);
415
+ scheduleSave();
416
+ };
417
+ const hydrate = async () => {
418
+ await gate.run(async () => {
419
+ try {
420
+ await writes.flush();
421
+ const items = await store.load();
422
+ inner.replaceAll(items);
423
+ emitPersist("persist:loaded", { size: inner.size() });
424
+ } catch (error) {
425
+ emitPersist("persist:error", { operation: "load", error });
426
+ throw error;
427
+ }
428
+ });
429
+ notifyQueueRestored({
430
+ size: inner.size,
431
+ peek: inner.peek,
432
+ emit: inner.emit
433
+ });
434
+ };
435
+ const api = markQueueLayer(
436
+ forwardQueue(inner, {
437
+ enqueue,
438
+ dequeue,
439
+ clear,
440
+ replaceAll,
441
+ expand: () => api,
442
+ hydrate,
443
+ persist,
444
+ flush: writes.flush
445
+ }),
446
+ PERSIST_LAYER
447
+ );
448
+ return api;
449
+ };
450
+
451
+ // src/queue/worker/with-worker.ts
452
+ var resolveConcurrency = (value) => {
453
+ const concurrency = value ?? 1;
454
+ if (!Number.isFinite(concurrency) || concurrency < 1) {
455
+ throw new Error("concurrency must be a finite number >= 1");
456
+ }
457
+ return Math.floor(concurrency);
458
+ };
459
+ var withWorker = (queue, worker, options = {}) => {
460
+ const concurrency = resolveConcurrency(options.concurrency);
461
+ const autoStart = options.autoStart ?? true;
462
+ const inner = queue.expand();
463
+ const emitWorker = createTypedEmit(
464
+ inner.emit
465
+ );
466
+ const onQueue = inner.on;
467
+ let running = false;
468
+ let active = 0;
469
+ const processItem = async (item) => {
470
+ emitWorker("worker:started", { item });
471
+ try {
472
+ const result = await worker(item);
473
+ emitWorker("worker:completed", { item, result });
474
+ } catch (error) {
475
+ emitWorker("worker:failed", { item, error });
476
+ } finally {
477
+ active -= 1;
478
+ if (active === 0 && inner.isEmpty()) {
479
+ emitWorker("worker:idle", void 0);
480
+ }
481
+ pump();
482
+ }
483
+ };
484
+ const pump = () => {
485
+ try {
486
+ while (running && active < concurrency) {
487
+ const item = inner.dequeue();
488
+ if (item === void 0) break;
489
+ active += 1;
490
+ void processItem(item);
491
+ }
492
+ } catch {
493
+ }
494
+ };
495
+ const start = () => {
496
+ if (running) return;
497
+ running = true;
498
+ pump();
499
+ };
500
+ const stop = () => {
501
+ running = false;
502
+ };
503
+ onQueue("queue:enqueued", () => {
504
+ pump();
505
+ });
506
+ if (autoStart) {
507
+ start();
508
+ }
509
+ const api = markQueueLayer(
510
+ forwardQueue(inner, {
511
+ expand: () => api,
512
+ start,
513
+ stop,
514
+ isRunning: () => running,
515
+ isProcessing: () => active > 0,
516
+ activeCount: () => active
517
+ }),
518
+ WORKER_LAYER
519
+ );
520
+ return api;
521
+ };
522
+
523
+ export { QueueFullError, buildQueue, createId, withRowPersist, withSnapshotPersist, withWorker };
524
+ //# sourceMappingURL=chunk-653YYS22.js.map
525
+ //# sourceMappingURL=chunk-653YYS22.js.map