@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.
Files changed (147) hide show
  1. package/.turbo/turbo-make.log +6 -0
  2. package/LICENSE.md +49 -0
  3. package/README.md +5 -0
  4. package/bundle.ts +15 -0
  5. package/dist/await.d.ts +1 -0
  6. package/dist/await.js +2 -0
  7. package/dist/calculate-chunk-times.d.ts +5 -0
  8. package/dist/calculate-chunk-times.js +29 -0
  9. package/dist/compress-props.d.ts +30 -0
  10. package/dist/compress-props.js +97 -0
  11. package/dist/constants.d.ts +314 -0
  12. package/dist/constants.js +64 -0
  13. package/dist/docs-url.d.ts +1 -0
  14. package/dist/docs-url.js +4 -0
  15. package/dist/error-category.d.ts +3 -0
  16. package/dist/error-category.js +16 -0
  17. package/dist/esm/index.mjs +3467 -0
  18. package/dist/estimate-price-from-bucket.d.ts +15 -0
  19. package/dist/estimate-price-from-bucket.js +31 -0
  20. package/dist/expected-out-name.d.ts +10 -0
  21. package/dist/expected-out-name.js +53 -0
  22. package/dist/format-costs-info.d.ts +2 -0
  23. package/dist/format-costs-info.js +23 -0
  24. package/dist/get-custom-out-name.d.ts +7 -0
  25. package/dist/get-custom-out-name.js +33 -0
  26. package/dist/get-files-in-folder.d.ts +5 -0
  27. package/dist/get-files-in-folder.js +2 -0
  28. package/dist/get-or-create-bucket.d.ts +23 -0
  29. package/dist/get-or-create-bucket.js +44 -0
  30. package/dist/get-overall-progress-from-storage.d.ts +11 -0
  31. package/dist/get-overall-progress-from-storage.js +25 -0
  32. package/dist/get-overall-progress.d.ts +9 -0
  33. package/dist/get-overall-progress.js +23 -0
  34. package/dist/index.d.ts +50 -0
  35. package/dist/index.js +105 -0
  36. package/dist/input-props-keys.d.ts +2 -0
  37. package/dist/input-props-keys.js +11 -0
  38. package/dist/inspect-error.d.ts +4 -0
  39. package/dist/inspect-error.js +39 -0
  40. package/dist/make-bucket-name.d.ts +3 -0
  41. package/dist/make-bucket-name.js +7 -0
  42. package/dist/make-timeout-error.d.ts +13 -0
  43. package/dist/make-timeout-error.js +32 -0
  44. package/dist/make-timeout-message.d.ts +12 -0
  45. package/dist/make-timeout-message.js +76 -0
  46. package/dist/min-max.d.ts +2 -0
  47. package/dist/min-max.js +33 -0
  48. package/dist/most-expensive-chunks.d.ts +13 -0
  49. package/dist/most-expensive-chunks.js +28 -0
  50. package/dist/overall-render-progress.d.ts +24 -0
  51. package/dist/overall-render-progress.js +2 -0
  52. package/dist/progress.d.ts +16 -0
  53. package/dist/progress.js +258 -0
  54. package/dist/provider-implementation.d.ts +193 -0
  55. package/dist/provider-implementation.js +2 -0
  56. package/dist/render-has-audio-video.d.ts +6 -0
  57. package/dist/render-has-audio-video.js +21 -0
  58. package/dist/render-metadata.d.ts +45 -0
  59. package/dist/render-metadata.js +2 -0
  60. package/dist/render-progress.d.ts +51 -0
  61. package/dist/render-progress.js +2 -0
  62. package/dist/return-values.d.ts +38 -0
  63. package/dist/return-values.js +2 -0
  64. package/dist/serialize-artifact.d.ts +9 -0
  65. package/dist/serialize-artifact.js +37 -0
  66. package/dist/stream-to-string.d.ts +2 -0
  67. package/dist/stream-to-string.js +14 -0
  68. package/dist/streaming/streaming.d.ts +101 -0
  69. package/dist/streaming/streaming.js +61 -0
  70. package/dist/test/dont-contain-forbidden.test.d.ts +1 -0
  71. package/dist/test/dont-contain-forbidden.test.js +18 -0
  72. package/dist/test/expected-out-name.test.d.ts +1 -0
  73. package/dist/test/expected-out-name.test.js +167 -0
  74. package/dist/test/min-max.test.d.ts +1 -0
  75. package/dist/test/min-max.test.js +24 -0
  76. package/dist/test/most-expensive-chunks.test.d.ts +1 -0
  77. package/dist/test/most-expensive-chunks.test.js +163 -0
  78. package/dist/truthy.d.ts +3 -0
  79. package/dist/truthy.js +6 -0
  80. package/dist/types.d.ts +55 -0
  81. package/dist/types.js +2 -0
  82. package/dist/validate-bucket-name.d.ts +7 -0
  83. package/dist/validate-bucket-name.js +16 -0
  84. package/dist/validate-download-behavior.d.ts +1 -0
  85. package/dist/validate-download-behavior.js +21 -0
  86. package/dist/validate-frames-per-function.d.ts +4 -0
  87. package/dist/validate-frames-per-function.js +29 -0
  88. package/dist/validate-outname.d.ts +9 -0
  89. package/dist/validate-outname.js +43 -0
  90. package/dist/validate-privacy.d.ts +2 -0
  91. package/dist/validate-privacy.js +14 -0
  92. package/dist/validate-webhook.d.ts +3 -0
  93. package/dist/validate-webhook.js +16 -0
  94. package/dist/webhook-types.d.ts +29 -0
  95. package/dist/webhook-types.js +2 -0
  96. package/dist/write-error-to-storage.d.ts +24 -0
  97. package/dist/write-error-to-storage.js +2 -0
  98. package/eslint.config.mjs +5 -0
  99. package/package.json +41 -0
  100. package/src/await.ts +1 -0
  101. package/src/calculate-chunk-times.ts +42 -0
  102. package/src/compress-props.ts +171 -0
  103. package/src/constants.ts +403 -0
  104. package/src/docs-url.ts +1 -0
  105. package/src/error-category.ts +14 -0
  106. package/src/estimate-price-from-bucket.ts +59 -0
  107. package/src/expected-out-name.ts +83 -0
  108. package/src/format-costs-info.ts +24 -0
  109. package/src/get-custom-out-name.ts +44 -0
  110. package/src/get-files-in-folder.ts +6 -0
  111. package/src/get-or-create-bucket.ts +79 -0
  112. package/src/get-overall-progress-from-storage.ts +44 -0
  113. package/src/get-overall-progress.ts +42 -0
  114. package/src/index.ts +125 -0
  115. package/src/input-props-keys.ts +7 -0
  116. package/src/inspect-error.ts +60 -0
  117. package/src/make-bucket-name.ts +9 -0
  118. package/src/make-timeout-error.ts +51 -0
  119. package/src/make-timeout-message.ts +118 -0
  120. package/src/min-max.ts +34 -0
  121. package/src/most-expensive-chunks.ts +46 -0
  122. package/src/overall-render-progress.ts +30 -0
  123. package/src/progress.ts +327 -0
  124. package/src/provider-implementation.ts +261 -0
  125. package/src/render-has-audio-video.ts +28 -0
  126. package/src/render-metadata.ts +60 -0
  127. package/src/render-progress.ts +58 -0
  128. package/src/return-values.ts +45 -0
  129. package/src/serialize-artifact.ts +51 -0
  130. package/src/stream-to-string.ts +14 -0
  131. package/src/streaming/streaming.ts +148 -0
  132. package/src/test/dont-contain-forbidden.test.ts +14 -0
  133. package/src/test/expected-out-name.test.ts +197 -0
  134. package/src/test/min-max.test.ts +25 -0
  135. package/src/test/most-expensive-chunks.test.ts +167 -0
  136. package/src/truthy.ts +5 -0
  137. package/src/types.ts +77 -0
  138. package/src/validate-bucket-name.ts +34 -0
  139. package/src/validate-download-behavior.ts +26 -0
  140. package/src/validate-frames-per-function.ts +54 -0
  141. package/src/validate-outname.ts +63 -0
  142. package/src/validate-privacy.ts +20 -0
  143. package/src/validate-webhook.ts +18 -0
  144. package/src/webhook-types.ts +36 -0
  145. package/src/write-error-to-storage.ts +23 -0
  146. package/tsconfig.json +18 -0
  147. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,28 @@
1
+ import {NoReactAPIs} from '@remotion/renderer/pure';
2
+ import type {RenderMetadata} from './render-metadata';
3
+ import type {CloudProvider} from './types';
4
+
5
+ export const lambdaRenderHasAudioVideo = <Provider extends CloudProvider>(
6
+ renderMetadata: RenderMetadata<Provider>,
7
+ ): {
8
+ hasAudio: boolean;
9
+ hasVideo: boolean;
10
+ } => {
11
+ if (renderMetadata.type === 'still') {
12
+ throw new Error('Cannot merge stills');
13
+ }
14
+
15
+ const support = NoReactAPIs.codecSupportsMedia(renderMetadata.codec);
16
+
17
+ const hasVideo = renderMetadata
18
+ ? !NoReactAPIs.isAudioCodec(renderMetadata.codec)
19
+ : false;
20
+ const hasAudio = renderMetadata
21
+ ? !renderMetadata.muted && support.audio
22
+ : false;
23
+
24
+ return {
25
+ hasAudio,
26
+ hasVideo,
27
+ };
28
+ };
@@ -0,0 +1,60 @@
1
+ import type {
2
+ AudioCodec,
3
+ DeleteAfter,
4
+ StillImageFormat,
5
+ VideoImageFormat,
6
+ } from '@remotion/renderer';
7
+ import type {
8
+ DownloadBehavior,
9
+ OutNameInputWithoutCredentials,
10
+ Privacy,
11
+ SerializedInputProps,
12
+ ServerlessCodec,
13
+ } from './constants';
14
+ import type {CloudProvider} from './types';
15
+
16
+ type Discriminated =
17
+ | {
18
+ type: 'still';
19
+ imageFormat: StillImageFormat;
20
+ codec: null;
21
+ }
22
+ | {
23
+ type: 'video';
24
+ imageFormat: VideoImageFormat;
25
+ muted: boolean;
26
+ frameRange: [number, number];
27
+ everyNthFrame: number;
28
+ codec: ServerlessCodec;
29
+ };
30
+
31
+ type Dimensions = {
32
+ width: number;
33
+ height: number;
34
+ };
35
+
36
+ export type RenderMetadata<Provider extends CloudProvider> = Discriminated & {
37
+ siteId: string;
38
+ startedDate: number;
39
+ totalChunks: number;
40
+ estimatedTotalLambdaInvokations: number;
41
+ estimatedRenderLambdaInvokations: number;
42
+ compositionId: string;
43
+ audioCodec: AudioCodec | null;
44
+ inputProps: SerializedInputProps;
45
+ framesPerLambda: number;
46
+ memorySizeInMb: number;
47
+ functionName: string;
48
+ rendererFunctionName: string;
49
+ lambdaVersion: string;
50
+ region: Provider['region'];
51
+ renderId: string;
52
+ outName: OutNameInputWithoutCredentials | undefined;
53
+ privacy: Privacy;
54
+ deleteAfter: DeleteAfter | null;
55
+ numberOfGifLoops: number | null;
56
+ audioBitrate: string | null;
57
+ downloadBehavior: DownloadBehavior;
58
+ metadata: Record<string, string> | null;
59
+ dimensions: Dimensions;
60
+ };
@@ -0,0 +1,58 @@
1
+ import type {ExpensiveChunk} from './most-expensive-chunks';
2
+ import type {RenderMetadata} from './render-metadata';
3
+ import type {
4
+ ChunkRetry,
5
+ CloudProvider,
6
+ CostsInfo,
7
+ ReceivedArtifact,
8
+ } from './types';
9
+ import type {EnhancedErrorInfo} from './write-error-to-storage';
10
+
11
+ export type CleanupInfo = {
12
+ doneIn: number | null;
13
+ minFilesToDelete: number;
14
+ filesDeleted: number;
15
+ };
16
+
17
+ type EncodingProgress = {
18
+ framesEncoded: number;
19
+ combinedFrames: number;
20
+ timeToCombine: number | null;
21
+ };
22
+
23
+ export type GenericRenderProgress<Provider extends CloudProvider> = {
24
+ chunks: number;
25
+ done: boolean;
26
+ encodingStatus: EncodingProgress | null;
27
+ costs: CostsInfo;
28
+ renderId: string;
29
+ renderMetadata: RenderMetadata<Provider> | null;
30
+ bucket: string;
31
+ outputFile: string | null;
32
+ outKey: string | null;
33
+ outBucket: string | null;
34
+ timeToFinish: number | null;
35
+ errors: EnhancedErrorInfo[];
36
+ fatalErrorEncountered: boolean;
37
+ currentTime: number;
38
+ renderSize: number;
39
+ lambdasInvoked: number;
40
+ cleanup: CleanupInfo | null;
41
+ timeToFinishChunks: number | null;
42
+ timeToRenderFrames: number | null;
43
+ timeToEncode: number | null;
44
+ overallProgress: number;
45
+ retriesInfo: ChunkRetry[];
46
+ mostExpensiveFrameRanges: ExpensiveChunk[] | null;
47
+ framesRendered: number;
48
+ outputSizeInBytes: number | null;
49
+ type: 'success';
50
+ estimatedBillingDurationInMilliseconds: number | null;
51
+ combinedFrames: number;
52
+ timeToCombine: number | null;
53
+ timeoutTimestamp: number;
54
+ functionLaunched: number;
55
+ serveUrlOpened: number | null;
56
+ compositionValidated: number | null;
57
+ artifacts: ReceivedArtifact<Provider>[];
58
+ };
@@ -0,0 +1,45 @@
1
+ import type {VideoConfig} from 'remotion/no-react';
2
+ import type {ServerlessRoutines} from './constants';
3
+ import type {GenericRenderProgress} from './render-progress';
4
+ import type {CloudProvider} from './types';
5
+
6
+ export type OrError<T> =
7
+ | T
8
+ | {
9
+ type: 'error';
10
+ message: string;
11
+ stack: string;
12
+ };
13
+
14
+ export interface ServerlessReturnValues<Provider extends CloudProvider> {
15
+ [ServerlessRoutines.start]: Promise<{
16
+ type: 'success';
17
+ bucketName: string;
18
+ renderId: string;
19
+ }>;
20
+ [ServerlessRoutines.launch]: Promise<{
21
+ type: 'success';
22
+ }>;
23
+ [ServerlessRoutines.renderer]: Promise<{
24
+ type: 'success';
25
+ }>;
26
+ [ServerlessRoutines.status]: Promise<GenericRenderProgress<Provider>>;
27
+ [ServerlessRoutines.info]: {
28
+ version: string;
29
+ type: 'success';
30
+ };
31
+ [ServerlessRoutines.still]: Promise<
32
+ | {
33
+ type: 'success';
34
+ }
35
+ | {
36
+ type: 'error';
37
+ message: string;
38
+ stack: string;
39
+ }
40
+ >;
41
+ [ServerlessRoutines.compositions]: Promise<{
42
+ compositions: VideoConfig[];
43
+ type: 'success';
44
+ }>;
45
+ }
@@ -0,0 +1,51 @@
1
+ import type {EmittedArtifact} from '@remotion/renderer';
2
+
3
+ export type SerializedArtifact = {
4
+ filename: string;
5
+ stringContent: string;
6
+ frame: number;
7
+ binary: boolean;
8
+ };
9
+
10
+ export const deserializeArtifact = (
11
+ serializedArtifact: SerializedArtifact,
12
+ ): EmittedArtifact => {
13
+ if (serializedArtifact.binary) {
14
+ const content = new TextEncoder().encode(
15
+ atob(serializedArtifact.stringContent),
16
+ );
17
+
18
+ return {
19
+ filename: serializedArtifact.filename,
20
+ content,
21
+ frame: serializedArtifact.frame,
22
+ };
23
+ }
24
+
25
+ return {
26
+ filename: serializedArtifact.filename,
27
+ content: serializedArtifact.stringContent,
28
+ frame: serializedArtifact.frame,
29
+ };
30
+ };
31
+
32
+ export const serializeArtifact = (
33
+ artifact: EmittedArtifact,
34
+ ): SerializedArtifact => {
35
+ if (artifact.content instanceof Uint8Array) {
36
+ const b64encoded = btoa(new TextDecoder('utf8').decode(artifact.content));
37
+ return {
38
+ filename: artifact.filename,
39
+ stringContent: b64encoded,
40
+ frame: artifact.frame,
41
+ binary: true,
42
+ };
43
+ }
44
+
45
+ return {
46
+ filename: artifact.filename,
47
+ stringContent: artifact.content,
48
+ frame: artifact.frame,
49
+ binary: false,
50
+ };
51
+ };
@@ -0,0 +1,14 @@
1
+ import type {Readable} from 'stream';
2
+
3
+ export function streamToString(stream: Readable | Buffer) {
4
+ if (Buffer.isBuffer(stream)) {
5
+ return stream.toString('utf-8');
6
+ }
7
+
8
+ const chunks: Buffer[] = [];
9
+ return new Promise<string>((resolve, reject) => {
10
+ stream.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
11
+ stream.on('error', (err) => reject(err));
12
+ stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
13
+ });
14
+ }
@@ -0,0 +1,148 @@
1
+ import {makeStreamPayloadMessage} from '@remotion/streaming';
2
+ import type {SerializedArtifact} from '../serialize-artifact';
3
+ import type {CloudProvider, RenderStillFunctionResponsePayload} from '../types';
4
+ import type {FunctionErrorInfo} from '../write-error-to-storage';
5
+
6
+ const framesRendered = 'frames-rendered' as const;
7
+ const errorOccurred = 'error-occurred' as const;
8
+ const renderIdDetermined = 'render-id-determined' as const;
9
+ const videoChunkRendered = 'video-chunk-rendered' as const;
10
+ const audioChunkRendered = 'audio-chunk-rendered' as const;
11
+ const chunkComplete = 'chunk-complete' as const;
12
+ const stillRendered = 'still-rendered' as const;
13
+ const functionInvoked = 'lambda-invoked' as const;
14
+ const artifactEmitted = 'artifact-emitted' as const;
15
+
16
+ const messageTypes = {
17
+ '1': {type: framesRendered},
18
+ '2': {type: errorOccurred},
19
+ '3': {type: renderIdDetermined},
20
+ '4': {type: videoChunkRendered},
21
+ '5': {type: audioChunkRendered},
22
+ '6': {type: stillRendered},
23
+ '7': {type: chunkComplete},
24
+ '8': {type: functionInvoked},
25
+ '9': {type: artifactEmitted},
26
+ } as const;
27
+
28
+ export type MessageTypeId = keyof typeof messageTypes;
29
+ type MessageType = (typeof messageTypes)[MessageTypeId]['type'];
30
+
31
+ export const formatMap: {[key in MessageType]: 'json' | 'binary'} = {
32
+ [framesRendered]: 'json',
33
+ [errorOccurred]: 'json',
34
+ [renderIdDetermined]: 'json',
35
+ [videoChunkRendered]: 'binary',
36
+ [audioChunkRendered]: 'binary',
37
+ [stillRendered]: 'json',
38
+ [chunkComplete]: 'json',
39
+ [functionInvoked]: 'json',
40
+ [artifactEmitted]: 'json',
41
+ };
42
+
43
+ export type StreamingPayload<Provider extends CloudProvider> =
44
+ | {
45
+ type: typeof framesRendered;
46
+ payload: {
47
+ rendered: number;
48
+ encoded: number;
49
+ };
50
+ }
51
+ | {
52
+ type: typeof videoChunkRendered;
53
+ payload: Buffer;
54
+ }
55
+ | {
56
+ type: typeof audioChunkRendered;
57
+ payload: Buffer;
58
+ }
59
+ | {
60
+ type: typeof errorOccurred;
61
+ payload: {
62
+ error: string;
63
+ shouldRetry: boolean;
64
+ errorInfo: FunctionErrorInfo;
65
+ };
66
+ }
67
+ | {
68
+ type: typeof renderIdDetermined;
69
+ payload: {
70
+ renderId: string;
71
+ };
72
+ }
73
+ | {
74
+ type: typeof stillRendered;
75
+ payload: RenderStillFunctionResponsePayload<Provider>;
76
+ }
77
+ | {
78
+ type: typeof chunkComplete;
79
+ payload: {
80
+ start: number;
81
+ rendered: number;
82
+ };
83
+ }
84
+ | {
85
+ type: typeof functionInvoked;
86
+ payload: {
87
+ attempt: number;
88
+ };
89
+ }
90
+ | {
91
+ type: typeof artifactEmitted;
92
+ payload: {
93
+ artifact: SerializedArtifact;
94
+ };
95
+ };
96
+
97
+ export const messageTypeIdToMessageType = (
98
+ messageTypeId: MessageTypeId,
99
+ ): MessageType => {
100
+ const types = messageTypes[messageTypeId];
101
+ if (!types) {
102
+ throw new Error(`Unknown message type id ${messageTypeId}`);
103
+ }
104
+
105
+ return types.type;
106
+ };
107
+
108
+ const messageTypeToMessageId = (messageType: MessageType): MessageTypeId => {
109
+ const id = (Object.keys(messageTypes) as unknown as MessageTypeId[]).find(
110
+ (key) => messageTypes[key].type === messageType,
111
+ ) as MessageTypeId;
112
+
113
+ if (!id) {
114
+ throw new Error(`Unknown message type ${messageType}`);
115
+ }
116
+
117
+ return id;
118
+ };
119
+
120
+ export type StreamingMessage<Provider extends CloudProvider> = {
121
+ successType: 'error' | 'success';
122
+ message: StreamingPayload<Provider>;
123
+ };
124
+
125
+ export type OnMessage<Provider extends CloudProvider> = (
126
+ options: StreamingMessage<Provider>,
127
+ ) => void;
128
+
129
+ export type OnStream<Provider extends CloudProvider> = (
130
+ payload: StreamingPayload<Provider>,
131
+ ) => Promise<void>;
132
+
133
+ export const makeStreamPayload = <Provider extends CloudProvider>({
134
+ message,
135
+ }: {
136
+ message: StreamingPayload<Provider>;
137
+ }) => {
138
+ const body =
139
+ formatMap[message.type] === 'json'
140
+ ? new TextEncoder().encode(JSON.stringify(message.payload))
141
+ : (message.payload as Buffer);
142
+
143
+ return makeStreamPayloadMessage({
144
+ body,
145
+ nonce: messageTypeToMessageId(message.type),
146
+ status: 0,
147
+ });
148
+ };
@@ -0,0 +1,14 @@
1
+ import {expect, test} from 'bun:test';
2
+ import path from 'path';
3
+
4
+ test('Should not contain forbidden imports', async () => {
5
+ const output = await Bun.build({
6
+ external: ['@remotion/renderer', 'react/jsx-runtime'],
7
+ entrypoints: [path.join(__filename, '..', '..', 'index.ts')],
8
+ });
9
+ expect(output.outputs.length).toBe(1);
10
+ const text = await output.outputs[0].text();
11
+ expect(text).not.toContain('jsx-runtime');
12
+ expect(text).not.toContain('"@remotion/renderer"');
13
+ expect(text).not.toContain("'@remotion/renderer'");
14
+ });
@@ -0,0 +1,197 @@
1
+ import {expect, test} from 'bun:test';
2
+ import {getExpectedOutName} from '../expected-out-name';
3
+ import type {RenderMetadata} from '../render-metadata';
4
+
5
+ const bucketName = 'remotionlambda-98fsduf';
6
+
7
+ type MockProvider = {
8
+ type: 'aws';
9
+ region: 'eu-central';
10
+ receivedArtifactType: {
11
+ s3Key: string;
12
+ s3Url: string;
13
+ };
14
+ creationFunctionOptions: {};
15
+ };
16
+
17
+ const testRenderMetadata: RenderMetadata<MockProvider> = {
18
+ compositionId: 'react-svg',
19
+ estimatedRenderLambdaInvokations: 100,
20
+ estimatedTotalLambdaInvokations: 100,
21
+ framesPerLambda: 20,
22
+ imageFormat: 'png',
23
+ type: 'video',
24
+ inputProps: {
25
+ type: 'payload',
26
+ payload: '{}',
27
+ },
28
+ lambdaVersion: '2022-02-14',
29
+ memorySizeInMb: 2048,
30
+ functionName: 'remotion-render-4-0-187-mem3000mb-disk10000mb-120sec',
31
+ rendererFunctionName: 'remotion-render-4-0-187-mem3000mb-disk10000mb-120sec',
32
+ outName: undefined,
33
+ region: 'eu-central',
34
+ renderId: '9n8dsfafs',
35
+ siteId: 'my-site',
36
+ startedDate: Date.now(),
37
+ totalChunks: 20,
38
+ privacy: 'public',
39
+ everyNthFrame: 1,
40
+ frameRange: [0, 199],
41
+ audioCodec: null,
42
+ deleteAfter: null,
43
+ numberOfGifLoops: null,
44
+ downloadBehavior: {type: 'play-in-browser'},
45
+ audioBitrate: null,
46
+ muted: false,
47
+ metadata: null,
48
+ codec: 'h264',
49
+ dimensions: {
50
+ width: 1920,
51
+ height: 1080,
52
+ },
53
+ };
54
+
55
+ test('Should get a custom outname', () => {
56
+ expect(
57
+ getExpectedOutName({
58
+ renderMetadata: testRenderMetadata,
59
+ bucketName,
60
+ customCredentials: null,
61
+ bucketNamePrefix: 'remotionlambda-',
62
+ }),
63
+ ).toEqual({
64
+ customCredentials: null,
65
+ renderBucketName: 'remotionlambda-98fsduf',
66
+ key: 'renders/9n8dsfafs/out.mp4',
67
+ });
68
+ });
69
+
70
+ test('Should save to a different outname', () => {
71
+ const newRenderMetadata: RenderMetadata<MockProvider> = {
72
+ ...testRenderMetadata,
73
+ outName: {
74
+ bucketName: 'my-bucket',
75
+ key: 'my-key',
76
+ },
77
+ };
78
+ expect(
79
+ getExpectedOutName({
80
+ renderMetadata: newRenderMetadata,
81
+ bucketName,
82
+ customCredentials: null,
83
+ bucketNamePrefix: 'remotionlambda-',
84
+ }),
85
+ ).toEqual({
86
+ customCredentials: null,
87
+ renderBucketName: 'my-bucket',
88
+ key: 'my-key',
89
+ });
90
+ });
91
+
92
+ test('For stills', () => {
93
+ const newRenderMetadata: RenderMetadata<MockProvider> = {
94
+ ...testRenderMetadata,
95
+ codec: null,
96
+ type: 'still',
97
+ imageFormat: 'png',
98
+ };
99
+ expect(
100
+ getExpectedOutName({
101
+ renderMetadata: newRenderMetadata,
102
+ bucketName,
103
+ customCredentials: null,
104
+ bucketNamePrefix: 'remotionlambda-',
105
+ }),
106
+ ).toEqual({
107
+ customCredentials: null,
108
+ renderBucketName: 'remotionlambda-98fsduf',
109
+ key: 'renders/9n8dsfafs/out.png',
110
+ });
111
+ });
112
+
113
+ test('Just a custom name', () => {
114
+ const newRenderMetadata: RenderMetadata<MockProvider> = {
115
+ ...testRenderMetadata,
116
+ type: 'still',
117
+ imageFormat: 'jpeg',
118
+ codec: null,
119
+ outName: 'justaname.jpeg',
120
+ };
121
+ expect(
122
+ getExpectedOutName({
123
+ renderMetadata: newRenderMetadata,
124
+ bucketName,
125
+ customCredentials: null,
126
+ bucketNamePrefix: 'remotionlambda-',
127
+ }),
128
+ ).toEqual({
129
+ customCredentials: null,
130
+ renderBucketName: 'remotionlambda-98fsduf',
131
+ key: 'renders/9n8dsfafs/justaname.jpeg',
132
+ });
133
+ });
134
+
135
+ test('Should throw on invalid names', () => {
136
+ const newRenderMetadata: RenderMetadata<MockProvider> = {
137
+ ...testRenderMetadata,
138
+ type: 'still',
139
+ imageFormat: 'png',
140
+ codec: null,
141
+ outName: '👺.jpeg',
142
+ };
143
+ expect(() => {
144
+ getExpectedOutName({
145
+ renderMetadata: newRenderMetadata,
146
+ bucketName,
147
+ customCredentials: null,
148
+ bucketNamePrefix: 'remotionlambda-',
149
+ });
150
+ }).toThrow(/The S3 Key must match the RegExp/);
151
+ });
152
+
153
+ test('Should allow outName an outname with a slash', () => {
154
+ const newRenderMetadata: RenderMetadata<MockProvider> = {
155
+ ...testRenderMetadata,
156
+ codec: null,
157
+ audioCodec: null,
158
+ type: 'still',
159
+ imageFormat: 'jpeg',
160
+ outName: 'justa/name.jpeg',
161
+ };
162
+ expect(
163
+ getExpectedOutName({
164
+ renderMetadata: newRenderMetadata,
165
+ bucketName,
166
+ customCredentials: null,
167
+ bucketNamePrefix: 'remotionlambda-',
168
+ }),
169
+ ).toEqual({
170
+ customCredentials: null,
171
+ key: 'renders/9n8dsfafs/justa/name.jpeg',
172
+ renderBucketName: 'remotionlambda-98fsduf',
173
+ });
174
+ });
175
+
176
+ test('Should allow outName an outname with colon', () => {
177
+ const newRenderMetadata: RenderMetadata<MockProvider> = {
178
+ ...testRenderMetadata,
179
+ codec: null,
180
+ audioCodec: null,
181
+ type: 'still' as const,
182
+ imageFormat: 'jpeg',
183
+ outName: 'ap-east-1:xxxxxx/video/XXXXX-0b9ba84XXXX.mp4',
184
+ };
185
+ expect(
186
+ getExpectedOutName({
187
+ renderMetadata: newRenderMetadata,
188
+ bucketName,
189
+ customCredentials: null,
190
+ bucketNamePrefix: 'remotionlambda-',
191
+ }),
192
+ ).toEqual({
193
+ customCredentials: null,
194
+ key: 'renders/9n8dsfafs/ap-east-1:xxxxxx/video/XXXXX-0b9ba84XXXX.mp4',
195
+ renderBucketName: 'remotionlambda-98fsduf',
196
+ });
197
+ });
@@ -0,0 +1,25 @@
1
+ import {describe, expect, test} from 'bun:test';
2
+ import {max, min} from '../min-max';
3
+ describe('min() and max()', () => {
4
+ test('Implemented min() functions correctly', () => {
5
+ expect(min([0, -30, 90, -120, 0])).toBe(-120);
6
+ });
7
+ test('Implemented max() functions correctly', () => {
8
+ expect(max([0, -30, 90, -120, 0])).toBe(90);
9
+ });
10
+
11
+ test('min() should throw on empty arr', () => {
12
+ expect(() => min([])).toThrow(/Array of 0 length/);
13
+ });
14
+ test('max() should throw on empty arr', () => {
15
+ expect(() => min([])).toThrow(/Array of 0 length/);
16
+ });
17
+
18
+ const bigArray = new Array(300000).fill(true).map((_, i) => {
19
+ return i;
20
+ });
21
+
22
+ test('Custom max() should not throw', () => {
23
+ expect(max(bigArray)).toBe(299999);
24
+ });
25
+ });