Compare commits

...

8 Commits

Author SHA1 Message Date
jkunz 868e33c0f4 v13.1.3
Default (tags) / security (push) Failing after 1s
Default (tags) / test (push) Failing after 1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-04-30 07:29:24 +00:00
jkunz 8a9c4175dc fix(config): migrate project config and harden SmartFile and StreamFile defaults for updated toolchain compatibility 2026-04-30 07:29:24 +00:00
jkunz 66c8de91ee 13.1.2
Default (tags) / security (push) Failing after 1s
Default (tags) / test (push) Failing after 1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-12-13 11:24:01 +00:00
jkunz 857469e86e 13.1.1
Default (tags) / security (push) Failing after 1s
Default (tags) / test (push) Failing after 1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-12-13 11:23:38 +00:00
jkunz 2e429ace56 v13.1.0 2025-11-29 17:42:44 +00:00
jkunz 055b78e5ea feat(smartfs): Integrate @push.rocks/smartfs and wire SmartFileFactory.nodeFs to return a real SmartFs instance 2025-11-29 17:42:44 +00:00
jkunz ff620acece v13.0.1 2025-11-22 13:41:24 +00:00
jkunz bfc0c0576b fix(smartfile): Stream and filesystem integrations: remove fs-extra, switch to fs/promises.rename, add Web WritableStream compatibility, and use smartFs recursive directory methods; update plugins exports and README. 2025-11-22 13:41:24 +00:00
13 changed files with 2909 additions and 4042 deletions
+18 -29
View File
@@ -1,45 +1,34 @@
{ {
"npmdocker": {}, "@git.zone/cli": {
"npmci": {
"npmGlobalTools": [],
"npmAccessLevel": "public"
},
"gitzone": {
"projectType": "npm", "projectType": "npm",
"module": { "module": {
"githost": "code.foss.global", "githost": "code.foss.global",
"gitscope": "push.rocks", "gitscope": "push.rocks",
"gitrepo": "smartfile", "gitrepo": "smartfile",
"description": "Provides comprehensive tools for efficient file management in Node.js using TypeScript, including handling streams, virtual directories, and various file operations.", "description": "High-level file representation classes (SmartFile, StreamFile, VirtualDirectory) for efficient in-memory file management in Node.js using TypeScript. Works seamlessly with @push.rocks/smartfs for filesystem operations.",
"npmPackagename": "@push.rocks/smartfile", "npmPackagename": "@push.rocks/smartfile",
"license": "MIT", "license": "MIT",
"keywords": [ "projectDomain": "push.rocks"
"file management", },
"TypeScript", "release": {
"Node.js", "registries": [
"file operations", "https://verdaccio.lossless.digital",
"file manipulation", "https://registry.npmjs.org"
"file streaming", ],
"virtual directory", "accessLevel": "public"
"filesystem utilities",
"memory-efficient file handling",
"custom file operations",
"write files",
"read files",
"copy files",
"delete files",
"list directories",
"handle large files",
"virtual filesystems",
"buffer operations"
]
} }
}, },
"tsdoc": { "@git.zone/tsdoc": {
"classes": ["SmartFile", "StreamFile"], "classes": [
"SmartFile",
"StreamFile"
],
"descriptions": [ "descriptions": [
"the purpose of the StreamFile class is to provide a hybrid interface between streaming files and simple handling when writing and reading those files multiple times." "the purpose of the StreamFile class is to provide a hybrid interface between streaming files and simple handling when writing and reading those files multiple times."
], ],
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n" "legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
},
"@ship.zone/szci": {
"npmGlobalTools": []
} }
} }
+26
View File
@@ -1,5 +1,31 @@
# Changelog # Changelog
## 2026-04-30 - 13.1.3 - fix(config)
migrate project config and harden SmartFile and StreamFile defaults for updated toolchain compatibility
- replace npmextra.json with .smartconfig.json and update package metadata for the current release tooling
- simplify the build script and align tsconfig with the newer TypeScript toolchain by enabling noImplicitAny
- initialize SmartFile properties with safe defaults and remove empty-file constructor logging
- validate StreamFile response streams and require a relative file path before writing to a directory
- update runtime and development dependencies to current major and minor versions
## 2025-11-29 - 13.1.0 - feat(smartfs)
Integrate @push.rocks/smartfs and wire SmartFileFactory.nodeFs to return a real SmartFs instance
- Add runtime dependency @push.rocks/smartfs@^1.1.0 to package.json (previous peerDependency removed).
- Export smartfs from ts/plugins.ts so internal modules can access SmartFs and providers.
- Implement SmartFileFactory.nodeFs() to instantiate plugins.smartfs.SmartFs with SmartFsProviderNode and return a factory bound to that SmartFs.
- Enable factory-created SmartFile/StreamFile/VirtualDirectory instances to use the bound SmartFs for filesystem operations (read/write/streams).
## 2025-11-22 - 13.0.1 - fix(smartfile)
Stream and filesystem integrations: remove fs-extra, switch to fs/promises.rename, add Web WritableStream compatibility, and use smartFs recursive directory methods; update plugins exports and README.
- Remove fs-extra dependency and its types from package.json and stop exporting fsExtra from plugins.
- Replace fs-extra rename with fs/promises.rename in SmartFile.rename to use native promises API.
- Add Web WritableStream handling in StreamFile.writeToDisk (convert to Node.js Writable via Writable.fromWeb) and ensure Web ReadableStream conversion in createReadStream.
- Use smartFs.directory(...).recursive().create() when creating directories and smartFs.directory(path).recursive().list() when listing to ensure recursive behavior.
- Update README to add Issue Reporting and Security section pointing to community.foss.global for bug/vulnerability reports.
## 2025-11-22 - 13.0.0 - BREAKING CHANGE(SmartFileFactory) ## 2025-11-22 - 13.0.0 - BREAKING CHANGE(SmartFileFactory)
Refactor to in-memory file API and introduce SmartFileFactory; delegate filesystem operations to @push.rocks/smartfs; bump to 12.0.0 Refactor to in-memory file API and introduce SmartFileFactory; delegate filesystem operations to @push.rocks/smartfs; bump to 12.0.0
+17 -29
View File
@@ -1,14 +1,14 @@
{ {
"name": "@push.rocks/smartfile", "name": "@push.rocks/smartfile",
"private": false, "private": false,
"version": "13.0.0", "version": "13.1.3",
"description": "High-level file representation classes (SmartFile, StreamFile, VirtualDirectory) for efficient in-memory file management in Node.js using TypeScript. Works seamlessly with @push.rocks/smartfs for filesystem operations.", "description": "High-level file representation classes (SmartFile, StreamFile, VirtualDirectory) for efficient in-memory file management in Node.js using TypeScript. Works seamlessly with @push.rocks/smartfs for filesystem operations.",
"main": "dist_ts/index.js", "main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts", "typings": "dist_ts/index.d.ts",
"type": "module", "type": "module",
"scripts": { "scripts": {
"test": "(tstest test/ --verbose --logfile --timeout 120)", "test": "(tstest test/ --verbose --logfile --timeout 120)",
"build": "(tsbuild --web --allowimplicitany)", "build": "tsbuild",
"buildDocs": "tsdoc" "buildDocs": "tsdoc"
}, },
"repository": { "repository": {
@@ -31,42 +31,33 @@
"buffer operations", "buffer operations",
"file content manipulation" "file content manipulation"
], ],
"author": "Lossless GmbH <hello@lossless.com> (https://lossless.com)", "author": "Task Venture Capital GmbH",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://code.foss.global/push.rocks/smartfile/issues" "url": "https://code.foss.global/push.rocks/smartfile/issues"
}, },
"homepage": "https://code.foss.global/push.rocks/smartfile#readme", "homepage": "https://code.foss.global/push.rocks/smartfile#readme",
"dependencies": { "dependencies": {
"@push.rocks/lik": "^6.2.2", "@push.rocks/lik": "^6.4.0",
"@push.rocks/smartdelay": "^3.0.5", "@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartfile-interfaces": "^1.0.7", "@push.rocks/smartfile-interfaces": "^1.0.7",
"@push.rocks/smarthash": "^3.2.3", "@push.rocks/smarthash": "^3.2.7",
"@push.rocks/smartjson": "^5.0.20", "@push.rocks/smartjson": "^6.0.1",
"@push.rocks/smartmime": "^2.0.4", "@push.rocks/smartmime": "^2.0.4",
"@push.rocks/smartpath": "^6.0.0", "@push.rocks/smartpath": "^6.0.0",
"@push.rocks/smartpromise": "^4.2.3", "@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartrequest": "^4.2.1", "@push.rocks/smartrequest": "^5.0.1",
"@push.rocks/smartstream": "^3.2.5", "@push.rocks/smartstream": "^3.4.0",
"@types/fs-extra": "^11.0.4",
"@types/js-yaml": "^4.0.9", "@types/js-yaml": "^4.0.9",
"fs-extra": "^11.3.1", "glob": "^13.0.6",
"glob": "^11.0.3", "js-yaml": "^4.1.0",
"js-yaml": "^4.1.0" "@push.rocks/smartfs": "^1.5.0"
},
"peerDependencies": {
"@push.rocks/smartfs": "^1.0.0"
},
"peerDependenciesMeta": {
"@push.rocks/smartfs": {
"optional": true
}
}, },
"devDependencies": { "devDependencies": {
"@git.zone/tsbuild": "^2.6.4", "@git.zone/tsbuild": "^4.4.0",
"@git.zone/tsrun": "^1.3.3", "@git.zone/tsrun": "^2.0.2",
"@git.zone/tstest": "^2.3.4", "@git.zone/tstest": "^3.6.3",
"@types/node": "^22.15.21" "@types/node": "^25.6.0"
}, },
"files": [ "files": [
"ts/**/*", "ts/**/*",
@@ -77,14 +68,11 @@
"dist_ts_web/**/*", "dist_ts_web/**/*",
"assets/**/*", "assets/**/*",
"cli.js", "cli.js",
"npmextra.json", ".smartconfig.json",
"readme.md" "readme.md"
], ],
"browserslist": [ "browserslist": [
"last 1 chrome versions" "last 1 chrome versions"
], ],
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39", "packageManager": "pnpm@10.28.2"
"pnpm": {
"overrides": {}
}
} }
+2634 -3873
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -8,6 +8,10 @@
Think of it as your go-to solution for **content manipulation**, **file transformations**, and **in-memory file operations** - all while seamlessly integrating with [@push.rocks/smartfs](https://code.foss.global/push.rocks/smartfs) for actual filesystem operations. Think of it as your go-to solution for **content manipulation**, **file transformations**, and **in-memory file operations** - all while seamlessly integrating with [@push.rocks/smartfs](https://code.foss.global/push.rocks/smartfs) for actual filesystem operations.
## Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who want to sign a contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
## 💾 Installation ## 💾 Installation
```bash ```bash
+168 -82
View File
@@ -1,95 +1,181 @@
/** /**
* Mock SmartFs implementation for testing until @push.rocks/smartfs is available * Mock SmartFs implementation for testing
* This wraps fs-extra to provide the SmartFs interface * Provides fluent API matching @push.rocks/smartfs using native Node.js fs
*/ */
import { ensureDir, pathExists, remove, copy } from 'fs-extra';
import { promises as fsPromises, createReadStream, createWriteStream } from 'fs'; import { promises as fsPromises, createReadStream, createWriteStream } from 'fs';
import * as path from 'path'; import * as path from 'path';
import { Readable, Writable } from 'stream'; import { Readable, Writable } from 'stream';
export class MockSmartFs { /**
public file(filePath: string) { * Mock SmartFsFile - Fluent file operations builder
return { */
async read(): Promise<string | Buffer> { class MockSmartFsFile {
return await fsPromises.readFile(filePath); private filePath: string;
}, private options: {
async write(content: string | Buffer): Promise<void> { encoding?: BufferEncoding;
await ensureDir(path.dirname(filePath)); recursive?: boolean;
await fsPromises.writeFile(filePath, content); } = {};
},
async exists(): Promise<boolean> { constructor(filePath: string) {
return await pathExists(filePath); this.filePath = filePath;
},
async delete(): Promise<void> {
await remove(filePath);
},
async stat(): Promise<any> {
return await fsPromises.stat(filePath);
},
async readStream(): Promise<Readable> {
return Promise.resolve(createReadStream(filePath));
},
async writeStream(): Promise<Writable> {
await ensureDir(path.dirname(filePath));
return Promise.resolve(createWriteStream(filePath));
},
async copy(dest: string): Promise<void> {
await copy(filePath, dest);
},
};
} }
public directory(dirPath: string) { // Configuration methods (return this for chaining)
return { public encoding(encoding: BufferEncoding): this {
async list(options?: { recursive?: boolean }): Promise<Array<{ path: string; isFile: boolean; isDirectory: boolean }>> { this.options.encoding = encoding;
const entries: Array<{ path: string; isFile: boolean; isDirectory: boolean }> = []; return this;
}
if (options?.recursive) { public recursive(): this {
// Recursive listing this.options.recursive = true;
const walk = async (dir: string) => { return this;
const items = await fsPromises.readdir(dir); }
for (const item of items) {
const fullPath = path.join(dir, item);
const stats = await fsPromises.stat(fullPath);
if (stats.isFile()) { // Action methods (return Promises)
entries.push({ path: fullPath, isFile: true, isDirectory: false }); public async read(): Promise<string | Buffer> {
} else if (stats.isDirectory()) { if (this.options.encoding) {
entries.push({ path: fullPath, isFile: false, isDirectory: true }); return await fsPromises.readFile(this.filePath, this.options.encoding);
await walk(fullPath); }
} return await fsPromises.readFile(this.filePath);
} }
};
await walk(dirPath);
} else {
// Non-recursive listing
const items = await fsPromises.readdir(dirPath);
for (const item of items) {
const fullPath = path.join(dirPath, item);
const stats = await fsPromises.stat(fullPath);
entries.push({
path: fullPath,
isFile: stats.isFile(),
isDirectory: stats.isDirectory(),
});
}
}
return entries; public async write(content: string | Buffer): Promise<void> {
}, // Ensure directory exists
async create(options?: { recursive?: boolean }): Promise<void> { const dirPath = path.dirname(this.filePath);
if (options?.recursive) { await fsPromises.mkdir(dirPath, { recursive: true });
await ensureDir(dirPath);
} else { if (this.options.encoding && typeof content === 'string') {
await fsPromises.mkdir(dirPath); await fsPromises.writeFile(this.filePath, content, this.options.encoding);
} } else {
}, await fsPromises.writeFile(this.filePath, content);
async exists(): Promise<boolean> { }
return await pathExists(dirPath); }
},
async delete(): Promise<void> { public async exists(): Promise<boolean> {
await remove(dirPath); try {
}, await fsPromises.access(this.filePath);
}; return true;
} catch {
return false;
}
}
public async delete(): Promise<void> {
await fsPromises.unlink(this.filePath);
}
public async stat(): Promise<any> {
return await fsPromises.stat(this.filePath);
}
public async readStream(): Promise<Readable> {
return createReadStream(this.filePath);
}
public async writeStream(): Promise<Writable> {
// Ensure directory exists
const dirPath = path.dirname(this.filePath);
await fsPromises.mkdir(dirPath, { recursive: true });
return createWriteStream(this.filePath);
}
public async copy(dest: string): Promise<void> {
await fsPromises.copyFile(this.filePath, dest);
}
}
/**
* Mock SmartFsDirectory - Fluent directory operations builder
*/
class MockSmartFsDirectory {
private dirPath: string;
private options: {
recursive?: boolean;
} = {};
constructor(dirPath: string) {
this.dirPath = dirPath;
}
// Configuration methods (return this for chaining)
public recursive(): this {
this.options.recursive = true;
return this;
}
// Action methods (return Promises)
public async list(): Promise<Array<{ path: string; isFile: boolean; isDirectory: boolean }>> {
const entries: Array<{ path: string; isFile: boolean; isDirectory: boolean }> = [];
if (this.options.recursive) {
// Recursive listing
const walk = async (dir: string) => {
const items = await fsPromises.readdir(dir);
for (const item of items) {
const fullPath = path.join(dir, item);
const stats = await fsPromises.stat(fullPath);
if (stats.isFile()) {
entries.push({ path: fullPath, isFile: true, isDirectory: false });
} else if (stats.isDirectory()) {
entries.push({ path: fullPath, isFile: false, isDirectory: true });
await walk(fullPath);
}
}
};
await walk(this.dirPath);
} else {
// Non-recursive listing
const items = await fsPromises.readdir(this.dirPath);
for (const item of items) {
const fullPath = path.join(this.dirPath, item);
const stats = await fsPromises.stat(fullPath);
entries.push({
path: fullPath,
isFile: stats.isFile(),
isDirectory: stats.isDirectory(),
});
}
}
return entries;
}
public async create(): Promise<void> {
if (this.options.recursive) {
await fsPromises.mkdir(this.dirPath, { recursive: true });
} else {
await fsPromises.mkdir(this.dirPath);
}
}
public async exists(): Promise<boolean> {
try {
const stats = await fsPromises.stat(this.dirPath);
return stats.isDirectory();
} catch {
return false;
}
}
public async delete(): Promise<void> {
if (this.options.recursive) {
await fsPromises.rm(this.dirPath, { recursive: true, force: true });
} else {
await fsPromises.rmdir(this.dirPath);
}
}
}
/**
* Mock SmartFs - Main class matching @push.rocks/smartfs API
*/
export class MockSmartFs {
public file(filePath: string): MockSmartFsFile {
return new MockSmartFsFile(filePath);
}
public directory(dirPath: string): MockSmartFsDirectory {
return new MockSmartFsDirectory(dirPath);
} }
} }
+1 -1
View File
@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@push.rocks/smartfile', name: '@push.rocks/smartfile',
version: '13.0.0', version: '13.1.3',
description: 'High-level file representation classes (SmartFile, StreamFile, VirtualDirectory) for efficient in-memory file management in Node.js using TypeScript. Works seamlessly with @push.rocks/smartfs for filesystem operations.' description: 'High-level file representation classes (SmartFile, StreamFile, VirtualDirectory) for efficient in-memory file management in Node.js using TypeScript. Works seamlessly with @push.rocks/smartfs for filesystem operations.'
} }
+1 -3
View File
@@ -14,9 +14,7 @@ export class SmartFileFactory {
* Creates a default factory using Node.js filesystem provider * Creates a default factory using Node.js filesystem provider
*/ */
public static nodeFs(): SmartFileFactory { public static nodeFs(): SmartFileFactory {
// Temporarily using a placeholder - will be replaced with actual SmartFs initialization const smartFs = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode());
// const smartFs = new SmartFs(new SmartFsProviderNode());
const smartFs = null; // Placeholder
return new SmartFileFactory(smartFs); return new SmartFileFactory(smartFs);
} }
+14 -11
View File
@@ -23,7 +23,7 @@ export class SmartFile extends plugins.smartjson.Smartjson {
* the relative path of the file * the relative path of the file
*/ */
@plugins.smartjson.foldDec() @plugins.smartjson.foldDec()
public path: string; public accessor path: string = '';
/** /**
* a parsed path * a parsed path
@@ -43,20 +43,20 @@ export class SmartFile extends plugins.smartjson.Smartjson {
* the content of the file as Buffer * the content of the file as Buffer
*/ */
@plugins.smartjson.foldDec() @plugins.smartjson.foldDec()
public contentBuffer: Buffer; public accessor contentBuffer: Buffer = Buffer.alloc(0);
/** /**
* The current working directory of the file * The current working directory of the file
* Note:this is similar to gulp and different from native node path base * Note:this is similar to gulp and different from native node path base
*/ */
@plugins.smartjson.foldDec() @plugins.smartjson.foldDec()
public base: string; public accessor base: string = process.cwd();
/** /**
* sync the file with disk * sync the file with disk
*/ */
@plugins.smartjson.foldDec() @plugins.smartjson.foldDec()
public sync: boolean; public accessor sync: boolean = false;
/** /**
* the constructor of Smartfile * the constructor of Smartfile
@@ -64,13 +64,16 @@ export class SmartFile extends plugins.smartjson.Smartjson {
* @param smartFs optional SmartFs instance for filesystem operations * @param smartFs optional SmartFs instance for filesystem operations
*/ */
constructor(optionsArg: ISmartfileConstructorOptions, smartFs?: any) { constructor(
optionsArg: ISmartfileConstructorOptions = {
path: '',
contentBuffer: Buffer.alloc(0),
base: process.cwd(),
},
smartFs?: any,
) {
super(); super();
if (optionsArg.contentBuffer) { this.contentBuffer = optionsArg.contentBuffer || Buffer.alloc(0);
this.contentBuffer = optionsArg.contentBuffer;
} else {
console.log('created empty Smartfile?');
}
this.path = optionsArg.path; this.path = optionsArg.path;
this.base = optionsArg.base; this.base = optionsArg.base;
this.smartFs = smartFs; this.smartFs = smartFs;
@@ -203,7 +206,7 @@ export class SmartFile extends plugins.smartjson.Smartjson {
); );
// Rename the file on disk // Rename the file on disk
await plugins.fsExtra.rename(oldAbsolutePath, newAbsolutePath); await plugins.fsPromises.rename(oldAbsolutePath, newAbsolutePath);
} }
// Return the new path // Return the new path
+21 -7
View File
@@ -1,5 +1,5 @@
import * as plugins from './plugins.js'; import * as plugins from './plugins.js';
import { Readable } from 'stream'; import { Readable, Writable } from 'stream';
type TStreamSource = (streamFile: StreamFile) => Promise<Readable | ReadableStream>; type TStreamSource = (streamFile: StreamFile) => Promise<Readable | ReadableStream>;
@@ -33,7 +33,11 @@ export class StreamFile {
const response = await plugins.smartrequest.SmartRequest.create() const response = await plugins.smartrequest.SmartRequest.create()
.url(url) .url(url)
.get(); .get();
return response.stream(); const responseStream = response.stream();
if (!responseStream) {
throw new Error(`No response stream available for ${url}`);
}
return responseStream;
}; };
const streamFile = new StreamFile(streamSource, undefined, smartFs); const streamFile = new StreamFile(streamSource, undefined, smartFs);
streamFile.multiUse = true; streamFile.multiUse = true;
@@ -117,9 +121,9 @@ export class StreamFile {
// enable stream based multi use // enable stream based multi use
private cachedStreamBuffer?: Buffer; private cachedStreamBuffer?: Buffer;
public multiUse: boolean; public multiUse: boolean = false;
public used: boolean = false; public used: boolean = false;
public byteLengthComputeFunction: () => Promise<number>; public byteLengthComputeFunction?: () => Promise<number>;
private constructor(streamSource: TStreamSource, relativeFilePath?: string, smartFs?: any) { private constructor(streamSource: TStreamSource, relativeFilePath?: string, smartFs?: any) {
this.streamSource = streamSource; this.streamSource = streamSource;
@@ -163,7 +167,13 @@ export class StreamFile {
this.checkMultiUse(); this.checkMultiUse();
const readStream = await this.createReadStream(); const readStream = await this.createReadStream();
const writeStream = await this.smartFs.file(filePathArg).writeStream(); let writeStream = await this.smartFs.file(filePathArg).writeStream();
// Check if it's a Web WritableStream and convert to Node.js Writable
if (writeStream && typeof (writeStream as any).getWriter === 'function') {
// This is a Web WritableStream, convert it to Node.js Writable
writeStream = Writable.fromWeb(writeStream as any);
}
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
readStream.pipe(writeStream); readStream.pipe(writeStream);
@@ -179,9 +189,13 @@ export class StreamFile {
} }
this.checkMultiUse(); this.checkMultiUse();
if (!this.relativeFilePath) {
throw new Error('Cannot write stream to directory without a relative file path.');
}
const filePath = plugins.path.join(dirPathArg, this.relativeFilePath); const filePath = plugins.path.join(dirPathArg, this.relativeFilePath);
const dirPath = plugins.path.parse(filePath).dir; const dirPath = plugins.path.parse(filePath).dir;
await this.smartFs.directory(dirPath).create({ recursive: true }); await this.smartFs.directory(dirPath).recursive().create();
return this.writeToDisk(filePath); return this.writeToDisk(filePath);
} }
@@ -207,7 +221,7 @@ export class StreamFile {
/** /**
* Returns the size of the file content in bytes. * Returns the size of the file content in bytes.
*/ */
public async getSize(): Promise<number> { public async getSize(): Promise<number | null> {
if (this.byteLengthComputeFunction) { if (this.byteLengthComputeFunction) {
return this.byteLengthComputeFunction(); return this.byteLengthComputeFunction();
} else { } else {
+1 -1
View File
@@ -23,7 +23,7 @@ export class VirtualDirectory {
const newVirtualDir = new VirtualDirectory(smartFs, factory); const newVirtualDir = new VirtualDirectory(smartFs, factory);
// Use smartFs to list directory and factory to create SmartFiles // Use smartFs to list directory and factory to create SmartFiles
const entries = await smartFs.directory(pathArg).list({ recursive: true }); const entries = await smartFs.directory(pathArg).recursive().list();
const smartfiles = await Promise.all( const smartfiles = await Promise.all(
entries entries
.filter((entry: any) => entry.isFile) .filter((entry: any) => entry.isFile)
+3 -2
View File
@@ -10,6 +10,7 @@ export { fs, fsPromises, path, stream };
import * as lik from '@push.rocks/lik'; import * as lik from '@push.rocks/lik';
import * as smartfileInterfaces from '@push.rocks/smartfile-interfaces'; import * as smartfileInterfaces from '@push.rocks/smartfile-interfaces';
import * as smartdelay from '@push.rocks/smartdelay'; import * as smartdelay from '@push.rocks/smartdelay';
import * as smartfs from '@push.rocks/smartfs';
import * as smarthash from '@push.rocks/smarthash'; import * as smarthash from '@push.rocks/smarthash';
import * as smartjson from '@push.rocks/smartjson'; import * as smartjson from '@push.rocks/smartjson';
import * as smartmime from '@push.rocks/smartmime'; import * as smartmime from '@push.rocks/smartmime';
@@ -22,6 +23,7 @@ export {
lik, lik,
smartfileInterfaces, smartfileInterfaces,
smartdelay, smartdelay,
smartfs,
smarthash, smarthash,
smartjson, smartjson,
smartmime, smartmime,
@@ -32,8 +34,7 @@ export {
}; };
// third party scope // third party scope
import fsExtra from 'fs-extra';
import * as glob from 'glob'; import * as glob from 'glob';
import yaml from 'js-yaml'; import yaml from 'js-yaml';
export { fsExtra, glob, yaml }; export { glob, yaml };
+1 -4
View File
@@ -1,14 +1,11 @@
{ {
"compilerOptions": { "compilerOptions": {
"experimentalDecorators": true,
"useDefineForClassFields": false,
"target": "ES2022", "target": "ES2022",
"module": "NodeNext", "module": "NodeNext",
"moduleResolution": "NodeNext", "moduleResolution": "NodeNext",
"esModuleInterop": true, "esModuleInterop": true,
"verbatimModuleSyntax": true, "verbatimModuleSyntax": true,
"baseUrl": ".", "noImplicitAny": true
"paths": {}
}, },
"exclude": ["dist_*/**/*.d.ts"] "exclude": ["dist_*/**/*.d.ts"]
} }