@nmtjs/http-client 0.15.0-beta.43 → 0.15.0-beta.45
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/dist/http-stream-parser.d.ts +8 -0
- package/dist/http-stream-parser.js +75 -0
- package/dist/http-stream-parser.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +66 -22
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/http-stream-parser.ts +91 -0
- package/src/index.ts +87 -27
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export class HttpStreamParser {
|
|
2
|
+
pending = '';
|
|
3
|
+
push(chunk, emit) {
|
|
4
|
+
this.pending += chunk;
|
|
5
|
+
this.pending = this.parse(this.pending, emit);
|
|
6
|
+
}
|
|
7
|
+
finish(emit) {
|
|
8
|
+
this.pending = this.parse(this.pending, emit);
|
|
9
|
+
if (this.pending.trim().length > 0) {
|
|
10
|
+
throw new Error('Malformed stream response frame');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
parse(pending, emit) {
|
|
14
|
+
let cursor = 0;
|
|
15
|
+
while (true) {
|
|
16
|
+
const separator = this.findNextEventSeparator(pending, cursor);
|
|
17
|
+
if (!separator)
|
|
18
|
+
break;
|
|
19
|
+
this.emitEventDataFrame(pending, cursor, separator.index, emit);
|
|
20
|
+
cursor = separator.index + separator.length;
|
|
21
|
+
}
|
|
22
|
+
if (cursor === 0)
|
|
23
|
+
return pending;
|
|
24
|
+
return pending.slice(cursor);
|
|
25
|
+
}
|
|
26
|
+
findNextEventSeparator(source, fromIndex) {
|
|
27
|
+
const lf = source.indexOf('\n\n', fromIndex);
|
|
28
|
+
const crlf = source.indexOf('\r\n\r\n', fromIndex);
|
|
29
|
+
if (lf < 0 && crlf < 0)
|
|
30
|
+
return null;
|
|
31
|
+
if (lf < 0)
|
|
32
|
+
return { index: crlf, length: 4 };
|
|
33
|
+
if (crlf < 0)
|
|
34
|
+
return { index: lf, length: 2 };
|
|
35
|
+
return lf < crlf ? { index: lf, length: 2 } : { index: crlf, length: 4 };
|
|
36
|
+
}
|
|
37
|
+
emitEventDataFrame(source, start, end, emit) {
|
|
38
|
+
const chunks = [];
|
|
39
|
+
let lineStart = start;
|
|
40
|
+
while (lineStart <= end) {
|
|
41
|
+
let lineEnd = source.indexOf('\n', lineStart);
|
|
42
|
+
if (lineEnd < 0 || lineEnd > end)
|
|
43
|
+
lineEnd = end;
|
|
44
|
+
let contentEnd = lineEnd;
|
|
45
|
+
if (contentEnd > lineStart &&
|
|
46
|
+
source.charCodeAt(contentEnd - 1) === 13 /* \r */) {
|
|
47
|
+
contentEnd -= 1;
|
|
48
|
+
}
|
|
49
|
+
if (contentEnd - lineStart >= 5 &&
|
|
50
|
+
source.charCodeAt(lineStart) === 100 /* d */ &&
|
|
51
|
+
source.charCodeAt(lineStart + 1) === 97 /* a */ &&
|
|
52
|
+
source.charCodeAt(lineStart + 2) === 116 /* t */ &&
|
|
53
|
+
source.charCodeAt(lineStart + 3) === 97 /* a */ &&
|
|
54
|
+
source.charCodeAt(lineStart + 4) === 58 /* : */) {
|
|
55
|
+
let dataStart = lineStart + 5;
|
|
56
|
+
while (dataStart < contentEnd) {
|
|
57
|
+
const code = source.charCodeAt(dataStart);
|
|
58
|
+
if (code !== 32 /* space */ && code !== 9 /* tab */)
|
|
59
|
+
break;
|
|
60
|
+
dataStart += 1;
|
|
61
|
+
}
|
|
62
|
+
chunks.push(source.slice(dataStart, contentEnd));
|
|
63
|
+
}
|
|
64
|
+
if (lineEnd >= end)
|
|
65
|
+
break;
|
|
66
|
+
lineStart = lineEnd + 1;
|
|
67
|
+
}
|
|
68
|
+
if (!chunks.length)
|
|
69
|
+
return;
|
|
70
|
+
const data = chunks.join('\n');
|
|
71
|
+
if (data.length > 0)
|
|
72
|
+
emit(data);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=http-stream-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-stream-parser.js","sourceRoot":"","sources":["../src/http-stream-parser.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,gBAAgB;IACnB,OAAO,GAAG,EAAE,CAAA;IAEpB,IAAI,CAAC,KAAa,EAAE,IAA4B,EAAE;QAChD,IAAI,CAAC,OAAO,IAAI,KAAK,CAAA;QACrB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IAAA,CAC9C;IAED,MAAM,CAAC,IAA4B,EAAE;QACnC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QAE7C,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;QACpD,CAAC;IAAA,CACF;IAEO,KAAK,CAAC,OAAe,EAAE,IAA4B,EAAU;QACnE,IAAI,MAAM,GAAG,CAAC,CAAA;QAEd,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,SAAS,GAAG,IAAI,CAAC,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;YAC9D,IAAI,CAAC,SAAS;gBAAE,MAAK;YAErB,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;YAC/D,MAAM,GAAG,SAAS,CAAC,KAAK,GAAG,SAAS,CAAC,MAAM,CAAA;QAC7C,CAAC;QAED,IAAI,MAAM,KAAK,CAAC;YAAE,OAAO,OAAO,CAAA;QAChC,OAAO,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IAAA,CAC7B;IAEO,sBAAsB,CAC5B,MAAc,EACd,SAAiB,EACyB;QAC1C,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;QAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;QAElD,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC;YAAE,OAAO,IAAI,CAAA;QACnC,IAAI,EAAE,GAAG,CAAC;YAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAA;QAC7C,IAAI,IAAI,GAAG,CAAC;YAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAA;QAC7C,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAA;IAAA,CACzE;IAEO,kBAAkB,CACxB,MAAc,EACd,KAAa,EACb,GAAW,EACX,IAA4B,EAC5B;QACA,MAAM,MAAM,GAAa,EAAE,CAAA;QAC3B,IAAI,SAAS,GAAG,KAAK,CAAA;QAErB,OAAO,SAAS,IAAI,GAAG,EAAE,CAAC;YACxB,IAAI,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;YAC7C,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,GAAG;gBAAE,OAAO,GAAG,GAAG,CAAA;YAE/C,IAAI,UAAU,GAAG,OAAO,CAAA;YACxB,IACE,UAAU,GAAG,SAAS;gBACtB,MAAM,CAAC,UAAU,CAAC,UAAU,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,QAAQ,EACjD,CAAC;gBACD,UAAU,IAAI,CAAC,CAAA;YACjB,CAAC;YAED,IACE,UAAU,GAAG,SAAS,IAAI,CAAC;gBAC3B,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,OAAO;gBAC5C,MAAM,CAAC,UAAU,CAAC,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,OAAO;gBAC/C,MAAM,CAAC,UAAU,CAAC,SAAS,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO;gBAChD,MAAM,CAAC,UAAU,CAAC,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,OAAO;gBAC/C,MAAM,CAAC,UAAU,CAAC,SAAS,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,OAAO,EAC/C,CAAC;gBACD,IAAI,SAAS,GAAG,SAAS,GAAG,CAAC,CAAA;gBAC7B,OAAO,SAAS,GAAG,UAAU,EAAE,CAAC;oBAC9B,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;oBACzC,IAAI,IAAI,KAAK,EAAE,CAAC,WAAW,IAAI,IAAI,KAAK,CAAC,CAAC,SAAS;wBAAE,MAAK;oBAC1D,SAAS,IAAI,CAAC,CAAA;gBAChB,CAAC;gBACD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAA;YAClD,CAAC;YAED,IAAI,OAAO,IAAI,GAAG;gBAAE,MAAK;YACzB,SAAS,GAAG,OAAO,GAAG,CAAC,CAAA;QACzB,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,MAAM;YAAE,OAAM;QAC1B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC9B,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,CAAA;IAAA,CAChC;CACF"}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export type HttpClientTransportOptions = {
|
|
|
11
11
|
url: string;
|
|
12
12
|
debug?: boolean;
|
|
13
13
|
EventSource?: typeof EventSource;
|
|
14
|
+
fetch?: typeof fetch;
|
|
14
15
|
decodeBase64?: DecodeBase64Function;
|
|
15
16
|
};
|
|
16
17
|
export declare class HttpTransportClient implements ClientTransport<ConnectionType.Unidirectional> {
|
|
@@ -20,6 +21,7 @@ export declare class HttpTransportClient implements ClientTransport<ConnectionTy
|
|
|
20
21
|
type: ConnectionType.Unidirectional;
|
|
21
22
|
decodeBase64: DecodeBase64Function;
|
|
22
23
|
constructor(format: BaseClientFormat, protocol: ProtocolVersion, options: HttpClientTransportOptions);
|
|
24
|
+
private getFetch;
|
|
23
25
|
url({ procedure, application, payload }: {
|
|
24
26
|
procedure: string;
|
|
25
27
|
application?: string;
|
|
@@ -32,7 +34,11 @@ export declare class HttpTransportClient implements ClientTransport<ConnectionTy
|
|
|
32
34
|
}, options: ClientTransportMessageOptions): Promise<{
|
|
33
35
|
type: "rpc_stream";
|
|
34
36
|
stream: ReadableStream<ArrayBufferView<ArrayBufferLike>>;
|
|
37
|
+
metadata?: undefined;
|
|
38
|
+
source?: undefined;
|
|
39
|
+
result?: undefined;
|
|
35
40
|
} | {
|
|
41
|
+
stream?: undefined;
|
|
36
42
|
type: "blob";
|
|
37
43
|
metadata: {
|
|
38
44
|
type: string;
|
|
@@ -42,6 +48,7 @@ export declare class HttpTransportClient implements ClientTransport<ConnectionTy
|
|
|
42
48
|
source: ReadableStream<Uint8Array<ArrayBuffer>>;
|
|
43
49
|
result?: undefined;
|
|
44
50
|
} | {
|
|
51
|
+
stream?: undefined;
|
|
45
52
|
metadata?: undefined;
|
|
46
53
|
source?: undefined;
|
|
47
54
|
type: "rpc";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createFuture } from '@nmtjs/common';
|
|
2
1
|
import { ConnectionType, ErrorCode, ProtocolBlob } from '@nmtjs/protocol';
|
|
3
2
|
import { ProtocolError } from '@nmtjs/protocol/client';
|
|
3
|
+
import { HttpStreamParser } from './http-stream-parser.js';
|
|
4
4
|
const createDecodeBase64 = (customFn) => {
|
|
5
5
|
return (string) => {
|
|
6
6
|
if ('fromBase64' in Uint8Array &&
|
|
@@ -32,6 +32,13 @@ export class HttpTransportClient {
|
|
|
32
32
|
this.options = { debug: false, ...options };
|
|
33
33
|
this.decodeBase64 = createDecodeBase64(options.decodeBase64);
|
|
34
34
|
}
|
|
35
|
+
getFetch() {
|
|
36
|
+
const implementation = this.options.fetch ?? globalThis.fetch;
|
|
37
|
+
if (!implementation) {
|
|
38
|
+
throw new Error('Fetch API is not available. Provide HttpClientTransportOptions.fetch');
|
|
39
|
+
}
|
|
40
|
+
return implementation;
|
|
41
|
+
}
|
|
35
42
|
url({ procedure, application, payload, }) {
|
|
36
43
|
const base = application ? `/${application}/${procedure}` : `/${procedure}`;
|
|
37
44
|
const url = new URL(base, this.options.url);
|
|
@@ -42,6 +49,7 @@ export class HttpTransportClient {
|
|
|
42
49
|
async call(client, rpc, options) {
|
|
43
50
|
const { procedure, payload } = rpc;
|
|
44
51
|
const requestHeaders = new Headers();
|
|
52
|
+
const fetchImpl = this.getFetch();
|
|
45
53
|
const url = this.url({ application: client.application, procedure });
|
|
46
54
|
if (client.auth)
|
|
47
55
|
requestHeaders.set('Authorization', client.auth);
|
|
@@ -56,35 +64,71 @@ export class HttpTransportClient {
|
|
|
56
64
|
body = buffer;
|
|
57
65
|
}
|
|
58
66
|
if (options._stream_response) {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
:
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
source.addEventListener('open', () => future.resolve({ type: 'rpc_stream', stream: readable }));
|
|
67
|
-
source.addEventListener('close', () => writable.close());
|
|
68
|
-
source.addEventListener('error', (event) => {
|
|
69
|
-
const error = new Error('Stream error', { cause: event });
|
|
70
|
-
future.reject(error);
|
|
71
|
-
writable.abort(error);
|
|
67
|
+
const response = await fetchImpl(url.toString(), {
|
|
68
|
+
body,
|
|
69
|
+
method: 'POST',
|
|
70
|
+
headers: requestHeaders,
|
|
71
|
+
signal: options.signal,
|
|
72
|
+
credentials: 'include',
|
|
73
|
+
keepalive: true,
|
|
72
74
|
});
|
|
73
|
-
|
|
75
|
+
if (!response.ok) {
|
|
74
76
|
try {
|
|
75
|
-
const buffer =
|
|
76
|
-
|
|
77
|
+
const buffer = await response.bytes();
|
|
78
|
+
const error = client.format.decode(buffer);
|
|
79
|
+
throw new ProtocolError(error.code || ErrorCode.ClientRequestError, error.message || response.statusText, error.data);
|
|
77
80
|
}
|
|
78
81
|
catch (cause) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
if (cause instanceof ProtocolError)
|
|
83
|
+
throw cause;
|
|
84
|
+
throw new ProtocolError(ErrorCode.ClientRequestError, `HTTP ${response.status}: ${response.statusText}`);
|
|
82
85
|
}
|
|
86
|
+
}
|
|
87
|
+
if (!response.body) {
|
|
88
|
+
throw new ProtocolError(ErrorCode.ClientRequestError, 'Empty stream response body');
|
|
89
|
+
}
|
|
90
|
+
const stream = new ReadableStream({
|
|
91
|
+
start: async (controller) => {
|
|
92
|
+
const reader = response.body.getReader();
|
|
93
|
+
const decoder = new TextDecoder();
|
|
94
|
+
const parser = new HttpStreamParser();
|
|
95
|
+
try {
|
|
96
|
+
while (true) {
|
|
97
|
+
const { done, value } = await reader.read();
|
|
98
|
+
if (done)
|
|
99
|
+
break;
|
|
100
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
101
|
+
parser.push(chunk, (eventData) => {
|
|
102
|
+
controller.enqueue(this.decodeBase64(eventData));
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
const tail = decoder.decode();
|
|
106
|
+
parser.push(tail, (eventData) => {
|
|
107
|
+
controller.enqueue(this.decodeBase64(eventData));
|
|
108
|
+
});
|
|
109
|
+
parser.finish((eventData) => {
|
|
110
|
+
controller.enqueue(this.decodeBase64(eventData));
|
|
111
|
+
});
|
|
112
|
+
controller.close();
|
|
113
|
+
}
|
|
114
|
+
catch (cause) {
|
|
115
|
+
controller.error(new Error('Stream error', { cause }));
|
|
116
|
+
}
|
|
117
|
+
finally {
|
|
118
|
+
reader.releaseLock();
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
cancel: async () => {
|
|
122
|
+
try {
|
|
123
|
+
await response.body?.cancel();
|
|
124
|
+
}
|
|
125
|
+
catch { }
|
|
126
|
+
},
|
|
83
127
|
});
|
|
84
|
-
return
|
|
128
|
+
return { type: 'rpc_stream', stream };
|
|
85
129
|
}
|
|
86
130
|
else {
|
|
87
|
-
const response = await
|
|
131
|
+
const response = await fetchImpl(url.toString(), {
|
|
88
132
|
body,
|
|
89
133
|
method: 'POST',
|
|
90
134
|
headers: requestHeaders,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@nmtjs/client": "0.15.0-beta.
|
|
14
|
-
"@nmtjs/common": "0.15.0-beta.
|
|
15
|
-
"@nmtjs/protocol": "0.15.0-beta.
|
|
13
|
+
"@nmtjs/client": "0.15.0-beta.45",
|
|
14
|
+
"@nmtjs/common": "0.15.0-beta.45",
|
|
15
|
+
"@nmtjs/protocol": "0.15.0-beta.45"
|
|
16
16
|
},
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"@nmtjs/
|
|
19
|
-
"@nmtjs/
|
|
20
|
-
"@nmtjs/protocol": "0.15.0-beta.
|
|
18
|
+
"@nmtjs/common": "0.15.0-beta.45",
|
|
19
|
+
"@nmtjs/client": "0.15.0-beta.45",
|
|
20
|
+
"@nmtjs/protocol": "0.15.0-beta.45"
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
23
23
|
"dist",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"LICENSE.md",
|
|
26
26
|
"README.md"
|
|
27
27
|
],
|
|
28
|
-
"version": "0.15.0-beta.
|
|
28
|
+
"version": "0.15.0-beta.45",
|
|
29
29
|
"scripts": {
|
|
30
30
|
"clean-build": "rm -rf ./dist"
|
|
31
31
|
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export class HttpStreamParser {
|
|
2
|
+
private pending = ''
|
|
3
|
+
|
|
4
|
+
push(chunk: string, emit: (data: string) => void) {
|
|
5
|
+
this.pending += chunk
|
|
6
|
+
this.pending = this.parse(this.pending, emit)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
finish(emit: (data: string) => void) {
|
|
10
|
+
this.pending = this.parse(this.pending, emit)
|
|
11
|
+
|
|
12
|
+
if (this.pending.trim().length > 0) {
|
|
13
|
+
throw new Error('Malformed stream response frame')
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
private parse(pending: string, emit: (data: string) => void): string {
|
|
18
|
+
let cursor = 0
|
|
19
|
+
|
|
20
|
+
while (true) {
|
|
21
|
+
const separator = this.findNextEventSeparator(pending, cursor)
|
|
22
|
+
if (!separator) break
|
|
23
|
+
|
|
24
|
+
this.emitEventDataFrame(pending, cursor, separator.index, emit)
|
|
25
|
+
cursor = separator.index + separator.length
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (cursor === 0) return pending
|
|
29
|
+
return pending.slice(cursor)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private findNextEventSeparator(
|
|
33
|
+
source: string,
|
|
34
|
+
fromIndex: number,
|
|
35
|
+
): { index: number; length: number } | null {
|
|
36
|
+
const lf = source.indexOf('\n\n', fromIndex)
|
|
37
|
+
const crlf = source.indexOf('\r\n\r\n', fromIndex)
|
|
38
|
+
|
|
39
|
+
if (lf < 0 && crlf < 0) return null
|
|
40
|
+
if (lf < 0) return { index: crlf, length: 4 }
|
|
41
|
+
if (crlf < 0) return { index: lf, length: 2 }
|
|
42
|
+
return lf < crlf ? { index: lf, length: 2 } : { index: crlf, length: 4 }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private emitEventDataFrame(
|
|
46
|
+
source: string,
|
|
47
|
+
start: number,
|
|
48
|
+
end: number,
|
|
49
|
+
emit: (data: string) => void,
|
|
50
|
+
) {
|
|
51
|
+
const chunks: string[] = []
|
|
52
|
+
let lineStart = start
|
|
53
|
+
|
|
54
|
+
while (lineStart <= end) {
|
|
55
|
+
let lineEnd = source.indexOf('\n', lineStart)
|
|
56
|
+
if (lineEnd < 0 || lineEnd > end) lineEnd = end
|
|
57
|
+
|
|
58
|
+
let contentEnd = lineEnd
|
|
59
|
+
if (
|
|
60
|
+
contentEnd > lineStart &&
|
|
61
|
+
source.charCodeAt(contentEnd - 1) === 13 /* \r */
|
|
62
|
+
) {
|
|
63
|
+
contentEnd -= 1
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (
|
|
67
|
+
contentEnd - lineStart >= 5 &&
|
|
68
|
+
source.charCodeAt(lineStart) === 100 /* d */ &&
|
|
69
|
+
source.charCodeAt(lineStart + 1) === 97 /* a */ &&
|
|
70
|
+
source.charCodeAt(lineStart + 2) === 116 /* t */ &&
|
|
71
|
+
source.charCodeAt(lineStart + 3) === 97 /* a */ &&
|
|
72
|
+
source.charCodeAt(lineStart + 4) === 58 /* : */
|
|
73
|
+
) {
|
|
74
|
+
let dataStart = lineStart + 5
|
|
75
|
+
while (dataStart < contentEnd) {
|
|
76
|
+
const code = source.charCodeAt(dataStart)
|
|
77
|
+
if (code !== 32 /* space */ && code !== 9 /* tab */) break
|
|
78
|
+
dataStart += 1
|
|
79
|
+
}
|
|
80
|
+
chunks.push(source.slice(dataStart, contentEnd))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (lineEnd >= end) break
|
|
84
|
+
lineStart = lineEnd + 1
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (!chunks.length) return
|
|
88
|
+
const data = chunks.join('\n')
|
|
89
|
+
if (data.length > 0) emit(data)
|
|
90
|
+
}
|
|
91
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -6,10 +6,11 @@ import type {
|
|
|
6
6
|
} from '@nmtjs/client'
|
|
7
7
|
import type { ProtocolVersion } from '@nmtjs/protocol'
|
|
8
8
|
import type { BaseClientFormat } from '@nmtjs/protocol/client'
|
|
9
|
-
import { createFuture } from '@nmtjs/common'
|
|
10
9
|
import { ConnectionType, ErrorCode, ProtocolBlob } from '@nmtjs/protocol'
|
|
11
10
|
import { ProtocolError } from '@nmtjs/protocol/client'
|
|
12
11
|
|
|
12
|
+
import { HttpStreamParser } from './http-stream-parser.ts'
|
|
13
|
+
|
|
13
14
|
type DecodeBase64Function = (data: string) => ArrayBufferView
|
|
14
15
|
|
|
15
16
|
const createDecodeBase64 = (
|
|
@@ -41,6 +42,7 @@ export type HttpClientTransportOptions = {
|
|
|
41
42
|
url: string
|
|
42
43
|
debug?: boolean
|
|
43
44
|
EventSource?: typeof EventSource
|
|
45
|
+
fetch?: typeof fetch
|
|
44
46
|
decodeBase64?: DecodeBase64Function
|
|
45
47
|
}
|
|
46
48
|
|
|
@@ -59,6 +61,16 @@ export class HttpTransportClient
|
|
|
59
61
|
this.decodeBase64 = createDecodeBase64(options.decodeBase64)
|
|
60
62
|
}
|
|
61
63
|
|
|
64
|
+
private getFetch(): typeof fetch {
|
|
65
|
+
const implementation = this.options.fetch ?? globalThis.fetch
|
|
66
|
+
if (!implementation) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
'Fetch API is not available. Provide HttpClientTransportOptions.fetch',
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
return implementation
|
|
72
|
+
}
|
|
73
|
+
|
|
62
74
|
url({
|
|
63
75
|
procedure,
|
|
64
76
|
application,
|
|
@@ -81,6 +93,7 @@ export class HttpTransportClient
|
|
|
81
93
|
) {
|
|
82
94
|
const { procedure, payload } = rpc
|
|
83
95
|
const requestHeaders = new Headers()
|
|
96
|
+
const fetchImpl = this.getFetch()
|
|
84
97
|
|
|
85
98
|
const url = this.url({ application: client.application, procedure })
|
|
86
99
|
|
|
@@ -98,38 +111,85 @@ export class HttpTransportClient
|
|
|
98
111
|
}
|
|
99
112
|
|
|
100
113
|
if (options._stream_response) {
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
:
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}>()
|
|
109
|
-
const { readable, writable } = new TransformStream()
|
|
110
|
-
const writer = writable.getWriter()
|
|
111
|
-
source.addEventListener('open', () =>
|
|
112
|
-
future.resolve({ type: 'rpc_stream', stream: readable }),
|
|
113
|
-
)
|
|
114
|
-
source.addEventListener('close', () => writable.close())
|
|
115
|
-
source.addEventListener('error', (event) => {
|
|
116
|
-
const error = new Error('Stream error', { cause: event })
|
|
117
|
-
future.reject(error)
|
|
118
|
-
writable.abort(error)
|
|
114
|
+
const response = await fetchImpl(url.toString(), {
|
|
115
|
+
body,
|
|
116
|
+
method: 'POST',
|
|
117
|
+
headers: requestHeaders,
|
|
118
|
+
signal: options.signal,
|
|
119
|
+
credentials: 'include',
|
|
120
|
+
keepalive: true,
|
|
119
121
|
})
|
|
120
|
-
|
|
122
|
+
|
|
123
|
+
if (!response.ok) {
|
|
121
124
|
try {
|
|
122
|
-
const buffer =
|
|
123
|
-
|
|
125
|
+
const buffer = await response.bytes()
|
|
126
|
+
const error = client.format.decode(buffer) as {
|
|
127
|
+
code?: string
|
|
128
|
+
message?: string
|
|
129
|
+
data?: unknown
|
|
130
|
+
}
|
|
131
|
+
throw new ProtocolError(
|
|
132
|
+
error.code || ErrorCode.ClientRequestError,
|
|
133
|
+
error.message || response.statusText,
|
|
134
|
+
error.data,
|
|
135
|
+
)
|
|
124
136
|
} catch (cause) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
137
|
+
if (cause instanceof ProtocolError) throw cause
|
|
138
|
+
throw new ProtocolError(
|
|
139
|
+
ErrorCode.ClientRequestError,
|
|
140
|
+
`HTTP ${response.status}: ${response.statusText}`,
|
|
141
|
+
)
|
|
128
142
|
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!response.body) {
|
|
146
|
+
throw new ProtocolError(
|
|
147
|
+
ErrorCode.ClientRequestError,
|
|
148
|
+
'Empty stream response body',
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const stream = new ReadableStream<ArrayBufferView>({
|
|
153
|
+
start: async (controller) => {
|
|
154
|
+
const reader = response.body!.getReader()
|
|
155
|
+
const decoder = new TextDecoder()
|
|
156
|
+
const parser = new HttpStreamParser()
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
while (true) {
|
|
160
|
+
const { done, value } = await reader.read()
|
|
161
|
+
if (done) break
|
|
162
|
+
const chunk = decoder.decode(value, { stream: true })
|
|
163
|
+
parser.push(chunk, (eventData) => {
|
|
164
|
+
controller.enqueue(this.decodeBase64(eventData))
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const tail = decoder.decode()
|
|
169
|
+
parser.push(tail, (eventData) => {
|
|
170
|
+
controller.enqueue(this.decodeBase64(eventData))
|
|
171
|
+
})
|
|
172
|
+
parser.finish((eventData) => {
|
|
173
|
+
controller.enqueue(this.decodeBase64(eventData))
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
controller.close()
|
|
177
|
+
} catch (cause) {
|
|
178
|
+
controller.error(new Error('Stream error', { cause }))
|
|
179
|
+
} finally {
|
|
180
|
+
reader.releaseLock()
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
cancel: async () => {
|
|
184
|
+
try {
|
|
185
|
+
await response.body?.cancel()
|
|
186
|
+
} catch {}
|
|
187
|
+
},
|
|
129
188
|
})
|
|
130
|
-
|
|
189
|
+
|
|
190
|
+
return { type: 'rpc_stream' as const, stream }
|
|
131
191
|
} else {
|
|
132
|
-
const response = await
|
|
192
|
+
const response = await fetchImpl(url.toString(), {
|
|
133
193
|
body,
|
|
134
194
|
method: 'POST',
|
|
135
195
|
headers: requestHeaders,
|