@orpc/standard-server-peer 0.0.0-next.e385fb7 → 0.0.0-next.e4b0df6
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 +8 -8
- package/dist/index.d.mts +54 -23
- package/dist/index.d.ts +54 -23
- package/dist/index.mjs +289 -168
- package/package.json +3 -3
package/README.md
CHANGED
@@ -30,7 +30,8 @@
|
|
30
30
|
- **🔗 End-to-End Type Safety**: Ensure type-safe inputs, outputs, and errors from client to server.
|
31
31
|
- **📘 First-Class OpenAPI**: Built-in support that fully adheres to the OpenAPI standard.
|
32
32
|
- **📝 Contract-First Development**: Optionally define your API contract before implementation.
|
33
|
-
-
|
33
|
+
- **🔍 First-Class OpenTelemetry**: Seamlessly integrate with OpenTelemetry for observability.
|
34
|
+
- **⚙️ Framework Integrations**: Seamlessly integrate with TanStack Query (React, Vue, Solid, Svelte, Angular), SWR, Pinia Colada, and more.
|
34
35
|
- **🚀 Server Actions**: Fully compatible with React Server Actions on Next.js, TanStack Start, and other platforms.
|
35
36
|
- **🔠 Standard Schema Support**: Works out of the box with Zod, Valibot, ArkType, and other schema validators.
|
36
37
|
- **🗃️ Native Types**: Supports native types like Date, File, Blob, BigInt, URL, and more.
|
@@ -38,7 +39,6 @@
|
|
38
39
|
- **📡 SSE & Streaming**: Enjoy full type-safe support for SSE and streaming.
|
39
40
|
- **🌍 Multi-Runtime Support**: Fast and lightweight on Cloudflare, Deno, Bun, Node.js, and beyond.
|
40
41
|
- **🔌 Extendability**: Easily extend functionality with plugins, middleware, and interceptors.
|
41
|
-
- **🛡️ Reliability**: Well-tested, TypeScript-based, production-ready, and MIT licensed.
|
42
42
|
|
43
43
|
## Documentation
|
44
44
|
|
@@ -49,14 +49,14 @@ You can find the full documentation [here](https://orpc.unnoq.com).
|
|
49
49
|
- [@orpc/contract](https://www.npmjs.com/package/@orpc/contract): Build your API contract.
|
50
50
|
- [@orpc/server](https://www.npmjs.com/package/@orpc/server): Build your API or implement API contract.
|
51
51
|
- [@orpc/client](https://www.npmjs.com/package/@orpc/client): Consume your API on the client with type-safety.
|
52
|
-
- [@orpc/
|
52
|
+
- [@orpc/openapi](https://www.npmjs.com/package/@orpc/openapi): Generate OpenAPI specs and handle OpenAPI requests.
|
53
|
+
- [@orpc/otel](https://www.npmjs.com/package/@orpc/otel): [OpenTelemetry](https://opentelemetry.io/) integration for observability.
|
54
|
+
- [@orpc/nest](https://www.npmjs.com/package/@orpc/nest): Deeply integrate oRPC with [NestJS](https://nestjs.com/).
|
53
55
|
- [@orpc/react](https://www.npmjs.com/package/@orpc/react): Utilities for integrating oRPC with React and React Server Actions.
|
54
|
-
- [@orpc/
|
55
|
-
- [@orpc/
|
56
|
-
- [@orpc/solid-query](https://www.npmjs.com/package/@orpc/solid-query): Integration with [Solid Query](https://tanstack.com/query/latest/docs/framework/solid/overview).
|
57
|
-
- [@orpc/svelte-query](https://www.npmjs.com/package/@orpc/svelte-query): Integration with [Svelte Query](https://tanstack.com/query/latest/docs/framework/svelte/overview).
|
56
|
+
- [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query): [TanStack Query](https://tanstack.com/query/latest) integration.
|
57
|
+
- [@orpc/experimental-react-swr](https://www.npmjs.com/package/@orpc/experimental-react-swr): [SWR](https://swr.vercel.app/) integration.
|
58
58
|
- [@orpc/vue-colada](https://www.npmjs.com/package/@orpc/vue-colada): Integration with [Pinia Colada](https://pinia-colada.esm.dev/).
|
59
|
-
- [@orpc/
|
59
|
+
- [@orpc/hey-api](https://www.npmjs.com/package/@orpc/hey-api): [Hey API](https://heyapi.dev/) integration.
|
60
60
|
- [@orpc/zod](https://www.npmjs.com/package/@orpc/zod): More schemas that [Zod](https://zod.dev/) doesn't support yet.
|
61
61
|
- [@orpc/valibot](https://www.npmjs.com/package/@orpc/valibot): OpenAPI spec generation from [Valibot](https://valibot.dev/).
|
62
62
|
- [@orpc/arktype](https://www.npmjs.com/package/@orpc/arktype): OpenAPI spec generation from [ArkType](https://arktype.io/).
|
package/dist/index.d.mts
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
import { Promisable, AsyncIdQueueCloseOptions as AsyncIdQueueCloseOptions$1,
|
2
|
-
import { StandardRequest, StandardResponse, EventMeta
|
1
|
+
import { Promisable, AsyncIdQueueCloseOptions as AsyncIdQueueCloseOptions$1, SetSpanErrorOptions, AsyncIteratorClassCleanupFn, AsyncIteratorClass } from '@orpc/shared';
|
2
|
+
import { StandardRequest, StandardResponse, EventMeta } from '@orpc/standard-server';
|
3
3
|
|
4
|
-
type EncodedMessage = string | ArrayBufferLike |
|
4
|
+
type EncodedMessage = string | ArrayBufferLike | Uint8Array;
|
5
5
|
interface EncodedMessageSendFn {
|
6
6
|
(message: EncodedMessage): Promisable<void>;
|
7
7
|
}
|
@@ -16,13 +16,26 @@ interface ClientPeerCloseOptions extends AsyncIdQueueCloseOptions$1 {
|
|
16
16
|
}
|
17
17
|
declare class ClientPeer {
|
18
18
|
private readonly idGenerator;
|
19
|
+
/**
|
20
|
+
* Queue of responses sent from server, awaiting consumption
|
21
|
+
*/
|
19
22
|
private readonly responseQueue;
|
23
|
+
/**
|
24
|
+
* Queue of event iterator messages sent from server, awaiting consumption
|
25
|
+
*/
|
20
26
|
private readonly serverEventIteratorQueue;
|
27
|
+
/**
|
28
|
+
* Controllers used to signal that the client should stop sending event iterator messages
|
29
|
+
*/
|
21
30
|
private readonly serverControllers;
|
31
|
+
/**
|
32
|
+
* Cleanup functions invoked when the request/response is closed
|
33
|
+
*/
|
34
|
+
private readonly cleanupFns;
|
22
35
|
private readonly send;
|
23
36
|
constructor(send: EncodedMessageSendFn);
|
24
37
|
get length(): number;
|
25
|
-
open(id:
|
38
|
+
open(id: string): AbortController;
|
26
39
|
request(request: StandardRequest): Promise<StandardResponse>;
|
27
40
|
message(raw: EncodedMessage): Promise<void>;
|
28
41
|
close(options?: AsyncIdQueueCloseOptions$1): void;
|
@@ -51,36 +64,42 @@ interface ResponseMessageMap {
|
|
51
64
|
[MessageType.ABORT_SIGNAL]: void;
|
52
65
|
}
|
53
66
|
type DecodedMessageUnion<TMap extends RequestMessageMap | ResponseMessageMap> = {
|
54
|
-
[K in keyof TMap]: [id:
|
67
|
+
[K in keyof TMap]: [id: string, type: K, payload: TMap[K]];
|
55
68
|
}[keyof TMap];
|
56
69
|
type DecodedRequestMessage = DecodedMessageUnion<RequestMessageMap>;
|
57
70
|
type DecodedResponseMessage = DecodedMessageUnion<ResponseMessageMap>;
|
58
|
-
declare function encodeRequestMessage<T extends keyof RequestMessageMap>(id:
|
71
|
+
declare function encodeRequestMessage<T extends keyof RequestMessageMap>(id: string, type: T, payload: RequestMessageMap[T]): Promise<EncodedMessage>;
|
59
72
|
declare function decodeRequestMessage(raw: EncodedMessage): Promise<DecodedRequestMessage>;
|
60
|
-
declare function encodeResponseMessage<T extends keyof ResponseMessageMap>(id:
|
73
|
+
declare function encodeResponseMessage<T extends keyof ResponseMessageMap>(id: string, type: T, payload: ResponseMessageMap[T]): Promise<EncodedMessage>;
|
61
74
|
declare function decodeResponseMessage(raw: EncodedMessage): Promise<DecodedResponseMessage>;
|
62
|
-
declare function isEventIteratorHeaders(headers: StandardHeaders): boolean;
|
63
75
|
|
64
76
|
interface AsyncIdQueueCloseOptions {
|
65
|
-
id?:
|
66
|
-
reason?:
|
77
|
+
id?: string;
|
78
|
+
reason?: unknown;
|
67
79
|
}
|
68
80
|
declare class AsyncIdQueue<T> {
|
69
81
|
private readonly openIds;
|
70
|
-
private readonly
|
71
|
-
private readonly
|
82
|
+
private readonly queues;
|
83
|
+
private readonly waiters;
|
72
84
|
get length(): number;
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
85
|
+
get waiterIds(): string[];
|
86
|
+
hasBufferedItems(id: string): boolean;
|
87
|
+
open(id: string): void;
|
88
|
+
isOpen(id: string): boolean;
|
89
|
+
push(id: string, item: T): void;
|
90
|
+
pull(id: string): Promise<T>;
|
77
91
|
close({ id, reason }?: AsyncIdQueueCloseOptions): void;
|
78
|
-
assertOpen(id:
|
92
|
+
assertOpen(id: string): void;
|
79
93
|
}
|
80
94
|
|
81
|
-
|
95
|
+
interface ToEventIteratorOptions extends SetSpanErrorOptions {
|
96
|
+
}
|
97
|
+
declare function toEventIterator(queue: AsyncIdQueue<EventIteratorPayload>, id: string, cleanup: AsyncIteratorClassCleanupFn, options?: ToEventIteratorOptions): AsyncIteratorClass<unknown>;
|
82
98
|
declare function resolveEventIterator(iterator: AsyncIterator<any>, callback: (payload: EventIteratorPayload) => Promise<'next' | 'abort'>): Promise<void>;
|
83
99
|
|
100
|
+
interface ServerPeerHandleRequestFn {
|
101
|
+
(request: StandardRequest): Promise<StandardResponse>;
|
102
|
+
}
|
84
103
|
interface ServerPeerCloseOptions extends AsyncIdQueueCloseOptions$1 {
|
85
104
|
/**
|
86
105
|
* Should abort or not?
|
@@ -90,16 +109,28 @@ interface ServerPeerCloseOptions extends AsyncIdQueueCloseOptions$1 {
|
|
90
109
|
abort?: boolean;
|
91
110
|
}
|
92
111
|
declare class ServerPeer {
|
112
|
+
/**
|
113
|
+
* Queue of event iterator messages sent from client, awaiting consumption
|
114
|
+
*/
|
93
115
|
private readonly clientEventIteratorQueue;
|
116
|
+
/**
|
117
|
+
* Map of active client request controllers, should be synced to request signal
|
118
|
+
*/
|
94
119
|
private readonly clientControllers;
|
95
120
|
private readonly send;
|
96
121
|
constructor(send: EncodedMessageSendFn);
|
97
122
|
get length(): number;
|
98
|
-
open(id:
|
99
|
-
|
100
|
-
|
123
|
+
open(id: string): AbortController;
|
124
|
+
/**
|
125
|
+
* @todo This method will return Promise<void> in the next major version.
|
126
|
+
*/
|
127
|
+
message(raw: EncodedMessage, handleRequest?: ServerPeerHandleRequestFn): Promise<[id: string, StandardRequest | undefined]>;
|
128
|
+
/**
|
129
|
+
* @deprecated Please pass the `handleRequest` (second arg) function to the `message` method instead.
|
130
|
+
*/
|
131
|
+
response(id: string, response: StandardResponse): Promise<void>;
|
101
132
|
close({ abort, ...options }?: ServerPeerCloseOptions): void;
|
102
133
|
}
|
103
134
|
|
104
|
-
export { ClientPeer, MessageType, ServerPeer, decodeRequestMessage, decodeResponseMessage, encodeRequestMessage, encodeResponseMessage,
|
105
|
-
export type { ClientPeerCloseOptions, DecodedRequestMessage, DecodedResponseMessage, EncodedMessage, EncodedMessageSendFn, EventIteratorEvent, EventIteratorPayload, RequestMessageMap, ResponseMessageMap, ServerPeerCloseOptions };
|
135
|
+
export { ClientPeer, MessageType, ServerPeer, decodeRequestMessage, decodeResponseMessage, encodeRequestMessage, encodeResponseMessage, resolveEventIterator, toEventIterator };
|
136
|
+
export type { ClientPeerCloseOptions, DecodedRequestMessage, DecodedResponseMessage, EncodedMessage, EncodedMessageSendFn, EventIteratorEvent, EventIteratorPayload, RequestMessageMap, ResponseMessageMap, ServerPeerCloseOptions, ServerPeerHandleRequestFn, ToEventIteratorOptions };
|
package/dist/index.d.ts
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
import { Promisable, AsyncIdQueueCloseOptions as AsyncIdQueueCloseOptions$1,
|
2
|
-
import { StandardRequest, StandardResponse, EventMeta
|
1
|
+
import { Promisable, AsyncIdQueueCloseOptions as AsyncIdQueueCloseOptions$1, SetSpanErrorOptions, AsyncIteratorClassCleanupFn, AsyncIteratorClass } from '@orpc/shared';
|
2
|
+
import { StandardRequest, StandardResponse, EventMeta } from '@orpc/standard-server';
|
3
3
|
|
4
|
-
type EncodedMessage = string | ArrayBufferLike |
|
4
|
+
type EncodedMessage = string | ArrayBufferLike | Uint8Array;
|
5
5
|
interface EncodedMessageSendFn {
|
6
6
|
(message: EncodedMessage): Promisable<void>;
|
7
7
|
}
|
@@ -16,13 +16,26 @@ interface ClientPeerCloseOptions extends AsyncIdQueueCloseOptions$1 {
|
|
16
16
|
}
|
17
17
|
declare class ClientPeer {
|
18
18
|
private readonly idGenerator;
|
19
|
+
/**
|
20
|
+
* Queue of responses sent from server, awaiting consumption
|
21
|
+
*/
|
19
22
|
private readonly responseQueue;
|
23
|
+
/**
|
24
|
+
* Queue of event iterator messages sent from server, awaiting consumption
|
25
|
+
*/
|
20
26
|
private readonly serverEventIteratorQueue;
|
27
|
+
/**
|
28
|
+
* Controllers used to signal that the client should stop sending event iterator messages
|
29
|
+
*/
|
21
30
|
private readonly serverControllers;
|
31
|
+
/**
|
32
|
+
* Cleanup functions invoked when the request/response is closed
|
33
|
+
*/
|
34
|
+
private readonly cleanupFns;
|
22
35
|
private readonly send;
|
23
36
|
constructor(send: EncodedMessageSendFn);
|
24
37
|
get length(): number;
|
25
|
-
open(id:
|
38
|
+
open(id: string): AbortController;
|
26
39
|
request(request: StandardRequest): Promise<StandardResponse>;
|
27
40
|
message(raw: EncodedMessage): Promise<void>;
|
28
41
|
close(options?: AsyncIdQueueCloseOptions$1): void;
|
@@ -51,36 +64,42 @@ interface ResponseMessageMap {
|
|
51
64
|
[MessageType.ABORT_SIGNAL]: void;
|
52
65
|
}
|
53
66
|
type DecodedMessageUnion<TMap extends RequestMessageMap | ResponseMessageMap> = {
|
54
|
-
[K in keyof TMap]: [id:
|
67
|
+
[K in keyof TMap]: [id: string, type: K, payload: TMap[K]];
|
55
68
|
}[keyof TMap];
|
56
69
|
type DecodedRequestMessage = DecodedMessageUnion<RequestMessageMap>;
|
57
70
|
type DecodedResponseMessage = DecodedMessageUnion<ResponseMessageMap>;
|
58
|
-
declare function encodeRequestMessage<T extends keyof RequestMessageMap>(id:
|
71
|
+
declare function encodeRequestMessage<T extends keyof RequestMessageMap>(id: string, type: T, payload: RequestMessageMap[T]): Promise<EncodedMessage>;
|
59
72
|
declare function decodeRequestMessage(raw: EncodedMessage): Promise<DecodedRequestMessage>;
|
60
|
-
declare function encodeResponseMessage<T extends keyof ResponseMessageMap>(id:
|
73
|
+
declare function encodeResponseMessage<T extends keyof ResponseMessageMap>(id: string, type: T, payload: ResponseMessageMap[T]): Promise<EncodedMessage>;
|
61
74
|
declare function decodeResponseMessage(raw: EncodedMessage): Promise<DecodedResponseMessage>;
|
62
|
-
declare function isEventIteratorHeaders(headers: StandardHeaders): boolean;
|
63
75
|
|
64
76
|
interface AsyncIdQueueCloseOptions {
|
65
|
-
id?:
|
66
|
-
reason?:
|
77
|
+
id?: string;
|
78
|
+
reason?: unknown;
|
67
79
|
}
|
68
80
|
declare class AsyncIdQueue<T> {
|
69
81
|
private readonly openIds;
|
70
|
-
private readonly
|
71
|
-
private readonly
|
82
|
+
private readonly queues;
|
83
|
+
private readonly waiters;
|
72
84
|
get length(): number;
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
85
|
+
get waiterIds(): string[];
|
86
|
+
hasBufferedItems(id: string): boolean;
|
87
|
+
open(id: string): void;
|
88
|
+
isOpen(id: string): boolean;
|
89
|
+
push(id: string, item: T): void;
|
90
|
+
pull(id: string): Promise<T>;
|
77
91
|
close({ id, reason }?: AsyncIdQueueCloseOptions): void;
|
78
|
-
assertOpen(id:
|
92
|
+
assertOpen(id: string): void;
|
79
93
|
}
|
80
94
|
|
81
|
-
|
95
|
+
interface ToEventIteratorOptions extends SetSpanErrorOptions {
|
96
|
+
}
|
97
|
+
declare function toEventIterator(queue: AsyncIdQueue<EventIteratorPayload>, id: string, cleanup: AsyncIteratorClassCleanupFn, options?: ToEventIteratorOptions): AsyncIteratorClass<unknown>;
|
82
98
|
declare function resolveEventIterator(iterator: AsyncIterator<any>, callback: (payload: EventIteratorPayload) => Promise<'next' | 'abort'>): Promise<void>;
|
83
99
|
|
100
|
+
interface ServerPeerHandleRequestFn {
|
101
|
+
(request: StandardRequest): Promise<StandardResponse>;
|
102
|
+
}
|
84
103
|
interface ServerPeerCloseOptions extends AsyncIdQueueCloseOptions$1 {
|
85
104
|
/**
|
86
105
|
* Should abort or not?
|
@@ -90,16 +109,28 @@ interface ServerPeerCloseOptions extends AsyncIdQueueCloseOptions$1 {
|
|
90
109
|
abort?: boolean;
|
91
110
|
}
|
92
111
|
declare class ServerPeer {
|
112
|
+
/**
|
113
|
+
* Queue of event iterator messages sent from client, awaiting consumption
|
114
|
+
*/
|
93
115
|
private readonly clientEventIteratorQueue;
|
116
|
+
/**
|
117
|
+
* Map of active client request controllers, should be synced to request signal
|
118
|
+
*/
|
94
119
|
private readonly clientControllers;
|
95
120
|
private readonly send;
|
96
121
|
constructor(send: EncodedMessageSendFn);
|
97
122
|
get length(): number;
|
98
|
-
open(id:
|
99
|
-
|
100
|
-
|
123
|
+
open(id: string): AbortController;
|
124
|
+
/**
|
125
|
+
* @todo This method will return Promise<void> in the next major version.
|
126
|
+
*/
|
127
|
+
message(raw: EncodedMessage, handleRequest?: ServerPeerHandleRequestFn): Promise<[id: string, StandardRequest | undefined]>;
|
128
|
+
/**
|
129
|
+
* @deprecated Please pass the `handleRequest` (second arg) function to the `message` method instead.
|
130
|
+
*/
|
131
|
+
response(id: string, response: StandardResponse): Promise<void>;
|
101
132
|
close({ abort, ...options }?: ServerPeerCloseOptions): void;
|
102
133
|
}
|
103
134
|
|
104
|
-
export { ClientPeer, MessageType, ServerPeer, decodeRequestMessage, decodeResponseMessage, encodeRequestMessage, encodeResponseMessage,
|
105
|
-
export type { ClientPeerCloseOptions, DecodedRequestMessage, DecodedResponseMessage, EncodedMessage, EncodedMessageSendFn, EventIteratorEvent, EventIteratorPayload, RequestMessageMap, ResponseMessageMap, ServerPeerCloseOptions };
|
135
|
+
export { ClientPeer, MessageType, ServerPeer, decodeRequestMessage, decodeResponseMessage, encodeRequestMessage, encodeResponseMessage, resolveEventIterator, toEventIterator };
|
136
|
+
export type { ClientPeerCloseOptions, DecodedRequestMessage, DecodedResponseMessage, EncodedMessage, EncodedMessageSendFn, EventIteratorEvent, EventIteratorPayload, RequestMessageMap, ResponseMessageMap, ServerPeerCloseOptions, ServerPeerHandleRequestFn, ToEventIteratorOptions };
|
package/dist/index.mjs
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import { isAsyncIteratorObject, stringifyJSON,
|
2
|
-
import { flattenHeader, getFilenameFromContentDisposition,
|
1
|
+
import { isAsyncIteratorObject, stringifyJSON, readAsBuffer, AsyncIteratorClass, startSpan, runInSpanContext, isTypescriptObject, setSpanError, runWithSpan, SequentialIdGenerator, AsyncIdQueue, getGlobalOtelConfig, clone, AbortError } from '@orpc/shared';
|
2
|
+
import { generateContentDisposition, flattenHeader, getFilenameFromContentDisposition, withEventMeta, ErrorEvent, getEventMeta, isEventIteratorHeaders, HibernationEventIterator } from '@orpc/standard-server';
|
3
3
|
|
4
4
|
var MessageType = /* @__PURE__ */ ((MessageType2) => {
|
5
5
|
MessageType2[MessageType2["REQUEST"] = 1] = "REQUEST";
|
@@ -22,7 +22,7 @@ async function encodeRequestMessage(id, type, payload) {
|
|
22
22
|
return encodeRawMessage({ i: id, t: type, p: payload });
|
23
23
|
}
|
24
24
|
const request = payload;
|
25
|
-
const { body: processedBody, headers: processedHeaders } = await
|
25
|
+
const { body: processedBody, headers: processedHeaders } = await serializeBodyAndHeaders(
|
26
26
|
request.body,
|
27
27
|
request.headers
|
28
28
|
);
|
@@ -42,7 +42,7 @@ async function encodeRequestMessage(id, type, payload) {
|
|
42
42
|
return encodeRawMessage(baseMessage);
|
43
43
|
}
|
44
44
|
async function decodeRequestMessage(raw) {
|
45
|
-
const { json: message,
|
45
|
+
const { json: message, buffer } = await decodeRawMessage(raw);
|
46
46
|
const id = message.i;
|
47
47
|
const type = message.t;
|
48
48
|
if (type === 3 /* EVENT_ITERATOR */) {
|
@@ -54,20 +54,7 @@ async function decodeRequestMessage(raw) {
|
|
54
54
|
}
|
55
55
|
const payload = message.p;
|
56
56
|
const headers = payload.h ?? {};
|
57
|
-
|
58
|
-
const contentType = flattenHeader(headers["content-type"]);
|
59
|
-
if (blobData) {
|
60
|
-
const contentDisposition = flattenHeader(headers["content-disposition"]);
|
61
|
-
if (contentDisposition === void 0 && contentType?.startsWith("multipart/form-data")) {
|
62
|
-
const tempRes = new Response(blobData, { headers: { "content-type": contentType } });
|
63
|
-
body = await tempRes.formData();
|
64
|
-
} else {
|
65
|
-
const filename = getFilenameFromContentDisposition(contentDisposition) ?? "blob";
|
66
|
-
body = new File([blobData], filename, { type: contentType });
|
67
|
-
}
|
68
|
-
} else if (contentType?.startsWith("application/x-www-form-urlencoded") && typeof body === "string") {
|
69
|
-
body = new URLSearchParams(body);
|
70
|
-
}
|
57
|
+
const body = await deserializeBody(headers, payload.b, buffer);
|
71
58
|
return [id, 1 /* REQUEST */, { url: new URL(payload.u, "orpc:/"), headers, method: payload.m ?? "POST", body }];
|
72
59
|
}
|
73
60
|
async function encodeResponseMessage(id, type, payload) {
|
@@ -84,7 +71,7 @@ async function encodeResponseMessage(id, type, payload) {
|
|
84
71
|
return encodeRawMessage({ i: id, t: type, p: void 0 });
|
85
72
|
}
|
86
73
|
const response = payload;
|
87
|
-
const { body: processedBody, headers: processedHeaders } = await
|
74
|
+
const { body: processedBody, headers: processedHeaders } = await serializeBodyAndHeaders(
|
88
75
|
response.body,
|
89
76
|
response.headers
|
90
77
|
);
|
@@ -103,7 +90,7 @@ async function encodeResponseMessage(id, type, payload) {
|
|
103
90
|
return encodeRawMessage(baseMessage);
|
104
91
|
}
|
105
92
|
async function decodeResponseMessage(raw) {
|
106
|
-
const { json: message,
|
93
|
+
const { json: message, buffer } = await decodeRawMessage(raw);
|
107
94
|
const id = message.i;
|
108
95
|
const type = message.t;
|
109
96
|
if (type === 3 /* EVENT_ITERATOR */) {
|
@@ -115,23 +102,10 @@ async function decodeResponseMessage(raw) {
|
|
115
102
|
}
|
116
103
|
const payload = message.p;
|
117
104
|
const headers = payload.h ?? {};
|
118
|
-
|
119
|
-
const contentType = flattenHeader(headers["content-type"]);
|
120
|
-
if (blobData) {
|
121
|
-
const contentDisposition = flattenHeader(headers["content-disposition"]);
|
122
|
-
if (contentDisposition === void 0 && contentType?.startsWith("multipart/form-data")) {
|
123
|
-
const tempRes = new Response(blobData, { headers: { "content-type": contentType } });
|
124
|
-
body = await tempRes.formData();
|
125
|
-
} else {
|
126
|
-
const filename = getFilenameFromContentDisposition(contentDisposition) ?? "blob";
|
127
|
-
body = new File([blobData], filename, { type: contentType });
|
128
|
-
}
|
129
|
-
} else if (contentType?.startsWith("application/x-www-form-urlencoded") && typeof body === "string") {
|
130
|
-
body = new URLSearchParams(body);
|
131
|
-
}
|
105
|
+
const body = await deserializeBody(headers, payload.b, buffer);
|
132
106
|
return [id, 2 /* RESPONSE */, { status: payload.s ?? 200, headers, body }];
|
133
107
|
}
|
134
|
-
async function
|
108
|
+
async function serializeBodyAndHeaders(body, originalHeaders) {
|
135
109
|
const headers = { ...originalHeaders };
|
136
110
|
const originalContentDisposition = headers["content-disposition"];
|
137
111
|
delete headers["content-type"];
|
@@ -159,113 +133,184 @@ async function prepareBodyAndHeadersForSerialization(body, originalHeaders) {
|
|
159
133
|
}
|
160
134
|
return { body, headers };
|
161
135
|
}
|
162
|
-
function
|
163
|
-
|
136
|
+
async function deserializeBody(headers, body, buffer) {
|
137
|
+
const contentType = flattenHeader(headers["content-type"]);
|
138
|
+
const contentDisposition = flattenHeader(headers["content-disposition"]);
|
139
|
+
if (typeof contentDisposition === "string") {
|
140
|
+
const filename = getFilenameFromContentDisposition(contentDisposition) ?? "blob";
|
141
|
+
return new File(buffer === void 0 ? [] : [buffer], filename, { type: contentType });
|
142
|
+
}
|
143
|
+
if (contentType?.startsWith("multipart/form-data")) {
|
144
|
+
const tempRes = new Response(buffer, { headers: { "content-type": contentType } });
|
145
|
+
return tempRes.formData();
|
146
|
+
}
|
147
|
+
if (contentType?.startsWith("application/x-www-form-urlencoded") && typeof body === "string") {
|
148
|
+
return new URLSearchParams(body);
|
149
|
+
}
|
150
|
+
return body;
|
164
151
|
}
|
165
152
|
const JSON_AND_BINARY_DELIMITER = 255;
|
166
|
-
async function encodeRawMessage(data,
|
153
|
+
async function encodeRawMessage(data, blob) {
|
167
154
|
const json = stringifyJSON(data);
|
168
|
-
if (
|
155
|
+
if (blob === void 0 || blob.size === 0) {
|
169
156
|
return json;
|
170
157
|
}
|
171
|
-
return new Blob([
|
158
|
+
return readAsBuffer(new Blob([
|
172
159
|
new TextEncoder().encode(json),
|
173
160
|
new Uint8Array([JSON_AND_BINARY_DELIMITER]),
|
174
|
-
|
175
|
-
]);
|
161
|
+
blob
|
162
|
+
]));
|
176
163
|
}
|
177
164
|
async function decodeRawMessage(raw) {
|
178
165
|
if (typeof raw === "string") {
|
179
166
|
return { json: JSON.parse(raw) };
|
180
167
|
}
|
181
|
-
const buffer =
|
168
|
+
const buffer = raw instanceof Uint8Array ? raw : new Uint8Array(raw);
|
182
169
|
const delimiterIndex = buffer.indexOf(JSON_AND_BINARY_DELIMITER);
|
183
170
|
if (delimiterIndex === -1) {
|
184
171
|
const jsonPart2 = new TextDecoder().decode(buffer);
|
185
172
|
return { json: JSON.parse(jsonPart2) };
|
186
173
|
}
|
187
|
-
const jsonPart = new TextDecoder().decode(buffer.
|
188
|
-
const
|
174
|
+
const jsonPart = new TextDecoder().decode(buffer.subarray(0, delimiterIndex));
|
175
|
+
const bufferPart = buffer.subarray(delimiterIndex + 1);
|
189
176
|
return {
|
190
177
|
json: JSON.parse(jsonPart),
|
191
|
-
|
178
|
+
buffer: bufferPart
|
192
179
|
};
|
193
180
|
}
|
194
181
|
|
195
|
-
function toEventIterator(queue, id, cleanup) {
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
182
|
+
function toEventIterator(queue, id, cleanup, options = {}) {
|
183
|
+
let span;
|
184
|
+
return new AsyncIteratorClass(async () => {
|
185
|
+
span ??= startSpan("consume_event_iterator_stream");
|
186
|
+
try {
|
187
|
+
const item = await runInSpanContext(span, () => queue.pull(id));
|
188
|
+
switch (item.event) {
|
189
|
+
case "message": {
|
190
|
+
let data = item.data;
|
191
|
+
if (item.meta && isTypescriptObject(data)) {
|
192
|
+
data = withEventMeta(data, item.meta);
|
193
|
+
}
|
194
|
+
span?.addEvent("message");
|
195
|
+
return { value: data, done: false };
|
203
196
|
}
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
197
|
+
case "error": {
|
198
|
+
let error = new ErrorEvent({
|
199
|
+
data: item.data
|
200
|
+
});
|
201
|
+
if (item.meta) {
|
202
|
+
error = withEventMeta(error, item.meta);
|
203
|
+
}
|
204
|
+
span?.addEvent("error");
|
205
|
+
throw error;
|
212
206
|
}
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
207
|
+
case "done": {
|
208
|
+
let data = item.data;
|
209
|
+
if (item.meta && isTypescriptObject(data)) {
|
210
|
+
data = withEventMeta(data, item.meta);
|
211
|
+
}
|
212
|
+
span?.addEvent("done");
|
213
|
+
return { value: data, done: true };
|
219
214
|
}
|
220
|
-
return { value: data, done: true };
|
221
215
|
}
|
222
|
-
}
|
223
|
-
|
224
|
-
|
225
|
-
async function resolveEventIterator(iterator, callback) {
|
226
|
-
while (true) {
|
227
|
-
const payload = await (async () => {
|
228
|
-
try {
|
229
|
-
const { value, done } = await iterator.next();
|
230
|
-
if (done) {
|
231
|
-
return { event: "done", data: value, meta: getEventMeta(value) };
|
232
|
-
}
|
233
|
-
return { event: "message", data: value, meta: getEventMeta(value) };
|
234
|
-
} catch (err) {
|
235
|
-
return {
|
236
|
-
meta: getEventMeta(err),
|
237
|
-
event: "error",
|
238
|
-
data: err instanceof ErrorEvent ? err.data : void 0
|
239
|
-
};
|
216
|
+
} catch (e) {
|
217
|
+
if (!(e instanceof ErrorEvent)) {
|
218
|
+
setSpanError(span, e, options);
|
240
219
|
}
|
241
|
-
|
220
|
+
throw e;
|
221
|
+
}
|
222
|
+
}, async (reason) => {
|
242
223
|
try {
|
243
|
-
|
244
|
-
|
245
|
-
return;
|
224
|
+
if (reason !== "next") {
|
225
|
+
span?.addEvent("cancelled");
|
246
226
|
}
|
247
|
-
|
227
|
+
await runInSpanContext(span, () => cleanup(reason));
|
228
|
+
} catch (e) {
|
229
|
+
setSpanError(span, e, options);
|
230
|
+
throw e;
|
231
|
+
} finally {
|
232
|
+
span?.end();
|
233
|
+
}
|
234
|
+
});
|
235
|
+
}
|
236
|
+
function resolveEventIterator(iterator, callback) {
|
237
|
+
return runWithSpan(
|
238
|
+
{ name: "stream_event_iterator" },
|
239
|
+
async (span) => {
|
240
|
+
while (true) {
|
241
|
+
const payload = await (async () => {
|
242
|
+
try {
|
243
|
+
const { value, done } = await iterator.next();
|
244
|
+
if (done) {
|
245
|
+
span?.addEvent("done");
|
246
|
+
return { event: "done", data: value, meta: getEventMeta(value) };
|
247
|
+
}
|
248
|
+
span?.addEvent("message");
|
249
|
+
return { event: "message", data: value, meta: getEventMeta(value) };
|
250
|
+
} catch (err) {
|
251
|
+
if (err instanceof ErrorEvent) {
|
252
|
+
span?.addEvent("error");
|
253
|
+
return {
|
254
|
+
event: "error",
|
255
|
+
data: err.data,
|
256
|
+
meta: getEventMeta(err)
|
257
|
+
};
|
258
|
+
} else {
|
259
|
+
try {
|
260
|
+
await callback({ event: "error", data: void 0 });
|
261
|
+
} catch (err2) {
|
262
|
+
setSpanError(span, err);
|
263
|
+
throw err2;
|
264
|
+
}
|
265
|
+
throw err;
|
266
|
+
}
|
267
|
+
}
|
268
|
+
})();
|
269
|
+
let isInvokeCleanupFn = false;
|
248
270
|
try {
|
249
|
-
await
|
250
|
-
|
271
|
+
const direction = await callback(payload);
|
272
|
+
if (payload.event === "done" || payload.event === "error") {
|
273
|
+
return;
|
274
|
+
}
|
275
|
+
if (direction === "abort") {
|
276
|
+
isInvokeCleanupFn = true;
|
277
|
+
await iterator.return?.();
|
278
|
+
return;
|
279
|
+
}
|
280
|
+
} catch (err) {
|
281
|
+
if (!isInvokeCleanupFn) {
|
282
|
+
try {
|
283
|
+
await iterator.return?.();
|
284
|
+
} catch (err2) {
|
285
|
+
setSpanError(span, err);
|
286
|
+
throw err2;
|
287
|
+
}
|
288
|
+
}
|
289
|
+
throw err;
|
251
290
|
}
|
252
|
-
return;
|
253
|
-
}
|
254
|
-
} catch (err) {
|
255
|
-
try {
|
256
|
-
await iterator.return?.();
|
257
|
-
} catch {
|
258
291
|
}
|
259
|
-
throw err;
|
260
292
|
}
|
261
|
-
|
293
|
+
);
|
262
294
|
}
|
263
295
|
|
264
296
|
class ClientPeer {
|
265
297
|
idGenerator = new SequentialIdGenerator();
|
298
|
+
/**
|
299
|
+
* Queue of responses sent from server, awaiting consumption
|
300
|
+
*/
|
266
301
|
responseQueue = new AsyncIdQueue();
|
302
|
+
/**
|
303
|
+
* Queue of event iterator messages sent from server, awaiting consumption
|
304
|
+
*/
|
267
305
|
serverEventIteratorQueue = new AsyncIdQueue();
|
306
|
+
/**
|
307
|
+
* Controllers used to signal that the client should stop sending event iterator messages
|
308
|
+
*/
|
268
309
|
serverControllers = /* @__PURE__ */ new Map();
|
310
|
+
/**
|
311
|
+
* Cleanup functions invoked when the request/response is closed
|
312
|
+
*/
|
313
|
+
cleanupFns = /* @__PURE__ */ new Map();
|
269
314
|
send;
|
270
315
|
constructor(send) {
|
271
316
|
this.send = async (id, ...rest) => encodeRequestMessage(id, ...rest).then(async (raw) => {
|
@@ -275,48 +320,85 @@ class ClientPeer {
|
|
275
320
|
});
|
276
321
|
}
|
277
322
|
get length() {
|
278
|
-
return (+this.responseQueue.length + this.serverEventIteratorQueue.length + this.serverControllers.size) /
|
323
|
+
return (+this.responseQueue.length + this.serverEventIteratorQueue.length + this.serverControllers.size + this.cleanupFns.size) / 4;
|
279
324
|
}
|
280
325
|
open(id) {
|
281
326
|
this.serverEventIteratorQueue.open(id);
|
282
327
|
this.responseQueue.open(id);
|
283
328
|
const controller = new AbortController();
|
284
329
|
this.serverControllers.set(id, controller);
|
330
|
+
this.cleanupFns.set(id, []);
|
285
331
|
return controller;
|
286
332
|
}
|
287
333
|
async request(request) {
|
288
334
|
const signal = request.signal;
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
const id = this.idGenerator.generate();
|
293
|
-
const serverController = this.open(id);
|
294
|
-
return new Promise((resolve, reject) => {
|
295
|
-
this.send(id, MessageType.REQUEST, request).then(async () => {
|
335
|
+
return runWithSpan(
|
336
|
+
{ name: "send_peer_request", signal },
|
337
|
+
async () => {
|
296
338
|
if (signal?.aborted) {
|
297
|
-
|
298
|
-
this.close({ id, reason: signal.reason });
|
299
|
-
return;
|
339
|
+
throw signal.reason;
|
300
340
|
}
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
341
|
+
const id = this.idGenerator.generate();
|
342
|
+
const serverController = this.open(id);
|
343
|
+
try {
|
344
|
+
const otelConfig = getGlobalOtelConfig();
|
345
|
+
if (otelConfig) {
|
346
|
+
const headers = clone(request.headers);
|
347
|
+
otelConfig.propagation.inject(otelConfig.context.active(), headers);
|
348
|
+
request = { ...request, headers };
|
349
|
+
}
|
350
|
+
await this.send(id, MessageType.REQUEST, request);
|
351
|
+
if (signal?.aborted) {
|
352
|
+
await this.send(id, MessageType.ABORT_SIGNAL, void 0);
|
353
|
+
throw signal.reason;
|
354
|
+
}
|
355
|
+
let abortListener;
|
356
|
+
signal?.addEventListener("abort", abortListener = async () => {
|
357
|
+
await this.send(id, MessageType.ABORT_SIGNAL, void 0);
|
358
|
+
this.close({ id, reason: signal.reason });
|
359
|
+
}, { once: true });
|
360
|
+
this.cleanupFns.get(id)?.push(() => {
|
361
|
+
signal?.removeEventListener("abort", abortListener);
|
312
362
|
});
|
363
|
+
if (isAsyncIteratorObject(request.body)) {
|
364
|
+
const iterator = request.body;
|
365
|
+
void resolveEventIterator(iterator, async (payload) => {
|
366
|
+
if (serverController.signal.aborted) {
|
367
|
+
return "abort";
|
368
|
+
}
|
369
|
+
await this.send(id, MessageType.EVENT_ITERATOR, payload);
|
370
|
+
return "next";
|
371
|
+
});
|
372
|
+
}
|
373
|
+
const response = await this.responseQueue.pull(id);
|
374
|
+
if (isEventIteratorHeaders(response.headers)) {
|
375
|
+
const iterator = toEventIterator(
|
376
|
+
this.serverEventIteratorQueue,
|
377
|
+
id,
|
378
|
+
async (reason) => {
|
379
|
+
try {
|
380
|
+
if (reason !== "next") {
|
381
|
+
await this.send(id, MessageType.ABORT_SIGNAL, void 0);
|
382
|
+
}
|
383
|
+
} finally {
|
384
|
+
this.close({ id });
|
385
|
+
}
|
386
|
+
},
|
387
|
+
{ signal }
|
388
|
+
);
|
389
|
+
return {
|
390
|
+
...response,
|
391
|
+
body: iterator
|
392
|
+
};
|
393
|
+
}
|
394
|
+
this.close({ id });
|
395
|
+
return response;
|
396
|
+
} catch (err) {
|
397
|
+
this.close({ id, reason: err });
|
398
|
+
throw err;
|
313
399
|
}
|
314
|
-
}
|
315
|
-
|
316
|
-
reject(err);
|
317
|
-
});
|
318
|
-
this.responseQueue.pull(id).then(resolve).catch(reject);
|
319
|
-
});
|
400
|
+
}
|
401
|
+
);
|
320
402
|
}
|
321
403
|
async message(raw) {
|
322
404
|
const [id, type, payload] = await decodeResponseMessage(raw);
|
@@ -333,31 +415,19 @@ class ClientPeer {
|
|
333
415
|
if (!this.responseQueue.isOpen(id)) {
|
334
416
|
return;
|
335
417
|
}
|
336
|
-
|
337
|
-
this.responseQueue.push(id, {
|
338
|
-
...payload,
|
339
|
-
body: toEventIterator(this.serverEventIteratorQueue, id, async (reason) => {
|
340
|
-
try {
|
341
|
-
if (reason !== "next") {
|
342
|
-
await this.send(id, MessageType.ABORT_SIGNAL, void 0);
|
343
|
-
}
|
344
|
-
} finally {
|
345
|
-
this.close({ id });
|
346
|
-
}
|
347
|
-
})
|
348
|
-
});
|
349
|
-
} else {
|
350
|
-
this.responseQueue.push(id, payload);
|
351
|
-
this.close({ id });
|
352
|
-
}
|
418
|
+
this.responseQueue.push(id, payload);
|
353
419
|
}
|
354
420
|
close(options = {}) {
|
355
421
|
if (options.id !== void 0) {
|
356
422
|
this.serverControllers.get(options.id)?.abort(options.reason);
|
357
423
|
this.serverControllers.delete(options.id);
|
424
|
+
this.cleanupFns.get(options.id)?.forEach((fn) => fn());
|
425
|
+
this.cleanupFns.delete(options.id);
|
358
426
|
} else {
|
359
427
|
this.serverControllers.forEach((c) => c.abort(options.reason));
|
360
428
|
this.serverControllers.clear();
|
429
|
+
this.cleanupFns.forEach((fns) => fns.forEach((fn) => fn()));
|
430
|
+
this.cleanupFns.clear();
|
361
431
|
}
|
362
432
|
this.responseQueue.close(options);
|
363
433
|
this.serverEventIteratorQueue.close(options);
|
@@ -365,7 +435,13 @@ class ClientPeer {
|
|
365
435
|
}
|
366
436
|
|
367
437
|
class ServerPeer {
|
438
|
+
/**
|
439
|
+
* Queue of event iterator messages sent from client, awaiting consumption
|
440
|
+
*/
|
368
441
|
clientEventIteratorQueue = new AsyncIdQueue();
|
442
|
+
/**
|
443
|
+
* Map of active client request controllers, should be synced to request signal
|
444
|
+
*/
|
369
445
|
clientControllers = /* @__PURE__ */ new Map();
|
370
446
|
send;
|
371
447
|
constructor(send) {
|
@@ -384,10 +460,13 @@ class ServerPeer {
|
|
384
460
|
this.clientControllers.set(id, controller);
|
385
461
|
return controller;
|
386
462
|
}
|
387
|
-
|
463
|
+
/**
|
464
|
+
* @todo This method will return Promise<void> in the next major version.
|
465
|
+
*/
|
466
|
+
async message(raw, handleRequest) {
|
388
467
|
const [id, type, payload] = await decodeRequestMessage(raw);
|
389
468
|
if (type === MessageType.ABORT_SIGNAL) {
|
390
|
-
this.close({ id });
|
469
|
+
this.close({ id, reason: new AbortError("Client aborted the request") });
|
391
470
|
return [id, void 0];
|
392
471
|
}
|
393
472
|
if (type === MessageType.EVENT_ITERATOR) {
|
@@ -397,47 +476,89 @@ class ServerPeer {
|
|
397
476
|
return [id, void 0];
|
398
477
|
}
|
399
478
|
const clientController = this.open(id);
|
479
|
+
const signal = clientController.signal;
|
400
480
|
const request = {
|
401
481
|
...payload,
|
402
|
-
signal
|
403
|
-
body: isEventIteratorHeaders(payload.headers) ? toEventIterator(
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
482
|
+
signal,
|
483
|
+
body: isEventIteratorHeaders(payload.headers) ? toEventIterator(
|
484
|
+
this.clientEventIteratorQueue,
|
485
|
+
id,
|
486
|
+
async (reason) => {
|
487
|
+
if (reason !== "next") {
|
488
|
+
await this.send(id, MessageType.ABORT_SIGNAL, void 0);
|
489
|
+
}
|
490
|
+
},
|
491
|
+
{ signal }
|
492
|
+
) : payload.body
|
408
493
|
};
|
494
|
+
if (handleRequest) {
|
495
|
+
let context;
|
496
|
+
const otelConfig = getGlobalOtelConfig();
|
497
|
+
if (otelConfig) {
|
498
|
+
context = otelConfig.propagation.extract(otelConfig.context.active(), request.headers);
|
499
|
+
}
|
500
|
+
await runWithSpan(
|
501
|
+
{ name: "receive_peer_request", context },
|
502
|
+
async () => {
|
503
|
+
const response = await runWithSpan(
|
504
|
+
{ name: "handle_request" },
|
505
|
+
async () => {
|
506
|
+
try {
|
507
|
+
return await handleRequest(request);
|
508
|
+
} catch (reason) {
|
509
|
+
this.close({ id, reason, abort: false });
|
510
|
+
throw reason;
|
511
|
+
}
|
512
|
+
}
|
513
|
+
);
|
514
|
+
await runWithSpan(
|
515
|
+
{ name: "send_peer_response" },
|
516
|
+
() => this.response(id, response)
|
517
|
+
);
|
518
|
+
}
|
519
|
+
);
|
520
|
+
}
|
409
521
|
return [id, request];
|
410
522
|
}
|
523
|
+
/**
|
524
|
+
* @deprecated Please pass the `handleRequest` (second arg) function to the `message` method instead.
|
525
|
+
*/
|
411
526
|
async response(id, response) {
|
412
527
|
const signal = this.clientControllers.get(id)?.signal;
|
413
528
|
if (!signal || signal.aborted) {
|
414
529
|
return;
|
415
530
|
}
|
416
|
-
|
531
|
+
try {
|
532
|
+
await this.send(id, MessageType.RESPONSE, response);
|
417
533
|
if (!signal.aborted && isAsyncIteratorObject(response.body)) {
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
await
|
423
|
-
|
424
|
-
|
534
|
+
if (response.body instanceof HibernationEventIterator) {
|
535
|
+
response.body.hibernationCallback?.(id);
|
536
|
+
} else {
|
537
|
+
const iterator = response.body;
|
538
|
+
await resolveEventIterator(iterator, async (payload) => {
|
539
|
+
if (signal.aborted) {
|
540
|
+
return "abort";
|
541
|
+
}
|
542
|
+
await this.send(id, MessageType.EVENT_ITERATOR, payload);
|
543
|
+
return "next";
|
544
|
+
});
|
545
|
+
}
|
425
546
|
}
|
426
547
|
this.close({ id, abort: false });
|
427
|
-
}
|
548
|
+
} catch (reason) {
|
428
549
|
this.close({ id, reason, abort: false });
|
429
550
|
throw reason;
|
430
|
-
}
|
551
|
+
}
|
431
552
|
}
|
432
553
|
close({ abort = true, ...options } = {}) {
|
433
554
|
if (options.id === void 0) {
|
434
555
|
if (abort) {
|
435
|
-
this.clientControllers.forEach((c) => c.abort());
|
556
|
+
this.clientControllers.forEach((c) => c.abort(options.reason));
|
436
557
|
}
|
437
558
|
this.clientControllers.clear();
|
438
559
|
} else {
|
439
560
|
if (abort) {
|
440
|
-
this.clientControllers.get(options.id)?.abort();
|
561
|
+
this.clientControllers.get(options.id)?.abort(options.reason);
|
441
562
|
}
|
442
563
|
this.clientControllers.delete(options.id);
|
443
564
|
}
|
@@ -445,4 +566,4 @@ class ServerPeer {
|
|
445
566
|
}
|
446
567
|
}
|
447
568
|
|
448
|
-
export { ClientPeer, MessageType, ServerPeer, decodeRequestMessage, decodeResponseMessage, encodeRequestMessage, encodeResponseMessage,
|
569
|
+
export { ClientPeer, MessageType, ServerPeer, decodeRequestMessage, decodeResponseMessage, encodeRequestMessage, encodeResponseMessage, resolveEventIterator, toEventIterator };
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@orpc/standard-server-peer",
|
3
3
|
"type": "module",
|
4
|
-
"version": "0.0.0-next.
|
4
|
+
"version": "0.0.0-next.e4b0df6",
|
5
5
|
"license": "MIT",
|
6
6
|
"homepage": "https://unnoq.com",
|
7
7
|
"repository": {
|
@@ -23,8 +23,8 @@
|
|
23
23
|
"dist"
|
24
24
|
],
|
25
25
|
"dependencies": {
|
26
|
-
"@orpc/shared": "0.0.0-next.
|
27
|
-
"@orpc/standard-server": "0.0.0-next.
|
26
|
+
"@orpc/shared": "0.0.0-next.e4b0df6",
|
27
|
+
"@orpc/standard-server": "0.0.0-next.e4b0df6"
|
28
28
|
},
|
29
29
|
"scripts": {
|
30
30
|
"build": "unbuild",
|