@mastra/deployer-vercel 0.0.1-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.
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@mastra/deployer-vercel",
3
+ "version": "0.0.1-alpha.0",
4
+ "description": "",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/deployer-vercel.esm.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/deployer-vercel.esm.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.ts",
17
+ "default": "./dist/index.js"
18
+ }
19
+ },
20
+ "./package.json": "./package.json"
21
+ },
22
+ "keywords": [],
23
+ "author": "",
24
+ "license": "ISC",
25
+ "dependencies": {
26
+ "date-fns": "^4.1.0",
27
+ "dotenv": "^16.3.1",
28
+ "execa": "^9.3.1",
29
+ "vercel": "^39.3.0",
30
+ "zod": "^3.24.1",
31
+ "@mastra/core": "0.1.27-alpha.66",
32
+ "@mastra/deployer": "0.0.1-alpha.0"
33
+ },
34
+ "devDependencies": {
35
+ "@babel/preset-env": "^7.26.0",
36
+ "@babel/preset-typescript": "^7.26.0",
37
+ "@tsconfig/recommended": "^1.0.7",
38
+ "@types/jsdom": "^21.1.7",
39
+ "@types/node": "^22.9.0",
40
+ "@types/pg": "^8.11.10",
41
+ "dts-cli": "^2.0.5",
42
+ "vitest": "^2.1.8"
43
+ },
44
+ "scripts": {
45
+ "build": "dts build",
46
+ "build:dev": "dts watch",
47
+ "test": "vitest run"
48
+ }
49
+ }
package/src/index.ts ADDED
@@ -0,0 +1,170 @@
1
+ import { MastraDeployer } from '@mastra/core';
2
+ import { execa } from 'execa';
3
+ import { readFileSync, writeFileSync } from 'fs';
4
+ import { join } from 'path';
5
+
6
+ interface EnvVar {
7
+ key: string;
8
+ value: string;
9
+ target: ('production' | 'preview' | 'development')[];
10
+ type: 'plain' | 'secret';
11
+ }
12
+
13
+ interface VercelError {
14
+ message: string;
15
+ code: string;
16
+ }
17
+
18
+ export class VercelDeployer extends MastraDeployer {
19
+ constructor({ scope, env, projectName }: { env?: Record<string, any>; scope: string; projectName: string }) {
20
+ super({ scope, env, projectName });
21
+ }
22
+ writeFiles({ dir }: { dir: string }): void {
23
+ this.writeIndex({ dir });
24
+
25
+ writeFileSync(
26
+ join(dir, 'vercel.json'),
27
+ JSON.stringify(
28
+ {
29
+ version: 2,
30
+ builds: [
31
+ {
32
+ src: 'index.mjs',
33
+ use: '@vercel/node',
34
+ config: { includeFiles: ['**'] },
35
+ },
36
+ ],
37
+ routes: [
38
+ {
39
+ src: '/(.*)',
40
+ dest: 'index.mjs',
41
+ },
42
+ ],
43
+ },
44
+ null,
45
+ 2,
46
+ ),
47
+ );
48
+ }
49
+
50
+ private getProjectId({ dir }: { dir: string }): string {
51
+ const projectJsonPath = join(dir, '.vercel', 'project.json');
52
+ try {
53
+ const projectJson = JSON.parse(readFileSync(projectJsonPath, 'utf-8'));
54
+ return projectJson.projectId;
55
+ } catch (error) {
56
+ throw new Error('Could not find project ID. Make sure the project has been deployed first.');
57
+ }
58
+ }
59
+
60
+ async syncEnv({ scope, dir, token }: { token: string; dir: string; scope: string }) {
61
+ const envFiles = this.getEnvFiles();
62
+ const envVars: string[] = [];
63
+
64
+ for (const file of envFiles) {
65
+ const vars = this.parseEnvFile(file);
66
+ envVars.push(...vars);
67
+ }
68
+
69
+ console.log('Syncing environment variables...');
70
+
71
+ // Transform env vars into the format expected by Vercel API
72
+ const vercelEnvVars: EnvVar[] = envVars.map(envVar => {
73
+ const [key, value] = envVar.split('=');
74
+ if (!key || !value) {
75
+ throw new Error(`Invalid environment variable format: ${envVar}`);
76
+ }
77
+ return {
78
+ key,
79
+ value,
80
+ target: ['production', 'preview', 'development'],
81
+ type: 'plain',
82
+ };
83
+ });
84
+
85
+ try {
86
+ const projectId = this.getProjectId({ dir });
87
+
88
+ const response = await fetch(`https://api.vercel.com/v10/projects/${projectId}/env?teamId=${scope}&upsert=true`, {
89
+ method: 'POST',
90
+ headers: {
91
+ Authorization: `Bearer ${token}`,
92
+ 'Content-Type': 'application/json',
93
+ },
94
+ body: JSON.stringify(vercelEnvVars),
95
+ });
96
+
97
+ if (!response.ok) {
98
+ const error = (await response.json()) as VercelError;
99
+ throw new Error(`Failed to sync environment variables: ${error.message}`);
100
+ }
101
+
102
+ console.log('✓ Successfully synced environment variables');
103
+ } catch (error) {
104
+ if (error instanceof Error) {
105
+ console.error('Failed to sync environment variables:', error.message);
106
+ } else {
107
+ console.error('Failed to sync environment variables:', error);
108
+ }
109
+ throw error;
110
+ }
111
+ }
112
+
113
+ async deploy({ dir, token }: { dir: string; token: string }): Promise<void> {
114
+ // Get env vars for initial deployment
115
+ const envFiles = this.getEnvFiles();
116
+ const envVars: string[] = [];
117
+
118
+ for (const file of envFiles) {
119
+ const vars = this.parseEnvFile(file);
120
+ envVars.push(...vars);
121
+ }
122
+
123
+ // Create the command array with base arguments
124
+ const commandArgs = [
125
+ '--scope',
126
+ this.scope as string,
127
+ '--cwd',
128
+ dir,
129
+ 'deploy',
130
+ '--token',
131
+ token,
132
+ '--yes',
133
+ ...(this.projectName ? ['--name', this.projectName] : []),
134
+ ];
135
+
136
+ // Add env vars to initial deployment
137
+ for (const envVar of envVars) {
138
+ commandArgs.push('--env', envVar);
139
+ }
140
+
141
+ // Run the Vercel deploy command
142
+ // console.log('Running command:', 'vercel', commandArgs.join(' '));
143
+ const p2 = execa('vercel', commandArgs);
144
+
145
+ p2.stdout.pipe(process.stdout);
146
+ p2.stderr.pipe(process.stderr);
147
+
148
+ console.log('Deployment started on Vercel. You can wait for it to finish or exit this command.');
149
+ await p2;
150
+
151
+ if (envVars.length > 0) {
152
+ // Sync environment variables for future deployments
153
+ await this.syncEnv({ scope: this.scope, dir, token });
154
+ } else {
155
+ console.log('\nAdd your ENV vars to .env or your vercel dashboard.\n');
156
+ }
157
+ }
158
+
159
+ writeIndex({ dir }: { dir: string }): void {
160
+ writeFileSync(
161
+ join(dir, 'index.mjs'),
162
+ `
163
+ import { handle } from 'hono/vercel'
164
+ import { app } from './hono.mjs';
165
+ export const GET = handle(app);
166
+ export const POST = handle(app);
167
+ `,
168
+ );
169
+ }
170
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "moduleResolution": "bundler",
5
+ "outDir": "./dist",
6
+ "rootDir": "./src"
7
+ },
8
+ "include": ["src/**/*"],
9
+ "exclude": ["node_modules", "**/*.test.ts"]
10
+ }
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ include: ['src/**/*.test.ts'],
7
+ },
8
+ });