@hyperframes/producer 0.1.15 → 0.2.0

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.
@@ -2149,11 +2149,11 @@ function __extends(d, b) {
2149
2149
  }
2150
2150
  function __awaiter(thisArg, _arguments, P, generator) {
2151
2151
  function adopt(value) {
2152
- return value instanceof P ? value : new P(function(resolve12) {
2153
- resolve12(value);
2152
+ return value instanceof P ? value : new P(function(resolve13) {
2153
+ resolve13(value);
2154
2154
  });
2155
2155
  }
2156
- return new (P || (P = Promise))(function(resolve12, reject) {
2156
+ return new (P || (P = Promise))(function(resolve13, reject) {
2157
2157
  function fulfilled(value) {
2158
2158
  try {
2159
2159
  step(generator.next(value));
@@ -2169,7 +2169,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
2169
2169
  }
2170
2170
  }
2171
2171
  function step(result) {
2172
- result.done ? resolve12(result.value) : adopt(result.value).then(fulfilled, rejected);
2172
+ result.done ? resolve13(result.value) : adopt(result.value).then(fulfilled, rejected);
2173
2173
  }
2174
2174
  step((generator = generator.apply(thisArg, _arguments || [])).next());
2175
2175
  });
@@ -2332,14 +2332,14 @@ function __asyncValues(o) {
2332
2332
  }, i);
2333
2333
  function verb(n) {
2334
2334
  i[n] = o[n] && function(v) {
2335
- return new Promise(function(resolve12, reject) {
2336
- v = o[n](v), settle(resolve12, reject, v.done, v.value);
2335
+ return new Promise(function(resolve13, reject) {
2336
+ v = o[n](v), settle(resolve13, reject, v.done, v.value);
2337
2337
  });
2338
2338
  };
2339
2339
  }
2340
- function settle(resolve12, reject, d, v) {
2340
+ function settle(resolve13, reject, d, v) {
2341
2341
  Promise.resolve(v).then(function(v2) {
2342
- resolve12({ value: v2, done: d });
2342
+ resolve13({ value: v2, done: d });
2343
2343
  }, reject);
2344
2344
  }
2345
2345
  }
@@ -2864,7 +2864,7 @@ function of() {
2864
2864
  }
2865
2865
  function lastValueFrom(source2, config2) {
2866
2866
  var hasConfig = typeof config2 === "object";
2867
- return new Promise(function(resolve12, reject) {
2867
+ return new Promise(function(resolve13, reject) {
2868
2868
  var _hasValue = false;
2869
2869
  var _value;
2870
2870
  source2.subscribe({
@@ -2875,9 +2875,9 @@ function lastValueFrom(source2, config2) {
2875
2875
  error: reject,
2876
2876
  complete: function() {
2877
2877
  if (_hasValue) {
2878
- resolve12(_value);
2878
+ resolve13(_value);
2879
2879
  } else if (hasConfig) {
2880
- resolve12(config2.defaultValue);
2880
+ resolve13(config2.defaultValue);
2881
2881
  } else {
2882
2882
  reject(new EmptyError());
2883
2883
  }
@@ -2887,16 +2887,16 @@ function lastValueFrom(source2, config2) {
2887
2887
  }
2888
2888
  function firstValueFrom(source2, config2) {
2889
2889
  var hasConfig = typeof config2 === "object";
2890
- return new Promise(function(resolve12, reject) {
2890
+ return new Promise(function(resolve13, reject) {
2891
2891
  var subscriber = new SafeSubscriber({
2892
2892
  next: function(value) {
2893
- resolve12(value);
2893
+ resolve13(value);
2894
2894
  subscriber.unsubscribe();
2895
2895
  },
2896
2896
  error: reject,
2897
2897
  complete: function() {
2898
2898
  if (hasConfig) {
2899
- resolve12(config2.defaultValue);
2899
+ resolve13(config2.defaultValue);
2900
2900
  } else {
2901
2901
  reject(new EmptyError());
2902
2902
  }
@@ -3935,7 +3935,7 @@ var init_rxjs = __esm({
3935
3935
  Observable2.prototype.forEach = function(next, promiseCtor) {
3936
3936
  var _this = this;
3937
3937
  promiseCtor = getPromiseCtor(promiseCtor);
3938
- return new promiseCtor(function(resolve12, reject) {
3938
+ return new promiseCtor(function(resolve13, reject) {
3939
3939
  var subscriber = new SafeSubscriber({
3940
3940
  next: function(value) {
3941
3941
  try {
@@ -3946,7 +3946,7 @@ var init_rxjs = __esm({
3946
3946
  }
3947
3947
  },
3948
3948
  error: reject,
3949
- complete: resolve12
3949
+ complete: resolve13
3950
3950
  });
3951
3951
  _this.subscribe(subscriber);
3952
3952
  });
@@ -3968,14 +3968,14 @@ var init_rxjs = __esm({
3968
3968
  Observable2.prototype.toPromise = function(promiseCtor) {
3969
3969
  var _this = this;
3970
3970
  promiseCtor = getPromiseCtor(promiseCtor);
3971
- return new promiseCtor(function(resolve12, reject) {
3971
+ return new promiseCtor(function(resolve13, reject) {
3972
3972
  var value;
3973
3973
  _this.subscribe(function(x) {
3974
3974
  return value = x;
3975
3975
  }, function(err) {
3976
3976
  return reject(err);
3977
3977
  }, function() {
3978
- return resolve12(value);
3978
+ return resolve13(value);
3979
3979
  });
3980
3980
  });
3981
3981
  };
@@ -6405,8 +6405,8 @@ var init_Deferred = __esm({
6405
6405
  // SAFETY: This is ensured by #taskPromise.
6406
6406
  #resolve;
6407
6407
  // TODO: Switch to Promise.withResolvers with Node 22
6408
- #taskPromise = new Promise((resolve12) => {
6409
- this.#resolve = resolve12;
6408
+ #taskPromise = new Promise((resolve13) => {
6409
+ this.#resolve = resolve13;
6410
6410
  });
6411
6411
  #timeoutId;
6412
6412
  #timeoutError;
@@ -6496,12 +6496,12 @@ var init_Mutex = __esm({
6496
6496
  return new _Mutex.Guard(this, onRelease);
6497
6497
  }
6498
6498
  release() {
6499
- const resolve12 = this.#acquirers.shift();
6500
- if (!resolve12) {
6499
+ const resolve13 = this.#acquirers.shift();
6500
+ if (!resolve13) {
6501
6501
  this.#locked = false;
6502
6502
  return;
6503
6503
  }
6504
- resolve12();
6504
+ resolve13();
6505
6505
  }
6506
6506
  };
6507
6507
  }
@@ -8516,12 +8516,12 @@ var init_locators = __esm({
8516
8516
  }
8517
8517
  return defer(() => {
8518
8518
  return from(handle.evaluate((element) => {
8519
- return new Promise((resolve12) => {
8519
+ return new Promise((resolve13) => {
8520
8520
  window.requestAnimationFrame(() => {
8521
8521
  const rect1 = element.getBoundingClientRect();
8522
8522
  window.requestAnimationFrame(() => {
8523
8523
  const rect2 = element.getBoundingClientRect();
8524
- resolve12([
8524
+ resolve13([
8525
8525
  {
8526
8526
  x: rect1.x,
8527
8527
  y: rect1.y,
@@ -10260,9 +10260,9 @@ var init_ElementHandle = __esm({
10260
10260
  const handle = await this.#asSVGElementHandle();
10261
10261
  const target = __addDisposableResource6(env_5, handle && await handle.#getOwnerSVGElement(), false);
10262
10262
  return await (target ?? this).evaluate(async (element, threshold) => {
10263
- const visibleRatio = await new Promise((resolve12) => {
10263
+ const visibleRatio = await new Promise((resolve13) => {
10264
10264
  const observer = new IntersectionObserver((entries2) => {
10265
- resolve12(entries2[0].intersectionRatio);
10265
+ resolve13(entries2[0].intersectionRatio);
10266
10266
  observer.disconnect();
10267
10267
  });
10268
10268
  observer.observe(element);
@@ -10908,7 +10908,7 @@ var init_Frame = __esm({
10908
10908
  }
10909
10909
  type = type ?? "text/javascript";
10910
10910
  return await this.mainRealm().transferHandle(await this.isolatedRealm().evaluateHandle(async ({ url, id, type: type2, content: content2 }) => {
10911
- return await new Promise((resolve12, reject) => {
10911
+ return await new Promise((resolve13, reject) => {
10912
10912
  const script = document.createElement("script");
10913
10913
  script.type = type2;
10914
10914
  script.text = content2;
@@ -10921,12 +10921,12 @@ var init_Frame = __esm({
10921
10921
  if (url) {
10922
10922
  script.src = url;
10923
10923
  script.addEventListener("load", () => {
10924
- resolve12(script);
10924
+ resolve13(script);
10925
10925
  }, { once: true });
10926
10926
  document.head.appendChild(script);
10927
10927
  } else {
10928
10928
  document.head.appendChild(script);
10929
- resolve12(script);
10929
+ resolve13(script);
10930
10930
  }
10931
10931
  });
10932
10932
  }, { ...options, type, content }));
@@ -10946,7 +10946,7 @@ var init_Frame = __esm({
10946
10946
  options.content = content;
10947
10947
  }
10948
10948
  return await this.mainRealm().transferHandle(await this.isolatedRealm().evaluateHandle(async ({ url, content: content2 }) => {
10949
- return await new Promise((resolve12, reject) => {
10949
+ return await new Promise((resolve13, reject) => {
10950
10950
  let element;
10951
10951
  if (!url) {
10952
10952
  element = document.createElement("style");
@@ -10958,7 +10958,7 @@ var init_Frame = __esm({
10958
10958
  element = link;
10959
10959
  }
10960
10960
  element.addEventListener("load", () => {
10961
- resolve12(element);
10961
+ resolve13(element);
10962
10962
  }, { once: true });
10963
10963
  element.addEventListener("error", (event) => {
10964
10964
  reject(new Error(event.message ?? "Could not load style"));
@@ -12697,9 +12697,9 @@ var init_Page = __esm({
12697
12697
  ++this.#screencastSessionCount;
12698
12698
  if (!this.#startScreencastPromise) {
12699
12699
  this.#startScreencastPromise = this.mainFrame().client.send("Page.startScreencast", { format: "png" }).then(() => {
12700
- return new Promise((resolve12) => {
12700
+ return new Promise((resolve13) => {
12701
12701
  return this.mainFrame().client.once("Page.screencastFrame", () => {
12702
- return resolve12();
12702
+ return resolve13();
12703
12703
  });
12704
12704
  });
12705
12705
  });
@@ -16017,11 +16017,11 @@ function addPageBinding(type, name, prefix) {
16017
16017
  return value instanceof Node;
16018
16018
  })
16019
16019
  }));
16020
- return new Promise((resolve12, reject) => {
16020
+ return new Promise((resolve13, reject) => {
16021
16021
  callPuppeteer.callbacks.set(seq, {
16022
16022
  resolve(value) {
16023
16023
  callPuppeteer.args.delete(seq);
16024
- resolve12(value);
16024
+ resolve13(value);
16025
16025
  },
16026
16026
  reject(value) {
16027
16027
  callPuppeteer.args.delete(seq);
@@ -19684,8 +19684,8 @@ var init_Input2 = __esm({
19684
19684
  if (typeof delay === "number") {
19685
19685
  await Promise.all(actions);
19686
19686
  actions.length = 0;
19687
- await new Promise((resolve12) => {
19688
- setTimeout(resolve12, delay);
19687
+ await new Promise((resolve13) => {
19688
+ setTimeout(resolve13, delay);
19689
19689
  });
19690
19690
  }
19691
19691
  actions.push(this.up({ ...options, clickCount }));
@@ -19705,9 +19705,9 @@ var init_Input2 = __esm({
19705
19705
  });
19706
19706
  }
19707
19707
  async drag(start, target) {
19708
- const promise = new Promise((resolve12) => {
19708
+ const promise = new Promise((resolve13) => {
19709
19709
  this.#client.once("Input.dragIntercepted", (event) => {
19710
- return resolve12(event.data);
19710
+ return resolve13(event.data);
19711
19711
  });
19712
19712
  });
19713
19713
  await this.move(start.x, start.y);
@@ -19748,8 +19748,8 @@ var init_Input2 = __esm({
19748
19748
  await this.dragEnter(target, data);
19749
19749
  await this.dragOver(target, data);
19750
19750
  if (delay) {
19751
- await new Promise((resolve12) => {
19752
- return setTimeout(resolve12, delay);
19751
+ await new Promise((resolve13) => {
19752
+ return setTimeout(resolve13, delay);
19753
19753
  });
19754
19754
  }
19755
19755
  await this.drop(target, data);
@@ -20633,9 +20633,9 @@ var init_Page2 = __esm({
20633
20633
  async captureHeapSnapshot(options) {
20634
20634
  const { createWriteStream: createWriteStream3 } = environment.value.fs;
20635
20635
  const stream2 = createWriteStream3(options.path);
20636
- const streamPromise = new Promise((resolve12, reject) => {
20636
+ const streamPromise = new Promise((resolve13, reject) => {
20637
20637
  stream2.on("error", reject);
20638
- stream2.on("finish", resolve12);
20638
+ stream2.on("finish", resolve13);
20639
20639
  });
20640
20640
  const client = this.#primaryTargetClient;
20641
20641
  await client.send("HeapProfiler.enable");
@@ -22277,10 +22277,10 @@ var init_BrowserWebSocketTransport = __esm({
22277
22277
  "../../node_modules/.bun/puppeteer-core@24.40.0/node_modules/puppeteer-core/lib/esm/puppeteer/common/BrowserWebSocketTransport.js"() {
22278
22278
  BrowserWebSocketTransport = class _BrowserWebSocketTransport {
22279
22279
  static create(url) {
22280
- return new Promise((resolve12, reject) => {
22280
+ return new Promise((resolve13, reject) => {
22281
22281
  const ws = new WebSocket(url);
22282
22282
  ws.addEventListener("open", () => {
22283
- return resolve12(new _BrowserWebSocketTransport(ws));
22283
+ return resolve13(new _BrowserWebSocketTransport(ws));
22284
22284
  });
22285
22285
  ws.addEventListener("error", reject);
22286
22286
  });
@@ -25202,11 +25202,11 @@ var require_BrowsingContextProcessor = __commonJS({
25202
25202
  }
25203
25203
  const parentCdpClient = context2.cdpTarget.parentCdpClient;
25204
25204
  try {
25205
- const detachedFromTargetPromise = new Promise((resolve12) => {
25205
+ const detachedFromTargetPromise = new Promise((resolve13) => {
25206
25206
  const onContextDestroyed = (event) => {
25207
25207
  if (event.targetId === params.context) {
25208
25208
  parentCdpClient.off("Target.detachedFromTarget", onContextDestroyed);
25209
- resolve12();
25209
+ resolve13();
25210
25210
  }
25211
25211
  };
25212
25212
  parentCdpClient.on("Target.detachedFromTarget", onContextDestroyed);
@@ -26569,7 +26569,7 @@ var require_ActionDispatcher = __commonJS({
26569
26569
  }
26570
26570
  }
26571
26571
  const promises = [
26572
- new Promise((resolve12) => setTimeout(resolve12, this.#tickDuration))
26572
+ new Promise((resolve13) => setTimeout(resolve13, this.#tickDuration))
26573
26573
  ];
26574
26574
  for (const option of options) {
26575
26575
  promises.push(this.#dispatchAction(option));
@@ -27170,8 +27170,8 @@ var require_Mutex = __commonJS({
27170
27170
  acquire() {
27171
27171
  const state = { resolved: false };
27172
27172
  if (this.#locked) {
27173
- return new Promise((resolve12) => {
27174
- this.#acquirers.push(() => resolve12(this.#release.bind(this, state)));
27173
+ return new Promise((resolve13) => {
27174
+ this.#acquirers.push(() => resolve13(this.#release.bind(this, state)));
27175
27175
  });
27176
27176
  }
27177
27177
  this.#locked = true;
@@ -27182,12 +27182,12 @@ var require_Mutex = __commonJS({
27182
27182
  throw new Error("Cannot release more than once.");
27183
27183
  }
27184
27184
  state.resolved = true;
27185
- const resolve12 = this.#acquirers.shift();
27186
- if (!resolve12) {
27185
+ const resolve13 = this.#acquirers.shift();
27186
+ if (!resolve13) {
27187
27187
  this.#locked = false;
27188
27188
  return;
27189
27189
  }
27190
- resolve12();
27190
+ resolve13();
27191
27191
  }
27192
27192
  async run(action) {
27193
27193
  const release = await this.acquire();
@@ -28369,8 +28369,8 @@ var require_ChannelProxy = __commonJS({
28369
28369
  * in the queue.
28370
28370
  */
28371
28371
  async getMessage() {
28372
- const onMessage = queue.length > 0 ? Promise.resolve() : new Promise((resolve12) => {
28373
- queueNonEmptyResolver = resolve12;
28372
+ const onMessage = queue.length > 0 ? Promise.resolve() : new Promise((resolve13) => {
28373
+ queueNonEmptyResolver = resolve13;
28374
28374
  });
28375
28375
  await onMessage;
28376
28376
  return queue.shift();
@@ -28475,7 +28475,7 @@ var require_ChannelProxy = __commonJS({
28475
28475
  functionDeclaration: String((id) => {
28476
28476
  const w = window;
28477
28477
  if (w[id] === void 0) {
28478
- return new Promise((resolve12) => w[id] = resolve12);
28478
+ return new Promise((resolve13) => w[id] = resolve13);
28479
28479
  }
28480
28480
  const channelProxy = w[id];
28481
28481
  delete w[id];
@@ -29976,8 +29976,8 @@ var require_Deferred = __commonJS({
29976
29976
  return this.#result;
29977
29977
  }
29978
29978
  constructor() {
29979
- this.#promise = new Promise((resolve12, reject) => {
29980
- this.#resolve = resolve12;
29979
+ this.#promise = new Promise((resolve13, reject) => {
29980
+ this.#resolve = resolve13;
29981
29981
  this.#reject = reject;
29982
29982
  });
29983
29983
  this.#promise.catch((_error) => {
@@ -34821,11 +34821,11 @@ var require_BrowsingContextStorage = __commonJS({
34821
34821
  if (this.#contexts.has(browsingContextId)) {
34822
34822
  return Promise.resolve(this.getContext(browsingContextId));
34823
34823
  }
34824
- return new Promise((resolve12) => {
34824
+ return new Promise((resolve13) => {
34825
34825
  const listener = (event) => {
34826
34826
  if (event.browsingContext.id === browsingContextId) {
34827
34827
  this.#eventEmitter.off("added", listener);
34828
- resolve12(event.browsingContext);
34828
+ resolve13(event.browsingContext);
34829
34829
  }
34830
34830
  };
34831
34831
  this.#eventEmitter.on("added", listener);
@@ -38407,8 +38407,8 @@ var init_ExposedFunction = __esm({
38407
38407
  const functionDeclaration = stringifyFunction(interpolateFunction((callback) => {
38408
38408
  Object.assign(globalThis, {
38409
38409
  [PLACEHOLDER("name")]: function(...args) {
38410
- return new Promise((resolve12, reject) => {
38411
- callback([resolve12, reject, args]);
38410
+ return new Promise((resolve13, reject) => {
38411
+ callback([resolve13, reject, args]);
38412
38412
  });
38413
38413
  }
38414
38414
  });
@@ -38496,8 +38496,8 @@ var init_ExposedFunction = __esm({
38496
38496
  return;
38497
38497
  }
38498
38498
  try {
38499
- await dataHandle.evaluate(([resolve12], result2) => {
38500
- resolve12(result2);
38499
+ await dataHandle.evaluate(([resolve13], result2) => {
38500
+ resolve13(result2);
38501
38501
  }, result);
38502
38502
  } catch (error) {
38503
38503
  debugError(error);
@@ -46578,7 +46578,7 @@ var init_NodeWebSocketTransport = __esm({
46578
46578
  init_version();
46579
46579
  NodeWebSocketTransport = class _NodeWebSocketTransport {
46580
46580
  static create(url, headers) {
46581
- return new Promise((resolve12, reject) => {
46581
+ return new Promise((resolve13, reject) => {
46582
46582
  const ws = new wrapper_default(url, [], {
46583
46583
  followRedirects: true,
46584
46584
  perMessageDeflate: false,
@@ -46591,7 +46591,7 @@ var init_NodeWebSocketTransport = __esm({
46591
46591
  }
46592
46592
  });
46593
46593
  ws.addEventListener("open", () => {
46594
- return resolve12(new _NodeWebSocketTransport(ws));
46594
+ return resolve13(new _NodeWebSocketTransport(ws));
46595
46595
  });
46596
46596
  ws.addEventListener("error", reject);
46597
46597
  });
@@ -49652,8 +49652,8 @@ var require_helpers = __commonJS({
49652
49652
  function req(url, opts = {}) {
49653
49653
  const href = typeof url === "string" ? url : url.href;
49654
49654
  const req2 = (href.startsWith("https:") ? https2 : http2).request(url, opts);
49655
- const promise = new Promise((resolve12, reject) => {
49656
- req2.once("response", resolve12).once("error", reject).end();
49655
+ const promise = new Promise((resolve13, reject) => {
49656
+ req2.once("response", resolve13).once("error", reject).end();
49657
49657
  });
49658
49658
  req2.then = promise.then.bind(promise);
49659
49659
  return req2;
@@ -50030,7 +50030,7 @@ var require_parse_proxy_response = __commonJS({
50030
50030
  var debug_1 = __importDefault2(require_src());
50031
50031
  var debug6 = (0, debug_1.default)("https-proxy-agent:parse-proxy-response");
50032
50032
  function parseProxyResponse(socket) {
50033
- return new Promise((resolve12, reject) => {
50033
+ return new Promise((resolve13, reject) => {
50034
50034
  let buffersLength = 0;
50035
50035
  const buffers = [];
50036
50036
  function read() {
@@ -50096,7 +50096,7 @@ var require_parse_proxy_response = __commonJS({
50096
50096
  }
50097
50097
  debug6("got proxy server response: %o %o", firstLine, headers);
50098
50098
  cleanup();
50099
- resolve12({
50099
+ resolve13({
50100
50100
  connect: {
50101
50101
  statusCode,
50102
50102
  statusText,
@@ -53354,11 +53354,11 @@ var require_socksclient = __commonJS({
53354
53354
  "use strict";
53355
53355
  var __awaiter3 = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
53356
53356
  function adopt(value) {
53357
- return value instanceof P ? value : new P(function(resolve12) {
53358
- resolve12(value);
53357
+ return value instanceof P ? value : new P(function(resolve13) {
53358
+ resolve13(value);
53359
53359
  });
53360
53360
  }
53361
- return new (P || (P = Promise))(function(resolve12, reject) {
53361
+ return new (P || (P = Promise))(function(resolve13, reject) {
53362
53362
  function fulfilled(value) {
53363
53363
  try {
53364
53364
  step(generator.next(value));
@@ -53374,7 +53374,7 @@ var require_socksclient = __commonJS({
53374
53374
  }
53375
53375
  }
53376
53376
  function step(result) {
53377
- result.done ? resolve12(result.value) : adopt(result.value).then(fulfilled, rejected);
53377
+ result.done ? resolve13(result.value) : adopt(result.value).then(fulfilled, rejected);
53378
53378
  }
53379
53379
  step((generator = generator.apply(thisArg, _arguments || [])).next());
53380
53380
  });
@@ -53408,13 +53408,13 @@ var require_socksclient = __commonJS({
53408
53408
  * @returns { Promise }
53409
53409
  */
53410
53410
  static createConnection(options, callback) {
53411
- return new Promise((resolve12, reject) => {
53411
+ return new Promise((resolve13, reject) => {
53412
53412
  try {
53413
53413
  (0, helpers_1.validateSocksClientOptions)(options, ["connect"]);
53414
53414
  } catch (err) {
53415
53415
  if (typeof callback === "function") {
53416
53416
  callback(err);
53417
- return resolve12(err);
53417
+ return resolve13(err);
53418
53418
  } else {
53419
53419
  return reject(err);
53420
53420
  }
@@ -53425,16 +53425,16 @@ var require_socksclient = __commonJS({
53425
53425
  client.removeAllListeners();
53426
53426
  if (typeof callback === "function") {
53427
53427
  callback(null, info);
53428
- resolve12(info);
53428
+ resolve13(info);
53429
53429
  } else {
53430
- resolve12(info);
53430
+ resolve13(info);
53431
53431
  }
53432
53432
  });
53433
53433
  client.once("error", (err) => {
53434
53434
  client.removeAllListeners();
53435
53435
  if (typeof callback === "function") {
53436
53436
  callback(err);
53437
- resolve12(err);
53437
+ resolve13(err);
53438
53438
  } else {
53439
53439
  reject(err);
53440
53440
  }
@@ -53451,13 +53451,13 @@ var require_socksclient = __commonJS({
53451
53451
  * @returns { Promise }
53452
53452
  */
53453
53453
  static createConnectionChain(options, callback) {
53454
- return new Promise((resolve12, reject) => __awaiter3(this, void 0, void 0, function* () {
53454
+ return new Promise((resolve13, reject) => __awaiter3(this, void 0, void 0, function* () {
53455
53455
  try {
53456
53456
  (0, helpers_1.validateSocksClientChainOptions)(options);
53457
53457
  } catch (err) {
53458
53458
  if (typeof callback === "function") {
53459
53459
  callback(err);
53460
- return resolve12(err);
53460
+ return resolve13(err);
53461
53461
  } else {
53462
53462
  return reject(err);
53463
53463
  }
@@ -53483,14 +53483,14 @@ var require_socksclient = __commonJS({
53483
53483
  }
53484
53484
  if (typeof callback === "function") {
53485
53485
  callback(null, { socket: sock });
53486
- resolve12({ socket: sock });
53486
+ resolve13({ socket: sock });
53487
53487
  } else {
53488
- resolve12({ socket: sock });
53488
+ resolve13({ socket: sock });
53489
53489
  }
53490
53490
  } catch (err) {
53491
53491
  if (typeof callback === "function") {
53492
53492
  callback(err);
53493
- resolve12(err);
53493
+ resolve13(err);
53494
53494
  } else {
53495
53495
  reject(err);
53496
53496
  }
@@ -54174,12 +54174,12 @@ var require_dist4 = __commonJS({
54174
54174
  let { host } = opts;
54175
54175
  const { port, lookup: lookupFn = dns.lookup } = opts;
54176
54176
  if (shouldLookup) {
54177
- host = await new Promise((resolve12, reject) => {
54177
+ host = await new Promise((resolve13, reject) => {
54178
54178
  lookupFn(host, {}, (err, res) => {
54179
54179
  if (err) {
54180
54180
  reject(err);
54181
54181
  } else {
54182
- resolve12(res);
54182
+ resolve13(res);
54183
54183
  }
54184
54184
  });
54185
54185
  });
@@ -55364,7 +55364,7 @@ var require_netUtils = __commonJS({
55364
55364
  return `${socket.remoteAddress}:${socket.remotePort}`;
55365
55365
  }
55366
55366
  function upgradeSocket(socket, options) {
55367
- return new Promise((resolve12, reject) => {
55367
+ return new Promise((resolve13, reject) => {
55368
55368
  const tlsOptions = Object.assign({}, options, {
55369
55369
  socket
55370
55370
  });
@@ -55374,7 +55374,7 @@ var require_netUtils = __commonJS({
55374
55374
  reject(tlsSocket.authorizationError);
55375
55375
  } else {
55376
55376
  tlsSocket.removeAllListeners("error");
55377
- resolve12(tlsSocket);
55377
+ resolve13(tlsSocket);
55378
55378
  }
55379
55379
  }).once("error", (error) => {
55380
55380
  reject(error);
@@ -55469,7 +55469,7 @@ var require_transfer = __commonJS({
55469
55469
  };
55470
55470
  }
55471
55471
  function connectForPassiveTransfer(host, port, ftp) {
55472
- return new Promise((resolve12, reject) => {
55472
+ return new Promise((resolve13, reject) => {
55473
55473
  let socket = ftp._newSocket();
55474
55474
  const handleConnErr = function(err) {
55475
55475
  err.message = "Can't open data connection in passive mode: " + err.message;
@@ -55497,7 +55497,7 @@ var require_transfer = __commonJS({
55497
55497
  socket.removeListener("error", handleConnErr);
55498
55498
  socket.removeListener("timeout", handleTimeout);
55499
55499
  ftp.dataSocket = socket;
55500
- resolve12();
55500
+ resolve13();
55501
55501
  });
55502
55502
  });
55503
55503
  }
@@ -57895,7 +57895,7 @@ var require_util2 = __commonJS({
57895
57895
  return path12;
57896
57896
  }
57897
57897
  exports.normalize = normalize2;
57898
- function join16(aRoot, aPath) {
57898
+ function join17(aRoot, aPath) {
57899
57899
  if (aRoot === "") {
57900
57900
  aRoot = ".";
57901
57901
  }
@@ -57927,7 +57927,7 @@ var require_util2 = __commonJS({
57927
57927
  }
57928
57928
  return joined;
57929
57929
  }
57930
- exports.join = join16;
57930
+ exports.join = join17;
57931
57931
  exports.isAbsolute = function(aPath) {
57932
57932
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
57933
57933
  };
@@ -58100,7 +58100,7 @@ var require_util2 = __commonJS({
58100
58100
  parsed.path = parsed.path.substring(0, index + 1);
58101
58101
  }
58102
58102
  }
58103
- sourceURL = join16(urlGenerate(parsed), sourceURL);
58103
+ sourceURL = join17(urlGenerate(parsed), sourceURL);
58104
58104
  }
58105
58105
  return normalize2(sourceURL);
58106
58106
  }
@@ -59902,7 +59902,7 @@ var require_escodegen = __commonJS({
59902
59902
  function noEmptySpace() {
59903
59903
  return space ? space : " ";
59904
59904
  }
59905
- function join16(left2, right2) {
59905
+ function join17(left2, right2) {
59906
59906
  var leftSource, rightSource, leftCharCode, rightCharCode;
59907
59907
  leftSource = toSourceNodeWhenNeeded(left2).toString();
59908
59908
  if (leftSource.length === 0) {
@@ -60233,8 +60233,8 @@ var require_escodegen = __commonJS({
60233
60233
  } else {
60234
60234
  result.push(that.generateExpression(stmt.left, Precedence.Call, E_TTT));
60235
60235
  }
60236
- result = join16(result, operator);
60237
- result = [join16(
60236
+ result = join17(result, operator);
60237
+ result = [join17(
60238
60238
  result,
60239
60239
  that.generateExpression(stmt.right, Precedence.Assignment, E_TTT)
60240
60240
  ), ")"];
@@ -60377,11 +60377,11 @@ var require_escodegen = __commonJS({
60377
60377
  var result, fragment;
60378
60378
  result = ["class"];
60379
60379
  if (stmt.id) {
60380
- result = join16(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
60380
+ result = join17(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
60381
60381
  }
60382
60382
  if (stmt.superClass) {
60383
- fragment = join16("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
60384
- result = join16(result, fragment);
60383
+ fragment = join17("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
60384
+ result = join17(result, fragment);
60385
60385
  }
60386
60386
  result.push(space);
60387
60387
  result.push(this.generateStatement(stmt.body, S_TFFT));
@@ -60394,9 +60394,9 @@ var require_escodegen = __commonJS({
60394
60394
  return escapeDirective(stmt.directive) + this.semicolon(flags);
60395
60395
  },
60396
60396
  DoWhileStatement: function(stmt, flags) {
60397
- var result = join16("do", this.maybeBlock(stmt.body, S_TFFF));
60397
+ var result = join17("do", this.maybeBlock(stmt.body, S_TFFF));
60398
60398
  result = this.maybeBlockSuffix(stmt.body, result);
60399
- return join16(result, [
60399
+ return join17(result, [
60400
60400
  "while" + space + "(",
60401
60401
  this.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
60402
60402
  ")" + this.semicolon(flags)
@@ -60432,11 +60432,11 @@ var require_escodegen = __commonJS({
60432
60432
  ExportDefaultDeclaration: function(stmt, flags) {
60433
60433
  var result = ["export"], bodyFlags;
60434
60434
  bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
60435
- result = join16(result, "default");
60435
+ result = join17(result, "default");
60436
60436
  if (isStatement(stmt.declaration)) {
60437
- result = join16(result, this.generateStatement(stmt.declaration, bodyFlags));
60437
+ result = join17(result, this.generateStatement(stmt.declaration, bodyFlags));
60438
60438
  } else {
60439
- result = join16(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
60439
+ result = join17(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
60440
60440
  }
60441
60441
  return result;
60442
60442
  },
@@ -60444,15 +60444,15 @@ var require_escodegen = __commonJS({
60444
60444
  var result = ["export"], bodyFlags, that = this;
60445
60445
  bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
60446
60446
  if (stmt.declaration) {
60447
- return join16(result, this.generateStatement(stmt.declaration, bodyFlags));
60447
+ return join17(result, this.generateStatement(stmt.declaration, bodyFlags));
60448
60448
  }
60449
60449
  if (stmt.specifiers) {
60450
60450
  if (stmt.specifiers.length === 0) {
60451
- result = join16(result, "{" + space + "}");
60451
+ result = join17(result, "{" + space + "}");
60452
60452
  } else if (stmt.specifiers[0].type === Syntax.ExportBatchSpecifier) {
60453
- result = join16(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
60453
+ result = join17(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
60454
60454
  } else {
60455
- result = join16(result, "{");
60455
+ result = join17(result, "{");
60456
60456
  withIndent(function(indent2) {
60457
60457
  var i, iz;
60458
60458
  result.push(newline);
@@ -60470,7 +60470,7 @@ var require_escodegen = __commonJS({
60470
60470
  result.push(base + "}");
60471
60471
  }
60472
60472
  if (stmt.source) {
60473
- result = join16(result, [
60473
+ result = join17(result, [
60474
60474
  "from" + space,
60475
60475
  // ModuleSpecifier
60476
60476
  this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
@@ -60558,7 +60558,7 @@ var require_escodegen = __commonJS({
60558
60558
  ];
60559
60559
  cursor = 0;
60560
60560
  if (stmt.specifiers[cursor].type === Syntax.ImportDefaultSpecifier) {
60561
- result = join16(result, [
60561
+ result = join17(result, [
60562
60562
  this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
60563
60563
  ]);
60564
60564
  ++cursor;
@@ -60568,7 +60568,7 @@ var require_escodegen = __commonJS({
60568
60568
  result.push(",");
60569
60569
  }
60570
60570
  if (stmt.specifiers[cursor].type === Syntax.ImportNamespaceSpecifier) {
60571
- result = join16(result, [
60571
+ result = join17(result, [
60572
60572
  space,
60573
60573
  this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
60574
60574
  ]);
@@ -60597,7 +60597,7 @@ var require_escodegen = __commonJS({
60597
60597
  }
60598
60598
  }
60599
60599
  }
60600
- result = join16(result, [
60600
+ result = join17(result, [
60601
60601
  "from" + space,
60602
60602
  // ModuleSpecifier
60603
60603
  this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
@@ -60651,7 +60651,7 @@ var require_escodegen = __commonJS({
60651
60651
  return result;
60652
60652
  },
60653
60653
  ThrowStatement: function(stmt, flags) {
60654
- return [join16(
60654
+ return [join17(
60655
60655
  "throw",
60656
60656
  this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
60657
60657
  ), this.semicolon(flags)];
@@ -60662,7 +60662,7 @@ var require_escodegen = __commonJS({
60662
60662
  result = this.maybeBlockSuffix(stmt.block, result);
60663
60663
  if (stmt.handlers) {
60664
60664
  for (i = 0, iz = stmt.handlers.length; i < iz; ++i) {
60665
- result = join16(result, this.generateStatement(stmt.handlers[i], S_TFFF));
60665
+ result = join17(result, this.generateStatement(stmt.handlers[i], S_TFFF));
60666
60666
  if (stmt.finalizer || i + 1 !== iz) {
60667
60667
  result = this.maybeBlockSuffix(stmt.handlers[i].body, result);
60668
60668
  }
@@ -60670,7 +60670,7 @@ var require_escodegen = __commonJS({
60670
60670
  } else {
60671
60671
  guardedHandlers = stmt.guardedHandlers || [];
60672
60672
  for (i = 0, iz = guardedHandlers.length; i < iz; ++i) {
60673
- result = join16(result, this.generateStatement(guardedHandlers[i], S_TFFF));
60673
+ result = join17(result, this.generateStatement(guardedHandlers[i], S_TFFF));
60674
60674
  if (stmt.finalizer || i + 1 !== iz) {
60675
60675
  result = this.maybeBlockSuffix(guardedHandlers[i].body, result);
60676
60676
  }
@@ -60678,13 +60678,13 @@ var require_escodegen = __commonJS({
60678
60678
  if (stmt.handler) {
60679
60679
  if (Array.isArray(stmt.handler)) {
60680
60680
  for (i = 0, iz = stmt.handler.length; i < iz; ++i) {
60681
- result = join16(result, this.generateStatement(stmt.handler[i], S_TFFF));
60681
+ result = join17(result, this.generateStatement(stmt.handler[i], S_TFFF));
60682
60682
  if (stmt.finalizer || i + 1 !== iz) {
60683
60683
  result = this.maybeBlockSuffix(stmt.handler[i].body, result);
60684
60684
  }
60685
60685
  }
60686
60686
  } else {
60687
- result = join16(result, this.generateStatement(stmt.handler, S_TFFF));
60687
+ result = join17(result, this.generateStatement(stmt.handler, S_TFFF));
60688
60688
  if (stmt.finalizer) {
60689
60689
  result = this.maybeBlockSuffix(stmt.handler.body, result);
60690
60690
  }
@@ -60692,7 +60692,7 @@ var require_escodegen = __commonJS({
60692
60692
  }
60693
60693
  }
60694
60694
  if (stmt.finalizer) {
60695
- result = join16(result, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
60695
+ result = join17(result, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
60696
60696
  }
60697
60697
  return result;
60698
60698
  },
@@ -60726,7 +60726,7 @@ var require_escodegen = __commonJS({
60726
60726
  withIndent(function() {
60727
60727
  if (stmt.test) {
60728
60728
  result = [
60729
- join16("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
60729
+ join17("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
60730
60730
  ":"
60731
60731
  ];
60732
60732
  } else {
@@ -60774,9 +60774,9 @@ var require_escodegen = __commonJS({
60774
60774
  result.push(this.maybeBlock(stmt.consequent, S_TFFF));
60775
60775
  result = this.maybeBlockSuffix(stmt.consequent, result);
60776
60776
  if (stmt.alternate.type === Syntax.IfStatement) {
60777
- result = join16(result, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
60777
+ result = join17(result, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
60778
60778
  } else {
60779
- result = join16(result, join16("else", this.maybeBlock(stmt.alternate, bodyFlags)));
60779
+ result = join17(result, join17("else", this.maybeBlock(stmt.alternate, bodyFlags)));
60780
60780
  }
60781
60781
  } else {
60782
60782
  result.push(this.maybeBlock(stmt.consequent, bodyFlags));
@@ -60877,7 +60877,7 @@ var require_escodegen = __commonJS({
60877
60877
  },
60878
60878
  ReturnStatement: function(stmt, flags) {
60879
60879
  if (stmt.argument) {
60880
- return [join16(
60880
+ return [join17(
60881
60881
  "return",
60882
60882
  this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
60883
60883
  ), this.semicolon(flags)];
@@ -60966,14 +60966,14 @@ var require_escodegen = __commonJS({
60966
60966
  if (leftSource.charCodeAt(leftSource.length - 1) === 47 && esutils.code.isIdentifierPartES5(expr.operator.charCodeAt(0))) {
60967
60967
  result = [fragment, noEmptySpace(), expr.operator];
60968
60968
  } else {
60969
- result = join16(fragment, expr.operator);
60969
+ result = join17(fragment, expr.operator);
60970
60970
  }
60971
60971
  fragment = this.generateExpression(expr.right, rightPrecedence, flags);
60972
60972
  if (expr.operator === "/" && fragment.toString().charAt(0) === "/" || expr.operator.slice(-1) === "<" && fragment.toString().slice(0, 3) === "!--") {
60973
60973
  result.push(noEmptySpace());
60974
60974
  result.push(fragment);
60975
60975
  } else {
60976
- result = join16(result, fragment);
60976
+ result = join17(result, fragment);
60977
60977
  }
60978
60978
  if (expr.operator === "in" && !(flags & F_ALLOW_IN)) {
60979
60979
  return ["(", result, ")"];
@@ -61013,7 +61013,7 @@ var require_escodegen = __commonJS({
61013
61013
  var result, length, i, iz, itemFlags;
61014
61014
  length = expr["arguments"].length;
61015
61015
  itemFlags = flags & F_ALLOW_UNPARATH_NEW && !parentheses && length === 0 ? E_TFT : E_TFF;
61016
- result = join16(
61016
+ result = join17(
61017
61017
  "new",
61018
61018
  this.generateExpression(expr.callee, Precedence.New, itemFlags)
61019
61019
  );
@@ -61063,11 +61063,11 @@ var require_escodegen = __commonJS({
61063
61063
  var result, fragment, rightCharCode, leftSource, leftCharCode;
61064
61064
  fragment = this.generateExpression(expr.argument, Precedence.Unary, E_TTT);
61065
61065
  if (space === "") {
61066
- result = join16(expr.operator, fragment);
61066
+ result = join17(expr.operator, fragment);
61067
61067
  } else {
61068
61068
  result = [expr.operator];
61069
61069
  if (expr.operator.length > 2) {
61070
- result = join16(result, fragment);
61070
+ result = join17(result, fragment);
61071
61071
  } else {
61072
61072
  leftSource = toSourceNodeWhenNeeded(result).toString();
61073
61073
  leftCharCode = leftSource.charCodeAt(leftSource.length - 1);
@@ -61090,7 +61090,7 @@ var require_escodegen = __commonJS({
61090
61090
  result = "yield";
61091
61091
  }
61092
61092
  if (expr.argument) {
61093
- result = join16(
61093
+ result = join17(
61094
61094
  result,
61095
61095
  this.generateExpression(expr.argument, Precedence.Yield, E_TTT)
61096
61096
  );
@@ -61098,7 +61098,7 @@ var require_escodegen = __commonJS({
61098
61098
  return parenthesize(result, Precedence.Yield, precedence);
61099
61099
  },
61100
61100
  AwaitExpression: function(expr, precedence, flags) {
61101
- var result = join16(
61101
+ var result = join17(
61102
61102
  expr.all ? "await*" : "await",
61103
61103
  this.generateExpression(expr.argument, Precedence.Await, E_TTT)
61104
61104
  );
@@ -61181,11 +61181,11 @@ var require_escodegen = __commonJS({
61181
61181
  var result, fragment;
61182
61182
  result = ["class"];
61183
61183
  if (expr.id) {
61184
- result = join16(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
61184
+ result = join17(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
61185
61185
  }
61186
61186
  if (expr.superClass) {
61187
- fragment = join16("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
61188
- result = join16(result, fragment);
61187
+ fragment = join17("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
61188
+ result = join17(result, fragment);
61189
61189
  }
61190
61190
  result.push(space);
61191
61191
  result.push(this.generateStatement(expr.body, S_TFFT));
@@ -61200,7 +61200,7 @@ var require_escodegen = __commonJS({
61200
61200
  }
61201
61201
  if (expr.kind === "get" || expr.kind === "set") {
61202
61202
  fragment = [
61203
- join16(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
61203
+ join17(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
61204
61204
  this.generateFunctionBody(expr.value)
61205
61205
  ];
61206
61206
  } else {
@@ -61210,7 +61210,7 @@ var require_escodegen = __commonJS({
61210
61210
  this.generateFunctionBody(expr.value)
61211
61211
  ];
61212
61212
  }
61213
- return join16(result, fragment);
61213
+ return join17(result, fragment);
61214
61214
  },
61215
61215
  Property: function(expr, precedence, flags) {
61216
61216
  if (expr.kind === "get" || expr.kind === "set") {
@@ -61405,7 +61405,7 @@ var require_escodegen = __commonJS({
61405
61405
  for (i = 0, iz = expr.blocks.length; i < iz; ++i) {
61406
61406
  fragment = that.generateExpression(expr.blocks[i], Precedence.Sequence, E_TTT);
61407
61407
  if (i > 0 || extra.moz.comprehensionExpressionStartsWithAssignment) {
61408
- result = join16(result, fragment);
61408
+ result = join17(result, fragment);
61409
61409
  } else {
61410
61410
  result.push(fragment);
61411
61411
  }
@@ -61413,13 +61413,13 @@ var require_escodegen = __commonJS({
61413
61413
  });
61414
61414
  }
61415
61415
  if (expr.filter) {
61416
- result = join16(result, "if" + space);
61416
+ result = join17(result, "if" + space);
61417
61417
  fragment = this.generateExpression(expr.filter, Precedence.Sequence, E_TTT);
61418
- result = join16(result, ["(", fragment, ")"]);
61418
+ result = join17(result, ["(", fragment, ")"]);
61419
61419
  }
61420
61420
  if (!extra.moz.comprehensionExpressionStartsWithAssignment) {
61421
61421
  fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT);
61422
- result = join16(result, fragment);
61422
+ result = join17(result, fragment);
61423
61423
  }
61424
61424
  result.push(expr.type === Syntax.GeneratorExpression ? ")" : "]");
61425
61425
  return result;
@@ -61435,8 +61435,8 @@ var require_escodegen = __commonJS({
61435
61435
  } else {
61436
61436
  fragment = this.generateExpression(expr.left, Precedence.Call, E_TTT);
61437
61437
  }
61438
- fragment = join16(fragment, expr.of ? "of" : "in");
61439
- fragment = join16(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
61438
+ fragment = join17(fragment, expr.of ? "of" : "in");
61439
+ fragment = join17(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
61440
61440
  return ["for" + space + "(", fragment, ")"];
61441
61441
  },
61442
61442
  SpreadElement: function(expr, precedence, flags) {
@@ -67966,11 +67966,11 @@ function __metadata(metadataKey, metadataValue) {
67966
67966
  }
67967
67967
  function __awaiter2(thisArg, _arguments, P, generator) {
67968
67968
  function adopt(value) {
67969
- return value instanceof P ? value : new P(function(resolve12) {
67970
- resolve12(value);
67969
+ return value instanceof P ? value : new P(function(resolve13) {
67970
+ resolve13(value);
67971
67971
  });
67972
67972
  }
67973
- return new (P || (P = Promise))(function(resolve12, reject) {
67973
+ return new (P || (P = Promise))(function(resolve13, reject) {
67974
67974
  function fulfilled(value) {
67975
67975
  try {
67976
67976
  step(generator.next(value));
@@ -67986,7 +67986,7 @@ function __awaiter2(thisArg, _arguments, P, generator) {
67986
67986
  }
67987
67987
  }
67988
67988
  function step(result) {
67989
- result.done ? resolve12(result.value) : adopt(result.value).then(fulfilled, rejected);
67989
+ result.done ? resolve13(result.value) : adopt(result.value).then(fulfilled, rejected);
67990
67990
  }
67991
67991
  step((generator = generator.apply(thisArg, _arguments || [])).next());
67992
67992
  });
@@ -68177,14 +68177,14 @@ function __asyncValues2(o) {
68177
68177
  }, i);
68178
68178
  function verb(n) {
68179
68179
  i[n] = o[n] && function(v) {
68180
- return new Promise(function(resolve12, reject) {
68181
- v = o[n](v), settle(resolve12, reject, v.done, v.value);
68180
+ return new Promise(function(resolve13, reject) {
68181
+ v = o[n](v), settle(resolve13, reject, v.done, v.value);
68182
68182
  });
68183
68183
  };
68184
68184
  }
68185
- function settle(resolve12, reject, d, v) {
68185
+ function settle(resolve13, reject, d, v) {
68186
68186
  Promise.resolve(v).then(function(v2) {
68187
- resolve12({ value: v2, done: d });
68187
+ resolve13({ value: v2, done: d });
68188
68188
  }, reject);
68189
68189
  }
68190
68190
  }
@@ -71737,12 +71737,12 @@ var require_util3 = __commonJS({
71737
71737
  exports.isGMT = exports.dnsLookup = void 0;
71738
71738
  var dns_1 = __require("dns");
71739
71739
  function dnsLookup(host, opts) {
71740
- return new Promise((resolve12, reject) => {
71740
+ return new Promise((resolve13, reject) => {
71741
71741
  (0, dns_1.lookup)(host, opts, (err, res) => {
71742
71742
  if (err) {
71743
71743
  reject(err);
71744
71744
  } else {
71745
- resolve12(res);
71745
+ resolve13(res);
71746
71746
  }
71747
71747
  });
71748
71748
  });
@@ -72107,10 +72107,10 @@ var require_myIpAddress = __commonJS({
72107
72107
  var ip_1 = require_ip();
72108
72108
  var net_1 = __importDefault2(__require("net"));
72109
72109
  async function myIpAddress() {
72110
- return new Promise((resolve12, reject) => {
72110
+ return new Promise((resolve13, reject) => {
72111
72111
  const socket = net_1.default.connect({ host: "8.8.8.8", port: 53 });
72112
72112
  const onError = () => {
72113
- resolve12(ip_1.ip.address());
72113
+ resolve13(ip_1.ip.address());
72114
72114
  };
72115
72115
  socket.once("error", onError);
72116
72116
  socket.once("connect", () => {
@@ -72118,9 +72118,9 @@ var require_myIpAddress = __commonJS({
72118
72118
  const addr = socket.address();
72119
72119
  socket.destroy();
72120
72120
  if (typeof addr === "string") {
72121
- resolve12(addr);
72121
+ resolve13(addr);
72122
72122
  } else if (addr.address) {
72123
- resolve12(addr.address);
72123
+ resolve13(addr.address);
72124
72124
  } else {
72125
72125
  reject(new Error("Expected a `string`"));
72126
72126
  }
@@ -72698,8 +72698,8 @@ var require_deferred_promise = __commonJS({
72698
72698
  this.context = args.context;
72699
72699
  this.owner = args.context.runtime;
72700
72700
  this.handle = args.promiseHandle;
72701
- this.settled = new Promise((resolve12) => {
72702
- this.onSettled = resolve12;
72701
+ this.settled = new Promise((resolve13) => {
72702
+ this.onSettled = resolve13;
72703
72703
  });
72704
72704
  this.resolveHandle = args.resolveHandle;
72705
72705
  this.rejectHandle = args.rejectHandle;
@@ -73220,13 +73220,13 @@ var require_context = __commonJS({
73220
73220
  if (vmResolveResult.error) {
73221
73221
  return Promise.resolve(vmResolveResult);
73222
73222
  }
73223
- return new Promise((resolve12) => {
73223
+ return new Promise((resolve13) => {
73224
73224
  lifetime_1.Scope.withScope((scope) => {
73225
73225
  const resolveHandle = scope.manage(this.newFunction("resolve", (value) => {
73226
- resolve12({ value: value && value.dup() });
73226
+ resolve13({ value: value && value.dup() });
73227
73227
  }));
73228
73228
  const rejectHandle = scope.manage(this.newFunction("reject", (error) => {
73229
- resolve12({ error: error && error.dup() });
73229
+ resolve13({ error: error && error.dup() });
73230
73230
  }));
73231
73231
  const promiseHandle = scope.manage(vmResolveResult.value);
73232
73232
  const promiseThenHandle = scope.manage(this.getProp(promiseHandle, "then"));
@@ -75601,13 +75601,13 @@ import * as http from "node:http";
75601
75601
  import * as https from "node:https";
75602
75602
  import { URL as URL2, urlToHttpOptions } from "node:url";
75603
75603
  function headHttpRequest(url) {
75604
- return new Promise((resolve12) => {
75604
+ return new Promise((resolve13) => {
75605
75605
  const request3 = httpRequest(url, "HEAD", (response) => {
75606
75606
  response.resume();
75607
- resolve12(response.statusCode === 200);
75607
+ resolve13(response.statusCode === 200);
75608
75608
  }, false);
75609
75609
  request3.on("error", () => {
75610
- resolve12(false);
75610
+ resolve13(false);
75611
75611
  });
75612
75612
  });
75613
75613
  }
@@ -75635,7 +75635,7 @@ function httpRequest(url, method, response, keepAlive = true) {
75635
75635
  return request3;
75636
75636
  }
75637
75637
  function downloadFile(url, destinationPath, progressCallback) {
75638
- return new Promise((resolve12, reject) => {
75638
+ return new Promise((resolve13, reject) => {
75639
75639
  let downloadedBytes = 0;
75640
75640
  let totalBytes = 0;
75641
75641
  function onData(chunk) {
@@ -75651,7 +75651,7 @@ function downloadFile(url, destinationPath, progressCallback) {
75651
75651
  }
75652
75652
  const file = createWriteStream(destinationPath);
75653
75653
  file.on("close", () => {
75654
- return resolve12();
75654
+ return resolve13();
75655
75655
  });
75656
75656
  file.on("error", (error) => {
75657
75657
  return reject(error);
@@ -75676,7 +75676,7 @@ async function getJSON(url) {
75676
75676
  }
75677
75677
  }
75678
75678
  function getText3(url) {
75679
- return new Promise((resolve12, reject) => {
75679
+ return new Promise((resolve13, reject) => {
75680
75680
  const request3 = httpRequest(url, "GET", (response) => {
75681
75681
  let data = "";
75682
75682
  if (response.statusCode && response.statusCode >= 400) {
@@ -75687,7 +75687,7 @@ function getText3(url) {
75687
75687
  });
75688
75688
  response.on("end", () => {
75689
75689
  try {
75690
- return resolve12(String(data));
75690
+ return resolve13(String(data));
75691
75691
  } catch {
75692
75692
  return reject(new Error(`Failed to read text response from ${url}`));
75693
75693
  }
@@ -77079,7 +77079,7 @@ var init_launch = __esm({
77079
77079
  if (opts.onExit) {
77080
77080
  this.#onExitHook = opts.onExit;
77081
77081
  }
77082
- this.#browserProcessExiting = new Promise((resolve12, reject) => {
77082
+ this.#browserProcessExiting = new Promise((resolve13, reject) => {
77083
77083
  this.#browserProcess.once("exit", async () => {
77084
77084
  debugLaunch(`Browser process ${this.#browserProcess.pid} onExit`);
77085
77085
  this.#clearListeners();
@@ -77090,7 +77090,7 @@ var init_launch = __esm({
77090
77090
  reject(err);
77091
77091
  return;
77092
77092
  }
77093
- resolve12();
77093
+ resolve13();
77094
77094
  });
77095
77095
  });
77096
77096
  }
@@ -77206,7 +77206,7 @@ Error cause: ${isErrorLike2(error) ? error.stack : error}`);
77206
77206
  return [...this.#logs];
77207
77207
  }
77208
77208
  waitForLineOutput(regex, timeout2 = 0) {
77209
- return new Promise((resolve12, reject) => {
77209
+ return new Promise((resolve13, reject) => {
77210
77210
  const onClose = (errorOrCode) => {
77211
77211
  cleanup();
77212
77212
  reject(new Error([
@@ -77242,7 +77242,7 @@ Error cause: ${isErrorLike2(error) ? error.stack : error}`);
77242
77242
  return;
77243
77243
  }
77244
77244
  cleanup();
77245
- resolve12(match2[1]);
77245
+ resolve13(match2[1]);
77246
77246
  }
77247
77247
  });
77248
77248
  }
@@ -77711,7 +77711,7 @@ var require_get_stream = __commonJS({
77711
77711
  };
77712
77712
  const { maxBuffer } = options;
77713
77713
  let stream2;
77714
- await new Promise((resolve12, reject) => {
77714
+ await new Promise((resolve13, reject) => {
77715
77715
  const rejectPromise = (error) => {
77716
77716
  if (error && stream2.getBufferedLength() <= BufferConstants.MAX_LENGTH) {
77717
77717
  error.bufferedData = stream2.getBufferedValue();
@@ -77723,7 +77723,7 @@ var require_get_stream = __commonJS({
77723
77723
  rejectPromise(error);
77724
77724
  return;
77725
77725
  }
77726
- resolve12();
77726
+ resolve13();
77727
77727
  });
77728
77728
  stream2.on("data", () => {
77729
77729
  if (stream2.getBufferedLength() > maxBuffer) {
@@ -79012,7 +79012,7 @@ var require_extract_zip = __commonJS({
79012
79012
  debug6("opening", this.zipPath, "with opts", this.opts);
79013
79013
  this.zipfile = await openZip(this.zipPath, { lazyEntries: true });
79014
79014
  this.canceled = false;
79015
- return new Promise((resolve12, reject) => {
79015
+ return new Promise((resolve13, reject) => {
79016
79016
  this.zipfile.on("error", (err) => {
79017
79017
  this.canceled = true;
79018
79018
  reject(err);
@@ -79021,7 +79021,7 @@ var require_extract_zip = __commonJS({
79021
79021
  this.zipfile.on("close", () => {
79022
79022
  if (!this.canceled) {
79023
79023
  debug6("zip extraction complete");
79024
- resolve12();
79024
+ resolve13();
79025
79025
  }
79026
79026
  });
79027
79027
  this.zipfile.on("entry", async (entry) => {
@@ -80278,8 +80278,8 @@ var require_streamx = __commonJS({
80278
80278
  return this;
80279
80279
  },
80280
80280
  next() {
80281
- return new Promise(function(resolve12, reject) {
80282
- promiseResolve = resolve12;
80281
+ return new Promise(function(resolve13, reject) {
80282
+ promiseResolve = resolve13;
80283
80283
  promiseReject = reject;
80284
80284
  const data = stream2.read();
80285
80285
  if (data !== null) ondata(data);
@@ -80309,11 +80309,11 @@ var require_streamx = __commonJS({
80309
80309
  }
80310
80310
  function destroy(err) {
80311
80311
  stream2.destroy(err);
80312
- return new Promise((resolve12, reject) => {
80313
- if (stream2._duplexState & DESTROYED) return resolve12({ value: void 0, done: true });
80312
+ return new Promise((resolve13, reject) => {
80313
+ if (stream2._duplexState & DESTROYED) return resolve13({ value: void 0, done: true });
80314
80314
  stream2.once("close", function() {
80315
80315
  if (err) reject(err);
80316
- else resolve12({ value: void 0, done: true });
80316
+ else resolve13({ value: void 0, done: true });
80317
80317
  });
80318
80318
  });
80319
80319
  }
@@ -80357,8 +80357,8 @@ var require_streamx = __commonJS({
80357
80357
  const writes = pending + (ws._duplexState & WRITE_WRITING ? 1 : 0);
80358
80358
  if (writes === 0) return Promise.resolve(true);
80359
80359
  if (state.drains === null) state.drains = [];
80360
- return new Promise((resolve12) => {
80361
- state.drains.push({ writes, resolve: resolve12 });
80360
+ return new Promise((resolve13) => {
80361
+ state.drains.push({ writes, resolve: resolve13 });
80362
80362
  });
80363
80363
  }
80364
80364
  write(data) {
@@ -80463,10 +80463,10 @@ var require_streamx = __commonJS({
80463
80463
  cb(null);
80464
80464
  }
80465
80465
  function pipelinePromise(...streams) {
80466
- return new Promise((resolve12, reject) => {
80466
+ return new Promise((resolve13, reject) => {
80467
80467
  return pipeline(...streams, (err) => {
80468
80468
  if (err) return reject(err);
80469
- resolve12();
80469
+ resolve13();
80470
80470
  });
80471
80471
  });
80472
80472
  }
@@ -81121,16 +81121,16 @@ var require_extract = __commonJS({
81121
81121
  entryCallback = null;
81122
81122
  cb(err);
81123
81123
  }
81124
- function onnext(resolve12, reject) {
81124
+ function onnext(resolve13, reject) {
81125
81125
  if (error) {
81126
81126
  return reject(error);
81127
81127
  }
81128
81128
  if (entryStream) {
81129
- resolve12({ value: entryStream, done: false });
81129
+ resolve13({ value: entryStream, done: false });
81130
81130
  entryStream = null;
81131
81131
  return;
81132
81132
  }
81133
- promiseResolve = resolve12;
81133
+ promiseResolve = resolve13;
81134
81134
  promiseReject = reject;
81135
81135
  consumeCallback(null);
81136
81136
  if (extract._finished && promiseResolve) {
@@ -81158,11 +81158,11 @@ var require_extract = __commonJS({
81158
81158
  function destroy(err) {
81159
81159
  extract.destroy(err);
81160
81160
  consumeCallback(err);
81161
- return new Promise((resolve12, reject) => {
81162
- if (extract.destroyed) return resolve12({ value: void 0, done: true });
81161
+ return new Promise((resolve13, reject) => {
81162
+ if (extract.destroyed) return resolve13({ value: void 0, done: true });
81163
81163
  extract.once("close", function() {
81164
81164
  if (err) reject(err);
81165
- else resolve12({ value: void 0, done: true });
81165
+ else resolve13({ value: void 0, done: true });
81166
81166
  });
81167
81167
  });
81168
81168
  }
@@ -86138,12 +86138,12 @@ var init_yargs_factory = __esm({
86138
86138
  async getCompletion(args, done) {
86139
86139
  argsert("<array> [function]", [args, done], arguments.length);
86140
86140
  if (!done) {
86141
- return new Promise((resolve12, reject) => {
86141
+ return new Promise((resolve13, reject) => {
86142
86142
  __classPrivateFieldGet2(this, _YargsInstance_completion, "f").getCompletion(args, (err, completions) => {
86143
86143
  if (err)
86144
86144
  reject(err);
86145
86145
  else
86146
- resolve12(completions);
86146
+ resolve13(completions);
86147
86147
  });
86148
86148
  });
86149
86149
  } else {
@@ -87598,9 +87598,9 @@ async function getConnectionTransport(options) {
87598
87598
  throw new Error("Could not detect required browser platform");
87599
87599
  }
87600
87600
  const { convertPuppeteerChannelToBrowsersChannel: convertPuppeteerChannelToBrowsersChannel2 } = await Promise.resolve().then(() => (init_LaunchOptions(), LaunchOptions_exports));
87601
- const { join: join16 } = await import("node:path");
87601
+ const { join: join17 } = await import("node:path");
87602
87602
  const userDataDir = resolveDefaultUserDataDir3(Browser4.CHROME, platform, convertPuppeteerChannelToBrowsersChannel2(options.channel));
87603
- const portPath = join16(userDataDir, "DevToolsActivePort");
87603
+ const portPath = join17(userDataDir, "DevToolsActivePort");
87604
87604
  try {
87605
87605
  const fileContent = await environment.value.fs.promises.readFile(portPath, "ascii");
87606
87606
  const [rawPort, rawPath] = fileContent.split("\n").map((line) => {
@@ -88944,8 +88944,8 @@ var init_ScreenRecorder = __esm({
88944
88944
  static {
88945
88945
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
88946
88946
  __esDecorate23(this, _private_writeFrame_descriptor = { value: __setFunctionName6(async function(buffer) {
88947
- const error = await new Promise((resolve12) => {
88948
- this.#process.stdin.write(buffer, resolve12);
88947
+ const error = await new Promise((resolve13) => {
88948
+ this.#process.stdin.write(buffer, resolve13);
88949
88949
  });
88950
88950
  if (error) {
88951
88951
  console.log(`ffmpeg failed to write: ${error.message}.`);
@@ -89135,8 +89135,8 @@ var init_ScreenRecorder = __esm({
89135
89135
  const [buffer, timestamp] = await this.#lastFrame;
89136
89136
  await Promise.all(Array(Math.max(1, Math.round(this.#fps * (performance.now() - timestamp) / 1e3))).fill(buffer).map(this.#writeFrame.bind(this)));
89137
89137
  this.#process.stdin.end();
89138
- await new Promise((resolve12) => {
89139
- this.#process.once("close", resolve12);
89138
+ await new Promise((resolve13) => {
89139
+ this.#process.once("close", resolve13);
89140
89140
  });
89141
89141
  }
89142
89142
  /**
@@ -89426,7 +89426,7 @@ import {
89426
89426
  rmSync as rmSync4,
89427
89427
  createReadStream as createReadStream2
89428
89428
  } from "node:fs";
89429
- import { resolve as resolve11, dirname as dirname10, join as join15 } from "node:path";
89429
+ import { resolve as resolve12, dirname as dirname11, join as join16 } from "node:path";
89430
89430
  import { tmpdir as tmpdir2 } from "node:os";
89431
89431
  import { parseArgs } from "node:util";
89432
89432
  import crypto2 from "node:crypto";
@@ -92061,7 +92061,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
92061
92061
  });
92062
92062
  if (!chunk) {
92063
92063
  if (i === 1) {
92064
- await new Promise((resolve12) => setTimeout(resolve12));
92064
+ await new Promise((resolve13) => setTimeout(resolve13));
92065
92065
  maxReadCount = 3;
92066
92066
  continue;
92067
92067
  }
@@ -95821,8 +95821,8 @@ var CustomElementRegistry = class {
95821
95821
  } : (element) => element.localName === localName;
95822
95822
  registry.set(localName, { Class, check });
95823
95823
  if (waiting.has(localName)) {
95824
- for (const resolve12 of waiting.get(localName))
95825
- resolve12(Class);
95824
+ for (const resolve13 of waiting.get(localName))
95825
+ resolve13(Class);
95826
95826
  waiting.delete(localName);
95827
95827
  }
95828
95828
  ownerDocument.querySelectorAll(
@@ -95862,13 +95862,13 @@ var CustomElementRegistry = class {
95862
95862
  */
95863
95863
  whenDefined(localName) {
95864
95864
  const { registry, waiting } = this;
95865
- return new Promise((resolve12) => {
95865
+ return new Promise((resolve13) => {
95866
95866
  if (registry.has(localName))
95867
- resolve12(registry.get(localName).Class);
95867
+ resolve13(registry.get(localName).Class);
95868
95868
  else {
95869
95869
  if (!waiting.has(localName))
95870
95870
  waiting.set(localName, []);
95871
- waiting.get(localName).push(resolve12);
95871
+ waiting.get(localName).push(resolve13);
95872
95872
  }
95873
95873
  });
95874
95874
  }
@@ -101696,7 +101696,7 @@ function buildChromeArgs(options, config2) {
101696
101696
 
101697
101697
  // ../engine/src/services/frameCapture.ts
101698
101698
  import { existsSync as existsSync4, mkdirSync, writeFileSync } from "fs";
101699
- import { join as join4 } from "path";
101699
+ import { join as join5 } from "path";
101700
101700
 
101701
101701
  // ../core/src/parsers/gsapParser.ts
101702
101702
  var GSAP_METHODS = /* @__PURE__ */ new Set(["set", "to", "from", "fromTo"]);
@@ -101852,10 +101852,14 @@ function hasAttr(tag, attr) {
101852
101852
  function injectAttr(tag, attr, value) {
101853
101853
  return tag.replace(/>$/, ` ${attr}="${value}">`);
101854
101854
  }
101855
- function compileTag(tag, isVideo) {
101855
+ function compileTag(tag, isVideo, generateId) {
101856
101856
  let result = tag;
101857
101857
  let unresolved = null;
101858
- const id = getAttr(result, "id");
101858
+ let id = getAttr(result, "id");
101859
+ if (!id) {
101860
+ id = `${isVideo ? "hf-video" : "hf-audio"}-${generateId()}`;
101861
+ result = injectAttr(result, "id", id);
101862
+ }
101859
101863
  const startStr = getAttr(result, "data-start");
101860
101864
  const start = startStr !== null ? parseFloat(startStr) : 0;
101861
101865
  const mediaStartStr = getAttr(result, "data-media-start");
@@ -101882,13 +101886,15 @@ function compileTag(tag, isVideo) {
101882
101886
  }
101883
101887
  function compileTimingAttrs(html) {
101884
101888
  const unresolved = [];
101889
+ let nextVideoId = 0;
101890
+ let nextAudioId = 0;
101885
101891
  html = html.replace(/<video[^>]*>/gi, (match2) => {
101886
- const { tag, unresolved: u } = compileTag(match2, true);
101892
+ const { tag, unresolved: u } = compileTag(match2, true, () => nextVideoId++);
101887
101893
  if (u) unresolved.push(u);
101888
101894
  return tag;
101889
101895
  });
101890
101896
  html = html.replace(/<audio[^>]*>/gi, (match2) => {
101891
- const { tag, unresolved: u } = compileTag(match2, false);
101897
+ const { tag, unresolved: u } = compileTag(match2, false, () => nextAudioId++);
101892
101898
  if (u) unresolved.push(u);
101893
101899
  return tag;
101894
101900
  });
@@ -101971,80 +101977,175 @@ function clampDurations(html, clamps) {
101971
101977
  return html;
101972
101978
  }
101973
101979
 
101974
- // ../core/src/lint/hyperframeLinter.ts
101980
+ // ../core/src/lint/utils.ts
101975
101981
  var TAG_PATTERN = /<([a-z][\w:-]*)(\s[^<>]*?)?>/gi;
101976
101982
  var STYLE_BLOCK_PATTERN = /<style\b([^>]*)>([\s\S]*?)<\/style>/gi;
101977
101983
  var SCRIPT_BLOCK_PATTERN = /<script\b([^>]*)>([\s\S]*?)<\/script>/gi;
101978
101984
  var COMPOSITION_ID_IN_CSS_PATTERN = /\[data-composition-id=["']([^"']+)["']\]/g;
101979
101985
  var TIMELINE_REGISTRY_INIT_PATTERN = /window\.__timelines\s*=\s*window\.__timelines\s*\|\|\s*\{\}|window\.__timelines\s*=\s*\{\}|window\.__timelines\s*\?\?=\s*\{\}/i;
101980
101986
  var TIMELINE_REGISTRY_ASSIGN_PATTERN = /window\.__timelines\[[^\]]+\]\s*=/i;
101981
- var INVALID_SCRIPT_CLOSE_PATTERN = /<script[^>]*>[\s\S]*?<\s*\/\s*script(?!>)/i;
101982
101987
  var WINDOW_TIMELINE_ASSIGN_PATTERN = /window\.__timelines\[\s*["']([^"']+)["']\s*\]\s*=\s*([A-Za-z_$][\w$]*)/i;
101983
- var META_GSAP_KEYS = /* @__PURE__ */ new Set(["duration", "ease", "repeat", "yoyo", "overwrite", "delay"]);
101984
- function lintHyperframeHtml(html, options = {}) {
101988
+ var INVALID_SCRIPT_CLOSE_PATTERN = /<script[^>]*>[\s\S]*?<\s*\/\s*script(?!>)/i;
101989
+ function extractOpenTags(source2) {
101990
+ const tags = [];
101991
+ let match2;
101992
+ const pattern = new RegExp(TAG_PATTERN.source, TAG_PATTERN.flags);
101993
+ while ((match2 = pattern.exec(source2)) !== null) {
101994
+ const raw2 = match2[0];
101995
+ if (raw2.startsWith("</") || raw2.startsWith("<!")) continue;
101996
+ tags.push({
101997
+ raw: raw2,
101998
+ name: (match2[1] || "").toLowerCase(),
101999
+ attrs: match2[2] || "",
102000
+ index: match2.index
102001
+ });
102002
+ }
102003
+ return tags;
102004
+ }
102005
+ function extractBlocks(source2, pattern) {
102006
+ const blocks = [];
102007
+ let match2;
102008
+ const p = new RegExp(pattern.source, pattern.flags);
102009
+ while ((match2 = p.exec(source2)) !== null) {
102010
+ blocks.push({
102011
+ attrs: match2[1] || "",
102012
+ content: match2[2] || "",
102013
+ raw: match2[0],
102014
+ index: match2.index
102015
+ });
102016
+ }
102017
+ return blocks;
102018
+ }
102019
+ function findRootTag(source2) {
102020
+ const bodyMatch = source2.match(/<body\b[^>]*>([\s\S]*?)<\/body>/i);
102021
+ const bodyContent = bodyMatch ? bodyMatch[1] ?? source2 : source2;
102022
+ const bodyTags = extractOpenTags(bodyContent);
102023
+ for (const tag of bodyTags) {
102024
+ if (["script", "style", "meta", "link", "title"].includes(tag.name)) continue;
102025
+ return tag;
102026
+ }
102027
+ return null;
102028
+ }
102029
+ function readAttr(tagSource, attr) {
102030
+ if (!tagSource) return null;
102031
+ const escaped = attr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
102032
+ const match2 = tagSource.match(new RegExp(`\\b${escaped}\\s*=\\s*["']([^"']+)["']`, "i"));
102033
+ return match2?.[1] || null;
102034
+ }
102035
+ function collectCompositionIds(tags) {
102036
+ const ids = /* @__PURE__ */ new Set();
102037
+ for (const tag of tags) {
102038
+ const compId = readAttr(tag.raw, "data-composition-id");
102039
+ if (compId) ids.add(compId);
102040
+ }
102041
+ return ids;
102042
+ }
102043
+ function extractCompositionIdsFromCss(css) {
102044
+ const ids = /* @__PURE__ */ new Set();
102045
+ let match2;
102046
+ const pattern = new RegExp(
102047
+ COMPOSITION_ID_IN_CSS_PATTERN.source,
102048
+ COMPOSITION_ID_IN_CSS_PATTERN.flags
102049
+ );
102050
+ while ((match2 = pattern.exec(css)) !== null) {
102051
+ if (match2[1]) ids.add(match2[1]);
102052
+ }
102053
+ return [...ids];
102054
+ }
102055
+ function getInlineScriptSyntaxError(source2) {
102056
+ if (!source2.trim()) return null;
102057
+ try {
102058
+ new Function(source2);
102059
+ return null;
102060
+ } catch (error) {
102061
+ if (error instanceof Error) return error.message;
102062
+ return String(error);
102063
+ }
102064
+ }
102065
+ function isMediaTag(tagName19) {
102066
+ return tagName19 === "video" || tagName19 === "audio" || tagName19 === "img";
102067
+ }
102068
+ function truncateSnippet(value, maxLength = 220) {
102069
+ const normalized = value.replace(/\s+/g, " ").trim();
102070
+ if (!normalized) return void 0;
102071
+ if (normalized.length <= maxLength) return normalized;
102072
+ return `${normalized.slice(0, maxLength - 3)}...`;
102073
+ }
102074
+
102075
+ // ../core/src/lint/context.ts
102076
+ function buildLintContext(html, options = {}) {
101985
102077
  let source2 = html || "";
101986
102078
  const templateMatch = source2.match(/<template[^>]*>([\s\S]*)<\/template>/i);
101987
102079
  if (templateMatch?.[1]) source2 = templateMatch[1];
101988
- const filePath = options.filePath;
101989
- const findings = [];
101990
- const seen = /* @__PURE__ */ new Set();
101991
- const pushFinding = (finding) => {
101992
- const dedupeKey = [
101993
- finding.code,
101994
- finding.severity,
101995
- finding.selector || "",
101996
- finding.elementId || "",
101997
- finding.message
101998
- ].join("|");
101999
- if (seen.has(dedupeKey)) {
102000
- return;
102001
- }
102002
- seen.add(dedupeKey);
102003
- findings.push(filePath ? { ...finding, file: filePath } : finding);
102004
- };
102005
102080
  const tags = extractOpenTags(source2);
102006
102081
  const styles = extractBlocks(source2, STYLE_BLOCK_PATTERN);
102007
102082
  const scripts = extractBlocks(source2, SCRIPT_BLOCK_PATTERN);
102008
102083
  const compositionIds = collectCompositionIds(tags);
102009
102084
  const rootTag = findRootTag(source2);
102010
102085
  const rootCompositionId = readAttr(rootTag?.raw || "", "data-composition-id");
102011
- if (!rootTag || !readAttr(rootTag.raw, "data-composition-id")) {
102012
- pushFinding({
102013
- code: "root_missing_composition_id",
102014
- severity: "error",
102015
- message: "Root composition is missing `data-composition-id`.",
102016
- elementId: rootTag ? readAttr(rootTag.raw, "id") || void 0 : void 0,
102017
- fixHint: "Add a stable `data-composition-id` to the entry composition wrapper.",
102018
- snippet: truncateSnippet(rootTag?.raw || "")
102019
- });
102020
- }
102021
- if (!rootTag || !readAttr(rootTag.raw, "data-width") || !readAttr(rootTag.raw, "data-height")) {
102022
- pushFinding({
102023
- code: "root_missing_dimensions",
102024
- severity: "error",
102025
- message: "Root composition is missing `data-width` or `data-height`.",
102026
- elementId: rootTag ? readAttr(rootTag.raw, "id") || void 0 : void 0,
102027
- fixHint: "Set numeric `data-width` and `data-height` on the entry composition root.",
102028
- snippet: truncateSnippet(rootTag?.raw || "")
102029
- });
102030
- }
102031
- if (!TIMELINE_REGISTRY_INIT_PATTERN.test(source2) && !TIMELINE_REGISTRY_ASSIGN_PATTERN.test(source2)) {
102032
- pushFinding({
102033
- code: "missing_timeline_registry",
102034
- severity: "error",
102035
- message: "Missing `window.__timelines` registration.",
102036
- fixHint: "Register each composition timeline on `window.__timelines[compositionId]`."
102037
- });
102038
- }
102039
- if (TIMELINE_REGISTRY_ASSIGN_PATTERN.test(source2) && !TIMELINE_REGISTRY_INIT_PATTERN.test(source2)) {
102040
- pushFinding({
102041
- code: "timeline_registry_missing_init",
102042
- severity: "error",
102043
- message: "`window.__timelines[\u2026] = \u2026` is used without initializing `window.__timelines` first.",
102044
- fixHint: "Add `window.__timelines = window.__timelines || {};` before any timeline assignment."
102045
- });
102046
- }
102047
- {
102086
+ return {
102087
+ source: source2,
102088
+ tags,
102089
+ styles,
102090
+ scripts,
102091
+ compositionIds,
102092
+ rootTag,
102093
+ rootCompositionId,
102094
+ options
102095
+ };
102096
+ }
102097
+
102098
+ // ../core/src/lint/rules/core.ts
102099
+ var coreRules = [
102100
+ // root_missing_composition_id + root_missing_dimensions
102101
+ ({ rootTag }) => {
102102
+ const findings = [];
102103
+ if (!rootTag || !readAttr(rootTag.raw, "data-composition-id")) {
102104
+ findings.push({
102105
+ code: "root_missing_composition_id",
102106
+ severity: "error",
102107
+ message: "Root composition is missing `data-composition-id`.",
102108
+ elementId: rootTag ? readAttr(rootTag.raw, "id") || void 0 : void 0,
102109
+ fixHint: "Add a stable `data-composition-id` to the entry composition wrapper.",
102110
+ snippet: truncateSnippet(rootTag?.raw || "")
102111
+ });
102112
+ }
102113
+ if (!rootTag || !readAttr(rootTag.raw, "data-width") || !readAttr(rootTag.raw, "data-height")) {
102114
+ findings.push({
102115
+ code: "root_missing_dimensions",
102116
+ severity: "error",
102117
+ message: "Root composition is missing `data-width` or `data-height`.",
102118
+ elementId: rootTag ? readAttr(rootTag.raw, "id") || void 0 : void 0,
102119
+ fixHint: "Set numeric `data-width` and `data-height` on the entry composition root.",
102120
+ snippet: truncateSnippet(rootTag?.raw || "")
102121
+ });
102122
+ }
102123
+ return findings;
102124
+ },
102125
+ // missing_timeline_registry + timeline_registry_missing_init
102126
+ ({ source: source2 }) => {
102127
+ const findings = [];
102128
+ if (!TIMELINE_REGISTRY_INIT_PATTERN.test(source2) && !TIMELINE_REGISTRY_ASSIGN_PATTERN.test(source2)) {
102129
+ findings.push({
102130
+ code: "missing_timeline_registry",
102131
+ severity: "error",
102132
+ message: "Missing `window.__timelines` registration.",
102133
+ fixHint: "Register each composition timeline on `window.__timelines[compositionId]`."
102134
+ });
102135
+ }
102136
+ if (TIMELINE_REGISTRY_ASSIGN_PATTERN.test(source2) && !TIMELINE_REGISTRY_INIT_PATTERN.test(source2)) {
102137
+ findings.push({
102138
+ code: "timeline_registry_missing_init",
102139
+ severity: "error",
102140
+ message: "`window.__timelines[\u2026] = \u2026` is used without initializing `window.__timelines` first.",
102141
+ fixHint: "Add `window.__timelines = window.__timelines || {};` before any timeline assignment."
102142
+ });
102143
+ }
102144
+ return findings;
102145
+ },
102146
+ // timeline_id_mismatch
102147
+ ({ source: source2 }) => {
102148
+ const findings = [];
102048
102149
  const htmlCompIds = /* @__PURE__ */ new Set();
102049
102150
  const timelineRegKeys = /* @__PURE__ */ new Set();
102050
102151
  const compIdRe = /data-composition-id\s*=\s*["']([^"']+)["']/gi;
@@ -102058,7 +102159,7 @@ function lintHyperframeHtml(html, options = {}) {
102058
102159
  }
102059
102160
  for (const key2 of timelineRegKeys) {
102060
102161
  if (!htmlCompIds.has(key2)) {
102061
- pushFinding({
102162
+ findings.push({
102062
102163
  code: "timeline_id_mismatch",
102063
102164
  severity: "error",
102064
102165
  message: `Timeline registered as "${key2}" but no element has data-composition-id="${key2}". The runtime cannot auto-nest this timeline.`,
@@ -102066,261 +102167,194 @@ function lintHyperframeHtml(html, options = {}) {
102066
102167
  });
102067
102168
  }
102068
102169
  }
102069
- }
102070
- if (INVALID_SCRIPT_CLOSE_PATTERN.test(source2)) {
102071
- pushFinding({
102072
- code: "invalid_inline_script_syntax",
102073
- severity: "error",
102074
- message: "Detected malformed inline `<script>` closing syntax.",
102075
- fixHint: "Close inline scripts with a valid `</script>` tag."
102076
- });
102077
- }
102078
- for (const script of scripts) {
102079
- const attrs = script.attrs || "";
102080
- if (/\bsrc\s*=/.test(attrs) || /\btype\s*=\s*["']application\/json["']/.test(attrs)) {
102081
- continue;
102082
- }
102083
- const syntaxError = getInlineScriptSyntaxError(script.content);
102084
- if (!syntaxError) {
102085
- continue;
102086
- }
102087
- pushFinding({
102088
- code: "invalid_inline_script_syntax",
102089
- severity: "error",
102090
- message: `Inline script has invalid syntax: ${syntaxError}`,
102091
- fixHint: "Fix the inline script syntax before render verification.",
102092
- snippet: truncateSnippet(script.content)
102093
- });
102094
- }
102095
- for (const tag of tags) {
102096
- const src = readAttr(tag.raw, "data-composition-src");
102097
- if (!src) {
102098
- continue;
102099
- }
102100
- const compId = readAttr(tag.raw, "data-composition-id");
102101
- if (compId) {
102102
- continue;
102103
- }
102104
- pushFinding({
102105
- code: "host_missing_composition_id",
102106
- severity: "error",
102107
- message: `Composition host for "${src}" is missing \`data-composition-id\`.`,
102108
- elementId: readAttr(tag.raw, "id") || void 0,
102109
- fixHint: "Set `data-composition-id` on every `data-composition-src` host element.",
102110
- snippet: truncateSnippet(tag.raw)
102111
- });
102112
- }
102113
- const scopedCssCompositionIds = /* @__PURE__ */ new Set();
102114
- for (const style of styles) {
102115
- for (const compId of extractCompositionIdsFromCss(style.content)) {
102116
- scopedCssCompositionIds.add(compId);
102117
- }
102118
- }
102119
- for (const compId of scopedCssCompositionIds) {
102120
- if (compositionIds.has(compId)) {
102121
- continue;
102122
- }
102123
- pushFinding({
102124
- code: "scoped_css_missing_wrapper",
102125
- severity: "warning",
102126
- message: `Scoped CSS targets composition "${compId}" but no matching wrapper exists in this HTML.`,
102127
- selector: `[data-composition-id="${compId}"]`,
102128
- fixHint: "Preserve the matching composition wrapper or align the CSS scope to an existing wrapper."
102129
- });
102130
- }
102131
- const mediaById = /* @__PURE__ */ new Map();
102132
- const mediaFingerprintCounts = /* @__PURE__ */ new Map();
102133
- for (const tag of tags) {
102134
- if (!isMediaTag(tag.name)) {
102135
- continue;
102136
- }
102137
- const elementId = readAttr(tag.raw, "id");
102138
- if (elementId) {
102139
- const existing = mediaById.get(elementId) || [];
102140
- existing.push(tag);
102141
- mediaById.set(elementId, existing);
102142
- }
102143
- const fingerprint = [
102144
- tag.name,
102145
- readAttr(tag.raw, "src") || "",
102146
- readAttr(tag.raw, "data-start") || "",
102147
- readAttr(tag.raw, "data-duration") || ""
102148
- ].join("|");
102149
- mediaFingerprintCounts.set(fingerprint, (mediaFingerprintCounts.get(fingerprint) || 0) + 1);
102150
- }
102151
- for (const [elementId, mediaTags] of mediaById) {
102152
- if (mediaTags.length < 2) {
102153
- continue;
102154
- }
102155
- pushFinding({
102156
- code: "duplicate_media_id",
102157
- severity: "error",
102158
- message: `Media id "${elementId}" is defined multiple times.`,
102159
- elementId,
102160
- fixHint: "Give each media element a unique id so preview and producer discover the same media graph.",
102161
- snippet: truncateSnippet(mediaTags[0]?.raw || "")
102162
- });
102163
- }
102164
- for (const [fingerprint, count] of mediaFingerprintCounts) {
102165
- if (count < 2) {
102166
- continue;
102167
- }
102168
- const [tagName19, src, dataStart, dataDuration] = fingerprint.split("|");
102169
- pushFinding({
102170
- code: "duplicate_media_discovery_risk",
102171
- severity: "warning",
102172
- message: `Detected ${count} matching ${tagName19} entries with the same source/start/duration.`,
102173
- fixHint: "Avoid duplicated media nodes that can be discovered twice during compilation.",
102174
- snippet: truncateSnippet(
102175
- `${tagName19} src=${src} data-start=${dataStart} data-duration=${dataDuration}`
102176
- )
102177
- });
102178
- }
102179
- const clipIds = /* @__PURE__ */ new Map();
102180
- const clipClasses = /* @__PURE__ */ new Map();
102181
- for (const tag of tags) {
102182
- const classAttr = readAttr(tag.raw, "class") || "";
102183
- const classes = classAttr.split(/\s+/).filter(Boolean);
102184
- if (!classes.includes("clip")) continue;
102185
- const id = readAttr(tag.raw, "id");
102186
- const info = { tag: tag.name, id: id || "", classes: classAttr };
102187
- if (id) clipIds.set(`#${id}`, info);
102188
- for (const cls of classes) {
102189
- if (cls !== "clip") clipClasses.set(`.${cls}`, info);
102190
- }
102191
- }
102192
- const classUsage = countClassUsage(tags);
102193
- for (const script of scripts) {
102194
- const localTimelineCompId = readRegisteredTimelineCompositionId(script.content);
102195
- const gsapWindows = extractGsapWindows(script.content);
102196
- for (let i = 0; i < gsapWindows.length; i++) {
102197
- const left2 = gsapWindows[i];
102198
- if (!left2) continue;
102199
- if (left2.end <= left2.position) {
102200
- continue;
102201
- }
102202
- for (let j = i + 1; j < gsapWindows.length; j++) {
102203
- const right2 = gsapWindows[j];
102204
- if (!right2) continue;
102205
- if (right2.end <= right2.position) {
102206
- continue;
102207
- }
102208
- if (left2.targetSelector !== right2.targetSelector) {
102209
- continue;
102210
- }
102211
- const overlapStart = Math.max(left2.position, right2.position);
102212
- const overlapEnd = Math.min(left2.end, right2.end);
102213
- if (overlapEnd <= overlapStart) {
102214
- continue;
102215
- }
102216
- if (left2.overwriteAuto || right2.overwriteAuto) {
102217
- continue;
102218
- }
102219
- const sharedProperties = left2.properties.filter((prop2) => right2.properties.includes(prop2));
102220
- if (sharedProperties.length === 0) {
102221
- continue;
102222
- }
102223
- pushFinding({
102224
- code: "overlapping_gsap_tweens",
102225
- severity: "warning",
102226
- message: `GSAP tweens overlap on "${left2.targetSelector}" for ${sharedProperties.join(", ")} between ${overlapStart.toFixed(2)}s and ${overlapEnd.toFixed(2)}s.`,
102227
- selector: left2.targetSelector,
102228
- fixHint: 'Shorten the earlier tween, move the later tween, or add `overwrite: "auto"`.',
102229
- snippet: truncateSnippet(`${left2.raw}
102230
- ${right2.raw}`)
102231
- });
102170
+ return findings;
102171
+ },
102172
+ // invalid_inline_script_syntax (malformed close tag)
102173
+ ({ source: source2 }) => {
102174
+ if (!INVALID_SCRIPT_CLOSE_PATTERN.test(source2)) return [];
102175
+ return [
102176
+ {
102177
+ code: "invalid_inline_script_syntax",
102178
+ severity: "error",
102179
+ message: "Detected malformed inline `<script>` closing syntax.",
102180
+ fixHint: "Close inline scripts with a valid `</script>` tag."
102232
102181
  }
102233
- }
102234
- for (const win of gsapWindows) {
102235
- const sel = win.targetSelector;
102236
- const clipInfo = clipIds.get(sel) || clipClasses.get(sel);
102237
- if (!clipInfo) continue;
102238
- const elDesc = `<${clipInfo.tag}${clipInfo.id ? ` id="${clipInfo.id}"` : ""} class="${clipInfo.classes}">`;
102239
- pushFinding({
102240
- code: "gsap_animates_clip_element",
102182
+ ];
102183
+ },
102184
+ // invalid_inline_script_syntax (JS parse error)
102185
+ ({ scripts }) => {
102186
+ const findings = [];
102187
+ for (const script of scripts) {
102188
+ const attrs = script.attrs || "";
102189
+ if (/\bsrc\s*=/.test(attrs) || /\btype\s*=\s*["']application\/json["']/.test(attrs)) continue;
102190
+ const syntaxError = getInlineScriptSyntaxError(script.content);
102191
+ if (!syntaxError) continue;
102192
+ findings.push({
102193
+ code: "invalid_inline_script_syntax",
102241
102194
  severity: "error",
102242
- message: `GSAP animation targets a clip element. Selector "${sel}" resolves to element ${elDesc}. The framework manages clip visibility \u2014 animate an inner wrapper instead.`,
102243
- selector: sel,
102244
- elementId: clipInfo.id || void 0,
102245
- fixHint: "Wrap content in a child <div> and target that with GSAP.",
102246
- snippet: truncateSnippet(win.raw)
102195
+ message: `Inline script has invalid syntax: ${syntaxError}`,
102196
+ fixHint: "Fix the inline script syntax before render verification.",
102197
+ snippet: truncateSnippet(script.content)
102247
102198
  });
102248
102199
  }
102249
- if (!localTimelineCompId || localTimelineCompId === rootCompositionId) {
102250
- continue;
102200
+ return findings;
102201
+ },
102202
+ // host_missing_composition_id
102203
+ ({ tags }) => {
102204
+ const findings = [];
102205
+ for (const tag of tags) {
102206
+ const src = readAttr(tag.raw, "data-composition-src");
102207
+ if (!src) continue;
102208
+ if (readAttr(tag.raw, "data-composition-id")) continue;
102209
+ findings.push({
102210
+ code: "host_missing_composition_id",
102211
+ severity: "error",
102212
+ message: `Composition host for "${src}" is missing \`data-composition-id\`.`,
102213
+ elementId: readAttr(tag.raw, "id") || void 0,
102214
+ fixHint: "Set `data-composition-id` on every `data-composition-src` host element.",
102215
+ snippet: truncateSnippet(tag.raw)
102216
+ });
102251
102217
  }
102252
- for (const win of gsapWindows) {
102253
- if (!isSuspiciousGlobalSelector(win.targetSelector)) {
102254
- continue;
102255
- }
102256
- const className = getSingleClassSelector(win.targetSelector);
102257
- if (className && (classUsage.get(className) || 0) < 2) {
102258
- continue;
102218
+ return findings;
102219
+ },
102220
+ // scoped_css_missing_wrapper
102221
+ ({ styles, compositionIds }) => {
102222
+ const findings = [];
102223
+ const scopedCssCompositionIds = /* @__PURE__ */ new Set();
102224
+ for (const style of styles) {
102225
+ for (const compId of extractCompositionIdsFromCss(style.content)) {
102226
+ scopedCssCompositionIds.add(compId);
102259
102227
  }
102260
- pushFinding({
102261
- code: "unscoped_gsap_selector",
102228
+ }
102229
+ for (const compId of scopedCssCompositionIds) {
102230
+ if (compositionIds.has(compId)) continue;
102231
+ findings.push({
102232
+ code: "scoped_css_missing_wrapper",
102262
102233
  severity: "warning",
102263
- message: `Timeline "${localTimelineCompId}" uses unscoped selector "${win.targetSelector}" that will target elements in ALL compositions when bundled, causing data loss (opacity, transforms, etc.).`,
102264
- selector: win.targetSelector,
102265
- fixHint: `Scope the selector: \`[data-composition-id="${localTimelineCompId}"] ${win.targetSelector}\` or use a unique id.`,
102266
- snippet: truncateSnippet(win.raw)
102234
+ message: `Scoped CSS targets composition "${compId}" but no matching wrapper exists in this HTML.`,
102235
+ selector: `[data-composition-id="${compId}"]`,
102236
+ fixHint: "Preserve the matching composition wrapper or align the CSS scope to an existing wrapper."
102267
102237
  });
102268
102238
  }
102239
+ return findings;
102269
102240
  }
102270
- for (const tag of tags) {
102271
- if (tag.name !== "video") continue;
102272
- const hasMuted = /\bmuted\b/i.test(tag.raw);
102273
- if (!hasMuted && readAttr(tag.raw, "data-start")) {
102274
- const elementId = readAttr(tag.raw, "id") || void 0;
102275
- pushFinding({
102276
- code: "video_missing_muted",
102241
+ ];
102242
+
102243
+ // ../core/src/lint/rules/media.ts
102244
+ var mediaRules = [
102245
+ // duplicate_media_id + duplicate_media_discovery_risk
102246
+ ({ tags }) => {
102247
+ const findings = [];
102248
+ const mediaById = /* @__PURE__ */ new Map();
102249
+ const mediaFingerprintCounts = /* @__PURE__ */ new Map();
102250
+ for (const tag of tags) {
102251
+ if (!isMediaTag(tag.name)) continue;
102252
+ const elementId = readAttr(tag.raw, "id");
102253
+ if (elementId) {
102254
+ const existing = mediaById.get(elementId) || [];
102255
+ existing.push(tag);
102256
+ mediaById.set(elementId, existing);
102257
+ }
102258
+ const fingerprint = [
102259
+ tag.name,
102260
+ readAttr(tag.raw, "src") || "",
102261
+ readAttr(tag.raw, "data-start") || "",
102262
+ readAttr(tag.raw, "data-duration") || ""
102263
+ ].join("|");
102264
+ mediaFingerprintCounts.set(fingerprint, (mediaFingerprintCounts.get(fingerprint) || 0) + 1);
102265
+ }
102266
+ for (const [elementId, mediaTags] of mediaById) {
102267
+ if (mediaTags.length < 2) continue;
102268
+ findings.push({
102269
+ code: "duplicate_media_id",
102277
102270
  severity: "error",
102278
- message: `<video${elementId ? ` id="${elementId}"` : ""}> has data-start but is not muted. The framework expects video to be muted with a separate <audio> element for sound.`,
102271
+ message: `Media id "${elementId}" is defined multiple times.`,
102279
102272
  elementId,
102280
- fixHint: "Add the `muted` attribute to the <video> tag and use a separate <audio> element with the same src for audio playback.",
102281
- snippet: truncateSnippet(tag.raw)
102273
+ fixHint: "Give each media element a unique id so preview and producer discover the same media graph.",
102274
+ snippet: truncateSnippet(mediaTags[0]?.raw || "")
102282
102275
  });
102283
102276
  }
102284
- }
102285
- const timedTagPositions = [];
102286
- for (const tag of tags) {
102287
- if (tag.name === "video" || tag.name === "audio") continue;
102288
- if (readAttr(tag.raw, "data-start")) {
102289
- timedTagPositions.push({
102290
- name: tag.name,
102291
- start: tag.index,
102292
- id: readAttr(tag.raw, "id") || void 0
102277
+ for (const [fingerprint, count] of mediaFingerprintCounts) {
102278
+ if (count < 2) continue;
102279
+ const [tagName19, src, dataStart, dataDuration] = fingerprint.split("|");
102280
+ findings.push({
102281
+ code: "duplicate_media_discovery_risk",
102282
+ severity: "warning",
102283
+ message: `Detected ${count} matching ${tagName19} entries with the same source/start/duration.`,
102284
+ fixHint: "Avoid duplicated media nodes that can be discovered twice during compilation.",
102285
+ snippet: truncateSnippet(
102286
+ `${tagName19} src=${src} data-start=${dataStart} data-duration=${dataDuration}`
102287
+ )
102293
102288
  });
102294
102289
  }
102295
- }
102296
- for (const tag of tags) {
102297
- if (tag.name !== "video") continue;
102298
- if (!readAttr(tag.raw, "data-start")) continue;
102299
- for (const parent of timedTagPositions) {
102300
- if (parent.start < tag.index) {
102301
- const parentClosePattern = new RegExp(`</${parent.name}>`, "gi");
102302
- const between = source2.substring(parent.start, tag.index);
102303
- if (!parentClosePattern.test(between)) {
102304
- pushFinding({
102305
- code: "video_nested_in_timed_element",
102306
- severity: "error",
102307
- message: `<video> with data-start is nested inside <${parent.name}${parent.id ? ` id="${parent.id}"` : ""}> which also has data-start. The framework cannot manage playback of nested media \u2014 video will be FROZEN in renders.`,
102308
- elementId: readAttr(tag.raw, "id") || void 0,
102309
- fixHint: "Move the <video> to be a direct child of the stage, or remove data-start from the wrapper div (use it as a non-timed visual container).",
102310
- snippet: truncateSnippet(tag.raw)
102311
- });
102312
- break;
102290
+ return findings;
102291
+ },
102292
+ // video_missing_muted
102293
+ ({ tags }) => {
102294
+ const findings = [];
102295
+ for (const tag of tags) {
102296
+ if (tag.name !== "video") continue;
102297
+ const hasMuted = /\bmuted\b/i.test(tag.raw);
102298
+ if (!hasMuted && readAttr(tag.raw, "data-start")) {
102299
+ const elementId = readAttr(tag.raw, "id") || void 0;
102300
+ findings.push({
102301
+ code: "video_missing_muted",
102302
+ severity: "error",
102303
+ message: `<video${elementId ? ` id="${elementId}"` : ""}> has data-start but is not muted. The framework expects video to be muted with a separate <audio> element for sound.`,
102304
+ elementId,
102305
+ fixHint: "Add the `muted` attribute to the <video> tag and use a separate <audio> element with the same src for audio playback.",
102306
+ snippet: truncateSnippet(tag.raw)
102307
+ });
102308
+ }
102309
+ }
102310
+ return findings;
102311
+ },
102312
+ // video_nested_in_timed_element
102313
+ ({ source: source2, tags }) => {
102314
+ const findings = [];
102315
+ const timedTagPositions = [];
102316
+ for (const tag of tags) {
102317
+ if (tag.name === "video" || tag.name === "audio") continue;
102318
+ if (readAttr(tag.raw, "data-start")) {
102319
+ timedTagPositions.push({
102320
+ name: tag.name,
102321
+ start: tag.index,
102322
+ id: readAttr(tag.raw, "id") || void 0
102323
+ });
102324
+ }
102325
+ }
102326
+ for (const tag of tags) {
102327
+ if (tag.name !== "video") continue;
102328
+ if (!readAttr(tag.raw, "data-start")) continue;
102329
+ for (const parent of timedTagPositions) {
102330
+ if (parent.start < tag.index) {
102331
+ const parentClosePattern = new RegExp(`</${parent.name}>`, "gi");
102332
+ const between = source2.substring(parent.start, tag.index);
102333
+ if (!parentClosePattern.test(between)) {
102334
+ findings.push({
102335
+ code: "video_nested_in_timed_element",
102336
+ severity: "error",
102337
+ message: `<video> with data-start is nested inside <${parent.name}${parent.id ? ` id="${parent.id}"` : ""}> which also has data-start. The framework cannot manage playback of nested media \u2014 video will be FROZEN in renders.`,
102338
+ elementId: readAttr(tag.raw, "id") || void 0,
102339
+ fixHint: "Move the <video> to be a direct child of the stage, or remove data-start from the wrapper div (use it as a non-timed visual container).",
102340
+ snippet: truncateSnippet(tag.raw)
102341
+ });
102342
+ break;
102343
+ }
102313
102344
  }
102314
102345
  }
102315
102346
  }
102316
- }
102317
- {
102347
+ return findings;
102348
+ },
102349
+ // self_closing_media_tag
102350
+ ({ source: source2 }) => {
102351
+ const findings = [];
102318
102352
  const selfClosingMediaRe = /<(audio|video)\b[^>]*\/>/gi;
102319
102353
  let scMatch;
102320
102354
  while ((scMatch = selfClosingMediaRe.exec(source2)) !== null) {
102321
102355
  const tagName19 = scMatch[1] || "audio";
102322
102356
  const elementId = readAttr(scMatch[0], "id") || void 0;
102323
- pushFinding({
102357
+ findings.push({
102324
102358
  code: "self_closing_media_tag",
102325
102359
  severity: "error",
102326
102360
  message: `Self-closing <${tagName19}/> is invalid HTML. The browser will leave the tag open, swallowing all subsequent elements as invisible fallback content. This makes compositions INVISIBLE.`,
@@ -102329,8 +102363,11 @@ ${right2.raw}`)
102329
102363
  snippet: truncateSnippet(scMatch[0])
102330
102364
  });
102331
102365
  }
102332
- }
102333
- {
102366
+ return findings;
102367
+ },
102368
+ // placeholder_media_url
102369
+ ({ tags }) => {
102370
+ const findings = [];
102334
102371
  const PLACEHOLDER_DOMAINS = /\b(placehold\.co|placeholder\.com|placekitten\.com|picsum\.photos|example\.com|via\.placeholder\.com|dummyimage\.com)\b/i;
102335
102372
  for (const tag of tags) {
102336
102373
  if (!isMediaTag(tag.name)) continue;
@@ -102338,7 +102375,7 @@ ${right2.raw}`)
102338
102375
  if (!src) continue;
102339
102376
  if (PLACEHOLDER_DOMAINS.test(src)) {
102340
102377
  const elementId = readAttr(tag.raw, "id") || void 0;
102341
- pushFinding({
102378
+ findings.push({
102342
102379
  code: "placeholder_media_url",
102343
102380
  severity: "error",
102344
102381
  message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> uses a placeholder URL that will 404 at render time: ${src.slice(0, 80)}`,
@@ -102348,8 +102385,11 @@ ${right2.raw}`)
102348
102385
  });
102349
102386
  }
102350
102387
  }
102351
- }
102352
- {
102388
+ return findings;
102389
+ },
102390
+ // base64_media_prohibited
102391
+ ({ source: source2 }) => {
102392
+ const findings = [];
102353
102393
  const base64MediaRe = /src\s*=\s*["'](data:(?:audio|video)\/[^;]+;base64,([A-Za-z0-9+/=]{20,}))["']/gi;
102354
102394
  let b64Match;
102355
102395
  while ((b64Match = base64MediaRe.exec(source2)) !== null) {
@@ -102357,7 +102397,7 @@ ${right2.raw}`)
102357
102397
  const uniqueChars = new Set(sample.replace(/[A-Za-z0-9+/=]/g, (c) => c)).size;
102358
102398
  const dataSize = Math.round((b64Match[2] || "").length * 3 / 4);
102359
102399
  const isSuspicious = uniqueChars < 15 || dataSize > 1e3 && dataSize < 5e4;
102360
- pushFinding({
102400
+ findings.push({
102361
102401
  code: "base64_media_prohibited",
102362
102402
  severity: "error",
102363
102403
  message: `Inline base64 audio/video detected (${(dataSize / 1024).toFixed(0)} KB)${isSuspicious ? " \u2014 likely fabricated data" : ""}. Base64 media is prohibited \u2014 it bloats file size and breaks rendering.`,
@@ -102365,331 +102405,57 @@ ${right2.raw}`)
102365
102405
  snippet: truncateSnippet((b64Match[1] ?? "").slice(0, 80) + "...")
102366
102406
  });
102367
102407
  }
102368
- }
102369
- for (const tag of tags) {
102370
- if (tag.name !== "video" && tag.name !== "audio") continue;
102371
- const hasDataStart = readAttr(tag.raw, "data-start");
102372
- const hasId = readAttr(tag.raw, "id");
102373
- const hasSrc = readAttr(tag.raw, "src");
102374
- if (hasDataStart && !hasId) {
102375
- pushFinding({
102376
- code: "media_missing_id",
102377
- severity: "error",
102378
- message: `<${tag.name}> has data-start but no id attribute. The renderer requires id to discover media elements \u2014 this ${tag.name === "audio" ? "audio will be SILENT" : "video will be FROZEN"} in renders.`,
102379
- fixHint: `Add a unique id attribute: <${tag.name} id="my-${tag.name}" ...>`,
102380
- snippet: truncateSnippet(tag.raw)
102381
- });
102382
- }
102383
- if (hasDataStart && hasId && !hasSrc) {
102384
- pushFinding({
102385
- code: "media_missing_src",
102386
- severity: "error",
102387
- message: `<${tag.name} id="${hasId}"> has data-start but no src attribute. The renderer cannot load this media.`,
102388
- elementId: hasId,
102389
- fixHint: `Add a src attribute to the <${tag.name}> element directly. If using <source> children, the renderer still requires src on the parent element.`,
102390
- snippet: truncateSnippet(tag.raw)
102391
- });
102392
- }
102393
- if (readAttr(tag.raw, "preload") === "none") {
102394
- pushFinding({
102395
- code: "media_preload_none",
102396
- severity: "warning",
102397
- message: `<${tag.name}${hasId ? ` id="${hasId}"` : ""}> has preload="none" which prevents the renderer from loading this media. The compiler strips it for renders, but preview may also have issues.`,
102398
- elementId: hasId || void 0,
102399
- fixHint: `Remove preload="none" or change to preload="auto". The framework manages media loading.`,
102400
- snippet: truncateSnippet(tag.raw)
102401
- });
102402
- }
102403
- }
102404
- for (const tag of tags) {
102405
- if (tag.name === "audio" || tag.name === "script" || tag.name === "style") continue;
102406
- if (!readAttr(tag.raw, "data-start")) continue;
102407
- if (readAttr(tag.raw, "data-composition-id")) continue;
102408
- if (readAttr(tag.raw, "data-composition-src")) continue;
102409
- const classAttr = readAttr(tag.raw, "class") || "";
102410
- const styleAttr = readAttr(tag.raw, "style") || "";
102411
- const hasClip = classAttr.split(/\s+/).includes("clip");
102412
- const hasHiddenStyle = /visibility\s*:\s*hidden/i.test(styleAttr) || /opacity\s*:\s*0/i.test(styleAttr);
102413
- if (!hasClip && !hasHiddenStyle) {
102414
- const elementId = readAttr(tag.raw, "id") || void 0;
102415
- pushFinding({
102416
- code: "timed_element_missing_visibility_hidden",
102417
- severity: "info",
102418
- message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> has data-start but no class="clip", visibility:hidden, or opacity:0. Consider adding initial hidden state if the element should not be visible before its start time.`,
102419
- elementId,
102420
- fixHint: 'Add class="clip" (with CSS: .clip { visibility: hidden; }) or style="opacity:0" if the element should start hidden.',
102421
- snippet: truncateSnippet(tag.raw)
102422
- });
102423
- }
102424
- }
102425
- for (const tag of tags) {
102426
- if (readAttr(tag.raw, "data-layer") && !readAttr(tag.raw, "data-track-index")) {
102427
- const elementId = readAttr(tag.raw, "id") || void 0;
102428
- pushFinding({
102429
- code: "deprecated_data_layer",
102430
- severity: "warning",
102431
- message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> uses data-layer instead of data-track-index.`,
102432
- elementId,
102433
- fixHint: "Replace data-layer with data-track-index. The runtime reads data-track-index.",
102434
- snippet: truncateSnippet(tag.raw)
102435
- });
102436
- }
102437
- if (readAttr(tag.raw, "data-end") && !readAttr(tag.raw, "data-duration")) {
102438
- const elementId = readAttr(tag.raw, "id") || void 0;
102439
- pushFinding({
102440
- code: "deprecated_data_end",
102441
- severity: "warning",
102442
- message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> uses data-end without data-duration. Use data-duration in source HTML.`,
102443
- elementId,
102444
- fixHint: "Replace data-end with data-duration. The compiler generates data-end from data-duration automatically.",
102445
- snippet: truncateSnippet(tag.raw)
102446
- });
102447
- }
102448
- }
102449
- for (const script of scripts) {
102450
- const templateLiteralSelectorPattern = /(?:querySelector|querySelectorAll)\s*\(\s*`[^`]*\$\{[^}]+\}[^`]*`\s*\)/g;
102451
- let tlMatch;
102452
- while ((tlMatch = templateLiteralSelectorPattern.exec(script.content)) !== null) {
102453
- pushFinding({
102454
- code: "template_literal_selector",
102455
- severity: "error",
102456
- message: "querySelector uses a template literal variable (e.g. `${compId}`). The HTML bundler's CSS parser crashes on these. Use a hardcoded string instead.",
102457
- file: filePath,
102458
- fixHint: "Replace the template literal variable with a hardcoded string. The bundler's CSS parser cannot handle interpolated variables in script content.",
102459
- snippet: truncateSnippet(tlMatch[0])
102460
- });
102461
- }
102462
- }
102463
- {
102464
- const cssTranslateSelectors = /* @__PURE__ */ new Map();
102465
- const cssScaleSelectors = /* @__PURE__ */ new Map();
102466
- for (const style of styles) {
102467
- for (const [, selector, body] of style.content.matchAll(
102468
- /([#.][a-zA-Z0-9_-]+)\s*\{([^}]+)\}/g
102469
- )) {
102470
- const tMatch = body?.match(/transform\s*:\s*([^;]+)/);
102471
- if (!tMatch || !tMatch[1]) continue;
102472
- const transformVal = tMatch[1].trim();
102473
- if (/translate/i.test(transformVal)) {
102474
- cssTranslateSelectors.set((selector ?? "").trim(), transformVal);
102475
- }
102476
- if (/scale/i.test(transformVal)) {
102477
- cssScaleSelectors.set((selector ?? "").trim(), transformVal);
102478
- }
102479
- }
102480
- }
102481
- if (cssTranslateSelectors.size > 0 || cssScaleSelectors.size > 0) {
102482
- for (const script of scripts) {
102483
- if (!/gsap\.timeline/.test(script.content)) continue;
102484
- const windows = extractGsapWindows(script.content);
102485
- const conflicts = /* @__PURE__ */ new Map();
102486
- for (const win of windows) {
102487
- if (win.method === "fromTo") continue;
102488
- const sel = win.targetSelector;
102489
- const cssKey = sel.startsWith("#") || sel.startsWith(".") ? sel : `#${sel}`;
102490
- const translateProps = win.properties.filter(
102491
- (p) => ["x", "y", "xPercent", "yPercent"].includes(p)
102492
- );
102493
- const scaleProps = win.properties.filter((p) => p === "scale");
102494
- const cssFromTranslate = translateProps.length > 0 ? cssTranslateSelectors.get(cssKey) : void 0;
102495
- const cssFromScale = scaleProps.length > 0 ? cssScaleSelectors.get(cssKey) : void 0;
102496
- if (!cssFromTranslate && !cssFromScale) continue;
102497
- const existing = conflicts.get(sel) ?? {
102498
- cssTransform: [cssFromTranslate, cssFromScale].filter(Boolean).join(" "),
102499
- props: /* @__PURE__ */ new Set(),
102500
- raw: win.raw
102501
- };
102502
- for (const p of [...translateProps, ...scaleProps]) existing.props.add(p);
102503
- conflicts.set(sel, existing);
102504
- }
102505
- for (const [sel, { cssTransform, props, raw: raw2 }] of conflicts) {
102506
- const propList = [...props].join("/");
102507
- pushFinding({
102508
- code: "gsap_css_transform_conflict",
102509
- severity: "warning",
102510
- message: `"${sel}" has CSS \`transform: ${cssTransform}\` and a GSAP tween animates ${propList}. GSAP will overwrite the full CSS transform, discarding any translateX(-50%) centering or CSS scale value.`,
102511
- selector: sel,
102512
- fixHint: `Remove the transform from CSS and use tl.fromTo('${sel}', { xPercent: -50, x: -1000 }, { xPercent: -50, x: 0 }) so GSAP owns the full transform state. tl.fromTo is exempt from this rule.`,
102513
- snippet: truncateSnippet(raw2)
102514
- });
102515
- }
102408
+ return findings;
102409
+ },
102410
+ // media_missing_id + media_missing_src + media_preload_none
102411
+ ({ tags }) => {
102412
+ const findings = [];
102413
+ for (const tag of tags) {
102414
+ if (tag.name !== "video" && tag.name !== "audio") continue;
102415
+ const hasDataStart = readAttr(tag.raw, "data-start");
102416
+ const hasId = readAttr(tag.raw, "id");
102417
+ const hasSrc = readAttr(tag.raw, "src");
102418
+ if (hasDataStart && !hasId) {
102419
+ findings.push({
102420
+ code: "media_missing_id",
102421
+ severity: "error",
102422
+ message: `<${tag.name}> has data-start but no id attribute. The renderer requires id to discover media elements \u2014 this ${tag.name === "audio" ? "audio will be SILENT" : "video will be FROZEN"} in renders.`,
102423
+ fixHint: `Add a unique id attribute: <${tag.name} id="my-${tag.name}" ...>`,
102424
+ snippet: truncateSnippet(tag.raw)
102425
+ });
102516
102426
  }
102517
- }
102518
- }
102519
- for (const script of scripts) {
102520
- const content = script.content;
102521
- const hasExitTween = /\.to\s*\([^,]+,\s*\{[^}]*opacity\s*:\s*0/.test(content);
102522
- const hasHardKill = /\.set\s*\([^,]+,\s*\{[^}]*(?:visibility\s*:\s*["']hidden["']|opacity\s*:\s*0)/.test(content);
102523
- const hasCaptionLoop = /forEach|\.forEach\s*\(/.test(content) && /createElement|caption|group|cg-/.test(content);
102524
- if (hasCaptionLoop && hasExitTween && !hasHardKill) {
102525
- pushFinding({
102526
- code: "caption_exit_missing_hard_kill",
102527
- severity: "warning",
102528
- message: "Caption exit animations (tl.to with opacity: 0) detected without a hard tl.set kill. Exit tweens can fail when karaoke word-level tweens conflict, leaving captions stuck on screen.",
102529
- fixHint: 'Add `tl.set(groupEl, { opacity: 0, visibility: "hidden" }, group.end)` after every exit tl.to animation as a deterministic kill.'
102530
- });
102531
- }
102532
- }
102533
- for (const style of styles) {
102534
- const content = style.content;
102535
- const captionBlocks = content.matchAll(
102536
- /(\.caption[-_]?(?:group|container|text|line|word)|#caption[-_]?container)\s*\{([^}]+)\}/gi
102537
- );
102538
- for (const [, selector, body] of captionBlocks) {
102539
- if (!body) continue;
102540
- const hasNowrap = /white-space\s*:\s*nowrap/i.test(body);
102541
- const hasMaxWidth = /max-width/i.test(body);
102542
- if (hasNowrap && !hasMaxWidth) {
102543
- pushFinding({
102544
- code: "caption_text_overflow_risk",
102545
- severity: "warning",
102546
- selector: (selector ?? "").trim(),
102547
- message: `Caption selector "${(selector ?? "").trim()}" has white-space: nowrap but no max-width. Long phrases will clip off-screen.`,
102548
- fixHint: "Add max-width: 1600px (landscape) or max-width: 900px (portrait) and overflow: hidden."
102427
+ if (hasDataStart && hasId && !hasSrc) {
102428
+ findings.push({
102429
+ code: "media_missing_src",
102430
+ severity: "error",
102431
+ message: `<${tag.name} id="${hasId}"> has data-start but no src attribute. The renderer cannot load this media.`,
102432
+ elementId: hasId,
102433
+ fixHint: `Add a src attribute to the <${tag.name}> element directly. If using <source> children, the renderer still requires src on the parent element.`,
102434
+ snippet: truncateSnippet(tag.raw)
102549
102435
  });
102550
102436
  }
102551
- }
102552
- }
102553
- for (const style of styles) {
102554
- const content = style.content;
102555
- const captionBlocks = content.matchAll(
102556
- /(\.caption[-_]?(?:group|container|text|line)|#caption[-_]?container)\s*\{([^}]+)\}/gi
102557
- );
102558
- for (const [, selector, body] of captionBlocks) {
102559
- if (!body) continue;
102560
- if (/position\s*:\s*relative/i.test(body)) {
102561
- pushFinding({
102562
- code: "caption_container_relative_position",
102437
+ if (readAttr(tag.raw, "preload") === "none") {
102438
+ findings.push({
102439
+ code: "media_preload_none",
102563
102440
  severity: "warning",
102564
- selector: (selector ?? "").trim(),
102565
- message: `Caption selector "${(selector ?? "").trim()}" uses position: relative which causes overflow and breaks caption stacking.`,
102566
- fixHint: "Use position: absolute for all caption elements."
102441
+ message: `<${tag.name}${hasId ? ` id="${hasId}"` : ""}> has preload="none" which prevents the renderer from loading this media. The compiler strips it for renders, but preview may also have issues.`,
102442
+ elementId: hasId || void 0,
102443
+ fixHint: `Remove preload="none" or change to preload="auto". The framework manages media loading.`,
102444
+ snippet: truncateSnippet(tag.raw)
102567
102445
  });
102568
102446
  }
102569
102447
  }
102448
+ return findings;
102570
102449
  }
102571
- {
102572
- const externalScriptRe = /<script\b[^>]*\bsrc=["'](https?:\/\/[^"']+)["'][^>]*>/gi;
102573
- let match2;
102574
- const seen2 = /* @__PURE__ */ new Set();
102575
- while ((match2 = externalScriptRe.exec(source2)) !== null) {
102576
- const src = match2[1] ?? "";
102577
- if (seen2.has(src)) continue;
102578
- seen2.add(src);
102579
- pushFinding({
102580
- code: "external_script_dependency",
102581
- severity: "info",
102582
- message: `This composition loads an external script from \`${src}\`. The HyperFrames bundler automatically hoists CDN scripts from sub-compositions into the parent document. In unbundled runtime mode, \`loadExternalCompositions\` re-injects them. If you're using a custom pipeline that bypasses both, you'll need to include this script manually.`,
102583
- fixHint: "No action needed when using `hyperframes dev` or `hyperframes render`. If using a custom pipeline, add this script tag to your root composition or HTML page.",
102584
- snippet: truncateSnippet(match2[0] ?? "")
102585
- });
102586
- }
102587
- }
102588
- const errorCount = findings.filter((finding) => finding.severity === "error").length;
102589
- const warningCount = findings.filter((finding) => finding.severity === "warning").length;
102590
- const infoCount = findings.filter((finding) => finding.severity === "info").length;
102591
- return {
102592
- ok: errorCount === 0,
102593
- errorCount,
102594
- warningCount,
102595
- infoCount,
102596
- findings
102597
- };
102598
- }
102599
- function extractOpenTags(source2) {
102600
- const tags = [];
102601
- let match2;
102602
- while ((match2 = TAG_PATTERN.exec(source2)) !== null) {
102603
- const raw2 = match2[0];
102604
- if (raw2.startsWith("</") || raw2.startsWith("<!")) {
102605
- continue;
102606
- }
102607
- tags.push({
102608
- raw: raw2,
102609
- name: (match2[1] || "").toLowerCase(),
102610
- attrs: match2[2] || "",
102611
- index: match2.index
102612
- });
102613
- }
102614
- return tags;
102615
- }
102616
- function extractBlocks(source2, pattern) {
102617
- const blocks = [];
102618
- let match2;
102619
- while ((match2 = pattern.exec(source2)) !== null) {
102620
- blocks.push({
102621
- attrs: match2[1] || "",
102622
- content: match2[2] || "",
102623
- raw: match2[0],
102624
- index: match2.index
102625
- });
102626
- }
102627
- return blocks;
102628
- }
102629
- function findRootTag(source2) {
102630
- const bodyMatch = source2.match(/<body\b[^>]*>([\s\S]*?)<\/body>/i);
102631
- const bodyContent = bodyMatch ? bodyMatch[1] ?? source2 : source2;
102632
- const bodyTags = extractOpenTags(bodyContent);
102633
- for (const tag of bodyTags) {
102634
- if (["script", "style", "meta", "link", "title"].includes(tag.name)) {
102635
- continue;
102636
- }
102637
- return tag;
102638
- }
102639
- return null;
102640
- }
102641
- function readAttr(tagSource, attr) {
102642
- if (!tagSource) {
102643
- return null;
102644
- }
102645
- const escaped = attr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
102646
- const match2 = tagSource.match(new RegExp(`\\b${escaped}\\s*=\\s*["']([^"']+)["']`, "i"));
102647
- return match2?.[1] || null;
102648
- }
102649
- function collectCompositionIds(tags) {
102650
- const ids = /* @__PURE__ */ new Set();
102651
- for (const tag of tags) {
102652
- const compId = readAttr(tag.raw, "data-composition-id");
102653
- if (compId) {
102654
- ids.add(compId);
102655
- }
102656
- }
102657
- return ids;
102658
- }
102659
- function extractCompositionIdsFromCss(css) {
102660
- const ids = /* @__PURE__ */ new Set();
102661
- let match2;
102662
- while ((match2 = COMPOSITION_ID_IN_CSS_PATTERN.exec(css)) !== null) {
102663
- if (match2[1]) {
102664
- ids.add(match2[1]);
102665
- }
102666
- }
102667
- return [...ids];
102668
- }
102669
- function getInlineScriptSyntaxError(source2) {
102670
- if (!source2.trim()) {
102671
- return null;
102672
- }
102673
- try {
102674
- new Function(source2);
102675
- return null;
102676
- } catch (error) {
102677
- if (error instanceof Error) {
102678
- return error.message;
102679
- }
102680
- return String(error);
102681
- }
102682
- }
102683
- function isMediaTag(tagName19) {
102684
- return tagName19 === "video" || tagName19 === "audio" || tagName19 === "img";
102685
- }
102450
+ ];
102451
+
102452
+ // ../core/src/lint/rules/gsap.ts
102453
+ var META_GSAP_KEYS = /* @__PURE__ */ new Set(["duration", "ease", "repeat", "yoyo", "overwrite", "delay"]);
102686
102454
  function countClassUsage(tags) {
102687
102455
  const counts = /* @__PURE__ */ new Map();
102688
102456
  for (const tag of tags) {
102689
102457
  const classAttr = readAttr(tag.raw, "class");
102690
- if (!classAttr) {
102691
- continue;
102692
- }
102458
+ if (!classAttr) continue;
102693
102459
  for (const className of classAttr.split(/\s+/).filter(Boolean)) {
102694
102460
  counts.set(className, (counts.get(className) || 0) + 1);
102695
102461
  }
@@ -102701,13 +102467,9 @@ function readRegisteredTimelineCompositionId(script) {
102701
102467
  return match2?.[1] || null;
102702
102468
  }
102703
102469
  function extractGsapWindows(script) {
102704
- if (!/gsap\.timeline/.test(script)) {
102705
- return [];
102706
- }
102470
+ if (!/gsap\.timeline/.test(script)) return [];
102707
102471
  const parsed = parseGsapScript(script);
102708
- if (parsed.animations.length === 0) {
102709
- return [];
102710
- }
102472
+ if (parsed.animations.length === 0) return [];
102711
102473
  const windows = [];
102712
102474
  const timelineVar = parsed.timelineVar;
102713
102475
  const methodPattern = new RegExp(
@@ -102721,9 +102483,7 @@ function extractGsapWindows(script) {
102721
102483
  const meta = parseGsapWindowMeta(match2[1] ?? "", match2[2] ?? "");
102722
102484
  const animation = parsed.animations[index];
102723
102485
  index += 1;
102724
- if (!animation) {
102725
- continue;
102726
- }
102486
+ if (!animation) continue;
102727
102487
  windows.push({
102728
102488
  targetSelector: animation.targetSelector,
102729
102489
  position: animation.position,
@@ -102738,9 +102498,7 @@ function extractGsapWindows(script) {
102738
102498
  }
102739
102499
  function parseGsapWindowMeta(method, argsStr) {
102740
102500
  const selectorMatch = argsStr.match(/^\s*["']([^"']+)["']\s*,/);
102741
- if (!selectorMatch) {
102742
- return { effectiveDuration: 0, properties: [], overwriteAuto: false };
102743
- }
102501
+ if (!selectorMatch) return { effectiveDuration: 0, properties: [], overwriteAuto: false };
102744
102502
  const afterSelector = argsStr.slice(selectorMatch[0].length);
102745
102503
  let properties = {};
102746
102504
  let fromProperties = {};
@@ -102765,20 +102523,15 @@ function parseGsapWindowMeta(method, argsStr) {
102765
102523
  }
102766
102524
  const duration = numberValue(properties.duration) || 0;
102767
102525
  const repeat = numberValue(properties.repeat) || 0;
102768
- const yoyo = stringValue(properties.yoyo) === "true";
102769
102526
  const cycleCount = repeat > 0 ? repeat + 1 : 1;
102770
- const effectiveDuration = duration * cycleCount * (yoyo ? 1 : 1);
102527
+ const effectiveDuration = duration * cycleCount;
102771
102528
  const overwriteAuto = stringValue(properties.overwrite) === "auto";
102772
102529
  const propertyNames = /* @__PURE__ */ new Set();
102773
102530
  for (const key2 of Object.keys(fromProperties)) {
102774
- if (!META_GSAP_KEYS.has(key2)) {
102775
- propertyNames.add(key2);
102776
- }
102531
+ if (!META_GSAP_KEYS.has(key2)) propertyNames.add(key2);
102777
102532
  }
102778
102533
  for (const key2 of Object.keys(properties)) {
102779
- if (!META_GSAP_KEYS.has(key2)) {
102780
- propertyNames.add(key2);
102781
- }
102534
+ if (!META_GSAP_KEYS.has(key2)) propertyNames.add(key2);
102782
102535
  }
102783
102536
  return {
102784
102537
  effectiveDuration: method === "set" ? 0 : effectiveDuration,
@@ -102789,17 +102542,13 @@ function parseGsapWindowMeta(method, argsStr) {
102789
102542
  function parseLooseObjectLiteral(source2) {
102790
102543
  const result = {};
102791
102544
  const cleaned = source2.replace(/^\{|\}$/g, "").trim();
102792
- if (!cleaned) {
102793
- return result;
102794
- }
102545
+ if (!cleaned) return result;
102795
102546
  const propertyPattern = /(\w+)\s*:\s*("[^"]*"|'[^']*'|true|false|-?[\d.]+|[a-zA-Z_][\w.]*)/g;
102796
102547
  let match2;
102797
102548
  while ((match2 = propertyPattern.exec(cleaned)) !== null) {
102798
102549
  const key2 = match2[1];
102799
102550
  const rawValue = match2[2];
102800
- if (!key2 || rawValue == null) {
102801
- continue;
102802
- }
102551
+ if (!key2 || rawValue == null) continue;
102803
102552
  if (rawValue.startsWith('"') && rawValue.endsWith('"') || rawValue.startsWith("'") && rawValue.endsWith("'")) {
102804
102553
  result[key2] = rawValue.slice(1, -1);
102805
102554
  continue;
@@ -102810,26 +102559,19 @@ function parseLooseObjectLiteral(source2) {
102810
102559
  return result;
102811
102560
  }
102812
102561
  function findMatchingBrace2(source2, startIndex) {
102813
- if (startIndex < 0) {
102814
- return -1;
102815
- }
102562
+ if (startIndex < 0) return -1;
102816
102563
  let depth = 0;
102817
102564
  for (let i = startIndex; i < source2.length; i++) {
102818
- if (source2[i] === "{") {
102819
- depth += 1;
102820
- } else if (source2[i] === "}") {
102565
+ if (source2[i] === "{") depth += 1;
102566
+ else if (source2[i] === "}") {
102821
102567
  depth -= 1;
102822
- if (depth === 0) {
102823
- return i;
102824
- }
102568
+ if (depth === 0) return i;
102825
102569
  }
102826
102570
  }
102827
102571
  return -1;
102828
102572
  }
102829
102573
  function numberValue(value) {
102830
- if (typeof value === "number") {
102831
- return value;
102832
- }
102574
+ if (typeof value === "number") return value;
102833
102575
  if (typeof value === "string" && value.trim()) {
102834
102576
  const numeric = Number(value);
102835
102577
  return Number.isFinite(numeric) ? numeric : null;
@@ -102837,39 +102579,451 @@ function numberValue(value) {
102837
102579
  return null;
102838
102580
  }
102839
102581
  function stringValue(value) {
102840
- if (typeof value === "string") {
102841
- return value;
102842
- }
102843
- if (typeof value === "number") {
102844
- return String(value);
102845
- }
102582
+ if (typeof value === "string") return value;
102583
+ if (typeof value === "number") return String(value);
102846
102584
  return null;
102847
102585
  }
102848
102586
  function isSuspiciousGlobalSelector(selector) {
102849
- if (!selector) {
102850
- return false;
102851
- }
102852
- if (selector.includes("[data-composition-id=")) {
102853
- return false;
102854
- }
102855
- if (selector.startsWith("#")) {
102856
- return false;
102857
- }
102587
+ if (!selector) return false;
102588
+ if (selector.includes("[data-composition-id=")) return false;
102589
+ if (selector.startsWith("#")) return false;
102858
102590
  return selector.startsWith(".") || /^[a-z]/i.test(selector);
102859
102591
  }
102860
102592
  function getSingleClassSelector(selector) {
102861
102593
  const match2 = selector.trim().match(/^\.(?<name>[A-Za-z0-9_-]+)$/);
102862
102594
  return match2?.groups?.name || null;
102863
102595
  }
102864
- function truncateSnippet(value, maxLength = 220) {
102865
- const normalized = value.replace(/\s+/g, " ").trim();
102866
- if (!normalized) {
102867
- return void 0;
102596
+ var gsapRules = [
102597
+ // overlapping_gsap_tweens + gsap_animates_clip_element + unscoped_gsap_selector
102598
+ ({ tags, scripts, rootCompositionId }) => {
102599
+ const findings = [];
102600
+ const clipIds = /* @__PURE__ */ new Map();
102601
+ const clipClasses = /* @__PURE__ */ new Map();
102602
+ for (const tag of tags) {
102603
+ const classAttr = readAttr(tag.raw, "class") || "";
102604
+ const classes = classAttr.split(/\s+/).filter(Boolean);
102605
+ if (!classes.includes("clip")) continue;
102606
+ const id = readAttr(tag.raw, "id");
102607
+ const info = {
102608
+ tag: tag.name,
102609
+ id: id || "",
102610
+ classes: classAttr
102611
+ };
102612
+ if (id) clipIds.set(`#${id}`, info);
102613
+ for (const cls of classes) {
102614
+ if (cls !== "clip") clipClasses.set(`.${cls}`, info);
102615
+ }
102616
+ }
102617
+ const classUsage = countClassUsage(tags);
102618
+ for (const script of scripts) {
102619
+ const localTimelineCompId = readRegisteredTimelineCompositionId(script.content);
102620
+ const gsapWindows = extractGsapWindows(script.content);
102621
+ for (let i = 0; i < gsapWindows.length; i++) {
102622
+ const left2 = gsapWindows[i];
102623
+ if (!left2) continue;
102624
+ if (left2.end <= left2.position) continue;
102625
+ for (let j = i + 1; j < gsapWindows.length; j++) {
102626
+ const right2 = gsapWindows[j];
102627
+ if (!right2) continue;
102628
+ if (right2.end <= right2.position) continue;
102629
+ if (left2.targetSelector !== right2.targetSelector) continue;
102630
+ const overlapStart = Math.max(left2.position, right2.position);
102631
+ const overlapEnd = Math.min(left2.end, right2.end);
102632
+ if (overlapEnd <= overlapStart) continue;
102633
+ if (left2.overwriteAuto || right2.overwriteAuto) continue;
102634
+ const sharedProperties = left2.properties.filter(
102635
+ (prop2) => right2.properties.includes(prop2)
102636
+ );
102637
+ if (sharedProperties.length === 0) continue;
102638
+ findings.push({
102639
+ code: "overlapping_gsap_tweens",
102640
+ severity: "warning",
102641
+ message: `GSAP tweens overlap on "${left2.targetSelector}" for ${sharedProperties.join(", ")} between ${overlapStart.toFixed(2)}s and ${overlapEnd.toFixed(2)}s.`,
102642
+ selector: left2.targetSelector,
102643
+ fixHint: 'Shorten the earlier tween, move the later tween, or add `overwrite: "auto"`.',
102644
+ snippet: truncateSnippet(`${left2.raw}
102645
+ ${right2.raw}`)
102646
+ });
102647
+ }
102648
+ }
102649
+ for (const win of gsapWindows) {
102650
+ const sel = win.targetSelector;
102651
+ const clipInfo = clipIds.get(sel) || clipClasses.get(sel);
102652
+ if (!clipInfo) continue;
102653
+ const elDesc = `<${clipInfo.tag}${clipInfo.id ? ` id="${clipInfo.id}"` : ""} class="${clipInfo.classes}">`;
102654
+ findings.push({
102655
+ code: "gsap_animates_clip_element",
102656
+ severity: "error",
102657
+ message: `GSAP animation targets a clip element. Selector "${sel}" resolves to element ${elDesc}. The framework manages clip visibility \u2014 animate an inner wrapper instead.`,
102658
+ selector: sel,
102659
+ elementId: clipInfo.id || void 0,
102660
+ fixHint: "Wrap content in a child <div> and target that with GSAP.",
102661
+ snippet: truncateSnippet(win.raw)
102662
+ });
102663
+ }
102664
+ if (!localTimelineCompId || localTimelineCompId === rootCompositionId) continue;
102665
+ for (const win of gsapWindows) {
102666
+ if (!isSuspiciousGlobalSelector(win.targetSelector)) continue;
102667
+ const className = getSingleClassSelector(win.targetSelector);
102668
+ if (className && (classUsage.get(className) || 0) < 2) continue;
102669
+ findings.push({
102670
+ code: "unscoped_gsap_selector",
102671
+ severity: "warning",
102672
+ message: `Timeline "${localTimelineCompId}" uses unscoped selector "${win.targetSelector}" that will target elements in ALL compositions when bundled, causing data loss (opacity, transforms, etc.).`,
102673
+ selector: win.targetSelector,
102674
+ fixHint: `Scope the selector: \`[data-composition-id="${localTimelineCompId}"] ${win.targetSelector}\` or use a unique id.`,
102675
+ snippet: truncateSnippet(win.raw)
102676
+ });
102677
+ }
102678
+ }
102679
+ return findings;
102680
+ },
102681
+ // gsap_css_transform_conflict
102682
+ ({ styles, scripts }) => {
102683
+ const findings = [];
102684
+ const cssTranslateSelectors = /* @__PURE__ */ new Map();
102685
+ const cssScaleSelectors = /* @__PURE__ */ new Map();
102686
+ for (const style of styles) {
102687
+ for (const [, selector, body] of style.content.matchAll(
102688
+ /([#.][a-zA-Z0-9_-]+)\s*\{([^}]+)\}/g
102689
+ )) {
102690
+ const tMatch = body?.match(/transform\s*:\s*([^;]+)/);
102691
+ if (!tMatch || !tMatch[1]) continue;
102692
+ const transformVal = tMatch[1].trim();
102693
+ if (/translate/i.test(transformVal))
102694
+ cssTranslateSelectors.set((selector ?? "").trim(), transformVal);
102695
+ if (/scale/i.test(transformVal))
102696
+ cssScaleSelectors.set((selector ?? "").trim(), transformVal);
102697
+ }
102698
+ }
102699
+ if (cssTranslateSelectors.size === 0 && cssScaleSelectors.size === 0) return findings;
102700
+ for (const script of scripts) {
102701
+ if (!/gsap\.timeline/.test(script.content)) continue;
102702
+ const windows = extractGsapWindows(script.content);
102703
+ const conflicts = /* @__PURE__ */ new Map();
102704
+ for (const win of windows) {
102705
+ if (win.method === "fromTo") continue;
102706
+ const sel = win.targetSelector;
102707
+ const cssKey = sel.startsWith("#") || sel.startsWith(".") ? sel : `#${sel}`;
102708
+ const translateProps = win.properties.filter(
102709
+ (p) => ["x", "y", "xPercent", "yPercent"].includes(p)
102710
+ );
102711
+ const scaleProps = win.properties.filter((p) => p === "scale");
102712
+ const cssFromTranslate = translateProps.length > 0 ? cssTranslateSelectors.get(cssKey) : void 0;
102713
+ const cssFromScale = scaleProps.length > 0 ? cssScaleSelectors.get(cssKey) : void 0;
102714
+ if (!cssFromTranslate && !cssFromScale) continue;
102715
+ const existing = conflicts.get(sel) ?? {
102716
+ cssTransform: [cssFromTranslate, cssFromScale].filter(Boolean).join(" "),
102717
+ props: /* @__PURE__ */ new Set(),
102718
+ raw: win.raw
102719
+ };
102720
+ for (const p of [...translateProps, ...scaleProps]) existing.props.add(p);
102721
+ conflicts.set(sel, existing);
102722
+ }
102723
+ for (const [sel, { cssTransform, props, raw: raw2 }] of conflicts) {
102724
+ const propList = [...props].join("/");
102725
+ findings.push({
102726
+ code: "gsap_css_transform_conflict",
102727
+ severity: "warning",
102728
+ message: `"${sel}" has CSS \`transform: ${cssTransform}\` and a GSAP tween animates ${propList}. GSAP will overwrite the full CSS transform, discarding any translateX(-50%) centering or CSS scale value.`,
102729
+ selector: sel,
102730
+ fixHint: `Remove the transform from CSS and use tl.fromTo('${sel}', { xPercent: -50, x: -1000 }, { xPercent: -50, x: 0 }) so GSAP owns the full transform state. tl.fromTo is exempt from this rule.`,
102731
+ snippet: truncateSnippet(raw2)
102732
+ });
102733
+ }
102734
+ }
102735
+ return findings;
102736
+ },
102737
+ // missing_gsap_script
102738
+ ({ scripts }) => {
102739
+ const allScriptTexts = scripts.filter((s) => !/\bsrc\s*=/.test(s.attrs)).map((s) => s.content);
102740
+ const allScriptSrcs = scripts.map((s) => readAttr(`<script ${s.attrs}>`, "src") || "").filter(Boolean);
102741
+ const usesGsap = allScriptTexts.some(
102742
+ (t) => /gsap\.(to|from|fromTo|timeline|set|registerPlugin)\b/.test(t)
102743
+ );
102744
+ const hasGsapScript = allScriptSrcs.some((src) => /gsap/i.test(src));
102745
+ if (!usesGsap || hasGsapScript) return [];
102746
+ return [
102747
+ {
102748
+ code: "missing_gsap_script",
102749
+ severity: "error",
102750
+ message: "Composition uses GSAP but no GSAP script is loaded. The animation will not run.",
102751
+ fixHint: 'Add <script src="https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js"></script> before your animation script.'
102752
+ }
102753
+ ];
102868
102754
  }
102869
- if (normalized.length <= maxLength) {
102870
- return normalized;
102755
+ ];
102756
+
102757
+ // ../core/src/lint/rules/captions.ts
102758
+ var captionRules = [
102759
+ // caption_exit_missing_hard_kill
102760
+ ({ scripts }) => {
102761
+ const findings = [];
102762
+ for (const script of scripts) {
102763
+ const content = script.content;
102764
+ const hasExitTween = /\.to\s*\([^,]+,\s*\{[^}]*opacity\s*:\s*0/.test(content);
102765
+ const hasHardKill = /\.set\s*\([^,]+,\s*\{[^}]*(?:visibility\s*:\s*["']hidden["']|opacity\s*:\s*0)/.test(
102766
+ content
102767
+ );
102768
+ const hasCaptionLoop = /forEach|\.forEach\s*\(/.test(content) && /createElement|caption|group|cg-/.test(content);
102769
+ if (hasCaptionLoop && hasExitTween && !hasHardKill) {
102770
+ findings.push({
102771
+ code: "caption_exit_missing_hard_kill",
102772
+ severity: "warning",
102773
+ message: "Caption exit animations (tl.to with opacity: 0) detected without a hard tl.set kill. Exit tweens can fail when karaoke word-level tweens conflict, leaving captions stuck on screen.",
102774
+ fixHint: 'Add `tl.set(groupEl, { opacity: 0, visibility: "hidden" }, group.end)` after every exit tl.to animation as a deterministic kill.'
102775
+ });
102776
+ }
102777
+ }
102778
+ return findings;
102779
+ },
102780
+ // caption_text_overflow_risk
102781
+ ({ styles }) => {
102782
+ const findings = [];
102783
+ for (const style of styles) {
102784
+ const captionBlocks = style.content.matchAll(
102785
+ /(\.caption[-_]?(?:group|container|text|line|word)|#caption[-_]?container)\s*\{([^}]+)\}/gi
102786
+ );
102787
+ for (const [, selector, body] of captionBlocks) {
102788
+ if (!body) continue;
102789
+ const hasNowrap = /white-space\s*:\s*nowrap/i.test(body);
102790
+ const hasMaxWidth = /max-width/i.test(body);
102791
+ if (hasNowrap && !hasMaxWidth) {
102792
+ findings.push({
102793
+ code: "caption_text_overflow_risk",
102794
+ severity: "warning",
102795
+ selector: (selector ?? "").trim(),
102796
+ message: `Caption selector "${(selector ?? "").trim()}" has white-space: nowrap but no max-width. Long phrases will clip off-screen.`,
102797
+ fixHint: "Add max-width: 1600px (landscape) or max-width: 900px (portrait) and overflow: hidden."
102798
+ });
102799
+ }
102800
+ }
102801
+ }
102802
+ return findings;
102803
+ },
102804
+ // caption_container_relative_position
102805
+ ({ styles }) => {
102806
+ const findings = [];
102807
+ for (const style of styles) {
102808
+ const captionBlocks = style.content.matchAll(
102809
+ /(\.caption[-_]?(?:group|container|text|line)|#caption[-_]?container)\s*\{([^}]+)\}/gi
102810
+ );
102811
+ for (const [, selector, body] of captionBlocks) {
102812
+ if (!body) continue;
102813
+ if (/position\s*:\s*relative/i.test(body)) {
102814
+ findings.push({
102815
+ code: "caption_container_relative_position",
102816
+ severity: "warning",
102817
+ selector: (selector ?? "").trim(),
102818
+ message: `Caption selector "${(selector ?? "").trim()}" uses position: relative which causes overflow and breaks caption stacking.`,
102819
+ fixHint: "Use position: absolute for all caption elements."
102820
+ });
102821
+ }
102822
+ }
102823
+ }
102824
+ return findings;
102825
+ }
102826
+ ];
102827
+
102828
+ // ../core/src/lint/rules/composition.ts
102829
+ var compositionRules = [
102830
+ // timed_element_missing_visibility_hidden
102831
+ ({ tags }) => {
102832
+ const findings = [];
102833
+ for (const tag of tags) {
102834
+ if (tag.name === "audio" || tag.name === "script" || tag.name === "style") continue;
102835
+ if (!readAttr(tag.raw, "data-start")) continue;
102836
+ if (readAttr(tag.raw, "data-composition-id")) continue;
102837
+ if (readAttr(tag.raw, "data-composition-src")) continue;
102838
+ const classAttr = readAttr(tag.raw, "class") || "";
102839
+ const styleAttr = readAttr(tag.raw, "style") || "";
102840
+ const hasClip = classAttr.split(/\s+/).includes("clip");
102841
+ const hasHiddenStyle = /visibility\s*:\s*hidden/i.test(styleAttr) || /opacity\s*:\s*0/i.test(styleAttr);
102842
+ if (!hasClip && !hasHiddenStyle) {
102843
+ const elementId = readAttr(tag.raw, "id") || void 0;
102844
+ findings.push({
102845
+ code: "timed_element_missing_visibility_hidden",
102846
+ severity: "info",
102847
+ message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> has data-start but no class="clip", visibility:hidden, or opacity:0. Consider adding initial hidden state if the element should not be visible before its start time.`,
102848
+ elementId,
102849
+ fixHint: 'Add class="clip" (with CSS: .clip { visibility: hidden; }) or style="opacity:0" if the element should start hidden.',
102850
+ snippet: truncateSnippet(tag.raw)
102851
+ });
102852
+ }
102853
+ }
102854
+ return findings;
102855
+ },
102856
+ // deprecated_data_layer + deprecated_data_end
102857
+ ({ tags }) => {
102858
+ const findings = [];
102859
+ for (const tag of tags) {
102860
+ if (readAttr(tag.raw, "data-layer") && !readAttr(tag.raw, "data-track-index")) {
102861
+ const elementId = readAttr(tag.raw, "id") || void 0;
102862
+ findings.push({
102863
+ code: "deprecated_data_layer",
102864
+ severity: "warning",
102865
+ message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> uses data-layer instead of data-track-index.`,
102866
+ elementId,
102867
+ fixHint: "Replace data-layer with data-track-index. The runtime reads data-track-index.",
102868
+ snippet: truncateSnippet(tag.raw)
102869
+ });
102870
+ }
102871
+ if (readAttr(tag.raw, "data-end") && !readAttr(tag.raw, "data-duration")) {
102872
+ const elementId = readAttr(tag.raw, "id") || void 0;
102873
+ findings.push({
102874
+ code: "deprecated_data_end",
102875
+ severity: "warning",
102876
+ message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> uses data-end without data-duration. Use data-duration in source HTML.`,
102877
+ elementId,
102878
+ fixHint: "Replace data-end with data-duration. The compiler generates data-end from data-duration automatically.",
102879
+ snippet: truncateSnippet(tag.raw)
102880
+ });
102881
+ }
102882
+ }
102883
+ return findings;
102884
+ },
102885
+ // template_literal_selector
102886
+ ({ scripts }) => {
102887
+ const findings = [];
102888
+ for (const script of scripts) {
102889
+ const templateLiteralSelectorPattern = /(?:querySelector|querySelectorAll)\s*\(\s*`[^`]*\$\{[^}]+\}[^`]*`\s*\)/g;
102890
+ let tlMatch;
102891
+ while ((tlMatch = templateLiteralSelectorPattern.exec(script.content)) !== null) {
102892
+ findings.push({
102893
+ code: "template_literal_selector",
102894
+ severity: "error",
102895
+ message: "querySelector uses a template literal variable (e.g. `${compId}`). The HTML bundler's CSS parser crashes on these. Use a hardcoded string instead.",
102896
+ fixHint: "Replace the template literal variable with a hardcoded string. The bundler's CSS parser cannot handle interpolated variables in script content.",
102897
+ snippet: truncateSnippet(tlMatch[0])
102898
+ });
102899
+ }
102900
+ }
102901
+ return findings;
102902
+ },
102903
+ // external_script_dependency
102904
+ ({ source: source2 }) => {
102905
+ const findings = [];
102906
+ const externalScriptRe = /<script\b[^>]*\bsrc=["'](https?:\/\/[^"']+)["'][^>]*>/gi;
102907
+ let match2;
102908
+ const seen = /* @__PURE__ */ new Set();
102909
+ while ((match2 = externalScriptRe.exec(source2)) !== null) {
102910
+ const src = match2[1] ?? "";
102911
+ if (seen.has(src)) continue;
102912
+ seen.add(src);
102913
+ findings.push({
102914
+ code: "external_script_dependency",
102915
+ severity: "info",
102916
+ message: `This composition loads an external script from \`${src}\`. The HyperFrames bundler automatically hoists CDN scripts from sub-compositions into the parent document. In unbundled runtime mode, \`loadExternalCompositions\` re-injects them. If you're using a custom pipeline that bypasses both, you'll need to include this script manually.`,
102917
+ fixHint: "No action needed when using `hyperframes preview` or `hyperframes render`. If using a custom pipeline, add this script tag to your root composition or HTML page.",
102918
+ snippet: truncateSnippet(match2[0] ?? "")
102919
+ });
102920
+ }
102921
+ return findings;
102922
+ }
102923
+ ];
102924
+
102925
+ // ../core/src/lint/rules/adapters.ts
102926
+ var adapterRules = [
102927
+ // missing_lottie_script
102928
+ ({ tags, scripts }) => {
102929
+ const allScriptTexts = scripts.filter((s) => !/\bsrc\s*=/.test(s.attrs)).map((s) => s.content);
102930
+ const allScriptSrcs = scripts.map((s) => readAttr(`<script ${s.attrs}>`, "src") || "").filter(Boolean);
102931
+ const hasLottieAttr = tags.some((t) => readAttr(t.raw, "data-lottie-src") !== null);
102932
+ const usesLottieApi = allScriptTexts.some(
102933
+ (t) => /lottie\.(loadAnimation|setSpeed|play|stop|destroy)\b/.test(t)
102934
+ );
102935
+ const hasLottieScript = allScriptSrcs.some((src) => /lottie/i.test(src));
102936
+ if (!(hasLottieAttr || usesLottieApi) || hasLottieScript) return [];
102937
+ return [
102938
+ {
102939
+ code: "missing_lottie_script",
102940
+ severity: "error",
102941
+ message: "Composition uses Lottie but no Lottie script is loaded. The animation will not render.",
102942
+ fixHint: 'Add <script src="https://cdn.jsdelivr.net/npm/lottie-web@5/build/player/lottie.min.js"></script> before your Lottie code.'
102943
+ }
102944
+ ];
102945
+ },
102946
+ // missing_three_script
102947
+ ({ scripts }) => {
102948
+ const allScriptTexts = scripts.filter((s) => !/\bsrc\s*=/.test(s.attrs)).map((s) => s.content);
102949
+ const allScriptSrcs = scripts.map((s) => readAttr(`<script ${s.attrs}>`, "src") || "").filter(Boolean);
102950
+ const usesThree = allScriptTexts.some((t) => /\bTHREE\./.test(t));
102951
+ const hasThreeScript = allScriptSrcs.some((src) => /three/i.test(src));
102952
+ if (!usesThree || hasThreeScript) return [];
102953
+ return [
102954
+ {
102955
+ code: "missing_three_script",
102956
+ severity: "error",
102957
+ message: "Composition uses Three.js but no Three.js script is loaded. The 3D scene will not render.",
102958
+ fixHint: 'Add <script src="https://cdn.jsdelivr.net/npm/three@0.160/build/three.min.js"></script> before your Three.js code.'
102959
+ }
102960
+ ];
102961
+ }
102962
+ ];
102963
+
102964
+ // ../core/src/lint/hyperframeLinter.ts
102965
+ var ALL_RULES = [
102966
+ ...coreRules,
102967
+ ...mediaRules,
102968
+ ...gsapRules,
102969
+ ...captionRules,
102970
+ ...compositionRules,
102971
+ ...adapterRules
102972
+ ];
102973
+ function lintHyperframeHtml(html, options = {}) {
102974
+ const ctx = buildLintContext(html, options);
102975
+ const findings = [];
102976
+ const seen = /* @__PURE__ */ new Set();
102977
+ for (const rule of ALL_RULES) {
102978
+ for (const finding of rule(ctx)) {
102979
+ const dedupeKey = [
102980
+ finding.code,
102981
+ finding.severity,
102982
+ finding.selector || "",
102983
+ finding.elementId || "",
102984
+ finding.message
102985
+ ].join("|");
102986
+ if (seen.has(dedupeKey)) continue;
102987
+ seen.add(dedupeKey);
102988
+ findings.push(options.filePath ? { ...finding, file: options.filePath } : finding);
102989
+ }
102990
+ }
102991
+ const errorCount = findings.filter((f) => f.severity === "error").length;
102992
+ const warningCount = findings.filter((f) => f.severity === "warning").length;
102993
+ const infoCount = findings.filter((f) => f.severity === "info").length;
102994
+ return {
102995
+ ok: errorCount === 0,
102996
+ errorCount,
102997
+ warningCount,
102998
+ infoCount,
102999
+ findings
103000
+ };
103001
+ }
103002
+
103003
+ // ../core/src/compiler/rewriteSubCompPaths.ts
103004
+ import { join as join4, resolve as resolve6, dirname as dirname4 } from "path";
103005
+ var PATH_ATTRS = ["src", "href"];
103006
+ function isAbsoluteOrSpecial(val) {
103007
+ return !val || val.startsWith("http://") || val.startsWith("https://") || val.startsWith("//") || val.startsWith("data:") || val.startsWith("#");
103008
+ }
103009
+ function needsRewrite(val) {
103010
+ return val.startsWith("../") || val === "..";
103011
+ }
103012
+ function rewriteAssetPaths(elements, compSrcPath, getAttr2, setAttr) {
103013
+ const compDir = dirname4(compSrcPath);
103014
+ if (!compDir || compDir === ".") return;
103015
+ for (const el of elements) {
103016
+ for (const attr of PATH_ATTRS) {
103017
+ const val = (getAttr2(el, attr) || "").trim();
103018
+ if (isAbsoluteOrSpecial(val)) continue;
103019
+ if (!needsRewrite(val)) continue;
103020
+ const rewritten = join4(compDir, val);
103021
+ const normalized = resolve6("/", rewritten).slice(1);
103022
+ if (normalized !== val) {
103023
+ setAttr(el, attr, normalized);
103024
+ }
103025
+ }
102871
103026
  }
102872
- return `${normalized.slice(0, maxLength - 3)}...`;
102873
103027
  }
102874
103028
 
102875
103029
  // ../core/src/inline-scripts/hyperframesRuntime.engine.ts
@@ -103237,9 +103391,9 @@ async function initializeSession(session) {
103237
103391
  }
103238
103392
  async function captureFrameErrorDiagnostics(session, frameIndex, time, error) {
103239
103393
  try {
103240
- const diagnosticsDir = join4(session.outputDir, "diagnostics");
103394
+ const diagnosticsDir = join5(session.outputDir, "diagnostics");
103241
103395
  if (!existsSync4(diagnosticsDir)) mkdirSync(diagnosticsDir, { recursive: true });
103242
- const base = join4(diagnosticsDir, `frame-error-${frameIndex}`);
103396
+ const base = join5(diagnosticsDir, `frame-error-${frameIndex}`);
103243
103397
  await session.page.screenshot({ path: `${base}.png`, type: "png", fullPage: true });
103244
103398
  const html = await session.page.content();
103245
103399
  writeFileSync(`${base}.html`, html, "utf-8");
@@ -103337,7 +103491,7 @@ async function captureFrame(session, frameIndex, time) {
103337
103491
  );
103338
103492
  const ext = options.format === "png" ? "png" : "jpg";
103339
103493
  const frameName = `frame_${String(frameIndex).padStart(6, "0")}.${ext}`;
103340
- const framePath = join4(outputDir, frameName);
103494
+ const framePath = join5(outputDir, frameName);
103341
103495
  writeFileSync(framePath, buffer);
103342
103496
  return { frameIndex, time: quantizedTime, path: framePath, captureTimeMs };
103343
103497
  }
@@ -103387,12 +103541,12 @@ function getCapturePerfSummary(session) {
103387
103541
  // ../engine/src/services/chunkEncoder.ts
103388
103542
  import { spawn as spawn5 } from "child_process";
103389
103543
  import { copyFileSync, existsSync as existsSync5, mkdirSync as mkdirSync2, readdirSync as readdirSync3, statSync as statSync3, writeFileSync as writeFileSync2 } from "fs";
103390
- import { join as join5, dirname as dirname4 } from "path";
103544
+ import { join as join6, dirname as dirname5 } from "path";
103391
103545
 
103392
103546
  // ../engine/src/utils/gpuEncoder.ts
103393
103547
  import { spawn as spawn3 } from "child_process";
103394
103548
  async function detectGpuEncoder() {
103395
- return new Promise((resolve12) => {
103549
+ return new Promise((resolve13) => {
103396
103550
  const ffmpeg = spawn3("ffmpeg", ["-encoders"], {
103397
103551
  stdio: ["pipe", "pipe", "pipe"]
103398
103552
  });
@@ -103401,13 +103555,13 @@ async function detectGpuEncoder() {
103401
103555
  stdout += data.toString();
103402
103556
  });
103403
103557
  ffmpeg.on("close", () => {
103404
- if (stdout.includes("h264_nvenc")) resolve12("nvenc");
103405
- else if (stdout.includes("h264_videotoolbox")) resolve12("videotoolbox");
103406
- else if (stdout.includes("h264_vaapi")) resolve12("vaapi");
103407
- else if (stdout.includes("h264_qsv")) resolve12("qsv");
103408
- else resolve12(null);
103558
+ if (stdout.includes("h264_nvenc")) resolve13("nvenc");
103559
+ else if (stdout.includes("h264_videotoolbox")) resolve13("videotoolbox");
103560
+ else if (stdout.includes("h264_vaapi")) resolve13("vaapi");
103561
+ else if (stdout.includes("h264_qsv")) resolve13("qsv");
103562
+ else resolve13(null);
103409
103563
  });
103410
- ffmpeg.on("error", () => resolve12(null));
103564
+ ffmpeg.on("error", () => resolve13(null));
103411
103565
  });
103412
103566
  }
103413
103567
  var cachedGpuEncoder = void 0;
@@ -103441,7 +103595,7 @@ async function runFfmpeg(args, opts) {
103441
103595
  const signal = opts?.signal;
103442
103596
  const timeout2 = opts?.timeout ?? DEFAULT_TIMEOUT2;
103443
103597
  const onStderr = opts?.onStderr;
103444
- return new Promise((resolve12) => {
103598
+ return new Promise((resolve13) => {
103445
103599
  const ffmpeg = spawn4("ffmpeg", args);
103446
103600
  let stderr = "";
103447
103601
  const onAbort = () => {
@@ -103467,7 +103621,7 @@ async function runFfmpeg(args, opts) {
103467
103621
  ffmpeg.on("close", (code) => {
103468
103622
  clearTimeout(timer2);
103469
103623
  if (signal) signal.removeEventListener("abort", onAbort);
103470
- resolve12({
103624
+ resolve13({
103471
103625
  success: !signal?.aborted && code === 0,
103472
103626
  exitCode: code,
103473
103627
  stderr,
@@ -103477,7 +103631,7 @@ async function runFfmpeg(args, opts) {
103477
103631
  ffmpeg.on("error", (err) => {
103478
103632
  clearTimeout(timer2);
103479
103633
  if (signal) signal.removeEventListener("abort", onAbort);
103480
- resolve12({
103634
+ resolve13({
103481
103635
  success: false,
103482
103636
  exitCode: null,
103483
103637
  stderr: err.message,
@@ -103573,7 +103727,7 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
103573
103727
  }
103574
103728
  async function encodeFramesFromDir(framesDir, framePattern, outputPath, options, signal, config2) {
103575
103729
  const startTime = Date.now();
103576
- const outputDir = dirname4(outputPath);
103730
+ const outputDir = dirname5(outputPath);
103577
103731
  if (!existsSync5(outputDir)) mkdirSync2(outputDir, { recursive: true });
103578
103732
  const files = readdirSync3(framesDir).filter((f) => f.match(/\.(jpg|jpeg|png)$/i));
103579
103733
  const frameCount = files.length;
@@ -103591,10 +103745,10 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
103591
103745
  if (options.useGpu) {
103592
103746
  gpuEncoder = await getCachedGpuEncoder();
103593
103747
  }
103594
- const inputPath = join5(framesDir, framePattern);
103748
+ const inputPath = join6(framesDir, framePattern);
103595
103749
  const inputArgs = ["-framerate", String(options.fps), "-i", inputPath];
103596
103750
  const args = buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder);
103597
- return new Promise((resolve12) => {
103751
+ return new Promise((resolve13) => {
103598
103752
  const ffmpeg = spawn5("ffmpeg", args);
103599
103753
  let stderr = "";
103600
103754
  const onAbort = () => {
@@ -103619,7 +103773,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
103619
103773
  if (signal) signal.removeEventListener("abort", onAbort);
103620
103774
  const durationMs = Date.now() - startTime;
103621
103775
  if (signal?.aborted) {
103622
- resolve12({
103776
+ resolve13({
103623
103777
  success: false,
103624
103778
  outputPath,
103625
103779
  durationMs,
@@ -103630,7 +103784,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
103630
103784
  return;
103631
103785
  }
103632
103786
  if (code !== 0) {
103633
- resolve12({
103787
+ resolve13({
103634
103788
  success: false,
103635
103789
  outputPath,
103636
103790
  durationMs,
@@ -103641,12 +103795,12 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
103641
103795
  return;
103642
103796
  }
103643
103797
  const fileSize = existsSync5(outputPath) ? statSync3(outputPath).size : 0;
103644
- resolve12({ success: true, outputPath, durationMs, framesEncoded: frameCount, fileSize });
103798
+ resolve13({ success: true, outputPath, durationMs, framesEncoded: frameCount, fileSize });
103645
103799
  });
103646
103800
  ffmpeg.on("error", (err) => {
103647
103801
  clearTimeout(timer2);
103648
103802
  if (signal) signal.removeEventListener("abort", onAbort);
103649
- resolve12({
103803
+ resolve13({
103650
103804
  success: false,
103651
103805
  outputPath,
103652
103806
  durationMs: Date.now() - startTime,
@@ -103672,7 +103826,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
103672
103826
  }
103673
103827
  const chunkSize = Math.max(30, Math.floor(chunkSizeFrames));
103674
103828
  const chunkCount = Math.ceil(files.length / chunkSize);
103675
- const chunkDir = join5(dirname4(outputPath), "chunk-encode");
103829
+ const chunkDir = join6(dirname5(outputPath), "chunk-encode");
103676
103830
  if (!existsSync5(chunkDir)) mkdirSync2(chunkDir, { recursive: true });
103677
103831
  const chunkPaths = [];
103678
103832
  for (let i = 0; i < chunkCount; i++) {
@@ -103689,8 +103843,8 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
103689
103843
  const startNumber = i * chunkSize;
103690
103844
  const framesInChunk = Math.min(chunkSize, files.length - startNumber);
103691
103845
  const ext = outputPath.endsWith(".webm") ? ".webm" : ".mp4";
103692
- const chunkPath = join5(chunkDir, `chunk_${String(i).padStart(4, "0")}${ext}`);
103693
- const inputPath = join5(framesDir, framePattern);
103846
+ const chunkPath = join6(chunkDir, `chunk_${String(i).padStart(4, "0")}${ext}`);
103847
+ const inputPath = join6(framesDir, framePattern);
103694
103848
  const inputArgs = [
103695
103849
  "-framerate",
103696
103850
  String(options.fps),
@@ -103704,18 +103858,18 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
103704
103858
  let gpuEncoder = null;
103705
103859
  if (options.useGpu) gpuEncoder = await getCachedGpuEncoder();
103706
103860
  const args = buildEncoderArgs(options, inputArgs, chunkPath, gpuEncoder);
103707
- const chunkResult = await new Promise((resolve12) => {
103861
+ const chunkResult = await new Promise((resolve13) => {
103708
103862
  const ffmpeg = spawn5("ffmpeg", args);
103709
103863
  let stderr = "";
103710
103864
  ffmpeg.stderr.on("data", (d) => {
103711
103865
  stderr += d.toString();
103712
103866
  });
103713
103867
  ffmpeg.on("close", (code) => {
103714
- if (code === 0) resolve12({ success: true });
103715
- else resolve12({ success: false, error: `Chunk ${i} encode failed: ${stderr.slice(-400)}` });
103868
+ if (code === 0) resolve13({ success: true });
103869
+ else resolve13({ success: false, error: `Chunk ${i} encode failed: ${stderr.slice(-400)}` });
103716
103870
  });
103717
103871
  ffmpeg.on("error", (err) => {
103718
- resolve12({ success: false, error: `Chunk ${i} encode error: ${err.message}` });
103872
+ resolve13({ success: false, error: `Chunk ${i} encode error: ${err.message}` });
103719
103873
  });
103720
103874
  });
103721
103875
  if (!chunkResult.success) {
@@ -103730,7 +103884,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
103730
103884
  }
103731
103885
  chunkPaths.push(chunkPath);
103732
103886
  }
103733
- const concatListPath = join5(chunkDir, "concat-list.txt");
103887
+ const concatListPath = join6(chunkDir, "concat-list.txt");
103734
103888
  const concatInput = chunkPaths.map((path12) => `file '${path12.replace(/'/g, "'\\''")}'`).join("\n");
103735
103889
  writeFileSync2(concatListPath, concatInput, "utf-8");
103736
103890
  const concatArgs = [
@@ -103745,18 +103899,18 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
103745
103899
  "-y",
103746
103900
  outputPath
103747
103901
  ];
103748
- const concatResult = await new Promise((resolve12) => {
103902
+ const concatResult = await new Promise((resolve13) => {
103749
103903
  const ffmpeg = spawn5("ffmpeg", concatArgs);
103750
103904
  let stderr = "";
103751
103905
  ffmpeg.stderr.on("data", (d) => {
103752
103906
  stderr += d.toString();
103753
103907
  });
103754
103908
  ffmpeg.on("close", (code) => {
103755
- if (code === 0) resolve12({ success: true });
103756
- else resolve12({ success: false, error: `Chunk concat failed: ${stderr.slice(-400)}` });
103909
+ if (code === 0) resolve13({ success: true });
103910
+ else resolve13({ success: false, error: `Chunk concat failed: ${stderr.slice(-400)}` });
103757
103911
  });
103758
103912
  ffmpeg.on("error", (err) => {
103759
- resolve12({ success: false, error: `Chunk concat error: ${err.message}` });
103913
+ resolve13({ success: false, error: `Chunk concat error: ${err.message}` });
103760
103914
  });
103761
103915
  });
103762
103916
  if (!concatResult.success) {
@@ -103779,7 +103933,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
103779
103933
  };
103780
103934
  }
103781
103935
  async function muxVideoWithAudio(videoPath, audioPath, outputPath, signal, config2) {
103782
- const outputDir = dirname4(outputPath);
103936
+ const outputDir = dirname5(outputPath);
103783
103937
  if (!existsSync5(outputDir)) mkdirSync2(outputDir, { recursive: true });
103784
103938
  const isWebm = outputPath.endsWith(".webm");
103785
103939
  const args = ["-i", videoPath, "-i", audioPath, "-c:v", "copy"];
@@ -103833,7 +103987,7 @@ async function applyFaststart(inputPath, outputPath, signal, config2) {
103833
103987
  // ../engine/src/services/streamingEncoder.ts
103834
103988
  import { spawn as spawn6 } from "child_process";
103835
103989
  import { existsSync as existsSync6, mkdirSync as mkdirSync3, statSync as statSync4 } from "fs";
103836
- import { dirname as dirname5 } from "path";
103990
+ import { dirname as dirname6 } from "path";
103837
103991
  function createFrameReorderBuffer(startFrame, endFrame) {
103838
103992
  let nextFrame = startFrame;
103839
103993
  let waiters = [];
@@ -103846,16 +104000,16 @@ function createFrameReorderBuffer(startFrame, endFrame) {
103846
104000
  }
103847
104001
  };
103848
104002
  return {
103849
- waitForFrame: (frame) => new Promise((resolve12) => {
103850
- waiters.push({ frame, resolve: resolve12 });
104003
+ waitForFrame: (frame) => new Promise((resolve13) => {
104004
+ waiters.push({ frame, resolve: resolve13 });
103851
104005
  resolveWaiters();
103852
104006
  }),
103853
104007
  advanceTo: (frame) => {
103854
104008
  nextFrame = frame;
103855
104009
  resolveWaiters();
103856
104010
  },
103857
- waitForAllDone: () => new Promise((resolve12) => {
103858
- waiters.push({ frame: endFrame, resolve: resolve12 });
104011
+ waitForAllDone: () => new Promise((resolve13) => {
104012
+ waiters.push({ frame: endFrame, resolve: resolve13 });
103859
104013
  resolveWaiters();
103860
104014
  })
103861
104015
  };
@@ -103940,7 +104094,7 @@ function buildStreamingArgs(options, outputPath, gpuEncoder = null) {
103940
104094
  return args;
103941
104095
  }
103942
104096
  async function spawnStreamingEncoder(outputPath, options, signal, config2) {
103943
- const outputDir = dirname5(outputPath);
104097
+ const outputDir = dirname6(outputPath);
103944
104098
  if (!existsSync6(outputDir)) mkdirSync3(outputDir, { recursive: true });
103945
104099
  let gpuEncoder = null;
103946
104100
  if (options.useGpu) {
@@ -103955,7 +104109,7 @@ async function spawnStreamingEncoder(outputPath, options, signal, config2) {
103955
104109
  let stderr = "";
103956
104110
  let exitCode = null;
103957
104111
  let exitPromiseResolve = null;
103958
- const exitPromise = new Promise((resolve12) => exitPromiseResolve = resolve12);
104112
+ const exitPromise = new Promise((resolve13) => exitPromiseResolve = resolve13);
103959
104113
  ffmpeg.stderr?.on("data", (data) => {
103960
104114
  stderr += data.toString();
103961
104115
  });
@@ -103999,8 +104153,8 @@ Process error: ${err.message}`;
103999
104153
  clearTimeout(timer2);
104000
104154
  if (signal) signal.removeEventListener("abort", onAbort);
104001
104155
  if (ffmpeg.stdin && !ffmpeg.stdin.destroyed) {
104002
- await new Promise((resolve12) => {
104003
- ffmpeg.stdin.end(() => resolve12());
104156
+ await new Promise((resolve13) => {
104157
+ ffmpeg.stdin.end(() => resolve13());
104004
104158
  });
104005
104159
  }
104006
104160
  await exitPromise;
@@ -104032,12 +104186,12 @@ Process error: ${err.message}`;
104032
104186
  // ../engine/src/services/videoFrameExtractor.ts
104033
104187
  import { spawn as spawn8 } from "child_process";
104034
104188
  import { existsSync as existsSync8, mkdirSync as mkdirSync5, readdirSync as readdirSync4, rmSync } from "fs";
104035
- import { join as join7 } from "path";
104189
+ import { join as join8 } from "path";
104036
104190
 
104037
104191
  // ../engine/src/utils/ffprobe.ts
104038
104192
  import { spawn as spawn7 } from "child_process";
104039
104193
  function runFfprobe(args) {
104040
- return new Promise((resolve12, reject) => {
104194
+ return new Promise((resolve13, reject) => {
104041
104195
  const proc = spawn7("ffprobe", args);
104042
104196
  let stdout = "";
104043
104197
  let stderr = "";
@@ -104051,7 +104205,7 @@ function runFfprobe(args) {
104051
104205
  if (code !== 0) {
104052
104206
  reject(new Error(`[FFmpeg] ffprobe exited with code ${code}: ${stderr}`));
104053
104207
  } else {
104054
- resolve12(stdout);
104208
+ resolve13(stdout);
104055
104209
  }
104056
104210
  });
104057
104211
  proc.on("error", (err) => {
@@ -104210,7 +104364,7 @@ async function analyzeKeyframeIntervalsUncached(filePath) {
104210
104364
  // ../engine/src/utils/urlDownloader.ts
104211
104365
  import { createWriteStream as createWriteStream2, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
104212
104366
  import { createHash } from "crypto";
104213
- import { join as join6, extname as extname2 } from "path";
104367
+ import { join as join7, extname as extname2 } from "path";
104214
104368
  import { Readable as Readable2 } from "stream";
104215
104369
  import { finished } from "stream/promises";
104216
104370
  var downloadPathCache = /* @__PURE__ */ new Map();
@@ -104234,7 +104388,7 @@ async function downloadToTemp(url, destDir, timeoutMs = 3e5) {
104234
104388
  mkdirSync4(destDir, { recursive: true });
104235
104389
  }
104236
104390
  const filename = getFilenameFromUrl(url);
104237
- const localPath = join6(destDir, filename);
104391
+ const localPath = join7(destDir, filename);
104238
104392
  if (existsSync7(localPath)) {
104239
104393
  downloadPathCache.set(url, localPath);
104240
104394
  return localPath;
@@ -104277,19 +104431,15 @@ function isHttpUrl(path12) {
104277
104431
  function parseVideoElements(html) {
104278
104432
  const videos = [];
104279
104433
  const { document: document2 } = parseHTML(html);
104280
- const videoEls = Array.from(
104281
- /* @__PURE__ */ new Set([
104282
- ...Array.from(document2.querySelectorAll("video[id][src]")),
104283
- ...Array.from(document2.querySelectorAll("video[src][data-start]"))
104284
- ])
104285
- );
104286
- videoEls.forEach((el, i) => {
104287
- if (!el.id) el.id = `hf-video-${i}`;
104288
- });
104434
+ const videoEls = document2.querySelectorAll("video[src]");
104435
+ let autoIdCounter = 0;
104289
104436
  for (const el of videoEls) {
104290
- const id = el.getAttribute("id");
104291
104437
  const src = el.getAttribute("src");
104292
- if (!id || !src) continue;
104438
+ if (!src) continue;
104439
+ const id = el.getAttribute("id") || `hf-video-${autoIdCounter++}`;
104440
+ if (!el.getAttribute("id")) {
104441
+ el.setAttribute("id", id);
104442
+ }
104293
104443
  const startAttr = el.getAttribute("data-start");
104294
104444
  const endAttr = el.getAttribute("data-end");
104295
104445
  const durationAttr = el.getAttribute("data-duration");
@@ -104318,11 +104468,11 @@ function parseVideoElements(html) {
104318
104468
  async function extractVideoFramesRange(videoPath, videoId, startTime, duration, options, signal, config2) {
104319
104469
  const ffmpegProcessTimeout = config2?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
104320
104470
  const { fps, outputDir, quality = 95, format: format3 = "jpg" } = options;
104321
- const videoOutputDir = join7(outputDir, videoId);
104471
+ const videoOutputDir = join8(outputDir, videoId);
104322
104472
  if (!existsSync8(videoOutputDir)) mkdirSync5(videoOutputDir, { recursive: true });
104323
104473
  const metadata = await extractVideoMetadata(videoPath);
104324
104474
  const framePattern = `frame_%05d.${format3}`;
104325
- const outputPattern = join7(videoOutputDir, framePattern);
104475
+ const outputPattern = join8(videoOutputDir, framePattern);
104326
104476
  const args = [
104327
104477
  "-ss",
104328
104478
  String(startTime),
@@ -104337,7 +104487,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
104337
104487
  ];
104338
104488
  if (format3 === "png") args.push("-compression_level", "6");
104339
104489
  args.push("-y", outputPattern);
104340
- return new Promise((resolve12, reject) => {
104490
+ return new Promise((resolve13, reject) => {
104341
104491
  const ffmpeg = spawn8("ffmpeg", args);
104342
104492
  let stderr = "";
104343
104493
  const onAbort = () => {
@@ -104370,9 +104520,9 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
104370
104520
  const framePaths = /* @__PURE__ */ new Map();
104371
104521
  const files = readdirSync4(videoOutputDir).filter((f) => f.startsWith("frame_") && f.endsWith(`.${format3}`)).sort();
104372
104522
  files.forEach((file, index) => {
104373
- framePaths.set(index, join7(videoOutputDir, file));
104523
+ framePaths.set(index, join8(videoOutputDir, file));
104374
104524
  });
104375
- resolve12({
104525
+ resolve13({
104376
104526
  videoId,
104377
104527
  srcPath: videoPath,
104378
104528
  outputDir: videoOutputDir,
@@ -104407,10 +104557,10 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2)
104407
104557
  try {
104408
104558
  let videoPath = video.src;
104409
104559
  if (!videoPath.startsWith("/") && !isHttpUrl(videoPath)) {
104410
- videoPath = join7(baseDir, videoPath);
104560
+ videoPath = join8(baseDir, videoPath);
104411
104561
  }
104412
104562
  if (isHttpUrl(videoPath)) {
104413
- const downloadDir = join7(options.outputDir, "_downloads");
104563
+ const downloadDir = join8(options.outputDir, "_downloads");
104414
104564
  mkdirSync5(downloadDir, { recursive: true });
104415
104565
  videoPath = await downloadToTemp(videoPath, downloadDir);
104416
104566
  }
@@ -104654,7 +104804,7 @@ function createVideoFrameInjector(frameLookup, config2) {
104654
104804
 
104655
104805
  // ../engine/src/services/audioMixer.ts
104656
104806
  import { existsSync as existsSync9, mkdirSync as mkdirSync6, rmSync as rmSync2 } from "fs";
104657
- import { join as join8, dirname as dirname6 } from "path";
104807
+ import { join as join9, dirname as dirname7 } from "path";
104658
104808
  function parseAudioElements(html) {
104659
104809
  const elements = [];
104660
104810
  const { document: document2 } = parseHTML(html);
@@ -104704,7 +104854,7 @@ function parseAudioElements(html) {
104704
104854
  }
104705
104855
  async function extractAudioFromVideo(videoPath, outputPath, options, signal, config2) {
104706
104856
  const ffmpegProcessTimeout = config2?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
104707
- const outputDir = dirname6(outputPath);
104857
+ const outputDir = dirname7(outputPath);
104708
104858
  if (!existsSync9(outputDir)) mkdirSync6(outputDir, { recursive: true });
104709
104859
  const args = ["-i", videoPath];
104710
104860
  if (options?.startTime !== void 0) args.push("-ss", String(options.startTime));
@@ -104731,7 +104881,7 @@ async function extractAudioFromVideo(videoPath, outputPath, options, signal, con
104731
104881
  }
104732
104882
  async function prepareAudioTrack(srcPath, outputPath, mediaStart, duration, signal, config2) {
104733
104883
  const ffmpegProcessTimeout = config2?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
104734
- const outputDir = dirname6(outputPath);
104884
+ const outputDir = dirname7(outputPath);
104735
104885
  if (!existsSync9(outputDir)) mkdirSync6(outputDir, { recursive: true });
104736
104886
  const args = [
104737
104887
  "-ss",
@@ -104767,7 +104917,7 @@ async function prepareAudioTrack(srcPath, outputPath, mediaStart, duration, sign
104767
104917
  }
104768
104918
  async function generateSilence(outputPath, duration, signal, config2) {
104769
104919
  const ffmpegProcessTimeout = config2?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
104770
- const outputDir = dirname6(outputPath);
104920
+ const outputDir = dirname7(outputPath);
104771
104921
  if (!existsSync9(outputDir)) mkdirSync6(outputDir, { recursive: true });
104772
104922
  const args = [
104773
104923
  "-f",
@@ -104810,7 +104960,7 @@ async function mixAudioTracks(tracks, outputPath, totalDuration, signal, config2
104810
104960
  error: result2.error
104811
104961
  };
104812
104962
  }
104813
- const outputDir = dirname6(outputPath);
104963
+ const outputDir = dirname7(outputPath);
104814
104964
  if (!existsSync9(outputDir)) mkdirSync6(outputDir, { recursive: true });
104815
104965
  const inputs = [];
104816
104966
  const filterParts = [];
@@ -104882,7 +105032,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
104882
105032
  try {
104883
105033
  let srcPath = element.src;
104884
105034
  if (!srcPath.startsWith("/") && !isHttpUrl(srcPath)) {
104885
- srcPath = join8(baseDir, srcPath);
105035
+ srcPath = join9(baseDir, srcPath);
104886
105036
  }
104887
105037
  if (isHttpUrl(srcPath)) {
104888
105038
  try {
@@ -104905,7 +105055,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
104905
105055
  }
104906
105056
  let audioSrcPath = srcPath;
104907
105057
  if (element.type === "video") {
104908
- const extractedPath = join8(workDir, `${element.id}-extracted.wav`);
105058
+ const extractedPath = join9(workDir, `${element.id}-extracted.wav`);
104909
105059
  const extractResult = await extractAudioFromVideo(
104910
105060
  srcPath,
104911
105061
  extractedPath,
@@ -104922,7 +105072,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
104922
105072
  }
104923
105073
  audioSrcPath = extractedPath;
104924
105074
  } else {
104925
- const trimmedPath = join8(workDir, `${element.id}-trimmed.wav`);
105075
+ const trimmedPath = join9(workDir, `${element.id}-trimmed.wav`);
104926
105076
  const prepResult = await prepareAudioTrack(
104927
105077
  srcPath,
104928
105078
  trimmedPath,
@@ -104967,7 +105117,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
104967
105117
  import { cpus, freemem, totalmem } from "os";
104968
105118
  import { existsSync as existsSync10, mkdirSync as mkdirSync7, readdirSync as readdirSync5 } from "fs";
104969
105119
  import { copyFile, rename as rename2 } from "fs/promises";
104970
- import { join as join9 } from "path";
105120
+ import { join as join10 } from "path";
104971
105121
  var MEMORY_PER_WORKER_MB = 256;
104972
105122
  var MIN_WORKERS = 1;
104973
105123
  var ABSOLUTE_MAX_WORKERS = 10;
@@ -105015,7 +105165,7 @@ function distributeFrames(totalFrames, workerCount, workDir) {
105015
105165
  workerId: i,
105016
105166
  startFrame,
105017
105167
  endFrame,
105018
- outputDir: join9(workDir, `worker-${i}`)
105168
+ outputDir: join10(workDir, `worker-${i}`)
105019
105169
  });
105020
105170
  }
105021
105171
  return tasks;
@@ -105122,8 +105272,8 @@ async function mergeWorkerFrames(workDir, tasks, outputDir) {
105122
105272
  }
105123
105273
  const files = readdirSync5(task.outputDir).filter((f) => f.startsWith("frame_") && (f.endsWith(".jpg") || f.endsWith(".png"))).sort();
105124
105274
  const copyTasks = files.map(async (file) => {
105125
- const sourcePath = join9(task.outputDir, file);
105126
- const targetPath = join9(outputDir, file);
105275
+ const sourcePath = join10(task.outputDir, file);
105276
+ const targetPath = join10(outputDir, file);
105127
105277
  try {
105128
105278
  await rename2(sourcePath, targetPath);
105129
105279
  } catch {
@@ -105137,33 +105287,33 @@ async function mergeWorkerFrames(workDir, tasks, outputDir) {
105137
105287
  }
105138
105288
 
105139
105289
  // src/services/renderOrchestrator.ts
105140
- import { join as join12, dirname as dirname9, resolve as resolve8 } from "path";
105290
+ import { join as join13, dirname as dirname10, resolve as resolve9 } from "path";
105141
105291
  import { randomUUID } from "crypto";
105142
105292
  import { freemem as freemem2 } from "os";
105143
105293
  import { fileURLToPath as fileURLToPath3 } from "url";
105144
105294
 
105145
105295
  // src/services/fileServer.ts
105146
105296
  import { readFileSync as readFileSync6, existsSync as existsSync12, statSync as statSync5 } from "node:fs";
105147
- import { join as join10, extname as extname3 } from "node:path";
105297
+ import { join as join11, extname as extname3 } from "node:path";
105148
105298
 
105149
105299
  // src/services/hyperframeRuntimeLoader.ts
105150
105300
  import { createHash as createHash2 } from "node:crypto";
105151
105301
  import { existsSync as existsSync11, readFileSync as readFileSync5 } from "node:fs";
105152
- import { dirname as dirname7, resolve as resolve6 } from "node:path";
105302
+ import { dirname as dirname8, resolve as resolve7 } from "node:path";
105153
105303
  import { fileURLToPath as fileURLToPath2 } from "node:url";
105154
- var PRODUCER_DIR = dirname7(fileURLToPath2(import.meta.url));
105155
- var SIBLING_MANIFEST_PATH = resolve6(PRODUCER_DIR, "hyperframe.manifest.json");
105156
- var MODULE_RELATIVE_MANIFEST_PATH = resolve6(
105304
+ var PRODUCER_DIR = dirname8(fileURLToPath2(import.meta.url));
105305
+ var SIBLING_MANIFEST_PATH = resolve7(PRODUCER_DIR, "hyperframe.manifest.json");
105306
+ var MODULE_RELATIVE_MANIFEST_PATH = resolve7(
105157
105307
  PRODUCER_DIR,
105158
105308
  "../../../core/dist/hyperframe.manifest.json"
105159
105309
  );
105160
105310
  var CWD_RELATIVE_MANIFEST_PATHS = [
105161
105311
  // When bundled to a single file (dist/public-server.js), the manifest
105162
105312
  // is copied as a sibling by build.mjs
105163
- resolve6(PRODUCER_DIR, "hyperframe.manifest.json"),
105164
- resolve6(process.cwd(), "packages/core/dist/hyperframe.manifest.json"),
105165
- resolve6(process.cwd(), "../core/dist/hyperframe.manifest.json"),
105166
- resolve6(process.cwd(), "core/dist/hyperframe.manifest.json")
105313
+ resolve7(PRODUCER_DIR, "hyperframe.manifest.json"),
105314
+ resolve7(process.cwd(), "packages/core/dist/hyperframe.manifest.json"),
105315
+ resolve7(process.cwd(), "../core/dist/hyperframe.manifest.json"),
105316
+ resolve7(process.cwd(), "core/dist/hyperframe.manifest.json")
105167
105317
  ];
105168
105318
  function resolveHyperframeManifestPath() {
105169
105319
  if (process.env.PRODUCER_HYPERFRAME_MANIFEST_PATH) {
@@ -105199,7 +105349,7 @@ function resolveVerifiedHyperframeRuntime() {
105199
105349
  `[HyperframeRuntimeLoader] Invalid manifest at ${manifestPath}; missing iife artifact or sha256.`
105200
105350
  );
105201
105351
  }
105202
- const runtimePath = resolve6(dirname7(manifestPath), runtimeFileName);
105352
+ const runtimePath = resolve7(dirname8(manifestPath), runtimeFileName);
105203
105353
  if (!existsSync11(runtimePath)) {
105204
105354
  throw new Error(`[HyperframeRuntimeLoader] Missing runtime artifact at ${runtimePath}.`);
105205
105355
  }
@@ -105450,11 +105600,11 @@ function createFileServer2(options) {
105450
105600
  let requestPath = c.req.path;
105451
105601
  if (requestPath === "/") requestPath = "/index.html";
105452
105602
  const relativePath = requestPath.replace(/^\//, "");
105453
- const compiledPath = compiledDir ? join10(compiledDir, relativePath) : null;
105603
+ const compiledPath = compiledDir ? join11(compiledDir, relativePath) : null;
105454
105604
  const hasCompiledFile = Boolean(
105455
105605
  compiledPath && existsSync12(compiledPath) && statSync5(compiledPath).isFile()
105456
105606
  );
105457
- const filePath = hasCompiledFile ? compiledPath : join10(projectDir, relativePath);
105607
+ const filePath = hasCompiledFile ? compiledPath : join11(projectDir, relativePath);
105458
105608
  if (!existsSync12(filePath) || !statSync5(filePath).isFile()) {
105459
105609
  return c.text("Not found", 404);
105460
105610
  }
@@ -105472,22 +105622,29 @@ function createFileServer2(options) {
105472
105622
  headers: { "Content-Type": contentType }
105473
105623
  });
105474
105624
  });
105475
- return new Promise((resolve12) => {
105625
+ return new Promise((resolve13) => {
105626
+ const connections = /* @__PURE__ */ new Set();
105476
105627
  const server = serve({ fetch: app.fetch, port }, (info) => {
105477
- const actualPort = info.port;
105478
- const url = `http://localhost:${actualPort}`;
105479
- resolve12({
105480
- url,
105481
- port: actualPort,
105482
- close: () => server.close()
105628
+ resolve13({
105629
+ url: `http://localhost:${info.port}`,
105630
+ port: info.port,
105631
+ close: () => {
105632
+ for (const socket of connections) socket.destroy();
105633
+ connections.clear();
105634
+ server.close();
105635
+ }
105483
105636
  });
105484
105637
  });
105638
+ server.on("connection", (socket) => {
105639
+ connections.add(socket);
105640
+ socket.on("close", () => connections.delete(socket));
105641
+ });
105485
105642
  });
105486
105643
  }
105487
105644
 
105488
105645
  // src/services/htmlCompiler.ts
105489
105646
  import { readFileSync as readFileSync7, existsSync as existsSync13, mkdirSync as mkdirSync8 } from "fs";
105490
- import { join as join11, dirname as dirname8, resolve as resolve7 } from "path";
105647
+ import { join as join12, dirname as dirname9, resolve as resolve8 } from "path";
105491
105648
 
105492
105649
  // src/services/fontData.generated.ts
105493
105650
  var EMBEDDED_FONT_DATA = /* @__PURE__ */ new Map([
@@ -105740,7 +105897,7 @@ async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagNa
105740
105897
  return { duration: 0, resolvedPath: src };
105741
105898
  }
105742
105899
  } else if (!filePath.startsWith("/")) {
105743
- filePath = join11(baseDir, filePath);
105900
+ filePath = join12(baseDir, filePath);
105744
105901
  }
105745
105902
  if (!existsSync13(filePath)) {
105746
105903
  return { duration: 0, resolvedPath: filePath };
@@ -105806,7 +105963,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
105806
105963
  const elEnd = elEndRaw ? parseFloat(elEndRaw) : Infinity;
105807
105964
  const absoluteStart = parentOffset + elStart;
105808
105965
  const absoluteEnd = Math.min(parentEnd, isFinite(elEnd) ? parentOffset + elEnd : Infinity);
105809
- const filePath = resolve7(projectDir, srcPath);
105966
+ const filePath = resolve8(projectDir, srcPath);
105810
105967
  if (visited.has(filePath)) {
105811
105968
  continue;
105812
105969
  }
@@ -105822,7 +105979,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
105822
105979
  workItems.map(async (item) => {
105823
105980
  const { html: compiledSub } = await compileHtmlFile(
105824
105981
  item.rawSubHtml,
105825
- dirname8(item.filePath),
105982
+ dirname9(item.filePath),
105826
105983
  downloadDir
105827
105984
  );
105828
105985
  const nested = await parseSubCompositions(
@@ -106001,12 +106158,13 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
106001
106158
  if (!hosts.length) return html;
106002
106159
  const collectedStyles = [];
106003
106160
  const collectedScripts = [];
106161
+ const collectedExternalScriptSrcs = [];
106004
106162
  for (const host of hosts) {
106005
106163
  const srcPath = host.getAttribute("data-composition-src");
106006
106164
  if (!srcPath) continue;
106007
106165
  let compHtml = subCompositions.get(srcPath) || null;
106008
106166
  if (!compHtml) {
106009
- const filePath = resolve7(projectDir, srcPath);
106167
+ const filePath = resolve8(projectDir, srcPath);
106010
106168
  if (existsSync13(filePath)) {
106011
106169
  compHtml = readFileSync7(filePath, "utf-8");
106012
106170
  }
@@ -106034,7 +106192,13 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
106034
106192
  }
106035
106193
  for (const scriptEl of contentDoc.querySelectorAll("script")) {
106036
106194
  const src = (scriptEl.getAttribute("src") || "").trim();
106037
- if (src) continue;
106195
+ if (src) {
106196
+ if (!collectedExternalScriptSrcs.includes(src)) {
106197
+ collectedExternalScriptSrcs.push(src);
106198
+ }
106199
+ scriptEl.remove();
106200
+ continue;
106201
+ }
106038
106202
  const content = (scriptEl.textContent || "").trim();
106039
106203
  if (content) {
106040
106204
  const scriptMountCompId = compId || inferredCompId || "";
@@ -106061,6 +106225,13 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
106061
106225
  }
106062
106226
  scriptEl.remove();
106063
106227
  }
106228
+ const rewriteTarget = innerRoot || contentDoc;
106229
+ rewriteAssetPaths(
106230
+ rewriteTarget.querySelectorAll("[src], [href]"),
106231
+ srcPath,
106232
+ (el, attr) => (el.getAttribute(attr) || "").trim(),
106233
+ (el, attr, val) => el.setAttribute(attr, val)
106234
+ );
106064
106235
  if (innerRoot) {
106065
106236
  const innerW = innerRoot.getAttribute("data-width");
106066
106237
  const innerH = innerRoot.getAttribute("data-height");
@@ -106104,6 +106275,21 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
106104
106275
  styleEl.textContent = collectedStyles.join("\n\n");
106105
106276
  head.appendChild(styleEl);
106106
106277
  }
106278
+ if (collectedExternalScriptSrcs.length && body) {
106279
+ const existingScriptSrcs = new Set(
106280
+ Array.from(document2.querySelectorAll("script[src]")).map(
106281
+ (el) => (el.getAttribute("src") || "").trim()
106282
+ )
106283
+ );
106284
+ for (const src of collectedExternalScriptSrcs) {
106285
+ if (!existingScriptSrcs.has(src)) {
106286
+ const scriptEl = document2.createElement("script");
106287
+ scriptEl.setAttribute("src", src);
106288
+ body.appendChild(scriptEl);
106289
+ existingScriptSrcs.add(src);
106290
+ }
106291
+ }
106292
+ }
106107
106293
  if (collectedScripts.length && body) {
106108
106294
  const scriptEl = document2.createElement("script");
106109
106295
  scriptEl.textContent = collectedScripts.join("\n;\n");
@@ -106150,11 +106336,11 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
106150
106336
  );
106151
106337
  const mainVideos = parseVideoElements(html);
106152
106338
  const mainAudios = parseAudioElements(html);
106153
- const videos = dedupeElementsById([...subVideos, ...mainVideos]);
106154
- const audios = dedupeElementsById([...subAudios, ...mainAudios]);
106339
+ const videos = dedupeElementsById([...mainVideos, ...subVideos]);
106340
+ const audios = dedupeElementsById([...mainAudios, ...subAudios]);
106155
106341
  for (const video of videos) {
106156
106342
  if (isHttpUrl(video.src)) continue;
106157
- const videoPath = resolve7(projectDir, video.src);
106343
+ const videoPath = resolve8(projectDir, video.src);
106158
106344
  const reencode = `ffmpeg -i "${video.src}" -c:v libx264 -r 30 -g 30 -keyint_min 30 -movflags +faststart -c:a copy output.mp4`;
106159
106345
  Promise.all([analyzeKeyframeIntervals(videoPath), extractVideoMetadata(videoPath)]).then(([analysis, metadata]) => {
106160
106346
  if (analysis.isProblematic) {
@@ -106170,22 +106356,6 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
106170
106356
  }).catch(() => {
106171
106357
  });
106172
106358
  }
106173
- const autoIdVideos = videos.filter((v) => v.id.startsWith("hf-video-"));
106174
- let htmlWithIds = html;
106175
- if (autoIdVideos.length > 0) {
106176
- const { document: idDoc } = parseHTML(html);
106177
- let changed = false;
106178
- for (const v of autoIdVideos) {
106179
- const el = idDoc.querySelector(`video[src="${v.src}"]:not([id])`);
106180
- if (el) {
106181
- el.id = v.id;
106182
- changed = true;
106183
- }
106184
- }
106185
- if (changed) {
106186
- htmlWithIds = idDoc.documentElement?.outerHTML ?? html;
106187
- }
106188
- }
106189
106359
  const { document: document2 } = parseHTML(html);
106190
106360
  const rootEl = document2.querySelector("[data-composition-id]");
106191
106361
  const width = rootEl ? parseInt(rootEl.getAttribute("data-width") || "1080", 10) : 1080;
@@ -106194,7 +106364,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
106194
106364
  rootEl.getAttribute("data-duration") || rootEl.getAttribute("data-composition-duration") || "0"
106195
106365
  ) : 0;
106196
106366
  return {
106197
- html: htmlWithIds,
106367
+ html,
106198
106368
  subCompositions,
106199
106369
  videos,
106200
106370
  audios,
@@ -106284,8 +106454,8 @@ async function recompileWithResolutions(compiled, resolutions, projectDir, downl
106284
106454
  } = await parseSubCompositions(html, projectDir, downloadDir);
106285
106455
  const mainVideos = parseVideoElements(html);
106286
106456
  const mainAudios = parseAudioElements(html);
106287
- const videos = dedupeElementsById([...subVideos, ...mainVideos]);
106288
- const audios = dedupeElementsById([...subAudios, ...mainAudios]);
106457
+ const videos = dedupeElementsById([...mainVideos, ...subVideos]);
106458
+ const audios = dedupeElementsById([...mainAudios, ...subAudios]);
106289
106459
  const remaining = compiled.unresolvedCompositions.filter(
106290
106460
  (c) => !resolutions.some((r) => r.id === c.id)
106291
106461
  );
@@ -106396,12 +106566,12 @@ function installDebugLogger(logPath, log = defaultLogger) {
106396
106566
  };
106397
106567
  }
106398
106568
  function writeCompiledArtifacts(compiled, workDir, includeSummary) {
106399
- const compileDir = join12(workDir, "compiled");
106569
+ const compileDir = join13(workDir, "compiled");
106400
106570
  mkdirSync9(compileDir, { recursive: true });
106401
- writeFileSync3(join12(compileDir, "index.html"), compiled.html, "utf-8");
106571
+ writeFileSync3(join13(compileDir, "index.html"), compiled.html, "utf-8");
106402
106572
  for (const [srcPath, html] of compiled.subCompositions) {
106403
- const outPath = join12(compileDir, srcPath);
106404
- mkdirSync9(dirname9(outPath), { recursive: true });
106573
+ const outPath = join13(compileDir, srcPath);
106574
+ mkdirSync9(dirname10(outPath), { recursive: true });
106405
106575
  writeFileSync3(outPath, html, "utf-8");
106406
106576
  }
106407
106577
  if (includeSummary) {
@@ -106425,7 +106595,7 @@ function writeCompiledArtifacts(compiled, workDir, includeSummary) {
106425
106595
  })),
106426
106596
  subCompositions: Array.from(compiled.subCompositions.keys())
106427
106597
  };
106428
- writeFileSync3(join12(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
106598
+ writeFileSync3(join13(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
106429
106599
  }
106430
106600
  }
106431
106601
  function createRenderJob(config2) {
@@ -106468,10 +106638,10 @@ function extractStandaloneEntryFromIndex(indexHtml, entryFile) {
106468
106638
  return document2.toString();
106469
106639
  }
106470
106640
  async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSignal) {
106471
- const moduleDir = dirname9(fileURLToPath3(import.meta.url));
106472
- const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve8(process.env.PRODUCER_RENDERS_DIR, "..") : resolve8(moduleDir, "../..");
106473
- const debugDir = join12(producerRoot, ".debug");
106474
- const workDir = job.config.debug ? join12(debugDir, job.id) : join12(dirname9(outputPath), `work-${job.id}`);
106641
+ const moduleDir = dirname10(fileURLToPath3(import.meta.url));
106642
+ const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve9(process.env.PRODUCER_RENDERS_DIR, "..") : resolve9(moduleDir, "../..");
106643
+ const debugDir = join13(producerRoot, ".debug");
106644
+ const workDir = job.config.debug ? join13(debugDir, job.id) : join13(dirname10(outputPath), `work-${job.id}`);
106475
106645
  const pipelineStart = Date.now();
106476
106646
  const log = job.config.logger ?? defaultLogger;
106477
106647
  let fileServer = null;
@@ -106479,7 +106649,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106479
106649
  let lastBrowserConsole = [];
106480
106650
  let restoreLogger = null;
106481
106651
  const perfStages = {};
106482
- const perfOutputPath = join12(workDir, "perf-summary.json");
106652
+ const perfOutputPath = join13(workDir, "perf-summary.json");
106483
106653
  const cfg = { ...job.config.producerConfig ?? resolveConfig() };
106484
106654
  const outputFormat = job.config.format ?? "mp4";
106485
106655
  const isWebm = outputFormat === "webm";
@@ -106499,19 +106669,19 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106499
106669
  assertNotAborted();
106500
106670
  if (!existsSync14(workDir)) mkdirSync9(workDir, { recursive: true });
106501
106671
  if (job.config.debug) {
106502
- const logPath = join12(workDir, "render.log");
106672
+ const logPath = join13(workDir, "render.log");
106503
106673
  restoreLogger = installDebugLogger(logPath, log);
106504
106674
  }
106505
106675
  const entryFile = job.config.entryFile || "index.html";
106506
- let htmlPath = join12(projectDir, entryFile);
106676
+ let htmlPath = join13(projectDir, entryFile);
106507
106677
  if (!existsSync14(htmlPath)) {
106508
106678
  throw new Error(`Entry file not found: ${htmlPath}`);
106509
106679
  }
106510
106680
  assertNotAborted();
106511
106681
  const rawEntry = readFileSync8(htmlPath, "utf-8");
106512
106682
  if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
106513
- const wrapperPath = join12(workDir, "standalone-entry.html");
106514
- const projectIndexPath = join12(projectDir, "index.html");
106683
+ const wrapperPath = join13(workDir, "standalone-entry.html");
106684
+ const projectIndexPath = join13(projectDir, "index.html");
106515
106685
  if (!existsSync14(projectIndexPath)) {
106516
106686
  throw new Error(
106517
106687
  `Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
@@ -106535,7 +106705,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106535
106705
  const stage1Start = Date.now();
106536
106706
  updateJobStatus(job, "preprocessing", "Compiling composition", 5, onProgress);
106537
106707
  const compileStart = Date.now();
106538
- let compiled = await compileForRender(projectDir, htmlPath, join12(workDir, "downloads"));
106708
+ let compiled = await compileForRender(projectDir, htmlPath, join13(workDir, "downloads"));
106539
106709
  assertNotAborted();
106540
106710
  perfStages.compileOnlyMs = Date.now() - compileStart;
106541
106711
  writeCompiledArtifacts(compiled, workDir, Boolean(job.config.debug));
@@ -106564,7 +106734,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106564
106734
  reasons.push(`${compiled.unresolvedCompositions.length} unresolved composition(s)`);
106565
106735
  fileServer = await createFileServer2({
106566
106736
  projectDir,
106567
- compiledDir: join12(workDir, "compiled"),
106737
+ compiledDir: join13(workDir, "compiled"),
106568
106738
  port: 0
106569
106739
  });
106570
106740
  assertNotAborted();
@@ -106577,7 +106747,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106577
106747
  };
106578
106748
  probeSession = await createCaptureSession(
106579
106749
  fileServer.url,
106580
- join12(workDir, "probe"),
106750
+ join13(workDir, "probe"),
106581
106751
  captureOpts,
106582
106752
  null,
106583
106753
  cfg
@@ -106609,7 +106779,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106609
106779
  compiled,
106610
106780
  resolutions,
106611
106781
  projectDir,
106612
- join12(workDir, "downloads")
106782
+ join13(workDir, "downloads")
106613
106783
  );
106614
106784
  assertNotAborted();
106615
106785
  composition.videos = compiled.videos;
@@ -106706,7 +106876,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106706
106876
  const extractionResult = await extractAllVideoFrames(
106707
106877
  composition.videos,
106708
106878
  projectDir,
106709
- { fps: job.config.fps, outputDir: join12(workDir, "video-frames") },
106879
+ { fps: job.config.fps, outputDir: join13(workDir, "video-frames") },
106710
106880
  abortSignal
106711
106881
  );
106712
106882
  assertNotAborted();
@@ -106738,13 +106908,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106738
106908
  }
106739
106909
  const stage3Start = Date.now();
106740
106910
  updateJobStatus(job, "preprocessing", "Processing audio tracks", 20, onProgress);
106741
- const audioOutputPath = join12(workDir, "audio.aac");
106911
+ const audioOutputPath = join13(workDir, "audio.aac");
106742
106912
  let hasAudio = false;
106743
106913
  if (composition.audios.length > 0) {
106744
106914
  const audioResult = await processCompositionAudio(
106745
106915
  composition.audios,
106746
106916
  projectDir,
106747
- join12(workDir, "audio-work"),
106917
+ join13(workDir, "audio-work"),
106748
106918
  audioOutputPath,
106749
106919
  job.duration,
106750
106920
  abortSignal
@@ -106760,12 +106930,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106760
106930
  if (!fileServer) {
106761
106931
  fileServer = await createFileServer2({
106762
106932
  projectDir,
106763
- compiledDir: join12(workDir, "compiled"),
106933
+ compiledDir: join13(workDir, "compiled"),
106764
106934
  port: 0
106765
106935
  });
106766
106936
  assertNotAborted();
106767
106937
  }
106768
- const framesDir = join12(workDir, "captured-frames");
106938
+ const framesDir = join13(workDir, "captured-frames");
106769
106939
  if (!existsSync14(framesDir)) mkdirSync9(framesDir, { recursive: true });
106770
106940
  const captureOptions = {
106771
106941
  width,
@@ -106776,7 +106946,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106776
106946
  };
106777
106947
  const workerCount = calculateOptimalWorkers(job.totalFrames, job.config.workers, cfg);
106778
106948
  const videoExt = isWebm ? ".webm" : ".mp4";
106779
- const videoOnlyPath = join12(workDir, `video-only${videoExt}`);
106949
+ const videoOnlyPath = join13(workDir, `video-only${videoExt}`);
106780
106950
  const preset = getEncoderPreset(job.config.quality, outputFormat);
106781
106951
  job.framesRendered = 0;
106782
106952
  let streamingEncoder = null;
@@ -107055,7 +107225,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107055
107225
  }
107056
107226
  if (job.config.debug) {
107057
107227
  if (existsSync14(outputPath)) {
107058
- const debugOutput = join12(workDir, isWebm ? "output.webm" : "output.mp4");
107228
+ const debugOutput = join13(workDir, isWebm ? "output.webm" : "output.mp4");
107059
107229
  copyFileSync2(outputPath, debugOutput);
107060
107230
  }
107061
107231
  } else {
@@ -107150,7 +107320,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
107150
107320
 
107151
107321
  // src/services/hyperframeLint.ts
107152
107322
  import { existsSync as existsSync15, readFileSync as readFileSync9, statSync as statSync6 } from "node:fs";
107153
- import { resolve as resolve9, join as join13 } from "node:path";
107323
+ import { resolve as resolve10, join as join14 } from "node:path";
107154
107324
  function isStringRecord(value) {
107155
107325
  if (!value || typeof value !== "object" || Array.isArray(value)) {
107156
107326
  return false;
@@ -107177,7 +107347,7 @@ function pickEntryFile(files, preferredEntryFile) {
107177
107347
  return null;
107178
107348
  }
107179
107349
  function readProjectEntryFile(projectDir, preferredEntryFile) {
107180
- const absProjectDir = resolve9(projectDir);
107350
+ const absProjectDir = resolve10(projectDir);
107181
107351
  if (!existsSync15(absProjectDir) || !statSync6(absProjectDir).isDirectory()) {
107182
107352
  return { error: `Project directory not found: ${absProjectDir}` };
107183
107353
  }
@@ -107185,7 +107355,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
107185
107355
  (value) => typeof value === "string" && value.trim().length > 0
107186
107356
  );
107187
107357
  for (const entryFile of entryCandidates) {
107188
- const absoluteEntryPath = resolve9(absProjectDir, entryFile);
107358
+ const absoluteEntryPath = resolve10(absProjectDir, entryFile);
107189
107359
  if (!absoluteEntryPath.startsWith(absProjectDir)) {
107190
107360
  return { error: `Entry file must stay inside project directory: ${entryFile}` };
107191
107361
  }
@@ -107198,7 +107368,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
107198
107368
  }
107199
107369
  }
107200
107370
  return {
107201
- error: `No HTML entry file found in project directory: ${join13(absProjectDir, preferredEntryFile || "index.html")}`
107371
+ error: `No HTML entry file found in project directory: ${join14(absProjectDir, preferredEntryFile || "index.html")}`
107202
107372
  };
107203
107373
  }
107204
107374
  function prepareHyperframeLintBody(body) {
@@ -107239,13 +107409,13 @@ function runHyperframeLint(prepared) {
107239
107409
  }
107240
107410
 
107241
107411
  // src/utils/paths.ts
107242
- import { resolve as resolve10, basename as basename2, join as join14 } from "node:path";
107243
- var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve10(new URL(import.meta.url).pathname, "../../..", "renders");
107412
+ import { resolve as resolve11, basename as basename2, join as join15 } from "node:path";
107413
+ var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve11(new URL(import.meta.url).pathname, "../../..", "renders");
107244
107414
  function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
107245
- const absoluteProjectDir = resolve10(projectDir);
107415
+ const absoluteProjectDir = resolve11(projectDir);
107246
107416
  const projectName = basename2(absoluteProjectDir);
107247
- const resolvedOutputPath = outputPath ?? join14(rendersDir, `${projectName}.mp4`);
107248
- const absoluteOutputPath = resolve10(resolvedOutputPath);
107417
+ const resolvedOutputPath = outputPath ?? join15(rendersDir, `${projectName}.mp4`);
107418
+ const absoluteOutputPath = resolve11(resolvedOutputPath);
107249
107419
  return { absoluteProjectDir, absoluteOutputPath };
107250
107420
  }
107251
107421
 
@@ -107265,12 +107435,12 @@ async function prepareRenderBody(body) {
107265
107435
  const options = parseRenderOptions(body);
107266
107436
  const projectDir = typeof body.projectDir === "string" ? body.projectDir : void 0;
107267
107437
  if (projectDir) {
107268
- const absProjectDir = resolve11(projectDir);
107438
+ const absProjectDir = resolve12(projectDir);
107269
107439
  if (!existsSync16(absProjectDir) || !statSync7(absProjectDir).isDirectory()) {
107270
107440
  return { error: `Project directory not found: ${absProjectDir}` };
107271
107441
  }
107272
107442
  const entry = options.entryFile || "index.html";
107273
- if (!existsSync16(resolve11(absProjectDir, entry))) {
107443
+ if (!existsSync16(resolve12(absProjectDir, entry))) {
107274
107444
  return { error: `Entry file "${entry}" not found in project directory: ${absProjectDir}` };
107275
107445
  }
107276
107446
  return { prepared: { input: { projectDir: absProjectDir, ...options } } };
@@ -107295,8 +107465,8 @@ async function prepareRenderBody(body) {
107295
107465
  }
107296
107466
  }
107297
107467
  const tempRoot = process.env.PRODUCER_TMP_PROJECT_DIR || tmpdir2();
107298
- const tempProjectDir = mkdtempSync(join15(tempRoot, "producer-project-"));
107299
- writeFileSync4(join15(tempProjectDir, "index.html"), htmlContent, "utf-8");
107468
+ const tempProjectDir = mkdtempSync(join16(tempRoot, "producer-project-"));
107469
+ writeFileSync4(join16(tempProjectDir, "index.html"), htmlContent, "utf-8");
107300
107470
  return {
107301
107471
  prepared: {
107302
107472
  input: {
@@ -107311,7 +107481,7 @@ function resolveOutputPath(projectDir, outputCandidate, rendersDir, log) {
107311
107481
  try {
107312
107482
  return resolveRenderPaths(projectDir, outputCandidate, rendersDir).absoluteOutputPath;
107313
107483
  } catch (error) {
107314
- const fallbackPath = resolve11(rendersDir, `producer-fallback-${Date.now()}.mp4`);
107484
+ const fallbackPath = resolve12(rendersDir, `producer-fallback-${Date.now()}.mp4`);
107315
107485
  log.warn("Failed to resolve output path, using fallback", {
107316
107486
  fallback: fallbackPath,
107317
107487
  error: error instanceof Error ? error.message : String(error)
@@ -107416,7 +107586,7 @@ function createRenderHandlers(options = {}) {
107416
107586
  rendersDir,
107417
107587
  log
107418
107588
  );
107419
- const outputDir = dirname10(absoluteOutputPath);
107589
+ const outputDir = dirname11(absoluteOutputPath);
107420
107590
  if (!existsSync16(outputDir)) mkdirSync10(outputDir, { recursive: true });
107421
107591
  log.info("render started", {
107422
107592
  requestId,
@@ -107525,7 +107695,7 @@ function createRenderHandlers(options = {}) {
107525
107695
  rendersDir,
107526
107696
  log
107527
107697
  );
107528
- const outputDir = dirname10(absoluteOutputPath);
107698
+ const outputDir = dirname11(absoluteOutputPath);
107529
107699
  if (!existsSync16(outputDir)) mkdirSync10(outputDir, { recursive: true });
107530
107700
  log.info("render-stream started", { requestId, projectDir: input2.projectDir });
107531
107701
  const job = createRenderJob({
@@ -107669,7 +107839,7 @@ function startServer(options = {}) {
107669
107839
  process.on("SIGINT", () => shutdown("SIGINT"));
107670
107840
  return server;
107671
107841
  }
107672
- var entryScript = process.argv[1] ? resolve11(process.argv[1]) : "";
107842
+ var entryScript = process.argv[1] ? resolve12(process.argv[1]) : "";
107673
107843
  var isPublicServerEntry = entryScript.endsWith("/public-server.js") || entryScript.endsWith("/src/server.ts");
107674
107844
  if (isPublicServerEntry) {
107675
107845
  const { values } = parseArgs({