@hyperframes/aws-lambda 0.8.181 → 0.8.184
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/_chunks/{chunk-PK7PO3MH.js → chunk-5FLGGUWE.js} +1 -1
- package/dist/_chunks/{chunk-AK7J3QQN.js → chunk-QCYPNODV.js} +113 -57
- package/dist/_chunks/{chunk-ZY5YIH5W.js → chunk-SGNVVPIS.js} +187 -17
- package/dist/cdk/index.js +38 -7
- package/dist/events.d.ts +16 -3
- package/dist/handler.d.ts +4 -3
- package/dist/handler.js +2 -2
- package/dist/index.js +3 -3
- package/dist/s3Stitch.d.ts +5 -2
- package/dist/s3Transport.d.ts +20 -8
- package/dist/sdk/index.js +2 -2
- package/package.json +3 -2
- package/prebuilt/handler-zip.json +4 -4
- package/prebuilt/template.yaml +149 -71
- package/scripts/pin-handler-zip.ts +2 -13
- package/scripts/prebuilt-template.mjs +19 -0
- package/scripts/build-zip.test.ts +0 -77
- package/scripts/pin-handler-zip.test.ts +0 -101
- package/scripts/probe-beginframe.test.ts +0 -80
package/dist/cdk/index.js
CHANGED
|
@@ -250,7 +250,8 @@ var HyperframesRenderStack = class extends Construct {
|
|
|
250
250
|
"ChunkCount.$": "$.Payload.ChunkCount",
|
|
251
251
|
"MaxChunkConcurrency.$": "$.Payload.MaxChunkConcurrency",
|
|
252
252
|
"Format.$": "$.Payload.Format",
|
|
253
|
-
"HasAudio.$": "$.Payload.HasAudio"
|
|
253
|
+
"HasAudio.$": "$.Payload.HasAudio",
|
|
254
|
+
"SeparateAudio.$": "$.Payload.SeparateAudio"
|
|
254
255
|
},
|
|
255
256
|
resultPath: "$.Plan"
|
|
256
257
|
});
|
|
@@ -404,8 +405,8 @@ var HyperframesRenderStack = class extends Construct {
|
|
|
404
405
|
"PlanV2ManifestS3Uri.$": "$.Plan.PlanV2ManifestS3Uri",
|
|
405
406
|
"PlanV2ArtifactS3Prefix.$": "$.Plan.PlanV2ArtifactS3Prefix",
|
|
406
407
|
"PlanHash.$": "$.Plan.PlanHash",
|
|
407
|
-
"ChunkS3Uris.$": "$.Chunks[*].ChunkS3Uri",
|
|
408
|
-
AudioS3Uri:
|
|
408
|
+
"ChunkS3Uris.$": "$.Render.Chunks[*].ChunkS3Uri",
|
|
409
|
+
"AudioS3Uri.$": "$.Render.Audio.AudioS3Uri",
|
|
409
410
|
"OutputS3Uri.$": "$.OutputS3Uri",
|
|
410
411
|
"Format.$": "$.Plan.Format"
|
|
411
412
|
}),
|
|
@@ -425,10 +426,40 @@ var HyperframesRenderStack = class extends Construct {
|
|
|
425
426
|
backoffRate: 2,
|
|
426
427
|
maxDelay: Duration.seconds(60)
|
|
427
428
|
});
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
429
|
+
const audio = new tasks.LambdaInvoke(this, "Audio", {
|
|
430
|
+
lambdaFunction: this.renderFunction,
|
|
431
|
+
payload: sfn.TaskInput.fromObject({
|
|
432
|
+
Action: "audio",
|
|
433
|
+
"ProjectS3Uri.$": "$.ProjectS3Uri",
|
|
434
|
+
"PlanOutputS3Prefix.$": "$.PlanOutputS3Prefix",
|
|
435
|
+
"Config.$": "$.Config"
|
|
436
|
+
}),
|
|
437
|
+
resultSelector: {
|
|
438
|
+
"HasAudio.$": "$.Payload.HasAudio",
|
|
439
|
+
"AudioS3Uri.$": "$.Payload.AudioS3Uri"
|
|
440
|
+
},
|
|
441
|
+
resultPath: "$.Audio"
|
|
442
|
+
});
|
|
443
|
+
audio.addRetry({ errors: NON_RETRYABLE_PLAN, maxAttempts: 0 });
|
|
444
|
+
audio.addRetry(THROTTLED_RETRY);
|
|
445
|
+
audio.addRetry({
|
|
446
|
+
errors: ["States.ALL"],
|
|
447
|
+
interval: Duration.seconds(2),
|
|
448
|
+
maxAttempts: 4,
|
|
449
|
+
backoffRate: 2,
|
|
450
|
+
maxDelay: Duration.seconds(60)
|
|
451
|
+
});
|
|
452
|
+
const audioNeeded = new sfn.Choice(this, "AudioNeeded").when(sfn.Condition.booleanEquals("$.Plan.SeparateAudio", true), audio).otherwise(
|
|
453
|
+
new sfn.Pass(this, "NoAudio", {
|
|
454
|
+
result: sfn.Result.fromObject({ HasAudio: false, AudioS3Uri: null }),
|
|
455
|
+
resultPath: "$.Audio"
|
|
456
|
+
})
|
|
457
|
+
);
|
|
458
|
+
const renderV2 = new sfn.Parallel(this, "RenderV2", {
|
|
459
|
+
resultSelector: { "Chunks.$": "$[0].Chunks", "Audio.$": "$[1].Audio" },
|
|
460
|
+
resultPath: "$.Render"
|
|
461
|
+
}).branch(renderChunksV2).branch(audioNeeded);
|
|
462
|
+
const selectWorkerProtocol = new sfn.Choice(this, "SelectWorkerProtocol").when(sfn.Condition.stringEquals("$.Plan.PlanProtocol", "v2"), renderV2.next(assembleV2)).otherwise(renderChunks.next(assemble));
|
|
432
463
|
const assertChunkCount = new sfn.Choice(this, "AssertChunkCount").when(sfn.Condition.numberGreaterThan("$.Plan.ChunkCount", 0), selectWorkerProtocol).otherwise(planProducedZero);
|
|
433
464
|
plan.next(buildChunkList);
|
|
434
465
|
planV2.next(buildChunkList);
|
package/dist/events.d.ts
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import type { DistributedFormat, SerializableDistributedRenderConfig } from "@hyperframes/producer/distributed";
|
|
19
19
|
export type { SerializableDistributedRenderConfig } from "@hyperframes/producer/distributed";
|
|
20
20
|
/** Discriminator for the three roles the one Lambda image fulfills. */
|
|
21
|
-
export type LambdaAction = "plan" | "renderChunk" | "assemble";
|
|
21
|
+
export type LambdaAction = "plan" | "audio" | "renderChunk" | "assemble";
|
|
22
22
|
/** Transport protocol selected for one complete distributed render. */
|
|
23
23
|
export type LambdaPlanProtocol = "v1" | "v2";
|
|
24
24
|
/**
|
|
@@ -29,7 +29,7 @@ export type LambdaPlanProtocol = "v1" | "v2";
|
|
|
29
29
|
* handler unwraps both `event.Payload` and `event.Input` before
|
|
30
30
|
* dispatching.
|
|
31
31
|
*/
|
|
32
|
-
export type LambdaEvent = PlanEvent | RenderChunkEvent | AssembleEvent | {
|
|
32
|
+
export type LambdaEvent = PlanEvent | AudioEvent | RenderChunkEvent | AssembleEvent | {
|
|
33
33
|
Payload: LambdaEvent;
|
|
34
34
|
} | {
|
|
35
35
|
Input: LambdaEvent;
|
|
@@ -57,6 +57,10 @@ export interface PlanV2Event extends PlanEventBase {
|
|
|
57
57
|
PlanProtocol?: "v2";
|
|
58
58
|
}
|
|
59
59
|
export type PlanEvent = PlanV1Event | PlanV2Event;
|
|
60
|
+
/** Makes a v2 plan's audio beside its chunks, from the same project and config as the plan. */
|
|
61
|
+
export interface AudioEvent extends Omit<PlanEventBase, "Action"> {
|
|
62
|
+
Action: "audio";
|
|
63
|
+
}
|
|
60
64
|
/** Activity B: fetch planDir, render one chunk, upload result. */
|
|
61
65
|
interface RenderChunkEventBase {
|
|
62
66
|
Action: "renderChunk";
|
|
@@ -165,8 +169,17 @@ export interface PlanV2LambdaResult extends PlanLambdaResultBase {
|
|
|
165
169
|
PlanProtocol: "v2";
|
|
166
170
|
PlanV2ManifestS3Uri: string;
|
|
167
171
|
PlanV2ArtifactS3Prefix: string;
|
|
172
|
+
/** The plan left its audio to the audio task, which has a worker kept free for it. */
|
|
173
|
+
SeparateAudio: boolean;
|
|
168
174
|
}
|
|
169
175
|
export type PlanLambdaResult = PlanV1LambdaResult | PlanV2LambdaResult;
|
|
176
|
+
export interface AudioLambdaResult {
|
|
177
|
+
Action: "audio";
|
|
178
|
+
HasAudio: boolean;
|
|
179
|
+
/** The track for the assembler to stitch in; `null` without audio or when the plan mixed it. */
|
|
180
|
+
AudioS3Uri: string | null;
|
|
181
|
+
DurationMs: number;
|
|
182
|
+
}
|
|
170
183
|
/** Result of a `renderChunk` invocation. Sized ≤200 bytes per §2.4. */
|
|
171
184
|
export interface RenderChunkLambdaResult {
|
|
172
185
|
Action: "renderChunk";
|
|
@@ -186,4 +199,4 @@ export interface AssembleLambdaResult {
|
|
|
186
199
|
FileSize: number;
|
|
187
200
|
DurationMs: number;
|
|
188
201
|
}
|
|
189
|
-
export type LambdaResult = PlanLambdaResult | RenderChunkLambdaResult | AssembleLambdaResult;
|
|
202
|
+
export type LambdaResult = PlanLambdaResult | AudioLambdaResult | RenderChunkLambdaResult | AssembleLambdaResult;
|
package/dist/handler.d.ts
CHANGED
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { LambdaClient } from "@aws-sdk/client-lambda";
|
|
14
14
|
import { S3Client } from "@aws-sdk/client-s3";
|
|
15
|
-
import { assemble, type ChunkRenderer, plan, planV2WithPublisher } from "@hyperframes/producer/distributed";
|
|
16
|
-
import type { AssembleEvent, LambdaEvent, LambdaResult, PlanEvent, RenderChunkEvent } from "./events.js";
|
|
15
|
+
import { assemble, buildPlanAudio, type ChunkRenderer, plan, planV2WithPublisher } from "@hyperframes/producer/distributed";
|
|
16
|
+
import type { AssembleEvent, AudioEvent, LambdaEvent, LambdaResult, PlanEvent, RenderChunkEvent } from "./events.js";
|
|
17
17
|
/**
|
|
18
18
|
* Optional injection points used by the handler's unit tests. Production
|
|
19
19
|
* callers leave these unset; the real OSS primitives are used. Tests
|
|
@@ -28,6 +28,7 @@ export interface HandlerDeps {
|
|
|
28
28
|
primitives?: {
|
|
29
29
|
plan: typeof plan;
|
|
30
30
|
planV2WithPublisher?: typeof planV2WithPublisher;
|
|
31
|
+
buildPlanAudio?: typeof buildPlanAudio;
|
|
31
32
|
renderChunk: ChunkRenderer;
|
|
32
33
|
assemble: typeof assemble;
|
|
33
34
|
};
|
|
@@ -47,4 +48,4 @@ export interface HandlerDeps {
|
|
|
47
48
|
* shape; unwrap until we hit a discriminated event.
|
|
48
49
|
*/
|
|
49
50
|
export declare function handler(event: LambdaEvent, deps?: HandlerDeps): Promise<LambdaResult>;
|
|
50
|
-
export declare function unwrapEvent(event: LambdaEvent): PlanEvent | RenderChunkEvent | AssembleEvent;
|
|
51
|
+
export declare function unwrapEvent(event: LambdaEvent): PlanEvent | AudioEvent | RenderChunkEvent | AssembleEvent;
|
package/dist/handler.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
resolveChromeExecutablePath,
|
|
7
7
|
resolveChromeSource,
|
|
8
8
|
unwrapEvent
|
|
9
|
-
} from "./_chunks/chunk-
|
|
9
|
+
} from "./_chunks/chunk-QCYPNODV.js";
|
|
10
10
|
import {
|
|
11
11
|
InvalidConfigError,
|
|
12
12
|
computeRenderCost,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
getRenderProgress,
|
|
15
15
|
renderToLambda,
|
|
16
16
|
validateDistributedRenderConfig
|
|
17
|
-
} from "./_chunks/chunk-
|
|
17
|
+
} from "./_chunks/chunk-5FLGGUWE.js";
|
|
18
18
|
import {
|
|
19
19
|
downloadS3ObjectToFile,
|
|
20
20
|
downloadS3ObjectToFileVerified,
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
untarDirectory,
|
|
25
25
|
uploadContentAddressedFileToS3,
|
|
26
26
|
uploadFileToS3
|
|
27
|
-
} from "./_chunks/chunk-
|
|
27
|
+
} from "./_chunks/chunk-SGNVVPIS.js";
|
|
28
28
|
import "./_chunks/chunk-YS3KY3C5.js";
|
|
29
29
|
export {
|
|
30
30
|
ChromeBinaryUnavailableError,
|
package/dist/s3Stitch.d.ts
CHANGED
|
@@ -21,6 +21,9 @@ export interface StitchResult {
|
|
|
21
21
|
parts: number;
|
|
22
22
|
downloadedBytes: number;
|
|
23
23
|
}
|
|
24
|
-
/** One faststart mp4 at `destUri` from the stitched mp4 chunks at `chunkUris`,
|
|
25
|
-
export declare function stitchMp4InS3(s3: S3Client, chunkUris: readonly string[], destUri: string, minPartBytes?:
|
|
24
|
+
/** One faststart mp4 at `destUri` from the stitched mp4 chunks at `chunkUris`, plus `audioUri`'s track when given. */
|
|
25
|
+
export declare function stitchMp4InS3(s3: S3Client, chunkUris: readonly string[], destUri: string, { audioUri, minPartBytes }?: {
|
|
26
|
+
audioUri?: string;
|
|
27
|
+
minPartBytes?: number;
|
|
28
|
+
}): Promise<StitchResult>;
|
|
26
29
|
export {};
|
package/dist/s3Transport.d.ts
CHANGED
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
* `/usr/bin`, so a system-binary tar would ENOENT in the actual
|
|
17
17
|
* deployment.
|
|
18
18
|
*/
|
|
19
|
-
import { type S3Client } from "@aws-sdk/client-s3";
|
|
19
|
+
import { type CompletedPart, type CreateMultipartUploadCommandInput, type S3Client } from "@aws-sdk/client-s3";
|
|
20
|
+
/** S3's largest PutObject or CopyObject; bigger objects go multipart. */
|
|
21
|
+
export declare const MAX_SINGLE_PUT_BYTES: number;
|
|
20
22
|
/** Parsed `s3://bucket/key` URI. */
|
|
21
23
|
export interface S3Location {
|
|
22
24
|
bucket: string;
|
|
@@ -35,13 +37,7 @@ export declare function downloadS3ObjectToFileVerified(client: S3Client, uri: st
|
|
|
35
37
|
* SHA-256 and size are the ones the manifest pins.
|
|
36
38
|
*/
|
|
37
39
|
export declare function presignVerifiedS3GetUrl(client: S3Client, uri: string, expectedSha256: string, expectedSize: number, expiresInSeconds: number): Promise<string>;
|
|
38
|
-
/**
|
|
39
|
-
* Upload a local file's contents to an S3 URI using a streaming
|
|
40
|
-
* `PutObjectCommand`. PutObject's 5 GB cap comfortably exceeds the
|
|
41
|
-
* distributed pipeline's 2 GB planDir limit and the typical
|
|
42
|
-
* chunk size (≤ 200 MB), so a single PUT works for every artifact this
|
|
43
|
-
* adapter handles.
|
|
44
|
-
*/
|
|
40
|
+
/** Upload a local file to an S3 URI, streamed: one PutObject up to S3's 5 GB cap, multipart above. */
|
|
45
41
|
export declare function uploadFileToS3(client: S3Client, localPath: string, uri: string, contentType?: string): Promise<void>;
|
|
46
42
|
/**
|
|
47
43
|
* Upload one content-addressed plan-v2 artifact exactly once; S3 verifies the bytes against
|
|
@@ -49,6 +45,22 @@ export declare function uploadFileToS3(client: S3Client, localPath: string, uri:
|
|
|
49
45
|
* and a conflicting one is never overwritten, since a chunk may already be reading that plan.
|
|
50
46
|
*/
|
|
51
47
|
export declare function uploadContentAddressedFileToS3(client: S3Client, localPath: string, uri: string, expectedSha256: string, contentType?: string): Promise<"uploaded" | "reused">;
|
|
48
|
+
export type MultipartTarget = {
|
|
49
|
+
Bucket: string;
|
|
50
|
+
Key: string;
|
|
51
|
+
UploadId: string;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Creates a multipart upload, lets `sendParts` fill it, then completes it. A failure aborts the
|
|
55
|
+
* upload so no parts linger; `sendParts` must settle every part before it rejects.
|
|
56
|
+
*/
|
|
57
|
+
export declare function multipartUpload(client: S3Client, create: CreateMultipartUploadCommandInput & {
|
|
58
|
+
Bucket: string;
|
|
59
|
+
Key: string;
|
|
60
|
+
}, sendParts: (target: MultipartTarget) => Promise<CompletedPart[]>, complete?: {
|
|
61
|
+
ifNoneMatch?: "*";
|
|
62
|
+
objectSize?: number;
|
|
63
|
+
}): Promise<void>;
|
|
52
64
|
export declare function mapConcurrent<T>(values: readonly T[], concurrency: number, fn: (value: T) => Promise<void>): Promise<void>;
|
|
53
65
|
export declare function sha256File(path: string): Promise<string>;
|
|
54
66
|
/** Put a file into the shared content store once; reusing an aging object restarts its expiry. */
|
package/dist/sdk/index.js
CHANGED
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
validateDistributedRenderConfig,
|
|
11
11
|
validateStepFunctionsInputSize,
|
|
12
12
|
validateVariablesPayload
|
|
13
|
-
} from "../_chunks/chunk-
|
|
14
|
-
import "../_chunks/chunk-
|
|
13
|
+
} from "../_chunks/chunk-5FLGGUWE.js";
|
|
14
|
+
import "../_chunks/chunk-SGNVVPIS.js";
|
|
15
15
|
import "../_chunks/chunk-YS3KY3C5.js";
|
|
16
16
|
|
|
17
17
|
// src/sdk/prebuiltHandler.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/aws-lambda",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.184",
|
|
4
4
|
"description": "AWS Lambda adapter for HyperFrames distributed rendering — handler, client-side SDK, and CDK construct.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"dist/",
|
|
12
12
|
"prebuilt/",
|
|
13
13
|
"scripts/",
|
|
14
|
+
"!scripts/*.test.ts",
|
|
14
15
|
"README.md"
|
|
15
16
|
],
|
|
16
17
|
"type": "module",
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
"ffprobe-static": "^3.1.0",
|
|
49
50
|
"puppeteer-core": "^25.8.0",
|
|
50
51
|
"tar": "^7.4.3",
|
|
51
|
-
"@hyperframes/producer": "^0.8.
|
|
52
|
+
"@hyperframes/producer": "^0.8.184"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
|
54
55
|
"@types/aws-lambda": "^8.10.146",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.8.
|
|
3
|
-
"url": "https://github.com/heygen-com/hyperframes/releases/download/v0.8.
|
|
4
|
-
"sha256": "
|
|
5
|
-
"bytes":
|
|
2
|
+
"version": "0.8.184",
|
|
3
|
+
"url": "https://github.com/heygen-com/hyperframes/releases/download/v0.8.184/hyperframes-lambda-handler.zip",
|
|
4
|
+
"sha256": "3bfb70ba6961f63748d6eccfde8236d2a5d566ae8794f5d21e4a1d0e160de3c5",
|
|
5
|
+
"bytes": 129237052
|
|
6
6
|
}
|
package/prebuilt/template.yaml
CHANGED
|
@@ -324,6 +324,7 @@ Resources:
|
|
|
324
324
|
MaxChunkConcurrency.$: "$.Payload.MaxChunkConcurrency"
|
|
325
325
|
Format.$: "$.Payload.Format"
|
|
326
326
|
HasAudio.$: "$.Payload.HasAudio"
|
|
327
|
+
SeparateAudio.$: "$.Payload.SeparateAudio"
|
|
327
328
|
ResultPath: $.Plan
|
|
328
329
|
Retry:
|
|
329
330
|
- ErrorEquals:
|
|
@@ -395,7 +396,7 @@ Resources:
|
|
|
395
396
|
Choices:
|
|
396
397
|
- Variable: $.Plan.PlanProtocol
|
|
397
398
|
StringEquals: v2
|
|
398
|
-
Next:
|
|
399
|
+
Next: RenderV2
|
|
399
400
|
Default: RenderChunks
|
|
400
401
|
|
|
401
402
|
RenderChunks:
|
|
@@ -511,74 +512,151 @@ Resources:
|
|
|
511
512
|
MaxDelaySeconds: 60
|
|
512
513
|
End: true
|
|
513
514
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
515
|
+
RenderV2:
|
|
516
|
+
# Chunks render video only while the audio task mixes the track AssembleV2 stitches in.
|
|
517
|
+
Type: Parallel
|
|
518
|
+
Branches:
|
|
519
|
+
- StartAt: RenderChunksV2
|
|
520
|
+
States:
|
|
521
|
+
RenderChunksV2:
|
|
522
|
+
Type: Map
|
|
523
|
+
Label: RenderChunksV2
|
|
524
|
+
ItemsPath: $.Iterator.ChunkIndexes
|
|
525
|
+
ItemSelector:
|
|
526
|
+
ChunkIndex.$: "$$.Map.Item.Value"
|
|
527
|
+
PlanV2ManifestS3Uri.$: "$.Plan.PlanV2ManifestS3Uri"
|
|
528
|
+
PlanV2ArtifactS3Prefix.$: "$.Plan.PlanV2ArtifactS3Prefix"
|
|
529
|
+
PlanHash.$: "$.Plan.PlanHash"
|
|
530
|
+
ChunkOutputS3Prefix.$: "$.PlanOutputS3Prefix"
|
|
531
|
+
Format.$: "$.Plan.Format"
|
|
532
|
+
# Chunks past the plan's concurrency queue here instead of being throttled by Lambda.
|
|
533
|
+
MaxConcurrencyPath: $.Plan.MaxChunkConcurrency
|
|
534
|
+
ResultPath: $.Chunks
|
|
535
|
+
ItemProcessor:
|
|
536
|
+
ProcessorConfig:
|
|
537
|
+
Mode: DISTRIBUTED
|
|
538
|
+
ExecutionType: STANDARD
|
|
539
|
+
StartAt: RenderChunkV2
|
|
540
|
+
States:
|
|
541
|
+
RenderChunkV2:
|
|
542
|
+
Type: Task
|
|
543
|
+
Resource: arn:aws:states:::lambda:invoke
|
|
544
|
+
Parameters:
|
|
545
|
+
FunctionName: !GetAtt RenderFunction.Arn
|
|
546
|
+
Payload:
|
|
547
|
+
Action: renderChunk
|
|
548
|
+
PlanProtocol: v2
|
|
549
|
+
ChunkIndex.$: "$.ChunkIndex"
|
|
550
|
+
PlanV2ManifestS3Uri.$: "$.PlanV2ManifestS3Uri"
|
|
551
|
+
PlanV2ArtifactS3Prefix.$: "$.PlanV2ArtifactS3Prefix"
|
|
552
|
+
PlanHash.$: "$.PlanHash"
|
|
553
|
+
ChunkOutputS3Prefix.$: "$.ChunkOutputS3Prefix"
|
|
554
|
+
Format.$: "$.Format"
|
|
555
|
+
ResultSelector:
|
|
556
|
+
ChunkS3Uri.$: "$.Payload.ChunkS3Uri"
|
|
557
|
+
ChunkIndex.$: "$.Payload.ChunkIndex"
|
|
558
|
+
Sha256.$: "$.Payload.Sha256"
|
|
559
|
+
FramesEncoded.$: "$.Payload.FramesEncoded"
|
|
560
|
+
DurationMs.$: "$.Payload.DurationMs"
|
|
561
|
+
Retry:
|
|
562
|
+
- ErrorEquals:
|
|
563
|
+
- FFMPEG_VERSION_MISMATCH
|
|
564
|
+
- PLAN_HASH_MISMATCH
|
|
565
|
+
- S3_URI_NOT_ALLOWED
|
|
566
|
+
- BROWSER_GPU_NOT_SOFTWARE
|
|
567
|
+
- PLAN_TOO_LARGE
|
|
568
|
+
- PlanTooLargeError
|
|
569
|
+
- PLAN_PROTOCOL_UNSUPPORTED
|
|
570
|
+
- PlanProtocolUnsupportedError
|
|
571
|
+
- PLAN_V2_INTEGRITY_UNRECOVERABLE
|
|
572
|
+
- INVALID_VIDEO_METADATA
|
|
573
|
+
- PlanV2IntegrityError
|
|
574
|
+
- PLAN_ARTIFACT_DIGEST_MISMATCH
|
|
575
|
+
- ChromeBinaryUnavailableError
|
|
576
|
+
MaxAttempts: 0
|
|
577
|
+
- ErrorEquals: [Lambda.TooManyRequestsException]
|
|
578
|
+
IntervalSeconds: 5
|
|
579
|
+
MaxAttempts: 10
|
|
580
|
+
BackoffRate: 2
|
|
581
|
+
MaxDelaySeconds: 60
|
|
582
|
+
JitterStrategy: FULL
|
|
583
|
+
- ErrorEquals: [States.ALL]
|
|
584
|
+
IntervalSeconds: 2
|
|
585
|
+
MaxAttempts: 4
|
|
586
|
+
BackoffRate: 2
|
|
587
|
+
MaxDelaySeconds: 60
|
|
588
|
+
End: true
|
|
589
|
+
End: true
|
|
590
|
+
- StartAt: AudioNeeded
|
|
591
|
+
States:
|
|
592
|
+
AudioNeeded:
|
|
593
|
+
Type: Choice
|
|
594
|
+
Choices:
|
|
595
|
+
- Variable: $.Plan.SeparateAudio
|
|
596
|
+
BooleanEquals: true
|
|
597
|
+
Next: Audio
|
|
598
|
+
Default: NoAudio
|
|
599
|
+
NoAudio:
|
|
600
|
+
Type: Pass
|
|
601
|
+
Result:
|
|
602
|
+
HasAudio: false
|
|
603
|
+
AudioS3Uri: null
|
|
604
|
+
ResultPath: $.Audio
|
|
605
|
+
End: true
|
|
606
|
+
Audio:
|
|
607
|
+
# The plan left its audio out: mix it here while the chunks render.
|
|
608
|
+
Type: Task
|
|
609
|
+
Resource: arn:aws:states:::lambda:invoke
|
|
610
|
+
Parameters:
|
|
611
|
+
FunctionName: !GetAtt RenderFunction.Arn
|
|
612
|
+
Payload:
|
|
613
|
+
Action: audio
|
|
614
|
+
ProjectS3Uri.$: "$.ProjectS3Uri"
|
|
615
|
+
PlanOutputS3Prefix.$: "$.PlanOutputS3Prefix"
|
|
616
|
+
Config.$: "$.Config"
|
|
617
|
+
ResultSelector:
|
|
618
|
+
HasAudio.$: "$.Payload.HasAudio"
|
|
619
|
+
AudioS3Uri.$: "$.Payload.AudioS3Uri"
|
|
620
|
+
ResultPath: $.Audio
|
|
621
|
+
Retry:
|
|
622
|
+
- ErrorEquals:
|
|
623
|
+
- FFMPEG_VERSION_MISMATCH
|
|
624
|
+
- PLAN_HASH_MISMATCH
|
|
625
|
+
- S3_URI_NOT_ALLOWED
|
|
626
|
+
- BROWSER_GPU_NOT_SOFTWARE
|
|
627
|
+
- FONT_FETCH_FAILED
|
|
628
|
+
- PLAN_TOO_LARGE
|
|
629
|
+
- PlanTooLargeError
|
|
630
|
+
- PLAN_PROTOCOL_UNSUPPORTED
|
|
631
|
+
- PlanProtocolUnsupportedError
|
|
632
|
+
- PLAN_V2_INTEGRITY_UNRECOVERABLE
|
|
633
|
+
- VIDEO_SOURCE_UNRENDERABLE
|
|
634
|
+
- INVALID_VIDEO_METADATA
|
|
635
|
+
- NOT_MEDIA_PAYLOAD
|
|
636
|
+
- NotMediaPayloadError
|
|
637
|
+
- PlanV2IntegrityError
|
|
638
|
+
- PLAN_ARTIFACT_DIGEST_MISMATCH
|
|
639
|
+
- FORMAT_NOT_SUPPORTED_IN_DISTRIBUTED
|
|
640
|
+
- CHUNK_EXCEEDS_WORKER_TIMEOUT
|
|
641
|
+
- ChromeBinaryUnavailableError
|
|
642
|
+
- SITE_MANIFEST_INVALID
|
|
643
|
+
MaxAttempts: 0
|
|
644
|
+
- ErrorEquals: [Lambda.TooManyRequestsException]
|
|
645
|
+
IntervalSeconds: 5
|
|
646
|
+
MaxAttempts: 10
|
|
647
|
+
BackoffRate: 2
|
|
648
|
+
MaxDelaySeconds: 60
|
|
649
|
+
JitterStrategy: FULL
|
|
650
|
+
- ErrorEquals: [States.ALL]
|
|
651
|
+
IntervalSeconds: 2
|
|
652
|
+
MaxAttempts: 4
|
|
653
|
+
BackoffRate: 2
|
|
654
|
+
MaxDelaySeconds: 60
|
|
655
|
+
End: true
|
|
656
|
+
ResultSelector:
|
|
657
|
+
Chunks.$: "$[0].Chunks"
|
|
658
|
+
Audio.$: "$[1].Audio"
|
|
659
|
+
ResultPath: $.Render
|
|
582
660
|
Next: AssembleV2
|
|
583
661
|
|
|
584
662
|
AssembleV2:
|
|
@@ -592,8 +670,8 @@ Resources:
|
|
|
592
670
|
PlanV2ManifestS3Uri.$: "$.Plan.PlanV2ManifestS3Uri"
|
|
593
671
|
PlanV2ArtifactS3Prefix.$: "$.Plan.PlanV2ArtifactS3Prefix"
|
|
594
672
|
PlanHash.$: "$.Plan.PlanHash"
|
|
595
|
-
ChunkS3Uris.$: "$.Chunks[*].ChunkS3Uri"
|
|
596
|
-
AudioS3Uri
|
|
673
|
+
ChunkS3Uris.$: "$.Render.Chunks[*].ChunkS3Uri"
|
|
674
|
+
AudioS3Uri.$: "$.Render.Audio.AudioS3Uri"
|
|
597
675
|
OutputS3Uri.$: "$.OutputS3Uri"
|
|
598
676
|
Format.$: "$.Plan.Format"
|
|
599
677
|
ResultSelector:
|
|
@@ -11,8 +11,7 @@ import {
|
|
|
11
11
|
type HandlerZipManifest,
|
|
12
12
|
PREBUILT_DIR,
|
|
13
13
|
} from "../src/sdk/prebuiltHandler.js";
|
|
14
|
-
|
|
15
|
-
const CHECKOUT_CODE_URI = "CodeUri: ../../packages/aws-lambda/dist/handler.zip";
|
|
14
|
+
import { writePrebuiltTemplate } from "./prebuilt-template.mjs";
|
|
16
15
|
|
|
17
16
|
export function pinHandlerZip(repoRoot: string): HandlerZipManifest {
|
|
18
17
|
const pkgDir = join(repoRoot, "packages", "aws-lambda");
|
|
@@ -31,18 +30,8 @@ export function pinHandlerZip(repoRoot: string): HandlerZipManifest {
|
|
|
31
30
|
const sha256 = createHash("sha256").update(bytes).digest("hex");
|
|
32
31
|
writeFileSync(asset.replace(/\.zip$/, ".sha256"), `${sha256} ${HANDLER_ZIP_ASSET}\n`);
|
|
33
32
|
|
|
34
|
-
const template = readFileSync(join(repoRoot, "examples", "aws-lambda", "template.yaml"), "utf-8");
|
|
35
|
-
if (template.split(CHECKOUT_CODE_URI).length !== 2) {
|
|
36
|
-
throw new Error(
|
|
37
|
-
`[pin-handler-zip] expected exactly one "${CHECKOUT_CODE_URI}" in the template`,
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
33
|
const outDir = join(pkgDir, PREBUILT_DIR);
|
|
41
|
-
|
|
42
|
-
writeFileSync(
|
|
43
|
-
join(outDir, "template.yaml"),
|
|
44
|
-
template.replace(CHECKOUT_CODE_URI, "CodeUri: handler.zip"),
|
|
45
|
-
);
|
|
34
|
+
writePrebuiltTemplate(repoRoot, outDir);
|
|
46
35
|
const manifest: HandlerZipManifest = {
|
|
47
36
|
version: pkg.version,
|
|
48
37
|
url: `${pkg.repository.url}/releases/download/v${pkg.version}/${HANDLER_ZIP_ASSET}`,
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
const CHECKOUT_CODE_URI = "CodeUri: ../../packages/aws-lambda/dist/handler.zip";
|
|
5
|
+
|
|
6
|
+
/** Writes `<outDir>/template.yaml`: the example SAM template, pointed at a `handler.zip` beside it. */
|
|
7
|
+
export function writePrebuiltTemplate(repoRoot, outDir) {
|
|
8
|
+
const template = readFileSync(join(repoRoot, "examples", "aws-lambda", "template.yaml"), "utf-8");
|
|
9
|
+
if (template.split(CHECKOUT_CODE_URI).length !== 2) {
|
|
10
|
+
throw new Error(
|
|
11
|
+
`[prebuilt-template] expected exactly one "${CHECKOUT_CODE_URI}" in the template`,
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
mkdirSync(outDir, { recursive: true });
|
|
15
|
+
writeFileSync(
|
|
16
|
+
join(outDir, "template.yaml"),
|
|
17
|
+
template.replace(CHECKOUT_CODE_URI, "CodeUri: handler.zip"),
|
|
18
|
+
);
|
|
19
|
+
}
|