@remotion/serverless-client 4.0.261
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-make.log +6 -0
- package/LICENSE.md +49 -0
- package/README.md +5 -0
- package/bundle.ts +15 -0
- package/dist/await.d.ts +1 -0
- package/dist/await.js +2 -0
- package/dist/calculate-chunk-times.d.ts +5 -0
- package/dist/calculate-chunk-times.js +29 -0
- package/dist/compress-props.d.ts +30 -0
- package/dist/compress-props.js +97 -0
- package/dist/constants.d.ts +314 -0
- package/dist/constants.js +64 -0
- package/dist/docs-url.d.ts +1 -0
- package/dist/docs-url.js +4 -0
- package/dist/error-category.d.ts +3 -0
- package/dist/error-category.js +16 -0
- package/dist/esm/index.mjs +3467 -0
- package/dist/estimate-price-from-bucket.d.ts +15 -0
- package/dist/estimate-price-from-bucket.js +31 -0
- package/dist/expected-out-name.d.ts +10 -0
- package/dist/expected-out-name.js +53 -0
- package/dist/format-costs-info.d.ts +2 -0
- package/dist/format-costs-info.js +23 -0
- package/dist/get-custom-out-name.d.ts +7 -0
- package/dist/get-custom-out-name.js +33 -0
- package/dist/get-files-in-folder.d.ts +5 -0
- package/dist/get-files-in-folder.js +2 -0
- package/dist/get-or-create-bucket.d.ts +23 -0
- package/dist/get-or-create-bucket.js +44 -0
- package/dist/get-overall-progress-from-storage.d.ts +11 -0
- package/dist/get-overall-progress-from-storage.js +25 -0
- package/dist/get-overall-progress.d.ts +9 -0
- package/dist/get-overall-progress.js +23 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +105 -0
- package/dist/input-props-keys.d.ts +2 -0
- package/dist/input-props-keys.js +11 -0
- package/dist/inspect-error.d.ts +4 -0
- package/dist/inspect-error.js +39 -0
- package/dist/make-bucket-name.d.ts +3 -0
- package/dist/make-bucket-name.js +7 -0
- package/dist/make-timeout-error.d.ts +13 -0
- package/dist/make-timeout-error.js +32 -0
- package/dist/make-timeout-message.d.ts +12 -0
- package/dist/make-timeout-message.js +76 -0
- package/dist/min-max.d.ts +2 -0
- package/dist/min-max.js +33 -0
- package/dist/most-expensive-chunks.d.ts +13 -0
- package/dist/most-expensive-chunks.js +28 -0
- package/dist/overall-render-progress.d.ts +24 -0
- package/dist/overall-render-progress.js +2 -0
- package/dist/progress.d.ts +16 -0
- package/dist/progress.js +258 -0
- package/dist/provider-implementation.d.ts +193 -0
- package/dist/provider-implementation.js +2 -0
- package/dist/render-has-audio-video.d.ts +6 -0
- package/dist/render-has-audio-video.js +21 -0
- package/dist/render-metadata.d.ts +45 -0
- package/dist/render-metadata.js +2 -0
- package/dist/render-progress.d.ts +51 -0
- package/dist/render-progress.js +2 -0
- package/dist/return-values.d.ts +38 -0
- package/dist/return-values.js +2 -0
- package/dist/serialize-artifact.d.ts +9 -0
- package/dist/serialize-artifact.js +37 -0
- package/dist/stream-to-string.d.ts +2 -0
- package/dist/stream-to-string.js +14 -0
- package/dist/streaming/streaming.d.ts +101 -0
- package/dist/streaming/streaming.js +61 -0
- package/dist/test/dont-contain-forbidden.test.d.ts +1 -0
- package/dist/test/dont-contain-forbidden.test.js +18 -0
- package/dist/test/expected-out-name.test.d.ts +1 -0
- package/dist/test/expected-out-name.test.js +167 -0
- package/dist/test/min-max.test.d.ts +1 -0
- package/dist/test/min-max.test.js +24 -0
- package/dist/test/most-expensive-chunks.test.d.ts +1 -0
- package/dist/test/most-expensive-chunks.test.js +163 -0
- package/dist/truthy.d.ts +3 -0
- package/dist/truthy.js +6 -0
- package/dist/types.d.ts +55 -0
- package/dist/types.js +2 -0
- package/dist/validate-bucket-name.d.ts +7 -0
- package/dist/validate-bucket-name.js +16 -0
- package/dist/validate-download-behavior.d.ts +1 -0
- package/dist/validate-download-behavior.js +21 -0
- package/dist/validate-frames-per-function.d.ts +4 -0
- package/dist/validate-frames-per-function.js +29 -0
- package/dist/validate-outname.d.ts +9 -0
- package/dist/validate-outname.js +43 -0
- package/dist/validate-privacy.d.ts +2 -0
- package/dist/validate-privacy.js +14 -0
- package/dist/validate-webhook.d.ts +3 -0
- package/dist/validate-webhook.js +16 -0
- package/dist/webhook-types.d.ts +29 -0
- package/dist/webhook-types.js +2 -0
- package/dist/write-error-to-storage.d.ts +24 -0
- package/dist/write-error-to-storage.js +2 -0
- package/eslint.config.mjs +5 -0
- package/package.json +41 -0
- package/src/await.ts +1 -0
- package/src/calculate-chunk-times.ts +42 -0
- package/src/compress-props.ts +171 -0
- package/src/constants.ts +403 -0
- package/src/docs-url.ts +1 -0
- package/src/error-category.ts +14 -0
- package/src/estimate-price-from-bucket.ts +59 -0
- package/src/expected-out-name.ts +83 -0
- package/src/format-costs-info.ts +24 -0
- package/src/get-custom-out-name.ts +44 -0
- package/src/get-files-in-folder.ts +6 -0
- package/src/get-or-create-bucket.ts +79 -0
- package/src/get-overall-progress-from-storage.ts +44 -0
- package/src/get-overall-progress.ts +42 -0
- package/src/index.ts +125 -0
- package/src/input-props-keys.ts +7 -0
- package/src/inspect-error.ts +60 -0
- package/src/make-bucket-name.ts +9 -0
- package/src/make-timeout-error.ts +51 -0
- package/src/make-timeout-message.ts +118 -0
- package/src/min-max.ts +34 -0
- package/src/most-expensive-chunks.ts +46 -0
- package/src/overall-render-progress.ts +30 -0
- package/src/progress.ts +327 -0
- package/src/provider-implementation.ts +261 -0
- package/src/render-has-audio-video.ts +28 -0
- package/src/render-metadata.ts +60 -0
- package/src/render-progress.ts +58 -0
- package/src/return-values.ts +45 -0
- package/src/serialize-artifact.ts +51 -0
- package/src/stream-to-string.ts +14 -0
- package/src/streaming/streaming.ts +148 -0
- package/src/test/dont-contain-forbidden.test.ts +14 -0
- package/src/test/expected-out-name.test.ts +197 -0
- package/src/test/min-max.test.ts +25 -0
- package/src/test/most-expensive-chunks.test.ts +167 -0
- package/src/truthy.ts +5 -0
- package/src/types.ts +77 -0
- package/src/validate-bucket-name.ts +34 -0
- package/src/validate-download-behavior.ts +26 -0
- package/src/validate-frames-per-function.ts +54 -0
- package/src/validate-outname.ts +63 -0
- package/src/validate-privacy.ts +20 -0
- package/src/validate-webhook.ts +18 -0
- package/src/webhook-types.ts +36 -0
- package/src/write-error-to-storage.ts +23 -0
- package/tsconfig.json +18 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import {expect, test} from 'bun:test';
|
|
2
|
+
import {getMostExpensiveChunks} from '../most-expensive-chunks';
|
|
3
|
+
|
|
4
|
+
test('Should calculate most expensive chunks', () => {
|
|
5
|
+
const most = getMostExpensiveChunks({
|
|
6
|
+
parsedTimings: [
|
|
7
|
+
{
|
|
8
|
+
chunk: 0,
|
|
9
|
+
rendered: 1000,
|
|
10
|
+
start: 0,
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
chunk: 1,
|
|
14
|
+
rendered: 4000,
|
|
15
|
+
start: 2000,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
chunk: 2,
|
|
19
|
+
rendered: 5000,
|
|
20
|
+
start: 2000,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
chunk: 3,
|
|
24
|
+
rendered: 3000,
|
|
25
|
+
start: 2000,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
chunk: 4,
|
|
29
|
+
rendered: 100000,
|
|
30
|
+
start: 2000,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
chunk: 5,
|
|
34
|
+
rendered: 2001,
|
|
35
|
+
start: 2000,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
chunk: 6,
|
|
39
|
+
rendered: 2500,
|
|
40
|
+
start: 2000,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
framesPerFunction: 10,
|
|
44
|
+
firstFrame: 0,
|
|
45
|
+
lastFrame: 99,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
expect(most).toEqual([
|
|
49
|
+
{timeInMilliseconds: 98000, chunk: 4, frameRange: [40, 49]},
|
|
50
|
+
{timeInMilliseconds: 3000, chunk: 2, frameRange: [20, 29]},
|
|
51
|
+
{timeInMilliseconds: 2000, chunk: 1, frameRange: [10, 19]},
|
|
52
|
+
{timeInMilliseconds: 1000, chunk: 0, frameRange: [0, 9]},
|
|
53
|
+
{timeInMilliseconds: 1000, chunk: 3, frameRange: [30, 39]},
|
|
54
|
+
]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('Render starting from frame 10 should have correct offset', () => {
|
|
58
|
+
const framesPerFunction = 10;
|
|
59
|
+
const firstFrame = 10;
|
|
60
|
+
const lastFrame = 99;
|
|
61
|
+
const most = getMostExpensiveChunks({
|
|
62
|
+
parsedTimings: [
|
|
63
|
+
{
|
|
64
|
+
chunk: 0,
|
|
65
|
+
rendered: 1000,
|
|
66
|
+
start: 0,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
chunk: 1,
|
|
70
|
+
rendered: 4000,
|
|
71
|
+
start: 2000,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
chunk: 2,
|
|
75
|
+
rendered: 5000,
|
|
76
|
+
start: 2000,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
chunk: 3,
|
|
80
|
+
rendered: 3000,
|
|
81
|
+
start: 2000,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
chunk: 4,
|
|
85
|
+
rendered: 100000,
|
|
86
|
+
start: 2000,
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
chunk: 5,
|
|
90
|
+
rendered: 2001,
|
|
91
|
+
start: 2000,
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
chunk: 6,
|
|
95
|
+
rendered: 2500,
|
|
96
|
+
start: 2000,
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
framesPerFunction,
|
|
100
|
+
firstFrame,
|
|
101
|
+
lastFrame,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
expect(most).toEqual([
|
|
105
|
+
{timeInMilliseconds: 98000, chunk: 4, frameRange: [50, 59]},
|
|
106
|
+
{timeInMilliseconds: 3000, chunk: 2, frameRange: [30, 39]},
|
|
107
|
+
{timeInMilliseconds: 2000, chunk: 1, frameRange: [20, 29]},
|
|
108
|
+
{timeInMilliseconds: 1000, chunk: 0, frameRange: [10, 19]},
|
|
109
|
+
{timeInMilliseconds: 1000, chunk: 3, frameRange: [40, 49]},
|
|
110
|
+
]);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('Render starting from frame 10 and last chunk in most expensive should be corret', () => {
|
|
114
|
+
const framesPerFunction = 10;
|
|
115
|
+
const firstFrame = 10;
|
|
116
|
+
const lastFrame = 79;
|
|
117
|
+
const most = getMostExpensiveChunks({
|
|
118
|
+
parsedTimings: [
|
|
119
|
+
{
|
|
120
|
+
chunk: 0,
|
|
121
|
+
rendered: 1000,
|
|
122
|
+
start: 0,
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
chunk: 1,
|
|
126
|
+
rendered: 4000,
|
|
127
|
+
start: 2000,
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
chunk: 2,
|
|
131
|
+
rendered: 5000,
|
|
132
|
+
start: 2000,
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
chunk: 3,
|
|
136
|
+
rendered: 3000,
|
|
137
|
+
start: 2000,
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
chunk: 4,
|
|
141
|
+
rendered: 100000,
|
|
142
|
+
start: 2000,
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
chunk: 5,
|
|
146
|
+
rendered: 2001,
|
|
147
|
+
start: 2000,
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
chunk: 6,
|
|
151
|
+
rendered: 125000,
|
|
152
|
+
start: 2000,
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
framesPerFunction,
|
|
156
|
+
firstFrame,
|
|
157
|
+
lastFrame,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
expect(most).toEqual([
|
|
161
|
+
{timeInMilliseconds: 123000, chunk: 6, frameRange: [70, 79]},
|
|
162
|
+
{timeInMilliseconds: 98000, chunk: 4, frameRange: [50, 59]},
|
|
163
|
+
{timeInMilliseconds: 3000, chunk: 2, frameRange: [30, 39]},
|
|
164
|
+
{timeInMilliseconds: 2000, chunk: 1, frameRange: [20, 29]},
|
|
165
|
+
{timeInMilliseconds: 1000, chunk: 0, frameRange: [10, 19]},
|
|
166
|
+
]);
|
|
167
|
+
});
|
package/src/truthy.ts
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type {ServerlessPayloads, ServerlessRoutines} from './constants';
|
|
2
|
+
|
|
3
|
+
export interface CloudProvider<
|
|
4
|
+
Region extends string = string,
|
|
5
|
+
ReceivedArtifactType extends Record<string, unknown> = Record<
|
|
6
|
+
string,
|
|
7
|
+
unknown
|
|
8
|
+
>,
|
|
9
|
+
CreateFunctionSpecifics extends Record<string, unknown> = Record<
|
|
10
|
+
string,
|
|
11
|
+
unknown
|
|
12
|
+
>,
|
|
13
|
+
> {
|
|
14
|
+
type: string;
|
|
15
|
+
region: Region;
|
|
16
|
+
receivedArtifactType: ReceivedArtifactType;
|
|
17
|
+
creationFunctionOptions: CreateFunctionSpecifics;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type ReceivedArtifact<Provider extends CloudProvider> = {
|
|
21
|
+
filename: string;
|
|
22
|
+
sizeInBytes: number;
|
|
23
|
+
s3Url: string;
|
|
24
|
+
s3Key: string;
|
|
25
|
+
} & Provider['receivedArtifactType'];
|
|
26
|
+
|
|
27
|
+
export type CostsInfo = {
|
|
28
|
+
accruedSoFar: number;
|
|
29
|
+
displayCost: string;
|
|
30
|
+
currency: string;
|
|
31
|
+
disclaimer: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type RenderStillFunctionResponsePayload<Provider extends CloudProvider> =
|
|
35
|
+
{
|
|
36
|
+
type: 'success';
|
|
37
|
+
output: string;
|
|
38
|
+
outKey: string;
|
|
39
|
+
size: number;
|
|
40
|
+
bucketName: string;
|
|
41
|
+
sizeInBytes: number;
|
|
42
|
+
estimatedPrice: CostsInfo;
|
|
43
|
+
renderId: string;
|
|
44
|
+
receivedArtifacts: ReceivedArtifact<Provider>[];
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type ChunkRetry = {
|
|
48
|
+
chunk: number;
|
|
49
|
+
attempt: number;
|
|
50
|
+
time: number;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type ParsedTiming = {
|
|
54
|
+
chunk: number;
|
|
55
|
+
start: number;
|
|
56
|
+
rendered: number;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export type CallFunctionOptions<
|
|
60
|
+
T extends ServerlessRoutines,
|
|
61
|
+
Provider extends CloudProvider,
|
|
62
|
+
> = {
|
|
63
|
+
functionName: string;
|
|
64
|
+
type: T;
|
|
65
|
+
payload: ServerlessPayloads<Provider>[T];
|
|
66
|
+
region: Provider['region'];
|
|
67
|
+
timeoutInTest: number;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export type ObjectChunkTimingData = {
|
|
71
|
+
chunk: number;
|
|
72
|
+
frameRange: [number, number];
|
|
73
|
+
startDate: number;
|
|
74
|
+
timings: {
|
|
75
|
+
[key: number]: number;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const validateBucketName = ({
|
|
2
|
+
bucketName,
|
|
3
|
+
bucketNamePrefix,
|
|
4
|
+
options,
|
|
5
|
+
}: {
|
|
6
|
+
bucketName: unknown;
|
|
7
|
+
bucketNamePrefix: string;
|
|
8
|
+
options: {
|
|
9
|
+
mustStartWithRemotion: boolean;
|
|
10
|
+
};
|
|
11
|
+
}) => {
|
|
12
|
+
if (typeof bucketName !== 'string') {
|
|
13
|
+
throw new TypeError(
|
|
14
|
+
`'bucketName' must be a string, but is ${JSON.stringify(bucketName)}`,
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (
|
|
19
|
+
options.mustStartWithRemotion &&
|
|
20
|
+
!bucketName.startsWith(bucketNamePrefix)
|
|
21
|
+
) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`The bucketName parameter must start with ${bucketNamePrefix}.`,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (
|
|
28
|
+
!bucketName.match(
|
|
29
|
+
/^(?=^.{3,63}$)(?!^(\d+\.)+\d+$)(^(([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])\.)*([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])$)/,
|
|
30
|
+
)
|
|
31
|
+
) {
|
|
32
|
+
throw new Error(`The bucket ${bucketName} `);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type {DownloadBehavior} from './constants';
|
|
2
|
+
|
|
3
|
+
export const validateDownloadBehavior = (downloadBehavior: unknown) => {
|
|
4
|
+
if (downloadBehavior === null || downloadBehavior === undefined) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (typeof downloadBehavior !== 'object') {
|
|
9
|
+
throw new Error('downloadBehavior must be null or an object');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const behavior = downloadBehavior as DownloadBehavior;
|
|
13
|
+
if (behavior.type !== 'download' && behavior.type !== 'play-in-browser') {
|
|
14
|
+
throw new Error(
|
|
15
|
+
'Download behavior must be either "download" or "play-in-browser"',
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (behavior.type === 'download') {
|
|
20
|
+
if (typeof behavior.fileName !== 'string' && behavior.fileName !== null) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
'If "downloadBehavior.type" is "download", then fileName must be "null" or a string',
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {MINIMUM_FRAMES_PER_FUNCTIONS} from './constants';
|
|
2
|
+
|
|
3
|
+
export const validateFramesPerFunction = ({
|
|
4
|
+
framesPerFunction,
|
|
5
|
+
durationInFrames,
|
|
6
|
+
}: {
|
|
7
|
+
framesPerFunction: unknown;
|
|
8
|
+
durationInFrames: number;
|
|
9
|
+
}) => {
|
|
10
|
+
if (framesPerFunction === null) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (framesPerFunction === undefined) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (typeof framesPerFunction !== 'number') {
|
|
19
|
+
throw new TypeError(
|
|
20
|
+
`'framesPerLambda' needs to be a number, passed ${JSON.stringify(
|
|
21
|
+
framesPerFunction,
|
|
22
|
+
)}`,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!Number.isFinite(framesPerFunction)) {
|
|
27
|
+
throw new TypeError(
|
|
28
|
+
`'framesPerLambda' needs to be finite, passed ${framesPerFunction}`,
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (Number.isNaN(framesPerFunction)) {
|
|
33
|
+
throw new TypeError(
|
|
34
|
+
`'framesPerLambda' needs to be NaN, passed ${framesPerFunction}`,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (framesPerFunction % 1 !== 0) {
|
|
39
|
+
throw new TypeError(
|
|
40
|
+
`'framesPerLambda' needs to be an integer, passed ${framesPerFunction}`,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const effectiveMinimum = Math.min(
|
|
45
|
+
MINIMUM_FRAMES_PER_FUNCTIONS,
|
|
46
|
+
durationInFrames,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
if (framesPerFunction < effectiveMinimum) {
|
|
50
|
+
throw new TypeError(
|
|
51
|
+
`The framesPerLambda needs to be at least ${effectiveMinimum}, but is ${framesPerFunction}`,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type {AudioCodec, Codec} from '@remotion/renderer';
|
|
2
|
+
import {NoReactAPIs} from '@remotion/renderer/pure';
|
|
3
|
+
import type {OutNameInputWithoutCredentials} from './constants';
|
|
4
|
+
import {validateBucketName} from './validate-bucket-name';
|
|
5
|
+
|
|
6
|
+
const validateS3Key = (s3Key: string) => {
|
|
7
|
+
if (typeof s3Key !== 'string') {
|
|
8
|
+
throw new TypeError(
|
|
9
|
+
'The S3 key must be a string. Passed an object of type ' + typeof s3Key,
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html
|
|
14
|
+
if (!s3Key.match(/^([0-9a-zA-Z-!_.*'()/:&$@=;+,?]+)/g)) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
"The S3 Key must match the RegExp `/^([0-9a-zA-Z-!_.*'()/:&$@=;+,?]+)/g`. You passed: " +
|
|
17
|
+
s3Key +
|
|
18
|
+
'. Check for invalid characters.',
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const validateOutname = ({
|
|
24
|
+
outName,
|
|
25
|
+
codec,
|
|
26
|
+
audioCodecSetting,
|
|
27
|
+
separateAudioTo,
|
|
28
|
+
bucketNamePrefix,
|
|
29
|
+
}: {
|
|
30
|
+
outName: OutNameInputWithoutCredentials | undefined | null;
|
|
31
|
+
codec: Codec | null;
|
|
32
|
+
audioCodecSetting: AudioCodec | null;
|
|
33
|
+
separateAudioTo: string | null;
|
|
34
|
+
bucketNamePrefix: string;
|
|
35
|
+
}) => {
|
|
36
|
+
if (typeof outName === 'undefined' || outName === null) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (typeof outName !== 'string') {
|
|
41
|
+
validateS3Key(outName.key);
|
|
42
|
+
validateBucketName({
|
|
43
|
+
bucketName: outName.bucketName,
|
|
44
|
+
bucketNamePrefix,
|
|
45
|
+
options: {
|
|
46
|
+
mustStartWithRemotion: false,
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (codec) {
|
|
53
|
+
NoReactAPIs.validateOutputFilename({
|
|
54
|
+
codec,
|
|
55
|
+
audioCodecSetting,
|
|
56
|
+
extension: NoReactAPIs.getExtensionOfFilename(outName) as string,
|
|
57
|
+
preferLossless: false,
|
|
58
|
+
separateAudioTo,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
validateS3Key(outName);
|
|
63
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type {Privacy} from './constants';
|
|
2
|
+
|
|
3
|
+
export function validatePrivacy(
|
|
4
|
+
privacy: unknown,
|
|
5
|
+
allowPrivate: boolean,
|
|
6
|
+
): asserts privacy is Privacy {
|
|
7
|
+
if (typeof privacy !== 'string') {
|
|
8
|
+
throw new TypeError('Privacy must be a string');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (!allowPrivate && privacy === 'private') {
|
|
12
|
+
throw new TypeError('Privacy must be either "public" or "no-acl"');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (privacy !== 'private' && privacy !== 'public' && privacy !== 'no-acl') {
|
|
16
|
+
throw new TypeError(
|
|
17
|
+
'Privacy must be either "private", "public" or "no-acl"',
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type {WebhookOption} from './constants';
|
|
2
|
+
|
|
3
|
+
export const MAX_WEBHOOK_CUSTOM_DATA_SIZE = 1024;
|
|
4
|
+
|
|
5
|
+
export const validateWebhook = (webhook?: WebhookOption | null) => {
|
|
6
|
+
if (typeof webhook === 'undefined' || webhook === null) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (webhook.customData) {
|
|
11
|
+
const size = JSON.stringify(webhook.customData).length;
|
|
12
|
+
if (size > MAX_WEBHOOK_CUSTOM_DATA_SIZE) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
`Webhook "customData" must be less than ${MAX_WEBHOOK_CUSTOM_DATA_SIZE} bytes. Current size: ${size} bytes.`,
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type {AfterRenderCost} from './constants';
|
|
2
|
+
import type {EnhancedErrorInfo} from './write-error-to-storage';
|
|
3
|
+
|
|
4
|
+
type StaticWebhookPayload = {
|
|
5
|
+
renderId: string;
|
|
6
|
+
expectedBucketOwner: string;
|
|
7
|
+
bucketName: string;
|
|
8
|
+
customData: Record<string, unknown> | null;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type WebhookErrorPayload = StaticWebhookPayload & {
|
|
12
|
+
type: 'error';
|
|
13
|
+
errors: {
|
|
14
|
+
message: string;
|
|
15
|
+
name: string;
|
|
16
|
+
stack: string;
|
|
17
|
+
}[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type WebhookSuccessPayload = StaticWebhookPayload & {
|
|
21
|
+
type: 'success';
|
|
22
|
+
lambdaErrors: EnhancedErrorInfo[];
|
|
23
|
+
outputUrl: string | undefined;
|
|
24
|
+
outputFile: string | undefined;
|
|
25
|
+
timeToFinish: number | undefined;
|
|
26
|
+
costs: AfterRenderCost;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type WebhookTimeoutPayload = StaticWebhookPayload & {
|
|
30
|
+
type: 'timeout';
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type WebhookPayload =
|
|
34
|
+
| WebhookErrorPayload
|
|
35
|
+
| WebhookSuccessPayload
|
|
36
|
+
| WebhookTimeoutPayload;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type {FileNameAndSize} from './get-files-in-folder';
|
|
2
|
+
|
|
3
|
+
export type FunctionErrorInfo = {
|
|
4
|
+
type: 'renderer' | 'browser' | 'stitcher' | 'webhook' | 'artifact';
|
|
5
|
+
message: string;
|
|
6
|
+
name: string;
|
|
7
|
+
stack: string;
|
|
8
|
+
frame: number | null;
|
|
9
|
+
chunk: number | null;
|
|
10
|
+
isFatal: boolean;
|
|
11
|
+
attempt: number;
|
|
12
|
+
willRetry: boolean;
|
|
13
|
+
totalAttempts: number;
|
|
14
|
+
tmpDir: {files: FileNameAndSize[]; total: number} | null;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type EnhancedErrorInfo = FunctionErrorInfo & {
|
|
18
|
+
/**
|
|
19
|
+
* @deprecated Will always be an empty string.
|
|
20
|
+
*/
|
|
21
|
+
s3Location: string;
|
|
22
|
+
explanation: string | null;
|
|
23
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../tsconfig.settings.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"composite": true,
|
|
5
|
+
"rootDir": "./src",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"skipLibCheck": true
|
|
8
|
+
},
|
|
9
|
+
"include": ["src"],
|
|
10
|
+
"references": [
|
|
11
|
+
{
|
|
12
|
+
"path": "../licensing"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"path": "../streaming"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|