@webpieces/core-util 0.4.794 → 0.4.796
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/package.json +1 -1
- package/src/errors/ApiError.d.ts +9 -5
- package/src/errors/ApiError.js +9 -4
- package/src/errors/ApiError.js.map +1 -1
- package/src/errors/ApiErrorCodec.js +5 -0
- package/src/errors/ApiErrorCodec.js.map +1 -1
- package/src/errors/ReceivedApiErrorRule.d.ts +5 -3
- package/src/errors/ReceivedApiErrorRule.js +23 -4
- package/src/errors/ReceivedApiErrorRule.js.map +1 -1
- package/src/errors/index.d.ts +1 -1
- package/src/errors/index.js +2 -1
- package/src/errors/index.js.map +1 -1
- package/src/http/ApiCallTimeoutError.d.ts +2 -1
- package/src/http/ApiCallTimeoutError.js +2 -1
- package/src/http/ApiCallTimeoutError.js.map +1 -1
- package/src/http/ApiErrorHttpStatus.js +1 -0
- package/src/http/ApiErrorHttpStatus.js.map +1 -1
- package/src/http/EndpointCompileAssertions.d.ts +1 -0
- package/src/http/EndpointCompileAssertions.js +21 -0
- package/src/http/EndpointCompileAssertions.js.map +1 -0
- package/src/http/HttpContract.d.ts +10 -1
- package/src/http/HttpContract.js +10 -1
- package/src/http/HttpContract.js.map +1 -1
- package/src/http/HttpEndpointOptions.d.ts +14 -3
- package/src/http/HttpEndpointOptions.js +12 -0
- package/src/http/HttpEndpointOptions.js.map +1 -1
- package/src/http/RouteMetadata.d.ts +6 -1
- package/src/http/RouteMetadata.js +5 -1
- package/src/http/RouteMetadata.js.map +1 -1
- package/src/http/RouteMetadataFactory.d.ts +3 -3
- package/src/http/RouteMetadataFactory.js +13 -16
- package/src/http/RouteMetadataFactory.js.map +1 -1
- package/src/http/WebpiecesDefaultErrorTranslator.d.ts +5 -3
- package/src/http/WebpiecesDefaultErrorTranslator.js +17 -4
- package/src/http/WebpiecesDefaultErrorTranslator.js.map +1 -1
- package/src/http/api-kind.js +2 -2
- package/src/http/api-kind.js.map +1 -1
- package/src/http/decorators.d.ts +41 -143
- package/src/http/decorators.js +123 -110
- package/src/http/decorators.js.map +1 -1
- package/src/http/external-caller.d.ts +4 -4
- package/src/http/external-caller.js +12 -5
- package/src/http/external-caller.js.map +1 -1
- package/src/index.d.ts +7 -5
- package/src/index.js +21 -5
- package/src/index.js.map +1 -1
- package/src/mcp/McpCompileAssertions.js +3 -9
- package/src/mcp/McpCompileAssertions.js.map +1 -1
- package/src/mcp/McpMetadata.d.ts +8 -14
- package/src/mcp/McpMetadata.js +19 -5
- package/src/mcp/McpMetadata.js.map +1 -1
package/package.json
CHANGED
package/src/errors/ApiError.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ApiErrorKind = 'end-user' | 'bad-request' | 'unauthorized' | 'forbidden' | 'not-found' | 'endpoint-not-found' | 'request-timeout' | 'rate-limited' | 'conflict' | 'unprocessable' | 'precondition-failed' | 'unsupported-media-type' | 'not-implemented' | 'coded' | 'implementation' | 'dependency' | 'unavailable' | 'dependency-timeout' | 'dependency-backoff' | 'connection';
|
|
1
|
+
export type ApiErrorKind = 'end-user' | 'bad-request' | 'unauthorized' | 'forbidden' | 'not-found' | 'endpoint-not-found' | 'request-timeout' | 'rate-limited' | 'conflict' | 'unprocessable' | 'precondition-failed' | 'unsupported-media-type' | 'not-implemented' | 'coded' | 'implementation' | 'dependency' | 'bad-gateway' | 'unavailable' | 'dependency-timeout' | 'dependency-backoff' | 'connection';
|
|
2
2
|
/** Category for portable API failures. Concrete subclasses alone define protocol mappings. */
|
|
3
3
|
export declare abstract class ApiError extends Error {
|
|
4
4
|
abstract readonly kind: ApiErrorKind;
|
|
@@ -9,12 +9,16 @@ export declare class ApiNotFoundError extends ApiError {
|
|
|
9
9
|
readonly kind: ApiErrorKind;
|
|
10
10
|
}
|
|
11
11
|
export declare class ApiDependencyError extends ApiError {
|
|
12
|
-
readonly kind:
|
|
12
|
+
readonly kind: ApiErrorKind;
|
|
13
|
+
}
|
|
14
|
+
/** A retry-eligible HTTP 502/proxy failure, distinct from a generic dependency defect. */
|
|
15
|
+
export declare class ApiBadGatewayError extends ApiDependencyError {
|
|
16
|
+
readonly kind: "bad-gateway";
|
|
13
17
|
}
|
|
14
|
-
export declare class ApiUnavailableError extends
|
|
18
|
+
export declare class ApiUnavailableError extends ApiDependencyError {
|
|
15
19
|
readonly kind: "unavailable";
|
|
16
20
|
}
|
|
17
|
-
export declare class ApiDependencyTimeoutError extends
|
|
21
|
+
export declare class ApiDependencyTimeoutError extends ApiDependencyError {
|
|
18
22
|
readonly kind: "dependency-timeout";
|
|
19
23
|
}
|
|
20
24
|
/** A bug or invalid implementation state. Local errors become server errors only after a remote decode. */
|
|
@@ -83,7 +87,7 @@ export declare class ApiUnauthorizedError extends ApiError {
|
|
|
83
87
|
readonly kind: "unauthorized";
|
|
84
88
|
constructor(message: string, subType?: string, cause?: Error);
|
|
85
89
|
}
|
|
86
|
-
export declare class ApiDependencyBackoffError extends
|
|
90
|
+
export declare class ApiDependencyBackoffError extends ApiDependencyError {
|
|
87
91
|
retryAfterSeconds: number;
|
|
88
92
|
readonly kind: "dependency-backoff";
|
|
89
93
|
constructor(message: string, retryAfterSeconds?: number, cause?: Error);
|
package/src/errors/ApiError.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ApiCodedError = exports.ApiNotImplementedError = exports.ApiUnsupportedMediaTypeError = exports.ApiPreconditionFailedError = exports.ApiUnprocessableError = exports.ApiConflictError = exports.ApiDependencyBackoffError = exports.ApiUnauthorizedError = exports.ApiBadRequestError = exports.ApiEndUserError = exports.ApiEndpointNotFoundError = exports.ApiConnectionError = exports.ApiRequestTimeoutError = exports.ApiForbiddenError = exports.ApiRateLimitedError = exports.ApiImplementationError = exports.ApiDependencyTimeoutError = exports.ApiUnavailableError = exports.ApiDependencyError = exports.ApiNotFoundError = exports.ApiError = void 0;
|
|
3
|
+
exports.ApiCodedError = exports.ApiNotImplementedError = exports.ApiUnsupportedMediaTypeError = exports.ApiPreconditionFailedError = exports.ApiUnprocessableError = exports.ApiConflictError = exports.ApiDependencyBackoffError = exports.ApiUnauthorizedError = exports.ApiBadRequestError = exports.ApiEndUserError = exports.ApiEndpointNotFoundError = exports.ApiConnectionError = exports.ApiRequestTimeoutError = exports.ApiForbiddenError = exports.ApiRateLimitedError = exports.ApiImplementationError = exports.ApiDependencyTimeoutError = exports.ApiUnavailableError = exports.ApiBadGatewayError = exports.ApiDependencyError = exports.ApiNotFoundError = exports.ApiError = void 0;
|
|
4
4
|
/** Category for portable API failures. Concrete subclasses alone define protocol mappings. */
|
|
5
5
|
class ApiError extends Error {
|
|
6
6
|
subType;
|
|
@@ -18,11 +18,16 @@ class ApiDependencyError extends ApiError {
|
|
|
18
18
|
kind = 'dependency';
|
|
19
19
|
}
|
|
20
20
|
exports.ApiDependencyError = ApiDependencyError;
|
|
21
|
-
|
|
21
|
+
/** A retry-eligible HTTP 502/proxy failure, distinct from a generic dependency defect. */
|
|
22
|
+
class ApiBadGatewayError extends ApiDependencyError {
|
|
23
|
+
kind = 'bad-gateway';
|
|
24
|
+
}
|
|
25
|
+
exports.ApiBadGatewayError = ApiBadGatewayError;
|
|
26
|
+
class ApiUnavailableError extends ApiDependencyError {
|
|
22
27
|
kind = 'unavailable';
|
|
23
28
|
}
|
|
24
29
|
exports.ApiUnavailableError = ApiUnavailableError;
|
|
25
|
-
class ApiDependencyTimeoutError extends
|
|
30
|
+
class ApiDependencyTimeoutError extends ApiDependencyError {
|
|
26
31
|
kind = 'dependency-timeout';
|
|
27
32
|
}
|
|
28
33
|
exports.ApiDependencyTimeoutError = ApiDependencyTimeoutError;
|
|
@@ -113,7 +118,7 @@ class ApiUnauthorizedError extends ApiError {
|
|
|
113
118
|
}
|
|
114
119
|
}
|
|
115
120
|
exports.ApiUnauthorizedError = ApiUnauthorizedError;
|
|
116
|
-
class ApiDependencyBackoffError extends
|
|
121
|
+
class ApiDependencyBackoffError extends ApiDependencyError {
|
|
117
122
|
retryAfterSeconds;
|
|
118
123
|
kind = 'dependency-backoff';
|
|
119
124
|
constructor(message, retryAfterSeconds = 30, cause) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApiError.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/errors/ApiError.ts"],"names":[],"mappings":";;;AAsBA,8FAA8F;AAC9F,MAAsB,QAAS,SAAQ,KAAK;IAEjC,OAAO,CAAU;IAExB,YAAY,OAAe,EAAE,KAAa;QACtC,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;IAChC,CAAC;CACJ;AARD,4BAQC;AAED,MAAa,gBAAiB,SAAQ,QAAQ;IACxB,IAAI,GAAiB,WAAW,CAAC;CACtD;AAFD,4CAEC;AACD,MAAa,kBAAmB,SAAQ,QAAQ;IAC1B,IAAI,GAAG,YAAqB,CAAC;CAClD;AAFD,gDAEC;AACD,MAAa,mBAAoB,SAAQ,QAAQ;IAC3B,IAAI,GAAG,aAAsB,CAAC;CACnD;AAFD,kDAEC;AACD,MAAa,yBAA0B,SAAQ,QAAQ;IACjC,IAAI,GAAG,oBAA6B,CAAC;CAC1D;AAFD,8DAEC;AAED,2GAA2G;AAC3G,MAAa,sBAAuB,SAAQ,QAAQ;IAM5B;IALF,IAAI,GAAG,gBAAyB,CAAC;IAEnD,YACI,OAAe,EACf,KAAa,EACG,cAAc,KAAK;QAEnC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAFN,gBAAW,GAAX,WAAW,CAAQ;IAGvC,CAAC;CACJ;AAVD,wDAUC;AAED,MAAa,mBAAoB,SAAQ,QAAQ;IAC3B,IAAI,GAAG,cAAuB,CAAC;CACpD;AAFD,kDAEC;AACD,MAAa,iBAAkB,SAAQ,QAAQ;IACzB,IAAI,GAAG,WAAoB,CAAC;CACjD;AAFD,8CAEC;AACD,MAAa,sBAAuB,SAAQ,QAAQ;IAC9B,IAAI,GAAG,iBAA0B,CAAC;CACvD;AAFD,wDAEC;AAED,gGAAgG;AAChG,MAAa,kBAAmB,SAAQ,QAAQ;IAC1B,IAAI,GAAG,YAAqB,CAAC;CAClD;AAFD,gDAEC;AAED,2EAA2E;AAC3E,MAAa,wBAAyB,SAAQ,gBAAgB;IACxC,IAAI,GAAG,oBAA6B,CAAC;CAC1D;AAFD,4DAEC;AASD;;;;;;;;;;;;GAYG;AACH,MAAa,eAAgB,SAAQ,QAAQ;IAK9B;IACA;IALO,IAAI,GAAG,UAAmB,CAAC;IAE7C,YACI,OAAe,EACR,SAAkB,EAClB,cAA+B,EACtC,KAAa;QAEb,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAJf,cAAS,GAAT,SAAS,CAAS;QAClB,mBAAc,GAAd,cAAc,CAAiB;QAItC,IAAI,CAAC,OAAO,GAAG,YAAY,CAAC;IAChC,CAAC;IAED,qGAAqG;IACrG,2IAA2I;IAC3I,MAAM,CAAC,gBAAgB,CAAC,KAAc;QAClC,OAAO,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,CAAC;IAC5E,CAAC;CACJ;AAlBD,0CAkBC;AAED;;;;;GAKG;AACH,MAAa,kBAAmB,SAAQ,QAAQ;IAKjC;IACA;IALO,IAAI,GAAG,aAAsB,CAAC;IAEhD,YACI,OAAe,EACR,KAAc,EACd,aAAsB,EAC7B,KAAa;QAEb,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAJf,UAAK,GAAL,KAAK,CAAS;QACd,kBAAa,GAAb,aAAa,CAAS;IAIjC,CAAC;CACJ;AAXD,gDAWC;AAED,MAAa,oBAAqB,SAAQ,QAAQ;IAC5B,IAAI,GAAG,cAAuB,CAAC;IAEjD,YAAY,OAAe,EAAE,OAAgB,EAAE,KAAa;QACxD,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACtB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;CACJ;AAPD,oDAOC;AAED,MAAa,yBAA0B,SAAQ,QAAQ;IAKxC;IAJO,IAAI,GAAG,oBAA6B,CAAC;IAEvD,YACI,OAAe,EACR,oBAAoB,EAAE,EAC7B,KAAa;QAEb,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAHf,sBAAiB,GAAjB,iBAAiB,CAAK;IAIjC,CAAC;CACJ;AAVD,8DAUC;AAED,sFAAsF;AACtF,MAAa,gBAAiB,SAAQ,QAAQ;IACxB,IAAI,GAAG,UAAmB,CAAC;CAChD;AAFD,4CAEC;AAED,6EAA6E;AAC7E,MAAa,qBAAsB,SAAQ,QAAQ;IAC7B,IAAI,GAAG,eAAwB,CAAC;CACrD;AAFD,sDAEC;AAED,qFAAqF;AACrF,MAAa,0BAA2B,SAAQ,QAAQ;IAClC,IAAI,GAAG,qBAA8B,CAAC;CAC3D;AAFD,gEAEC;AAED,qFAAqF;AACrF,MAAa,4BAA6B,SAAQ,QAAQ;IACpC,IAAI,GAAG,wBAAiC,CAAC;CAC9D;AAFD,oEAEC;AAED,6FAA6F;AAC7F,MAAa,sBAAuB,SAAQ,QAAQ;IAC9B,IAAI,GAAG,iBAA0B,CAAC;CACvD;AAFD,wDAEC;AAcD;;;;;;GAMG;AACH,MAAa,aAAc,SAAQ,QAAQ;IAKnB;IACT;IALO,IAAI,GAAG,OAAgB,CAAC;IAE1C,YACI,OAAe,EACC,UAAyB,EAClC,SAAkB,EACzB,KAAa;QAEb,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAJN,eAAU,GAAV,UAAU,CAAe;QAClC,cAAS,GAAT,SAAS,CAAS;IAI7B,CAAC;IAED,2FAA2F;IAC3F,mJAAmJ;IACnJ,MAAM,CAAC,YAAY,CAAC,KAAc;QAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC;IAChG,CAAC;IAED,mGAAmG;IACnG,aAAa;QACT,OAAO,IAAI,CAAC,UAAU,GAAG,GAAG,IAAI,IAAI,CAAC,UAAU,KAAK,GAAG,IAAI,IAAI,CAAC,UAAU,KAAK,GAAG,CAAC;IACvF,CAAC;CACJ;AAtBD,sCAsBC","sourcesContent":["export type ApiErrorKind =\n | 'end-user'\n | 'bad-request'\n | 'unauthorized'\n | 'forbidden'\n | 'not-found'\n | 'endpoint-not-found'\n | 'request-timeout'\n | 'rate-limited'\n | 'conflict'\n | 'unprocessable'\n | 'precondition-failed'\n | 'unsupported-media-type'\n | 'not-implemented'\n | 'coded'\n | 'implementation'\n | 'dependency'\n | 'unavailable'\n | 'dependency-timeout'\n | 'dependency-backoff'\n | 'connection';\n\n/** Category for portable API failures. Concrete subclasses alone define protocol mappings. */\nexport abstract class ApiError extends Error {\n abstract readonly kind: ApiErrorKind;\n public subType?: string;\n\n constructor(message: string, cause?: Error) {\n super(message, { cause });\n this.name = new.target.name;\n }\n}\n\nexport class ApiNotFoundError extends ApiError {\n override readonly kind: ApiErrorKind = 'not-found';\n}\nexport class ApiDependencyError extends ApiError {\n override readonly kind = 'dependency' as const;\n}\nexport class ApiUnavailableError extends ApiError {\n override readonly kind = 'unavailable' as const;\n}\nexport class ApiDependencyTimeoutError extends ApiError {\n override readonly kind = 'dependency-timeout' as const;\n}\n\n/** A bug or invalid implementation state. Local errors become server errors only after a remote decode. */\nexport class ApiImplementationError extends ApiError {\n override readonly kind = 'implementation' as const;\n\n constructor(\n message: string,\n cause?: Error,\n public readonly serverError = false,\n ) {\n super(message, cause);\n }\n}\n\nexport class ApiRateLimitedError extends ApiError {\n override readonly kind = 'rate-limited' as const;\n}\nexport class ApiForbiddenError extends ApiError {\n override readonly kind = 'forbidden' as const;\n}\nexport class ApiRequestTimeoutError extends ApiError {\n override readonly kind = 'request-timeout' as const;\n}\n\n/** A caller-local connection failure. HTTP servers normalize this to ApiImplementationError. */\nexport class ApiConnectionError extends ApiError {\n override readonly kind = 'connection' as const;\n}\n\n/** The API operation is missing, distinct from an absent domain entity. */\nexport class ApiEndpointNotFoundError extends ApiNotFoundError {\n override readonly kind = 'endpoint-not-found' as const;\n}\n\n/**\n * The HTTP status an API EDGE answers for an {@link ApiEndUserError}. End-user outcomes only, so\n * nobody tunnels a 5xx/401/403/429 through the end-user channel (auth, rate limiting and dependency\n * failure keep their own types). Extend deliberately.\n */\nexport type EdgeHttpStatus = 400 | 404 | 409 | 422;\n\n/**\n * Expected mistake by the ACTOR driving the call: the input was well-formed but wrong in a way the actor\n * must fix (for example \"the two passwords you entered do not match\"). The actor may be a human user in\n * a GUI OR an LLM calling an MCP tool; the same class serves both. Its message is deliberately\n * caller-safe and is the only ApiError message published verbatim: `ApiErrorCodec` keeps it (and\n * `errorCode`) across every remote hop, so a downstream service's text reaches the GUI or the model\n * byte-for-byte.\n *\n * `edgeHttpStatus` travels the same way. It is what a partner-facing API edge (an http-server router\n * in `'edge'` end-user-status mode) answers instead of 266, so one throw site serves both a GUI and a\n * published REST contract: `throw new ApiEndUserError('That report does not exist', 'report_not_found', 404)`.\n * GUI edges ignore it and keep answering 266.\n */\nexport class ApiEndUserError extends ApiError {\n override readonly kind = 'end-user' as const;\n\n constructor(\n message: string,\n public errorCode?: string,\n public edgeHttpStatus?: EdgeHttpStatus,\n cause?: Error,\n ) {\n super(message, cause);\n this.subType = 'USER_ERROR';\n }\n\n /** Narrows a dynamic value (for example one read off the wire) to a legal {@link EdgeHttpStatus}. */\n // webpieces-disable no-function-outside-class -- stateless status guard; webpieces-disable no-any-unknown -- wire values are narrowed here\n static isEdgeHttpStatus(value: unknown): value is EdgeHttpStatus {\n return value === 400 || value === 404 || value === 409 || value === 422;\n }\n}\n\n/**\n * Invalid API caller input (malformed, or failed validation). `message` is operator-only diagnostic\n * text and may name internals; it is never published. `callerMessage` (plus `field`) is what a GUI OR\n * an MCP model is shown so it can correct its input, so throw sites that want the caller to\n * self-correct MUST set it.\n */\nexport class ApiBadRequestError extends ApiError {\n override readonly kind = 'bad-request' as const;\n\n constructor(\n message: string,\n public field?: string,\n public callerMessage?: string,\n cause?: Error,\n ) {\n super(message, cause);\n }\n}\n\nexport class ApiUnauthorizedError extends ApiError {\n override readonly kind = 'unauthorized' as const;\n\n constructor(message: string, subType?: string, cause?: Error) {\n super(message, cause);\n this.subType = subType;\n }\n}\n\nexport class ApiDependencyBackoffError extends ApiError {\n override readonly kind = 'dependency-backoff' as const;\n\n constructor(\n message: string,\n public retryAfterSeconds = 30,\n cause?: Error,\n ) {\n super(message, cause);\n }\n}\n\n/** The request conflicts with the current state of the target resource (HTTP 409). */\nexport class ApiConflictError extends ApiError {\n override readonly kind = 'conflict' as const;\n}\n\n/** The request was well-formed but semantically unprocessable (HTTP 422). */\nexport class ApiUnprocessableError extends ApiError {\n override readonly kind = 'unprocessable' as const;\n}\n\n/** A caller-supplied precondition (for example If-Match) did not hold (HTTP 412). */\nexport class ApiPreconditionFailedError extends ApiError {\n override readonly kind = 'precondition-failed' as const;\n}\n\n/** The request body is in a media type this operation does not accept (HTTP 415). */\nexport class ApiUnsupportedMediaTypeError extends ApiError {\n override readonly kind = 'unsupported-media-type' as const;\n}\n\n/** The operation exists in the contract but this server does not implement it (HTTP 501). */\nexport class ApiNotImplementedError extends ApiError {\n override readonly kind = 'not-implemented' as const;\n}\n\n/** Builds the tuple [0, 1, ..., N-1]; tail-recursive so TypeScript can reach 600. */\ntype StatusRange<N extends number, Acc extends number[] = []> = Acc['length'] extends N\n ? Acc\n : StatusRange<N, [...Acc, Acc['length']]>;\n\n/**\n * Every integer from 100 through 599 as a literal union. `new ApiCodedError(msg, 600)`,\n * `new ApiCodedError(msg, 99)` and `new ApiCodedError(msg, 404.5)` do not compile; a dynamic\n * `number` must be narrowed with {@link ApiCodedError.isStatusCode} first.\n */\nexport type ApiStatusCode = Exclude<StatusRange<600>[number], StatusRange<100>[number]>;\n\n/**\n * Catch-all carrying an explicit protocol status for outcomes no named ApiError covers. Any code in\n * 100-599 is accepted, including one a named class already owns. `statusCode` and `errorCode` survive\n * every remote hop through `ApiErrorCodec`; `message` stays operator-only like every other non\n * end-user kind. A status below 500 is a caller outcome (except 408 and 429, which mirror\n * `ApiRequestTimeoutError` and `ApiRateLimitedError`); 500 and above is a server/dependency fault.\n */\nexport class ApiCodedError extends ApiError {\n override readonly kind = 'coded' as const;\n\n constructor(\n message: string,\n public readonly statusCode: ApiStatusCode,\n public errorCode?: string,\n cause?: Error,\n ) {\n super(message, cause);\n }\n\n /** Narrows a dynamic number (for example one read off the wire) to a legal status code. */\n // webpieces-disable no-function-outside-class -- stateless status guard; webpieces-disable no-any-unknown -- wire and app values are narrowed here\n static isStatusCode(value: unknown): value is ApiStatusCode {\n return typeof value === 'number' && Number.isInteger(value) && value >= 100 && value <= 599;\n }\n\n /** True when the status describes the caller's mistake rather than a fault on the serving side. */\n isCallerError(): boolean {\n return this.statusCode < 500 && this.statusCode !== 408 && this.statusCode !== 429;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ApiError.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/errors/ApiError.ts"],"names":[],"mappings":"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","sourcesContent":["export type ApiErrorKind =\n | 'end-user'\n | 'bad-request'\n | 'unauthorized'\n | 'forbidden'\n | 'not-found'\n | 'endpoint-not-found'\n | 'request-timeout'\n | 'rate-limited'\n | 'conflict'\n | 'unprocessable'\n | 'precondition-failed'\n | 'unsupported-media-type'\n | 'not-implemented'\n | 'coded'\n | 'implementation'\n | 'dependency'\n | 'bad-gateway'\n | 'unavailable'\n | 'dependency-timeout'\n | 'dependency-backoff'\n | 'connection';\n\n/** Category for portable API failures. Concrete subclasses alone define protocol mappings. */\nexport abstract class ApiError extends Error {\n abstract readonly kind: ApiErrorKind;\n public subType?: string;\n\n constructor(message: string, cause?: Error) {\n super(message, { cause });\n this.name = new.target.name;\n }\n}\n\nexport class ApiNotFoundError extends ApiError {\n override readonly kind: ApiErrorKind = 'not-found';\n}\nexport class ApiDependencyError extends ApiError {\n override readonly kind: ApiErrorKind = 'dependency';\n}\n/** A retry-eligible HTTP 502/proxy failure, distinct from a generic dependency defect. */\nexport class ApiBadGatewayError extends ApiDependencyError {\n override readonly kind = 'bad-gateway' as const;\n}\nexport class ApiUnavailableError extends ApiDependencyError {\n override readonly kind = 'unavailable' as const;\n}\nexport class ApiDependencyTimeoutError extends ApiDependencyError {\n override readonly kind = 'dependency-timeout' as const;\n}\n\n/** A bug or invalid implementation state. Local errors become server errors only after a remote decode. */\nexport class ApiImplementationError extends ApiError {\n override readonly kind = 'implementation' as const;\n\n constructor(\n message: string,\n cause?: Error,\n public readonly serverError = false,\n ) {\n super(message, cause);\n }\n}\n\nexport class ApiRateLimitedError extends ApiError {\n override readonly kind = 'rate-limited' as const;\n}\nexport class ApiForbiddenError extends ApiError {\n override readonly kind = 'forbidden' as const;\n}\nexport class ApiRequestTimeoutError extends ApiError {\n override readonly kind = 'request-timeout' as const;\n}\n\n/** A caller-local connection failure. HTTP servers normalize this to ApiImplementationError. */\nexport class ApiConnectionError extends ApiError {\n override readonly kind = 'connection' as const;\n}\n\n/** The API operation is missing, distinct from an absent domain entity. */\nexport class ApiEndpointNotFoundError extends ApiNotFoundError {\n override readonly kind = 'endpoint-not-found' as const;\n}\n\n/**\n * The HTTP status an API EDGE answers for an {@link ApiEndUserError}. End-user outcomes only, so\n * nobody tunnels a 5xx/401/403/429 through the end-user channel (auth, rate limiting and dependency\n * failure keep their own types). Extend deliberately.\n */\nexport type EdgeHttpStatus = 400 | 404 | 409 | 422;\n\n/**\n * Expected mistake by the ACTOR driving the call: the input was well-formed but wrong in a way the actor\n * must fix (for example \"the two passwords you entered do not match\"). The actor may be a human user in\n * a GUI OR an LLM calling an MCP tool; the same class serves both. Its message is deliberately\n * caller-safe and is the only ApiError message published verbatim: `ApiErrorCodec` keeps it (and\n * `errorCode`) across every remote hop, so a downstream service's text reaches the GUI or the model\n * byte-for-byte.\n *\n * `edgeHttpStatus` travels the same way. It is what a partner-facing API edge (an http-server router\n * in `'edge'` end-user-status mode) answers instead of 266, so one throw site serves both a GUI and a\n * published REST contract: `throw new ApiEndUserError('That report does not exist', 'report_not_found', 404)`.\n * GUI edges ignore it and keep answering 266.\n */\nexport class ApiEndUserError extends ApiError {\n override readonly kind = 'end-user' as const;\n\n constructor(\n message: string,\n public errorCode?: string,\n public edgeHttpStatus?: EdgeHttpStatus,\n cause?: Error,\n ) {\n super(message, cause);\n this.subType = 'USER_ERROR';\n }\n\n /** Narrows a dynamic value (for example one read off the wire) to a legal {@link EdgeHttpStatus}. */\n // webpieces-disable no-function-outside-class -- stateless status guard; webpieces-disable no-any-unknown -- wire values are narrowed here\n static isEdgeHttpStatus(value: unknown): value is EdgeHttpStatus {\n return value === 400 || value === 404 || value === 409 || value === 422;\n }\n}\n\n/**\n * Invalid API caller input (malformed, or failed validation). `message` is operator-only diagnostic\n * text and may name internals; it is never published. `callerMessage` (plus `field`) is what a GUI OR\n * an MCP model is shown so it can correct its input, so throw sites that want the caller to\n * self-correct MUST set it.\n */\nexport class ApiBadRequestError extends ApiError {\n override readonly kind = 'bad-request' as const;\n\n constructor(\n message: string,\n public field?: string,\n public callerMessage?: string,\n cause?: Error,\n ) {\n super(message, cause);\n }\n}\n\nexport class ApiUnauthorizedError extends ApiError {\n override readonly kind = 'unauthorized' as const;\n\n constructor(message: string, subType?: string, cause?: Error) {\n super(message, cause);\n this.subType = subType;\n }\n}\n\nexport class ApiDependencyBackoffError extends ApiDependencyError {\n override readonly kind = 'dependency-backoff' as const;\n\n constructor(\n message: string,\n public retryAfterSeconds = 30,\n cause?: Error,\n ) {\n super(message, cause);\n }\n}\n\n/** The request conflicts with the current state of the target resource (HTTP 409). */\nexport class ApiConflictError extends ApiError {\n override readonly kind = 'conflict' as const;\n}\n\n/** The request was well-formed but semantically unprocessable (HTTP 422). */\nexport class ApiUnprocessableError extends ApiError {\n override readonly kind = 'unprocessable' as const;\n}\n\n/** A caller-supplied precondition (for example If-Match) did not hold (HTTP 412). */\nexport class ApiPreconditionFailedError extends ApiError {\n override readonly kind = 'precondition-failed' as const;\n}\n\n/** The request body is in a media type this operation does not accept (HTTP 415). */\nexport class ApiUnsupportedMediaTypeError extends ApiError {\n override readonly kind = 'unsupported-media-type' as const;\n}\n\n/** The operation exists in the contract but this server does not implement it (HTTP 501). */\nexport class ApiNotImplementedError extends ApiError {\n override readonly kind = 'not-implemented' as const;\n}\n\n/** Builds the tuple [0, 1, ..., N-1]; tail-recursive so TypeScript can reach 600. */\ntype StatusRange<N extends number, Acc extends number[] = []> = Acc['length'] extends N\n ? Acc\n : StatusRange<N, [...Acc, Acc['length']]>;\n\n/**\n * Every integer from 100 through 599 as a literal union. `new ApiCodedError(msg, 600)`,\n * `new ApiCodedError(msg, 99)` and `new ApiCodedError(msg, 404.5)` do not compile; a dynamic\n * `number` must be narrowed with {@link ApiCodedError.isStatusCode} first.\n */\nexport type ApiStatusCode = Exclude<StatusRange<600>[number], StatusRange<100>[number]>;\n\n/**\n * Catch-all carrying an explicit protocol status for outcomes no named ApiError covers. Any code in\n * 100-599 is accepted, including one a named class already owns. `statusCode` and `errorCode` survive\n * every remote hop through `ApiErrorCodec`; `message` stays operator-only like every other non\n * end-user kind. A status below 500 is a caller outcome (except 408 and 429, which mirror\n * `ApiRequestTimeoutError` and `ApiRateLimitedError`); 500 and above is a server/dependency fault.\n */\nexport class ApiCodedError extends ApiError {\n override readonly kind = 'coded' as const;\n\n constructor(\n message: string,\n public readonly statusCode: ApiStatusCode,\n public errorCode?: string,\n cause?: Error,\n ) {\n super(message, cause);\n }\n\n /** Narrows a dynamic number (for example one read off the wire) to a legal status code. */\n // webpieces-disable no-function-outside-class -- stateless status guard; webpieces-disable no-any-unknown -- wire and app values are narrowed here\n static isStatusCode(value: unknown): value is ApiStatusCode {\n return typeof value === 'number' && Number.isInteger(value) && value >= 100 && value <= 599;\n }\n\n /** True when the status describes the caller's mistake rather than a fault on the serving side. */\n isCallerError(): boolean {\n return this.statusCode < 500 && this.statusCode !== 408 && this.statusCode !== 429;\n }\n}\n"]}
|
|
@@ -137,6 +137,8 @@ class ApiErrorCodec {
|
|
|
137
137
|
return this.coded(message, field('statusCode'), field('errorCode'));
|
|
138
138
|
case 'dependency':
|
|
139
139
|
return new ApiError_1.ApiDependencyError(message);
|
|
140
|
+
case 'bad-gateway':
|
|
141
|
+
return new ApiError_1.ApiBadGatewayError(message);
|
|
140
142
|
case 'unavailable':
|
|
141
143
|
return new ApiError_1.ApiUnavailableError(message);
|
|
142
144
|
case 'dependency-timeout':
|
|
@@ -215,6 +217,8 @@ class ApiErrorCodec {
|
|
|
215
217
|
return 'Request Failed';
|
|
216
218
|
case 'dependency':
|
|
217
219
|
return 'Dependency Error';
|
|
220
|
+
case 'bad-gateway':
|
|
221
|
+
return 'Bad Gateway';
|
|
218
222
|
case 'unavailable':
|
|
219
223
|
return 'Service Unavailable';
|
|
220
224
|
case 'dependency-timeout':
|
|
@@ -244,6 +248,7 @@ class ApiErrorCodec {
|
|
|
244
248
|
'coded',
|
|
245
249
|
'implementation',
|
|
246
250
|
'dependency',
|
|
251
|
+
'bad-gateway',
|
|
247
252
|
'unavailable',
|
|
248
253
|
'dependency-timeout',
|
|
249
254
|
'dependency-backoff',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApiErrorCodec.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/errors/ApiErrorCodec.ts"],"names":[],"mappings":";;;AAAA,yCAwBoB;AACpB,kDAA4C;AAE5C,gGAAgG;AAChG,MAAa,eAAe;IAYb;IACA;IAZJ,KAAK,CAAmB;IACxB,OAAO,CAAU;IACjB,KAAK,CAAU;IACf,aAAa,CAAU;IACvB,SAAS,CAAU;IACnB,iBAAiB,CAAU;IAC3B,UAAU,CAAU;IAC3B,mGAAmG;IAC5F,cAAc,CAAU;IAE/B,YACW,OAAe,gBAAgB,EAC/B,UAAkB,gBAAgB;QADlC,SAAI,GAAJ,IAAI,CAA2B;QAC/B,YAAO,GAAP,OAAO,CAA2B;IAC1C,CAAC;CACP;AAfD,0CAeC;AAED,yEAAyE;AACzE,MAAa,aAAa;IACtB;;;;;;;;;OASG;IACH,kFAAkF;IAClF,MAAM,CAAC,MAAM,CAAC,KAAY;QACtB,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACtC,CAAC;IAED,mFAAmF;IAC3E,MAAM,CAAC,WAAW,CAAC,KAAY,EAAE,KAAa;QAClD,MAAM,IAAI,GAAG,KAAK,YAAY,mBAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC;QACvE,MAAM,OAAO,GAAG,IAAI,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3E,IAAI,KAAK,YAAY,mBAAQ;YAAE,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1E,IAAI,KAAK,YAAY,0BAAe,EAAE,CAAC;YACnC,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YAC/C,OAAO,CAAC,cAAc,GAAG,KAAK,CAAC,cAAc,CAAC;QAClD,CAAC;QACD,IAAI,KAAK,YAAY,wBAAa,EAAE,CAAC;YACjC,OAAO,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;YACtC,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACnD,CAAC;QACD,IAAI,KAAK,YAAY,6BAAkB,EAAE,CAAC;YACtC,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACvC,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,KAAK,YAAY,oCAAyB,EAAE,CAAC;YAC7C,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACZ,yFAAyF;YACzF,wFAAwF;YACxF,MAAM,KAAK,GAAG,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC;YACrE,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACxC,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,IAAA,oBAAO,EAAC,KAAK,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;YAChE,CAAC;QACL,CAAC;QACD,OAAO,OAAO,CAAC;IACnB,CAAC;IAED,+FAA+F;IAC/F,sJAAsJ;IACtJ,MAAM,CAAC,MAAM,CAAC,KAAc;QACxB,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACtC,CAAC;IAED,4EAA4E;IAC5E,wJAAwJ;IACxJ,MAAM,CAAC,SAAS,CAAC,KAAc;QAC3B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,KAAK,CAAC;QACnE,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAoB,CAAC,CAAC;IAC5E,CAAC;IAED,yJAAyJ;IACjJ,MAAM,CAAC,WAAW,CAAC,KAAc,EAAE,KAAa;QACpD,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YAC3D,MAAM,KAAK,GAAG,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC;YACrE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBAC9C,wGAAwG;gBACxG,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE;oBAClC,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC;oBACzC,YAAY,EAAE,IAAI;oBAClB,QAAQ,EAAE,IAAI;iBACjB,CAAC,CAAC;YACP,CAAC;QACL,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,4IAA4I;IACpI,MAAM,CAAC,SAAS,CAAC,KAAc;QACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACzF,sFAAsF;QACtF,MAAM,KAAK,GAAG,CAAC,GAAW,EAAW,EAAE,CAAC,MAAM,CAAC,wBAAwB,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC;QAC3F,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;QAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAClE,QAAQ,IAAI,EAAE,CAAC;YACX,KAAK,UAAU;gBACX,OAAO,IAAI,0BAAe,CACtB,OAAO,EACP,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAC7B,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAC3C,CAAC;YACN,KAAK,aAAa;gBACd,OAAO,IAAI,6BAAkB,CACzB,OAAO,EACP,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EACzB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CACpC,CAAC;YACN,KAAK,cAAc;gBACf,OAAO,IAAI,+BAAoB,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAC1E,KAAK,WAAW;gBACZ,OAAO,IAAI,4BAAiB,CAAC,OAAO,CAAC,CAAC;YAC1C,KAAK,WAAW;gBACZ,OAAO,IAAI,2BAAgB,CAAC,OAAO,CAAC,CAAC;YACzC,KAAK,oBAAoB;gBACrB,OAAO,IAAI,mCAAwB,CAAC,OAAO,CAAC,CAAC;YACjD,KAAK,iBAAiB;gBAClB,OAAO,IAAI,iCAAsB,CAAC,OAAO,CAAC,CAAC;YAC/C,KAAK,cAAc;gBACf,OAAO,IAAI,8BAAmB,CAAC,OAAO,CAAC,CAAC;YAC5C,KAAK,UAAU;gBACX,OAAO,IAAI,2BAAgB,CAAC,OAAO,CAAC,CAAC;YACzC,KAAK,eAAe;gBAChB,OAAO,IAAI,gCAAqB,CAAC,OAAO,CAAC,CAAC;YAC9C,KAAK,qBAAqB;gBACtB,OAAO,IAAI,qCAA0B,CAAC,OAAO,CAAC,CAAC;YACnD,KAAK,wBAAwB;gBACzB,OAAO,IAAI,uCAA4B,CAAC,OAAO,CAAC,CAAC;YACrD,KAAK,iBAAiB;gBAClB,OAAO,IAAI,iCAAsB,CAAC,OAAO,CAAC,CAAC;YAC/C,KAAK,OAAO;gBACR,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;YACxE,KAAK,YAAY;gBACb,OAAO,IAAI,6BAAkB,CAAC,OAAO,CAAC,CAAC;YAC3C,KAAK,aAAa;gBACd,OAAO,IAAI,8BAAmB,CAAC,OAAO,CAAC,CAAC;YAC5C,KAAK,oBAAoB;gBACrB,OAAO,IAAI,oCAAyB,CAAC,OAAO,CAAC,CAAC;YAClD,KAAK,oBAAoB;gBACrB,OAAO,IAAI,oCAAyB,CAChC,OAAO,EACP,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,CACxC,CAAC;YACN,KAAK,YAAY;gBACb,OAAO,IAAI,6BAAkB,CAAC,OAAO,CAAC,CAAC;YAC3C,KAAK,gBAAgB;gBACjB,OAAO,IAAI,iCAAsB,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;YAChE;gBACI,OAAO,IAAI,CAAC,yBAAyB,EAAE,CAAC;QAChD,CAAC;IACL,CAAC;IAED,uIAAuI;IAC/H,MAAM,CAAC,KAAK,CAAC,OAAe,EAAE,UAAmB,EAAE,SAAkB;QACzE,IAAI,CAAC,wBAAa,CAAC,YAAY,CAAC,UAAU,CAAC;YAAE,OAAO,IAAI,CAAC,yBAAyB,EAAE,CAAC;QACrF,OAAO,IAAI,wBAAa,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IACxE,CAAC;IAED,oGAAoG;IAC5F,MAAM,CAAC,yBAAyB;QACpC,OAAO,IAAI,iCAAsB,CAAC,gBAAgB,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IACzE,CAAC;IAED,+EAA+E;IACvE,MAAM,CAAC,aAAa,CAAC,KAAY,EAAE,IAAkB;QACzD,IAAI,KAAK,YAAY,0BAAe;YAAE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAC1E,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,uIAAuI;IAC/H,MAAM,CAAC,IAAI,CAAC,KAAc;QAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxE,CAAC;IAED,6GAA6G;IAC7G,uIAAuI;IAC/H,MAAM,CAAC,UAAU,CAAC,KAAc;QACpC,OAAO,0BAAe,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IACvE,CAAC;IAED,uIAAuI;IAC/H,MAAM,CAAC,IAAI,CAAC,KAAc;QAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;YACpE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC;YACxB,CAAC,CAAC,SAAS,CAAC;IACpB,CAAC;IAED,wJAAwJ;IAChJ,MAAM,CAAC,OAAO,CAAC,IAAa;QAChC,QAAQ,IAAI,EAAE,CAAC;YACX,KAAK,UAAU;gBACX,OAAO,gBAAgB,CAAC;YAC5B,KAAK,aAAa;gBACd,OAAO,aAAa,CAAC;YACzB,KAAK,cAAc;gBACf,OAAO,cAAc,CAAC;YAC1B,KAAK,WAAW;gBACZ,OAAO,WAAW,CAAC;YACvB,KAAK,WAAW;gBACZ,OAAO,WAAW,CAAC;YACvB,KAAK,oBAAoB;gBACrB,OAAO,oBAAoB,CAAC;YAChC,KAAK,iBAAiB;gBAClB,OAAO,iBAAiB,CAAC;YAC7B,KAAK,cAAc;gBACf,OAAO,cAAc,CAAC;YAC1B,KAAK,UAAU;gBACX,OAAO,UAAU,CAAC;YACtB,KAAK,eAAe;gBAChB,OAAO,uBAAuB,CAAC;YACnC,KAAK,qBAAqB;gBACtB,OAAO,qBAAqB,CAAC;YACjC,KAAK,wBAAwB;gBACzB,OAAO,wBAAwB,CAAC;YACpC,KAAK,iBAAiB;gBAClB,OAAO,iBAAiB,CAAC;YAC7B,KAAK,OAAO;gBACR,OAAO,gBAAgB,CAAC;YAC5B,KAAK,YAAY;gBACb,OAAO,kBAAkB,CAAC;YAC9B,KAAK,aAAa;gBACd,OAAO,qBAAqB,CAAC;YACjC,KAAK,oBAAoB;gBACrB,OAAO,oBAAoB,CAAC;YAChC,KAAK,oBAAoB;gBACrB,OAAO,wBAAwB,CAAC;YACpC,KAAK,YAAY;gBACb,OAAO,kBAAkB,CAAC;YAC9B;gBACI,OAAO,gBAAgB,CAAC;QAChC,CAAC;IACL,CAAC;IAEO,MAAM,CAAU,KAAK,GAA8B,IAAI,GAAG,CAAe;QAC7E,UAAU;QACV,aAAa;QACb,cAAc;QACd,WAAW;QACX,WAAW;QACX,oBAAoB;QACpB,iBAAiB;QACjB,cAAc;QACd,UAAU;QACV,eAAe;QACf,qBAAqB;QACrB,wBAAwB;QACxB,iBAAiB;QACjB,OAAO;QACP,gBAAgB;QAChB,YAAY;QACZ,aAAa;QACb,oBAAoB;QACpB,oBAAoB;QACpB,YAAY;KACf,CAAC,CAAC;;AApPP,sCAqPC","sourcesContent":["import {\n ApiBadRequestError,\n ApiCodedError,\n ApiConflictError,\n ApiConnectionError,\n ApiDependencyBackoffError,\n ApiDependencyError,\n ApiDependencyTimeoutError,\n ApiEndpointNotFoundError,\n ApiEndUserError,\n ApiError,\n ApiErrorKind,\n ApiForbiddenError,\n ApiImplementationError,\n ApiNotFoundError,\n ApiNotImplementedError,\n ApiPreconditionFailedError,\n ApiRateLimitedError,\n ApiRequestTimeoutError,\n ApiUnauthorizedError,\n ApiUnavailableError,\n ApiUnprocessableError,\n ApiUnsupportedMediaTypeError,\n EdgeHttpStatus,\n} from './ApiError';\nimport { toError } from '../lib/errorUtils';\n\n/** Allowlisted transport-neutral envelope. It never contains stacks or arbitrary properties. */\nexport class ApiErrorPayload {\n public cause?: ApiErrorPayload;\n public subType?: string;\n public field?: string;\n public callerMessage?: string;\n public errorCode?: string;\n public retryAfterSeconds?: number;\n public statusCode?: number;\n /** {@link ApiEndUserError.edgeHttpStatus}; absent when the thrower (or an older peer) set none. */\n public edgeHttpStatus?: number;\n\n constructor(\n public kind: string = 'implementation',\n public message: string = 'Internal Error',\n ) {}\n}\n\n/** Bounded safe codec shared by HTTP, IPC, and other remote adapters. */\nexport class ApiErrorCodec {\n /**\n * Encode a thrown error faithfully. The input is an `Error`, never `unknown`: every caller in\n * the framework has already narrowed with `toError` at its catch, and the `unknown` this used to\n * advertise leaked out of the PRIVATE `.cause` recursion below (`Error.cause` is typed `unknown`\n * in TypeScript), which is an internal concern.\n *\n * This is the FAITHFUL encode: it publishes `kind` exactly as the error declares it. The\n * boundary rule that a caller-local `ApiConnectionError` publishes as `implementation` belongs\n * to {@link ApiErrorBoundary}, which every protocol edge uses instead of calling this directly.\n */\n // webpieces-disable no-function-outside-class -- stateless public transport codec\n static encode(error: Error): ApiErrorPayload {\n return this.encodeDepth(error, 0);\n }\n\n // webpieces-disable no-function-outside-class -- recursive bounded transport codec\n private static encodeDepth(error: Error, depth: number): ApiErrorPayload {\n const kind = error instanceof ApiError ? error.kind : 'implementation';\n const payload = new ApiErrorPayload(kind, this.publicMessage(error, kind));\n if (error instanceof ApiError) payload.subType = this.text(error.subType);\n if (error instanceof ApiEndUserError) {\n payload.errorCode = this.text(error.errorCode);\n payload.edgeHttpStatus = error.edgeHttpStatus;\n }\n if (error instanceof ApiCodedError) {\n payload.statusCode = error.statusCode;\n payload.errorCode = this.text(error.errorCode);\n }\n if (error instanceof ApiBadRequestError) {\n payload.field = this.text(error.field);\n payload.callerMessage = this.text(error.callerMessage);\n }\n if (error instanceof ApiDependencyBackoffError) {\n payload.retryAfterSeconds = this.wait(error.retryAfterSeconds);\n }\n if (depth < 3) {\n // `Error.cause` is `unknown` by construction, so the recursion narrows it with `toError`\n // exactly as a catch block would — and then deals only in `Error` like everything else.\n const cause = Object.getOwnPropertyDescriptor(error, 'cause')?.value;\n if (cause !== undefined && cause !== null) {\n payload.cause = this.encodeDepth(toError(cause), depth + 1);\n }\n }\n return payload;\n }\n\n /** Decode a value received from another process. Implementation failures are marked remote. */\n // webpieces-disable no-function-outside-class -- stateless public transport codec; webpieces-disable no-any-unknown -- wire values require validation\n static decode(value: unknown): ApiError {\n return this.decodeDepth(value, 0);\n }\n\n /** Whether a body carries a recognized Webpieces semantic discriminator. */\n // webpieces-disable no-function-outside-class -- stateless wire discriminator check; webpieces-disable no-any-unknown -- wire values require validation\n static isPayload(value: unknown): boolean {\n if (typeof value !== 'object' || value === null) return false;\n const kind = Object.getOwnPropertyDescriptor(value, 'kind')?.value;\n return typeof kind === 'string' && this.kinds.has(kind as ApiErrorKind);\n }\n\n // webpieces-disable no-function-outside-class -- recursive bounded transport codec; webpieces-disable no-any-unknown -- remote causes require validation\n private static decodeDepth(value: unknown, depth: number): ApiError {\n const error = this.decodeOne(value);\n if (typeof value === 'object' && value !== null && depth < 3) {\n const cause = Object.getOwnPropertyDescriptor(value, 'cause')?.value;\n if (typeof cause === 'object' && cause !== null) {\n // webpieces-disable no-anonymous-object-literals -- standard descriptor preserves Error.cause semantics\n Object.defineProperty(error, 'cause', {\n value: this.decodeDepth(cause, depth + 1),\n configurable: true,\n writable: true,\n });\n }\n }\n return error;\n }\n\n // webpieces-disable no-function-outside-class -- allowlisted wire codec; webpieces-disable no-any-unknown -- wire fields require validation\n private static decodeOne(value: unknown): ApiError {\n if (typeof value !== 'object' || value === null) return this.remoteImplementationError();\n // webpieces-disable no-any-unknown -- own wire fields remain untrusted until narrowed\n const field = (key: string): unknown => Object.getOwnPropertyDescriptor(value, key)?.value;\n const kind = field('kind');\n const message = this.text(field('message')) ?? this.message(kind);\n switch (kind) {\n case 'end-user':\n return new ApiEndUserError(\n message,\n this.text(field('errorCode')),\n this.edgeStatus(field('edgeHttpStatus')),\n );\n case 'bad-request':\n return new ApiBadRequestError(\n message,\n this.text(field('field')),\n this.text(field('callerMessage')),\n );\n case 'unauthorized':\n return new ApiUnauthorizedError(message, this.text(field('subType')));\n case 'forbidden':\n return new ApiForbiddenError(message);\n case 'not-found':\n return new ApiNotFoundError(message);\n case 'endpoint-not-found':\n return new ApiEndpointNotFoundError(message);\n case 'request-timeout':\n return new ApiRequestTimeoutError(message);\n case 'rate-limited':\n return new ApiRateLimitedError(message);\n case 'conflict':\n return new ApiConflictError(message);\n case 'unprocessable':\n return new ApiUnprocessableError(message);\n case 'precondition-failed':\n return new ApiPreconditionFailedError(message);\n case 'unsupported-media-type':\n return new ApiUnsupportedMediaTypeError(message);\n case 'not-implemented':\n return new ApiNotImplementedError(message);\n case 'coded':\n return this.coded(message, field('statusCode'), field('errorCode'));\n case 'dependency':\n return new ApiDependencyError(message);\n case 'unavailable':\n return new ApiUnavailableError(message);\n case 'dependency-timeout':\n return new ApiDependencyTimeoutError(message);\n case 'dependency-backoff':\n return new ApiDependencyBackoffError(\n message,\n this.wait(field('retryAfterSeconds')),\n );\n case 'connection':\n return new ApiConnectionError(message);\n case 'implementation':\n return new ApiImplementationError(message, undefined, true);\n default:\n return this.remoteImplementationError();\n }\n }\n\n // webpieces-disable no-function-outside-class -- coded wire decode; webpieces-disable no-any-unknown -- wire fields require validation\n private static coded(message: string, statusCode: unknown, errorCode: unknown): ApiError {\n if (!ApiCodedError.isStatusCode(statusCode)) return this.remoteImplementationError();\n return new ApiCodedError(message, statusCode, this.text(errorCode));\n }\n\n // webpieces-disable no-function-outside-class -- concrete normalization for malformed remote errors\n private static remoteImplementationError(): ApiImplementationError {\n return new ApiImplementationError('Internal Error', undefined, true);\n }\n\n // webpieces-disable no-function-outside-class -- caller-safe message selection\n private static publicMessage(error: Error, kind: ApiErrorKind): string {\n if (error instanceof ApiEndUserError) return error.message.slice(0, 4096);\n return this.message(kind);\n }\n\n // webpieces-disable no-function-outside-class -- wire string bound; webpieces-disable no-any-unknown -- wire values require validation\n private static text(value: unknown): string | undefined {\n return typeof value === 'string' ? value.slice(0, 4096) : undefined;\n }\n\n /** Tolerant: a peer that sends nothing, or a status outside {@link EdgeHttpStatus}, decodes as undefined. */\n // webpieces-disable no-function-outside-class -- wire status bound; webpieces-disable no-any-unknown -- wire values require validation\n private static edgeStatus(value: unknown): EdgeHttpStatus | undefined {\n return ApiEndUserError.isEdgeHttpStatus(value) ? value : undefined;\n }\n\n // webpieces-disable no-function-outside-class -- wire number bound; webpieces-disable no-any-unknown -- wire values require validation\n private static wait(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0\n ? Math.min(value, 86400)\n : undefined;\n }\n\n // webpieces-disable no-function-outside-class -- allowlisted generic messages; webpieces-disable no-any-unknown -- discriminator is validated by switch\n private static message(kind: unknown): string {\n switch (kind) {\n case 'end-user':\n return 'End User Error';\n case 'bad-request':\n return 'Bad Request';\n case 'unauthorized':\n return 'Unauthorized';\n case 'forbidden':\n return 'Forbidden';\n case 'not-found':\n return 'Not Found';\n case 'endpoint-not-found':\n return 'Endpoint Not Found';\n case 'request-timeout':\n return 'Request Timeout';\n case 'rate-limited':\n return 'Rate Limited';\n case 'conflict':\n return 'Conflict';\n case 'unprocessable':\n return 'Unprocessable Content';\n case 'precondition-failed':\n return 'Precondition Failed';\n case 'unsupported-media-type':\n return 'Unsupported Media Type';\n case 'not-implemented':\n return 'Not Implemented';\n case 'coded':\n return 'Request Failed';\n case 'dependency':\n return 'Dependency Error';\n case 'unavailable':\n return 'Service Unavailable';\n case 'dependency-timeout':\n return 'Dependency Timeout';\n case 'dependency-backoff':\n return 'Dependency Unavailable';\n case 'connection':\n return 'Connection Error';\n default:\n return 'Internal Error';\n }\n }\n\n private static readonly kinds: ReadonlySet<ApiErrorKind> = new Set<ApiErrorKind>([\n 'end-user',\n 'bad-request',\n 'unauthorized',\n 'forbidden',\n 'not-found',\n 'endpoint-not-found',\n 'request-timeout',\n 'rate-limited',\n 'conflict',\n 'unprocessable',\n 'precondition-failed',\n 'unsupported-media-type',\n 'not-implemented',\n 'coded',\n 'implementation',\n 'dependency',\n 'unavailable',\n 'dependency-timeout',\n 'dependency-backoff',\n 'connection',\n ]);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ApiErrorCodec.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/errors/ApiErrorCodec.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ApiBadRequestError,\n ApiBadGatewayError,\n ApiCodedError,\n ApiConflictError,\n ApiConnectionError,\n ApiDependencyBackoffError,\n ApiDependencyError,\n ApiDependencyTimeoutError,\n ApiEndpointNotFoundError,\n ApiEndUserError,\n ApiError,\n ApiErrorKind,\n ApiForbiddenError,\n ApiImplementationError,\n ApiNotFoundError,\n ApiNotImplementedError,\n ApiPreconditionFailedError,\n ApiRateLimitedError,\n ApiRequestTimeoutError,\n ApiUnauthorizedError,\n ApiUnavailableError,\n ApiUnprocessableError,\n ApiUnsupportedMediaTypeError,\n EdgeHttpStatus,\n} from './ApiError';\nimport { toError } from '../lib/errorUtils';\n\n/** Allowlisted transport-neutral envelope. It never contains stacks or arbitrary properties. */\nexport class ApiErrorPayload {\n public cause?: ApiErrorPayload;\n public subType?: string;\n public field?: string;\n public callerMessage?: string;\n public errorCode?: string;\n public retryAfterSeconds?: number;\n public statusCode?: number;\n /** {@link ApiEndUserError.edgeHttpStatus}; absent when the thrower (or an older peer) set none. */\n public edgeHttpStatus?: number;\n\n constructor(\n public kind: string = 'implementation',\n public message: string = 'Internal Error',\n ) {}\n}\n\n/** Bounded safe codec shared by HTTP, IPC, and other remote adapters. */\nexport class ApiErrorCodec {\n /**\n * Encode a thrown error faithfully. The input is an `Error`, never `unknown`: every caller in\n * the framework has already narrowed with `toError` at its catch, and the `unknown` this used to\n * advertise leaked out of the PRIVATE `.cause` recursion below (`Error.cause` is typed `unknown`\n * in TypeScript), which is an internal concern.\n *\n * This is the FAITHFUL encode: it publishes `kind` exactly as the error declares it. The\n * boundary rule that a caller-local `ApiConnectionError` publishes as `implementation` belongs\n * to {@link ApiErrorBoundary}, which every protocol edge uses instead of calling this directly.\n */\n // webpieces-disable no-function-outside-class -- stateless public transport codec\n static encode(error: Error): ApiErrorPayload {\n return this.encodeDepth(error, 0);\n }\n\n // webpieces-disable no-function-outside-class -- recursive bounded transport codec\n private static encodeDepth(error: Error, depth: number): ApiErrorPayload {\n const kind = error instanceof ApiError ? error.kind : 'implementation';\n const payload = new ApiErrorPayload(kind, this.publicMessage(error, kind));\n if (error instanceof ApiError) payload.subType = this.text(error.subType);\n if (error instanceof ApiEndUserError) {\n payload.errorCode = this.text(error.errorCode);\n payload.edgeHttpStatus = error.edgeHttpStatus;\n }\n if (error instanceof ApiCodedError) {\n payload.statusCode = error.statusCode;\n payload.errorCode = this.text(error.errorCode);\n }\n if (error instanceof ApiBadRequestError) {\n payload.field = this.text(error.field);\n payload.callerMessage = this.text(error.callerMessage);\n }\n if (error instanceof ApiDependencyBackoffError) {\n payload.retryAfterSeconds = this.wait(error.retryAfterSeconds);\n }\n if (depth < 3) {\n // `Error.cause` is `unknown` by construction, so the recursion narrows it with `toError`\n // exactly as a catch block would — and then deals only in `Error` like everything else.\n const cause = Object.getOwnPropertyDescriptor(error, 'cause')?.value;\n if (cause !== undefined && cause !== null) {\n payload.cause = this.encodeDepth(toError(cause), depth + 1);\n }\n }\n return payload;\n }\n\n /** Decode a value received from another process. Implementation failures are marked remote. */\n // webpieces-disable no-function-outside-class -- stateless public transport codec; webpieces-disable no-any-unknown -- wire values require validation\n static decode(value: unknown): ApiError {\n return this.decodeDepth(value, 0);\n }\n\n /** Whether a body carries a recognized Webpieces semantic discriminator. */\n // webpieces-disable no-function-outside-class -- stateless wire discriminator check; webpieces-disable no-any-unknown -- wire values require validation\n static isPayload(value: unknown): boolean {\n if (typeof value !== 'object' || value === null) return false;\n const kind = Object.getOwnPropertyDescriptor(value, 'kind')?.value;\n return typeof kind === 'string' && this.kinds.has(kind as ApiErrorKind);\n }\n\n // webpieces-disable no-function-outside-class -- recursive bounded transport codec; webpieces-disable no-any-unknown -- remote causes require validation\n private static decodeDepth(value: unknown, depth: number): ApiError {\n const error = this.decodeOne(value);\n if (typeof value === 'object' && value !== null && depth < 3) {\n const cause = Object.getOwnPropertyDescriptor(value, 'cause')?.value;\n if (typeof cause === 'object' && cause !== null) {\n // webpieces-disable no-anonymous-object-literals -- standard descriptor preserves Error.cause semantics\n Object.defineProperty(error, 'cause', {\n value: this.decodeDepth(cause, depth + 1),\n configurable: true,\n writable: true,\n });\n }\n }\n return error;\n }\n\n // webpieces-disable no-function-outside-class -- allowlisted wire codec; webpieces-disable no-any-unknown -- wire fields require validation\n private static decodeOne(value: unknown): ApiError {\n if (typeof value !== 'object' || value === null) return this.remoteImplementationError();\n // webpieces-disable no-any-unknown -- own wire fields remain untrusted until narrowed\n const field = (key: string): unknown => Object.getOwnPropertyDescriptor(value, key)?.value;\n const kind = field('kind');\n const message = this.text(field('message')) ?? this.message(kind);\n switch (kind) {\n case 'end-user':\n return new ApiEndUserError(\n message,\n this.text(field('errorCode')),\n this.edgeStatus(field('edgeHttpStatus')),\n );\n case 'bad-request':\n return new ApiBadRequestError(\n message,\n this.text(field('field')),\n this.text(field('callerMessage')),\n );\n case 'unauthorized':\n return new ApiUnauthorizedError(message, this.text(field('subType')));\n case 'forbidden':\n return new ApiForbiddenError(message);\n case 'not-found':\n return new ApiNotFoundError(message);\n case 'endpoint-not-found':\n return new ApiEndpointNotFoundError(message);\n case 'request-timeout':\n return new ApiRequestTimeoutError(message);\n case 'rate-limited':\n return new ApiRateLimitedError(message);\n case 'conflict':\n return new ApiConflictError(message);\n case 'unprocessable':\n return new ApiUnprocessableError(message);\n case 'precondition-failed':\n return new ApiPreconditionFailedError(message);\n case 'unsupported-media-type':\n return new ApiUnsupportedMediaTypeError(message);\n case 'not-implemented':\n return new ApiNotImplementedError(message);\n case 'coded':\n return this.coded(message, field('statusCode'), field('errorCode'));\n case 'dependency':\n return new ApiDependencyError(message);\n case 'bad-gateway':\n return new ApiBadGatewayError(message);\n case 'unavailable':\n return new ApiUnavailableError(message);\n case 'dependency-timeout':\n return new ApiDependencyTimeoutError(message);\n case 'dependency-backoff':\n return new ApiDependencyBackoffError(\n message,\n this.wait(field('retryAfterSeconds')),\n );\n case 'connection':\n return new ApiConnectionError(message);\n case 'implementation':\n return new ApiImplementationError(message, undefined, true);\n default:\n return this.remoteImplementationError();\n }\n }\n\n // webpieces-disable no-function-outside-class -- coded wire decode; webpieces-disable no-any-unknown -- wire fields require validation\n private static coded(message: string, statusCode: unknown, errorCode: unknown): ApiError {\n if (!ApiCodedError.isStatusCode(statusCode)) return this.remoteImplementationError();\n return new ApiCodedError(message, statusCode, this.text(errorCode));\n }\n\n // webpieces-disable no-function-outside-class -- concrete normalization for malformed remote errors\n private static remoteImplementationError(): ApiImplementationError {\n return new ApiImplementationError('Internal Error', undefined, true);\n }\n\n // webpieces-disable no-function-outside-class -- caller-safe message selection\n private static publicMessage(error: Error, kind: ApiErrorKind): string {\n if (error instanceof ApiEndUserError) return error.message.slice(0, 4096);\n return this.message(kind);\n }\n\n // webpieces-disable no-function-outside-class -- wire string bound; webpieces-disable no-any-unknown -- wire values require validation\n private static text(value: unknown): string | undefined {\n return typeof value === 'string' ? value.slice(0, 4096) : undefined;\n }\n\n /** Tolerant: a peer that sends nothing, or a status outside {@link EdgeHttpStatus}, decodes as undefined. */\n // webpieces-disable no-function-outside-class -- wire status bound; webpieces-disable no-any-unknown -- wire values require validation\n private static edgeStatus(value: unknown): EdgeHttpStatus | undefined {\n return ApiEndUserError.isEdgeHttpStatus(value) ? value : undefined;\n }\n\n // webpieces-disable no-function-outside-class -- wire number bound; webpieces-disable no-any-unknown -- wire values require validation\n private static wait(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0\n ? Math.min(value, 86400)\n : undefined;\n }\n\n // webpieces-disable no-function-outside-class -- allowlisted generic messages; webpieces-disable no-any-unknown -- discriminator is validated by switch\n private static message(kind: unknown): string {\n switch (kind) {\n case 'end-user':\n return 'End User Error';\n case 'bad-request':\n return 'Bad Request';\n case 'unauthorized':\n return 'Unauthorized';\n case 'forbidden':\n return 'Forbidden';\n case 'not-found':\n return 'Not Found';\n case 'endpoint-not-found':\n return 'Endpoint Not Found';\n case 'request-timeout':\n return 'Request Timeout';\n case 'rate-limited':\n return 'Rate Limited';\n case 'conflict':\n return 'Conflict';\n case 'unprocessable':\n return 'Unprocessable Content';\n case 'precondition-failed':\n return 'Precondition Failed';\n case 'unsupported-media-type':\n return 'Unsupported Media Type';\n case 'not-implemented':\n return 'Not Implemented';\n case 'coded':\n return 'Request Failed';\n case 'dependency':\n return 'Dependency Error';\n case 'bad-gateway':\n return 'Bad Gateway';\n case 'unavailable':\n return 'Service Unavailable';\n case 'dependency-timeout':\n return 'Dependency Timeout';\n case 'dependency-backoff':\n return 'Dependency Unavailable';\n case 'connection':\n return 'Connection Error';\n default:\n return 'Internal Error';\n }\n }\n\n private static readonly kinds: ReadonlySet<ApiErrorKind> = new Set<ApiErrorKind>([\n 'end-user',\n 'bad-request',\n 'unauthorized',\n 'forbidden',\n 'not-found',\n 'endpoint-not-found',\n 'request-timeout',\n 'rate-limited',\n 'conflict',\n 'unprocessable',\n 'precondition-failed',\n 'unsupported-media-type',\n 'not-implemented',\n 'coded',\n 'implementation',\n 'dependency',\n 'bad-gateway',\n 'unavailable',\n 'dependency-timeout',\n 'dependency-backoff',\n 'connection',\n ]);\n}\n"]}
|
|
@@ -6,14 +6,16 @@ import { ApiError } from './ApiError';
|
|
|
6
6
|
* A status a peer answered describes OUR request to it. It is never, by itself, an answer for our
|
|
7
7
|
* own caller, and the two ways it can be wrong have OPPOSITE owners:
|
|
8
8
|
*
|
|
9
|
-
* - **caller-error status (4xx-equivalent) -> {@link ApiImplementationError}.** WE sent a bad request,
|
|
9
|
+
* - **ordinary caller-error status (4xx-equivalent) -> {@link ApiImplementationError}.** WE sent a bad request,
|
|
10
10
|
* called a path that does not exist, or presented the wrong credentials. MY bug. The peer that
|
|
11
11
|
* answered 404 is correct.
|
|
12
|
-
* - **server-error status (5xx-equivalent) -> {@link ApiDependencyError}.** THEY broke. Not my bug,
|
|
12
|
+
* - **ordinary server-error status (5xx-equivalent) -> {@link ApiDependencyError}.** THEY broke. Not my bug,
|
|
13
13
|
* so this process's failure metrics stay clean and page the right team.
|
|
14
14
|
* - **an {@link ApiDependencyError} coming back -> rethrown AS-IS.** The fault is already attributed,
|
|
15
15
|
* somewhere further downstream; this hop adds nothing by re-wrapping it, and re-wrapping would bury
|
|
16
16
|
* the original message one `cause` deeper on every hop of a chain.
|
|
17
|
+
* - **408/429/502/503/504 preserve retry-relevant semantics.** Timeout, backoff, bad-gateway and
|
|
18
|
+
* unavailable must not collapse into the generic non-retryable dependency bucket.
|
|
17
19
|
* - **266 / `end-user` -> {@link ApiEndUserError}**, the intended user-facing message, published
|
|
18
20
|
* verbatim. It is the one message the taxonomy lets a peer write for a human.
|
|
19
21
|
*
|
|
@@ -39,5 +41,5 @@ export declare class ReceivedApiErrorRule {
|
|
|
39
41
|
* @param decoded - the peer's own typed error when the body was a webpieces `ApiErrorPayload`.
|
|
40
42
|
* Absent for a foreign responder.
|
|
41
43
|
*/
|
|
42
|
-
static adapt(statusCode: number, message: string, decoded?: ApiError): Error;
|
|
44
|
+
static adapt(statusCode: number, message: string, decoded?: ApiError, retryAfterSeconds?: number): Error;
|
|
43
45
|
}
|
|
@@ -9,14 +9,16 @@ const ApiError_1 = require("./ApiError");
|
|
|
9
9
|
* A status a peer answered describes OUR request to it. It is never, by itself, an answer for our
|
|
10
10
|
* own caller, and the two ways it can be wrong have OPPOSITE owners:
|
|
11
11
|
*
|
|
12
|
-
* - **caller-error status (4xx-equivalent) -> {@link ApiImplementationError}.** WE sent a bad request,
|
|
12
|
+
* - **ordinary caller-error status (4xx-equivalent) -> {@link ApiImplementationError}.** WE sent a bad request,
|
|
13
13
|
* called a path that does not exist, or presented the wrong credentials. MY bug. The peer that
|
|
14
14
|
* answered 404 is correct.
|
|
15
|
-
* - **server-error status (5xx-equivalent) -> {@link ApiDependencyError}.** THEY broke. Not my bug,
|
|
15
|
+
* - **ordinary server-error status (5xx-equivalent) -> {@link ApiDependencyError}.** THEY broke. Not my bug,
|
|
16
16
|
* so this process's failure metrics stay clean and page the right team.
|
|
17
17
|
* - **an {@link ApiDependencyError} coming back -> rethrown AS-IS.** The fault is already attributed,
|
|
18
18
|
* somewhere further downstream; this hop adds nothing by re-wrapping it, and re-wrapping would bury
|
|
19
19
|
* the original message one `cause` deeper on every hop of a chain.
|
|
20
|
+
* - **408/429/502/503/504 preserve retry-relevant semantics.** Timeout, backoff, bad-gateway and
|
|
21
|
+
* unavailable must not collapse into the generic non-retryable dependency bucket.
|
|
20
22
|
* - **266 / `end-user` -> {@link ApiEndUserError}**, the intended user-facing message, published
|
|
21
23
|
* verbatim. It is the one message the taxonomy lets a peer write for a human.
|
|
22
24
|
*
|
|
@@ -43,14 +45,31 @@ class ReceivedApiErrorRule {
|
|
|
43
45
|
* Absent for a foreign responder.
|
|
44
46
|
*/
|
|
45
47
|
// webpieces-disable no-function-outside-class -- stateless shared rule, called by both protocol translators
|
|
46
|
-
static adapt(statusCode, message, decoded) {
|
|
48
|
+
static adapt(statusCode, message, decoded, retryAfterSeconds) {
|
|
47
49
|
// 266 is protocol SUCCESS carrying the actor's own answer — the one message published verbatim.
|
|
48
50
|
if (statusCode === 266) {
|
|
49
51
|
return decoded instanceof ApiError_1.ApiEndUserError ? decoded : new ApiError_1.ApiEndUserError(message);
|
|
50
52
|
}
|
|
51
|
-
if (decoded instanceof ApiError_1.ApiDependencyError
|
|
53
|
+
if (decoded instanceof ApiError_1.ApiDependencyError ||
|
|
54
|
+
decoded instanceof ApiError_1.ApiBadGatewayError ||
|
|
55
|
+
decoded instanceof ApiError_1.ApiUnavailableError ||
|
|
56
|
+
decoded instanceof ApiError_1.ApiDependencyTimeoutError ||
|
|
57
|
+
decoded instanceof ApiError_1.ApiDependencyBackoffError) {
|
|
52
58
|
return decoded;
|
|
53
59
|
}
|
|
60
|
+
if (statusCode === 408 || statusCode === 504) {
|
|
61
|
+
return new ApiError_1.ApiDependencyTimeoutError(`dependency timed out with HTTP ${statusCode}. Downstream said: ${message}`, decoded);
|
|
62
|
+
}
|
|
63
|
+
if (statusCode === 429 || (statusCode === 503 && retryAfterSeconds !== undefined)) {
|
|
64
|
+
return new ApiError_1.ApiDependencyBackoffError(`dependency asked this service to back off after HTTP ${statusCode}. ` +
|
|
65
|
+
`Downstream said: ${message}`, retryAfterSeconds, decoded);
|
|
66
|
+
}
|
|
67
|
+
if (statusCode === 502) {
|
|
68
|
+
return new ApiError_1.ApiBadGatewayError(`gateway answered HTTP 502. Downstream said: ${message}`, decoded);
|
|
69
|
+
}
|
|
70
|
+
if (statusCode === 503) {
|
|
71
|
+
return new ApiError_1.ApiUnavailableError(`dependency is unavailable (HTTP 503). Downstream said: ${message}`, decoded);
|
|
72
|
+
}
|
|
54
73
|
if (statusCode >= 500) {
|
|
55
74
|
return new ApiError_1.ApiDependencyError(`dependency answered ${statusCode} — it is broken, not this service. ` +
|
|
56
75
|
`Downstream said: ${message}`, decoded);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReceivedApiErrorRule.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/errors/ReceivedApiErrorRule.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"ReceivedApiErrorRule.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/errors/ReceivedApiErrorRule.ts"],"names":[],"mappings":";;;AAAA,yCASoB;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAa,oBAAoB;IAC7B;;;;;;;;OAQG;IACH,4GAA4G;IAC5G,MAAM,CAAC,KAAK,CACR,UAAkB,EAClB,OAAe,EACf,OAAkB,EAClB,iBAA0B;QAE1B,gGAAgG;QAChG,IAAI,UAAU,KAAK,GAAG,EAAE,CAAC;YACrB,OAAO,OAAO,YAAY,0BAAe,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,0BAAe,CAAC,OAAO,CAAC,CAAC;QACvF,CAAC;QACD,IACI,OAAO,YAAY,6BAAkB;YACrC,OAAO,YAAY,6BAAkB;YACrC,OAAO,YAAY,8BAAmB;YACtC,OAAO,YAAY,oCAAyB;YAC5C,OAAO,YAAY,oCAAyB,EAC9C,CAAC;YACC,OAAO,OAAO,CAAC;QACnB,CAAC;QACD,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,GAAG,EAAE,CAAC;YAC3C,OAAO,IAAI,oCAAyB,CAChC,kCAAkC,UAAU,sBAAsB,OAAO,EAAE,EAC3E,OAAO,CACV,CAAC;QACN,CAAC;QACD,IAAI,UAAU,KAAK,GAAG,IAAI,CAAC,UAAU,KAAK,GAAG,IAAI,iBAAiB,KAAK,SAAS,CAAC,EAAE,CAAC;YAChF,OAAO,IAAI,oCAAyB,CAChC,wDAAwD,UAAU,IAAI;gBAClE,oBAAoB,OAAO,EAAE,EACjC,iBAAiB,EACjB,OAAO,CACV,CAAC;QACN,CAAC;QACD,IAAI,UAAU,KAAK,GAAG,EAAE,CAAC;YACrB,OAAO,IAAI,6BAAkB,CACzB,+CAA+C,OAAO,EAAE,EACxD,OAAO,CACV,CAAC;QACN,CAAC;QACD,IAAI,UAAU,KAAK,GAAG,EAAE,CAAC;YACrB,OAAO,IAAI,8BAAmB,CAC1B,0DAA0D,OAAO,EAAE,EACnE,OAAO,CACV,CAAC;QACN,CAAC;QACD,IAAI,UAAU,IAAI,GAAG,EAAE,CAAC;YACpB,OAAO,IAAI,6BAAkB,CACzB,uBAAuB,UAAU,qCAAqC;gBAClE,oBAAoB,OAAO,EAAE,EACjC,OAAO,CACV,CAAC;QACN,CAAC;QACD,OAAO,IAAI,iCAAsB,CAC7B,uBAAuB,UAAU,oDAAoD;YACjF,iFAAiF;YACjF,mEAAmE;YACnE,oBAAoB,OAAO,EAAE,EACjC,OAAO,CACV,CAAC;IACN,CAAC;CACJ;AAvED,oDAuEC","sourcesContent":["import {\n ApiBadGatewayError,\n ApiDependencyBackoffError,\n ApiDependencyError,\n ApiDependencyTimeoutError,\n ApiEndUserError,\n ApiError,\n ApiImplementationError,\n ApiUnavailableError,\n} from './ApiError';\n\n/**\n * THE rule for an error this process RECEIVED from another one — identical over HTTP and over IPC,\n * which is why it lives here and not in either protocol's translator.\n *\n * A status a peer answered describes OUR request to it. It is never, by itself, an answer for our\n * own caller, and the two ways it can be wrong have OPPOSITE owners:\n *\n * - **ordinary caller-error status (4xx-equivalent) -> {@link ApiImplementationError}.** WE sent a bad request,\n * called a path that does not exist, or presented the wrong credentials. MY bug. The peer that\n * answered 404 is correct.\n * - **ordinary server-error status (5xx-equivalent) -> {@link ApiDependencyError}.** THEY broke. Not my bug,\n * so this process's failure metrics stay clean and page the right team.\n * - **an {@link ApiDependencyError} coming back -> rethrown AS-IS.** The fault is already attributed,\n * somewhere further downstream; this hop adds nothing by re-wrapping it, and re-wrapping would bury\n * the original message one `cause` deeper on every hop of a chain.\n * - **408/429/502/503/504 preserve retry-relevant semantics.** Timeout, backoff, bad-gateway and\n * unavailable must not collapse into the generic non-retryable dependency bucket.\n * - **266 / `end-user` -> {@link ApiEndUserError}**, the intended user-facing message, published\n * verbatim. It is the one message the taxonomy lets a peer write for a human.\n *\n * # Why this is UNIFORM, in a browser as much as in a server\n *\n * An earlier design made the browser pass a received status through unchanged on the theory that\n * \"the browser IS the user's agent, so a 404 is the user's answer\". That is wrong. If a browser\n * received a 404 the browser called the wrong path — that is the BROWSER's bug, and the code that\n * catches it wants to know that, not to show a user a spinner. Read in a browser this reads exactly\n * as intended: `ApiImplementationError` means the client has a bug, `ApiDependencyError` means the\n * server has one.\n *\n * An app that genuinely wants a peer's status relayed as its OWN typed error says so out loud, in one\n * greppable place, by throwing it from its registered translator's `fromWire`.\n */\nexport class ReceivedApiErrorRule {\n /**\n * @param statusCode - the HTTP status the peer published. IPC has no wire status, so it derives\n * the equivalent from the payload's `kind` through the same `ApiErrorHttpStatus` table — one\n * table, so the two protocols cannot drift apart.\n * @param message - the text to carry forward: the decoded payload's message, else whatever the\n * transport could salvage from the body.\n * @param decoded - the peer's own typed error when the body was a webpieces `ApiErrorPayload`.\n * Absent for a foreign responder.\n */\n // webpieces-disable no-function-outside-class -- stateless shared rule, called by both protocol translators\n static adapt(\n statusCode: number,\n message: string,\n decoded?: ApiError,\n retryAfterSeconds?: number,\n ): Error {\n // 266 is protocol SUCCESS carrying the actor's own answer — the one message published verbatim.\n if (statusCode === 266) {\n return decoded instanceof ApiEndUserError ? decoded : new ApiEndUserError(message);\n }\n if (\n decoded instanceof ApiDependencyError ||\n decoded instanceof ApiBadGatewayError ||\n decoded instanceof ApiUnavailableError ||\n decoded instanceof ApiDependencyTimeoutError ||\n decoded instanceof ApiDependencyBackoffError\n ) {\n return decoded;\n }\n if (statusCode === 408 || statusCode === 504) {\n return new ApiDependencyTimeoutError(\n `dependency timed out with HTTP ${statusCode}. Downstream said: ${message}`,\n decoded,\n );\n }\n if (statusCode === 429 || (statusCode === 503 && retryAfterSeconds !== undefined)) {\n return new ApiDependencyBackoffError(\n `dependency asked this service to back off after HTTP ${statusCode}. ` +\n `Downstream said: ${message}`,\n retryAfterSeconds,\n decoded,\n );\n }\n if (statusCode === 502) {\n return new ApiBadGatewayError(\n `gateway answered HTTP 502. Downstream said: ${message}`,\n decoded,\n );\n }\n if (statusCode === 503) {\n return new ApiUnavailableError(\n `dependency is unavailable (HTTP 503). Downstream said: ${message}`,\n decoded,\n );\n }\n if (statusCode >= 500) {\n return new ApiDependencyError(\n `dependency answered ${statusCode} — it is broken, not this service. ` +\n `Downstream said: ${message}`,\n decoded,\n );\n }\n return new ApiImplementationError(\n `dependency answered ${statusCode}. That status describes OUR request to it, not an ` +\n `answer for our caller, so this service owns it — check the path, the base URL, ` +\n `whether the dependency is deployed, and our service credentials. ` +\n `Downstream said: ${message}`,\n decoded,\n );\n }\n}\n"]}
|
package/src/errors/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ApiError, ApiNotFoundError, ApiDependencyError, ApiUnavailableError, ApiDependencyTimeoutError, ApiImplementationError, ApiRateLimitedError, ApiForbiddenError, ApiRequestTimeoutError, ApiConnectionError, ApiEndpointNotFoundError, ApiEndUserError, ApiBadRequestError, ApiUnauthorizedError, ApiDependencyBackoffError, ApiConflictError, ApiUnprocessableError, ApiPreconditionFailedError, ApiUnsupportedMediaTypeError, ApiNotImplementedError, ApiCodedError, } from './ApiError';
|
|
1
|
+
export { ApiError, ApiNotFoundError, ApiDependencyError, ApiBadGatewayError, ApiUnavailableError, ApiDependencyTimeoutError, ApiImplementationError, ApiRateLimitedError, ApiForbiddenError, ApiRequestTimeoutError, ApiConnectionError, ApiEndpointNotFoundError, ApiEndUserError, ApiBadRequestError, ApiUnauthorizedError, ApiDependencyBackoffError, ApiConflictError, ApiUnprocessableError, ApiPreconditionFailedError, ApiUnsupportedMediaTypeError, ApiNotImplementedError, ApiCodedError, } from './ApiError';
|
|
2
2
|
export type { ApiErrorKind, ApiStatusCode, EdgeHttpStatus } from './ApiError';
|
|
3
3
|
export { ApiErrorCodec, ApiErrorPayload } from './ApiErrorCodec';
|
|
4
4
|
export { ApiErrorBoundary } from './ApiErrorBoundary';
|
package/src/errors/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NO_REG_CODE = exports.WRONG_COMPANY = exports.WRONG_DOMAIN = exports.EMAIL_NOT_CONFIRMED = exports.NOT_APPROVED = exports.WRONG_LOGIN = exports.WRONG_LOGIN_TYPE = exports.ENTITY_NOT_FOUND = exports.ReceivedApiErrorRule = exports.ApiErrorBoundary = exports.ApiErrorPayload = exports.ApiErrorCodec = exports.ApiCodedError = exports.ApiNotImplementedError = exports.ApiUnsupportedMediaTypeError = exports.ApiPreconditionFailedError = exports.ApiUnprocessableError = exports.ApiConflictError = exports.ApiDependencyBackoffError = exports.ApiUnauthorizedError = exports.ApiBadRequestError = exports.ApiEndUserError = exports.ApiEndpointNotFoundError = exports.ApiConnectionError = exports.ApiRequestTimeoutError = exports.ApiForbiddenError = exports.ApiRateLimitedError = exports.ApiImplementationError = exports.ApiDependencyTimeoutError = exports.ApiUnavailableError = exports.ApiDependencyError = exports.ApiNotFoundError = exports.ApiError = void 0;
|
|
3
|
+
exports.NO_REG_CODE = exports.WRONG_COMPANY = exports.WRONG_DOMAIN = exports.EMAIL_NOT_CONFIRMED = exports.NOT_APPROVED = exports.WRONG_LOGIN = exports.WRONG_LOGIN_TYPE = exports.ENTITY_NOT_FOUND = exports.ReceivedApiErrorRule = exports.ApiErrorBoundary = exports.ApiErrorPayload = exports.ApiErrorCodec = exports.ApiCodedError = exports.ApiNotImplementedError = exports.ApiUnsupportedMediaTypeError = exports.ApiPreconditionFailedError = exports.ApiUnprocessableError = exports.ApiConflictError = exports.ApiDependencyBackoffError = exports.ApiUnauthorizedError = exports.ApiBadRequestError = exports.ApiEndUserError = exports.ApiEndpointNotFoundError = exports.ApiConnectionError = exports.ApiRequestTimeoutError = exports.ApiForbiddenError = exports.ApiRateLimitedError = exports.ApiImplementationError = exports.ApiDependencyTimeoutError = exports.ApiUnavailableError = exports.ApiBadGatewayError = exports.ApiDependencyError = exports.ApiNotFoundError = exports.ApiError = void 0;
|
|
4
4
|
var ApiError_1 = require("./ApiError");
|
|
5
5
|
Object.defineProperty(exports, "ApiError", { enumerable: true, get: function () { return ApiError_1.ApiError; } });
|
|
6
6
|
Object.defineProperty(exports, "ApiNotFoundError", { enumerable: true, get: function () { return ApiError_1.ApiNotFoundError; } });
|
|
7
7
|
Object.defineProperty(exports, "ApiDependencyError", { enumerable: true, get: function () { return ApiError_1.ApiDependencyError; } });
|
|
8
|
+
Object.defineProperty(exports, "ApiBadGatewayError", { enumerable: true, get: function () { return ApiError_1.ApiBadGatewayError; } });
|
|
8
9
|
Object.defineProperty(exports, "ApiUnavailableError", { enumerable: true, get: function () { return ApiError_1.ApiUnavailableError; } });
|
|
9
10
|
Object.defineProperty(exports, "ApiDependencyTimeoutError", { enumerable: true, get: function () { return ApiError_1.ApiDependencyTimeoutError; } });
|
|
10
11
|
Object.defineProperty(exports, "ApiImplementationError", { enumerable: true, get: function () { return ApiError_1.ApiImplementationError; } });
|
package/src/errors/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/errors/index.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/errors/index.ts"],"names":[],"mappings":";;;AAAA,uCAuBoB;AAtBhB,oGAAA,QAAQ,OAAA;AACR,4GAAA,gBAAgB,OAAA;AAChB,8GAAA,kBAAkB,OAAA;AAClB,8GAAA,kBAAkB,OAAA;AAClB,+GAAA,mBAAmB,OAAA;AACnB,qHAAA,yBAAyB,OAAA;AACzB,kHAAA,sBAAsB,OAAA;AACtB,+GAAA,mBAAmB,OAAA;AACnB,6GAAA,iBAAiB,OAAA;AACjB,kHAAA,sBAAsB,OAAA;AACtB,8GAAA,kBAAkB,OAAA;AAClB,oHAAA,wBAAwB,OAAA;AACxB,2GAAA,eAAe,OAAA;AACf,8GAAA,kBAAkB,OAAA;AAClB,gHAAA,oBAAoB,OAAA;AACpB,qHAAA,yBAAyB,OAAA;AACzB,4GAAA,gBAAgB,OAAA;AAChB,iHAAA,qBAAqB,OAAA;AACrB,sHAAA,0BAA0B,OAAA;AAC1B,wHAAA,4BAA4B,OAAA;AAC5B,kHAAA,sBAAsB,OAAA;AACtB,yGAAA,aAAa,OAAA;AAGjB,iDAAiE;AAAxD,8GAAA,aAAa,OAAA;AAAE,gHAAA,eAAe,OAAA;AACvC,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA;AACzB,+DAA8D;AAArD,4HAAA,oBAAoB,OAAA;AAC7B,yDAS6B;AARzB,qHAAA,gBAAgB,OAAA;AAChB,qHAAA,gBAAgB,OAAA;AAChB,gHAAA,WAAW,OAAA;AACX,iHAAA,YAAY,OAAA;AACZ,wHAAA,mBAAmB,OAAA;AACnB,iHAAA,YAAY,OAAA;AACZ,kHAAA,aAAa,OAAA;AACb,gHAAA,WAAW,OAAA","sourcesContent":["export {\n ApiError,\n ApiNotFoundError,\n ApiDependencyError,\n ApiBadGatewayError,\n ApiUnavailableError,\n ApiDependencyTimeoutError,\n ApiImplementationError,\n ApiRateLimitedError,\n ApiForbiddenError,\n ApiRequestTimeoutError,\n ApiConnectionError,\n ApiEndpointNotFoundError,\n ApiEndUserError,\n ApiBadRequestError,\n ApiUnauthorizedError,\n ApiDependencyBackoffError,\n ApiConflictError,\n ApiUnprocessableError,\n ApiPreconditionFailedError,\n ApiUnsupportedMediaTypeError,\n ApiNotImplementedError,\n ApiCodedError,\n} from './ApiError';\nexport type { ApiErrorKind, ApiStatusCode, EdgeHttpStatus } from './ApiError';\nexport { ApiErrorCodec, ApiErrorPayload } from './ApiErrorCodec';\nexport { ApiErrorBoundary } from './ApiErrorBoundary';\nexport { ReceivedApiErrorRule } from './ReceivedApiErrorRule';\nexport {\n ENTITY_NOT_FOUND,\n WRONG_LOGIN_TYPE,\n WRONG_LOGIN,\n NOT_APPROVED,\n EMAIL_NOT_CONFIRMED,\n WRONG_DOMAIN,\n WRONG_COMPANY,\n NO_REG_CODE,\n} from './AuthErrorSubtypes';\n"]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CallContext } from './CallStrategy';
|
|
2
|
+
import { ApiDependencyTimeoutError } from '../errors/ApiError';
|
|
2
3
|
/** Stopped waiting; this does not prove the remote operation did not run. */
|
|
3
|
-
export declare class ApiCallTimeoutError extends
|
|
4
|
+
export declare class ApiCallTimeoutError extends ApiDependencyTimeoutError {
|
|
4
5
|
readonly timeoutMs: number;
|
|
5
6
|
readonly context: CallContext;
|
|
6
7
|
constructor(timeoutMs: number, context: CallContext);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ApiCallTimeoutError = void 0;
|
|
4
|
+
const ApiError_1 = require("../errors/ApiError");
|
|
4
5
|
/** Stopped waiting; this does not prove the remote operation did not run. */
|
|
5
|
-
class ApiCallTimeoutError extends
|
|
6
|
+
class ApiCallTimeoutError extends ApiError_1.ApiDependencyTimeoutError {
|
|
6
7
|
timeoutMs;
|
|
7
8
|
context;
|
|
8
9
|
constructor(timeoutMs, context) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApiCallTimeoutError.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/ApiCallTimeoutError.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"ApiCallTimeoutError.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/ApiCallTimeoutError.ts"],"names":[],"mappings":";;;AACA,iDAA+D;AAE/D,6EAA6E;AAC7E,MAAa,mBAAoB,SAAQ,oCAAyB;IAE1C;IACA;IAFpB,YACoB,SAAiB,EACjB,OAAoB;QAEpC,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,oBAAoB,SAAS,IAAI,CAAC,CAAC;QAHjE,cAAS,GAAT,SAAS,CAAQ;QACjB,YAAO,GAAP,OAAO,CAAa;QAGpC,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACtC,CAAC;CACJ;AARD,kDAQC","sourcesContent":["import { CallContext } from './CallStrategy';\nimport { ApiDependencyTimeoutError } from '../errors/ApiError';\n\n/** Stopped waiting; this does not prove the remote operation did not run. */\nexport class ApiCallTimeoutError extends ApiDependencyTimeoutError {\n constructor(\n public readonly timeoutMs: number,\n public readonly context: CallContext,\n ) {\n super(`${context.apiName}.${context.methodName} timed out after ${timeoutMs}ms`);\n this.name = 'ApiCallTimeoutError';\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ApiErrorHttpStatus.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/ApiErrorHttpStatus.ts"],"names":[],"mappings":";;;AAaA,sFAAsF;AACtF,MAAa,kBAAkB;IAC3B;;;;OAIG;IACH,6EAA6E;IAC7E,MAAM,CAAC,OAAO,CAAC,KAAe;QAC1B,OAAO,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC;IACvC,CAAC;IAED;;;;OAIG;IACH,2FAA2F;IAC3F,MAAM,CAAC,OAAO,CAAC,IAAmB,EAAE,UAAmB;QACnD,QAAQ,IAAI,EAAE,CAAC;YACX,KAAK,UAAU;gBACX,OAAO,GAAG,CAAC;YACf,KAAK,aAAa;gBACd,OAAO,GAAG,CAAC;YACf,KAAK,cAAc;gBACf,OAAO,GAAG,CAAC;YACf,KAAK,WAAW;gBACZ,OAAO,GAAG,CAAC;YACf,KAAK,WAAW,CAAC;YACjB,KAAK,oBAAoB;gBACrB,OAAO,GAAG,CAAC;YACf,KAAK,iBAAiB;gBAClB,OAAO,GAAG,CAAC;YACf,KAAK,UAAU;gBACX,OAAO,GAAG,CAAC;YACf,KAAK,qBAAqB;gBACtB,OAAO,GAAG,CAAC;YACf,KAAK,wBAAwB;gBACzB,OAAO,GAAG,CAAC;YACf,KAAK,eAAe;gBAChB,OAAO,GAAG,CAAC;YACf,KAAK,cAAc;gBACf,OAAO,GAAG,CAAC;YACf,KAAK,gBAAgB;gBACjB,OAAO,GAAG,CAAC;YACf,KAAK,iBAAiB;gBAClB,OAAO,GAAG,CAAC;YACf,KAAK,OAAO;gBACR,oFAAoF;gBACpF,4CAA4C;gBAC5C,OAAO,UAAU,IAAI,GAAG,CAAC;YAC7B,KAAK,YAAY;
|
|
1
|
+
{"version":3,"file":"ApiErrorHttpStatus.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/ApiErrorHttpStatus.ts"],"names":[],"mappings":";;;AAaA,sFAAsF;AACtF,MAAa,kBAAkB;IAC3B;;;;OAIG;IACH,6EAA6E;IAC7E,MAAM,CAAC,OAAO,CAAC,KAAe;QAC1B,OAAO,KAAK,CAAC,IAAI,KAAK,YAAY,CAAC;IACvC,CAAC;IAED;;;;OAIG;IACH,2FAA2F;IAC3F,MAAM,CAAC,OAAO,CAAC,IAAmB,EAAE,UAAmB;QACnD,QAAQ,IAAI,EAAE,CAAC;YACX,KAAK,UAAU;gBACX,OAAO,GAAG,CAAC;YACf,KAAK,aAAa;gBACd,OAAO,GAAG,CAAC;YACf,KAAK,cAAc;gBACf,OAAO,GAAG,CAAC;YACf,KAAK,WAAW;gBACZ,OAAO,GAAG,CAAC;YACf,KAAK,WAAW,CAAC;YACjB,KAAK,oBAAoB;gBACrB,OAAO,GAAG,CAAC;YACf,KAAK,iBAAiB;gBAClB,OAAO,GAAG,CAAC;YACf,KAAK,UAAU;gBACX,OAAO,GAAG,CAAC;YACf,KAAK,qBAAqB;gBACtB,OAAO,GAAG,CAAC;YACf,KAAK,wBAAwB;gBACzB,OAAO,GAAG,CAAC;YACf,KAAK,eAAe;gBAChB,OAAO,GAAG,CAAC;YACf,KAAK,cAAc;gBACf,OAAO,GAAG,CAAC;YACf,KAAK,gBAAgB;gBACjB,OAAO,GAAG,CAAC;YACf,KAAK,iBAAiB;gBAClB,OAAO,GAAG,CAAC;YACf,KAAK,OAAO;gBACR,oFAAoF;gBACpF,4CAA4C;gBAC5C,OAAO,UAAU,IAAI,GAAG,CAAC;YAC7B,KAAK,YAAY,CAAC;YAClB,KAAK,aAAa;gBACd,OAAO,GAAG,CAAC;YACf,KAAK,aAAa,CAAC;YACnB,KAAK,oBAAoB;gBACrB,OAAO,GAAG,CAAC;YACf,KAAK,oBAAoB;gBACrB,OAAO,GAAG,CAAC;QACnB,CAAC;IACL,CAAC;CACJ;AA5DD,gDA4DC","sourcesContent":["import { ApiError, ApiErrorKind } from '../errors/ApiError';\n\n/**\n * Every kind that HAS an HTTP status. `'connection'` is excluded on purpose: a caller-local\n * connection failure is never published as itself — `ApiErrorBoundary.encode` publishes it as\n * `implementation` — so asking this table for its status is a bug the COMPILER now rejects rather\n * than a `throw` at the bottom of a switch.\n */\nexport type PublishedKind = Exclude<ApiErrorKind, 'connection'>;\n\n/** An {@link ApiError} that {@link ApiErrorHttpStatus.hasCode} has proved carries an HTTP status. */\nexport type PublishedApiError = ApiError & { readonly kind: PublishedKind };\n\n/** HTTP-only adapter: semantic errors themselves have no protocol status property. */\nexport class ApiErrorHttpStatus {\n /**\n * CLIENT direction. A client that just DECODED a payload holds an `ApiError`, and needs to know\n * whether the status it received agrees with the kind the body claims. This narrows the error to\n * the kinds {@link codeFor} accepts, so the pair reads as one guarded call with no cast.\n */\n // webpieces-disable no-function-outside-class -- stateless mapping predicate\n static hasCode(error: ApiError): error is PublishedApiError {\n return error.kind !== 'connection';\n }\n\n /**\n * The ONE status table, keyed by the published kind. `statusCode` is the `'coded'` kind's own\n * status — it travels on {@link ApiErrorPayload.statusCode} and on `ApiCodedError.statusCode`,\n * so both directions can supply it without this table reaching back into the error object.\n */\n // webpieces-disable no-function-outside-class -- stateless mapping shared by HTTP adapters\n static codeFor(kind: PublishedKind, statusCode?: number): number {\n switch (kind) {\n case 'end-user':\n return 266;\n case 'bad-request':\n return 400;\n case 'unauthorized':\n return 401;\n case 'forbidden':\n return 403;\n case 'not-found':\n case 'endpoint-not-found':\n return 404;\n case 'request-timeout':\n return 408;\n case 'conflict':\n return 409;\n case 'precondition-failed':\n return 412;\n case 'unsupported-media-type':\n return 415;\n case 'unprocessable':\n return 422;\n case 'rate-limited':\n return 429;\n case 'implementation':\n return 500;\n case 'not-implemented':\n return 501;\n case 'coded':\n // A 'coded' failure whose status did not survive the wire is an internal failure to\n // this adapter, not a status it may invent.\n return statusCode ?? 500;\n case 'dependency':\n case 'bad-gateway':\n return 502;\n case 'unavailable':\n case 'dependency-backoff':\n return 503;\n case 'dependency-timeout':\n return 504;\n }\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const decorators_1 = require("./decorators");
|
|
4
|
+
(0, decorators_1.Endpoint)(decorators_1.POST, '/valid-rpc', decorators_1.WRITE, decorators_1.RPC);
|
|
5
|
+
(0, decorators_1.Endpoint)(decorators_1.POST, '/valid-external', decorators_1.WRITE, decorators_1.EXTERNAL, { calledBy: 'twilio' });
|
|
6
|
+
// @ts-expect-error external endpoints require options containing calledBy
|
|
7
|
+
(0, decorators_1.Endpoint)(decorators_1.POST, '/missing-external-options', decorators_1.WRITE, decorators_1.EXTERNAL);
|
|
8
|
+
// @ts-expect-error external endpoint options require calledBy
|
|
9
|
+
(0, decorators_1.Endpoint)(decorators_1.POST, '/missing-external-caller', decorators_1.WRITE, decorators_1.EXTERNAL, { formPost: true });
|
|
10
|
+
// @ts-expect-error callerKind is a closed enum-backed union rather than free text
|
|
11
|
+
(0, decorators_1.Endpoint)(decorators_1.POST, '/invalid-caller-kind', decorators_1.WRITE, decorators_1.EXTERNAL, {
|
|
12
|
+
calledBy: 'twilio',
|
|
13
|
+
callerKind: 'vendor',
|
|
14
|
+
});
|
|
15
|
+
// @ts-expect-error callers must import the enum-backed operation constant
|
|
16
|
+
(0, decorators_1.Endpoint)(decorators_1.POST, '/raw-operation', 'write', decorators_1.RPC);
|
|
17
|
+
// @ts-expect-error callers must import the enum-backed HTTP method constant
|
|
18
|
+
(0, decorators_1.Endpoint)('POST', '/raw-method', decorators_1.WRITE, decorators_1.RPC);
|
|
19
|
+
// @ts-expect-error callers must import the enum-backed trigger-kind constant
|
|
20
|
+
(0, decorators_1.Endpoint)(decorators_1.POST, '/raw-trigger', decorators_1.WRITE, 'rpc');
|
|
21
|
+
//# sourceMappingURL=EndpointCompileAssertions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EndpointCompileAssertions.js","sourceRoot":"","sources":["../../../../../../packages/core/core-util/src/http/EndpointCompileAssertions.ts"],"names":[],"mappings":";;AAAA,6CAAoE;AAEpE,IAAA,qBAAQ,EAAC,iBAAI,EAAE,YAAY,EAAE,kBAAK,EAAE,gBAAG,CAAC,CAAC;AACzC,IAAA,qBAAQ,EAAC,iBAAI,EAAE,iBAAiB,EAAE,kBAAK,EAAE,qBAAQ,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;AAE3E,0EAA0E;AAC1E,IAAA,qBAAQ,EAAC,iBAAI,EAAE,2BAA2B,EAAE,kBAAK,EAAE,qBAAQ,CAAC,CAAC;AAE7D,8DAA8D;AAC9D,IAAA,qBAAQ,EAAC,iBAAI,EAAE,0BAA0B,EAAE,kBAAK,EAAE,qBAAQ,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AAEhF,kFAAkF;AAClF,IAAA,qBAAQ,EAAC,iBAAI,EAAE,sBAAsB,EAAE,kBAAK,EAAE,qBAAQ,EAAE;IACpD,QAAQ,EAAE,QAAQ;IAClB,UAAU,EAAE,QAAQ;CACvB,CAAC,CAAC;AAEH,0EAA0E;AAC1E,IAAA,qBAAQ,EAAC,iBAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,gBAAG,CAAC,CAAC;AAE/C,4EAA4E;AAC5E,IAAA,qBAAQ,EAAC,MAAM,EAAE,aAAa,EAAE,kBAAK,EAAE,gBAAG,CAAC,CAAC;AAE5C,6EAA6E;AAC7E,IAAA,qBAAQ,EAAC,iBAAI,EAAE,cAAc,EAAE,kBAAK,EAAE,KAAK,CAAC,CAAC","sourcesContent":["import { Endpoint, EXTERNAL, POST, RPC, WRITE } from './decorators';\n\nEndpoint(POST, '/valid-rpc', WRITE, RPC);\nEndpoint(POST, '/valid-external', WRITE, EXTERNAL, { calledBy: 'twilio' });\n\n// @ts-expect-error external endpoints require options containing calledBy\nEndpoint(POST, '/missing-external-options', WRITE, EXTERNAL);\n\n// @ts-expect-error external endpoint options require calledBy\nEndpoint(POST, '/missing-external-caller', WRITE, EXTERNAL, { formPost: true });\n\n// @ts-expect-error callerKind is a closed enum-backed union rather than free text\nEndpoint(POST, '/invalid-caller-kind', WRITE, EXTERNAL, {\n calledBy: 'twilio',\n callerKind: 'vendor',\n});\n\n// @ts-expect-error callers must import the enum-backed operation constant\nEndpoint(POST, '/raw-operation', 'write', RPC);\n\n// @ts-expect-error callers must import the enum-backed HTTP method constant\nEndpoint('POST', '/raw-method', WRITE, RPC);\n\n// @ts-expect-error callers must import the enum-backed trigger-kind constant\nEndpoint(POST, '/raw-trigger', WRITE, 'rpc');\n"]}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
+
/** Nominal backing keeps raw string literals out of endpoint declarations. */
|
|
2
|
+
declare enum HttpMethodValue {
|
|
3
|
+
GET = "GET",
|
|
4
|
+
POST = "POST"
|
|
5
|
+
}
|
|
6
|
+
/** Short, statically importable decorator arguments. Raw strings do not satisfy {@link HttpMethod}. */
|
|
7
|
+
export declare const GET = HttpMethodValue.GET;
|
|
8
|
+
export declare const POST = HttpMethodValue.POST;
|
|
1
9
|
/** HTTP verbs currently supported by generated Webpieces request/response contracts. */
|
|
2
|
-
export type
|
|
10
|
+
export type HttpMethod = typeof GET | typeof POST;
|
|
3
11
|
/** Whether a generated client returns the response body or the whole transport-neutral response. */
|
|
4
12
|
export type EndpointResponseType = 'body' | 'full';
|
|
5
13
|
/** The wire source for one explicitly mapped scalar/list method parameter. */
|
|
@@ -37,3 +45,4 @@ export declare class HttpContractMapper {
|
|
|
37
45
|
static fromWire(bindings: readonly HttpParameterBinding[], bodyParameterIndex: number | undefined, body: unknown, pathValues: ReadonlyMap<string, string | readonly string[]>, queryValues: ReadonlyMap<string, string | readonly string[]>): unknown[];
|
|
38
46
|
private static convert;
|
|
39
47
|
}
|
|
48
|
+
export {};
|
package/src/http/HttpContract.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.HttpContractMapper = exports.BoundHttpRequest = exports.HttpParameterBinding = exports.HttpParameterDeclaration = void 0;
|
|
3
|
+
exports.HttpContractMapper = exports.BoundHttpRequest = exports.HttpParameterBinding = exports.HttpParameterDeclaration = exports.POST = exports.GET = void 0;
|
|
4
4
|
const ApiError_1 = require("../errors/ApiError");
|
|
5
|
+
/** Nominal backing keeps raw string literals out of endpoint declarations. */
|
|
6
|
+
var HttpMethodValue;
|
|
7
|
+
(function (HttpMethodValue) {
|
|
8
|
+
HttpMethodValue["GET"] = "GET";
|
|
9
|
+
HttpMethodValue["POST"] = "POST";
|
|
10
|
+
})(HttpMethodValue || (HttpMethodValue = {}));
|
|
11
|
+
/** Short, statically importable decorator arguments. Raw strings do not satisfy {@link HttpMethod}. */
|
|
12
|
+
exports.GET = HttpMethodValue.GET;
|
|
13
|
+
exports.POST = HttpMethodValue.POST;
|
|
5
14
|
/** Metadata written by `@PathParam` / `@QueryParam` before route construction knows the value type. */
|
|
6
15
|
class HttpParameterDeclaration {
|
|
7
16
|
index;
|