@react-router/node 0.0.0-experimental-f7761f1cd → 0.0.0-experimental-63fd291ad

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.
@@ -0,0 +1,48 @@
1
+ import { RequestListener } from 'node:http';
2
+ import { ServerBuild, UNSAFE_MiddlewareEnabled, RouterContextProvider, AppLoadContext, SessionData, SessionIdStorageStrategy, SessionStorage } from 'react-router';
3
+ import { ClientAddress } from '@mjackson/node-fetch-server';
4
+ import { Readable, Writable } from 'node:stream';
5
+
6
+ type MaybePromise<T> = T | Promise<T>;
7
+ interface RequestListenerOptions {
8
+ build: ServerBuild | (() => ServerBuild | Promise<ServerBuild>);
9
+ getLoadContext?: (request: Request, client: ClientAddress) => UNSAFE_MiddlewareEnabled extends true ? MaybePromise<RouterContextProvider> : MaybePromise<AppLoadContext>;
10
+ mode?: string;
11
+ }
12
+ /**
13
+ * Creates a request listener that handles requests using Node's built-in HTTP server.
14
+ *
15
+ * @param options Options for creating a request listener.
16
+ * @returns A request listener that can be used with `http.createServer`.
17
+ */
18
+ declare function createRequestListener(options: RequestListenerOptions): RequestListener;
19
+
20
+ interface FileSessionStorageOptions {
21
+ /**
22
+ * The Cookie used to store the session id on the client, or options used
23
+ * to automatically create one.
24
+ */
25
+ cookie?: SessionIdStorageStrategy["cookie"];
26
+ /**
27
+ * The directory to use to store session files.
28
+ */
29
+ dir: string;
30
+ }
31
+ /**
32
+ * Creates a SessionStorage that stores session data on a filesystem.
33
+ *
34
+ * The advantage of using this instead of cookie session storage is that
35
+ * files may contain much more data than cookies.
36
+ *
37
+ * @see https://api.reactrouter.com/v7/functions/_react-router_node.createFileSessionStorage
38
+ */
39
+ declare function createFileSessionStorage<Data = SessionData, FlashData = Data>({ cookie, dir, }: FileSessionStorageOptions): SessionStorage<Data, FlashData>;
40
+
41
+ declare function writeReadableStreamToWritable(stream: ReadableStream, writable: Writable): Promise<void>;
42
+ declare function writeAsyncIterableToWritable(iterable: AsyncIterable<Uint8Array>, writable: Writable): Promise<void>;
43
+ declare function readableStreamToString(stream: ReadableStream<Uint8Array>, encoding?: BufferEncoding): Promise<string>;
44
+ declare const createReadableStreamFromReadable: (source: Readable & {
45
+ readableHighWaterMark?: number;
46
+ }) => ReadableStream<Uint8Array>;
47
+
48
+ export { type RequestListenerOptions, createFileSessionStorage, createReadableStreamFromReadable, createRequestListener, readableStreamToString, writeAsyncIterableToWritable, writeReadableStreamToWritable };
package/dist/index.d.ts CHANGED
@@ -1,15 +1,13 @@
1
+ import { RequestListener } from 'node:http';
2
+ import { ServerBuild, UNSAFE_MiddlewareEnabled, RouterContextProvider, AppLoadContext, SessionData, SessionIdStorageStrategy, SessionStorage } from 'react-router';
3
+ import { ClientAddress } from '@mjackson/node-fetch-server';
4
+ import { Readable, Writable } from 'node:stream';
1
5
 
2
- import { ClientAddress } from "@remix-run/node-fetch-server";
3
- import { RouterContextProvider, ServerBuild, SessionData, SessionIdStorageStrategy, SessionStorage } from "react-router";
4
- import { Readable, Writable } from "node:stream";
5
- import { RequestListener } from "node:http";
6
-
7
- //#region server.d.ts
8
6
  type MaybePromise<T> = T | Promise<T>;
9
7
  interface RequestListenerOptions {
10
- build: ServerBuild | (() => ServerBuild | Promise<ServerBuild>);
11
- getLoadContext?: (request: Request, client: ClientAddress) => MaybePromise<RouterContextProvider>;
12
- mode?: string;
8
+ build: ServerBuild | (() => ServerBuild | Promise<ServerBuild>);
9
+ getLoadContext?: (request: Request, client: ClientAddress) => UNSAFE_MiddlewareEnabled extends true ? MaybePromise<RouterContextProvider> : MaybePromise<AppLoadContext>;
10
+ mode?: string;
13
11
  }
14
12
  /**
15
13
  * Creates a request listener that handles requests using Node's built-in HTTP server.
@@ -18,18 +16,17 @@ interface RequestListenerOptions {
18
16
  * @returns A request listener that can be used with `http.createServer`.
19
17
  */
20
18
  declare function createRequestListener(options: RequestListenerOptions): RequestListener;
21
- //#endregion
22
- //#region sessions/fileStorage.d.ts
19
+
23
20
  interface FileSessionStorageOptions {
24
- /**
25
- * The Cookie used to store the session id on the client, or options used
26
- * to automatically create one.
27
- */
28
- cookie?: SessionIdStorageStrategy["cookie"];
29
- /**
30
- * The directory to use to store session files.
31
- */
32
- dir: string;
21
+ /**
22
+ * The Cookie used to store the session id on the client, or options used
23
+ * to automatically create one.
24
+ */
25
+ cookie?: SessionIdStorageStrategy["cookie"];
26
+ /**
27
+ * The directory to use to store session files.
28
+ */
29
+ dir: string;
33
30
  }
34
31
  /**
35
32
  * Creates a SessionStorage that stores session data on a filesystem.
@@ -39,17 +36,13 @@ interface FileSessionStorageOptions {
39
36
  *
40
37
  * @see https://api.reactrouter.com/v7/functions/_react-router_node.createFileSessionStorage
41
38
  */
42
- declare function createFileSessionStorage<Data = SessionData, FlashData = Data>({
43
- cookie,
44
- dir
45
- }: FileSessionStorageOptions): SessionStorage<Data, FlashData>;
46
- //#endregion
47
- //#region stream.d.ts
39
+ declare function createFileSessionStorage<Data = SessionData, FlashData = Data>({ cookie, dir, }: FileSessionStorageOptions): SessionStorage<Data, FlashData>;
40
+
48
41
  declare function writeReadableStreamToWritable(stream: ReadableStream, writable: Writable): Promise<void>;
49
42
  declare function writeAsyncIterableToWritable(iterable: AsyncIterable<Uint8Array>, writable: Writable): Promise<void>;
50
43
  declare function readableStreamToString(stream: ReadableStream<Uint8Array>, encoding?: BufferEncoding): Promise<string>;
51
44
  declare const createReadableStreamFromReadable: (source: Readable & {
52
- readableHighWaterMark?: number;
53
- }) => ReadableStream<Uint8Array<ArrayBufferLike>>;
54
- //#endregion
55
- export { type RequestListenerOptions, createFileSessionStorage, createReadableStreamFromReadable, createRequestListener, readableStreamToString, writeAsyncIterableToWritable, writeReadableStreamToWritable };
45
+ readableHighWaterMark?: number;
46
+ }) => ReadableStream<Uint8Array>;
47
+
48
+ export { type RequestListenerOptions, createFileSessionStorage, createReadableStreamFromReadable, createRequestListener, readableStreamToString, writeAsyncIterableToWritable, writeReadableStreamToWritable };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @react-router/node v0.0.0-experimental-f7761f1cd
2
+ * @react-router/node v0.0.0-experimental-63fd291ad
3
3
  *
4
4
  * Copyright (c) Remix Software Inc.
5
5
  *
@@ -8,286 +8,371 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- import { createRequestListener as createRequestListener$1 } from "@remix-run/node-fetch-server";
12
- import { createRequestHandler, createSessionStorage } from "react-router";
13
- import { promises } from "node:fs";
14
- import * as path from "node:path";
15
- import { Stream } from "node:stream";
16
- //#region server.ts
17
- /**
18
- * Creates a request listener that handles requests using Node's built-in HTTP server.
19
- *
20
- * @param options Options for creating a request listener.
21
- * @returns A request listener that can be used with `http.createServer`.
22
- */
11
+ "use strict";
12
+ var __create = Object.create;
13
+ var __defProp = Object.defineProperty;
14
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
15
+ var __getOwnPropNames = Object.getOwnPropertyNames;
16
+ var __getProtoOf = Object.getPrototypeOf;
17
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
18
+ var __export = (target, all) => {
19
+ for (var name in all)
20
+ __defProp(target, name, { get: all[name], enumerable: true });
21
+ };
22
+ var __copyProps = (to, from, except, desc) => {
23
+ if (from && typeof from === "object" || typeof from === "function") {
24
+ for (let key of __getOwnPropNames(from))
25
+ if (!__hasOwnProp.call(to, key) && key !== except)
26
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
27
+ }
28
+ return to;
29
+ };
30
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
31
+ // If the importer is in node compatibility mode or this is not an ESM
32
+ // file that has been converted to a CommonJS file using a Babel-
33
+ // compatible transform (i.e. "__esModule" has not been set), then set
34
+ // "default" to the CommonJS "module.exports" for node compatibility.
35
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
36
+ mod
37
+ ));
38
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
39
+
40
+ // index.ts
41
+ var index_exports = {};
42
+ __export(index_exports, {
43
+ createFileSessionStorage: () => createFileSessionStorage,
44
+ createReadableStreamFromReadable: () => createReadableStreamFromReadable,
45
+ createRequestListener: () => createRequestListener,
46
+ readableStreamToString: () => readableStreamToString,
47
+ writeAsyncIterableToWritable: () => writeAsyncIterableToWritable,
48
+ writeReadableStreamToWritable: () => writeReadableStreamToWritable
49
+ });
50
+ module.exports = __toCommonJS(index_exports);
51
+
52
+ // server.ts
53
+ var import_react_router = require("react-router");
54
+ var import_node_fetch_server = require("@mjackson/node-fetch-server");
23
55
  function createRequestListener(options) {
24
- let handleRequest = createRequestHandler(options.build, options.mode);
25
- return createRequestListener$1(async (request, client) => {
26
- return handleRequest(request, await options.getLoadContext?.(request, client));
27
- });
56
+ let handleRequest = (0, import_react_router.createRequestHandler)(options.build, options.mode);
57
+ return (0, import_node_fetch_server.createRequestListener)(async (request, client) => {
58
+ let loadContext = await options.getLoadContext?.(request, client);
59
+ return handleRequest(request, loadContext);
60
+ });
28
61
  }
29
- //#endregion
30
- //#region sessions/fileStorage.ts
31
- /**
32
- * Creates a SessionStorage that stores session data on a filesystem.
33
- *
34
- * The advantage of using this instead of cookie session storage is that
35
- * files may contain much more data than cookies.
36
- *
37
- * @see https://api.reactrouter.com/v7/functions/_react-router_node.createFileSessionStorage
38
- */
39
- function createFileSessionStorage({ cookie, dir }) {
40
- return createSessionStorage({
41
- cookie,
42
- async createData(data, expires) {
43
- let content = JSON.stringify({
44
- data,
45
- expires
46
- });
47
- while (true) {
48
- let randomBytes = crypto.getRandomValues(new Uint8Array(8));
49
- let id = Buffer.from(randomBytes).toString("hex");
50
- try {
51
- let file = getFile(dir, id);
52
- if (!file) throw new Error("Error generating session");
53
- await promises.mkdir(path.dirname(file), { recursive: true });
54
- await promises.writeFile(file, content, {
55
- encoding: "utf-8",
56
- flag: "wx"
57
- });
58
- return id;
59
- } catch (error) {
60
- if (error.code !== "EEXIST") throw error;
61
- }
62
- }
63
- },
64
- async readData(id) {
65
- try {
66
- let file = getFile(dir, id);
67
- if (!file) return null;
68
- let content = JSON.parse(await promises.readFile(file, "utf-8"));
69
- let data = content.data;
70
- let expires = typeof content.expires === "string" ? new Date(content.expires) : null;
71
- if (!expires || expires > /* @__PURE__ */ new Date()) return data;
72
- if (expires) await promises.unlink(file);
73
- return null;
74
- } catch (error) {
75
- if (error.code !== "ENOENT") throw error;
76
- return null;
77
- }
78
- },
79
- async updateData(id, data, expires) {
80
- let content = JSON.stringify({
81
- data,
82
- expires
83
- });
84
- let file = getFile(dir, id);
85
- if (!file) return;
86
- await promises.mkdir(path.dirname(file), { recursive: true });
87
- await promises.writeFile(file, content, "utf-8");
88
- },
89
- async deleteData(id) {
90
- if (!id) return;
91
- let file = getFile(dir, id);
92
- if (!file) return;
93
- try {
94
- await promises.unlink(file);
95
- } catch (error) {
96
- if (error.code !== "ENOENT") throw error;
97
- }
98
- }
99
- });
62
+
63
+ // sessions/fileStorage.ts
64
+ var import_node_fs = require("fs");
65
+ var path = __toESM(require("path"));
66
+ var import_react_router2 = require("react-router");
67
+ function createFileSessionStorage({
68
+ cookie,
69
+ dir
70
+ }) {
71
+ return (0, import_react_router2.createSessionStorage)({
72
+ cookie,
73
+ async createData(data, expires) {
74
+ let content = JSON.stringify({ data, expires });
75
+ while (true) {
76
+ let randomBytes = crypto.getRandomValues(new Uint8Array(8));
77
+ let id = Buffer.from(randomBytes).toString("hex");
78
+ try {
79
+ let file = getFile(dir, id);
80
+ if (!file) {
81
+ throw new Error("Error generating session");
82
+ }
83
+ await import_node_fs.promises.mkdir(path.dirname(file), { recursive: true });
84
+ await import_node_fs.promises.writeFile(file, content, { encoding: "utf-8", flag: "wx" });
85
+ return id;
86
+ } catch (error) {
87
+ if (error.code !== "EEXIST") throw error;
88
+ }
89
+ }
90
+ },
91
+ async readData(id) {
92
+ try {
93
+ let file = getFile(dir, id);
94
+ if (!file) {
95
+ return null;
96
+ }
97
+ let content = JSON.parse(await import_node_fs.promises.readFile(file, "utf-8"));
98
+ let data = content.data;
99
+ let expires = typeof content.expires === "string" ? new Date(content.expires) : null;
100
+ if (!expires || expires > /* @__PURE__ */ new Date()) {
101
+ return data;
102
+ }
103
+ if (expires) await import_node_fs.promises.unlink(file);
104
+ return null;
105
+ } catch (error) {
106
+ if (error.code !== "ENOENT") throw error;
107
+ return null;
108
+ }
109
+ },
110
+ async updateData(id, data, expires) {
111
+ let content = JSON.stringify({ data, expires });
112
+ let file = getFile(dir, id);
113
+ if (!file) {
114
+ return;
115
+ }
116
+ await import_node_fs.promises.mkdir(path.dirname(file), { recursive: true });
117
+ await import_node_fs.promises.writeFile(file, content, "utf-8");
118
+ },
119
+ async deleteData(id) {
120
+ if (!id) {
121
+ return;
122
+ }
123
+ let file = getFile(dir, id);
124
+ if (!file) {
125
+ return;
126
+ }
127
+ try {
128
+ await import_node_fs.promises.unlink(file);
129
+ } catch (error) {
130
+ if (error.code !== "ENOENT") throw error;
131
+ }
132
+ }
133
+ });
100
134
  }
101
135
  function getFile(dir, id) {
102
- if (!/^[0-9a-f]{16}$/i.test(id)) return null;
103
- return path.join(dir, id.slice(0, 4), id.slice(4));
136
+ if (!/^[0-9a-f]{16}$/i.test(id)) {
137
+ return null;
138
+ }
139
+ return path.join(dir, id.slice(0, 4), id.slice(4));
104
140
  }
105
- //#endregion
106
- //#region stream.ts
141
+
142
+ // stream.ts
143
+ var import_node_stream = require("stream");
107
144
  async function writeReadableStreamToWritable(stream, writable) {
108
- let reader = stream.getReader();
109
- let flushable = writable;
110
- let writableError = monitorWritableError(writable);
111
- try {
112
- while (true) {
113
- writableError.throwIfClosed();
114
- let { done, value } = await writableError.race(reader.read());
115
- if (done) {
116
- writable.end();
117
- break;
118
- }
119
- writableError.throwIfClosed();
120
- let canContinueWriting = writable.write(value);
121
- if (typeof flushable.flush === "function") flushable.flush();
122
- if (!canContinueWriting) await waitForDrain(writable, writableError);
123
- }
124
- } catch (error) {
125
- try {
126
- reader.cancel(error).catch(() => {});
127
- } catch {}
128
- writable.destroy(error);
129
- throw error;
130
- } finally {
131
- writableError.cleanup();
132
- try {
133
- reader.releaseLock();
134
- } catch {}
135
- }
145
+ let reader = stream.getReader();
146
+ let flushable = writable;
147
+ let writableError = monitorWritableError(writable);
148
+ try {
149
+ while (true) {
150
+ writableError.throwIfClosed();
151
+ let { done, value } = await writableError.race(reader.read());
152
+ if (done) {
153
+ writable.end();
154
+ break;
155
+ }
156
+ writableError.throwIfClosed();
157
+ let canContinueWriting = writable.write(value);
158
+ if (typeof flushable.flush === "function") {
159
+ flushable.flush();
160
+ }
161
+ if (!canContinueWriting) {
162
+ await waitForDrain(writable, writableError);
163
+ }
164
+ }
165
+ } catch (error) {
166
+ try {
167
+ reader.cancel(error).catch(() => {
168
+ });
169
+ } catch {
170
+ }
171
+ writable.destroy(error);
172
+ throw error;
173
+ } finally {
174
+ writableError.cleanup();
175
+ try {
176
+ reader.releaseLock();
177
+ } catch {
178
+ }
179
+ }
136
180
  }
137
181
  function monitorWritableError(writable) {
138
- let settled = false;
139
- let writableError;
140
- let rejectWritableError;
141
- let writableErrorPromise = new Promise((_, reject) => {
142
- rejectWritableError = reject;
143
- });
144
- writableErrorPromise.catch(() => {});
145
- function cleanup() {
146
- writable.off("error", onError);
147
- writable.off("close", onClose);
148
- }
149
- function reject(error) {
150
- if (settled) return;
151
- settled = true;
152
- writableError = error;
153
- cleanup();
154
- rejectWritableError(error);
155
- }
156
- function onError(error) {
157
- reject(error);
158
- }
159
- function onClose() {
160
- reject(/* @__PURE__ */ new Error("Writable closed before stream finished"));
161
- }
162
- writable.once("error", onError);
163
- writable.once("close", onClose);
164
- return {
165
- cleanup,
166
- race(promise) {
167
- return Promise.race([promise, writableErrorPromise]);
168
- },
169
- throwIfClosed() {
170
- if (writableError) throw writableError;
171
- if (writable.destroyed || writable.writableEnded) throw new Error("Cannot write to a destroyed or ended writable stream");
172
- }
173
- };
182
+ let settled = false;
183
+ let writableError;
184
+ let rejectWritableError;
185
+ let writableErrorPromise = new Promise((_, reject2) => {
186
+ rejectWritableError = reject2;
187
+ });
188
+ writableErrorPromise.catch(() => {
189
+ });
190
+ function cleanup() {
191
+ writable.off("error", onError);
192
+ writable.off("close", onClose);
193
+ }
194
+ function reject(error) {
195
+ if (settled) {
196
+ return;
197
+ }
198
+ settled = true;
199
+ writableError = error;
200
+ cleanup();
201
+ rejectWritableError(error);
202
+ }
203
+ function onError(error) {
204
+ reject(error);
205
+ }
206
+ function onClose() {
207
+ reject(new Error("Writable closed before stream finished"));
208
+ }
209
+ writable.once("error", onError);
210
+ writable.once("close", onClose);
211
+ return {
212
+ cleanup,
213
+ race(promise) {
214
+ return Promise.race([promise, writableErrorPromise]);
215
+ },
216
+ throwIfClosed() {
217
+ if (writableError) {
218
+ throw writableError;
219
+ }
220
+ if (writable.destroyed || writable.writableEnded) {
221
+ throw new Error("Cannot write to a destroyed or ended writable stream");
222
+ }
223
+ }
224
+ };
174
225
  }
175
226
  function waitForDrain(writable, writableError) {
176
- let cleanup = () => {};
177
- let drainPromise = new Promise((resolve) => {
178
- function onDrain() {
179
- cleanup();
180
- resolve();
181
- }
182
- cleanup = function cleanup() {
183
- writable.off("drain", onDrain);
184
- };
185
- writable.once("drain", onDrain);
186
- });
187
- return writableError.race(drainPromise).finally(cleanup);
227
+ let cleanup = () => {
228
+ };
229
+ let drainPromise = new Promise((resolve) => {
230
+ function onDrain() {
231
+ cleanup();
232
+ resolve();
233
+ }
234
+ cleanup = function cleanup2() {
235
+ writable.off("drain", onDrain);
236
+ };
237
+ writable.once("drain", onDrain);
238
+ });
239
+ return writableError.race(drainPromise).finally(cleanup);
188
240
  }
189
241
  async function writeAsyncIterableToWritable(iterable, writable) {
190
- let writableError = monitorWritableError(writable);
191
- let iterator = iterable[Symbol.asyncIterator]();
192
- let completed = false;
193
- try {
194
- while (true) {
195
- writableError.throwIfClosed();
196
- let { done, value: chunk } = await writableError.race(iterator.next());
197
- if (done) {
198
- completed = true;
199
- break;
200
- }
201
- writableError.throwIfClosed();
202
- if (!writable.write(chunk)) await waitForDrain(writable, writableError);
203
- }
204
- writable.end();
205
- } catch (error) {
206
- if (!completed) try {
207
- Promise.resolve(iterator.return?.()).catch(() => {});
208
- } catch {}
209
- writable.destroy(error);
210
- throw error;
211
- } finally {
212
- writableError.cleanup();
213
- }
242
+ let writableError = monitorWritableError(writable);
243
+ let iterator = iterable[Symbol.asyncIterator]();
244
+ let completed = false;
245
+ try {
246
+ while (true) {
247
+ writableError.throwIfClosed();
248
+ let { done, value: chunk } = await writableError.race(iterator.next());
249
+ if (done) {
250
+ completed = true;
251
+ break;
252
+ }
253
+ writableError.throwIfClosed();
254
+ let canContinueWriting = writable.write(chunk);
255
+ if (!canContinueWriting) {
256
+ await waitForDrain(writable, writableError);
257
+ }
258
+ }
259
+ writable.end();
260
+ } catch (error) {
261
+ if (!completed) {
262
+ try {
263
+ Promise.resolve(iterator.return?.()).catch(() => {
264
+ });
265
+ } catch {
266
+ }
267
+ }
268
+ writable.destroy(error);
269
+ throw error;
270
+ } finally {
271
+ writableError.cleanup();
272
+ }
214
273
  }
215
274
  async function readableStreamToString(stream, encoding) {
216
- let reader = stream.getReader();
217
- let chunks = [];
218
- while (true) {
219
- let { done, value } = await reader.read();
220
- if (done) break;
221
- if (value) chunks.push(value);
222
- }
223
- return Buffer.concat(chunks).toString(encoding);
275
+ let reader = stream.getReader();
276
+ let chunks = [];
277
+ while (true) {
278
+ let { done, value } = await reader.read();
279
+ if (done) {
280
+ break;
281
+ }
282
+ if (value) {
283
+ chunks.push(value);
284
+ }
285
+ }
286
+ return Buffer.concat(chunks).toString(encoding);
224
287
  }
225
- const createReadableStreamFromReadable = (source) => {
226
- let pump = new StreamPump(source);
227
- return new ReadableStream(pump, pump);
288
+ var createReadableStreamFromReadable = (source) => {
289
+ let pump = new StreamPump(source);
290
+ let stream = new ReadableStream(pump, pump);
291
+ return stream;
228
292
  };
229
293
  var StreamPump = class {
230
- highWaterMark;
231
- accumulatedSize;
232
- stream;
233
- controller;
234
- constructor(stream) {
235
- this.highWaterMark = stream.readableHighWaterMark || new Stream.Readable().readableHighWaterMark;
236
- this.accumulatedSize = 0;
237
- this.stream = stream;
238
- this.enqueue = this.enqueue.bind(this);
239
- this.error = this.error.bind(this);
240
- this.close = this.close.bind(this);
241
- }
242
- size(chunk) {
243
- return chunk?.byteLength || 0;
244
- }
245
- start(controller) {
246
- this.controller = controller;
247
- this.stream.on("data", this.enqueue);
248
- this.stream.once("error", this.error);
249
- this.stream.once("end", this.close);
250
- this.stream.once("close", this.close);
251
- }
252
- pull() {
253
- this.resume();
254
- }
255
- cancel(reason) {
256
- if (this.stream.destroy) this.stream.destroy(reason);
257
- this.stream.off("data", this.enqueue);
258
- this.stream.off("error", this.error);
259
- this.stream.off("end", this.close);
260
- this.stream.off("close", this.close);
261
- }
262
- enqueue(chunk) {
263
- if (this.controller) try {
264
- let bytes = typeof chunk === "string" ? Buffer.from(chunk) : new Uint8Array(chunk);
265
- let available = (this.controller.desiredSize || 0) - bytes.byteLength;
266
- this.controller.enqueue(bytes);
267
- if (available <= 0) this.pause();
268
- } catch (e) {
269
- this.controller.error(/* @__PURE__ */ new Error("Could not create Buffer, chunk must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object"));
270
- this.cancel();
271
- }
272
- }
273
- pause() {
274
- if (this.stream.pause) this.stream.pause();
275
- }
276
- resume() {
277
- if (this.stream.readable && this.stream.resume) this.stream.resume();
278
- }
279
- close() {
280
- if (this.controller) {
281
- this.controller.close();
282
- delete this.controller;
283
- }
284
- }
285
- error(error) {
286
- if (this.controller) {
287
- this.controller.error(error);
288
- delete this.controller;
289
- }
290
- }
294
+ highWaterMark;
295
+ accumulatedSize;
296
+ stream;
297
+ controller;
298
+ constructor(stream) {
299
+ this.highWaterMark = stream.readableHighWaterMark || new import_node_stream.Stream.Readable().readableHighWaterMark;
300
+ this.accumulatedSize = 0;
301
+ this.stream = stream;
302
+ this.enqueue = this.enqueue.bind(this);
303
+ this.error = this.error.bind(this);
304
+ this.close = this.close.bind(this);
305
+ }
306
+ size(chunk) {
307
+ return chunk?.byteLength || 0;
308
+ }
309
+ start(controller) {
310
+ this.controller = controller;
311
+ this.stream.on("data", this.enqueue);
312
+ this.stream.once("error", this.error);
313
+ this.stream.once("end", this.close);
314
+ this.stream.once("close", this.close);
315
+ }
316
+ pull() {
317
+ this.resume();
318
+ }
319
+ cancel(reason) {
320
+ if (this.stream.destroy) {
321
+ this.stream.destroy(reason);
322
+ }
323
+ this.stream.off("data", this.enqueue);
324
+ this.stream.off("error", this.error);
325
+ this.stream.off("end", this.close);
326
+ this.stream.off("close", this.close);
327
+ }
328
+ enqueue(chunk) {
329
+ if (this.controller) {
330
+ try {
331
+ let bytes = chunk instanceof Uint8Array ? chunk : Buffer.from(chunk);
332
+ let available = (this.controller.desiredSize || 0) - bytes.byteLength;
333
+ this.controller.enqueue(bytes);
334
+ if (available <= 0) {
335
+ this.pause();
336
+ }
337
+ } catch (e) {
338
+ this.controller.error(
339
+ new Error(
340
+ "Could not create Buffer, chunk must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object"
341
+ )
342
+ );
343
+ this.cancel();
344
+ }
345
+ }
346
+ }
347
+ pause() {
348
+ if (this.stream.pause) {
349
+ this.stream.pause();
350
+ }
351
+ }
352
+ resume() {
353
+ if (this.stream.readable && this.stream.resume) {
354
+ this.stream.resume();
355
+ }
356
+ }
357
+ close() {
358
+ if (this.controller) {
359
+ this.controller.close();
360
+ delete this.controller;
361
+ }
362
+ }
363
+ error(error) {
364
+ if (this.controller) {
365
+ this.controller.error(error);
366
+ delete this.controller;
367
+ }
368
+ }
291
369
  };
292
- //#endregion
293
- export { createFileSessionStorage, createReadableStreamFromReadable, createRequestListener, readableStreamToString, writeAsyncIterableToWritable, writeReadableStreamToWritable };
370
+ // Annotate the CommonJS export names for ESM import in node:
371
+ 0 && (module.exports = {
372
+ createFileSessionStorage,
373
+ createReadableStreamFromReadable,
374
+ createRequestListener,
375
+ readableStreamToString,
376
+ writeAsyncIterableToWritable,
377
+ writeReadableStreamToWritable
378
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,337 @@
1
+ /**
2
+ * @react-router/node v0.0.0-experimental-63fd291ad
3
+ *
4
+ * Copyright (c) Remix Software Inc.
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE.md file in the root directory of this source tree.
8
+ *
9
+ * @license MIT
10
+ */
11
+
12
+ // server.ts
13
+ import { createRequestHandler } from "react-router";
14
+ import { createRequestListener as createRequestListener_ } from "@mjackson/node-fetch-server";
15
+ function createRequestListener(options) {
16
+ let handleRequest = createRequestHandler(options.build, options.mode);
17
+ return createRequestListener_(async (request, client) => {
18
+ let loadContext = await options.getLoadContext?.(request, client);
19
+ return handleRequest(request, loadContext);
20
+ });
21
+ }
22
+
23
+ // sessions/fileStorage.ts
24
+ import { promises as fsp } from "fs";
25
+ import * as path from "path";
26
+ import { createSessionStorage } from "react-router";
27
+ function createFileSessionStorage({
28
+ cookie,
29
+ dir
30
+ }) {
31
+ return createSessionStorage({
32
+ cookie,
33
+ async createData(data, expires) {
34
+ let content = JSON.stringify({ data, expires });
35
+ while (true) {
36
+ let randomBytes = crypto.getRandomValues(new Uint8Array(8));
37
+ let id = Buffer.from(randomBytes).toString("hex");
38
+ try {
39
+ let file = getFile(dir, id);
40
+ if (!file) {
41
+ throw new Error("Error generating session");
42
+ }
43
+ await fsp.mkdir(path.dirname(file), { recursive: true });
44
+ await fsp.writeFile(file, content, { encoding: "utf-8", flag: "wx" });
45
+ return id;
46
+ } catch (error) {
47
+ if (error.code !== "EEXIST") throw error;
48
+ }
49
+ }
50
+ },
51
+ async readData(id) {
52
+ try {
53
+ let file = getFile(dir, id);
54
+ if (!file) {
55
+ return null;
56
+ }
57
+ let content = JSON.parse(await fsp.readFile(file, "utf-8"));
58
+ let data = content.data;
59
+ let expires = typeof content.expires === "string" ? new Date(content.expires) : null;
60
+ if (!expires || expires > /* @__PURE__ */ new Date()) {
61
+ return data;
62
+ }
63
+ if (expires) await fsp.unlink(file);
64
+ return null;
65
+ } catch (error) {
66
+ if (error.code !== "ENOENT") throw error;
67
+ return null;
68
+ }
69
+ },
70
+ async updateData(id, data, expires) {
71
+ let content = JSON.stringify({ data, expires });
72
+ let file = getFile(dir, id);
73
+ if (!file) {
74
+ return;
75
+ }
76
+ await fsp.mkdir(path.dirname(file), { recursive: true });
77
+ await fsp.writeFile(file, content, "utf-8");
78
+ },
79
+ async deleteData(id) {
80
+ if (!id) {
81
+ return;
82
+ }
83
+ let file = getFile(dir, id);
84
+ if (!file) {
85
+ return;
86
+ }
87
+ try {
88
+ await fsp.unlink(file);
89
+ } catch (error) {
90
+ if (error.code !== "ENOENT") throw error;
91
+ }
92
+ }
93
+ });
94
+ }
95
+ function getFile(dir, id) {
96
+ if (!/^[0-9a-f]{16}$/i.test(id)) {
97
+ return null;
98
+ }
99
+ return path.join(dir, id.slice(0, 4), id.slice(4));
100
+ }
101
+
102
+ // stream.ts
103
+ import { Stream } from "stream";
104
+ async function writeReadableStreamToWritable(stream, writable) {
105
+ let reader = stream.getReader();
106
+ let flushable = writable;
107
+ let writableError = monitorWritableError(writable);
108
+ try {
109
+ while (true) {
110
+ writableError.throwIfClosed();
111
+ let { done, value } = await writableError.race(reader.read());
112
+ if (done) {
113
+ writable.end();
114
+ break;
115
+ }
116
+ writableError.throwIfClosed();
117
+ let canContinueWriting = writable.write(value);
118
+ if (typeof flushable.flush === "function") {
119
+ flushable.flush();
120
+ }
121
+ if (!canContinueWriting) {
122
+ await waitForDrain(writable, writableError);
123
+ }
124
+ }
125
+ } catch (error) {
126
+ try {
127
+ reader.cancel(error).catch(() => {
128
+ });
129
+ } catch {
130
+ }
131
+ writable.destroy(error);
132
+ throw error;
133
+ } finally {
134
+ writableError.cleanup();
135
+ try {
136
+ reader.releaseLock();
137
+ } catch {
138
+ }
139
+ }
140
+ }
141
+ function monitorWritableError(writable) {
142
+ let settled = false;
143
+ let writableError;
144
+ let rejectWritableError;
145
+ let writableErrorPromise = new Promise((_, reject2) => {
146
+ rejectWritableError = reject2;
147
+ });
148
+ writableErrorPromise.catch(() => {
149
+ });
150
+ function cleanup() {
151
+ writable.off("error", onError);
152
+ writable.off("close", onClose);
153
+ }
154
+ function reject(error) {
155
+ if (settled) {
156
+ return;
157
+ }
158
+ settled = true;
159
+ writableError = error;
160
+ cleanup();
161
+ rejectWritableError(error);
162
+ }
163
+ function onError(error) {
164
+ reject(error);
165
+ }
166
+ function onClose() {
167
+ reject(new Error("Writable closed before stream finished"));
168
+ }
169
+ writable.once("error", onError);
170
+ writable.once("close", onClose);
171
+ return {
172
+ cleanup,
173
+ race(promise) {
174
+ return Promise.race([promise, writableErrorPromise]);
175
+ },
176
+ throwIfClosed() {
177
+ if (writableError) {
178
+ throw writableError;
179
+ }
180
+ if (writable.destroyed || writable.writableEnded) {
181
+ throw new Error("Cannot write to a destroyed or ended writable stream");
182
+ }
183
+ }
184
+ };
185
+ }
186
+ function waitForDrain(writable, writableError) {
187
+ let cleanup = () => {
188
+ };
189
+ let drainPromise = new Promise((resolve) => {
190
+ function onDrain() {
191
+ cleanup();
192
+ resolve();
193
+ }
194
+ cleanup = function cleanup2() {
195
+ writable.off("drain", onDrain);
196
+ };
197
+ writable.once("drain", onDrain);
198
+ });
199
+ return writableError.race(drainPromise).finally(cleanup);
200
+ }
201
+ async function writeAsyncIterableToWritable(iterable, writable) {
202
+ let writableError = monitorWritableError(writable);
203
+ let iterator = iterable[Symbol.asyncIterator]();
204
+ let completed = false;
205
+ try {
206
+ while (true) {
207
+ writableError.throwIfClosed();
208
+ let { done, value: chunk } = await writableError.race(iterator.next());
209
+ if (done) {
210
+ completed = true;
211
+ break;
212
+ }
213
+ writableError.throwIfClosed();
214
+ let canContinueWriting = writable.write(chunk);
215
+ if (!canContinueWriting) {
216
+ await waitForDrain(writable, writableError);
217
+ }
218
+ }
219
+ writable.end();
220
+ } catch (error) {
221
+ if (!completed) {
222
+ try {
223
+ Promise.resolve(iterator.return?.()).catch(() => {
224
+ });
225
+ } catch {
226
+ }
227
+ }
228
+ writable.destroy(error);
229
+ throw error;
230
+ } finally {
231
+ writableError.cleanup();
232
+ }
233
+ }
234
+ async function readableStreamToString(stream, encoding) {
235
+ let reader = stream.getReader();
236
+ let chunks = [];
237
+ while (true) {
238
+ let { done, value } = await reader.read();
239
+ if (done) {
240
+ break;
241
+ }
242
+ if (value) {
243
+ chunks.push(value);
244
+ }
245
+ }
246
+ return Buffer.concat(chunks).toString(encoding);
247
+ }
248
+ var createReadableStreamFromReadable = (source) => {
249
+ let pump = new StreamPump(source);
250
+ let stream = new ReadableStream(pump, pump);
251
+ return stream;
252
+ };
253
+ var StreamPump = class {
254
+ highWaterMark;
255
+ accumulatedSize;
256
+ stream;
257
+ controller;
258
+ constructor(stream) {
259
+ this.highWaterMark = stream.readableHighWaterMark || new Stream.Readable().readableHighWaterMark;
260
+ this.accumulatedSize = 0;
261
+ this.stream = stream;
262
+ this.enqueue = this.enqueue.bind(this);
263
+ this.error = this.error.bind(this);
264
+ this.close = this.close.bind(this);
265
+ }
266
+ size(chunk) {
267
+ return chunk?.byteLength || 0;
268
+ }
269
+ start(controller) {
270
+ this.controller = controller;
271
+ this.stream.on("data", this.enqueue);
272
+ this.stream.once("error", this.error);
273
+ this.stream.once("end", this.close);
274
+ this.stream.once("close", this.close);
275
+ }
276
+ pull() {
277
+ this.resume();
278
+ }
279
+ cancel(reason) {
280
+ if (this.stream.destroy) {
281
+ this.stream.destroy(reason);
282
+ }
283
+ this.stream.off("data", this.enqueue);
284
+ this.stream.off("error", this.error);
285
+ this.stream.off("end", this.close);
286
+ this.stream.off("close", this.close);
287
+ }
288
+ enqueue(chunk) {
289
+ if (this.controller) {
290
+ try {
291
+ let bytes = chunk instanceof Uint8Array ? chunk : Buffer.from(chunk);
292
+ let available = (this.controller.desiredSize || 0) - bytes.byteLength;
293
+ this.controller.enqueue(bytes);
294
+ if (available <= 0) {
295
+ this.pause();
296
+ }
297
+ } catch (e) {
298
+ this.controller.error(
299
+ new Error(
300
+ "Could not create Buffer, chunk must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object"
301
+ )
302
+ );
303
+ this.cancel();
304
+ }
305
+ }
306
+ }
307
+ pause() {
308
+ if (this.stream.pause) {
309
+ this.stream.pause();
310
+ }
311
+ }
312
+ resume() {
313
+ if (this.stream.readable && this.stream.resume) {
314
+ this.stream.resume();
315
+ }
316
+ }
317
+ close() {
318
+ if (this.controller) {
319
+ this.controller.close();
320
+ delete this.controller;
321
+ }
322
+ }
323
+ error(error) {
324
+ if (this.controller) {
325
+ this.controller.error(error);
326
+ delete this.controller;
327
+ }
328
+ }
329
+ };
330
+ export {
331
+ createFileSessionStorage,
332
+ createReadableStreamFromReadable,
333
+ createRequestListener,
334
+ readableStreamToString,
335
+ writeAsyncIterableToWritable,
336
+ writeReadableStreamToWritable
337
+ };
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "@react-router/node",
3
- "type": "module",
4
- "version": "0.0.0-experimental-f7761f1cd",
3
+ "version": "0.0.0-experimental-63fd291ad",
5
4
  "description": "Node.js platform abstractions for React Router",
6
5
  "bugs": {
7
6
  "url": "https://github.com/remix-run/react-router/issues"
@@ -16,15 +15,25 @@
16
15
  "main": "dist/index.js",
17
16
  "exports": {
18
17
  ".": {
19
- "types": "./dist/index.d.ts",
20
- "module-sync": "./dist/index.js",
21
- "default": "./dist/index.js"
18
+ "node": {
19
+ "types": "./dist/index.d.ts",
20
+ "module-sync": "./dist/index.mjs",
21
+ "default": "./dist/index.js"
22
+ },
23
+ "import": {
24
+ "types": "./dist/index.d.mts",
25
+ "default": "./dist/index.mjs"
26
+ },
27
+ "default": {
28
+ "types": "./dist/index.d.ts",
29
+ "default": "./dist/index.js"
30
+ }
22
31
  },
23
32
  "./package.json": "./package.json"
24
33
  },
25
34
  "wireit": {
26
35
  "build": {
27
- "command": "tsdown",
36
+ "command": "tsup",
28
37
  "files": [
29
38
  "../../pnpm-workspace.yaml",
30
39
  "sessions/**",
@@ -38,18 +47,17 @@
38
47
  }
39
48
  },
40
49
  "dependencies": {
41
- "@remix-run/node-fetch-server": "^0.13.3"
50
+ "@mjackson/node-fetch-server": "^0.2.0"
42
51
  },
43
52
  "devDependencies": {
44
- "@types/node": "^22.19.19",
45
- "tsdown": "^0.22.0",
46
- "typescript": "^6.0.3",
47
- "wireit": "0.14.12",
48
- "react-router": "0.0.0-experimental-f7761f1cd"
53
+ "tsup": "^8.3.0",
54
+ "typescript": "^5.4.5",
55
+ "wireit": "0.14.9",
56
+ "react-router": "0.0.0-experimental-63fd291ad"
49
57
  },
50
58
  "peerDependencies": {
51
59
  "typescript": "^5.1.0 || ^6.0.0",
52
- "react-router": "0.0.0-experimental-f7761f1cd"
60
+ "react-router": "0.0.0-experimental-63fd291ad"
53
61
  },
54
62
  "peerDependenciesMeta": {
55
63
  "typescript": {
@@ -57,7 +65,7 @@
57
65
  }
58
66
  },
59
67
  "engines": {
60
- "node": ">=22.12.0"
68
+ "node": ">=20.0.0"
61
69
  },
62
70
  "files": [
63
71
  "dist/",