@react-router/node
Advanced tools
| /** | ||
| * @react-router/node v0.0.0-experimental-3bba3331c | ||
| * | ||
| * Copyright (c) Remix Software Inc. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE.md file in the root directory of this source tree. | ||
| * | ||
| * @license MIT | ||
| */ | ||
| import { File, Headers, Request, Response, fetch, FormData } from 'undici'; | ||
| import { webcrypto } from 'node:crypto'; | ||
| function installGlobals() { | ||
| global.File = File; | ||
| // @ts-ignore - this shows as an error in VSCode but is not an error via TSC so we can't use `ts-expect-error` | ||
| global.Headers = Headers; | ||
| // @ts-expect-error - overriding globals | ||
| global.Request = Request; | ||
| // @ts-expect-error - overriding globals | ||
| global.Response = Response; | ||
| // @ts-expect-error - overriding globals | ||
| global.fetch = fetch; | ||
| // @ts-expect-error - overriding globals | ||
| global.FormData = FormData; | ||
| if (!global.crypto) { | ||
| // @ts-expect-error - overriding globals | ||
| global.crypto = webcrypto; | ||
| } | ||
| } | ||
| export { installGlobals }; |
| /** | ||
| * @react-router/node v0.0.0-experimental-3bba3331c | ||
| * | ||
| * Copyright (c) Remix Software Inc. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE.md file in the root directory of this source tree. | ||
| * | ||
| * @license MIT | ||
| */ | ||
| export { installGlobals } from './globals.mjs'; | ||
| export { createFileSessionStorage } from './sessions/fileStorage.mjs'; | ||
| export { createReadableStreamFromReadable, readableStreamToString, writeAsyncIterableToWritable, writeReadableStreamToWritable } from './stream.mjs'; |
| /** | ||
| * @react-router/node v0.0.0-experimental-3bba3331c | ||
| * | ||
| * Copyright (c) Remix Software Inc. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE.md file in the root directory of this source tree. | ||
| * | ||
| * @license MIT | ||
| */ | ||
| import { installGlobals } from './globals.mjs'; | ||
| installGlobals(); |
| /** | ||
| * @react-router/node v0.0.0-experimental-3bba3331c | ||
| * | ||
| * Copyright (c) Remix Software Inc. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE.md file in the root directory of this source tree. | ||
| * | ||
| * @license MIT | ||
| */ | ||
| import { promises } from 'node:fs'; | ||
| import * as path from 'node:path'; | ||
| import { createSessionStorage } from 'react-router'; | ||
| /** | ||
| * Creates a SessionStorage that stores session data on a filesystem. | ||
| * | ||
| * The advantage of using this instead of cookie session storage is that | ||
| * files may contain much more data than cookies. | ||
| * | ||
| * @see https://remix.run/utils/sessions#createfilesessionstorage-node | ||
| */ | ||
| function createFileSessionStorage({ | ||
| cookie, | ||
| dir | ||
| }) { | ||
| return createSessionStorage({ | ||
| cookie, | ||
| async createData(data, expires) { | ||
| let content = JSON.stringify({ | ||
| data, | ||
| expires | ||
| }); | ||
| while (true) { | ||
| let randomBytes = crypto.getRandomValues(new Uint8Array(8)); | ||
| // This storage manages an id space of 2^64 ids, which is far greater | ||
| // than the maximum number of files allowed on an NTFS or ext4 volume | ||
| // (2^32). However, the larger id space should help to avoid collisions | ||
| // with existing ids when creating new sessions, which speeds things up. | ||
| let id = Buffer.from(randomBytes).toString("hex"); | ||
| try { | ||
| let file = getFile(dir, id); | ||
| await promises.mkdir(path.dirname(file), { | ||
| recursive: true | ||
| }); | ||
| await promises.writeFile(file, content, { | ||
| encoding: "utf-8", | ||
| flag: "wx" | ||
| }); | ||
| return id; | ||
| } catch (error) { | ||
| if (error.code !== "EEXIST") throw error; | ||
| } | ||
| } | ||
| }, | ||
| async readData(id) { | ||
| try { | ||
| let file = getFile(dir, id); | ||
| let content = JSON.parse(await promises.readFile(file, "utf-8")); | ||
| let data = content.data; | ||
| let expires = typeof content.expires === "string" ? new Date(content.expires) : null; | ||
| if (!expires || expires > new Date()) { | ||
| return data; | ||
| } | ||
| // Remove expired session data. | ||
| if (expires) await promises.unlink(file); | ||
| return null; | ||
| } catch (error) { | ||
| if (error.code !== "ENOENT") throw error; | ||
| return null; | ||
| } | ||
| }, | ||
| async updateData(id, data, expires) { | ||
| let content = JSON.stringify({ | ||
| data, | ||
| expires | ||
| }); | ||
| let file = getFile(dir, id); | ||
| await promises.mkdir(path.dirname(file), { | ||
| recursive: true | ||
| }); | ||
| await promises.writeFile(file, content, "utf-8"); | ||
| }, | ||
| async deleteData(id) { | ||
| // Return early if the id is empty, otherwise we'll end up trying to | ||
| // unlink the dir, which will cause the EPERM error. | ||
| if (!id) { | ||
| return; | ||
| } | ||
| try { | ||
| await promises.unlink(getFile(dir, id)); | ||
| } catch (error) { | ||
| if (error.code !== "ENOENT") throw error; | ||
| } | ||
| } | ||
| }); | ||
| } | ||
| function getFile(dir, id) { | ||
| // Divide the session id up into a directory (first 2 bytes) and filename | ||
| // (remaining 6 bytes) to reduce the chance of having very large directories, | ||
| // which should speed up file access. This is a maximum of 2^16 directories, | ||
| // each with 2^48 files. | ||
| return path.join(dir, id.slice(0, 4), id.slice(4)); | ||
| } | ||
| export { createFileSessionStorage, getFile }; |
+139
| /** | ||
| * @react-router/node v0.0.0-experimental-3bba3331c | ||
| * | ||
| * Copyright (c) Remix Software Inc. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE.md file in the root directory of this source tree. | ||
| * | ||
| * @license MIT | ||
| */ | ||
| import { Stream } from 'node:stream'; | ||
| async function writeReadableStreamToWritable(stream, writable) { | ||
| let reader = stream.getReader(); | ||
| let flushable = writable; | ||
| try { | ||
| while (true) { | ||
| let { | ||
| done, | ||
| value | ||
| } = await reader.read(); | ||
| if (done) { | ||
| writable.end(); | ||
| break; | ||
| } | ||
| writable.write(value); | ||
| if (typeof flushable.flush === "function") { | ||
| flushable.flush(); | ||
| } | ||
| } | ||
| } catch (error) { | ||
| writable.destroy(error); | ||
| throw error; | ||
| } | ||
| } | ||
| async function writeAsyncIterableToWritable(iterable, writable) { | ||
| try { | ||
| for await (let chunk of iterable) { | ||
| writable.write(chunk); | ||
| } | ||
| writable.end(); | ||
| } catch (error) { | ||
| writable.destroy(error); | ||
| throw error; | ||
| } | ||
| } | ||
| async function readableStreamToString(stream, encoding) { | ||
| let reader = stream.getReader(); | ||
| let chunks = []; | ||
| while (true) { | ||
| let { | ||
| done, | ||
| value | ||
| } = await reader.read(); | ||
| if (done) { | ||
| break; | ||
| } | ||
| if (value) { | ||
| chunks.push(value); | ||
| } | ||
| } | ||
| return Buffer.concat(chunks).toString(encoding); | ||
| } | ||
| const createReadableStreamFromReadable = source => { | ||
| let pump = new StreamPump(source); | ||
| let stream = new ReadableStream(pump, pump); | ||
| return stream; | ||
| }; | ||
| class StreamPump { | ||
| constructor(stream) { | ||
| this.highWaterMark = stream.readableHighWaterMark || new Stream.Readable().readableHighWaterMark; | ||
| this.accumalatedSize = 0; | ||
| this.stream = stream; | ||
| this.enqueue = this.enqueue.bind(this); | ||
| this.error = this.error.bind(this); | ||
| this.close = this.close.bind(this); | ||
| } | ||
| size(chunk) { | ||
| return (chunk === null || chunk === void 0 ? void 0 : chunk.byteLength) || 0; | ||
| } | ||
| start(controller) { | ||
| this.controller = controller; | ||
| this.stream.on("data", this.enqueue); | ||
| this.stream.once("error", this.error); | ||
| this.stream.once("end", this.close); | ||
| this.stream.once("close", this.close); | ||
| } | ||
| pull() { | ||
| this.resume(); | ||
| } | ||
| cancel(reason) { | ||
| if (this.stream.destroy) { | ||
| this.stream.destroy(reason); | ||
| } | ||
| this.stream.off("data", this.enqueue); | ||
| this.stream.off("error", this.error); | ||
| this.stream.off("end", this.close); | ||
| this.stream.off("close", this.close); | ||
| } | ||
| enqueue(chunk) { | ||
| if (this.controller) { | ||
| try { | ||
| let bytes = chunk instanceof Uint8Array ? chunk : Buffer.from(chunk); | ||
| let available = (this.controller.desiredSize || 0) - bytes.byteLength; | ||
| this.controller.enqueue(bytes); | ||
| if (available <= 0) { | ||
| this.pause(); | ||
| } | ||
| } catch (error) { | ||
| this.controller.error(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")); | ||
| this.cancel(); | ||
| } | ||
| } | ||
| } | ||
| pause() { | ||
| if (this.stream.pause) { | ||
| this.stream.pause(); | ||
| } | ||
| } | ||
| resume() { | ||
| if (this.stream.readable && this.stream.resume) { | ||
| this.stream.resume(); | ||
| } | ||
| } | ||
| close() { | ||
| if (this.controller) { | ||
| this.controller.close(); | ||
| delete this.controller; | ||
| } | ||
| } | ||
| error(error) { | ||
| if (this.controller) { | ||
| this.controller.error(error); | ||
| delete this.controller; | ||
| } | ||
| } | ||
| } | ||
| export { createReadableStreamFromReadable, readableStreamToString, writeAsyncIterableToWritable, writeReadableStreamToWritable }; |
@@ -0,1 +1,3 @@ | ||
| /// <reference types="node" /> | ||
| import { webcrypto as nodeWebCrypto } from "node:crypto"; | ||
| declare global { | ||
@@ -15,2 +17,3 @@ namespace NodeJS { | ||
| WritableStream: typeof WritableStream; | ||
| crypto: typeof nodeWebCrypto; | ||
| } | ||
@@ -17,0 +20,0 @@ } |
+7
-2
| /** | ||
| * @react-router/node v0.0.0-experimental-3a25d7f8a | ||
| * @react-router/node v0.0.0-experimental-3bba3331c | ||
| * | ||
@@ -16,6 +16,7 @@ * Copyright (c) Remix Software Inc. | ||
| var undici = require('undici'); | ||
| var node_crypto = require('node:crypto'); | ||
| function installGlobals() { | ||
| global.File = undici.File; | ||
| // @ts-expect-error - overriding globals | ||
| // @ts-ignore - this shows as an error in VSCode but is not an error via TSC so we can't use `ts-expect-error` | ||
| global.Headers = undici.Headers; | ||
@@ -30,4 +31,8 @@ // @ts-expect-error - overriding globals | ||
| global.FormData = undici.FormData; | ||
| if (!global.crypto) { | ||
| // @ts-expect-error - overriding globals | ||
| global.crypto = node_crypto.webcrypto; | ||
| } | ||
| } | ||
| exports.installGlobals = installGlobals; |
+0
-4
| export { installGlobals } from "./globals"; | ||
| export { createFileSessionStorage } from "./sessions/fileStorage"; | ||
| export { createFileUploadHandler as unstable_createFileUploadHandler, NodeOnDiskFile, } from "./upload/fileUploadHandler"; | ||
| export { createCookie, createCookieSessionStorage, createMemorySessionStorage, createSessionStorage, } from "./implementations"; | ||
| export { createReadableStreamFromReadable, readableStreamToString, writeAsyncIterableToWritable, writeReadableStreamToWritable, } from "./stream"; | ||
| export { createRequestHandler, createSession, defer, isCookie, isSession, json, MaxPartSizeExceededError, redirect, redirectDocument, unstable_composeUploadHandlers, unstable_createMemoryUploadHandler, unstable_parseMultipartFormData, } from "@react-router/server-runtime"; | ||
| export type { ActionFunction, ActionFunctionArgs, AppLoadContext, Cookie, CookieOptions, CookieParseOptions, CookieSerializeOptions, CookieSignatureOptions, DataFunctionArgs, EntryContext, ErrorResponse, HandleDataRequestFunction, HandleDocumentRequestFunction, HeadersArgs, HeadersFunction, HtmlLinkDescriptor, JsonFunction, LinkDescriptor, LinksFunction, LoaderFunction, LoaderFunctionArgs, MemoryUploadHandlerFilterArgs, MemoryUploadHandlerOptions, HandleErrorFunction, PageLinkDescriptor, RequestHandler, SerializeFrom, ServerBuild, ServerEntryModule, ServerRuntimeMetaArgs as MetaArgs, ServerRuntimeMetaDescriptor as MetaDescriptor, ServerRuntimeMetaFunction as MetaFunction, Session, SessionData, SessionIdStorageStrategy, SessionStorage, SignFunction, TypedDeferredData, TypedResponse, UnsignFunction, UploadHandler, UploadHandlerPart, } from "@react-router/server-runtime"; |
+1
-58
| /** | ||
| * @react-router/node v0.0.0-experimental-3a25d7f8a | ||
| * @react-router/node v0.0.0-experimental-3bba3331c | ||
| * | ||
@@ -17,6 +17,3 @@ * Copyright (c) Remix Software Inc. | ||
| var fileStorage = require('./sessions/fileStorage.js'); | ||
| var fileUploadHandler = require('./upload/fileUploadHandler.js'); | ||
| var implementations = require('./implementations.js'); | ||
| var stream = require('./stream.js'); | ||
| var serverRuntime = require('@react-router/server-runtime'); | ||
@@ -27,8 +24,2 @@ | ||
| exports.createFileSessionStorage = fileStorage.createFileSessionStorage; | ||
| exports.NodeOnDiskFile = fileUploadHandler.NodeOnDiskFile; | ||
| exports.unstable_createFileUploadHandler = fileUploadHandler.createFileUploadHandler; | ||
| exports.createCookie = implementations.createCookie; | ||
| exports.createCookieSessionStorage = implementations.createCookieSessionStorage; | ||
| exports.createMemorySessionStorage = implementations.createMemorySessionStorage; | ||
| exports.createSessionStorage = implementations.createSessionStorage; | ||
| exports.createReadableStreamFromReadable = stream.createReadableStreamFromReadable; | ||
@@ -38,49 +29,1 @@ exports.readableStreamToString = stream.readableStreamToString; | ||
| exports.writeReadableStreamToWritable = stream.writeReadableStreamToWritable; | ||
| Object.defineProperty(exports, 'MaxPartSizeExceededError', { | ||
| enumerable: true, | ||
| get: function () { return serverRuntime.MaxPartSizeExceededError; } | ||
| }); | ||
| Object.defineProperty(exports, 'createRequestHandler', { | ||
| enumerable: true, | ||
| get: function () { return serverRuntime.createRequestHandler; } | ||
| }); | ||
| Object.defineProperty(exports, 'createSession', { | ||
| enumerable: true, | ||
| get: function () { return serverRuntime.createSession; } | ||
| }); | ||
| Object.defineProperty(exports, 'defer', { | ||
| enumerable: true, | ||
| get: function () { return serverRuntime.defer; } | ||
| }); | ||
| Object.defineProperty(exports, 'isCookie', { | ||
| enumerable: true, | ||
| get: function () { return serverRuntime.isCookie; } | ||
| }); | ||
| Object.defineProperty(exports, 'isSession', { | ||
| enumerable: true, | ||
| get: function () { return serverRuntime.isSession; } | ||
| }); | ||
| Object.defineProperty(exports, 'json', { | ||
| enumerable: true, | ||
| get: function () { return serverRuntime.json; } | ||
| }); | ||
| Object.defineProperty(exports, 'redirect', { | ||
| enumerable: true, | ||
| get: function () { return serverRuntime.redirect; } | ||
| }); | ||
| Object.defineProperty(exports, 'redirectDocument', { | ||
| enumerable: true, | ||
| get: function () { return serverRuntime.redirectDocument; } | ||
| }); | ||
| Object.defineProperty(exports, 'unstable_composeUploadHandlers', { | ||
| enumerable: true, | ||
| get: function () { return serverRuntime.unstable_composeUploadHandlers; } | ||
| }); | ||
| Object.defineProperty(exports, 'unstable_createMemoryUploadHandler', { | ||
| enumerable: true, | ||
| get: function () { return serverRuntime.unstable_createMemoryUploadHandler; } | ||
| }); | ||
| Object.defineProperty(exports, 'unstable_parseMultipartFormData', { | ||
| enumerable: true, | ||
| get: function () { return serverRuntime.unstable_parseMultipartFormData; } | ||
| }); |
+1
-1
| /** | ||
| * @react-router/node v0.0.0-experimental-3a25d7f8a | ||
| * @react-router/node v0.0.0-experimental-3bba3331c | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
@@ -1,2 +0,2 @@ | ||
| import type { SessionStorage, SessionIdStorageStrategy, SessionData } from "@react-router/server-runtime"; | ||
| import type { SessionStorage, SessionIdStorageStrategy, SessionData } from "react-router"; | ||
| interface FileSessionStorageOptions { | ||
@@ -3,0 +3,0 @@ /** |
| /** | ||
| * @react-router/node v0.0.0-experimental-3a25d7f8a | ||
| * @react-router/node v0.0.0-experimental-3bba3331c | ||
| * | ||
@@ -15,26 +15,24 @@ * Copyright (c) Remix Software Inc. | ||
| var crypto = require('node:crypto'); | ||
| var node_fs = require('node:fs'); | ||
| var path = require('node:path'); | ||
| var implementations = require('../implementations.js'); | ||
| var reactRouter = require('react-router'); | ||
| function _interopNamespace(e) { | ||
| if (e && e.__esModule) return e; | ||
| var n = Object.create(null); | ||
| if (e) { | ||
| Object.keys(e).forEach(function (k) { | ||
| if (k !== 'default') { | ||
| var d = Object.getOwnPropertyDescriptor(e, k); | ||
| Object.defineProperty(n, k, d.get ? d : { | ||
| enumerable: true, | ||
| get: function () { return e[k]; } | ||
| }); | ||
| } | ||
| if (e && e.__esModule) return e; | ||
| var n = Object.create(null); | ||
| if (e) { | ||
| Object.keys(e).forEach(function (k) { | ||
| if (k !== 'default') { | ||
| var d = Object.getOwnPropertyDescriptor(e, k); | ||
| Object.defineProperty(n, k, d.get ? d : { | ||
| enumerable: true, | ||
| get: function () { return e[k]; } | ||
| }); | ||
| } | ||
| n["default"] = e; | ||
| return Object.freeze(n); | ||
| } | ||
| }); | ||
| } | ||
| n["default"] = e; | ||
| return Object.freeze(n); | ||
| } | ||
| var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto); | ||
| var path__namespace = /*#__PURE__*/_interopNamespace(path); | ||
@@ -54,3 +52,3 @@ | ||
| }) { | ||
| return implementations.createSessionStorage({ | ||
| return reactRouter.createSessionStorage({ | ||
| cookie, | ||
@@ -63,5 +61,3 @@ async createData(data, expires) { | ||
| while (true) { | ||
| // TODO: Once Node v19 is supported we should use the globally provided | ||
| // Web Crypto API's crypto.getRandomValues() function here instead. | ||
| let randomBytes = crypto__namespace.webcrypto.getRandomValues(new Uint8Array(8)); | ||
| let randomBytes = crypto.getRandomValues(new Uint8Array(8)); | ||
| // This storage manages an id space of 2^64 ids, which is far greater | ||
@@ -96,2 +92,3 @@ // than the maximum number of files allowed on an NTFS or ext4 volume | ||
| } | ||
| // Remove expired session data. | ||
@@ -98,0 +95,0 @@ if (expires) await node_fs.promises.unlink(file); |
+1
-1
| /** | ||
| * @react-router/node v0.0.0-experimental-3a25d7f8a | ||
| * @react-router/node v0.0.0-experimental-3bba3331c | ||
| * | ||
@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc. |
+13
-11
| { | ||
| "name": "@react-router/node", | ||
| "version": "0.0.0-experimental-3a25d7f8a", | ||
| "version": "0.0.0-experimental-3bba3331c", | ||
| "description": "Node.js platform abstractions for React Router", | ||
@@ -11,3 +11,3 @@ "bugs": { | ||
| "url": "https://github.com/remix-run/react-router", | ||
| "directory": "packages/remix-node" | ||
| "directory": "packages/react-router-node" | ||
| }, | ||
@@ -20,7 +20,9 @@ "license": "MIT", | ||
| "types": "./dist/index.d.ts", | ||
| "default": "./dist/index.js" | ||
| "import": "./dist/index.mjs", | ||
| "require": "./dist/index.js" | ||
| }, | ||
| "./install": { | ||
| "types": "./dist/install.d.ts", | ||
| "default": "./dist/install.js" | ||
| "import": "./dist/install.mjs", | ||
| "require": "./dist/install.js" | ||
| }, | ||
@@ -30,19 +32,19 @@ "./package.json": "./package.json" | ||
| "sideEffects": [ | ||
| "./dist/install.js" | ||
| "./dist/install.js", | ||
| "./dist/install.mjs" | ||
| ], | ||
| "dependencies": { | ||
| "@web3-storage/multipart-parser": "^1.0.0", | ||
| "cookie-signature": "^1.1.0", | ||
| "source-map-support": "^0.5.21", | ||
| "stream-slice": "^0.1.2", | ||
| "undici": "^6.10.1", | ||
| "@react-router/server-runtime": "0.0.0-experimental-3a25d7f8a" | ||
| "undici": "^6.19.2" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/cookie-signature": "^1.0.3", | ||
| "@types/source-map-support": "^0.5.4", | ||
| "typescript": "^5.1.6" | ||
| "typescript": "^5.1.6", | ||
| "react-router": "0.0.0-experimental-3bba3331c" | ||
| }, | ||
| "peerDependencies": { | ||
| "typescript": "^5.1.0" | ||
| "typescript": "^5.1.0", | ||
| "react-router": "0.0.0-experimental-3bba3331c" | ||
| }, | ||
@@ -49,0 +51,0 @@ "peerDependenciesMeta": { |
| import type { SignFunction, UnsignFunction } from "@react-router/server-runtime"; | ||
| export declare const sign: SignFunction; | ||
| export declare const unsign: UnsignFunction; |
| /** | ||
| * @react-router/node v0.0.0-experimental-3a25d7f8a | ||
| * | ||
| * Copyright (c) Remix Software Inc. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE.md file in the root directory of this source tree. | ||
| * | ||
| * @license MIT | ||
| */ | ||
| 'use strict'; | ||
| Object.defineProperty(exports, '__esModule', { value: true }); | ||
| var cookieSignature = require('cookie-signature'); | ||
| function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
| var cookieSignature__default = /*#__PURE__*/_interopDefaultLegacy(cookieSignature); | ||
| const sign = async (value, secret) => { | ||
| return cookieSignature__default["default"].sign(value, secret); | ||
| }; | ||
| const unsign = async (signed, secret) => { | ||
| return cookieSignature__default["default"].unsign(signed, secret); | ||
| }; | ||
| exports.sign = sign; | ||
| exports.unsign = unsign; |
| export declare const createCookie: import("@react-router/server-runtime").CreateCookieFunction; | ||
| export declare const createCookieSessionStorage: import("@react-router/server-runtime").CreateCookieSessionStorageFunction; | ||
| export declare const createSessionStorage: import("@react-router/server-runtime").CreateSessionStorageFunction; | ||
| export declare const createMemorySessionStorage: import("@react-router/server-runtime").CreateMemorySessionStorageFunction; |
| /** | ||
| * @react-router/node v0.0.0-experimental-3a25d7f8a | ||
| * | ||
| * Copyright (c) Remix Software Inc. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE.md file in the root directory of this source tree. | ||
| * | ||
| * @license MIT | ||
| */ | ||
| 'use strict'; | ||
| Object.defineProperty(exports, '__esModule', { value: true }); | ||
| var serverRuntime = require('@react-router/server-runtime'); | ||
| var crypto = require('./crypto.js'); | ||
| const createCookie = serverRuntime.createCookieFactory({ | ||
| sign: crypto.sign, | ||
| unsign: crypto.unsign | ||
| }); | ||
| const createCookieSessionStorage = serverRuntime.createCookieSessionStorageFactory(createCookie); | ||
| const createSessionStorage = serverRuntime.createSessionStorageFactory(createCookie); | ||
| const createMemorySessionStorage = serverRuntime.createMemorySessionStorageFactory(createSessionStorage); | ||
| exports.createCookie = createCookie; | ||
| exports.createCookieSessionStorage = createCookieSessionStorage; | ||
| exports.createMemorySessionStorage = createMemorySessionStorage; | ||
| exports.createSessionStorage = createSessionStorage; |
| /// <reference types="node" /> | ||
| import type { UploadHandler } from "@react-router/server-runtime"; | ||
| export type FileUploadHandlerFilterArgs = { | ||
| filename: string; | ||
| contentType: string; | ||
| name: string; | ||
| }; | ||
| export type FileUploadHandlerPathResolverArgs = { | ||
| filename: string; | ||
| contentType: string; | ||
| name: string; | ||
| }; | ||
| /** | ||
| * Chooses the path of the file to be uploaded. If a string is not | ||
| * returned the file will not be written. | ||
| */ | ||
| export type FileUploadHandlerPathResolver = (args: FileUploadHandlerPathResolverArgs) => string | undefined; | ||
| export type FileUploadHandlerOptions = { | ||
| /** | ||
| * Avoid file conflicts by appending a count on the end of the filename | ||
| * if it already exists on disk. Defaults to `true`. | ||
| */ | ||
| avoidFileConflicts?: boolean; | ||
| /** | ||
| * The directory to write the upload. | ||
| */ | ||
| directory?: string | FileUploadHandlerPathResolver; | ||
| /** | ||
| * The name of the file in the directory. Can be a relative path, the directory | ||
| * structure will be created if it does not exist. | ||
| */ | ||
| file?: FileUploadHandlerPathResolver; | ||
| /** | ||
| * The maximum upload size allowed. If the size is exceeded an error will be thrown. | ||
| * Defaults to 3000000B (3MB). | ||
| */ | ||
| maxPartSize?: number; | ||
| /** | ||
| * | ||
| * @param filename | ||
| * @param contentType | ||
| * @param name | ||
| */ | ||
| filter?(args: FileUploadHandlerFilterArgs): boolean | Promise<boolean>; | ||
| }; | ||
| export declare function createFileUploadHandler({ directory, avoidFileConflicts, file, filter, maxPartSize, }?: FileUploadHandlerOptions): UploadHandler; | ||
| export declare class NodeOnDiskFile implements Omit<File, "constructor"> { | ||
| private filepath; | ||
| type: string; | ||
| private slicer?; | ||
| name: string; | ||
| lastModified: number; | ||
| webkitRelativePath: string; | ||
| prototype: File; | ||
| constructor(filepath: string, type: string, slicer?: { | ||
| start: number; | ||
| end: number; | ||
| } | undefined); | ||
| get size(): number; | ||
| slice(start?: number, end?: number, type?: string): Blob; | ||
| arrayBuffer(): Promise<ArrayBuffer>; | ||
| stream(): ReadableStream<any>; | ||
| stream(): NodeJS.ReadableStream; | ||
| text(): Promise<string>; | ||
| get [Symbol.toStringTag](): string; | ||
| remove(): Promise<void>; | ||
| getFilePath(): string; | ||
| } |
| /** | ||
| * @react-router/node v0.0.0-experimental-3a25d7f8a | ||
| * | ||
| * Copyright (c) Remix Software Inc. | ||
| * | ||
| * This source code is licensed under the MIT license found in the | ||
| * LICENSE.md file in the root directory of this source tree. | ||
| * | ||
| * @license MIT | ||
| */ | ||
| 'use strict'; | ||
| Object.defineProperty(exports, '__esModule', { value: true }); | ||
| var crypto = require('node:crypto'); | ||
| var node_fs = require('node:fs'); | ||
| var promises = require('node:fs/promises'); | ||
| var node_os = require('node:os'); | ||
| var path = require('node:path'); | ||
| var node_stream = require('node:stream'); | ||
| var node_util = require('node:util'); | ||
| var serverRuntime = require('@react-router/server-runtime'); | ||
| var streamSlice = require('stream-slice'); | ||
| var stream = require('../stream.js'); | ||
| function _interopNamespace(e) { | ||
| if (e && e.__esModule) return e; | ||
| var n = Object.create(null); | ||
| if (e) { | ||
| Object.keys(e).forEach(function (k) { | ||
| if (k !== 'default') { | ||
| var d = Object.getOwnPropertyDescriptor(e, k); | ||
| Object.defineProperty(n, k, d.get ? d : { | ||
| enumerable: true, | ||
| get: function () { return e[k]; } | ||
| }); | ||
| } | ||
| }); | ||
| } | ||
| n["default"] = e; | ||
| return Object.freeze(n); | ||
| } | ||
| var streamSlice__namespace = /*#__PURE__*/_interopNamespace(streamSlice); | ||
| let defaultFilePathResolver = ({ | ||
| filename | ||
| }) => { | ||
| let ext = filename ? path.extname(filename) : ""; | ||
| return "upload_" + crypto.randomBytes(4).readUInt32LE(0) + ext; | ||
| }; | ||
| async function uniqueFile(filepath) { | ||
| let ext = path.extname(filepath); | ||
| let uniqueFilepath = filepath; | ||
| for (let i = 1; await promises.stat(uniqueFilepath).then(() => true).catch(() => false); i++) { | ||
| uniqueFilepath = (ext ? filepath.slice(0, -ext.length) : filepath) + `-${new Date().getTime()}${ext}`; | ||
| } | ||
| return uniqueFilepath; | ||
| } | ||
| function createFileUploadHandler({ | ||
| directory = node_os.tmpdir(), | ||
| avoidFileConflicts = true, | ||
| file = defaultFilePathResolver, | ||
| filter, | ||
| maxPartSize = 3000000 | ||
| } = {}) { | ||
| return async ({ | ||
| name, | ||
| filename, | ||
| contentType, | ||
| data | ||
| }) => { | ||
| if (!filename || filter && !(await filter({ | ||
| name, | ||
| filename, | ||
| contentType | ||
| }))) { | ||
| return undefined; | ||
| } | ||
| let dir = typeof directory === "string" ? directory : directory({ | ||
| name, | ||
| filename, | ||
| contentType | ||
| }); | ||
| if (!dir) { | ||
| return undefined; | ||
| } | ||
| let filedir = path.resolve(dir); | ||
| let path$1 = typeof file === "string" ? file : file({ | ||
| name, | ||
| filename, | ||
| contentType | ||
| }); | ||
| if (!path$1) { | ||
| return undefined; | ||
| } | ||
| let filepath = path.resolve(filedir, path$1); | ||
| if (avoidFileConflicts) { | ||
| filepath = await uniqueFile(filepath); | ||
| } | ||
| await promises.mkdir(path.dirname(filepath), { | ||
| recursive: true | ||
| }).catch(() => {}); | ||
| let writeFileStream = node_fs.createWriteStream(filepath); | ||
| let size = 0; | ||
| let deleteFile = false; | ||
| try { | ||
| for await (let chunk of data) { | ||
| size += chunk.byteLength; | ||
| if (size > maxPartSize) { | ||
| deleteFile = true; | ||
| throw new serverRuntime.MaxPartSizeExceededError(name, maxPartSize); | ||
| } | ||
| writeFileStream.write(chunk); | ||
| } | ||
| } finally { | ||
| writeFileStream.end(); | ||
| await node_util.promisify(node_stream.finished)(writeFileStream); | ||
| if (deleteFile) { | ||
| await promises.rm(filepath).catch(() => {}); | ||
| } | ||
| } | ||
| // TODO: remove this typecast once TS fixed File class regression | ||
| // https://github.com/microsoft/TypeScript/issues/52166 | ||
| return new NodeOnDiskFile(filepath, contentType); | ||
| }; | ||
| } | ||
| // TODO: remove this `Omit` usage once TS fixed File class regression | ||
| // https://github.com/microsoft/TypeScript/issues/52166 | ||
| class NodeOnDiskFile { | ||
| lastModified = 0; | ||
| webkitRelativePath = ""; | ||
| // TODO: remove this property once TS fixed File class regression | ||
| // https://github.com/microsoft/TypeScript/issues/52166 | ||
| prototype = File.prototype; | ||
| constructor(filepath, type, slicer) { | ||
| this.filepath = filepath; | ||
| this.type = type; | ||
| this.slicer = slicer; | ||
| this.name = path.basename(filepath); | ||
| } | ||
| get size() { | ||
| let stats = node_fs.statSync(this.filepath); | ||
| if (this.slicer) { | ||
| let slice = this.slicer.end - this.slicer.start; | ||
| return slice < 0 ? 0 : slice > stats.size ? stats.size : slice; | ||
| } | ||
| return stats.size; | ||
| } | ||
| slice(start, end, type) { | ||
| var _this$slicer; | ||
| if (typeof start === "number" && start < 0) start = this.size + start; | ||
| if (typeof end === "number" && end < 0) end = this.size + end; | ||
| let startOffset = ((_this$slicer = this.slicer) === null || _this$slicer === void 0 ? void 0 : _this$slicer.start) || 0; | ||
| start = startOffset + (start || 0); | ||
| end = startOffset + (end || this.size); | ||
| return new NodeOnDiskFile(this.filepath, typeof type === "string" ? type : this.type, { | ||
| start, | ||
| end | ||
| } | ||
| // TODO: remove this typecast once TS fixed File class regression | ||
| // https://github.com/microsoft/TypeScript/issues/52166 | ||
| ); | ||
| } | ||
| async arrayBuffer() { | ||
| let stream = node_fs.createReadStream(this.filepath); | ||
| if (this.slicer) { | ||
| stream = stream.pipe(streamSlice__namespace.slice(this.slicer.start, this.slicer.end)); | ||
| } | ||
| return new Promise((resolve, reject) => { | ||
| let buf = []; | ||
| stream.on("data", chunk => buf.push(chunk)); | ||
| stream.on("end", () => resolve(Buffer.concat(buf))); | ||
| stream.on("error", err => reject(err)); | ||
| }); | ||
| } | ||
| stream() { | ||
| let stream$1 = node_fs.createReadStream(this.filepath); | ||
| if (this.slicer) { | ||
| stream$1 = stream$1.pipe(streamSlice__namespace.slice(this.slicer.start, this.slicer.end)); | ||
| } | ||
| return stream.createReadableStreamFromReadable(stream$1); | ||
| } | ||
| async text() { | ||
| return stream.readableStreamToString(this.stream()); | ||
| } | ||
| get [Symbol.toStringTag]() { | ||
| return "File"; | ||
| } | ||
| remove() { | ||
| return promises.unlink(this.filepath); | ||
| } | ||
| getFilePath() { | ||
| return this.filepath; | ||
| } | ||
| } | ||
| exports.NodeOnDiskFile = NodeOnDiskFile; | ||
| exports.createFileUploadHandler = createFileUploadHandler; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
6
-14.29%0
-100%41611
-12.19%19
-5%689
-10.52%8
100%+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated