@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.
- package/.turbo/turbo-build.log +41 -0
- package/CHANGELOG.md +897 -0
- package/LICENSE +44 -0
- package/README.md +159 -0
- package/dist/_tsup-dts-rollup.d.cts +360 -0
- package/dist/_tsup-dts-rollup.d.ts +360 -0
- package/dist/build/analyze.cjs +367 -0
- package/dist/build/analyze.d.cts +1 -0
- package/dist/build/analyze.d.ts +1 -0
- package/dist/build/analyze.js +2 -0
- package/dist/build/bundler.cjs +353 -0
- package/dist/build/bundler.d.cts +2 -0
- package/dist/build/bundler.d.ts +2 -0
- package/dist/build/bundler.js +2 -0
- package/dist/build/index.cjs +1146 -0
- package/dist/build/index.d.cts +10 -0
- package/dist/build/index.d.ts +10 -0
- package/dist/build/index.js +5 -0
- package/dist/bundler/index.cjs +999 -0
- package/dist/bundler/index.d.cts +1 -0
- package/dist/bundler/index.d.ts +1 -0
- package/dist/bundler/index.js +5 -0
- package/dist/chunk-3ONBKVC4.js +113 -0
- package/dist/chunk-AXS5WSIK.js +290 -0
- package/dist/chunk-DTSFVNIF.js +260 -0
- package/dist/chunk-JMH7HCD6.js +274 -0
- package/dist/chunk-SGK37ZWD.js +254 -0
- package/dist/chunk-YNXJO2XU.js +69 -0
- package/dist/index.cjs +1229 -0
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +131 -0
- package/dist/server/index.cjs +4930 -0
- package/dist/server/index.d.cts +2 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +4923 -0
- package/dist/templates/instrumentation-template.js +86 -0
- package/eslint.config.js +6 -0
- package/global.d.ts +0 -0
- package/package.json +112 -0
- package/public/templates/instrumentation-template.js +86 -0
- package/src/build/analyze.ts +279 -0
- package/src/build/babel/fix-libsql.ts +41 -0
- package/src/build/babel/get-deployer.ts +54 -0
- package/src/build/babel/get-telemetry-config.ts +62 -0
- package/src/build/babel/remove-deployer.ts +43 -0
- package/src/build/bundle.ts +139 -0
- package/src/build/bundler.ts +135 -0
- package/src/build/deployer.ts +67 -0
- package/src/build/deps.ts +149 -0
- package/src/build/env.ts +76 -0
- package/src/build/fs.ts +66 -0
- package/src/build/index.ts +7 -0
- package/src/build/isNodeBuiltin.ts +7 -0
- package/src/build/plugins/fix-libsql.ts +69 -0
- package/src/build/plugins/hono-alias.ts +17 -0
- package/src/build/plugins/pino.ts +93 -0
- package/src/build/plugins/remove-deployer.ts +37 -0
- package/src/build/plugins/telemetry-fix.ts +54 -0
- package/src/build/telemetry.ts +76 -0
- package/src/build/utils.ts +12 -0
- package/src/build/watcher.ts +43 -0
- package/src/bundler/index.ts +144 -0
- package/src/deploy/base.ts +30 -0
- package/src/deploy/index.ts +2 -0
- package/src/deploy/log.ts +61 -0
- package/src/index.ts +3 -0
- package/src/server/handlers/agents.ts +209 -0
- package/src/server/handlers/client.ts +36 -0
- package/src/server/handlers/error.ts +29 -0
- package/src/server/handlers/logs.ts +53 -0
- package/src/server/handlers/memory.ts +196 -0
- package/src/server/handlers/prompt.ts +128 -0
- package/src/server/handlers/root.ts +6 -0
- package/src/server/handlers/telemetry.ts +48 -0
- package/src/server/handlers/tools.ts +114 -0
- package/src/server/handlers/utils.ts +15 -0
- package/src/server/handlers/vector.ts +149 -0
- package/src/server/handlers/workflows.ts +119 -0
- package/src/server/index.ts +1355 -0
- package/src/server/openapi.json +434 -0
- package/src/server/openapi.script.js +22 -0
- package/src/server/types.ts +4 -0
- package/src/server/welcome.ts +105 -0
- package/tsconfig.json +5 -0
- package/vitest.config.ts +8 -0
package/src/build/fs.ts
ADDED
|
@@ -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,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
|
+
}
|