shelving 1.184.1 → 1.185.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/api/provider/APIProvider.d.ts +3 -1
- package/api/provider/APIProvider.js +6 -0
- package/api/provider/ClientAPIProvider.d.ts +23 -15
- package/api/provider/ClientAPIProvider.js +15 -6
- package/api/provider/DebugAPIProvider.d.ts +1 -1
- package/api/provider/DebugAPIProvider.js +27 -5
- package/api/provider/MockAPIProvider.d.ts +15 -5
- package/api/provider/MockAPIProvider.js +19 -7
- package/api/provider/MockEndpointAPIProvider.js +1 -1
- package/api/provider/ThroughAPIProvider.d.ts +3 -3
- package/api/provider/ThroughAPIProvider.js +5 -3
- package/api/provider/ValidationAPIProvider.d.ts +2 -1
- package/api/provider/ValidationAPIProvider.js +12 -15
- package/api/provider/XMLAPIProvider.d.ts +1 -1
- package/api/store/EndpointStore.js +1 -1
- package/db/collection/Collection.d.ts +1 -0
- package/db/collection/Collection.js +3 -0
- package/package.json +1 -1
- package/util/debug.d.ts +19 -0
- package/util/debug.js +43 -0
|
@@ -34,6 +34,8 @@ export declare abstract class APIProvider<P = unknown, R = unknown> {
|
|
|
34
34
|
* @throws {RequiredError} if this is a `HEAD` or `GET` request but `payload` is not a data object.
|
|
35
35
|
*/
|
|
36
36
|
abstract getRequest<PP extends P, RR extends R>(endpoint: Endpoint<PP, RR>, payload: PP, options?: RequestOptions, caller?: AnyCaller): Request;
|
|
37
|
+
/** Fetch a `Resource` using this provider (defaults to Javascript `fetch()` API). */
|
|
38
|
+
abstract fetch(request: Request): Promise<Response>;
|
|
37
39
|
/**
|
|
38
40
|
* Parse an HTTP `Response` for this endpoint.
|
|
39
41
|
* - Non-2xx responses become `ResponseError`.
|
|
@@ -41,5 +43,5 @@ export declare abstract class APIProvider<P = unknown, R = unknown> {
|
|
|
41
43
|
*/
|
|
42
44
|
abstract parseResponse<PP extends P, RR extends R>(_endpoint: Endpoint<PP, RR>, response: Response, caller?: AnyCaller): Promise<RR>;
|
|
43
45
|
/** Send a payload to an `Endpoint` and retrieve the result. */
|
|
44
|
-
|
|
46
|
+
call<PP extends P, RR extends R>(endpoint: Endpoint<PP, RR>, payload: PP, options?: RequestOptions, caller?: AnyCaller): Promise<RR>;
|
|
45
47
|
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
/** Provider for API endpoints rooted at a common base URL. */
|
|
2
2
|
export class APIProvider {
|
|
3
|
+
/** Send a payload to an `Endpoint` and retrieve the result. */
|
|
4
|
+
async call(endpoint, payload, options, caller) {
|
|
5
|
+
const request = this.getRequest(endpoint, payload, options, caller);
|
|
6
|
+
const response = await this.fetch(request);
|
|
7
|
+
return this.parseResponse(endpoint, response, caller);
|
|
8
|
+
}
|
|
3
9
|
}
|
|
@@ -4,8 +4,28 @@ import type { Nullish } from "../../util/null.js";
|
|
|
4
4
|
import { type PossibleURIParams } from "../../util/uri.js";
|
|
5
5
|
import { type PossibleURL, type URL, type URLString } from "../../util/url.js";
|
|
6
6
|
import type { Endpoint } from "../endpoint/Endpoint.js";
|
|
7
|
-
import
|
|
8
|
-
|
|
7
|
+
import { APIProvider } from "./APIProvider.js";
|
|
8
|
+
/** Options for a `ClientAPIProvider`. */
|
|
9
|
+
export interface ClientAPIProviderOptions {
|
|
10
|
+
/** The common base URL for all rendered endpoint requests. */
|
|
11
|
+
readonly url: PossibleURL;
|
|
12
|
+
/**
|
|
13
|
+
* Options used for HTTP requests created with `this.getRequest()` and `this.fetch()`
|
|
14
|
+
* - Omits `signal` because it's not relevant at the provider level.
|
|
15
|
+
*/
|
|
16
|
+
readonly options?: Omit<RequestOptions, "signal">;
|
|
17
|
+
/** Timeout in milliseconds, or `undefined` for no timeout. */
|
|
18
|
+
readonly timeout?: number | undefined;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A client-side API provider that sends requests over the network using `fetch()`.
|
|
22
|
+
* - Can be used on a server environment to make outgoing API calls, or in a browser environment to call a server API.
|
|
23
|
+
* - Renders endpoint paths and query params into the URL and sends body payloads as JSON.
|
|
24
|
+
* - Parses JSON responses and throws `ResponseError` for non-2xx responses.
|
|
25
|
+
* - Extendable with custom request-building and response-parsing logic by overriding `getRequest()` and `parseResponse()`.
|
|
26
|
+
* - Wrap in `ValidationAPIProvider` to add automatic validation of request payloads and response results against endpoint schemas.
|
|
27
|
+
*/
|
|
28
|
+
export declare class ClientAPIProvider<P = unknown, R = unknown> extends APIProvider<P, R> {
|
|
9
29
|
/** The common base URL for all rendered endpoint requests. */
|
|
10
30
|
readonly url: URLString;
|
|
11
31
|
/** Default options used for HTTP requests created with `this.getRequest()` and `this.fetch()` */
|
|
@@ -21,18 +41,6 @@ export declare class ClientAPIProvider<P = unknown, R = unknown> implements APIP
|
|
|
21
41
|
/** Internal implementation function for `getRequest()` used for requests that have a body. */
|
|
22
42
|
protected _getBodyRequest(method: RequestBodyMethod, //
|
|
23
43
|
url: PossibleURL, payload: P, options: RequestOptions, caller: AnyCaller): Request;
|
|
44
|
+
fetch(request: Request): Promise<Response>;
|
|
24
45
|
parseResponse<PP extends P, RR extends R>(_endpoint: Endpoint<PP, RR>, response: Response, caller?: AnyCaller): Promise<RR>;
|
|
25
|
-
fetch<PP extends P, RR extends R>(endpoint: Endpoint<PP, RR>, payload: PP, options?: RequestOptions, caller?: AnyCaller): Promise<RR>;
|
|
26
|
-
}
|
|
27
|
-
/** Options for an `APIProvider`. */
|
|
28
|
-
export interface ClientAPIProviderOptions {
|
|
29
|
-
/** The common base URL for all rendered endpoint requests. */
|
|
30
|
-
readonly url: PossibleURL;
|
|
31
|
-
/**
|
|
32
|
-
* Options used for HTTP requests created with `this.getRequest()` and `this.fetch()`
|
|
33
|
-
* - Omits `signal` because it's not relevant at the provider level.
|
|
34
|
-
*/
|
|
35
|
-
readonly options?: Omit<RequestOptions, "signal">;
|
|
36
|
-
/** Timeout in milliseconds, or `undefined` for no timeout. */
|
|
37
|
-
readonly timeout?: number | undefined;
|
|
38
46
|
}
|
|
@@ -5,7 +5,16 @@ import { assertRequestHeadPayload, getHeadRequest, getRequest, isRequestHeadMeth
|
|
|
5
5
|
import { omitProps } from "../../util/object.js";
|
|
6
6
|
import { withURIParams } from "../../util/uri.js";
|
|
7
7
|
import { requireBaseURL, requireURL } from "../../util/url.js";
|
|
8
|
-
|
|
8
|
+
import { APIProvider } from "./APIProvider.js";
|
|
9
|
+
/**
|
|
10
|
+
* A client-side API provider that sends requests over the network using `fetch()`.
|
|
11
|
+
* - Can be used on a server environment to make outgoing API calls, or in a browser environment to call a server API.
|
|
12
|
+
* - Renders endpoint paths and query params into the URL and sends body payloads as JSON.
|
|
13
|
+
* - Parses JSON responses and throws `ResponseError` for non-2xx responses.
|
|
14
|
+
* - Extendable with custom request-building and response-parsing logic by overriding `getRequest()` and `parseResponse()`.
|
|
15
|
+
* - Wrap in `ValidationAPIProvider` to add automatic validation of request payloads and response results against endpoint schemas.
|
|
16
|
+
*/
|
|
17
|
+
export class ClientAPIProvider extends APIProvider {
|
|
9
18
|
/** The common base URL for all rendered endpoint requests. */
|
|
10
19
|
url;
|
|
11
20
|
/** Default options used for HTTP requests created with `this.getRequest()` and `this.fetch()` */
|
|
@@ -13,6 +22,7 @@ export class ClientAPIProvider {
|
|
|
13
22
|
/** Timeout in milliseconds, or `undefined` for no timeout. */
|
|
14
23
|
timeout;
|
|
15
24
|
constructor({ url, options = {}, timeout }) {
|
|
25
|
+
super();
|
|
16
26
|
this.url = requireBaseURL(url, undefined, ClientAPIProvider);
|
|
17
27
|
this.options = options;
|
|
18
28
|
this.timeout = timeout;
|
|
@@ -53,6 +63,10 @@ export class ClientAPIProvider {
|
|
|
53
63
|
url, payload, options, caller) {
|
|
54
64
|
return getRequest(method, url, payload, options, caller);
|
|
55
65
|
}
|
|
66
|
+
// Override to set default functionality of a client provider to send requests over the network with `fetch()` and parse responses with `parseResponse()`.
|
|
67
|
+
async fetch(request) {
|
|
68
|
+
return fetch(request);
|
|
69
|
+
}
|
|
56
70
|
async parseResponse(_endpoint, response, caller = this.parseResponse) {
|
|
57
71
|
const { ok, status } = response;
|
|
58
72
|
const content = await parseResponseBody(response, caller);
|
|
@@ -60,9 +74,4 @@ export class ClientAPIProvider {
|
|
|
60
74
|
throw new ResponseError(getMessage(content) ?? `Error ${status}`, { code: status, cause: response, caller });
|
|
61
75
|
return content;
|
|
62
76
|
}
|
|
63
|
-
async fetch(endpoint, payload, options, caller = this.fetch) {
|
|
64
|
-
const request = this.getRequest(endpoint, payload, options, caller);
|
|
65
|
-
const response = await fetch(request);
|
|
66
|
-
return this.parseResponse(endpoint, response, caller);
|
|
67
|
-
}
|
|
68
77
|
}
|
|
@@ -4,5 +4,5 @@ import type { Endpoint } from "../endpoint/Endpoint.js";
|
|
|
4
4
|
import { ThroughAPIProvider } from "./ThroughAPIProvider.js";
|
|
5
5
|
/** Provider that logs API operations to the console. */
|
|
6
6
|
export declare class DebugAPIProvider<P, R> extends ThroughAPIProvider<P, R> {
|
|
7
|
-
|
|
7
|
+
call<PP extends P, RR extends R>(endpoint: Endpoint<PP, RR>, payload: PP, options?: RequestOptions, caller?: AnyCaller): Promise<RR>;
|
|
8
8
|
}
|
|
@@ -1,15 +1,37 @@
|
|
|
1
|
+
import { debugFullRequest, debugFullResponse } from "../../util/debug.js";
|
|
1
2
|
import { ThroughAPIProvider } from "./ThroughAPIProvider.js";
|
|
2
3
|
/** Provider that logs API operations to the console. */
|
|
3
4
|
export class DebugAPIProvider extends ThroughAPIProvider {
|
|
4
|
-
async
|
|
5
|
+
async call(endpoint, payload, options, caller = this.call) {
|
|
6
|
+
// Turn the payload into a request and debug it before sending.
|
|
7
|
+
let request;
|
|
5
8
|
try {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
request = this.getRequest(endpoint, payload, options, caller);
|
|
10
|
+
}
|
|
11
|
+
catch (reason) {
|
|
12
|
+
console.error("✘ FETCH", this.url, endpoint.toString(), payload, reason);
|
|
13
|
+
throw reason;
|
|
14
|
+
}
|
|
15
|
+
const debuggedRequest = await debugFullRequest(request);
|
|
16
|
+
console.debug("… FETCH", this.url, endpoint.toString(), payload, debuggedRequest);
|
|
17
|
+
// Fetch the response and debug if it throws.
|
|
18
|
+
let response;
|
|
19
|
+
try {
|
|
20
|
+
response = await this.fetch(request);
|
|
21
|
+
}
|
|
22
|
+
catch (reason) {
|
|
23
|
+
console.error("✘ FETCH", this.url, endpoint.toString(), payload, debuggedRequest, reason);
|
|
24
|
+
throw reason;
|
|
25
|
+
}
|
|
26
|
+
const debuggedResponse = await debugFullResponse(response);
|
|
27
|
+
// Convert the result or any parsing error.
|
|
28
|
+
try {
|
|
29
|
+
const result = await this.parseResponse(endpoint, response, caller);
|
|
30
|
+
console.debug("✔ FETCH", this.url, endpoint.toString(), payload, debuggedRequest, debuggedResponse, result);
|
|
9
31
|
return result;
|
|
10
32
|
}
|
|
11
33
|
catch (reason) {
|
|
12
|
-
console.error("✘ FETCH",
|
|
34
|
+
console.error("✘ FETCH", this.url, endpoint.toString(), payload, debuggedRequest, debuggedResponse, reason);
|
|
13
35
|
throw reason;
|
|
14
36
|
}
|
|
15
37
|
}
|
|
@@ -3,12 +3,18 @@ import type { RequestHandler, RequestOptions } from "../../util/http.js";
|
|
|
3
3
|
import type { AnyEndpoint, Endpoint } from "../endpoint/Endpoint.js";
|
|
4
4
|
import { ClientAPIProvider } from "./ClientAPIProvider.js";
|
|
5
5
|
import { ThroughAPIProvider } from "./ThroughAPIProvider.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
readonly
|
|
6
|
+
export type MockAPIFetchCall = {
|
|
7
|
+
readonly request: Request;
|
|
8
|
+
readonly response: Response;
|
|
9
|
+
};
|
|
10
|
+
export type MockAPIRequestCall = {
|
|
9
11
|
readonly endpoint: AnyEndpoint;
|
|
10
12
|
readonly payload: unknown;
|
|
13
|
+
readonly options: RequestOptions | undefined;
|
|
11
14
|
readonly request: Request;
|
|
15
|
+
};
|
|
16
|
+
export type MockAPIResponseCall = {
|
|
17
|
+
readonly endpoint: AnyEndpoint;
|
|
12
18
|
readonly response: Response;
|
|
13
19
|
readonly result: unknown;
|
|
14
20
|
};
|
|
@@ -18,8 +24,12 @@ export type MockAPICall = {
|
|
|
18
24
|
* - The source provider's `fetch()` is never called — this provider intercepts all fetches and routes them through a `RequestHandler`.
|
|
19
25
|
*/
|
|
20
26
|
export declare class MockAPIProvider<P = unknown, R = unknown> extends ThroughAPIProvider<P, R> {
|
|
21
|
-
readonly
|
|
27
|
+
readonly requestCalls: MockAPIRequestCall[];
|
|
28
|
+
readonly fetchCalls: MockAPIFetchCall[];
|
|
29
|
+
readonly responseCalls: MockAPIResponseCall[];
|
|
22
30
|
readonly handler: RequestHandler;
|
|
23
31
|
constructor(handler?: RequestHandler, source?: ClientAPIProvider<P, R>);
|
|
24
|
-
|
|
32
|
+
getRequest<PP extends P, RR extends R>(endpoint: Endpoint<PP, RR>, payload: PP, options?: RequestOptions, caller?: AnyCaller): Request;
|
|
33
|
+
parseResponse<PP extends P, RR extends R>(endpoint: Endpoint<PP, RR>, response: Response, caller?: AnyCaller): Promise<RR>;
|
|
34
|
+
fetch(request: Request): Promise<Response>;
|
|
25
35
|
}
|
|
@@ -10,18 +10,30 @@ async function _passthroughHandler(request) {
|
|
|
10
10
|
* - The source provider's `fetch()` is never called — this provider intercepts all fetches and routes them through a `RequestHandler`.
|
|
11
11
|
*/
|
|
12
12
|
export class MockAPIProvider extends ThroughAPIProvider {
|
|
13
|
-
|
|
13
|
+
requestCalls = [];
|
|
14
|
+
fetchCalls = [];
|
|
15
|
+
responseCalls = [];
|
|
14
16
|
handler;
|
|
15
17
|
constructor(handler = _passthroughHandler, source = new ClientAPIProvider({ url: "https://api.mock.com" })) {
|
|
16
18
|
super(source);
|
|
17
19
|
this.handler = handler;
|
|
18
20
|
}
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
const request =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
// Override `getRequest()` to log the endpoint and payload before delegating to the source provider for request building.
|
|
22
|
+
getRequest(endpoint, payload, options, caller = this.getRequest) {
|
|
23
|
+
const request = super.getRequest(endpoint, payload, options, caller);
|
|
24
|
+
this.requestCalls.push({ endpoint, payload, options, request });
|
|
25
|
+
return request;
|
|
26
|
+
}
|
|
27
|
+
// Override `parseResponse()` to log the response and result.
|
|
28
|
+
async parseResponse(endpoint, response, caller = this.parseResponse) {
|
|
29
|
+
const result = await super.parseResponse(endpoint, response, caller);
|
|
30
|
+
this.responseCalls.push({ endpoint, response, result });
|
|
25
31
|
return result;
|
|
26
32
|
}
|
|
33
|
+
// Override `fetch()` to route through the handler instead of the network.
|
|
34
|
+
async fetch(request) {
|
|
35
|
+
const response = await this.handler(request);
|
|
36
|
+
this.fetchCalls.push({ request, response });
|
|
37
|
+
return response;
|
|
38
|
+
}
|
|
27
39
|
}
|
|
@@ -13,6 +13,6 @@ import { MockAPIProvider } from "./MockAPIProvider.js";
|
|
|
13
13
|
*/
|
|
14
14
|
export class MockEndpointAPIProvider extends MockAPIProvider {
|
|
15
15
|
constructor(handlers, context, source) {
|
|
16
|
-
super(request => handleEndpoints(this.url, handlers, request, context, this.
|
|
16
|
+
super(request => handleEndpoints(this.url, handlers, request, context, this.call), source);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -3,17 +3,17 @@ import type { RequestOptions } from "../../util/http.js";
|
|
|
3
3
|
import type { Sourceable } from "../../util/source.js";
|
|
4
4
|
import type { URL, URLString } from "../../util/url.js";
|
|
5
5
|
import type { Endpoint } from "../endpoint/Endpoint.js";
|
|
6
|
-
import
|
|
6
|
+
import { APIProvider } from "./APIProvider.js";
|
|
7
7
|
/**
|
|
8
8
|
* Provider wrapper that delegates API operations to a source provider.
|
|
9
9
|
* - Extend this when you want to intercept only selected API operations, such as injecting auth headers or logging.
|
|
10
10
|
*/
|
|
11
|
-
export declare class ThroughAPIProvider<P, R>
|
|
11
|
+
export declare class ThroughAPIProvider<P, R> extends APIProvider<P, R> implements Sourceable<APIProvider<P, R>> {
|
|
12
12
|
get url(): URLString;
|
|
13
13
|
readonly source: APIProvider<P, R>;
|
|
14
14
|
constructor(source: APIProvider<P, R>);
|
|
15
15
|
renderURL<PP extends P, RR extends R>(endpoint: Endpoint<PP, RR>, payload: PP, caller?: AnyCaller): URL;
|
|
16
16
|
getRequest<PP extends P, RR extends R>(endpoint: Endpoint<PP, RR>, payload: PP, options?: RequestOptions, caller?: AnyCaller): Request;
|
|
17
17
|
parseResponse<PP extends P, RR extends R>(endpoint: Endpoint<PP, RR>, response: Response, caller?: AnyCaller): Promise<RR>;
|
|
18
|
-
fetch
|
|
18
|
+
fetch(request: Request): Promise<Response>;
|
|
19
19
|
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
import { APIProvider } from "./APIProvider.js";
|
|
1
2
|
/**
|
|
2
3
|
* Provider wrapper that delegates API operations to a source provider.
|
|
3
4
|
* - Extend this when you want to intercept only selected API operations, such as injecting auth headers or logging.
|
|
4
5
|
*/
|
|
5
|
-
export class ThroughAPIProvider {
|
|
6
|
+
export class ThroughAPIProvider extends APIProvider {
|
|
6
7
|
get url() {
|
|
7
8
|
return this.source.url;
|
|
8
9
|
}
|
|
9
10
|
source;
|
|
10
11
|
constructor(source) {
|
|
12
|
+
super();
|
|
11
13
|
this.source = source;
|
|
12
14
|
}
|
|
13
15
|
renderURL(endpoint, payload, caller = this.renderURL) {
|
|
@@ -19,7 +21,7 @@ export class ThroughAPIProvider {
|
|
|
19
21
|
parseResponse(endpoint, response, caller = this.parseResponse) {
|
|
20
22
|
return this.source.parseResponse(endpoint, response, caller);
|
|
21
23
|
}
|
|
22
|
-
fetch(
|
|
23
|
-
return this.source.fetch(
|
|
24
|
+
fetch(request) {
|
|
25
|
+
return this.source.fetch(request);
|
|
24
26
|
}
|
|
25
27
|
}
|
|
@@ -4,5 +4,6 @@ import type { Endpoint } from "../endpoint/Endpoint.js";
|
|
|
4
4
|
import { ThroughAPIProvider } from "./ThroughAPIProvider.js";
|
|
5
5
|
/** Validate an asynchronous source provider (source can have any type because validation guarantees the type). */
|
|
6
6
|
export declare class ValidationAPIProvider<P, R> extends ThroughAPIProvider<P, R> {
|
|
7
|
-
|
|
7
|
+
getRequest<PP extends P, RR extends R>(endpoint: Endpoint<PP, RR>, payload: PP, options?: RequestOptions, caller?: AnyCaller): Request;
|
|
8
|
+
parseResponse<PP extends P, RR extends R>(endpoint: Endpoint<PP, RR>, response: Response, caller?: AnyCaller): Promise<RR>;
|
|
8
9
|
}
|
|
@@ -2,22 +2,19 @@ import { ResponseError } from "../../error/ResponseError.js";
|
|
|
2
2
|
import { ThroughAPIProvider } from "./ThroughAPIProvider.js";
|
|
3
3
|
/** Validate an asynchronous source provider (source can have any type because validation guarantees the type). */
|
|
4
4
|
export class ValidationAPIProvider extends ThroughAPIProvider {
|
|
5
|
-
|
|
5
|
+
getRequest(endpoint, payload, options, caller = this.getRequest) {
|
|
6
6
|
// Validate payload — let thrown strings bubble up as user-readable messages for e.g. form handlers.
|
|
7
|
-
|
|
8
|
-
// Call through to source (raw transport, no schema validation).
|
|
9
|
-
const content = await this.source.fetch(endpoint, validPayload, options, caller);
|
|
10
|
-
// Validate result — wrap in ResponseError as this is a server/transport problem, not user error.
|
|
11
|
-
return _validateResult(endpoint, content, caller);
|
|
7
|
+
return super.getRequest(endpoint, endpoint.payload.validate(payload), options, caller);
|
|
12
8
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
9
|
+
async parseResponse(endpoint, response, caller = this.parseResponse) {
|
|
10
|
+
try {
|
|
11
|
+
// Validate result — wrap in ResponseError as this is a server/transport problem, not user error.
|
|
12
|
+
return endpoint.result.validate(await super.parseResponse(endpoint, response, caller));
|
|
13
|
+
}
|
|
14
|
+
catch (thrown) {
|
|
15
|
+
if (typeof thrown === "string")
|
|
16
|
+
throw new ResponseError(`Invalid result for ${endpoint}:\n${thrown}`, { provider: this, endpoint, code: 422, caller });
|
|
17
|
+
throw thrown;
|
|
18
|
+
}
|
|
22
19
|
}
|
|
23
20
|
}
|
|
@@ -5,7 +5,7 @@ import type { PossibleURL } from "../../util/url.js";
|
|
|
5
5
|
import type { Endpoint } from "../endpoint/Endpoint.js";
|
|
6
6
|
import { ClientAPIProvider } from "./ClientAPIProvider.js";
|
|
7
7
|
/** API provider that always sends request bodies as XML and parses responses as plain text. */
|
|
8
|
-
export declare class XMLAPIProvider<P extends Data = Data, R = string> extends ClientAPIProvider<P, R> {
|
|
8
|
+
export declare class XMLAPIProvider<P extends Data = Data, R extends string = string> extends ClientAPIProvider<P, R> {
|
|
9
9
|
protected _getBodyRequest(method: RequestBodyMethod, url: PossibleURL, payload: P, options: RequestOptions, caller: AnyCaller): Request;
|
|
10
10
|
/**
|
|
11
11
|
* Parse a text `Response` for an endpoint.
|
|
@@ -93,7 +93,7 @@ export class EndpointStore extends Store {
|
|
|
93
93
|
/** Fetch the result from the API endpoint now. */
|
|
94
94
|
async _fetch(abort) {
|
|
95
95
|
try {
|
|
96
|
-
const value = await this.provider.
|
|
96
|
+
const value = await this.provider.call(this.endpoint, this._payload, { signal: abort.signal });
|
|
97
97
|
this.reason = undefined;
|
|
98
98
|
this.value = value;
|
|
99
99
|
}
|
|
@@ -15,6 +15,7 @@ export declare class Collection<N extends string = string, I extends Identifier
|
|
|
15
15
|
/** Schema for a complete item (id + data). */
|
|
16
16
|
readonly item: DataSchema<Item<I, T>>;
|
|
17
17
|
constructor(name: N, id: Schema<I>, data: Schemas<T> | DataSchema<T>);
|
|
18
|
+
toString(): string;
|
|
18
19
|
}
|
|
19
20
|
/** Shortcut factory for creating a Collection. */
|
|
20
21
|
export declare function COLLECTION<K extends string, I extends Identifier, T extends Data>(name: K, id: Schema<I>, data: Schemas<T> | DataSchema<T>): Collection<K, I, T>;
|
package/package.json
CHANGED
package/util/debug.d.ts
CHANGED
|
@@ -6,6 +6,25 @@ import type { ImmutableSet } from "./set.js";
|
|
|
6
6
|
export declare function debug(value: unknown, depth?: number): string;
|
|
7
7
|
/** Debug a string. */
|
|
8
8
|
export declare const debugString: (value: string) => string;
|
|
9
|
+
/** Debug a set of `Headers` as a string. */
|
|
10
|
+
export declare function debugHeaders(headers: Headers): string;
|
|
11
|
+
/**
|
|
12
|
+
* Debug a full `Request` as a string including its body.
|
|
13
|
+
* - Clones the request before reading the body so the original request can still be sent or parsed later.
|
|
14
|
+
* - Omits the body section when the request body is empty.
|
|
15
|
+
*/
|
|
16
|
+
export declare function debugFullRequest(request: Request): Promise<string>;
|
|
17
|
+
/**
|
|
18
|
+
* Debug a full `Response` as a string including its headers and body.
|
|
19
|
+
* - Clones the response before reading the body so the original response can still be parsed later.
|
|
20
|
+
* - Omits the headers section when there are no headers.
|
|
21
|
+
* - Omits the body section when the response body is empty.
|
|
22
|
+
*/
|
|
23
|
+
export declare function debugFullResponse(response: Response): Promise<string>;
|
|
24
|
+
/** Debug a `Request` as a string. */
|
|
25
|
+
export declare function debugRequest(request: Request): string;
|
|
26
|
+
/** Debug a `Response` as a string. */
|
|
27
|
+
export declare function debugResponse(response: Response): string;
|
|
9
28
|
/** Debug an array. */
|
|
10
29
|
export declare function debugArray(value: ImmutableArray, depth?: number): string;
|
|
11
30
|
/** Debug a set. */
|
package/util/debug.js
CHANGED
|
@@ -19,6 +19,12 @@ export function debug(value, depth = 1) {
|
|
|
19
19
|
return value.toISOString();
|
|
20
20
|
if (value instanceof Error)
|
|
21
21
|
return value.toString();
|
|
22
|
+
if (value instanceof Request)
|
|
23
|
+
return debugRequest(value);
|
|
24
|
+
if (value instanceof Response)
|
|
25
|
+
return debugResponse(value);
|
|
26
|
+
if (value instanceof Headers)
|
|
27
|
+
return debugHeaders(value);
|
|
22
28
|
// biome-ignore lint/suspicious/useIsArray: Intential in this context.
|
|
23
29
|
if (value instanceof Array)
|
|
24
30
|
return debugArray(value, depth);
|
|
@@ -45,6 +51,43 @@ const ESCAPE_LIST = {
|
|
|
45
51
|
"\v": "\\v",
|
|
46
52
|
};
|
|
47
53
|
const _escapeChar = (char) => ESCAPE_LIST[char] || `\\x${char.charCodeAt(0).toString(16).padStart(2, "00")}`;
|
|
54
|
+
/** Debug a set of `Headers` as a string. */
|
|
55
|
+
export function debugHeaders(headers) {
|
|
56
|
+
return Array.from(headers, ([key, value]) => `${key}: ${value}`).join("\n");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Debug a full `Request` as a string including its body.
|
|
60
|
+
* - Clones the request before reading the body so the original request can still be sent or parsed later.
|
|
61
|
+
* - Omits the body section when the request body is empty.
|
|
62
|
+
*/
|
|
63
|
+
export async function debugFullRequest(request) {
|
|
64
|
+
return _debugFullMessage(debugRequest(request), request);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Debug a full `Response` as a string including its headers and body.
|
|
68
|
+
* - Clones the response before reading the body so the original response can still be parsed later.
|
|
69
|
+
* - Omits the headers section when there are no headers.
|
|
70
|
+
* - Omits the body section when the response body is empty.
|
|
71
|
+
*/
|
|
72
|
+
export async function debugFullResponse(response) {
|
|
73
|
+
return _debugFullMessage(debugResponse(response), response);
|
|
74
|
+
}
|
|
75
|
+
async function _debugFullMessage(head, message) {
|
|
76
|
+
const headers = debugHeaders(message.headers);
|
|
77
|
+
const body = await _debugMessageBody(message);
|
|
78
|
+
return `${head}${headers && `\n${headers}`}${body && `\n\n${body}`}`;
|
|
79
|
+
}
|
|
80
|
+
async function _debugMessageBody(message) {
|
|
81
|
+
return message.bodyUsed ? "[body used]" : await message.clone().text();
|
|
82
|
+
}
|
|
83
|
+
/** Debug a `Request` as a string. */
|
|
84
|
+
export function debugRequest(request) {
|
|
85
|
+
return `${request.method} ${request.url}`;
|
|
86
|
+
}
|
|
87
|
+
/** Debug a `Response` as a string. */
|
|
88
|
+
export function debugResponse(response) {
|
|
89
|
+
return `${response.status} ${response.statusText}`;
|
|
90
|
+
}
|
|
48
91
|
/** Debug an array. */
|
|
49
92
|
export function debugArray(value, depth = 1) {
|
|
50
93
|
const prototype = Object.getPrototypeOf(value);
|