@mastra/deployer 0.10.13 → 0.10.15-alpha.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.
Files changed (56) hide show
  1. package/dist/_tsup-dts-rollup.d.cts +844 -0
  2. package/dist/_tsup-dts-rollup.d.ts +844 -0
  3. package/dist/build/analyze.cjs +10 -0
  4. package/dist/build/analyze.d.cts +1 -0
  5. package/dist/build/analyze.d.ts +1 -0
  6. package/dist/build/analyze.js +1 -0
  7. package/dist/build/bundler.cjs +14 -0
  8. package/dist/build/bundler.d.cts +2 -0
  9. package/dist/build/bundler.d.ts +2 -0
  10. package/dist/build/bundler.js +1 -0
  11. package/dist/build/index.cjs +50 -0
  12. package/dist/build/index.d.cts +10 -0
  13. package/dist/build/index.d.ts +10 -0
  14. package/dist/build/index.js +5 -0
  15. package/dist/bundler/index.cjs +10 -0
  16. package/dist/bundler/index.d.cts +1 -0
  17. package/dist/bundler/index.d.ts +1 -0
  18. package/dist/bundler/index.js +1 -0
  19. package/dist/chunk-54KOF3NB.cjs +137 -0
  20. package/dist/chunk-6QMONK4A.cjs +2 -0
  21. package/dist/chunk-C4JT7CIH.js +1 -0
  22. package/dist/chunk-D2DCFCLH.cjs +157 -0
  23. package/dist/chunk-D6736SJL.js +209 -0
  24. package/dist/chunk-ENT5RDOI.js +99 -0
  25. package/dist/chunk-FK2WUSEN.cjs +238 -0
  26. package/dist/chunk-GPD54HBC.js +380 -0
  27. package/dist/chunk-HJGC75ZR.js +490 -0
  28. package/dist/chunk-KCP5ITLV.cjs +412 -0
  29. package/dist/chunk-M2VZQFTW.cjs +125 -0
  30. package/dist/chunk-TIC2KT3M.js +146 -0
  31. package/dist/chunk-UYQZMNZL.js +572 -0
  32. package/dist/chunk-XKH6F4NE.cjs +604 -0
  33. package/dist/chunk-YFMAWUII.cjs +502 -0
  34. package/dist/chunk-Z544XXXK.js +111 -0
  35. package/dist/index.cjs +194 -0
  36. package/dist/index.d.cts +8 -0
  37. package/dist/index.d.ts +8 -0
  38. package/dist/index.js +153 -0
  39. package/dist/server/index.cjs +8446 -0
  40. package/dist/server/index.d.cts +2 -0
  41. package/dist/server/index.d.ts +2 -0
  42. package/dist/server/index.js +8438 -0
  43. package/dist/services/index.cjs +18 -0
  44. package/dist/services/index.d.cts +3 -0
  45. package/dist/services/index.d.ts +3 -0
  46. package/dist/services/index.js +1 -0
  47. package/dist/templates/instrumentation-template.js +137 -0
  48. package/dist/validator/custom-resolver.cjs +52 -0
  49. package/dist/validator/custom-resolver.d.cts +1 -0
  50. package/dist/validator/custom-resolver.d.ts +1 -0
  51. package/dist/validator/custom-resolver.js +50 -0
  52. package/dist/validator/loader.cjs +7 -0
  53. package/dist/validator/loader.d.cts +1 -0
  54. package/dist/validator/loader.d.ts +1 -0
  55. package/dist/validator/loader.js +4 -0
  56. package/package.json +5 -5
@@ -0,0 +1,490 @@
1
+ import { writeTelemetryConfig } from './chunk-ENT5RDOI.js';
2
+ import { analyzeBundle } from './chunk-UYQZMNZL.js';
3
+ import { createBundler, getInputOptions } from './chunk-TIC2KT3M.js';
4
+ import { DepsService, FileService } from './chunk-GPD54HBC.js';
5
+ import { existsSync } from 'fs';
6
+ import { writeFile, stat } from 'fs/promises';
7
+ import { join, dirname } from 'path';
8
+ import { fileURLToPath } from 'url';
9
+ import { MastraBundler } from '@mastra/core/bundler';
10
+ import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
11
+ import virtual from '@rollup/plugin-virtual';
12
+ import fsExtra, { emptyDir, ensureDir, copy, readJSON } from 'fs-extra/esm';
13
+ import { globby } from 'globby';
14
+ import resolveFrom from 'resolve-from';
15
+ import { rollup } from 'rollup';
16
+ import esbuild from 'rollup-plugin-esbuild';
17
+ import commonjs from '@rollup/plugin-commonjs';
18
+ import slugify from '@sindresorhus/slugify';
19
+ import { findWorkspaces, findWorkspacesRoot } from 'find-workspaces';
20
+ import { ensureDir as ensureDir$1 } from 'fs-extra';
21
+
22
+ function getCustomInstrumentationBundler(entryFile, result) {
23
+ return rollup({
24
+ logLevel: "silent",
25
+ input: {
26
+ instrumentation: entryFile
27
+ },
28
+ treeshake: false,
29
+ plugins: [
30
+ // transpile typescript to something we understand
31
+ esbuild({
32
+ target: "node20",
33
+ platform: "node",
34
+ minify: false
35
+ }),
36
+ commonjs({
37
+ extensions: [".js", ".ts"],
38
+ strictRequires: "strict",
39
+ transformMixedEsModules: true,
40
+ ignoreTryCatch: false
41
+ })
42
+ ]
43
+ });
44
+ }
45
+ async function writeCustomInstrumentation(entryFile, outputDir) {
46
+ const result = {
47
+ hasCustomConfig: false
48
+ };
49
+ const bundle = await getCustomInstrumentationBundler(entryFile);
50
+ const { output } = await bundle.write({
51
+ dir: outputDir,
52
+ format: "es",
53
+ entryFileNames: "[name].mjs"
54
+ });
55
+ const externals = output[0].imports.filter((x) => !x.startsWith("./"));
56
+ return { ...result, externalDependencies: externals };
57
+ }
58
+ var createWorkspacePackageMap = async () => {
59
+ const workspaces = await findWorkspaces();
60
+ const workspaceMap = new Map(
61
+ workspaces?.map((workspace) => [
62
+ workspace.package.name,
63
+ {
64
+ location: workspace.location,
65
+ dependencies: workspace.package.dependencies,
66
+ version: workspace.package.version
67
+ }
68
+ ]) ?? []
69
+ );
70
+ return workspaceMap;
71
+ };
72
+ var collectTransitiveWorkspaceDependencies = ({
73
+ workspaceMap,
74
+ initialDependencies,
75
+ logger
76
+ }) => {
77
+ const usedWorkspacePackages = /* @__PURE__ */ new Set();
78
+ const queue = Array.from(initialDependencies);
79
+ const resolutions = {};
80
+ while (queue.length > 0) {
81
+ const len = queue.length;
82
+ for (let i = 0; i < len; i += 1) {
83
+ const pkgName = queue.shift();
84
+ if (!pkgName || usedWorkspacePackages.has(pkgName)) {
85
+ continue;
86
+ }
87
+ const dep = workspaceMap.get(pkgName);
88
+ if (!dep) continue;
89
+ const root = findWorkspacesRoot();
90
+ if (!root) {
91
+ throw new Error("Could not find workspace root");
92
+ }
93
+ const depsService = new DepsService(root.location);
94
+ depsService.__setLogger(logger);
95
+ const sanitizedName = slugify(pkgName);
96
+ const tgzPath = depsService.getWorkspaceDependencyPath({
97
+ pkgName: sanitizedName,
98
+ version: dep.version
99
+ });
100
+ resolutions[pkgName] = tgzPath;
101
+ usedWorkspacePackages.add(pkgName);
102
+ for (const [depName, _depVersion] of Object.entries(dep?.dependencies ?? {})) {
103
+ if (!usedWorkspacePackages.has(depName) && workspaceMap.has(depName)) {
104
+ queue.push(depName);
105
+ }
106
+ }
107
+ }
108
+ }
109
+ return { resolutions, usedWorkspacePackages };
110
+ };
111
+ var packWorkspaceDependencies = async ({
112
+ workspaceMap,
113
+ usedWorkspacePackages,
114
+ bundleOutputDir,
115
+ logger
116
+ }) => {
117
+ const root = findWorkspacesRoot();
118
+ if (!root) {
119
+ throw new Error("Could not find workspace root");
120
+ }
121
+ const depsService = new DepsService(root.location);
122
+ depsService.__setLogger(logger);
123
+ if (usedWorkspacePackages.size > 0) {
124
+ const workspaceDirPath = join(bundleOutputDir, "workspace-module");
125
+ await ensureDir$1(workspaceDirPath);
126
+ logger.info(`Packaging ${usedWorkspacePackages.size} workspace dependencies...`);
127
+ const batchSize = 5;
128
+ const packages = Array.from(usedWorkspacePackages.values());
129
+ for (let i = 0; i < packages.length; i += batchSize) {
130
+ const batch = packages.slice(i, i + batchSize);
131
+ logger.info(
132
+ `Packaging batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(packages.length / batchSize)}: ${batch.join(", ")}`
133
+ );
134
+ await Promise.all(
135
+ batch.map(async (pkgName) => {
136
+ const dep = workspaceMap.get(pkgName);
137
+ if (!dep) return;
138
+ await depsService.pack({ dir: dep.location, destination: workspaceDirPath });
139
+ })
140
+ );
141
+ }
142
+ logger.info(`Successfully packaged ${usedWorkspacePackages.size} workspace dependencies`);
143
+ }
144
+ };
145
+
146
+ // src/bundler/index.ts
147
+ var Bundler = class extends MastraBundler {
148
+ analyzeOutputDir = ".build";
149
+ outputDir = "output";
150
+ constructor(name, component = "BUNDLER") {
151
+ super({ name, component });
152
+ }
153
+ async prepare(outputDirectory) {
154
+ await emptyDir(outputDirectory);
155
+ await ensureDir(join(outputDirectory, this.analyzeOutputDir));
156
+ await ensureDir(join(outputDirectory, this.outputDir));
157
+ }
158
+ async writeInstrumentationFile(outputDirectory, customInstrumentationFile) {
159
+ const instrumentationFile = join(outputDirectory, "instrumentation.mjs");
160
+ const __dirname = dirname(fileURLToPath(import.meta.url));
161
+ if (customInstrumentationFile) {
162
+ await copy(customInstrumentationFile, instrumentationFile);
163
+ } else {
164
+ await copy(join(__dirname, "templates", "instrumentation-template.js"), instrumentationFile);
165
+ }
166
+ }
167
+ async writePackageJson(outputDirectory, dependencies, resolutions) {
168
+ this.logger.debug(`Writing project's package.json`);
169
+ await ensureDir(outputDirectory);
170
+ const pkgPath = join(outputDirectory, "package.json");
171
+ const dependenciesMap = /* @__PURE__ */ new Map();
172
+ for (const [key, value] of dependencies.entries()) {
173
+ if (key.startsWith("@")) {
174
+ const pkgChunks = key.split("/");
175
+ dependenciesMap.set(`${pkgChunks[0]}/${pkgChunks[1]}`, value);
176
+ } else {
177
+ const pkgName = key.split("/")[0] || key;
178
+ dependenciesMap.set(pkgName, value);
179
+ }
180
+ }
181
+ dependenciesMap.set("@opentelemetry/core", "^2.0.1");
182
+ dependenciesMap.set("@opentelemetry/auto-instrumentations-node", "^0.59.0");
183
+ dependenciesMap.set("@opentelemetry/exporter-trace-otlp-grpc", "^0.201.0");
184
+ dependenciesMap.set("@opentelemetry/exporter-trace-otlp-http", "^0.201.0");
185
+ dependenciesMap.set("@opentelemetry/resources", "^2.0.1");
186
+ dependenciesMap.set("@opentelemetry/sdk-node", "^0.201.0");
187
+ dependenciesMap.set("@opentelemetry/sdk-trace-base", "^2.0.1");
188
+ dependenciesMap.set("@opentelemetry/semantic-conventions", "^1.33.0");
189
+ dependenciesMap.set("@opentelemetry/instrumentation", "^0.202.0");
190
+ await writeFile(
191
+ pkgPath,
192
+ JSON.stringify(
193
+ {
194
+ name: "server",
195
+ version: "1.0.0",
196
+ description: "",
197
+ type: "module",
198
+ main: "index.mjs",
199
+ scripts: {
200
+ start: "node --import=./instrumentation.mjs --import=@opentelemetry/instrumentation/hook.mjs ./index.mjs"
201
+ },
202
+ author: "Mastra",
203
+ license: "ISC",
204
+ dependencies: Object.fromEntries(dependenciesMap.entries()),
205
+ ...Object.keys(resolutions ?? {}).length > 0 && { resolutions },
206
+ pnpm: {
207
+ neverBuiltDependencies: []
208
+ }
209
+ },
210
+ null,
211
+ 2
212
+ )
213
+ );
214
+ }
215
+ createBundler(inputOptions, outputOptions) {
216
+ return createBundler(inputOptions, outputOptions);
217
+ }
218
+ async analyze(entry, mastraFile, outputDirectory) {
219
+ return await analyzeBundle(
220
+ [].concat(entry),
221
+ mastraFile,
222
+ join(outputDirectory, this.analyzeOutputDir),
223
+ "node",
224
+ this.logger
225
+ );
226
+ }
227
+ async installDependencies(outputDirectory, rootDir = process.cwd()) {
228
+ const deps = new DepsService(rootDir);
229
+ deps.__setLogger(this.logger);
230
+ await deps.install({ dir: join(outputDirectory, this.outputDir) });
231
+ }
232
+ async copyPublic(mastraDir, outputDirectory) {
233
+ const publicDir = join(mastraDir, "public");
234
+ try {
235
+ await stat(publicDir);
236
+ } catch {
237
+ return;
238
+ }
239
+ await copy(publicDir, join(outputDirectory, this.outputDir));
240
+ }
241
+ async copyDOTNPMRC({
242
+ rootDir = process.cwd(),
243
+ outputDirectory
244
+ }) {
245
+ const sourceDotNpmRcPath = join(rootDir, ".npmrc");
246
+ const targetDotNpmRcPath = join(outputDirectory, this.outputDir, ".npmrc");
247
+ try {
248
+ await stat(sourceDotNpmRcPath);
249
+ await copy(sourceDotNpmRcPath, targetDotNpmRcPath);
250
+ } catch {
251
+ return;
252
+ }
253
+ }
254
+ async getBundlerOptions(serverFile, mastraEntryFile, analyzedBundleInfo, toolsPaths) {
255
+ const inputOptions = await getInputOptions(mastraEntryFile, analyzedBundleInfo, "node", {
256
+ "process.env.NODE_ENV": JSON.stringify("production")
257
+ });
258
+ const isVirtual = serverFile.includes("\n") || existsSync(serverFile);
259
+ const toolsInputOptions = await this.getToolsInputOptions(toolsPaths);
260
+ if (isVirtual) {
261
+ inputOptions.input = { index: "#entry", ...toolsInputOptions };
262
+ if (Array.isArray(inputOptions.plugins)) {
263
+ inputOptions.plugins.unshift(virtual({ "#entry": serverFile }));
264
+ } else {
265
+ inputOptions.plugins = [virtual({ "#entry": serverFile })];
266
+ }
267
+ } else {
268
+ inputOptions.input = { index: serverFile, ...toolsInputOptions };
269
+ }
270
+ return inputOptions;
271
+ }
272
+ async getToolsInputOptions(toolsPaths) {
273
+ const inputs = {};
274
+ for (const toolPath of toolsPaths) {
275
+ const expandedPaths = await globby(toolPath, {});
276
+ for (const path of expandedPaths) {
277
+ if (await fsExtra.pathExists(path)) {
278
+ const fileService = new FileService();
279
+ const entryFile = fileService.getFirstExistingFile([
280
+ join(path, "index.ts"),
281
+ join(path, "index.js"),
282
+ path
283
+ // if path itself is a file
284
+ ]);
285
+ if (!entryFile || (await stat(entryFile)).isDirectory()) {
286
+ this.logger.warn(`No entry file found in ${path}, skipping...`);
287
+ continue;
288
+ }
289
+ const uniqueToolID = crypto.randomUUID();
290
+ inputs[`tools/${uniqueToolID}`] = entryFile;
291
+ } else {
292
+ this.logger.warn(`Tool path ${path} does not exist, skipping...`);
293
+ }
294
+ }
295
+ }
296
+ return inputs;
297
+ }
298
+ async _bundle(serverFile, mastraEntryFile, outputDirectory, toolsPaths = [], bundleLocation = join(outputDirectory, this.outputDir)) {
299
+ this.logger.info("Start bundling Mastra");
300
+ let analyzedBundleInfo;
301
+ try {
302
+ const resolvedToolsPaths = await this.getToolsInputOptions(toolsPaths);
303
+ analyzedBundleInfo = await analyzeBundle(
304
+ [serverFile, ...Object.values(resolvedToolsPaths)],
305
+ mastraEntryFile,
306
+ join(outputDirectory, this.analyzeOutputDir),
307
+ "node",
308
+ this.logger
309
+ );
310
+ } catch (error) {
311
+ const message = error instanceof Error ? error.message : String(error);
312
+ throw new MastraError(
313
+ {
314
+ id: "DEPLOYER_BUNDLER_ANALYZE_FAILED",
315
+ text: `Failed to analyze Mastra application: ${message}`,
316
+ domain: ErrorDomain.DEPLOYER,
317
+ category: ErrorCategory.SYSTEM
318
+ },
319
+ error
320
+ );
321
+ }
322
+ let externalDependencies;
323
+ try {
324
+ const result = await writeTelemetryConfig(mastraEntryFile, join(outputDirectory, this.outputDir));
325
+ externalDependencies = result.externalDependencies;
326
+ } catch (error) {
327
+ const message = error instanceof Error ? error.message : String(error);
328
+ throw new MastraError(
329
+ {
330
+ id: "DEPLOYER_BUNDLER_TELEMETRY_FAILED",
331
+ text: `Failed to write telemetry config: ${message}`,
332
+ domain: ErrorDomain.DEPLOYER,
333
+ category: ErrorCategory.SYSTEM
334
+ },
335
+ error
336
+ );
337
+ }
338
+ const mastraFolder = dirname(mastraEntryFile);
339
+ const fileService = new FileService();
340
+ const customInstrumentation = fileService.getFirstExistingFileOrUndefined([
341
+ join(mastraFolder, "instrumentation.js"),
342
+ join(mastraFolder, "instrumentation.ts"),
343
+ join(mastraFolder, "instrumentation.mjs")
344
+ ]);
345
+ try {
346
+ if (customInstrumentation) {
347
+ const result = await writeCustomInstrumentation(customInstrumentation, join(outputDirectory, this.outputDir));
348
+ externalDependencies = [...externalDependencies, ...result.externalDependencies];
349
+ await this.writeInstrumentationFile(join(outputDirectory, this.outputDir), customInstrumentation);
350
+ } else {
351
+ await this.writeInstrumentationFile(join(outputDirectory, this.outputDir));
352
+ }
353
+ } catch (error) {
354
+ const message = error instanceof Error ? error.message : String(error);
355
+ throw new MastraError(
356
+ {
357
+ id: "DEPLOYER_BUNDLER_INSTRUMENTATION_FILE_FAILED",
358
+ text: `Failed to write instrumentation file: ${message}, ${customInstrumentation ? ` Found custom instrumentation file: ${customInstrumentation}` : ""}`,
359
+ domain: ErrorDomain.DEPLOYER,
360
+ category: ErrorCategory.SYSTEM
361
+ },
362
+ error
363
+ );
364
+ }
365
+ const dependenciesToInstall = /* @__PURE__ */ new Map();
366
+ for (const external of externalDependencies) {
367
+ dependenciesToInstall.set(external, "latest");
368
+ }
369
+ const workspaceMap = await createWorkspacePackageMap();
370
+ const workspaceDependencies = /* @__PURE__ */ new Set();
371
+ for (const dep of analyzedBundleInfo.externalDependencies) {
372
+ try {
373
+ const pkgPath = resolveFrom(mastraEntryFile, `${dep}/package.json`);
374
+ const pkg = await readJSON(pkgPath);
375
+ if (workspaceMap.has(pkg.name)) {
376
+ workspaceDependencies.add(pkg.name);
377
+ continue;
378
+ }
379
+ dependenciesToInstall.set(dep, pkg.version);
380
+ } catch {
381
+ dependenciesToInstall.set(dep, "latest");
382
+ }
383
+ }
384
+ let resolutions = {};
385
+ if (workspaceDependencies.size > 0) {
386
+ try {
387
+ const result = collectTransitiveWorkspaceDependencies({
388
+ workspaceMap,
389
+ initialDependencies: workspaceDependencies,
390
+ logger: this.logger
391
+ });
392
+ resolutions = result.resolutions;
393
+ Object.entries(resolutions).forEach(([pkgName, tgzPath]) => {
394
+ dependenciesToInstall.set(pkgName, tgzPath);
395
+ });
396
+ await packWorkspaceDependencies({
397
+ workspaceMap,
398
+ usedWorkspacePackages: result.usedWorkspacePackages,
399
+ bundleOutputDir: join(outputDirectory, this.outputDir),
400
+ logger: this.logger
401
+ });
402
+ } catch (error) {
403
+ throw new MastraError(
404
+ {
405
+ id: "DEPLOYER_BUNDLER_WORKSPACE_DEPS_FAILED",
406
+ text: `Failed to collect and pack workspace dependencies.`,
407
+ domain: ErrorDomain.DEPLOYER,
408
+ category: ErrorCategory.USER
409
+ },
410
+ error
411
+ );
412
+ }
413
+ }
414
+ try {
415
+ await this.writePackageJson(join(outputDirectory, this.outputDir), dependenciesToInstall, resolutions);
416
+ this.logger.info("Bundling Mastra application");
417
+ const inputOptions = await this.getBundlerOptions(
418
+ serverFile,
419
+ mastraEntryFile,
420
+ analyzedBundleInfo,
421
+ toolsPaths
422
+ );
423
+ const bundler = await this.createBundler(
424
+ {
425
+ ...inputOptions,
426
+ logLevel: inputOptions.logLevel === "silent" ? "warn" : inputOptions.logLevel,
427
+ onwarn: (warning) => {
428
+ if (warning.code === "CIRCULAR_DEPENDENCY") {
429
+ if (warning.ids?.[0]?.includes("node_modules")) {
430
+ return;
431
+ }
432
+ this.logger.warn(`Circular dependency found:
433
+ ${warning.message.replace("Circular dependency: ", "")}`);
434
+ }
435
+ }
436
+ },
437
+ {
438
+ dir: bundleLocation,
439
+ manualChunks: {
440
+ mastra: ["#mastra"]
441
+ }
442
+ }
443
+ );
444
+ await bundler.write();
445
+ const toolImports = [];
446
+ const toolsExports = [];
447
+ Array.from(Object.keys(inputOptions.input || {})).filter((key) => key.startsWith("tools/")).forEach((key, index) => {
448
+ const toolExport = `tool${index}`;
449
+ toolImports.push(`import * as ${toolExport} from './${key}.mjs';`);
450
+ toolsExports.push(toolExport);
451
+ });
452
+ await writeFile(
453
+ join(bundleLocation, "tools.mjs"),
454
+ `${toolImports.join("\n")}
455
+
456
+ export const tools = [${toolsExports.join(", ")}]`
457
+ );
458
+ this.logger.info("Bundling Mastra done");
459
+ this.logger.info("Copying public files");
460
+ await this.copyPublic(dirname(mastraEntryFile), outputDirectory);
461
+ this.logger.info("Done copying public files");
462
+ this.logger.info("Copying .npmrc file");
463
+ await this.copyDOTNPMRC({ outputDirectory });
464
+ this.logger.info("Done copying .npmrc file");
465
+ this.logger.info("Installing dependencies");
466
+ await this.installDependencies(outputDirectory);
467
+ this.logger.info("Done installing dependencies");
468
+ } catch (error) {
469
+ const message = error instanceof Error ? error.message : String(error);
470
+ throw new MastraError(
471
+ {
472
+ id: "DEPLOYER_BUNDLER_BUNDLE_STAGE_FAILED",
473
+ text: `Failed during bundler bundle stage: ${message}`,
474
+ domain: ErrorDomain.DEPLOYER,
475
+ category: ErrorCategory.SYSTEM
476
+ },
477
+ error
478
+ );
479
+ }
480
+ }
481
+ async lint(_entryFile, _outputDirectory, toolsPaths) {
482
+ const toolsInputOptions = await this.getToolsInputOptions(toolsPaths);
483
+ const toolsLength = Object.keys(toolsInputOptions).length;
484
+ if (toolsLength > 0) {
485
+ this.logger.info(`Found ${toolsLength} ${toolsLength === 1 ? "tool" : "tools"}`);
486
+ }
487
+ }
488
+ };
489
+
490
+ export { Bundler };