@webpieces/http-server 0.4.785 → 0.4.787

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webpieces/http-server",
3
- "version": "0.4.785",
3
+ "version": "0.4.787",
4
4
  "description": "WebPieces server with filter chain and dependency injection",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -22,10 +22,10 @@
22
22
  "access": "public"
23
23
  },
24
24
  "dependencies": {
25
- "@webpieces/core-context": "0.4.785",
26
- "@webpieces/core-util": "0.4.785",
27
- "@webpieces/gcp-identity": "0.4.785",
28
- "@webpieces/http-routing": "0.4.785",
25
+ "@webpieces/core-context": "0.4.787",
26
+ "@webpieces/core-util": "0.4.787",
27
+ "@webpieces/gcp-identity": "0.4.787",
28
+ "@webpieces/http-routing": "0.4.787",
29
29
  "cors": "2.8.5",
30
30
  "express": "5.1.0",
31
31
  "inversify": "7.10.4"
@@ -20,11 +20,14 @@ export declare class ApiErrorHttpMapper {
20
20
  private readonly boundary;
21
21
  private readonly genericMessages;
22
22
  /**
23
- * Unknown throws and caller-local failures become a concrete implementation failure at this
24
- * owning API boundary. ApiError itself has no fallback status mapping.
23
+ * Unknown throws and caller-local failures answer as a 500 implementation failure at this owning
24
+ * API boundary. The thrown error itself is never replaced: it is what gets logged and classified.
25
25
  */
26
26
  toResponse(thrown: unknown): HttpResponseDto;
27
- /** The protocol status; only an end-user error in `'edge'` mode departs from the shared mapping. */
27
+ /**
28
+ * The protocol status; only an end-user error in `'edge'` mode departs from the shared mapping.
29
+ * Anything the boundary does not classify as an API outcome is this server's own bug: 500.
30
+ */
28
31
  private statusFor;
29
32
  genericMessage(code: number): string;
30
33
  }
@@ -29,21 +29,27 @@ class ApiErrorHttpMapper {
29
29
  [504, 'Gateway Timeout'],
30
30
  ]);
31
31
  /**
32
- * Unknown throws and caller-local failures become a concrete implementation failure at this
33
- * owning API boundary. ApiError itself has no fallback status mapping.
32
+ * Unknown throws and caller-local failures answer as a 500 implementation failure at this owning
33
+ * API boundary. The thrown error itself is never replaced: it is what gets logged and classified.
34
34
  */
35
- // webpieces-disable no-any-unknown -- thrown values are unknown until normalized at this boundary
35
+ // webpieces-disable no-any-unknown -- thrown values are unknown until classified at this boundary
36
36
  toResponse(thrown) {
37
- const error = this.boundary.normalize(thrown);
38
- const status = this.statusFor(error);
39
- this.boundary.logOperatorDetail(error);
40
- const headers = error instanceof core_util_1.ApiDependencyBackoffError
41
- ? [new core_util_1.HttpHeader('retry-after', String(error.retryAfterSeconds))]
37
+ const status = this.statusFor(thrown);
38
+ this.boundary.logOperatorDetail(thrown);
39
+ const headers = thrown instanceof core_util_1.ApiDependencyBackoffError
40
+ ? [new core_util_1.HttpHeader('retry-after', String(thrown.retryAfterSeconds))]
42
41
  : [];
43
- return new core_util_1.HttpResponseDto(new core_util_1.HttpResponseStatus(status, this.genericMessage(status)), headers, core_util_1.ApiErrorCodec.encode(error));
42
+ return new core_util_1.HttpResponseDto(new core_util_1.HttpResponseStatus(status, this.genericMessage(status)), headers, this.boundary.encode(thrown));
44
43
  }
45
- /** The protocol status; only an end-user error in `'edge'` mode departs from the shared mapping. */
46
- statusFor(error) {
44
+ /**
45
+ * The protocol status; only an end-user error in `'edge'` mode departs from the shared mapping.
46
+ * Anything the boundary does not classify as an API outcome is this server's own bug: 500.
47
+ */
48
+ // webpieces-disable no-any-unknown -- thrown values are unknown until classified at this boundary
49
+ statusFor(thrown) {
50
+ const error = this.boundary.apiOutcome(thrown);
51
+ if (!error)
52
+ return 500;
47
53
  if (this.endUserStatus === 'edge' && error instanceof core_util_1.ApiEndUserError) {
48
54
  return error.edgeHttpStatus ?? 400;
49
55
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ApiErrorHttpMapper.js","sourceRoot":"","sources":["../../../../../packages/http/http-server/src/ApiErrorHttpMapper.ts"],"names":[],"mappings":";;;AAAA,oDAW8B;AAE9B,MAAM,GAAG,GAAG,sBAAU,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;AAiBvD,iEAAiE;AACjE,MAAa,kBAAkB;IACE;IAA7B,YAA6B,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;IAAG,CAAC;IAE5C,QAAQ,GAAG,IAAI,4BAAgB,CAAC,GAAG,CAAC,CAAC;IACrC,eAAe,GAAwB,IAAI,GAAG,CAAiB;QAC5E,CAAC,GAAG,EAAE,gBAAgB,CAAC;QACvB,CAAC,GAAG,EAAE,aAAa,CAAC;QACpB,CAAC,GAAG,EAAE,cAAc,CAAC;QACrB,CAAC,GAAG,EAAE,WAAW,CAAC;QAClB,CAAC,GAAG,EAAE,WAAW,CAAC;QAClB,CAAC,GAAG,EAAE,iBAAiB,CAAC;QACxB,CAAC,GAAG,EAAE,UAAU,CAAC;QACjB,CAAC,GAAG,EAAE,qBAAqB,CAAC;QAC5B,CAAC,GAAG,EAAE,wBAAwB,CAAC;QAC/B,CAAC,GAAG,EAAE,uBAAuB,CAAC;QAC9B,CAAC,GAAG,EAAE,mBAAmB,CAAC;QAC1B,CAAC,GAAG,EAAE,uBAAuB,CAAC;QAC9B,CAAC,GAAG,EAAE,iBAAiB,CAAC;QACxB,CAAC,GAAG,EAAE,aAAa,CAAC;QACpB,CAAC,GAAG,EAAE,qBAAqB,CAAC;QAC5B,CAAC,GAAG,EAAE,iBAAiB,CAAC;KAC3B,CAAC,CAAC;IAEH;;;OAGG;IACH,kGAAkG;IAC3F,UAAU,CAAC,MAAe;QAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,OAAO,GACT,KAAK,YAAY,qCAAyB;YACtC,CAAC,CAAC,CAAC,IAAI,sBAAU,CAAC,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC;YAClE,CAAC,CAAC,EAAE,CAAC;QACb,OAAO,IAAI,2BAAe,CACtB,IAAI,8BAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EAC3D,OAAO,EACP,yBAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAC9B,CAAC;IACN,CAAC;IAED,oGAAoG;IAC5F,SAAS,CAAC,KAAe;QAC7B,IAAI,IAAI,CAAC,aAAa,KAAK,MAAM,IAAI,KAAK,YAAY,2BAAe,EAAE,CAAC;YACpE,OAAO,KAAK,CAAC,cAAc,IAAI,GAAG,CAAC;QACvC,CAAC;QACD,OAAO,8BAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;IAEM,cAAc,CAAC,IAAY;QAC9B,OAAO,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,gBAAgB,CAAC;IAC9D,CAAC;CACJ;AAtDD,gDAsDC","sourcesContent":["import {\n ApiDependencyBackoffError,\n ApiEndUserError,\n ApiError,\n ApiErrorBoundary,\n ApiErrorCodec,\n ApiErrorHttpStatus,\n HttpHeader,\n HttpResponseDto,\n HttpResponseStatus,\n LogManager,\n} from '@webpieces/core-util';\n\nconst log = LogManager.getLogger('ApiErrorHttpMapper');\n\n/**\n * How a server answers an {@link ApiEndUserError}.\n *\n * - `'gui'` (the default): 266. The call succeeded; the GUI (or any webpieces client, including the\n * next server-to-server hop) decodes the error and shows its message. `edgeHttpStatus` is ignored,\n * and still travels in the body so a downstream edge can use it.\n * - `'edge'`: a partner/public REST edge whose published contract promises real 4xx statuses. The\n * response carries `edgeHttpStatus`, or 400 when the thrower set none (still a caller-fixable\n * end-user outcome). Only for the OUTERMOST server: a webpieces client receiving an end-user body at\n * anything other than 266 treats it as a mismatched response, so internal hops stay `'gui'`.\n *\n * Chosen per router with `WebpiecesExpressRouter.setEndUserStatus`.\n */\nexport type EndUserStatus = 'gui' | 'edge';\n\n/** HTTP adapter for the transport-neutral API error taxonomy. */\nexport class ApiErrorHttpMapper {\n constructor(private readonly endUserStatus: EndUserStatus) {}\n\n private readonly boundary = new ApiErrorBoundary(log);\n private readonly genericMessages: Map<number, string> = new Map<number, string>([\n [266, 'End User Error'],\n [400, 'Bad Request'],\n [401, 'Unauthorized'],\n [403, 'Forbidden'],\n [404, 'Not Found'],\n [408, 'Request Timeout'],\n [409, 'Conflict'],\n [412, 'Precondition Failed'],\n [415, 'Unsupported Media Type'],\n [422, 'Unprocessable Content'],\n [429, 'Too Many Requests'],\n [500, 'Internal Server Error'],\n [501, 'Not Implemented'],\n [502, 'Bad Gateway'],\n [503, 'Service Unavailable'],\n [504, 'Gateway Timeout'],\n ]);\n\n /**\n * Unknown throws and caller-local failures become a concrete implementation failure at this\n * owning API boundary. ApiError itself has no fallback status mapping.\n */\n // webpieces-disable no-any-unknown -- thrown values are unknown until normalized at this boundary\n public toResponse(thrown: unknown): HttpResponseDto {\n const error = this.boundary.normalize(thrown);\n const status = this.statusFor(error);\n this.boundary.logOperatorDetail(error);\n const headers =\n error instanceof ApiDependencyBackoffError\n ? [new HttpHeader('retry-after', String(error.retryAfterSeconds))]\n : [];\n return new HttpResponseDto(\n new HttpResponseStatus(status, this.genericMessage(status)),\n headers,\n ApiErrorCodec.encode(error),\n );\n }\n\n /** The protocol status; only an end-user error in `'edge'` mode departs from the shared mapping. */\n private statusFor(error: ApiError): number {\n if (this.endUserStatus === 'edge' && error instanceof ApiEndUserError) {\n return error.edgeHttpStatus ?? 400;\n }\n return ApiErrorHttpStatus.code(error);\n }\n\n public genericMessage(code: number): string {\n return this.genericMessages.get(code) ?? 'Request Failed';\n }\n}\n"]}
1
+ {"version":3,"file":"ApiErrorHttpMapper.js","sourceRoot":"","sources":["../../../../../packages/http/http-server/src/ApiErrorHttpMapper.ts"],"names":[],"mappings":";;;AAAA,oDAS8B;AAE9B,MAAM,GAAG,GAAG,sBAAU,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;AAiBvD,iEAAiE;AACjE,MAAa,kBAAkB;IACE;IAA7B,YAA6B,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;IAAG,CAAC;IAE5C,QAAQ,GAAG,IAAI,4BAAgB,CAAC,GAAG,CAAC,CAAC;IACrC,eAAe,GAAwB,IAAI,GAAG,CAAiB;QAC5E,CAAC,GAAG,EAAE,gBAAgB,CAAC;QACvB,CAAC,GAAG,EAAE,aAAa,CAAC;QACpB,CAAC,GAAG,EAAE,cAAc,CAAC;QACrB,CAAC,GAAG,EAAE,WAAW,CAAC;QAClB,CAAC,GAAG,EAAE,WAAW,CAAC;QAClB,CAAC,GAAG,EAAE,iBAAiB,CAAC;QACxB,CAAC,GAAG,EAAE,UAAU,CAAC;QACjB,CAAC,GAAG,EAAE,qBAAqB,CAAC;QAC5B,CAAC,GAAG,EAAE,wBAAwB,CAAC;QAC/B,CAAC,GAAG,EAAE,uBAAuB,CAAC;QAC9B,CAAC,GAAG,EAAE,mBAAmB,CAAC;QAC1B,CAAC,GAAG,EAAE,uBAAuB,CAAC;QAC9B,CAAC,GAAG,EAAE,iBAAiB,CAAC;QACxB,CAAC,GAAG,EAAE,aAAa,CAAC;QACpB,CAAC,GAAG,EAAE,qBAAqB,CAAC;QAC5B,CAAC,GAAG,EAAE,iBAAiB,CAAC;KAC3B,CAAC,CAAC;IAEH;;;OAGG;IACH,kGAAkG;IAC3F,UAAU,CAAC,MAAe;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,OAAO,GACT,MAAM,YAAY,qCAAyB;YACvC,CAAC,CAAC,CAAC,IAAI,sBAAU,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;YACnE,CAAC,CAAC,EAAE,CAAC;QACb,OAAO,IAAI,2BAAe,CACtB,IAAI,8BAAkB,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EAC3D,OAAO,EACP,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAC/B,CAAC;IACN,CAAC;IAED;;;OAGG;IACH,kGAAkG;IAC1F,SAAS,CAAC,MAAe;QAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAC/C,IAAI,CAAC,KAAK;YAAE,OAAO,GAAG,CAAC;QACvB,IAAI,IAAI,CAAC,aAAa,KAAK,MAAM,IAAI,KAAK,YAAY,2BAAe,EAAE,CAAC;YACpE,OAAO,KAAK,CAAC,cAAc,IAAI,GAAG,CAAC;QACvC,CAAC;QACD,OAAO,8BAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;IAEM,cAAc,CAAC,IAAY;QAC9B,OAAO,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,gBAAgB,CAAC;IAC9D,CAAC;CACJ;AA3DD,gDA2DC","sourcesContent":["import {\n ApiDependencyBackoffError,\n ApiEndUserError,\n ApiErrorBoundary,\n ApiErrorHttpStatus,\n HttpHeader,\n HttpResponseDto,\n HttpResponseStatus,\n LogManager,\n} from '@webpieces/core-util';\n\nconst log = LogManager.getLogger('ApiErrorHttpMapper');\n\n/**\n * How a server answers an {@link ApiEndUserError}.\n *\n * - `'gui'` (the default): 266. The call succeeded; the GUI (or any webpieces client, including the\n * next server-to-server hop) decodes the error and shows its message. `edgeHttpStatus` is ignored,\n * and still travels in the body so a downstream edge can use it.\n * - `'edge'`: a partner/public REST edge whose published contract promises real 4xx statuses. The\n * response carries `edgeHttpStatus`, or 400 when the thrower set none (still a caller-fixable\n * end-user outcome). Only for the OUTERMOST server: a webpieces client receiving an end-user body at\n * anything other than 266 treats it as a mismatched response, so internal hops stay `'gui'`.\n *\n * Chosen per router with `WebpiecesExpressRouter.setEndUserStatus`.\n */\nexport type EndUserStatus = 'gui' | 'edge';\n\n/** HTTP adapter for the transport-neutral API error taxonomy. */\nexport class ApiErrorHttpMapper {\n constructor(private readonly endUserStatus: EndUserStatus) {}\n\n private readonly boundary = new ApiErrorBoundary(log);\n private readonly genericMessages: Map<number, string> = new Map<number, string>([\n [266, 'End User Error'],\n [400, 'Bad Request'],\n [401, 'Unauthorized'],\n [403, 'Forbidden'],\n [404, 'Not Found'],\n [408, 'Request Timeout'],\n [409, 'Conflict'],\n [412, 'Precondition Failed'],\n [415, 'Unsupported Media Type'],\n [422, 'Unprocessable Content'],\n [429, 'Too Many Requests'],\n [500, 'Internal Server Error'],\n [501, 'Not Implemented'],\n [502, 'Bad Gateway'],\n [503, 'Service Unavailable'],\n [504, 'Gateway Timeout'],\n ]);\n\n /**\n * Unknown throws and caller-local failures answer as a 500 implementation failure at this owning\n * API boundary. The thrown error itself is never replaced: it is what gets logged and classified.\n */\n // webpieces-disable no-any-unknown -- thrown values are unknown until classified at this boundary\n public toResponse(thrown: unknown): HttpResponseDto {\n const status = this.statusFor(thrown);\n this.boundary.logOperatorDetail(thrown);\n const headers =\n thrown instanceof ApiDependencyBackoffError\n ? [new HttpHeader('retry-after', String(thrown.retryAfterSeconds))]\n : [];\n return new HttpResponseDto(\n new HttpResponseStatus(status, this.genericMessage(status)),\n headers,\n this.boundary.encode(thrown),\n );\n }\n\n /**\n * The protocol status; only an end-user error in `'edge'` mode departs from the shared mapping.\n * Anything the boundary does not classify as an API outcome is this server's own bug: 500.\n */\n // webpieces-disable no-any-unknown -- thrown values are unknown until classified at this boundary\n private statusFor(thrown: unknown): number {\n const error = this.boundary.apiOutcome(thrown);\n if (!error) return 500;\n if (this.endUserStatus === 'edge' && error instanceof ApiEndUserError) {\n return error.edgeHttpStatus ?? 400;\n }\n return ApiErrorHttpStatus.code(error);\n }\n\n public genericMessage(code: number): string {\n return this.genericMessages.get(code) ?? 'Request Failed';\n }\n}\n"]}