@hyperframes/aws-lambda 0.8.189 → 0.8.191
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-YS3KY3C5.js → chunk-3UDA73TT.js} +5 -1
- package/dist/_chunks/{chunk-CKQ6SAJX.js → chunk-FQDVV4JA.js} +23 -1
- package/dist/_chunks/{chunk-ROTCAPRH.js → chunk-J3OLGMWP.js} +7 -2
- package/dist/_chunks/{chunk-EG2WRNUL.js → chunk-L4R3FJOR.js} +37 -4
- package/dist/cdk/index.js +1 -1
- package/dist/contentStore.d.ts +1 -0
- package/dist/events.d.ts +8 -2
- package/dist/handler.js +3 -3
- package/dist/index.js +4 -4
- package/dist/s3Transport.d.ts +1 -0
- package/dist/sdk/deploySite.d.ts +2 -0
- package/dist/sdk/index.js +3 -3
- package/dist/sdk/renderToLambda.d.ts +1 -0
- package/package.json +2 -2
- package/prebuilt/handler-zip.json +4 -4
- package/prebuilt/template.yaml +22 -0
- package/prebuilt/video-image.json +4 -4
|
@@ -10,10 +10,14 @@ function contentStoreUri(bucket, sha256) {
|
|
|
10
10
|
}
|
|
11
11
|
return `s3://${bucket}/${CONTENT_STORE_PREFIX}/${sha256.slice(0, 2)}/${sha256}`;
|
|
12
12
|
}
|
|
13
|
+
function audioSidecarUri(bucket, sha256) {
|
|
14
|
+
return `${contentStoreUri(bucket, sha256)}.audio.m4a`;
|
|
15
|
+
}
|
|
13
16
|
|
|
14
17
|
export {
|
|
15
18
|
CONTENT_STORE_PREFIX,
|
|
16
19
|
CONTENT_STORE_RETENTION_DAYS,
|
|
17
20
|
CONTENT_STORE_REFRESH_AFTER_DAYS,
|
|
18
|
-
contentStoreUri
|
|
21
|
+
contentStoreUri,
|
|
22
|
+
audioSidecarUri
|
|
19
23
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CONTENT_STORE_REFRESH_AFTER_DAYS,
|
|
3
|
+
audioSidecarUri,
|
|
3
4
|
contentStoreUri
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-3UDA73TT.js";
|
|
5
6
|
|
|
6
7
|
// src/s3Transport.ts
|
|
7
8
|
import {
|
|
@@ -333,6 +334,24 @@ async function putContentStoreFile(client, localPath, bucket, sha256) {
|
|
|
333
334
|
if (lastModified) await refreshAgingObject(client, uri, sha256, lastModified, size ?? 0);
|
|
334
335
|
return outcome;
|
|
335
336
|
}
|
|
337
|
+
async function putAudioSidecar(client, localPath, bucket, sha256) {
|
|
338
|
+
const uri = audioSidecarUri(bucket, sha256);
|
|
339
|
+
if (await s3ObjectExists(client, uri)) return "reused";
|
|
340
|
+
const { key } = parseS3Uri(uri);
|
|
341
|
+
const size = statSync(localPath).size;
|
|
342
|
+
const own = await sha256File(localPath);
|
|
343
|
+
try {
|
|
344
|
+
if (size > MAX_SINGLE_PUT_BYTES) {
|
|
345
|
+
await uploadFileInParts(client, localPath, size, { Bucket: bucket, Key: key }, own);
|
|
346
|
+
} else {
|
|
347
|
+
await putImmutableBody(client, localPath, bucket, key, size, own, "audio/mp4");
|
|
348
|
+
}
|
|
349
|
+
} catch (error) {
|
|
350
|
+
if (!isS3PreconditionFailed(error)) throw error;
|
|
351
|
+
return "reused";
|
|
352
|
+
}
|
|
353
|
+
return "uploaded";
|
|
354
|
+
}
|
|
336
355
|
async function ensureContentStoreObject(client, bucket, sha256, sizeBytes) {
|
|
337
356
|
const uri = contentStoreUri(bucket, sha256);
|
|
338
357
|
const { key } = parseS3Uri(uri);
|
|
@@ -519,8 +538,10 @@ async function downloadSiteFiles(s3, manifestUri, projectDir, leaveVideosRemote)
|
|
|
519
538
|
await mapConcurrent(files, 16, async ({ path, sha256, sizeBytes }) => {
|
|
520
539
|
const uri = contentStoreUri(bucket, sha256);
|
|
521
540
|
if (leaveVideosRemote && VIDEO_EXTENSIONS_PLANNED_IN_PLACE.has(extname(path).toLowerCase())) {
|
|
541
|
+
const sidecar = audioSidecarUri(bucket, sha256);
|
|
522
542
|
remoteFiles[path] = {
|
|
523
543
|
url: await presignS3GetUrl(s3, uri, REMOTE_URL_TTL_SECONDS),
|
|
544
|
+
...await s3ObjectExists(s3, sidecar) ? { audioSidecarUrl: await presignS3GetUrl(s3, sidecar, REMOTE_URL_TTL_SECONDS) } : {},
|
|
524
545
|
sha256,
|
|
525
546
|
sizeBytes
|
|
526
547
|
};
|
|
@@ -551,6 +572,7 @@ export {
|
|
|
551
572
|
mapConcurrent,
|
|
552
573
|
sha256File,
|
|
553
574
|
putContentStoreFile,
|
|
575
|
+
putAudioSidecar,
|
|
554
576
|
ensureContentStoreObject,
|
|
555
577
|
s3ObjectExists,
|
|
556
578
|
isS3NotFound,
|
|
@@ -15,10 +15,10 @@ import {
|
|
|
15
15
|
untarDirectory,
|
|
16
16
|
uploadContentAddressedFileToS3,
|
|
17
17
|
uploadFileToS3
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-FQDVV4JA.js";
|
|
19
19
|
import {
|
|
20
20
|
CONTENT_STORE_PREFIX
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-3UDA73TT.js";
|
|
22
22
|
|
|
23
23
|
// src/handler.ts
|
|
24
24
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, mkdtempSync as mkdtempSync2, readFileSync, rmSync as rmSync2, statSync as statSync2 } from "node:fs";
|
|
@@ -345,6 +345,11 @@ function getS3Client() {
|
|
|
345
345
|
return cachedS3Client;
|
|
346
346
|
}
|
|
347
347
|
async function handler(event, deps) {
|
|
348
|
+
if (event.Action === "warm") {
|
|
349
|
+
primeRuntimeEnv();
|
|
350
|
+
await ensureChromePath(deps);
|
|
351
|
+
return { Action: "warm" };
|
|
352
|
+
}
|
|
348
353
|
const unwrapped = unwrapEvent(event);
|
|
349
354
|
validatePlanProtocolShape(unwrapped);
|
|
350
355
|
validateEventS3Uris(unwrapped);
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
mapConcurrent,
|
|
10
10
|
parseS3Uri,
|
|
11
11
|
parseSiteManifest,
|
|
12
|
+
putAudioSidecar,
|
|
12
13
|
putContentStoreFile,
|
|
13
14
|
s3ObjectExists,
|
|
14
15
|
serializeSiteManifest,
|
|
@@ -16,17 +17,23 @@ import {
|
|
|
16
17
|
siteManifestUri,
|
|
17
18
|
siteTarballUri,
|
|
18
19
|
uploadContentAddressedFileToS3
|
|
19
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-FQDVV4JA.js";
|
|
20
21
|
import {
|
|
21
|
-
CONTENT_STORE_RETENTION_DAYS
|
|
22
|
-
|
|
22
|
+
CONTENT_STORE_RETENTION_DAYS,
|
|
23
|
+
audioSidecarUri
|
|
24
|
+
} from "./chunk-3UDA73TT.js";
|
|
23
25
|
|
|
24
26
|
// src/sdk/deploySite.ts
|
|
25
27
|
import { existsSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
26
28
|
import { tmpdir } from "node:os";
|
|
27
29
|
import { join } from "node:path";
|
|
28
30
|
import { S3Client } from "@aws-sdk/client-s3";
|
|
29
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
buildAudioSidecar,
|
|
33
|
+
hashProjectDir,
|
|
34
|
+
listSiteFiles,
|
|
35
|
+
wantsAudioSidecar
|
|
36
|
+
} from "@hyperframes/producer/distributed";
|
|
30
37
|
function siteHandleFromId(bucketName, siteId) {
|
|
31
38
|
const projectS3Uri = siteManifestUri(bucketName, siteId);
|
|
32
39
|
return { siteId, bucketName, projectS3Uri, bytes: 0, uploadedAt: "", uploaded: false };
|
|
@@ -97,6 +104,7 @@ async function deploySite(opts) {
|
|
|
97
104
|
uploaded ||= outcome === "uploaded";
|
|
98
105
|
});
|
|
99
106
|
stored.sort((a, b) => a.path < b.path ? -1 : 1);
|
|
107
|
+
await storeAudioSidecars(s3, opts, stored);
|
|
100
108
|
const workdir = mkdtempSync(join(tmpdir(), "hf-deploy-site-"));
|
|
101
109
|
try {
|
|
102
110
|
const manifestPath = join(workdir, "files.json");
|
|
@@ -122,6 +130,30 @@ async function deploySite(opts) {
|
|
|
122
130
|
uploaded
|
|
123
131
|
};
|
|
124
132
|
}
|
|
133
|
+
async function storeAudioSidecars(s3, opts, files) {
|
|
134
|
+
const videos = files.filter((file) => wantsAudioSidecar(file.path, file.sizeBytes));
|
|
135
|
+
if (videos.length === 0) return;
|
|
136
|
+
const workdir = mkdtempSync(join(tmpdir(), "hf-audio-sidecar-"));
|
|
137
|
+
let unavailable = false;
|
|
138
|
+
try {
|
|
139
|
+
await mapConcurrent(videos, 2, async ({ path, sha256 }) => {
|
|
140
|
+
if (unavailable || await s3ObjectExists(s3, audioSidecarUri(opts.bucketName, sha256)))
|
|
141
|
+
return;
|
|
142
|
+
const sidecarPath = join(workdir, `${sha256}.m4a`);
|
|
143
|
+
const outcome = await buildAudioSidecar(join(opts.projectDir, path), sidecarPath);
|
|
144
|
+
if (outcome === "unavailable") unavailable = true;
|
|
145
|
+
if (outcome === "built") await putAudioSidecar(s3, sidecarPath, opts.bucketName, sha256);
|
|
146
|
+
rmSync(sidecarPath, { force: true });
|
|
147
|
+
});
|
|
148
|
+
} finally {
|
|
149
|
+
rmSync(workdir, { recursive: true, force: true });
|
|
150
|
+
}
|
|
151
|
+
if (unavailable) {
|
|
152
|
+
opts.onNotice?.(
|
|
153
|
+
"ffmpeg was not found on this machine, so the audio of large videos was not stored on its own: renders will read the whole video for its audio and take longer. Install ffmpeg and run `sites create` again."
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
125
157
|
|
|
126
158
|
// src/sdk/validateConfig.ts
|
|
127
159
|
import { InvalidConfigError } from "@hyperframes/producer/distributed";
|
|
@@ -190,6 +222,7 @@ async function renderToLambda(opts) {
|
|
|
190
222
|
projectDir: opts.projectDir,
|
|
191
223
|
bucketName: opts.bucketName,
|
|
192
224
|
region: opts.region,
|
|
225
|
+
onNotice: opts.onNotice,
|
|
193
226
|
s3: opts.s3
|
|
194
227
|
});
|
|
195
228
|
const input = {
|
package/dist/cdk/index.js
CHANGED
package/dist/contentStore.d.ts
CHANGED
|
@@ -3,3 +3,4 @@ export declare const CONTENT_STORE_RETENTION_DAYS = 30;
|
|
|
3
3
|
/** Reusing an object at least this old rewrites it, so a plan's objects outlive it by 23+ days. */
|
|
4
4
|
export declare const CONTENT_STORE_REFRESH_AFTER_DAYS = 7;
|
|
5
5
|
export declare function contentStoreUri(bucket: string, sha256: string): string;
|
|
6
|
+
export declare function audioSidecarUri(bucket: string, sha256: string): string;
|
package/dist/events.d.ts
CHANGED
|
@@ -19,6 +19,9 @@ import type { DistributedFormat, SerializableDistributedRenderConfig } from "@hy
|
|
|
19
19
|
export type { SerializableDistributedRenderConfig } from "@hyperframes/producer/distributed";
|
|
20
20
|
/** Discriminator for the three roles the one Lambda image fulfills. */
|
|
21
21
|
export type LambdaAction = "plan" | "audio" | "renderChunk" | "assemble";
|
|
22
|
+
export interface WarmEvent {
|
|
23
|
+
Action: "warm";
|
|
24
|
+
}
|
|
22
25
|
/** Transport protocol selected for one complete distributed render. */
|
|
23
26
|
export type LambdaPlanProtocol = "v1" | "v2";
|
|
24
27
|
/**
|
|
@@ -29,7 +32,7 @@ export type LambdaPlanProtocol = "v1" | "v2";
|
|
|
29
32
|
* handler unwraps both `event.Payload` and `event.Input` before
|
|
30
33
|
* dispatching.
|
|
31
34
|
*/
|
|
32
|
-
export type LambdaEvent = PlanEvent | AudioEvent | RenderChunkEvent | AssembleEvent | {
|
|
35
|
+
export type LambdaEvent = PlanEvent | AudioEvent | RenderChunkEvent | AssembleEvent | WarmEvent | {
|
|
33
36
|
Payload: LambdaEvent;
|
|
34
37
|
} | {
|
|
35
38
|
Input: LambdaEvent;
|
|
@@ -199,4 +202,7 @@ export interface AssembleLambdaResult {
|
|
|
199
202
|
FileSize: number;
|
|
200
203
|
DurationMs: number;
|
|
201
204
|
}
|
|
202
|
-
export
|
|
205
|
+
export interface WarmLambdaResult {
|
|
206
|
+
Action: "warm";
|
|
207
|
+
}
|
|
208
|
+
export type LambdaResult = WarmLambdaResult | PlanLambdaResult | AudioLambdaResult | RenderChunkLambdaResult | AssembleLambdaResult;
|
package/dist/handler.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handler,
|
|
3
3
|
unwrapEvent
|
|
4
|
-
} from "./_chunks/chunk-
|
|
5
|
-
import "./_chunks/chunk-
|
|
6
|
-
import "./_chunks/chunk-
|
|
4
|
+
} from "./_chunks/chunk-J3OLGMWP.js";
|
|
5
|
+
import "./_chunks/chunk-FQDVV4JA.js";
|
|
6
|
+
import "./_chunks/chunk-3UDA73TT.js";
|
|
7
7
|
export {
|
|
8
8
|
handler,
|
|
9
9
|
unwrapEvent
|
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-J3OLGMWP.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-L4R3FJOR.js";
|
|
18
18
|
import {
|
|
19
19
|
downloadS3ObjectToFile,
|
|
20
20
|
downloadS3ObjectToFileVerified,
|
|
@@ -24,8 +24,8 @@ import {
|
|
|
24
24
|
untarDirectory,
|
|
25
25
|
uploadContentAddressedFileToS3,
|
|
26
26
|
uploadFileToS3
|
|
27
|
-
} from "./_chunks/chunk-
|
|
28
|
-
import "./_chunks/chunk-
|
|
27
|
+
} from "./_chunks/chunk-FQDVV4JA.js";
|
|
28
|
+
import "./_chunks/chunk-3UDA73TT.js";
|
|
29
29
|
export {
|
|
30
30
|
ChromeBinaryUnavailableError,
|
|
31
31
|
InvalidConfigError,
|
package/dist/s3Transport.d.ts
CHANGED
|
@@ -65,6 +65,7 @@ export declare function mapConcurrent<T>(values: readonly T[], concurrency: numb
|
|
|
65
65
|
export declare function sha256File(path: string): Promise<string>;
|
|
66
66
|
/** Put a file into the shared content store once; reusing an aging object restarts its expiry. */
|
|
67
67
|
export declare function putContentStoreFile(client: S3Client, localPath: string, bucket: string, sha256: string): Promise<"uploaded" | "reused">;
|
|
68
|
+
export declare function putAudioSidecar(client: S3Client, localPath: string, bucket: string, sha256: string): Promise<"uploaded" | "reused">;
|
|
68
69
|
/** Confirm an object the caller never uploaded is in the content store, restarting an aging one. */
|
|
69
70
|
export declare function ensureContentStoreObject(client: S3Client, bucket: string, sha256: string, sizeBytes: number): Promise<void>;
|
|
70
71
|
export declare function presignS3GetUrl(client: S3Client, uri: string, expiresInSeconds: number): Promise<string>;
|
package/dist/sdk/deploySite.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export interface DeploySiteOptions {
|
|
|
25
25
|
* unset, the hash of the project tree picks it.
|
|
26
26
|
*/
|
|
27
27
|
siteId?: string;
|
|
28
|
+
/** Called with a line a user should see, such as audio sidecars skipped for want of ffmpeg. */
|
|
29
|
+
onNotice?: (message: string) => void;
|
|
28
30
|
/** Injection seam for tests. Production callers leave unset. */
|
|
29
31
|
s3?: S3Client;
|
|
30
32
|
}
|
package/dist/sdk/index.js
CHANGED
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
validateDistributedRenderConfig,
|
|
11
11
|
validateStepFunctionsInputSize,
|
|
12
12
|
validateVariablesPayload
|
|
13
|
-
} from "../_chunks/chunk-
|
|
13
|
+
} from "../_chunks/chunk-L4R3FJOR.js";
|
|
14
14
|
import {
|
|
15
15
|
sha256File
|
|
16
|
-
} from "../_chunks/chunk-
|
|
17
|
-
import "../_chunks/chunk-
|
|
16
|
+
} from "../_chunks/chunk-FQDVV4JA.js";
|
|
17
|
+
import "../_chunks/chunk-3UDA73TT.js";
|
|
18
18
|
|
|
19
19
|
// src/sdk/prebuiltHandler.ts
|
|
20
20
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -26,6 +26,7 @@ export interface RenderToLambdaOptions {
|
|
|
26
26
|
projectDir?: string;
|
|
27
27
|
/** Re-use an existing `deploySite` upload (skips tar+S3 PUT). */
|
|
28
28
|
siteHandle?: SiteHandle;
|
|
29
|
+
onNotice?: (message: string) => void;
|
|
29
30
|
/** Validated `SerializableDistributedRenderConfig` (no logger / abortSignal). */
|
|
30
31
|
config: SerializableDistributedRenderConfig;
|
|
31
32
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/aws-lambda",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.191",
|
|
4
4
|
"description": "AWS Lambda adapter for HyperFrames distributed rendering — handler, client-side SDK, and CDK construct.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"ffprobe-static": "^3.1.0",
|
|
53
53
|
"puppeteer-core": "^25.8.0",
|
|
54
54
|
"tar": "^7.4.3",
|
|
55
|
-
"@hyperframes/producer": "^0.8.
|
|
55
|
+
"@hyperframes/producer": "^0.8.191"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
58
|
"@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.191",
|
|
3
|
+
"url": "https://github.com/heygen-com/hyperframes/releases/download/v0.8.191/hyperframes-lambda-handler.zip",
|
|
4
|
+
"sha256": "1f3e446a2c315dd675f283920d6231e3d80fc57a09ba6e16788a1f8ba9470a8d",
|
|
5
|
+
"bytes": 129256219
|
|
6
6
|
}
|
package/prebuilt/template.yaml
CHANGED
|
@@ -254,6 +254,11 @@ Resources:
|
|
|
254
254
|
SelectPlanProtocol:
|
|
255
255
|
Type: Choice
|
|
256
256
|
Choices:
|
|
257
|
+
# Only a stack with the arm64 video function has a cold x86 function to warm.
|
|
258
|
+
# Without one the compared value can never match.
|
|
259
|
+
- Variable: $.PlanProtocol
|
|
260
|
+
StringEquals: !If [HasVideoFunction, v2, v2-without-video-function]
|
|
261
|
+
Next: WarmRender
|
|
257
262
|
- Variable: $.PlanProtocol
|
|
258
263
|
StringEquals: v2
|
|
259
264
|
Next: PlanV2
|
|
@@ -265,6 +270,23 @@ Resources:
|
|
|
265
270
|
Next: UnsupportedPlanProtocol
|
|
266
271
|
Default: PlanV2
|
|
267
272
|
|
|
273
|
+
# The audio task runs on this function once the plan is done; starting its container now hides the cold start.
|
|
274
|
+
WarmRender:
|
|
275
|
+
Type: Task
|
|
276
|
+
Resource: arn:aws:states:::lambda:invoke
|
|
277
|
+
Parameters:
|
|
278
|
+
FunctionName: !GetAtt RenderFunction.Arn
|
|
279
|
+
InvocationType: Event
|
|
280
|
+
Payload:
|
|
281
|
+
Action: warm
|
|
282
|
+
ResultPath: null
|
|
283
|
+
Catch:
|
|
284
|
+
- ErrorEquals:
|
|
285
|
+
- States.ALL
|
|
286
|
+
ResultPath: null
|
|
287
|
+
Next: PlanV2
|
|
288
|
+
Next: PlanV2
|
|
289
|
+
|
|
268
290
|
UnsupportedPlanProtocol:
|
|
269
291
|
Type: Fail
|
|
270
292
|
Error: PLAN_PROTOCOL_UNSUPPORTED
|
|
@@ -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.191",
|
|
3
|
+
"url": "https://github.com/heygen-com/hyperframes/releases/download/v0.8.191/hyperframes-lambda-video-arm64.oci.tar",
|
|
4
|
+
"sha256": "a2aa52fe187cff37f073a5bccad3778832deb720b036b1df41b4329e197750e1",
|
|
5
|
+
"bytes": 244635136
|
|
6
6
|
}
|