@mastra/deployer 0.0.0-commonjs-20250227130920

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 (86) hide show
  1. package/.turbo/turbo-build.log +41 -0
  2. package/CHANGELOG.md +897 -0
  3. package/LICENSE +44 -0
  4. package/README.md +159 -0
  5. package/dist/_tsup-dts-rollup.d.cts +360 -0
  6. package/dist/_tsup-dts-rollup.d.ts +360 -0
  7. package/dist/build/analyze.cjs +367 -0
  8. package/dist/build/analyze.d.cts +1 -0
  9. package/dist/build/analyze.d.ts +1 -0
  10. package/dist/build/analyze.js +2 -0
  11. package/dist/build/bundler.cjs +353 -0
  12. package/dist/build/bundler.d.cts +2 -0
  13. package/dist/build/bundler.d.ts +2 -0
  14. package/dist/build/bundler.js +2 -0
  15. package/dist/build/index.cjs +1146 -0
  16. package/dist/build/index.d.cts +10 -0
  17. package/dist/build/index.d.ts +10 -0
  18. package/dist/build/index.js +5 -0
  19. package/dist/bundler/index.cjs +999 -0
  20. package/dist/bundler/index.d.cts +1 -0
  21. package/dist/bundler/index.d.ts +1 -0
  22. package/dist/bundler/index.js +5 -0
  23. package/dist/chunk-3ONBKVC4.js +113 -0
  24. package/dist/chunk-AXS5WSIK.js +290 -0
  25. package/dist/chunk-DTSFVNIF.js +260 -0
  26. package/dist/chunk-JMH7HCD6.js +274 -0
  27. package/dist/chunk-SGK37ZWD.js +254 -0
  28. package/dist/chunk-YNXJO2XU.js +69 -0
  29. package/dist/index.cjs +1229 -0
  30. package/dist/index.d.cts +6 -0
  31. package/dist/index.d.ts +6 -0
  32. package/dist/index.js +131 -0
  33. package/dist/server/index.cjs +4930 -0
  34. package/dist/server/index.d.cts +2 -0
  35. package/dist/server/index.d.ts +2 -0
  36. package/dist/server/index.js +4923 -0
  37. package/dist/templates/instrumentation-template.js +86 -0
  38. package/eslint.config.js +6 -0
  39. package/global.d.ts +0 -0
  40. package/package.json +112 -0
  41. package/public/templates/instrumentation-template.js +86 -0
  42. package/src/build/analyze.ts +279 -0
  43. package/src/build/babel/fix-libsql.ts +41 -0
  44. package/src/build/babel/get-deployer.ts +54 -0
  45. package/src/build/babel/get-telemetry-config.ts +62 -0
  46. package/src/build/babel/remove-deployer.ts +43 -0
  47. package/src/build/bundle.ts +139 -0
  48. package/src/build/bundler.ts +135 -0
  49. package/src/build/deployer.ts +67 -0
  50. package/src/build/deps.ts +149 -0
  51. package/src/build/env.ts +76 -0
  52. package/src/build/fs.ts +66 -0
  53. package/src/build/index.ts +7 -0
  54. package/src/build/isNodeBuiltin.ts +7 -0
  55. package/src/build/plugins/fix-libsql.ts +69 -0
  56. package/src/build/plugins/hono-alias.ts +17 -0
  57. package/src/build/plugins/pino.ts +93 -0
  58. package/src/build/plugins/remove-deployer.ts +37 -0
  59. package/src/build/plugins/telemetry-fix.ts +54 -0
  60. package/src/build/telemetry.ts +76 -0
  61. package/src/build/utils.ts +12 -0
  62. package/src/build/watcher.ts +43 -0
  63. package/src/bundler/index.ts +144 -0
  64. package/src/deploy/base.ts +30 -0
  65. package/src/deploy/index.ts +2 -0
  66. package/src/deploy/log.ts +61 -0
  67. package/src/index.ts +3 -0
  68. package/src/server/handlers/agents.ts +209 -0
  69. package/src/server/handlers/client.ts +36 -0
  70. package/src/server/handlers/error.ts +29 -0
  71. package/src/server/handlers/logs.ts +53 -0
  72. package/src/server/handlers/memory.ts +196 -0
  73. package/src/server/handlers/prompt.ts +128 -0
  74. package/src/server/handlers/root.ts +6 -0
  75. package/src/server/handlers/telemetry.ts +48 -0
  76. package/src/server/handlers/tools.ts +114 -0
  77. package/src/server/handlers/utils.ts +15 -0
  78. package/src/server/handlers/vector.ts +149 -0
  79. package/src/server/handlers/workflows.ts +119 -0
  80. package/src/server/index.ts +1355 -0
  81. package/src/server/openapi.json +434 -0
  82. package/src/server/openapi.script.js +22 -0
  83. package/src/server/types.ts +4 -0
  84. package/src/server/welcome.ts +105 -0
  85. package/tsconfig.json +5 -0
  86. package/vitest.config.ts +8 -0
@@ -0,0 +1,66 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ import fsExtra from 'fs-extra/esm';
6
+
7
+ import { FileEnvService } from './env.js';
8
+
9
+ export class FileService {
10
+ /**
11
+ *
12
+ * @param inputFile the file in the starter files directory to copy
13
+ * @param outputFilePath the destination path
14
+ * @param replaceIfExists flag to replace if it exists
15
+ * @returns
16
+ */
17
+ public async copyStarterFile(inputFile: string, outputFilePath: string, replaceIfExists?: boolean) {
18
+ const __filename = fileURLToPath(import.meta.url);
19
+ const __dirname = path.dirname(__filename);
20
+ const filePath = path.resolve(__dirname, '..', 'starter-files', inputFile);
21
+ const fileString = fs.readFileSync(filePath, 'utf8');
22
+
23
+ if (fs.existsSync(outputFilePath) && !replaceIfExists) {
24
+ console.log(`${outputFilePath} already exists`);
25
+ return false;
26
+ }
27
+
28
+ await fsExtra.outputFile(outputFilePath, fileString);
29
+
30
+ return true;
31
+ }
32
+
33
+ public async setupEnvFile({ dbUrl }: { dbUrl: string }) {
34
+ const envPath = path.join(process.cwd(), '.env.development');
35
+
36
+ await fsExtra.ensureFile(envPath);
37
+
38
+ const fileEnvService = new FileEnvService(envPath);
39
+ await fileEnvService.setEnvValue('DB_URL', dbUrl);
40
+ }
41
+
42
+ public getFirstExistingFile(files: string[]): string {
43
+ for (const f of files) {
44
+ if (fs.existsSync(f)) {
45
+ return f;
46
+ }
47
+ }
48
+
49
+ throw new Error('Missing required file, checked the following paths: ' + files.join(', '));
50
+ }
51
+
52
+ public replaceValuesInFile({
53
+ filePath,
54
+ replacements,
55
+ }: {
56
+ filePath: string;
57
+ replacements: { search: string; replace: string }[];
58
+ }) {
59
+ let fileContent = fs.readFileSync(filePath, 'utf8');
60
+ replacements.forEach(({ search, replace }) => {
61
+ fileContent = fileContent.replaceAll(search, replace);
62
+ });
63
+
64
+ fs.writeFileSync(filePath, fileContent);
65
+ }
66
+ }
@@ -0,0 +1,7 @@
1
+ export { getBundler, getWatcher } from './bundle';
2
+ export { createBundler, getInputOptions as getBundlerInputOptions } from './bundler';
3
+ export { createWatcher, getInputOptions as getWatcherInputOptions } from './watcher';
4
+ export { analyzeBundle } from './analyze';
5
+ export { FileService } from './fs';
6
+ export { Deps } from './deps';
7
+ export { writeTelemetryConfig } from './telemetry';
@@ -0,0 +1,7 @@
1
+ import { builtinModules } from 'node:module';
2
+
3
+ export function isNodeBuiltin(dep: string): boolean {
4
+ const [pkg] = dep.split('/');
5
+
6
+ return dep.startsWith('node:') || builtinModules.includes(dep) || builtinModules.includes(pkg!);
7
+ }
@@ -0,0 +1,69 @@
1
+ import * as babel from '@babel/core';
2
+ import { currentTarget } from '@neon-rs/load';
3
+ import { familySync, GLIBC } from 'detect-libc';
4
+ import { dirname, join } from 'path';
5
+ import type { Plugin } from 'rollup';
6
+
7
+ import fsExtra from 'fs-extra/esm';
8
+
9
+ import { rewriteLibsqlImport } from '../babel/fix-libsql';
10
+
11
+ export function libSqlFix(): Plugin {
12
+ return {
13
+ name: 'libSqlFix',
14
+ transform(code, id) {
15
+ if (!id.includes('\\libsql\\index.js') && !id.includes('/libsql/index.js')) {
16
+ return null;
17
+ }
18
+
19
+ return new Promise((resolve, reject) => {
20
+ babel.transform(
21
+ code,
22
+ {
23
+ babelrc: false,
24
+ configFile: false,
25
+ filename: id,
26
+ plugins: [rewriteLibsqlImport],
27
+ },
28
+ (err, result) => {
29
+ if (err) {
30
+ return reject(err);
31
+ }
32
+
33
+ resolve({
34
+ code: result!.code!,
35
+ map: result!.map!,
36
+ });
37
+ },
38
+ );
39
+ });
40
+ },
41
+ async generateBundle({ file, dir }) {
42
+ if (!file && !dir) {
43
+ throw new Error('No output options were given.');
44
+ }
45
+
46
+ const outputDirectory = dir || dirname(file!);
47
+
48
+ let target = currentTarget();
49
+ // Workaround for Bun, which reports a musl target, but really wants glibc...
50
+ if (familySync() == GLIBC) {
51
+ switch (target) {
52
+ case 'linux-x64-musl':
53
+ target = 'linux-x64-gnu';
54
+ break;
55
+ case 'linux-arm64-musl':
56
+ target = 'linux-arm64-gnu';
57
+ break;
58
+ }
59
+ }
60
+
61
+ const fileToCopy = await this.resolve(`@libsql/${target}/index.node`);
62
+ if (fileToCopy) {
63
+ await fsExtra.copy(fileToCopy.id, join(outputDirectory, 'libsql.node'));
64
+ } else {
65
+ // throw new Error(`libsql binding not found for @libsql/${target}/index.node`);
66
+ }
67
+ },
68
+ } satisfies Plugin;
69
+ }
@@ -0,0 +1,17 @@
1
+ import { fileURLToPath } from 'node:url';
2
+ import type { Plugin } from 'rollup';
3
+
4
+ // hono is imported from deployer, so we need to resolve from here instead of the project root
5
+ export function aliasHono(): Plugin {
6
+ return {
7
+ name: 'hono-alias',
8
+ resolveId(id: string) {
9
+ if (!id.startsWith('@hono/') && !id.startsWith('hono/') && id !== 'hono' && id !== 'hono-openapi') {
10
+ return;
11
+ }
12
+
13
+ const path = import.meta.resolve(id);
14
+ return fileURLToPath(path);
15
+ },
16
+ } satisfies Plugin;
17
+ }
@@ -0,0 +1,93 @@
1
+ import path from 'path';
2
+ import type { OutputChunk, Plugin } from 'rollup';
3
+
4
+ export function pino() {
5
+ let emittedChunks = new Map();
6
+
7
+ const workerFiles = [
8
+ {
9
+ id: 'thread-stream-worker',
10
+ file: 'pino-thread-stream-worker',
11
+ },
12
+ {
13
+ id: 'pino-worker',
14
+ file: 'pino-worker',
15
+ },
16
+ {
17
+ id: 'pino/file',
18
+ file: 'pino-file',
19
+ },
20
+ {
21
+ id: 'pino-pretty',
22
+ file: 'pino-pretty',
23
+ },
24
+ ];
25
+
26
+ const fileReferences = new Map();
27
+ return {
28
+ name: 'rollup-plugin-pino',
29
+
30
+ async resolveId(id, importee) {
31
+ if (id === 'pino') {
32
+ // resolve pino first
33
+ const resolvedPino = await this.resolve(id, importee);
34
+
35
+ if (resolvedPino) {
36
+ await Promise.all(
37
+ workerFiles.map(async file => {
38
+ const resolvedEntry = await this.resolve(file.id, resolvedPino.id);
39
+
40
+ if (!resolvedEntry) {
41
+ return null;
42
+ }
43
+
44
+ const reference = this.emitFile({
45
+ type: 'chunk',
46
+ id: resolvedEntry.id,
47
+ name: `${file.file}`,
48
+ });
49
+
50
+ fileReferences.set(file.id, reference);
51
+ }),
52
+ );
53
+ }
54
+ }
55
+ },
56
+ renderChunk(code, chunk) {
57
+ if (chunk.type === 'chunk' && (chunk as OutputChunk).isEntry && fileReferences.size && chunk.name === 'index') {
58
+ const importRegex = /^(?:import(?:["'\s]*[\w*${}\n\r\t, ]+from\s*)?["'\s].+[;"'\s]*)$/gm;
59
+
60
+ const codeToInject = `globalThis.__bundlerPathsOverrides = {
61
+ ${Array.from(fileReferences.entries())
62
+ .map(([key, file]) => {
63
+ return '"' + key + '": import.meta.ROLLUP_FILE_URL_' + file;
64
+ })
65
+ .join(',\n')}
66
+ };`;
67
+
68
+ // Find all import matches
69
+ const matches = Array.from(code.matchAll(importRegex));
70
+
71
+ if (matches.length > 0) {
72
+ // Get the last import's position
73
+ const lastImport = matches[matches.length - 1]!;
74
+ const lastImportEnd = lastImport.index + lastImport[0].length;
75
+
76
+ // Insert the code after the last import with a newline
77
+ const newCode = code.slice(0, lastImportEnd) + '\n\n' + codeToInject + '\n\n' + code.slice(lastImportEnd);
78
+
79
+ return {
80
+ code: newCode,
81
+ map: null,
82
+ };
83
+ }
84
+
85
+ // If no imports found, inject at the start of the file
86
+ return {
87
+ code: `${codeToInject}\n\n${code}`,
88
+ map: null,
89
+ };
90
+ }
91
+ },
92
+ } satisfies Plugin;
93
+ }
@@ -0,0 +1,37 @@
1
+ import * as babel from '@babel/core';
2
+ import type { Plugin } from 'rollup';
3
+
4
+ import { removeDeployer as removeDeployerBabelPlugin } from '../babel/remove-deployer';
5
+
6
+ export function removeDeployer(mastraEntry: string): Plugin {
7
+ return {
8
+ name: 'remove-deployer',
9
+ transform(code, id) {
10
+ if (id !== mastraEntry) {
11
+ return;
12
+ }
13
+
14
+ return new Promise((resolve, reject) => {
15
+ babel.transform(
16
+ code,
17
+ {
18
+ babelrc: false,
19
+ configFile: false,
20
+ filename: id,
21
+ plugins: [removeDeployerBabelPlugin],
22
+ },
23
+ (err, result) => {
24
+ if (err) {
25
+ return reject(err);
26
+ }
27
+
28
+ resolve({
29
+ code: result!.code!,
30
+ map: result!.map!,
31
+ });
32
+ },
33
+ );
34
+ });
35
+ },
36
+ } satisfies Plugin;
37
+ }
@@ -0,0 +1,54 @@
1
+ import { dirname, resolve } from 'path';
2
+ import { platform } from 'process';
3
+ import type { Plugin } from 'rollup';
4
+
5
+ function getTelemetryMachineFile() {
6
+ switch (platform) {
7
+ case 'darwin':
8
+ return 'getMachineId-darwin';
9
+ case 'linux':
10
+ return 'getMachineId-linux';
11
+ case 'freebsd':
12
+ return 'getMachineId-bsd';
13
+ case 'win32':
14
+ return 'getMachineId-win';
15
+ default:
16
+ return 'getMachineId-unsupported';
17
+ }
18
+ }
19
+
20
+ export function telemetryFix(): Plugin {
21
+ return {
22
+ name: 'telemetry-fix',
23
+ transform(code, id) {
24
+ if (id.includes('require-in-the-middle')) {
25
+ return code
26
+ .replace(
27
+ `const path = require('path')`,
28
+ `const path = require('path');
29
+ const { createRequire } = require('module');
30
+ const realRequire = createRequire(import.meta.url)`,
31
+ )
32
+ .replaceAll(`require.resolve`, `realRequire.resolve`);
33
+ }
34
+ },
35
+ resolveId(id: string, importer?: string) {
36
+ if (id === './machine-id/getMachineId' && importer) {
37
+ // rewrite dynamic require to correct file
38
+ return { id: resolve(dirname(importer), `./machine-id/${getTelemetryMachineFile()}.js`) };
39
+ }
40
+
41
+ if (id === 'formdata-node') {
42
+ return { id: 'formdata-node', external: false };
43
+ }
44
+ },
45
+ load(id: string) {
46
+ if (id.startsWith('formdata-node')) {
47
+ // Return an empty module
48
+ return 'export default {};';
49
+ }
50
+
51
+ return null;
52
+ },
53
+ } satisfies Plugin;
54
+ }
@@ -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
+ }
@@ -0,0 +1,12 @@
1
+ import { execSync } from 'child_process';
2
+ import { existsSync, mkdirSync } from 'fs';
3
+ import { join } from 'path';
4
+
5
+ export function upsertMastraDir({ dir = process.cwd() }: { dir?: string }) {
6
+ const dirPath = join(dir, '.mastra');
7
+
8
+ if (!existsSync(dirPath)) {
9
+ mkdirSync(dirPath, { recursive: true });
10
+ execSync(`echo ".mastra" >> .gitignore`);
11
+ }
12
+ }
@@ -0,0 +1,43 @@
1
+ import type { InputOptions, OutputOptions } from 'rollup';
2
+ import { watch } from 'rollup';
3
+
4
+ import { getInputOptions as getBundlerInputOptions } from './bundler';
5
+ import { aliasHono } from './plugins/hono-alias';
6
+
7
+ export async function getInputOptions(entryFile: string, platform: 'node' | 'browser') {
8
+ const inputOptions = await getBundlerInputOptions(
9
+ entryFile,
10
+ {
11
+ dependencies: new Map(),
12
+ externalDependencies: new Set(),
13
+ invalidChunks: new Set(),
14
+ },
15
+ platform,
16
+ );
17
+
18
+ if (Array.isArray(inputOptions.plugins)) {
19
+ // filter out node-resolve plugin so all node_modules are external
20
+ inputOptions.plugins = inputOptions.plugins.filter(
21
+ // @ts-ignore
22
+ plugin => !plugin || !plugin?.name || plugin.name !== 'node-resolve',
23
+ );
24
+
25
+ inputOptions.plugins.push(aliasHono());
26
+ }
27
+
28
+ return inputOptions;
29
+ }
30
+
31
+ export async function createWatcher(inputOptions: InputOptions, outputOptions: OutputOptions) {
32
+ const watcher = await watch({
33
+ ...inputOptions,
34
+ output: {
35
+ ...outputOptions,
36
+ format: 'esm',
37
+ entryFileNames: '[name].mjs',
38
+ chunkFileNames: '[name].mjs',
39
+ },
40
+ });
41
+
42
+ return watcher;
43
+ }
@@ -0,0 +1,144 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { writeFile } from 'node:fs/promises';
3
+ import { dirname, join } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { MastraBundler } from '@mastra/core/bundler';
6
+ import virtual from '@rollup/plugin-virtual';
7
+ import { copy, ensureDir } from 'fs-extra';
8
+ import fsExtra from 'fs-extra/esm';
9
+ import type { InputOptions, OutputOptions } from 'rollup';
10
+
11
+ import { analyzeBundle } from '../build/analyze';
12
+ import { createBundler as createBundlerUtil, getInputOptions } from '../build/bundler';
13
+ import { Deps } from '../build/deps';
14
+ import { writeTelemetryConfig } from '../build/telemetry';
15
+
16
+ export abstract class Bundler extends MastraBundler {
17
+ protected analyzeOutputDir = '.build';
18
+ protected outputDir = 'output';
19
+
20
+ constructor(name: string, component: 'BUNDLER' | 'DEPLOYER' = 'BUNDLER') {
21
+ super({ name, component });
22
+ }
23
+
24
+ async prepare(outputDirectory: string): Promise<void> {
25
+ // Clean up the output directory first
26
+ await fsExtra.emptyDir(outputDirectory);
27
+
28
+ await ensureDir(join(outputDirectory, this.analyzeOutputDir));
29
+ await ensureDir(join(outputDirectory, this.outputDir));
30
+ }
31
+
32
+ async writeInstrumentationFile(outputDirectory: string) {
33
+ const instrumentationFile = join(outputDirectory, 'instrumentation.mjs');
34
+ const __dirname = dirname(fileURLToPath(import.meta.url));
35
+
36
+ await copy(join(__dirname, 'templates', 'instrumentation-template.js'), instrumentationFile);
37
+ }
38
+
39
+ async writePackageJson(outputDirectory: string, dependencies: Map<string, string>) {
40
+ this.logger.debug(`Writing project's package.json`);
41
+ await ensureDir(outputDirectory);
42
+ const pkgPath = join(outputDirectory, 'package.json');
43
+
44
+ const dependenciesMap = new Map();
45
+ for (const [key, value] of dependencies.entries()) {
46
+ if (key.startsWith('@')) {
47
+ const pkgChunks = key.split('/');
48
+ dependenciesMap.set(`${pkgChunks[0]}/${pkgChunks[1]}`, value);
49
+ continue;
50
+ }
51
+ dependenciesMap.set(key, value);
52
+ }
53
+
54
+ dependenciesMap.set('@opentelemetry/instrumentation', 'latest');
55
+
56
+ await writeFile(
57
+ pkgPath,
58
+ JSON.stringify(
59
+ {
60
+ name: 'server',
61
+ version: '1.0.0',
62
+ description: '',
63
+ type: 'module',
64
+ main: 'index.mjs',
65
+ scripts: {
66
+ start: 'node ./index.mjs',
67
+ },
68
+ author: 'Mastra',
69
+ license: 'ISC',
70
+ dependencies: Object.fromEntries(dependenciesMap.entries()),
71
+ },
72
+ null,
73
+ 2,
74
+ ),
75
+ );
76
+ }
77
+
78
+ protected createBundler(inputOptions: InputOptions, outputOptions: Partial<OutputOptions> & { dir: string }) {
79
+ return createBundlerUtil(inputOptions, outputOptions);
80
+ }
81
+
82
+ protected async analyze(entry: string, mastraFile: string, outputDirectory: string) {
83
+ return await analyzeBundle(entry, mastraFile, join(outputDirectory, this.analyzeOutputDir), 'node', this.logger);
84
+ }
85
+
86
+ protected async installDependencies(outputDirectory: string, rootDir = process.cwd()) {
87
+ const deps = new Deps(rootDir);
88
+ deps.__setLogger(this.logger);
89
+
90
+ await deps.install({ dir: join(outputDirectory, this.outputDir) });
91
+ }
92
+
93
+ protected async _bundle(
94
+ serverFile: string,
95
+ mastraEntryFile: string,
96
+ outputDirectory: string,
97
+ bundleLocation: string = join(outputDirectory, this.outputDir),
98
+ ): Promise<void> {
99
+ this.logger.info('Start bundling Mastra');
100
+ const isVirtual = serverFile.includes('\n') || existsSync(serverFile);
101
+
102
+ const analyzedBundleInfo = await analyzeBundle(
103
+ serverFile,
104
+ mastraEntryFile,
105
+ join(outputDirectory, this.analyzeOutputDir),
106
+ 'node',
107
+ this.logger,
108
+ );
109
+
110
+ await writeTelemetryConfig(mastraEntryFile, join(outputDirectory, this.outputDir));
111
+
112
+ const dependenciesToInstall = Array.from(analyzedBundleInfo.externalDependencies).reduce((acc, dep) => {
113
+ acc.set(dep, 'latest');
114
+ return acc;
115
+ }, new Map<string, string>());
116
+
117
+ await this.writePackageJson(join(outputDirectory, this.outputDir), dependenciesToInstall);
118
+ await this.writeInstrumentationFile(join(outputDirectory, this.outputDir));
119
+
120
+ this.logger.info('Bundling Mastra application');
121
+ const inputOptions: InputOptions = await getInputOptions(mastraEntryFile, analyzedBundleInfo, 'node');
122
+
123
+ if (isVirtual) {
124
+ inputOptions.input = { index: '#entry' };
125
+
126
+ if (Array.isArray(inputOptions.plugins)) {
127
+ inputOptions.plugins.unshift(virtual({ '#entry': serverFile }));
128
+ } else {
129
+ inputOptions.plugins = [virtual({ '#entry': serverFile })];
130
+ }
131
+ } else {
132
+ inputOptions.input = { index: serverFile };
133
+ }
134
+
135
+ const bundler = await this.createBundler(inputOptions, { dir: bundleLocation });
136
+
137
+ await bundler.write();
138
+ this.logger.info('Bundling Mastra done');
139
+
140
+ this.logger.info('Installing dependencies');
141
+ await this.installDependencies(outputDirectory);
142
+ this.logger.info('Done installing dependencies');
143
+ }
144
+ }
@@ -0,0 +1,30 @@
1
+ import type { IDeployer } from '@mastra/core/deployer';
2
+
3
+ import { Deps } from '../build/deps.js';
4
+ import { FileService } from '../build/fs';
5
+ import { Bundler } from '../bundler';
6
+
7
+ export abstract class Deployer extends Bundler implements IDeployer {
8
+ deps: Deps = new Deps();
9
+
10
+ constructor(args: { name: string }) {
11
+ super(args.name, 'DEPLOYER');
12
+
13
+ this.deps.__setLogger(this.logger);
14
+ }
15
+
16
+ getEnvFiles(): Promise<string[]> {
17
+ const possibleFiles = ['.env.production', '.env'];
18
+
19
+ try {
20
+ const fileService = new FileService();
21
+ const envFile = fileService.getFirstExistingFile(possibleFiles);
22
+
23
+ return Promise.resolve([envFile]);
24
+ } catch {}
25
+
26
+ return Promise.resolve([]);
27
+ }
28
+
29
+ abstract deploy(outputDirectory: string): Promise<void>;
30
+ }
@@ -0,0 +1,2 @@
1
+ export * from './base.js';
2
+ export * from './log.js';