{"_id":"@cafeine-software/foxyfs","name":"@cafeine-software/foxyfs","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@cafeine-software/foxyfs","version":"1.0.0","description":"Wrappers around node:fs/promises — every operation checks its result before resolving.","license":"CC-BY-SA-4.0","author":{"name":"Quentin Lamamy","email":"contact@quentin-lamamy.fr","url":"https://github.com/quentinlamamy"},"type":"module","main":"index.js","keywords":["fs","filesystem","fs-promises","file","safe","node"],"repository":{"type":"git","url":"git+https://github.com/Cafeine-Software/foxyFs.git"},"homepage":"http://cafeine-sofware.fr/products","scripts":{"test":"node --test"},"gitHead":"54a7594f29c299da407c12bcf003404a7540f6d6","_id":"@cafeine-software/foxyfs@1.0.0","bugs":{"url":"https://github.com/Cafeine-Software/foxyFs/issues"},"_nodeVersion":"25.2.0","_npmVersion":"11.10.1","dist":{"integrity":"sha512-9owpQTqrygAeRsRT6J8rK5y1sBo2YokWnIz0DIphMt7sz0Igl5Sg7JFuZu/L6uNFk35jOU5ktmTXJ5hUjLS90g==","shasum":"de89d2ca8bb5e76711c755f4165ac33fbdba18b2","tarball":"https://registry.npmjs.org/@cafeine-software/foxyfs/-/foxyfs-1.0.0.tgz","fileCount":11,"unpackedSize":279081,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQChOCJVVsya+Go8AQ7UbEPwtIV8o4gF3bcu0IARQ8f2qgIgTVRcNvBGBLliEhmWyuVM1G1S9lQcvMgOkirmXnD4jkE="}]},"_npmUser":{"name":"quentin_lamamy","email":"contact@quentin-lamamy.fr"},"directories":{},"maintainers":[{"name":"quentin_lamamy","email":"contact@quentin-lamamy.fr"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/foxyfs_1.0.0_1772478348248_0.4818559426581652"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-02T19:05:48.247Z","1.0.0":"2026-03-02T19:05:48.471Z","modified":"2026-03-02T19:05:48.953Z"},"maintainers":[{"name":"quentin_lamamy","email":"contact@quentin-lamamy.fr"}],"description":"Wrappers around node:fs/promises — every operation checks its result before resolving.","homepage":"http://cafeine-sofware.fr/products","keywords":["fs","filesystem","fs-promises","file","safe","node"],"repository":{"type":"git","url":"git+https://github.com/Cafeine-Software/foxyFs.git"},"author":{"name":"Quentin Lamamy","email":"contact@quentin-lamamy.fr","url":"https://github.com/quentinlamamy"},"bugs":{"url":"https://github.com/Cafeine-Software/foxyFs/issues"},"license":"CC-BY-SA-4.0","readme":"<div align=\"center\">\n\n<img src=\"./assets/banner.svg\" alt=\"foxyFs\" width=\"800\"/>\n\n<br/>\n\n<p>\n  <img alt=\"Tests\" src=\"https://img.shields.io/github/actions/workflow/status/Cafeine-Software/foxyFs/tests.yml?style=flat-square&label=tests&logo=github&logoColor=white\" />\n  <img alt=\"License\" src=\"https://img.shields.io/badge/License-CC%20BY--SA%204.0-6F4E37?style=flat-square\" />\n  <img alt=\"Node.js\" src=\"https://img.shields.io/badge/Node.js-ESM-339933?style=flat-square&logo=node.js&logoColor=white\" />\n</p>\n\n<p>🇫🇷 <a href=\"./README.fr.md\">Version française</a></p>\n\n</div>\n\n---\n\n## Table of contents\n\n- [Installation](#installation)\n- [API](#api)\n  - [`writeFileSafe`](#writefilesafepath-content)\n  - [`fileExists`](#fileexistspath)\n  - [`mkdirSafe`](#mkdirsafepath-deleteifexists)\n  - [`deleteFileSafe`](#deletefilesafepath)\n  - [`emptyFolderSafe`](#emptyfoldersafepath)\n  - [`isEmptySafe`](#isemptysafepath)\n  - [`isDirectory`](#isdirectorypath)\n  - [`cpSafe`](#cpsafesrc-dest)\n  - [`mvSafe`](#mvsafesrc-dest)\n  - [`statSafe`](#statsafepath)\n  - [`listFilesSafe`](#listfilessafepath)\n- [Error handling](#error-handling)\n- [Tests](#tests)\n- [Contributors](#contributors)\n- [Support](#support)\n- [License](#license)\n\n---\n\n## Installation\n\n```bash\nnpm install foxyfs\n```\n\n## API\n\n### `writeFileSafe(path, content)`\n\nWrites `content` (UTF-8) to `path`, then verifies the file is readable and its content matches exactly what was written.\n\n```js\nimport { writeFileSafe } from 'foxyfs';\n\nawait writeFileSafe('/tmp/hello.txt', 'Hello world');\n```\n\n| Parameter | Type     | Description              |\n|-----------|----------|--------------------------|\n| `path`    | `String` | Absolute or relative path|\n| `content` | `String` | UTF-8 content to write   |\n\nThrows `Error(\"Unable to write file\")` if the write or verification fails.\n\n---\n\n### `fileExists(path)`\n\nReturns `true` if the path exists and is readable, `false` otherwise. Never throws.\n\n```js\nimport { fileExists } from 'foxyfs';\n\nif (await fileExists('/tmp/config.json')) { /* ... */ }\n```\n\n**Returns** `Promise<Boolean>`\n\n---\n\n### `mkdirSafe(path, deleteIfExists?)`\n\nCreates a directory (and its parents) recursively. If the directory already exists and `deleteIfExists` is `true`, it is deleted before being recreated.\n\n```js\nimport { mkdirSafe } from 'foxyfs';\n\nawait mkdirSafe('/tmp/a/b/c');\nawait mkdirSafe('/tmp/output', true); // wipes and recreates if already present\n```\n\n| Parameter        | Type      | Default | Description                                   |\n|------------------|-----------|---------|-----------------------------------------------|\n| `path`           | `String`  | —       | Path of the directory to create               |\n| `deleteIfExists` | `Boolean` | `false` | Delete the existing directory first if `true` |\n\n---\n\n### `deleteFileSafe(path)`\n\nDeletes a file or directory (recursively), then verifies it no longer exists.\n\n```js\nimport { deleteFileSafe } from 'foxyfs';\n\nawait deleteFileSafe('/tmp/old-dir');\n```\n\nThrows `Error(\"Unable to delete file\")` if the path does not exist or deletion fails.\n\n---\n\n### `emptyFolderSafe(path)`\n\nDeletes all direct children of a directory without removing the directory itself, then verifies it is empty.\n\n```js\nimport { emptyFolderSafe } from 'foxyfs';\n\nawait emptyFolderSafe('/tmp/cache');\n```\n\nThrows if `path` is not a directory or if the emptying is incomplete.\n\n---\n\n### `isEmptySafe(path)`\n\nReturns `true` if a file has zero size, or if a directory contains no entries.\n\n```js\nimport { isEmptySafe } from 'foxyfs';\n\nconst empty = await isEmptySafe('/tmp/output');\n```\n\n**Returns** `Promise<Boolean>`\nThrows `Error(\"Unable to check if path is empty\")` if the path does not exist.\n\n---\n\n### `isDirectory(path)`\n\nReturns `true` if the path points to a directory.\n\n```js\nimport { isDirectory } from 'foxyfs';\n\nconst isDir = await isDirectory('/tmp/output');\n```\n\n**Returns** `Promise<Boolean>`\nThrows if the path does not exist or is not accessible.\n\n---\n\n### `cpSafe(src, dest)`\n\nCopies a file or directory (recursively) from `src` to `dest`. The original is preserved.\n\n```js\nimport { cpSafe } from 'foxyfs';\n\nawait cpSafe('/tmp/source', '/tmp/backup');\n```\n\nThrows `Error(\"Unable to copy file\")` if the source does not exist or the copy fails.\n\n---\n\n### `mvSafe(src, dest)`\n\nMoves a file or directory from `src` to `dest`. Verifies the destination exists and the source is gone afterwards.\n\n```js\nimport { mvSafe } from 'foxyfs';\n\nawait mvSafe('/tmp/draft.txt', '/tmp/final.txt');\n```\n\nThrows `Error(\"Unable to move file\")` if the source does not exist or the move fails.\n\n---\n\n### `statSafe(path)`\n\nReturns the `Stats` object from `node:fs` for the given path, after verifying accessibility.\n\n```js\nimport { statSafe } from 'foxyfs';\n\nconst stats = await statSafe('/tmp/file.txt');\nconsole.log(stats.size, stats.isFile());\n```\n\n**Returns** `Promise<fs.Stats>`\nThrows `Error(\"Unable to stat file\")` if the path does not exist.\n\n---\n\n### `listFilesSafe(path)`\n\nReturns the list of entry names (files and subdirectories) inside a directory, non-recursive.\n\n```js\nimport { listFilesSafe } from 'foxyfs';\n\nconst entries = await listFilesSafe('/tmp/output');\n// ['a.txt', 'b.txt', 'subdir']\n```\n\n**Returns** `Promise<Array<String>>`\nThrows if `path` is not a directory or does not exist.\n\n---\n\n## Error handling\n\nAll functions throw enriched errors:\n\n```js\ntry {\n    await deleteFileSafe('/no/such/path');\n} catch (err) {\n    console.log(err.message);       // \"Unable to delete file\"\n    console.log(err.cause.message); // chained root cause\n    console.log(err.data);          // { path: '/no/such/path' }\n}\n```\n\nThe `data` property contains the operation context (path, src/dest, etc.).\n\n## Tests\n\n```bash\nnpm test\n```\n\nUses the native `node:test` runner — no external test dependency.\n\n## Contributors\n\n[![Quentin Lamamy](./assets/contributor-quentinlamamy.svg)](https://github.com/quentinlamamy)\n\n## Support\n\n[![Buy me a coffee](./assets/support-banner.svg)](https://example.com)\n\n## License\n\n[![CC BY-SA 4.0](./assets/license-banner.svg)](https://creativecommons.org/licenses/by-sa/4.0/)\n","readmeFilename":"README.md","_rev":"1-7d4de1e96c5d7e0737aa54c187865a9e"}