diff --git a/.changeset/wet-hornets-study.md b/.changeset/wet-hornets-study.md new file mode 100644 index 0000000..99cbdd5 --- /dev/null +++ b/.changeset/wet-hornets-study.md @@ -0,0 +1,5 @@ +--- +"@webiny/stdlib": patch +--- + +feat: add HashFolderTool — deterministic SHA-256 folder hashing with sync and async (parallel I/O) methods, replacing the unmaintained folder-hash library diff --git a/README.md b/README.md index b1757e5..63ad910 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ The package is ESM-only and ships three subpath exports. Because each is a separ | `NdJsonReaderTool` / `NdJsonReaderToolFeature` | Parse NDJSON from files, streams, or in-memory lines with checkpoint support — [docs](src/node/features/NdJsonReaderTool/README.md) | | `ReadStreamFactory` / `ReadStreamFactoryFeature` | Disposable `node:fs` read streams via `AsyncDisposable` — [docs](src/node/features/ReadStreamFactory/README.md) | | `PackageJsonFileTool` / `PackageJsonFileToolFeature` | Read, validate, mutate, and write `package.json` files — [docs](src/node/features/PackageJsonFileTool/README.md) | +| `HashFolderTool` / `HashFolderToolFeature` | Deterministic SHA-256 hash of a folder's contents — [docs](src/node/features/HashFolderTool/README.md) | --- diff --git a/__tests__/node/HashFolderTool.test.ts b/__tests__/node/HashFolderTool.test.ts new file mode 100644 index 0000000..b64e6ff --- /dev/null +++ b/__tests__/node/HashFolderTool.test.ts @@ -0,0 +1,327 @@ +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import { mkdirSync, rmSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import { tmpdir } from "node:os"; +import { Container } from "@webiny/di"; +import { + HashFolderTool, + HashFolderToolFeature, + createHashFolderTool, + hashFolder, + hashFolderAsync +} from "../../src/node/features/HashFolderTool/index.js"; + +function makeContainer(): Container { + const container = new Container(); + HashFolderToolFeature.register(container); + return container; +} + +describe("HashFolderTool", () => { + let tmpDir: string; + let tool: HashFolderTool.Interface; + + beforeEach(() => { + tmpDir = join(tmpdir(), `wby-hash-test-${Date.now()}`); + mkdirSync(tmpDir, { recursive: true }); + tool = makeContainer().resolve(HashFolderTool); + }); + + afterEach(() => { + rmSync(tmpDir, { recursive: true, force: true }); + }); + + describe("hash (sync)", () => { + it("returns a result with a hex hash", () => { + writeFileSync(join(tmpDir, "a.txt"), "hello"); + writeFileSync(join(tmpDir, "b.txt"), "world"); + + const result = tool.hash(tmpDir); + expect(result).toEqual({ hash: expect.stringMatching(/^[a-f0-9]{64}$/) }); + }); + + it("returns a deterministic hash for the same content", () => { + writeFileSync(join(tmpDir, "file.txt"), "content"); + + const result1 = tool.hash(tmpDir); + const result2 = tool.hash(tmpDir); + expect(result1).toEqual(result2); + }); + + it("produces different hashes when file content changes", () => { + writeFileSync(join(tmpDir, "file.txt"), "version1"); + const result1 = tool.hash(tmpDir); + + writeFileSync(join(tmpDir, "file.txt"), "version2"); + const result2 = tool.hash(tmpDir); + + expect(result1).not.toEqual(result2); + }); + + it("includes files in nested subdirectories", () => { + mkdirSync(join(tmpDir, "sub"), { recursive: true }); + writeFileSync(join(tmpDir, "sub", "nested.txt"), "deep"); + + const result1 = tool.hash(tmpDir); + + writeFileSync(join(tmpDir, "sub", "nested.txt"), "changed"); + const result2 = tool.hash(tmpDir); + + expect(result1).not.toEqual(result2); + }); + + it("excludes specified folders", () => { + writeFileSync(join(tmpDir, "keep.txt"), "kept"); + mkdirSync(join(tmpDir, "dist"), { recursive: true }); + writeFileSync(join(tmpDir, "dist", "bundle.js"), "compiled"); + + const result1 = tool.hash(tmpDir, { excludeFolders: ["dist"] }); + + writeFileSync(join(tmpDir, "dist", "bundle.js"), "recompiled"); + const result2 = tool.hash(tmpDir, { excludeFolders: ["dist"] }); + + expect(result1).toEqual(result2); + }); + + it("excludes specified files", () => { + writeFileSync(join(tmpDir, "source.ts"), "code"); + writeFileSync(join(tmpDir, "tsconfig.build.tsbuildinfo"), "info"); + + const result1 = tool.hash(tmpDir, { + excludeFiles: ["tsconfig.build.tsbuildinfo"] + }); + + writeFileSync(join(tmpDir, "tsconfig.build.tsbuildinfo"), "updated-info"); + const result2 = tool.hash(tmpDir, { + excludeFiles: ["tsconfig.build.tsbuildinfo"] + }); + + expect(result1).toEqual(result2); + }); + + it("excludes multiple folders and files together", () => { + writeFileSync(join(tmpDir, "source.ts"), "code"); + mkdirSync(join(tmpDir, "dist"), { recursive: true }); + mkdirSync(join(tmpDir, "node_modules"), { recursive: true }); + writeFileSync(join(tmpDir, "dist", "out.js"), "compiled"); + writeFileSync(join(tmpDir, "node_modules", "dep.js"), "dep"); + writeFileSync(join(tmpDir, "tsconfig.build.tsbuildinfo"), "info"); + + const result1 = tool.hash(tmpDir, { + excludeFolders: ["dist", "node_modules"], + excludeFiles: ["tsconfig.build.tsbuildinfo"] + }); + + writeFileSync(join(tmpDir, "dist", "out.js"), "recompiled"); + writeFileSync(join(tmpDir, "node_modules", "dep.js"), "updated-dep"); + writeFileSync(join(tmpDir, "tsconfig.build.tsbuildinfo"), "new-info"); + + const result2 = tool.hash(tmpDir, { + excludeFolders: ["dist", "node_modules"], + excludeFiles: ["tsconfig.build.tsbuildinfo"] + }); + + expect(result1).toEqual(result2); + }); + + it("is order-independent — same files in different creation order produce same hash", () => { + const dir1 = join(tmpDir, "dir1"); + const dir2 = join(tmpDir, "dir2"); + mkdirSync(dir1, { recursive: true }); + mkdirSync(dir2, { recursive: true }); + + writeFileSync(join(dir1, "a.txt"), "alpha"); + writeFileSync(join(dir1, "b.txt"), "beta"); + + writeFileSync(join(dir2, "b.txt"), "beta"); + writeFileSync(join(dir2, "a.txt"), "alpha"); + + const result1 = tool.hash(dir1); + const result2 = tool.hash(dir2); + expect(result1).toEqual(result2); + }); + + it("returns a hash for an empty folder", () => { + const result = tool.hash(tmpDir); + expect(result).toEqual({ hash: expect.stringMatching(/^[a-f0-9]{64}$/) }); + }); + + it("includes relative path in the hash so renames are detected", () => { + writeFileSync(join(tmpDir, "original.txt"), "content"); + const result1 = tool.hash(tmpDir); + + rmSync(join(tmpDir, "original.txt")); + writeFileSync(join(tmpDir, "renamed.txt"), "content"); + const result2 = tool.hash(tmpDir); + + expect(result1).not.toEqual(result2); + }); + }); + + describe("hashAsync (parallel)", () => { + it("returns a result with a hex hash", async () => { + writeFileSync(join(tmpDir, "a.txt"), "hello"); + writeFileSync(join(tmpDir, "b.txt"), "world"); + + const result = await tool.hashAsync(tmpDir); + expect(result).toEqual({ hash: expect.stringMatching(/^[a-f0-9]{64}$/) }); + }); + + it("returns a deterministic hash for the same content", async () => { + writeFileSync(join(tmpDir, "file.txt"), "content"); + + const result1 = await tool.hashAsync(tmpDir); + const result2 = await tool.hashAsync(tmpDir); + expect(result1).toEqual(result2); + }); + + it("excludes specified folders and files", async () => { + writeFileSync(join(tmpDir, "source.ts"), "code"); + mkdirSync(join(tmpDir, "dist"), { recursive: true }); + writeFileSync(join(tmpDir, "dist", "out.js"), "compiled"); + writeFileSync(join(tmpDir, "tsconfig.build.tsbuildinfo"), "info"); + + const result1 = await tool.hashAsync(tmpDir, { + excludeFolders: ["dist"], + excludeFiles: ["tsconfig.build.tsbuildinfo"] + }); + + writeFileSync(join(tmpDir, "dist", "out.js"), "recompiled"); + writeFileSync(join(tmpDir, "tsconfig.build.tsbuildinfo"), "new-info"); + + const result2 = await tool.hashAsync(tmpDir, { + excludeFolders: ["dist"], + excludeFiles: ["tsconfig.build.tsbuildinfo"] + }); + + expect(result1).toEqual(result2); + }); + + it("produces the same result as the sync method", async () => { + writeFileSync(join(tmpDir, "a.txt"), "alpha"); + mkdirSync(join(tmpDir, "sub"), { recursive: true }); + writeFileSync(join(tmpDir, "sub", "b.txt"), "beta"); + + const syncResult = tool.hash(tmpDir); + const asyncResult = await tool.hashAsync(tmpDir); + expect(asyncResult).toEqual(syncResult); + }); + + it("returns a hash for an empty folder", async () => { + const result = await tool.hashAsync(tmpDir); + expect(result).toEqual({ hash: expect.stringMatching(/^[a-f0-9]{64}$/) }); + }); + }); +}); + +describe("createHashFolderTool", () => { + let tmpDir: string; + + beforeEach(() => { + tmpDir = join(tmpdir(), `wby-hash-factory-test-${Date.now()}`); + mkdirSync(tmpDir, { recursive: true }); + }); + + afterEach(() => { + rmSync(tmpDir, { recursive: true, force: true }); + }); + + it("creates a working tool (sync)", () => { + const tool = createHashFolderTool(); + writeFileSync(join(tmpDir, "file.txt"), "content"); + const result = tool.hash(tmpDir); + expect(result).toEqual({ hash: expect.stringMatching(/^[a-f0-9]{64}$/) }); + }); + + it("creates a working tool (async)", async () => { + const tool = createHashFolderTool(); + writeFileSync(join(tmpDir, "file.txt"), "content"); + const result = await tool.hashAsync(tmpDir); + expect(result).toEqual({ hash: expect.stringMatching(/^[a-f0-9]{64}$/) }); + }); +}); + +describe("hashFolder (sync standalone)", () => { + let tmpDir: string; + + beforeEach(() => { + tmpDir = join(tmpdir(), `wby-hash-standalone-test-${Date.now()}`); + mkdirSync(tmpDir, { recursive: true }); + }); + + afterEach(() => { + rmSync(tmpDir, { recursive: true, force: true }); + }); + + it("returns a result object", () => { + writeFileSync(join(tmpDir, "file.txt"), "content"); + const result = hashFolder(tmpDir); + expect(result).toEqual({ hash: expect.stringMatching(/^[a-f0-9]{64}$/) }); + }); + + it("supports exclude options", () => { + writeFileSync(join(tmpDir, "source.ts"), "code"); + mkdirSync(join(tmpDir, "dist"), { recursive: true }); + writeFileSync(join(tmpDir, "dist", "out.js"), "compiled"); + + const result1 = hashFolder(tmpDir, { excludeFolders: ["dist"] }); + + writeFileSync(join(tmpDir, "dist", "out.js"), "recompiled"); + const result2 = hashFolder(tmpDir, { excludeFolders: ["dist"] }); + + expect(result1).toEqual(result2); + }); + + it("produces the same result as the DI tool", () => { + writeFileSync(join(tmpDir, "file.txt"), "content"); + + const tool = createHashFolderTool(); + const diResult = tool.hash(tmpDir); + const standaloneResult = hashFolder(tmpDir); + + expect(standaloneResult).toEqual(diResult); + }); +}); + +describe("hashFolderAsync (async standalone)", () => { + let tmpDir: string; + + beforeEach(() => { + tmpDir = join(tmpdir(), `wby-hash-async-standalone-test-${Date.now()}`); + mkdirSync(tmpDir, { recursive: true }); + }); + + afterEach(() => { + rmSync(tmpDir, { recursive: true, force: true }); + }); + + it("returns a result object", async () => { + writeFileSync(join(tmpDir, "file.txt"), "content"); + const result = await hashFolderAsync(tmpDir); + expect(result).toEqual({ hash: expect.stringMatching(/^[a-f0-9]{64}$/) }); + }); + + it("supports exclude options", async () => { + writeFileSync(join(tmpDir, "source.ts"), "code"); + mkdirSync(join(tmpDir, "dist"), { recursive: true }); + writeFileSync(join(tmpDir, "dist", "out.js"), "compiled"); + + const result1 = await hashFolderAsync(tmpDir, { excludeFolders: ["dist"] }); + + writeFileSync(join(tmpDir, "dist", "out.js"), "recompiled"); + const result2 = await hashFolderAsync(tmpDir, { excludeFolders: ["dist"] }); + + expect(result1).toEqual(result2); + }); + + it("produces the same result as sync standalone", async () => { + writeFileSync(join(tmpDir, "file.txt"), "content"); + mkdirSync(join(tmpDir, "sub"), { recursive: true }); + writeFileSync(join(tmpDir, "sub", "nested.txt"), "nested"); + + const syncResult = hashFolder(tmpDir); + const asyncResult = await hashFolderAsync(tmpDir); + + expect(asyncResult).toEqual(syncResult); + }); +}); diff --git a/package.json b/package.json index 82b7999..9dc71a6 100644 --- a/package.json +++ b/package.json @@ -35,13 +35,13 @@ "devDependencies": { "@changesets/cli": "^2.31.0", "@types/node": ">=24", - "@typescript/native-preview": "^7.0.0-dev.20260519.1", - "@vitest/coverage-v8": "^4.1.6", + "@typescript/native-preview": "^7.0.0-dev.20260522.1", + "@vitest/coverage-v8": "^4.1.7", "adio": "^3.0.0", "happy-dom": "^20.9.0", "oxfmt": "^0.51.0", "oxlint": "^1.66.0", - "vitest": "^4.1.6" + "vitest": "^4.1.7" }, "scripts": { "clean": "rm -rf dist", diff --git a/src/node/features/HashFolderTool/HashFolderTool.ts b/src/node/features/HashFolderTool/HashFolderTool.ts new file mode 100644 index 0000000..72f560b --- /dev/null +++ b/src/node/features/HashFolderTool/HashFolderTool.ts @@ -0,0 +1,155 @@ +import { createHash } from "node:crypto"; +import { readdirSync, readFileSync } from "node:fs"; +import { readdir, readFile } from "node:fs/promises"; +import { join, relative } from "node:path"; +import { + HashFolderTool as HashFolderToolAbstraction, + type HashFolderOptions, + type HashFolderResult +} from "./abstractions/HashFolderTool.js"; + +interface FileEntry { + relativePath: string; + fileHash: string; +} + +function combineEntries(entries: FileEntry[]): string { + entries.sort((a, b) => a.relativePath.localeCompare(b.relativePath)); + const combined = createHash("sha256"); + for (const entry of entries) { + combined.update(entry.relativePath); + combined.update(entry.fileHash); + } + return combined.digest("hex"); +} + +function collectFilesSync( + rootPath: string, + currentPath: string, + excludeFolders: Set, + excludeFiles: Set +): FileEntry[] { + const entries: FileEntry[] = []; + const dirEntries = readdirSync(currentPath, { withFileTypes: true }); + + for (const dirEntry of dirEntries) { + if (dirEntry.isDirectory()) { + if (excludeFolders.has(dirEntry.name)) { + continue; + } + const subEntries = collectFilesSync( + rootPath, + join(currentPath, dirEntry.name), + excludeFolders, + excludeFiles + ); + entries.push(...subEntries); + } else if (dirEntry.isFile()) { + if (excludeFiles.has(dirEntry.name)) { + continue; + } + const filePath = join(currentPath, dirEntry.name); + const content = readFileSync(filePath); + const fileHash = createHash("sha256").update(content).digest("hex"); + entries.push({ relativePath: relative(rootPath, filePath), fileHash }); + } + } + + return entries; +} + +async function collectFilesAsync( + rootPath: string, + currentPath: string, + excludeFolders: Set, + excludeFiles: Set +): Promise { + const dirEntries = await readdir(currentPath, { withFileTypes: true }); + + const tasks: Promise[] = []; + const fileEntries: Promise[] = []; + + for (const dirEntry of dirEntries) { + if (dirEntry.isDirectory()) { + if (excludeFolders.has(dirEntry.name)) { + continue; + } + tasks.push( + collectFilesAsync( + rootPath, + join(currentPath, dirEntry.name), + excludeFolders, + excludeFiles + ) + ); + } else if (dirEntry.isFile()) { + if (excludeFiles.has(dirEntry.name)) { + continue; + } + const filePath = join(currentPath, dirEntry.name); + fileEntries.push( + readFile(filePath).then(content => ({ + relativePath: relative(rootPath, filePath), + fileHash: createHash("sha256").update(content).digest("hex") + })) + ); + } + } + + const [subResults, localFiles] = await Promise.all([ + Promise.all(tasks), + Promise.all(fileEntries) + ]); + + return subResults.flat().concat(localFiles); +} + +class HashFolderToolImpl implements HashFolderToolAbstraction.Interface { + public hash(folderPath: string, options?: HashFolderOptions): HashFolderResult { + const excludeFolders = new Set(options?.excludeFolders ?? []); + const excludeFiles = new Set(options?.excludeFiles ?? []); + const entries = collectFilesSync(folderPath, folderPath, excludeFolders, excludeFiles); + return { hash: combineEntries(entries) }; + } + + public async hashAsync( + folderPath: string, + options?: HashFolderOptions + ): Promise { + const excludeFolders = new Set(options?.excludeFolders ?? []); + const excludeFiles = new Set(options?.excludeFiles ?? []); + const entries = await collectFilesAsync( + folderPath, + folderPath, + excludeFolders, + excludeFiles + ); + return { hash: combineEntries(entries) }; + } +} + +export const HashFolderTool = HashFolderToolAbstraction.createImplementation({ + implementation: HashFolderToolImpl, + dependencies: [] +}); + +export function createHashFolderTool(): HashFolderToolAbstraction.Interface { + return new HashFolderToolImpl(); +} + +/** + * Standalone sync — computes a SHA-256 hash of a folder's contents. + */ +export function hashFolder(folderPath: string, options?: HashFolderOptions): HashFolderResult { + return new HashFolderToolImpl().hash(folderPath, options); +} + +/** + * Standalone async — reads files and subdirectories in parallel. + */ +export async function hashFolderAsync( + folderPath: string, + options?: HashFolderOptions +): Promise { + return new HashFolderToolImpl().hashAsync(folderPath, options); +} diff --git a/src/node/features/HashFolderTool/README.md b/src/node/features/HashFolderTool/README.md new file mode 100644 index 0000000..1cf891c --- /dev/null +++ b/src/node/features/HashFolderTool/README.md @@ -0,0 +1,83 @@ +# HashFolderTool + +Computes a deterministic SHA-256 hash of a folder's contents. Walks the directory tree recursively, hashes each file individually, sorts entries by relative path for deterministic ordering, then produces a single combined hex digest. Use it to detect whether a folder's contents have changed — for example, to skip redundant builds when source files haven't been modified. + +Two methods: `hash` (synchronous) for small-to-medium folders, and `hashAsync` (parallel I/O) for large directory trees where concurrent reads improve throughput. Both return a `HashFolderResult` object. + +## Interface + +```ts +interface IHashFolderTool { + /** Returns a result containing the hex-encoded SHA-256 hash (synchronous). */ + hash(folderPath: string, options?: HashFolderOptions): HashFolderResult; + /** Parallel variant — reads files and subdirectories concurrently. */ + hashAsync(folderPath: string, options?: HashFolderOptions): Promise; +} + +interface HashFolderResult { + /** Hex-encoded SHA-256 digest. */ + hash: string; +} + +interface HashFolderOptions { + /** Folder names to skip during traversal (e.g. "node_modules", "dist"). */ + excludeFolders?: string[]; + /** File names to skip (e.g. "tsconfig.build.tsbuildinfo"). */ + excludeFiles?: string[]; +} +``` + +## Usage + +### DI container wiring + +```ts +import { Container } from "@webiny/di"; +import { HashFolderTool, HashFolderToolFeature } from "@webiny/stdlib/node"; + +const container = new Container(); +HashFolderToolFeature.register(container); + +const tool = container.resolve(HashFolderTool); + +// Sync +const { hash } = tool.hash("./packages/my-package", { + excludeFolders: ["dist", "lib", "node_modules"], + excludeFiles: ["tsconfig.build.tsbuildinfo"] +}); + +// Async (parallel I/O) +const { hash } = await tool.hashAsync("./packages/my-package", { + excludeFolders: ["dist", "lib", "node_modules"], + excludeFiles: ["tsconfig.build.tsbuildinfo"] +}); +``` + +### Factory function + +```ts +import { createHashFolderTool } from "@webiny/stdlib/node"; + +const tool = createHashFolderTool(); +const { hash } = tool.hash("./packages/my-package", { + excludeFolders: ["dist", "node_modules"] +}); +``` + +### Standalone functions + +```ts +import { hashFolder, hashFolderAsync } from "@webiny/stdlib/node"; + +// Sync +const { hash } = hashFolder("./packages/my-package", { + excludeFolders: ["dist", "lib", "node_modules"], + excludeFiles: ["tsconfig.build.tsbuildinfo"] +}); + +// Async (parallel I/O) +const { hash } = await hashFolderAsync("./packages/my-package", { + excludeFolders: ["dist", "lib", "node_modules"], + excludeFiles: ["tsconfig.build.tsbuildinfo"] +}); +``` diff --git a/src/node/features/HashFolderTool/abstractions/HashFolderTool.ts b/src/node/features/HashFolderTool/abstractions/HashFolderTool.ts new file mode 100644 index 0000000..d6733c2 --- /dev/null +++ b/src/node/features/HashFolderTool/abstractions/HashFolderTool.ts @@ -0,0 +1,37 @@ +import { createAbstraction } from "~/common/index.js"; + +/** + * Options for filtering which folders and files are included in the hash. + */ +export interface HashFolderOptions { + /** Folder names to skip during traversal (e.g. "node_modules", "dist"). */ + excludeFolders?: string[]; + /** File names to skip (e.g. "tsconfig.build.tsbuildinfo"). */ + excludeFiles?: string[]; +} + +/** + * Result of hashing a folder's contents. + */ +export interface HashFolderResult { + /** Hex-encoded SHA-256 digest. */ + hash: string; +} + +/** + * Computes a deterministic SHA-256 hash of a folder's contents. + * Walks the directory recursively, hashes each file, sorts by relative path, + * then produces a single combined hash. + */ +export interface IHashFolderTool { + /** Returns a result containing the hex-encoded SHA-256 hash (synchronous). */ + hash(folderPath: string, options?: HashFolderOptions): HashFolderResult; + /** Parallel variant — reads files and subdirectories concurrently. */ + hashAsync(folderPath: string, options?: HashFolderOptions): Promise; +} + +export const HashFolderTool = createAbstraction("Node/HashFolderTool"); + +export namespace HashFolderTool { + export type Interface = IHashFolderTool; +} diff --git a/src/node/features/HashFolderTool/abstractions/index.ts b/src/node/features/HashFolderTool/abstractions/index.ts new file mode 100644 index 0000000..d0ab691 --- /dev/null +++ b/src/node/features/HashFolderTool/abstractions/index.ts @@ -0,0 +1 @@ +export { HashFolderTool, type HashFolderOptions, type HashFolderResult } from "./HashFolderTool.js"; diff --git a/src/node/features/HashFolderTool/feature.ts b/src/node/features/HashFolderTool/feature.ts new file mode 100644 index 0000000..9af4492 --- /dev/null +++ b/src/node/features/HashFolderTool/feature.ts @@ -0,0 +1,9 @@ +import { createFeature } from "~/common/index.js"; +import { HashFolderTool } from "./HashFolderTool.js"; + +export const HashFolderToolFeature = createFeature({ + name: "Node/HashFolderToolFeature", + register(container) { + container.register(HashFolderTool).inSingletonScope(); + } +}); diff --git a/src/node/features/HashFolderTool/index.ts b/src/node/features/HashFolderTool/index.ts new file mode 100644 index 0000000..c22b9b5 --- /dev/null +++ b/src/node/features/HashFolderTool/index.ts @@ -0,0 +1,7 @@ +export { + HashFolderTool, + type HashFolderOptions, + type HashFolderResult +} from "./abstractions/index.js"; +export { HashFolderToolFeature } from "./feature.js"; +export { createHashFolderTool, hashFolder, hashFolderAsync } from "./HashFolderTool.js"; diff --git a/src/node/index.ts b/src/node/index.ts index 50e8808..9ad3d6f 100644 --- a/src/node/index.ts +++ b/src/node/index.ts @@ -51,3 +51,12 @@ export { type CreatePackageJsonFileToolParams, PackageJsonFile } from "./features/PackageJsonFileTool/index.js"; +export { + HashFolderTool, + HashFolderToolFeature, + createHashFolderTool, + hashFolder, + hashFolderAsync, + type HashFolderOptions, + type HashFolderResult +} from "./features/HashFolderTool/index.js"; diff --git a/yarn.lock b/yarn.lock index 0b4a9df..7607385 100644 --- a/yarn.lock +++ b/yarn.lock @@ -522,10 +522,10 @@ __metadata: languageName: node linkType: hard -"@oxc-project/types@npm:=0.130.0": - version: 0.130.0 - resolution: "@oxc-project/types@npm:0.130.0" - checksum: 10c0/7ec8c03407b0bcb235b930c62859e6efcb3fe5cbaa5db98770d760df5c3e6b3e28a0ad22c2e35d1addede8065b40000c3822c5235dde2959af226639eb870000 +"@oxc-project/types@npm:=0.132.0": + version: 0.132.0 + resolution: "@oxc-project/types@npm:0.132.0" + checksum: 10c0/d0ca5e98be0b873d69e4f0f743eb35026833603dac11db9d55f2b5438251b381b886dc556fe3175a17b673f8e2073c49bde88d7e6e702aa09298c22b8b5504e1 languageName: node linkType: hard @@ -809,93 +809,93 @@ __metadata: languageName: node linkType: hard -"@rolldown/binding-android-arm64@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-android-arm64@npm:1.0.1" +"@rolldown/binding-android-arm64@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-android-arm64@npm:1.0.2" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-darwin-arm64@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-darwin-arm64@npm:1.0.1" +"@rolldown/binding-darwin-arm64@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-darwin-arm64@npm:1.0.2" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-darwin-x64@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-darwin-x64@npm:1.0.1" +"@rolldown/binding-darwin-x64@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-darwin-x64@npm:1.0.2" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rolldown/binding-freebsd-x64@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-freebsd-x64@npm:1.0.1" +"@rolldown/binding-freebsd-x64@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-freebsd-x64@npm:1.0.2" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rolldown/binding-linux-arm-gnueabihf@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.1" +"@rolldown/binding-linux-arm-gnueabihf@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.2" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@rolldown/binding-linux-arm64-gnu@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.1" +"@rolldown/binding-linux-arm64-gnu@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.2" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-arm64-musl@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.1" +"@rolldown/binding-linux-arm64-musl@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.2" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rolldown/binding-linux-ppc64-gnu@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.0.1" +"@rolldown/binding-linux-ppc64-gnu@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.0.2" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-s390x-gnu@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.0.1" +"@rolldown/binding-linux-s390x-gnu@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.0.2" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-x64-gnu@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.1" +"@rolldown/binding-linux-x64-gnu@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.2" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rolldown/binding-linux-x64-musl@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.1" +"@rolldown/binding-linux-x64-musl@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.2" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rolldown/binding-openharmony-arm64@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.1" +"@rolldown/binding-openharmony-arm64@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.2" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-wasm32-wasi@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.1" +"@rolldown/binding-wasm32-wasi@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.2" dependencies: "@emnapi/core": "npm:1.10.0" "@emnapi/runtime": "npm:1.10.0" @@ -904,16 +904,16 @@ __metadata: languageName: node linkType: hard -"@rolldown/binding-win32-arm64-msvc@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.1" +"@rolldown/binding-win32-arm64-msvc@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.2" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rolldown/binding-win32-x64-msvc@npm:1.0.1": - version: 1.0.1 - resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.1" +"@rolldown/binding-win32-x64-msvc@npm:1.0.2": + version: 1.0.2 + resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.2" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -966,11 +966,11 @@ __metadata: linkType: hard "@types/node@npm:*, @types/node@npm:>=20.0.0, @types/node@npm:>=24": - version: 25.9.0 - resolution: "@types/node@npm:25.9.0" + version: 25.9.1 + resolution: "@types/node@npm:25.9.1" dependencies: undici-types: "npm:>=7.24.0 <7.24.7" - checksum: 10c0/1845f0ce5471213a4f0c887845c50993968ea863c03bb355282b59bdcc877d009a2785f0f506cfc40b8ce7548a21e33ac826e998be62d42b000bfd9ccdc6c910 + checksum: 10c0/9a04682842bebbcf21a1779dfeab9aa733d7bd7bbc0a0edb641ab3a9a3d43eac543225acf669c334f458f1956443ebc072bc3c72840c543b8b356cab5c82d456 languageName: node linkType: hard @@ -997,66 +997,66 @@ __metadata: languageName: node linkType: hard -"@typescript/native-preview-darwin-arm64@npm:7.0.0-dev.20260519.1": - version: 7.0.0-dev.20260519.1 - resolution: "@typescript/native-preview-darwin-arm64@npm:7.0.0-dev.20260519.1" +"@typescript/native-preview-darwin-arm64@npm:7.0.0-dev.20260522.1": + version: 7.0.0-dev.20260522.1 + resolution: "@typescript/native-preview-darwin-arm64@npm:7.0.0-dev.20260522.1" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@typescript/native-preview-darwin-x64@npm:7.0.0-dev.20260519.1": - version: 7.0.0-dev.20260519.1 - resolution: "@typescript/native-preview-darwin-x64@npm:7.0.0-dev.20260519.1" +"@typescript/native-preview-darwin-x64@npm:7.0.0-dev.20260522.1": + version: 7.0.0-dev.20260522.1 + resolution: "@typescript/native-preview-darwin-x64@npm:7.0.0-dev.20260522.1" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@typescript/native-preview-linux-arm64@npm:7.0.0-dev.20260519.1": - version: 7.0.0-dev.20260519.1 - resolution: "@typescript/native-preview-linux-arm64@npm:7.0.0-dev.20260519.1" +"@typescript/native-preview-linux-arm64@npm:7.0.0-dev.20260522.1": + version: 7.0.0-dev.20260522.1 + resolution: "@typescript/native-preview-linux-arm64@npm:7.0.0-dev.20260522.1" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@typescript/native-preview-linux-arm@npm:7.0.0-dev.20260519.1": - version: 7.0.0-dev.20260519.1 - resolution: "@typescript/native-preview-linux-arm@npm:7.0.0-dev.20260519.1" +"@typescript/native-preview-linux-arm@npm:7.0.0-dev.20260522.1": + version: 7.0.0-dev.20260522.1 + resolution: "@typescript/native-preview-linux-arm@npm:7.0.0-dev.20260522.1" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@typescript/native-preview-linux-x64@npm:7.0.0-dev.20260519.1": - version: 7.0.0-dev.20260519.1 - resolution: "@typescript/native-preview-linux-x64@npm:7.0.0-dev.20260519.1" +"@typescript/native-preview-linux-x64@npm:7.0.0-dev.20260522.1": + version: 7.0.0-dev.20260522.1 + resolution: "@typescript/native-preview-linux-x64@npm:7.0.0-dev.20260522.1" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@typescript/native-preview-win32-arm64@npm:7.0.0-dev.20260519.1": - version: 7.0.0-dev.20260519.1 - resolution: "@typescript/native-preview-win32-arm64@npm:7.0.0-dev.20260519.1" +"@typescript/native-preview-win32-arm64@npm:7.0.0-dev.20260522.1": + version: 7.0.0-dev.20260522.1 + resolution: "@typescript/native-preview-win32-arm64@npm:7.0.0-dev.20260522.1" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@typescript/native-preview-win32-x64@npm:7.0.0-dev.20260519.1": - version: 7.0.0-dev.20260519.1 - resolution: "@typescript/native-preview-win32-x64@npm:7.0.0-dev.20260519.1" +"@typescript/native-preview-win32-x64@npm:7.0.0-dev.20260522.1": + version: 7.0.0-dev.20260522.1 + resolution: "@typescript/native-preview-win32-x64@npm:7.0.0-dev.20260522.1" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@typescript/native-preview@npm:^7.0.0-dev.20260519.1": - version: 7.0.0-dev.20260519.1 - resolution: "@typescript/native-preview@npm:7.0.0-dev.20260519.1" +"@typescript/native-preview@npm:^7.0.0-dev.20260522.1": + version: 7.0.0-dev.20260522.1 + resolution: "@typescript/native-preview@npm:7.0.0-dev.20260522.1" dependencies: - "@typescript/native-preview-darwin-arm64": "npm:7.0.0-dev.20260519.1" - "@typescript/native-preview-darwin-x64": "npm:7.0.0-dev.20260519.1" - "@typescript/native-preview-linux-arm": "npm:7.0.0-dev.20260519.1" - "@typescript/native-preview-linux-arm64": "npm:7.0.0-dev.20260519.1" - "@typescript/native-preview-linux-x64": "npm:7.0.0-dev.20260519.1" - "@typescript/native-preview-win32-arm64": "npm:7.0.0-dev.20260519.1" - "@typescript/native-preview-win32-x64": "npm:7.0.0-dev.20260519.1" + "@typescript/native-preview-darwin-arm64": "npm:7.0.0-dev.20260522.1" + "@typescript/native-preview-darwin-x64": "npm:7.0.0-dev.20260522.1" + "@typescript/native-preview-linux-arm": "npm:7.0.0-dev.20260522.1" + "@typescript/native-preview-linux-arm64": "npm:7.0.0-dev.20260522.1" + "@typescript/native-preview-linux-x64": "npm:7.0.0-dev.20260522.1" + "@typescript/native-preview-win32-arm64": "npm:7.0.0-dev.20260522.1" + "@typescript/native-preview-win32-x64": "npm:7.0.0-dev.20260522.1" dependenciesMeta: "@typescript/native-preview-darwin-arm64": optional: true @@ -1074,16 +1074,16 @@ __metadata: optional: true bin: tsgo: bin/tsgo.js - checksum: 10c0/f1f220a404a00c68f1cfa97c6aa18a73ed241547125ad6f4b916107dbbfd3b524f564eafabc988b571ee0297278f5bfc4ab15bf5abe0051073c76a1a335a91c9 + checksum: 10c0/b4eaa6bce32ca1e77cc5ef467d4ce65589b076775e8444a4f358f89b6609eabd637369601027c2b5c3914b7b920b533cb88e4febfd6ca34d8dab4aceee8ab86d languageName: node linkType: hard -"@vitest/coverage-v8@npm:^4.1.6": - version: 4.1.6 - resolution: "@vitest/coverage-v8@npm:4.1.6" +"@vitest/coverage-v8@npm:^4.1.7": + version: 4.1.7 + resolution: "@vitest/coverage-v8@npm:4.1.7" dependencies: "@bcoe/v8-coverage": "npm:^1.0.2" - "@vitest/utils": "npm:4.1.6" + "@vitest/utils": "npm:4.1.7" ast-v8-to-istanbul: "npm:^1.0.0" istanbul-lib-coverage: "npm:^3.2.2" istanbul-lib-report: "npm:^3.0.1" @@ -1093,34 +1093,34 @@ __metadata: std-env: "npm:^4.0.0-rc.1" tinyrainbow: "npm:^3.1.0" peerDependencies: - "@vitest/browser": 4.1.6 - vitest: 4.1.6 + "@vitest/browser": 4.1.7 + vitest: 4.1.7 peerDependenciesMeta: "@vitest/browser": optional: true - checksum: 10c0/5cc45784200a13ccab166c5d2ed0a4026ab0e28c395a654f046d91ff344a02d38db77b1022d7aa6d07973966c64844a6b62756c88c33609529535c12cc8b1af4 + checksum: 10c0/288fa77cfec00d84528154be90727ee0a868b91a32847b57e078fa4f3061711a53036a68d78bb4ea15e5c65b4644af6d2b7ad28b68b9301e9145426cdc27c0cd languageName: node linkType: hard -"@vitest/expect@npm:4.1.6": - version: 4.1.6 - resolution: "@vitest/expect@npm:4.1.6" +"@vitest/expect@npm:4.1.7": + version: 4.1.7 + resolution: "@vitest/expect@npm:4.1.7" dependencies: "@standard-schema/spec": "npm:^1.1.0" "@types/chai": "npm:^5.2.2" - "@vitest/spy": "npm:4.1.6" - "@vitest/utils": "npm:4.1.6" + "@vitest/spy": "npm:4.1.7" + "@vitest/utils": "npm:4.1.7" chai: "npm:^6.2.2" tinyrainbow: "npm:^3.1.0" - checksum: 10c0/a6767bdf586c82f64674998bf74987e99aa106ac5d0b5c4c2c1d3924e145b34fd80e138c65568a8fc2544aa71c85b1272f9607fe5ef6a7060ece1c232db46655 + checksum: 10c0/1a72387c6d3cac1e12cd4df382e666d96560b38001ea0133f1e0a22825f71ccf1640ccce13244296b0054c15cf04442f3adbd67dfc57fe542bd35a46cd805487 languageName: node linkType: hard -"@vitest/mocker@npm:4.1.6": - version: 4.1.6 - resolution: "@vitest/mocker@npm:4.1.6" +"@vitest/mocker@npm:4.1.7": + version: 4.1.7 + resolution: "@vitest/mocker@npm:4.1.7" dependencies: - "@vitest/spy": "npm:4.1.6" + "@vitest/spy": "npm:4.1.7" estree-walker: "npm:^3.0.3" magic-string: "npm:^0.30.21" peerDependencies: @@ -1131,56 +1131,56 @@ __metadata: optional: true vite: optional: true - checksum: 10c0/d9f3236940e160467edb7a2552fa014451347c4f08c13d26220fcfe7e12b385fd4975c6a81a6b174117650772cf3c45195b3a1838f8ee28fc8e6c37e07b99b2d + checksum: 10c0/e03dbbba435543e3cfa5e034ba8ade371de5e398255f75366ebc370ff8dd78d45f7d7cc9daa76eb1d399b31e659e47d3cbb710566e64ceeeba3f99b418e4b955 languageName: node linkType: hard -"@vitest/pretty-format@npm:4.1.6": - version: 4.1.6 - resolution: "@vitest/pretty-format@npm:4.1.6" +"@vitest/pretty-format@npm:4.1.7": + version: 4.1.7 + resolution: "@vitest/pretty-format@npm:4.1.7" dependencies: tinyrainbow: "npm:^3.1.0" - checksum: 10c0/f818a6abff9b7cf642edc2d0fe84d4f124911696bc7591f2af9ab6d88685b72133a1e9f87499e9b4dc2314dff85403ea66c64f7b408b2eb39f9880c6d3517ca0 + checksum: 10c0/49ef801171708e3a92214e8720efbedbd6e0e6baf17971aaf4feb7422e5c9eba82262c24a9e6dd4d41a31fae77bd31d5b37cf140d13e0ac4ce29a7457bdc692f languageName: node linkType: hard -"@vitest/runner@npm:4.1.6": - version: 4.1.6 - resolution: "@vitest/runner@npm:4.1.6" +"@vitest/runner@npm:4.1.7": + version: 4.1.7 + resolution: "@vitest/runner@npm:4.1.7" dependencies: - "@vitest/utils": "npm:4.1.6" + "@vitest/utils": "npm:4.1.7" pathe: "npm:^2.0.3" - checksum: 10c0/8047051d730de66b7cde8e6803ea718eaa8342ffbe55ff3d787fe7085a2b824a979689782d5303e464411fe67b556384b0c5af337e3e335cf140bf7adf5f6aa0 + checksum: 10c0/63474c6fc088d75b5d7fe735195504f923c694b83a22eb9caa53d6486c923974304c2e3ef4d5bcd808d88082174f38434be320fc4fe649a8cf33f0459a0576e3 languageName: node linkType: hard -"@vitest/snapshot@npm:4.1.6": - version: 4.1.6 - resolution: "@vitest/snapshot@npm:4.1.6" +"@vitest/snapshot@npm:4.1.7": + version: 4.1.7 + resolution: "@vitest/snapshot@npm:4.1.7" dependencies: - "@vitest/pretty-format": "npm:4.1.6" - "@vitest/utils": "npm:4.1.6" + "@vitest/pretty-format": "npm:4.1.7" + "@vitest/utils": "npm:4.1.7" magic-string: "npm:^0.30.21" pathe: "npm:^2.0.3" - checksum: 10c0/596d7cd2fe12b57516e983e550d238c324a3cefaac826e557b0903cfbb11f6ff79582bf2df6dc3163cf604c305ffe3840e47f03a95b8fb8d7bf6200462e8cfea + checksum: 10c0/6fa49c4242a4acc0557ee6a20552db41f4f4c9d2d4c05993181c3f5f19e66579e08f63d34f792b79400547ab791ef500a9955b77390c381e45c3bb8e33717793 languageName: node linkType: hard -"@vitest/spy@npm:4.1.6": - version: 4.1.6 - resolution: "@vitest/spy@npm:4.1.6" - checksum: 10c0/908034532fb10888f759603194b11058bdabdf9bb86ef7839feec98f809e4802cf8d74c279c521ef2df12fa9ab97d0aec7c886e1e6910c5c9dfb10ba00913d91 +"@vitest/spy@npm:4.1.7": + version: 4.1.7 + resolution: "@vitest/spy@npm:4.1.7" + checksum: 10c0/be2a95d5c5c438b57c9b33cef1289fb02659214754b5e946cb4b8183e2b5089e49e3fda6ca05981f3ea9872b207595db109e25072668c0a671203f69fddbbe99 languageName: node linkType: hard -"@vitest/utils@npm:4.1.6": - version: 4.1.6 - resolution: "@vitest/utils@npm:4.1.6" +"@vitest/utils@npm:4.1.7": + version: 4.1.7 + resolution: "@vitest/utils@npm:4.1.7" dependencies: - "@vitest/pretty-format": "npm:4.1.6" + "@vitest/pretty-format": "npm:4.1.7" convert-source-map: "npm:^2.0.0" tinyrainbow: "npm:^3.1.0" - checksum: 10c0/36437888088a1aae8565e62b9f145de9fb1599725574924477c655c7617ad677b575ac0eb3f2b3288854ed1aafff914a0417dffbb7f5244c821f157119701227 + checksum: 10c0/aa0079d8923506300527dc23ff68cf090ffcb2c6a9549e598ae22ba0eb8a6bb4448b10724b38bc6b077f9957333302a857d791ad2f7abd807bb6263c9a218833 languageName: node linkType: hard @@ -1199,8 +1199,8 @@ __metadata: dependencies: "@changesets/cli": "npm:^2.31.0" "@types/node": "npm:>=24" - "@typescript/native-preview": "npm:^7.0.0-dev.20260519.1" - "@vitest/coverage-v8": "npm:^4.1.6" + "@typescript/native-preview": "npm:^7.0.0-dev.20260522.1" + "@vitest/coverage-v8": "npm:^4.1.7" "@webiny/di": "npm:^1.0.1" adio: "npm:^3.0.0" dot-prop: "npm:^10.1.0" @@ -1211,7 +1211,7 @@ __metadata: pino: "npm:^10.3.1" pino-pretty: "npm:^13.1.3" type-fest: "npm:^5.6.0" - vitest: "npm:^4.1.6" + vitest: "npm:^4.1.7" zod: "npm:^4.4.3" languageName: unknown linkType: soft @@ -2052,9 +2052,9 @@ __metadata: linkType: hard "lru-cache@npm:^11.0.0": - version: 11.4.0 - resolution: "lru-cache@npm:11.4.0" - checksum: 10c0/ac59697b1bcc19494b4a12af5e2320bb6c353473654d73e6c84033deb22faf220c861b1e0bc1ac9f65a394d46653870e982598a046c5976f44c4b1deb5ad8197 + version: 11.5.0 + resolution: "lru-cache@npm:11.5.0" + checksum: 10c0/b92c2a7518128dec6b244bf3eb9fd79964d316cdeb12865ebfc2cebb4dfe9b24e3767a3923d71e6eb735f56b557fc55f08f150a53097d7805afb628c90158df4 languageName: node linkType: hard @@ -2597,7 +2597,7 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8.5.14": +"postcss@npm:^8.5.15": version: 8.5.15 resolution: "postcss@npm:8.5.15" dependencies: @@ -2716,26 +2716,26 @@ __metadata: languageName: node linkType: hard -"rolldown@npm:1.0.1": - version: 1.0.1 - resolution: "rolldown@npm:1.0.1" - dependencies: - "@oxc-project/types": "npm:=0.130.0" - "@rolldown/binding-android-arm64": "npm:1.0.1" - "@rolldown/binding-darwin-arm64": "npm:1.0.1" - "@rolldown/binding-darwin-x64": "npm:1.0.1" - "@rolldown/binding-freebsd-x64": "npm:1.0.1" - "@rolldown/binding-linux-arm-gnueabihf": "npm:1.0.1" - "@rolldown/binding-linux-arm64-gnu": "npm:1.0.1" - "@rolldown/binding-linux-arm64-musl": "npm:1.0.1" - "@rolldown/binding-linux-ppc64-gnu": "npm:1.0.1" - "@rolldown/binding-linux-s390x-gnu": "npm:1.0.1" - "@rolldown/binding-linux-x64-gnu": "npm:1.0.1" - "@rolldown/binding-linux-x64-musl": "npm:1.0.1" - "@rolldown/binding-openharmony-arm64": "npm:1.0.1" - "@rolldown/binding-wasm32-wasi": "npm:1.0.1" - "@rolldown/binding-win32-arm64-msvc": "npm:1.0.1" - "@rolldown/binding-win32-x64-msvc": "npm:1.0.1" +"rolldown@npm:1.0.2": + version: 1.0.2 + resolution: "rolldown@npm:1.0.2" + dependencies: + "@oxc-project/types": "npm:=0.132.0" + "@rolldown/binding-android-arm64": "npm:1.0.2" + "@rolldown/binding-darwin-arm64": "npm:1.0.2" + "@rolldown/binding-darwin-x64": "npm:1.0.2" + "@rolldown/binding-freebsd-x64": "npm:1.0.2" + "@rolldown/binding-linux-arm-gnueabihf": "npm:1.0.2" + "@rolldown/binding-linux-arm64-gnu": "npm:1.0.2" + "@rolldown/binding-linux-arm64-musl": "npm:1.0.2" + "@rolldown/binding-linux-ppc64-gnu": "npm:1.0.2" + "@rolldown/binding-linux-s390x-gnu": "npm:1.0.2" + "@rolldown/binding-linux-x64-gnu": "npm:1.0.2" + "@rolldown/binding-linux-x64-musl": "npm:1.0.2" + "@rolldown/binding-openharmony-arm64": "npm:1.0.2" + "@rolldown/binding-wasm32-wasi": "npm:1.0.2" + "@rolldown/binding-win32-arm64-msvc": "npm:1.0.2" + "@rolldown/binding-win32-x64-msvc": "npm:1.0.2" "@rolldown/pluginutils": "npm:^1.0.0" dependenciesMeta: "@rolldown/binding-android-arm64": @@ -2769,8 +2769,8 @@ __metadata: "@rolldown/binding-win32-x64-msvc": optional: true bin: - rolldown: bin/cli.mjs - checksum: 10c0/0631c071874e1471c33923905061fa514fce2bd43c2e741adcddcaa4d9beaa2ba7a5d14af130d53753d838823e15b59f5acef7d24fb83ffb7aef15933b78e7d3 + rolldown: ./bin/cli.mjs + checksum: 10c0/628327a6e3122c0b62880f1c87d54095394e5138a6af2e6e7b2f67ef4c4b11f1421db68c9a5bb4e1be161465a863ab4f68f15076ce895cd4bb3d0ba18a3b20b1 languageName: node linkType: hard @@ -2805,11 +2805,11 @@ __metadata: linkType: hard "semver@npm:^7.3.5, semver@npm:^7.5.3": - version: 7.8.0 - resolution: "semver@npm:7.8.0" + version: 7.8.1 + resolution: "semver@npm:7.8.1" bin: semver: bin/semver.js - checksum: 10c0/8f096ca9b80ffd47b308d03f9ce8c873e27e2983f36023c559cdc92c51e8433fc23ebbfe57ec9623fc155636a6961ee989501099841ae4bb1babc8d2b3f048cd + checksum: 10c0/92d6871d6347e1f99d0ba396a70f2545ccf2a032cda3d378fa0699edf7506b5c6d266aed55c8b88e72bd91a30d2351e4f39db479375374430fcdc4b58f4e3c1a languageName: node linkType: hard @@ -3057,14 +3057,14 @@ __metadata: linkType: hard "vite@npm:^6.0.0 || ^7.0.0 || ^8.0.0": - version: 8.0.13 - resolution: "vite@npm:8.0.13" + version: 8.0.14 + resolution: "vite@npm:8.0.14" dependencies: fsevents: "npm:~2.3.3" lightningcss: "npm:^1.32.0" picomatch: "npm:^4.0.4" - postcss: "npm:^8.5.14" - rolldown: "npm:1.0.1" + postcss: "npm:^8.5.15" + rolldown: "npm:1.0.2" tinyglobby: "npm:^0.2.16" peerDependencies: "@types/node": ^20.19.0 || >=22.12.0 @@ -3109,21 +3109,21 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10c0/8f4d6fd30c3be710f76dba8ee7cd156902200e649884911cfa8e6e5f7ad4dd5b6933bdd4f0c46c0169c49ddce9ce1bfab6d395df9d176c0d959e3ba0e5ee54e4 + checksum: 10c0/1ff99b4daadc64aed5f9e40387ecf39fd3bca45c1a5c4fa4aa82197de901930f0507af8d75c54715e2744c99575913947efb625653a78ef6df3997c5613970bd languageName: node linkType: hard -"vitest@npm:^4.1.6": - version: 4.1.6 - resolution: "vitest@npm:4.1.6" +"vitest@npm:^4.1.7": + version: 4.1.7 + resolution: "vitest@npm:4.1.7" dependencies: - "@vitest/expect": "npm:4.1.6" - "@vitest/mocker": "npm:4.1.6" - "@vitest/pretty-format": "npm:4.1.6" - "@vitest/runner": "npm:4.1.6" - "@vitest/snapshot": "npm:4.1.6" - "@vitest/spy": "npm:4.1.6" - "@vitest/utils": "npm:4.1.6" + "@vitest/expect": "npm:4.1.7" + "@vitest/mocker": "npm:4.1.7" + "@vitest/pretty-format": "npm:4.1.7" + "@vitest/runner": "npm:4.1.7" + "@vitest/snapshot": "npm:4.1.7" + "@vitest/spy": "npm:4.1.7" + "@vitest/utils": "npm:4.1.7" es-module-lexer: "npm:^2.0.0" expect-type: "npm:^1.3.0" magic-string: "npm:^0.30.21" @@ -3141,12 +3141,12 @@ __metadata: "@edge-runtime/vm": "*" "@opentelemetry/api": ^1.9.0 "@types/node": ^20.0.0 || ^22.0.0 || >=24.0.0 - "@vitest/browser-playwright": 4.1.6 - "@vitest/browser-preview": 4.1.6 - "@vitest/browser-webdriverio": 4.1.6 - "@vitest/coverage-istanbul": 4.1.6 - "@vitest/coverage-v8": 4.1.6 - "@vitest/ui": 4.1.6 + "@vitest/browser-playwright": 4.1.7 + "@vitest/browser-preview": 4.1.7 + "@vitest/browser-webdriverio": 4.1.7 + "@vitest/coverage-istanbul": 4.1.7 + "@vitest/coverage-v8": 4.1.7 + "@vitest/ui": 4.1.7 happy-dom: "*" jsdom: "*" vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -3177,7 +3177,7 @@ __metadata: optional: false bin: vitest: vitest.mjs - checksum: 10c0/1da4c23f02cd39cb20a857d48462d1d6100eeb4644fc0defc7c6eef9d481f85d2598b72d39eb4a8d271fafa8328ac3ffcca11b27865385e88d9d65c8b29b8091 + checksum: 10c0/5328eab211161bdb854159154b02d7b2beab0cf1e26a1c13f6a64b0f1402029d41f19987cf60684051c09a6925030285195ecbe57271c2033e1d4f7a666590d0 languageName: node linkType: hard @@ -3230,8 +3230,8 @@ __metadata: linkType: hard "ws@npm:^8.18.3": - version: 8.20.1 - resolution: "ws@npm:8.20.1" + version: 8.21.0 + resolution: "ws@npm:8.21.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -3240,7 +3240,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 10c0/ce162433218399cdedeb76fd33363d4d86a7d910058d4e3c679dce08cea65d6da6b39f11baa4d7808d024cf46ed88f6a05c17611621aaad8fc5e62edacc30c5d + checksum: 10c0/ef4a243476283fc49bc7550966c4af4aa0eef56273837211e700de3b664e08604a760cdddcb5ba43c049140e74ccfec5b0ee0bb439e08c2adf9138902fdde5f9 languageName: node linkType: hard