file

File read and write streams for Node.js and the browser.

Install

npm install @datastream/file

fileReadStream Readable

Reads a file as a stream.

  • Node.js: Uses fs.createReadStream
  • Browser: Uses window.showOpenFilePicker (File System Access API)

Options

OptionTypeDescription
pathstringFile path (Node.js)
basePathstringWhen provided, enforces that path resolves within basePath. Prevents path traversal and rejects symbolic links
typesobject[]File type filter for the file picker (see below)

Example — Node.js

import { pipeline } from '@datastream/core'
import { fileReadStream } from '@datastream/file'

await pipeline([
  fileReadStream({ path: './data.csv' }),
])

Example — Browser

import { fileReadStream } from '@datastream/file'

const stream = await fileReadStream({
  types: [{ accept: { 'text/csv': ['.csv'] } }],
})

fileWriteStream Writable

Writes a stream to a file.

  • Node.js: Uses fs.createWriteStream
  • Browser: Uses window.showSaveFilePicker (File System Access API)

Options

OptionTypeDescription
pathstringFile path (Node.js), suggested file name (Browser)
basePathstringWhen provided, enforces that path resolves within basePath. Prevents path traversal and rejects symbolic links
typesobject[]File type filter

Example — Node.js

import { pipeline, createReadableStream } from '@datastream/core'
import { fileWriteStream } from '@datastream/file'

await pipeline([
  createReadableStream('hello world'),
  fileWriteStream({ path: './output.txt' }),
])

Example — Browser

import { fileWriteStream } from '@datastream/file'

const writable = await fileWriteStream({
  path: 'output.csv',
  types: [{ accept: { 'text/csv': ['.csv'] } }],
})

File type filtering

The types option validates file extensions (Node.js) and configures the file picker dialog (Browser):

const types = [
  {
    accept: {
      'text/csv': ['.csv'],
      'application/json': ['.json'],
    },
  },
]

On Node.js, if types is provided and the file extension doesn’t match, an "Invalid extension" error is thrown.

Security

When accepting file paths from user input, always use an absolute path or set basePath to prevent path traversal attacks (e.g., ../../etc/passwd). Relative paths without a basePath constraint can resolve outside the intended directory.

basePath is opt-in. When provided, paths are resolved and checked with path.resolve().startsWith(basePath), and symbolic links are rejected. When omitted, no path restriction is applied.

// Restrict reads to a specific directory
fileReadStream({ path: userInput, basePath: '/data/uploads', types })

// Convenience helper for cwd-scoped reads
const safeFileRead = (path, types) =>
  fileReadStream({ path, basePath: process.cwd(), types })