@orpc/client 2.0.0-beta.15 → 2.0.0-beta.16
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/README.md +1 -1
- package/dist/adapters/fetch/index.mjs +26 -1
- package/dist/plugins/index.d.mts +57 -2
- package/dist/plugins/index.d.ts +57 -2
- package/dist/plugins/index.mjs +227 -3
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -175,7 +175,7 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
|
|
|
175
175
|
<a href="https://github.com/illarionvk?ref=orpc" target="_blank" rel="noopener" title="Illarion Koperski"><img src="https://avatars.githubusercontent.com/u/5012724?u=7cfa13652f7ac5fb3c56d880e3eb3fbe40c3ea34&v=4" width="32" height="32" alt="Illarion Koperski" /></a>
|
|
176
176
|
<a href="https://github.com/steelbrain?ref=orpc" target="_blank" rel="noopener" title="Anees Iqbal"><img src="https://avatars.githubusercontent.com/u/4278113?u=22b80b5399eed68ac76cd58b02961b0481f1db11&v=4" width="32" height="32" alt="Anees Iqbal" /></a>
|
|
177
177
|
<a href="https://github.com/Scrumplex?ref=orpc" target="_blank" rel="noopener" title="Sefa Eyeoglu"><img src="https://avatars.githubusercontent.com/u/11587657?u=ab503582165c0bbff0cca47ce31c9450bb1553c9&v=4" width="32" height="32" alt="Sefa Eyeoglu" /></a>
|
|
178
|
-
<a href="https://github.com/nattstack?ref=orpc" target="_blank" rel="noopener" title="
|
|
178
|
+
<a href="https://github.com/nattstack?ref=orpc" target="_blank" rel="noopener" title="NΛTT"><img src="https://avatars.githubusercontent.com/u/31426677?u=fa9dbb8b3e66eb0ea3c88db5dc07f31c8c5418fe&v=4" width="32" height="32" alt="NΛTT" /></a>
|
|
179
179
|
<a href="https://github.com/ChromeGG?ref=orpc" target="_blank" rel="noopener" title="Adam Tkaczyk"><img src="https://avatars.githubusercontent.com/u/39050595?u=a58ca6042a6950e94e6e92442db76ef584279bc0&v=4" width="32" height="32" alt="Adam Tkaczyk" /></a>
|
|
180
180
|
<a href="https://github.com/plancraft?ref=orpc" target="_blank" rel="noopener" title="plancraft"><img src="https://avatars.githubusercontent.com/u/46482287?v=4" width="32" height="32" alt="plancraft" /></a>
|
|
181
181
|
</p>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { sortPlugins, value, intercept } from '@orpc/shared';
|
|
1
|
+
import { sortPlugins, value, intercept, once } from '@orpc/shared';
|
|
2
2
|
import { toFetchBody, toFetchHeaders, toStandardLazyResponse } from '@standardserver/fetch';
|
|
3
3
|
import { S as StandardLink, R as RPCLinkCodec } from '../../shared/client.BRJnOJ0R.mjs';
|
|
4
4
|
import '@standardserver/core';
|
|
@@ -21,6 +21,25 @@ class CompositeFetchLinkTransportPlugin {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
const GET_SUPPORTED_DUPLEX_MODE = once(() => {
|
|
25
|
+
try {
|
|
26
|
+
let duplex;
|
|
27
|
+
void new Request(
|
|
28
|
+
"https://example.com",
|
|
29
|
+
{
|
|
30
|
+
method: "POST",
|
|
31
|
+
body: new ReadableStream(),
|
|
32
|
+
get duplex() {
|
|
33
|
+
duplex = "half";
|
|
34
|
+
return "half";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
return duplex;
|
|
39
|
+
} catch {
|
|
40
|
+
return void 0;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
24
43
|
class FetchLinkTransport {
|
|
25
44
|
origin;
|
|
26
45
|
fetch;
|
|
@@ -47,6 +66,12 @@ class FetchLinkTransport {
|
|
|
47
66
|
signal: options.signal,
|
|
48
67
|
redirect: "manual"
|
|
49
68
|
};
|
|
69
|
+
if (body instanceof ReadableStream) {
|
|
70
|
+
const duplex = GET_SUPPORTED_DUPLEX_MODE();
|
|
71
|
+
if (duplex !== void 0) {
|
|
72
|
+
init.duplex = duplex;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
50
75
|
const response = await intercept(
|
|
51
76
|
this.fetchInterceptors,
|
|
52
77
|
{ ...options, url, path, init },
|
package/dist/plugins/index.d.mts
CHANGED
|
@@ -136,6 +136,61 @@ declare class DedupeLinkPlugin<T extends ClientContext> implements StandardLinkP
|
|
|
136
136
|
private execute;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
interface RequestCompressionLinkPluginOptions<_T extends ClientContext> {
|
|
140
|
+
/**
|
|
141
|
+
* The compression scheme to use for request compression.
|
|
142
|
+
*
|
|
143
|
+
* @default 'gzip'
|
|
144
|
+
*/
|
|
145
|
+
encoding?: 'gzip' | 'deflate' | 'deflate-raw';
|
|
146
|
+
/**
|
|
147
|
+
* The minimum request size in bytes required to trigger compression.
|
|
148
|
+
* Requests smaller than this threshold will not be compressed to avoid overhead.
|
|
149
|
+
* If the request size cannot be determined, compression will still be applied.
|
|
150
|
+
*
|
|
151
|
+
* @default 1024 (1KB)
|
|
152
|
+
*/
|
|
153
|
+
threshold?: number;
|
|
154
|
+
}
|
|
155
|
+
declare class RequestCompressionLinkPlugin<T extends ClientContext> implements StandardLinkPlugin<T> {
|
|
156
|
+
name: string;
|
|
157
|
+
/**
|
|
158
|
+
* Compression should be done after batching, to compress the final request
|
|
159
|
+
*/
|
|
160
|
+
after: string[];
|
|
161
|
+
private readonly encoding;
|
|
162
|
+
private readonly threshold;
|
|
163
|
+
constructor(options?: RequestCompressionLinkPluginOptions<T>);
|
|
164
|
+
init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
interface ResponseCompressionLinkPluginOptions<_T extends ClientContext> {
|
|
168
|
+
/**
|
|
169
|
+
* Compression schemes to advertise via Accept-Encoding, in preference order.
|
|
170
|
+
* Only schemes that can be decompressed by this plugin should be listed.
|
|
171
|
+
*
|
|
172
|
+
* @default ['gzip', 'deflate']
|
|
173
|
+
*/
|
|
174
|
+
encodings?: readonly ('gzip' | 'deflate' | 'deflate-raw')[];
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Advertises Accept-Encoding on requests and decompresses response bodies
|
|
178
|
+
* based on the Content-Encoding header. Works at the standard link level,
|
|
179
|
+
* so it supports all adapters.
|
|
180
|
+
*
|
|
181
|
+
* @see {@link https://orpc.dev/docs/plugins/response-compression Response Compression Plugin Docs}
|
|
182
|
+
*/
|
|
183
|
+
declare class ResponseCompressionLinkPlugin<T extends ClientContext> implements StandardLinkPlugin<T> {
|
|
184
|
+
name: string;
|
|
185
|
+
/**
|
|
186
|
+
* Decompression should wrap the final batch response instead of sub-responses.
|
|
187
|
+
*/
|
|
188
|
+
after: string[];
|
|
189
|
+
private readonly encodings;
|
|
190
|
+
constructor(options?: ResponseCompressionLinkPluginOptions<T>);
|
|
191
|
+
init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
|
|
192
|
+
}
|
|
193
|
+
|
|
139
194
|
interface RetryLinkPluginAttemptOptions<T extends RetryLinkPluginContext> extends StandardLinkInterceptorOptions<T> {
|
|
140
195
|
/**
|
|
141
196
|
* Latest retry delay advertised by the server via event metadata.
|
|
@@ -236,5 +291,5 @@ declare class RetryAfterLinkPlugin<T extends ClientContext> implements StandardL
|
|
|
236
291
|
init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
|
|
237
292
|
}
|
|
238
293
|
|
|
239
|
-
export { BatchLinkPlugin, BatchLinkPluginError, DedupeLinkPlugin, RetryAfterLinkPlugin, RetryLinkPlugin };
|
|
240
|
-
export type { BatchLinkPluginGroup, BatchLinkPluginMode, BatchLinkPluginOptions, DedupeLinkPluginGroup, DedupeLinkPluginOptions, RetryAfterLinkPluginOptions, RetryLinkPluginAttemptOptions, RetryLinkPluginContext, RetryLinkPluginOptions };
|
|
294
|
+
export { BatchLinkPlugin, BatchLinkPluginError, DedupeLinkPlugin, RequestCompressionLinkPlugin, ResponseCompressionLinkPlugin, RetryAfterLinkPlugin, RetryLinkPlugin };
|
|
295
|
+
export type { BatchLinkPluginGroup, BatchLinkPluginMode, BatchLinkPluginOptions, DedupeLinkPluginGroup, DedupeLinkPluginOptions, RequestCompressionLinkPluginOptions, ResponseCompressionLinkPluginOptions, RetryAfterLinkPluginOptions, RetryLinkPluginAttemptOptions, RetryLinkPluginContext, RetryLinkPluginOptions };
|
package/dist/plugins/index.d.ts
CHANGED
|
@@ -136,6 +136,61 @@ declare class DedupeLinkPlugin<T extends ClientContext> implements StandardLinkP
|
|
|
136
136
|
private execute;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
interface RequestCompressionLinkPluginOptions<_T extends ClientContext> {
|
|
140
|
+
/**
|
|
141
|
+
* The compression scheme to use for request compression.
|
|
142
|
+
*
|
|
143
|
+
* @default 'gzip'
|
|
144
|
+
*/
|
|
145
|
+
encoding?: 'gzip' | 'deflate' | 'deflate-raw';
|
|
146
|
+
/**
|
|
147
|
+
* The minimum request size in bytes required to trigger compression.
|
|
148
|
+
* Requests smaller than this threshold will not be compressed to avoid overhead.
|
|
149
|
+
* If the request size cannot be determined, compression will still be applied.
|
|
150
|
+
*
|
|
151
|
+
* @default 1024 (1KB)
|
|
152
|
+
*/
|
|
153
|
+
threshold?: number;
|
|
154
|
+
}
|
|
155
|
+
declare class RequestCompressionLinkPlugin<T extends ClientContext> implements StandardLinkPlugin<T> {
|
|
156
|
+
name: string;
|
|
157
|
+
/**
|
|
158
|
+
* Compression should be done after batching, to compress the final request
|
|
159
|
+
*/
|
|
160
|
+
after: string[];
|
|
161
|
+
private readonly encoding;
|
|
162
|
+
private readonly threshold;
|
|
163
|
+
constructor(options?: RequestCompressionLinkPluginOptions<T>);
|
|
164
|
+
init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
interface ResponseCompressionLinkPluginOptions<_T extends ClientContext> {
|
|
168
|
+
/**
|
|
169
|
+
* Compression schemes to advertise via Accept-Encoding, in preference order.
|
|
170
|
+
* Only schemes that can be decompressed by this plugin should be listed.
|
|
171
|
+
*
|
|
172
|
+
* @default ['gzip', 'deflate']
|
|
173
|
+
*/
|
|
174
|
+
encodings?: readonly ('gzip' | 'deflate' | 'deflate-raw')[];
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Advertises Accept-Encoding on requests and decompresses response bodies
|
|
178
|
+
* based on the Content-Encoding header. Works at the standard link level,
|
|
179
|
+
* so it supports all adapters.
|
|
180
|
+
*
|
|
181
|
+
* @see {@link https://orpc.dev/docs/plugins/response-compression Response Compression Plugin Docs}
|
|
182
|
+
*/
|
|
183
|
+
declare class ResponseCompressionLinkPlugin<T extends ClientContext> implements StandardLinkPlugin<T> {
|
|
184
|
+
name: string;
|
|
185
|
+
/**
|
|
186
|
+
* Decompression should wrap the final batch response instead of sub-responses.
|
|
187
|
+
*/
|
|
188
|
+
after: string[];
|
|
189
|
+
private readonly encodings;
|
|
190
|
+
constructor(options?: ResponseCompressionLinkPluginOptions<T>);
|
|
191
|
+
init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
|
|
192
|
+
}
|
|
193
|
+
|
|
139
194
|
interface RetryLinkPluginAttemptOptions<T extends RetryLinkPluginContext> extends StandardLinkInterceptorOptions<T> {
|
|
140
195
|
/**
|
|
141
196
|
* Latest retry delay advertised by the server via event metadata.
|
|
@@ -236,5 +291,5 @@ declare class RetryAfterLinkPlugin<T extends ClientContext> implements StandardL
|
|
|
236
291
|
init(options: StandardLinkOptions<T>): StandardLinkOptions<T>;
|
|
237
292
|
}
|
|
238
293
|
|
|
239
|
-
export { BatchLinkPlugin, BatchLinkPluginError, DedupeLinkPlugin, RetryAfterLinkPlugin, RetryLinkPlugin };
|
|
240
|
-
export type { BatchLinkPluginGroup, BatchLinkPluginMode, BatchLinkPluginOptions, DedupeLinkPluginGroup, DedupeLinkPluginOptions, RetryAfterLinkPluginOptions, RetryLinkPluginAttemptOptions, RetryLinkPluginContext, RetryLinkPluginOptions };
|
|
294
|
+
export { BatchLinkPlugin, BatchLinkPluginError, DedupeLinkPlugin, RequestCompressionLinkPlugin, ResponseCompressionLinkPlugin, RetryAfterLinkPlugin, RetryLinkPlugin };
|
|
295
|
+
export type { BatchLinkPluginGroup, BatchLinkPluginMode, BatchLinkPluginOptions, DedupeLinkPluginGroup, DedupeLinkPluginOptions, RequestCompressionLinkPluginOptions, ResponseCompressionLinkPluginOptions, RetryAfterLinkPluginOptions, RetryLinkPluginAttemptOptions, RetryLinkPluginContext, RetryLinkPluginOptions };
|
package/dist/plugins/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { toArray, value, splitInHalf, stringifyJSON, isAsyncIteratorObject, defer, loadBytes, allAbortSignal, replicateAsyncIterator, replicateReadableStream, override, AsyncIteratorClass, sleep } from '@orpc/shared';
|
|
2
|
-
import { parseStandardUrl,
|
|
1
|
+
import { toArray, value, splitInHalf, stringifyJSON, isAsyncIteratorObject, defer, loadBytes, allAbortSignal, replicateAsyncIterator, replicateReadableStream, isCompressibleContentType, override, AsyncIteratorClass, sleep } from '@orpc/shared';
|
|
2
|
+
import { parseStandardUrl, flattenStandardHeader, generateContentDisposition, getEventMeta } from '@standardserver/core';
|
|
3
3
|
import { ClientPeer, isServerPeerSendMessage, decodePeerMessage } from '@standardserver/peer';
|
|
4
|
+
import { toFetchHeaders, toStandardBody } from '@standardserver/fetch';
|
|
4
5
|
import { C as COMMON_ERROR_STATUS_MAP } from '../shared/client.Dnfj8jnT.mjs';
|
|
5
6
|
|
|
6
7
|
class BatchLinkPluginError extends TypeError {
|
|
@@ -387,6 +388,229 @@ function shouldDedupe(items) {
|
|
|
387
388
|
return items.length >= 2;
|
|
388
389
|
}
|
|
389
390
|
|
|
391
|
+
const AVG_BYTES_PER_CHAR = 1.2;
|
|
392
|
+
class RequestCompressionLinkPlugin {
|
|
393
|
+
name = "~request-compression";
|
|
394
|
+
/**
|
|
395
|
+
* Compression should be done after batching, to compress the final request
|
|
396
|
+
*/
|
|
397
|
+
after = ["~batch"];
|
|
398
|
+
encoding;
|
|
399
|
+
threshold;
|
|
400
|
+
constructor(options = {}) {
|
|
401
|
+
this.encoding = options.encoding ?? "gzip";
|
|
402
|
+
this.threshold = options.threshold ?? 1024;
|
|
403
|
+
}
|
|
404
|
+
init(options) {
|
|
405
|
+
const transportInterceptor = async ({ next, ...interceptorOptions }) => {
|
|
406
|
+
const request = interceptorOptions.request;
|
|
407
|
+
const contentEncoding = flattenStandardHeader(request.headers["content-encoding"])?.trim()?.toLowerCase();
|
|
408
|
+
if (contentEncoding !== void 0) {
|
|
409
|
+
return next();
|
|
410
|
+
}
|
|
411
|
+
if (request.body instanceof ReadableStream) {
|
|
412
|
+
const contentLength = Number(flattenStandardHeader(request.headers["content-length"]));
|
|
413
|
+
if ((!Number.isFinite(contentLength) || contentLength >= this.threshold) && isCompressibleContentType(flattenStandardHeader(request.headers["content-type"]))) {
|
|
414
|
+
const compressedStream = request.body.pipeThrough(new CompressionStream(this.encoding));
|
|
415
|
+
return next({
|
|
416
|
+
...interceptorOptions,
|
|
417
|
+
request: {
|
|
418
|
+
...interceptorOptions.request,
|
|
419
|
+
body: compressedStream,
|
|
420
|
+
headers: {
|
|
421
|
+
...request.headers,
|
|
422
|
+
"standard-server": "octet-stream",
|
|
423
|
+
"content-length": [],
|
|
424
|
+
"content-encoding": this.encoding
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
} else if (request.body instanceof Blob) {
|
|
430
|
+
if ((!Number.isFinite(request.body.size) || request.body.size >= this.threshold) && isCompressibleContentType(request.body.type)) {
|
|
431
|
+
const compressedStream = request.body.stream().pipeThrough(new CompressionStream(this.encoding));
|
|
432
|
+
const contentDisposition = request.headers["content-disposition"] ?? generateContentDisposition(
|
|
433
|
+
request.body instanceof File ? request.body.name : "blob"
|
|
434
|
+
);
|
|
435
|
+
return next({
|
|
436
|
+
...interceptorOptions,
|
|
437
|
+
request: {
|
|
438
|
+
...interceptorOptions.request,
|
|
439
|
+
body: compressedStream,
|
|
440
|
+
headers: {
|
|
441
|
+
...request.headers,
|
|
442
|
+
"standard-server": "file",
|
|
443
|
+
"content-type": request.body.type,
|
|
444
|
+
"content-length": [],
|
|
445
|
+
"content-disposition": contentDisposition,
|
|
446
|
+
"content-encoding": this.encoding
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
} else if (request.body instanceof FormData) {
|
|
452
|
+
const PART_OVERHEAD = 64;
|
|
453
|
+
let contentLength = 0;
|
|
454
|
+
for (const [key, value] of request.body) {
|
|
455
|
+
contentLength += PART_OVERHEAD + key.length;
|
|
456
|
+
if (value instanceof Blob) {
|
|
457
|
+
if (!Number.isFinite(value.size)) {
|
|
458
|
+
if (!isCompressibleContentType(value.type)) {
|
|
459
|
+
contentLength = -Infinity;
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
contentLength = Infinity;
|
|
463
|
+
} else {
|
|
464
|
+
contentLength += isCompressibleContentType(value.type) ? value.size : -value.size;
|
|
465
|
+
}
|
|
466
|
+
} else {
|
|
467
|
+
contentLength += value.length * AVG_BYTES_PER_CHAR;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (contentLength >= this.threshold) {
|
|
471
|
+
const res = new Response(request.body);
|
|
472
|
+
const compressedStream = res.body.pipeThrough(new CompressionStream(this.encoding));
|
|
473
|
+
return next({
|
|
474
|
+
...interceptorOptions,
|
|
475
|
+
request: {
|
|
476
|
+
...interceptorOptions.request,
|
|
477
|
+
body: compressedStream,
|
|
478
|
+
headers: {
|
|
479
|
+
...request.headers,
|
|
480
|
+
"standard-server": [],
|
|
481
|
+
"content-type": res.headers.get("content-type"),
|
|
482
|
+
"content-length": [],
|
|
483
|
+
"content-encoding": this.encoding
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
} else if (request.body instanceof URLSearchParams) {
|
|
489
|
+
const string = request.body.toString();
|
|
490
|
+
if (string.length * AVG_BYTES_PER_CHAR >= this.threshold) {
|
|
491
|
+
const compressedStream = new Blob([string]).stream().pipeThrough(new CompressionStream(this.encoding));
|
|
492
|
+
return next({
|
|
493
|
+
...interceptorOptions,
|
|
494
|
+
request: {
|
|
495
|
+
...interceptorOptions.request,
|
|
496
|
+
body: compressedStream,
|
|
497
|
+
headers: {
|
|
498
|
+
...request.headers,
|
|
499
|
+
"standard-server": [],
|
|
500
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
501
|
+
"content-length": [],
|
|
502
|
+
"content-encoding": this.encoding
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
} else if (request.body !== void 0 && !isAsyncIteratorObject(request.body)) {
|
|
508
|
+
const string = stringifyJSON(request.body);
|
|
509
|
+
if (string.length * AVG_BYTES_PER_CHAR >= this.threshold) {
|
|
510
|
+
const compressedStream = new Blob([string]).stream().pipeThrough(new CompressionStream(this.encoding));
|
|
511
|
+
return next({
|
|
512
|
+
...interceptorOptions,
|
|
513
|
+
request: {
|
|
514
|
+
...interceptorOptions.request,
|
|
515
|
+
body: compressedStream,
|
|
516
|
+
headers: {
|
|
517
|
+
...request.headers,
|
|
518
|
+
"standard-server": [],
|
|
519
|
+
"content-type": "application/json",
|
|
520
|
+
"content-length": [],
|
|
521
|
+
"content-encoding": this.encoding
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return next();
|
|
528
|
+
};
|
|
529
|
+
return {
|
|
530
|
+
...options,
|
|
531
|
+
transportInterceptors: [
|
|
532
|
+
...toArray(options.transportInterceptors),
|
|
533
|
+
transportInterceptor
|
|
534
|
+
]
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
class ResponseCompressionLinkPlugin {
|
|
540
|
+
name = "~response-compression";
|
|
541
|
+
/**
|
|
542
|
+
* Decompression should wrap the final batch response instead of sub-responses.
|
|
543
|
+
*/
|
|
544
|
+
after = ["~batch"];
|
|
545
|
+
encodings;
|
|
546
|
+
constructor(options = {}) {
|
|
547
|
+
this.encodings = options.encodings ?? ["gzip", "deflate"];
|
|
548
|
+
}
|
|
549
|
+
init(options) {
|
|
550
|
+
const acceptEncodingHeader = this.encodings.join(", ");
|
|
551
|
+
const transportInterceptor = async ({ next, ...interceptorOptions }) => {
|
|
552
|
+
const response = await next({
|
|
553
|
+
...interceptorOptions,
|
|
554
|
+
request: {
|
|
555
|
+
...interceptorOptions.request,
|
|
556
|
+
headers: {
|
|
557
|
+
...interceptorOptions.request.headers,
|
|
558
|
+
"accept-encoding": acceptEncodingHeader
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
const encodings = parseContentEncodings(
|
|
563
|
+
flattenStandardHeader(response.headers["content-encoding"])
|
|
564
|
+
);
|
|
565
|
+
if (encodings.length === 0 || !encodings.every(isSupportedEncoding)) {
|
|
566
|
+
return response;
|
|
567
|
+
}
|
|
568
|
+
const decompressedHeaders = {
|
|
569
|
+
...response.headers,
|
|
570
|
+
"content-length": void 0,
|
|
571
|
+
"content-encoding": void 0
|
|
572
|
+
};
|
|
573
|
+
return {
|
|
574
|
+
...response,
|
|
575
|
+
headers: decompressedHeaders,
|
|
576
|
+
async resolveBody(hint) {
|
|
577
|
+
const stream = await response.resolveBody("octet-stream");
|
|
578
|
+
if (!(stream instanceof ReadableStream)) {
|
|
579
|
+
return stream;
|
|
580
|
+
}
|
|
581
|
+
let decompressedStream = stream;
|
|
582
|
+
for (let i = encodings.length - 1; i >= 0; i--) {
|
|
583
|
+
decompressedStream = decompressedStream.pipeThrough(
|
|
584
|
+
new DecompressionStream(encodings[i])
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
const fetchResponse = new Response(decompressedStream, {
|
|
588
|
+
headers: toFetchHeaders(decompressedHeaders)
|
|
589
|
+
});
|
|
590
|
+
return toStandardBody(fetchResponse, { hint });
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
};
|
|
594
|
+
return {
|
|
595
|
+
...options,
|
|
596
|
+
transportInterceptors: [
|
|
597
|
+
...toArray(options.transportInterceptors),
|
|
598
|
+
transportInterceptor
|
|
599
|
+
]
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
const SUPPORTED_ENCODINGS = ["gzip", "deflate", "deflate-raw"];
|
|
604
|
+
function isSupportedEncoding(encoding) {
|
|
605
|
+
return SUPPORTED_ENCODINGS.includes(encoding);
|
|
606
|
+
}
|
|
607
|
+
function parseContentEncodings(header) {
|
|
608
|
+
if (header === void 0) {
|
|
609
|
+
return [];
|
|
610
|
+
}
|
|
611
|
+
return header.split(",").map((part) => part.trim().toLowerCase());
|
|
612
|
+
}
|
|
613
|
+
|
|
390
614
|
class RetryLinkPlugin {
|
|
391
615
|
defaultRetry;
|
|
392
616
|
defaultRetryDelay;
|
|
@@ -569,4 +793,4 @@ function parseRetryAfterHeader(value2) {
|
|
|
569
793
|
return void 0;
|
|
570
794
|
}
|
|
571
795
|
|
|
572
|
-
export { BatchLinkPlugin, BatchLinkPluginError, DedupeLinkPlugin, RetryAfterLinkPlugin, RetryLinkPlugin };
|
|
796
|
+
export { BatchLinkPlugin, BatchLinkPluginError, DedupeLinkPlugin, RequestCompressionLinkPlugin, ResponseCompressionLinkPlugin, RetryAfterLinkPlugin, RetryLinkPlugin };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orpc/client",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0.0-beta.
|
|
4
|
+
"version": "2.0.0-beta.16",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://orpc.dev",
|
|
7
7
|
"repository": {
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"dist"
|
|
51
51
|
],
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@standardserver/core": "^0.0
|
|
54
|
-
"@standardserver/fetch": "^0.0
|
|
55
|
-
"@standardserver/peer": "^0.0
|
|
56
|
-
"@orpc/shared": "2.0.0-beta.
|
|
53
|
+
"@standardserver/core": "^0.2.0",
|
|
54
|
+
"@standardserver/fetch": "^0.2.0",
|
|
55
|
+
"@standardserver/peer": "^0.2.0",
|
|
56
|
+
"@orpc/shared": "2.0.0-beta.16"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"zod": "^4.4.3"
|