-
-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathremotion-deploy.ts
More file actions
173 lines (159 loc) · 5.42 KB
/
remotion-deploy.ts
File metadata and controls
173 lines (159 loc) · 5.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/**
* Remotion Lambda deployment service — one-time CLI setup only.
*
* This file imports deploySite, deployFunction, and getOrCreateBucket from
* @remotion/lambda, which pull in @rspack/core → @rspack/binding (a native
* binary). These MUST NOT be imported from Vercel serverless routes.
*
* Run this locally or in CI to set up the Lambda infrastructure, then store
* the resulting REMOTION_SERVE_URL and REMOTION_FUNCTION_NAME as env vars.
*
* @module lib/services/remotion-deploy
*/
import {
deploySite,
deployFunction,
getOrCreateBucket,
type AwsRegion,
} from "@remotion/lambda";
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function log(message: string, data?: Record<string, unknown>): void {
const ts = new Date().toISOString();
if (data) {
console.log(`[REMOTION] [${ts}] ${message}`, data);
} else {
console.log(`[REMOTION] [${ts}] ${message}`);
}
}
// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------
export interface DeployResult {
functionName: string;
serveUrl: string;
siteName: string;
bucketName: string;
region: string;
}
// ---------------------------------------------------------------------------
// Deploy helper (one-time setup)
// ---------------------------------------------------------------------------
/**
* Deploy the Remotion Lambda infrastructure (one-time setup).
*
* This will:
* 1. Create or reuse an S3 bucket for Remotion
* 2. Deploy the Remotion bundle (site) to S3
* 3. Deploy the Lambda function
*
* After running this, set the returned `serveUrl` as REMOTION_SERVE_URL
* and `functionName` as REMOTION_FUNCTION_NAME in your environment.
*
* @param entryPoint - Path to the Remotion entry file (e.g., "remotion/index.ts")
* @returns Deploy result with function name, serve URL, etc.
*/
export async function deployRemotionLambda(
entryPoint: string = "remotion/index.ts"
): Promise<DeployResult> {
const region = (process.env.REMOTION_AWS_REGION || "us-east-1") as AwsRegion;
if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY) {
throw new Error(
"[REMOTION] Cannot deploy: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY " +
"must be set in environment variables."
);
}
log("Starting Remotion Lambda deployment", { region, entryPoint });
// Step 1: Get or create the S3 bucket
log("Step 1/3: Getting or creating S3 bucket...");
let bucketName: string;
try {
const bucketResult = await getOrCreateBucket({ region });
bucketName = bucketResult.bucketName;
log(`Bucket ready: ${bucketName}`);
} catch (err: unknown) {
const message = err instanceof Error ? err.message : String(err);
throw new Error(
`[REMOTION] Failed to get or create S3 bucket in ${region}: ${message}. ` +
`Ensure your AWS credentials have S3 permissions.`
);
}
// Step 2: Deploy the site (bundle) to S3
log("Step 2/3: Deploying Remotion bundle to S3...");
let serveUrl: string;
let siteName: string;
try {
const siteResult = await deploySite({
entryPoint,
bucketName,
region,
siteName: "codingcat-video-pipeline",
options: {
onBundleProgress: (progress: number) => {
if (progress % 25 === 0 || progress === 100) {
log(`Bundle progress: ${progress}%`);
}
},
onUploadProgress: (upload) => {
if (upload.totalFiles > 0) {
const pct = Math.round(
(upload.filesUploaded / upload.totalFiles) * 100
);
if (pct % 25 === 0) {
log(
`Upload progress: ${upload.filesUploaded}/${upload.totalFiles} files (${pct}%)`
);
}
}
},
},
});
serveUrl = siteResult.serveUrl;
siteName = siteResult.siteName;
log(`Site deployed: ${serveUrl}`, { siteName });
} catch (err: unknown) {
const message = err instanceof Error ? err.message : String(err);
throw new Error(
`[REMOTION] Failed to deploy site to S3: ${message}. ` +
`Ensure the entry point "${entryPoint}" exists and is a valid Remotion project.`
);
}
// Step 3: Deploy the Lambda function
log("Step 3/3: Deploying Lambda function...");
let functionName: string;
try {
const fnResult = await deployFunction({
region,
timeoutInSeconds: 240,
memorySizeInMb: 2048,
createCloudWatchLogGroup: true,
cloudWatchLogRetentionPeriodInDays: 14,
diskSizeInMb: 2048,
});
functionName = fnResult.functionName;
log(
`Lambda function deployed: ${functionName}` +
(fnResult.alreadyExisted ? " (already existed)" : " (newly created)")
);
} catch (err: unknown) {
const message = err instanceof Error ? err.message : String(err);
throw new Error(
`[REMOTION] Failed to deploy Lambda function: ${message}. ` +
`Ensure your AWS credentials have Lambda and IAM permissions. ` +
`See: https://www.remotion.dev/docs/lambda/permissions`
);
}
log("Deployment complete! Set these environment variables:", {
REMOTION_SERVE_URL: serveUrl,
REMOTION_FUNCTION_NAME: functionName,
REMOTION_AWS_REGION: region,
});
return {
functionName,
serveUrl,
siteName,
bucketName,
region,
};
}