@webpieces/http-client-core 0.4.806 → 0.4.807
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-client-core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.807",
|
|
4
4
|
"description": "Isomorphic core of the webpieces HTTP client: the decorator-driven ProxyClient, error translation, and the Proxy trap shared by http-client-node and http-client-browser",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -21,6 +21,6 @@
|
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@webpieces/core-util": "0.4.
|
|
24
|
+
"@webpieces/core-util": "0.4.807"
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -29,7 +29,7 @@ class NdjsonRequestStream {
|
|
|
29
29
|
}
|
|
30
30
|
async event(value, correlation) {
|
|
31
31
|
this.requireWritable();
|
|
32
|
-
this.validator.validate(this.metadata.
|
|
32
|
+
this.validator.validate(this.metadata.requestSchema, value, 'request');
|
|
33
33
|
await this.write(new core_util_1.StreamEnvelope('event', value, undefined, correlation));
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NdjsonRequestStream.js","sourceRoot":"","sources":["../../../../../packages/http/http-client-core/src/NdjsonRequestStream.ts"],"names":[],"mappings":";;;AAAA,oDAW8B;AAC9B,+DAA4D;AAC5D,2CAAwC;AAGxC,oFAAoF;AACpF,MAAa,mBAAmB;IAUP;IAEA;IAXZ,IAAI,CAAqB;IACjB,MAAM,CAA0C;IAChD,OAAO,GAAG,IAAI,qBAAS,EAAE,CAAC;IAC1B,SAAS,GAAG,IAAI,gCAAoB,EAAE,CAAC;IACvC,KAAK,CAAgB;IAC9B,QAAQ,GAAG,KAAK,CAAC;IACjB,SAAS,GAAG,KAAK,CAAC;IAE1B,YACqB,QAAmC;IACpD,+EAA+E;IAC9D,KAAiC;QAFjC,aAAQ,GAAR,QAAQ,CAA2B;QAEnC,UAAK,GAAL,KAAK,CAA4B;QAElD,MAAM,SAAS,GAAG,IAAI,eAAe,EAA0B,CAAC;QAChE,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;QAC7C,4FAA4F;QAC5F,sFAAsF;QACtF,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAAe,EAAE,WAA+B;QACxD,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"NdjsonRequestStream.js","sourceRoot":"","sources":["../../../../../packages/http/http-client-core/src/NdjsonRequestStream.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ApiErrorCodec,\n DtoValue,\n RequestStream,\n StreamCorrelation,\n StreamEnvelope,\n StreamEventValidator,\n StreamFailureOptions,\n StreamingEndpointMetadata,\n StreamTransportError,\n toError,\n} from '@webpieces/core-util';\nimport { StreamEnvelopeCodec } from './StreamEnvelopeCodec';\nimport { Utf8Codec } from './Utf8Codec';\nimport { ByteReadableStream } from './ByteStream';\n\n/** NDJSON upload half: exactly one JSON envelope plus LF per acknowledged write. */\nexport class NdjsonRequestStream implements RequestStream<DtoValue> {\n readonly body: ByteReadableStream;\n private readonly writer: WritableStreamDefaultWriter<Uint8Array>;\n private readonly encoder = new Utf8Codec();\n private readonly validator = new StreamEventValidator();\n private readonly ready: Promise<void>;\n private terminal = false;\n private cancelled = false;\n\n constructor(\n private readonly metadata: StreamingEndpointMetadata,\n // webpieces-disable no-any-unknown -- AbortSignal reasons are platform-defined\n private readonly abort: (reason?: unknown) => void,\n ) {\n const transport = new TransformStream<Uint8Array, Uint8Array>();\n this.body = transport.readable;\n this.writer = transport.writable.getWriter();\n // A blank NDJSON line is a transport preamble. It makes Node/undici send request headers so\n // the server can establish the SSE response before the caller has its request writer.\n this.ready = this.writer.write(this.encoder.encode('\\n'));\n }\n\n async event(value: DtoValue, correlation?: StreamCorrelation): Promise<void> {\n this.requireWritable();\n this.validator.validate(this.metadata.requestSchema, value, 'request');\n await this.write(new StreamEnvelope('event', value, undefined, correlation));\n }\n\n /**\n * Takes `Error`: webpieces never demands its own `ApiError` taxonomy from an application. The\n * faithful codec encode, for the reason {@link ResponseStream.fail} documents — a\n * `StreamTransportError` must reach the peer as kind `connection`.\n */\n async fail(\n error: Error,\n correlation?: StreamCorrelation,\n options?: StreamFailureOptions,\n ): Promise<void> {\n this.requireWritable();\n const terminal = options?.terminal ?? true;\n await this.write(\n new StreamEnvelope<DtoValue>(\n 'failure',\n undefined,\n ApiErrorCodec.encode(error),\n correlation,\n terminal,\n ),\n );\n if (terminal) await this.closeWriter();\n }\n\n async complete(): Promise<void> {\n this.requireWritable();\n await this.write(new StreamEnvelope<DtoValue>('complete'));\n await this.closeWriter();\n }\n\n // webpieces-disable no-any-unknown -- AbortSignal reasons are platform-defined\n async cancel(reason?: unknown): Promise<void> {\n if (this.terminal || this.cancelled) return;\n this.cancelled = true;\n this.terminal = true;\n this.abort(reason);\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- abort may race a fetch-owned stream close\n try {\n await this.writer.abort(reason);\n } catch (err: unknown) {\n const error = toError(err);\n void error;\n }\n }\n\n // webpieces-disable no-any-unknown -- a transport failure carries the platform cause\n async transportFailed(reason: unknown): Promise<void> {\n await this.cancel(reason);\n }\n\n private async write(envelope: StreamEnvelope<DtoValue>): Promise<void> {\n await this.ready;\n const line = `${StreamEnvelopeCodec.encode(envelope)}\\n`;\n // WritableStream.write resolves only when the fetch consumer accepts the chunk.\n await this.writer.write(this.encoder.encode(line));\n }\n\n private async closeWriter(): Promise<void> {\n this.terminal = true;\n await this.ready;\n await this.writer.close();\n }\n\n private requireWritable(): void {\n if (this.terminal || this.cancelled) {\n throw new StreamTransportError('Cannot write after stream termination.');\n }\n }\n}\n"]}
|
package/src/SseResponseStream.js
CHANGED
|
@@ -48,7 +48,7 @@ class SseResponseStream {
|
|
|
48
48
|
continue;
|
|
49
49
|
const envelope = StreamEnvelopeCodec_1.StreamEnvelopeCodec.decode(event.data);
|
|
50
50
|
if (envelope.kind === 'event') {
|
|
51
|
-
this.validator.validate(metadata.
|
|
51
|
+
this.validator.validate(metadata.responseSchema, envelope.value, 'response');
|
|
52
52
|
await destination.event(envelope.value, envelope.correlation);
|
|
53
53
|
continue;
|
|
54
54
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SseResponseStream.js","sourceRoot":"","sources":["../../../../../packages/http/http-client-core/src/SseResponseStream.ts"],"names":[],"mappings":";;;AAAA,oDAQ8B;AAE9B,qDAA4D;AAC5D,+DAA4D;AAE5D,wFAAwF;AACxF,MAAa,iBAAiB;IACT,SAAS,GAAG,IAAI,gCAAoB,EAAE,CAAC;IAExD,KAAK,CAAC,OAAO,CACT,QAAkB,EAClB,WAAqC,EACrC,QAAmC,EACnC,aAAkC;QAElC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC3B,IAAI,CAAC,IAAI,EAAE,CAAC;YACR,MAAM,IAAI,CAAC,gBAAgB,CACvB,IAAI,gCAAoB,CAAC,0CAA0C,CAAC,EACpE,WAAW,EACX,aAAa,CAChB,CAAC;YACF,OAAO;QACX,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,+BAAc,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QAChC,IAAI,UAAU,GAAG,KAAK,CAAC;QACvB,+GAA+G;QAC/G,IAAI,CAAC;YACD,OAAO,CAAC,UAAU,EAAE,CAAC;gBACjB,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBACjC,IAAI,IAAI,CAAC,IAAI;oBAAE,MAAM;gBACrB,UAAU,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;YACxF,CAAC;YACD,IAAI,CAAC,UAAU,EAAE,CAAC;gBACd,UAAU,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;YAChF,CAAC;YACD,IAAI,CAAC,UAAU,EAAE,CAAC;gBACd,MAAM,IAAI,gCAAoB,CAC1B,qEAAqE,CACxE,CAAC;YACN,CAAC;QACL,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAA,mBAAO,EAAC,GAAG,CAAC,CAAC;YAC3B,MAAM,cAAc,GAChB,KAAK,YAAY,gCAAoB;gBACjC,CAAC,CAAC,KAAK;gBACP,CAAC,CAAC,IAAI,gCAAoB,CACpB,gCAAgC,EAChC,SAAS,EACT,SAAS,EACT,KAAK,CACR,CAAC;YACZ,MAAM,IAAI,CAAC,gBAAgB,CAAC,cAAc,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;QAC5E,CAAC;gBAAS,CAAC;YACP,MAAM,CAAC,WAAW,EAAE,CAAC;QACzB,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,WAAW,CACrB,MAA2B,EAC3B,WAAqC,EACrC,QAAmC;QAEnC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YACzB,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;gBAAE,SAAS;YACrE,MAAM,QAAQ,GAAG,yCAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACxD,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC5B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"SseResponseStream.js","sourceRoot":"","sources":["../../../../../packages/http/http-client-core/src/SseResponseStream.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ApiErrorCodec,\n DtoValue,\n ResponseStream,\n StreamEventValidator,\n StreamingEndpointMetadata,\n StreamTransportError,\n toError,\n} from '@webpieces/core-util';\nimport { NdjsonRequestStream } from './NdjsonRequestStream';\nimport { SseEvent, SseEventParser } from './SseEventParser';\nimport { StreamEnvelopeCodec } from './StreamEnvelopeCodec';\n\n/** Consumes generic Webpieces stream envelopes from one request-scoped SSE response. */\nexport class SseResponseStream {\n private readonly validator = new StreamEventValidator();\n\n async consume(\n response: Response,\n destination: ResponseStream<DtoValue>,\n metadata: StreamingEndpointMetadata,\n requestStream: NdjsonRequestStream,\n ): Promise<void> {\n const body = response.body;\n if (!body) {\n await this.transportFailure(\n new StreamTransportError('Streaming response has no readable body.'),\n destination,\n requestStream,\n );\n return;\n }\n const parser = new SseEventParser();\n const reader = body.getReader();\n let terminated = false;\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions -- all wire/reader failures are translated below\n try {\n while (!terminated) {\n const part = await reader.read();\n if (part.done) break;\n terminated = await this.dispatchAll(parser.feed(part.value), destination, metadata);\n }\n if (!terminated) {\n terminated = await this.dispatchAll(parser.finish(), destination, metadata);\n }\n if (!terminated) {\n throw new StreamTransportError(\n 'SSE response closed before a terminal failure or complete envelope.',\n );\n }\n } catch (err: unknown) {\n const error = toError(err);\n const transportError =\n error instanceof StreamTransportError\n ? error\n : new StreamTransportError(\n 'SSE response transport failed.',\n undefined,\n undefined,\n error,\n );\n await this.transportFailure(transportError, destination, requestStream);\n } finally {\n reader.releaseLock();\n }\n }\n\n private async dispatchAll(\n events: readonly SseEvent[],\n destination: ResponseStream<DtoValue>,\n metadata: StreamingEndpointMetadata,\n ): Promise<boolean> {\n for (const event of events) {\n if (event.event !== undefined && event.event !== 'message') continue;\n const envelope = StreamEnvelopeCodec.decode(event.data);\n if (envelope.kind === 'event') {\n this.validator.validate(metadata.responseSchema, envelope.value, 'response');\n await destination.event(envelope.value as DtoValue, envelope.correlation);\n continue;\n }\n if (envelope.kind === 'failure') {\n const error = ApiErrorCodec.decode(envelope.error);\n await destination.fail(error, envelope.correlation, {\n terminal: envelope.terminal,\n });\n if (envelope.terminal) return true;\n continue;\n }\n await destination.complete();\n return true;\n }\n return false;\n }\n\n private async transportFailure(\n error: StreamTransportError,\n destination: ResponseStream<DtoValue>,\n requestStream: NdjsonRequestStream,\n ): Promise<void> {\n await requestStream.transportFailed(error);\n await destination.fail(error, error.correlation, { terminal: true });\n }\n}\n"]}
|