@orpc/standard-server-node 0.0.0-next.f72e6b9 → 0.0.0-next.f779f69

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 CHANGED
@@ -49,6 +49,7 @@ 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/nest](https://www.npmjs.com/package/@orpc/nest): Deeply integrate oRPC with NestJS.
52
53
  - [@orpc/react](https://www.npmjs.com/package/@orpc/react): Utilities for integrating oRPC with React and React Server Actions.
53
54
  - [@orpc/react-query](https://www.npmjs.com/package/@orpc/react-query): Integration with [React Query](https://tanstack.com/query/latest/docs/framework/react/overview).
54
55
  - [@orpc/vue-query](https://www.npmjs.com/package/@orpc/vue-query): Integration with [Vue Query](https://tanstack.com/query/latest/docs/framework/vue/overview).
package/dist/index.d.mts CHANGED
@@ -1,28 +1,11 @@
1
1
  import { StandardBody, StandardHeaders, StandardLazyRequest, StandardResponse } from '@orpc/standard-server';
2
- import { Readable } from 'node:stream';
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(res: NodeHttpResponse): AbortSignal;
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 { Readable } from 'node:stream';
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(res: NodeHttpResponse): AbortSignal;
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 { stringifyJSON, parseEmptyableJSON, isTypescriptObject, toArray, isAsyncIteratorObject, once } from '@orpc/shared';
3
- import { EventDecoderStream, encodeEventMessage, getEventMeta, ErrorEvent, withEventMeta, getFilenameFromContentDisposition, generateContentDisposition } from '@orpc/standard-server';
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
- const eventStream = Readable.toWeb(stream).pipeThrough(new TextDecoderStream()).pipeThrough(new EventDecoderStream());
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
- const keepAliveEnabled = options.eventIteratorKeepAliveEnabled ?? true;
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 = toArray(headers["content-disposition"])[0];
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 toAbortSignal(res) {
91
+ function toStandardMethod(method) {
92
+ return method ?? "GET";
93
+ }
94
+
95
+ function toAbortSignal(stream) {
180
96
  const controller = new AbortController();
181
- res.on("close", () => {
182
- if (res.errored) {
183
- controller.abort(res.errored.toString());
184
- } else if (!res.writableFinished) {
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 toStandardLazyRequest(req, res) {
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.on("error", reject);
210
- res.on("finish", resolve);
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(resBody);
131
+ res.end();
216
132
  } else if (typeof resBody === "string") {
217
133
  res.end(resBody);
218
134
  } else {
219
- res.on("close", () => {
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.f72e6b9",
4
+ "version": "0.0.0-next.f779f69",
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/standard-server": "0.0.0-next.f72e6b9",
27
- "@orpc/shared": "0.0.0-next.f72e6b9"
26
+ "@orpc/standard-server": "0.0.0-next.f779f69",
27
+ "@orpc/shared": "0.0.0-next.f779f69",
28
+ "@orpc/standard-server-fetch": "0.0.0-next.f779f69"
28
29
  },
29
30
  "devDependencies": {
30
- "@types/node": "^22.14.1",
31
+ "@types/node": "^22.15.18",
31
32
  "@types/supertest": "^6.0.3",
32
33
  "supertest": "^7.1.0"
33
34
  },