@orpc/standard-server-node 0.0.0-next.ff41b3a → 0.0.0-next.ffd5805
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 +4 -5
- package/dist/index.d.mts +10 -23
- package/dist/index.d.ts +10 -23
- package/dist/index.mjs +29 -112
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -49,13 +49,12 @@ 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/openapi](https://www.npmjs.com/package/@orpc/openapi): Generate OpenAPI specs and handle OpenAPI requests.
|
|
53
|
+
- [@orpc/nest](https://www.npmjs.com/package/@orpc/nest): Deeply integrate oRPC with [NestJS](https://nestjs.com/).
|
|
52
54
|
- [@orpc/react](https://www.npmjs.com/package/@orpc/react): Utilities for integrating oRPC with React and React Server Actions.
|
|
53
|
-
- [@orpc/
|
|
54
|
-
- [@orpc/vue-query](https://www.npmjs.com/package/@orpc/vue-query): Integration with [Vue Query](https://tanstack.com/query/latest/docs/framework/vue/overview).
|
|
55
|
-
- [@orpc/solid-query](https://www.npmjs.com/package/@orpc/solid-query): Integration with [Solid Query](https://tanstack.com/query/latest/docs/framework/solid/overview).
|
|
56
|
-
- [@orpc/svelte-query](https://www.npmjs.com/package/@orpc/svelte-query): Integration with [Svelte Query](https://tanstack.com/query/latest/docs/framework/svelte/overview).
|
|
55
|
+
- [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query): [TanStack Query](https://tanstack.com/query/latest) integration.
|
|
57
56
|
- [@orpc/vue-colada](https://www.npmjs.com/package/@orpc/vue-colada): Integration with [Pinia Colada](https://pinia-colada.esm.dev/).
|
|
58
|
-
- [@orpc/
|
|
57
|
+
- [@orpc/hey-api](https://www.npmjs.com/package/@orpc/hey-api): [Hey API](https://heyapi.dev/) integration.
|
|
59
58
|
- [@orpc/zod](https://www.npmjs.com/package/@orpc/zod): More schemas that [Zod](https://zod.dev/) doesn't support yet.
|
|
60
59
|
- [@orpc/valibot](https://www.npmjs.com/package/@orpc/valibot): OpenAPI spec generation from [Valibot](https://valibot.dev/).
|
|
61
60
|
- [@orpc/arktype](https://www.npmjs.com/package/@orpc/arktype): OpenAPI spec generation from [ArkType](https://arktype.io/).
|
package/dist/index.d.mts
CHANGED
|
@@ -1,28 +1,11 @@
|
|
|
1
1
|
import { StandardBody, StandardHeaders, StandardLazyRequest, StandardResponse } from '@orpc/standard-server';
|
|
2
|
-
import {
|
|
2
|
+
import { ToEventStreamOptions as ToEventStreamOptions$1 } from '@orpc/standard-server-fetch';
|
|
3
|
+
import Stream, { Readable } from 'node:stream';
|
|
3
4
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
4
5
|
import { Http2ServerRequest, Http2ServerResponse } from 'node:http2';
|
|
5
6
|
|
|
6
|
-
declare function toEventIterator(stream: Readable): AsyncGenerator<unknown | void, unknown | void, void>;
|
|
7
|
-
interface ToEventStreamOptions {
|
|
8
|
-
/**
|
|
9
|
-
* If true, a ping comment is sent periodically to keep the connection alive.
|
|
10
|
-
*
|
|
11
|
-
* @default true
|
|
12
|
-
*/
|
|
13
|
-
eventIteratorKeepAliveEnabled?: boolean;
|
|
14
|
-
/**
|
|
15
|
-
* Interval (in milliseconds) between ping comments sent after the last event.
|
|
16
|
-
*
|
|
17
|
-
* @default 5000
|
|
18
|
-
*/
|
|
19
|
-
eventIteratorKeepAliveInterval?: number;
|
|
20
|
-
/**
|
|
21
|
-
* The content of the ping comment. Must not include newline characters.
|
|
22
|
-
*
|
|
23
|
-
* @default ''
|
|
24
|
-
*/
|
|
25
|
-
eventIteratorKeepAliveComment?: string;
|
|
7
|
+
declare function toEventIterator(stream: Readable): AsyncIteratorObject<unknown | void, unknown | void, void> & AsyncGenerator<unknown | void, unknown | void, void>;
|
|
8
|
+
interface ToEventStreamOptions extends ToEventStreamOptions$1 {
|
|
26
9
|
}
|
|
27
10
|
declare function toEventStream(iterator: AsyncIterator<unknown | void, unknown | void, void>, options?: ToEventStreamOptions): Readable;
|
|
28
11
|
|
|
@@ -45,13 +28,17 @@ interface ToNodeHttpBodyOptions extends ToEventStreamOptions {
|
|
|
45
28
|
*/
|
|
46
29
|
declare function toNodeHttpBody(body: StandardBody, headers: StandardHeaders, options?: ToNodeHttpBodyOptions): Readable | undefined | string;
|
|
47
30
|
|
|
31
|
+
declare function toStandardMethod(method: string | undefined): string;
|
|
32
|
+
|
|
48
33
|
declare function toStandardLazyRequest(req: NodeHttpRequest, res: NodeHttpResponse): StandardLazyRequest;
|
|
49
34
|
|
|
50
35
|
interface SendStandardResponseOptions extends ToNodeHttpBodyOptions {
|
|
51
36
|
}
|
|
52
37
|
declare function sendStandardResponse(res: NodeHttpResponse, standardResponse: StandardResponse, options?: SendStandardResponseOptions): Promise<void>;
|
|
53
38
|
|
|
54
|
-
declare function toAbortSignal(
|
|
39
|
+
declare function toAbortSignal(stream: Stream.Writable): AbortSignal;
|
|
40
|
+
|
|
41
|
+
declare function toStandardUrl(req: NodeHttpRequest): URL;
|
|
55
42
|
|
|
56
|
-
export { sendStandardResponse, toAbortSignal, toEventIterator, toEventStream, toNodeHttpBody, toStandardBody, toStandardLazyRequest };
|
|
43
|
+
export { sendStandardResponse, toAbortSignal, toEventIterator, toEventStream, toNodeHttpBody, toStandardBody, toStandardLazyRequest, toStandardMethod, toStandardUrl };
|
|
57
44
|
export type { NodeHttpRequest, NodeHttpResponse, SendStandardResponseOptions, ToEventStreamOptions, ToNodeHttpBodyOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,28 +1,11 @@
|
|
|
1
1
|
import { StandardBody, StandardHeaders, StandardLazyRequest, StandardResponse } from '@orpc/standard-server';
|
|
2
|
-
import {
|
|
2
|
+
import { ToEventStreamOptions as ToEventStreamOptions$1 } from '@orpc/standard-server-fetch';
|
|
3
|
+
import Stream, { Readable } from 'node:stream';
|
|
3
4
|
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
4
5
|
import { Http2ServerRequest, Http2ServerResponse } from 'node:http2';
|
|
5
6
|
|
|
6
|
-
declare function toEventIterator(stream: Readable): AsyncGenerator<unknown | void, unknown | void, void>;
|
|
7
|
-
interface ToEventStreamOptions {
|
|
8
|
-
/**
|
|
9
|
-
* If true, a ping comment is sent periodically to keep the connection alive.
|
|
10
|
-
*
|
|
11
|
-
* @default true
|
|
12
|
-
*/
|
|
13
|
-
eventIteratorKeepAliveEnabled?: boolean;
|
|
14
|
-
/**
|
|
15
|
-
* Interval (in milliseconds) between ping comments sent after the last event.
|
|
16
|
-
*
|
|
17
|
-
* @default 5000
|
|
18
|
-
*/
|
|
19
|
-
eventIteratorKeepAliveInterval?: number;
|
|
20
|
-
/**
|
|
21
|
-
* The content of the ping comment. Must not include newline characters.
|
|
22
|
-
*
|
|
23
|
-
* @default ''
|
|
24
|
-
*/
|
|
25
|
-
eventIteratorKeepAliveComment?: string;
|
|
7
|
+
declare function toEventIterator(stream: Readable): AsyncIteratorObject<unknown | void, unknown | void, void> & AsyncGenerator<unknown | void, unknown | void, void>;
|
|
8
|
+
interface ToEventStreamOptions extends ToEventStreamOptions$1 {
|
|
26
9
|
}
|
|
27
10
|
declare function toEventStream(iterator: AsyncIterator<unknown | void, unknown | void, void>, options?: ToEventStreamOptions): Readable;
|
|
28
11
|
|
|
@@ -45,13 +28,17 @@ interface ToNodeHttpBodyOptions extends ToEventStreamOptions {
|
|
|
45
28
|
*/
|
|
46
29
|
declare function toNodeHttpBody(body: StandardBody, headers: StandardHeaders, options?: ToNodeHttpBodyOptions): Readable | undefined | string;
|
|
47
30
|
|
|
31
|
+
declare function toStandardMethod(method: string | undefined): string;
|
|
32
|
+
|
|
48
33
|
declare function toStandardLazyRequest(req: NodeHttpRequest, res: NodeHttpResponse): StandardLazyRequest;
|
|
49
34
|
|
|
50
35
|
interface SendStandardResponseOptions extends ToNodeHttpBodyOptions {
|
|
51
36
|
}
|
|
52
37
|
declare function sendStandardResponse(res: NodeHttpResponse, standardResponse: StandardResponse, options?: SendStandardResponseOptions): Promise<void>;
|
|
53
38
|
|
|
54
|
-
declare function toAbortSignal(
|
|
39
|
+
declare function toAbortSignal(stream: Stream.Writable): AbortSignal;
|
|
40
|
+
|
|
41
|
+
declare function toStandardUrl(req: NodeHttpRequest): URL;
|
|
55
42
|
|
|
56
|
-
export { sendStandardResponse, toAbortSignal, toEventIterator, toEventStream, toNodeHttpBody, toStandardBody, toStandardLazyRequest };
|
|
43
|
+
export { sendStandardResponse, toAbortSignal, toEventIterator, toEventStream, toNodeHttpBody, toStandardBody, toStandardLazyRequest, toStandardMethod, toStandardUrl };
|
|
57
44
|
export type { NodeHttpRequest, NodeHttpResponse, SendStandardResponseOptions, ToEventStreamOptions, ToNodeHttpBodyOptions };
|
package/dist/index.mjs
CHANGED
|
@@ -1,102 +1,16 @@
|
|
|
1
1
|
import { Readable } from 'node:stream';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { parseEmptyableJSON, isAsyncIteratorObject, stringifyJSON, once } from '@orpc/shared';
|
|
3
|
+
import { getFilenameFromContentDisposition, flattenHeader, generateContentDisposition } from '@orpc/standard-server';
|
|
4
|
+
import { toEventIterator as toEventIterator$1, toEventStream as toEventStream$1 } from '@orpc/standard-server-fetch';
|
|
4
5
|
|
|
5
6
|
function toEventIterator(stream) {
|
|
6
|
-
|
|
7
|
-
const reader = eventStream.getReader();
|
|
8
|
-
async function* gen() {
|
|
9
|
-
try {
|
|
10
|
-
while (true) {
|
|
11
|
-
const { done, value } = await reader.read();
|
|
12
|
-
if (done) {
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
switch (value.event) {
|
|
16
|
-
case "message": {
|
|
17
|
-
let message = parseEmptyableJSON(value.data);
|
|
18
|
-
if (isTypescriptObject(message)) {
|
|
19
|
-
message = withEventMeta(message, value);
|
|
20
|
-
}
|
|
21
|
-
yield message;
|
|
22
|
-
break;
|
|
23
|
-
}
|
|
24
|
-
case "error": {
|
|
25
|
-
let error = new ErrorEvent({
|
|
26
|
-
data: parseEmptyableJSON(value.data)
|
|
27
|
-
});
|
|
28
|
-
error = withEventMeta(error, value);
|
|
29
|
-
throw error;
|
|
30
|
-
}
|
|
31
|
-
case "done": {
|
|
32
|
-
let done2 = parseEmptyableJSON(value.data);
|
|
33
|
-
if (isTypescriptObject(done2)) {
|
|
34
|
-
done2 = withEventMeta(done2, value);
|
|
35
|
-
}
|
|
36
|
-
return done2;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
} finally {
|
|
41
|
-
await reader.cancel();
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return gen();
|
|
7
|
+
return toEventIterator$1(Readable.toWeb(stream));
|
|
45
8
|
}
|
|
46
9
|
function toEventStream(iterator, options = {}) {
|
|
47
|
-
|
|
48
|
-
const keepAliveInterval = options.eventIteratorKeepAliveInterval ?? 5e3;
|
|
49
|
-
const keepAliveComment = options.eventIteratorKeepAliveComment ?? "";
|
|
50
|
-
let timeout;
|
|
51
|
-
const stream = new ReadableStream({
|
|
52
|
-
async pull(controller) {
|
|
53
|
-
try {
|
|
54
|
-
if (keepAliveEnabled) {
|
|
55
|
-
timeout = setInterval(() => {
|
|
56
|
-
controller.enqueue(encodeEventMessage({
|
|
57
|
-
comments: [keepAliveComment]
|
|
58
|
-
}));
|
|
59
|
-
}, keepAliveInterval);
|
|
60
|
-
}
|
|
61
|
-
const value = await iterator.next();
|
|
62
|
-
clearInterval(timeout);
|
|
63
|
-
const meta = getEventMeta(value.value);
|
|
64
|
-
if (!value.done || value.value !== void 0 || meta !== void 0) {
|
|
65
|
-
controller.enqueue(encodeEventMessage({
|
|
66
|
-
...meta,
|
|
67
|
-
event: value.done ? "done" : "message",
|
|
68
|
-
data: stringifyJSON(value.value)
|
|
69
|
-
}));
|
|
70
|
-
}
|
|
71
|
-
if (value.done) {
|
|
72
|
-
controller.close();
|
|
73
|
-
}
|
|
74
|
-
} catch (err) {
|
|
75
|
-
clearInterval(timeout);
|
|
76
|
-
controller.enqueue(encodeEventMessage({
|
|
77
|
-
...getEventMeta(err),
|
|
78
|
-
event: "error",
|
|
79
|
-
data: err instanceof ErrorEvent ? stringifyJSON(err.data) : void 0
|
|
80
|
-
}));
|
|
81
|
-
controller.close();
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
async cancel(reason) {
|
|
85
|
-
if (reason) {
|
|
86
|
-
await iterator.throw?.(reason);
|
|
87
|
-
} else {
|
|
88
|
-
await iterator.return?.();
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
return Readable.fromWeb(stream);
|
|
10
|
+
return Readable.fromWeb(toEventStream$1(iterator, options));
|
|
93
11
|
}
|
|
94
12
|
|
|
95
13
|
async function toStandardBody(req) {
|
|
96
|
-
const method = req.method ?? "GET";
|
|
97
|
-
if (method === "GET" || method === "HEAD") {
|
|
98
|
-
return void 0;
|
|
99
|
-
}
|
|
100
14
|
const contentDisposition = req.headers["content-disposition"];
|
|
101
15
|
const contentType = req.headers["content-type"];
|
|
102
16
|
if (typeof contentDisposition === "string") {
|
|
@@ -123,7 +37,7 @@ async function toStandardBody(req) {
|
|
|
123
37
|
return _streamToFile(req, "blob", contentType);
|
|
124
38
|
}
|
|
125
39
|
function toNodeHttpBody(body, headers, options = {}) {
|
|
126
|
-
const currentContentDisposition =
|
|
40
|
+
const currentContentDisposition = flattenHeader(headers["content-disposition"]);
|
|
127
41
|
delete headers["content-type"];
|
|
128
42
|
delete headers["content-disposition"];
|
|
129
43
|
if (body === void 0) {
|
|
@@ -146,8 +60,6 @@ function toNodeHttpBody(body, headers, options = {}) {
|
|
|
146
60
|
}
|
|
147
61
|
if (isAsyncIteratorObject(body)) {
|
|
148
62
|
headers["content-type"] = "text/event-stream";
|
|
149
|
-
headers["cache-control"] = "no-cache";
|
|
150
|
-
headers.connection = "keep-alive";
|
|
151
63
|
return toEventStream(body, options);
|
|
152
64
|
}
|
|
153
65
|
headers["content-type"] = "application/json";
|
|
@@ -176,28 +88,32 @@ async function _streamToFile(stream, fileName, contentType) {
|
|
|
176
88
|
return new File(chunks, fileName, { type: contentType });
|
|
177
89
|
}
|
|
178
90
|
|
|
179
|
-
function
|
|
91
|
+
function toStandardMethod(method) {
|
|
92
|
+
return method ?? "GET";
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function toAbortSignal(stream) {
|
|
180
96
|
const controller = new AbortController();
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
controller.abort("Client connection prematurely closed.");
|
|
186
|
-
} else {
|
|
187
|
-
controller.abort("Server closed the connection.");
|
|
97
|
+
stream.once("error", (error) => controller.abort(error));
|
|
98
|
+
stream.once("close", () => {
|
|
99
|
+
if (!stream.writableFinished) {
|
|
100
|
+
controller.abort(new Error("Writable stream closed before it finished writing"));
|
|
188
101
|
}
|
|
189
102
|
});
|
|
190
103
|
return controller.signal;
|
|
191
104
|
}
|
|
192
105
|
|
|
193
|
-
function
|
|
194
|
-
const method = req.method ?? "GET";
|
|
106
|
+
function toStandardUrl(req) {
|
|
195
107
|
const protocol = "encrypted" in req.socket && req.socket.encrypted ? "https:" : "http:";
|
|
196
108
|
const host = req.headers.host ?? "localhost";
|
|
197
109
|
const url = new URL(req.originalUrl ?? req.url ?? "/", `${protocol}//${host}`);
|
|
110
|
+
return url;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function toStandardLazyRequest(req, res) {
|
|
198
114
|
return {
|
|
199
|
-
method,
|
|
200
|
-
url,
|
|
115
|
+
method: toStandardMethod(req.method),
|
|
116
|
+
url: toStandardUrl(req),
|
|
201
117
|
headers: req.headers,
|
|
202
118
|
body: once(() => toStandardBody(req)),
|
|
203
119
|
signal: toAbortSignal(res)
|
|
@@ -206,24 +122,25 @@ function toStandardLazyRequest(req, res) {
|
|
|
206
122
|
|
|
207
123
|
function sendStandardResponse(res, standardResponse, options = {}) {
|
|
208
124
|
return new Promise((resolve, reject) => {
|
|
209
|
-
res.
|
|
210
|
-
res.
|
|
211
|
-
const resHeaders = standardResponse.headers;
|
|
125
|
+
res.once("error", reject);
|
|
126
|
+
res.once("close", resolve);
|
|
127
|
+
const resHeaders = { ...standardResponse.headers };
|
|
212
128
|
const resBody = toNodeHttpBody(standardResponse.body, resHeaders, options);
|
|
213
129
|
res.writeHead(standardResponse.status, resHeaders);
|
|
214
130
|
if (resBody === void 0) {
|
|
215
|
-
res.end(
|
|
131
|
+
res.end();
|
|
216
132
|
} else if (typeof resBody === "string") {
|
|
217
133
|
res.end(resBody);
|
|
218
134
|
} else {
|
|
219
|
-
res.
|
|
135
|
+
res.once("close", () => {
|
|
220
136
|
if (!resBody.closed) {
|
|
221
137
|
resBody.destroy(res.errored ?? void 0);
|
|
222
138
|
}
|
|
223
139
|
});
|
|
140
|
+
resBody.once("error", (error) => res.destroy(error));
|
|
224
141
|
resBody.pipe(res);
|
|
225
142
|
}
|
|
226
143
|
});
|
|
227
144
|
}
|
|
228
145
|
|
|
229
|
-
export { sendStandardResponse, toAbortSignal, toEventIterator, toEventStream, toNodeHttpBody, toStandardBody, toStandardLazyRequest };
|
|
146
|
+
export { sendStandardResponse, toAbortSignal, toEventIterator, toEventStream, toNodeHttpBody, toStandardBody, toStandardLazyRequest, toStandardMethod, toStandardUrl };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orpc/standard-server-node",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.0-next.
|
|
4
|
+
"version": "0.0.0-next.ffd5805",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://orpc.unnoq.com",
|
|
7
7
|
"repository": {
|
|
@@ -23,11 +23,12 @@
|
|
|
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.ffd5805",
|
|
27
|
+
"@orpc/standard-server-fetch": "0.0.0-next.ffd5805",
|
|
28
|
+
"@orpc/standard-server": "0.0.0-next.ffd5805"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
|
-
"@types/node": "^22.
|
|
31
|
+
"@types/node": "^22.15.18",
|
|
31
32
|
"@types/supertest": "^6.0.3",
|
|
32
33
|
"supertest": "^7.1.0"
|
|
33
34
|
},
|