hyperframes 0.4.25 → 0.4.26

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 (2) hide show
  1. package/dist/cli.js +175 -32
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -54,7 +54,7 @@ var VERSION;
54
54
  var init_version = __esm({
55
55
  "src/version.ts"() {
56
56
  "use strict";
57
- VERSION = true ? "0.4.25" : "0.0.0-dev";
57
+ VERSION = true ? "0.4.26" : "0.0.0-dev";
58
58
  }
59
59
  });
60
60
 
@@ -37572,6 +37572,89 @@ var init_play = __esm({
37572
37572
  import { basename as basename7, join as join39, relative as relative4 } from "path";
37573
37573
  import { readdirSync as readdirSync15, readFileSync as readFileSync27, statSync as statSync14 } from "fs";
37574
37574
  import AdmZip from "adm-zip";
37575
+ function isRecord(value) {
37576
+ return typeof value === "object" && value !== null && !Array.isArray(value);
37577
+ }
37578
+ function dataRecord(payload) {
37579
+ if (!isRecord(payload) || !isRecord(payload["data"])) return null;
37580
+ return payload["data"];
37581
+ }
37582
+ function stringField(record, key2) {
37583
+ const value = record[key2];
37584
+ return typeof value === "string" ? value : null;
37585
+ }
37586
+ function parsePublishedProjectResponse(payload) {
37587
+ const data = dataRecord(payload);
37588
+ if (!data) return null;
37589
+ const projectId = stringField(data, "project_id");
37590
+ const title = stringField(data, "title");
37591
+ const url = stringField(data, "url");
37592
+ const claimToken = stringField(data, "claim_token");
37593
+ const fileCount = data["file_count"];
37594
+ if (!projectId || !title || !url || !claimToken || typeof fileCount !== "number") {
37595
+ return null;
37596
+ }
37597
+ return {
37598
+ projectId,
37599
+ title,
37600
+ fileCount,
37601
+ url,
37602
+ claimToken
37603
+ };
37604
+ }
37605
+ function parseStagedUploadResponse(payload, archiveByteLength) {
37606
+ const data = dataRecord(payload);
37607
+ if (!data) return null;
37608
+ const uploadUrl = stringField(data, "upload_url");
37609
+ const uploadKey = stringField(data, "upload_key");
37610
+ const contentType = stringField(data, "content_type") || PUBLISH_CONTENT_TYPE;
37611
+ if (!uploadUrl || !uploadKey) return null;
37612
+ return {
37613
+ uploadUrl,
37614
+ uploadKey,
37615
+ contentType,
37616
+ uploadHeaders: getUploadHeaders(data, uploadUrl, contentType, archiveByteLength)
37617
+ };
37618
+ }
37619
+ function getUploadHeaders(data, uploadUrl, contentType, archiveByteLength) {
37620
+ const headers = {};
37621
+ const uploadHeaders = data["upload_headers"];
37622
+ if (isRecord(uploadHeaders)) {
37623
+ for (const [key2, value] of Object.entries(uploadHeaders)) {
37624
+ if (typeof value === "string" && key2.trim()) {
37625
+ headers[key2] = value;
37626
+ }
37627
+ }
37628
+ }
37629
+ if (!Object.keys(headers).some((key2) => key2.toLowerCase() === "content-type")) {
37630
+ headers["content-type"] = contentType;
37631
+ }
37632
+ const signedHeaders = new URL(uploadUrl).searchParams.get("X-Amz-SignedHeaders");
37633
+ if (signedHeaders?.split(";").includes("x-amz-server-side-encryption") && !Object.keys(headers).some((key2) => key2.toLowerCase() === "x-amz-server-side-encryption")) {
37634
+ headers["x-amz-server-side-encryption"] = "AES256";
37635
+ }
37636
+ if (signedHeaders?.split(";").includes("content-length") && !Object.keys(headers).some((key2) => key2.toLowerCase() === "content-length")) {
37637
+ headers["content-length"] = String(archiveByteLength);
37638
+ }
37639
+ return headers;
37640
+ }
37641
+ async function readJson(response) {
37642
+ return response.clone().json().catch(() => null);
37643
+ }
37644
+ async function readErrorMessage(response, fallback) {
37645
+ const contentType = response.headers.get("content-type") || "";
37646
+ if (contentType.includes("application/json")) {
37647
+ const payload = await readJson(response);
37648
+ if (isRecord(payload) && typeof payload["message"] === "string") {
37649
+ return payload["message"];
37650
+ }
37651
+ }
37652
+ if (response.status === 403 && response.headers.get("cf-mitigated") === "challenge") {
37653
+ return "Publish upload was blocked before reaching HyperFrames. Please retry after staged uploads are available.";
37654
+ }
37655
+ const text = await response.text().catch(() => "");
37656
+ return text.trim() ? `${fallback}: ${text.trim().slice(0, 180)}` : fallback;
37657
+ }
37575
37658
  function shouldIgnoreSegment(segment) {
37576
37659
  return segment.startsWith(".") || IGNORED_DIRS.has(segment) || IGNORED_FILES.has(segment);
37577
37660
  }
@@ -37607,42 +37690,102 @@ function createPublishArchive(projectDir) {
37607
37690
  function getPublishApiBaseUrl() {
37608
37691
  return (process.env["HYPERFRAMES_PUBLISHED_PROJECTS_API_URL"] || process.env["HEYGEN_API_URL"] || "https://api2.heygen.com").replace(/\/$/, "");
37609
37692
  }
37610
- async function publishProjectArchive(projectDir) {
37611
- const title = basename7(projectDir);
37612
- const archive = createPublishArchive(projectDir);
37613
- const archiveBytes = new Uint8Array(archive.buffer.byteLength);
37614
- archiveBytes.set(archive.buffer);
37693
+ function archiveArrayBuffer(archive) {
37694
+ const arrayBuffer = new ArrayBuffer(archive.buffer.byteLength);
37695
+ new Uint8Array(arrayBuffer).set(archive.buffer);
37696
+ return arrayBuffer;
37697
+ }
37698
+ async function publishProjectArchiveDirect(apiBaseUrl, title, archive) {
37615
37699
  const body = new FormData();
37616
37700
  body.set("title", title);
37617
- body.set("file", new File([archiveBytes], `${title}.zip`, { type: "application/zip" }));
37701
+ body.set(
37702
+ "file",
37703
+ new File([archiveArrayBuffer(archive)], `${title}.zip`, { type: PUBLISH_CONTENT_TYPE })
37704
+ );
37618
37705
  const headers = {
37619
37706
  heygen_route: "canary"
37620
37707
  };
37621
- const response = await fetch(`${getPublishApiBaseUrl()}/v1/hyperframes/projects/publish`, {
37708
+ const response = await fetch(`${apiBaseUrl}/v1/hyperframes/projects/publish`, {
37622
37709
  method: "POST",
37623
37710
  body,
37624
37711
  headers,
37625
- signal: AbortSignal.timeout(3e4)
37712
+ signal: AbortSignal.timeout(PUBLISH_REQUEST_TIMEOUT_MS)
37626
37713
  });
37627
- const payload = await response.json().catch(() => null);
37628
- const message = typeof payload?.message === "string" ? payload.message : "Failed to publish project";
37629
- if (!response.ok || !payload?.data) {
37630
- throw new Error(message);
37714
+ const payload = await readJson(response);
37715
+ const publishedProject = parsePublishedProjectResponse(payload);
37716
+ if (!response.ok || !publishedProject) {
37717
+ throw new Error(await readErrorMessage(response, "Failed to publish project"));
37631
37718
  }
37632
- return {
37633
- projectId: String(payload.data.project_id),
37634
- title: String(payload.data.title),
37635
- fileCount: Number(payload.data.file_count),
37636
- url: String(payload.data.url),
37637
- claimToken: String(payload.data.claim_token)
37638
- };
37719
+ return publishedProject;
37720
+ }
37721
+ async function publishProjectArchiveStaged(apiBaseUrl, title, archive) {
37722
+ const fileName = `${title}.zip`;
37723
+ const uploadResponse = await fetch(`${apiBaseUrl}/v1/hyperframes/projects/publish/upload`, {
37724
+ method: "POST",
37725
+ body: JSON.stringify({
37726
+ file_name: fileName,
37727
+ content_type: PUBLISH_CONTENT_TYPE,
37728
+ content_length: archive.buffer.byteLength
37729
+ }),
37730
+ headers: {
37731
+ "content-type": "application/json",
37732
+ heygen_route: "canary"
37733
+ },
37734
+ signal: AbortSignal.timeout(PUBLISH_REQUEST_TIMEOUT_MS)
37735
+ });
37736
+ if (uploadResponse.status === 404 || uploadResponse.status === 405) {
37737
+ return null;
37738
+ }
37739
+ const uploadPayload = await readJson(uploadResponse);
37740
+ const stagedUpload = parseStagedUploadResponse(uploadPayload, archive.buffer.byteLength);
37741
+ if (!uploadResponse.ok || !stagedUpload) {
37742
+ throw new Error(await readErrorMessage(uploadResponse, "Failed to prepare project upload"));
37743
+ }
37744
+ const s3Response = await fetch(stagedUpload.uploadUrl, {
37745
+ method: "PUT",
37746
+ body: new Blob([archiveArrayBuffer(archive)], { type: stagedUpload.contentType }),
37747
+ headers: stagedUpload.uploadHeaders,
37748
+ signal: AbortSignal.timeout(PUBLISH_REQUEST_TIMEOUT_MS)
37749
+ });
37750
+ if (!s3Response.ok) {
37751
+ throw new Error(await readErrorMessage(s3Response, "Failed to upload project archive"));
37752
+ }
37753
+ const completeResponse = await fetch(`${apiBaseUrl}/v1/hyperframes/projects/publish/complete`, {
37754
+ method: "POST",
37755
+ body: JSON.stringify({
37756
+ upload_key: stagedUpload.uploadKey,
37757
+ file_name: fileName,
37758
+ title
37759
+ }),
37760
+ headers: {
37761
+ "content-type": "application/json",
37762
+ heygen_route: "canary"
37763
+ },
37764
+ signal: AbortSignal.timeout(PUBLISH_REQUEST_TIMEOUT_MS)
37765
+ });
37766
+ const completePayload = await readJson(completeResponse);
37767
+ const publishedProject = parsePublishedProjectResponse(completePayload);
37768
+ if (!completeResponse.ok || !publishedProject) {
37769
+ throw new Error(await readErrorMessage(completeResponse, "Failed to publish project"));
37770
+ }
37771
+ return publishedProject;
37772
+ }
37773
+ async function publishProjectArchive(projectDir) {
37774
+ const title = basename7(projectDir);
37775
+ const archive = createPublishArchive(projectDir);
37776
+ const apiBaseUrl = getPublishApiBaseUrl();
37777
+ const stagedResult = await publishProjectArchiveStaged(apiBaseUrl, title, archive);
37778
+ if (stagedResult) return stagedResult;
37779
+ return publishProjectArchiveDirect(apiBaseUrl, title, archive);
37639
37780
  }
37640
- var IGNORED_DIRS, IGNORED_FILES;
37781
+ var IGNORED_DIRS, IGNORED_FILES, PUBLISH_CONTENT_TYPE, PUBLISH_REQUEST_TIMEOUT_MS;
37641
37782
  var init_publishProject = __esm({
37642
37783
  "src/utils/publishProject.ts"() {
37643
37784
  "use strict";
37644
37785
  IGNORED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".next", "coverage"]);
37645
37786
  IGNORED_FILES = /* @__PURE__ */ new Set([".DS_Store", "Thumbs.db"]);
37787
+ PUBLISH_CONTENT_TYPE = "application/zip";
37788
+ PUBLISH_REQUEST_TIMEOUT_MS = 3e4;
37646
37789
  }
37647
37790
  });
37648
37791
 
@@ -65171,19 +65314,19 @@ function _moveValueRecursive(data, sourceKeys, destKeys, keyIdx, excludeKeys) {
65171
65314
  const key2 = sourceKeys[keyIdx];
65172
65315
  if (key2.endsWith("[]")) {
65173
65316
  const keyName = key2.slice(0, -2);
65174
- const dataRecord = data;
65175
- if (keyName in dataRecord && Array.isArray(dataRecord[keyName])) {
65176
- for (const item of dataRecord[keyName]) {
65317
+ const dataRecord2 = data;
65318
+ if (keyName in dataRecord2 && Array.isArray(dataRecord2[keyName])) {
65319
+ for (const item of dataRecord2[keyName]) {
65177
65320
  _moveValueRecursive(item, sourceKeys, destKeys, keyIdx + 1, excludeKeys);
65178
65321
  }
65179
65322
  }
65180
65323
  } else if (key2 === "*") {
65181
65324
  if (typeof data === "object" && data !== null && !Array.isArray(data)) {
65182
- const dataRecord = data;
65183
- const keysToMove = Object.keys(dataRecord).filter((k2) => !k2.startsWith("_") && !excludeKeys.has(k2));
65325
+ const dataRecord2 = data;
65326
+ const keysToMove = Object.keys(dataRecord2).filter((k2) => !k2.startsWith("_") && !excludeKeys.has(k2));
65184
65327
  const valuesToMove = {};
65185
65328
  for (const k2 of keysToMove) {
65186
- valuesToMove[k2] = dataRecord[k2];
65329
+ valuesToMove[k2] = dataRecord2[k2];
65187
65330
  }
65188
65331
  for (const [k2, v] of Object.entries(valuesToMove)) {
65189
65332
  const newDestKeys = [];
@@ -65194,16 +65337,16 @@ function _moveValueRecursive(data, sourceKeys, destKeys, keyIdx, excludeKeys) {
65194
65337
  newDestKeys.push(dk);
65195
65338
  }
65196
65339
  }
65197
- setValueByPath(dataRecord, newDestKeys, v);
65340
+ setValueByPath(dataRecord2, newDestKeys, v);
65198
65341
  }
65199
65342
  for (const k2 of keysToMove) {
65200
- delete dataRecord[k2];
65343
+ delete dataRecord2[k2];
65201
65344
  }
65202
65345
  }
65203
65346
  } else {
65204
- const dataRecord = data;
65205
- if (key2 in dataRecord) {
65206
- _moveValueRecursive(dataRecord[key2], sourceKeys, destKeys, keyIdx + 1, excludeKeys);
65347
+ const dataRecord2 = data;
65348
+ if (key2 in dataRecord2) {
65349
+ _moveValueRecursive(dataRecord2[key2], sourceKeys, destKeys, keyIdx + 1, excludeKeys);
65207
65350
  }
65208
65351
  }
65209
65352
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hyperframes",
3
- "version": "0.4.25",
3
+ "version": "0.4.26",
4
4
  "description": "HyperFrames CLI — create, preview, and render HTML video compositions",
5
5
  "repository": {
6
6
  "type": "git",