Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@datastream/file

Package Overview
Dependencies
Maintainers
1
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@datastream/file - npm Package Compare versions

Comparing version
0.3.2
to
0.4.0
+3
-2
index.node.mjs

@@ -8,3 +8,3 @@ import {

} from "node:fs";
import { extname, resolve } from "node:path";
import { extname, isAbsolute, relative, resolve } from "node:path";
import { makeOptions } from "@datastream/core";

@@ -36,3 +36,4 @@ const fileReadStream = ({ path, basePath, types }, streamOptions = {}) => {

const resolvedBase = resolve(basePath);
if (!resolvedPath.startsWith(resolvedBase)) {
const rel = relative(resolvedBase, resolvedPath);
if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) {
throw new Error("Path traversal detected");

@@ -39,0 +40,0 @@ }

+2
-2
{
"version": 3,
"sources": ["index.node.js"],
"sourcesContent": ["// Copyright 2026 will Farrell, and datastream contributors.\n// SPDX-License-Identifier: MIT\nimport {\n\tconstants,\n\tcreateReadStream,\n\tcreateWriteStream,\n\tlstatSync,\n\topenSync,\n} from \"node:fs\";\nimport { extname, resolve } from \"node:path\";\nimport { makeOptions } from \"@datastream/core\";\n\nexport const fileReadStream = (\n\t{ path, basePath, types },\n\tstreamOptions = {},\n) => {\n\tenforcePath(path, basePath);\n\tenforceType(path, types);\n\tif (basePath != null) {\n\t\t// Open with O_NOFOLLOW to prevent TOCTOU symlink race\n\t\tconst fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW);\n\t\treturn createReadStream(null, { ...makeOptions(streamOptions), fd });\n\t}\n\treturn createReadStream(path, makeOptions(streamOptions));\n};\n\nexport const fileWriteStream = (\n\t{ path, basePath, types },\n\tstreamOptions = {},\n) => {\n\tenforcePath(path, basePath);\n\tenforceType(path, types);\n\tif (basePath != null) {\n\t\tconst fd = openSync(\n\t\t\tpath,\n\t\t\tconstants.O_WRONLY |\n\t\t\t\tconstants.O_CREAT |\n\t\t\t\tconstants.O_TRUNC |\n\t\t\t\tconstants.O_NOFOLLOW,\n\t\t);\n\t\treturn createWriteStream(null, { ...makeOptions(streamOptions), fd });\n\t}\n\treturn createWriteStream(path, makeOptions(streamOptions));\n};\n\nconst enforcePath = (path, basePath) => {\n\tif (basePath != null) {\n\t\tconst resolvedPath = resolve(path);\n\t\tconst resolvedBase = resolve(basePath);\n\t\tif (!resolvedPath.startsWith(resolvedBase)) {\n\t\t\tthrow new Error(\"Path traversal detected\");\n\t\t}\n\t\ttry {\n\t\t\tconst stat = lstatSync(resolvedPath);\n\t\t\tif (stat.isSymbolicLink()) {\n\t\t\t\tthrow new Error(\"Symbolic links are not allowed\");\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tif (e.message === \"Symbolic links are not allowed\") throw e;\n\t\t\t// File may not exist yet (for writes), that's ok\n\t\t\tif (e.code !== \"ENOENT\") {\n\t\t\t\tthrow new Error(\"Path not found\", { cause: e });\n\t\t\t}\n\t\t}\n\t}\n};\n\nconst enforceType = (path, types = []) => {\n\tconst pathExt = extname(path);\n\tfor (const type of types) {\n\t\tfor (const mime in type.accept) {\n\t\t\tfor (const ext of type.accept[mime]) {\n\t\t\t\tif (pathExt === ext) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif (types.length) {\n\t\tthrow new Error(\"Invalid extension\");\n\t}\n};\n\nexport default {\n\treadStream: fileReadStream,\n\twriteStream: fileWriteStream,\n};\n"],
"mappings": "AAEA;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,SAAS,eAAe;AACjC,SAAS,mBAAmB;AAErB,MAAM,iBAAiB,CAC7B,EAAE,MAAM,UAAU,MAAM,GACxB,gBAAgB,CAAC,MACb;AACJ,cAAY,MAAM,QAAQ;AAC1B,cAAY,MAAM,KAAK;AACvB,MAAI,YAAY,MAAM;AAErB,UAAM,KAAK,SAAS,MAAM,UAAU,WAAW,UAAU,UAAU;AACnE,WAAO,iBAAiB,MAAM,EAAE,GAAG,YAAY,aAAa,GAAG,GAAG,CAAC;AAAA,EACpE;AACA,SAAO,iBAAiB,MAAM,YAAY,aAAa,CAAC;AACzD;AAEO,MAAM,kBAAkB,CAC9B,EAAE,MAAM,UAAU,MAAM,GACxB,gBAAgB,CAAC,MACb;AACJ,cAAY,MAAM,QAAQ;AAC1B,cAAY,MAAM,KAAK;AACvB,MAAI,YAAY,MAAM;AACrB,UAAM,KAAK;AAAA,MACV;AAAA,MACA,UAAU,WACT,UAAU,UACV,UAAU,UACV,UAAU;AAAA,IACZ;AACA,WAAO,kBAAkB,MAAM,EAAE,GAAG,YAAY,aAAa,GAAG,GAAG,CAAC;AAAA,EACrE;AACA,SAAO,kBAAkB,MAAM,YAAY,aAAa,CAAC;AAC1D;AAEA,MAAM,cAAc,CAAC,MAAM,aAAa;AACvC,MAAI,YAAY,MAAM;AACrB,UAAM,eAAe,QAAQ,IAAI;AACjC,UAAM,eAAe,QAAQ,QAAQ;AACrC,QAAI,CAAC,aAAa,WAAW,YAAY,GAAG;AAC3C,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC1C;AACA,QAAI;AACH,YAAM,OAAO,UAAU,YAAY;AACnC,UAAI,KAAK,eAAe,GAAG;AAC1B,cAAM,IAAI,MAAM,gCAAgC;AAAA,MACjD;AAAA,IACD,SAAS,GAAG;AACX,UAAI,EAAE,YAAY,iCAAkC,OAAM;AAE1D,UAAI,EAAE,SAAS,UAAU;AACxB,cAAM,IAAI,MAAM,kBAAkB,EAAE,OAAO,EAAE,CAAC;AAAA,MAC/C;AAAA,IACD;AAAA,EACD;AACD;AAEA,MAAM,cAAc,CAAC,MAAM,QAAQ,CAAC,MAAM;AACzC,QAAM,UAAU,QAAQ,IAAI;AAC5B,aAAW,QAAQ,OAAO;AACzB,eAAW,QAAQ,KAAK,QAAQ;AAC/B,iBAAW,OAAO,KAAK,OAAO,IAAI,GAAG;AACpC,YAAI,YAAY,KAAK;AACpB;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACA,MAAI,MAAM,QAAQ;AACjB,UAAM,IAAI,MAAM,mBAAmB;AAAA,EACpC;AACD;AAEA,IAAO,qBAAQ;AAAA,EACd,YAAY;AAAA,EACZ,aAAa;AACd;",
"sourcesContent": ["// Copyright 2026 will Farrell, and datastream contributors.\n// SPDX-License-Identifier: MIT\nimport {\n\tconstants,\n\tcreateReadStream,\n\tcreateWriteStream,\n\tlstatSync,\n\topenSync,\n} from \"node:fs\";\nimport { extname, isAbsolute, relative, resolve } from \"node:path\";\nimport { makeOptions } from \"@datastream/core\";\n\nexport const fileReadStream = (\n\t{ path, basePath, types },\n\tstreamOptions = {},\n) => {\n\tenforcePath(path, basePath);\n\tenforceType(path, types);\n\tif (basePath != null) {\n\t\t// Open with O_NOFOLLOW to prevent TOCTOU symlink race\n\t\tconst fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW);\n\t\treturn createReadStream(null, { ...makeOptions(streamOptions), fd });\n\t}\n\treturn createReadStream(path, makeOptions(streamOptions));\n};\n\nexport const fileWriteStream = (\n\t{ path, basePath, types },\n\tstreamOptions = {},\n) => {\n\tenforcePath(path, basePath);\n\tenforceType(path, types);\n\tif (basePath != null) {\n\t\tconst fd = openSync(\n\t\t\tpath,\n\t\t\tconstants.O_WRONLY |\n\t\t\t\tconstants.O_CREAT |\n\t\t\t\tconstants.O_TRUNC |\n\t\t\t\tconstants.O_NOFOLLOW,\n\t\t);\n\t\treturn createWriteStream(null, { ...makeOptions(streamOptions), fd });\n\t}\n\treturn createWriteStream(path, makeOptions(streamOptions));\n};\n\nconst enforcePath = (path, basePath) => {\n\tif (basePath != null) {\n\t\tconst resolvedPath = resolve(path);\n\t\tconst resolvedBase = resolve(basePath);\n\t\tconst rel = relative(resolvedBase, resolvedPath);\n\t\tif (rel === \"\" || rel.startsWith(\"..\") || isAbsolute(rel)) {\n\t\t\tthrow new Error(\"Path traversal detected\");\n\t\t}\n\t\ttry {\n\t\t\tconst stat = lstatSync(resolvedPath);\n\t\t\tif (stat.isSymbolicLink()) {\n\t\t\t\tthrow new Error(\"Symbolic links are not allowed\");\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tif (e.message === \"Symbolic links are not allowed\") throw e;\n\t\t\t// File may not exist yet (for writes), that's ok\n\t\t\tif (e.code !== \"ENOENT\") {\n\t\t\t\tthrow new Error(\"Path not found\", { cause: e });\n\t\t\t}\n\t\t}\n\t}\n};\n\nconst enforceType = (path, types = []) => {\n\tconst pathExt = extname(path);\n\tfor (const type of types) {\n\t\tfor (const mime in type.accept) {\n\t\t\tfor (const ext of type.accept[mime]) {\n\t\t\t\tif (pathExt === ext) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tif (types.length) {\n\t\tthrow new Error(\"Invalid extension\");\n\t}\n};\n\nexport default {\n\treadStream: fileReadStream,\n\twriteStream: fileWriteStream,\n};\n"],
"mappings": "AAEA;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,SAAS,YAAY,UAAU,eAAe;AACvD,SAAS,mBAAmB;AAErB,MAAM,iBAAiB,CAC7B,EAAE,MAAM,UAAU,MAAM,GACxB,gBAAgB,CAAC,MACb;AACJ,cAAY,MAAM,QAAQ;AAC1B,cAAY,MAAM,KAAK;AACvB,MAAI,YAAY,MAAM;AAErB,UAAM,KAAK,SAAS,MAAM,UAAU,WAAW,UAAU,UAAU;AACnE,WAAO,iBAAiB,MAAM,EAAE,GAAG,YAAY,aAAa,GAAG,GAAG,CAAC;AAAA,EACpE;AACA,SAAO,iBAAiB,MAAM,YAAY,aAAa,CAAC;AACzD;AAEO,MAAM,kBAAkB,CAC9B,EAAE,MAAM,UAAU,MAAM,GACxB,gBAAgB,CAAC,MACb;AACJ,cAAY,MAAM,QAAQ;AAC1B,cAAY,MAAM,KAAK;AACvB,MAAI,YAAY,MAAM;AACrB,UAAM,KAAK;AAAA,MACV;AAAA,MACA,UAAU,WACT,UAAU,UACV,UAAU,UACV,UAAU;AAAA,IACZ;AACA,WAAO,kBAAkB,MAAM,EAAE,GAAG,YAAY,aAAa,GAAG,GAAG,CAAC;AAAA,EACrE;AACA,SAAO,kBAAkB,MAAM,YAAY,aAAa,CAAC;AAC1D;AAEA,MAAM,cAAc,CAAC,MAAM,aAAa;AACvC,MAAI,YAAY,MAAM;AACrB,UAAM,eAAe,QAAQ,IAAI;AACjC,UAAM,eAAe,QAAQ,QAAQ;AACrC,UAAM,MAAM,SAAS,cAAc,YAAY;AAC/C,QAAI,QAAQ,MAAM,IAAI,WAAW,IAAI,KAAK,WAAW,GAAG,GAAG;AAC1D,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC1C;AACA,QAAI;AACH,YAAM,OAAO,UAAU,YAAY;AACnC,UAAI,KAAK,eAAe,GAAG;AAC1B,cAAM,IAAI,MAAM,gCAAgC;AAAA,MACjD;AAAA,IACD,SAAS,GAAG;AACX,UAAI,EAAE,YAAY,iCAAkC,OAAM;AAE1D,UAAI,EAAE,SAAS,UAAU;AACxB,cAAM,IAAI,MAAM,kBAAkB,EAAE,OAAO,EAAE,CAAC;AAAA,MAC/C;AAAA,IACD;AAAA,EACD;AACD;AAEA,MAAM,cAAc,CAAC,MAAM,QAAQ,CAAC,MAAM;AACzC,QAAM,UAAU,QAAQ,IAAI;AAC5B,aAAW,QAAQ,OAAO;AACzB,eAAW,QAAQ,KAAK,QAAQ;AAC/B,iBAAW,OAAO,KAAK,OAAO,IAAI,GAAG;AACpC,YAAI,YAAY,KAAK;AACpB;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACA,MAAI,MAAM,QAAQ;AACjB,UAAM,IAAI,MAAM,mBAAmB;AAAA,EACpC;AACD;AAEA,IAAO,qBAAQ;AAAA,EACd,YAAY;AAAA,EACZ,aAAa;AACd;",
"names": []
}
{
"name": "@datastream/file",
"version": "0.3.2",
"version": "0.4.0",
"description": "File system readable and writable streams with extension type enforcement",

@@ -63,4 +63,4 @@ "type": "module",

"dependencies": {
"@datastream/core": "0.3.2"
"@datastream/core": "0.4.0"
}
}