@mastra/deployer 0.1.0-alpha.61 → 0.1.0-alpha.62

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @mastra/deployer
2
2
 
3
+ ## 0.1.0-alpha.62
4
+
5
+ ### Patch Changes
6
+
7
+ - 382f4dc: move telemetry init to instrumentation.mjs file in build directory
8
+ - Updated dependencies [016493a]
9
+ - Updated dependencies [382f4dc]
10
+ - Updated dependencies [176bc42]
11
+ - Updated dependencies [d68b532]
12
+ - Updated dependencies [fe3dcb0]
13
+ - Updated dependencies [e448a26]
14
+ - Updated dependencies [fd75f3c]
15
+ - Updated dependencies [ccf115c]
16
+ - Updated dependencies [a221426]
17
+ - @mastra/core@0.2.0-alpha.110
18
+
3
19
  ## 0.1.0-alpha.61
4
20
 
5
21
  ### Patch Changes
@@ -54,6 +54,7 @@ export declare abstract class Bundler extends MastraBundler {
54
54
  protected outputDir: string;
55
55
  constructor(name: string, component?: 'BUNDLER' | 'DEPLOYER');
56
56
  prepare(outputDirectory: string): Promise<void>;
57
+ writeInstrumentationFile(outputDirectory: string): Promise<void>;
57
58
  writePackageJson(outputDirectory: string, dependencies: Map<string, string>): Promise<void>;
58
59
  protected createBundler(inputOptions: InputOptions, outputOptions: Partial<OutputOptions> & {
59
60
  dir: string;
@@ -307,6 +308,10 @@ export declare function queryVectors(c: Context): Promise<Response>;
307
308
 
308
309
  export declare function removeAllExceptDeployer(): babel_2.PluginObj;
309
310
 
311
+ export declare function removeAllExceptTelemetryConfig(result: {
312
+ hasCustomConfig: boolean;
313
+ }): babel_2.PluginObj;
314
+
310
315
  export declare function removeDeployer(): babel_2.PluginObj;
311
316
 
312
317
  export declare function removeDeployer_alias_1(mastraEntry: string): Plugin_2;
@@ -342,4 +347,10 @@ declare type Variables = {
342
347
  playground: boolean;
343
348
  };
344
349
 
350
+ declare function writeTelemetryConfig(entryFile: string, outputDir: string): Promise<{
351
+ hasCustomConfig: boolean;
352
+ }>;
353
+ export { writeTelemetryConfig }
354
+ export { writeTelemetryConfig as writeTelemetryConfig_alias_1 }
355
+
345
356
  export { }
@@ -7,3 +7,4 @@ export { getWatcherInputOptions } from '../_tsup-dts-rollup.js';
7
7
  export { analyzeBundle_alias_1 as analyzeBundle } from '../_tsup-dts-rollup.js';
8
8
  export { FileService_alias_2 as FileService } from '../_tsup-dts-rollup.js';
9
9
  export { Deps_alias_2 as Deps } from '../_tsup-dts-rollup.js';
10
+ export { writeTelemetryConfig } from '../_tsup-dts-rollup.js';
@@ -1,5 +1,5 @@
1
- export { FileService, createWatcher, getBundler, getWatcher, getInputOptions as getWatcherInputOptions } from '../chunk-I7EFK2FV.js';
2
- export { Deps } from '../chunk-Q3WKR6OZ.js';
1
+ export { FileService, createWatcher, getBundler, getWatcher, getInputOptions as getWatcherInputOptions } from '../chunk-VCRMX3ZD.js';
2
+ export { Deps, writeTelemetryConfig } from '../chunk-E4D6R3B4.js';
3
3
  export { analyzeBundle } from '../chunk-ERNQNTBH.js';
4
4
  export { createBundler, getInputOptions as getBundlerInputOptions } from '../chunk-KXS4XYEJ.js';
5
5
  import '../chunk-YNXJO2XU.js';
@@ -1,5 +1,5 @@
1
- export { Bundler } from '../chunk-XSSW3PB4.js';
2
- import '../chunk-Q3WKR6OZ.js';
1
+ export { Bundler } from '../chunk-3MSZJSZW.js';
2
+ import '../chunk-E4D6R3B4.js';
3
3
  import '../chunk-ERNQNTBH.js';
4
4
  import '../chunk-KXS4XYEJ.js';
5
5
  import '../chunk-YNXJO2XU.js';
@@ -1,12 +1,13 @@
1
- import { Deps } from './chunk-Q3WKR6OZ.js';
1
+ import { Deps, writeTelemetryConfig } from './chunk-E4D6R3B4.js';
2
2
  import { analyzeBundle } from './chunk-ERNQNTBH.js';
3
3
  import { createBundler, getInputOptions } from './chunk-KXS4XYEJ.js';
4
4
  import { MastraBundler } from '@mastra/core/bundler';
5
5
  import virtual from '@rollup/plugin-virtual';
6
- import { ensureDir } from 'fs-extra';
6
+ import { ensureDir, copy } from 'fs-extra';
7
7
  import { existsSync } from 'node:fs';
8
8
  import { writeFile } from 'node:fs/promises';
9
- import { join } from 'node:path';
9
+ import { join, dirname } from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
10
11
  import fsExtra from 'fs-extra/esm';
11
12
 
12
13
  var Bundler = class extends MastraBundler {
@@ -20,6 +21,11 @@ var Bundler = class extends MastraBundler {
20
21
  await ensureDir(join(outputDirectory, this.analyzeOutputDir));
21
22
  await ensureDir(join(outputDirectory, this.outputDir));
22
23
  }
24
+ async writeInstrumentationFile(outputDirectory) {
25
+ const instrumentationFile = join(outputDirectory, "instrumentation.mjs");
26
+ const __dirname = dirname(fileURLToPath(import.meta.url));
27
+ await copy(join(__dirname, "templates", "instrumentation-template.js"), instrumentationFile);
28
+ }
23
29
  async writePackageJson(outputDirectory, dependencies) {
24
30
  this.logger.debug(`Writing project's package.json`);
25
31
  await ensureDir(outputDirectory);
@@ -75,13 +81,13 @@ var Bundler = class extends MastraBundler {
75
81
  "node",
76
82
  this.logger
77
83
  );
78
- await this.writePackageJson(
79
- join(outputDirectory, this.outputDir),
80
- Array.from(analyzedBundleInfo.externalDependencies).reduce((acc, dep) => {
81
- acc.set(dep, "latest");
82
- return acc;
83
- }, /* @__PURE__ */ new Map())
84
- );
84
+ await writeTelemetryConfig(mastraEntryFile, join(outputDirectory, this.outputDir));
85
+ const dependenciesToInstall = Array.from(analyzedBundleInfo.externalDependencies).reduce((acc, dep) => {
86
+ acc.set(dep, "latest");
87
+ return acc;
88
+ }, /* @__PURE__ */ new Map());
89
+ await this.writePackageJson(join(outputDirectory, this.outputDir), dependenciesToInstall);
90
+ await this.writeInstrumentationFile(join(outputDirectory, this.outputDir));
85
91
  this.logger.info("Bundling Mastra application");
86
92
  const inputOptions = await getInputOptions(mastraEntryFile, analyzedBundleInfo, "node");
87
93
  if (isVirtual) {
@@ -7,6 +7,10 @@ import path, { dirname } from 'path';
7
7
  import { fileURLToPath } from 'url';
8
8
  import fsExtra from 'fs-extra/esm';
9
9
  import fsPromises from 'fs/promises';
10
+ import * as babel from '@babel/core';
11
+ import babel__default from '@babel/core';
12
+ import { rollup } from 'rollup';
13
+ import esbuild from 'rollup-plugin-esbuild';
10
14
 
11
15
  // src/deploy/log.ts
12
16
  var createPinoStream = (logger) => {
@@ -175,5 +179,113 @@ var Deps = class extends MastraBase {
175
179
  await fsPromises.writeFile("package.json", JSON.stringify(packageJson, null, 2));
176
180
  }
177
181
  };
182
+ function removeAllExceptTelemetryConfig(result) {
183
+ let mastraClass = null;
184
+ const t = babel__default.types;
185
+ return {
186
+ name: "remove-all-except-telemetry-config",
187
+ visitor: {
188
+ ExportNamedDeclaration: {
189
+ // remove all exports
190
+ exit(path2) {
191
+ path2.remove();
192
+ }
193
+ },
194
+ ImportDeclaration(path2) {
195
+ if ((path2.node.source.value === "@mastra/core" || path2.node.source.value === "@mastra/core/mastra") && path2.node.specifiers) {
196
+ mastraClass = path2.node.specifiers.find(
197
+ // @ts-ignore - no need to type
198
+ (p) => p.imported?.name === "Mastra"
199
+ )?.local?.name ?? null;
200
+ }
201
+ },
202
+ NewExpression(path2) {
203
+ if (mastraClass && path2.node.callee.name === mastraClass) {
204
+ let telemetry = path2.node.arguments[0]?.properties?.find(
205
+ // @ts-ignore
206
+ (prop) => prop.key.name === "telemetry"
207
+ );
208
+ const programPath = path2.scope.getProgramParent().path;
209
+ if (!programPath) {
210
+ return;
211
+ }
212
+ if (telemetry) {
213
+ result.hasCustomConfig = true;
214
+ } else {
215
+ telemetry = {
216
+ value: t.objectExpression([])
217
+ };
218
+ }
219
+ const exportDeclaration = t.exportNamedDeclaration(
220
+ t.variableDeclaration("const", [t.variableDeclarator(t.identifier("telemetry"), telemetry.value)]),
221
+ []
222
+ );
223
+ programPath.node.body.push(exportDeclaration);
224
+ }
225
+ }
226
+ }
227
+ };
228
+ }
229
+
230
+ // src/build/telemetry.ts
231
+ async function writeTelemetryConfig(entryFile, outputDir) {
232
+ const result = {
233
+ hasCustomConfig: false
234
+ };
235
+ const bundle = await rollup({
236
+ input: {
237
+ "telemetry-config": entryFile
238
+ },
239
+ treeshake: true,
240
+ plugins: [
241
+ // transpile typescript to something we understand
242
+ esbuild({
243
+ target: "node20",
244
+ platform: "node",
245
+ minify: false
246
+ }),
247
+ {
248
+ name: "get-telemetry-config",
249
+ transform(code, id) {
250
+ if (!this.getModuleInfo(id)?.isEntry) {
251
+ return;
252
+ }
253
+ return new Promise((resolve, reject) => {
254
+ babel.transform(
255
+ code,
256
+ {
257
+ babelrc: false,
258
+ configFile: false,
259
+ filename: id,
260
+ plugins: [removeAllExceptTelemetryConfig(result)]
261
+ },
262
+ (err, result2) => {
263
+ if (err) {
264
+ return reject(err);
265
+ }
266
+ resolve({
267
+ code: result2.code,
268
+ map: result2.map
269
+ });
270
+ }
271
+ );
272
+ });
273
+ }
274
+ },
275
+ // let esbuild remove all unused imports
276
+ esbuild({
277
+ target: "node20",
278
+ platform: "node",
279
+ minify: false
280
+ })
281
+ ]
282
+ });
283
+ await bundle.write({
284
+ dir: outputDir,
285
+ format: "es",
286
+ entryFileNames: "[name].mjs"
287
+ });
288
+ return result;
289
+ }
178
290
 
179
- export { Deps, createChildProcessLogger, createPinoStream };
291
+ export { Deps, createChildProcessLogger, createPinoStream, writeTelemetryConfig };
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { Bundler } from './chunk-XSSW3PB4.js';
2
- import { FileService } from './chunk-I7EFK2FV.js';
3
- export { FileService, getBundler, getWatcher } from './chunk-I7EFK2FV.js';
4
- import { Deps } from './chunk-Q3WKR6OZ.js';
5
- export { Deps, createChildProcessLogger, createPinoStream } from './chunk-Q3WKR6OZ.js';
1
+ import { FileService } from './chunk-VCRMX3ZD.js';
2
+ export { FileService, getBundler, getWatcher } from './chunk-VCRMX3ZD.js';
3
+ import { Bundler } from './chunk-3MSZJSZW.js';
4
+ import { Deps } from './chunk-E4D6R3B4.js';
5
+ export { Deps, createChildProcessLogger, createPinoStream } from './chunk-E4D6R3B4.js';
6
6
  import './chunk-ERNQNTBH.js';
7
7
  import './chunk-KXS4XYEJ.js';
8
8
  import './chunk-YNXJO2XU.js';
@@ -0,0 +1,85 @@
1
+ import {
2
+ NodeSDK, getNodeAutoInstrumentations, ATTR_SERVICE_NAME, Resource,
3
+ ParentBasedSampler,
4
+ TraceIdRatioBasedSampler,
5
+ AlwaysOnSampler,
6
+ AlwaysOffSampler,
7
+ } from '@mastra/core/telemetry/otel-vendor';
8
+ import { OTLPStorageExporter } from '@mastra/core/telemetry'
9
+ import { MastraStorageLibSql } from '@mastra/core/storage'
10
+ import { createLogger } from '@mastra/core/logger'
11
+ import { telemetry } from './telemetry-config.mjs'
12
+
13
+
14
+ function getSampler(config) {
15
+ if (!config.sampling) {
16
+ return new AlwaysOnSampler();
17
+ }
18
+
19
+ if (!config.enabled) {
20
+ return new AlwaysOffSampler();
21
+ }
22
+
23
+ switch (config.sampling.type) {
24
+ case 'ratio':
25
+ return new TraceIdRatioBasedSampler(config.sampling.probability);
26
+ case 'always_on':
27
+ return new AlwaysOnSampler();
28
+ case 'always_off':
29
+ return new AlwaysOffSampler();
30
+ case 'parent_based':
31
+ const rootSampler = new TraceIdRatioBasedSampler(config.sampling.root?.probability || 1.0);
32
+ return new ParentBasedSampler({ root: rootSampler });
33
+ default:
34
+ return new AlwaysOnSampler();
35
+ }
36
+
37
+ }
38
+
39
+ async function getExporter(config) {
40
+ if (config.export?.type === 'otlp') {
41
+ return new OTLPHttpExporter({
42
+ url: config.export.endpoint,
43
+ headers: config.export.headers,
44
+ })
45
+ } else if (config.export?.type === 'custom') {
46
+ return config.export.exporter
47
+ } else {
48
+ const storage = new MastraStorageLibSql({
49
+ config: {
50
+ // file lives in ./.mastra/output, and we need to write to ./.mastra/mastra.db
51
+ url: "file:../mastra.db",
52
+ },
53
+ })
54
+ await storage.init()
55
+
56
+ return new OTLPStorageExporter({
57
+ logger: createLogger({
58
+ name: 'telemetry',
59
+ level: 'silent',
60
+ }),
61
+ storage,
62
+ })
63
+ }
64
+ }
65
+
66
+ const sampler = getSampler(telemetry);
67
+ const exporter = await getExporter(telemetry);
68
+
69
+ const sdk = new NodeSDK({
70
+ resource: new Resource({
71
+ [ATTR_SERVICE_NAME]: telemetry.serviceName || 'default-service',
72
+ }),
73
+ sampler,
74
+ traceExporter: exporter,
75
+ instrumentations: [getNodeAutoInstrumentations()],
76
+ });
77
+
78
+ sdk.start();
79
+
80
+ // gracefully shut down the SDK on process exit
81
+ process.on('SIGTERM', () => {
82
+ sdk.shutdown().catch(() => {
83
+ // do nothing
84
+ })
85
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/deployer",
3
- "version": "0.1.0-alpha.61",
3
+ "version": "0.1.0-alpha.62",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -52,7 +52,7 @@
52
52
  "rollup-plugin-esbuild": "^6.1.1",
53
53
  "rollup-plugin-node-externals": "^8.0.0",
54
54
  "zod": "^3.24.1",
55
- "@mastra/core": "^0.2.0-alpha.109"
55
+ "@mastra/core": "^0.2.0-alpha.110"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@hono/node-server": "^1.13.7",
@@ -73,7 +73,7 @@
73
73
  "zod-to-json-schema": "^3.24.1"
74
74
  },
75
75
  "scripts": {
76
- "build": "tsup src/index.ts src/build/index.ts src/server/index.ts src/build/bundler.ts src/build/analyze.ts src/bundler/index.ts --format esm --clean --experimental-dts --treeshake",
76
+ "build": "tsup src/index.ts src/build/index.ts src/server/index.ts src/build/bundler.ts src/build/analyze.ts src/bundler/index.ts --format esm --clean --experimental-dts --treeshake --publicDir",
77
77
  "build:watch": "pnpm build --watch",
78
78
  "pull:openapispec": "node src/server/openapi.script.js",
79
79
  "test": "vitest run"
@@ -0,0 +1,85 @@
1
+ import {
2
+ NodeSDK, getNodeAutoInstrumentations, ATTR_SERVICE_NAME, Resource,
3
+ ParentBasedSampler,
4
+ TraceIdRatioBasedSampler,
5
+ AlwaysOnSampler,
6
+ AlwaysOffSampler,
7
+ } from '@mastra/core/telemetry/otel-vendor';
8
+ import { OTLPStorageExporter } from '@mastra/core/telemetry'
9
+ import { MastraStorageLibSql } from '@mastra/core/storage'
10
+ import { createLogger } from '@mastra/core/logger'
11
+ import { telemetry } from './telemetry-config.mjs'
12
+
13
+
14
+ function getSampler(config) {
15
+ if (!config.sampling) {
16
+ return new AlwaysOnSampler();
17
+ }
18
+
19
+ if (!config.enabled) {
20
+ return new AlwaysOffSampler();
21
+ }
22
+
23
+ switch (config.sampling.type) {
24
+ case 'ratio':
25
+ return new TraceIdRatioBasedSampler(config.sampling.probability);
26
+ case 'always_on':
27
+ return new AlwaysOnSampler();
28
+ case 'always_off':
29
+ return new AlwaysOffSampler();
30
+ case 'parent_based':
31
+ const rootSampler = new TraceIdRatioBasedSampler(config.sampling.root?.probability || 1.0);
32
+ return new ParentBasedSampler({ root: rootSampler });
33
+ default:
34
+ return new AlwaysOnSampler();
35
+ }
36
+
37
+ }
38
+
39
+ async function getExporter(config) {
40
+ if (config.export?.type === 'otlp') {
41
+ return new OTLPHttpExporter({
42
+ url: config.export.endpoint,
43
+ headers: config.export.headers,
44
+ })
45
+ } else if (config.export?.type === 'custom') {
46
+ return config.export.exporter
47
+ } else {
48
+ const storage = new MastraStorageLibSql({
49
+ config: {
50
+ // file lives in ./.mastra/output, and we need to write to ./.mastra/mastra.db
51
+ url: "file:../mastra.db",
52
+ },
53
+ })
54
+ await storage.init()
55
+
56
+ return new OTLPStorageExporter({
57
+ logger: createLogger({
58
+ name: 'telemetry',
59
+ level: 'silent',
60
+ }),
61
+ storage,
62
+ })
63
+ }
64
+ }
65
+
66
+ const sampler = getSampler(telemetry);
67
+ const exporter = await getExporter(telemetry);
68
+
69
+ const sdk = new NodeSDK({
70
+ resource: new Resource({
71
+ [ATTR_SERVICE_NAME]: telemetry.serviceName || 'default-service',
72
+ }),
73
+ sampler,
74
+ traceExporter: exporter,
75
+ instrumentations: [getNodeAutoInstrumentations()],
76
+ });
77
+
78
+ sdk.start();
79
+
80
+ // gracefully shut down the SDK on process exit
81
+ process.on('SIGTERM', () => {
82
+ sdk.shutdown().catch(() => {
83
+ // do nothing
84
+ })
85
+ });
@@ -0,0 +1,62 @@
1
+ import babel from '@babel/core';
2
+
3
+ export function removeAllExceptTelemetryConfig(result: { hasCustomConfig: boolean }) {
4
+ let mastraClass: string | null = null;
5
+
6
+ const t = babel.types;
7
+
8
+ return {
9
+ name: 'remove-all-except-telemetry-config',
10
+ visitor: {
11
+ ExportNamedDeclaration: {
12
+ // remove all exports
13
+ exit(path) {
14
+ path.remove();
15
+ },
16
+ },
17
+ ImportDeclaration(path) {
18
+ if (
19
+ (path.node.source.value === '@mastra/core' || path.node.source.value === '@mastra/core/mastra') &&
20
+ path.node.specifiers
21
+ ) {
22
+ mastraClass =
23
+ path.node.specifiers.find(
24
+ // @ts-ignore - no need to type
25
+ p => p.imported?.name === 'Mastra',
26
+ )?.local?.name ?? null;
27
+ }
28
+ },
29
+ NewExpression(path) {
30
+ if (mastraClass && (path.node.callee as babel.types.Identifier).name === mastraClass) {
31
+ // @ts-ignore
32
+ let telemetry = path.node.arguments[0]?.properties?.find(
33
+ // @ts-ignore
34
+ prop => prop.key.name === 'telemetry',
35
+ );
36
+
37
+ const programPath = path.scope.getProgramParent().path;
38
+ if (!programPath) {
39
+ return;
40
+ }
41
+
42
+ if (telemetry) {
43
+ result.hasCustomConfig = true;
44
+ } else {
45
+ telemetry = {
46
+ value: t.objectExpression([]),
47
+ };
48
+ }
49
+
50
+ // add the deployer export
51
+ const exportDeclaration = t.exportNamedDeclaration(
52
+ t.variableDeclaration('const', [t.variableDeclarator(t.identifier('telemetry'), telemetry.value)]),
53
+ [],
54
+ );
55
+
56
+ // @ts-ignore
57
+ programPath.node.body.push(exportDeclaration);
58
+ }
59
+ },
60
+ },
61
+ } as babel.PluginObj;
62
+ }
@@ -4,3 +4,4 @@ export { createWatcher, getInputOptions as getWatcherInputOptions } from './watc
4
4
  export { analyzeBundle } from './analyze';
5
5
  export { FileService } from './fs';
6
6
  export { Deps } from './deps';
7
+ export { writeTelemetryConfig } from './telemetry';
@@ -0,0 +1,76 @@
1
+ import * as babel from '@babel/core';
2
+ import type { MastraDeployer } from '@mastra/core';
3
+ import { rollup } from 'rollup';
4
+ import esbuild from 'rollup-plugin-esbuild';
5
+
6
+ import { removeAllExceptTelemetryConfig } from './babel/get-telemetry-config';
7
+
8
+ export async function writeTelemetryConfig(
9
+ entryFile: string,
10
+ outputDir: string,
11
+ ): Promise<{
12
+ hasCustomConfig: boolean;
13
+ }> {
14
+ const result = {
15
+ hasCustomConfig: false,
16
+ };
17
+
18
+ const bundle = await rollup({
19
+ input: {
20
+ 'telemetry-config': entryFile,
21
+ },
22
+ treeshake: true,
23
+ plugins: [
24
+ // transpile typescript to something we understand
25
+ esbuild({
26
+ target: 'node20',
27
+ platform: 'node',
28
+ minify: false,
29
+ }),
30
+ {
31
+ name: 'get-telemetry-config',
32
+ transform(code, id) {
33
+ if (!this.getModuleInfo(id)?.isEntry) {
34
+ return;
35
+ }
36
+
37
+ return new Promise((resolve, reject) => {
38
+ babel.transform(
39
+ code,
40
+ {
41
+ babelrc: false,
42
+ configFile: false,
43
+ filename: id,
44
+ plugins: [removeAllExceptTelemetryConfig(result)],
45
+ },
46
+ (err, result) => {
47
+ if (err) {
48
+ return reject(err);
49
+ }
50
+
51
+ resolve({
52
+ code: result!.code!,
53
+ map: result!.map!,
54
+ });
55
+ },
56
+ );
57
+ });
58
+ },
59
+ },
60
+ // let esbuild remove all unused imports
61
+ esbuild({
62
+ target: 'node20',
63
+ platform: 'node',
64
+ minify: false,
65
+ }),
66
+ ],
67
+ });
68
+
69
+ await bundle.write({
70
+ dir: outputDir,
71
+ format: 'es',
72
+ entryFileNames: '[name].mjs',
73
+ });
74
+
75
+ return result;
76
+ }
@@ -1,9 +1,10 @@
1
1
  import { MastraBundler } from '@mastra/core/bundler';
2
2
  import virtual from '@rollup/plugin-virtual';
3
- import { ensureDir } from 'fs-extra';
3
+ import { copy, ensureDir } from 'fs-extra';
4
4
  import { existsSync } from 'node:fs';
5
5
  import { writeFile } from 'node:fs/promises';
6
- import { join } from 'node:path';
6
+ import { dirname, join } from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
7
8
  import type { InputOptions, OutputOptions } from 'rollup';
8
9
 
9
10
  import fsExtra from 'fs-extra/esm';
@@ -11,6 +12,7 @@ import fsExtra from 'fs-extra/esm';
11
12
  import { analyzeBundle } from '../build/analyze';
12
13
  import { createBundler as createBundlerUtil, getInputOptions } from '../build/bundler';
13
14
  import { Deps } from '../build/deps';
15
+ import { writeTelemetryConfig } from '../build/telemetry';
14
16
 
15
17
  export abstract class Bundler extends MastraBundler {
16
18
  protected analyzeOutputDir = '.build';
@@ -28,6 +30,13 @@ export abstract class Bundler extends MastraBundler {
28
30
  await ensureDir(join(outputDirectory, this.outputDir));
29
31
  }
30
32
 
33
+ async writeInstrumentationFile(outputDirectory: string) {
34
+ const instrumentationFile = join(outputDirectory, 'instrumentation.mjs');
35
+ const __dirname = dirname(fileURLToPath(import.meta.url));
36
+
37
+ await copy(join(__dirname, 'templates', 'instrumentation-template.js'), instrumentationFile);
38
+ }
39
+
31
40
  async writePackageJson(outputDirectory: string, dependencies: Map<string, string>) {
32
41
  this.logger.debug(`Writing project's package.json`);
33
42
  await ensureDir(outputDirectory);
@@ -97,13 +106,15 @@ export abstract class Bundler extends MastraBundler {
97
106
  this.logger,
98
107
  );
99
108
 
100
- await this.writePackageJson(
101
- join(outputDirectory, this.outputDir),
102
- Array.from(analyzedBundleInfo.externalDependencies).reduce((acc, dep) => {
103
- acc.set(dep, 'latest');
104
- return acc;
105
- }, new Map<string, string>()),
106
- );
109
+ await writeTelemetryConfig(mastraEntryFile, join(outputDirectory, this.outputDir));
110
+
111
+ const dependenciesToInstall = Array.from(analyzedBundleInfo.externalDependencies).reduce((acc, dep) => {
112
+ acc.set(dep, 'latest');
113
+ return acc;
114
+ }, new Map<string, string>());
115
+
116
+ await this.writePackageJson(join(outputDirectory, this.outputDir), dependenciesToInstall);
117
+ await this.writeInstrumentationFile(join(outputDirectory, this.outputDir));
107
118
 
108
119
  this.logger.info('Bundling Mastra application');
109
120
  const inputOptions: InputOptions = await getInputOptions(mastraEntryFile, analyzedBundleInfo, 'node');
File without changes