@buildplease/webkit 1.0.1 → 1.0.3

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
@@ -1,8 +1,8 @@
1
1
  # @buildplease/webkit
2
2
 
3
- WebKit provides the shared browser-side runtime for BuildPlease applications, including dependency injection, HTTP networking, request interceptors, web models, and L10n integration.
3
+ WebKit is the BuildPlease application kit for browser applications. It builds on Core and provides shared web application architecture and runtime primitives without depending on a specific frontend framework.
4
4
 
5
- ## Install
5
+ ## Installation
6
6
 
7
7
  ```bash
8
8
  pnpm add @buildplease/webkit
@@ -11,20 +11,20 @@ pnpm add @buildplease/webkit
11
11
  ## Usage
12
12
 
13
13
  ```ts
14
- import { HttpError, InterceptorSet, webkitAssembly } from '@buildplease/webkit';
14
+ import { webkitAssembly } from '@buildplease/webkit';
15
15
 
16
16
  const assemblies = webkitAssembly();
17
17
  ```
18
18
 
19
- WebKit re-exports the Core API, so shared BuildPlease primitives can be imported from the same package in browser applications.
19
+ ## Features
20
20
 
21
- ## What’s included
22
-
23
- - browser application assembly
24
- - Axios-based remote networking primitives
25
- - request interceptors and cookie handling
26
- - HTTP error handling
27
- - shared web models
21
+ - browser application architecture and dependency injection
22
+ - asynchronous operations and remote resources
23
+ - transport-independent HTTP primitives
24
+ - request interception and error handling
25
+ - shared web models and utilities
28
26
  - L10n integration
29
27
 
30
- Part of [BuildPlease](https://github.com/BuildPlease/buildplease).
28
+ ## License
29
+
30
+ MIT
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,s)=>(s=n==null?{}:e(i(n)),o(r||!n||!n.__esModule||!a.call(n,`default`)?t(s,`default`,{value:n,enumerable:!0}):s,n));require("reflect-metadata");let c=require("@buildplease/core"),l=require("axios");l=s(l,1);let u=require("inversify");function d(){return[]}const f={name:`buildplease`,displayName:`BuildPlease`,scope:`@buildplease`};`${f.name}`;const p={DI:{}},m=c.CoreL10nResource;var h=class extends Error{statusCode;code;details;constructor(e){super(e.message),this.name=`HttpError`,this.statusCode=e.statusCode,this.code=e.code,this.details=e.details}},g=class e{order=-10;hash(){return Symbol.for(`${f.scope}.webkit.networking.interceptor.cookie`)}equals(t){return t instanceof e}intercept(e){return{...e,withCredentials:!0}}};function _(e,t){if(typeof Reflect==`object`&&typeof Reflect.metadata==`function`)return Reflect.metadata(e,t)}function v(e,t){return function(n,r){t(n,r,e)}}function y(e,t,n,r){var i=arguments.length,a=i<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r,o;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)a=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(a=(i<3?o(a):i>3?o(t,n,a):o(t,n))||a);return i>3&&a&&Object.defineProperty(t,n,a),a}const b=`Unknown Error`;let x=class{endpoint;interceptors=new S;constructor(e){this.endpoint=e,this.use(new g)}use(...e){return this.interceptors.add(...e),this}removeInterceptor(e){return this.interceptors.remove(e),this}clearInterceptors(){return this.interceptors.clear(),this}async execute(e,t){try{let n=await this.convertOrThrow(()=>this.endpoint.convertInput(e)),r={...t};for(let e of this.interceptors.list())r=e.intercept(r);let i=await this.endpoint.makeRequest(n,r);return await this.convertOrThrow(()=>this.endpoint.convertOutput(i))}catch(e){throw this.parseError(e)}}parseError(e){if(e instanceof h||e instanceof c.TimeoutError||e instanceof c.NetworkError||e instanceof c.CanceledError||e instanceof c.ConversionError||e instanceof c.UnknownError)return e;if(l.default.isCancel?.(e)||l.default.isAxiosError(e)&&(e.code===`ERR_CANCELED`||e.message===`canceled`))return new c.CanceledError({cause:e});if(l.default.isAxiosError(e)&&e.code===`ECONNABORTED`)return new c.TimeoutError({cause:e});if(l.default.isAxiosError(e)&&!e.response)return new c.NetworkError({message:e.message,cause:e});if(l.default.isAxiosError(e)&&e.response){let{status:t,data:n}=e.response,r=n;typeof r==`string`&&(r=(0,c.ignoreError)(()=>JSON.parse(r)).orDefault(r));let i=this.isStringArrayRecord(r.details)?r.details:void 0;return new h(this.buildHttpErrorOptions(t,r,i))}let t=e instanceof Error?e.message:b;return new c.UnknownError({message:t,cause:e})}async convertOrThrow(e){try{return await e()}catch(e){throw new c.ConversionError({cause:e})}}isStringArrayRecord(e){return!(0,c.isDefinedAndNotNull)(e)||!(0,c.isPlainObject)(e)?!1:Object.values(e).every(e=>Array.isArray(e)&&e.every(e=>typeof e==`string`))}buildHttpErrorOptions(e,t,n){return{statusCode:e,code:(0,c.isNonEmptyString)(t?.code)?t.code:`UNKNOWN_ERROR`,message:(0,c.isNonEmptyString)(t?.message)?t.message:b,details:n}}};x=y([(0,u.injectable)(),v(0,(0,u.unmanaged)()),_(`design:paramtypes`,[Object])],x);var S=class{map=new Map;add(...e){for(let t of e){let e=t.hash(),n=this.map.get(e);n&&n.equals(t)||this.map.set(e,t)}return this}remove(e){return this.map.delete(e.hash()),this}clear(){return this.map.clear(),this}list(){return[...this.map.values()].sort((e,t)=>e.order-t.order)}};function C(){let e=(0,c.coreAssembly)(),t=d();return[...e,...t]}Object.defineProperty(exports,"BaseRemoteResource",{enumerable:!0,get:function(){return x}}),exports.CookieInterceptor=g,exports.HttpError=h,exports.InterceptorSet=S,exports.WebKitL10nResource=m,exports.WebKitSymbols=p,exports.webkitAssembly=C,Object.keys(c).forEach(function(e){e!=="default"&&!Object.prototype.hasOwnProperty.call(exports,e)&&Object.defineProperty(exports,e,{enumerable:!0,get:function(){return c[e]}})});
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`}),require("reflect-metadata");let e=require("@buildplease/core"),t=require("inversify");function n(){return[]}`${{name:`buildplease`,displayName:`BuildPlease`,scope:`@buildplease`}.name}`;const r={DI:{}},i=e.CoreL10nResource;var a=class{mode;pendingEntries=[];activeEntries=new Set;interruption;isSerialOperationRunning=!1;constructor(e=`parallel`){this.mode=e}execute(t){if(this.interruption)return Promise.reject(new e.CanceledError);let n=this.createEntry(t);return this.mode===`serial`?(this.pendingEntries.push(n),this.startNextSerialOperation()):this.startEntry(n),n.promise}cancelAll(e){let t=this.pendingEntries.splice(0);for(let n of t)this.cancelEntry(n,e);for(let t of this.activeEntries)this.cancelEntry(t,e)}async interrupt(e){if(!this.interruption){let t=Promise.resolve().then(e).finally(()=>{this.interruption===t&&(this.interruption=void 0,this.startNextSerialOperation())});this.interruption=t,this.cancelAll()}await this.interruption}createEntry(e){let t,n;return{operation:e,promise:new Promise((e,r)=>{t=e,n=r}),resolve:e=>t?.(e),reject:e=>n?.(e),canceled:!1,settled:!1}}startEntry(e){if(e.canceled||this.interruption){this.cancelEntry(e);return}this.activeEntries.add(e),this.mode===`serial`&&(this.isSerialOperationRunning=!0),Promise.resolve().then(e.operation).then(t=>{e.canceled||this.resolveEntry(e,t)},t=>{e.canceled||this.rejectEntry(e,t)}).finally(()=>{this.activeEntries.delete(e),this.mode===`serial`&&(this.isSerialOperationRunning=!1,this.startNextSerialOperation())})}startNextSerialOperation(){if(this.mode!==`serial`||this.isSerialOperationRunning||this.interruption)return;let e=this.pendingEntries.shift();e&&this.startEntry(e)}cancelEntry(t,n){t.canceled||(t.canceled=!0,t.settled||this.rejectEntry(t,new e.CanceledError({cause:n})))}resolveEntry(e,t){e.settled||(e.settled=!0,e.resolve(t))}rejectEntry(e,t){e.settled||(e.settled=!0,e.reject(t))}},o=class extends Error{statusCode;code;details;constructor(e){super(e.message),this.name=`HttpError`,this.statusCode=e.statusCode,this.code=e.code,this.details=e.details,e.cause!==void 0&&(this.cause=e.cause)}},s=class{interceptors;constructor(e=[],t){this.interceptors=this.resolveInterceptors(e,t)}async intercept(e){let t=e;for(let e of this.interceptors)t=await e.intercept(t);return t}resolveInterceptors(e,t){let n=new Set,r=[];for(let i of e){if(n.has(i.identity)){t?.(`Duplicate HTTP request interceptor ignored: ${String(i.identity)}`);continue}n.add(i.identity),r.push(i)}return Object.freeze(r)}};const c={credentials:!0,headers:{}};var l=class{requestOptions;interceptorPipeline;asyncQueue;unauthorized;constructor(e={}){this.requestOptions=e.requestOptions??{},this.interceptorPipeline=e.interceptorPipeline??new s,this.asyncQueue=e.asyncQueue??new a,this.unauthorized=e.unauthorized}execute(e,t){return this.asyncQueue.execute(async()=>{let n=await this.makeRequestOptions(e,t);try{let t=this.createClient(n);return await e.execute(t)}catch(e){throw this.handleError(e)}})}handleError(t){return t instanceof o||t instanceof e.NetworkError||t instanceof e.TimeoutError||t instanceof e.CanceledError||t instanceof e.UnknownError?t:new e.UnknownError({message:t instanceof Error?t.message:void 0,cause:t})}async makeRequestOptions(e,t){let n=this.mergeRequestOptions(c,this.requestOptions);return n=await this.interceptorPipeline.intercept(n),n=this.mergeRequestOptions(n,e.options),n=this.mergeRequestOptions(n,t),n}mergeRequestOptions(e,t){return t?{credentials:t.credentials??e.credentials,headers:{...e.headers,...t.headers}}:e}};function u(e,t){if(typeof Reflect==`object`&&typeof Reflect.metadata==`function`)return Reflect.metadata(e,t)}function d(e,t){return function(n,r){t(n,r,e)}}function f(e,t,n,r){var i=arguments.length,a=i<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r,o;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)a=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(a=(i<3?o(a):i>3?o(t,n,a):o(t,n))||a);return i>3&&a&&Object.defineProperty(t,n,a),a}let p=class{endpoint;httpClient;constructor(e,t){this.endpoint=e,this.httpClient=t}async execute(e,t){let n=await this.convertOrThrow(()=>this.endpoint.convertInput(e)),r=this.endpoint.makeRequest(n),i=await this.httpClient.execute(r,t);return await this.convertOrThrow(()=>this.endpoint.convertOutput(i))}async convertOrThrow(t){try{return await t()}catch(t){throw new e.ConversionError({cause:t})}}};p=f([(0,t.injectable)(),d(0,(0,t.unmanaged)()),d(1,(0,t.unmanaged)()),u(`design:paramtypes`,[Object,Object])],p);let m=class extends p{constructor(e,t){super(e,t)}};m=f([(0,t.injectable)(),u(`design:paramtypes`,[Object,Object])],m);let h=class extends p{constructor(e,t){super(e,t)}async execute(t,n){try{return await super.execute(t,n)}catch(t){if(!(t instanceof o))throw t;let n=this.httpClient.unauthorized;throw!n||!n.statusCodes.includes(t.statusCode)?t:n.cancelAll?(await this.httpClient.asyncQueue.interrupt(()=>n.handler.handle(t)),new e.CanceledError({cause:t})):(await n.handler.handle(t),t)}}};h=f([(0,t.injectable)(),u(`design:paramtypes`,[Object,Object])],h);function g(){let t=(0,e.coreAssembly)(),r=n();return[...t,...r]}exports.AsyncQueueImpl=a,exports.HttpClient=l,exports.HttpError=o,exports.HttpRequestInterceptorPipeline=s,Object.defineProperty(exports,"PublicRemoteResource",{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,"RemoteResource",{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,"SecuredRemoteResource",{enumerable:!0,get:function(){return h}}),exports.WebKitL10nResource=i,exports.WebKitSymbols=r,exports.webkitAssembly=g,Object.keys(e).forEach(function(t){t!=="default"&&!Object.prototype.hasOwnProperty.call(exports,t)&&Object.defineProperty(exports,t,{enumerable:!0,get:function(){return e[t]}})});
@@ -1,6 +1,5 @@
1
1
  import "reflect-metadata";
2
- import { Assembly, AsyncOperation, Equatable, Hashable, Identity } from "@buildplease/core";
3
- import { AxiosRequestConfig } from "axios";
2
+ import { Assembly, AsyncOperation, Identity } from "@buildplease/core";
4
3
  export * from "@buildplease/core";
5
4
  //#region src/di/symbols.d.ts
6
5
  declare const WebKitSymbols: {
@@ -308,116 +307,225 @@ interface TablePaginationModel {
308
307
  pageSizeOptions?: number[];
309
308
  }
310
309
  //#endregion
311
- //#region src/networking/http-error.d.ts
312
- interface HttpErrorOptions {
310
+ //#region src/networking/async-queue.d.ts
311
+ /**
312
+ * Defines how queued operations are processed.
313
+ *
314
+ * `parallel` starts each operation immediately without waiting for previous operations to finish.
315
+ * `serial` starts an operation only after the previous operation has finished.
316
+ */
317
+ type AsyncQueueMode = 'parallel' | 'serial';
318
+ /**
319
+ * Executes and coordinates asynchronous operations.
320
+ */
321
+ interface AsyncQueue {
313
322
  /**
314
- * HTTP status code for the error response.
315
- * @example 404 // Not Found
316
- * @example 500 // Internal Server Error
323
+ * Executes an operation according to the configured queue mode.
324
+ * Operations submitted during an interruption are canceled without running.
317
325
  */
318
- statusCode: number;
326
+ execute<Output>(operation: () => Promise<Output>): Promise<Output>;
319
327
  /**
320
- * Machine‐readable error code for programmatic handling.
321
- * @example "UNAUTHORIZED"
322
- * @example "RESOURCE_NOT_FOUND"
328
+ * Cancels all unresolved operations. Pending serial operations are not started and results from
329
+ * already-running operations are ignored.
330
+ *
331
+ * @param cause Optional cancellation cause.
323
332
  */
324
- code: string;
333
+ cancelAll(cause?: unknown): void;
325
334
  /**
326
- * Human‐readable error description (localized or raw).
327
- * @example "Authentication required"
328
- * @example "User profile not found"
335
+ * Cancels all unresolved operations and executes one interruption handler.
336
+ * Concurrent interruptions wait for the same handler to complete.
329
337
  */
330
- message: string;
338
+ interrupt(handler: () => Promise<void>): Promise<void>;
339
+ }
340
+ declare class AsyncQueueImpl implements AsyncQueue {
341
+ private readonly mode;
342
+ private readonly pendingEntries;
343
+ private readonly activeEntries;
344
+ private interruption?;
345
+ private isSerialOperationRunning;
346
+ constructor(mode?: AsyncQueueMode);
347
+ execute<Output>(operation: () => Promise<Output>): Promise<Output>;
348
+ cancelAll(cause?: unknown): void;
349
+ interrupt(handler: () => Promise<void>): Promise<void>;
350
+ private createEntry;
351
+ private startEntry;
352
+ private startNextSerialOperation;
353
+ private cancelEntry;
354
+ private resolveEntry;
355
+ private rejectEntry;
356
+ }
357
+ //#endregion
358
+ //#region src/networking/http-request-options.d.ts
359
+ interface HttpRequestOptions {
331
360
  /**
332
- * Optional structured details for debugging.
333
- * Each key maps to an array of error messages for that field.
361
+ * Whether browser credentials such as cookies should be included with the request,
362
+ * including cross-origin requests.
334
363
  *
335
- * @example
336
- * {
337
- * "email": ["must be a valid email address"],
338
- * "password": ["required", "must be at least 8 characters"]
339
- * }
364
+ * @default true
340
365
  */
341
- details?: Record<string, string[]>;
366
+ readonly credentials?: boolean;
367
+ /**
368
+ * Headers included with the request.
369
+ *
370
+ * @default {}
371
+ */
372
+ readonly headers?: Readonly<Record<string, string>>;
342
373
  }
374
+ //#endregion
375
+ //#region src/networking/http-request.d.ts
376
+ interface HttpRequest<Client, Output> {
377
+ /**
378
+ * Executes the request using the configured client.
379
+ */
380
+ readonly execute: (client: Client) => Promise<Output>;
381
+ /**
382
+ * Options applied specifically to this request.
383
+ *
384
+ * @default undefined
385
+ */
386
+ readonly options?: HttpRequestOptions;
387
+ }
388
+ //#endregion
389
+ //#region src/networking/http-request-interceptor.d.ts
343
390
  /**
344
- * A specialized `Error` carrying an HTTP status code, machine‐readable code,
345
- * human‐readable message, and optional debug details.
346
- *
347
- * @example
348
- * // Basic usage
349
- * throw new HttpError({
350
- * statusCode: 404,
351
- * code: "NOT_FOUND",
352
- * message: "Resource not found"
353
- * });
354
- *
355
- * @example
356
- * // With structured debug details
357
- * throw new HttpError({
358
- * statusCode: 422,
359
- * code: "VALIDATION_ERROR",
360
- * message: "One or more fields are invalid",
361
- * details: {
362
- * "email": ["must be a valid email address"],
363
- * "password": ["required", "must be at least 8 characters"]
364
- * }
365
- * });
391
+ * Modifies HTTP request options before a request is executed.
366
392
  */
393
+ interface HttpRequestInterceptor {
394
+ /** Stable identity used to ignore duplicate interceptors. */
395
+ readonly identity: Identity;
396
+ /** Applies this interceptor to the current request options. */
397
+ intercept(options: HttpRequestOptions): HttpRequestOptions | Promise<HttpRequestOptions>;
398
+ }
399
+ declare class HttpRequestInterceptorPipeline {
400
+ private readonly interceptors;
401
+ constructor(interceptors?: readonly HttpRequestInterceptor[], onWarning?: (message: string) => void);
402
+ intercept(options: HttpRequestOptions): Promise<HttpRequestOptions>;
403
+ private resolveInterceptors;
404
+ }
405
+ //#endregion
406
+ //#region src/networking/http-error.d.ts
407
+ interface HttpErrorOptions {
408
+ /** HTTP status code. */
409
+ readonly statusCode: number;
410
+ /**
411
+ * Error code.
412
+ * @default undefined
413
+ * @example "not_found"
414
+ */
415
+ readonly code?: string;
416
+ /**
417
+ * Error message.
418
+ * @default undefined
419
+ * @example "Not found"
420
+ */
421
+ readonly message?: string;
422
+ /**
423
+ * Error details.
424
+ * @default undefined
425
+ */
426
+ readonly details?: unknown;
427
+ /**
428
+ * Original error.
429
+ * @default undefined
430
+ */
431
+ readonly cause?: unknown;
432
+ }
367
433
  declare class HttpError extends Error {
368
434
  readonly statusCode: HttpErrorOptions['statusCode'];
369
- readonly code: HttpErrorOptions['code'];
435
+ readonly code?: HttpErrorOptions['code'];
370
436
  readonly details?: HttpErrorOptions['details'];
371
437
  constructor(options: HttpErrorOptions);
372
438
  }
373
439
  //#endregion
374
- //#region src/networking/cookie-interceptor.d.ts
375
- declare class CookieInterceptor implements RemoteRequestInterceptor {
376
- order: number;
377
- hash(): Identity;
378
- equals(other: unknown): boolean;
379
- intercept(config: RemoteRequestConfig): RemoteRequestConfig;
440
+ //#region src/networking/unauthorized.d.ts
441
+ interface UnauthorizedHandler {
442
+ handle(error: HttpError): Promise<void>;
443
+ }
444
+ interface UnauthorizedOptions {
445
+ /** HTTP status codes that trigger unauthorized handling. */
446
+ readonly statusCodes: readonly number[];
447
+ /** Whether unauthorized handling cancels all unresolved requests sharing the same HTTP client. */
448
+ readonly cancelAll: boolean;
449
+ /** Application-specific unauthorized handler. */
450
+ readonly handler: UnauthorizedHandler;
451
+ }
452
+ //#endregion
453
+ //#region src/networking/http-client.d.ts
454
+ interface HttpClientOptions {
455
+ /**
456
+ * Default options applied to every request before interceptors and request-specific options.
457
+ *
458
+ * @default {}
459
+ */
460
+ readonly requestOptions?: HttpRequestOptions;
461
+ /**
462
+ * Interceptors applied to every request.
463
+ *
464
+ * @default Empty `HttpRequestInterceptorPipeline`
465
+ */
466
+ readonly interceptorPipeline?: HttpRequestInterceptorPipeline;
467
+ /**
468
+ * Queue used to execute requests.
469
+ *
470
+ * @default `AsyncQueueImpl` in `parallel` mode
471
+ */
472
+ readonly asyncQueue?: AsyncQueue;
473
+ /**
474
+ * Unauthorized handling for secured requests.
475
+ *
476
+ * @default undefined
477
+ */
478
+ readonly unauthorized?: UnauthorizedOptions;
479
+ }
480
+ declare abstract class HttpClient<Client> {
481
+ private readonly requestOptions;
482
+ private readonly interceptorPipeline;
483
+ readonly asyncQueue: AsyncQueue;
484
+ readonly unauthorized?: UnauthorizedOptions;
485
+ constructor(options?: HttpClientOptions);
486
+ execute<Output>(request: HttpRequest<Client, Output>, options?: HttpRequestOptions): Promise<Output>;
487
+ /** Creates the concrete client for the resolved request options. */
488
+ protected abstract createClient(options: HttpRequestOptions): Client;
489
+ /** Maps a transport-specific failure to a BuildPlease error. */
490
+ protected handleError(error: unknown): Error;
491
+ private makeRequestOptions;
492
+ private mergeRequestOptions;
380
493
  }
381
494
  //#endregion
382
495
  //#region src/networking/remote-endpoint.d.ts
383
- interface RemoteEndpoint<Input, InputDto, Output, OutputDto> {
384
- makeRequest(input: InputDto, options?: RemoteRequestConfig): Promise<OutputDto>;
496
+ /**
497
+ * Defines conversion and request creation for a remote operation.
498
+ */
499
+ interface RemoteEndpoint<Input, InputDto, Output, OutputDto, Client> {
500
+ /** Converts operation input to the request DTO. */
385
501
  convertInput(input: Input): Promise<InputDto>;
502
+ /** Creates the HTTP request for the converted input. */
503
+ makeRequest(input: InputDto): HttpRequest<Client, OutputDto>;
504
+ /** Converts the response DTO to the operation output. */
386
505
  convertOutput(response: OutputDto): Promise<Output>;
387
506
  }
388
507
  //#endregion
389
508
  //#region src/networking/remote-resource.d.ts
390
- declare abstract class BaseRemoteResource<Input, Output, Endpoint extends RemoteEndpoint<Input, unknown, Output, unknown>> implements AsyncOperation<Input, Output> {
391
- protected readonly endpoint: Endpoint;
392
- protected readonly interceptors: InterceptorSet;
393
- constructor(endpoint: Endpoint);
394
- protected use(...items: RemoteRequestInterceptor[]): this;
395
- protected removeInterceptor(item: RemoteRequestInterceptor): this;
396
- protected clearInterceptors(): this;
397
- execute(input: Input, options?: RemoteRequestConfig): Promise<Output>;
398
- protected parseError(error: unknown): Error;
399
- protected convertOrThrow<T>(fn: () => Promise<T>): Promise<T>;
400
- private isStringArrayRecord;
401
- private buildHttpErrorOptions;
509
+ declare abstract class RemoteResource<Input, Output, Client> implements AsyncOperation<Input, Output, HttpRequestOptions> {
510
+ protected readonly endpoint: RemoteEndpoint<Input, unknown, Output, unknown, Client>;
511
+ protected readonly httpClient: HttpClient<Client>;
512
+ protected constructor(endpoint: RemoteEndpoint<Input, unknown, Output, unknown, Client>, httpClient: HttpClient<Client>);
513
+ execute(input: Input, options?: HttpRequestOptions): Promise<Output>;
514
+ private convertOrThrow;
402
515
  }
403
516
  //#endregion
404
- //#region src/networking/remote-request-config.d.ts
405
- type RemoteRequestConfig = AxiosRequestConfig;
406
- //#endregion
407
- //#region src/networking/remote-request-interceptor.d.ts
408
- interface RemoteRequestInterceptor extends Equatable, Hashable {
409
- order: number;
410
- intercept(config: RemoteRequestConfig): RemoteRequestConfig;
517
+ //#region src/networking/public-remote-resource.d.ts
518
+ declare class PublicRemoteResource<Input, Output, Client> extends RemoteResource<Input, Output, Client> {
519
+ constructor(endpoint: RemoteEndpoint<Input, unknown, Output, unknown, Client>, httpClient: HttpClient<Client>);
411
520
  }
412
- declare class InterceptorSet {
413
- private map;
414
- add(...items: RemoteRequestInterceptor[]): this;
415
- remove(item: RemoteRequestInterceptor): this;
416
- clear(): this;
417
- list(): RemoteRequestInterceptor[];
521
+ //#endregion
522
+ //#region src/networking/secured-remote-resource.d.ts
523
+ declare class SecuredRemoteResource<Input, Output, Client> extends RemoteResource<Input, Output, Client> {
524
+ constructor(endpoint: RemoteEndpoint<Input, unknown, Output, unknown, Client>, httpClient: HttpClient<Client>);
525
+ execute(input: Input, options?: HttpRequestOptions): Promise<Output>;
418
526
  }
419
527
  //#endregion
420
528
  //#region src/index.d.ts
421
529
  declare function webkitAssembly(): Assembly[];
422
530
  //#endregion
423
- export { BaseRemoteResource, CookieInterceptor, HttpError, HttpErrorOptions, InterceptorSet, RemoteEndpoint, RemoteRequestConfig, RemoteRequestInterceptor, TableDataModel, TablePaginationModel, WebKitL10nResource, WebKitSymbols, webkitAssembly };
531
+ export { AsyncQueue, AsyncQueueImpl, AsyncQueueMode, HttpClient, HttpClientOptions, HttpError, HttpErrorOptions, HttpRequest, HttpRequestInterceptor, HttpRequestInterceptorPipeline, HttpRequestOptions, PublicRemoteResource, RemoteEndpoint, RemoteResource, SecuredRemoteResource, TableDataModel, TablePaginationModel, UnauthorizedHandler, UnauthorizedOptions, WebKitL10nResource, WebKitSymbols, webkitAssembly };
@@ -1,6 +1,5 @@
1
1
  import "reflect-metadata";
2
- import { Assembly, AsyncOperation, Equatable, Hashable, Identity } from "@buildplease/core";
3
- import { AxiosRequestConfig } from "axios";
2
+ import { Assembly, AsyncOperation, Identity } from "@buildplease/core";
4
3
  export * from "@buildplease/core";
5
4
  //#region src/di/symbols.d.ts
6
5
  declare const WebKitSymbols: {
@@ -308,116 +307,225 @@ interface TablePaginationModel {
308
307
  pageSizeOptions?: number[];
309
308
  }
310
309
  //#endregion
311
- //#region src/networking/http-error.d.ts
312
- interface HttpErrorOptions {
310
+ //#region src/networking/async-queue.d.ts
311
+ /**
312
+ * Defines how queued operations are processed.
313
+ *
314
+ * `parallel` starts each operation immediately without waiting for previous operations to finish.
315
+ * `serial` starts an operation only after the previous operation has finished.
316
+ */
317
+ type AsyncQueueMode = 'parallel' | 'serial';
318
+ /**
319
+ * Executes and coordinates asynchronous operations.
320
+ */
321
+ interface AsyncQueue {
313
322
  /**
314
- * HTTP status code for the error response.
315
- * @example 404 // Not Found
316
- * @example 500 // Internal Server Error
323
+ * Executes an operation according to the configured queue mode.
324
+ * Operations submitted during an interruption are canceled without running.
317
325
  */
318
- statusCode: number;
326
+ execute<Output>(operation: () => Promise<Output>): Promise<Output>;
319
327
  /**
320
- * Machine‐readable error code for programmatic handling.
321
- * @example "UNAUTHORIZED"
322
- * @example "RESOURCE_NOT_FOUND"
328
+ * Cancels all unresolved operations. Pending serial operations are not started and results from
329
+ * already-running operations are ignored.
330
+ *
331
+ * @param cause Optional cancellation cause.
323
332
  */
324
- code: string;
333
+ cancelAll(cause?: unknown): void;
325
334
  /**
326
- * Human‐readable error description (localized or raw).
327
- * @example "Authentication required"
328
- * @example "User profile not found"
335
+ * Cancels all unresolved operations and executes one interruption handler.
336
+ * Concurrent interruptions wait for the same handler to complete.
329
337
  */
330
- message: string;
338
+ interrupt(handler: () => Promise<void>): Promise<void>;
339
+ }
340
+ declare class AsyncQueueImpl implements AsyncQueue {
341
+ private readonly mode;
342
+ private readonly pendingEntries;
343
+ private readonly activeEntries;
344
+ private interruption?;
345
+ private isSerialOperationRunning;
346
+ constructor(mode?: AsyncQueueMode);
347
+ execute<Output>(operation: () => Promise<Output>): Promise<Output>;
348
+ cancelAll(cause?: unknown): void;
349
+ interrupt(handler: () => Promise<void>): Promise<void>;
350
+ private createEntry;
351
+ private startEntry;
352
+ private startNextSerialOperation;
353
+ private cancelEntry;
354
+ private resolveEntry;
355
+ private rejectEntry;
356
+ }
357
+ //#endregion
358
+ //#region src/networking/http-request-options.d.ts
359
+ interface HttpRequestOptions {
331
360
  /**
332
- * Optional structured details for debugging.
333
- * Each key maps to an array of error messages for that field.
361
+ * Whether browser credentials such as cookies should be included with the request,
362
+ * including cross-origin requests.
334
363
  *
335
- * @example
336
- * {
337
- * "email": ["must be a valid email address"],
338
- * "password": ["required", "must be at least 8 characters"]
339
- * }
364
+ * @default true
340
365
  */
341
- details?: Record<string, string[]>;
366
+ readonly credentials?: boolean;
367
+ /**
368
+ * Headers included with the request.
369
+ *
370
+ * @default {}
371
+ */
372
+ readonly headers?: Readonly<Record<string, string>>;
342
373
  }
374
+ //#endregion
375
+ //#region src/networking/http-request.d.ts
376
+ interface HttpRequest<Client, Output> {
377
+ /**
378
+ * Executes the request using the configured client.
379
+ */
380
+ readonly execute: (client: Client) => Promise<Output>;
381
+ /**
382
+ * Options applied specifically to this request.
383
+ *
384
+ * @default undefined
385
+ */
386
+ readonly options?: HttpRequestOptions;
387
+ }
388
+ //#endregion
389
+ //#region src/networking/http-request-interceptor.d.ts
343
390
  /**
344
- * A specialized `Error` carrying an HTTP status code, machine‐readable code,
345
- * human‐readable message, and optional debug details.
346
- *
347
- * @example
348
- * // Basic usage
349
- * throw new HttpError({
350
- * statusCode: 404,
351
- * code: "NOT_FOUND",
352
- * message: "Resource not found"
353
- * });
354
- *
355
- * @example
356
- * // With structured debug details
357
- * throw new HttpError({
358
- * statusCode: 422,
359
- * code: "VALIDATION_ERROR",
360
- * message: "One or more fields are invalid",
361
- * details: {
362
- * "email": ["must be a valid email address"],
363
- * "password": ["required", "must be at least 8 characters"]
364
- * }
365
- * });
391
+ * Modifies HTTP request options before a request is executed.
366
392
  */
393
+ interface HttpRequestInterceptor {
394
+ /** Stable identity used to ignore duplicate interceptors. */
395
+ readonly identity: Identity;
396
+ /** Applies this interceptor to the current request options. */
397
+ intercept(options: HttpRequestOptions): HttpRequestOptions | Promise<HttpRequestOptions>;
398
+ }
399
+ declare class HttpRequestInterceptorPipeline {
400
+ private readonly interceptors;
401
+ constructor(interceptors?: readonly HttpRequestInterceptor[], onWarning?: (message: string) => void);
402
+ intercept(options: HttpRequestOptions): Promise<HttpRequestOptions>;
403
+ private resolveInterceptors;
404
+ }
405
+ //#endregion
406
+ //#region src/networking/http-error.d.ts
407
+ interface HttpErrorOptions {
408
+ /** HTTP status code. */
409
+ readonly statusCode: number;
410
+ /**
411
+ * Error code.
412
+ * @default undefined
413
+ * @example "not_found"
414
+ */
415
+ readonly code?: string;
416
+ /**
417
+ * Error message.
418
+ * @default undefined
419
+ * @example "Not found"
420
+ */
421
+ readonly message?: string;
422
+ /**
423
+ * Error details.
424
+ * @default undefined
425
+ */
426
+ readonly details?: unknown;
427
+ /**
428
+ * Original error.
429
+ * @default undefined
430
+ */
431
+ readonly cause?: unknown;
432
+ }
367
433
  declare class HttpError extends Error {
368
434
  readonly statusCode: HttpErrorOptions['statusCode'];
369
- readonly code: HttpErrorOptions['code'];
435
+ readonly code?: HttpErrorOptions['code'];
370
436
  readonly details?: HttpErrorOptions['details'];
371
437
  constructor(options: HttpErrorOptions);
372
438
  }
373
439
  //#endregion
374
- //#region src/networking/cookie-interceptor.d.ts
375
- declare class CookieInterceptor implements RemoteRequestInterceptor {
376
- order: number;
377
- hash(): Identity;
378
- equals(other: unknown): boolean;
379
- intercept(config: RemoteRequestConfig): RemoteRequestConfig;
440
+ //#region src/networking/unauthorized.d.ts
441
+ interface UnauthorizedHandler {
442
+ handle(error: HttpError): Promise<void>;
443
+ }
444
+ interface UnauthorizedOptions {
445
+ /** HTTP status codes that trigger unauthorized handling. */
446
+ readonly statusCodes: readonly number[];
447
+ /** Whether unauthorized handling cancels all unresolved requests sharing the same HTTP client. */
448
+ readonly cancelAll: boolean;
449
+ /** Application-specific unauthorized handler. */
450
+ readonly handler: UnauthorizedHandler;
451
+ }
452
+ //#endregion
453
+ //#region src/networking/http-client.d.ts
454
+ interface HttpClientOptions {
455
+ /**
456
+ * Default options applied to every request before interceptors and request-specific options.
457
+ *
458
+ * @default {}
459
+ */
460
+ readonly requestOptions?: HttpRequestOptions;
461
+ /**
462
+ * Interceptors applied to every request.
463
+ *
464
+ * @default Empty `HttpRequestInterceptorPipeline`
465
+ */
466
+ readonly interceptorPipeline?: HttpRequestInterceptorPipeline;
467
+ /**
468
+ * Queue used to execute requests.
469
+ *
470
+ * @default `AsyncQueueImpl` in `parallel` mode
471
+ */
472
+ readonly asyncQueue?: AsyncQueue;
473
+ /**
474
+ * Unauthorized handling for secured requests.
475
+ *
476
+ * @default undefined
477
+ */
478
+ readonly unauthorized?: UnauthorizedOptions;
479
+ }
480
+ declare abstract class HttpClient<Client> {
481
+ private readonly requestOptions;
482
+ private readonly interceptorPipeline;
483
+ readonly asyncQueue: AsyncQueue;
484
+ readonly unauthorized?: UnauthorizedOptions;
485
+ constructor(options?: HttpClientOptions);
486
+ execute<Output>(request: HttpRequest<Client, Output>, options?: HttpRequestOptions): Promise<Output>;
487
+ /** Creates the concrete client for the resolved request options. */
488
+ protected abstract createClient(options: HttpRequestOptions): Client;
489
+ /** Maps a transport-specific failure to a BuildPlease error. */
490
+ protected handleError(error: unknown): Error;
491
+ private makeRequestOptions;
492
+ private mergeRequestOptions;
380
493
  }
381
494
  //#endregion
382
495
  //#region src/networking/remote-endpoint.d.ts
383
- interface RemoteEndpoint<Input, InputDto, Output, OutputDto> {
384
- makeRequest(input: InputDto, options?: RemoteRequestConfig): Promise<OutputDto>;
496
+ /**
497
+ * Defines conversion and request creation for a remote operation.
498
+ */
499
+ interface RemoteEndpoint<Input, InputDto, Output, OutputDto, Client> {
500
+ /** Converts operation input to the request DTO. */
385
501
  convertInput(input: Input): Promise<InputDto>;
502
+ /** Creates the HTTP request for the converted input. */
503
+ makeRequest(input: InputDto): HttpRequest<Client, OutputDto>;
504
+ /** Converts the response DTO to the operation output. */
386
505
  convertOutput(response: OutputDto): Promise<Output>;
387
506
  }
388
507
  //#endregion
389
508
  //#region src/networking/remote-resource.d.ts
390
- declare abstract class BaseRemoteResource<Input, Output, Endpoint extends RemoteEndpoint<Input, unknown, Output, unknown>> implements AsyncOperation<Input, Output> {
391
- protected readonly endpoint: Endpoint;
392
- protected readonly interceptors: InterceptorSet;
393
- constructor(endpoint: Endpoint);
394
- protected use(...items: RemoteRequestInterceptor[]): this;
395
- protected removeInterceptor(item: RemoteRequestInterceptor): this;
396
- protected clearInterceptors(): this;
397
- execute(input: Input, options?: RemoteRequestConfig): Promise<Output>;
398
- protected parseError(error: unknown): Error;
399
- protected convertOrThrow<T>(fn: () => Promise<T>): Promise<T>;
400
- private isStringArrayRecord;
401
- private buildHttpErrorOptions;
509
+ declare abstract class RemoteResource<Input, Output, Client> implements AsyncOperation<Input, Output, HttpRequestOptions> {
510
+ protected readonly endpoint: RemoteEndpoint<Input, unknown, Output, unknown, Client>;
511
+ protected readonly httpClient: HttpClient<Client>;
512
+ protected constructor(endpoint: RemoteEndpoint<Input, unknown, Output, unknown, Client>, httpClient: HttpClient<Client>);
513
+ execute(input: Input, options?: HttpRequestOptions): Promise<Output>;
514
+ private convertOrThrow;
402
515
  }
403
516
  //#endregion
404
- //#region src/networking/remote-request-config.d.ts
405
- type RemoteRequestConfig = AxiosRequestConfig;
406
- //#endregion
407
- //#region src/networking/remote-request-interceptor.d.ts
408
- interface RemoteRequestInterceptor extends Equatable, Hashable {
409
- order: number;
410
- intercept(config: RemoteRequestConfig): RemoteRequestConfig;
517
+ //#region src/networking/public-remote-resource.d.ts
518
+ declare class PublicRemoteResource<Input, Output, Client> extends RemoteResource<Input, Output, Client> {
519
+ constructor(endpoint: RemoteEndpoint<Input, unknown, Output, unknown, Client>, httpClient: HttpClient<Client>);
411
520
  }
412
- declare class InterceptorSet {
413
- private map;
414
- add(...items: RemoteRequestInterceptor[]): this;
415
- remove(item: RemoteRequestInterceptor): this;
416
- clear(): this;
417
- list(): RemoteRequestInterceptor[];
521
+ //#endregion
522
+ //#region src/networking/secured-remote-resource.d.ts
523
+ declare class SecuredRemoteResource<Input, Output, Client> extends RemoteResource<Input, Output, Client> {
524
+ constructor(endpoint: RemoteEndpoint<Input, unknown, Output, unknown, Client>, httpClient: HttpClient<Client>);
525
+ execute(input: Input, options?: HttpRequestOptions): Promise<Output>;
418
526
  }
419
527
  //#endregion
420
528
  //#region src/index.d.ts
421
529
  declare function webkitAssembly(): Assembly[];
422
530
  //#endregion
423
- export { BaseRemoteResource, CookieInterceptor, HttpError, HttpErrorOptions, InterceptorSet, RemoteEndpoint, RemoteRequestConfig, RemoteRequestInterceptor, TableDataModel, TablePaginationModel, WebKitL10nResource, WebKitSymbols, webkitAssembly };
531
+ export { AsyncQueue, AsyncQueueImpl, AsyncQueueMode, HttpClient, HttpClientOptions, HttpError, HttpErrorOptions, HttpRequest, HttpRequestInterceptor, HttpRequestInterceptorPipeline, HttpRequestOptions, PublicRemoteResource, RemoteEndpoint, RemoteResource, SecuredRemoteResource, TableDataModel, TablePaginationModel, UnauthorizedHandler, UnauthorizedOptions, WebKitL10nResource, WebKitSymbols, webkitAssembly };
package/dist/src/index.js CHANGED
@@ -1 +1 @@
1
- import"reflect-metadata";import{CanceledError as e,ConversionError as t,CoreL10nResource as n,NetworkError as r,TimeoutError as i,UnknownError as a,coreAssembly as o,ignoreError as s,isDefinedAndNotNull as c,isNonEmptyString as l,isPlainObject as u}from"@buildplease/core";import d from"axios";import{injectable as f,unmanaged as p}from"inversify";export*from"@buildplease/core";function m(){return[]}const h={name:`buildplease`,displayName:`BuildPlease`,scope:`@buildplease`};`${h.name}`;const g={DI:{}},_=n;var v=class extends Error{statusCode;code;details;constructor(e){super(e.message),this.name=`HttpError`,this.statusCode=e.statusCode,this.code=e.code,this.details=e.details}},y=class e{order=-10;hash(){return Symbol.for(`${h.scope}.webkit.networking.interceptor.cookie`)}equals(t){return t instanceof e}intercept(e){return{...e,withCredentials:!0}}};function b(e,t){if(typeof Reflect==`object`&&typeof Reflect.metadata==`function`)return Reflect.metadata(e,t)}function x(e,t){return function(n,r){t(n,r,e)}}function S(e,t,n,r){var i=arguments.length,a=i<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r,o;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)a=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(a=(i<3?o(a):i>3?o(t,n,a):o(t,n))||a);return i>3&&a&&Object.defineProperty(t,n,a),a}const C=`Unknown Error`;let w=class{endpoint;interceptors=new T;constructor(e){this.endpoint=e,this.use(new y)}use(...e){return this.interceptors.add(...e),this}removeInterceptor(e){return this.interceptors.remove(e),this}clearInterceptors(){return this.interceptors.clear(),this}async execute(e,t){try{let n=await this.convertOrThrow(()=>this.endpoint.convertInput(e)),r={...t};for(let e of this.interceptors.list())r=e.intercept(r);let i=await this.endpoint.makeRequest(n,r);return await this.convertOrThrow(()=>this.endpoint.convertOutput(i))}catch(e){throw this.parseError(e)}}parseError(n){if(n instanceof v||n instanceof i||n instanceof r||n instanceof e||n instanceof t||n instanceof a)return n;if(d.isCancel?.(n)||d.isAxiosError(n)&&(n.code===`ERR_CANCELED`||n.message===`canceled`))return new e({cause:n});if(d.isAxiosError(n)&&n.code===`ECONNABORTED`)return new i({cause:n});if(d.isAxiosError(n)&&!n.response)return new r({message:n.message,cause:n});if(d.isAxiosError(n)&&n.response){let{status:e,data:t}=n.response,r=t;typeof r==`string`&&(r=s(()=>JSON.parse(r)).orDefault(r));let i=this.isStringArrayRecord(r.details)?r.details:void 0;return new v(this.buildHttpErrorOptions(e,r,i))}let o=n instanceof Error?n.message:C;return new a({message:o,cause:n})}async convertOrThrow(e){try{return await e()}catch(e){throw new t({cause:e})}}isStringArrayRecord(e){return!c(e)||!u(e)?!1:Object.values(e).every(e=>Array.isArray(e)&&e.every(e=>typeof e==`string`))}buildHttpErrorOptions(e,t,n){return{statusCode:e,code:l(t?.code)?t.code:`UNKNOWN_ERROR`,message:l(t?.message)?t.message:C,details:n}}};w=S([f(),x(0,p()),b(`design:paramtypes`,[Object])],w);var T=class{map=new Map;add(...e){for(let t of e){let e=t.hash(),n=this.map.get(e);n&&n.equals(t)||this.map.set(e,t)}return this}remove(e){return this.map.delete(e.hash()),this}clear(){return this.map.clear(),this}list(){return[...this.map.values()].sort((e,t)=>e.order-t.order)}};function E(){let e=o(),t=m();return[...e,...t]}export{w as BaseRemoteResource,y as CookieInterceptor,v as HttpError,T as InterceptorSet,_ as WebKitL10nResource,g as WebKitSymbols,E as webkitAssembly};
1
+ import"reflect-metadata";import{CanceledError as e,ConversionError as t,CoreL10nResource as n,NetworkError as r,TimeoutError as i,UnknownError as a,coreAssembly as o}from"@buildplease/core";import{injectable as s,unmanaged as c}from"inversify";export*from"@buildplease/core";function l(){return[]}`${{name:`buildplease`,displayName:`BuildPlease`,scope:`@buildplease`}.name}`;const u={DI:{}},d=n;var f=class{mode;pendingEntries=[];activeEntries=new Set;interruption;isSerialOperationRunning=!1;constructor(e=`parallel`){this.mode=e}execute(t){if(this.interruption)return Promise.reject(new e);let n=this.createEntry(t);return this.mode===`serial`?(this.pendingEntries.push(n),this.startNextSerialOperation()):this.startEntry(n),n.promise}cancelAll(e){let t=this.pendingEntries.splice(0);for(let n of t)this.cancelEntry(n,e);for(let t of this.activeEntries)this.cancelEntry(t,e)}async interrupt(e){if(!this.interruption){let t=Promise.resolve().then(e).finally(()=>{this.interruption===t&&(this.interruption=void 0,this.startNextSerialOperation())});this.interruption=t,this.cancelAll()}await this.interruption}createEntry(e){let t,n;return{operation:e,promise:new Promise((e,r)=>{t=e,n=r}),resolve:e=>t?.(e),reject:e=>n?.(e),canceled:!1,settled:!1}}startEntry(e){if(e.canceled||this.interruption){this.cancelEntry(e);return}this.activeEntries.add(e),this.mode===`serial`&&(this.isSerialOperationRunning=!0),Promise.resolve().then(e.operation).then(t=>{e.canceled||this.resolveEntry(e,t)},t=>{e.canceled||this.rejectEntry(e,t)}).finally(()=>{this.activeEntries.delete(e),this.mode===`serial`&&(this.isSerialOperationRunning=!1,this.startNextSerialOperation())})}startNextSerialOperation(){if(this.mode!==`serial`||this.isSerialOperationRunning||this.interruption)return;let e=this.pendingEntries.shift();e&&this.startEntry(e)}cancelEntry(t,n){t.canceled||(t.canceled=!0,t.settled||this.rejectEntry(t,new e({cause:n})))}resolveEntry(e,t){e.settled||(e.settled=!0,e.resolve(t))}rejectEntry(e,t){e.settled||(e.settled=!0,e.reject(t))}},p=class extends Error{statusCode;code;details;constructor(e){super(e.message),this.name=`HttpError`,this.statusCode=e.statusCode,this.code=e.code,this.details=e.details,e.cause!==void 0&&(this.cause=e.cause)}},m=class{interceptors;constructor(e=[],t){this.interceptors=this.resolveInterceptors(e,t)}async intercept(e){let t=e;for(let e of this.interceptors)t=await e.intercept(t);return t}resolveInterceptors(e,t){let n=new Set,r=[];for(let i of e){if(n.has(i.identity)){t?.(`Duplicate HTTP request interceptor ignored: ${String(i.identity)}`);continue}n.add(i.identity),r.push(i)}return Object.freeze(r)}};const h={credentials:!0,headers:{}};var g=class{requestOptions;interceptorPipeline;asyncQueue;unauthorized;constructor(e={}){this.requestOptions=e.requestOptions??{},this.interceptorPipeline=e.interceptorPipeline??new m,this.asyncQueue=e.asyncQueue??new f,this.unauthorized=e.unauthorized}execute(e,t){return this.asyncQueue.execute(async()=>{let n=await this.makeRequestOptions(e,t);try{let t=this.createClient(n);return await e.execute(t)}catch(e){throw this.handleError(e)}})}handleError(t){return t instanceof p||t instanceof r||t instanceof i||t instanceof e||t instanceof a?t:new a({message:t instanceof Error?t.message:void 0,cause:t})}async makeRequestOptions(e,t){let n=this.mergeRequestOptions(h,this.requestOptions);return n=await this.interceptorPipeline.intercept(n),n=this.mergeRequestOptions(n,e.options),n=this.mergeRequestOptions(n,t),n}mergeRequestOptions(e,t){return t?{credentials:t.credentials??e.credentials,headers:{...e.headers,...t.headers}}:e}};function _(e,t){if(typeof Reflect==`object`&&typeof Reflect.metadata==`function`)return Reflect.metadata(e,t)}function v(e,t){return function(n,r){t(n,r,e)}}function y(e,t,n,r){var i=arguments.length,a=i<3?t:r===null?r=Object.getOwnPropertyDescriptor(t,n):r,o;if(typeof Reflect==`object`&&typeof Reflect.decorate==`function`)a=Reflect.decorate(e,t,n,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(a=(i<3?o(a):i>3?o(t,n,a):o(t,n))||a);return i>3&&a&&Object.defineProperty(t,n,a),a}let b=class{endpoint;httpClient;constructor(e,t){this.endpoint=e,this.httpClient=t}async execute(e,t){let n=await this.convertOrThrow(()=>this.endpoint.convertInput(e)),r=this.endpoint.makeRequest(n),i=await this.httpClient.execute(r,t);return await this.convertOrThrow(()=>this.endpoint.convertOutput(i))}async convertOrThrow(e){try{return await e()}catch(e){throw new t({cause:e})}}};b=y([s(),v(0,c()),v(1,c()),_(`design:paramtypes`,[Object,Object])],b);let x=class extends b{constructor(e,t){super(e,t)}};x=y([s(),_(`design:paramtypes`,[Object,Object])],x);let S=class extends b{constructor(e,t){super(e,t)}async execute(t,n){try{return await super.execute(t,n)}catch(t){if(!(t instanceof p))throw t;let n=this.httpClient.unauthorized;throw!n||!n.statusCodes.includes(t.statusCode)?t:n.cancelAll?(await this.httpClient.asyncQueue.interrupt(()=>n.handler.handle(t)),new e({cause:t})):(await n.handler.handle(t),t)}}};S=y([s(),_(`design:paramtypes`,[Object,Object])],S);function C(){let e=o(),t=l();return[...e,...t]}export{f as AsyncQueueImpl,g as HttpClient,p as HttpError,m as HttpRequestInterceptorPipeline,x as PublicRemoteResource,b as RemoteResource,S as SecuredRemoteResource,d as WebKitL10nResource,u as WebKitSymbols,C as webkitAssembly};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buildplease/webkit",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "keywords": [],
5
5
  "repository": {
6
6
  "type": "git",
@@ -37,8 +37,7 @@
37
37
  "resources"
38
38
  ],
39
39
  "dependencies": {
40
- "axios": "1.19.0",
41
- "@buildplease/core": "1.0.1"
40
+ "@buildplease/core": "1.0.2"
42
41
  },
43
42
  "devDependencies": {
44
43
  "@buildplease/identity": "1.0.0"