@nmtjs/http-client 0.15.0-beta.9 → 0.15.1

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,7 +21,8 @@ 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);
23
- url({ procedure, application, payload, }: {
24
+ private getFetch;
25
+ url({ procedure, application, payload }: {
24
26
  procedure: string;
25
27
  application?: string;
26
28
  payload?: unknown;
@@ -31,21 +33,26 @@ export declare class HttpTransportClient implements ClientTransport<ConnectionTy
31
33
  payload: unknown;
32
34
  }, options: ClientTransportMessageOptions): Promise<{
33
35
  type: "rpc_stream";
34
- stream: ReadableStream<ArrayBufferView>;
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;
39
45
  size: number | undefined;
40
46
  filename: string | undefined;
41
47
  };
42
- source: any;
48
+ source: ReadableStream<Uint8Array<ArrayBuffer>>;
43
49
  result?: undefined;
44
50
  } | {
45
- type: "rpc";
46
- result: Uint8Array<ArrayBuffer>;
51
+ stream?: undefined;
47
52
  metadata?: undefined;
48
53
  source?: undefined;
54
+ type: "rpc";
55
+ result: Uint8Array<ArrayBuffer>;
49
56
  }>;
50
57
  }
51
58
  export type HttpTransportFactory = ClientTransportFactory<ConnectionType.Unidirectional, HttpClientTransportOptions, HttpTransportClient>;
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
- import { createFuture } from '@nmtjs/common';
2
- import { ConnectionType, ProtocolBlob } from '@nmtjs/protocol';
1
+ import { ConnectionType, ErrorCode, ProtocolBlob } from '@nmtjs/protocol';
2
+ import { ProtocolError } from '@nmtjs/protocol/client';
3
+ import { HttpStreamParser } from './http-stream-parser.js';
3
4
  const createDecodeBase64 = (customFn) => {
4
5
  return (string) => {
5
6
  if ('fromBase64' in Uint8Array &&
@@ -31,6 +32,13 @@ export class HttpTransportClient {
31
32
  this.options = { debug: false, ...options };
32
33
  this.decodeBase64 = createDecodeBase64(options.decodeBase64);
33
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
+ }
34
42
  url({ procedure, application, payload, }) {
35
43
  const base = application ? `/${application}/${procedure}` : `/${procedure}`;
36
44
  const url = new URL(base, this.options.url);
@@ -41,9 +49,11 @@ export class HttpTransportClient {
41
49
  async call(client, rpc, options) {
42
50
  const { procedure, payload } = rpc;
43
51
  const requestHeaders = new Headers();
52
+ const fetchImpl = this.getFetch();
44
53
  const url = this.url({ application: client.application, procedure });
45
54
  if (client.auth)
46
55
  requestHeaders.set('Authorization', client.auth);
56
+ requestHeaders.set('Accept', client.format.contentType);
47
57
  let body;
48
58
  if (payload instanceof ProtocolBlob) {
49
59
  requestHeaders.set('Content-Type', payload.metadata.type);
@@ -55,34 +65,71 @@ export class HttpTransportClient {
55
65
  body = buffer;
56
66
  }
57
67
  if (options._stream_response) {
58
- const _constructor = this.options.EventSource
59
- ? this.options.EventSource
60
- : EventSource;
61
- const source = new _constructor(url.toString(), { withCredentials: true });
62
- const future = createFuture();
63
- const { readable, writable } = new TransformStream();
64
- const writer = writable.getWriter();
65
- source.addEventListener('open', () => future.resolve({ type: 'rpc_stream', stream: readable }));
66
- source.addEventListener('close', () => writable.close());
67
- source.addEventListener('error', (event) => {
68
- const error = new Error('Stream error', { cause: event });
69
- future.reject(error);
70
- writable.abort(error);
68
+ const response = await fetchImpl(url.toString(), {
69
+ body,
70
+ method: 'POST',
71
+ headers: requestHeaders,
72
+ signal: options.signal,
73
+ credentials: 'include',
74
+ keepalive: true,
71
75
  });
72
- source.addEventListener('message', (event) => {
76
+ if (!response.ok) {
73
77
  try {
74
- const buffer = this.decodeBase64(event.data);
75
- writer.write(buffer);
78
+ const buffer = await response.bytes();
79
+ const error = client.format.decode(buffer);
80
+ throw new ProtocolError(error.code || ErrorCode.ClientRequestError, error.message || response.statusText, error.data);
76
81
  }
77
82
  catch (cause) {
78
- const error = new Error('Failed to decode stream message', { cause });
79
- writable.abort(error);
83
+ if (cause instanceof ProtocolError)
84
+ throw cause;
85
+ throw new ProtocolError(ErrorCode.ClientRequestError, `HTTP ${response.status}: ${response.statusText}`);
80
86
  }
87
+ }
88
+ if (!response.body) {
89
+ throw new ProtocolError(ErrorCode.ClientRequestError, 'Empty stream response body');
90
+ }
91
+ const stream = new ReadableStream({
92
+ start: async (controller) => {
93
+ const reader = response.body.getReader();
94
+ const decoder = new TextDecoder();
95
+ const parser = new HttpStreamParser();
96
+ try {
97
+ while (true) {
98
+ const { done, value } = await reader.read();
99
+ if (done)
100
+ break;
101
+ const chunk = decoder.decode(value, { stream: true });
102
+ parser.push(chunk, (eventData) => {
103
+ controller.enqueue(this.decodeBase64(eventData));
104
+ });
105
+ }
106
+ const tail = decoder.decode();
107
+ parser.push(tail, (eventData) => {
108
+ controller.enqueue(this.decodeBase64(eventData));
109
+ });
110
+ parser.finish((eventData) => {
111
+ controller.enqueue(this.decodeBase64(eventData));
112
+ });
113
+ controller.close();
114
+ }
115
+ catch (cause) {
116
+ controller.error(new Error('Stream error', { cause }));
117
+ }
118
+ finally {
119
+ reader.releaseLock();
120
+ }
121
+ },
122
+ cancel: async () => {
123
+ try {
124
+ await response.body?.cancel();
125
+ }
126
+ catch { }
127
+ },
81
128
  });
82
- return future.promise;
129
+ return { type: 'rpc_stream', stream };
83
130
  }
84
131
  else {
85
- const response = await fetch(url.toString(), {
132
+ const response = await fetchImpl(url.toString(), {
86
133
  body,
87
134
  method: 'POST',
88
135
  headers: requestHeaders,
@@ -106,7 +153,7 @@ export class HttpTransportClient {
106
153
  return {
107
154
  type: 'blob',
108
155
  metadata: { type, size, filename },
109
- source: body,
156
+ source: response.body,
110
157
  };
111
158
  }
112
159
  else {
@@ -114,9 +161,17 @@ export class HttpTransportClient {
114
161
  }
115
162
  }
116
163
  else {
117
- const decoded = await response.text();
118
- // throw new ProtocolError()
119
- throw new Error();
164
+ try {
165
+ const buffer = await response.bytes();
166
+ const error = client.format.decode(buffer);
167
+ throw new ProtocolError(error.code || ErrorCode.ClientRequestError, error.message || response.statusText, error.data);
168
+ }
169
+ catch (cause) {
170
+ if (cause instanceof ProtocolError)
171
+ throw cause;
172
+ // If decoding fails, throw generic error with status info
173
+ throw new ProtocolError(ErrorCode.ClientRequestError, `HTTP ${response.status}: ${response.statusText}`);
174
+ }
120
175
  }
121
176
  }
122
177
  }
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
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "@nmtjs/http-client",
3
+ "description": "HTTP client transport for Neemata.",
3
4
  "type": "module",
4
5
  "exports": {
5
6
  ".": {
@@ -9,14 +10,14 @@
9
10
  }
10
11
  },
11
12
  "dependencies": {
12
- "@nmtjs/client": "0.15.0-beta.9",
13
- "@nmtjs/protocol": "0.15.0-beta.9",
14
- "@nmtjs/common": "0.15.0-beta.9"
13
+ "@nmtjs/client": "0.15.1",
14
+ "@nmtjs/common": "0.15.1",
15
+ "@nmtjs/protocol": "0.15.1"
15
16
  },
16
17
  "peerDependencies": {
17
- "@nmtjs/client": "0.15.0-beta.9",
18
- "@nmtjs/common": "0.15.0-beta.9",
19
- "@nmtjs/protocol": "0.15.0-beta.9"
18
+ "@nmtjs/client": "0.15.1",
19
+ "@nmtjs/protocol": "0.15.1",
20
+ "@nmtjs/common": "0.15.1"
20
21
  },
21
22
  "files": [
22
23
  "dist",
@@ -24,11 +25,8 @@
24
25
  "LICENSE.md",
25
26
  "README.md"
26
27
  ],
27
- "version": "0.15.0-beta.9",
28
+ "version": "0.15.1",
28
29
  "scripts": {
29
- "clean-build": "rm -rf ./dist",
30
- "build": "tsc --declaration --sourcemap",
31
- "dev": "tsc --watch",
32
- "type-check": "tsc --noEmit"
30
+ "clean-build": "rm -rf ./dist"
33
31
  }
34
32
  }
@@ -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,8 +6,10 @@ 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
- import { ConnectionType, ProtocolBlob } from '@nmtjs/protocol'
9
+ import { ConnectionType, ErrorCode, ProtocolBlob } from '@nmtjs/protocol'
10
+ import { ProtocolError } from '@nmtjs/protocol/client'
11
+
12
+ import { HttpStreamParser } from './http-stream-parser.ts'
11
13
 
12
14
  type DecodeBase64Function = (data: string) => ArrayBufferView
13
15
 
@@ -40,6 +42,7 @@ export type HttpClientTransportOptions = {
40
42
  url: string
41
43
  debug?: boolean
42
44
  EventSource?: typeof EventSource
45
+ fetch?: typeof fetch
43
46
  decodeBase64?: DecodeBase64Function
44
47
  }
45
48
 
@@ -58,6 +61,16 @@ export class HttpTransportClient
58
61
  this.decodeBase64 = createDecodeBase64(options.decodeBase64)
59
62
  }
60
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
+
61
74
  url({
62
75
  procedure,
63
76
  application,
@@ -80,10 +93,12 @@ export class HttpTransportClient
80
93
  ) {
81
94
  const { procedure, payload } = rpc
82
95
  const requestHeaders = new Headers()
96
+ const fetchImpl = this.getFetch()
83
97
 
84
98
  const url = this.url({ application: client.application, procedure })
85
99
 
86
100
  if (client.auth) requestHeaders.set('Authorization', client.auth)
101
+ requestHeaders.set('Accept', client.format.contentType)
87
102
 
88
103
  let body: any
89
104
 
@@ -97,37 +112,85 @@ export class HttpTransportClient
97
112
  }
98
113
 
99
114
  if (options._stream_response) {
100
- const _constructor = this.options.EventSource
101
- ? this.options.EventSource
102
- : EventSource
103
- const source = new _constructor(url.toString(), { withCredentials: true })
104
- const future = createFuture<{
105
- type: 'rpc_stream'
106
- stream: ReadableStream<ArrayBufferView>
107
- }>()
108
- const { readable, writable } = new TransformStream()
109
- const writer = writable.getWriter()
110
- source.addEventListener('open', () =>
111
- future.resolve({ type: 'rpc_stream', stream: readable }),
112
- )
113
- source.addEventListener('close', () => writable.close())
114
- source.addEventListener('error', (event) => {
115
- const error = new Error('Stream error', { cause: event })
116
- future.reject(error)
117
- writable.abort(error)
115
+ const response = await fetchImpl(url.toString(), {
116
+ body,
117
+ method: 'POST',
118
+ headers: requestHeaders,
119
+ signal: options.signal,
120
+ credentials: 'include',
121
+ keepalive: true,
118
122
  })
119
- source.addEventListener('message', (event) => {
123
+
124
+ if (!response.ok) {
120
125
  try {
121
- const buffer = this.decodeBase64(event.data)
122
- writer.write(buffer)
126
+ const buffer = await response.bytes()
127
+ const error = client.format.decode(buffer) as {
128
+ code?: string
129
+ message?: string
130
+ data?: unknown
131
+ }
132
+ throw new ProtocolError(
133
+ error.code || ErrorCode.ClientRequestError,
134
+ error.message || response.statusText,
135
+ error.data,
136
+ )
123
137
  } catch (cause) {
124
- const error = new Error('Failed to decode stream message', { cause })
125
- writable.abort(error)
138
+ if (cause instanceof ProtocolError) throw cause
139
+ throw new ProtocolError(
140
+ ErrorCode.ClientRequestError,
141
+ `HTTP ${response.status}: ${response.statusText}`,
142
+ )
126
143
  }
144
+ }
145
+
146
+ if (!response.body) {
147
+ throw new ProtocolError(
148
+ ErrorCode.ClientRequestError,
149
+ 'Empty stream response body',
150
+ )
151
+ }
152
+
153
+ const stream = new ReadableStream<ArrayBufferView>({
154
+ start: async (controller) => {
155
+ const reader = response.body!.getReader()
156
+ const decoder = new TextDecoder()
157
+ const parser = new HttpStreamParser()
158
+
159
+ try {
160
+ while (true) {
161
+ const { done, value } = await reader.read()
162
+ if (done) break
163
+ const chunk = decoder.decode(value, { stream: true })
164
+ parser.push(chunk, (eventData) => {
165
+ controller.enqueue(this.decodeBase64(eventData))
166
+ })
167
+ }
168
+
169
+ const tail = decoder.decode()
170
+ parser.push(tail, (eventData) => {
171
+ controller.enqueue(this.decodeBase64(eventData))
172
+ })
173
+ parser.finish((eventData) => {
174
+ controller.enqueue(this.decodeBase64(eventData))
175
+ })
176
+
177
+ controller.close()
178
+ } catch (cause) {
179
+ controller.error(new Error('Stream error', { cause }))
180
+ } finally {
181
+ reader.releaseLock()
182
+ }
183
+ },
184
+ cancel: async () => {
185
+ try {
186
+ await response.body?.cancel()
187
+ } catch {}
188
+ },
127
189
  })
128
- return future.promise
190
+
191
+ return { type: 'rpc_stream' as const, stream }
129
192
  } else {
130
- const response = await fetch(url.toString(), {
193
+ const response = await fetchImpl(url.toString(), {
131
194
  body,
132
195
  method: 'POST',
133
196
  headers: requestHeaders,
@@ -153,15 +216,32 @@ export class HttpTransportClient
153
216
  return {
154
217
  type: 'blob' as const,
155
218
  metadata: { type, size, filename },
156
- source: body,
219
+ source: response.body!,
157
220
  }
158
221
  } else {
159
222
  return { type: 'rpc' as const, result: await response.bytes() }
160
223
  }
161
224
  } else {
162
- const decoded = await response.text()
163
- // throw new ProtocolError()
164
- throw new Error()
225
+ try {
226
+ const buffer = await response.bytes()
227
+ const error = client.format.decode(buffer) as {
228
+ code?: string
229
+ message?: string
230
+ data?: unknown
231
+ }
232
+ throw new ProtocolError(
233
+ error.code || ErrorCode.ClientRequestError,
234
+ error.message || response.statusText,
235
+ error.data,
236
+ )
237
+ } catch (cause) {
238
+ if (cause instanceof ProtocolError) throw cause
239
+ // If decoding fails, throw generic error with status info
240
+ throw new ProtocolError(
241
+ ErrorCode.ClientRequestError,
242
+ `HTTP ${response.status}: ${response.statusText}`,
243
+ )
244
+ }
165
245
  }
166
246
  }
167
247
  }