@mainframework/api-request-worker 1.0.3 → 1.0.4
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 +114 -50
- package/dist/shared/output/react.d.ts +3 -3
- package/dist/shared/output/react.js +132 -67
- package/dist/shared/output/react.js.map +1 -1
- package/dist/shared/output/vanilla.d.ts +1 -1
- package/dist/shared/output/vanilla.js +1 -1
- package/dist/shared/output/vanilla.js.map +1 -1
- package/dist/{types-LYmxol0c.d.ts → types-C6nnvGO7.d.ts} +23 -49
- package/dist/workers/api/api.worker.js +202 -64
- package/dist/workers/api/api.worker.js.map +1 -1
- package/package.json +12 -9
package/README.md
CHANGED
|
@@ -23,13 +23,15 @@ The library is **framework- and library-agnostic**: you use the worker via the s
|
|
|
23
23
|
|
|
24
24
|
## Response Types and Download Behavior
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
`responseType` controls in-flight deduplication and streaming behavior. For non-stream requests, **response parsing follows the server's `Content-Type` header**, not `responseType` — a GET without `responseType: "binary"` can still return an `ArrayBuffer` when the server sends a binary content type.
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
| `responseType` | Effect |
|
|
29
|
+
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
30
|
+
| omitted / `"json"` (default) | In-flight dedupe enabled (keyed by `cacheName`). Full response buffered and sent in one `type: "result"` message. |
|
|
31
|
+
| `"binary"` | Skips in-flight dedupe (always fetches fresh). Response still parsed by `Content-Type`; binary bodies arrive as `ArrayBuffer` with `meta`. |
|
|
32
|
+
| `"stream"` | Enables incremental delivery (`start` → `chunk` → ... → `end`), Range-based retries, and hook `streamChunks`. |
|
|
29
33
|
|
|
30
|
-
- **`responseType: "
|
|
31
|
-
|
|
32
|
-
- **`responseType: "stream"`**: Responses are streamed incrementally to the client. The worker sends chunks as they arrive (`start` → `chunk` → `chunk` → ... → `end`), enabling playback of audio/video streams to begin before the full file downloads. The React hook returns `streamChunks` (batches of `ArrayBuffer[]`) as they arrive and a final `Blob` in `data` when complete. Throttling (default: every 5 chunks or 50ms) minimizes re-renders. For vanilla JavaScript, you handle stream events manually for maximum control.
|
|
34
|
+
- **`responseType: "stream"`**: The worker sends chunks as they arrive, enabling audio/video playback before the full file downloads. The React hook exposes the latest flushed batch in `streamChunks` (`ArrayBuffer[]`) and a final `Blob` in `data` when complete. Throttling (default: every 5 chunks, configurable via `streamChunkBatchSize`) minimizes re-renders. For vanilla JavaScript, handle `type: "stream"` messages manually.
|
|
33
35
|
|
|
34
36
|
Binary and stream responses are not stored in the worker cache; only json/text responses are cached.
|
|
35
37
|
|
|
@@ -101,10 +103,10 @@ worker.postMessage({
|
|
|
101
103
|
|
|
102
104
|
Use only these import paths. Do not import the worker script directly.
|
|
103
105
|
|
|
104
|
-
| Use case | Import from | What you get
|
|
105
|
-
| ----------- | ----------------------------------------- |
|
|
106
|
-
| **Vanilla** | `@mainframework/api-request-worker` | `createApiWorker`, `RequestConfig`, `DataRequest`, `BinaryResponseMeta`, `WorkerMessagePayload`, and other protocol types |
|
|
107
|
-
| **React** | `@mainframework/api-request-worker/react` | `useApiWorker`, `RequestConfig`,
|
|
106
|
+
| Use case | Import from | What you get |
|
|
107
|
+
| ----------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
108
|
+
| **Vanilla** | `@mainframework/api-request-worker` | `createApiWorker`, `RequestConfig`, `DataRequest`, `BinaryResponseMeta`, `WorkerMessagePayload`, `WorkerErrorCode`, `WorkerResponseType`, and other protocol types |
|
|
109
|
+
| **React** | `@mainframework/api-request-worker/react` | `useApiWorker`, `RequestConfig`, `UseApiWorkerConfig`, `UseApiWorkerReturn` |
|
|
108
110
|
|
|
109
111
|
The worker is not a public entry. Obtain it only by calling `createApiWorker()` from the main package (or use the React hook, which uses `createApiWorker` internally).
|
|
110
112
|
|
|
@@ -119,6 +121,7 @@ The worker is not a public entry. Obtain it only by calling `createApiWorker()`
|
|
|
119
121
|
- **Next.js**: Use **client-only** code paths.
|
|
120
122
|
- Add `"use client";` at the top of any file that imports `@mainframework/api-request-worker/react`.
|
|
121
123
|
- Do not call `createApiWorker()` during SSR.
|
|
124
|
+
- `useApiWorker` returns `null` when `window` is undefined — guard before destructuring in SSR or shared modules.
|
|
122
125
|
|
|
123
126
|
---
|
|
124
127
|
|
|
@@ -160,21 +163,49 @@ Send a single object: `{ dataRequest: { ... } }`.
|
|
|
160
163
|
|
|
161
164
|
**Incoming messages (worker → main thread):**
|
|
162
165
|
|
|
163
|
-
Every message includes
|
|
166
|
+
Every message includes:
|
|
167
|
+
|
|
168
|
+
- **`type`**: `"result"` | `"delete"` | `"stream"` — disambiguates delete acknowledgements from real payloads and stream events.
|
|
169
|
+
- **`requestId`**: Echoes the originating request when present; omitted for cache-only `get` / `delete` without a client `requestId`.
|
|
170
|
+
- **`error`**: `{ message: string; code?: WorkerErrorCode }` — always present.
|
|
171
|
+
|
|
172
|
+
- **Success**: `type: "result"`, `data` contains the response body, `error.message` is `""` (empty string).
|
|
173
|
+
- **Failure**: `type: "result"`, `data` is `null`, `error.message` contains the error description, optional `error.code` classifies the failure.
|
|
174
|
+
- **Delete ack**: `type: "delete"`, `data: null`, `error: { message: "" }` — the `type` field is the signal; there is no `{ deleted: true }` payload.
|
|
175
|
+
|
|
176
|
+
**Error codes (`error.code`):**
|
|
164
177
|
|
|
165
|
-
|
|
166
|
-
|
|
178
|
+
| Code | When |
|
|
179
|
+
| -------------- | ----------------------------------------------- |
|
|
180
|
+
| `"aborted"` | Manual `cancel` or `AbortError` without timeout |
|
|
181
|
+
| `"timeout"` | `timeoutMs` fired |
|
|
182
|
+
| `"http"` | HTTP status ≥ 400 |
|
|
183
|
+
| `"network"` | Fetch, parse, or other runtime failure |
|
|
184
|
+
| `"validation"` | Cache miss, invalid request, etc. |
|
|
167
185
|
|
|
168
186
|
**Message formats:**
|
|
169
187
|
|
|
170
|
-
- **Success (JSON/text):** `{ cacheName, data, error: { message: "" }, hookId?, httpStatus? }`
|
|
171
|
-
- **Success (binary):** `{ cacheName, data: ArrayBuffer, meta: { contentType?, contentDisposition }, error: { message: "" }, hookId?, httpStatus? }`
|
|
188
|
+
- **Success (JSON/text):** `{ type: "result", cacheName, data, error: { message: "" }, requestId?, hookId?, httpStatus? }`
|
|
189
|
+
- **Success (binary):** `{ type: "result", cacheName, data: ArrayBuffer, meta: { contentType?, contentDisposition }, error: { message: "" }, requestId?, hookId?, httpStatus? }`
|
|
190
|
+
- **Delete ack:** `{ type: "delete", cacheName, data: null, error: { message: "" }, requestId?, hookId? }`
|
|
172
191
|
- **Success (stream):** Multiple messages in sequence:
|
|
173
|
-
- `{ cacheName, stream: "start", meta: { contentType?, contentDisposition }, hookId?, httpStatus?, error: { message: "" } }`
|
|
174
|
-
- `{ cacheName, stream: "chunk", data: ArrayBuffer, hookId?, error: { message: "" } }` (one or more)
|
|
175
|
-
- `{ cacheName, stream: "resume", meta: { contentType?, contentDisposition }, hookId?, httpStatus?, error: { message: "" } }` (after retry)
|
|
176
|
-
- `{ cacheName, stream: "end", hookId?, error: { message: "" } }` (final message)
|
|
177
|
-
- **Error:** `{ cacheName?, data: null, error: { message: "..." }, hookId? }`. If the request had no `cacheName`, match by `hookId` instead.
|
|
192
|
+
- `{ type: "stream", cacheName, stream: "start", meta: { contentType?, contentDisposition }, requestId?, hookId?, httpStatus?, error: { message: "" } }`
|
|
193
|
+
- `{ type: "stream", cacheName, stream: "chunk", data: ArrayBuffer, requestId?, hookId?, error: { message: "" } }` (one or more)
|
|
194
|
+
- `{ type: "stream", cacheName, stream: "resume", meta: { contentType?, contentDisposition }, requestId?, hookId?, httpStatus?, error: { message: "" } }` (after retry)
|
|
195
|
+
- `{ type: "stream", cacheName, stream: "end", requestId?, hookId?, error: { message: "" } }` (final message)
|
|
196
|
+
- **Error:** `{ type: "result", cacheName?, data: null, error: { message: "...", code?: "..." }, requestId?, hookId? }`. If the request had no `cacheName`, match by `hookId` instead.
|
|
197
|
+
|
|
198
|
+
**Design notes:**
|
|
199
|
+
|
|
200
|
+
| # | Note |
|
|
201
|
+
| --- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
202
|
+
| 7 | In-flight dedupe for json/text is keyed by `cacheName` only (not HTTP method). Two concurrent mutations on the same key coalesce — intentional for read caching; use distinct `cacheName` values for independent writes. |
|
|
203
|
+
| 8 | `retries` applies only when `responseType: "stream"`. |
|
|
204
|
+
| 9 | Auto-run refires when `data` / `request` object identity changes — callers must memoize inline literals. |
|
|
205
|
+
| 10 | `streamChunks` exposes the latest flushed batch (`ArrayBuffer[]`), not the cumulative stream — accumulate in consumer if needed. |
|
|
206
|
+
| 11 | Joiners on a deduped json/text fetch may receive **two** `type: "result"` messages: cached value immediately, then fresh value after the shared fetch completes. Vanilla consumers should handle or ignore the first message. |
|
|
207
|
+
|
|
208
|
+
**Joiner cancel:** Multiple subscribers sharing a `cacheName` coalesce into one in-flight fetch (json/text). Each caller registers its own `requestId`. Cancel removes only that `requestId`; the shared fetch is aborted only when the last registered `requestId` is cancelled. For `responseType: "binary"` or `"stream"`, in-flight tracking is keyed by `requestId` (not `cacheName`), so those requests do not dedupe across callers.
|
|
178
209
|
|
|
179
210
|
**Common error messages:**
|
|
180
211
|
|
|
@@ -203,9 +234,15 @@ interface RequestConfig {
|
|
|
203
234
|
}
|
|
204
235
|
```
|
|
205
236
|
|
|
206
|
-
- **`responseType: "binary"`**:
|
|
237
|
+
- **`responseType: "binary"`**: Skips in-flight dedupe so each request fetches fresh data. Response parsing still follows `Content-Type`; when the server returns binary content, the worker sends an `ArrayBuffer` with `meta.contentType` and `meta.contentDisposition` so you can construct a `Blob`: `new Blob([data], { type: meta?.contentType })`.
|
|
207
238
|
|
|
208
|
-
- **`responseType: "stream"`**:
|
|
239
|
+
- **`responseType: "stream"`**: Enables incremental chunk delivery. The hook exposes the latest flushed batch in `streamChunks` (`ArrayBuffer[]`) and a final `Blob` in `data` when complete. Batching via `streamChunkBatchSize` (default 5) controls how many chunks are delivered per update. Supports automatic reconnection with configurable retries (default 3, max 5).
|
|
240
|
+
|
|
241
|
+
- **`formDataFileFieldName`** (default `"Files"`): FormData field name for all `File`/`Blob` parts when the worker auto-builds multipart form data.
|
|
242
|
+
|
|
243
|
+
- **`formDataKey`** (default `"Files"`): FormData key for the root payload object when building multipart form data.
|
|
244
|
+
|
|
245
|
+
**File upload:** When a `set` payload contains `File` or `Blob` values (including nested in objects or arrays), the worker automatically sends the request as `multipart/form-data` and omits any caller `Content-Type` header so the browser sets the boundary. No manual `Content-Type: multipart/form-data` header is required.
|
|
209
246
|
|
|
210
247
|
### Vanilla JavaScript Examples
|
|
211
248
|
|
|
@@ -252,6 +289,24 @@ worker.postMessage({
|
|
|
252
289
|
});
|
|
253
290
|
```
|
|
254
291
|
|
|
292
|
+
**POST request with file upload (auto multipart):**
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
worker.postMessage({
|
|
296
|
+
dataRequest: {
|
|
297
|
+
type: "set",
|
|
298
|
+
cacheName: "upload-" + Date.now(),
|
|
299
|
+
payload: { title: "My Photo", photos: [fileInput.files[0]] },
|
|
300
|
+
request: {
|
|
301
|
+
url: "https://api.example.com/upload",
|
|
302
|
+
method: "POST",
|
|
303
|
+
// No Content-Type header needed — worker detects File/Blob and sends multipart/form-data
|
|
304
|
+
},
|
|
305
|
+
hookId: "vanilla-upload",
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
```
|
|
309
|
+
|
|
255
310
|
**PATCH request:**
|
|
256
311
|
|
|
257
312
|
```ts
|
|
@@ -300,7 +355,7 @@ setTimeout(() => {
|
|
|
300
355
|
worker.postMessage({
|
|
301
356
|
dataRequest: { type: "get", cacheName: "nonexistent-key", hookId: "cache-miss" },
|
|
302
357
|
});
|
|
303
|
-
// onmessage receives: { cacheName: "nonexistent-key", data: null, error: { message: "Cache miss" }, hookId: "cache-miss" }
|
|
358
|
+
// onmessage receives: { type: "result", cacheName: "nonexistent-key", data: null, error: { message: "Cache miss", code: "validation" }, hookId: "cache-miss" }
|
|
304
359
|
```
|
|
305
360
|
|
|
306
361
|
**Delete cached data:**
|
|
@@ -315,7 +370,7 @@ worker.postMessage({
|
|
|
315
370
|
worker.postMessage({
|
|
316
371
|
dataRequest: { type: "delete", cacheName: "temp-data", hookId: "delete-op" },
|
|
317
372
|
});
|
|
318
|
-
// Response: { cacheName: "temp-data", data:
|
|
373
|
+
// Response: { type: "delete", cacheName: "temp-data", data: null, error: { message: "" }, hookId: "delete-op" }
|
|
319
374
|
|
|
320
375
|
// Subsequent get for the same cacheName returns: { error: { message: "Cache miss" } }
|
|
321
376
|
```
|
|
@@ -360,7 +415,7 @@ let meta: { contentType?: string; contentDisposition: string | null } | null = n
|
|
|
360
415
|
|
|
361
416
|
worker.onmessage = (event) => {
|
|
362
417
|
const msg = event.data;
|
|
363
|
-
if (msg.cacheName !== cacheName) return;
|
|
418
|
+
if (msg.cacheName !== cacheName || msg.type !== "stream") return;
|
|
364
419
|
|
|
365
420
|
if (msg.stream === "start") {
|
|
366
421
|
// Stream started
|
|
@@ -477,7 +532,8 @@ const result = useApiWorker({
|
|
|
477
532
|
enabled: true, // optional: if false, no request is sent (default true)
|
|
478
533
|
});
|
|
479
534
|
|
|
480
|
-
// result:
|
|
535
|
+
// result: UseApiWorkerReturn<T> | null — null when window is undefined (SSR)
|
|
536
|
+
// { data, meta, loading, error, errorCode, refetch, deleteCache, streamChunks? }
|
|
481
537
|
```
|
|
482
538
|
|
|
483
539
|
**Parameters:**
|
|
@@ -493,15 +549,16 @@ const result = useApiWorker({
|
|
|
493
549
|
|
|
494
550
|
**Return value:**
|
|
495
551
|
|
|
496
|
-
| Property | Type | Description
|
|
497
|
-
| -------------- | ---------------------------- |
|
|
498
|
-
| `data` | `T \| null` | Response body: JSON/text
|
|
499
|
-
| `meta` | `BinaryResponseMeta \| null` | For binary and stream responses: `contentType`, `contentDisposition`.
|
|
500
|
-
| `loading` | `boolean` | `true` while a request is in flight.
|
|
501
|
-
| `error` | `string \| null` | Error message when the request failed; `null` when there is no error. See [Errors](#errors).
|
|
502
|
-
| `
|
|
503
|
-
| `
|
|
504
|
-
| `
|
|
552
|
+
| Property | Type | Description |
|
|
553
|
+
| -------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
554
|
+
| `data` | `T \| null` | Response body: JSON/text or `ArrayBuffer` per server `Content-Type`; `Blob` when `responseType: "stream"` completes. |
|
|
555
|
+
| `meta` | `BinaryResponseMeta \| null` | For binary and stream responses: `contentType`, `contentDisposition`. |
|
|
556
|
+
| `loading` | `boolean` | `true` while a request is in flight. |
|
|
557
|
+
| `error` | `string \| null` | Error message when the request failed; `null` when there is no error. See [Errors](#errors). |
|
|
558
|
+
| `errorCode` | `WorkerErrorCode \| null` | Structured error classification (`"aborted"`, `"timeout"`, `"http"`, `"network"`, `"validation"`); `null` when there is no error. |
|
|
559
|
+
| `refetch` | `() => void` | Re-runs the same logical request. See [Refetch semantics](#refetch-semantics). |
|
|
560
|
+
| `deleteCache` | `() => void` | Tells the worker to delete the cache entry for this `cacheName`. |
|
|
561
|
+
| `streamChunks` | `ArrayBuffer[] \| undefined` | For `responseType: "stream"`: the latest flushed batch of chunks. Append to `MediaSource` or process incrementally. `undefined` for non-stream. |
|
|
505
562
|
|
|
506
563
|
### React Examples
|
|
507
564
|
|
|
@@ -636,7 +693,7 @@ const { data, meta, loading, error, streamChunks } = useApiWorker({
|
|
|
636
693
|
runMode: "auto",
|
|
637
694
|
});
|
|
638
695
|
|
|
639
|
-
// streamChunks:
|
|
696
|
+
// streamChunks: latest flushed batch (ArrayBuffer[]) as chunks arrive (append to MediaSource, etc.)
|
|
640
697
|
// data: Blob when the stream completes
|
|
641
698
|
// loading: true until stream ends
|
|
642
699
|
// const videoUrl = data ? URL.createObjectURL(data) : null;
|
|
@@ -659,9 +716,11 @@ const handleClearCache = () => {
|
|
|
659
716
|
|
|
660
717
|
### Shared cacheName / Multiple Subscribers
|
|
661
718
|
|
|
662
|
-
When multiple components use the same `cacheName`, they share a single
|
|
719
|
+
When multiple components use the same `cacheName`, they share a single client queue entry and a single worker cache key. All mounted subscribers register on that entry; when the worker responds, **all subscribers re-render** with the same `data`, `loading`, and `error` state.
|
|
720
|
+
|
|
721
|
+
**Recommendation:** Use distinct `cacheName` values when components need independent state, different `request` configs, or separate `loading`/`error` tracking.
|
|
663
722
|
|
|
664
|
-
**
|
|
723
|
+
**Unmount cancel:** When a component unmounts, its in-flight `requestId` is cancelled only if it is the last subscriber for that `cacheName`. Other subscribers keep the shared fetch alive.
|
|
665
724
|
|
|
666
725
|
### Refetch Semantics
|
|
667
726
|
|
|
@@ -674,15 +733,16 @@ It does not switch between get and set based on prior runs; it uses the current
|
|
|
674
733
|
|
|
675
734
|
### Errors
|
|
676
735
|
|
|
677
|
-
The worker always includes an `error` field in every message: `{ message: string }`.
|
|
736
|
+
The worker always includes an `error` field in every message: `{ message: string; code?: WorkerErrorCode }`.
|
|
678
737
|
|
|
679
738
|
- **No error**: `{ message: "" }` (empty string)
|
|
680
|
-
- **Error occurred**: `{ message: "error description" }`
|
|
739
|
+
- **Error occurred**: `{ message: "error description", code?: "aborted" | "timeout" | "http" | "network" | "validation" }`
|
|
681
740
|
|
|
682
|
-
The hook exposes this as `error: string | null`:
|
|
741
|
+
The hook exposes this as `error: string | null` and `errorCode: WorkerErrorCode | null`:
|
|
683
742
|
|
|
684
743
|
- `null` when `error.message` is empty
|
|
685
744
|
- The error message string when an error occurred
|
|
745
|
+
- `errorCode` mirrors `error.code` when present
|
|
686
746
|
|
|
687
747
|
Common error messages:
|
|
688
748
|
|
|
@@ -705,13 +765,14 @@ import type {
|
|
|
705
765
|
BinaryResponseMeta,
|
|
706
766
|
WorkerMessagePayload,
|
|
707
767
|
WorkerErrorPayload,
|
|
768
|
+
WorkerErrorCode,
|
|
769
|
+
WorkerResponseType,
|
|
708
770
|
WorkerResponseMessage,
|
|
709
771
|
ResponseType,
|
|
710
772
|
RunMode,
|
|
711
773
|
WorkerDataRequestType,
|
|
712
774
|
WorkerMessageData,
|
|
713
775
|
BinaryParseResult,
|
|
714
|
-
ContentType,
|
|
715
776
|
} from "@mainframework/api-request-worker";
|
|
716
777
|
```
|
|
717
778
|
|
|
@@ -729,10 +790,10 @@ import type { RequestConfig, UseApiWorkerConfig, UseApiWorkerReturn } from "@mai
|
|
|
729
790
|
|
|
730
791
|
## Quick Reference
|
|
731
792
|
|
|
732
|
-
| Use case | Entry point | Primary API
|
|
733
|
-
| ----------------- | ----------------------------------------- |
|
|
734
|
-
| **Vanilla JS/TS** | `@mainframework/api-request-worker` | `createApiWorker()`; set `worker.onmessage`, use `worker.postMessage`
|
|
735
|
-
| **React** | `@mainframework/api-request-worker/react` | `useApiWorker({ cacheName, request?, data?, runMode?, enabled? })` → `
|
|
793
|
+
| Use case | Entry point | Primary API |
|
|
794
|
+
| ----------------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
795
|
+
| **Vanilla JS/TS** | `@mainframework/api-request-worker` | `createApiWorker()`; set `worker.onmessage`, use `worker.postMessage` |
|
|
796
|
+
| **React** | `@mainframework/api-request-worker/react` | `useApiWorker({ cacheName, request?, data?, runMode?, enabled? })` → `UseApiWorkerReturn<T> \| null` (`data`, `meta`, `loading`, `error`, `errorCode`, `refetch`, `deleteCache`, `streamChunks?`) |
|
|
736
797
|
|
|
737
798
|
---
|
|
738
799
|
|
|
@@ -746,13 +807,16 @@ import type { RequestConfig, UseApiWorkerConfig, UseApiWorkerReturn } from "@mai
|
|
|
746
807
|
|
|
747
808
|
---
|
|
748
809
|
|
|
749
|
-
##
|
|
750
|
-
|
|
751
|
-
Tests use Vitest in browser mode (Playwright Chromium). The worker is created inside `useApiWorker`; there are no mocks.
|
|
810
|
+
## Changelog
|
|
752
811
|
|
|
753
|
-
|
|
812
|
+
### 1.1.0
|
|
754
813
|
|
|
755
|
-
|
|
814
|
+
- Added `type` and `requestId` to all worker→main messages for protocol disambiguation and request correlation.
|
|
815
|
+
- Added structured `error.code` (`WorkerErrorCode`) alongside existing `error.message`.
|
|
816
|
+
- Delete responses now use `type: "delete"` with `data: null` instead of `{ deleted: true }` — **breaking** for consumers relying on the old delete payload shape.
|
|
817
|
+
- Joiner-aware cancel: shared in-flight fetches track multiple `requestId`s; abort only when the last subscriber cancels.
|
|
818
|
+
- Last-activity eviction for idle queue entries (client) and cache store entries (worker).
|
|
819
|
+
- Stream `responseType` detection in the React hook now uses `toLocaleLowerCase()` consistently (was `toLowerCase()`).
|
|
756
820
|
|
|
757
821
|
---
|
|
758
822
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { U as UseApiWorkerConfig, a as UseApiWorkerReturn } from '../../types-
|
|
2
|
-
export { R as RequestConfig } from '../../types-
|
|
1
|
+
import { U as UseApiWorkerConfig, a as UseApiWorkerReturn } from '../../types-C6nnvGO7.js';
|
|
2
|
+
export { R as RequestConfig } from '../../types-C6nnvGO7.js';
|
|
3
3
|
|
|
4
|
-
declare const useApiWorker: <T>(config: UseApiWorkerConfig) => UseApiWorkerReturn<T
|
|
4
|
+
declare const useApiWorker: <T>(config: UseApiWorkerConfig) => UseApiWorkerReturn<T> | null;
|
|
5
5
|
|
|
6
6
|
export { UseApiWorkerConfig, UseApiWorkerReturn, useApiWorker };
|