From 1bdb6f0fd089242e061e54c696858075442dca02 Mon Sep 17 00:00:00 2001 From: magnus Date: Mon, 31 Mar 2025 12:44:44 +0200 Subject: [PATCH 1/3] add copyFiles --- .../open-next/src/build/createServerBundle.ts | 4 +++ .../src/build/edge/createEdgeBundle.ts | 10 ++++++- packages/open-next/src/build/helper.ts | 28 +++++++++++++++++++ packages/open-next/src/types/open-next.ts | 23 +++++++++++++++ 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/packages/open-next/src/build/createServerBundle.ts b/packages/open-next/src/build/createServerBundle.ts index df185b06f..42dd235f1 100644 --- a/packages/open-next/src/build/createServerBundle.ts +++ b/packages/open-next/src/build/createServerBundle.ts @@ -329,6 +329,10 @@ CMD ["node", "index.mjs"] `, ); } + + if (fnOptions.copyFiles) { + buildHelper.copyCustomFiles(fnOptions.copyFiles, outPackagePath); + } } function shouldGenerateDockerfile(options: FunctionOptions) { diff --git a/packages/open-next/src/build/edge/createEdgeBundle.ts b/packages/open-next/src/build/edge/createEdgeBundle.ts index 2ca114c24..0a9cc7f2b 100644 --- a/packages/open-next/src/build/edge/createEdgeBundle.ts +++ b/packages/open-next/src/build/edge/createEdgeBundle.ts @@ -23,7 +23,11 @@ import { openNextReplacementPlugin } from "../../plugins/replacement.js"; import { openNextResolvePlugin } from "../../plugins/resolve.js"; import { getCrossPlatformPathRegex } from "../../utils/regex.js"; import { type BuildOptions, isEdgeRuntime } from "../helper.js"; -import { copyOpenNextConfig, esbuildAsync } from "../helper.js"; +import { + copyCustomFiles, + copyOpenNextConfig, + esbuildAsync, +} from "../helper.js"; type Override = OverrideOptions & { originResolver?: LazyLoadedOverride | IncludedOriginResolver; @@ -221,6 +225,10 @@ export async function generateEdgeBundle( name, additionalPlugins, }); + + if (fnOptions.copyFiles) { + copyCustomFiles(fnOptions.copyFiles, outputDir); + } } /** diff --git a/packages/open-next/src/build/helper.ts b/packages/open-next/src/build/helper.ts index 030b309cd..717e3c3ab 100644 --- a/packages/open-next/src/build/helper.ts +++ b/packages/open-next/src/build/helper.ts @@ -6,6 +6,7 @@ import url from "node:url"; import type { BuildOptions as ESBuildOptions } from "esbuild"; import { build as buildAsync, buildSync } from "esbuild"; import type { + CopyFile, DefaultOverrideOptions, OpenNextConfig, } from "types/open-next.js"; @@ -440,3 +441,30 @@ export async function isEdgeRuntime( export function getPackagePath(options: BuildOptions) { return path.relative(options.monorepoRoot, options.appBuildOutputPath); } + +/** + * Copy files that are specified in the `copyFiles` property of the OpenNext config into the output directory. + * + * @param copyFiles - Array of files to copy. Each file should have a `srcPath` and `dstPath` property. + * @param outputPath - Path to the output directory. + */ +export function copyCustomFiles(copyFiles: CopyFile[], outputPath: string) { + copyFiles.forEach(({ srcPath, dstPath }) => { + if (!fs.existsSync(srcPath)) { + logger.warn( + `${srcPath} was not found. Make sure this file exists. Can be a relative path to the app directory or an absolute path.`, + ); + return; + } + + // Create the destination directory if it doesn't exist + const fullDestPath = path.join(outputPath, dstPath); + const destDir = path.dirname(fullDestPath); + if (!fs.existsSync(destDir)) { + fs.mkdirSync(destDir, { recursive: true }); + } + + fs.copyFileSync(srcPath, fullDestPath); + logger.debug(`Copied ${srcPath} to ${fullDestPath}`); + }); +} diff --git a/packages/open-next/src/types/open-next.ts b/packages/open-next/src/types/open-next.ts index f9e435a28..5135d9e2f 100644 --- a/packages/open-next/src/types/open-next.ts +++ b/packages/open-next/src/types/open-next.ts @@ -290,6 +290,15 @@ export interface DefaultFunctionOptions< install?: InstallOptions; } +/** + * @srcPath The path to the file to copy. Can be absolute or relative path. + * @dstPath The path to the destination in the server function. Must be a relative path. + */ +export interface CopyFile { + srcPath: string; + dstPath: string; +} + export interface FunctionOptions extends DefaultFunctionOptions { /** * Runtime used @@ -313,6 +322,20 @@ export interface FunctionOptions extends DefaultFunctionOptions { * @deprecated This is not supported in 14.2+ */ experimentalBundledNextServer?: boolean; + /** + * Manually copy files into the server function after the build. + * @copyFiles The files to copy. Is an array of objects with srcPath and dstPath. + * @example + * ```ts + * copyFiles: [ + * { + * srcPath: 'relativefile.txt', + * dstPath: '/this/is/a/folder.txt', + * }, + * ] + * ``` + */ + copyFiles?: CopyFile[]; } export type RouteTemplate = From 1c227d44f6bf692618eb8c85ec80587cf8de1730 Mon Sep 17 00:00:00 2001 From: magnus Date: Tue, 1 Apr 2025 19:37:06 +0200 Subject: [PATCH 2/3] add glob to copyFiles --- packages/open-next/package.json | 1 + packages/open-next/src/build/helper.ts | 54 +++++++++++++++++------ packages/open-next/src/types/open-next.ts | 5 ++- pnpm-workspace.yaml | 1 + 4 files changed, 46 insertions(+), 15 deletions(-) diff --git a/packages/open-next/package.json b/packages/open-next/package.json index 00284f3e8..8eee76c33 100644 --- a/packages/open-next/package.json +++ b/packages/open-next/package.json @@ -50,6 +50,7 @@ "chalk": "^5.3.0", "esbuild": "0.19.2", "express": "5.0.1", + "glob": "catalog:", "path-to-regexp": "^6.3.0", "urlpattern-polyfill": "^10.0.0", "yaml": "^2.7.0" diff --git a/packages/open-next/src/build/helper.ts b/packages/open-next/src/build/helper.ts index 717e3c3ab..b695c402e 100644 --- a/packages/open-next/src/build/helper.ts +++ b/packages/open-next/src/build/helper.ts @@ -5,6 +5,7 @@ import url from "node:url"; import type { BuildOptions as ESBuildOptions } from "esbuild"; import { build as buildAsync, buildSync } from "esbuild"; +import { globSync } from "glob"; import type { CopyFile, DefaultOverrideOptions, @@ -443,28 +444,55 @@ export function getPackagePath(options: BuildOptions) { } /** - * Copy files that are specified in the `copyFiles` property of the OpenNext config into the output directory. + * Copy files that are specified in the `copyFiles` property into the server functions output directory. * * @param copyFiles - Array of files to copy. Each file should have a `srcPath` and `dstPath` property. * @param outputPath - Path to the output directory. */ export function copyCustomFiles(copyFiles: CopyFile[], outputPath: string) { copyFiles.forEach(({ srcPath, dstPath }) => { - if (!fs.existsSync(srcPath)) { - logger.warn( - `${srcPath} was not found. Make sure this file exists. Can be a relative path to the app directory or an absolute path.`, - ); + // Find all files matching the pattern + const matchedFiles = globSync(srcPath, { + nodir: true, + windowsPathsNoEscape: true, + }); + + if (matchedFiles.length === 0) { + logger.warn(`No files found for pattern: ${srcPath}`); return; } - // Create the destination directory if it doesn't exist - const fullDestPath = path.join(outputPath, dstPath); - const destDir = path.dirname(fullDestPath); - if (!fs.existsSync(destDir)) { - fs.mkdirSync(destDir, { recursive: true }); + if (matchedFiles.length === 1) { + // Single file match - use dstPath as it is + const srcFile = matchedFiles[0]; + const fullDstPath = path.join(outputPath, dstPath); + + copyFile(srcFile, fullDstPath); + } else { + // Multiple files matched, dstPath will become a directory + matchedFiles.forEach((srcFile) => { + const filename = path.basename(srcFile); + const fullDstPath = path.join(outputPath, dstPath, filename); + copyFile(srcFile, fullDstPath); + }); } - - fs.copyFileSync(srcPath, fullDestPath); - logger.debug(`Copied ${srcPath} to ${fullDestPath}`); }); } +/** + * Copy a file to the destination path. + * + * @param srcFile - Path to the source file. + * @param fullDstPath - Path to the destination file. + */ +function copyFile(srcFile: string, fullDstPath: string) { + const dstDir = path.dirname(fullDstPath); + + if (!fs.existsSync(dstDir)) { + fs.mkdirSync(dstDir, { recursive: true }); + } + if (fs.existsSync(fullDstPath)) { + logger.warn(`File already exists: ${fullDstPath}. It will be overwritten.`); + } + fs.copyFileSync(srcFile, fullDstPath); + logger.debug(`Copied ${srcFile} to ${fullDstPath}`); +} diff --git a/packages/open-next/src/types/open-next.ts b/packages/open-next/src/types/open-next.ts index 5135d9e2f..7eae98a35 100644 --- a/packages/open-next/src/types/open-next.ts +++ b/packages/open-next/src/types/open-next.ts @@ -291,8 +291,8 @@ export interface DefaultFunctionOptions< } /** - * @srcPath The path to the file to copy. Can be absolute or relative path. - * @dstPath The path to the destination in the server function. Must be a relative path. + * @srcPath The path to the file to copy. Can be absolute or relative path. Can use glob pattern. + * @dstPath The relative path to the destination in the server function. Will become a directory if multiple files are found in srcPath. */ export interface CopyFile { srcPath: string; @@ -324,6 +324,7 @@ export interface FunctionOptions extends DefaultFunctionOptions { experimentalBundledNextServer?: boolean; /** * Manually copy files into the server function after the build. + * If multiple files are found with srcPath, dstPath will become a directory. * @copyFiles The files to copy. Is an array of objects with srcPath and dstPath. * @example * ```ts diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 106e0be17..570cc2bd9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -13,3 +13,4 @@ catalog: postcss: 8.4.27 tailwindcss: 3.3.3 typescript: 5.6.3 + glob: ^11.0.1 From d28ff4d9f79ca250bb57ae46bc208bab3030a8e5 Mon Sep 17 00:00:00 2001 From: magnus Date: Tue, 1 Apr 2025 20:54:27 +0200 Subject: [PATCH 3/3] add unit test --- packages/tests-unit/package.json | 2 + .../tests-unit/tests/build/helper.test.ts | 183 +++++++++++++++++- pnpm-lock.yaml | 70 +++++++ 3 files changed, 254 insertions(+), 1 deletion(-) diff --git a/packages/tests-unit/package.json b/packages/tests-unit/package.json index 1aca6057c..619732eaf 100644 --- a/packages/tests-unit/package.json +++ b/packages/tests-unit/package.json @@ -11,9 +11,11 @@ "@opennextjs/aws": "workspace:*" }, "devDependencies": { + "@types/mock-fs": "^4.13.4", "@types/testing-library__jest-dom": "^5.14.9", "@vitest/coverage-v8": "^2.1.3", "jsdom": "^22.1.0", + "mock-fs": "^5.5.0", "vite": "5.4.9", "vite-tsconfig-paths": "^5.0.1", "vitest": "^2.1.3" diff --git a/packages/tests-unit/tests/build/helper.test.ts b/packages/tests-unit/tests/build/helper.test.ts index 3c5d4717e..b8ccee480 100644 --- a/packages/tests-unit/tests/build/helper.test.ts +++ b/packages/tests-unit/tests/build/helper.test.ts @@ -1,4 +1,13 @@ -import { compareSemver } from "@opennextjs/aws/build/helper.js"; +import fs from "node:fs"; +import path from "node:path"; + +import { + compareSemver, + copyCustomFiles, +} from "@opennextjs/aws/build/helper.js"; +import logger from "@opennextjs/aws/logger.js"; +import mockFs from "mock-fs"; +import { vi } from "vitest"; // We don't need to test canary versions, they are stripped out describe("compareSemver", () => { @@ -65,3 +74,175 @@ describe("compareSemver", () => { expect(() => compareSemver("14.0.0", "!=" as any, "14.0.0")).toThrow(); }); }); + +const outputFolder = ".open-next/server-functions/default"; + +describe("copyFiles", () => { + beforeEach(() => { + mockFs({ + "this/is/a/fake/dir": { + "some-file24214.txt": "some content", + "another-fil321313e.txt": "another content", + "empty-file321441.txt": "", + "important-js": { + "another-important.js": "console.log('important!')", + }, + }, + "this/is/a/real/dir": { + "randomfile.txt": "some content", + "another-dirfdsf": { + "another-filedsfdsf.txt": "another content", + }, + "empty-file.txtfdsf": "", + "imporant-files": { + "important.js": "console.log('important!')", + "super-important.js": "console.log('super important!')", + }, + }, + [`${outputFolder}/server`]: { + "index.mjs": "globalThis.process.env = {}", + }, + }); + + vi.spyOn(fs, "copyFileSync"); + vi.spyOn(fs, "mkdirSync"); + vi.spyOn(fs, "readFileSync"); + }); + + afterAll(() => { + mockFs.restore(); + vi.restoreAllMocks(); + }); + + it("should work with a glob, dstPath should become a directory", () => { + copyCustomFiles( + [ + { + srcPath: "**/*.js", + dstPath: "functions", + }, + ], + outputFolder, + ); + + const dstDir = path.join(outputFolder, "functions"); + expect(fs.copyFileSync).toHaveBeenCalledTimes(3); + expect(fs.mkdirSync).toHaveBeenCalledWith(dstDir, { recursive: true }); + expect(fs.mkdirSync).toHaveBeenCalledTimes(1); + + expect(fs.readdirSync(dstDir)).toEqual([ + "another-important.js", + "important.js", + "super-important.js", + ]); + + expect( + fs.readFileSync(path.join(dstDir, "important.js")).toString(), + ).toMatchInlineSnapshot(`"console.log('important!')"`); + }); + + it("should copy a single file when srcPath matches one file", () => { + copyCustomFiles( + [ + { + srcPath: "this/is/a/real/dir/randomfile.txt", + dstPath: "randomfolder/randomfile.txt", + }, + ], + outputFolder, + ); + + const dstDir = path.join(outputFolder, "randomfolder"); + expect(fs.mkdirSync).toHaveBeenCalledWith(dstDir, { recursive: true }); + expect(fs.mkdirSync).toHaveBeenCalledTimes(1); + + expect(fs.copyFileSync).toHaveBeenCalledTimes(1); + expect(fs.copyFileSync).toHaveBeenCalledWith( + "this/is/a/real/dir/randomfile.txt", + path.join(outputFolder, "randomfolder/randomfile.txt"), + ); + + expect( + fs.readFileSync(path.join(outputFolder, "randomfolder/randomfile.txt"), { + encoding: "utf-8", + }), + ).toMatchInlineSnapshot(`"some content"`); + }); + + it("should work with a glob in a sub directory", () => { + copyCustomFiles( + [ + { + srcPath: "this/is/a/real/dir/imporant-files/**/*.js", + dstPath: "super/functions", + }, + ], + outputFolder, + ); + + expect(fs.mkdirSync).toHaveBeenCalledWith( + path.join(outputFolder, "super/functions"), + { recursive: true }, + ); + expect(fs.mkdirSync).toHaveBeenCalledTimes(1); + + expect(fs.copyFileSync).toHaveBeenCalledTimes(2); + expect(fs.copyFileSync).toHaveBeenCalledWith( + "this/is/a/real/dir/imporant-files/important.js", + path.join(outputFolder, "super/functions/important.js"), + ); + expect(fs.copyFileSync).toHaveBeenCalledWith( + "this/is/a/real/dir/imporant-files/super-important.js", + path.join(outputFolder, "super/functions/super-important.js"), + ); + + expect(fs.readdirSync(path.join(outputFolder, "super/functions"))).toEqual([ + "important.js", + "super-important.js", + ]); + expect( + fs.readFileSync( + path.join(outputFolder, "super/functions/super-important.js"), + { encoding: "utf-8" }, + ), + ).toMatchInlineSnapshot(`"console.log('super important!')"`); + }); + it("should warn when file already exists", () => { + const logSpy = vi.spyOn(logger, "warn"); + + copyCustomFiles( + [ + { + srcPath: "this/is/a/fake/dir/some-file24214.txt", + dstPath: "server/index.mjs", + }, + ], + outputFolder, + ); + + const fullDstPath = path.join(outputFolder, "server/index.mjs"); + expect(logSpy).toHaveBeenCalledWith( + `File already exists: ${fullDstPath}. It will be overwritten.`, + ); + logSpy.mockRestore(); + }); + it("should warn when no files are found", () => { + const logSpy = vi.spyOn(logger, "warn"); + const srcPath = "path/to/dir/does-not-exist.txt"; + + copyCustomFiles( + [ + { + srcPath: srcPath, + dstPath: "server/index.mjs", + }, + ], + outputFolder, + ); + + expect(logSpy).toHaveBeenCalledWith( + `No files found for pattern: ${srcPath}`, + ); + logSpy.mockRestore(); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4327bfa4f..bfc00d151 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,6 +18,9 @@ catalogs: autoprefixer: specifier: 10.4.15 version: 10.4.15 + glob: + specifier: ^11.0.1 + version: 11.0.1 next: specifier: 15.2.0 version: 15.2.0 @@ -243,6 +246,9 @@ importers: express: specifier: 5.0.1 version: 5.0.1 + glob: + specifier: 'catalog:' + version: 11.0.1 path-to-regexp: specifier: ^6.3.0 version: 6.3.0 @@ -287,6 +293,9 @@ importers: specifier: workspace:* version: link:../open-next devDependencies: + '@types/mock-fs': + specifier: ^4.13.4 + version: 4.13.4 '@types/testing-library__jest-dom': specifier: ^5.14.9 version: 5.14.9 @@ -296,6 +305,9 @@ importers: jsdom: specifier: ^22.1.0 version: 22.1.0 + mock-fs: + specifier: ^5.5.0 + version: 5.5.0 vite: specifier: 5.4.9 version: 5.4.9(@types/node@20.17.6)(terser@5.16.9) @@ -2507,6 +2519,9 @@ packages: '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + '@types/mock-fs@4.13.4': + resolution: {integrity: sha512-mXmM0o6lULPI8z3XNnQCpL0BGxPwx1Ul1wXYEPBGl4efShyxW2Rln0JOPEWGyZaYZMM6OVXM/15zUuFMY52ljg==} + '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} @@ -3575,6 +3590,11 @@ packages: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true + glob@11.0.1: + resolution: {integrity: sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==} + engines: {node: 20 || >=22} + hasBin: true + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -3856,6 +3876,10 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jackspeak@4.1.0: + resolution: {integrity: sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==} + engines: {node: 20 || >=22} + jest-diff@29.7.0: resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4037,6 +4061,10 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.1.0: + resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==} + engines: {node: 20 || >=22} + lru-cache@4.1.5: resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} @@ -4134,6 +4162,10 @@ packages: minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + minimatch@10.0.1: + resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + engines: {node: 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -4181,6 +4213,10 @@ packages: mnemonist@0.39.8: resolution: {integrity: sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ==} + mock-fs@5.5.0: + resolution: {integrity: sha512-d/P1M/RacgM3dB0sJ8rjeRNXxtapkPCUnMGmIN0ixJ16F/E4GUZCvWcSGfWGz8eaXYvn1s9baUwNjI4LOPEjiA==} + engines: {node: '>=12.0.0'} + mqtt-packet@6.10.0: resolution: {integrity: sha512-ja8+mFKIHdB1Tpl6vac+sktqy3gA8t9Mduom1BA75cI+R9AHnZOiaBQwpGiWnaVJLDGRdNhQmFaAqd7tkKSMGA==} @@ -4402,6 +4438,10 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + path-to-regexp@0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} @@ -8978,6 +9018,10 @@ snapshots: '@types/mime@1.3.5': {} + '@types/mock-fs@4.13.4': + dependencies: + '@types/node': 20.17.6 + '@types/node@12.20.55': {} '@types/node@20.17.6': @@ -10249,6 +10293,15 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + glob@11.0.1: + dependencies: + foreground-child: 3.3.0 + jackspeak: 4.1.0 + minimatch: 10.0.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -10544,6 +10597,10 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jackspeak@4.1.0: + dependencies: + '@isaacs/cliui': 8.0.2 + jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -10725,6 +10782,8 @@ snapshots: lru-cache@10.4.3: {} + lru-cache@11.1.0: {} + lru-cache@4.1.5: dependencies: pseudomap: 1.0.2 @@ -10799,6 +10858,10 @@ snapshots: minimalistic-assert@1.0.1: {} + minimatch@10.0.1: + dependencies: + brace-expansion: 2.0.1 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 @@ -10844,6 +10907,8 @@ snapshots: dependencies: obliterator: 2.0.4 + mock-fs@5.5.0: {} + mqtt-packet@6.10.0: dependencies: bl: 4.1.0 @@ -11075,6 +11140,11 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 + path-scurry@2.0.0: + dependencies: + lru-cache: 11.1.0 + minipass: 7.1.2 + path-to-regexp@0.1.12: {} path-to-regexp@6.3.0: {}