{"_id":"@cajuncodemonkey/json-streamify","_rev":"4-433a9f60afa219db4cd13781051caf06","name":"@cajuncodemonkey/json-streamify","dist-tags":{"latest":"2.0.1"},"versions":{"1.0.0":{"name":"@cajuncodemonkey/json-streamify","version":"1.0.0","keywords":["json","stream","stringify","base64","readable"],"author":{"name":"Ken Courville"},"license":"MIT","_id":"@cajuncodemonkey/json-streamify@1.0.0","maintainers":[{"name":"krcourville","email":"krcourville@gmail.com"}],"dist":{"shasum":"6119c118325cca4dcd92f92cabbf006ee61ff96c","tarball":"https://registry.npmjs.org/@cajuncodemonkey/json-streamify/-/json-streamify-1.0.0.tgz","fileCount":58,"integrity":"sha512-f3JX2XOnYJ2MnREaaBVbOYg8I6dnZeN0UQgcJ7jO5Kxw4BGC4oNFpYyQK4jHKS2r60wI/3fdptYXGRlG7l6jaw==","signatures":[{"sig":"MEYCIQCg+8CLhfJWGUIy0kkKAVnBPnVy37DkdK9QB3lz3B9ojgIhANqdg5BtR/OdfoPirQouo0GRGapx2Pve5WRriXMzpvw6","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":84164},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"ccf6ccaf838e246f42345d45ff7ac3d6c13b1776","scripts":{"pr":"npm run clean && npm run lint:fix && npm run format && npm run test && npm run build","dev":"tsc --watch","demo":"npm run demo:server & sleep 2 && npm run demo:client && pkill -f 'ts-node examples/server.ts'","lint":"eslint src examples --ext .ts","test":"jest","build":"npm run build:cjs && npm run build:esm","check":"npm run lint && npm run format:check && npm run test","clean":"rm -rf dist dist-esm","format":"prettier --write .","prepare":"npm run build","lint:fix":"eslint src examples --ext .ts --fix","build:cjs":"tsc -p tsconfig.build.json","build:esm":"tsc -p tsconfig.build.json --module esnext --outDir dist-esm && mv dist-esm/index.js dist/index.mjs && rm -rf dist-esm","demo:client":"ts-node examples/client.ts","demo:server":"ts-node examples/server.ts","format:check":"prettier --check .","demo:sparkpost":"ts-node examples/sparkpost-email.ts"},"_npmUser":{"name":"krcourville","email":"krcourville@gmail.com"},"_npmVersion":"10.9.2","description":"Like JSON.stringify but returns a Readable stream with Base64 encoding for nested streams","directories":{},"_nodeVersion":"22.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.0.0","dotenv":"^16.0.0","eslint":"^8.0.0","wretch":"^2.8.0","express":"^4.18.0","ts-jest":"^29.0.0","ts-node":"^10.9.0","prettier":"^3.0.0","typescript":"^5.0.0","@types/jest":"^29.0.0","@types/node":"^20.0.0","@types/express":"^4.17.0","eslint-config-prettier":"^9.0.0","eslint-plugin-prettier":"^5.0.0","@typescript-eslint/parser":"^6.0.0","@typescript-eslint/eslint-plugin":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/json-streamify_1.0.0_1752940992686_0.33705735798298564","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@cajuncodemonkey/json-streamify","version":"1.0.1","keywords":["json","stream","stringify","base64","readable"],"author":{"name":"Ken Courville"},"license":"MIT","_id":"@cajuncodemonkey/json-streamify@1.0.1","maintainers":[{"name":"krcourville","email":"krcourville@gmail.com"}],"dist":{"shasum":"9b3fcbd3f7c5d79725e25302cf3bd93f67e65bb1","tarball":"https://registry.npmjs.org/@cajuncodemonkey/json-streamify/-/json-streamify-1.0.1.tgz","fileCount":58,"integrity":"sha512-YEUEUZU1bSgfb1s50TGXVTKDQb8aM89KM0kB1wSzuOpgh0CgKB3ierB2mqPQsrFBeRaAN4mX2kJu5lKBuPqcAg==","signatures":[{"sig":"MEUCIFQZOwcflO1X0hukSXIdD5Sj7o3yUcbx8DLyRMWMBFhXAiEAtXpXTok/ASZ0WlINHsO0xBUTxCfBXunNbcfvr7TFwLw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":84295},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"e8aa670e71e4ed2d0c013f22286edbfcfd14b4a2","scripts":{"pr":"npm run clean && npm run lint:fix && npm run format && npm run test && npm run build","dev":"tsc --watch","demo":"npm run demo:server & sleep 2 && npm run demo:client && pkill -f 'ts-node examples/server.ts'","lint":"eslint src examples --ext .ts","test":"jest","build":"npm run build:cjs && npm run build:esm","check":"npm run lint && npm run format:check && npm run test","clean":"rm -rf dist dist-esm","format":"prettier --write .","prepare":"npm run build","lint:fix":"eslint src examples --ext .ts --fix","build:cjs":"tsc -p tsconfig.build.json","build:esm":"tsc -p tsconfig.build.json --module esnext --outDir dist-esm && mv dist-esm/index.js dist/index.mjs && rm -rf dist-esm","demo:client":"ts-node examples/client.ts","demo:server":"ts-node examples/server.ts","format:check":"prettier --check .","demo:sparkpost":"ts-node examples/sparkpost-email.ts"},"_npmUser":{"name":"krcourville","email":"krcourville@gmail.com"},"_npmVersion":"10.9.2","description":"Like JSON.stringify but returns a Readable stream with Base64 encoding for nested streams","directories":{},"_nodeVersion":"22.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.0.0","dotenv":"^16.0.0","eslint":"^8.0.0","wretch":"^2.8.0","express":"^4.18.0","ts-jest":"^29.0.0","ts-node":"^10.9.0","prettier":"^3.0.0","typescript":"^5.0.0","@types/jest":"^29.0.0","@types/node":"^20.0.0","@types/express":"^4.17.0","eslint-config-prettier":"^9.0.0","eslint-plugin-prettier":"^5.0.0","@typescript-eslint/parser":"^6.0.0","@typescript-eslint/eslint-plugin":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/json-streamify_1.0.1_1752941362704_0.1337618201281019","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@cajuncodemonkey/json-streamify","version":"2.0.0","keywords":["json","stream","stringify","base64","readable"],"author":{"name":"Ken Courville"},"license":"MIT","_id":"@cajuncodemonkey/json-streamify@2.0.0","maintainers":[{"name":"krcourville","email":"krcourville@gmail.com"}],"dist":{"shasum":"a834fb2b35bdcf1f7e677b8dff42a1946efdc926","tarball":"https://registry.npmjs.org/@cajuncodemonkey/json-streamify/-/json-streamify-2.0.0.tgz","fileCount":58,"integrity":"sha512-69YQUOeOWaKf8K8HQMBB+lhyxW/CvwEbw03Y/cVEWtGkPZonRdD171C4fcS+LTtFewr6sBOOqS3yPEg9ycyNfw==","signatures":[{"sig":"MEUCIQCLf03vNBT2r2TKG2UdCG27hBa0JTFJoZK0S1CF/GxKDQIgcGfUCOcqQiIO8SFbn2cDbhQ8yFkXQPyWN1I6VE0MOsg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":112129},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"15f418e62b8d8e4cb273d2e71a69fa5f29535176","scripts":{"pr":"npm run clean && npm run lint:fix && npm run format && npm run test && npm run build","dev":"tsc --watch","demo":"npm run demo:server & sleep 2 && npm run demo:client && pkill -f 'ts-node examples/server.ts'","lint":"eslint src examples --ext .ts","test":"jest","build":"npm run build:cjs && npm run build:esm","check":"npm run lint && npm run format:check && npm run test","clean":"rm -rf dist dist-esm","format":"prettier --write .","prepare":"npm run build","lint:fix":"eslint src examples --ext .ts --fix","build:cjs":"tsc -p tsconfig.build.json","build:esm":"tsc -p tsconfig.build.json --module esnext --outDir dist-esm && mv dist-esm/index.js dist/index.mjs && rm -rf dist-esm","demo:client":"ts-node examples/client.ts","demo:server":"ts-node examples/server.ts","format:check":"prettier --check .","demo:sparkpost":"ts-node examples/sparkpost-email.ts"},"_npmUser":{"name":"krcourville","email":"krcourville@gmail.com"},"_npmVersion":"10.9.2","description":"Like JSON.stringify but returns a ReadableStream with Base64 encoding for nested streams","directories":{},"_nodeVersion":"22.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.0.0","dotenv":"^16.0.0","eslint":"^8.0.0","wretch":"^2.8.0","express":"^4.18.0","ts-jest":"^29.0.0","ts-node":"^10.9.0","prettier":"^3.0.0","typescript":"^5.0.0","@types/jest":"^29.0.0","@types/node":"^20.0.0","@types/express":"^4.17.0","eslint-config-prettier":"^9.0.0","eslint-plugin-prettier":"^5.0.0","@typescript-eslint/parser":"^6.0.0","@typescript-eslint/eslint-plugin":"^6.0.0"},"_npmOperationalInternal":{"tmp":"tmp/json-streamify_2.0.0_1752945438631_0.6599587140476766","host":"s3://npm-registry-packages-npm-production"}},"2.0.1":{"name":"@cajuncodemonkey/json-streamify","version":"2.0.1","description":"Like JSON.stringify but returns a ReadableStream with Base64 encoding for nested streams","main":"dist/index.js","module":"dist/index.mjs","types":"dist/index.d.ts","exports":{".":{"import":"./dist/index.mjs","require":"./dist/index.js","types":"./dist/index.d.ts"}},"scripts":{"build":"npm run build:cjs && npm run build:esm","build:cjs":"tsc -p tsconfig.build.json","build:esm":"tsc -p tsconfig.build.json --module esnext --outDir dist-esm && mv dist-esm/index.js dist/index.mjs && rm -rf dist-esm","test":"jest","dev":"tsc --watch","clean":"rm -rf dist dist-esm","demo:server":"ts-node examples/server.ts","demo:client":"ts-node examples/client.ts","demo:sparkpost":"ts-node examples/sparkpost-email.ts","demo":"npm run demo:server & sleep 2 && npm run demo:client && pkill -f 'ts-node examples/server.ts'","lint":"eslint src examples --ext .ts","lint:fix":"eslint src examples --ext .ts --fix","format":"prettier --write .","format:check":"prettier --check .","check":"npm run lint && npm run format:check && npm run test","pr":"npm run clean && npm run lint:fix && npm run format && npm run test && npm run build","prepare":"npm run build"},"keywords":["json","stream","stringify","base64","readable"],"author":{"name":"Ken Courville"},"license":"MIT","devDependencies":{"typescript":"^5.0.0","@types/node":"^20.0.0","jest":"^29.0.0","@types/jest":"^29.0.0","ts-jest":"^29.0.0","express":"^4.18.0","@types/express":"^4.17.0","ts-node":"^10.9.0","wretch":"^2.8.0","dotenv":"^16.0.0","eslint":"^8.0.0","@typescript-eslint/eslint-plugin":"^6.0.0","@typescript-eslint/parser":"^6.0.0","eslint-config-prettier":"^9.0.0","eslint-plugin-prettier":"^5.0.0","prettier":"^3.0.0"},"engines":{"node":">=18.0.0"},"publishConfig":{"access":"public"},"_id":"@cajuncodemonkey/json-streamify@2.0.1","gitHead":"395a4b050c35f900a23e5c82f58f5fb7dc91ef5f","_nodeVersion":"22.15.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-WKjcVVoh2L5YLQsNBsskHACkL+QJj5aXSOBZovrTaQH4GoNOAHn9a1EKvMQzyZ5iUDOeHIMk2NfgiSJfV7wsTw==","shasum":"ce973a3022c8f613eeb71207a7c9ed17734d897d","tarball":"https://registry.npmjs.org/@cajuncodemonkey/json-streamify/-/json-streamify-2.0.1.tgz","fileCount":58,"unpackedSize":112201,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDeDSd4VK+Ju95O0xoLTaq1xSw+phn01ybd0k3IurvPegIgbw5B+RrNPkG3HyBcRTR3YSYE5e1sAibM1Cs4hrq4oog="}]},"_npmUser":{"name":"krcourville","email":"krcourville@gmail.com"},"directories":{},"maintainers":[{"name":"krcourville","email":"krcourville@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/json-streamify_2.0.1_1752955048504_0.19206614521521925"},"_hasShrinkwrap":false}},"time":{"created":"2025-07-19T16:03:12.569Z","modified":"2025-07-19T19:57:28.906Z","1.0.0":"2025-07-19T16:03:12.911Z","1.0.1":"2025-07-19T16:09:22.901Z","2.0.0":"2025-07-19T17:17:18.903Z","2.0.1":"2025-07-19T19:57:28.702Z"},"author":{"name":"Ken Courville"},"license":"MIT","keywords":["json","stream","stringify","base64","readable"],"description":"Like JSON.stringify but returns a ReadableStream with Base64 encoding for nested streams","maintainers":[{"name":"krcourville","email":"krcourville@gmail.com"}],"readme":"# json-streamify\n\nA streaming JSON serializer that automatically converts embedded ReadableStreams to Base64.\n\n## Table of Contents\n\n- [Why json-streamify?](#why-json-streamify)\n- [Key Features](#key-features)\n- [Installation](#installation)\n- [API](#api)\n- [Compatibility](#compatibility)\n- [Quick Start](#quick-start)\n- [Demo](#demo)\n- [Working with Streams](#working-with-streams)\n- [Additional Utilities](#additional-utilities)\n- [Common Use Cases](#common-use-cases)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Why json-streamify?\n\nWhen building APIs that need to send JSON with binary file data, you typically face two problems:\n\n1. **Memory usage**: Loading entire files into memory for JSON encoding\n2. **Encoding complexity**: Manually converting files to Base64 before JSON serialization\n\n`json-streamify` solves both by:\n\n- Accepting `ReadableStream` streams directly in your JSON structure\n- Automatically converting them to Base64 during serialization\n- Returning a `ReadableStream` for memory-efficient HTTP requests\n\n## Key Features\n\n- **Drop-in replacement** for `JSON.stringify()` with stream support\n- **Automatic Base64 encoding** of any `ReadableStream` streams in your data\n- **Memory efficient** - streams files instead of loading into memory\n- **TypeScript support** with full type definitions\n- **Dual module support** - works with both CommonJS and ES modules\n\n## Installation\n\n```sh\nnpm install @cajuncodemonkey/json-streamify\n```\n\n## API\n\n### `jsonStreamify(value, replacer?, space?)`\n\nWorks exactly like `JSON.stringify()` but returns a `ReadableStream` and automatically converts embedded `ReadableStream` streams to Base64.\n\n**Parameters:**\n\n- `value` - The value to serialize (can contain `ReadableStream` streams)\n- `replacer` - Optional function to transform values (same as JSON.stringify)\n- `space` - Optional formatting parameter (same as JSON.stringify)\n\n**Returns:** `ReadableStream<string>` - A stream that outputs the JSON string\n\n#### `streamToString(stream)`\n\nUtility function to convert a `ReadableStream` to a string.\n\n**Parameters:**\n\n- `stream` - The `ReadableStream` to convert\n\n**Returns:** `Promise<string>` - Promise that resolves to the complete string content\n\n#### `createStreamFromFile(filePath)`\n\nUtility function to create a `ReadableStream` from a file.\n\n**Parameters:**\n\n- `filePath` - The path to the file to read\n\n**Returns:** `ReadableStream<Uint8Array>` - A stream containing the file content\n\n## Compatibility\n\n- **Node.js**: 18.0.0 or higher (uses Web Streams API)\n- **Browsers**: Modern browsers with ReadableStream support\n- **Deno**: Full support for web standard streams\n- **TypeScript**: Full type definitions included\n- **Modules**: Supports both CommonJS (`require`) and ES modules (`import`)\n\n## Quick Start\n\n```typescript\nimport { jsonStreamify, streamToString } from '@cajuncodemonkey/json-streamify';\n\n// Your data with embedded file streams\nconst payload = {\n  message: 'Upload request',\n  file: new ReadableStream({\n    start(controller) {\n      controller.enqueue(new TextEncoder().encode('Hello, World!'));\n      controller.close();\n    },\n  }),\n  metadata: { filename: 'hello.txt' },\n};\n\n// Convert to JSON stream (file automatically becomes Base64)\nconst jsonStream = jsonStreamify(payload);\n\n// Use directly with fetch - no manual Base64 conversion needed!\nconst response = await fetch('/api/upload', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: jsonStream,\n  duplex: 'half', // Required for streaming bodies\n} as RequestInit); // Type assertion needed for TypeScript compatibility\n\n// Or with wretch for cleaner API calls\nimport wretch from 'wretch';\n\nconst result = await wretch('/api/upload')\n  .headers({ 'Content-Type': 'application/json' })\n  .body(jsonStream)\n  .options({ duplex: 'half' })\n  .post()\n  .json();\n```\n\n### What the server receives\n\n```json\n{\n  \"message\": \"Upload request\",\n  \"file\": \"SGVsbG8sIFdvcmxkIQ==\",\n  \"metadata\": { \"filename\": \"hello.txt\" }\n}\n```\n\nThe `ReadableStream` was automatically converted to Base64!\n\n## Demo\n\nRun the included demonstration to see json-streamify working with a real web API:\n\n```bash\nnpm run demo\n```\n\nThis starts a local Express server that accepts Base64-encoded files and demonstrates:\n\n- Converting Readable streams to Base64 within JSON\n- HTTP transmission of the resulting JSON\n- Server-side decoding and file reconstruction\n- Metadata preservation throughout the process\n\nSee [examples/README.md](examples/README.md) for detailed demo documentation.\n\n## Working with Streams\n\n### Using Web Standard ReadableStreams\n\n`json-streamify` uses the web standard `ReadableStream` API, making it compatible across Node.js, browsers, and Deno:\n\n```typescript\nimport { jsonStreamify } from '@cajuncodemonkey/json-streamify';\n\n// Create a ReadableStream from data\nconst dataStream = new ReadableStream({\n  start(controller) {\n    controller.enqueue(new TextEncoder().encode('Hello, World!'));\n    controller.close();\n  },\n});\n\nconst payload = { attachment: dataStream };\nconst jsonStream = jsonStreamify(payload);\n```\n\n### Converting Node.js Streams to ReadableStream\n\nFor Node.js built-in streams, convert them to web ReadableStreams:\n\n```typescript\nimport { createReadStream } from 'fs';\nimport { Readable } from 'stream';\n\n// Convert Node.js Readable to web ReadableStream\nconst nodeStream = createReadStream('./document.pdf');\nconst webStream = Readable.toWeb(nodeStream);\n\nconst payload = { attachment: webStream };\nconst jsonStream = jsonStreamify(payload);\n```\n\n### Creating ReadableStreams from Data\n\n```typescript\n// From Uint8Array\nconst binaryStream = new ReadableStream({\n  start(controller) {\n    const data = new Uint8Array([72, 101, 108, 108, 111]); // \"Hello\"\n    controller.enqueue(data);\n    controller.close();\n  },\n});\n\n// From string chunks\nconst textStream = new ReadableStream({\n  start(controller) {\n    const chunks = ['Hello', ' ', 'World', '!'];\n    chunks.forEach(chunk =>\n      controller.enqueue(new TextEncoder().encode(chunk))\n    );\n    controller.close();\n  },\n});\n```\n\n## Additional Utilities\n\nThe library also exports two utility functions that are useful for stream handling:\n\n### `streamToString(stream)` utility\n\n```typescript\nimport { streamToString } from '@cajuncodemonkey/json-streamify';\n\nconst stream = new ReadableStream({\n  start(controller) {\n    controller.enqueue('Hello');\n    controller.enqueue(' ');\n    controller.enqueue('World');\n    controller.close();\n  },\n});\nconst text = await streamToString(stream);\nconsole.log(text); // \"Hello World\"\n```\n\n### `createStreamFromFile(filePath)` utility\n\n```typescript\nimport { createStreamFromFile } from '@cajuncodemonkey/json-streamify';\n\nconst fileStream = createStreamFromFile('./document.pdf');\n// Use the stream in your JSON payload\nconst payload = { attachment: fileStream };\n```\n\n## Common Use Cases\n\n- **File uploads in JSON APIs** - Send files as part of JSON requests\n- **GraphQL mutations** - Include binary data in GraphQL variables\n- **Webhooks with attachments** - Send files along with metadata\n- **Microservice communication** - Pass files between services via JSON\n- **API testing** - Mock file uploads in test suites\n\n## Contributing\n\nInterested in contributing? See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, testing, code quality standards, and publishing guidelines.\n\n## License\n\nThis library applies a MIT license. Use it however you want at your own risk. Feel free to copy/paste\nthe code to your own repo vs using the npm package.\n","readmeFilename":"README.md"}