@mastra/deployer 1.58.0-alpha.8 → 1.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/deployer",
3
- "version": "1.58.0-alpha.8",
3
+ "version": "1.58.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "files": [
@@ -113,7 +113,7 @@
113
113
  "typescript-paths": "^1.5.2",
114
114
  "ws": "^8.21.0",
115
115
  "yaml": "^2.9.0",
116
- "@mastra/server": "1.58.0-alpha.8"
116
+ "@mastra/server": "1.58.0"
117
117
  },
118
118
  "devDependencies": {
119
119
  "@hono/node-server": "^2.0.0",
@@ -133,13 +133,13 @@
133
133
  "typescript": "^6.0.3",
134
134
  "vitest": "4.1.10",
135
135
  "zod": "^4.4.3",
136
- "@internal/types-builder": "0.0.96",
137
- "@internal/lint": "0.0.121",
138
- "@mastra/agent-browser": "0.5.1-alpha.0",
139
- "@mastra/core": "1.58.0-alpha.8",
140
- "@mastra/mcp": "^1.16.0-alpha.1",
141
- "@mastra/server": "1.58.0-alpha.8",
142
- "@mastra/hono": "1.6.0-alpha.8"
136
+ "@internal/lint": "0.0.122",
137
+ "@internal/types-builder": "0.0.97",
138
+ "@mastra/hono": "1.6.0",
139
+ "@mastra/core": "1.58.0",
140
+ "@mastra/agent-browser": "0.5.1",
141
+ "@mastra/server": "1.58.0",
142
+ "@mastra/mcp": "^1.16.0"
143
143
  },
144
144
  "peerDependencies": {
145
145
  "@mastra/core": ">=1.50.0-0 <2.0.0-0"
@@ -1,12 +0,0 @@
1
- /**
2
- * Resolves the user's `bundler.entries` config into the absolute source paths the
3
- * bundler emits beside the server bundle.
4
- *
5
- * Names become output filenames (`<name>.mjs` via rollup's `entryFileNames`), so they
6
- * are rejected when they would collide with the server or tool bundles, or when they
7
- * would escape the output directory. Paths resolve relative to the Mastra directory —
8
- * the directory holding the entry file — so they read the same way as the imports
9
- * already in that file.
10
- */
11
- export declare function resolveExtraEntries(entries: Record<string, string> | undefined, mastraEntryFile: string): Record<string, string>;
12
- //# sourceMappingURL=entries.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"entries.d.ts","sourceRoot":"","sources":["../../src/bundler/entries.ts"],"names":[],"mappings":"AAyBA;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EAC3C,eAAe,EAAE,MAAM,GACtB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAyExB"}
@@ -1,565 +0,0 @@
1
- import { a as collectTransitiveWorkspaceDependencies, o as getWorkspaceInformation, s as packWorkspaceDependencies, t as analyzeBundle } from "./analyze-CNv6Qdaz.js";
2
- import { a as getPackageName, p as slash, s as isBareModuleSpecifier } from "./utils-FVOUvj-I.js";
3
- import { i as DepsService, t as FileService } from "./services-BRF1RRXB.js";
4
- import { n as getInputOptions, t as createBundler } from "./bundler-gff4vn1T.js";
5
- import { t as getBundlerOptions } from "./bundlerOptions-NMtZPD7p.js";
6
- import { execSync } from "child_process";
7
- import { existsSync, statSync } from "fs";
8
- import { readFile, rm, stat, writeFile } from "fs/promises";
9
- import { dirname, isAbsolute, join, posix, resolve } from "path";
10
- import { MastraBundler } from "@mastra/core/bundler";
11
- import { ErrorCategory, ErrorDomain, MastraError } from "@mastra/core/error";
12
- import virtual from "@rollup/plugin-virtual";
13
- import * as pkg from "empathic/package";
14
- import fsExtra, { copy, emptyDir, ensureDir, readJSON } from "fs-extra/esm";
15
- import { glob } from "tinyglobby";
16
- //#region src/bundler/entries.ts
17
- /** Reserved by the server bundle (`index.mjs`). */
18
- const SERVER_ENTRY_NAME = "index";
19
- /**
20
- * Reserved by the tool aggregator, which `_bundle` writes to `tools.mjs` with `writeFile`
21
- * *after* rollup finishes. Rollup deduplicates colliding chunk names, but that write
22
- * happens outside its control, so an entry named `tools` is silently overwritten.
23
- */
24
- const TOOLS_ENTRY_NAME = "tools";
25
- /** Reserved by tool bundles (`tools/<uuid>.mjs`), which the aggregator collects by prefix. */
26
- const TOOLS_ENTRY_PREFIX = "tools/";
27
- function invalidEntries(text) {
28
- return new MastraError({
29
- id: "DEPLOYER_BUNDLER_INVALID_ENTRIES",
30
- text,
31
- domain: ErrorDomain.DEPLOYER,
32
- category: ErrorCategory.USER
33
- });
34
- }
35
- /**
36
- * Resolves the user's `bundler.entries` config into the absolute source paths the
37
- * bundler emits beside the server bundle.
38
- *
39
- * Names become output filenames (`<name>.mjs` via rollup's `entryFileNames`), so they
40
- * are rejected when they would collide with the server or tool bundles, or when they
41
- * would escape the output directory. Paths resolve relative to the Mastra directory —
42
- * the directory holding the entry file — so they read the same way as the imports
43
- * already in that file.
44
- */
45
- function resolveExtraEntries(entries, mastraEntryFile) {
46
- if (!entries) return {};
47
- const mastraDir = dirname(mastraEntryFile);
48
- const resolved = /* @__PURE__ */ new Map();
49
- for (const [name, entryPath] of Object.entries(entries)) {
50
- if (!name || name !== name.trim()) throw invalidEntries(`bundler.entries has an empty or untrimmed entry name: ${JSON.stringify(name)}`);
51
- const normalizedName = slash(name);
52
- if (normalizedName === SERVER_ENTRY_NAME) throw invalidEntries(`bundler.entries cannot use the name "${SERVER_ENTRY_NAME}" — it is reserved for the Mastra server bundle.`);
53
- if (normalizedName === TOOLS_ENTRY_NAME || normalizedName.startsWith(TOOLS_ENTRY_PREFIX)) throw invalidEntries(`bundler.entries cannot use the name "${name}" — "${TOOLS_ENTRY_NAME}" and names starting with "${TOOLS_ENTRY_PREFIX}" are reserved for tool bundles.`);
54
- if (isAbsolute(name) || normalizedName.startsWith("/") || normalizedName.split("/").includes("..")) throw invalidEntries(`bundler.entries name "${name}" must be a relative name without ".." segments — it becomes a file inside the build output.`);
55
- if (resolved.has(normalizedName)) throw invalidEntries(`bundler.entries has two entries that resolve to the output name "${normalizedName}" (the second is "${name}"). Entry names must be unique once path separators are normalized.`);
56
- if (!entryPath) throw invalidEntries(`bundler.entries entry "${name}" has an empty path.`);
57
- const absolutePath = isAbsolute(entryPath) ? entryPath : resolve(mastraDir, entryPath);
58
- let entryStats;
59
- try {
60
- entryStats = statSync(absolutePath);
61
- } catch (error) {
62
- if (error.code === "ENOENT" || error.code === "ENOTDIR") throw invalidEntries(`bundler.entries entry "${name}" points at "${entryPath}", which does not exist (resolved to ${absolutePath}). Paths are resolved relative to your Mastra directory (${mastraDir}).`);
63
- throw error;
64
- }
65
- if (!entryStats.isFile()) throw invalidEntries(`bundler.entries entry "${name}" points at "${entryPath}", which is not a file (resolved to ${absolutePath}). Point it at the source file to bundle.`);
66
- resolved.set(normalizedName, slash(absolutePath));
67
- }
68
- return Object.fromEntries(resolved);
69
- }
70
- //#endregion
71
- //#region src/bundler/index.ts
72
- const IS_DEFAULT = Symbol("IS_DEFAULT");
73
- const NPM_ALIAS_PREFIX = "npm:";
74
- /** Characters a registry range or dist tag can contain. Protocols need `:`, git shorthand needs `/` or `#`. */
75
- const REGISTRY_SPEC_PATTERN = /^[A-Za-z0-9.+_^~><=*|!\s-]+$/;
76
- const PACKAGE_NAME_PATTERN = /^(?:@[A-Za-z0-9._-]+\/)?[A-Za-z0-9._-]+$/;
77
- const TARBALL_SUFFIX_PATTERN = /\.(?:tgz|tar\.gz|tar)$/i;
78
- /** npm reads a value starting like this as a path, whatever follows. A bare `~` is a semver range. */
79
- const FILE_SPEC_PREFIX_PATTERN = /^(?:\.|~[/\\]|[/\\]|[A-Za-z]:[/\\])/;
80
- /** A range admitting any published version: `*`, `x`, `>=0`, and any union containing one. */
81
- const UNBOUNDED_RANGE_PATTERN = /(?:^|\|\||\s)\s*(?:[*xX]|>=?\s*0(?:\.0)*(?:\.0)*)\s*(?:$|\|\|)/;
82
- const toStringRecord = (value) => {
83
- if (!value || typeof value !== "object" || Array.isArray(value)) return {};
84
- return Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === "string"));
85
- };
86
- /**
87
- * True when a specifier is something the isolated install in `.mastra/output` can resolve from the
88
- * registry: a semver range, a dist tag, a wildcard, or an npm alias whose target is a registry
89
- * package and range.
90
- *
91
- * This is an allowlist rather than a denylist of known protocols, so an unfamiliar protocol is
92
- * rejected without this code having to know it exists. The output directory is not a workspace, has
93
- * no catalog definitions and has a different relative-path base, so `catalog:`, `workspace:`,
94
- * `file:`, `link:` and git specifiers are all either uninstallable there or point somewhere else.
95
- */
96
- const isRegistryVersionSpec = (spec) => {
97
- if (FILE_SPEC_PREFIX_PATTERN.test(spec) || TARBALL_SUFFIX_PATTERN.test(spec)) return false;
98
- if (spec.startsWith(NPM_ALIAS_PREFIX)) {
99
- const alias = spec.slice(4);
100
- const rangeSeparator = alias.lastIndexOf("@");
101
- const name = rangeSeparator > 0 ? alias.slice(0, rangeSeparator) : alias;
102
- const range = rangeSeparator > 0 ? alias.slice(rangeSeparator + 1) : "*";
103
- return PACKAGE_NAME_PATTERN.test(name) && isRegistryVersionSpec(range);
104
- }
105
- return REGISTRY_SPEC_PATTERN.test(spec);
106
- };
107
- /**
108
- * True when a specifier names a version the output install can be held to.
109
- *
110
- * A range admitting anything (`*`, `latest`, `>=0`, an alias with no range) is looser than the
111
- * version already resolved, so writing it would let a later install pull something the bundle was
112
- * never analyzed against.
113
- */
114
- const isBoundedVersionSpec = (spec) => {
115
- const range = spec.startsWith(NPM_ALIAS_PREFIX) ? (() => {
116
- const alias = spec.slice(4);
117
- const rangeSeparator = alias.lastIndexOf("@");
118
- return rangeSeparator > 0 ? alias.slice(rangeSeparator + 1) : "";
119
- })() : spec;
120
- return /\d/.test(range) && !UNBOUNDED_RANGE_PATTERN.test(range);
121
- };
122
- const readManifest = async (manifestPath) => {
123
- if (!manifestPath) return;
124
- try {
125
- const manifest = await readJSON(manifestPath);
126
- return manifest && typeof manifest === "object" ? manifest : void 0;
127
- } catch {
128
- return;
129
- }
130
- };
131
- /** Collect the package names a manifest's resolution fields pin, ignoring their values. */
132
- const collectManifestPinnedNames = (manifest, pinned) => {
133
- const pnpmSection = manifest?.pnpm;
134
- const records = [
135
- manifest?.overrides,
136
- manifest?.resolutions,
137
- pnpmSection && typeof pnpmSection === "object" ? pnpmSection.overrides : void 0
138
- ];
139
- for (const record of records) if (record && typeof record === "object" && !Array.isArray(record)) for (const key of Object.keys(record)) pinned.add(key);
140
- };
141
- /**
142
- * Collect the names under a top-level `overrides:` block in `pnpm-workspace.yaml`.
143
- *
144
- * pnpm moved overrides out of `package.json` into this file, so a workspace on a current pnpm keeps
145
- * them only here. Reading names off the indented block avoids a YAML dependency, the same tradeoff
146
- * `copyPnpmWorkspaceSettings` already makes for the top-level keys it copies.
147
- */
148
- const collectPnpmWorkspacePinnedNames = (source, pinned) => {
149
- const lines = source.split(/\r?\n/);
150
- let insideOverrides = false;
151
- for (const line of lines) {
152
- if (/^\S/.test(line)) {
153
- insideOverrides = /^overrides:\s*$/.test(line);
154
- continue;
155
- }
156
- if (!insideOverrides) continue;
157
- const key = /^\s+(?:'([^']+)'|"([^"]+)"|([^'"\s:][^:]*?))\s*:/.exec(line);
158
- if (key) pinned.add((key[1] ?? key[2] ?? key[3] ?? "").trim());
159
- }
160
- };
161
- /**
162
- * Read the constraints the source app declared.
163
- *
164
- * `dependencies` come from the manifest at `projectRoot`, the package the build was invoked for and
165
- * whose directory receives the output, falling back to the manifest above the entry file. Anchoring
166
- * on `projectRoot` rather than the entry file keeps the answer deterministic when the entry handed
167
- * to the bundler is a generated wrapper rather than the app's own source file.
168
- *
169
- * Resolution-field names are collected from both that manifest and the workspace root, including the
170
- * root `pnpm-workspace.yaml`, because a name pinned anywhere means the resolved version may have been
171
- * chosen deliberately rather than hoisted by accident.
172
- */
173
- const getSourceDependencyConstraints = async ({ projectRoot, mastraEntryFile, workspaceRoot }) => {
174
- const manifestPaths = [pkg.up({ cwd: projectRoot }), pkg.up({ cwd: dirname(mastraEntryFile) })].filter((entry, index, entries) => !!entry && entries.indexOf(entry) === index);
175
- if (workspaceRoot) manifestPaths.push(join(workspaceRoot, "package.json"));
176
- const pinnedByResolutionField = /* @__PURE__ */ new Set();
177
- let dependencies;
178
- for (const manifestPath of manifestPaths) {
179
- const manifest = await readManifest(manifestPath);
180
- if (!manifest) continue;
181
- dependencies ??= toStringRecord(manifest.dependencies);
182
- collectManifestPinnedNames(manifest, pinnedByResolutionField);
183
- }
184
- if (workspaceRoot) try {
185
- collectPnpmWorkspacePinnedNames(await readFile(join(workspaceRoot, "pnpm-workspace.yaml"), "utf-8"), pinnedByResolutionField);
186
- } catch {}
187
- return {
188
- dependencies: dependencies ?? {},
189
- pinnedByResolutionField
190
- };
191
- };
192
- const findDeclaredConstraint = (constraints, dependencyName) => {
193
- const names = [dependencyName, getPackageName(dependencyName)].filter((name, index, all) => !!name && all.indexOf(name) === index);
194
- for (const name of names) if (constraints.pinnedByResolutionField.has(name)) return;
195
- for (const name of names) {
196
- const declared = (constraints.dependencies[name] ?? "").trim();
197
- if (declared && isBoundedVersionSpec(declared) && isRegistryVersionSpec(declared)) return declared;
198
- }
199
- };
200
- /**
201
- * Prefer the constraint the app declared over the version resolved from `node_modules`.
202
- *
203
- * The resolved version is whatever the install happened to hoist, so an app declaring `zod: ^4.3.6`
204
- * next to a hoisted `zod@3.25.76` gets the hoisted version written into the output manifest and the
205
- * isolated install then locks it in.
206
- */
207
- const applySourceDependencyRange = (dependencyName, dependencyInfo, constraints) => {
208
- const declared = findDeclaredConstraint(constraints, dependencyName);
209
- if (!declared) return dependencyInfo;
210
- if (declared.startsWith(NPM_ALIAS_PREFIX)) return {
211
- ...dependencyInfo,
212
- packageSpec: declared
213
- };
214
- if (dependencyInfo.packageSpec) return dependencyInfo;
215
- return {
216
- ...dependencyInfo,
217
- version: declared
218
- };
219
- };
220
- var Bundler = class extends MastraBundler {
221
- analyzeOutputDir = ".build";
222
- outputDir = "output";
223
- platform = "node";
224
- constructor(name, component = "BUNDLER") {
225
- super({
226
- name,
227
- component
228
- });
229
- }
230
- async prepare(outputDirectory) {
231
- await emptyDir(outputDirectory);
232
- await ensureDir(join(outputDirectory, this.analyzeOutputDir));
233
- await ensureDir(join(outputDirectory, this.outputDir));
234
- }
235
- async writePackageJson(outputDirectory, dependencies, resolutions) {
236
- this.logger.debug("Writing project's package.json");
237
- await ensureDir(outputDirectory);
238
- const pkgPath = join(outputDirectory, "package.json");
239
- const dependenciesMap = /* @__PURE__ */ new Map();
240
- for (const [key, value] of dependencies.entries()) {
241
- const dependencyValue = typeof value === "string" ? value : value.packageSpec ?? value.version ?? "latest";
242
- if (key.startsWith("@")) {
243
- const pkgChunks = key.split("/");
244
- dependenciesMap.set(`${pkgChunks[0]}/${pkgChunks[1]}`, dependencyValue);
245
- } else {
246
- const pkgName = key.split("/")[0] || key;
247
- dependenciesMap.set(pkgName, dependencyValue);
248
- }
249
- }
250
- await writeFile(pkgPath, JSON.stringify({
251
- name: "server",
252
- version: "1.0.0",
253
- private: true,
254
- type: "module",
255
- main: "index.mjs",
256
- scripts: { start: "node ./index.mjs" },
257
- dependencies: Object.fromEntries(dependenciesMap.entries()),
258
- ...Object.keys(resolutions ?? {}).length > 0 && { resolutions }
259
- }, null, 2));
260
- }
261
- createBundler(inputOptions, outputOptions) {
262
- return createBundler(inputOptions, outputOptions);
263
- }
264
- async getUserBundlerOptions(mastraEntryFile, outputDirectory) {
265
- const defaultBundlerOptions = {
266
- externals: [],
267
- sourcemap: false,
268
- transpilePackages: [],
269
- [IS_DEFAULT]: true
270
- };
271
- try {
272
- return await getBundlerOptions(mastraEntryFile, outputDirectory) ?? defaultBundlerOptions;
273
- } catch (error) {
274
- this.logger.debug("Failed to get bundler options, sourcemap will be disabled", { error });
275
- }
276
- return defaultBundlerOptions;
277
- }
278
- async analyze(entry, mastraFile, outputDirectory) {
279
- return await analyzeBundle([].concat(entry), mastraFile, {
280
- outputDir: join(outputDirectory, this.analyzeOutputDir),
281
- projectRoot: outputDirectory,
282
- platform: this.platform
283
- }, this.logger);
284
- }
285
- pnpmNodeLinker;
286
- async installDependencies(outputDirectory, rootDir = process.cwd(), pnpmOverrides) {
287
- const deps = new DepsService(rootDir);
288
- deps.__setLogger(this.logger);
289
- await deps.install({
290
- dir: join(outputDirectory, this.outputDir),
291
- pnpmOverrides,
292
- pnpmNodeLinker: this.pnpmNodeLinker
293
- });
294
- }
295
- /**
296
- * Generate a package-lock.json for the output directory so that deploy targets
297
- * can use `npm ci` instead of `npm install`, skipping version resolution entirely.
298
- * This is a lockfile-only operation — no packages are downloaded.
299
- *
300
- * Temporarily moves node_modules out of the way because pnpm's symlink-based
301
- * layout confuses npm's arborist, then restores it afterwards so that
302
- * `mastra start` (or wrangler) can still resolve dependencies at runtime.
303
- */
304
- async generateNpmLockfile(outputDir) {
305
- const nodeModules = join(outputDir, "node_modules");
306
- const nodeModulesTmp = join(outputDir, "node_modules.__tmp");
307
- let movedNodeModules = false;
308
- try {
309
- if (await fsExtra.pathExists(nodeModules)) {
310
- await fsExtra.move(nodeModules, nodeModulesTmp, { overwrite: true });
311
- movedNodeModules = true;
312
- }
313
- execSync("npm install --package-lock-only --force", {
314
- cwd: outputDir,
315
- stdio: "pipe",
316
- timeout: 6e4
317
- });
318
- } catch {
319
- this.logger.warn("Failed to generate package-lock.json — deploy will fall back to npm install");
320
- } finally {
321
- if (movedNodeModules) {
322
- await rm(nodeModules, {
323
- recursive: true,
324
- force: true
325
- });
326
- await fsExtra.move(nodeModulesTmp, nodeModules, { overwrite: true });
327
- }
328
- }
329
- }
330
- async copyPublic(mastraDir, outputDirectory) {
331
- const publicDir = join(mastraDir, "public");
332
- try {
333
- await stat(publicDir);
334
- } catch {
335
- return;
336
- }
337
- await copy(publicDir, join(outputDirectory, this.outputDir));
338
- }
339
- async copyDOTNPMRC({ rootDir = process.cwd(), outputDirectory }) {
340
- const sourceDotNpmRcPath = join(rootDir, ".npmrc");
341
- const targetDotNpmRcPath = join(outputDirectory, this.outputDir, ".npmrc");
342
- try {
343
- await stat(sourceDotNpmRcPath);
344
- await copy(sourceDotNpmRcPath, targetDotNpmRcPath);
345
- } catch {
346
- return;
347
- }
348
- }
349
- /**
350
- * Writes the `mastra-project.json` deployment marker for Software Factory
351
- * projects after public assets have been copied. Verifies that the Factory
352
- * SPA (`factory/index.html`) exists in the output before emitting the marker.
353
- */
354
- async writeFactoryMarker(outputDirectory) {
355
- const outputDir = join(outputDirectory, this.outputDir);
356
- if (!existsSync(join(outputDir, "factory", "index.html"))) throw new MastraError({
357
- id: "DEPLOYER_BUNDLER_FACTORY_UI_MISSING",
358
- text: "Software Factory project detected but factory/index.html was not found after copying the prebuilt Factory UI.",
359
- domain: ErrorDomain.DEPLOYER,
360
- category: ErrorCategory.SYSTEM
361
- });
362
- await writeFile(join(outputDir, "mastra-project.json"), JSON.stringify({
363
- schemaVersion: 1,
364
- projectType: "factory",
365
- assets: { ui: "factory" }
366
- }, null, 2));
367
- this.logger.info("Wrote mastra-project.json for Software Factory project");
368
- }
369
- async getBundlerOptions(serverFile, mastraEntryFile, analyzedBundleInfo, toolsPaths, { enableSourcemap, enableMinify, enableEsmShim, externals, entries }) {
370
- const { workspaceRoot } = await getWorkspaceInformation({ mastraEntryFile });
371
- const closestPkgJson = pkg.up({ cwd: dirname(mastraEntryFile) });
372
- const projectRoot = closestPkgJson ? dirname(closestPkgJson) : process.cwd();
373
- const inputOptions = await getInputOptions(mastraEntryFile, analyzedBundleInfo, this.platform, { "process.env.NODE_ENV": JSON.stringify("production") }, {
374
- sourcemap: enableSourcemap,
375
- minify: enableMinify,
376
- workspaceRoot,
377
- projectRoot,
378
- enableEsmShim,
379
- externalsPreset: externals === true
380
- });
381
- const isVirtual = serverFile.includes("\n") || !existsSync(serverFile);
382
- const toolsInputOptions = await this.listToolsInputOptions(toolsPaths);
383
- const extraEntries = entries ?? {};
384
- if (isVirtual) {
385
- inputOptions.input = {
386
- index: "#entry",
387
- ...extraEntries,
388
- ...toolsInputOptions
389
- };
390
- if (Array.isArray(inputOptions.plugins)) inputOptions.plugins.unshift(virtual({ "#entry": serverFile }));
391
- else inputOptions.plugins = [virtual({ "#entry": serverFile })];
392
- } else inputOptions.input = {
393
- index: serverFile,
394
- ...extraEntries,
395
- ...toolsInputOptions
396
- };
397
- return inputOptions;
398
- }
399
- getAllToolPaths(mastraDir, toolsPaths = []) {
400
- const normalizedMastraDir = slash(mastraDir);
401
- const defaultPaths = [posix.join(normalizedMastraDir, "tools/**/*.{js,ts}"), ...[`!${posix.join(normalizedMastraDir, "tools/**/*.{test,spec}.{js,ts}")}`, `!${posix.join(normalizedMastraDir, "tools/**/__tests__/**")}`]];
402
- if (toolsPaths.length === 0) return [defaultPaths];
403
- return [...toolsPaths, defaultPaths];
404
- }
405
- async listToolsInputOptions(toolsPaths) {
406
- const inputs = {};
407
- for (const toolPath of toolsPaths) {
408
- const expandedPaths = await glob(toolPath, {
409
- absolute: true,
410
- expandDirectories: false
411
- });
412
- for (const path of expandedPaths) if (await fsExtra.pathExists(path)) {
413
- const entryFile = new FileService().getFirstExistingFile([
414
- join(path, "index.ts"),
415
- join(path, "index.js"),
416
- path
417
- ]);
418
- if (!entryFile || (await stat(entryFile)).isDirectory()) {
419
- this.logger.warn("No entry file found, skipping", { path });
420
- continue;
421
- }
422
- const uniqueToolID = crypto.randomUUID();
423
- const normalizedEntryFile = entryFile.replaceAll("\\", "/");
424
- inputs[`tools/${uniqueToolID}`] = normalizedEntryFile;
425
- } else this.logger.warn("Tool path does not exist, skipping", { path });
426
- }
427
- return inputs;
428
- }
429
- async _bundle(serverFile, mastraEntryFile, { projectRoot, outputDirectory, enableEsmShim = true }, toolsPaths = [], bundleLocation = join(outputDirectory, this.outputDir)) {
430
- const analyzeDir = join(outputDirectory, this.analyzeOutputDir);
431
- const bundlerOptions = await this.getUserBundlerOptions(mastraEntryFile, outputDirectory);
432
- const extraEntries = resolveExtraEntries(bundlerOptions.entries, mastraEntryFile);
433
- const internalBundlerOptions = {
434
- enableSourcemap: !!bundlerOptions.sourcemap,
435
- enableMinify: !!bundlerOptions.minify,
436
- externals: bundlerOptions.externals ?? [],
437
- enableEsmShim,
438
- dynamicPackages: bundlerOptions.dynamicPackages,
439
- entries: extraEntries
440
- };
441
- if (Object.keys(extraEntries).length > 0) this.logger.info("Found additional entries", { entries: Object.keys(extraEntries) });
442
- let analyzedBundleInfo;
443
- try {
444
- const resolvedToolsPaths = await this.listToolsInputOptions(toolsPaths);
445
- analyzedBundleInfo = await analyzeBundle([
446
- serverFile,
447
- ...Object.values(extraEntries),
448
- ...Object.values(resolvedToolsPaths)
449
- ], mastraEntryFile, {
450
- outputDir: analyzeDir,
451
- projectRoot,
452
- platform: this.platform,
453
- bundlerOptions: internalBundlerOptions
454
- }, this.logger);
455
- } catch (error) {
456
- const message = error instanceof Error ? error.message : String(error);
457
- if (error instanceof MastraError) throw error;
458
- throw new MastraError({
459
- id: "DEPLOYER_BUNDLER_ANALYZE_FAILED",
460
- text: `Failed to analyze Mastra application: ${message}`,
461
- domain: ErrorDomain.DEPLOYER,
462
- category: ErrorCategory.SYSTEM
463
- }, error);
464
- }
465
- const { workspaceRoot } = await getWorkspaceInformation({
466
- dir: projectRoot,
467
- mastraEntryFile
468
- });
469
- const sourceDependencyConstraints = await getSourceDependencyConstraints({
470
- projectRoot,
471
- mastraEntryFile,
472
- workspaceRoot
473
- });
474
- const dependenciesToInstall = /* @__PURE__ */ new Map();
475
- for (const [dep, depInfo] of analyzedBundleInfo.externalDependencies) {
476
- if (analyzedBundleInfo.workspaceMap.has(dep) || !isBareModuleSpecifier(dep)) continue;
477
- dependenciesToInstall.set(dep, applySourceDependencyRange(dep, depInfo, sourceDependencyConstraints));
478
- }
479
- const initialWorkspaceDependencies = /* @__PURE__ */ new Set();
480
- for (const dep of analyzedBundleInfo.dependencies.keys()) {
481
- const pkgName = getPackageName(dep);
482
- if (pkgName && analyzedBundleInfo.workspaceMap.has(pkgName)) initialWorkspaceDependencies.add(pkgName);
483
- }
484
- const transitiveWorkspaceDependencies = collectTransitiveWorkspaceDependencies({
485
- workspaceMap: analyzedBundleInfo.workspaceMap,
486
- initialDependencies: initialWorkspaceDependencies,
487
- logger: this.logger
488
- });
489
- for (const [dep, packageSpec] of Object.entries(transitiveWorkspaceDependencies.resolutions)) dependenciesToInstall.set(dep, {
490
- version: analyzedBundleInfo.workspaceMap.get(dep)?.version,
491
- packageSpec
492
- });
493
- try {
494
- await this.writePackageJson(join(outputDirectory, this.outputDir), dependenciesToInstall, transitiveWorkspaceDependencies.resolutions);
495
- if (transitiveWorkspaceDependencies.usedWorkspacePackages.size > 0) await packWorkspaceDependencies({
496
- workspaceMap: analyzedBundleInfo.workspaceMap,
497
- usedWorkspacePackages: transitiveWorkspaceDependencies.usedWorkspacePackages,
498
- bundleOutputDir: join(outputDirectory, this.outputDir),
499
- logger: this.logger
500
- });
501
- this.logger.info("Bundling Mastra application");
502
- const inputOptions = await this.getBundlerOptions(serverFile, mastraEntryFile, analyzedBundleInfo, toolsPaths, internalBundlerOptions);
503
- await (await this.createBundler({
504
- ...inputOptions,
505
- logLevel: inputOptions.logLevel === "silent" ? "warn" : inputOptions.logLevel,
506
- onwarn: (warning) => {
507
- if (warning.code === "CIRCULAR_DEPENDENCY") {
508
- if (warning.ids?.[0]?.includes("node_modules")) return;
509
- this.logger.warn("Circular dependency found", { dependency: warning.message.replace("Circular dependency: ", "") });
510
- }
511
- }
512
- }, {
513
- dir: bundleLocation,
514
- manualChunks: { mastra: ["#mastra"] },
515
- sourcemap: internalBundlerOptions.enableSourcemap
516
- })).write();
517
- const toolImports = [];
518
- const toolsExports = [];
519
- Array.from(Object.keys(inputOptions.input || {})).filter((key) => key.startsWith("tools/")).forEach((key, index) => {
520
- const toolExport = `tool${index}`;
521
- toolImports.push(`import * as ${toolExport} from './${key}.mjs';`);
522
- toolsExports.push(toolExport);
523
- });
524
- await writeFile(join(bundleLocation, "tools.mjs"), `${toolImports.join("\n")}
525
-
526
- export const tools = [${toolsExports.join(", ")}]`);
527
- this.logger.info("Bundling Mastra done");
528
- this.logger.info("Copying public files");
529
- await this.copyPublic(dirname(mastraEntryFile), outputDirectory);
530
- this.logger.info("Done copying public files");
531
- if (analyzedBundleInfo.projectType === "factory") await this.writeFactoryMarker(outputDirectory);
532
- this.logger.info("Copying .npmrc file");
533
- await this.copyDOTNPMRC({
534
- outputDirectory,
535
- rootDir: projectRoot
536
- });
537
- this.logger.info("Done copying .npmrc file");
538
- this.logger.info("Installing dependencies");
539
- await this.installDependencies(outputDirectory, projectRoot, transitiveWorkspaceDependencies.resolutions);
540
- this.logger.info("Done installing dependencies");
541
- if (Object.keys(transitiveWorkspaceDependencies.resolutions).length === 0) {
542
- this.logger.info("Generating package-lock.json for deploy");
543
- await this.generateNpmLockfile(join(outputDirectory, this.outputDir));
544
- this.logger.info("Done generating package-lock.json");
545
- } else this.logger.warn("Skipping package-lock.json generation because the output contains packed workspace dependencies");
546
- } catch (error) {
547
- if (error instanceof MastraError && error.id === "DEPLOYER_BUNDLER_FACTORY_UI_MISSING") throw error;
548
- throw new MastraError({
549
- id: "DEPLOYER_BUNDLER_BUNDLE_STAGE_FAILED",
550
- text: `Failed during bundler bundle stage: ${error instanceof Error ? error.message : String(error)}`,
551
- domain: ErrorDomain.DEPLOYER,
552
- category: ErrorCategory.SYSTEM
553
- }, error);
554
- }
555
- }
556
- async lint(_entryFile, _outputDirectory, toolsPaths) {
557
- const toolsInputOptions = await this.listToolsInputOptions(toolsPaths);
558
- const toolsLength = Object.keys(toolsInputOptions).length;
559
- if (toolsLength > 0) this.logger.info("Found tools", { count: toolsLength });
560
- }
561
- };
562
- //#endregion
563
- export { isRegistryVersionSpec as a, getSourceDependencyConstraints as i, IS_DEFAULT as n, applySourceDependencyRange as r, Bundler as t };
564
-
565
- //# sourceMappingURL=bundler-Ct1ToG6x.js.map