@angular-helpers/worker-http 0.2.0 → 0.4.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 +112 -22
- package/fesm2022/angular-helpers-worker-http-backend.mjs +428 -0
- package/fesm2022/angular-helpers-worker-http-interceptors.mjs +377 -196
- package/fesm2022/angular-helpers-worker-http-transport.mjs +3 -0
- package/package.json +1 -1
- package/types/angular-helpers-worker-http-backend.d.ts +306 -3
- package/types/angular-helpers-worker-http-interceptors.d.ts +127 -5
- package/types/angular-helpers-worker-http-transport.d.ts +12 -0
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Provider, InjectionToken, EnvironmentProviders, OnDestroy } from '@angular/core';
|
|
3
|
+
import { HttpContextToken, HttpBackend, HttpRequest, HttpEvent, HttpContext, HttpResponse } from '@angular/common/http';
|
|
4
|
+
import { WorkerSerializer } from '@angular-helpers/worker-http/serializer';
|
|
5
|
+
import { WorkerInterceptorSpec } from '@angular-helpers/worker-http/interceptors';
|
|
6
|
+
import { Observable } from 'rxjs';
|
|
2
7
|
|
|
3
8
|
/**
|
|
4
9
|
* Discriminated union for worker HTTP feature kinds.
|
|
5
10
|
* Mirrors Angular's HttpFeatureKind pattern.
|
|
6
11
|
*/
|
|
7
|
-
type WorkerHttpFeatureKind = 'WorkerConfigs' | 'WorkerRoutes' | 'WorkerFallback' | 'WorkerSerialization';
|
|
12
|
+
type WorkerHttpFeatureKind = 'WorkerConfigs' | 'WorkerRoutes' | 'WorkerFallback' | 'WorkerSerialization' | 'WorkerInterceptors';
|
|
8
13
|
/**
|
|
9
14
|
* Feature object — mirrors Angular's HttpFeature<K> shape.
|
|
10
15
|
*/
|
|
@@ -38,5 +43,303 @@ interface WorkerRoute {
|
|
|
38
43
|
* Fallback strategy when workers are unavailable (SSR, old browsers).
|
|
39
44
|
*/
|
|
40
45
|
type WorkerFallbackStrategy = 'main-thread' | 'error';
|
|
46
|
+
/**
|
|
47
|
+
* Serializable HTTP request — POJO version of Angular's HttpRequest.
|
|
48
|
+
* Structured-clone safe: no classes, no functions, no prototype chains.
|
|
49
|
+
*/
|
|
50
|
+
interface SerializableRequest {
|
|
51
|
+
method: string;
|
|
52
|
+
url: string;
|
|
53
|
+
headers: Record<string, string[]>;
|
|
54
|
+
params: Record<string, string[]>;
|
|
55
|
+
body: unknown;
|
|
56
|
+
responseType: 'json' | 'text' | 'blob' | 'arraybuffer';
|
|
57
|
+
withCredentials: boolean;
|
|
58
|
+
context: Record<string, unknown>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Serializable HTTP response — POJO version of Angular's HttpResponse.
|
|
62
|
+
*/
|
|
63
|
+
interface SerializableResponse {
|
|
64
|
+
status: number;
|
|
65
|
+
statusText: string;
|
|
66
|
+
headers: Record<string, string[]>;
|
|
67
|
+
body: unknown;
|
|
68
|
+
url: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Per-worker interceptor specs map. Key is the worker id from
|
|
73
|
+
* `WorkerConfig.id`, plus the special `'*'` wildcard that applies to every
|
|
74
|
+
* worker. Specs from `'*'` are prepended to the worker-specific specs at
|
|
75
|
+
* resolve time.
|
|
76
|
+
*/
|
|
77
|
+
type WorkerInterceptorSpecsMap = Readonly<Record<string, readonly WorkerInterceptorSpec[]>>;
|
|
78
|
+
/**
|
|
79
|
+
* Per-request HttpContextToken that carries the target worker ID.
|
|
80
|
+
*
|
|
81
|
+
* `null` → use URL-pattern auto-routing (or main-thread fallback if no route matches).
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* // With WorkerHttpClient (recommended)
|
|
86
|
+
* this.http.get('/api/data', { worker: 'secure' });
|
|
87
|
+
*
|
|
88
|
+
* // With standard HttpClient (power user)
|
|
89
|
+
* this.http.get('/api/data', {
|
|
90
|
+
* context: new HttpContext().set(WORKER_TARGET, 'secure'),
|
|
91
|
+
* });
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
declare const WORKER_TARGET: HttpContextToken<string>;
|
|
95
|
+
/**
|
|
96
|
+
* Optional serializer for crossing the worker boundary.
|
|
97
|
+
* Provided via `withWorkerSerialization()`. Defaults to `null` (structured clone).
|
|
98
|
+
*
|
|
99
|
+
* When set, `WorkerHttpBackend` serializes the request body before `postMessage`
|
|
100
|
+
* using this serializer. The worker-side `createWorkerPipeline()` receives the
|
|
101
|
+
* serialized form — add a worker interceptor to deserialize it if needed.
|
|
102
|
+
*/
|
|
103
|
+
declare const WORKER_HTTP_SERIALIZER_TOKEN: InjectionToken<WorkerSerializer>;
|
|
104
|
+
/**
|
|
105
|
+
* Per-worker interceptor specs provided via `withWorkerInterceptors()`.
|
|
106
|
+
* Defaults to an empty map (no interceptors).
|
|
107
|
+
*/
|
|
108
|
+
declare const WORKER_HTTP_INTERCEPTORS_TOKEN: InjectionToken<Readonly<Record<string, readonly WorkerInterceptorSpec[]>>>;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Sets up the worker HTTP infrastructure and replaces Angular's `HttpBackend`
|
|
112
|
+
* with `WorkerHttpBackend`.
|
|
113
|
+
*
|
|
114
|
+
* Drop-in companion to `provideHttpClient()`. Can be used INSTEAD of it —
|
|
115
|
+
* `HttpClient` and the full interceptor chain are included automatically.
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* // app.config.ts
|
|
120
|
+
* export const appConfig: ApplicationConfig = {
|
|
121
|
+
* providers: [
|
|
122
|
+
* provideWorkerHttpClient(
|
|
123
|
+
* withWorkerConfigs([
|
|
124
|
+
* { id: 'public', workerUrl: new URL('./workers/public.worker', import.meta.url) },
|
|
125
|
+
* ]),
|
|
126
|
+
* withWorkerRoutes([
|
|
127
|
+
* { pattern: /\/api\//, worker: 'public', priority: 1 },
|
|
128
|
+
* ]),
|
|
129
|
+
* withWorkerFallback('main-thread'),
|
|
130
|
+
* ),
|
|
131
|
+
* ],
|
|
132
|
+
* };
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
declare function provideWorkerHttpClient(...features: WorkerHttpFeature<WorkerHttpFeatureKind>[]): EnvironmentProviders;
|
|
136
|
+
/**
|
|
137
|
+
* Registers worker definitions (id + workerUrl + optional pool size).
|
|
138
|
+
*
|
|
139
|
+
* At least one config is required for any request to reach a worker.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```typescript
|
|
143
|
+
* withWorkerConfigs([
|
|
144
|
+
* { id: 'public', workerUrl: new URL('./workers/public.worker', import.meta.url) },
|
|
145
|
+
* { id: 'secure', workerUrl: new URL('./workers/secure.worker', import.meta.url), maxInstances: 2 },
|
|
146
|
+
* ])
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
declare function withWorkerConfigs(configs: WorkerConfig[]): WorkerHttpFeature<'WorkerConfigs'>;
|
|
150
|
+
/**
|
|
151
|
+
* Declares URL-pattern → worker routing rules evaluated in priority order.
|
|
152
|
+
*
|
|
153
|
+
* When a request URL matches a pattern, the associated worker handles it.
|
|
154
|
+
* Explicit `WORKER_TARGET` context always takes precedence over routes.
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```typescript
|
|
158
|
+
* withWorkerRoutes([
|
|
159
|
+
* { pattern: /\/api\/secure\//, worker: 'secure', priority: 10 },
|
|
160
|
+
* { pattern: /\/api\//, worker: 'public', priority: 1 },
|
|
161
|
+
* ])
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
declare function withWorkerRoutes(routes: WorkerRoute[]): WorkerHttpFeature<'WorkerRoutes'>;
|
|
165
|
+
/**
|
|
166
|
+
* Sets the fallback strategy when workers are unavailable (SSR, old browsers,
|
|
167
|
+
* or when no route matches).
|
|
168
|
+
*
|
|
169
|
+
* - `'main-thread'` (default) — silently delegates to `FetchBackend`
|
|
170
|
+
* - `'error'` — throws, forcing explicit handling in the application
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* ```typescript
|
|
174
|
+
* withWorkerFallback('main-thread') // SSR-safe
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
declare function withWorkerFallback(strategy: WorkerFallbackStrategy): WorkerHttpFeature<'WorkerFallback'>;
|
|
178
|
+
/**
|
|
179
|
+
* Configures a custom serializer for crossing the worker boundary.
|
|
180
|
+
*
|
|
181
|
+
* By default `WorkerHttpBackend` relies on the browser's structured clone algorithm
|
|
182
|
+
* (safe for plain objects, arrays, primitives, `Date`, `ArrayBuffer`).
|
|
183
|
+
* Use `withWorkerSerialization` when your request bodies contain types that
|
|
184
|
+
* structured clone cannot handle (e.g. class instances, circular references, `Map`, `Set`).
|
|
185
|
+
*
|
|
186
|
+
* **Worker-side note:** The serialized form is what the worker receives as `req.body`.
|
|
187
|
+
* If you use `createSerovalSerializer` or similar, add a worker-side interceptor
|
|
188
|
+
* to deserialize the body before calling `fetch()`.
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```typescript
|
|
192
|
+
* import { createSerovalSerializer } from '@angular-helpers/worker-http/serializer';
|
|
193
|
+
*
|
|
194
|
+
* provideWorkerHttpClient(
|
|
195
|
+
* withWorkerConfigs([...]),
|
|
196
|
+
* withWorkerSerialization(createSerovalSerializer()),
|
|
197
|
+
* )
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
declare function withWorkerSerialization(serializer: WorkerSerializer): WorkerHttpFeature<'WorkerSerialization'>;
|
|
201
|
+
/**
|
|
202
|
+
* Configures the worker-side interceptor pipeline from Angular DI.
|
|
203
|
+
*
|
|
204
|
+
* Specs are forwarded to each worker via an `init-interceptors` handshake
|
|
205
|
+
* message posted before any HTTP request. Workers must call
|
|
206
|
+
* `createConfigurableWorkerPipeline()` to receive and act on the handshake.
|
|
207
|
+
*
|
|
208
|
+
* Two shapes are accepted:
|
|
209
|
+
* - `WorkerInterceptorSpec[]` — applied to every registered worker
|
|
210
|
+
* - `Record<workerId, WorkerInterceptorSpec[]>` — per-worker, with the
|
|
211
|
+
* special `'*'` key applied to all workers in addition to the
|
|
212
|
+
* worker-specific specs
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```typescript
|
|
216
|
+
* provideWorkerHttpClient(
|
|
217
|
+
* withWorkerConfigs([{ id: 'api', workerUrl: ... }]),
|
|
218
|
+
* withWorkerInterceptors([
|
|
219
|
+
* workerLogging(),
|
|
220
|
+
* workerRetry({ maxRetries: 3 }),
|
|
221
|
+
* workerCache({ ttl: 30_000 }),
|
|
222
|
+
* ]),
|
|
223
|
+
* );
|
|
224
|
+
* ```
|
|
225
|
+
*
|
|
226
|
+
* @example Per-worker specs
|
|
227
|
+
* ```typescript
|
|
228
|
+
* withWorkerInterceptors({
|
|
229
|
+
* '*': [workerLogging()],
|
|
230
|
+
* 'secure': [workerHmacSigning({ keyMaterial })],
|
|
231
|
+
* });
|
|
232
|
+
* ```
|
|
233
|
+
*/
|
|
234
|
+
declare function withWorkerInterceptors(specs: readonly WorkerInterceptorSpec[] | WorkerInterceptorSpecsMap): WorkerHttpFeature<'WorkerInterceptors'>;
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Angular `HttpBackend` replacement that routes HTTP requests to web workers.
|
|
238
|
+
*
|
|
239
|
+
* Registered via `provideWorkerHttpClient()`. Not meant to be used directly.
|
|
240
|
+
*
|
|
241
|
+
* Flow per request:
|
|
242
|
+
* 1. Check SSR: if `Worker` is undefined → fallback strategy
|
|
243
|
+
* 2. Resolve target worker ID from `WORKER_TARGET` context or URL-pattern routing
|
|
244
|
+
* 3. Serialize `HttpRequest` → `SerializableRequest` (structured-clone safe)
|
|
245
|
+
* 4. Dispatch to the worker's `WorkerTransport`
|
|
246
|
+
* 5. Deserialize `SerializableResponse` → `HttpResponse`
|
|
247
|
+
*/
|
|
248
|
+
declare class WorkerHttpBackend extends HttpBackend implements OnDestroy {
|
|
249
|
+
private readonly configs;
|
|
250
|
+
private readonly routes;
|
|
251
|
+
private readonly fallback;
|
|
252
|
+
private readonly serializer;
|
|
253
|
+
private readonly interceptorSpecs;
|
|
254
|
+
private readonly fetchBackend;
|
|
255
|
+
private readonly transports;
|
|
256
|
+
handle(req: HttpRequest<unknown>): Observable<HttpEvent<unknown>>;
|
|
257
|
+
ngOnDestroy(): void;
|
|
258
|
+
private getOrCreateTransport;
|
|
259
|
+
private resolveSpecsFor;
|
|
260
|
+
private handleFallback;
|
|
261
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<WorkerHttpBackend, never>;
|
|
262
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<WorkerHttpBackend>;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Options accepted by `WorkerHttpClient` methods.
|
|
267
|
+
* Identical to `HttpClient` options with an optional `worker` field added.
|
|
268
|
+
*/
|
|
269
|
+
interface WorkerRequestOptions {
|
|
270
|
+
/** Target worker ID. Overrides URL-pattern routing for this specific request. */
|
|
271
|
+
worker?: string | null;
|
|
272
|
+
context?: HttpContext;
|
|
273
|
+
headers?: Record<string, string | string[]>;
|
|
274
|
+
params?: Record<string, string | number | boolean | ReadonlyArray<string | number | boolean>>;
|
|
275
|
+
responseType?: 'json';
|
|
276
|
+
withCredentials?: boolean;
|
|
277
|
+
observe?: 'body';
|
|
278
|
+
reportProgress?: boolean;
|
|
279
|
+
transferCache?: {
|
|
280
|
+
includeHeaders?: string[];
|
|
281
|
+
} | boolean;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Convenience wrapper over `HttpClient` that adds an optional `{ worker }` field
|
|
285
|
+
* to every method. Under the hood it sets `WORKER_TARGET` on the `HttpContext` —
|
|
286
|
+
* the caller never has to touch the context manually.
|
|
287
|
+
*
|
|
288
|
+
* Usage is identical to `HttpClient` — just inject `WorkerHttpClient` instead.
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* ```typescript
|
|
292
|
+
* @Injectable({ providedIn: 'root' })
|
|
293
|
+
* export class DataService {
|
|
294
|
+
* private readonly http = inject(WorkerHttpClient);
|
|
295
|
+
*
|
|
296
|
+
* getUsers(): Observable<User[]> {
|
|
297
|
+
* return this.http.get<User[]>('/api/users'); // auto-routed by URL pattern
|
|
298
|
+
* }
|
|
299
|
+
*
|
|
300
|
+
* getSensitiveReport(): Observable<Report> {
|
|
301
|
+
* return this.http.get<Report>('/api/secure/reports', { worker: 'secure' });
|
|
302
|
+
* }
|
|
303
|
+
* }
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
declare class WorkerHttpClient {
|
|
307
|
+
private readonly http;
|
|
308
|
+
get<T>(url: string, options?: WorkerRequestOptions): Observable<T>;
|
|
309
|
+
post<T>(url: string, body: unknown, options?: WorkerRequestOptions): Observable<T>;
|
|
310
|
+
put<T>(url: string, body: unknown, options?: WorkerRequestOptions): Observable<T>;
|
|
311
|
+
patch<T>(url: string, body: unknown, options?: WorkerRequestOptions): Observable<T>;
|
|
312
|
+
delete<T>(url: string, options?: WorkerRequestOptions): Observable<T>;
|
|
313
|
+
head<T>(url: string, options?: WorkerRequestOptions): Observable<T>;
|
|
314
|
+
private withWorker;
|
|
315
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<WorkerHttpClient, never>;
|
|
316
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<WorkerHttpClient>;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Converts an Angular `HttpRequest` into a structured-clone-safe POJO
|
|
321
|
+
* that can be sent to a web worker via `postMessage`.
|
|
322
|
+
*
|
|
323
|
+
* Notes:
|
|
324
|
+
* - `urlWithParams` is used so query params embedded via `HttpParams` are included.
|
|
325
|
+
* - The `context` field is intentionally left empty: `HttpContext` uses class references
|
|
326
|
+
* as keys which cannot cross the worker boundary.
|
|
327
|
+
*/
|
|
328
|
+
declare function toSerializableRequest(req: HttpRequest<unknown>): SerializableRequest;
|
|
329
|
+
/**
|
|
330
|
+
* Converts a worker `SerializableResponse` back into an Angular `HttpResponse`.
|
|
331
|
+
*/
|
|
332
|
+
declare function toHttpResponse(res: SerializableResponse, req: HttpRequest<unknown>): HttpResponse<unknown>;
|
|
333
|
+
/**
|
|
334
|
+
* Matches a URL against a sorted list of `WorkerRoute` rules.
|
|
335
|
+
* Rules with higher `priority` are evaluated first.
|
|
336
|
+
* Returns the matched worker ID or `null` if no rule matches.
|
|
337
|
+
*/
|
|
338
|
+
declare function matchWorkerRoute(url: string, routes: Array<{
|
|
339
|
+
pattern: RegExp | string;
|
|
340
|
+
worker: string;
|
|
341
|
+
priority?: number;
|
|
342
|
+
}>): string | null;
|
|
41
343
|
|
|
42
|
-
export
|
|
344
|
+
export { WORKER_HTTP_INTERCEPTORS_TOKEN, WORKER_HTTP_SERIALIZER_TOKEN, WORKER_TARGET, WorkerHttpBackend, WorkerHttpClient, matchWorkerRoute, provideWorkerHttpClient, toHttpResponse, toSerializableRequest, withWorkerConfigs, withWorkerFallback, withWorkerInterceptors, withWorkerRoutes, withWorkerSerialization };
|
|
345
|
+
export type { SerializableRequest, SerializableResponse, WorkerConfig, WorkerFallbackStrategy, WorkerHttpFeature, WorkerHttpFeatureKind, WorkerInterceptorSpecsMap, WorkerRequestOptions, WorkerRoute };
|
|
@@ -109,17 +109,120 @@ interface ContentIntegrityConfig {
|
|
|
109
109
|
* runs them through the interceptor chain, executes `fetch()`,
|
|
110
110
|
* and sends the response back.
|
|
111
111
|
*
|
|
112
|
+
* For a runtime-configurable variant whose chain is built from specs sent
|
|
113
|
+
* from the main thread, use `createConfigurableWorkerPipeline()` instead.
|
|
114
|
+
*
|
|
112
115
|
* @example
|
|
113
116
|
* ```typescript
|
|
114
117
|
* // workers/secure.worker.ts
|
|
115
|
-
* import { createWorkerPipeline } from '@angular-helpers/worker-http/interceptors';
|
|
116
|
-
* import { hmacSigningInterceptor } from './my-interceptors';
|
|
118
|
+
* import { createWorkerPipeline, hmacSigningInterceptor } from '@angular-helpers/worker-http/interceptors';
|
|
117
119
|
*
|
|
118
|
-
* createWorkerPipeline([hmacSigningInterceptor]);
|
|
120
|
+
* createWorkerPipeline([hmacSigningInterceptor({ keyMaterial })]);
|
|
119
121
|
* ```
|
|
120
122
|
*/
|
|
121
123
|
declare function createWorkerPipeline(interceptors: WorkerInterceptorFn[]): void;
|
|
122
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Serializable subset of LoggingConfig — `logger` is a function and cannot
|
|
127
|
+
* cross the worker boundary, so it is dropped here. The configurable pipeline
|
|
128
|
+
* uses `console.log` inside the worker for built-in logging.
|
|
129
|
+
*/
|
|
130
|
+
type SerializableLoggingConfig = Omit<LoggingConfig, 'logger'>;
|
|
131
|
+
/**
|
|
132
|
+
* Serializable subset of HmacInterceptorConfig — `payloadBuilder` is a function
|
|
133
|
+
* and cannot cross the worker boundary. The default payload builder is used.
|
|
134
|
+
*
|
|
135
|
+
* `keyMaterial` is `ArrayBuffer | Uint8Array`, both of which ARE supported by
|
|
136
|
+
* the structured clone algorithm.
|
|
137
|
+
*/
|
|
138
|
+
type SerializableHmacConfig = Omit<HmacInterceptorConfig, 'payloadBuilder'>;
|
|
139
|
+
/**
|
|
140
|
+
* Discriminated union of interceptor specifications that can be configured
|
|
141
|
+
* from Angular DI via `withWorkerInterceptors([...])` and forwarded to the
|
|
142
|
+
* worker over `postMessage`.
|
|
143
|
+
*
|
|
144
|
+
* For interceptors with custom function fields (loggers, payload builders),
|
|
145
|
+
* register the interceptor in the worker file via `registerInterceptor()` and
|
|
146
|
+
* reference it here with `kind: 'custom'`.
|
|
147
|
+
*/
|
|
148
|
+
type WorkerInterceptorSpec = {
|
|
149
|
+
readonly kind: 'logging';
|
|
150
|
+
readonly config?: SerializableLoggingConfig;
|
|
151
|
+
} | {
|
|
152
|
+
readonly kind: 'retry';
|
|
153
|
+
readonly config?: RetryConfig;
|
|
154
|
+
} | {
|
|
155
|
+
readonly kind: 'cache';
|
|
156
|
+
readonly config?: CacheConfig;
|
|
157
|
+
} | {
|
|
158
|
+
readonly kind: 'hmac-signing';
|
|
159
|
+
readonly config: SerializableHmacConfig;
|
|
160
|
+
} | {
|
|
161
|
+
readonly kind: 'rate-limit';
|
|
162
|
+
readonly config?: RateLimitConfig;
|
|
163
|
+
} | {
|
|
164
|
+
readonly kind: 'content-integrity';
|
|
165
|
+
readonly config?: ContentIntegrityConfig;
|
|
166
|
+
} | {
|
|
167
|
+
readonly kind: 'custom';
|
|
168
|
+
readonly name: string;
|
|
169
|
+
readonly config?: unknown;
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* Wire format for the init handshake message sent from the main thread to the
|
|
173
|
+
* worker. Posted exactly once per worker, before any HTTP request.
|
|
174
|
+
*/
|
|
175
|
+
interface WorkerInterceptorInitMessage {
|
|
176
|
+
readonly type: 'init-interceptors';
|
|
177
|
+
readonly specs: readonly WorkerInterceptorSpec[];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
type CustomFactory = (config?: unknown) => WorkerInterceptorFn;
|
|
181
|
+
/**
|
|
182
|
+
* Registers a custom interceptor factory that can be referenced from
|
|
183
|
+
* `withWorkerInterceptors([workerCustom('my-name', config)])`.
|
|
184
|
+
*
|
|
185
|
+
* Must be called inside the worker file BEFORE `createConfigurableWorkerPipeline()`.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* // app.worker.ts
|
|
190
|
+
* import { createConfigurableWorkerPipeline, registerInterceptor } from '@angular-helpers/worker-http/interceptors';
|
|
191
|
+
*
|
|
192
|
+
* registerInterceptor('auth-token', (config: { token: string }) => async (req, next) => {
|
|
193
|
+
* const headers = { ...req.headers, authorization: [`Bearer ${config.token}`] };
|
|
194
|
+
* return next({ ...req, headers });
|
|
195
|
+
* });
|
|
196
|
+
*
|
|
197
|
+
* createConfigurableWorkerPipeline();
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
declare function registerInterceptor(name: string, factory: CustomFactory): void;
|
|
201
|
+
/**
|
|
202
|
+
* Resolves a single spec to its concrete `WorkerInterceptorFn`.
|
|
203
|
+
*
|
|
204
|
+
* Exported for test use. Throws on unknown `kind` or unregistered custom name
|
|
205
|
+
* so misconfiguration fails loudly at init time, not on the first request.
|
|
206
|
+
*/
|
|
207
|
+
declare function resolveSpec(spec: WorkerInterceptorSpec): WorkerInterceptorFn;
|
|
208
|
+
/**
|
|
209
|
+
* Creates a worker-side pipeline whose interceptor chain is supplied at
|
|
210
|
+
* runtime via the init handshake message sent by `WorkerHttpBackend`.
|
|
211
|
+
*
|
|
212
|
+
* Behavior:
|
|
213
|
+
* - Listens for the first `init-interceptors` message and builds the chain
|
|
214
|
+
* from the received specs.
|
|
215
|
+
* - Until init arrives, incoming `request` messages are buffered (they will
|
|
216
|
+
* be flushed once the chain is ready).
|
|
217
|
+
* - If no init arrives (e.g. worker used standalone without
|
|
218
|
+
* `withWorkerInterceptors`), the pipeline runs with an empty chain so
|
|
219
|
+
* every request goes straight to `fetch()`.
|
|
220
|
+
*
|
|
221
|
+
* Custom interceptor factories must be registered with
|
|
222
|
+
* `registerInterceptor(name, factory)` before this call.
|
|
223
|
+
*/
|
|
224
|
+
declare function createConfigurableWorkerPipeline(): void;
|
|
225
|
+
|
|
123
226
|
/**
|
|
124
227
|
* Creates a retry interceptor with exponential backoff.
|
|
125
228
|
*
|
|
@@ -240,5 +343,24 @@ declare function contentIntegrityInterceptor(config?: ContentIntegrityConfig): W
|
|
|
240
343
|
*/
|
|
241
344
|
declare function composeInterceptors(...fns: WorkerInterceptorFn[]): WorkerInterceptorFn;
|
|
242
345
|
|
|
243
|
-
|
|
244
|
-
|
|
346
|
+
/**
|
|
347
|
+
* Spec builders — pure factories that return POJO `WorkerInterceptorSpec`
|
|
348
|
+
* objects suitable for `withWorkerInterceptors([...])`.
|
|
349
|
+
*
|
|
350
|
+
* Each builder mirrors the corresponding worker-side interceptor factory but
|
|
351
|
+
* accepts only serializable config (no function fields).
|
|
352
|
+
*/
|
|
353
|
+
declare function workerLogging(config?: SerializableLoggingConfig): WorkerInterceptorSpec;
|
|
354
|
+
declare function workerRetry(config?: RetryConfig): WorkerInterceptorSpec;
|
|
355
|
+
declare function workerCache(config?: CacheConfig): WorkerInterceptorSpec;
|
|
356
|
+
declare function workerHmacSigning(config: SerializableHmacConfig): WorkerInterceptorSpec;
|
|
357
|
+
declare function workerRateLimit(config?: RateLimitConfig): WorkerInterceptorSpec;
|
|
358
|
+
declare function workerContentIntegrity(config?: ContentIntegrityConfig): WorkerInterceptorSpec;
|
|
359
|
+
/**
|
|
360
|
+
* Reference a custom interceptor that has been registered on the worker side
|
|
361
|
+
* via `registerInterceptor(name, factory)`.
|
|
362
|
+
*/
|
|
363
|
+
declare function workerCustom(name: string, config?: unknown): WorkerInterceptorSpec;
|
|
364
|
+
|
|
365
|
+
export { cacheInterceptor, composeInterceptors, contentIntegrityInterceptor, createConfigurableWorkerPipeline, createWorkerPipeline, hmacSigningInterceptor, loggingInterceptor, rateLimitInterceptor, registerInterceptor, resolveSpec, retryInterceptor, workerCache, workerContentIntegrity, workerCustom, workerHmacSigning, workerLogging, workerRateLimit, workerRetry };
|
|
366
|
+
export type { CacheConfig, ContentIntegrityConfig, HmacInterceptorConfig, LoggingConfig, RateLimitConfig, RetryConfig, SerializableHmacConfig, SerializableLoggingConfig, SerializableRequest, SerializableResponse, WorkerInterceptorFn, WorkerInterceptorInitMessage, WorkerInterceptorSpec };
|
|
@@ -38,6 +38,18 @@ interface WorkerTransportConfig {
|
|
|
38
38
|
transferDetection?: 'auto' | 'manual' | 'none';
|
|
39
39
|
/** Timeout in ms for a single request (default: 30000) */
|
|
40
40
|
requestTimeout?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Optional handshake message posted to every worker as soon as it is
|
|
43
|
+
* created, BEFORE any request. Useful to ship runtime configuration
|
|
44
|
+
* (e.g. interceptor specs) that the worker uses to build its pipeline.
|
|
45
|
+
*
|
|
46
|
+
* The shape is opaque to the transport — the worker is responsible for
|
|
47
|
+
* recognising and acting on it.
|
|
48
|
+
*/
|
|
49
|
+
initMessage?: {
|
|
50
|
+
type: string;
|
|
51
|
+
[key: string]: unknown;
|
|
52
|
+
};
|
|
41
53
|
}
|
|
42
54
|
/**
|
|
43
55
|
* Message sent from main thread to worker.
|