hyperframes 0.6.58 → 0.6.59

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 +79 -47
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -50,7 +50,7 @@ var VERSION;
50
50
  var init_version = __esm({
51
51
  "src/version.ts"() {
52
52
  "use strict";
53
- VERSION = true ? "0.6.58" : "0.0.0-dev";
53
+ VERSION = true ? "0.6.59" : "0.0.0-dev";
54
54
  }
55
55
  });
56
56
 
@@ -69555,6 +69555,7 @@ __export(deterministicFonts_exports, {
69555
69555
  iterateFontFamilyDeclarations: () => iterateFontFamilyDeclarations,
69556
69556
  parseFontFamilyValue: () => parseFontFamilyValue
69557
69557
  });
69558
+ import { createHash as createHash6 } from "crypto";
69558
69559
  import { existsSync as existsSync31, mkdirSync as mkdirSync18, readFileSync as readFileSync24, writeFileSync as writeFileSync15 } from "fs";
69559
69560
  import { homedir as homedir8, tmpdir as tmpdir3 } from "os";
69560
69561
  import { join as join33 } from "path";
@@ -69609,7 +69610,7 @@ function extractRequestedFontFamilies(html) {
69609
69610
  }
69610
69611
  return requested;
69611
69612
  }
69612
- function buildFontFaceRule(familyName, src, weight, style) {
69613
+ function buildFontFaceRule(familyName, src, weight, style, unicodeRange) {
69613
69614
  return [
69614
69615
  "@font-face {",
69615
69616
  ` font-family: "${familyName}";`,
@@ -69617,6 +69618,9 @@ function buildFontFaceRule(familyName, src, weight, style) {
69617
69618
  ` font-style: ${style};`,
69618
69619
  ` font-weight: ${weight};`,
69619
69620
  " font-display: block;",
69621
+ // Preserve the subset's unicode-range so the browser selects the right
69622
+ // per-codepoint subset (matching Google Fonts' own CSS semantics).
69623
+ ...unicodeRange ? [` unicode-range: ${unicodeRange};`] : [],
69620
69624
  "}"
69621
69625
  ].join("\n");
69622
69626
  }
@@ -69637,18 +69641,31 @@ async function buildFontFaceCss(requestedFamilies, options) {
69637
69641
  }
69638
69642
  const googleFaces2 = await fetchGoogleFont(originalCaseFamily, options);
69639
69643
  for (const face of googleFaces2) {
69640
- const key2 = `${face.weight}:${face.style}`;
69641
- if (!coveredWeights.has(key2)) {
69642
- rules.push(buildFontFaceRule(originalCaseFamily, face.dataUri, face.weight, face.style));
69643
- coveredWeights.add(key2);
69644
- }
69644
+ if (coveredWeights.has(`${face.weight}:${face.style}`)) continue;
69645
+ rules.push(
69646
+ buildFontFaceRule(
69647
+ originalCaseFamily,
69648
+ face.dataUri,
69649
+ face.weight,
69650
+ face.style,
69651
+ face.unicodeRange
69652
+ )
69653
+ );
69645
69654
  }
69646
69655
  continue;
69647
69656
  }
69648
69657
  const googleFaces = await fetchGoogleFont(originalCaseFamily, options);
69649
69658
  if (googleFaces.length > 0) {
69650
69659
  for (const face of googleFaces) {
69651
- rules.push(buildFontFaceRule(originalCaseFamily, face.dataUri, face.weight, face.style));
69660
+ rules.push(
69661
+ buildFontFaceRule(
69662
+ originalCaseFamily,
69663
+ face.dataUri,
69664
+ face.weight,
69665
+ face.style,
69666
+ face.unicodeRange
69667
+ )
69668
+ );
69652
69669
  }
69653
69670
  continue;
69654
69671
  }
@@ -69689,14 +69706,43 @@ function fontCacheDir(slug) {
69689
69706
  }
69690
69707
  return dir;
69691
69708
  }
69692
- function cachedWoff2Path(slug, weight, style) {
69693
- return join33(fontCacheDir(slug), `${weight}-${style}.woff2`);
69709
+ function subsetToken(woff2Url) {
69710
+ return createHash6("sha1").update(woff2Url).digest("hex").slice(0, 12);
69711
+ }
69712
+ function cachedWoff2Path(slug, weight, style, subset) {
69713
+ return join33(fontCacheDir(slug), `${weight}-${style}-${subset}.woff2`);
69694
69714
  }
69695
69715
  function fontFetchError(familyName, url, what, cause) {
69696
69716
  const reason = "status" in cause ? `returned HTTP ${cause.status}` : `failed: ${cause.error.message}`;
69697
69717
  const message = `[deterministicFonts] ${what} fetch for ${JSON.stringify(familyName)} ${reason}. Distributed renders require deterministic fonts; system-font fallback would produce non-byte-identical output.`;
69698
69718
  return new FontFetchError(familyName, url, message, "error" in cause ? cause.error : void 0);
69699
69719
  }
69720
+ async function ensureWoff2DataUri(cachePath2, woff2Url, familyName, weight, style, options) {
69721
+ try {
69722
+ return `data:font/woff2;base64,${readFileSync24(cachePath2).toString("base64")}`;
69723
+ } catch {
69724
+ }
69725
+ const woff2What = `Google Fonts woff2 (${weight}/${style})`;
69726
+ try {
69727
+ const fontRes = await options.fetchImpl(woff2Url);
69728
+ if (!fontRes.ok) {
69729
+ if (fontRes.status >= 500 && options.failClosedFontFetch) {
69730
+ throw fontFetchError(familyName, woff2Url, woff2What, { status: fontRes.status });
69731
+ }
69732
+ return null;
69733
+ }
69734
+ writeFileSync15(cachePath2, Buffer.from(await fontRes.arrayBuffer()), { flag: "wx", mode: 420 });
69735
+ } catch (err) {
69736
+ if (err instanceof FontFetchError) throw err;
69737
+ if (err.code === "EEXIST") {
69738
+ } else if (options.failClosedFontFetch) {
69739
+ throw fontFetchError(familyName, woff2Url, woff2What, { error: err });
69740
+ } else {
69741
+ return null;
69742
+ }
69743
+ }
69744
+ return `data:font/woff2;base64,${readFileSync24(cachePath2).toString("base64")}`;
69745
+ }
69700
69746
  async function fetchGoogleFont(familyName, options) {
69701
69747
  const slug = fontSlug(familyName);
69702
69748
  const encodedFamily = encodeURIComponent(familyName);
@@ -69720,37 +69766,24 @@ async function fetchGoogleFont(familyName, options) {
69720
69766
  }
69721
69767
  return [];
69722
69768
  }
69723
- const faceRegex = /@font-face\s*\{[^}]*font-style:\s*(normal|italic)[^}]*font-weight:\s*(\d+)[^}]*src:\s*url\(([^)]+)\)\s*format\(['"]woff2['"]\)[^}]*\}/gi;
69769
+ const faceRegex = /@font-face\s*\{[^}]*font-style:\s*(normal|italic)[^}]*font-weight:\s*(\d+)[^}]*src:\s*url\(([^)]+)\)\s*format\(['"]woff2['"]\)(?:[^}]*?unicode-range:\s*([^;}]+))?[^}]*\}/gi;
69724
69770
  const faces = [];
69725
69771
  for (const match of cssText.matchAll(faceRegex)) {
69726
69772
  const style = match[1] || "normal";
69727
69773
  const weight = match[2] || "400";
69728
69774
  const woff2Url = match[3] || "";
69775
+ const unicodeRange = match[4]?.trim() || void 0;
69729
69776
  if (!woff2Url) continue;
69730
- const cachePath2 = cachedWoff2Path(slug, weight, style);
69731
- if (!existsSync31(cachePath2)) {
69732
- const woff2What = `Google Fonts woff2 (${weight}/${style})`;
69733
- try {
69734
- const fontRes = await options.fetchImpl(woff2Url);
69735
- if (!fontRes.ok) {
69736
- if (fontRes.status >= 500 && options.failClosedFontFetch) {
69737
- throw fontFetchError(familyName, woff2Url, woff2What, { status: fontRes.status });
69738
- }
69739
- continue;
69740
- }
69741
- const buffer = Buffer.from(await fontRes.arrayBuffer());
69742
- writeFileSync15(cachePath2, buffer);
69743
- } catch (err) {
69744
- if (err instanceof FontFetchError) throw err;
69745
- if (options.failClosedFontFetch) {
69746
- throw fontFetchError(familyName, woff2Url, woff2What, { error: err });
69747
- }
69748
- continue;
69749
- }
69750
- }
69751
- const fontBytes = readFileSync24(cachePath2);
69752
- const dataUri = `data:font/woff2;base64,${fontBytes.toString("base64")}`;
69753
- faces.push({ weight, style, dataUri });
69777
+ const cachePath2 = cachedWoff2Path(slug, weight, style, subsetToken(woff2Url));
69778
+ const dataUri = await ensureWoff2DataUri(
69779
+ cachePath2,
69780
+ woff2Url,
69781
+ familyName,
69782
+ weight,
69783
+ style,
69784
+ options
69785
+ );
69786
+ if (dataUri) faces.push({ weight, style, dataUri, unicodeRange });
69754
69787
  }
69755
69788
  if (faces.length > 0) {
69756
69789
  console.log(
@@ -69947,7 +69980,7 @@ var init_deterministicFonts = __esm({
69947
69980
  });
69948
69981
 
69949
69982
  // ../producer/src/services/hyperframeRuntimeLoader.ts
69950
- import { createHash as createHash6 } from "crypto";
69983
+ import { createHash as createHash7 } from "crypto";
69951
69984
  import { existsSync as existsSync32, readFileSync as readFileSync25 } from "fs";
69952
69985
  import { dirname as dirname11, resolve as resolve16 } from "path";
69953
69986
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -69990,7 +70023,7 @@ function resolveVerifiedHyperframeRuntime() {
69990
70023
  throw new Error(`[HyperframeRuntimeLoader] Missing runtime artifact at ${runtimePath}.`);
69991
70024
  }
69992
70025
  const runtimeSource = readFileSync25(runtimePath, "utf8");
69993
- const runtimeSha = createHash6("sha256").update(runtimeSource, "utf8").digest("hex");
70026
+ const runtimeSha = createHash7("sha256").update(runtimeSource, "utf8").digest("hex");
69994
70027
  if (runtimeSha !== manifest.sha256) {
69995
70028
  throw new Error(
69996
70029
  `[HyperframeRuntimeLoader] Runtime checksum mismatch. expected=${manifest.sha256} actual=${runtimeSha}`
@@ -76508,9 +76541,9 @@ var init_parityContract2 = __esm({
76508
76541
  });
76509
76542
 
76510
76543
  // ../producer/src/services/render/stages/planHash.ts
76511
- import { createHash as createHash7 } from "crypto";
76544
+ import { createHash as createHash8 } from "crypto";
76512
76545
  function computePlanHash(input2) {
76513
- const hash2 = createHash7("sha256");
76546
+ const hash2 = createHash8("sha256");
76514
76547
  hash2.update(PLAN_HASH_SCHEMA_PREFIX, "utf8");
76515
76548
  hash2.update(input2.compositionHtml);
76516
76549
  hash2.update(FIELD_DELIMITER);
@@ -76557,7 +76590,7 @@ function canonicalJsonStringify(value) {
76557
76590
  throw new TypeError(`canonicalJsonStringify: unsupported value type ${typeof value}`);
76558
76591
  }
76559
76592
  function sha256Hex(bytes) {
76560
- const h3 = createHash7("sha256");
76593
+ const h3 = createHash8("sha256");
76561
76594
  h3.update(bytes);
76562
76595
  return h3.digest("hex");
76563
76596
  }
@@ -106800,7 +106833,7 @@ var require_websocket = __commonJS({
106800
106833
  var http4 = __require("http");
106801
106834
  var net2 = __require("net");
106802
106835
  var tls = __require("tls");
106803
- var { randomBytes: randomBytes4, createHash: createHash9 } = __require("crypto");
106836
+ var { randomBytes: randomBytes4, createHash: createHash10 } = __require("crypto");
106804
106837
  var { Duplex, Readable: Readable3 } = __require("stream");
106805
106838
  var { URL: URL2 } = __require("url");
106806
106839
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -107460,7 +107493,7 @@ var require_websocket = __commonJS({
107460
107493
  abortHandshake(websocket, socket, "Invalid Upgrade header");
107461
107494
  return;
107462
107495
  }
107463
- const digest = createHash9("sha1").update(key2 + GUID).digest("base64");
107496
+ const digest = createHash10("sha1").update(key2 + GUID).digest("base64");
107464
107497
  if (res.headers["sec-websocket-accept"] !== digest) {
107465
107498
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
107466
107499
  return;
@@ -107827,7 +107860,7 @@ var require_websocket_server = __commonJS({
107827
107860
  var EventEmitter = __require("events");
107828
107861
  var http4 = __require("http");
107829
107862
  var { Duplex } = __require("stream");
107830
- var { createHash: createHash9 } = __require("crypto");
107863
+ var { createHash: createHash10 } = __require("crypto");
107831
107864
  var extension2 = require_extension();
107832
107865
  var PerMessageDeflate2 = require_permessage_deflate();
107833
107866
  var subprotocol2 = require_subprotocol();
@@ -108128,7 +108161,7 @@ var require_websocket_server = __commonJS({
108128
108161
  );
108129
108162
  }
108130
108163
  if (this._state > RUNNING) return abortHandshake(socket, 503);
108131
- const digest = createHash9("sha1").update(key2 + GUID).digest("base64");
108164
+ const digest = createHash10("sha1").update(key2 + GUID).digest("base64");
108132
108165
  const headers = [
108133
108166
  "HTTP/1.1 101 Switching Protocols",
108134
108167
  "Upgrade: websocket",
@@ -132285,10 +132318,10 @@ var init_client3 = __esm({
132285
132318
  });
132286
132319
 
132287
132320
  // src/auth/pkce.ts
132288
- import { createHash as createHash8, randomBytes as randomBytes3 } from "crypto";
132321
+ import { createHash as createHash9, randomBytes as randomBytes3 } from "crypto";
132289
132322
  function generatePkcePair() {
132290
132323
  const verifier = base64UrlEncode(randomBytes3(VERIFIER_BYTES));
132291
- const challenge = base64UrlEncode(createHash8("sha256").update(verifier).digest());
132324
+ const challenge = base64UrlEncode(createHash9("sha256").update(verifier).digest());
132292
132325
  return { verifier, challenge, method: "S256" };
132293
132326
  }
132294
132327
  function generateState() {
@@ -133087,7 +133120,6 @@ var init_errors2 = __esm({
133087
133120
  init_format();
133088
133121
  init_client2();
133089
133122
  ERROR_CODE_HINTS = {
133090
- hyperframes_project_invalid: "The uploaded zip didn't validate. Confirm it contains index.html at the root (or matches --composition), and that all referenced assets are present.",
133091
133123
  hyperframes_project_too_large: "The zip exceeded the 32 MB limit. Trim large media (or pre-host them and reference by URL), then try again.",
133092
133124
  hyperframes_render_not_found: "The render_id no longer exists \u2014 either soft-deleted or never created.",
133093
133125
  invalid_parameter: "Check the listed parameter against `hyperframes cloud render --help` for the accepted values.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hyperframes",
3
- "version": "0.6.58",
3
+ "version": "0.6.59",
4
4
  "description": "HyperFrames CLI — create, preview, and render HTML video compositions",
5
5
  "repository": {
6
6
  "type": "git",