@nmtjs/http-client 0.15.0-beta.43 → 0.15.0-beta.44

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.
@@ -0,0 +1,8 @@
1
+ export declare class HttpStreamParser {
2
+ private pending;
3
+ push(chunk: string, emit: (data: string) => void): void;
4
+ finish(emit: (data: string) => void): void;
5
+ private parse;
6
+ private findNextEventSeparator;
7
+ private emitEventDataFrame;
8
+ }
@@ -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":"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"}
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 _constructor = this.options.EventSource
60
- ? this.options.EventSource
61
- : EventSource;
62
- const source = new _constructor(url.toString(), { withCredentials: true });
63
- const future = createFuture();
64
- const { readable, writable } = new TransformStream();
65
- const writer = writable.getWriter();
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
- source.addEventListener('message', (event) => {
75
+ if (!response.ok) {
74
76
  try {
75
- const buffer = this.decodeBase64(event.data);
76
- writer.write(buffer);
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
- const error = new Error('Failed to decode stream message', { cause });
80
- writable.abort(error);
81
- source.close();
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 future.promise;
128
+ return { type: 'rpc_stream', stream };
85
129
  }
86
130
  else {
87
- const response = await fetch(url.toString(), {
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":"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"}
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.43",
14
- "@nmtjs/common": "0.15.0-beta.43",
15
- "@nmtjs/protocol": "0.15.0-beta.43"
13
+ "@nmtjs/client": "0.15.0-beta.44",
14
+ "@nmtjs/protocol": "0.15.0-beta.44",
15
+ "@nmtjs/common": "0.15.0-beta.44"
16
16
  },
17
17
  "peerDependencies": {
18
- "@nmtjs/client": "0.15.0-beta.43",
19
- "@nmtjs/common": "0.15.0-beta.43",
20
- "@nmtjs/protocol": "0.15.0-beta.43"
18
+ "@nmtjs/client": "0.15.0-beta.44",
19
+ "@nmtjs/common": "0.15.0-beta.44",
20
+ "@nmtjs/protocol": "0.15.0-beta.44"
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.43",
28
+ "version": "0.15.0-beta.44",
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 _constructor = this.options.EventSource
102
- ? this.options.EventSource
103
- : EventSource
104
- const source = new _constructor(url.toString(), { withCredentials: true })
105
- const future = createFuture<{
106
- type: 'rpc_stream'
107
- stream: ReadableStream<ArrayBufferView>
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
- source.addEventListener('message', (event) => {
122
+
123
+ if (!response.ok) {
121
124
  try {
122
- const buffer = this.decodeBase64(event.data)
123
- writer.write(buffer)
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
- const error = new Error('Failed to decode stream message', { cause })
126
- writable.abort(error)
127
- source.close()
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
- return future.promise
189
+
190
+ return { type: 'rpc_stream' as const, stream }
131
191
  } else {
132
- const response = await fetch(url.toString(), {
192
+ const response = await fetchImpl(url.toString(), {
133
193
  body,
134
194
  method: 'POST',
135
195
  headers: requestHeaders,