Compare commits

...

25 Commits

Author SHA1 Message Date
207320ff26 11.1.3 2025-01-07 04:36:32 +01:00
be99bdae66 fix(fs): Fix TypeScript type issue in fs module 2025-01-07 04:36:32 +01:00
768d970918 11.1.2 2025-01-07 04:35:56 +01:00
a9799e05ee fix(fs): Fix issues in file stability check and directory existence verification in fs module 2025-01-07 04:35:56 +01:00
7c07c5c174 11.1.1 2025-01-07 04:30:39 +01:00
4c4e41b158 fix(fs): Improve waitForFileToBeReady function for file stability detection 2025-01-07 04:30:39 +01:00
d557e4b4fe 11.1.0 2025-01-07 04:15:33 +01:00
16ded5c3cf feat(SmartFile): Add rename functionality to SmartFile class 2025-01-07 04:15:32 +01:00
a2bd049ebd 11.0.23 2024-12-15 21:40:19 +01:00
f95c5c9a15 fix(fs): Handle errors in toObjectSync method 2024-12-15 21:40:19 +01:00
b55a3eb83f 11.0.22 2024-06-23 23:59:07 +02:00
fc8d994943 fix(core): Update dependencies and changelog 2024-06-23 23:59:07 +02:00
f1daec6f44 11.0.21 2024-06-23 23:55:55 +02:00
6698a583e9 fix(dependencies): Update dependencies to latest versions 2024-06-23 23:55:54 +02:00
bf52f01365 11.0.20 2024-06-07 17:13:08 +02:00
14adec5ba3 fix(core): update 2024-06-07 17:13:07 +02:00
fb2880c995 11.0.19 2024-06-07 12:24:54 +02:00
0e0ae7e42f fix(core): update 2024-06-07 12:24:53 +02:00
1391dbddbc 11.0.18 2024-06-06 23:33:36 +02:00
477736da82 fix(core): update 2024-06-06 23:33:35 +02:00
26a67d9662 11.0.17 2024-06-06 22:29:06 +02:00
14771fab27 fix(core): update 2024-06-06 22:29:06 +02:00
b0ae383622 update description 2024-05-29 14:13:08 +02:00
921f1cbb66 11.0.16 2024-05-28 12:43:47 +02:00
a9b373f5f8 fix(core): update 2024-05-28 12:43:46 +02:00
8 changed files with 9749 additions and 2973 deletions

312
changelog.md Normal file
View File

@ -0,0 +1,312 @@
# Changelog
## 2025-01-07 - 11.1.3 - fix(fs)
Fix TypeScript type issue in fs module
- Corrected a TypeScript type in the fs module's checkFileStability function.
## 2025-01-07 - 11.1.2 - fix(fs)
Fix issues in file stability check and directory existence verification in fs module
- Removed unused variable 'isFileAvailable' in 'waitForFileToBeReady'.
- Fixed logic for ensuring the target directory exists before setting up file stability watcher.
- Refactored directory existence logic into 'ensureDirectoryExists' function.
## 2025-01-07 - 11.1.1 - fix(fs)
Improve waitForFileToBeReady function for file stability detection
- Enhanced error handling and file stability checks in waitForFileToBeReady function
- Added timeout feature for file readiness check
- Improved directory access check before file availability check
## 2025-01-07 - 11.1.0 - feat(SmartFile)
Add rename functionality to SmartFile class
- Implemented a new method to rename a file within the SmartFile class.
- The rename method updates the file path and optionally writes the renamed file to the disk.
## 2024-12-15 - 11.0.23 - fix(fs)
Handle errors in toObjectSync method
- Added error handling in toObjectSync function to capture and provide more informative error messages.
## 2024-06-23 - 11.0.22 - fix(core)
Update dependencies and changelog
- Updated @push.rocks/smartstream to ^3.0.44
- Updated glob to ^10.4.2
- Updated @types/node to ^20.14.8
## 2024-06-23 - 11.0.21 - fix(dependencies)
Update dependencies to latest versions
- Updated @push.rocks/smartpromise to ^4.0.4
- Updated @push.rocks/smartstream to ^3.0.44
- Updated glob to ^10.4.2
- Updated @types/node to ^20.14.8
## 2024-06-07 - 11.0.20 - Changelog
11.0.20
## 2024-06-07 - 11.0.19 - fix(core): update
11.0.19
- fix(core): update
## 2024-06-07 - 11.0.18 - fix(core): update
11.0.18
- fix(core): update
## 2024-06-06 - 11.0.17 - fix(core): update
11.0.17
- fix(core): update
## 2024-06-06 - 11.0.16 - fix(core): update
11.0.16
- fix(core): update
## 2024-05-29 - 11.0.16 - update description
11.0.16
- update description
## 2024-05-17 - 11.0.15 - fix(core): update
11.0.15
- fix(core): update
## 2024-04-14 - 11.0.14 - update tsconfig
11.0.14
- update tsconfig
## 2024-04-12 - 11.0.13 - fix(core): update
11.0.13
- fix(core): update
## 2024-04-12 - 11.0.12 - fix(core): update
11.0.12
- fix(core): update
## 2024-04-12 - 11.0.11 - fix(core): update
11.0.11
- fix(core): update
## 2024-04-03 - 11.0.10 - fix(core): update
11.0.10
- fix(core): update
## 2024-04-03 - 11.0.9 - fix(core): update
11.0.9
- fix(core): update
## 2024-04-02 - 11.0.8 - fix(core): update
11.0.8
- fix(core): update
## 2024-04-02 - 11.0.7 - fix(core): update
11.0.7
- fix(core): update
## 2024-04-02 - 11.0.6 - fix(core): update
11.0.6
- fix(core): update
## 2024-04-01 - 11.0.5 - update npmextra.json
11.0.5
- update npmextra.json: githost
## 2024-04-01 - 11.0.4 - fix(core): update
11.0.4
- fix(core): update
## 2023-11-24 - 11.0.3 - fix(core): update
11.0.3
- fix(core): update
## 2023-11-07 - 11.0.2 - fix(core): update
11.0.2
- fix(core): update
## 2023-11-07 - 11.0.1 - fix(core): update
11.0.1
- fix(core): update
## 2023-11-06 - 11.0.0 - fix(core): update
11.0.0
- fix(core): update
## 2023-11-06 - 10.0.40 - BREAKING CHANGE(core): update
10.0.40
- BREAKING CHANGE(core): update
## 2023-11-04 - 10.0.39 - fix(core): update
10.0.39
- fix(core): update
## 2023-11-04 - 10.0.38 - fix(core): update
10.0.38
- fix(core): update
## 2023-11-04 - 10.0.37 - fix(core): update
10.0.37
- fix(core): update
## 2023-11-03 - 10.0.36 - fix(core): update
10.0.36
- fix(core): update
## 2023-11-03 - 10.0.35 - fix(core): update
10.0.35
- fix(core): update
## 2023-11-03 - 10.0.34 - fix(core): update
10.0.34
- fix(core): update
## 2023-11-03 - 10.0.33 - fix(core): update
10.0.33
- fix(core): update
## 2023-10-12 - 10.0.32 - fix(core): update
10.0.32
- fix(core): update
## 2023-09-22 - 10.0.31 - fix(core): update
10.0.31
- fix(core): update
## 2023-08-31 - 10.0.30 - fix(core): update
10.0.30
- fix(core): update
## 2023-08-23 - 10.0.29 - fix(core): update
10.0.29
- fix(core): update
## 2023-07-12 - 10.0.28 - fix(core): update
10.0.28
- fix(core): update
## 2023-07-10 - 10.0.27 - fix(core): update
10.0.27
- fix(core): update
## 2023-07-10 - 10.0.26 - fix(core): update
10.0.26
- fix(core): update
## 2023-07-08 - 10.0.25 - fix(core): update
10.0.25
- fix(core): update
## 2023-06-25 - 10.0.24 to 10.0.14 - Series of Fixes
10.0.24 to 10.0.14
- Series of fixes in the core module
## 2023-01-09 - 10.0.13 to 10.0.6 - Series of Fixes
10.0.13 to 10.0.6
- Series of fixes in the core module
## 2022-09-05 - 10.0.5 to 10.0.3 - Series of Fixes
10.0.5 to 10.0.3
- Series of fixes in the core module
## 2022-06-07 - 10.0.2 to 10.0.1 - Series of Fixes
10.0.2 to 10.0.1
- Series of fixes in the core module
## 2022-06-07 - 9.0.7 - BREAKING CHANGE(core): switch to esm
9.0.7
- BREAKING CHANGE(core): switch to esm
## 2022-03-11 - 9.0.6 to 9.0.2 - Series of Fixes
9.0.6 to 9.0.2
- Series of fixes in the core module
## 2021-12-01 - 9.0.1 - fix(core): update
9.0.1
- fix(core): update
## 2021-12-01 - 9.0.0 - fix(absolute pathing)
9.0.0
- add functions for easily getting absolute paths
## 2021-11-30 - 8.0.11 - BREAKING CHANGE(relative pathing)
8.0.11
- improved relative pathing
## 2020-08-10 - 8.0.10 to 7.0.12 - Series of Fixes and Updates
8.0.10 to 7.0.12
- Series of fixes in the core module
- BREAKING CHANGE(Smartfile class): switch to a Buffer-only approach
## 2019-02-17 - 7.0.0 - fix(core): update dependencies
7.0.0
- fix(core): update dependencies
## 2019-01-27 - 6.0.12 - BREAKING CHANGE(smartfile.fs.fileExists)
6.0.12
- now returns a Promise<boolean>
## 2018-08-19 - 6.0.11 to 6.0.6 - Series of Fixes
6.0.11 to 6.0.6
- Series of fixes in core and dependencies
## 2018-07-03 - 6.0.5 to 5.0.0 - Series of Fixes
6.0.5 to 5.0.0
- Series of fixes in core and dependencies
## 2018-02-16 - 4.2.28 - BREAKING CHANGE(scope)
4.2.28
- switch to pushrocks scope

View File

@ -1,7 +1,7 @@
{ {
"name": "@push.rocks/smartfile", "name": "@push.rocks/smartfile",
"private": false, "private": false,
"version": "11.0.15", "version": "11.1.3",
"description": "Provides comprehensive tools for efficient file management in Node.js using TypeScript, including handling streams, virtual directories, and various file operations.", "description": "Provides comprehensive tools for efficient file management in Node.js using TypeScript, including handling streams, virtual directories, and various file operations.",
"main": "dist_ts/index.js", "main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts", "typings": "dist_ts/index.d.ts",
@ -13,7 +13,7 @@
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://gitlab.com/push.rocks/smartfile.git" "url": "https://code.foss.global/push.rocks/smartfile.git"
}, },
"keywords": [ "keywords": [
"file management", "file management",
@ -40,31 +40,31 @@
"bugs": { "bugs": {
"url": "https://gitlab.com/push.rocks/smartfile/issues" "url": "https://gitlab.com/push.rocks/smartfile/issues"
}, },
"homepage": "https://gitlab.com/push.rocks/smartfile#readme", "homepage": "https://code.foss.global/push.rocks/smartfile",
"dependencies": { "dependencies": {
"@push.rocks/lik": "^6.0.14", "@push.rocks/lik": "^6.1.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.0.4", "@push.rocks/smarthash": "^3.0.4",
"@push.rocks/smartjson": "^5.0.16", "@push.rocks/smartjson": "^5.0.20",
"@push.rocks/smartmime": "^1.0.5", "@push.rocks/smartmime": "^2.0.4",
"@push.rocks/smartpath": "^5.0.13", "@push.rocks/smartpath": "^5.0.18",
"@push.rocks/smartpromise": "^4.0.2", "@push.rocks/smartpromise": "^4.1.0",
"@push.rocks/smartrequest": "^2.0.21", "@push.rocks/smartrequest": "^2.0.23",
"@push.rocks/smartstream": "^3.0.34", "@push.rocks/smartstream": "^3.2.5",
"@types/fs-extra": "^11.0.4", "@types/fs-extra": "^11.0.4",
"@types/glob": "^8.1.0", "@types/glob": "^8.1.0",
"@types/js-yaml": "^4.0.9", "@types/js-yaml": "^4.0.9",
"fs-extra": "^11.2.0", "fs-extra": "^11.2.0",
"glob": "^10.3.12", "glob": "^11.0.0",
"js-yaml": "^4.1.0" "js-yaml": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@git.zone/tsbuild": "^2.1.72", "@git.zone/tsbuild": "^2.2.0",
"@git.zone/tsrun": "^1.2.46", "@git.zone/tsrun": "^1.3.3",
"@git.zone/tstest": "^1.0.88", "@git.zone/tstest": "^1.0.90",
"@push.rocks/tapbundle": "^5.0.22", "@push.rocks/tapbundle": "^5.5.4",
"@types/node": "^20.12.7" "@types/node": "^22.10.5"
}, },
"files": [ "files": [
"ts/**/*", "ts/**/*",

12080
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
/** /**
* autocreated commitinfo by @pushrocks/commitinfo * autocreated commitinfo by @push.rocks/commitinfo
*/ */
export const commitinfo = { export const commitinfo = {
name: '@push.rocks/smartfile', name: '@push.rocks/smartfile',
version: '11.0.15', version: '11.1.3',
description: 'Provides comprehensive tools for efficient file management in Node.js using TypeScript, including handling streams, virtual directories, and various file operations.' description: 'Provides comprehensive tools for efficient file management in Node.js using TypeScript, including handling streams, virtual directories, and various file operations.'
} }

View File

@ -212,6 +212,43 @@ export class SmartFile extends plugins.smartjson.Smartjson {
await fs.remove(plugins.path.join(this.base, this.path)); await fs.remove(plugins.path.join(this.base, this.path));
} }
/**
* Renames the file to the specified new name.
* - Updates the `path` property with the new name.
* - Writes the file to the new location if it exists on disk.
* @param newName The new name of the file (including extension if applicable).
* @param writeToDisk (optional) If true, also renames the file on the disk.
* @returns The updated file path after renaming.
*/
public async rename(newName: string, writeToDisk: boolean = false): Promise<string> {
// Validate the new name
if (!newName || typeof newName !== 'string') {
throw new Error('Invalid new name provided.');
}
// Extract the directory path
const oldFilePath = this.path;
const dirPath = plugins.path.dirname(this.path);
// Create the new file path
const newFilePath = plugins.path.join(dirPath, newName);
// Update the `path` property
this.path = newFilePath;
// Optionally write the renamed file to disk
if (writeToDisk) {
const oldAbsolutePath = plugins.smartpath.transform.makeAbsolute(oldFilePath, this.base);
const newAbsolutePath = plugins.smartpath.transform.makeAbsolute(newFilePath, this.base);
// Rename the file on disk
await plugins.fsExtra.rename(oldAbsolutePath, newAbsolutePath);
}
// Return the new path
return this.path;
}
// ----------------------------------------------- // -----------------------------------------------
// vinyl compatibility // vinyl compatibility
// ----------------------------------------------- // -----------------------------------------------
@ -306,4 +343,11 @@ export class SmartFile extends plugins.smartjson.Smartjson {
stream.push(null); // Push null to signify the end of the stream (EOF) stream.push(null); // Push null to signify the end of the stream (EOF)
return stream; return stream;
} }
/**
* Returns the size of the file in bytes
*/
public async getSize(): Promise<number> {
return this.contentBuffer.length;
}
} }

View File

@ -10,26 +10,16 @@ type TStreamSource = (streamFile: StreamFile) => Promise<Readable>;
* It allows creating streams from a file path, a URL, or a buffer. * It allows creating streams from a file path, a URL, or a buffer.
*/ */
export class StreamFile { export class StreamFile {
// INSTANCE
relativeFilePath?: string;
private streamSource: TStreamSource;
// enable stream based multi use
private cachedStreamBuffer?: Buffer;
public multiUse: boolean;
public used: boolean = false;
private constructor(streamSource: TStreamSource, relativeFilePath?: string) {
this.streamSource = streamSource;
this.relativeFilePath = relativeFilePath;
}
// STATIC // STATIC
public static async fromPath(filePath: string): Promise<StreamFile> { public static async fromPath(filePath: string): Promise<StreamFile> {
const streamSource: TStreamSource = async (stremFileArg) => smartfileFsStream.createReadStream(filePath); const streamSource: TStreamSource = async (streamFileArg) => smartfileFsStream.createReadStream(filePath);
const streamFile = new StreamFile(streamSource, filePath); const streamFile = new StreamFile(streamSource, filePath);
streamFile.multiUse = true; streamFile.multiUse = true;
streamFile.byteLengthComputeFunction = async () => {
const stats = await smartfileFs.stat(filePath);
return stats.size;
}
return streamFile; return streamFile;
} }
@ -37,6 +27,10 @@ export class StreamFile {
const streamSource: TStreamSource = async (streamFileArg) => plugins.smartrequest.getStream(url); // Replace with actual plugin method const streamSource: TStreamSource = async (streamFileArg) => plugins.smartrequest.getStream(url); // Replace with actual plugin method
const streamFile = new StreamFile(streamSource); const streamFile = new StreamFile(streamSource);
streamFile.multiUse = true; streamFile.multiUse = true;
streamFile.byteLengthComputeFunction = async () => {
const response = await plugins.smartrequest.getBinary(url); // TODO: switch to future .getBinaryByteLength()
return response.body.length;
}
return streamFile; return streamFile;
} }
@ -49,6 +43,7 @@ export class StreamFile {
}; };
const streamFile = new StreamFile(streamSource, relativeFilePath); const streamFile = new StreamFile(streamSource, relativeFilePath);
streamFile.multiUse = true; streamFile.multiUse = true;
streamFile.byteLengthComputeFunction = async () => buffer.length;
return streamFile; return streamFile;
} }
@ -91,6 +86,22 @@ export class StreamFile {
return streamFile; return streamFile;
} }
// INSTANCE
relativeFilePath?: string;
private streamSource: TStreamSource;
// enable stream based multi use
private cachedStreamBuffer?: Buffer;
public multiUse: boolean;
public used: boolean = false;
public byteLengthComputeFunction: () => Promise<number>;
private constructor(streamSource: TStreamSource, relativeFilePath?: string) {
this.streamSource = streamSource;
this.relativeFilePath = relativeFilePath;
}
// METHODS // METHODS
private checkMultiUse() { private checkMultiUse() {
@ -149,4 +160,15 @@ export class StreamFile {
const contentBuffer = await this.getContentAsBuffer(); const contentBuffer = await this.getContentAsBuffer();
return contentBuffer.toString(formatArg); return contentBuffer.toString(formatArg);
} }
/**
* Returns the size of the file content in bytes.
*/
public async getSize(): Promise<number> {
if (this.byteLengthComputeFunction) {
return this.byteLengthComputeFunction();
} else {
return null;
}
}
} }

103
ts/fs.ts
View File

@ -190,7 +190,8 @@ export const removeManySync = (filePathArrayArg: string[]): void => {
===============================================================*/ ===============================================================*/
/** /**
* * reads a file content to an object
* good for JSON, YAML, TOML, etc.
* @param filePathArg * @param filePathArg
* @param fileTypeArg * @param fileTypeArg
* @returns {any} * @returns {any}
@ -199,14 +200,19 @@ export const toObjectSync = (filePathArg, fileTypeArg?) => {
const fileString = plugins.fsExtra.readFileSync(filePathArg, 'utf8'); const fileString = plugins.fsExtra.readFileSync(filePathArg, 'utf8');
let fileType; let fileType;
fileTypeArg ? (fileType = fileTypeArg) : (fileType = interpreter.filetype(filePathArg)); fileTypeArg ? (fileType = fileTypeArg) : (fileType = interpreter.filetype(filePathArg));
try {
return interpreter.objectFile(fileString, fileType); return interpreter.objectFile(fileString, fileType);
} catch (err) {
err.message = `Failed to read file at ${filePathArg}` + err.message;
throw err;
}
}; };
/** /**
* reads a file content to a String * reads a file content to a String
*/ */
export const toStringSync = (filePath: string): string => { export const toStringSync = (filePath: string): string => {
const encoding = plugins.smartmime.getEncoding(filePath); const encoding = plugins.smartmime.getEncodingForPathSync(filePath);
let fileString: string | Buffer = plugins.fsExtra.readFileSync(filePath, encoding); let fileString: string | Buffer = plugins.fsExtra.readFileSync(filePath, encoding);
if (Buffer.isBuffer(fileString)) { if (Buffer.isBuffer(fileString)) {
fileString = fileString.toString('binary'); fileString = fileString.toString('binary');
@ -391,37 +397,64 @@ export const listFileTree = async (
/** /**
* Watches for file stability before resolving the promise. * Watches for file stability before resolving the promise.
* @param filePathArg The path of the file to monitor.
* @param timeoutMs The maximum time to wait for the file to stabilize (in milliseconds). Default is 60 seconds.
* @returns A promise that resolves when the file is stable or rejects on timeout or error.
*/ */
export const waitForFileToBeReady = (filePathArg: string): Promise<void> => { export const waitForFileToBeReady = (
filePathArg: string,
timeoutMs: number = 60000
): Promise<void> => {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
let lastFileSize = -1; let lastFileSize = -1;
let fileIsStable = false; let fileIsStable = false;
const checkFileStability = async () => { const startTime = Date.now();
let currentFileSize: number; const fileDir = plugins.path.dirname(filePathArg);
const deferred = plugins.smartpromise.defer();
plugins.fs.stat(filePathArg, (err, stats) => { const ensureDirectoryExists = async () => {
if (err) { while (true) {
fileIsStable = true; try {
watcher.close(); // Check if the directory exists
reject(err); await plugins.smartpromise.fromCallback((cb) =>
plugins.fs.access(fileDir, plugins.fs.constants.R_OK, cb)
);
break; // Exit the loop if the directory exists
} catch (err) {
if (Date.now() - startTime > timeoutMs) {
reject(new Error(`Timeout waiting for directory to exist: ${fileDir}`));
return; return;
} }
currentFileSize = stats.size; // Wait and retry
deferred.resolve(); await plugins.smartdelay.delayFor(500);
}); }
await deferred.promise;
if (currentFileSize === lastFileSize) {
fileIsStable = true;
await plugins.smartdelay.delayFor(100);
resolve();
} }
lastFileSize = currentFileSize;
}; };
const watcher = plugins.fs.watch(filePathArg, (eventType, filename) => { const checkFileStability = async () => {
if (eventType === 'change') { try {
checkFileStability(); const stats = await plugins.smartpromise.fromCallback<plugins.fs.Stats>((cb) =>
plugins.fs.stat(filePathArg, cb)
);
if (stats.size === lastFileSize) {
fileIsStable = true;
} else {
lastFileSize = stats.size;
fileIsStable = false;
}
} catch (err) {
if (err.code !== 'ENOENT') {
throw err; // Only ignore ENOENT (file not found) errors
}
}
};
// Ensure the directory exists before setting up the watcher
await ensureDirectoryExists();
const watcher = plugins.fs.watch(filePathArg, { persistent: true }, async () => {
if (!fileIsStable) {
await checkFileStability();
} }
}); });
@ -430,13 +463,28 @@ export const waitForFileToBeReady = (filePathArg: string): Promise<void> => {
reject(error); reject(error);
}); });
try {
while (!fileIsStable) { while (!fileIsStable) {
// Check for timeout
if (Date.now() - startTime > timeoutMs) {
watcher.close();
reject(new Error(`Timeout waiting for file to be ready: ${filePathArg}`));
return;
}
// Check file stability
await checkFileStability(); await checkFileStability();
if (!fileIsStable) { if (!fileIsStable) {
await plugins.smartdelay.delayFor(5000); await plugins.smartdelay.delayFor(1000); // Polling interval
} }
} }
watcher.close(); watcher.close();
resolve();
} catch (err) {
watcher.close();
reject(err);
}
}); });
}; };
@ -485,7 +533,6 @@ export let toFs = async (
return await done.promise; return await done.promise;
}; };
export const stat = async (filePathArg: string) => {
return plugins.fsPromises.stat(filePathArg);
};

View File

@ -1,9 +1,10 @@
// node native scope // node native scope
import * as fs from 'fs'; import * as fs from 'fs';
import * as fsPromises from 'fs/promises';
import * as path from 'path'; import * as path from 'path';
import * as stream from 'stream'; import * as stream from 'stream';
export { fs, path, stream }; export { fs, fsPromises, path, stream };
// @pushrocks scope // @pushrocks scope
import * as lik from '@push.rocks/lik'; import * as lik from '@push.rocks/lik';