@orpc/standard-server-node 0.0.0-next.b36125c → 0.0.0-next.bf49833

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
@@ -1,5 +1,5 @@
1
1
  <div align="center">
2
- <image align="center" src="https://orpc.unnoq.com/logo.webp" width=280 />
2
+ <image align="center" src="https://orpc.unnoq.com/logo.webp" width=280 alt="oRPC logo" />
3
3
  </div>
4
4
 
5
5
  <h1></h1>
@@ -0,0 +1,56 @@
1
+ import { StandardBody, StandardHeaders, StandardLazyRequest, StandardResponse } from '@orpc/standard-server';
2
+ import { Readable } from 'node:stream';
3
+ import { IncomingMessage, ServerResponse } from 'node:http';
4
+ import { Http2ServerRequest, Http2ServerResponse } from 'node:http2';
5
+
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;
26
+ }
27
+ declare function toEventStream(iterator: AsyncIterator<unknown | void, unknown | void, void>, options?: ToEventStreamOptions): Readable;
28
+
29
+ type NodeHttpRequest = (IncomingMessage | Http2ServerRequest) & {
30
+ /**
31
+ * Replace `req.url` with `req.originalUrl` when `req.originalUrl` is available.
32
+ * This is useful for `express.js` middleware.
33
+ */
34
+ originalUrl?: string;
35
+ };
36
+ type NodeHttpResponse = ServerResponse | Http2ServerResponse;
37
+
38
+ declare function toStandardBody(req: NodeHttpRequest): Promise<StandardBody>;
39
+ interface ToNodeHttpBodyOptions extends ToEventStreamOptions {
40
+ }
41
+ /**
42
+ * @param body
43
+ * @param headers - WARNING: The headers can be changed by the function and effects on the original headers.
44
+ * @param options
45
+ */
46
+ declare function toNodeHttpBody(body: StandardBody, headers: StandardHeaders, options?: ToNodeHttpBodyOptions): Readable | undefined | string;
47
+
48
+ declare function toStandardLazyRequest(req: NodeHttpRequest, res: NodeHttpResponse): StandardLazyRequest;
49
+
50
+ interface SendStandardResponseOptions extends ToNodeHttpBodyOptions {
51
+ }
52
+ declare function sendStandardResponse(res: NodeHttpResponse, standardResponse: StandardResponse, options?: SendStandardResponseOptions): Promise<void>;
53
+
54
+ declare function toAbortSignal(res: NodeHttpResponse): AbortSignal;
55
+
56
+ export { type NodeHttpRequest, type NodeHttpResponse, type SendStandardResponseOptions, type ToEventStreamOptions, type ToNodeHttpBodyOptions, sendStandardResponse, toAbortSignal, toEventIterator, toEventStream, toNodeHttpBody, toStandardBody, toStandardLazyRequest };
@@ -0,0 +1,56 @@
1
+ import { StandardBody, StandardHeaders, StandardLazyRequest, StandardResponse } from '@orpc/standard-server';
2
+ import { Readable } from 'node:stream';
3
+ import { IncomingMessage, ServerResponse } from 'node:http';
4
+ import { Http2ServerRequest, Http2ServerResponse } from 'node:http2';
5
+
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;
26
+ }
27
+ declare function toEventStream(iterator: AsyncIterator<unknown | void, unknown | void, void>, options?: ToEventStreamOptions): Readable;
28
+
29
+ type NodeHttpRequest = (IncomingMessage | Http2ServerRequest) & {
30
+ /**
31
+ * Replace `req.url` with `req.originalUrl` when `req.originalUrl` is available.
32
+ * This is useful for `express.js` middleware.
33
+ */
34
+ originalUrl?: string;
35
+ };
36
+ type NodeHttpResponse = ServerResponse | Http2ServerResponse;
37
+
38
+ declare function toStandardBody(req: NodeHttpRequest): Promise<StandardBody>;
39
+ interface ToNodeHttpBodyOptions extends ToEventStreamOptions {
40
+ }
41
+ /**
42
+ * @param body
43
+ * @param headers - WARNING: The headers can be changed by the function and effects on the original headers.
44
+ * @param options
45
+ */
46
+ declare function toNodeHttpBody(body: StandardBody, headers: StandardHeaders, options?: ToNodeHttpBodyOptions): Readable | undefined | string;
47
+
48
+ declare function toStandardLazyRequest(req: NodeHttpRequest, res: NodeHttpResponse): StandardLazyRequest;
49
+
50
+ interface SendStandardResponseOptions extends ToNodeHttpBodyOptions {
51
+ }
52
+ declare function sendStandardResponse(res: NodeHttpResponse, standardResponse: StandardResponse, options?: SendStandardResponseOptions): Promise<void>;
53
+
54
+ declare function toAbortSignal(res: NodeHttpResponse): AbortSignal;
55
+
56
+ export { type NodeHttpRequest, type NodeHttpResponse, type SendStandardResponseOptions, type ToEventStreamOptions, type ToNodeHttpBodyOptions, sendStandardResponse, toAbortSignal, toEventIterator, toEventStream, toNodeHttpBody, toStandardBody, toStandardLazyRequest };
@@ -1,18 +1,7 @@
1
- // src/body.ts
2
- import { Readable as Readable2 } from "node:stream";
3
- import { isAsyncIteratorObject, parseEmptyableJSON as parseEmptyableJSON2, stringifyJSON as stringifyJSON2 } from "@orpc/shared";
4
- import { contentDisposition, parseContentDisposition } from "@orpc/standard-server";
1
+ import { Readable } from 'node:stream';
2
+ import { stringifyJSON, parseEmptyableJSON, isTypescriptObject, isAsyncIteratorObject, once } from '@orpc/shared';
3
+ import { EventDecoderStream, encodeEventMessage, getEventMeta, ErrorEvent, withEventMeta, parseContentDisposition, contentDisposition } from '@orpc/standard-server';
5
4
 
6
- // src/event-source.ts
7
- import { Readable } from "node:stream";
8
- import { isTypescriptObject, parseEmptyableJSON, stringifyJSON } from "@orpc/shared";
9
- import {
10
- encodeEventMessage,
11
- ErrorEvent,
12
- EventDecoderStream,
13
- getEventMeta,
14
- withEventMeta
15
- } from "@orpc/standard-server";
16
5
  function toEventIterator(stream) {
17
6
  const eventStream = Readable.toWeb(stream).pipeThrough(new TextDecoderStream()).pipeThrough(new EventDecoderStream());
18
7
  const reader = eventStream.getReader();
@@ -54,11 +43,23 @@ function toEventIterator(stream) {
54
43
  }
55
44
  return gen();
56
45
  }
57
- function toEventStream(iterator) {
46
+ function toEventStream(iterator, options = {}) {
47
+ const keepAliveEnabled = options.eventIteratorKeepAliveEnabled ?? true;
48
+ const keepAliveInterval = options.eventIteratorKeepAliveInterval ?? 5e3;
49
+ const keepAliveComment = options.eventIteratorKeepAliveComment ?? "";
50
+ let timeout;
58
51
  const stream = new ReadableStream({
59
52
  async pull(controller) {
60
53
  try {
54
+ if (keepAliveEnabled) {
55
+ timeout = setInterval(() => {
56
+ controller.enqueue(encodeEventMessage({
57
+ comments: [keepAliveComment]
58
+ }));
59
+ }, keepAliveInterval);
60
+ }
61
61
  const value = await iterator.next();
62
+ clearInterval(timeout);
62
63
  controller.enqueue(encodeEventMessage({
63
64
  ...getEventMeta(value.value),
64
65
  event: value.done ? "done" : "message",
@@ -68,6 +69,7 @@ function toEventStream(iterator) {
68
69
  controller.close();
69
70
  }
70
71
  } catch (err) {
72
+ clearInterval(timeout);
71
73
  controller.enqueue(encodeEventMessage({
72
74
  ...getEventMeta(err),
73
75
  event: "error",
@@ -87,7 +89,6 @@ function toEventStream(iterator) {
87
89
  return Readable.fromWeb(stream);
88
90
  }
89
91
 
90
- // src/body.ts
91
92
  async function toStandardBody(req) {
92
93
  const method = req.method ?? "GET";
93
94
  if (method === "GET" || method === "HEAD") {
@@ -103,7 +104,7 @@ async function toStandardBody(req) {
103
104
  }
104
105
  if (!contentType || contentType.startsWith("application/json")) {
105
106
  const text = await _streamToString(req);
106
- return parseEmptyableJSON2(text);
107
+ return parseEmptyableJSON(text);
107
108
  }
108
109
  if (contentType.startsWith("multipart/form-data")) {
109
110
  return _streamToFormData(req, contentType);
@@ -120,7 +121,7 @@ async function toStandardBody(req) {
120
121
  }
121
122
  return _streamToFile(req, "blob", contentType);
122
123
  }
123
- function toNodeHttpBody(body, headers) {
124
+ function toNodeHttpBody(body, headers, options = {}) {
124
125
  delete headers["content-type"];
125
126
  delete headers["content-disposition"];
126
127
  if (body === void 0) {
@@ -133,12 +134,12 @@ function toNodeHttpBody(body, headers) {
133
134
  body instanceof File ? body.name : "blob",
134
135
  { type: "inline" }
135
136
  );
136
- return Readable2.fromWeb(body.stream());
137
+ return Readable.fromWeb(body.stream());
137
138
  }
138
139
  if (body instanceof FormData) {
139
140
  const response = new Response(body);
140
141
  headers["content-type"] = response.headers.get("content-type");
141
- return Readable2.fromWeb(response.body);
142
+ return Readable.fromWeb(response.body);
142
143
  }
143
144
  if (body instanceof URLSearchParams) {
144
145
  headers["content-type"] = "application/x-www-form-urlencoded";
@@ -148,10 +149,10 @@ function toNodeHttpBody(body, headers) {
148
149
  headers["content-type"] = "text/event-stream";
149
150
  headers["cache-control"] = "no-cache";
150
151
  headers.connection = "keep-alive";
151
- return toEventStream(body);
152
+ return toEventStream(body, options);
152
153
  }
153
154
  headers["content-type"] = "application/json";
154
- return stringifyJSON2(body);
155
+ return stringifyJSON(body);
155
156
  }
156
157
  function _streamToFormData(stream, contentType) {
157
158
  const response = new Response(stream, {
@@ -176,10 +177,6 @@ async function _streamToFile(stream, fileName, contentType) {
176
177
  return new File(chunks, fileName, { type: contentType });
177
178
  }
178
179
 
179
- // src/request.ts
180
- import { once } from "@orpc/shared";
181
-
182
- // src/signal.ts
183
180
  function toAbortSignal(res) {
184
181
  const controller = new AbortController();
185
182
  res.on("close", () => {
@@ -194,8 +191,7 @@ function toAbortSignal(res) {
194
191
  return controller.signal;
195
192
  }
196
193
 
197
- // src/request.ts
198
- function toStandardRequest(req, res) {
194
+ function toStandardLazyRequest(req, res) {
199
195
  const method = req.method ?? "GET";
200
196
  const protocol = "encrypted" in req.socket && req.socket.encrypted ? "https:" : "http:";
201
197
  const host = req.headers.host ?? "localhost";
@@ -210,13 +206,12 @@ function toStandardRequest(req, res) {
210
206
  };
211
207
  }
212
208
 
213
- // src/response.ts
214
- function sendStandardResponse(res, standardResponse) {
209
+ function sendStandardResponse(res, standardResponse, options = {}) {
215
210
  return new Promise((resolve, reject) => {
216
211
  res.on("error", reject);
217
212
  res.on("finish", resolve);
218
213
  const resHeaders = standardResponse.headers;
219
- const resBody = toNodeHttpBody(standardResponse.body, resHeaders);
214
+ const resBody = toNodeHttpBody(standardResponse.body, resHeaders, options);
220
215
  res.writeHead(standardResponse.status, resHeaders);
221
216
  if (resBody === void 0) {
222
217
  res.end(resBody);
@@ -232,13 +227,5 @@ function sendStandardResponse(res, standardResponse) {
232
227
  }
233
228
  });
234
229
  }
235
- export {
236
- sendStandardResponse,
237
- toAbortSignal,
238
- toEventIterator,
239
- toEventStream,
240
- toNodeHttpBody,
241
- toStandardBody,
242
- toStandardRequest
243
- };
244
- //# sourceMappingURL=index.js.map
230
+
231
+ export { sendStandardResponse, toAbortSignal, toEventIterator, toEventStream, toNodeHttpBody, toStandardBody, toStandardLazyRequest };
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.b36125c",
4
+ "version": "0.0.0-next.bf49833",
5
5
  "license": "MIT",
6
6
  "homepage": "https://orpc.unnoq.com",
7
7
  "repository": {
@@ -14,22 +14,17 @@
14
14
  ],
15
15
  "exports": {
16
16
  ".": {
17
- "types": "./dist/src/index.d.ts",
18
- "import": "./dist/index.js",
19
- "default": "./dist/index.js"
20
- },
21
- "./🔒/*": {
22
- "types": "./dist/src/*.d.ts"
17
+ "types": "./dist/index.d.mts",
18
+ "import": "./dist/index.mjs",
19
+ "default": "./dist/index.mjs"
23
20
  }
24
21
  },
25
22
  "files": [
26
- "!**/*.map",
27
- "!**/*.tsbuildinfo",
28
23
  "dist"
29
24
  ],
30
25
  "dependencies": {
31
- "@orpc/shared": "0.0.0-next.b36125c",
32
- "@orpc/standard-server": "0.0.0-next.b36125c"
26
+ "@orpc/shared": "0.0.0-next.bf49833",
27
+ "@orpc/standard-server": "0.0.0-next.bf49833"
33
28
  },
34
29
  "devDependencies": {
35
30
  "@types/node": "^22.13.1",
@@ -37,7 +32,7 @@
37
32
  "supertest": "^7.0.0"
38
33
  },
39
34
  "scripts": {
40
- "build": "tsup --clean --sourcemap --entry.index=src/index.ts --format=esm --onSuccess='tsc -b --noCheck'",
35
+ "build": "unbuild",
41
36
  "build:watch": "pnpm run build --watch",
42
37
  "type:check": "tsc -b"
43
38
  }
@@ -1,10 +0,0 @@
1
- import type { StandardBody, StandardHeaders } from '@orpc/standard-server';
2
- import type { NodeHttpRequest } from './types';
3
- import { Readable } from 'node:stream';
4
- export declare function toStandardBody(req: NodeHttpRequest): Promise<StandardBody>;
5
- /**
6
- * @param body
7
- * @param headers - The headers can be changed by the function and effects on the original headers.
8
- */
9
- export declare function toNodeHttpBody(body: StandardBody, headers: StandardHeaders): Readable | undefined | string;
10
- //# sourceMappingURL=body.d.ts.map
@@ -1,4 +0,0 @@
1
- import { Readable } from 'node:stream';
2
- export declare function toEventIterator(stream: Readable): AsyncGenerator<unknown | void, unknown | void, void>;
3
- export declare function toEventStream(iterator: AsyncIterator<unknown | void, unknown | void, void>): Readable;
4
- //# sourceMappingURL=event-source.d.ts.map
@@ -1,7 +0,0 @@
1
- export * from './body';
2
- export * from './event-source';
3
- export * from './request';
4
- export * from './response';
5
- export * from './signal';
6
- export * from './types';
7
- //# sourceMappingURL=index.d.ts.map
@@ -1,4 +0,0 @@
1
- import type { StandardRequest } from '@orpc/standard-server';
2
- import type { NodeHttpRequest, NodeHttpResponse } from './types';
3
- export declare function toStandardRequest(req: NodeHttpRequest, res: NodeHttpResponse): StandardRequest;
4
- //# sourceMappingURL=request.d.ts.map
@@ -1,4 +0,0 @@
1
- import type { StandardResponse } from '@orpc/standard-server';
2
- import type { NodeHttpResponse } from './types';
3
- export declare function sendStandardResponse(res: NodeHttpResponse, standardResponse: StandardResponse): Promise<void>;
4
- //# sourceMappingURL=response.d.ts.map
@@ -1,3 +0,0 @@
1
- import type { NodeHttpResponse } from './types';
2
- export declare function toAbortSignal(res: NodeHttpResponse): AbortSignal;
3
- //# sourceMappingURL=signal.d.ts.map
@@ -1,11 +0,0 @@
1
- import type { IncomingMessage, ServerResponse } from 'node:http';
2
- import type { Http2ServerRequest, Http2ServerResponse } from 'node:http2';
3
- export type NodeHttpRequest = (IncomingMessage | Http2ServerRequest) & {
4
- /**
5
- * Replace `req.url` with `req.originalUrl` when `req.originalUrl` is available.
6
- * This is useful for `express.js` middleware.
7
- */
8
- originalUrl?: string;
9
- };
10
- export type NodeHttpResponse = ServerResponse | Http2ServerResponse;
11
- //# sourceMappingURL=types.d.ts.map