@hyperframes/aws-lambda 0.8.190 → 0.8.192

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.
@@ -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-YS3KY3C5.js";
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-CKQ6SAJX.js";
18
+ } from "./chunk-FQDVV4JA.js";
19
19
  import {
20
20
  CONTENT_STORE_PREFIX
21
- } from "./chunk-YS3KY3C5.js";
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";
@@ -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-CKQ6SAJX.js";
20
+ } from "./chunk-FQDVV4JA.js";
20
21
  import {
21
- CONTENT_STORE_RETENTION_DAYS
22
- } from "./chunk-YS3KY3C5.js";
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 { hashProjectDir, listSiteFiles } from "@hyperframes/producer/distributed";
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
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CONTENT_STORE_PREFIX,
3
3
  CONTENT_STORE_RETENTION_DAYS
4
- } from "../_chunks/chunk-YS3KY3C5.js";
4
+ } from "../_chunks/chunk-3UDA73TT.js";
5
5
 
6
6
  // src/cdk/HyperframesRenderStack.ts
7
7
  import { dirname, resolve } from "node:path";
@@ -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/handler.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  handler,
3
3
  unwrapEvent
4
- } from "./_chunks/chunk-Z7KVGDNN.js";
5
- import "./_chunks/chunk-CKQ6SAJX.js";
6
- import "./_chunks/chunk-YS3KY3C5.js";
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-Z7KVGDNN.js";
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-EG2WRNUL.js";
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-CKQ6SAJX.js";
28
- import "./_chunks/chunk-YS3KY3C5.js";
27
+ } from "./_chunks/chunk-FQDVV4JA.js";
28
+ import "./_chunks/chunk-3UDA73TT.js";
29
29
  export {
30
30
  ChromeBinaryUnavailableError,
31
31
  InvalidConfigError,
@@ -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>;
@@ -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-EG2WRNUL.js";
13
+ } from "../_chunks/chunk-L4R3FJOR.js";
14
14
  import {
15
15
  sha256File
16
- } from "../_chunks/chunk-CKQ6SAJX.js";
17
- import "../_chunks/chunk-YS3KY3C5.js";
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.190",
3
+ "version": "0.8.192",
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.190"
55
+ "@hyperframes/producer": "^0.8.192"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@types/aws-lambda": "^8.10.146",
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "0.8.190",
3
- "url": "https://github.com/heygen-com/hyperframes/releases/download/v0.8.190/hyperframes-lambda-handler.zip",
4
- "sha256": "0ce69454c04f63dc984681ff94999337897a198378bdd3adb00af94c967a6a44",
5
- "bytes": 129254500
2
+ "version": "0.8.192",
3
+ "url": "https://github.com/heygen-com/hyperframes/releases/download/v0.8.192/hyperframes-lambda-handler.zip",
4
+ "sha256": "96ec79a65e6803ff0542daf1c5f4feb28890f53019df7aeffcedf27f2c185f99",
5
+ "bytes": 129257853
6
6
  }
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "0.8.190",
3
- "url": "https://github.com/heygen-com/hyperframes/releases/download/v0.8.190/hyperframes-lambda-video-arm64.oci.tar",
4
- "sha256": "17ec30066b1d0f8fc4ce49495ce3fa3efba5cb8b2a609131b2b256b9c2f153f0",
5
- "bytes": 244633600
2
+ "version": "0.8.192",
3
+ "url": "https://github.com/heygen-com/hyperframes/releases/download/v0.8.192/hyperframes-lambda-video-arm64.oci.tar",
4
+ "sha256": "904678eceb8c21d5ec2f5981b694c90fc776b4b9647ea3b11cdc09703356940c",
5
+ "bytes": 244637696
6
6
  }