@remotion/lambda-client 4.0.364 → 4.0.366
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/dist/cjs/index.js +1 -1
- package/dist/esm/index.mjs +1 -1
- package/package.json +4 -4
- package/.turbo/turbo-formatting.log +0 -4
- package/.turbo/turbo-lint.log +0 -25
- package/.turbo/turbo-make.log +0 -3
- package/bundle.ts +0 -20
- package/dist/cjs/test/concurrency-payload.test.d.ts +0 -1
- package/dist/cjs/test/encode-aws-url.test.d.ts +0 -1
- package/dist/cjs/test/price-calculation.test.d.ts +0 -1
- package/dist/cjs/test/pricing.test.d.ts +0 -1
- package/dist/cjs/test/request-handler.test.d.ts +0 -1
- package/dist/cjs/test/validate-disk-size-in-mb.test.d.ts +0 -1
- package/dist/test/concurrency-payload.test.d.ts +0 -1
- package/dist/test/concurrency-payload.test.js +0 -119
- package/dist/test/encode-aws-url.test.d.ts +0 -1
- package/dist/test/encode-aws-url.test.js +0 -8
- package/dist/test/price-calculation.test.d.ts +0 -1
- package/dist/test/price-calculation.test.js +0 -62
- package/dist/test/pricing.test.d.ts +0 -1
- package/dist/test/pricing.test.js +0 -27
- package/dist/test/request-handler.test.d.ts +0 -1
- package/dist/test/request-handler.test.js +0 -36
- package/dist/test/validate-disk-size-in-mb.test.d.ts +0 -1
- package/dist/test/validate-disk-size-in-mb.test.js +0 -14
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/eslint.config.mjs +0 -5
- package/src/app-router-webhook.ts +0 -73
- package/src/apply-lifecycle.ts +0 -30
- package/src/aws-clients.ts +0 -75
- package/src/aws-provider.ts +0 -139
- package/src/bucket-exists.ts +0 -35
- package/src/call-lambda-async.ts +0 -43
- package/src/call-lambda-streaming.ts +0 -226
- package/src/call-lambda-sync.ts +0 -59
- package/src/check-credentials.ts +0 -51
- package/src/clean-items.ts +0 -50
- package/src/constants.ts +0 -38
- package/src/content-disposition-header.ts +0 -64
- package/src/convert-to-serve-url.ts +0 -24
- package/src/create-bucket.ts +0 -87
- package/src/delete-file.ts +0 -38
- package/src/delete-function.ts +0 -28
- package/src/delete-render.ts +0 -114
- package/src/encode-aws-url-params.ts +0 -3
- package/src/estimate-price.ts +0 -95
- package/src/express-webhook.ts +0 -57
- package/src/get-account-id.ts +0 -22
- package/src/get-aws-client.ts +0 -63
- package/src/get-aws-urls.ts +0 -85
- package/src/get-buckets.ts +0 -84
- package/src/get-compositions-on-lambda.ts +0 -111
- package/src/get-credentials.ts +0 -81
- package/src/get-env-variable.ts +0 -15
- package/src/get-function-name.ts +0 -24
- package/src/get-function-version.ts +0 -49
- package/src/get-functions.ts +0 -114
- package/src/get-output-url-from-metadata.ts +0 -23
- package/src/get-render-progress.ts +0 -66
- package/src/get-s3-client.ts +0 -26
- package/src/get-service-client.ts +0 -195
- package/src/get-sites.ts +0 -136
- package/src/head-file.ts +0 -30
- package/src/index.ts +0 -152
- package/src/is-cli.ts +0 -7
- package/src/is-flaky-error.ts +0 -104
- package/src/is-in-lambda.ts +0 -5
- package/src/is-likely-to-have-aws-profile.ts +0 -55
- package/src/lambda-version-string.ts +0 -5
- package/src/lifecycle-rules.ts +0 -119
- package/src/lifecycle.ts +0 -44
- package/src/list-objects.ts +0 -87
- package/src/make-lambda-payload.ts +0 -328
- package/src/make-s3-url.ts +0 -13
- package/src/p-limit.ts +0 -75
- package/src/pages-router-webhook.ts +0 -68
- package/src/parse-function-name.ts +0 -24
- package/src/presign-url.ts +0 -121
- package/src/price-per-1s.ts +0 -863
- package/src/random-hash.ts +0 -10
- package/src/read-file.ts +0 -35
- package/src/regions.ts +0 -48
- package/src/render-media-on-lambda.ts +0 -227
- package/src/render-still-on-lambda.ts +0 -209
- package/src/runtime-preference.ts +0 -7
- package/src/speculate-function-name.ts +0 -60
- package/src/test/concurrency-payload.test.ts +0 -121
- package/src/test/encode-aws-url.test.ts +0 -7
- package/src/test/price-calculation.test.ts +0 -62
- package/src/test/pricing.test.ts +0 -32
- package/src/test/request-handler.test.ts +0 -42
- package/src/test/validate-disk-size-in-mb.test.ts +0 -15
- package/src/types.ts +0 -7
- package/src/validate-aws-region.ts +0 -14
- package/src/validate-bucketname.ts +0 -24
- package/src/validate-disk-size-in-mb.ts +0 -37
- package/src/validate-lambda-codec.ts +0 -28
- package/src/validate-memory-size.ts +0 -31
- package/src/validate-presign-expiration.ts +0 -46
- package/src/validate-serveurl.ts +0 -9
- package/src/validate-webhook-signature.ts +0 -42
- package/src/write-file.ts +0 -108
- package/tsconfig.json +0 -10
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import {ServerlessRoutines} from '@remotion/serverless-client';
|
|
2
|
-
import {expect, test} from 'bun:test';
|
|
3
|
-
import {makeLambdaRenderMediaPayload} from '../make-lambda-payload';
|
|
4
|
-
|
|
5
|
-
test('Should include concurrency field in payload', async () => {
|
|
6
|
-
const payload = await makeLambdaRenderMediaPayload({
|
|
7
|
-
region: 'us-east-1',
|
|
8
|
-
functionName: 'test-function',
|
|
9
|
-
serveUrl: 'https://example.com',
|
|
10
|
-
composition: 'test-composition',
|
|
11
|
-
inputProps: {},
|
|
12
|
-
codec: 'h264',
|
|
13
|
-
imageFormat: 'jpeg',
|
|
14
|
-
crf: undefined,
|
|
15
|
-
envVariables: {},
|
|
16
|
-
pixelFormat: undefined,
|
|
17
|
-
proResProfile: undefined,
|
|
18
|
-
x264Preset: null,
|
|
19
|
-
privacy: 'public',
|
|
20
|
-
jpegQuality: 80,
|
|
21
|
-
maxRetries: 1,
|
|
22
|
-
framesPerLambda: null,
|
|
23
|
-
concurrency: 10,
|
|
24
|
-
logLevel: 'info',
|
|
25
|
-
frameRange: null,
|
|
26
|
-
outName: null,
|
|
27
|
-
timeoutInMilliseconds: 30000,
|
|
28
|
-
chromiumOptions: {},
|
|
29
|
-
scale: 1,
|
|
30
|
-
everyNthFrame: 1,
|
|
31
|
-
numberOfGifLoops: null,
|
|
32
|
-
concurrencyPerLambda: 1,
|
|
33
|
-
downloadBehavior: {type: 'play-in-browser'},
|
|
34
|
-
muted: false,
|
|
35
|
-
overwrite: false,
|
|
36
|
-
audioBitrate: null,
|
|
37
|
-
videoBitrate: null,
|
|
38
|
-
encodingMaxRate: null,
|
|
39
|
-
encodingBufferSize: null,
|
|
40
|
-
webhook: null,
|
|
41
|
-
forceHeight: null,
|
|
42
|
-
forceWidth: null,
|
|
43
|
-
rendererFunctionName: null,
|
|
44
|
-
forceBucketName: null,
|
|
45
|
-
audioCodec: null,
|
|
46
|
-
colorSpace: null,
|
|
47
|
-
deleteAfter: null,
|
|
48
|
-
indent: false,
|
|
49
|
-
forcePathStyle: false,
|
|
50
|
-
metadata: null,
|
|
51
|
-
apiKey: null,
|
|
52
|
-
offthreadVideoCacheSizeInBytes: null,
|
|
53
|
-
mediaCacheSizeInBytes: null,
|
|
54
|
-
offthreadVideoThreads: null,
|
|
55
|
-
storageClass: null,
|
|
56
|
-
requestHandler: null,
|
|
57
|
-
preferLossless: false,
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
expect(payload.type).toBe(ServerlessRoutines.start);
|
|
61
|
-
expect(payload.concurrency).toBe(10);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
test('Should handle null concurrency', async () => {
|
|
65
|
-
const payload = await makeLambdaRenderMediaPayload({
|
|
66
|
-
region: 'us-east-1',
|
|
67
|
-
functionName: 'test-function',
|
|
68
|
-
serveUrl: 'https://example.com',
|
|
69
|
-
composition: 'test-composition',
|
|
70
|
-
inputProps: {},
|
|
71
|
-
codec: 'h264',
|
|
72
|
-
imageFormat: 'jpeg',
|
|
73
|
-
crf: undefined,
|
|
74
|
-
envVariables: {},
|
|
75
|
-
pixelFormat: undefined,
|
|
76
|
-
proResProfile: undefined,
|
|
77
|
-
x264Preset: null,
|
|
78
|
-
privacy: 'public',
|
|
79
|
-
jpegQuality: 80,
|
|
80
|
-
maxRetries: 1,
|
|
81
|
-
framesPerLambda: null,
|
|
82
|
-
concurrency: null,
|
|
83
|
-
logLevel: 'info',
|
|
84
|
-
frameRange: null,
|
|
85
|
-
outName: null,
|
|
86
|
-
timeoutInMilliseconds: 30000,
|
|
87
|
-
chromiumOptions: {},
|
|
88
|
-
scale: 1,
|
|
89
|
-
everyNthFrame: 1,
|
|
90
|
-
numberOfGifLoops: null,
|
|
91
|
-
concurrencyPerLambda: 1,
|
|
92
|
-
downloadBehavior: {type: 'play-in-browser'},
|
|
93
|
-
muted: false,
|
|
94
|
-
overwrite: false,
|
|
95
|
-
audioBitrate: null,
|
|
96
|
-
videoBitrate: null,
|
|
97
|
-
encodingMaxRate: null,
|
|
98
|
-
encodingBufferSize: null,
|
|
99
|
-
webhook: null,
|
|
100
|
-
forceHeight: null,
|
|
101
|
-
forceWidth: null,
|
|
102
|
-
rendererFunctionName: null,
|
|
103
|
-
forceBucketName: null,
|
|
104
|
-
audioCodec: null,
|
|
105
|
-
colorSpace: null,
|
|
106
|
-
deleteAfter: null,
|
|
107
|
-
indent: false,
|
|
108
|
-
forcePathStyle: false,
|
|
109
|
-
metadata: null,
|
|
110
|
-
apiKey: null,
|
|
111
|
-
offthreadVideoCacheSizeInBytes: null,
|
|
112
|
-
mediaCacheSizeInBytes: null,
|
|
113
|
-
offthreadVideoThreads: null,
|
|
114
|
-
storageClass: null,
|
|
115
|
-
requestHandler: null,
|
|
116
|
-
preferLossless: false,
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
expect(payload.type).toBe(ServerlessRoutines.start);
|
|
120
|
-
expect(payload.concurrency).toBe(null);
|
|
121
|
-
});
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import {estimatePriceFromMetadata} from '@remotion/serverless-client';
|
|
2
|
-
import {expect, test} from 'bun:test';
|
|
3
|
-
import {awsImplementation} from '../aws-provider';
|
|
4
|
-
|
|
5
|
-
test('Should not throw while calculating prices when time shifts occur', () => {
|
|
6
|
-
const aDate = Date.now();
|
|
7
|
-
process.env.AWS_REGION = 'us-east-1';
|
|
8
|
-
|
|
9
|
-
const price = estimatePriceFromMetadata({
|
|
10
|
-
memorySizeInMb: 1024,
|
|
11
|
-
renderMetadata: {
|
|
12
|
-
audioBitrate: null,
|
|
13
|
-
codec: 'h264',
|
|
14
|
-
compositionId: 'react-svg',
|
|
15
|
-
estimatedRenderLambdaInvokations: 10,
|
|
16
|
-
estimatedTotalLambdaInvokations: 10,
|
|
17
|
-
framesPerLambda: 10,
|
|
18
|
-
imageFormat: 'jpeg',
|
|
19
|
-
inputProps: {
|
|
20
|
-
type: 'payload',
|
|
21
|
-
payload: '{}',
|
|
22
|
-
},
|
|
23
|
-
lambdaVersion: '2021-11-29',
|
|
24
|
-
memorySizeInMb: 1024,
|
|
25
|
-
region: 'eu-central-1',
|
|
26
|
-
renderId: '123',
|
|
27
|
-
deleteAfter: null,
|
|
28
|
-
siteId: 'my-site',
|
|
29
|
-
startedDate: aDate + 1000,
|
|
30
|
-
totalChunks: 20,
|
|
31
|
-
type: 'video',
|
|
32
|
-
outName: 'out.mp4',
|
|
33
|
-
privacy: 'public',
|
|
34
|
-
everyNthFrame: 1,
|
|
35
|
-
frameRange: [0, 99],
|
|
36
|
-
audioCodec: null,
|
|
37
|
-
downloadBehavior: {type: 'play-in-browser'},
|
|
38
|
-
numberOfGifLoops: null,
|
|
39
|
-
muted: false,
|
|
40
|
-
metadata: {Author: 'Lunar'},
|
|
41
|
-
functionName: 'remotion-render-la8ffw',
|
|
42
|
-
rendererFunctionName: 'remotion-render-la8ffw',
|
|
43
|
-
dimensions: {
|
|
44
|
-
height: 1080,
|
|
45
|
-
width: 1920,
|
|
46
|
-
},
|
|
47
|
-
scale: 1,
|
|
48
|
-
},
|
|
49
|
-
diskSizeInMb: 512,
|
|
50
|
-
functionsInvoked: 1,
|
|
51
|
-
timings: [
|
|
52
|
-
{
|
|
53
|
-
chunk: 1,
|
|
54
|
-
rendered: aDate - 2000,
|
|
55
|
-
start: aDate,
|
|
56
|
-
},
|
|
57
|
-
],
|
|
58
|
-
region: 'eu-central-1',
|
|
59
|
-
providerSpecifics: awsImplementation,
|
|
60
|
-
});
|
|
61
|
-
expect(price?.accruedSoFar).toBeGreaterThanOrEqual(0);
|
|
62
|
-
});
|
package/src/test/pricing.test.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import {expect, test} from 'bun:test';
|
|
2
|
-
import {estimatePrice} from '../estimate-price';
|
|
3
|
-
|
|
4
|
-
test('Should calculate costs accurately', () => {
|
|
5
|
-
expect(
|
|
6
|
-
estimatePrice({
|
|
7
|
-
region: 'us-east-1',
|
|
8
|
-
durationInMiliseconds: 20000000,
|
|
9
|
-
memorySizeInMb: 2048,
|
|
10
|
-
diskSizeInMb: 512,
|
|
11
|
-
lambdasInvoked: 1,
|
|
12
|
-
}),
|
|
13
|
-
).toEqual(0.53334);
|
|
14
|
-
expect(
|
|
15
|
-
estimatePrice({
|
|
16
|
-
region: 'us-east-1',
|
|
17
|
-
durationInMilliseconds: 20000000,
|
|
18
|
-
memorySizeInMb: 2048,
|
|
19
|
-
diskSizeInMb: 10240,
|
|
20
|
-
lambdasInvoked: 1,
|
|
21
|
-
}),
|
|
22
|
-
).toEqual(0.53921);
|
|
23
|
-
expect(
|
|
24
|
-
estimatePrice({
|
|
25
|
-
region: 'us-east-1',
|
|
26
|
-
durationInMiliseconds: 20000000,
|
|
27
|
-
memorySizeInMb: 2048,
|
|
28
|
-
diskSizeInMb: 10240,
|
|
29
|
-
lambdasInvoked: 1,
|
|
30
|
-
}),
|
|
31
|
-
).toEqual(0.53921);
|
|
32
|
-
});
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import {expect, test} from 'bun:test';
|
|
2
|
-
import type {GetAwsClientInput} from '../get-aws-client';
|
|
3
|
-
import type {GetFunctionsInput} from '../get-functions';
|
|
4
|
-
import type {RequestHandler} from '../types';
|
|
5
|
-
|
|
6
|
-
test('RequestHandler type should be properly exported and defined', () => {
|
|
7
|
-
// Just verify the type can be imported
|
|
8
|
-
const requestHandler: RequestHandler = {
|
|
9
|
-
httpsAgent: {
|
|
10
|
-
maxSockets: 100,
|
|
11
|
-
},
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
expect(requestHandler).toBeDefined();
|
|
15
|
-
expect(typeof requestHandler).toBe('object');
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test('API input types should accept requestHandler option', () => {
|
|
19
|
-
// Test that the type checking works for various API inputs
|
|
20
|
-
const getAwsClientInput: GetAwsClientInput<'lambda'> = {
|
|
21
|
-
region: 'us-east-1',
|
|
22
|
-
service: 'lambda',
|
|
23
|
-
requestHandler: {
|
|
24
|
-
httpsAgent: {
|
|
25
|
-
maxSockets: 50,
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const getFunctionsInput: GetFunctionsInput = {
|
|
31
|
-
region: 'us-east-1',
|
|
32
|
-
compatibleOnly: false,
|
|
33
|
-
requestHandler: {
|
|
34
|
-
httpsAgent: {
|
|
35
|
-
maxSockets: 25,
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
expect(getAwsClientInput.requestHandler).toBeDefined();
|
|
41
|
-
expect(getFunctionsInput.requestHandler).toBeDefined();
|
|
42
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import {expect, test} from 'bun:test';
|
|
2
|
-
import {validateDiskSizeInMb} from '../validate-disk-size-in-mb';
|
|
3
|
-
|
|
4
|
-
test('Disk size tests', () => {
|
|
5
|
-
expect(() => validateDiskSizeInMb(512)).not.toThrow();
|
|
6
|
-
expect(() => validateDiskSizeInMb(10240)).not.toThrow();
|
|
7
|
-
expect(() => {
|
|
8
|
-
validateDiskSizeInMb(0);
|
|
9
|
-
}).toThrow(
|
|
10
|
-
/parameter 'diskSizeInMb' must be between 512 and 10240, but got 0/,
|
|
11
|
-
);
|
|
12
|
-
expect(() => {
|
|
13
|
-
validateDiskSizeInMb({});
|
|
14
|
-
}).toThrow(/parameter 'diskSizeInMb' must be a number, got a object/);
|
|
15
|
-
});
|
package/src/types.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type {LambdaClient} from '@aws-sdk/client-lambda';
|
|
2
|
-
|
|
3
|
-
// Extract RequestHandler type from AWS SDK LambdaClient constructor
|
|
4
|
-
type LambdaClientConfig = NonNullable<
|
|
5
|
-
ConstructorParameters<typeof LambdaClient>[0]
|
|
6
|
-
>;
|
|
7
|
-
export type RequestHandler = LambdaClientConfig['requestHandler'];
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type {AwsRegion} from './regions';
|
|
2
|
-
import {AWS_REGIONS} from './regions';
|
|
3
|
-
|
|
4
|
-
export function validateAwsRegion(
|
|
5
|
-
region: unknown,
|
|
6
|
-
): asserts region is AwsRegion {
|
|
7
|
-
if (!AWS_REGIONS.includes(region as AwsRegion)) {
|
|
8
|
-
throw new TypeError(
|
|
9
|
-
`${region} is not a supported AWS region. Must be one of: ${AWS_REGIONS.join(
|
|
10
|
-
', ',
|
|
11
|
-
)}`,
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import {REMOTION_BUCKET_PREFIX} from './constants';
|
|
2
|
-
import type {AwsRegion} from './regions';
|
|
3
|
-
import {AWS_REGIONS} from './regions';
|
|
4
|
-
|
|
5
|
-
export const parseBucketName = (
|
|
6
|
-
name: string,
|
|
7
|
-
): {
|
|
8
|
-
region: AwsRegion | null;
|
|
9
|
-
} => {
|
|
10
|
-
const parsed = name.match(
|
|
11
|
-
new RegExp(`^${REMOTION_BUCKET_PREFIX}(.*)-([a-z0-9A-Z]+)$`),
|
|
12
|
-
);
|
|
13
|
-
const region = parsed?.[1] as AwsRegion;
|
|
14
|
-
|
|
15
|
-
if (!region) {
|
|
16
|
-
return {region: null};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const realRegionFound = AWS_REGIONS.find(
|
|
20
|
-
(r) => r.replace(/-/g, '') === region,
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
return {region: realRegionFound ?? null};
|
|
24
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
MAX_EPHEMERAL_STORAGE_IN_MB,
|
|
3
|
-
MIN_EPHEMERAL_STORAGE_IN_MB,
|
|
4
|
-
} from './constants';
|
|
5
|
-
|
|
6
|
-
export const validateDiskSizeInMb = (diskSizeInMb: unknown) => {
|
|
7
|
-
if (typeof diskSizeInMb !== 'number') {
|
|
8
|
-
throw new TypeError(
|
|
9
|
-
`parameter 'diskSizeInMb' must be a number, got a ${typeof diskSizeInMb}`,
|
|
10
|
-
);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if (Number.isNaN(diskSizeInMb)) {
|
|
14
|
-
throw new TypeError(`parameter 'diskSizeInMb' must not be NaN, but is`);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (!Number.isFinite(diskSizeInMb)) {
|
|
18
|
-
throw new TypeError(
|
|
19
|
-
`parameter 'diskSizeInMb' must be finite, but is ${diskSizeInMb}`,
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (
|
|
24
|
-
diskSizeInMb < MIN_EPHEMERAL_STORAGE_IN_MB ||
|
|
25
|
-
diskSizeInMb > MAX_EPHEMERAL_STORAGE_IN_MB
|
|
26
|
-
) {
|
|
27
|
-
throw new TypeError(
|
|
28
|
-
`parameter 'diskSizeInMb' must be between ${MIN_EPHEMERAL_STORAGE_IN_MB} and ${MAX_EPHEMERAL_STORAGE_IN_MB}, but got ${diskSizeInMb}`,
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (diskSizeInMb % 1 !== 0) {
|
|
33
|
-
throw new TypeError(
|
|
34
|
-
`parameter 'diskSizeInMb' must be an integer but got ${diskSizeInMb}`,
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
import type {ServerlessCodec} from '@remotion/serverless-client';
|
|
3
|
-
import {serverlessCodecs} from '@remotion/serverless-client';
|
|
4
|
-
|
|
5
|
-
export const validateLambdaCodec = (codec: unknown): ServerlessCodec => {
|
|
6
|
-
if (typeof codec !== 'string') {
|
|
7
|
-
throw new TypeError('"codec" must be a string ');
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
if (!(serverlessCodecs as readonly string[]).includes(codec)) {
|
|
11
|
-
throw new TypeError(
|
|
12
|
-
"'" +
|
|
13
|
-
codec +
|
|
14
|
-
"' is not a valid codec for Lambda. The following values are supported: " +
|
|
15
|
-
serverlessCodecs.join(', '),
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if ((codec as string) === 'h264-mkv') {
|
|
20
|
-
console.warn(
|
|
21
|
-
'The "h264-mkv" codec for renderMediaOnLambda() is deprecated - it\'s now just "h264".',
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
return 'h264';
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return codec as ServerlessCodec;
|
|
28
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import {MAX_MEMORY, MIN_MEMORY} from './constants';
|
|
2
|
-
|
|
3
|
-
export const validateMemorySize = (memorySizeInMb: unknown) => {
|
|
4
|
-
if (typeof memorySizeInMb !== 'number') {
|
|
5
|
-
throw new TypeError(
|
|
6
|
-
`parameter 'memorySizeInMb' must be a number, got a ${typeof memorySizeInMb}`,
|
|
7
|
-
);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
if (Number.isNaN(memorySizeInMb)) {
|
|
11
|
-
throw new TypeError(`parameter 'memorySizeInMb' must not be NaN, but is`);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
if (!Number.isFinite(memorySizeInMb)) {
|
|
15
|
-
throw new TypeError(
|
|
16
|
-
`parameter 'memorySizeInMb' must be finite, but is ${memorySizeInMb}`,
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (memorySizeInMb < MIN_MEMORY || memorySizeInMb > MAX_MEMORY) {
|
|
21
|
-
throw new TypeError(
|
|
22
|
-
`parameter 'memorySizeInMb' must be between ${MIN_MEMORY} and ${MAX_MEMORY}, but got ${memorySizeInMb}`,
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (memorySizeInMb % 1 !== 0) {
|
|
27
|
-
throw new TypeError(
|
|
28
|
-
`parameter 'memorySizeInMb' must be an integer but got ${memorySizeInMb}`,
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
const MAX_PRESIGN_EXPIRATION = 604800;
|
|
2
|
-
const MIN_PRESIGN_EXPIRATION = 1;
|
|
3
|
-
|
|
4
|
-
export const validatePresignExpiration = (presignExpiration: unknown) => {
|
|
5
|
-
if (typeof presignExpiration === 'undefined' || presignExpiration === null) {
|
|
6
|
-
return;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
if (typeof presignExpiration !== 'number') {
|
|
10
|
-
throw new TypeError(
|
|
11
|
-
`'expiresIn' should be a number, but is ${JSON.stringify(
|
|
12
|
-
presignExpiration,
|
|
13
|
-
)}`,
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (Number.isNaN(presignExpiration)) {
|
|
18
|
-
throw new TypeError(`'expiresIn' should not be NaN, but is NaN`);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (!Number.isFinite(presignExpiration)) {
|
|
22
|
-
throw new TypeError(
|
|
23
|
-
`'expiresIn' should be finite but is ${presignExpiration}`,
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (presignExpiration % 1 !== 0) {
|
|
28
|
-
throw new TypeError(
|
|
29
|
-
`'expiresIn' should be an integer but is ${JSON.stringify(
|
|
30
|
-
presignExpiration,
|
|
31
|
-
)}`,
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (presignExpiration > MAX_PRESIGN_EXPIRATION) {
|
|
36
|
-
throw new TypeError(
|
|
37
|
-
`The 'expiresIn' parameter must be less or equal than ${MAX_PRESIGN_EXPIRATION} (7 days) as enforced by AWS`,
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (presignExpiration < MIN_PRESIGN_EXPIRATION) {
|
|
42
|
-
throw new TypeError(
|
|
43
|
-
`The 'expiresIn' parameter must be greater or equal than ${MIN_PRESIGN_EXPIRATION}`,
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
};
|
package/src/validate-serveurl.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @description Validates that the signature received by a webhook endpoint is authentic. If validation fails, an error is thrown.
|
|
3
|
-
* @see [Documentation](https://remotion.dev/docs/lambda/validatewebhooksignature)
|
|
4
|
-
*/
|
|
5
|
-
export const validateWebhookSignature = ({
|
|
6
|
-
secret,
|
|
7
|
-
body,
|
|
8
|
-
signatureHeader,
|
|
9
|
-
}: {
|
|
10
|
-
secret: string;
|
|
11
|
-
body: unknown;
|
|
12
|
-
signatureHeader: string;
|
|
13
|
-
}) => {
|
|
14
|
-
if (!secret) {
|
|
15
|
-
throw new TypeError(
|
|
16
|
-
"No 'secret' was provided to validateWebhookSignature().",
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (!body) {
|
|
21
|
-
throw new TypeError(
|
|
22
|
-
"No 'body' was provided to validateWebhookSignature().",
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (typeof require === 'undefined') {
|
|
27
|
-
throw new Error('validateWebhookSignature can only be called from Node.JS');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const Crypto = require('crypto');
|
|
31
|
-
|
|
32
|
-
const hmac = Crypto.createHmac('sha512', secret);
|
|
33
|
-
const signature = `sha512=${hmac.update(JSON.stringify(body)).digest('hex')}`;
|
|
34
|
-
|
|
35
|
-
if (!signatureHeader || signatureHeader === 'NO_SECRET_PROVIDED') {
|
|
36
|
-
throw new Error('No webhook signature was provided');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (signatureHeader !== signature) {
|
|
40
|
-
throw new Error('Signatures do not match');
|
|
41
|
-
}
|
|
42
|
-
};
|
package/src/write-file.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
import type {ObjectCannedACL, PutObjectCommandInput} from '@aws-sdk/client-s3';
|
|
3
|
-
import {PutObjectCommand} from '@aws-sdk/client-s3';
|
|
4
|
-
import {Upload} from '@aws-sdk/lib-storage';
|
|
5
|
-
import type {
|
|
6
|
-
CustomCredentials,
|
|
7
|
-
WriteFileInput,
|
|
8
|
-
} from '@remotion/serverless-client';
|
|
9
|
-
import mimeTypes from 'mime-types';
|
|
10
|
-
import type {AwsProvider} from './aws-provider';
|
|
11
|
-
import {getContentDispositionHeader} from './content-disposition-header';
|
|
12
|
-
import {getS3Client} from './get-s3-client';
|
|
13
|
-
|
|
14
|
-
// Files larger than 100MB will use multipart upload
|
|
15
|
-
const MULTIPART_THRESHOLD = 100 * 1024 * 1024; // 5MB in bytes
|
|
16
|
-
|
|
17
|
-
const tryLambdaWriteFile = async ({
|
|
18
|
-
bucketName,
|
|
19
|
-
key,
|
|
20
|
-
body,
|
|
21
|
-
region,
|
|
22
|
-
privacy,
|
|
23
|
-
expectedBucketOwner,
|
|
24
|
-
downloadBehavior,
|
|
25
|
-
customCredentials,
|
|
26
|
-
forcePathStyle,
|
|
27
|
-
storageClass,
|
|
28
|
-
requestHandler,
|
|
29
|
-
}: WriteFileInput<AwsProvider>): Promise<void> => {
|
|
30
|
-
const client = getS3Client({
|
|
31
|
-
region,
|
|
32
|
-
customCredentials: customCredentials as CustomCredentials<AwsProvider>,
|
|
33
|
-
forcePathStyle,
|
|
34
|
-
requestHandler,
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
const params: PutObjectCommandInput = {
|
|
38
|
-
Bucket: bucketName,
|
|
39
|
-
Key: key,
|
|
40
|
-
Body: body,
|
|
41
|
-
ACL:
|
|
42
|
-
privacy === 'no-acl'
|
|
43
|
-
? undefined
|
|
44
|
-
: ((privacy === 'private'
|
|
45
|
-
? 'private'
|
|
46
|
-
: 'public-read') as ObjectCannedACL),
|
|
47
|
-
ExpectedBucketOwner: customCredentials
|
|
48
|
-
? undefined
|
|
49
|
-
: (expectedBucketOwner ?? undefined),
|
|
50
|
-
ContentType: mimeTypes.lookup(key) || 'application/octet-stream',
|
|
51
|
-
ContentDisposition: getContentDispositionHeader(downloadBehavior),
|
|
52
|
-
StorageClass: storageClass ?? undefined,
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
// Determine file size
|
|
56
|
-
const size =
|
|
57
|
-
body instanceof Buffer || body instanceof Uint8Array
|
|
58
|
-
? body.length
|
|
59
|
-
: body instanceof Blob
|
|
60
|
-
? body.size
|
|
61
|
-
: typeof body === 'string'
|
|
62
|
-
? Buffer.from(body).length
|
|
63
|
-
: null;
|
|
64
|
-
|
|
65
|
-
// Use multipart upload for large files or streams (where we can't determine size)
|
|
66
|
-
if (size === null || size > MULTIPART_THRESHOLD) {
|
|
67
|
-
const upload = new Upload({
|
|
68
|
-
client,
|
|
69
|
-
params,
|
|
70
|
-
queueSize: 4, // number of concurrent uploads
|
|
71
|
-
partSize: 5 * 1024 * 1024, // chunk size of 5MB
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
await upload.done();
|
|
75
|
-
} else {
|
|
76
|
-
// Use regular PutObject for small files
|
|
77
|
-
await client.send(new PutObjectCommand(params));
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
export const lambdaWriteFileImplementation = async (
|
|
82
|
-
params: WriteFileInput<AwsProvider> & {
|
|
83
|
-
retries?: number;
|
|
84
|
-
},
|
|
85
|
-
): Promise<void> => {
|
|
86
|
-
const remainingRetries = params.retries ?? 2;
|
|
87
|
-
try {
|
|
88
|
-
await tryLambdaWriteFile(params);
|
|
89
|
-
} catch (err) {
|
|
90
|
-
if (remainingRetries === 0) {
|
|
91
|
-
throw err;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const backoff = 2 ** (2 - remainingRetries) * 2000;
|
|
95
|
-
await new Promise((resolve) => {
|
|
96
|
-
setTimeout(resolve, backoff);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
console.warn('Failed to write file to storage:');
|
|
100
|
-
console.warn(err);
|
|
101
|
-
console.warn(`Retrying (${remainingRetries} retries remaining)...`);
|
|
102
|
-
|
|
103
|
-
return lambdaWriteFileImplementation({
|
|
104
|
-
...params,
|
|
105
|
-
retries: remainingRetries - 1,
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
};
|
package/tsconfig.json
DELETED