From a6e718a00a5bbe662f0d45c48b419b2d935a4791 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 9 Jan 2026 08:25:04 +0000 Subject: [PATCH 1/6] fix(build): add destination option to additionalFiles extension When using glob patterns with parent directory references (../), the default behavior strips ".." segments resulting in unexpected paths. For example, "../shared/**" would place files at "shared/" instead of preserving the original path structure. This adds an optional "destination" parameter that allows users to explicitly specify where matched files should be placed: additionalFiles({ files: ["../shared/**"], destination: "apps/shared" }) When destination is specified, files are placed relative to the glob pattern's base directory under the destination path. This is useful in monorepo setups where files need to maintain their structure. Also updates documentation to explain this behavior and the new option. Slack thread: https://triggerdotdev.slack.com/archives/C08N6PJTK2Q/p1767946469914139?thread_ts=1756405171.439939&cid=C08N6PJTK2Q --- docs/config/extensions/additionalFiles.mdx | 72 ++++++++++++++++++- .../src/extensions/core/additionalFiles.ts | 19 +++++ .../build/src/internal/additionalFiles.ts | 66 ++++++++++++++--- 3 files changed, 147 insertions(+), 10 deletions(-) diff --git a/docs/config/extensions/additionalFiles.mdx b/docs/config/extensions/additionalFiles.mdx index 038bf185ab..5503b641e6 100644 --- a/docs/config/extensions/additionalFiles.mdx +++ b/docs/config/extensions/additionalFiles.mdx @@ -24,7 +24,7 @@ export default defineConfig({ This will copy the files specified in the `files` array to the build directory. The `files` array can contain globs. The output paths will match the path of the file, relative to the root of the project. -This extension effects both the `dev` and the `deploy` commands, and the resulting paths will be the same for both. +This extension affects both the `dev` and the `deploy` commands, and the resulting paths will be the same for both. If you use `legacyDevProcessCwdBehaviour: false`, you can then do this: @@ -36,3 +36,73 @@ const interRegularFont = path.join(process.cwd(), "assets/Inter-Regular.ttf"); ``` The root of the project is the directory that contains the trigger.config.ts file + +## Copying files from parent directories (monorepos) + +When copying files from parent directories using `..` in your glob patterns, the default behavior strips the `..` segments from the destination path. This can lead to unexpected results in monorepo setups. + +For example, if your monorepo structure looks like this: + +``` +monorepo/ +├── apps/ +│ ├── trigger/ # Contains trigger.config.ts +│ │ └── trigger.config.ts +│ └── shared/ # Directory you want to copy +│ └── utils.ts +``` + +Using `additionalFiles({ files: ["../shared/**"] })` would copy `utils.ts` to `shared/utils.ts` in the build directory (not `apps/shared/utils.ts`), because the `..` segment is stripped. + +### Using the `destination` option + +To control exactly where files are placed, use the `destination` option: + +```ts +import { defineConfig } from "@trigger.dev/sdk"; +import { additionalFiles } from "@trigger.dev/build/extensions/core"; + +export default defineConfig({ + project: "", + build: { + extensions: [ + additionalFiles({ + files: ["../shared/**"], + destination: "apps/shared", // Files will be placed under apps/shared/ + }), + ], + }, +}); +``` + +With this configuration, `../shared/utils.ts` will be copied to `apps/shared/utils.ts` in the build directory. + + +When using `destination`, the file structure relative to the glob pattern's base directory is preserved. +For example, `../shared/nested/file.ts` with `destination: "libs"` will be copied to `libs/nested/file.ts`. + + +### Multiple directories with different destinations + +If you need to copy multiple directories to different locations, use multiple `additionalFiles` extensions: + +```ts +import { defineConfig } from "@trigger.dev/sdk"; +import { additionalFiles } from "@trigger.dev/build/extensions/core"; + +export default defineConfig({ + project: "", + build: { + extensions: [ + additionalFiles({ + files: ["../shared/**"], + destination: "libs/shared", + }), + additionalFiles({ + files: ["../templates/**"], + destination: "assets/templates", + }), + ], + }, +}); +``` diff --git a/packages/build/src/extensions/core/additionalFiles.ts b/packages/build/src/extensions/core/additionalFiles.ts index cc2a04e0e0..a71f42287f 100644 --- a/packages/build/src/extensions/core/additionalFiles.ts +++ b/packages/build/src/extensions/core/additionalFiles.ts @@ -3,6 +3,25 @@ import { addAdditionalFilesToBuild } from "../../internal/additionalFiles.js"; export type AdditionalFilesOptions = { files: string[]; + /** + * Optional destination directory for the matched files. + * + * When specified, files will be placed under this directory while preserving + * their structure relative to the glob pattern's base directory. + * + * This is useful when including files from parent directories (using `..` in the glob pattern), + * as the default behavior strips `..` segments which can result in unexpected destination paths. + * + * @example + * // In a monorepo with structure: apps/trigger, apps/shared + * // From apps/trigger/trigger.config.ts: + * additionalFiles({ + * files: ["../shared/**"], + * destination: "apps/shared" + * }) + * // Files from ../shared/utils.ts will be copied to apps/shared/utils.ts + */ + destination?: string; }; export function additionalFiles(options: AdditionalFilesOptions): BuildExtension { diff --git a/packages/build/src/internal/additionalFiles.ts b/packages/build/src/internal/additionalFiles.ts index a815b53c9a..b4f0a618f6 100644 --- a/packages/build/src/internal/additionalFiles.ts +++ b/packages/build/src/internal/additionalFiles.ts @@ -1,11 +1,30 @@ import { BuildManifest } from "@trigger.dev/core/v3"; import { BuildContext } from "@trigger.dev/core/v3/build"; import { copyFile, mkdir } from "node:fs/promises"; -import { dirname, join, posix, relative } from "node:path"; +import { dirname, isAbsolute, join, posix, relative, resolve } from "node:path"; import { glob } from "tinyglobby"; export type AdditionalFilesOptions = { files: string[]; + /** + * Optional destination directory for the matched files. + * + * When specified, files will be placed under this directory while preserving + * their structure relative to the glob pattern's base directory. + * + * This is useful when including files from parent directories (using `..` in the glob pattern), + * as the default behavior strips `..` segments which can result in unexpected destination paths. + * + * @example + * // In a monorepo with structure: apps/trigger, apps/shared + * // From apps/trigger/trigger.config.ts: + * additionalFiles({ + * files: ["../shared/**"], + * destination: "apps/shared" + * }) + * // Files from ../shared/utils.ts will be copied to apps/shared/utils.ts + */ + destination?: string; }; export async function addAdditionalFilesToBuild( @@ -17,6 +36,7 @@ export async function addAdditionalFilesToBuild( // Copy any static assets to the destination const staticAssets = await findStaticAssetFiles(options.files ?? [], manifest.outputPath, { cwd: context.workingDir, + destination: options.destination, }); for (const { assets, matcher } of staticAssets) { @@ -40,7 +60,7 @@ type FoundStaticAssetFiles = Array<{ async function findStaticAssetFiles( matchers: string[], destinationPath: string, - options?: { cwd?: string; ignore?: string[] } + options?: { cwd?: string; ignore?: string[]; destination?: string } ): Promise { const result: FoundStaticAssetFiles = []; @@ -53,10 +73,27 @@ async function findStaticAssetFiles( return result; } +// Extracts the base directory from a glob pattern (the non-wildcard prefix). +// For example: "../shared/**" -> "../shared", "./assets/*.txt" -> "./assets" +function getGlobBase(pattern: string): string { + const parts = pattern.split(/[/\\]/); + const baseParts: string[] = []; + + for (const part of parts) { + // Stop at the first part that contains glob characters + if (part.includes("*") || part.includes("?") || part.includes("[") || part.includes("{")) { + break; + } + baseParts.push(part); + } + + return baseParts.length > 0 ? baseParts.join(posix.sep) : "."; +} + async function findStaticAssetsForMatcher( matcher: string, destinationPath: string, - options?: { cwd?: string; ignore?: string[] } + options?: { cwd?: string; ignore?: string[]; destination?: string } ): Promise { const result: MatchedStaticAssets = []; @@ -68,15 +105,26 @@ async function findStaticAssetsForMatcher( absolute: true, }); - let matches = 0; + const cwd = options?.cwd ?? process.cwd(); for (const file of files) { - matches++; + let pathInsideDestinationDir: string; + + if (options?.destination) { + // When destination is specified, compute path relative to the glob pattern's base directory + const globBase = getGlobBase(matcher); + const absoluteGlobBase = isAbsolute(globBase) ? globBase : resolve(cwd, globBase); + const relativeToGlobBase = relative(absoluteGlobBase, file); - const pathInsideDestinationDir = relative(options?.cwd ?? process.cwd(), file) - .split(posix.sep) - .filter((p) => p !== "..") - .join(posix.sep); + // Place files under the specified destination directory + pathInsideDestinationDir = join(options.destination, relativeToGlobBase); + } else { + // Default behavior: compute relative path from cwd and strip ".." segments + pathInsideDestinationDir = relative(cwd, file) + .split(posix.sep) + .filter((p) => p !== "..") + .join(posix.sep); + } const relativeDestinationPath = join(destinationPath, pathInsideDestinationDir); From 55aba75c47121adab6d0293795871782d06f8cfb Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 09:10:11 +0000 Subject: [PATCH 2/6] fix(build): handle specific file paths in getGlobBase for destination option When a pattern has no glob characters (e.g., './config/settings.json'), return the parent directory instead of the full path. This ensures that relative() preserves the filename when computing the destination path. Co-authored-by: Eric Allam --- packages/build/src/internal/additionalFiles.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/build/src/internal/additionalFiles.ts b/packages/build/src/internal/additionalFiles.ts index b4f0a618f6..9bde93f468 100644 --- a/packages/build/src/internal/additionalFiles.ts +++ b/packages/build/src/internal/additionalFiles.ts @@ -75,18 +75,27 @@ async function findStaticAssetFiles( // Extracts the base directory from a glob pattern (the non-wildcard prefix). // For example: "../shared/**" -> "../shared", "./assets/*.txt" -> "./assets" +// For specific files without globs: "./config/settings.json" -> "./config" (parent dir) function getGlobBase(pattern: string): string { const parts = pattern.split(/[/\\]/); const baseParts: string[] = []; + let hasGlobCharacters = false; for (const part of parts) { // Stop at the first part that contains glob characters if (part.includes("*") || part.includes("?") || part.includes("[") || part.includes("{")) { + hasGlobCharacters = true; break; } baseParts.push(part); } + // If no glob characters were found, the pattern is a specific file path. + // Return the parent directory so that relative() preserves the filename. + if (!hasGlobCharacters && baseParts.length > 1) { + baseParts.pop(); // Remove the filename, keep the directory + } + return baseParts.length > 0 ? baseParts.join(posix.sep) : "."; } From 345722e1c7a995842e755b3d7143fcf463cd6f4e Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 10:04:51 +0000 Subject: [PATCH 3/6] fix(build): address review comments and add unit tests for additionalFiles - Fix getGlobBase to return '.' for single-part patterns like 'file.txt' - Fix Windows path separator handling by using 'sep' instead of 'posix.sep' when splitting - Export getGlobBase function for testing - Add comprehensive unit tests for getGlobBase function - Add vitest configuration for @trigger.dev/build package Co-authored-by: Eric Allam --- packages/build/package.json | 7 +- .../build/src/internal/additionalFiles.ts | 13 ++- packages/build/test/additionalFiles.test.ts | 94 +++++++++++++++++++ packages/build/vitest.config.ts | 8 ++ 4 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 packages/build/test/additionalFiles.test.ts create mode 100644 packages/build/vitest.config.ts diff --git a/packages/build/package.json b/packages/build/package.json index d5ec39213f..da42a211f7 100644 --- a/packages/build/package.json +++ b/packages/build/package.json @@ -74,7 +74,9 @@ "dev": "tshy --watch", "typecheck": "tsc --noEmit -p tsconfig.src.json", "update-version": "tsx ../../scripts/updateVersion.ts", - "check-exports": "attw --pack ." + "check-exports": "attw --pack .", + "test": "vitest run", + "test:dev": "vitest" }, "dependencies": { "@prisma/config": "^6.10.0", @@ -91,7 +93,8 @@ "esbuild": "^0.23.0", "rimraf": "6.0.1", "tshy": "^3.0.2", - "tsx": "4.17.0" + "tsx": "4.17.0", + "vitest": "^2.0.0" }, "engines": { "node": ">=18.20.0" diff --git a/packages/build/src/internal/additionalFiles.ts b/packages/build/src/internal/additionalFiles.ts index 9bde93f468..c92b848dc8 100644 --- a/packages/build/src/internal/additionalFiles.ts +++ b/packages/build/src/internal/additionalFiles.ts @@ -1,7 +1,7 @@ import { BuildManifest } from "@trigger.dev/core/v3"; import { BuildContext } from "@trigger.dev/core/v3/build"; import { copyFile, mkdir } from "node:fs/promises"; -import { dirname, isAbsolute, join, posix, relative, resolve } from "node:path"; +import { dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path"; import { glob } from "tinyglobby"; export type AdditionalFilesOptions = { @@ -76,7 +76,8 @@ async function findStaticAssetFiles( // Extracts the base directory from a glob pattern (the non-wildcard prefix). // For example: "../shared/**" -> "../shared", "./assets/*.txt" -> "./assets" // For specific files without globs: "./config/settings.json" -> "./config" (parent dir) -function getGlobBase(pattern: string): string { +// For single-part patterns: "file.txt" -> "." (current dir) +export function getGlobBase(pattern: string): string { const parts = pattern.split(/[/\\]/); const baseParts: string[] = []; let hasGlobCharacters = false; @@ -92,8 +93,9 @@ function getGlobBase(pattern: string): string { // If no glob characters were found, the pattern is a specific file path. // Return the parent directory so that relative() preserves the filename. - if (!hasGlobCharacters && baseParts.length > 1) { - baseParts.pop(); // Remove the filename, keep the directory + // For single-part patterns (just a filename), return "." to indicate current directory. + if (!hasGlobCharacters) { + baseParts.pop(); // Remove the filename, keep the directory (or empty for single-part) } return baseParts.length > 0 ? baseParts.join(posix.sep) : "."; @@ -129,8 +131,9 @@ async function findStaticAssetsForMatcher( pathInsideDestinationDir = join(options.destination, relativeToGlobBase); } else { // Default behavior: compute relative path from cwd and strip ".." segments + // Use platform-specific separator for splitting since path.relative() returns platform separators pathInsideDestinationDir = relative(cwd, file) - .split(posix.sep) + .split(sep) .filter((p) => p !== "..") .join(posix.sep); } diff --git a/packages/build/test/additionalFiles.test.ts b/packages/build/test/additionalFiles.test.ts new file mode 100644 index 0000000000..b8fea20d90 --- /dev/null +++ b/packages/build/test/additionalFiles.test.ts @@ -0,0 +1,94 @@ +import { describe, it, expect } from "vitest"; +import { getGlobBase } from "../src/internal/additionalFiles.js"; + +describe("getGlobBase", () => { + describe("glob patterns with wildcards", () => { + it("extracts base from parent directory glob pattern", () => { + expect(getGlobBase("../shared/**")).toBe("../shared"); + }); + + it("extracts base from relative directory glob pattern", () => { + expect(getGlobBase("./assets/*.txt")).toBe("./assets"); + }); + + it("extracts base from nested directory glob pattern", () => { + expect(getGlobBase("files/nested/**/*.js")).toBe("files/nested"); + }); + + it("returns current directory for top-level glob", () => { + expect(getGlobBase("**/*.js")).toBe("."); + }); + + it("returns current directory for star pattern", () => { + expect(getGlobBase("*.js")).toBe("."); + }); + + it("handles question mark wildcard", () => { + expect(getGlobBase("./src/?/*.ts")).toBe("./src"); + }); + + it("handles bracket patterns", () => { + expect(getGlobBase("./src/[abc]/*.ts")).toBe("./src"); + }); + + it("handles brace expansion patterns", () => { + expect(getGlobBase("./src/{a,b}/*.ts")).toBe("./src"); + }); + + it("handles deeply nested patterns", () => { + expect(getGlobBase("a/b/c/d/**")).toBe("a/b/c/d"); + }); + }); + + describe("specific file paths without globs", () => { + it("returns parent directory for file in subdirectory", () => { + expect(getGlobBase("./config/settings.json")).toBe("./config"); + }); + + it("returns parent directory for file in nested subdirectory", () => { + expect(getGlobBase("../shared/utils/helpers.ts")).toBe("../shared/utils"); + }); + + it("returns current directory for single-part filename", () => { + expect(getGlobBase("file.txt")).toBe("."); + }); + + it("returns current directory for filename starting with dot", () => { + expect(getGlobBase(".env")).toBe("."); + }); + + it("returns parent directory for explicit relative path to file", () => { + expect(getGlobBase("./file.txt")).toBe("."); + }); + + it("returns parent directories for parent reference to file", () => { + expect(getGlobBase("../file.txt")).toBe(".."); + }); + + it("handles multiple parent references", () => { + expect(getGlobBase("../../config/app.json")).toBe("../../config"); + }); + }); + + describe("edge cases", () => { + it("returns current directory for empty string", () => { + expect(getGlobBase("")).toBe("."); + }); + + it("handles Windows-style backslashes", () => { + expect(getGlobBase("..\\shared\\**")).toBe("../shared"); + }); + + it("handles mixed forward and back slashes", () => { + expect(getGlobBase("../shared\\nested/**")).toBe("../shared/nested"); + }); + + it("handles patterns with only dots", () => { + expect(getGlobBase("./")).toBe("."); + }); + + it("handles parent directory reference only", () => { + expect(getGlobBase("../")).toBe(".."); + }); + }); +}); diff --git a/packages/build/vitest.config.ts b/packages/build/vitest.config.ts new file mode 100644 index 0000000000..7f850a5445 --- /dev/null +++ b/packages/build/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + include: ["test/**/*.test.ts", "src/**/*.test.ts"], + globals: true, + }, +}); From 520ebcd3c7f6cd0fbe335e6473e839948af1a613 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 10:24:08 +0000 Subject: [PATCH 4/6] chore: update pnpm-lock.yaml after adding vitest dependency Co-authored-by: Eric Allam --- pnpm-lock.yaml | 144 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cce281d1fd..a692d73005 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1333,6 +1333,9 @@ importers: tsx: specifier: 4.17.0 version: 4.17.0 + vitest: + specifier: ^2.0.0 + version: 2.1.9(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1) packages/cli-v3: dependencies: @@ -10931,9 +10934,23 @@ packages: '@vitest/browser': optional: true + '@vitest/expect@2.1.9': + resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==} + '@vitest/expect@3.1.4': resolution: {integrity: sha512-xkD/ljeliyaClDYqHPNCiJ0plY5YIcM0OlRiZizLhlPmpXWpxnGMyTZXOHFhFeG7w9P5PBeL4IdtJ/HeQwTbQA==} + '@vitest/mocker@2.1.9': + resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + '@vitest/mocker@3.1.4': resolution: {integrity: sha512-8IJ3CvwtSw/EFXqWFL8aCMu+YyYXG2WUSrQbViOZkWTKTVicVwZ/YiEZDSqD00kX+v/+W+OnxhNWoeVKorHygA==} peerDependencies: @@ -10957,9 +10974,15 @@ packages: '@vitest/runner@3.1.4': resolution: {integrity: sha512-djTeF1/vt985I/wpKVFBMWUlk/I7mb5hmD5oP8K9ACRmVXgKTae3TUOtXAEBfslNKPzUQvnKhNd34nnRSYgLNQ==} + '@vitest/snapshot@2.1.9': + resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==} + '@vitest/snapshot@3.1.4': resolution: {integrity: sha512-JPHf68DvuO7vilmvwdPr9TS0SuuIzHvxeaCkxYcCD4jTk67XwL45ZhEHFKIuCm8CYstgI6LZ4XbwD6ANrwMpFg==} + '@vitest/spy@2.1.9': + resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==} + '@vitest/spy@3.1.4': resolution: {integrity: sha512-Xg1bXhu+vtPXIodYN369M86K8shGLouNjoVI78g8iAq2rFoHFdajNvJJ5A/9bPMFcfQqdaCpOgWKEoMQg/s0Yg==} @@ -19498,6 +19521,11 @@ packages: engines: {node: '>=v14.16.0'} hasBin: true + vite-node@2.1.9: + resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + vite-node@3.1.4: resolution: {integrity: sha512-6enNwYnpyDo4hEgytbmc6mYWHXDHYEn0D1/rw4Q+tnHUGtKTJsn8T1YkX6Q18wI5LCrS8CTYlBaiCqxOy2kvUA==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -19565,6 +19593,31 @@ packages: terser: optional: true + vitest@2.1.9: + resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.1.9 + '@vitest/ui': 2.1.9 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vitest@3.1.4: resolution: {integrity: sha512-Ta56rT7uWxCSJXlBtKgIlApJnT6e6IGmTYxYcmxjJ4ujuZDI59GUQgVDObXXJujOmPDBYXHK1qmaGtneu6TNIQ==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -31242,6 +31295,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@vitest/expect@2.1.9': + dependencies: + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.2.0 + tinyrainbow: 1.2.0 + '@vitest/expect@3.1.4': dependencies: '@vitest/spy': 3.1.4 @@ -31249,6 +31309,14 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 + '@vitest/mocker@2.1.9(vite@5.4.21(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1))': + dependencies: + '@vitest/spy': 2.1.9 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 5.4.21(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1) + '@vitest/mocker@3.1.4(vite@5.4.21(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1))': dependencies: '@vitest/spy': 3.1.4 @@ -31275,12 +31343,22 @@ snapshots: '@vitest/utils': 3.1.4 pathe: 2.0.3 + '@vitest/snapshot@2.1.9': + dependencies: + '@vitest/pretty-format': 2.1.9 + magic-string: 0.30.21 + pathe: 1.1.2 + '@vitest/snapshot@3.1.4': dependencies: '@vitest/pretty-format': 3.1.4 magic-string: 0.30.21 pathe: 2.0.3 + '@vitest/spy@2.1.9': + dependencies: + tinyspy: 3.0.2 + '@vitest/spy@3.1.4': dependencies: tinyspy: 3.0.2 @@ -37190,7 +37268,7 @@ snapshots: nano-css@5.6.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 css-tree: 1.1.3 csstype: 3.2.0 fastest-stable-stringify: 2.0.2 @@ -41589,6 +41667,24 @@ snapshots: - supports-color - terser + vite-node@2.1.9(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1): + dependencies: + cac: 6.7.14 + debug: 4.4.1(supports-color@10.0.0) + es-module-lexer: 1.7.0 + pathe: 1.1.2 + vite: 5.4.21(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + vite-node@3.1.4(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1): dependencies: cac: 6.7.14 @@ -41647,6 +41743,52 @@ snapshots: lightningcss: 1.29.2 terser: 5.44.1 + vite@5.4.21(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1): + dependencies: + esbuild: 0.21.5 + postcss: 8.5.6 + rollup: 4.36.0 + optionalDependencies: + '@types/node': 22.13.9 + fsevents: 2.3.3 + lightningcss: 1.29.2 + terser: 5.44.1 + + vitest@2.1.9(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1): + dependencies: + '@vitest/expect': 2.1.9 + '@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1)) + '@vitest/pretty-format': 2.1.9 + '@vitest/runner': 2.1.9 + '@vitest/snapshot': 2.1.9 + '@vitest/spy': 2.1.9 + '@vitest/utils': 2.1.9 + chai: 5.2.0 + debug: 4.4.1(supports-color@10.0.0) + expect-type: 1.2.1 + magic-string: 0.30.21 + pathe: 1.1.2 + std-env: 3.9.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinypool: 1.0.2 + tinyrainbow: 1.2.0 + vite: 5.4.21(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1) + vite-node: 2.1.9(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 22.13.9 + transitivePeerDependencies: + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + vitest@3.1.4(@types/debug@4.1.12)(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1): dependencies: '@vitest/expect': 3.1.4 From ff856f78256842291fc505a39f456a07d89da080 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 11:01:12 +0000 Subject: [PATCH 5/6] chore: update vitest to 3.1.4 in packages/build for consistent test reporting Co-authored-by: Eric Allam --- packages/build/package.json | 2 +- pnpm-lock.yaml | 141 +++++++++--------------------------- 2 files changed, 35 insertions(+), 108 deletions(-) diff --git a/packages/build/package.json b/packages/build/package.json index da42a211f7..7790be9259 100644 --- a/packages/build/package.json +++ b/packages/build/package.json @@ -94,7 +94,7 @@ "rimraf": "6.0.1", "tshy": "^3.0.2", "tsx": "4.17.0", - "vitest": "^2.0.0" + "vitest": "3.1.4" }, "engines": { "node": ">=18.20.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a692d73005..12c3accea7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1054,7 +1054,7 @@ importers: version: 18.3.1 react-email: specifier: ^2.1.1 - version: 2.1.2(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.15)(bufferutil@4.0.9)(eslint@8.31.0) + version: 2.1.2(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.15)(eslint@8.31.0) resend: specifier: ^3.2.0 version: 3.2.0 @@ -1334,8 +1334,8 @@ importers: specifier: 4.17.0 version: 4.17.0 vitest: - specifier: ^2.0.0 - version: 2.1.9(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1) + specifier: 3.1.4 + version: 3.1.4(@types/debug@4.1.12)(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1) packages/cli-v3: dependencies: @@ -10934,23 +10934,9 @@ packages: '@vitest/browser': optional: true - '@vitest/expect@2.1.9': - resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==} - '@vitest/expect@3.1.4': resolution: {integrity: sha512-xkD/ljeliyaClDYqHPNCiJ0plY5YIcM0OlRiZizLhlPmpXWpxnGMyTZXOHFhFeG7w9P5PBeL4IdtJ/HeQwTbQA==} - '@vitest/mocker@2.1.9': - resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==} - peerDependencies: - msw: ^2.4.9 - vite: ^5.0.0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - '@vitest/mocker@3.1.4': resolution: {integrity: sha512-8IJ3CvwtSw/EFXqWFL8aCMu+YyYXG2WUSrQbViOZkWTKTVicVwZ/YiEZDSqD00kX+v/+W+OnxhNWoeVKorHygA==} peerDependencies: @@ -10974,15 +10960,9 @@ packages: '@vitest/runner@3.1.4': resolution: {integrity: sha512-djTeF1/vt985I/wpKVFBMWUlk/I7mb5hmD5oP8K9ACRmVXgKTae3TUOtXAEBfslNKPzUQvnKhNd34nnRSYgLNQ==} - '@vitest/snapshot@2.1.9': - resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==} - '@vitest/snapshot@3.1.4': resolution: {integrity: sha512-JPHf68DvuO7vilmvwdPr9TS0SuuIzHvxeaCkxYcCD4jTk67XwL45ZhEHFKIuCm8CYstgI6LZ4XbwD6ANrwMpFg==} - '@vitest/spy@2.1.9': - resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==} - '@vitest/spy@3.1.4': resolution: {integrity: sha512-Xg1bXhu+vtPXIodYN369M86K8shGLouNjoVI78g8iAq2rFoHFdajNvJJ5A/9bPMFcfQqdaCpOgWKEoMQg/s0Yg==} @@ -19521,11 +19501,6 @@ packages: engines: {node: '>=v14.16.0'} hasBin: true - vite-node@2.1.9: - resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - vite-node@3.1.4: resolution: {integrity: sha512-6enNwYnpyDo4hEgytbmc6mYWHXDHYEn0D1/rw4Q+tnHUGtKTJsn8T1YkX6Q18wI5LCrS8CTYlBaiCqxOy2kvUA==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -19593,31 +19568,6 @@ packages: terser: optional: true - vitest@2.1.9: - resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 2.1.9 - '@vitest/ui': 2.1.9 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - vitest@3.1.4: resolution: {integrity: sha512-Ta56rT7uWxCSJXlBtKgIlApJnT6e6IGmTYxYcmxjJ4ujuZDI59GUQgVDObXXJujOmPDBYXHK1qmaGtneu6TNIQ==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -31295,13 +31245,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/expect@2.1.9': - dependencies: - '@vitest/spy': 2.1.9 - '@vitest/utils': 2.1.9 - chai: 5.2.0 - tinyrainbow: 1.2.0 - '@vitest/expect@3.1.4': dependencies: '@vitest/spy': 3.1.4 @@ -31309,14 +31252,6 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@2.1.9(vite@5.4.21(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1))': - dependencies: - '@vitest/spy': 2.1.9 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 5.4.21(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1) - '@vitest/mocker@3.1.4(vite@5.4.21(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1))': dependencies: '@vitest/spy': 3.1.4 @@ -31343,22 +31278,12 @@ snapshots: '@vitest/utils': 3.1.4 pathe: 2.0.3 - '@vitest/snapshot@2.1.9': - dependencies: - '@vitest/pretty-format': 2.1.9 - magic-string: 0.30.21 - pathe: 1.1.2 - '@vitest/snapshot@3.1.4': dependencies: '@vitest/pretty-format': 3.1.4 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@2.1.9': - dependencies: - tinyspy: 3.0.2 - '@vitest/spy@3.1.4': dependencies: tinyspy: 3.0.2 @@ -38915,7 +38840,7 @@ snapshots: react: 19.1.0 scheduler: 0.26.0 - react-email@2.1.2(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.15)(bufferutil@4.0.9)(eslint@8.31.0): + react-email@2.1.2(@opentelemetry/api@1.9.0)(@swc/helpers@0.5.15)(eslint@8.31.0): dependencies: '@babel/parser': 7.24.1 '@radix-ui/colors': 1.0.1 @@ -38952,8 +38877,8 @@ snapshots: react: 18.3.1 react-dom: 18.2.0(react@18.3.1) shelljs: 0.8.5 - socket.io: 4.7.3(bufferutil@4.0.9) - socket.io-client: 4.7.3(bufferutil@4.0.9) + socket.io: 4.7.3 + socket.io-client: 4.7.3 sonner: 1.3.1(react-dom@18.2.0(react@18.3.1))(react@18.3.1) source-map-js: 1.0.2 stacktrace-parser: 0.1.10 @@ -40078,7 +40003,7 @@ snapshots: - supports-color - utf-8-validate - socket.io-client@4.7.3(bufferutil@4.0.9): + socket.io-client@4.7.3: dependencies: '@socket.io/component-emitter': 3.1.0 debug: 4.3.7(supports-color@10.0.0) @@ -40107,7 +40032,7 @@ snapshots: transitivePeerDependencies: - supports-color - socket.io@4.7.3(bufferutil@4.0.9): + socket.io@4.7.3: dependencies: accepts: 1.3.8 base64id: 2.0.0 @@ -41667,13 +41592,13 @@ snapshots: - supports-color - terser - vite-node@2.1.9(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1): + vite-node@3.1.4(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1): dependencies: cac: 6.7.14 debug: 4.4.1(supports-color@10.0.0) es-module-lexer: 1.7.0 - pathe: 1.1.2 - vite: 5.4.21(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1) + pathe: 2.0.3 + vite: 5.4.21(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1) transitivePeerDependencies: - '@types/node' - less @@ -41685,13 +41610,13 @@ snapshots: - supports-color - terser - vite-node@3.1.4(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1): + vite-node@3.1.4(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1): dependencies: cac: 6.7.14 debug: 4.4.1(supports-color@10.0.0) es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 5.4.21(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1) + vite: 5.4.21(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1) transitivePeerDependencies: - '@types/node' - less @@ -41754,30 +41679,32 @@ snapshots: lightningcss: 1.29.2 terser: 5.44.1 - vitest@2.1.9(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1): + vitest@3.1.4(@types/debug@4.1.12)(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1): dependencies: - '@vitest/expect': 2.1.9 - '@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1)) - '@vitest/pretty-format': 2.1.9 - '@vitest/runner': 2.1.9 - '@vitest/snapshot': 2.1.9 - '@vitest/spy': 2.1.9 - '@vitest/utils': 2.1.9 + '@vitest/expect': 3.1.4 + '@vitest/mocker': 3.1.4(vite@5.4.21(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1)) + '@vitest/pretty-format': 3.1.4 + '@vitest/runner': 3.1.4 + '@vitest/snapshot': 3.1.4 + '@vitest/spy': 3.1.4 + '@vitest/utils': 3.1.4 chai: 5.2.0 - debug: 4.4.1(supports-color@10.0.0) + debug: 4.4.0 expect-type: 1.2.1 - magic-string: 0.30.21 - pathe: 1.1.2 + magic-string: 0.30.17 + pathe: 2.0.3 std-env: 3.9.0 tinybench: 2.9.0 tinyexec: 0.3.2 + tinyglobby: 0.2.13 tinypool: 1.0.2 - tinyrainbow: 1.2.0 - vite: 5.4.21(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1) - vite-node: 2.1.9(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1) + tinyrainbow: 2.0.0 + vite: 5.4.21(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1) + vite-node: 3.1.4(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.13.9 + '@types/debug': 4.1.12 + '@types/node': 20.14.14 transitivePeerDependencies: - less - lightningcss @@ -41789,7 +41716,7 @@ snapshots: - supports-color - terser - vitest@3.1.4(@types/debug@4.1.12)(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1): + vitest@3.1.4(@types/debug@4.1.12)(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1): dependencies: '@vitest/expect': 3.1.4 '@vitest/mocker': 3.1.4(vite@5.4.21(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1)) @@ -41809,12 +41736,12 @@ snapshots: tinyglobby: 0.2.13 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 5.4.21(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1) - vite-node: 3.1.4(@types/node@20.14.14)(lightningcss@1.29.2)(terser@5.44.1) + vite: 5.4.21(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1) + vite-node: 3.1.4(@types/node@22.13.9)(lightningcss@1.29.2)(terser@5.44.1) why-is-node-running: 2.3.0 optionalDependencies: '@types/debug': 4.1.12 - '@types/node': 20.14.14 + '@types/node': 22.13.9 transitivePeerDependencies: - less - lightningcss From 674f5c77b7d2bf2a837fa927695f8715eaa5caa3 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 9 Jan 2026 13:56:16 +0000 Subject: [PATCH 6/6] chore: add patch changeset for additionalFiles destination option Co-authored-by: Eric Allam --- .changeset/polite-lobsters-double.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/polite-lobsters-double.md diff --git a/.changeset/polite-lobsters-double.md b/.changeset/polite-lobsters-double.md new file mode 100644 index 0000000000..75f78dfea1 --- /dev/null +++ b/.changeset/polite-lobsters-double.md @@ -0,0 +1,7 @@ +--- +"@trigger.dev/build": patch +--- + +fix(build): add destination option to additionalFiles extension + +When using glob patterns with parent directory references (../), the default behavior strips ".." segments resulting in unexpected paths. This adds an optional "destination" parameter that allows users to explicitly specify where matched files should be placed, which is useful in monorepo setups where files need to maintain their structure.