@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
package/src/min-max.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Standard library Math.min and Math.max can throw
|
|
2
|
+
// if array length is very long. Fixing this with own implementation
|
|
3
|
+
|
|
4
|
+
export const min = (arr: number[]) => {
|
|
5
|
+
if (arr.length === 0) {
|
|
6
|
+
throw new Error('Array of 0 length');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let smallest = arr[0];
|
|
10
|
+
for (let i = 0; i < arr.length; i++) {
|
|
11
|
+
const elem = arr[i];
|
|
12
|
+
if (elem < smallest) {
|
|
13
|
+
smallest = elem;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return smallest;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const max = (arr: number[]) => {
|
|
21
|
+
if (arr.length === 0) {
|
|
22
|
+
throw new Error('Array of 0 length');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let biggest = arr[0];
|
|
26
|
+
for (let i = 0; i < arr.length; i++) {
|
|
27
|
+
const elem = arr[i];
|
|
28
|
+
if (elem > biggest) {
|
|
29
|
+
biggest = elem;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return biggest;
|
|
34
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type {ParsedTiming} from './types';
|
|
2
|
+
|
|
3
|
+
export const OVERHEAD_TIME_PER_LAMBDA = 100;
|
|
4
|
+
|
|
5
|
+
export type ExpensiveChunk = {
|
|
6
|
+
chunk: number;
|
|
7
|
+
frameRange: [number, number];
|
|
8
|
+
timeInMilliseconds: number;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const getMostExpensiveChunks = ({
|
|
12
|
+
parsedTimings,
|
|
13
|
+
framesPerFunction: framesPerLambda,
|
|
14
|
+
firstFrame,
|
|
15
|
+
lastFrame,
|
|
16
|
+
}: {
|
|
17
|
+
parsedTimings: ParsedTiming[];
|
|
18
|
+
framesPerFunction: number;
|
|
19
|
+
firstFrame: number;
|
|
20
|
+
lastFrame: number;
|
|
21
|
+
}): ExpensiveChunk[] => {
|
|
22
|
+
const mostExpensiveChunks = parsedTimings
|
|
23
|
+
.slice(0)
|
|
24
|
+
.sort((a, b) => {
|
|
25
|
+
const durA = a.rendered - a.start;
|
|
26
|
+
const durB = b.rendered - b.start;
|
|
27
|
+
|
|
28
|
+
return durB - durA;
|
|
29
|
+
})
|
|
30
|
+
.slice(0, 5);
|
|
31
|
+
|
|
32
|
+
return mostExpensiveChunks.map((c) => {
|
|
33
|
+
const isLastChunk = c.chunk === parsedTimings.length - 1;
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
timeInMilliseconds: c.rendered - c.start,
|
|
37
|
+
chunk: c.chunk,
|
|
38
|
+
frameRange: [
|
|
39
|
+
framesPerLambda * c.chunk + firstFrame,
|
|
40
|
+
isLastChunk
|
|
41
|
+
? lastFrame
|
|
42
|
+
: framesPerLambda * (c.chunk + 1) - 1 + firstFrame,
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type {PostRenderData} from './constants';
|
|
2
|
+
import type {RenderMetadata} from './render-metadata';
|
|
3
|
+
import type {
|
|
4
|
+
ChunkRetry,
|
|
5
|
+
CloudProvider,
|
|
6
|
+
ParsedTiming,
|
|
7
|
+
ReceivedArtifact,
|
|
8
|
+
} from './types';
|
|
9
|
+
import type {FunctionErrorInfo} from './write-error-to-storage';
|
|
10
|
+
|
|
11
|
+
export type OverallRenderProgress<Provider extends CloudProvider> = {
|
|
12
|
+
chunks: number[];
|
|
13
|
+
framesRendered: number;
|
|
14
|
+
framesEncoded: number;
|
|
15
|
+
combinedFrames: number;
|
|
16
|
+
timeToCombine: number | null;
|
|
17
|
+
timeToEncode: number | null;
|
|
18
|
+
timeToRenderFrames: number | null;
|
|
19
|
+
lambdasInvoked: number;
|
|
20
|
+
retries: ChunkRetry[];
|
|
21
|
+
postRenderData: PostRenderData<Provider> | null;
|
|
22
|
+
timings: ParsedTiming[];
|
|
23
|
+
renderMetadata: RenderMetadata<Provider> | null;
|
|
24
|
+
errors: FunctionErrorInfo[];
|
|
25
|
+
timeoutTimestamp: number;
|
|
26
|
+
functionLaunched: number;
|
|
27
|
+
serveUrlOpened: number | null;
|
|
28
|
+
compositionValidated: number | null;
|
|
29
|
+
receivedArtifact: ReceivedArtifact<Provider>[];
|
|
30
|
+
};
|
package/src/progress.ts
ADDED
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import {NoReactAPIs} from '@remotion/renderer/pure';
|
|
2
|
+
|
|
3
|
+
import {calculateChunkTimes} from './calculate-chunk-times';
|
|
4
|
+
import type {CustomCredentials} from './constants';
|
|
5
|
+
import {estimatePriceFromMetadata} from './estimate-price-from-bucket';
|
|
6
|
+
import {getExpectedOutName} from './expected-out-name';
|
|
7
|
+
import {formatCostsInfo} from './format-costs-info';
|
|
8
|
+
import {getOverallProgress} from './get-overall-progress';
|
|
9
|
+
import {getOverallProgressFromStorage} from './get-overall-progress-from-storage';
|
|
10
|
+
import {inspectErrors} from './inspect-error';
|
|
11
|
+
import {makeTimeoutError} from './make-timeout-error';
|
|
12
|
+
import type {ProviderSpecifics} from './provider-implementation';
|
|
13
|
+
import {lambdaRenderHasAudioVideo} from './render-has-audio-video';
|
|
14
|
+
import type {CleanupInfo, GenericRenderProgress} from './render-progress';
|
|
15
|
+
import {truthy} from './truthy';
|
|
16
|
+
import type {CloudProvider} from './types';
|
|
17
|
+
import type {EnhancedErrorInfo} from './write-error-to-storage';
|
|
18
|
+
|
|
19
|
+
export const getProgress = async <Provider extends CloudProvider>({
|
|
20
|
+
bucketName,
|
|
21
|
+
renderId,
|
|
22
|
+
expectedBucketOwner,
|
|
23
|
+
region,
|
|
24
|
+
memorySizeInMb,
|
|
25
|
+
timeoutInMilliseconds,
|
|
26
|
+
customCredentials,
|
|
27
|
+
providerSpecifics,
|
|
28
|
+
forcePathStyle,
|
|
29
|
+
functionName,
|
|
30
|
+
}: {
|
|
31
|
+
bucketName: string;
|
|
32
|
+
renderId: string;
|
|
33
|
+
expectedBucketOwner: string | null;
|
|
34
|
+
region: Provider['region'];
|
|
35
|
+
memorySizeInMb: number;
|
|
36
|
+
timeoutInMilliseconds: number;
|
|
37
|
+
customCredentials: CustomCredentials<Provider> | null;
|
|
38
|
+
providerSpecifics: ProviderSpecifics<Provider>;
|
|
39
|
+
forcePathStyle: boolean;
|
|
40
|
+
functionName: string;
|
|
41
|
+
}): Promise<GenericRenderProgress<Provider>> => {
|
|
42
|
+
const overallProgress = await getOverallProgressFromStorage({
|
|
43
|
+
renderId,
|
|
44
|
+
bucketName,
|
|
45
|
+
expectedBucketOwner,
|
|
46
|
+
region,
|
|
47
|
+
providerSpecifics,
|
|
48
|
+
forcePathStyle,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (overallProgress.postRenderData) {
|
|
52
|
+
if (!overallProgress.renderMetadata) {
|
|
53
|
+
throw new Error(
|
|
54
|
+
'No render metadata found even though render is finished',
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (overallProgress.renderMetadata.type === 'still') {
|
|
59
|
+
throw new Error(
|
|
60
|
+
"You don't need to call getRenderProgress() on a still render. Once you have obtained the `renderId`, the render is already done! 😉",
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const outData = getExpectedOutName({
|
|
65
|
+
renderMetadata: overallProgress.renderMetadata,
|
|
66
|
+
bucketName,
|
|
67
|
+
customCredentials,
|
|
68
|
+
bucketNamePrefix: providerSpecifics.getBucketPrefix(),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const totalFrameCount = NoReactAPIs.getFramesToRender(
|
|
72
|
+
overallProgress.renderMetadata.frameRange,
|
|
73
|
+
overallProgress.renderMetadata.everyNthFrame,
|
|
74
|
+
).length;
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
framesRendered: totalFrameCount,
|
|
78
|
+
bucket: bucketName,
|
|
79
|
+
renderSize: overallProgress.postRenderData.renderSize,
|
|
80
|
+
chunks: overallProgress.renderMetadata.totalChunks,
|
|
81
|
+
cleanup: {
|
|
82
|
+
doneIn: overallProgress.postRenderData.timeToCleanUp,
|
|
83
|
+
filesDeleted: overallProgress.postRenderData.filesCleanedUp,
|
|
84
|
+
minFilesToDelete: overallProgress.postRenderData.filesCleanedUp,
|
|
85
|
+
},
|
|
86
|
+
costs: {
|
|
87
|
+
accruedSoFar: overallProgress.postRenderData.cost.estimatedCost,
|
|
88
|
+
displayCost: overallProgress.postRenderData.cost.estimatedDisplayCost,
|
|
89
|
+
currency: overallProgress.postRenderData.cost.currency,
|
|
90
|
+
disclaimer: overallProgress.postRenderData.cost.disclaimer,
|
|
91
|
+
},
|
|
92
|
+
currentTime: Date.now(),
|
|
93
|
+
done: true,
|
|
94
|
+
encodingStatus: {
|
|
95
|
+
framesEncoded: totalFrameCount,
|
|
96
|
+
combinedFrames: totalFrameCount,
|
|
97
|
+
timeToCombine: overallProgress.postRenderData.timeToCombine,
|
|
98
|
+
},
|
|
99
|
+
errors: overallProgress.postRenderData.errors,
|
|
100
|
+
fatalErrorEncountered: false,
|
|
101
|
+
lambdasInvoked: overallProgress.renderMetadata.totalChunks,
|
|
102
|
+
outputFile: overallProgress.postRenderData.outputFile,
|
|
103
|
+
renderId,
|
|
104
|
+
timeToFinish: overallProgress.postRenderData.timeToFinish,
|
|
105
|
+
timeToFinishChunks: overallProgress.postRenderData.timeToRenderChunks,
|
|
106
|
+
timeToRenderFrames: overallProgress.postRenderData.timeToRenderFrames,
|
|
107
|
+
overallProgress: 1,
|
|
108
|
+
retriesInfo: overallProgress.postRenderData.retriesInfo,
|
|
109
|
+
outKey: outData.key,
|
|
110
|
+
outBucket: outData.renderBucketName,
|
|
111
|
+
mostExpensiveFrameRanges:
|
|
112
|
+
overallProgress.postRenderData.mostExpensiveFrameRanges ?? null,
|
|
113
|
+
timeToEncode: overallProgress.postRenderData.timeToEncode,
|
|
114
|
+
outputSizeInBytes: overallProgress.postRenderData.outputSize,
|
|
115
|
+
type: 'success',
|
|
116
|
+
estimatedBillingDurationInMilliseconds:
|
|
117
|
+
overallProgress.postRenderData.estimatedBillingDurationInMilliseconds,
|
|
118
|
+
timeToCombine: overallProgress.postRenderData.timeToCombine,
|
|
119
|
+
combinedFrames: totalFrameCount,
|
|
120
|
+
renderMetadata: overallProgress.renderMetadata,
|
|
121
|
+
timeoutTimestamp: overallProgress.timeoutTimestamp,
|
|
122
|
+
compositionValidated: overallProgress.compositionValidated,
|
|
123
|
+
functionLaunched: overallProgress.functionLaunched,
|
|
124
|
+
serveUrlOpened: overallProgress.serveUrlOpened,
|
|
125
|
+
artifacts: overallProgress.receivedArtifact,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const {renderMetadata} = overallProgress;
|
|
130
|
+
|
|
131
|
+
const errorExplanations = inspectErrors({
|
|
132
|
+
errors: overallProgress.errors,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const {hasAudio, hasVideo} = renderMetadata
|
|
136
|
+
? lambdaRenderHasAudioVideo(renderMetadata)
|
|
137
|
+
: {hasAudio: false, hasVideo: false};
|
|
138
|
+
|
|
139
|
+
const chunkCount = overallProgress.chunks.length ?? 0;
|
|
140
|
+
|
|
141
|
+
const cleanup: CleanupInfo = {
|
|
142
|
+
doneIn: null,
|
|
143
|
+
minFilesToDelete: 0,
|
|
144
|
+
filesDeleted: 0,
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
if (renderMetadata === null) {
|
|
148
|
+
return {
|
|
149
|
+
framesRendered: overallProgress.framesRendered ?? 0,
|
|
150
|
+
chunks: chunkCount,
|
|
151
|
+
done: false,
|
|
152
|
+
encodingStatus: {
|
|
153
|
+
framesEncoded: overallProgress.framesEncoded,
|
|
154
|
+
combinedFrames: overallProgress.combinedFrames,
|
|
155
|
+
timeToCombine: overallProgress.timeToCombine,
|
|
156
|
+
},
|
|
157
|
+
timeToRenderFrames: overallProgress.timeToRenderFrames,
|
|
158
|
+
costs: formatCostsInfo(0),
|
|
159
|
+
renderId,
|
|
160
|
+
renderMetadata,
|
|
161
|
+
bucket: bucketName,
|
|
162
|
+
outputFile: null,
|
|
163
|
+
timeToFinish: null,
|
|
164
|
+
errors: errorExplanations,
|
|
165
|
+
fatalErrorEncountered: errorExplanations.some(
|
|
166
|
+
(f) => f.isFatal && !f.willRetry,
|
|
167
|
+
),
|
|
168
|
+
currentTime: Date.now(),
|
|
169
|
+
renderSize: 0,
|
|
170
|
+
lambdasInvoked: overallProgress.lambdasInvoked ?? 0,
|
|
171
|
+
cleanup,
|
|
172
|
+
timeToFinishChunks: null,
|
|
173
|
+
overallProgress: getOverallProgress({
|
|
174
|
+
encoding: 0,
|
|
175
|
+
invoking: 0,
|
|
176
|
+
frames: 0,
|
|
177
|
+
gotComposition: overallProgress.compositionValidated,
|
|
178
|
+
visitedServeUrl: overallProgress.serveUrlOpened,
|
|
179
|
+
invokedLambda: overallProgress.lambdasInvoked,
|
|
180
|
+
combining: 0,
|
|
181
|
+
}),
|
|
182
|
+
retriesInfo: overallProgress.retries ?? [],
|
|
183
|
+
outKey: null,
|
|
184
|
+
outBucket: null,
|
|
185
|
+
mostExpensiveFrameRanges: null,
|
|
186
|
+
timeToEncode: overallProgress.timeToEncode,
|
|
187
|
+
outputSizeInBytes: null,
|
|
188
|
+
estimatedBillingDurationInMilliseconds: null,
|
|
189
|
+
combinedFrames: overallProgress.combinedFrames ?? 0,
|
|
190
|
+
timeToCombine: overallProgress.timeToCombine ?? null,
|
|
191
|
+
timeoutTimestamp: overallProgress.timeoutTimestamp,
|
|
192
|
+
type: 'success',
|
|
193
|
+
compositionValidated: overallProgress.compositionValidated,
|
|
194
|
+
functionLaunched: overallProgress.functionLaunched,
|
|
195
|
+
serveUrlOpened: overallProgress.serveUrlOpened,
|
|
196
|
+
artifacts: overallProgress.receivedArtifact,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const priceFromBucket = estimatePriceFromMetadata({
|
|
201
|
+
renderMetadata,
|
|
202
|
+
memorySizeInMb:
|
|
203
|
+
providerSpecifics.parseFunctionName(renderMetadata.rendererFunctionName)
|
|
204
|
+
?.memorySizeInMb ?? memorySizeInMb,
|
|
205
|
+
functionsInvoked: renderMetadata.estimatedRenderLambdaInvokations ?? 0,
|
|
206
|
+
diskSizeInMb: providerSpecifics.getEphemeralStorageForPriceCalculation(),
|
|
207
|
+
timings: overallProgress.timings ?? [],
|
|
208
|
+
region,
|
|
209
|
+
providerSpecifics,
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
const chunkMultiplier = [hasAudio, hasVideo].filter(truthy).length;
|
|
213
|
+
|
|
214
|
+
if (renderMetadata.type === 'still') {
|
|
215
|
+
throw new Error(
|
|
216
|
+
"You don't need to call getRenderProgress() on a still render. Once you have obtained the `renderId`, the render is already done! 😉",
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const allChunks =
|
|
221
|
+
(overallProgress.chunks ?? []).length / chunkMultiplier ===
|
|
222
|
+
(renderMetadata.totalChunks ?? Infinity);
|
|
223
|
+
|
|
224
|
+
const frameCount = NoReactAPIs.getFramesToRender(
|
|
225
|
+
renderMetadata.frameRange,
|
|
226
|
+
renderMetadata.everyNthFrame,
|
|
227
|
+
).length;
|
|
228
|
+
|
|
229
|
+
const missingChunks = new Array(renderMetadata.totalChunks)
|
|
230
|
+
.fill(true)
|
|
231
|
+
.map((_, i) => i)
|
|
232
|
+
.filter((index) => {
|
|
233
|
+
return (
|
|
234
|
+
typeof (overallProgress.chunks ?? []).find((c) => c === index) ===
|
|
235
|
+
'undefined'
|
|
236
|
+
);
|
|
237
|
+
});
|
|
238
|
+
// We add a 20 second buffer for it, since AWS timeshifts can be quite a lot. Once it's 20sec over the limit, we consider it timed out
|
|
239
|
+
|
|
240
|
+
// 1. If we have missing chunks, we consider it timed out
|
|
241
|
+
const isBeyondTimeoutAndMissingChunks =
|
|
242
|
+
Date.now() > renderMetadata.startedDate + timeoutInMilliseconds + 20000 &&
|
|
243
|
+
missingChunks &&
|
|
244
|
+
missingChunks.length > 0;
|
|
245
|
+
|
|
246
|
+
// 2. If we have no missing chunks, but the encoding is not done, even after the additional `merge` function has been spawned, we consider it timed out
|
|
247
|
+
const isBeyondTimeoutAndHasStitchTimeout =
|
|
248
|
+
Date.now() > renderMetadata.startedDate + timeoutInMilliseconds * 2 + 20000;
|
|
249
|
+
|
|
250
|
+
const allErrors: EnhancedErrorInfo[] = [
|
|
251
|
+
isBeyondTimeoutAndMissingChunks || isBeyondTimeoutAndHasStitchTimeout
|
|
252
|
+
? makeTimeoutError({
|
|
253
|
+
timeoutInMilliseconds,
|
|
254
|
+
renderMetadata,
|
|
255
|
+
renderId,
|
|
256
|
+
missingChunks: missingChunks ?? [],
|
|
257
|
+
region,
|
|
258
|
+
functionName,
|
|
259
|
+
providerSpecifics,
|
|
260
|
+
})
|
|
261
|
+
: null,
|
|
262
|
+
...errorExplanations,
|
|
263
|
+
].filter(truthy);
|
|
264
|
+
|
|
265
|
+
return {
|
|
266
|
+
framesRendered: overallProgress.framesRendered ?? 0,
|
|
267
|
+
chunks: chunkCount,
|
|
268
|
+
done: false,
|
|
269
|
+
encodingStatus: {
|
|
270
|
+
framesEncoded: overallProgress.framesEncoded,
|
|
271
|
+
combinedFrames: overallProgress.combinedFrames,
|
|
272
|
+
timeToCombine: overallProgress.timeToCombine,
|
|
273
|
+
},
|
|
274
|
+
timeToRenderFrames: overallProgress.timeToRenderFrames,
|
|
275
|
+
costs: priceFromBucket
|
|
276
|
+
? formatCostsInfo(priceFromBucket.accruedSoFar)
|
|
277
|
+
: formatCostsInfo(0),
|
|
278
|
+
renderId,
|
|
279
|
+
renderMetadata,
|
|
280
|
+
bucket: bucketName,
|
|
281
|
+
outputFile: null,
|
|
282
|
+
timeToFinish: null,
|
|
283
|
+
errors: allErrors,
|
|
284
|
+
fatalErrorEncountered: allErrors.some((f) => f.isFatal && !f.willRetry),
|
|
285
|
+
currentTime: Date.now(),
|
|
286
|
+
renderSize: 0,
|
|
287
|
+
lambdasInvoked: overallProgress.lambdasInvoked ?? 0,
|
|
288
|
+
cleanup,
|
|
289
|
+
timeToFinishChunks:
|
|
290
|
+
allChunks && overallProgress
|
|
291
|
+
? calculateChunkTimes({
|
|
292
|
+
type: 'absolute-time',
|
|
293
|
+
timings: overallProgress.timings,
|
|
294
|
+
})
|
|
295
|
+
: null,
|
|
296
|
+
overallProgress: getOverallProgress({
|
|
297
|
+
encoding: frameCount
|
|
298
|
+
? (overallProgress.framesEncoded ?? 0) / frameCount
|
|
299
|
+
: 0,
|
|
300
|
+
invoking:
|
|
301
|
+
(overallProgress.lambdasInvoked ?? 0) /
|
|
302
|
+
renderMetadata.estimatedRenderLambdaInvokations,
|
|
303
|
+
frames: (overallProgress.framesRendered ?? 0) / (frameCount ?? 1),
|
|
304
|
+
gotComposition: overallProgress.compositionValidated,
|
|
305
|
+
visitedServeUrl: overallProgress.serveUrlOpened,
|
|
306
|
+
invokedLambda: overallProgress.lambdasInvoked,
|
|
307
|
+
combining: overallProgress.combinedFrames / (frameCount ?? 1),
|
|
308
|
+
}),
|
|
309
|
+
retriesInfo: overallProgress.retries ?? [],
|
|
310
|
+
outKey: null,
|
|
311
|
+
outBucket: null,
|
|
312
|
+
mostExpensiveFrameRanges: null,
|
|
313
|
+
timeToEncode: overallProgress.timeToEncode,
|
|
314
|
+
outputSizeInBytes: null,
|
|
315
|
+
estimatedBillingDurationInMilliseconds: priceFromBucket
|
|
316
|
+
? priceFromBucket.estimatedBillingDurationInMilliseconds
|
|
317
|
+
: null,
|
|
318
|
+
combinedFrames: overallProgress.combinedFrames ?? 0,
|
|
319
|
+
timeToCombine: overallProgress.timeToCombine ?? null,
|
|
320
|
+
timeoutTimestamp: overallProgress.timeoutTimestamp,
|
|
321
|
+
type: 'success',
|
|
322
|
+
compositionValidated: overallProgress.compositionValidated,
|
|
323
|
+
functionLaunched: overallProgress.functionLaunched,
|
|
324
|
+
serveUrlOpened: overallProgress.serveUrlOpened,
|
|
325
|
+
artifacts: overallProgress.receivedArtifact,
|
|
326
|
+
};
|
|
327
|
+
};
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import type {LogLevel} from '@remotion/renderer';
|
|
2
|
+
import type {Readable} from 'node:stream';
|
|
3
|
+
import type {
|
|
4
|
+
CustomCredentials,
|
|
5
|
+
DownloadBehavior,
|
|
6
|
+
Privacy,
|
|
7
|
+
ServerlessRoutines,
|
|
8
|
+
} from './constants';
|
|
9
|
+
import type {RenderMetadata} from './render-metadata';
|
|
10
|
+
import type {ServerlessReturnValues} from './return-values';
|
|
11
|
+
import type {OnMessage} from './streaming/streaming';
|
|
12
|
+
import type {CallFunctionOptions, CloudProvider} from './types';
|
|
13
|
+
|
|
14
|
+
export type ParseFunctionName = (functionName: string) => {
|
|
15
|
+
version: string;
|
|
16
|
+
memorySizeInMb: number;
|
|
17
|
+
diskSizeInMb: number;
|
|
18
|
+
timeoutInSeconds: number;
|
|
19
|
+
} | null;
|
|
20
|
+
|
|
21
|
+
type DeleteFile<Provider extends CloudProvider> = (params: {
|
|
22
|
+
bucketName: string;
|
|
23
|
+
key: string;
|
|
24
|
+
region: Provider['region'];
|
|
25
|
+
customCredentials: CustomCredentials<Provider> | null;
|
|
26
|
+
forcePathStyle: boolean;
|
|
27
|
+
}) => Promise<void>;
|
|
28
|
+
|
|
29
|
+
export type BucketWithLocation<Provider extends CloudProvider> = {
|
|
30
|
+
name: string;
|
|
31
|
+
creationDate: number;
|
|
32
|
+
region: Provider['region'];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
type BucketExists<Provider extends CloudProvider> = (params: {
|
|
36
|
+
bucketName: string;
|
|
37
|
+
region: Provider['region'];
|
|
38
|
+
expectedBucketOwner: string | null;
|
|
39
|
+
forcePathStyle: boolean;
|
|
40
|
+
}) => Promise<boolean>;
|
|
41
|
+
|
|
42
|
+
type ReadFile<Provider extends CloudProvider> = (params: {
|
|
43
|
+
bucketName: string;
|
|
44
|
+
key: string;
|
|
45
|
+
region: Provider['region'];
|
|
46
|
+
expectedBucketOwner: string | null;
|
|
47
|
+
forcePathStyle: boolean;
|
|
48
|
+
}) => Promise<Readable>;
|
|
49
|
+
|
|
50
|
+
type GetBuckets<Provider extends CloudProvider> = (options: {
|
|
51
|
+
region: Provider['region'];
|
|
52
|
+
forceBucketName: string | null;
|
|
53
|
+
forcePathStyle: boolean;
|
|
54
|
+
}) => Promise<BucketWithLocation<Provider>[]>;
|
|
55
|
+
|
|
56
|
+
type CreateBucket<Provider extends CloudProvider> = (params: {
|
|
57
|
+
region: Provider['region'];
|
|
58
|
+
bucketName: string;
|
|
59
|
+
forcePathStyle: boolean;
|
|
60
|
+
skipPutAcl: boolean;
|
|
61
|
+
}) => Promise<void>;
|
|
62
|
+
|
|
63
|
+
type ApplyLifeCycle<Provider extends CloudProvider> = (params: {
|
|
64
|
+
enableFolderExpiry: boolean | null;
|
|
65
|
+
bucketName: string;
|
|
66
|
+
region: Provider['region'];
|
|
67
|
+
customCredentials: CustomCredentials<Provider> | null;
|
|
68
|
+
forcePathStyle: boolean;
|
|
69
|
+
}) => Promise<void>;
|
|
70
|
+
|
|
71
|
+
type ListObjects<Provider extends CloudProvider> = (params: {
|
|
72
|
+
bucketName: string;
|
|
73
|
+
prefix: string;
|
|
74
|
+
region: Provider['region'];
|
|
75
|
+
expectedBucketOwner: string | null;
|
|
76
|
+
forcePathStyle: boolean;
|
|
77
|
+
continuationToken?: string;
|
|
78
|
+
}) => Promise<BucketObject[]>;
|
|
79
|
+
|
|
80
|
+
type BucketObject = {
|
|
81
|
+
Key: string;
|
|
82
|
+
LastModified: Date;
|
|
83
|
+
ETag: string;
|
|
84
|
+
Size: number;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
type HeadFile<Provider extends CloudProvider> = (
|
|
88
|
+
params: HeadFileInput<Provider>,
|
|
89
|
+
) => Promise<HeadFileOutput>;
|
|
90
|
+
|
|
91
|
+
type RandomHash = () => string;
|
|
92
|
+
|
|
93
|
+
type ConvertToServeUrl<Provider extends CloudProvider> = (params: {
|
|
94
|
+
urlOrId: string;
|
|
95
|
+
region: Provider['region'];
|
|
96
|
+
bucketName: string;
|
|
97
|
+
}) => string;
|
|
98
|
+
|
|
99
|
+
type HeadFileOutput = {
|
|
100
|
+
LastModified?: Date | undefined;
|
|
101
|
+
ContentLength?: number | undefined;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export type DeleteFunctionInput<Provider extends CloudProvider> = {
|
|
105
|
+
region: Provider['region'];
|
|
106
|
+
functionName: string;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export type DeleteFunction<Provider extends CloudProvider> = (
|
|
110
|
+
options: DeleteFunctionInput<Provider>,
|
|
111
|
+
) => Promise<void>;
|
|
112
|
+
|
|
113
|
+
export type WriteFileInput<Provider extends CloudProvider> = {
|
|
114
|
+
bucketName: string;
|
|
115
|
+
key: string;
|
|
116
|
+
body: Readable | string | Uint8Array;
|
|
117
|
+
region: Provider['region'];
|
|
118
|
+
privacy: Privacy;
|
|
119
|
+
expectedBucketOwner: string | null;
|
|
120
|
+
downloadBehavior: DownloadBehavior | null;
|
|
121
|
+
customCredentials: CustomCredentials<Provider> | null;
|
|
122
|
+
forcePathStyle: boolean;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
type WriteFile<Provider extends CloudProvider> = (
|
|
126
|
+
params: WriteFileInput<Provider>,
|
|
127
|
+
) => Promise<void>;
|
|
128
|
+
|
|
129
|
+
type HeadFileInput<Provider extends CloudProvider> = {
|
|
130
|
+
bucketName: string;
|
|
131
|
+
key: string;
|
|
132
|
+
region: Provider['region'];
|
|
133
|
+
customCredentials: CustomCredentials<Provider> | null;
|
|
134
|
+
forcePathStyle: boolean;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export type CallFunctionAsync<Provider extends CloudProvider> = <
|
|
138
|
+
T extends ServerlessRoutines,
|
|
139
|
+
>({
|
|
140
|
+
functionName,
|
|
141
|
+
payload,
|
|
142
|
+
region,
|
|
143
|
+
timeoutInTest,
|
|
144
|
+
}: CallFunctionOptions<T, Provider>) => Promise<void>;
|
|
145
|
+
|
|
146
|
+
export type CallFunctionStreaming<Provider extends CloudProvider> = <
|
|
147
|
+
T extends ServerlessRoutines,
|
|
148
|
+
>(
|
|
149
|
+
options: CallFunctionOptions<T, Provider> & {
|
|
150
|
+
receivedStreamingPayload: OnMessage<Provider>;
|
|
151
|
+
retriesRemaining: number;
|
|
152
|
+
},
|
|
153
|
+
) => Promise<void>;
|
|
154
|
+
|
|
155
|
+
export type CallFunctionSync<Provider extends CloudProvider> = <
|
|
156
|
+
T extends ServerlessRoutines,
|
|
157
|
+
>({
|
|
158
|
+
functionName,
|
|
159
|
+
payload,
|
|
160
|
+
region,
|
|
161
|
+
timeoutInTest,
|
|
162
|
+
}: CallFunctionOptions<T, Provider>) => Promise<
|
|
163
|
+
ServerlessReturnValues<Provider>[T]
|
|
164
|
+
>;
|
|
165
|
+
|
|
166
|
+
export type GetOutputUrl<Provider extends CloudProvider> = (options: {
|
|
167
|
+
renderMetadata: RenderMetadata<Provider>;
|
|
168
|
+
bucketName: string;
|
|
169
|
+
customCredentials: CustomCredentials<Provider> | null;
|
|
170
|
+
currentRegion: Provider['region'];
|
|
171
|
+
}) => {url: string; key: string};
|
|
172
|
+
|
|
173
|
+
export type EstimatePriceInput<Provider extends CloudProvider> = {
|
|
174
|
+
region: Provider['region'];
|
|
175
|
+
memorySizeInMb: number;
|
|
176
|
+
diskSizeInMb: number;
|
|
177
|
+
lambdasInvoked: number;
|
|
178
|
+
durationInMilliseconds: number;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export type EstimatePrice<Provider extends CloudProvider> = ({
|
|
182
|
+
region,
|
|
183
|
+
memorySizeInMb,
|
|
184
|
+
diskSizeInMb,
|
|
185
|
+
lambdasInvoked,
|
|
186
|
+
...other
|
|
187
|
+
}: EstimatePriceInput<Provider>) => number;
|
|
188
|
+
|
|
189
|
+
export type GetLoggingUrlForRendererFunction<Provider extends CloudProvider> =
|
|
190
|
+
(options: {
|
|
191
|
+
region: Provider['region'];
|
|
192
|
+
functionName: string;
|
|
193
|
+
rendererFunctionName: string | null;
|
|
194
|
+
renderId: string;
|
|
195
|
+
chunk: null | number;
|
|
196
|
+
}) => string;
|
|
197
|
+
|
|
198
|
+
export type GetFunctionsInput<Provider extends CloudProvider> = {
|
|
199
|
+
region: Provider['region'];
|
|
200
|
+
compatibleOnly: boolean;
|
|
201
|
+
logLevel?: LogLevel;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
export type GetLoggingUrlForMethod<Provider extends CloudProvider> = (options: {
|
|
205
|
+
region: Provider['region'];
|
|
206
|
+
functionName: string;
|
|
207
|
+
method: ServerlessRoutines;
|
|
208
|
+
rendererFunctionName: string | null;
|
|
209
|
+
renderId: string;
|
|
210
|
+
}) => string;
|
|
211
|
+
|
|
212
|
+
export type GetAccountId<Provider extends CloudProvider> = (options: {
|
|
213
|
+
region: Provider['region'];
|
|
214
|
+
}) => Promise<string>;
|
|
215
|
+
|
|
216
|
+
export type FunctionInfo = {
|
|
217
|
+
functionName: string;
|
|
218
|
+
timeoutInSeconds: number;
|
|
219
|
+
memorySizeInMb: number;
|
|
220
|
+
version: string | null;
|
|
221
|
+
diskSizeInMb: number;
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
export type GetFunctions<Provider extends CloudProvider> = (
|
|
225
|
+
params: GetFunctionsInput<Provider>,
|
|
226
|
+
) => Promise<FunctionInfo[]>;
|
|
227
|
+
|
|
228
|
+
export type ProviderSpecifics<Provider extends CloudProvider> = {
|
|
229
|
+
getChromiumPath: () => string | null;
|
|
230
|
+
getBuckets: GetBuckets<Provider>;
|
|
231
|
+
getBucketPrefix: () => string;
|
|
232
|
+
createBucket: CreateBucket<Provider>;
|
|
233
|
+
applyLifeCycle: ApplyLifeCycle<Provider>;
|
|
234
|
+
listObjects: ListObjects<Provider>;
|
|
235
|
+
deleteFile: DeleteFile<Provider>;
|
|
236
|
+
bucketExists: BucketExists<Provider>;
|
|
237
|
+
randomHash: RandomHash;
|
|
238
|
+
readFile: ReadFile<Provider>;
|
|
239
|
+
writeFile: WriteFile<Provider>;
|
|
240
|
+
headFile: HeadFile<Provider>;
|
|
241
|
+
convertToServeUrl: ConvertToServeUrl<Provider>;
|
|
242
|
+
printLoggingHelper: boolean;
|
|
243
|
+
validateDeleteAfter: (lifeCycleValue: unknown) => void;
|
|
244
|
+
callFunctionAsync: CallFunctionAsync<Provider>;
|
|
245
|
+
callFunctionStreaming: CallFunctionStreaming<Provider>;
|
|
246
|
+
callFunctionSync: CallFunctionSync<Provider>;
|
|
247
|
+
estimatePrice: EstimatePrice<Provider>;
|
|
248
|
+
getLoggingUrlForRendererFunction: GetLoggingUrlForRendererFunction<Provider>;
|
|
249
|
+
getLoggingUrlForMethod: GetLoggingUrlForMethod<Provider>;
|
|
250
|
+
getEphemeralStorageForPriceCalculation: () => number;
|
|
251
|
+
getOutputUrl: GetOutputUrl<Provider>;
|
|
252
|
+
isFlakyError: (err: Error) => boolean;
|
|
253
|
+
serverStorageProductName: () => string;
|
|
254
|
+
getMaxStillInlinePayloadSize: () => number;
|
|
255
|
+
getMaxNonInlinePayloadSizePerFunction: () => number;
|
|
256
|
+
getAccountId: GetAccountId<Provider>;
|
|
257
|
+
deleteFunction: DeleteFunction<Provider>;
|
|
258
|
+
getFunctions: GetFunctions<Provider>;
|
|
259
|
+
parseFunctionName: ParseFunctionName;
|
|
260
|
+
checkCredentials: () => void;
|
|
261
|
+
};
|