From 6ed14fac8d0bbafaa6de9aa7c3dfb9b5c3a64828 Mon Sep 17 00:00:00 2001 From: Balint Ujvari Date: Tue, 11 Aug 2026 12:42:01 +0200 Subject: [PATCH] chore: use tsup for build chore: complete node and browser env build separation chore: update docs and packaging chore: update tests to write to a temp folder --- .gitignore | 1 + .npmignore | 7 +- .nvmrc | 2 +- README.md | 6 +- eslint.config.mjs | 8 +- jest.config.ts | 2 +- package.json | 39 +- pnpm-lock.yaml | 850 ++++++++++++++++-- pnpm-workspace.yaml | 1 + src/download/index.ts | 6 +- src/fileManager.ts | 44 +- src/mantarayStore.ts | 14 +- src/types/download.ts | 4 +- src/types/fileManager.ts | 26 +- src/types/info.ts | 4 +- src/types/upload.ts | 4 +- src/types/utils.ts | 2 +- src/upload/index.ts | 4 +- .../{upload.browser.ts => upload-browser.ts} | 14 +- src/upload/{upload.node.ts => upload-node.ts} | 18 +- src/utils/asserts.ts | 22 +- src/utils/bee.ts | 16 +- src/utils/common.ts | 2 +- src/utils/fs/{fs.node.ts => fs-node.ts} | 0 src/utils/mantaray.ts | 21 +- tests/TESTS.md | 44 +- tests/integration/abort.spec.ts | 43 +- tests/integration/drive.spec.ts | 6 +- tests/integration/e2e.spec.ts | 14 +- tests/integration/file.spec.ts | 96 +- tests/integration/folder.spec.ts | 6 +- tests/integration/init.spec.ts | 12 +- tests/integration/setup/utils.ts | 21 +- tests/integration/trash.spec.ts | 11 +- tests/integration/version.spec.ts | 54 +- ...latform.browser.ts => platform-browser.ts} | 0 tests/unit/abort.spec.ts | 2 +- tests/unit/drive.spec.ts | 2 +- tests/unit/file.spec.ts | 19 +- tests/unit/folder.spec.ts | 13 +- tests/unit/mock.ts | 18 +- tests/unit/trash.spec.ts | 6 +- tests/unit/version.spec.ts | 6 +- tests/utils.ts | 4 +- tsconfig.json | 13 +- tsup.config.ts | 53 ++ 46 files changed, 1231 insertions(+), 329 deletions(-) rename src/upload/{upload.browser.ts => upload-browser.ts} (75%) rename src/upload/{upload.node.ts => upload-node.ts} (79%) rename src/utils/fs/{fs.node.ts => fs-node.ts} (100%) rename tests/{platform.browser.ts => platform-browser.ts} (100%) create mode 100644 tsup.config.ts diff --git a/.gitignore b/.gitignore index cf512e2..1fd647b 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ yalc.lock coverage/ *.pid tests/**/bee-dev/ +tests/integration/tmp/ **.tgz *.md diff --git a/.npmignore b/.npmignore index 57f286f..eaecea6 100644 --- a/.npmignore +++ b/.npmignore @@ -1,5 +1,5 @@ # Dependencies -node_modules +node_modules/ # Tests tests/ @@ -48,4 +48,7 @@ Thumbs.db .nvmrc # docs -REFERENCE.md \ No newline at end of file +CLAUDE.md +REFERENCE.md +memory/ +changelog/ \ No newline at end of file diff --git a/.nvmrc b/.nvmrc index 18c92ea..92f279e 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v24 \ No newline at end of file +v22 \ No newline at end of file diff --git a/README.md b/README.md index 5049e14..0c233c7 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,9 @@ flowchart TD pnpm install @solarpunkltd/file-manager-lib ``` -Peer dependency: `@ethersphere/bee-js`. +Requires **Node.js ≥ 22**. Peer dependency: `@ethersphere/bee-js`. The package ships dual **ESM + CJS** builds with +separate **Node** and **browser** bundles, selected automatically via `package.json` `exports` conditions — bundlers get +a `fs`/`path`-free browser build. --- @@ -205,7 +207,7 @@ when each fires. From `package.json`: -- `pnpm run build` → compile Node + browser + types. +- `pnpm run build` → bundle Node + browser (ESM + CJS) + type declarations via **tsup**. - `pnpm run test` → run Jest tests (see [tests/TESTS.md](tests/TESTS.md)). - `pnpm run lint` / `pnpm run lint:fix` → linting. - `pnpm init:husky` → husky init. diff --git a/eslint.config.mjs b/eslint.config.mjs index 6aef5ad..1886bd7 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -49,13 +49,12 @@ export default [ { ignores: [ '**/node_modules/**', - '**/dist/**', + 'dist/**', 'eslint.config.mjs', 'eslint-compat.cjs', 'commitlint.config.cjs', - 'tests/fixtures/**', - 'tests/**/bee-dev/**', - '**/coverage/**', + 'tests/coverage/**', + 'tsup.config.ts', ], }, { @@ -103,6 +102,7 @@ export default [ 'simple-import-sort': simpleImportSort, }, rules: { + '@typescript-eslint/consistent-type-imports': ['error', { fixStyle: 'inline-type-imports' }], '@typescript-eslint/no-explicit-any': 'error', '@typescript-eslint/explicit-function-return-type': 'error', '@typescript-eslint/no-non-null-assertion': 'error', diff --git a/jest.config.ts b/jest.config.ts index 5dda9ca..0395509 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -1,4 +1,4 @@ -const browserSetup = '/tests/platform.browser.ts'; +const browserSetup = '/tests/platform-browser.ts'; const tsProject = { preset: 'ts-jest', diff --git a/package.json b/package.json index 2ed82ea..2bddb55 100644 --- a/package.json +++ b/package.json @@ -2,23 +2,27 @@ "name": "@solarpunkltd/file-manager-lib", "version": "2.0.0", "description": "A file manager for storing and handling data on Swarm.", - "main": "dist/cjs/index.js", - "module": "dist/esm/index.js", - "types": "dist/types/index.d.ts", + "main": "dist/node/index.cjs", + "module": "dist/node/index.mjs", + "types": "dist/node/index.d.ts", "exports": { ".": { - "types": "./dist/types/index.d.ts", - "require": "./dist/cjs/index.js", - "import": "./dist/esm/index.js" + "types": "./dist/node/index.d.ts", + "browser": { + "import": "./dist/browser/index.mjs", + "require": "./dist/browser/index.cjs" + }, + "node": { + "import": "./dist/node/index.mjs", + "require": "./dist/node/index.cjs" + }, + "default": "./dist/node/index.mjs" }, "./package.json": "./package.json" }, "scripts": { "prepublishOnly": "pnpm run build", - "build": "rimraf dist && pnpm run build:types && pnpm run build:cjs && pnpm run build:esm", - "build:cjs": "tsc -p tsconfig.cjs.json", - "build:esm": "tsc -p tsconfig.esm.json", - "build:types": "tsc --emitDeclarationOnly --declaration --outDir dist/types", + "build": "tsup", "test": "jest --config=jest.config.ts --maxWorkers=4 --verbose --silent", "test:ut": "pnpm run test --selectProjects=unit-node && pnpm run test --selectProjects=unit-browser", "test:it": "pnpm run test --selectProjects=integration", @@ -27,10 +31,11 @@ "test:coverage": "pnpm run test --coverage", "lint": "eslint . --report-unused-disable-directives --no-cache --max-warnings=5", "lint:fix": "pnpm run lint --fix", - "check:types": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.cjs.json --noEmit && tsc -p tsconfig.esm.json --noEmit", + "check:types": "tsc -p tsconfig.json --noEmit", "depcheck": "depcheck .", "init:husky": "pnpm husky install" }, + "sideEffects": false, "files": [ "dist" ], @@ -51,6 +56,10 @@ "author": "SolarPunkLtd", "homepage": "https://github.com/Solar-Punk-Ltd/file-manager-lib", "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/Solar-Punk-Ltd/file-manager-lib.git" + }, "dependencies": { "@ethersphere/bee-js": "npm:@solarpunkltd/bee-js@0.0.0-fmv2.1", "cafe-utility": "^36.2.0", @@ -64,8 +73,8 @@ "devDependencies": { "@commitlint/cli": "^20.4.1", "@commitlint/config-conventional": "^20.4.1", - "@ethersphere/bee-factory": "^1.1.1", "@eslint/js": "^9.39.2", + "@ethersphere/bee-factory": "^1.1.1", "@types/event-emitter": "^0.3.5", "@types/fs-extra": "^11.0.4", "@types/jest": "^30.0.0", @@ -85,15 +94,15 @@ "husky": "^9.1.7", "jest": "^30.2.0", "prettier": "^3.8.1", - "rimraf": "^6.1.2", "ts-jest": "^29.4.6", "ts-node": "^10.9.2", + "tsup": "^8.5.1", "typescript": "^5.9.3" }, "engines": { - "node": ">=24.0.0", + "node": ">=22.0.0", "npm": ">=11.0.0", "pnpm": ">=10.0.0", - "bee": "2.8.0" + "bee": "2.8.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ca0f387..becd186 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -87,15 +87,15 @@ importers: prettier: specifier: ^3.8.1 version: 3.8.1 - rimraf: - specifier: ^6.1.2 - version: 6.1.2 ts-jest: specifier: ^29.4.6 - version: 29.4.6(@babel/core@7.28.6)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.6))(jest-util@30.2.0)(jest@30.2.0(@types/node@25.1.0)(ts-node@10.9.2(@types/node@25.1.0)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.6(@babel/core@7.28.6)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.6))(esbuild@0.27.7)(jest-util@30.2.0)(jest@30.2.0(@types/node@25.1.0)(ts-node@10.9.2(@types/node@25.1.0)(typescript@5.9.3)))(typescript@5.9.3) ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@25.1.0)(typescript@5.9.3) + tsup: + specifier: ^8.5.1 + version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(typescript@5.9.3) typescript: specifier: ^5.9.3 version: 5.9.3 @@ -355,6 +355,162 @@ packages: '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -432,14 +588,6 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.0': - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} - engines: {node: 20 || >=22} - '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -556,6 +704,13 @@ packages: '@js-sdsl/ordered-map@4.4.2': resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} + engines: {node: ^22.20 || ^24.12 || >=25} + cpu: [x64] + os: [linux] + libc: [glibc] + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -601,6 +756,144 @@ packages: '@protobufjs/utf8@1.1.2': resolution: {integrity: sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==} + '@rollup/rollup-android-arm-eabi@4.62.4': + resolution: {integrity: sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.62.4': + resolution: {integrity: sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.62.4': + resolution: {integrity: sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.62.4': + resolution: {integrity: sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.62.4': + resolution: {integrity: sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.62.4': + resolution: {integrity: sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.62.4': + resolution: {integrity: sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.62.4': + resolution: {integrity: sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.62.4': + resolution: {integrity: sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.62.4': + resolution: {integrity: sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.62.4': + resolution: {integrity: sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.62.4': + resolution: {integrity: sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.62.4': + resolution: {integrity: sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.62.4': + resolution: {integrity: sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.62.4': + resolution: {integrity: sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.62.4': + resolution: {integrity: sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.62.4': + resolution: {integrity: sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.62.4': + resolution: {integrity: sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.62.4': + resolution: {integrity: sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.62.4': + resolution: {integrity: sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.62.4': + resolution: {integrity: sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.62.4': + resolution: {integrity: sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.62.4': + resolution: {integrity: sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.62.4': + resolution: {integrity: sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.62.4': + resolution: {integrity: sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==} + cpu: [x64] + os: [win32] + '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} @@ -650,6 +943,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + '@types/event-emitter@0.3.5': resolution: {integrity: sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ==} @@ -893,6 +1189,11 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.18.0: + resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} + engines: {node: '>=0.4.0'} + hasBin: true + aes-js@4.0.0-beta.5: resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} @@ -926,6 +1227,9 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -1062,6 +1366,16 @@ packages: resolution: {integrity: sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==} engines: {node: '>=10.0.0'} + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.18' + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + cafe-utility@34.0.0: resolution: {integrity: sha512-4gxiVyngFbRa1G10+DIDUjk/Qu8OMxgK5bnNXMj4y80Tc+RLdZlk+pE7scgediQS2cxn8L+3XauS8tE62EfsTg==} @@ -1110,6 +1424,10 @@ packages: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} @@ -1149,12 +1467,23 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + conventional-changelog-angular@8.1.0: resolution: {integrity: sha512-GGf2Nipn1RUCAktxuVauVr1e3r8QrLP/B0lEUsFktmGqc3ddbQkhoJZHJctVU829U1c6mTSWftrVOCHaL85Q3w==} engines: {node: '>=18'} @@ -1360,6 +1689,11 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -1608,6 +1942,9 @@ packages: resolution: {integrity: sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==} engines: {node: '>= 10.13.0'} + fix-dts-default-cjs-exports@1.0.1: + resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} @@ -1698,10 +2035,6 @@ packages: deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true - glob@13.0.0: - resolution: {integrity: sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==} - engines: {node: 20 || >=22} - glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me @@ -2139,6 +2472,10 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2190,9 +2527,17 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -2238,10 +2583,6 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.2.5: - resolution: {integrity: sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==} - engines: {node: 20 || >=22} - lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -2285,10 +2626,6 @@ packages: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} - minimatch@10.1.1: - resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} - engines: {node: 20 || >=22} - minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -2310,6 +2647,9 @@ packages: mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2317,6 +2657,9 @@ packages: resolution: {integrity: sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==} engines: {node: '>=10'} + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + nan@2.28.0: resolution: {integrity: sha512-fTsDz99OTq2sVePhGdp4qQhggZFtKr64ZNVyVajRKtMOkJxYekplBh577PiJB12v/D3s2E5cGtOI45LWp6rnLQ==} @@ -2350,6 +2693,10 @@ packages: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} @@ -2451,14 +2798,13 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-scurry@2.0.1: - resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} - engines: {node: 20 || >=22} - path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2478,6 +2824,9 @@ packages: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + please-upgrade-node@3.2.0: resolution: {integrity: sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==} @@ -2485,6 +2834,24 @@ packages: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -2531,6 +2898,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -2582,9 +2953,9 @@ packages: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} - rimraf@6.1.2: - resolution: {integrity: sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g==} - engines: {node: 20 || >=22} + rollup@4.62.4: + resolution: {integrity: sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true safe-array-concat@1.1.3: @@ -2675,6 +3046,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + split-ca@1.0.1: resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} @@ -2763,6 +3138,11 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -2790,6 +3170,16 @@ packages: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.0.2: resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} engines: {node: '>=18'} @@ -2805,12 +3195,19 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + ts-api-utils@2.4.0: resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-jest@29.4.6: resolution: {integrity: sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} @@ -2861,6 +3258,25 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsup@8.5.1: + resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + tweetnacl@0.14.5: resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} @@ -2901,6 +3317,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + uglify-js@3.19.3: resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} engines: {node: '>=0.8.0'} @@ -3379,6 +3798,84 @@ snapshots: tslib: 2.8.1 optional: true + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': dependencies: eslint: 9.39.2(jiti@2.6.1) @@ -3481,12 +3978,6 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.0': - dependencies: - '@isaacs/balanced-match': 4.0.1 - '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -3711,6 +4202,9 @@ snapshots: '@js-sdsl/ordered-map@4.4.2': {} + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + optional: true + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.8.1 @@ -3749,6 +4243,81 @@ snapshots: '@protobufjs/utf8@1.1.2': {} + '@rollup/rollup-android-arm-eabi@4.62.4': + optional: true + + '@rollup/rollup-android-arm64@4.62.4': + optional: true + + '@rollup/rollup-darwin-arm64@4.62.4': + optional: true + + '@rollup/rollup-darwin-x64@4.62.4': + optional: true + + '@rollup/rollup-freebsd-arm64@4.62.4': + optional: true + + '@rollup/rollup-freebsd-x64@4.62.4': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.62.4': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.62.4': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.62.4': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.62.4': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.62.4': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.62.4': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.62.4': + optional: true + + '@rollup/rollup-linux-x64-musl@4.62.4': + optional: true + + '@rollup/rollup-openbsd-x64@4.62.4': + optional: true + + '@rollup/rollup-openharmony-arm64@4.62.4': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.62.4': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.62.4': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.62.4': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.62.4': + optional: true + '@rtsao/scc@1.1.0': {} '@sinclair/typebox@0.34.48': {} @@ -3810,12 +4379,14 @@ snapshots: '@types/eslint@9.6.1': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 optional: true '@types/estree@1.0.8': {} + '@types/estree@1.0.9': {} + '@types/event-emitter@0.3.5': {} '@types/fs-extra@11.0.4': @@ -4060,6 +4631,8 @@ snapshots: acorn@8.15.0: {} + acorn@8.18.0: {} + aes-js@4.0.0-beta.5: {} ajv@6.12.6: @@ -4092,6 +4665,8 @@ snapshots: ansi-styles@6.2.3: {} + any-promise@1.3.0: {} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 @@ -4280,6 +4855,13 @@ snapshots: buildcheck@0.0.7: optional: true + bundle-require@5.1.0(esbuild@0.27.7): + dependencies: + esbuild: 0.27.7 + load-tsconfig: 0.2.5 + + cac@6.7.14: {} + cafe-utility@34.0.0: {} cafe-utility@36.2.0: {} @@ -4320,6 +4902,10 @@ snapshots: char-regex@1.0.2: {} + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + chownr@1.1.4: {} ci-info@4.4.0: {} @@ -4354,6 +4940,8 @@ snapshots: color-name@1.1.4: {} + commander@4.1.1: {} + compare-func@2.0.0: dependencies: array-ify: 1.0.0 @@ -4361,6 +4949,10 @@ snapshots: concat-map@0.0.1: {} + confbox@0.1.8: {} + + consola@3.4.2: {} + conventional-changelog-angular@8.1.0: dependencies: compare-func: 2.0.0 @@ -4636,6 +5228,35 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + escalade@3.2.0: {} escape-string-regexp@2.0.0: {} @@ -4922,6 +5543,12 @@ snapshots: micromatch: 4.0.8 resolve-dir: 1.0.1 + fix-dts-default-cjs-exports@1.0.1: + dependencies: + magic-string: 0.30.21 + mlly: 1.8.2 + rollup: 4.62.4 + flat-cache@4.0.1: dependencies: flatted: 3.3.3 @@ -5017,12 +5644,6 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 - glob@13.0.0: - dependencies: - minimatch: 10.1.1 - minipass: 7.1.2 - path-scurry: 2.0.1 - glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -5634,6 +6255,8 @@ snapshots: jiti@2.6.1: {} + joycon@3.1.1: {} + js-tokens@4.0.0: {} js-yaml@3.14.2: @@ -5674,8 +6297,12 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lilconfig@3.1.3: {} + lines-and-columns@1.2.4: {} + load-tsconfig@0.2.5: {} + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -5711,8 +6338,6 @@ snapshots: lru-cache@10.4.3: {} - lru-cache@11.2.5: {} - lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -5748,10 +6373,6 @@ snapshots: mimic-function@5.0.1: {} - minimatch@10.1.1: - dependencies: - '@isaacs/brace-expansion': 5.0.0 - minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -5770,6 +6391,13 @@ snapshots: mkdirp-classic@0.5.3: {} + mlly@1.8.2: + dependencies: + acorn: 8.18.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + ms@2.1.3: {} multimatch@5.0.0: @@ -5780,6 +6408,12 @@ snapshots: arrify: 2.0.1 minimatch: 3.1.2 + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + nan@2.28.0: optional: true @@ -5801,6 +6435,8 @@ snapshots: dependencies: path-key: 3.1.1 + object-assign@4.1.1: {} + object-inspect@1.13.4: {} object-keys@1.1.1: {} @@ -5919,13 +6555,10 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 - path-scurry@2.0.1: - dependencies: - lru-cache: 11.2.5 - minipass: 7.1.2 - path-type@4.0.0: {} + pathe@2.0.3: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -5938,12 +6571,25 @@ snapshots: dependencies: find-up: 4.1.0 + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + please-upgrade-node@3.2.0: dependencies: semver-compare: 1.0.0 possible-typed-array-names@1.1.0: {} + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.6): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 2.6.1 + postcss: 8.5.6 + postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -5999,6 +6645,8 @@ snapshots: dependencies: picomatch: 2.3.1 + readdirp@4.1.2: {} + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 @@ -6053,10 +6701,37 @@ snapshots: onetime: 7.0.0 signal-exit: 4.1.0 - rimraf@6.1.2: + rollup@4.62.4: dependencies: - glob: 13.0.0 - package-json-from-dist: 1.0.1 + '@types/estree': 1.0.9 + optionalDependencies: + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.62.4 + '@rollup/rollup-android-arm64': 4.62.4 + '@rollup/rollup-darwin-arm64': 4.62.4 + '@rollup/rollup-darwin-x64': 4.62.4 + '@rollup/rollup-freebsd-arm64': 4.62.4 + '@rollup/rollup-freebsd-x64': 4.62.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.4 + '@rollup/rollup-linux-arm-musleabihf': 4.62.4 + '@rollup/rollup-linux-arm64-gnu': 4.62.4 + '@rollup/rollup-linux-arm64-musl': 4.62.4 + '@rollup/rollup-linux-loong64-gnu': 4.62.4 + '@rollup/rollup-linux-loong64-musl': 4.62.4 + '@rollup/rollup-linux-ppc64-gnu': 4.62.4 + '@rollup/rollup-linux-ppc64-musl': 4.62.4 + '@rollup/rollup-linux-riscv64-gnu': 4.62.4 + '@rollup/rollup-linux-riscv64-musl': 4.62.4 + '@rollup/rollup-linux-s390x-gnu': 4.62.4 + '@rollup/rollup-linux-x64-gnu': 4.62.4 + '@rollup/rollup-linux-x64-musl': 4.62.4 + '@rollup/rollup-openbsd-x64': 4.62.4 + '@rollup/rollup-openharmony-arm64': 4.62.4 + '@rollup/rollup-win32-arm64-msvc': 4.62.4 + '@rollup/rollup-win32-ia32-msvc': 4.62.4 + '@rollup/rollup-win32-x64-gnu': 4.62.4 + '@rollup/rollup-win32-x64-msvc': 4.62.4 + fsevents: 2.3.3 safe-array-concat@1.1.3: dependencies: @@ -6158,6 +6833,8 @@ snapshots: source-map@0.6.1: {} + source-map@0.7.6: {} + split-ca@1.0.1: {} split2@4.2.0: {} @@ -6253,6 +6930,16 @@ snapshots: strip-json-comments@3.1.1: {} + sucrase@3.35.1: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.15 + ts-interface-checker: 0.1.13 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -6288,6 +6975,16 @@ snapshots: glob: 7.2.3 minimatch: 3.1.2 + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + tinyexec@0.3.2: {} + tinyexec@1.0.2: {} tinyglobby@0.2.15: @@ -6301,11 +6998,15 @@ snapshots: dependencies: is-number: 7.0.0 + tree-kill@1.2.2: {} + ts-api-utils@2.4.0(typescript@5.9.3): dependencies: typescript: 5.9.3 - ts-jest@29.4.6(@babel/core@7.28.6)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.6))(jest-util@30.2.0)(jest@30.2.0(@types/node@25.1.0)(ts-node@10.9.2(@types/node@25.1.0)(typescript@5.9.3)))(typescript@5.9.3): + ts-interface-checker@0.1.13: {} + + ts-jest@29.4.6(@babel/core@7.28.6)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.28.6))(esbuild@0.27.7)(jest-util@30.2.0)(jest@30.2.0(@types/node@25.1.0)(ts-node@10.9.2(@types/node@25.1.0)(typescript@5.9.3)))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 @@ -6323,6 +7024,7 @@ snapshots: '@jest/transform': 30.2.0 '@jest/types': 30.2.0 babel-jest: 30.2.0(@babel/core@7.28.6) + esbuild: 0.27.7 jest-util: 30.2.0 ts-node@10.9.2(@types/node@25.1.0)(typescript@5.9.3): @@ -6355,6 +7057,34 @@ snapshots: tslib@2.8.1: optional: true + tsup@8.5.1(jiti@2.6.1)(postcss@8.5.6)(typescript@5.9.3): + dependencies: + bundle-require: 5.1.0(esbuild@0.27.7) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.3 + esbuild: 0.27.7 + fix-dts-default-cjs-exports: 1.0.1 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6) + resolve-from: 5.0.0 + rollup: 4.62.4 + source-map: 0.7.6 + sucrase: 3.35.1 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.6 + typescript: 5.9.3 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + tweetnacl@0.14.5: {} type-check@0.4.0: @@ -6402,6 +7132,8 @@ snapshots: typescript@5.9.3: {} + ufo@1.6.4: {} + uglify-js@3.19.3: optional: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4b8186c..bd7e570 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,5 +1,6 @@ allowBuilds: cpu-features: true + esbuild: true protobufjs: true ssh2: true unrs-resolver: true diff --git a/src/download/index.ts b/src/download/index.ts index eb3a028..a045147 100644 --- a/src/download/index.ts +++ b/src/download/index.ts @@ -1,7 +1,7 @@ -import { Bee, BeeRequestOptions, DownloadOptions } from '@ethersphere/bee-js'; +import { type Bee, type BeeRequestOptions, type DownloadOptions } from '@ethersphere/bee-js'; -import { DownloadFilesResult, DownloadResource, DownloadResult } from '../types/download'; -import { FailedResult } from '../types/utils'; +import { type DownloadFilesResult, type DownloadResource, type DownloadResult } from '../types/download'; +import { type FailedResult } from '../types/utils'; import { settlePromises } from '../utils/common'; import { Logger } from '../utils/logger'; diff --git a/src/fileManager.ts b/src/fileManager.ts index 3a328e2..a98aaec 100644 --- a/src/fileManager.ts +++ b/src/fileManager.ts @@ -1,38 +1,38 @@ import { - BatchId, - Bee, - BeeRequestOptions, - Bytes, - DownloadOptions, + type BatchId, + type Bee, + type BeeRequestOptions, + type Bytes, + type DownloadOptions, FeedIndex, - FileUploadOptions, + type FileUploadOptions, Identifier, MantarayNode, - PostageBatch, - PrivateKey, - PublicKey, + type PostageBatch, + type PrivateKey, + type PublicKey, RedundancyLevel, - RedundantUploadOptions, + type RedundantUploadOptions, Reference, Topic, } from '@ethersphere/bee-js'; -import { DownloadFilesResult, DownloadResource, DownloadResult } from './types/download'; -import { FileManager, FileManagerConfig } from './types/fileManager'; +import { type DownloadFilesResult, type DownloadResource, type DownloadResult } from './types/download'; +import { type FileManager, type FileManagerConfig } from './types/fileManager'; import { - DriveInfo, - FileRecord, - FolderInfo, + type DriveInfo, + type FileRecord, + type FolderInfo, ListDepth, - ManifestHost, - NodeEntry, - NodeHeader, + type ManifestHost, + type NodeEntry, + type NodeHeader, NodeStatus, NodeType, - TrashEntry, + type TrashEntry, } from './types/info'; -import { UpdateItem, UploadFilesResult, UploadItem } from './types/upload'; -import { ActReferences, FailedResult } from './types/utils'; +import { type UpdateItem, type UploadFilesResult, type UploadItem } from './types/upload'; +import { type ActReferences, type FailedResult } from './types/utils'; import { assertActReferences, assertDriveInfoFromMetadata, assertReady } from './utils/asserts'; import { fetchStamp, @@ -68,7 +68,7 @@ import { } from './utils/mantaray'; import { assertValidRelativePath, normalizePath, pathSegments, splitPath } from './utils/path'; import { processDownload } from './download'; -import { EventEmitter, EventEmitterBase } from './eventEmitter'; +import { type EventEmitter, EventEmitterBase } from './eventEmitter'; import { MantarayStore } from './mantarayStore'; import { assertUploadableSource, processUpload } from './upload'; diff --git a/src/mantarayStore.ts b/src/mantarayStore.ts index bb31c75..c921dbb 100644 --- a/src/mantarayStore.ts +++ b/src/mantarayStore.ts @@ -1,16 +1,16 @@ import { - Bee, - BeeRequestOptions, + type Bee, + type BeeRequestOptions, FeedIndex, - MantarayNode, - PrivateKey, - RedundancyLevel, + type MantarayNode, + type PrivateKey, + type RedundancyLevel, Reference, Topic, } from '@ethersphere/bee-js'; -import { DriveInfo, FileRecord, FolderInfo, ManifestHost, NodeType } from './types/info'; -import { ActReferences, FeedResultWithIndex } from './types/utils'; +import { type DriveInfo, type FileRecord, type FolderInfo, type ManifestHost, NodeType } from './types/info'; +import { type ActReferences, type FeedResultWithIndex } from './types/utils'; import { assertActReferences, assertFileRecord } from './utils/asserts'; import { getFeedData, writeActFeed } from './utils/bee'; import { diff --git a/src/types/download.ts b/src/types/download.ts index 1bcb630..820f149 100644 --- a/src/types/download.ts +++ b/src/types/download.ts @@ -1,6 +1,6 @@ -import { PublicKey } from '@ethersphere/bee-js'; +import { type PublicKey } from '@ethersphere/bee-js'; -import { FailedResult } from './utils'; +import { type FailedResult } from './utils'; export interface DownloadResource { path: string; diff --git a/src/types/fileManager.ts b/src/types/fileManager.ts index ef4de7e..b15f14c 100644 --- a/src/types/fileManager.ts +++ b/src/types/fileManager.ts @@ -1,20 +1,20 @@ import { - BatchId, - BeeRequestOptions, - DownloadOptions, - FeedIndex, - FileUploadOptions, - Identifier, - PostageBatch, - RedundancyLevel, - RedundantUploadOptions, + type BatchId, + type BeeRequestOptions, + type DownloadOptions, + type FeedIndex, + type FileUploadOptions, + type Identifier, + type PostageBatch, + type RedundancyLevel, + type RedundantUploadOptions, } from '@ethersphere/bee-js'; -import { EventEmitter } from '../eventEmitter'; +import { type EventEmitter } from '../eventEmitter'; -import { DownloadFilesResult, DownloadResult } from './download'; -import { DriveInfo, FileRecord, FolderInfo, ListDepth, NodeEntry } from './info'; -import { UpdateItem, UploadFilesResult, UploadItem } from './upload'; +import { type DownloadFilesResult, type DownloadResult } from './download'; +import { type DriveInfo, type FileRecord, type FolderInfo, type ListDepth, type NodeEntry } from './info'; +import { type UpdateItem, type UploadFilesResult, type UploadItem } from './upload'; /** * Interface representing a file manager with various file, folder and drive operations. diff --git a/src/types/info.ts b/src/types/info.ts index 7e2dd61..0f737fe 100644 --- a/src/types/info.ts +++ b/src/types/info.ts @@ -1,6 +1,6 @@ -import { RedundancyLevel } from '@ethersphere/bee-js'; +import { type RedundancyLevel } from '@ethersphere/bee-js'; -import { ActReferences } from './utils'; +import { type ActReferences } from './utils'; export enum NodeStatus { Active = 'active', diff --git a/src/types/upload.ts b/src/types/upload.ts index 4abcc28..69f5303 100644 --- a/src/types/upload.ts +++ b/src/types/upload.ts @@ -1,5 +1,5 @@ -import { FileRecord } from './info'; -import { FailedResult } from './utils'; +import { type FileRecord } from './info'; +import { type FailedResult } from './utils'; export interface BrowserUploadOptions { file: File; diff --git a/src/types/utils.ts b/src/types/utils.ts index 6f749d8..244fe78 100644 --- a/src/types/utils.ts +++ b/src/types/utils.ts @@ -1,4 +1,4 @@ -import { Bytes, FeedIndex, Reference } from '@ethersphere/bee-js'; +import { type Bytes, type FeedIndex, type Reference } from '@ethersphere/bee-js'; export interface ActReferences { reference: string; diff --git a/src/upload/index.ts b/src/upload/index.ts index a2e82fe..050b1d3 100644 --- a/src/upload/index.ts +++ b/src/upload/index.ts @@ -60,7 +60,7 @@ export async function processUpload( } = processOptions(isNode, item, redundancyLevel, uploadOptions); if (isNode) { - const { processUploadNode } = await import('./upload.node'); + const { processUploadNode } = await import('./upload-node'); const contentRefs = await processUploadNode( bee, driveInfo, @@ -72,7 +72,7 @@ export async function processUpload( return { contentRefs, rLevel }; } - const { processUploadBrowser } = await import('./upload.browser'); + const { processUploadBrowser } = await import('./upload-browser'); const contentRefs = await processUploadBrowser( bee, driveInfo, diff --git a/src/upload/upload.browser.ts b/src/upload/upload-browser.ts similarity index 75% rename from src/upload/upload.browser.ts rename to src/upload/upload-browser.ts index c1027db..cc597f9 100644 --- a/src/upload/upload.browser.ts +++ b/src/upload/upload-browser.ts @@ -1,8 +1,14 @@ -import { BatchId, Bee, BeeRequestOptions, RedundantUploadOptions, UploadResult } from '@ethersphere/bee-js'; +import { + type BatchId, + type Bee, + type BeeRequestOptions, + type RedundantUploadOptions, + type UploadResult, +} from '@ethersphere/bee-js'; -import { DriveInfo } from '../types/info'; -import { BrowserUploadOptions } from '../types/upload'; -import { ActReferences } from '../types/utils'; +import { type DriveInfo } from '../types/info'; +import { type BrowserUploadOptions } from '../types/upload'; +import { type ActReferences } from '../types/utils'; async function uploadBrowser( bee: Bee, diff --git a/src/upload/upload.node.ts b/src/upload/upload-node.ts similarity index 79% rename from src/upload/upload.node.ts rename to src/upload/upload-node.ts index e05a24d..e9b56f3 100644 --- a/src/upload/upload.node.ts +++ b/src/upload/upload-node.ts @@ -1,8 +1,14 @@ -import { BatchId, Bee, BeeRequestOptions, FileUploadOptions, UploadResult } from '@ethersphere/bee-js'; +import { + type BatchId, + type Bee, + type BeeRequestOptions, + type FileUploadOptions, + type UploadResult, +} from '@ethersphere/bee-js'; -import { DriveInfo } from '../types/info'; -import { NodeUploadOptions } from '../types/upload'; -import { ActReferences } from '../types/utils'; +import { type DriveInfo } from '../types/info'; +import { type NodeUploadOptions } from '../types/upload'; +import { type ActReferences } from '../types/utils'; import { ErrorHandler, FileError } from '../utils/errors'; const errorHandler = ErrorHandler.getInstance(); @@ -30,7 +36,7 @@ async function uploadFile( uploadOptions?: FileUploadOptions, requestOptions?: BeeRequestOptions, ): Promise { - const { isDir } = await import('../utils/fs/fs.node'); + const { isDir } = await import('../utils/fs/fs-node'); const isPathDir = await isDir(resolvedPath); if (isPathDir) { @@ -38,7 +44,7 @@ async function uploadFile( } try { - const { readFile } = await import('../utils/fs/fs.node'); + const { readFile } = await import('../utils/fs/fs-node'); const { data } = await readFile(resolvedPath); return await bee.uploadData(batchId, data, uploadOptions, requestOptions); diff --git a/src/utils/asserts.ts b/src/utils/asserts.ts index 30da97b..15c097e 100644 --- a/src/utils/asserts.ts +++ b/src/utils/asserts.ts @@ -1,8 +1,24 @@ -import { BatchId, EthAddress, Identifier, PublicKey, RedundancyLevel, Reference, Topic } from '@ethersphere/bee-js'; +import { + BatchId, + EthAddress, + Identifier, + PublicKey, + type RedundancyLevel, + Reference, + Topic, +} from '@ethersphere/bee-js'; import { Types } from 'cafe-utility'; -import { DriveInfo, FileRecord, FolderInfo, NodeResource, NodeStatus, NodeType, TrashEntry } from '../types/info'; -import { ActReferences } from '../types/utils'; +import { + type DriveInfo, + type FileRecord, + type FolderInfo, + type NodeResource, + NodeStatus, + NodeType, + type TrashEntry, +} from '../types/info'; +import { type ActReferences } from '../types/utils'; import { MANIFEST_METADATA_DRIVE_ACT_PUBLISHER, diff --git a/src/utils/bee.ts b/src/utils/bee.ts index ce641c1..803e9ca 100644 --- a/src/utils/bee.ts +++ b/src/utils/bee.ts @@ -1,16 +1,16 @@ import { - BatchId, - Bee, - BeeRequestOptions, - EthAddress, + type BatchId, + type Bee, + type BeeRequestOptions, + type EthAddress, FeedIndex, - PostageBatch, - PrivateKey, - RedundancyLevel, + type PostageBatch, + type PrivateKey, + type RedundancyLevel, Topic, } from '@ethersphere/bee-js'; -import { ActReferences, FeedResultWithIndex } from '../types/utils'; +import { type ActReferences, type FeedResultWithIndex } from '../types/utils'; import { isNotFoundError } from './common'; import { FEED_INDEX_ZERO, SWARM_ZERO_ADDRESS } from './constants'; diff --git a/src/utils/common.ts b/src/utils/common.ts index 853d57e..0dd3edd 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -1,4 +1,4 @@ -import { DriveInfo, NodeStatus } from '../types/info'; +import { type DriveInfo, NodeStatus } from '../types/info'; import { Logger } from './logger'; diff --git a/src/utils/fs/fs.node.ts b/src/utils/fs/fs-node.ts similarity index 100% rename from src/utils/fs/fs.node.ts rename to src/utils/fs/fs-node.ts diff --git a/src/utils/mantaray.ts b/src/utils/mantaray.ts index a7bd303..f3829d4 100644 --- a/src/utils/mantaray.ts +++ b/src/utils/mantaray.ts @@ -1,15 +1,22 @@ import { - Bee, - BeeRequestOptions, - DownloadOptions, + type Bee, + type BeeRequestOptions, + type DownloadOptions, MantarayNode, - PrivateKey, + type PrivateKey, RedundancyLevel, - Reference, + type Reference, } from '@ethersphere/bee-js'; -import { DriveInfo, FileRecord, FolderInfo, ManifestHost, NodeHeader, NodeType } from '../types/info'; -import { ActReferences } from '../types/utils'; +import { + type DriveInfo, + type FileRecord, + type FolderInfo, + type ManifestHost, + type NodeHeader, + NodeType, +} from '../types/info'; +import { type ActReferences } from '../types/utils'; import { writeActFeed } from './bee'; import { diff --git a/tests/TESTS.md b/tests/TESTS.md index e3ebc4e..84b0ddd 100644 --- a/tests/TESTS.md +++ b/tests/TESTS.md @@ -9,19 +9,23 @@ and troubleshoot it. It covers both **unit** and **integration** tests (includin ## At a glance -- **Jest** with two **projects** (`unit` and `integration`), both running under **ts-jest** in a Node environment. -- **Unit tests** mock all Swarm/Bee internals and focus on `FileManagerBase` behavior — no network. +- **Jest** with three **projects** (`unit-node`, `unit-browser`, `integration`), all under **ts-jest** in a Node + environment. +- **Unit tests** mock all Swarm/Bee internals and focus on `FileManagerBase` behavior — no network. They run **twice**: + `unit-node` and `unit-browser` execute the same specs, the latter adding `tests/platform-browser.ts` to shim browser + globals so the platform-split code is exercised both ways. - **Integration tests** run against real Bee nodes provisioned by **`@ethersphere/bee-factory`** and exercise ACT encryption, per‑file feeds, mantaray drive manifests, versioning and the trash overlay end‑to‑end. -- Tests run **serially** (`--runInBand`) to avoid shared Bee/port conflicts. +- The runner uses **`--maxWorkers=4`**; integration steps lean on the 5-minute `testTimeout` + propagation retries + rather than serial execution. - `testTimeout` is **5 minutes** per test (integration steps wait on chunk propagation). -- Coverage is collected by default (`v8` provider) into `tests/coverage`. +- Coverage is **opt-in** via `pnpm run test:coverage` (`v8` provider) into `tests/coverage`. --- ## Prerequisites -- **Node.js** — a recent LTS (matching the version bee-js targets). +- **Node.js** — **≥ 22** (matches `engines.node`). - **Docker** — required for integration tests. `bee-factory` spins up a local Bee cluster in containers. - **`@ethersphere/bee-factory`** — a dev/test dependency. The integration project's `globalSetup` starts it and `globalTeardown` stops it automatically; you don't start Bee manually. @@ -36,23 +40,28 @@ Unit tests need none of the above — they never touch the network. ## Running tests ```bash -# Everything (unit + integration), serial + verbose +# Everything (unit-node + unit-browser + integration), verbose pnpm test -# Only unit / only integration +# Only unit (both envs) / only integration pnpm run test:ut pnpm run test:it +# A single unit env +pnpm run test:ut:node +pnpm run test:ut:browser + # Coverage pnpm run test:coverage ``` Scripts exposed by `package.json`: -- **`pnpm test`** → `jest --config=jest.config.ts --runInBand --verbose --silent` -- **`pnpm run test:ut`** → runs `pnpm test --selectProjects=unit` -- **`pnpm run test:it`** → runs `pnpm test --selectProjects=integration` -- **`pnpm run test:coverage`** → `jest --coverage` +- **`pnpm test`** → `jest --config=jest.config.ts --maxWorkers=4 --verbose --silent` +- **`pnpm run test:ut`** → `test --selectProjects=unit-node` then `test --selectProjects=unit-browser` +- **`pnpm run test:ut:node`** / **`pnpm run test:ut:browser`** → a single unit env +- **`pnpm run test:it`** → `test --selectProjects=integration` +- **`pnpm run test:coverage`** → `test --coverage` Everything is configured in `jest.config.ts`, including the `@/*` → `src/*` path mapping used throughout the specs. @@ -64,6 +73,7 @@ Everything is configured in `jest.config.ts`, including the `@/*` → `src/*` pa tests/ ├─ TESTS.md ├─ utils.ts # shared: URLs, signers, batch params, createInitializedFileManager, retry/stream helpers +├─ platform-browser.ts # unit-browser setupFilesAfterEnv — shims browser globals (File/Blob/…) ├─ unit/ │ ├─ setup.ts # setupFilesAfterEnv — centralizes jest.mock() for @/utils/bee & @/utils/mantaray │ ├─ mock.ts # applyDefaultMocks, mock factories, seedRecords, unit createInitializedFileManager @@ -120,8 +130,11 @@ Each domain area lives in its own spec file, mirrored across `unit/` and `integr - `setupUserDrive(driveName, { stampLabel?, reuseOwnerStamp? })` — the standard `beforeAll` fixture: ensures a signer, initializes a `FileManagerBase` (with admin drive), buys a stamp, creates the named user drive, and returns `{ bee, fileManager, drive, ownerStamp, batchId, signer }`. -- `tempFileRegistry()` — returns `{ writeTempFile, writeTempDir, cleanup }`. All on-disk fixtures are written through it - and removed in a single `afterAll(cleanup)`, so **no temporary file survives the run** even if a test throws. +- `tempFileRegistry()` — returns `{ writeTempFile, writeTempDir, cleanup }`. All on-disk fixtures are written under + **`tests/integration/tmp/`** (gitignored + npmignored, never the repo root), and removed in a single + `afterAll(cleanup)`, so **no temporary file survives the run** even if a test throws. `writeTempFile` / `writeTempDir` + return the **absolute** on-disk path — feed that to `sourcePath`, and keep the logical drive `path` separate (they are + decoupled: the disk fixture lives in `tmp/`, the drive path is whatever you upload it as). --- @@ -220,8 +233,9 @@ Emitted events live in `FileManagerEvents` (`src/utils/events.ts`): `FILE_UPLOAD afterAll(cleanup); ``` -- **On-disk fixtures** — always create them via `writeTempFile` / `writeTempDir` so `afterAll(cleanup)` removes them. - Never call `fs.writeFileSync`/`mkdirSync` directly in a spec. +- **On-disk fixtures** — always create them via `writeTempFile` / `writeTempDir` (they write under + `tests/integration/tmp/` and return the absolute source path to pass as `sourcePath`). Never call + `fs.writeFileSync`/`mkdirSync` directly in a spec, and never reuse the drive `path` string as the `sourcePath`. - **ACT download parameters** — pass `actHistoryAddress` and `actPublisher` from the same context that uploaded: diff --git a/tests/integration/abort.spec.ts b/tests/integration/abort.spec.ts index 004abd6..1c40b62 100644 --- a/tests/integration/abort.spec.ts +++ b/tests/integration/abort.spec.ts @@ -1,10 +1,11 @@ -import { Bee, PublicKey } from '@ethersphere/bee-js'; +import { type Bee, type PublicKey } from '@ethersphere/bee-js'; +import path from 'path'; import { setTimeout } from 'timers'; import { setupUserDrive, tempFileRegistry } from './setup/utils'; -import { FileManagerBase } from '@/fileManager'; -import { DriveInfo, FileRecord, FolderInfo, ListDepth } from '@/types'; +import { type FileManagerBase } from '@/fileManager'; +import { type DriveInfo, type FileRecord, type FolderInfo, ListDepth } from '@/types'; import { ROOT_PATH } from '@/utils/constants'; describe('Abort signal handling', () => { @@ -25,15 +26,20 @@ describe('Abort signal handling', () => { const successFile = 'it-abort-success.txt'; const multi1File = 'it-abort-multi-1.txt'; const multi2File = 'it-abort-multi-2.txt'; + let preAbortSrc: string; + let midAbortSrc: string; + let successSrc: string; + let multi1Src: string; + let multi2Src: string; beforeAll(() => { // Larger files (1MB) give abort tests enough time to actually cancel mid-flight. const largeData = Buffer.alloc(1 * 1024 * 1024, 'x'); - writeTempFile(preAbortFile, largeData); - writeTempFile(midAbortFile, largeData); - writeTempFile(successFile, 'This file should upload successfully'); - writeTempFile(multi1File, 'Content 1'); - writeTempFile(multi2File, 'Content 2'); + preAbortSrc = writeTempFile(preAbortFile, largeData); + midAbortSrc = writeTempFile(midAbortFile, largeData); + successSrc = writeTempFile(successFile, 'This file should upload successfully'); + multi1Src = writeTempFile(multi1File, 'Content 1'); + multi2Src = writeTempFile(multi2File, 'Content 2'); }); it('should throw an AbortError when upload is aborted with pre-aborted signal', async () => { @@ -42,7 +48,7 @@ describe('Abort signal handling', () => { const uploadPromise = fileManager.uploadFile( drive.id, - { path: preAbortFile, sourcePath: preAbortFile }, + { path: preAbortFile, sourcePath: preAbortSrc }, undefined, { signal: controller.signal, @@ -64,7 +70,7 @@ describe('Abort signal handling', () => { // Start upload and abort after a short delay const uploadPromise = fileManager.uploadFile( drive.id, - { path: midAbortFile, sourcePath: midAbortFile }, + { path: midAbortFile, sourcePath: midAbortSrc }, undefined, { signal: controller.signal, @@ -85,7 +91,7 @@ describe('Abort signal handling', () => { const controller = new AbortController(); // Upload with signal that is NOT aborted - await fileManager.uploadFile(drive.id, { path: successFile, sourcePath: successFile }, undefined, { + await fileManager.uploadFile(drive.id, { path: successFile, sourcePath: successSrc }, undefined, { signal: controller.signal, }); @@ -103,7 +109,7 @@ describe('Abort signal handling', () => { // First upload should fail (aborted) const firstUploadPromise = fileManager.uploadFile( drive.id, - { path: multi1File, sourcePath: multi1File }, + { path: multi1File, sourcePath: multi1Src }, undefined, { signal: controller1.signal, @@ -119,7 +125,7 @@ describe('Abort signal handling', () => { } // Second upload should succeed (not aborted) - await fileManager.uploadFile(drive.id, { path: multi2File, sourcePath: multi2File }, undefined, { + await fileManager.uploadFile(drive.id, { path: multi2File, sourcePath: multi2Src }, undefined, { signal: controller2.signal, }); @@ -135,8 +141,8 @@ describe('Abort signal handling', () => { beforeAll(async () => { // Upload a 1MB file to download later (large enough for reliable abort timing) - writeTempFile(downloadTestFile, Buffer.alloc(1 * 1024 * 1024, 'x')); - await fileManager.uploadFile(drive.id, { path: downloadTestFile, sourcePath: downloadTestFile }); + const src = writeTempFile(downloadTestFile, Buffer.alloc(1 * 1024 * 1024, 'x')); + await fileManager.uploadFile(drive.id, { path: downloadTestFile, sourcePath: src }); const fr = fileManager.recordList.find((fr) => fr.path === downloadTestFile); expect(fr).toBeDefined(); uploadedFileInfo = fr!; @@ -238,8 +244,11 @@ describe('Abort signal handling', () => { beforeAll(async () => { folderInfo = await fileManager.createFolder(drive.id, ROOT_PATH, folderName); - writeTempDir(folderName, { 'it-abort-listfolder-file.txt': 'listFolder abort test content' }); - await fileManager.uploadFile(drive.id, { path: fileInFolder, sourcePath: fileInFolder }); + const dir = writeTempDir(folderName, { 'it-abort-listfolder-file.txt': 'listFolder abort test content' }); + await fileManager.uploadFile(drive.id, { + path: fileInFolder, + sourcePath: path.join(dir, 'it-abort-listfolder-file.txt'), + }); }); it('should throw error when listFolder is aborted with pre-aborted signal', async () => { diff --git a/tests/integration/drive.spec.ts b/tests/integration/drive.spec.ts index 6ffadab..e22015f 100644 --- a/tests/integration/drive.spec.ts +++ b/tests/integration/drive.spec.ts @@ -1,11 +1,11 @@ -import { Bee, Identifier, PostageBatch, PrivateKey, RedundancyLevel } from '@ethersphere/bee-js'; +import { type Bee, Identifier, type PostageBatch, type PrivateKey, RedundancyLevel } from '@ethersphere/bee-js'; import { buyStampSerialized, createInitializedFileManager, DEFAULT_BATCH_AMOUNT, DEFAULT_BATCH_DEPTH } from '../utils'; import { ensureUniqueSignerWithStamp, tempFileRegistry } from './setup/utils'; -import { FileManagerBase } from '@/fileManager'; -import { DriveInfo } from '@/types'; +import { type FileManagerBase } from '@/fileManager'; +import { type DriveInfo } from '@/types'; import { DriveError, FileManagerEvents } from '@/utils'; describe('Drive operations', () => { diff --git a/tests/integration/e2e.spec.ts b/tests/integration/e2e.spec.ts index d2ca93e..dea9de6 100644 --- a/tests/integration/e2e.spec.ts +++ b/tests/integration/e2e.spec.ts @@ -1,9 +1,11 @@ +import path from 'path'; + import { retryOnPropagationDelay, streamToUint8Array } from '../utils'; import { setupUserDrive, tempFileRegistry } from './setup/utils'; -import { FileManagerBase } from '@/fileManager'; -import { DriveInfo, ListDepth, NodeType } from '@/types'; +import { type FileManagerBase } from '@/fileManager'; +import { type DriveInfo, ListDepth, NodeType } from '@/types'; describe('End-to-End User Workflow', () => { let fileManager: FileManagerBase; @@ -34,11 +36,11 @@ describe('End-to-End User Workflow', () => { expect(reportFi).toBeDefined(); expect(noteFi).toBeDefined(); - // Update just one file in place — mirror the manifest path on disk since Node's upload() - // re-upload path doubles as both the fs source and the manifest fork identity. - writeTempDir('it-e2e-project', { 'report.txt': 'Report V2' }); + // Update just one file in place: rewrite the on-disk source and point the update at it. The + // manifest fork identity comes from reportFi; the disk source is independent of the drive path. + const projectDir = writeTempDir('it-e2e-project', { 'report.txt': 'Report V2' }); - await fileManager.updateFile(drive.id, reportFi, { item: { sourcePath: 'it-e2e-project/report.txt' } }); + await fileManager.updateFile(drive.id, reportFi, { item: { sourcePath: path.join(projectDir, 'report.txt') } }); const projectEntries = await retryOnPropagationDelay(() => fileManager.listFolder(drive.id, 'it-e2e-project', ListDepth.Shallow), diff --git a/tests/integration/file.spec.ts b/tests/integration/file.spec.ts index 8dee0cc..9782e95 100644 --- a/tests/integration/file.spec.ts +++ b/tests/integration/file.spec.ts @@ -1,4 +1,4 @@ -import { Bee, FeedIndex } from '@ethersphere/bee-js'; +import { type Bee, FeedIndex } from '@ethersphere/bee-js'; import path from 'path'; import { @@ -12,8 +12,8 @@ import { import { ensureUniqueSignerWithStamp, setupUserDrive, tempFileRegistry } from './setup/utils'; -import { FileManagerBase } from '@/fileManager'; -import { DriveInfo, ListDepth, NodeType } from '@/types'; +import { type FileManagerBase } from '@/fileManager'; +import { type DriveInfo, ListDepth, NodeType } from '@/types'; import { FileManagerEvents } from '@/utils'; import { FEED_INDEX_ZERO, ROOT_PATH } from '@/utils/constants'; @@ -29,20 +29,22 @@ describe('uploadFile', () => { afterAll(cleanup); it('uploads a new file and adds it to the file record list at version 0', async () => { - const name = writeTempFile('it-upload-new.txt', 'New Content'); - await fileManager.uploadFile(drive.id, { path: name, sourcePath: name }); + const name = 'it-upload-new.txt'; + const src = writeTempFile(name, 'New Content'); + await fileManager.uploadFile(drive.id, { path: name, sourcePath: src }); const record = fileManager.recordList.find((fr) => fr.path === name); expect(record).toBeDefined(); expect(record!.version).toEqual(FEED_INDEX_ZERO.toString()); }); it('throws when uploading a directory — directories must go through uploadFiles', async () => { - const dirPath = writeTempDir('it-upload-integration-dir', { 'inner.txt': 'Inner Content' }); + const dirName = 'it-upload-integration-dir'; + const dirPath = writeTempDir(dirName, { 'inner.txt': 'Inner Content' }); - await expect(fileManager.uploadFile(drive.id, { path: dirPath, sourcePath: dirPath })).rejects.toThrow( + await expect(fileManager.uploadFile(drive.id, { path: dirName, sourcePath: dirPath })).rejects.toThrow( 'Cannot upload a directory - use uploadFiles', ); - expect(fileManager.recordList.some((fr) => fr.path === dirPath)).toBe(false); + expect(fileManager.recordList.some((fr) => fr.path === dirName)).toBe(false); }); }); @@ -197,8 +199,8 @@ describe('uploadFiles', () => { it('fails fast without writing anything when a needed folder path is blocked by an existing file', async () => { const blockerPath = 'it-uploadmany-blocker'; - writeTempFile(blockerPath, 'blocker content'); - await fileManager.uploadFile(drive.id, { path: blockerPath, sourcePath: blockerPath }); + const blockerSrc = writeTempFile(blockerPath, 'blocker content'); + await fileManager.uploadFile(drive.id, { path: blockerPath, sourcePath: blockerSrc }); const innerFile = writeTempFile('it-uploadmany-inner-src.txt', 'inner content'); @@ -224,9 +226,8 @@ describe('uploadFiles', () => { it('uploads a nested folder with files and fetches them back', async () => { const rootFile = writeTempFile('it-init-nested-root.txt', 'Init nested root content'); - const nestedDir = 'it-init-nested-docs'; - const nestedFile = path.join(nestedDir, 'note.txt'); - writeTempDir(nestedDir, { 'note.txt': 'Init nested docs content' }); + const nestedDirPath = writeTempDir('it-init-nested-docs', { 'note.txt': 'Init nested docs content' }); + const nestedFile = path.join(nestedDirPath, 'note.txt'); const driveBatchId = await buyStampSerialized( bee, @@ -279,26 +280,28 @@ describe('updateFile', () => { afterAll(cleanup); it('re-versions a file with new bytes via update(), keeping the topic and advancing the version', async () => { - const name = writeTempFile('it-upload-versions.txt', 'v0'); - await fileManager.uploadFile(drive.id, { path: name, sourcePath: name }); + const name = 'it-upload-versions.txt'; + const src = writeTempFile(name, 'v0'); + await fileManager.uploadFile(drive.id, { path: name, sourcePath: src }); const firstInfo = fileManager.recordList.find((fr) => fr.path === name)!; expect(firstInfo).toBeDefined(); writeTempFile(name, 'v1'); - await fileManager.updateFile(drive.id, firstInfo, { item: { sourcePath: name } }); + await fileManager.updateFile(drive.id, firstInfo, { item: { sourcePath: src } }); const secondInfo = fileManager.recordList.find((fr) => fr.topic.toString() === firstInfo.topic.toString())!; expect(secondInfo.topic.toString()).toEqual(firstInfo.topic.toString()); expect(secondInfo.version).toEqual(new FeedIndex(firstInfo.version!).next().toString()); writeTempFile(name, 'v2'); - await fileManager.updateFile(drive.id, secondInfo, { item: { sourcePath: name } }); + await fileManager.updateFile(drive.id, secondInfo, { item: { sourcePath: src } }); const thirdInfo = fileManager.recordList.find((fr) => fr.topic.toString() === firstInfo.topic.toString())!; expect(thirdInfo.version).toEqual(new FeedIndex(secondInfo.version!).next().toString()); }); it('metadata-only update() keeps the same content ref across versions', async () => { - const name = writeTempFile('it-upload-metadata.txt', 'Metadata Content'); - await fileManager.uploadFile(drive.id, { path: name, sourcePath: name }); + const name = 'it-upload-metadata.txt'; + const src = writeTempFile(name, 'Metadata Content'); + await fileManager.uploadFile(drive.id, { path: name, sourcePath: src }); const firstInfo = fileManager.recordList.find((fr) => fr.path === name)!; expect(firstInfo).toBeDefined(); @@ -314,23 +317,25 @@ describe('updateFile', () => { }); it('should upload a single file and update the file record list', async () => { - const tempFile = writeTempFile('it-upload-single-file.txt', 'Single File Content'); + const name = 'it-upload-single-file.txt'; + const src = writeTempFile(name, 'Single File Content'); await fileManager.uploadFile(drive.id, { - path: tempFile, - sourcePath: tempFile, + path: name, + sourcePath: src, }); const recordList = fileManager.recordList; - const uploadedInfo = recordList.find((fr) => fr.path === tempFile); + const uploadedInfo = recordList.find((fr) => fr.path === name); expect(uploadedInfo).toBeDefined(); }); it('does not create a second record when bumping to a new version', async () => { - const name = writeTempFile('it-upload-bump.txt', 'Bump Content'); - await fileManager.uploadFile(drive.id, { path: name, sourcePath: name }); + const name = 'it-upload-bump.txt'; + const src = writeTempFile(name, 'Bump Content'); + await fileManager.uploadFile(drive.id, { path: name, sourcePath: src }); const original = fileManager.recordList.find((fr) => fr.path === name)!; expect(original).toBeDefined(); - await fileManager.updateFile(drive.id, original, { item: { sourcePath: name } }); + await fileManager.updateFile(drive.id, original, { item: { sourcePath: src } }); const entries = fileManager.recordList.filter((fr) => fr.topic.toString() === original.topic.toString()); expect(entries).toHaveLength(1); @@ -338,9 +343,10 @@ describe('updateFile', () => { }); it('rejects a directory as the update() content source', async () => { - const name = writeTempFile('it-update-dir-src.txt', 'Src Content'); + const name = 'it-update-dir-src.txt'; + const src = writeTempFile(name, 'Src Content'); const dirPath = writeTempDir('it-update-dir-src', {}); - await fileManager.uploadFile(drive.id, { path: name, sourcePath: name }); + await fileManager.uploadFile(drive.id, { path: name, sourcePath: src }); const record = fileManager.recordList.find((fr) => fr.path === name)!; await expect(fileManager.updateFile(drive.id, record, { item: { sourcePath: dirPath } })).rejects.toThrow( @@ -450,8 +456,9 @@ describe('move', () => { afterAll(cleanup); it('renames a file within the drive root, preserving content and bumping the version', async () => { - const fileA = writeTempFile('it-move-a.txt', 'Move Content A'); - await fileManager.uploadFile(driveA.id, { path: fileA, sourcePath: fileA }); + const fileA = 'it-move-a.txt'; + const src = writeTempFile(fileA, 'Move Content A'); + await fileManager.uploadFile(driveA.id, { path: fileA, sourcePath: src }); const before = fileManager.recordList.find((fr) => fr.path === fileA)!; expect(before).toBeDefined(); @@ -477,8 +484,9 @@ describe('move', () => { }); it('moves a root file into a newly created folder', async () => { - const docFile = writeTempFile('it-move-doc.txt', 'Archive Me'); - await fileManager.uploadFile(driveA.id, { path: docFile, sourcePath: docFile }); + const docFile = 'it-move-doc.txt'; + const src = writeTempFile(docFile, 'Archive Me'); + await fileManager.uploadFile(driveA.id, { path: docFile, sourcePath: src }); await fileManager.createFolder(driveA.id, ROOT_PATH, 'archive'); await fileManager.move(docFile, 'archive/doc.txt', driveA.id); @@ -502,10 +510,10 @@ describe('move', () => { const folderName = 'it-move-inbox'; await fileManager.createFolder(driveA.id, ROOT_PATH, folderName); - writeTempDir(folderName, { 'note.txt': 'Inbox Note' }); + const inboxDir = writeTempDir(folderName, { 'note.txt': 'Inbox Note' }); const inboxFilePath = path.join(folderName, 'note.txt'); - await fileManager.uploadFile(driveA.id, { path: inboxFilePath, sourcePath: inboxFilePath }); + await fileManager.uploadFile(driveA.id, { path: inboxFilePath, sourcePath: path.join(inboxDir, 'note.txt') }); await fileManager.move(inboxFilePath, 'note.txt', driveA.id); @@ -525,8 +533,9 @@ describe('move', () => { }); it('moves a file across drives, updating driveId and remaining downloadable from the target', async () => { - const xFile = writeTempFile('it-move-x.txt', 'Cross Drive Content'); - await fileManager.uploadFile(driveA.id, { path: xFile, sourcePath: xFile }); + const xFile = 'it-move-x.txt'; + const src = writeTempFile(xFile, 'Cross Drive Content'); + await fileManager.uploadFile(driveA.id, { path: xFile, sourcePath: src }); await fileManager.move(xFile, xFile, driveA.id, driveB.id); @@ -549,18 +558,21 @@ describe('move', () => { it('rejects invalid move calls', async () => { await expect(fileManager.move('it-move-nonexistent.txt', 'dest.txt', driveA.id)).rejects.toThrow(/not found/i); - const sameFile = writeTempFile('it-move-same.txt', 'Same Path Content'); - await fileManager.uploadFile(driveA.id, { path: sameFile, sourcePath: sameFile }); + const sameFile = 'it-move-same.txt'; + const sameSrc = writeTempFile(sameFile, 'Same Path Content'); + await fileManager.uploadFile(driveA.id, { path: sameFile, sourcePath: sameSrc }); await expect(fileManager.move(sameFile, sameFile, driveA.id)).rejects.toThrow(/identical/i); await expect(fileManager.move(sameFile, 'nosuchfolder/dest.txt', driveA.id)).rejects.toThrow(/not found/i); }); it('rejects a move onto an existing destination, leaving both files intact and downloadable', async () => { - const f1 = writeTempFile('it-move-collide-1.txt', 'Collide One'); - const f2 = writeTempFile('it-move-collide-2.txt', 'Collide Two'); - await fileManager.uploadFile(driveA.id, { path: f1, sourcePath: f1 }); - await fileManager.uploadFile(driveA.id, { path: f2, sourcePath: f2 }); + const f1 = 'it-move-collide-1.txt'; + const f2 = 'it-move-collide-2.txt'; + const src1 = writeTempFile(f1, 'Collide One'); + const src2 = writeTempFile(f2, 'Collide Two'); + await fileManager.uploadFile(driveA.id, { path: f1, sourcePath: src1 }); + await fileManager.uploadFile(driveA.id, { path: f2, sourcePath: src2 }); await expect(fileManager.move(f1, f2, driveA.id)).rejects.toThrow(/already exists/i); diff --git a/tests/integration/folder.spec.ts b/tests/integration/folder.spec.ts index 765e68b..d03ec07 100644 --- a/tests/integration/folder.spec.ts +++ b/tests/integration/folder.spec.ts @@ -1,4 +1,4 @@ -import { BatchId, Identifier } from '@ethersphere/bee-js'; +import { type BatchId, Identifier } from '@ethersphere/bee-js'; import { buyStampSerialized, @@ -10,8 +10,8 @@ import { import { ensureUniqueSignerWithStamp, setupUserDrive, tempFileRegistry } from './setup/utils'; -import { FileManagerBase } from '@/fileManager'; -import { DriveInfo, ListDepth, NodeType } from '@/types'; +import { type FileManagerBase } from '@/fileManager'; +import { type DriveInfo, ListDepth, NodeType } from '@/types'; import { ROOT_PATH } from '@/utils/constants'; describe('Folder operations', () => { diff --git a/tests/integration/init.spec.ts b/tests/integration/init.spec.ts index 998341a..b02d123 100644 --- a/tests/integration/init.spec.ts +++ b/tests/integration/init.spec.ts @@ -1,4 +1,12 @@ -import { BatchId, Bee, BeeResponseError, PrivateKey, PublicKey, RedundancyLevel, Reference } from '@ethersphere/bee-js'; +import { + BatchId, + Bee, + BeeResponseError, + type PrivateKey, + type PublicKey, + RedundancyLevel, + Reference, +} from '@ethersphere/bee-js'; import { buyStampSerialized, @@ -13,7 +21,7 @@ import { import { ensureUniqueSignerWithStamp } from './setup/utils'; import { FileManagerBase } from '@/fileManager'; -import { ActReferences } from '@/types'; +import { type ActReferences } from '@/types'; import { ADMIN_STAMP_LABEL, FILEMANAGER_STATE_TOPIC, FileManagerEvents, StampError } from '@/utils'; import { assertActReferences } from '@/utils/asserts'; import { getFeedData } from '@/utils/bee'; diff --git a/tests/integration/setup/utils.ts b/tests/integration/setup/utils.ts index 653d8fa..c3bda56 100644 --- a/tests/integration/setup/utils.ts +++ b/tests/integration/setup/utils.ts @@ -1,4 +1,4 @@ -import { BatchId, Bee, PrivateKey } from '@ethersphere/bee-js'; +import { type BatchId, Bee, PrivateKey } from '@ethersphere/bee-js'; import * as fs from 'fs'; import path from 'path'; @@ -11,8 +11,8 @@ import { DEFAULT_MOCK_SIGNER, } from '../../utils'; -import { FileManagerBase } from '@/fileManager'; -import { DriveInfo } from '@/types'; +import { type FileManagerBase } from '@/fileManager'; +import { type DriveInfo } from '@/types'; import { ADMIN_STAMP_LABEL } from '@/utils/constants'; import { generateRandomBytes } from '@/utils/crypto'; @@ -81,6 +81,8 @@ export interface TempFileRegistry { cleanup: () => void; } +const TMP_DIR = path.resolve(__dirname, '../tmp'); + export function tempFileRegistry(): TempFileRegistry { const paths: string[] = []; const track = (p: string): string => { @@ -90,17 +92,20 @@ export function tempFileRegistry(): TempFileRegistry { return { writeTempFile(name, content) { - fs.writeFileSync(name, content); - return track(name); + const full = path.join(TMP_DIR, name); + fs.mkdirSync(path.dirname(full), { recursive: true }); + fs.writeFileSync(full, content); + return track(full); }, writeTempDir(dir, files) { - fs.mkdirSync(dir, { recursive: true }); + const root = path.join(TMP_DIR, dir); + fs.mkdirSync(root, { recursive: true }); for (const [relativePath, content] of Object.entries(files)) { - const full = path.join(dir, relativePath); + const full = path.join(root, relativePath); fs.mkdirSync(path.dirname(full), { recursive: true }); fs.writeFileSync(full, content); } - return track(dir); + return track(root); }, cleanup() { for (const p of paths) { diff --git a/tests/integration/trash.spec.ts b/tests/integration/trash.spec.ts index 383165c..b4a3773 100644 --- a/tests/integration/trash.spec.ts +++ b/tests/integration/trash.spec.ts @@ -1,11 +1,11 @@ -import { BatchId, Bee, Identifier } from '@ethersphere/bee-js'; +import { type BatchId, type Bee, Identifier } from '@ethersphere/bee-js'; import { createInitializedFileManager, retryOnPropagationDelay } from '../utils'; import { setupUserDrive, tempFileRegistry } from './setup/utils'; import { FileManagerBase } from '@/fileManager'; -import { DriveInfo, FileRecord, ListDepth, NodeStatus, NodeType } from '@/types'; +import { type DriveInfo, type FileRecord, ListDepth, NodeStatus, NodeType } from '@/types'; import { ROOT_PATH } from '@/utils/constants'; describe('Lifecycle management', () => { @@ -15,6 +15,7 @@ describe('Lifecycle management', () => { let testFi: FileRecord; let drive: DriveInfo; const TEST_NAME = 'trash-restore-forget.txt'; + let testSrc: string; const { writeTempFile, cleanup } = tempFileRegistry(); beforeAll(async () => { @@ -25,8 +26,8 @@ describe('Lifecycle management', () => { ownerStamp: adminBatch, } = await setupUserDrive('fileoperations', { stampLabel: 'fileOpsIntegration' })); - writeTempFile(TEST_NAME, 'file ops content'); - await fileManager.uploadFile(drive.id, { path: TEST_NAME, sourcePath: TEST_NAME }); + testSrc = writeTempFile(TEST_NAME, 'file ops content'); + await fileManager.uploadFile(drive.id, { path: TEST_NAME, sourcePath: testSrc }); testFi = fileManager.recordList.find((fr) => fr.path === TEST_NAME)!; expect(testFi).toBeDefined(); @@ -111,7 +112,7 @@ describe('Lifecycle management', () => { }); it('should never duplicate FileRecord entries when trashing/recovering', async () => { - await fileManager.uploadFile(drive.id, { path: TEST_NAME, sourcePath: TEST_NAME }); + await fileManager.uploadFile(drive.id, { path: TEST_NAME, sourcePath: testSrc }); const freshFi = fileManager.recordList.find((fr) => fr.path === TEST_NAME)!; const topic = freshFi.topic.toString(); diff --git a/tests/integration/version.spec.ts b/tests/integration/version.spec.ts index ec7a4c4..2b64ab9 100644 --- a/tests/integration/version.spec.ts +++ b/tests/integration/version.spec.ts @@ -1,4 +1,4 @@ -import { Bee, FeedIndex, PrivateKey, Topic } from '@ethersphere/bee-js'; +import { type Bee, FeedIndex, type PrivateKey, Topic } from '@ethersphere/bee-js'; import { buyStampSerialized, @@ -11,7 +11,7 @@ import { import { setupUserDrive, tempFileRegistry } from './setup/utils'; import { FileManagerBase } from '@/fileManager'; -import { DriveInfo, FileRecord } from '@/types'; +import { type DriveInfo, type FileRecord } from '@/types'; import { getFeedData } from '@/utils/bee'; import { FEED_INDEX_ZERO, ROOT_PATH } from '@/utils/constants'; @@ -23,13 +23,13 @@ describe('Version control', () => { const { writeTempFile, cleanup } = tempFileRegistry(); // helper to ensure at least one base FileRecord exists. - // Flat, cwd-relative name: upload()'s `path` doubles as both the on-disk source and the - // top-level drive manifest fork name, so it must resolve with zero intermediate segments. + // Flat drive-manifest fork name (`name`) with the on-disk source (`src`) kept separate: the + // disk fixture lives under tests/integration/tmp/ while the manifest fork stays a bare leaf. const ensureBase = async (name = `versioned-file-${Date.now()}`, di: DriveInfo = drive): Promise => { const existing = fileManager.recordList.find((f) => f.path === name); if (existing) return existing; - writeTempFile(name, 'seed'); - await fileManager.uploadFile(di.id, { path: name, sourcePath: name }); + const src = writeTempFile(name, 'seed'); + await fileManager.uploadFile(di.id, { path: name, sourcePath: src }); return fileManager.recordList.at(-1)!; }; @@ -47,15 +47,15 @@ describe('Version control', () => { it('handles sequential uploads with proper slot indices', async () => { const name = `parallel-${Date.now()}`; - writeTempFile(name, 'v0'); - await fileManager.uploadFile(drive.id, { path: name, sourcePath: name }); + const src = writeTempFile(name, 'v0'); + await fileManager.uploadFile(drive.id, { path: name, sourcePath: src }); const base = fileManager.recordList.at(-1)!; let latestVersion = BigInt(base.version!.toString()); for (const i of [1, 2, 3]) { writeTempFile(name, `v${i}`); - await fileManager.updateFile(drive.id, base, { item: { sourcePath: name } }); + await fileManager.updateFile(drive.id, base, { item: { sourcePath: src } }); latestVersion = BigInt(i); } @@ -74,8 +74,8 @@ describe('Version control', () => { it('updateFile lazy-loads the record on a cold cache (fresh instance, no prior listing)', async () => { const NAME = `cold-update-${Date.now()}`; - writeTempFile(NAME, 'cold v0'); - await fileManager.uploadFile(drive.id, { path: NAME, sourcePath: NAME }); + const src = writeTempFile(NAME, 'cold v0'); + await fileManager.uploadFile(drive.id, { path: NAME, sourcePath: src }); const base = fileManager.recordList.find((fr) => fr.path === NAME)!; expect(base.version).toBe(FEED_INDEX_ZERO.toString()); @@ -85,7 +85,7 @@ describe('Version control', () => { expect(fm2.recordList.find((fr) => fr.topic === base.topic)).toBeUndefined(); writeTempFile(NAME, 'cold v1'); - const updated = await fm2.updateFile(drive.id, base, { item: { sourcePath: NAME } }); + const updated = await fm2.updateFile(drive.id, base, { item: { sourcePath: src } }); // Re-versioned via lazy hydration; the record is now present in the fresh instance's cache. expect(updated.version).toBe(FeedIndex.fromBigInt(1n).toString()); @@ -113,12 +113,12 @@ describe('Version control', () => { it('getFileVersion returns independently downloadable, version-correct bytes', async () => { const NAME = `version-bytes-${Date.now()}`; - writeTempFile(NAME, 'Version bytes v0'); - await fileManager.uploadFile(drive.id, { path: NAME, sourcePath: NAME }); + const src = writeTempFile(NAME, 'Version bytes v0'); + await fileManager.uploadFile(drive.id, { path: NAME, sourcePath: src }); const v0Fi = fileManager.recordList.at(-1)!; writeTempFile(NAME, 'Version bytes v1'); - await fileManager.updateFile(drive.id, v0Fi, { item: { sourcePath: NAME } }); + await fileManager.updateFile(drive.id, v0Fi, { item: { sourcePath: src } }); const v0 = await fileManager.getFileVersion(v0Fi, FEED_INDEX_ZERO); const head = await fileManager.getFileVersion(v0Fi); @@ -168,18 +168,18 @@ describe('Version control', () => { it('uploads multiple versions, counts them, fetches an old version and downloads it', async () => { const NAME = `versioned-file-${Date.now()}`; const content = 'Version 0 content'; - writeTempFile(NAME, content); - await fileManager.uploadFile(drive.id, { path: NAME, sourcePath: NAME }); + const src = writeTempFile(NAME, content); + await fileManager.uploadFile(drive.id, { path: NAME, sourcePath: src }); const v0Fi = fileManager.recordList.at(-1)!; const initialVersion = BigInt(v0Fi.version!); writeTempFile(NAME, 'Version 1 content'); - await fileManager.updateFile(drive.id, v0Fi, { item: { sourcePath: NAME } }); + await fileManager.updateFile(drive.id, v0Fi, { item: { sourcePath: src } }); const countAfterV1 = await getFeedData(bee, new Topic(v0Fi.topic), signer.publicKey().address().toString()); const latestFi = await fileManager.getFileVersion(v0Fi, countAfterV1.feedIndex); writeTempFile(NAME, 'Version 2 content'); - await fileManager.updateFile(drive.id, latestFi, { item: { sourcePath: NAME } }); + await fileManager.updateFile(drive.id, latestFi, { item: { sourcePath: src } }); // Raw feed reads are eventually consistent; under parallel node load the last write may not be // visible immediately. Retry until the feed reflects all three writes (v0 + two updates). @@ -198,14 +198,14 @@ describe('Version control', () => { }); it('can restore a prior version and make it the new head', async () => { - // Re-upload must reuse the exact path ensureBase() uploaded with — see ensureBase() comment above. + // Re-upload must reuse the exact drive path ensureBase() uploaded with — see ensureBase() comment above. const NAME = 'restore-file'; const base = await ensureBase(NAME); const initialVersion = BigInt(base.version!.toString()); const firstRef = base.content.reference; - writeTempFile(NAME, 'second'); - await fileManager.updateFile(drive.id, base, { item: { sourcePath: NAME } }); + const src = writeTempFile(NAME, 'second'); + await fileManager.updateFile(drive.id, base, { item: { sourcePath: src } }); await fileManager.restoreFileVersion(base); @@ -229,8 +229,8 @@ describe('Version control', () => { it('restoring on a single version file reaffirms the head', async () => { const NAME = 'noop-restore'; const base = await ensureBase(NAME); - writeTempFile(NAME, 'B'); - await fileManager.updateFile(drive.id, base, { item: { sourcePath: NAME } }); + const src = writeTempFile(NAME, 'B'); + await fileManager.updateFile(drive.id, base, { item: { sourcePath: src } }); const currentHead = await fileManager.getFileVersion(base, base.version); @@ -257,13 +257,13 @@ describe('Version control', () => { it("restoring an old version keeps the current (post-move) location, not the version's recorded path", async () => { const NAME = 'restore-move-file.txt'; - writeTempFile(NAME, 'Restore Move V0 Content'); - await fileManager.uploadFile(drive.id, { path: NAME, sourcePath: NAME }); + const src = writeTempFile(NAME, 'Restore Move V0 Content'); + await fileManager.uploadFile(drive.id, { path: NAME, sourcePath: src }); const base = fileManager.recordList.at(-1)!; const topic = base.topic.toString(); writeTempFile(NAME, 'Restore Move V1 Content'); - await fileManager.updateFile(drive.id, base, { item: { sourcePath: NAME } }); + await fileManager.updateFile(drive.id, base, { item: { sourcePath: src } }); await fileManager.createFolder(drive.id, ROOT_PATH, 'restore-move-dest'); const destPath = 'restore-move-dest/restore-move-file.txt'; diff --git a/tests/platform.browser.ts b/tests/platform-browser.ts similarity index 100% rename from tests/platform.browser.ts rename to tests/platform-browser.ts diff --git a/tests/unit/abort.spec.ts b/tests/unit/abort.spec.ts index 014e567..dc1bc07 100644 --- a/tests/unit/abort.spec.ts +++ b/tests/unit/abort.spec.ts @@ -10,7 +10,7 @@ import { import { applyDefaultMocks, createMockDriveInfo, createMockNodeAddresses, seedRecords } from './mock'; -import { FileRecord, ListDepth, NodeType } from '@/types'; +import { type FileRecord, ListDepth, NodeType } from '@/types'; import { DriveError } from '@/utils'; import { SWARM_ZERO_ADDRESS } from '@/utils/constants'; diff --git a/tests/unit/drive.spec.ts b/tests/unit/drive.spec.ts index 15e5639..9499e93 100644 --- a/tests/unit/drive.spec.ts +++ b/tests/unit/drive.spec.ts @@ -4,7 +4,7 @@ import { createInitializedFileManager, DEFAULT_MOCK_SIGNER, DUMMY_BATCH_ID } fro import { applyDefaultMocks, createMockDriveInfo, createMockNodeAddresses, seedRecords } from './mock'; -import { DriveInfo, NodeType } from '@/types'; +import { type DriveInfo, NodeType } from '@/types'; import { DriveError, FileManagerEvents } from '@/utils'; import { ADMIN_STAMP_LABEL, SWARM_ZERO_ADDRESS } from '@/utils/constants'; diff --git a/tests/unit/file.spec.ts b/tests/unit/file.spec.ts index b85a2b0..1a03552 100644 --- a/tests/unit/file.spec.ts +++ b/tests/unit/file.spec.ts @@ -1,4 +1,13 @@ -import { BatchId, Bee, Bytes, FeedIndex, MantarayNode, RedundancyLevel, Reference, Topic } from '@ethersphere/bee-js'; +import { + BatchId, + Bee, + Bytes, + FeedIndex, + type MantarayNode, + RedundancyLevel, + Reference, + Topic, +} from '@ethersphere/bee-js'; import { createInitializedFileManager, @@ -12,13 +21,13 @@ import { applyDefaultMocks, createMockDriveInfo, createMockNodeAddresses, - SeedableFm, + type SeedableFm, seedDummyFile, seedRecords, } from './mock'; -import { FileManagerBase } from '@/fileManager'; -import { DriveInfo, FileRecord, NodeStatus, NodeType } from '@/types'; +import { type FileManagerBase } from '@/fileManager'; +import { type DriveInfo, type FileRecord, NodeStatus, NodeType } from '@/types'; import { FileError, FileManagerEvents, FileRecordError } from '@/utils'; import { getFeedData } from '@/utils/bee'; import { @@ -547,7 +556,7 @@ describe('File operations', () => { describe('upload source validation', () => { it('isDir throws when the path does not exist (node fs)', async () => { - const { isDir } = await import('@/utils/fs/fs.node'); + const { isDir } = await import('@/utils/fs/fs-node'); await expect(isDir('definitely-missing-path-xyz-123')).rejects.toThrow(/does not exist/); }); diff --git a/tests/unit/folder.spec.ts b/tests/unit/folder.spec.ts index 903ae47..4174c68 100644 --- a/tests/unit/folder.spec.ts +++ b/tests/unit/folder.spec.ts @@ -1,10 +1,19 @@ -import { BatchId, Bee, Bytes, FeedIndex, Identifier, MantarayNode, RedundancyLevel, Topic } from '@ethersphere/bee-js'; +import { + BatchId, + Bee, + Bytes, + FeedIndex, + Identifier, + type MantarayNode, + RedundancyLevel, + Topic, +} from '@ethersphere/bee-js'; import { createInitializedFileManager, DEFAULT_MOCK_SIGNER, DUMMY_BATCH_ID } from '../utils'; import { applyDefaultMocks, createMockDriveInfo, createMockNodeAddresses, seedDummyFile, seedRecords } from './mock'; -import { ListDepth, NodeHeader, NodeType } from '@/types'; +import { ListDepth, type NodeHeader, NodeType } from '@/types'; import { FileManagerEvents } from '@/utils'; import { getFeedData } from '@/utils/bee'; import { SWARM_ZERO_ADDRESS } from '@/utils/constants'; diff --git a/tests/unit/mock.ts b/tests/unit/mock.ts index 6faec01..39884bb 100644 --- a/tests/unit/mock.ts +++ b/tests/unit/mock.ts @@ -1,32 +1,32 @@ import { BatchId, Bee, - BeeVersions, + type BeeVersions, Bytes, Duration, EthAddress, FeedIndex, - FeedReader, - FeedWriter, + type FeedReader, + type FeedWriter, Identifier, MantarayNode, - NodeAddresses, - NumberString, + type NodeAddresses, + type NumberString, PeerAddress, - PostageBatch, + type PostageBatch, PublicKey, RedundancyLevel, Reference, Size, Topic, - UploadResult, + type UploadResult, } from '@ethersphere/bee-js'; import { Optional } from 'cafe-utility'; import { DEFAULT_MOCK_SIGNER, DUMMY_BATCH_ID } from '../utils'; -import { FileManagerBase } from '@/fileManager'; -import { DriveInfo, FileRecord, NodeType } from '@/types'; +import { type FileManagerBase } from '@/fileManager'; +import { type DriveInfo, type FileRecord, NodeType } from '@/types'; import { fetchStamp, getFeedData } from '@/utils/bee'; import { ADMIN_STAMP_LABEL, FEED_INDEX_ZERO, SWARM_ZERO_ADDRESS } from '@/utils/constants'; import { getAllNodeEntries, loadMantaray } from '@/utils/mantaray'; diff --git a/tests/unit/trash.spec.ts b/tests/unit/trash.spec.ts index 1383d8d..620f36b 100644 --- a/tests/unit/trash.spec.ts +++ b/tests/unit/trash.spec.ts @@ -1,11 +1,11 @@ -import { Bytes, FeedIndex, Identifier, MantarayNode, RedundancyLevel, Topic } from '@ethersphere/bee-js'; +import { Bytes, FeedIndex, Identifier, type MantarayNode, RedundancyLevel, Topic } from '@ethersphere/bee-js'; import { createInitializedFileManager, DEFAULT_MOCK_SIGNER, DUMMY_BATCH_ID, makeUploadSource } from '../utils'; import { applyDefaultMocks, createMockNodeAddresses, seedRecords } from './mock'; -import { FileManagerBase } from '@/fileManager'; -import { DriveInfo, FileRecord, FolderInfo, NodeStatus, NodeType } from '@/types'; +import { type FileManagerBase } from '@/fileManager'; +import { type DriveInfo, type FileRecord, type FolderInfo, NodeStatus, NodeType } from '@/types'; import { FileManagerEvents } from '@/utils'; import { getFeedData } from '@/utils/bee'; import { SWARM_ZERO_ADDRESS } from '@/utils/constants'; diff --git a/tests/unit/version.spec.ts b/tests/unit/version.spec.ts index f52de58..026b1ec 100644 --- a/tests/unit/version.spec.ts +++ b/tests/unit/version.spec.ts @@ -4,9 +4,9 @@ import { createInitializedFileManager, DEFAULT_MOCK_SIGNER, DUMMY_BATCH_ID } fro import { applyDefaultMocks, createMockNodeAddresses, seedRecords } from './mock'; -import { FileManagerBase } from '@/fileManager'; -import { FileRecord, NodeType } from '@/types'; -import { FeedResultWithIndex } from '@/types/utils'; +import { type FileManagerBase } from '@/fileManager'; +import { type FileRecord, NodeType } from '@/types'; +import { type FeedResultWithIndex } from '@/types/utils'; import { FileManagerEvents } from '@/utils'; import { getFeedData } from '@/utils/bee'; import { FEED_INDEX_ZERO, SWARM_ZERO_ADDRESS } from '@/utils/constants'; diff --git a/tests/utils.ts b/tests/utils.ts index 039f3ae..497a516 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -1,9 +1,9 @@ -import { BatchId, Bee, BeeRequestOptions, PrivateKey, RedundancyLevel } from '@ethersphere/bee-js'; +import { type BatchId, Bee, type BeeRequestOptions, PrivateKey, RedundancyLevel } from '@ethersphere/bee-js'; import * as fs from 'fs'; import path from 'path'; import { isNode } from 'std-env'; -import { EventEmitter } from '@/eventEmitter'; +import { type EventEmitter } from '@/eventEmitter'; import { FileManagerBase } from '@/fileManager'; import { FileManagerEvents } from '@/utils'; diff --git a/tsconfig.json b/tsconfig.json index c4c0fb4..d46c869 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,24 +4,21 @@ "compilerOptions": { "target": "ES2022", "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ES2022", - "moduleResolution": "node", + "module": "ESNext", + "moduleResolution": "Bundler", + "verbatimModuleSyntax": true, "resolveJsonModule": true, - "declaration": true, - "emitDeclarationOnly": false, - "declarationDir": "dist/types", "esModuleInterop": true, + "noEmit": true, "types": ["node", "jest"], "skipLibCheck": true, - "declarationMap": true, - "sourceMap": true, "strict": true, "alwaysStrict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, "strictPropertyInitialization": true, - "isolatedModules": false, + "isolatedModules": true, "allowSyntheticDefaultImports": true, "noImplicitAny": true, "typeRoots": ["src/@types", "node_modules/@types"], diff --git a/tsup.config.ts b/tsup.config.ts new file mode 100644 index 0000000..d976755 --- /dev/null +++ b/tsup.config.ts @@ -0,0 +1,53 @@ +import { defineConfig } from 'tsup'; + +const stubForeignPlatform = (name: string, filter: RegExp, exportNames: string[]) => ({ + name, + setup(build: any) { + build.onResolve({ filter }, (args: any) => ({ path: args.path, namespace: name })); + build.onLoad({ filter: /.*/, namespace: name }, () => ({ + loader: 'ts', + contents: + `const unavailable = () => { throw new Error('Platform module loaded on the wrong platform'); };\n` + + exportNames.map((n) => `export const ${n} = unavailable;`).join('\n'), + })); + }, +}); + +const stubNodeInBrowser = stubForeignPlatform('stub-node-in-browser', /(?:^|\/)(upload-node|fs-node)$/, [ + 'processUploadNode', + 'isDir', + 'readFile', + 'getContentType', +]); +const stubBrowserInNode = stubForeignPlatform('stub-browser-in-node', /(?:^|\/)upload-browser$/, [ + 'processUploadBrowser', +]); + +export default defineConfig([ + { + entry: { index: 'src/index.ts' }, + format: ['esm', 'cjs'], + platform: 'node', + outDir: 'dist/node', + dts: true, + treeshake: true, + clean: true, + esbuildPlugins: [stubBrowserInNode], + outExtension({ format }) { + return { js: format === 'cjs' ? '.cjs' : '.mjs' }; + }, + }, + { + entry: { index: 'src/index.ts' }, + format: ['esm', 'cjs'], + platform: 'browser', + outDir: 'dist/browser', + dts: false, + treeshake: true, + external: ['fs', 'path', 'node:fs', 'node:path'], + esbuildPlugins: [stubNodeInBrowser], + outExtension({ format }) { + return { js: format === 'cjs' ? '.cjs' : '.mjs' }; + }, + }, +]);