@orpc/standard-server-node 1.3.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
7
  declare function toEventIterator(stream: Readable): AsyncIteratorObject<unknown | void, unknown | void, void> & 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;
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
7
  declare function toEventIterator(stream: Readable): AsyncIteratorObject<unknown | void, unknown | void, void> & 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;
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,96 +1,13 @@
1
1
  import { Readable } from 'node:stream';
2
- import { createAsyncIteratorObject, parseEmptyableJSON, isTypescriptObject, stringifyJSON, isAsyncIteratorObject, once } from '@orpc/shared';
3
- import { EventDecoderStream, withEventMeta, ErrorEvent, encodeEventMessage, getEventMeta, getFilenameFromContentDisposition, flattenHeader, 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
- return createAsyncIteratorObject(async () => {
9
- while (true) {
10
- const { done, value } = await reader.read();
11
- if (done) {
12
- return { done: true, value: void 0 };
13
- }
14
- switch (value.event) {
15
- case "message": {
16
- let message = parseEmptyableJSON(value.data);
17
- if (isTypescriptObject(message)) {
18
- message = withEventMeta(message, value);
19
- }
20
- return { done: false, value: message };
21
- }
22
- case "error": {
23
- let error = new ErrorEvent({
24
- data: parseEmptyableJSON(value.data)
25
- });
26
- error = withEventMeta(error, value);
27
- throw error;
28
- }
29
- case "done": {
30
- let done2 = parseEmptyableJSON(value.data);
31
- if (isTypescriptObject(done2)) {
32
- done2 = withEventMeta(done2, value);
33
- }
34
- return { done: true, value: done2 };
35
- }
36
- }
37
- }
38
- }, async () => {
39
- await reader.cancel();
40
- });
7
+ return toEventIterator$1(Readable.toWeb(stream));
41
8
  }
42
9
  function toEventStream(iterator, options = {}) {
43
- const keepAliveEnabled = options.eventIteratorKeepAliveEnabled ?? true;
44
- const keepAliveInterval = options.eventIteratorKeepAliveInterval ?? 5e3;
45
- const keepAliveComment = options.eventIteratorKeepAliveComment ?? "";
46
- let cancelled = false;
47
- let timeout;
48
- const stream = new ReadableStream({
49
- async pull(controller) {
50
- try {
51
- if (keepAliveEnabled) {
52
- timeout = setInterval(() => {
53
- controller.enqueue(encodeEventMessage({
54
- comments: [keepAliveComment]
55
- }));
56
- }, keepAliveInterval);
57
- }
58
- const value = await iterator.next();
59
- clearInterval(timeout);
60
- if (cancelled) {
61
- return;
62
- }
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
- if (cancelled) {
77
- return;
78
- }
79
- controller.enqueue(encodeEventMessage({
80
- ...getEventMeta(err),
81
- event: "error",
82
- data: err instanceof ErrorEvent ? stringifyJSON(err.data) : void 0
83
- }));
84
- controller.close();
85
- }
86
- },
87
- async cancel() {
88
- cancelled = true;
89
- clearInterval(timeout);
90
- await iterator.return?.();
91
- }
92
- });
93
- return Readable.fromWeb(stream);
10
+ return Readable.fromWeb(toEventStream$1(iterator, options));
94
11
  }
95
12
 
96
13
  async function toStandardBody(req) {
@@ -143,8 +60,6 @@ function toNodeHttpBody(body, headers, options = {}) {
143
60
  }
144
61
  if (isAsyncIteratorObject(body)) {
145
62
  headers["content-type"] = "text/event-stream";
146
- headers["cache-control"] = "no-cache";
147
- headers.connection = "keep-alive";
148
63
  return toEventStream(body, options);
149
64
  }
150
65
  headers["content-type"] = "application/json";
@@ -173,28 +88,32 @@ async function _streamToFile(stream, fileName, contentType) {
173
88
  return new File(chunks, fileName, { type: contentType });
174
89
  }
175
90
 
176
- function toAbortSignal(res) {
91
+ function toStandardMethod(method) {
92
+ return method ?? "GET";
93
+ }
94
+
95
+ function toAbortSignal(stream) {
177
96
  const controller = new AbortController();
178
- res.on("close", () => {
179
- if (res.errored) {
180
- controller.abort(res.errored.toString());
181
- } else if (!res.writableFinished) {
182
- controller.abort("Client connection prematurely closed.");
183
- } else {
184
- 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"));
185
101
  }
186
102
  });
187
103
  return controller.signal;
188
104
  }
189
105
 
190
- function toStandardLazyRequest(req, res) {
191
- const method = req.method ?? "GET";
106
+ function toStandardUrl(req) {
192
107
  const protocol = "encrypted" in req.socket && req.socket.encrypted ? "https:" : "http:";
193
108
  const host = req.headers.host ?? "localhost";
194
109
  const url = new URL(req.originalUrl ?? req.url ?? "/", `${protocol}//${host}`);
110
+ return url;
111
+ }
112
+
113
+ function toStandardLazyRequest(req, res) {
195
114
  return {
196
- method,
197
- url,
115
+ method: toStandardMethod(req.method),
116
+ url: toStandardUrl(req),
198
117
  headers: req.headers,
199
118
  body: once(() => toStandardBody(req)),
200
119
  signal: toAbortSignal(res)
@@ -203,24 +122,25 @@ function toStandardLazyRequest(req, res) {
203
122
 
204
123
  function sendStandardResponse(res, standardResponse, options = {}) {
205
124
  return new Promise((resolve, reject) => {
206
- res.on("error", reject);
207
- res.on("finish", resolve);
125
+ res.once("error", reject);
126
+ res.once("close", resolve);
208
127
  const resHeaders = { ...standardResponse.headers };
209
128
  const resBody = toNodeHttpBody(standardResponse.body, resHeaders, options);
210
129
  res.writeHead(standardResponse.status, resHeaders);
211
130
  if (resBody === void 0) {
212
- res.end(resBody);
131
+ res.end();
213
132
  } else if (typeof resBody === "string") {
214
133
  res.end(resBody);
215
134
  } else {
216
- res.on("close", () => {
135
+ res.once("close", () => {
217
136
  if (!resBody.closed) {
218
137
  resBody.destroy(res.errored ?? void 0);
219
138
  }
220
139
  });
140
+ resBody.once("error", (error) => res.destroy(error));
221
141
  resBody.pipe(res);
222
142
  }
223
143
  });
224
144
  }
225
145
 
226
- 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": "1.3.0",
4
+ "version": "1.4.1",
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": "1.3.0",
27
- "@orpc/standard-server": "1.3.0"
26
+ "@orpc/shared": "1.4.1",
27
+ "@orpc/standard-server": "1.4.1",
28
+ "@orpc/standard-server-fetch": "1.4.1"
28
29
  },
29
30
  "devDependencies": {
30
- "@types/node": "^22.15.17",
31
+ "@types/node": "^22.15.18",
31
32
  "@types/supertest": "^6.0.3",
32
33
  "supertest": "^7.1.0"
33
34
  },