@hyperframes/producer 0.1.14 → 0.2.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2148,11 +2148,11 @@ function __extends(d, b) {
2148
2148
  }
2149
2149
  function __awaiter(thisArg, _arguments, P, generator) {
2150
2150
  function adopt(value) {
2151
- return value instanceof P ? value : new P(function(resolve12) {
2152
- resolve12(value);
2151
+ return value instanceof P ? value : new P(function(resolve13) {
2152
+ resolve13(value);
2153
2153
  });
2154
2154
  }
2155
- return new (P || (P = Promise))(function(resolve12, reject) {
2155
+ return new (P || (P = Promise))(function(resolve13, reject) {
2156
2156
  function fulfilled(value) {
2157
2157
  try {
2158
2158
  step(generator.next(value));
@@ -2168,7 +2168,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
2168
2168
  }
2169
2169
  }
2170
2170
  function step(result) {
2171
- result.done ? resolve12(result.value) : adopt(result.value).then(fulfilled, rejected);
2171
+ result.done ? resolve13(result.value) : adopt(result.value).then(fulfilled, rejected);
2172
2172
  }
2173
2173
  step((generator = generator.apply(thisArg, _arguments || [])).next());
2174
2174
  });
@@ -2331,14 +2331,14 @@ function __asyncValues(o) {
2331
2331
  }, i);
2332
2332
  function verb(n) {
2333
2333
  i[n] = o[n] && function(v) {
2334
- return new Promise(function(resolve12, reject) {
2335
- v = o[n](v), settle(resolve12, reject, v.done, v.value);
2334
+ return new Promise(function(resolve13, reject) {
2335
+ v = o[n](v), settle(resolve13, reject, v.done, v.value);
2336
2336
  });
2337
2337
  };
2338
2338
  }
2339
- function settle(resolve12, reject, d, v) {
2339
+ function settle(resolve13, reject, d, v) {
2340
2340
  Promise.resolve(v).then(function(v2) {
2341
- resolve12({ value: v2, done: d });
2341
+ resolve13({ value: v2, done: d });
2342
2342
  }, reject);
2343
2343
  }
2344
2344
  }
@@ -2863,7 +2863,7 @@ function of() {
2863
2863
  }
2864
2864
  function lastValueFrom(source2, config2) {
2865
2865
  var hasConfig = typeof config2 === "object";
2866
- return new Promise(function(resolve12, reject) {
2866
+ return new Promise(function(resolve13, reject) {
2867
2867
  var _hasValue = false;
2868
2868
  var _value;
2869
2869
  source2.subscribe({
@@ -2874,9 +2874,9 @@ function lastValueFrom(source2, config2) {
2874
2874
  error: reject,
2875
2875
  complete: function() {
2876
2876
  if (_hasValue) {
2877
- resolve12(_value);
2877
+ resolve13(_value);
2878
2878
  } else if (hasConfig) {
2879
- resolve12(config2.defaultValue);
2879
+ resolve13(config2.defaultValue);
2880
2880
  } else {
2881
2881
  reject(new EmptyError());
2882
2882
  }
@@ -2886,16 +2886,16 @@ function lastValueFrom(source2, config2) {
2886
2886
  }
2887
2887
  function firstValueFrom(source2, config2) {
2888
2888
  var hasConfig = typeof config2 === "object";
2889
- return new Promise(function(resolve12, reject) {
2889
+ return new Promise(function(resolve13, reject) {
2890
2890
  var subscriber = new SafeSubscriber({
2891
2891
  next: function(value) {
2892
- resolve12(value);
2892
+ resolve13(value);
2893
2893
  subscriber.unsubscribe();
2894
2894
  },
2895
2895
  error: reject,
2896
2896
  complete: function() {
2897
2897
  if (hasConfig) {
2898
- resolve12(config2.defaultValue);
2898
+ resolve13(config2.defaultValue);
2899
2899
  } else {
2900
2900
  reject(new EmptyError());
2901
2901
  }
@@ -3934,7 +3934,7 @@ var init_rxjs = __esm({
3934
3934
  Observable2.prototype.forEach = function(next, promiseCtor) {
3935
3935
  var _this = this;
3936
3936
  promiseCtor = getPromiseCtor(promiseCtor);
3937
- return new promiseCtor(function(resolve12, reject) {
3937
+ return new promiseCtor(function(resolve13, reject) {
3938
3938
  var subscriber = new SafeSubscriber({
3939
3939
  next: function(value) {
3940
3940
  try {
@@ -3945,7 +3945,7 @@ var init_rxjs = __esm({
3945
3945
  }
3946
3946
  },
3947
3947
  error: reject,
3948
- complete: resolve12
3948
+ complete: resolve13
3949
3949
  });
3950
3950
  _this.subscribe(subscriber);
3951
3951
  });
@@ -3967,14 +3967,14 @@ var init_rxjs = __esm({
3967
3967
  Observable2.prototype.toPromise = function(promiseCtor) {
3968
3968
  var _this = this;
3969
3969
  promiseCtor = getPromiseCtor(promiseCtor);
3970
- return new promiseCtor(function(resolve12, reject) {
3970
+ return new promiseCtor(function(resolve13, reject) {
3971
3971
  var value;
3972
3972
  _this.subscribe(function(x) {
3973
3973
  return value = x;
3974
3974
  }, function(err) {
3975
3975
  return reject(err);
3976
3976
  }, function() {
3977
- return resolve12(value);
3977
+ return resolve13(value);
3978
3978
  });
3979
3979
  });
3980
3980
  };
@@ -6404,8 +6404,8 @@ var init_Deferred = __esm({
6404
6404
  // SAFETY: This is ensured by #taskPromise.
6405
6405
  #resolve;
6406
6406
  // TODO: Switch to Promise.withResolvers with Node 22
6407
- #taskPromise = new Promise((resolve12) => {
6408
- this.#resolve = resolve12;
6407
+ #taskPromise = new Promise((resolve13) => {
6408
+ this.#resolve = resolve13;
6409
6409
  });
6410
6410
  #timeoutId;
6411
6411
  #timeoutError;
@@ -6495,12 +6495,12 @@ var init_Mutex = __esm({
6495
6495
  return new _Mutex.Guard(this, onRelease);
6496
6496
  }
6497
6497
  release() {
6498
- const resolve12 = this.#acquirers.shift();
6499
- if (!resolve12) {
6498
+ const resolve13 = this.#acquirers.shift();
6499
+ if (!resolve13) {
6500
6500
  this.#locked = false;
6501
6501
  return;
6502
6502
  }
6503
- resolve12();
6503
+ resolve13();
6504
6504
  }
6505
6505
  };
6506
6506
  }
@@ -8515,12 +8515,12 @@ var init_locators = __esm({
8515
8515
  }
8516
8516
  return defer(() => {
8517
8517
  return from(handle.evaluate((element) => {
8518
- return new Promise((resolve12) => {
8518
+ return new Promise((resolve13) => {
8519
8519
  window.requestAnimationFrame(() => {
8520
8520
  const rect1 = element.getBoundingClientRect();
8521
8521
  window.requestAnimationFrame(() => {
8522
8522
  const rect2 = element.getBoundingClientRect();
8523
- resolve12([
8523
+ resolve13([
8524
8524
  {
8525
8525
  x: rect1.x,
8526
8526
  y: rect1.y,
@@ -10259,9 +10259,9 @@ var init_ElementHandle = __esm({
10259
10259
  const handle = await this.#asSVGElementHandle();
10260
10260
  const target = __addDisposableResource6(env_5, handle && await handle.#getOwnerSVGElement(), false);
10261
10261
  return await (target ?? this).evaluate(async (element, threshold) => {
10262
- const visibleRatio = await new Promise((resolve12) => {
10262
+ const visibleRatio = await new Promise((resolve13) => {
10263
10263
  const observer = new IntersectionObserver((entries2) => {
10264
- resolve12(entries2[0].intersectionRatio);
10264
+ resolve13(entries2[0].intersectionRatio);
10265
10265
  observer.disconnect();
10266
10266
  });
10267
10267
  observer.observe(element);
@@ -10907,7 +10907,7 @@ var init_Frame = __esm({
10907
10907
  }
10908
10908
  type = type ?? "text/javascript";
10909
10909
  return await this.mainRealm().transferHandle(await this.isolatedRealm().evaluateHandle(async ({ url, id, type: type2, content: content2 }) => {
10910
- return await new Promise((resolve12, reject) => {
10910
+ return await new Promise((resolve13, reject) => {
10911
10911
  const script = document.createElement("script");
10912
10912
  script.type = type2;
10913
10913
  script.text = content2;
@@ -10920,12 +10920,12 @@ var init_Frame = __esm({
10920
10920
  if (url) {
10921
10921
  script.src = url;
10922
10922
  script.addEventListener("load", () => {
10923
- resolve12(script);
10923
+ resolve13(script);
10924
10924
  }, { once: true });
10925
10925
  document.head.appendChild(script);
10926
10926
  } else {
10927
10927
  document.head.appendChild(script);
10928
- resolve12(script);
10928
+ resolve13(script);
10929
10929
  }
10930
10930
  });
10931
10931
  }, { ...options, type, content }));
@@ -10945,7 +10945,7 @@ var init_Frame = __esm({
10945
10945
  options.content = content;
10946
10946
  }
10947
10947
  return await this.mainRealm().transferHandle(await this.isolatedRealm().evaluateHandle(async ({ url, content: content2 }) => {
10948
- return await new Promise((resolve12, reject) => {
10948
+ return await new Promise((resolve13, reject) => {
10949
10949
  let element;
10950
10950
  if (!url) {
10951
10951
  element = document.createElement("style");
@@ -10957,7 +10957,7 @@ var init_Frame = __esm({
10957
10957
  element = link;
10958
10958
  }
10959
10959
  element.addEventListener("load", () => {
10960
- resolve12(element);
10960
+ resolve13(element);
10961
10961
  }, { once: true });
10962
10962
  element.addEventListener("error", (event) => {
10963
10963
  reject(new Error(event.message ?? "Could not load style"));
@@ -12696,9 +12696,9 @@ var init_Page = __esm({
12696
12696
  ++this.#screencastSessionCount;
12697
12697
  if (!this.#startScreencastPromise) {
12698
12698
  this.#startScreencastPromise = this.mainFrame().client.send("Page.startScreencast", { format: "png" }).then(() => {
12699
- return new Promise((resolve12) => {
12699
+ return new Promise((resolve13) => {
12700
12700
  return this.mainFrame().client.once("Page.screencastFrame", () => {
12701
- return resolve12();
12701
+ return resolve13();
12702
12702
  });
12703
12703
  });
12704
12704
  });
@@ -16016,11 +16016,11 @@ function addPageBinding(type, name, prefix) {
16016
16016
  return value instanceof Node;
16017
16017
  })
16018
16018
  }));
16019
- return new Promise((resolve12, reject) => {
16019
+ return new Promise((resolve13, reject) => {
16020
16020
  callPuppeteer.callbacks.set(seq, {
16021
16021
  resolve(value) {
16022
16022
  callPuppeteer.args.delete(seq);
16023
- resolve12(value);
16023
+ resolve13(value);
16024
16024
  },
16025
16025
  reject(value) {
16026
16026
  callPuppeteer.args.delete(seq);
@@ -19683,8 +19683,8 @@ var init_Input2 = __esm({
19683
19683
  if (typeof delay === "number") {
19684
19684
  await Promise.all(actions);
19685
19685
  actions.length = 0;
19686
- await new Promise((resolve12) => {
19687
- setTimeout(resolve12, delay);
19686
+ await new Promise((resolve13) => {
19687
+ setTimeout(resolve13, delay);
19688
19688
  });
19689
19689
  }
19690
19690
  actions.push(this.up({ ...options, clickCount }));
@@ -19704,9 +19704,9 @@ var init_Input2 = __esm({
19704
19704
  });
19705
19705
  }
19706
19706
  async drag(start, target) {
19707
- const promise = new Promise((resolve12) => {
19707
+ const promise = new Promise((resolve13) => {
19708
19708
  this.#client.once("Input.dragIntercepted", (event) => {
19709
- return resolve12(event.data);
19709
+ return resolve13(event.data);
19710
19710
  });
19711
19711
  });
19712
19712
  await this.move(start.x, start.y);
@@ -19747,8 +19747,8 @@ var init_Input2 = __esm({
19747
19747
  await this.dragEnter(target, data);
19748
19748
  await this.dragOver(target, data);
19749
19749
  if (delay) {
19750
- await new Promise((resolve12) => {
19751
- return setTimeout(resolve12, delay);
19750
+ await new Promise((resolve13) => {
19751
+ return setTimeout(resolve13, delay);
19752
19752
  });
19753
19753
  }
19754
19754
  await this.drop(target, data);
@@ -20632,9 +20632,9 @@ var init_Page2 = __esm({
20632
20632
  async captureHeapSnapshot(options) {
20633
20633
  const { createWriteStream: createWriteStream3 } = environment.value.fs;
20634
20634
  const stream2 = createWriteStream3(options.path);
20635
- const streamPromise = new Promise((resolve12, reject) => {
20635
+ const streamPromise = new Promise((resolve13, reject) => {
20636
20636
  stream2.on("error", reject);
20637
- stream2.on("finish", resolve12);
20637
+ stream2.on("finish", resolve13);
20638
20638
  });
20639
20639
  const client = this.#primaryTargetClient;
20640
20640
  await client.send("HeapProfiler.enable");
@@ -22276,10 +22276,10 @@ var init_BrowserWebSocketTransport = __esm({
22276
22276
  "../../node_modules/.bun/puppeteer-core@24.40.0/node_modules/puppeteer-core/lib/esm/puppeteer/common/BrowserWebSocketTransport.js"() {
22277
22277
  BrowserWebSocketTransport = class _BrowserWebSocketTransport {
22278
22278
  static create(url) {
22279
- return new Promise((resolve12, reject) => {
22279
+ return new Promise((resolve13, reject) => {
22280
22280
  const ws = new WebSocket(url);
22281
22281
  ws.addEventListener("open", () => {
22282
- return resolve12(new _BrowserWebSocketTransport(ws));
22282
+ return resolve13(new _BrowserWebSocketTransport(ws));
22283
22283
  });
22284
22284
  ws.addEventListener("error", reject);
22285
22285
  });
@@ -25201,11 +25201,11 @@ var require_BrowsingContextProcessor = __commonJS({
25201
25201
  }
25202
25202
  const parentCdpClient = context2.cdpTarget.parentCdpClient;
25203
25203
  try {
25204
- const detachedFromTargetPromise = new Promise((resolve12) => {
25204
+ const detachedFromTargetPromise = new Promise((resolve13) => {
25205
25205
  const onContextDestroyed = (event) => {
25206
25206
  if (event.targetId === params.context) {
25207
25207
  parentCdpClient.off("Target.detachedFromTarget", onContextDestroyed);
25208
- resolve12();
25208
+ resolve13();
25209
25209
  }
25210
25210
  };
25211
25211
  parentCdpClient.on("Target.detachedFromTarget", onContextDestroyed);
@@ -26568,7 +26568,7 @@ var require_ActionDispatcher = __commonJS({
26568
26568
  }
26569
26569
  }
26570
26570
  const promises = [
26571
- new Promise((resolve12) => setTimeout(resolve12, this.#tickDuration))
26571
+ new Promise((resolve13) => setTimeout(resolve13, this.#tickDuration))
26572
26572
  ];
26573
26573
  for (const option of options) {
26574
26574
  promises.push(this.#dispatchAction(option));
@@ -27169,8 +27169,8 @@ var require_Mutex = __commonJS({
27169
27169
  acquire() {
27170
27170
  const state = { resolved: false };
27171
27171
  if (this.#locked) {
27172
- return new Promise((resolve12) => {
27173
- this.#acquirers.push(() => resolve12(this.#release.bind(this, state)));
27172
+ return new Promise((resolve13) => {
27173
+ this.#acquirers.push(() => resolve13(this.#release.bind(this, state)));
27174
27174
  });
27175
27175
  }
27176
27176
  this.#locked = true;
@@ -27181,12 +27181,12 @@ var require_Mutex = __commonJS({
27181
27181
  throw new Error("Cannot release more than once.");
27182
27182
  }
27183
27183
  state.resolved = true;
27184
- const resolve12 = this.#acquirers.shift();
27185
- if (!resolve12) {
27184
+ const resolve13 = this.#acquirers.shift();
27185
+ if (!resolve13) {
27186
27186
  this.#locked = false;
27187
27187
  return;
27188
27188
  }
27189
- resolve12();
27189
+ resolve13();
27190
27190
  }
27191
27191
  async run(action) {
27192
27192
  const release = await this.acquire();
@@ -28368,8 +28368,8 @@ var require_ChannelProxy = __commonJS({
28368
28368
  * in the queue.
28369
28369
  */
28370
28370
  async getMessage() {
28371
- const onMessage = queue.length > 0 ? Promise.resolve() : new Promise((resolve12) => {
28372
- queueNonEmptyResolver = resolve12;
28371
+ const onMessage = queue.length > 0 ? Promise.resolve() : new Promise((resolve13) => {
28372
+ queueNonEmptyResolver = resolve13;
28373
28373
  });
28374
28374
  await onMessage;
28375
28375
  return queue.shift();
@@ -28474,7 +28474,7 @@ var require_ChannelProxy = __commonJS({
28474
28474
  functionDeclaration: String((id) => {
28475
28475
  const w = window;
28476
28476
  if (w[id] === void 0) {
28477
- return new Promise((resolve12) => w[id] = resolve12);
28477
+ return new Promise((resolve13) => w[id] = resolve13);
28478
28478
  }
28479
28479
  const channelProxy = w[id];
28480
28480
  delete w[id];
@@ -29975,8 +29975,8 @@ var require_Deferred = __commonJS({
29975
29975
  return this.#result;
29976
29976
  }
29977
29977
  constructor() {
29978
- this.#promise = new Promise((resolve12, reject) => {
29979
- this.#resolve = resolve12;
29978
+ this.#promise = new Promise((resolve13, reject) => {
29979
+ this.#resolve = resolve13;
29980
29980
  this.#reject = reject;
29981
29981
  });
29982
29982
  this.#promise.catch((_error) => {
@@ -34820,11 +34820,11 @@ var require_BrowsingContextStorage = __commonJS({
34820
34820
  if (this.#contexts.has(browsingContextId)) {
34821
34821
  return Promise.resolve(this.getContext(browsingContextId));
34822
34822
  }
34823
- return new Promise((resolve12) => {
34823
+ return new Promise((resolve13) => {
34824
34824
  const listener = (event) => {
34825
34825
  if (event.browsingContext.id === browsingContextId) {
34826
34826
  this.#eventEmitter.off("added", listener);
34827
- resolve12(event.browsingContext);
34827
+ resolve13(event.browsingContext);
34828
34828
  }
34829
34829
  };
34830
34830
  this.#eventEmitter.on("added", listener);
@@ -38406,8 +38406,8 @@ var init_ExposedFunction = __esm({
38406
38406
  const functionDeclaration = stringifyFunction(interpolateFunction((callback) => {
38407
38407
  Object.assign(globalThis, {
38408
38408
  [PLACEHOLDER("name")]: function(...args) {
38409
- return new Promise((resolve12, reject) => {
38410
- callback([resolve12, reject, args]);
38409
+ return new Promise((resolve13, reject) => {
38410
+ callback([resolve13, reject, args]);
38411
38411
  });
38412
38412
  }
38413
38413
  });
@@ -38495,8 +38495,8 @@ var init_ExposedFunction = __esm({
38495
38495
  return;
38496
38496
  }
38497
38497
  try {
38498
- await dataHandle.evaluate(([resolve12], result2) => {
38499
- resolve12(result2);
38498
+ await dataHandle.evaluate(([resolve13], result2) => {
38499
+ resolve13(result2);
38500
38500
  }, result);
38501
38501
  } catch (error) {
38502
38502
  debugError(error);
@@ -46577,7 +46577,7 @@ var init_NodeWebSocketTransport = __esm({
46577
46577
  init_version();
46578
46578
  NodeWebSocketTransport = class _NodeWebSocketTransport {
46579
46579
  static create(url, headers) {
46580
- return new Promise((resolve12, reject) => {
46580
+ return new Promise((resolve13, reject) => {
46581
46581
  const ws = new wrapper_default(url, [], {
46582
46582
  followRedirects: true,
46583
46583
  perMessageDeflate: false,
@@ -46590,7 +46590,7 @@ var init_NodeWebSocketTransport = __esm({
46590
46590
  }
46591
46591
  });
46592
46592
  ws.addEventListener("open", () => {
46593
- return resolve12(new _NodeWebSocketTransport(ws));
46593
+ return resolve13(new _NodeWebSocketTransport(ws));
46594
46594
  });
46595
46595
  ws.addEventListener("error", reject);
46596
46596
  });
@@ -49651,8 +49651,8 @@ var require_helpers = __commonJS({
49651
49651
  function req(url, opts = {}) {
49652
49652
  const href = typeof url === "string" ? url : url.href;
49653
49653
  const req2 = (href.startsWith("https:") ? https2 : http2).request(url, opts);
49654
- const promise = new Promise((resolve12, reject) => {
49655
- req2.once("response", resolve12).once("error", reject).end();
49654
+ const promise = new Promise((resolve13, reject) => {
49655
+ req2.once("response", resolve13).once("error", reject).end();
49656
49656
  });
49657
49657
  req2.then = promise.then.bind(promise);
49658
49658
  return req2;
@@ -50029,7 +50029,7 @@ var require_parse_proxy_response = __commonJS({
50029
50029
  var debug_1 = __importDefault2(require_src());
50030
50030
  var debug6 = (0, debug_1.default)("https-proxy-agent:parse-proxy-response");
50031
50031
  function parseProxyResponse(socket) {
50032
- return new Promise((resolve12, reject) => {
50032
+ return new Promise((resolve13, reject) => {
50033
50033
  let buffersLength = 0;
50034
50034
  const buffers = [];
50035
50035
  function read() {
@@ -50095,7 +50095,7 @@ var require_parse_proxy_response = __commonJS({
50095
50095
  }
50096
50096
  debug6("got proxy server response: %o %o", firstLine, headers);
50097
50097
  cleanup();
50098
- resolve12({
50098
+ resolve13({
50099
50099
  connect: {
50100
50100
  statusCode,
50101
50101
  statusText,
@@ -53353,11 +53353,11 @@ var require_socksclient = __commonJS({
53353
53353
  "use strict";
53354
53354
  var __awaiter3 = exports && exports.__awaiter || function(thisArg, _arguments, P, generator) {
53355
53355
  function adopt(value) {
53356
- return value instanceof P ? value : new P(function(resolve12) {
53357
- resolve12(value);
53356
+ return value instanceof P ? value : new P(function(resolve13) {
53357
+ resolve13(value);
53358
53358
  });
53359
53359
  }
53360
- return new (P || (P = Promise))(function(resolve12, reject) {
53360
+ return new (P || (P = Promise))(function(resolve13, reject) {
53361
53361
  function fulfilled(value) {
53362
53362
  try {
53363
53363
  step(generator.next(value));
@@ -53373,7 +53373,7 @@ var require_socksclient = __commonJS({
53373
53373
  }
53374
53374
  }
53375
53375
  function step(result) {
53376
- result.done ? resolve12(result.value) : adopt(result.value).then(fulfilled, rejected);
53376
+ result.done ? resolve13(result.value) : adopt(result.value).then(fulfilled, rejected);
53377
53377
  }
53378
53378
  step((generator = generator.apply(thisArg, _arguments || [])).next());
53379
53379
  });
@@ -53407,13 +53407,13 @@ var require_socksclient = __commonJS({
53407
53407
  * @returns { Promise }
53408
53408
  */
53409
53409
  static createConnection(options, callback) {
53410
- return new Promise((resolve12, reject) => {
53410
+ return new Promise((resolve13, reject) => {
53411
53411
  try {
53412
53412
  (0, helpers_1.validateSocksClientOptions)(options, ["connect"]);
53413
53413
  } catch (err) {
53414
53414
  if (typeof callback === "function") {
53415
53415
  callback(err);
53416
- return resolve12(err);
53416
+ return resolve13(err);
53417
53417
  } else {
53418
53418
  return reject(err);
53419
53419
  }
@@ -53424,16 +53424,16 @@ var require_socksclient = __commonJS({
53424
53424
  client.removeAllListeners();
53425
53425
  if (typeof callback === "function") {
53426
53426
  callback(null, info);
53427
- resolve12(info);
53427
+ resolve13(info);
53428
53428
  } else {
53429
- resolve12(info);
53429
+ resolve13(info);
53430
53430
  }
53431
53431
  });
53432
53432
  client.once("error", (err) => {
53433
53433
  client.removeAllListeners();
53434
53434
  if (typeof callback === "function") {
53435
53435
  callback(err);
53436
- resolve12(err);
53436
+ resolve13(err);
53437
53437
  } else {
53438
53438
  reject(err);
53439
53439
  }
@@ -53450,13 +53450,13 @@ var require_socksclient = __commonJS({
53450
53450
  * @returns { Promise }
53451
53451
  */
53452
53452
  static createConnectionChain(options, callback) {
53453
- return new Promise((resolve12, reject) => __awaiter3(this, void 0, void 0, function* () {
53453
+ return new Promise((resolve13, reject) => __awaiter3(this, void 0, void 0, function* () {
53454
53454
  try {
53455
53455
  (0, helpers_1.validateSocksClientChainOptions)(options);
53456
53456
  } catch (err) {
53457
53457
  if (typeof callback === "function") {
53458
53458
  callback(err);
53459
- return resolve12(err);
53459
+ return resolve13(err);
53460
53460
  } else {
53461
53461
  return reject(err);
53462
53462
  }
@@ -53482,14 +53482,14 @@ var require_socksclient = __commonJS({
53482
53482
  }
53483
53483
  if (typeof callback === "function") {
53484
53484
  callback(null, { socket: sock });
53485
- resolve12({ socket: sock });
53485
+ resolve13({ socket: sock });
53486
53486
  } else {
53487
- resolve12({ socket: sock });
53487
+ resolve13({ socket: sock });
53488
53488
  }
53489
53489
  } catch (err) {
53490
53490
  if (typeof callback === "function") {
53491
53491
  callback(err);
53492
- resolve12(err);
53492
+ resolve13(err);
53493
53493
  } else {
53494
53494
  reject(err);
53495
53495
  }
@@ -54173,12 +54173,12 @@ var require_dist4 = __commonJS({
54173
54173
  let { host } = opts;
54174
54174
  const { port, lookup: lookupFn = dns.lookup } = opts;
54175
54175
  if (shouldLookup) {
54176
- host = await new Promise((resolve12, reject) => {
54176
+ host = await new Promise((resolve13, reject) => {
54177
54177
  lookupFn(host, {}, (err, res) => {
54178
54178
  if (err) {
54179
54179
  reject(err);
54180
54180
  } else {
54181
- resolve12(res);
54181
+ resolve13(res);
54182
54182
  }
54183
54183
  });
54184
54184
  });
@@ -55363,7 +55363,7 @@ var require_netUtils = __commonJS({
55363
55363
  return `${socket.remoteAddress}:${socket.remotePort}`;
55364
55364
  }
55365
55365
  function upgradeSocket(socket, options) {
55366
- return new Promise((resolve12, reject) => {
55366
+ return new Promise((resolve13, reject) => {
55367
55367
  const tlsOptions = Object.assign({}, options, {
55368
55368
  socket
55369
55369
  });
@@ -55373,7 +55373,7 @@ var require_netUtils = __commonJS({
55373
55373
  reject(tlsSocket.authorizationError);
55374
55374
  } else {
55375
55375
  tlsSocket.removeAllListeners("error");
55376
- resolve12(tlsSocket);
55376
+ resolve13(tlsSocket);
55377
55377
  }
55378
55378
  }).once("error", (error) => {
55379
55379
  reject(error);
@@ -55468,7 +55468,7 @@ var require_transfer = __commonJS({
55468
55468
  };
55469
55469
  }
55470
55470
  function connectForPassiveTransfer(host, port, ftp) {
55471
- return new Promise((resolve12, reject) => {
55471
+ return new Promise((resolve13, reject) => {
55472
55472
  let socket = ftp._newSocket();
55473
55473
  const handleConnErr = function(err) {
55474
55474
  err.message = "Can't open data connection in passive mode: " + err.message;
@@ -55496,7 +55496,7 @@ var require_transfer = __commonJS({
55496
55496
  socket.removeListener("error", handleConnErr);
55497
55497
  socket.removeListener("timeout", handleTimeout);
55498
55498
  ftp.dataSocket = socket;
55499
- resolve12();
55499
+ resolve13();
55500
55500
  });
55501
55501
  });
55502
55502
  }
@@ -57894,7 +57894,7 @@ var require_util2 = __commonJS({
57894
57894
  return path12;
57895
57895
  }
57896
57896
  exports.normalize = normalize2;
57897
- function join16(aRoot, aPath) {
57897
+ function join17(aRoot, aPath) {
57898
57898
  if (aRoot === "") {
57899
57899
  aRoot = ".";
57900
57900
  }
@@ -57926,7 +57926,7 @@ var require_util2 = __commonJS({
57926
57926
  }
57927
57927
  return joined;
57928
57928
  }
57929
- exports.join = join16;
57929
+ exports.join = join17;
57930
57930
  exports.isAbsolute = function(aPath) {
57931
57931
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
57932
57932
  };
@@ -58099,7 +58099,7 @@ var require_util2 = __commonJS({
58099
58099
  parsed.path = parsed.path.substring(0, index + 1);
58100
58100
  }
58101
58101
  }
58102
- sourceURL = join16(urlGenerate(parsed), sourceURL);
58102
+ sourceURL = join17(urlGenerate(parsed), sourceURL);
58103
58103
  }
58104
58104
  return normalize2(sourceURL);
58105
58105
  }
@@ -59901,7 +59901,7 @@ var require_escodegen = __commonJS({
59901
59901
  function noEmptySpace() {
59902
59902
  return space ? space : " ";
59903
59903
  }
59904
- function join16(left2, right2) {
59904
+ function join17(left2, right2) {
59905
59905
  var leftSource, rightSource, leftCharCode, rightCharCode;
59906
59906
  leftSource = toSourceNodeWhenNeeded(left2).toString();
59907
59907
  if (leftSource.length === 0) {
@@ -60232,8 +60232,8 @@ var require_escodegen = __commonJS({
60232
60232
  } else {
60233
60233
  result.push(that.generateExpression(stmt.left, Precedence.Call, E_TTT));
60234
60234
  }
60235
- result = join16(result, operator);
60236
- result = [join16(
60235
+ result = join17(result, operator);
60236
+ result = [join17(
60237
60237
  result,
60238
60238
  that.generateExpression(stmt.right, Precedence.Assignment, E_TTT)
60239
60239
  ), ")"];
@@ -60376,11 +60376,11 @@ var require_escodegen = __commonJS({
60376
60376
  var result, fragment;
60377
60377
  result = ["class"];
60378
60378
  if (stmt.id) {
60379
- result = join16(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
60379
+ result = join17(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
60380
60380
  }
60381
60381
  if (stmt.superClass) {
60382
- fragment = join16("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
60383
- result = join16(result, fragment);
60382
+ fragment = join17("extends", this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
60383
+ result = join17(result, fragment);
60384
60384
  }
60385
60385
  result.push(space);
60386
60386
  result.push(this.generateStatement(stmt.body, S_TFFT));
@@ -60393,9 +60393,9 @@ var require_escodegen = __commonJS({
60393
60393
  return escapeDirective(stmt.directive) + this.semicolon(flags);
60394
60394
  },
60395
60395
  DoWhileStatement: function(stmt, flags) {
60396
- var result = join16("do", this.maybeBlock(stmt.body, S_TFFF));
60396
+ var result = join17("do", this.maybeBlock(stmt.body, S_TFFF));
60397
60397
  result = this.maybeBlockSuffix(stmt.body, result);
60398
- return join16(result, [
60398
+ return join17(result, [
60399
60399
  "while" + space + "(",
60400
60400
  this.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
60401
60401
  ")" + this.semicolon(flags)
@@ -60431,11 +60431,11 @@ var require_escodegen = __commonJS({
60431
60431
  ExportDefaultDeclaration: function(stmt, flags) {
60432
60432
  var result = ["export"], bodyFlags;
60433
60433
  bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
60434
- result = join16(result, "default");
60434
+ result = join17(result, "default");
60435
60435
  if (isStatement(stmt.declaration)) {
60436
- result = join16(result, this.generateStatement(stmt.declaration, bodyFlags));
60436
+ result = join17(result, this.generateStatement(stmt.declaration, bodyFlags));
60437
60437
  } else {
60438
- result = join16(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
60438
+ result = join17(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
60439
60439
  }
60440
60440
  return result;
60441
60441
  },
@@ -60443,15 +60443,15 @@ var require_escodegen = __commonJS({
60443
60443
  var result = ["export"], bodyFlags, that = this;
60444
60444
  bodyFlags = flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF;
60445
60445
  if (stmt.declaration) {
60446
- return join16(result, this.generateStatement(stmt.declaration, bodyFlags));
60446
+ return join17(result, this.generateStatement(stmt.declaration, bodyFlags));
60447
60447
  }
60448
60448
  if (stmt.specifiers) {
60449
60449
  if (stmt.specifiers.length === 0) {
60450
- result = join16(result, "{" + space + "}");
60450
+ result = join17(result, "{" + space + "}");
60451
60451
  } else if (stmt.specifiers[0].type === Syntax.ExportBatchSpecifier) {
60452
- result = join16(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
60452
+ result = join17(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
60453
60453
  } else {
60454
- result = join16(result, "{");
60454
+ result = join17(result, "{");
60455
60455
  withIndent(function(indent2) {
60456
60456
  var i, iz;
60457
60457
  result.push(newline);
@@ -60469,7 +60469,7 @@ var require_escodegen = __commonJS({
60469
60469
  result.push(base + "}");
60470
60470
  }
60471
60471
  if (stmt.source) {
60472
- result = join16(result, [
60472
+ result = join17(result, [
60473
60473
  "from" + space,
60474
60474
  // ModuleSpecifier
60475
60475
  this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
@@ -60557,7 +60557,7 @@ var require_escodegen = __commonJS({
60557
60557
  ];
60558
60558
  cursor = 0;
60559
60559
  if (stmt.specifiers[cursor].type === Syntax.ImportDefaultSpecifier) {
60560
- result = join16(result, [
60560
+ result = join17(result, [
60561
60561
  this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
60562
60562
  ]);
60563
60563
  ++cursor;
@@ -60567,7 +60567,7 @@ var require_escodegen = __commonJS({
60567
60567
  result.push(",");
60568
60568
  }
60569
60569
  if (stmt.specifiers[cursor].type === Syntax.ImportNamespaceSpecifier) {
60570
- result = join16(result, [
60570
+ result = join17(result, [
60571
60571
  space,
60572
60572
  this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
60573
60573
  ]);
@@ -60596,7 +60596,7 @@ var require_escodegen = __commonJS({
60596
60596
  }
60597
60597
  }
60598
60598
  }
60599
- result = join16(result, [
60599
+ result = join17(result, [
60600
60600
  "from" + space,
60601
60601
  // ModuleSpecifier
60602
60602
  this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
@@ -60650,7 +60650,7 @@ var require_escodegen = __commonJS({
60650
60650
  return result;
60651
60651
  },
60652
60652
  ThrowStatement: function(stmt, flags) {
60653
- return [join16(
60653
+ return [join17(
60654
60654
  "throw",
60655
60655
  this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
60656
60656
  ), this.semicolon(flags)];
@@ -60661,7 +60661,7 @@ var require_escodegen = __commonJS({
60661
60661
  result = this.maybeBlockSuffix(stmt.block, result);
60662
60662
  if (stmt.handlers) {
60663
60663
  for (i = 0, iz = stmt.handlers.length; i < iz; ++i) {
60664
- result = join16(result, this.generateStatement(stmt.handlers[i], S_TFFF));
60664
+ result = join17(result, this.generateStatement(stmt.handlers[i], S_TFFF));
60665
60665
  if (stmt.finalizer || i + 1 !== iz) {
60666
60666
  result = this.maybeBlockSuffix(stmt.handlers[i].body, result);
60667
60667
  }
@@ -60669,7 +60669,7 @@ var require_escodegen = __commonJS({
60669
60669
  } else {
60670
60670
  guardedHandlers = stmt.guardedHandlers || [];
60671
60671
  for (i = 0, iz = guardedHandlers.length; i < iz; ++i) {
60672
- result = join16(result, this.generateStatement(guardedHandlers[i], S_TFFF));
60672
+ result = join17(result, this.generateStatement(guardedHandlers[i], S_TFFF));
60673
60673
  if (stmt.finalizer || i + 1 !== iz) {
60674
60674
  result = this.maybeBlockSuffix(guardedHandlers[i].body, result);
60675
60675
  }
@@ -60677,13 +60677,13 @@ var require_escodegen = __commonJS({
60677
60677
  if (stmt.handler) {
60678
60678
  if (Array.isArray(stmt.handler)) {
60679
60679
  for (i = 0, iz = stmt.handler.length; i < iz; ++i) {
60680
- result = join16(result, this.generateStatement(stmt.handler[i], S_TFFF));
60680
+ result = join17(result, this.generateStatement(stmt.handler[i], S_TFFF));
60681
60681
  if (stmt.finalizer || i + 1 !== iz) {
60682
60682
  result = this.maybeBlockSuffix(stmt.handler[i].body, result);
60683
60683
  }
60684
60684
  }
60685
60685
  } else {
60686
- result = join16(result, this.generateStatement(stmt.handler, S_TFFF));
60686
+ result = join17(result, this.generateStatement(stmt.handler, S_TFFF));
60687
60687
  if (stmt.finalizer) {
60688
60688
  result = this.maybeBlockSuffix(stmt.handler.body, result);
60689
60689
  }
@@ -60691,7 +60691,7 @@ var require_escodegen = __commonJS({
60691
60691
  }
60692
60692
  }
60693
60693
  if (stmt.finalizer) {
60694
- result = join16(result, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
60694
+ result = join17(result, ["finally", this.maybeBlock(stmt.finalizer, S_TFFF)]);
60695
60695
  }
60696
60696
  return result;
60697
60697
  },
@@ -60725,7 +60725,7 @@ var require_escodegen = __commonJS({
60725
60725
  withIndent(function() {
60726
60726
  if (stmt.test) {
60727
60727
  result = [
60728
- join16("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
60728
+ join17("case", that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
60729
60729
  ":"
60730
60730
  ];
60731
60731
  } else {
@@ -60773,9 +60773,9 @@ var require_escodegen = __commonJS({
60773
60773
  result.push(this.maybeBlock(stmt.consequent, S_TFFF));
60774
60774
  result = this.maybeBlockSuffix(stmt.consequent, result);
60775
60775
  if (stmt.alternate.type === Syntax.IfStatement) {
60776
- result = join16(result, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
60776
+ result = join17(result, ["else ", this.generateStatement(stmt.alternate, bodyFlags)]);
60777
60777
  } else {
60778
- result = join16(result, join16("else", this.maybeBlock(stmt.alternate, bodyFlags)));
60778
+ result = join17(result, join17("else", this.maybeBlock(stmt.alternate, bodyFlags)));
60779
60779
  }
60780
60780
  } else {
60781
60781
  result.push(this.maybeBlock(stmt.consequent, bodyFlags));
@@ -60876,7 +60876,7 @@ var require_escodegen = __commonJS({
60876
60876
  },
60877
60877
  ReturnStatement: function(stmt, flags) {
60878
60878
  if (stmt.argument) {
60879
- return [join16(
60879
+ return [join17(
60880
60880
  "return",
60881
60881
  this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
60882
60882
  ), this.semicolon(flags)];
@@ -60965,14 +60965,14 @@ var require_escodegen = __commonJS({
60965
60965
  if (leftSource.charCodeAt(leftSource.length - 1) === 47 && esutils.code.isIdentifierPartES5(expr.operator.charCodeAt(0))) {
60966
60966
  result = [fragment, noEmptySpace(), expr.operator];
60967
60967
  } else {
60968
- result = join16(fragment, expr.operator);
60968
+ result = join17(fragment, expr.operator);
60969
60969
  }
60970
60970
  fragment = this.generateExpression(expr.right, rightPrecedence, flags);
60971
60971
  if (expr.operator === "/" && fragment.toString().charAt(0) === "/" || expr.operator.slice(-1) === "<" && fragment.toString().slice(0, 3) === "!--") {
60972
60972
  result.push(noEmptySpace());
60973
60973
  result.push(fragment);
60974
60974
  } else {
60975
- result = join16(result, fragment);
60975
+ result = join17(result, fragment);
60976
60976
  }
60977
60977
  if (expr.operator === "in" && !(flags & F_ALLOW_IN)) {
60978
60978
  return ["(", result, ")"];
@@ -61012,7 +61012,7 @@ var require_escodegen = __commonJS({
61012
61012
  var result, length, i, iz, itemFlags;
61013
61013
  length = expr["arguments"].length;
61014
61014
  itemFlags = flags & F_ALLOW_UNPARATH_NEW && !parentheses && length === 0 ? E_TFT : E_TFF;
61015
- result = join16(
61015
+ result = join17(
61016
61016
  "new",
61017
61017
  this.generateExpression(expr.callee, Precedence.New, itemFlags)
61018
61018
  );
@@ -61062,11 +61062,11 @@ var require_escodegen = __commonJS({
61062
61062
  var result, fragment, rightCharCode, leftSource, leftCharCode;
61063
61063
  fragment = this.generateExpression(expr.argument, Precedence.Unary, E_TTT);
61064
61064
  if (space === "") {
61065
- result = join16(expr.operator, fragment);
61065
+ result = join17(expr.operator, fragment);
61066
61066
  } else {
61067
61067
  result = [expr.operator];
61068
61068
  if (expr.operator.length > 2) {
61069
- result = join16(result, fragment);
61069
+ result = join17(result, fragment);
61070
61070
  } else {
61071
61071
  leftSource = toSourceNodeWhenNeeded(result).toString();
61072
61072
  leftCharCode = leftSource.charCodeAt(leftSource.length - 1);
@@ -61089,7 +61089,7 @@ var require_escodegen = __commonJS({
61089
61089
  result = "yield";
61090
61090
  }
61091
61091
  if (expr.argument) {
61092
- result = join16(
61092
+ result = join17(
61093
61093
  result,
61094
61094
  this.generateExpression(expr.argument, Precedence.Yield, E_TTT)
61095
61095
  );
@@ -61097,7 +61097,7 @@ var require_escodegen = __commonJS({
61097
61097
  return parenthesize(result, Precedence.Yield, precedence);
61098
61098
  },
61099
61099
  AwaitExpression: function(expr, precedence, flags) {
61100
- var result = join16(
61100
+ var result = join17(
61101
61101
  expr.all ? "await*" : "await",
61102
61102
  this.generateExpression(expr.argument, Precedence.Await, E_TTT)
61103
61103
  );
@@ -61180,11 +61180,11 @@ var require_escodegen = __commonJS({
61180
61180
  var result, fragment;
61181
61181
  result = ["class"];
61182
61182
  if (expr.id) {
61183
- result = join16(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
61183
+ result = join17(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
61184
61184
  }
61185
61185
  if (expr.superClass) {
61186
- fragment = join16("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
61187
- result = join16(result, fragment);
61186
+ fragment = join17("extends", this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
61187
+ result = join17(result, fragment);
61188
61188
  }
61189
61189
  result.push(space);
61190
61190
  result.push(this.generateStatement(expr.body, S_TFFT));
@@ -61199,7 +61199,7 @@ var require_escodegen = __commonJS({
61199
61199
  }
61200
61200
  if (expr.kind === "get" || expr.kind === "set") {
61201
61201
  fragment = [
61202
- join16(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
61202
+ join17(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
61203
61203
  this.generateFunctionBody(expr.value)
61204
61204
  ];
61205
61205
  } else {
@@ -61209,7 +61209,7 @@ var require_escodegen = __commonJS({
61209
61209
  this.generateFunctionBody(expr.value)
61210
61210
  ];
61211
61211
  }
61212
- return join16(result, fragment);
61212
+ return join17(result, fragment);
61213
61213
  },
61214
61214
  Property: function(expr, precedence, flags) {
61215
61215
  if (expr.kind === "get" || expr.kind === "set") {
@@ -61404,7 +61404,7 @@ var require_escodegen = __commonJS({
61404
61404
  for (i = 0, iz = expr.blocks.length; i < iz; ++i) {
61405
61405
  fragment = that.generateExpression(expr.blocks[i], Precedence.Sequence, E_TTT);
61406
61406
  if (i > 0 || extra.moz.comprehensionExpressionStartsWithAssignment) {
61407
- result = join16(result, fragment);
61407
+ result = join17(result, fragment);
61408
61408
  } else {
61409
61409
  result.push(fragment);
61410
61410
  }
@@ -61412,13 +61412,13 @@ var require_escodegen = __commonJS({
61412
61412
  });
61413
61413
  }
61414
61414
  if (expr.filter) {
61415
- result = join16(result, "if" + space);
61415
+ result = join17(result, "if" + space);
61416
61416
  fragment = this.generateExpression(expr.filter, Precedence.Sequence, E_TTT);
61417
- result = join16(result, ["(", fragment, ")"]);
61417
+ result = join17(result, ["(", fragment, ")"]);
61418
61418
  }
61419
61419
  if (!extra.moz.comprehensionExpressionStartsWithAssignment) {
61420
61420
  fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT);
61421
- result = join16(result, fragment);
61421
+ result = join17(result, fragment);
61422
61422
  }
61423
61423
  result.push(expr.type === Syntax.GeneratorExpression ? ")" : "]");
61424
61424
  return result;
@@ -61434,8 +61434,8 @@ var require_escodegen = __commonJS({
61434
61434
  } else {
61435
61435
  fragment = this.generateExpression(expr.left, Precedence.Call, E_TTT);
61436
61436
  }
61437
- fragment = join16(fragment, expr.of ? "of" : "in");
61438
- fragment = join16(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
61437
+ fragment = join17(fragment, expr.of ? "of" : "in");
61438
+ fragment = join17(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
61439
61439
  return ["for" + space + "(", fragment, ")"];
61440
61440
  },
61441
61441
  SpreadElement: function(expr, precedence, flags) {
@@ -67965,11 +67965,11 @@ function __metadata(metadataKey, metadataValue) {
67965
67965
  }
67966
67966
  function __awaiter2(thisArg, _arguments, P, generator) {
67967
67967
  function adopt(value) {
67968
- return value instanceof P ? value : new P(function(resolve12) {
67969
- resolve12(value);
67968
+ return value instanceof P ? value : new P(function(resolve13) {
67969
+ resolve13(value);
67970
67970
  });
67971
67971
  }
67972
- return new (P || (P = Promise))(function(resolve12, reject) {
67972
+ return new (P || (P = Promise))(function(resolve13, reject) {
67973
67973
  function fulfilled(value) {
67974
67974
  try {
67975
67975
  step(generator.next(value));
@@ -67985,7 +67985,7 @@ function __awaiter2(thisArg, _arguments, P, generator) {
67985
67985
  }
67986
67986
  }
67987
67987
  function step(result) {
67988
- result.done ? resolve12(result.value) : adopt(result.value).then(fulfilled, rejected);
67988
+ result.done ? resolve13(result.value) : adopt(result.value).then(fulfilled, rejected);
67989
67989
  }
67990
67990
  step((generator = generator.apply(thisArg, _arguments || [])).next());
67991
67991
  });
@@ -68176,14 +68176,14 @@ function __asyncValues2(o) {
68176
68176
  }, i);
68177
68177
  function verb(n) {
68178
68178
  i[n] = o[n] && function(v) {
68179
- return new Promise(function(resolve12, reject) {
68180
- v = o[n](v), settle(resolve12, reject, v.done, v.value);
68179
+ return new Promise(function(resolve13, reject) {
68180
+ v = o[n](v), settle(resolve13, reject, v.done, v.value);
68181
68181
  });
68182
68182
  };
68183
68183
  }
68184
- function settle(resolve12, reject, d, v) {
68184
+ function settle(resolve13, reject, d, v) {
68185
68185
  Promise.resolve(v).then(function(v2) {
68186
- resolve12({ value: v2, done: d });
68186
+ resolve13({ value: v2, done: d });
68187
68187
  }, reject);
68188
68188
  }
68189
68189
  }
@@ -71736,12 +71736,12 @@ var require_util3 = __commonJS({
71736
71736
  exports.isGMT = exports.dnsLookup = void 0;
71737
71737
  var dns_1 = __require("dns");
71738
71738
  function dnsLookup(host, opts) {
71739
- return new Promise((resolve12, reject) => {
71739
+ return new Promise((resolve13, reject) => {
71740
71740
  (0, dns_1.lookup)(host, opts, (err, res) => {
71741
71741
  if (err) {
71742
71742
  reject(err);
71743
71743
  } else {
71744
- resolve12(res);
71744
+ resolve13(res);
71745
71745
  }
71746
71746
  });
71747
71747
  });
@@ -72106,10 +72106,10 @@ var require_myIpAddress = __commonJS({
72106
72106
  var ip_1 = require_ip();
72107
72107
  var net_1 = __importDefault2(__require("net"));
72108
72108
  async function myIpAddress() {
72109
- return new Promise((resolve12, reject) => {
72109
+ return new Promise((resolve13, reject) => {
72110
72110
  const socket = net_1.default.connect({ host: "8.8.8.8", port: 53 });
72111
72111
  const onError = () => {
72112
- resolve12(ip_1.ip.address());
72112
+ resolve13(ip_1.ip.address());
72113
72113
  };
72114
72114
  socket.once("error", onError);
72115
72115
  socket.once("connect", () => {
@@ -72117,9 +72117,9 @@ var require_myIpAddress = __commonJS({
72117
72117
  const addr = socket.address();
72118
72118
  socket.destroy();
72119
72119
  if (typeof addr === "string") {
72120
- resolve12(addr);
72120
+ resolve13(addr);
72121
72121
  } else if (addr.address) {
72122
- resolve12(addr.address);
72122
+ resolve13(addr.address);
72123
72123
  } else {
72124
72124
  reject(new Error("Expected a `string`"));
72125
72125
  }
@@ -72697,8 +72697,8 @@ var require_deferred_promise = __commonJS({
72697
72697
  this.context = args.context;
72698
72698
  this.owner = args.context.runtime;
72699
72699
  this.handle = args.promiseHandle;
72700
- this.settled = new Promise((resolve12) => {
72701
- this.onSettled = resolve12;
72700
+ this.settled = new Promise((resolve13) => {
72701
+ this.onSettled = resolve13;
72702
72702
  });
72703
72703
  this.resolveHandle = args.resolveHandle;
72704
72704
  this.rejectHandle = args.rejectHandle;
@@ -73219,13 +73219,13 @@ var require_context = __commonJS({
73219
73219
  if (vmResolveResult.error) {
73220
73220
  return Promise.resolve(vmResolveResult);
73221
73221
  }
73222
- return new Promise((resolve12) => {
73222
+ return new Promise((resolve13) => {
73223
73223
  lifetime_1.Scope.withScope((scope) => {
73224
73224
  const resolveHandle = scope.manage(this.newFunction("resolve", (value) => {
73225
- resolve12({ value: value && value.dup() });
73225
+ resolve13({ value: value && value.dup() });
73226
73226
  }));
73227
73227
  const rejectHandle = scope.manage(this.newFunction("reject", (error) => {
73228
- resolve12({ error: error && error.dup() });
73228
+ resolve13({ error: error && error.dup() });
73229
73229
  }));
73230
73230
  const promiseHandle = scope.manage(vmResolveResult.value);
73231
73231
  const promiseThenHandle = scope.manage(this.getProp(promiseHandle, "then"));
@@ -75600,13 +75600,13 @@ import * as http from "node:http";
75600
75600
  import * as https from "node:https";
75601
75601
  import { URL as URL2, urlToHttpOptions } from "node:url";
75602
75602
  function headHttpRequest(url) {
75603
- return new Promise((resolve12) => {
75603
+ return new Promise((resolve13) => {
75604
75604
  const request3 = httpRequest(url, "HEAD", (response) => {
75605
75605
  response.resume();
75606
- resolve12(response.statusCode === 200);
75606
+ resolve13(response.statusCode === 200);
75607
75607
  }, false);
75608
75608
  request3.on("error", () => {
75609
- resolve12(false);
75609
+ resolve13(false);
75610
75610
  });
75611
75611
  });
75612
75612
  }
@@ -75634,7 +75634,7 @@ function httpRequest(url, method, response, keepAlive = true) {
75634
75634
  return request3;
75635
75635
  }
75636
75636
  function downloadFile(url, destinationPath, progressCallback) {
75637
- return new Promise((resolve12, reject) => {
75637
+ return new Promise((resolve13, reject) => {
75638
75638
  let downloadedBytes = 0;
75639
75639
  let totalBytes = 0;
75640
75640
  function onData(chunk) {
@@ -75650,7 +75650,7 @@ function downloadFile(url, destinationPath, progressCallback) {
75650
75650
  }
75651
75651
  const file = createWriteStream(destinationPath);
75652
75652
  file.on("close", () => {
75653
- return resolve12();
75653
+ return resolve13();
75654
75654
  });
75655
75655
  file.on("error", (error) => {
75656
75656
  return reject(error);
@@ -75675,7 +75675,7 @@ async function getJSON(url) {
75675
75675
  }
75676
75676
  }
75677
75677
  function getText3(url) {
75678
- return new Promise((resolve12, reject) => {
75678
+ return new Promise((resolve13, reject) => {
75679
75679
  const request3 = httpRequest(url, "GET", (response) => {
75680
75680
  let data = "";
75681
75681
  if (response.statusCode && response.statusCode >= 400) {
@@ -75686,7 +75686,7 @@ function getText3(url) {
75686
75686
  });
75687
75687
  response.on("end", () => {
75688
75688
  try {
75689
- return resolve12(String(data));
75689
+ return resolve13(String(data));
75690
75690
  } catch {
75691
75691
  return reject(new Error(`Failed to read text response from ${url}`));
75692
75692
  }
@@ -77078,7 +77078,7 @@ var init_launch = __esm({
77078
77078
  if (opts.onExit) {
77079
77079
  this.#onExitHook = opts.onExit;
77080
77080
  }
77081
- this.#browserProcessExiting = new Promise((resolve12, reject) => {
77081
+ this.#browserProcessExiting = new Promise((resolve13, reject) => {
77082
77082
  this.#browserProcess.once("exit", async () => {
77083
77083
  debugLaunch(`Browser process ${this.#browserProcess.pid} onExit`);
77084
77084
  this.#clearListeners();
@@ -77089,7 +77089,7 @@ var init_launch = __esm({
77089
77089
  reject(err);
77090
77090
  return;
77091
77091
  }
77092
- resolve12();
77092
+ resolve13();
77093
77093
  });
77094
77094
  });
77095
77095
  }
@@ -77205,7 +77205,7 @@ Error cause: ${isErrorLike2(error) ? error.stack : error}`);
77205
77205
  return [...this.#logs];
77206
77206
  }
77207
77207
  waitForLineOutput(regex, timeout2 = 0) {
77208
- return new Promise((resolve12, reject) => {
77208
+ return new Promise((resolve13, reject) => {
77209
77209
  const onClose = (errorOrCode) => {
77210
77210
  cleanup();
77211
77211
  reject(new Error([
@@ -77241,7 +77241,7 @@ Error cause: ${isErrorLike2(error) ? error.stack : error}`);
77241
77241
  return;
77242
77242
  }
77243
77243
  cleanup();
77244
- resolve12(match2[1]);
77244
+ resolve13(match2[1]);
77245
77245
  }
77246
77246
  });
77247
77247
  }
@@ -77710,7 +77710,7 @@ var require_get_stream = __commonJS({
77710
77710
  };
77711
77711
  const { maxBuffer } = options;
77712
77712
  let stream2;
77713
- await new Promise((resolve12, reject) => {
77713
+ await new Promise((resolve13, reject) => {
77714
77714
  const rejectPromise = (error) => {
77715
77715
  if (error && stream2.getBufferedLength() <= BufferConstants.MAX_LENGTH) {
77716
77716
  error.bufferedData = stream2.getBufferedValue();
@@ -77722,7 +77722,7 @@ var require_get_stream = __commonJS({
77722
77722
  rejectPromise(error);
77723
77723
  return;
77724
77724
  }
77725
- resolve12();
77725
+ resolve13();
77726
77726
  });
77727
77727
  stream2.on("data", () => {
77728
77728
  if (stream2.getBufferedLength() > maxBuffer) {
@@ -79011,7 +79011,7 @@ var require_extract_zip = __commonJS({
79011
79011
  debug6("opening", this.zipPath, "with opts", this.opts);
79012
79012
  this.zipfile = await openZip(this.zipPath, { lazyEntries: true });
79013
79013
  this.canceled = false;
79014
- return new Promise((resolve12, reject) => {
79014
+ return new Promise((resolve13, reject) => {
79015
79015
  this.zipfile.on("error", (err) => {
79016
79016
  this.canceled = true;
79017
79017
  reject(err);
@@ -79020,7 +79020,7 @@ var require_extract_zip = __commonJS({
79020
79020
  this.zipfile.on("close", () => {
79021
79021
  if (!this.canceled) {
79022
79022
  debug6("zip extraction complete");
79023
- resolve12();
79023
+ resolve13();
79024
79024
  }
79025
79025
  });
79026
79026
  this.zipfile.on("entry", async (entry) => {
@@ -80277,8 +80277,8 @@ var require_streamx = __commonJS({
80277
80277
  return this;
80278
80278
  },
80279
80279
  next() {
80280
- return new Promise(function(resolve12, reject) {
80281
- promiseResolve = resolve12;
80280
+ return new Promise(function(resolve13, reject) {
80281
+ promiseResolve = resolve13;
80282
80282
  promiseReject = reject;
80283
80283
  const data = stream2.read();
80284
80284
  if (data !== null) ondata(data);
@@ -80308,11 +80308,11 @@ var require_streamx = __commonJS({
80308
80308
  }
80309
80309
  function destroy(err) {
80310
80310
  stream2.destroy(err);
80311
- return new Promise((resolve12, reject) => {
80312
- if (stream2._duplexState & DESTROYED) return resolve12({ value: void 0, done: true });
80311
+ return new Promise((resolve13, reject) => {
80312
+ if (stream2._duplexState & DESTROYED) return resolve13({ value: void 0, done: true });
80313
80313
  stream2.once("close", function() {
80314
80314
  if (err) reject(err);
80315
- else resolve12({ value: void 0, done: true });
80315
+ else resolve13({ value: void 0, done: true });
80316
80316
  });
80317
80317
  });
80318
80318
  }
@@ -80356,8 +80356,8 @@ var require_streamx = __commonJS({
80356
80356
  const writes = pending + (ws._duplexState & WRITE_WRITING ? 1 : 0);
80357
80357
  if (writes === 0) return Promise.resolve(true);
80358
80358
  if (state.drains === null) state.drains = [];
80359
- return new Promise((resolve12) => {
80360
- state.drains.push({ writes, resolve: resolve12 });
80359
+ return new Promise((resolve13) => {
80360
+ state.drains.push({ writes, resolve: resolve13 });
80361
80361
  });
80362
80362
  }
80363
80363
  write(data) {
@@ -80462,10 +80462,10 @@ var require_streamx = __commonJS({
80462
80462
  cb(null);
80463
80463
  }
80464
80464
  function pipelinePromise(...streams) {
80465
- return new Promise((resolve12, reject) => {
80465
+ return new Promise((resolve13, reject) => {
80466
80466
  return pipeline(...streams, (err) => {
80467
80467
  if (err) return reject(err);
80468
- resolve12();
80468
+ resolve13();
80469
80469
  });
80470
80470
  });
80471
80471
  }
@@ -81120,16 +81120,16 @@ var require_extract = __commonJS({
81120
81120
  entryCallback = null;
81121
81121
  cb(err);
81122
81122
  }
81123
- function onnext(resolve12, reject) {
81123
+ function onnext(resolve13, reject) {
81124
81124
  if (error) {
81125
81125
  return reject(error);
81126
81126
  }
81127
81127
  if (entryStream) {
81128
- resolve12({ value: entryStream, done: false });
81128
+ resolve13({ value: entryStream, done: false });
81129
81129
  entryStream = null;
81130
81130
  return;
81131
81131
  }
81132
- promiseResolve = resolve12;
81132
+ promiseResolve = resolve13;
81133
81133
  promiseReject = reject;
81134
81134
  consumeCallback(null);
81135
81135
  if (extract._finished && promiseResolve) {
@@ -81157,11 +81157,11 @@ var require_extract = __commonJS({
81157
81157
  function destroy(err) {
81158
81158
  extract.destroy(err);
81159
81159
  consumeCallback(err);
81160
- return new Promise((resolve12, reject) => {
81161
- if (extract.destroyed) return resolve12({ value: void 0, done: true });
81160
+ return new Promise((resolve13, reject) => {
81161
+ if (extract.destroyed) return resolve13({ value: void 0, done: true });
81162
81162
  extract.once("close", function() {
81163
81163
  if (err) reject(err);
81164
- else resolve12({ value: void 0, done: true });
81164
+ else resolve13({ value: void 0, done: true });
81165
81165
  });
81166
81166
  });
81167
81167
  }
@@ -86137,12 +86137,12 @@ var init_yargs_factory = __esm({
86137
86137
  async getCompletion(args, done) {
86138
86138
  argsert("<array> [function]", [args, done], arguments.length);
86139
86139
  if (!done) {
86140
- return new Promise((resolve12, reject) => {
86140
+ return new Promise((resolve13, reject) => {
86141
86141
  __classPrivateFieldGet2(this, _YargsInstance_completion, "f").getCompletion(args, (err, completions) => {
86142
86142
  if (err)
86143
86143
  reject(err);
86144
86144
  else
86145
- resolve12(completions);
86145
+ resolve13(completions);
86146
86146
  });
86147
86147
  });
86148
86148
  } else {
@@ -87597,9 +87597,9 @@ async function getConnectionTransport(options) {
87597
87597
  throw new Error("Could not detect required browser platform");
87598
87598
  }
87599
87599
  const { convertPuppeteerChannelToBrowsersChannel: convertPuppeteerChannelToBrowsersChannel2 } = await Promise.resolve().then(() => (init_LaunchOptions(), LaunchOptions_exports));
87600
- const { join: join16 } = await import("node:path");
87600
+ const { join: join17 } = await import("node:path");
87601
87601
  const userDataDir = resolveDefaultUserDataDir3(Browser4.CHROME, platform, convertPuppeteerChannelToBrowsersChannel2(options.channel));
87602
- const portPath = join16(userDataDir, "DevToolsActivePort");
87602
+ const portPath = join17(userDataDir, "DevToolsActivePort");
87603
87603
  try {
87604
87604
  const fileContent = await environment.value.fs.promises.readFile(portPath, "ascii");
87605
87605
  const [rawPort, rawPath] = fileContent.split("\n").map((line) => {
@@ -88943,8 +88943,8 @@ var init_ScreenRecorder = __esm({
88943
88943
  static {
88944
88944
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
88945
88945
  __esDecorate23(this, _private_writeFrame_descriptor = { value: __setFunctionName6(async function(buffer) {
88946
- const error = await new Promise((resolve12) => {
88947
- this.#process.stdin.write(buffer, resolve12);
88946
+ const error = await new Promise((resolve13) => {
88947
+ this.#process.stdin.write(buffer, resolve13);
88948
88948
  });
88949
88949
  if (error) {
88950
88950
  console.log(`ffmpeg failed to write: ${error.message}.`);
@@ -89134,8 +89134,8 @@ var init_ScreenRecorder = __esm({
89134
89134
  const [buffer, timestamp] = await this.#lastFrame;
89135
89135
  await Promise.all(Array(Math.max(1, Math.round(this.#fps * (performance.now() - timestamp) / 1e3))).fill(buffer).map(this.#writeFrame.bind(this)));
89136
89136
  this.#process.stdin.end();
89137
- await new Promise((resolve12) => {
89138
- this.#process.once("close", resolve12);
89137
+ await new Promise((resolve13) => {
89138
+ this.#process.once("close", resolve13);
89139
89139
  });
89140
89140
  }
89141
89141
  /**
@@ -93032,8 +93032,8 @@ var CustomElementRegistry = class {
93032
93032
  } : (element) => element.localName === localName;
93033
93033
  registry.set(localName, { Class, check });
93034
93034
  if (waiting.has(localName)) {
93035
- for (const resolve12 of waiting.get(localName))
93036
- resolve12(Class);
93035
+ for (const resolve13 of waiting.get(localName))
93036
+ resolve13(Class);
93037
93037
  waiting.delete(localName);
93038
93038
  }
93039
93039
  ownerDocument.querySelectorAll(
@@ -93073,13 +93073,13 @@ var CustomElementRegistry = class {
93073
93073
  */
93074
93074
  whenDefined(localName) {
93075
93075
  const { registry, waiting } = this;
93076
- return new Promise((resolve12) => {
93076
+ return new Promise((resolve13) => {
93077
93077
  if (registry.has(localName))
93078
- resolve12(registry.get(localName).Class);
93078
+ resolve13(registry.get(localName).Class);
93079
93079
  else {
93080
93080
  if (!waiting.has(localName))
93081
93081
  waiting.set(localName, []);
93082
- waiting.get(localName).push(resolve12);
93082
+ waiting.get(localName).push(resolve13);
93083
93083
  }
93084
93084
  });
93085
93085
  }
@@ -98907,7 +98907,7 @@ function buildChromeArgs(options, config2) {
98907
98907
 
98908
98908
  // ../engine/src/services/frameCapture.ts
98909
98909
  import { existsSync as existsSync4, mkdirSync, writeFileSync } from "fs";
98910
- import { join as join4 } from "path";
98910
+ import { join as join5 } from "path";
98911
98911
 
98912
98912
  // ../core/src/parsers/gsapParser.ts
98913
98913
  var GSAP_METHODS = /* @__PURE__ */ new Set(["set", "to", "from", "fromTo"]);
@@ -99182,80 +99182,175 @@ function clampDurations(html, clamps) {
99182
99182
  return html;
99183
99183
  }
99184
99184
 
99185
- // ../core/src/lint/hyperframeLinter.ts
99185
+ // ../core/src/lint/utils.ts
99186
99186
  var TAG_PATTERN = /<([a-z][\w:-]*)(\s[^<>]*?)?>/gi;
99187
99187
  var STYLE_BLOCK_PATTERN = /<style\b([^>]*)>([\s\S]*?)<\/style>/gi;
99188
99188
  var SCRIPT_BLOCK_PATTERN = /<script\b([^>]*)>([\s\S]*?)<\/script>/gi;
99189
99189
  var COMPOSITION_ID_IN_CSS_PATTERN = /\[data-composition-id=["']([^"']+)["']\]/g;
99190
99190
  var TIMELINE_REGISTRY_INIT_PATTERN = /window\.__timelines\s*=\s*window\.__timelines\s*\|\|\s*\{\}|window\.__timelines\s*=\s*\{\}|window\.__timelines\s*\?\?=\s*\{\}/i;
99191
99191
  var TIMELINE_REGISTRY_ASSIGN_PATTERN = /window\.__timelines\[[^\]]+\]\s*=/i;
99192
- var INVALID_SCRIPT_CLOSE_PATTERN = /<script[^>]*>[\s\S]*?<\s*\/\s*script(?!>)/i;
99193
99192
  var WINDOW_TIMELINE_ASSIGN_PATTERN = /window\.__timelines\[\s*["']([^"']+)["']\s*\]\s*=\s*([A-Za-z_$][\w$]*)/i;
99194
- var META_GSAP_KEYS = /* @__PURE__ */ new Set(["duration", "ease", "repeat", "yoyo", "overwrite", "delay"]);
99195
- function lintHyperframeHtml(html, options = {}) {
99193
+ var INVALID_SCRIPT_CLOSE_PATTERN = /<script[^>]*>[\s\S]*?<\s*\/\s*script(?!>)/i;
99194
+ function extractOpenTags(source2) {
99195
+ const tags = [];
99196
+ let match2;
99197
+ const pattern = new RegExp(TAG_PATTERN.source, TAG_PATTERN.flags);
99198
+ while ((match2 = pattern.exec(source2)) !== null) {
99199
+ const raw2 = match2[0];
99200
+ if (raw2.startsWith("</") || raw2.startsWith("<!")) continue;
99201
+ tags.push({
99202
+ raw: raw2,
99203
+ name: (match2[1] || "").toLowerCase(),
99204
+ attrs: match2[2] || "",
99205
+ index: match2.index
99206
+ });
99207
+ }
99208
+ return tags;
99209
+ }
99210
+ function extractBlocks(source2, pattern) {
99211
+ const blocks = [];
99212
+ let match2;
99213
+ const p = new RegExp(pattern.source, pattern.flags);
99214
+ while ((match2 = p.exec(source2)) !== null) {
99215
+ blocks.push({
99216
+ attrs: match2[1] || "",
99217
+ content: match2[2] || "",
99218
+ raw: match2[0],
99219
+ index: match2.index
99220
+ });
99221
+ }
99222
+ return blocks;
99223
+ }
99224
+ function findRootTag(source2) {
99225
+ const bodyMatch = source2.match(/<body\b[^>]*>([\s\S]*?)<\/body>/i);
99226
+ const bodyContent = bodyMatch ? bodyMatch[1] ?? source2 : source2;
99227
+ const bodyTags = extractOpenTags(bodyContent);
99228
+ for (const tag of bodyTags) {
99229
+ if (["script", "style", "meta", "link", "title"].includes(tag.name)) continue;
99230
+ return tag;
99231
+ }
99232
+ return null;
99233
+ }
99234
+ function readAttr(tagSource, attr) {
99235
+ if (!tagSource) return null;
99236
+ const escaped = attr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
99237
+ const match2 = tagSource.match(new RegExp(`\\b${escaped}\\s*=\\s*["']([^"']+)["']`, "i"));
99238
+ return match2?.[1] || null;
99239
+ }
99240
+ function collectCompositionIds(tags) {
99241
+ const ids = /* @__PURE__ */ new Set();
99242
+ for (const tag of tags) {
99243
+ const compId = readAttr(tag.raw, "data-composition-id");
99244
+ if (compId) ids.add(compId);
99245
+ }
99246
+ return ids;
99247
+ }
99248
+ function extractCompositionIdsFromCss(css) {
99249
+ const ids = /* @__PURE__ */ new Set();
99250
+ let match2;
99251
+ const pattern = new RegExp(
99252
+ COMPOSITION_ID_IN_CSS_PATTERN.source,
99253
+ COMPOSITION_ID_IN_CSS_PATTERN.flags
99254
+ );
99255
+ while ((match2 = pattern.exec(css)) !== null) {
99256
+ if (match2[1]) ids.add(match2[1]);
99257
+ }
99258
+ return [...ids];
99259
+ }
99260
+ function getInlineScriptSyntaxError(source2) {
99261
+ if (!source2.trim()) return null;
99262
+ try {
99263
+ new Function(source2);
99264
+ return null;
99265
+ } catch (error) {
99266
+ if (error instanceof Error) return error.message;
99267
+ return String(error);
99268
+ }
99269
+ }
99270
+ function isMediaTag(tagName19) {
99271
+ return tagName19 === "video" || tagName19 === "audio" || tagName19 === "img";
99272
+ }
99273
+ function truncateSnippet(value, maxLength = 220) {
99274
+ const normalized = value.replace(/\s+/g, " ").trim();
99275
+ if (!normalized) return void 0;
99276
+ if (normalized.length <= maxLength) return normalized;
99277
+ return `${normalized.slice(0, maxLength - 3)}...`;
99278
+ }
99279
+
99280
+ // ../core/src/lint/context.ts
99281
+ function buildLintContext(html, options = {}) {
99196
99282
  let source2 = html || "";
99197
99283
  const templateMatch = source2.match(/<template[^>]*>([\s\S]*)<\/template>/i);
99198
99284
  if (templateMatch?.[1]) source2 = templateMatch[1];
99199
- const filePath = options.filePath;
99200
- const findings = [];
99201
- const seen = /* @__PURE__ */ new Set();
99202
- const pushFinding = (finding) => {
99203
- const dedupeKey = [
99204
- finding.code,
99205
- finding.severity,
99206
- finding.selector || "",
99207
- finding.elementId || "",
99208
- finding.message
99209
- ].join("|");
99210
- if (seen.has(dedupeKey)) {
99211
- return;
99212
- }
99213
- seen.add(dedupeKey);
99214
- findings.push(filePath ? { ...finding, file: filePath } : finding);
99215
- };
99216
99285
  const tags = extractOpenTags(source2);
99217
99286
  const styles = extractBlocks(source2, STYLE_BLOCK_PATTERN);
99218
99287
  const scripts = extractBlocks(source2, SCRIPT_BLOCK_PATTERN);
99219
99288
  const compositionIds = collectCompositionIds(tags);
99220
99289
  const rootTag = findRootTag(source2);
99221
99290
  const rootCompositionId = readAttr(rootTag?.raw || "", "data-composition-id");
99222
- if (!rootTag || !readAttr(rootTag.raw, "data-composition-id")) {
99223
- pushFinding({
99224
- code: "root_missing_composition_id",
99225
- severity: "error",
99226
- message: "Root composition is missing `data-composition-id`.",
99227
- elementId: rootTag ? readAttr(rootTag.raw, "id") || void 0 : void 0,
99228
- fixHint: "Add a stable `data-composition-id` to the entry composition wrapper.",
99229
- snippet: truncateSnippet(rootTag?.raw || "")
99230
- });
99231
- }
99232
- if (!rootTag || !readAttr(rootTag.raw, "data-width") || !readAttr(rootTag.raw, "data-height")) {
99233
- pushFinding({
99234
- code: "root_missing_dimensions",
99235
- severity: "error",
99236
- message: "Root composition is missing `data-width` or `data-height`.",
99237
- elementId: rootTag ? readAttr(rootTag.raw, "id") || void 0 : void 0,
99238
- fixHint: "Set numeric `data-width` and `data-height` on the entry composition root.",
99239
- snippet: truncateSnippet(rootTag?.raw || "")
99240
- });
99241
- }
99242
- if (!TIMELINE_REGISTRY_INIT_PATTERN.test(source2) && !TIMELINE_REGISTRY_ASSIGN_PATTERN.test(source2)) {
99243
- pushFinding({
99244
- code: "missing_timeline_registry",
99245
- severity: "error",
99246
- message: "Missing `window.__timelines` registration.",
99247
- fixHint: "Register each composition timeline on `window.__timelines[compositionId]`."
99248
- });
99249
- }
99250
- if (TIMELINE_REGISTRY_ASSIGN_PATTERN.test(source2) && !TIMELINE_REGISTRY_INIT_PATTERN.test(source2)) {
99251
- pushFinding({
99252
- code: "timeline_registry_missing_init",
99253
- severity: "error",
99254
- message: "`window.__timelines[\u2026] = \u2026` is used without initializing `window.__timelines` first.",
99255
- fixHint: "Add `window.__timelines = window.__timelines || {};` before any timeline assignment."
99256
- });
99257
- }
99258
- {
99291
+ return {
99292
+ source: source2,
99293
+ tags,
99294
+ styles,
99295
+ scripts,
99296
+ compositionIds,
99297
+ rootTag,
99298
+ rootCompositionId,
99299
+ options
99300
+ };
99301
+ }
99302
+
99303
+ // ../core/src/lint/rules/core.ts
99304
+ var coreRules = [
99305
+ // root_missing_composition_id + root_missing_dimensions
99306
+ ({ rootTag }) => {
99307
+ const findings = [];
99308
+ if (!rootTag || !readAttr(rootTag.raw, "data-composition-id")) {
99309
+ findings.push({
99310
+ code: "root_missing_composition_id",
99311
+ severity: "error",
99312
+ message: "Root composition is missing `data-composition-id`.",
99313
+ elementId: rootTag ? readAttr(rootTag.raw, "id") || void 0 : void 0,
99314
+ fixHint: "Add a stable `data-composition-id` to the entry composition wrapper.",
99315
+ snippet: truncateSnippet(rootTag?.raw || "")
99316
+ });
99317
+ }
99318
+ if (!rootTag || !readAttr(rootTag.raw, "data-width") || !readAttr(rootTag.raw, "data-height")) {
99319
+ findings.push({
99320
+ code: "root_missing_dimensions",
99321
+ severity: "error",
99322
+ message: "Root composition is missing `data-width` or `data-height`.",
99323
+ elementId: rootTag ? readAttr(rootTag.raw, "id") || void 0 : void 0,
99324
+ fixHint: "Set numeric `data-width` and `data-height` on the entry composition root.",
99325
+ snippet: truncateSnippet(rootTag?.raw || "")
99326
+ });
99327
+ }
99328
+ return findings;
99329
+ },
99330
+ // missing_timeline_registry + timeline_registry_missing_init
99331
+ ({ source: source2 }) => {
99332
+ const findings = [];
99333
+ if (!TIMELINE_REGISTRY_INIT_PATTERN.test(source2) && !TIMELINE_REGISTRY_ASSIGN_PATTERN.test(source2)) {
99334
+ findings.push({
99335
+ code: "missing_timeline_registry",
99336
+ severity: "error",
99337
+ message: "Missing `window.__timelines` registration.",
99338
+ fixHint: "Register each composition timeline on `window.__timelines[compositionId]`."
99339
+ });
99340
+ }
99341
+ if (TIMELINE_REGISTRY_ASSIGN_PATTERN.test(source2) && !TIMELINE_REGISTRY_INIT_PATTERN.test(source2)) {
99342
+ findings.push({
99343
+ code: "timeline_registry_missing_init",
99344
+ severity: "error",
99345
+ message: "`window.__timelines[\u2026] = \u2026` is used without initializing `window.__timelines` first.",
99346
+ fixHint: "Add `window.__timelines = window.__timelines || {};` before any timeline assignment."
99347
+ });
99348
+ }
99349
+ return findings;
99350
+ },
99351
+ // timeline_id_mismatch
99352
+ ({ source: source2 }) => {
99353
+ const findings = [];
99259
99354
  const htmlCompIds = /* @__PURE__ */ new Set();
99260
99355
  const timelineRegKeys = /* @__PURE__ */ new Set();
99261
99356
  const compIdRe = /data-composition-id\s*=\s*["']([^"']+)["']/gi;
@@ -99269,7 +99364,7 @@ function lintHyperframeHtml(html, options = {}) {
99269
99364
  }
99270
99365
  for (const key2 of timelineRegKeys) {
99271
99366
  if (!htmlCompIds.has(key2)) {
99272
- pushFinding({
99367
+ findings.push({
99273
99368
  code: "timeline_id_mismatch",
99274
99369
  severity: "error",
99275
99370
  message: `Timeline registered as "${key2}" but no element has data-composition-id="${key2}". The runtime cannot auto-nest this timeline.`,
@@ -99277,261 +99372,194 @@ function lintHyperframeHtml(html, options = {}) {
99277
99372
  });
99278
99373
  }
99279
99374
  }
99280
- }
99281
- if (INVALID_SCRIPT_CLOSE_PATTERN.test(source2)) {
99282
- pushFinding({
99283
- code: "invalid_inline_script_syntax",
99284
- severity: "error",
99285
- message: "Detected malformed inline `<script>` closing syntax.",
99286
- fixHint: "Close inline scripts with a valid `</script>` tag."
99287
- });
99288
- }
99289
- for (const script of scripts) {
99290
- const attrs = script.attrs || "";
99291
- if (/\bsrc\s*=/.test(attrs) || /\btype\s*=\s*["']application\/json["']/.test(attrs)) {
99292
- continue;
99293
- }
99294
- const syntaxError = getInlineScriptSyntaxError(script.content);
99295
- if (!syntaxError) {
99296
- continue;
99297
- }
99298
- pushFinding({
99299
- code: "invalid_inline_script_syntax",
99300
- severity: "error",
99301
- message: `Inline script has invalid syntax: ${syntaxError}`,
99302
- fixHint: "Fix the inline script syntax before render verification.",
99303
- snippet: truncateSnippet(script.content)
99304
- });
99305
- }
99306
- for (const tag of tags) {
99307
- const src = readAttr(tag.raw, "data-composition-src");
99308
- if (!src) {
99309
- continue;
99310
- }
99311
- const compId = readAttr(tag.raw, "data-composition-id");
99312
- if (compId) {
99313
- continue;
99314
- }
99315
- pushFinding({
99316
- code: "host_missing_composition_id",
99317
- severity: "error",
99318
- message: `Composition host for "${src}" is missing \`data-composition-id\`.`,
99319
- elementId: readAttr(tag.raw, "id") || void 0,
99320
- fixHint: "Set `data-composition-id` on every `data-composition-src` host element.",
99321
- snippet: truncateSnippet(tag.raw)
99322
- });
99323
- }
99324
- const scopedCssCompositionIds = /* @__PURE__ */ new Set();
99325
- for (const style of styles) {
99326
- for (const compId of extractCompositionIdsFromCss(style.content)) {
99327
- scopedCssCompositionIds.add(compId);
99328
- }
99329
- }
99330
- for (const compId of scopedCssCompositionIds) {
99331
- if (compositionIds.has(compId)) {
99332
- continue;
99333
- }
99334
- pushFinding({
99335
- code: "scoped_css_missing_wrapper",
99336
- severity: "warning",
99337
- message: `Scoped CSS targets composition "${compId}" but no matching wrapper exists in this HTML.`,
99338
- selector: `[data-composition-id="${compId}"]`,
99339
- fixHint: "Preserve the matching composition wrapper or align the CSS scope to an existing wrapper."
99340
- });
99341
- }
99342
- const mediaById = /* @__PURE__ */ new Map();
99343
- const mediaFingerprintCounts = /* @__PURE__ */ new Map();
99344
- for (const tag of tags) {
99345
- if (!isMediaTag(tag.name)) {
99346
- continue;
99347
- }
99348
- const elementId = readAttr(tag.raw, "id");
99349
- if (elementId) {
99350
- const existing = mediaById.get(elementId) || [];
99351
- existing.push(tag);
99352
- mediaById.set(elementId, existing);
99353
- }
99354
- const fingerprint = [
99355
- tag.name,
99356
- readAttr(tag.raw, "src") || "",
99357
- readAttr(tag.raw, "data-start") || "",
99358
- readAttr(tag.raw, "data-duration") || ""
99359
- ].join("|");
99360
- mediaFingerprintCounts.set(fingerprint, (mediaFingerprintCounts.get(fingerprint) || 0) + 1);
99361
- }
99362
- for (const [elementId, mediaTags] of mediaById) {
99363
- if (mediaTags.length < 2) {
99364
- continue;
99365
- }
99366
- pushFinding({
99367
- code: "duplicate_media_id",
99368
- severity: "error",
99369
- message: `Media id "${elementId}" is defined multiple times.`,
99370
- elementId,
99371
- fixHint: "Give each media element a unique id so preview and producer discover the same media graph.",
99372
- snippet: truncateSnippet(mediaTags[0]?.raw || "")
99373
- });
99374
- }
99375
- for (const [fingerprint, count] of mediaFingerprintCounts) {
99376
- if (count < 2) {
99377
- continue;
99378
- }
99379
- const [tagName19, src, dataStart, dataDuration] = fingerprint.split("|");
99380
- pushFinding({
99381
- code: "duplicate_media_discovery_risk",
99382
- severity: "warning",
99383
- message: `Detected ${count} matching ${tagName19} entries with the same source/start/duration.`,
99384
- fixHint: "Avoid duplicated media nodes that can be discovered twice during compilation.",
99385
- snippet: truncateSnippet(
99386
- `${tagName19} src=${src} data-start=${dataStart} data-duration=${dataDuration}`
99387
- )
99388
- });
99389
- }
99390
- const clipIds = /* @__PURE__ */ new Map();
99391
- const clipClasses = /* @__PURE__ */ new Map();
99392
- for (const tag of tags) {
99393
- const classAttr = readAttr(tag.raw, "class") || "";
99394
- const classes = classAttr.split(/\s+/).filter(Boolean);
99395
- if (!classes.includes("clip")) continue;
99396
- const id = readAttr(tag.raw, "id");
99397
- const info = { tag: tag.name, id: id || "", classes: classAttr };
99398
- if (id) clipIds.set(`#${id}`, info);
99399
- for (const cls of classes) {
99400
- if (cls !== "clip") clipClasses.set(`.${cls}`, info);
99401
- }
99402
- }
99403
- const classUsage = countClassUsage(tags);
99404
- for (const script of scripts) {
99405
- const localTimelineCompId = readRegisteredTimelineCompositionId(script.content);
99406
- const gsapWindows = extractGsapWindows(script.content);
99407
- for (let i = 0; i < gsapWindows.length; i++) {
99408
- const left2 = gsapWindows[i];
99409
- if (!left2) continue;
99410
- if (left2.end <= left2.position) {
99411
- continue;
99412
- }
99413
- for (let j = i + 1; j < gsapWindows.length; j++) {
99414
- const right2 = gsapWindows[j];
99415
- if (!right2) continue;
99416
- if (right2.end <= right2.position) {
99417
- continue;
99418
- }
99419
- if (left2.targetSelector !== right2.targetSelector) {
99420
- continue;
99421
- }
99422
- const overlapStart = Math.max(left2.position, right2.position);
99423
- const overlapEnd = Math.min(left2.end, right2.end);
99424
- if (overlapEnd <= overlapStart) {
99425
- continue;
99426
- }
99427
- if (left2.overwriteAuto || right2.overwriteAuto) {
99428
- continue;
99429
- }
99430
- const sharedProperties = left2.properties.filter((prop2) => right2.properties.includes(prop2));
99431
- if (sharedProperties.length === 0) {
99432
- continue;
99433
- }
99434
- pushFinding({
99435
- code: "overlapping_gsap_tweens",
99436
- severity: "warning",
99437
- message: `GSAP tweens overlap on "${left2.targetSelector}" for ${sharedProperties.join(", ")} between ${overlapStart.toFixed(2)}s and ${overlapEnd.toFixed(2)}s.`,
99438
- selector: left2.targetSelector,
99439
- fixHint: 'Shorten the earlier tween, move the later tween, or add `overwrite: "auto"`.',
99440
- snippet: truncateSnippet(`${left2.raw}
99441
- ${right2.raw}`)
99442
- });
99375
+ return findings;
99376
+ },
99377
+ // invalid_inline_script_syntax (malformed close tag)
99378
+ ({ source: source2 }) => {
99379
+ if (!INVALID_SCRIPT_CLOSE_PATTERN.test(source2)) return [];
99380
+ return [
99381
+ {
99382
+ code: "invalid_inline_script_syntax",
99383
+ severity: "error",
99384
+ message: "Detected malformed inline `<script>` closing syntax.",
99385
+ fixHint: "Close inline scripts with a valid `</script>` tag."
99443
99386
  }
99444
- }
99445
- for (const win of gsapWindows) {
99446
- const sel = win.targetSelector;
99447
- const clipInfo = clipIds.get(sel) || clipClasses.get(sel);
99448
- if (!clipInfo) continue;
99449
- const elDesc = `<${clipInfo.tag}${clipInfo.id ? ` id="${clipInfo.id}"` : ""} class="${clipInfo.classes}">`;
99450
- pushFinding({
99451
- code: "gsap_animates_clip_element",
99387
+ ];
99388
+ },
99389
+ // invalid_inline_script_syntax (JS parse error)
99390
+ ({ scripts }) => {
99391
+ const findings = [];
99392
+ for (const script of scripts) {
99393
+ const attrs = script.attrs || "";
99394
+ if (/\bsrc\s*=/.test(attrs) || /\btype\s*=\s*["']application\/json["']/.test(attrs)) continue;
99395
+ const syntaxError = getInlineScriptSyntaxError(script.content);
99396
+ if (!syntaxError) continue;
99397
+ findings.push({
99398
+ code: "invalid_inline_script_syntax",
99452
99399
  severity: "error",
99453
- message: `GSAP animation targets a clip element. Selector "${sel}" resolves to element ${elDesc}. The framework manages clip visibility \u2014 animate an inner wrapper instead.`,
99454
- selector: sel,
99455
- elementId: clipInfo.id || void 0,
99456
- fixHint: "Wrap content in a child <div> and target that with GSAP.",
99457
- snippet: truncateSnippet(win.raw)
99400
+ message: `Inline script has invalid syntax: ${syntaxError}`,
99401
+ fixHint: "Fix the inline script syntax before render verification.",
99402
+ snippet: truncateSnippet(script.content)
99458
99403
  });
99459
99404
  }
99460
- if (!localTimelineCompId || localTimelineCompId === rootCompositionId) {
99461
- continue;
99405
+ return findings;
99406
+ },
99407
+ // host_missing_composition_id
99408
+ ({ tags }) => {
99409
+ const findings = [];
99410
+ for (const tag of tags) {
99411
+ const src = readAttr(tag.raw, "data-composition-src");
99412
+ if (!src) continue;
99413
+ if (readAttr(tag.raw, "data-composition-id")) continue;
99414
+ findings.push({
99415
+ code: "host_missing_composition_id",
99416
+ severity: "error",
99417
+ message: `Composition host for "${src}" is missing \`data-composition-id\`.`,
99418
+ elementId: readAttr(tag.raw, "id") || void 0,
99419
+ fixHint: "Set `data-composition-id` on every `data-composition-src` host element.",
99420
+ snippet: truncateSnippet(tag.raw)
99421
+ });
99462
99422
  }
99463
- for (const win of gsapWindows) {
99464
- if (!isSuspiciousGlobalSelector(win.targetSelector)) {
99465
- continue;
99466
- }
99467
- const className = getSingleClassSelector(win.targetSelector);
99468
- if (className && (classUsage.get(className) || 0) < 2) {
99469
- continue;
99423
+ return findings;
99424
+ },
99425
+ // scoped_css_missing_wrapper
99426
+ ({ styles, compositionIds }) => {
99427
+ const findings = [];
99428
+ const scopedCssCompositionIds = /* @__PURE__ */ new Set();
99429
+ for (const style of styles) {
99430
+ for (const compId of extractCompositionIdsFromCss(style.content)) {
99431
+ scopedCssCompositionIds.add(compId);
99470
99432
  }
99471
- pushFinding({
99472
- code: "unscoped_gsap_selector",
99433
+ }
99434
+ for (const compId of scopedCssCompositionIds) {
99435
+ if (compositionIds.has(compId)) continue;
99436
+ findings.push({
99437
+ code: "scoped_css_missing_wrapper",
99473
99438
  severity: "warning",
99474
- message: `Timeline "${localTimelineCompId}" uses unscoped selector "${win.targetSelector}" that will target elements in ALL compositions when bundled, causing data loss (opacity, transforms, etc.).`,
99475
- selector: win.targetSelector,
99476
- fixHint: `Scope the selector: \`[data-composition-id="${localTimelineCompId}"] ${win.targetSelector}\` or use a unique id.`,
99477
- snippet: truncateSnippet(win.raw)
99439
+ message: `Scoped CSS targets composition "${compId}" but no matching wrapper exists in this HTML.`,
99440
+ selector: `[data-composition-id="${compId}"]`,
99441
+ fixHint: "Preserve the matching composition wrapper or align the CSS scope to an existing wrapper."
99478
99442
  });
99479
99443
  }
99444
+ return findings;
99480
99445
  }
99481
- for (const tag of tags) {
99482
- if (tag.name !== "video") continue;
99483
- const hasMuted = /\bmuted\b/i.test(tag.raw);
99484
- if (!hasMuted && readAttr(tag.raw, "data-start")) {
99485
- const elementId = readAttr(tag.raw, "id") || void 0;
99486
- pushFinding({
99487
- code: "video_missing_muted",
99446
+ ];
99447
+
99448
+ // ../core/src/lint/rules/media.ts
99449
+ var mediaRules = [
99450
+ // duplicate_media_id + duplicate_media_discovery_risk
99451
+ ({ tags }) => {
99452
+ const findings = [];
99453
+ const mediaById = /* @__PURE__ */ new Map();
99454
+ const mediaFingerprintCounts = /* @__PURE__ */ new Map();
99455
+ for (const tag of tags) {
99456
+ if (!isMediaTag(tag.name)) continue;
99457
+ const elementId = readAttr(tag.raw, "id");
99458
+ if (elementId) {
99459
+ const existing = mediaById.get(elementId) || [];
99460
+ existing.push(tag);
99461
+ mediaById.set(elementId, existing);
99462
+ }
99463
+ const fingerprint = [
99464
+ tag.name,
99465
+ readAttr(tag.raw, "src") || "",
99466
+ readAttr(tag.raw, "data-start") || "",
99467
+ readAttr(tag.raw, "data-duration") || ""
99468
+ ].join("|");
99469
+ mediaFingerprintCounts.set(fingerprint, (mediaFingerprintCounts.get(fingerprint) || 0) + 1);
99470
+ }
99471
+ for (const [elementId, mediaTags] of mediaById) {
99472
+ if (mediaTags.length < 2) continue;
99473
+ findings.push({
99474
+ code: "duplicate_media_id",
99488
99475
  severity: "error",
99489
- 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.`,
99476
+ message: `Media id "${elementId}" is defined multiple times.`,
99490
99477
  elementId,
99491
- fixHint: "Add the `muted` attribute to the <video> tag and use a separate <audio> element with the same src for audio playback.",
99492
- snippet: truncateSnippet(tag.raw)
99478
+ fixHint: "Give each media element a unique id so preview and producer discover the same media graph.",
99479
+ snippet: truncateSnippet(mediaTags[0]?.raw || "")
99493
99480
  });
99494
99481
  }
99495
- }
99496
- const timedTagPositions = [];
99497
- for (const tag of tags) {
99498
- if (tag.name === "video" || tag.name === "audio") continue;
99499
- if (readAttr(tag.raw, "data-start")) {
99500
- timedTagPositions.push({
99501
- name: tag.name,
99502
- start: tag.index,
99503
- id: readAttr(tag.raw, "id") || void 0
99482
+ for (const [fingerprint, count] of mediaFingerprintCounts) {
99483
+ if (count < 2) continue;
99484
+ const [tagName19, src, dataStart, dataDuration] = fingerprint.split("|");
99485
+ findings.push({
99486
+ code: "duplicate_media_discovery_risk",
99487
+ severity: "warning",
99488
+ message: `Detected ${count} matching ${tagName19} entries with the same source/start/duration.`,
99489
+ fixHint: "Avoid duplicated media nodes that can be discovered twice during compilation.",
99490
+ snippet: truncateSnippet(
99491
+ `${tagName19} src=${src} data-start=${dataStart} data-duration=${dataDuration}`
99492
+ )
99504
99493
  });
99505
99494
  }
99506
- }
99507
- for (const tag of tags) {
99508
- if (tag.name !== "video") continue;
99509
- if (!readAttr(tag.raw, "data-start")) continue;
99510
- for (const parent of timedTagPositions) {
99511
- if (parent.start < tag.index) {
99512
- const parentClosePattern = new RegExp(`</${parent.name}>`, "gi");
99513
- const between = source2.substring(parent.start, tag.index);
99514
- if (!parentClosePattern.test(between)) {
99515
- pushFinding({
99516
- code: "video_nested_in_timed_element",
99517
- severity: "error",
99518
- 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.`,
99519
- elementId: readAttr(tag.raw, "id") || void 0,
99520
- 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).",
99521
- snippet: truncateSnippet(tag.raw)
99522
- });
99523
- break;
99495
+ return findings;
99496
+ },
99497
+ // video_missing_muted
99498
+ ({ tags }) => {
99499
+ const findings = [];
99500
+ for (const tag of tags) {
99501
+ if (tag.name !== "video") continue;
99502
+ const hasMuted = /\bmuted\b/i.test(tag.raw);
99503
+ if (!hasMuted && readAttr(tag.raw, "data-start")) {
99504
+ const elementId = readAttr(tag.raw, "id") || void 0;
99505
+ findings.push({
99506
+ code: "video_missing_muted",
99507
+ severity: "error",
99508
+ 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.`,
99509
+ elementId,
99510
+ fixHint: "Add the `muted` attribute to the <video> tag and use a separate <audio> element with the same src for audio playback.",
99511
+ snippet: truncateSnippet(tag.raw)
99512
+ });
99513
+ }
99514
+ }
99515
+ return findings;
99516
+ },
99517
+ // video_nested_in_timed_element
99518
+ ({ source: source2, tags }) => {
99519
+ const findings = [];
99520
+ const timedTagPositions = [];
99521
+ for (const tag of tags) {
99522
+ if (tag.name === "video" || tag.name === "audio") continue;
99523
+ if (readAttr(tag.raw, "data-start")) {
99524
+ timedTagPositions.push({
99525
+ name: tag.name,
99526
+ start: tag.index,
99527
+ id: readAttr(tag.raw, "id") || void 0
99528
+ });
99529
+ }
99530
+ }
99531
+ for (const tag of tags) {
99532
+ if (tag.name !== "video") continue;
99533
+ if (!readAttr(tag.raw, "data-start")) continue;
99534
+ for (const parent of timedTagPositions) {
99535
+ if (parent.start < tag.index) {
99536
+ const parentClosePattern = new RegExp(`</${parent.name}>`, "gi");
99537
+ const between = source2.substring(parent.start, tag.index);
99538
+ if (!parentClosePattern.test(between)) {
99539
+ findings.push({
99540
+ code: "video_nested_in_timed_element",
99541
+ severity: "error",
99542
+ 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.`,
99543
+ elementId: readAttr(tag.raw, "id") || void 0,
99544
+ 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).",
99545
+ snippet: truncateSnippet(tag.raw)
99546
+ });
99547
+ break;
99548
+ }
99524
99549
  }
99525
99550
  }
99526
99551
  }
99527
- }
99528
- {
99552
+ return findings;
99553
+ },
99554
+ // self_closing_media_tag
99555
+ ({ source: source2 }) => {
99556
+ const findings = [];
99529
99557
  const selfClosingMediaRe = /<(audio|video)\b[^>]*\/>/gi;
99530
99558
  let scMatch;
99531
99559
  while ((scMatch = selfClosingMediaRe.exec(source2)) !== null) {
99532
99560
  const tagName19 = scMatch[1] || "audio";
99533
99561
  const elementId = readAttr(scMatch[0], "id") || void 0;
99534
- pushFinding({
99562
+ findings.push({
99535
99563
  code: "self_closing_media_tag",
99536
99564
  severity: "error",
99537
99565
  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.`,
@@ -99540,8 +99568,11 @@ ${right2.raw}`)
99540
99568
  snippet: truncateSnippet(scMatch[0])
99541
99569
  });
99542
99570
  }
99543
- }
99544
- {
99571
+ return findings;
99572
+ },
99573
+ // placeholder_media_url
99574
+ ({ tags }) => {
99575
+ const findings = [];
99545
99576
  const PLACEHOLDER_DOMAINS = /\b(placehold\.co|placeholder\.com|placekitten\.com|picsum\.photos|example\.com|via\.placeholder\.com|dummyimage\.com)\b/i;
99546
99577
  for (const tag of tags) {
99547
99578
  if (!isMediaTag(tag.name)) continue;
@@ -99549,7 +99580,7 @@ ${right2.raw}`)
99549
99580
  if (!src) continue;
99550
99581
  if (PLACEHOLDER_DOMAINS.test(src)) {
99551
99582
  const elementId = readAttr(tag.raw, "id") || void 0;
99552
- pushFinding({
99583
+ findings.push({
99553
99584
  code: "placeholder_media_url",
99554
99585
  severity: "error",
99555
99586
  message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> uses a placeholder URL that will 404 at render time: ${src.slice(0, 80)}`,
@@ -99559,8 +99590,11 @@ ${right2.raw}`)
99559
99590
  });
99560
99591
  }
99561
99592
  }
99562
- }
99563
- {
99593
+ return findings;
99594
+ },
99595
+ // base64_media_prohibited
99596
+ ({ source: source2 }) => {
99597
+ const findings = [];
99564
99598
  const base64MediaRe = /src\s*=\s*["'](data:(?:audio|video)\/[^;]+;base64,([A-Za-z0-9+/=]{20,}))["']/gi;
99565
99599
  let b64Match;
99566
99600
  while ((b64Match = base64MediaRe.exec(source2)) !== null) {
@@ -99568,7 +99602,7 @@ ${right2.raw}`)
99568
99602
  const uniqueChars = new Set(sample.replace(/[A-Za-z0-9+/=]/g, (c) => c)).size;
99569
99603
  const dataSize = Math.round((b64Match[2] || "").length * 3 / 4);
99570
99604
  const isSuspicious = uniqueChars < 15 || dataSize > 1e3 && dataSize < 5e4;
99571
- pushFinding({
99605
+ findings.push({
99572
99606
  code: "base64_media_prohibited",
99573
99607
  severity: "error",
99574
99608
  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.`,
@@ -99576,331 +99610,57 @@ ${right2.raw}`)
99576
99610
  snippet: truncateSnippet((b64Match[1] ?? "").slice(0, 80) + "...")
99577
99611
  });
99578
99612
  }
99579
- }
99580
- for (const tag of tags) {
99581
- if (tag.name !== "video" && tag.name !== "audio") continue;
99582
- const hasDataStart = readAttr(tag.raw, "data-start");
99583
- const hasId = readAttr(tag.raw, "id");
99584
- const hasSrc = readAttr(tag.raw, "src");
99585
- if (hasDataStart && !hasId) {
99586
- pushFinding({
99587
- code: "media_missing_id",
99588
- severity: "error",
99589
- 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.`,
99590
- fixHint: `Add a unique id attribute: <${tag.name} id="my-${tag.name}" ...>`,
99591
- snippet: truncateSnippet(tag.raw)
99592
- });
99593
- }
99594
- if (hasDataStart && hasId && !hasSrc) {
99595
- pushFinding({
99596
- code: "media_missing_src",
99597
- severity: "error",
99598
- message: `<${tag.name} id="${hasId}"> has data-start but no src attribute. The renderer cannot load this media.`,
99599
- elementId: hasId,
99600
- fixHint: `Add a src attribute to the <${tag.name}> element directly. If using <source> children, the renderer still requires src on the parent element.`,
99601
- snippet: truncateSnippet(tag.raw)
99602
- });
99603
- }
99604
- if (readAttr(tag.raw, "preload") === "none") {
99605
- pushFinding({
99606
- code: "media_preload_none",
99607
- severity: "warning",
99608
- 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.`,
99609
- elementId: hasId || void 0,
99610
- fixHint: `Remove preload="none" or change to preload="auto". The framework manages media loading.`,
99611
- snippet: truncateSnippet(tag.raw)
99612
- });
99613
- }
99614
- }
99615
- for (const tag of tags) {
99616
- if (tag.name === "audio" || tag.name === "script" || tag.name === "style") continue;
99617
- if (!readAttr(tag.raw, "data-start")) continue;
99618
- if (readAttr(tag.raw, "data-composition-id")) continue;
99619
- if (readAttr(tag.raw, "data-composition-src")) continue;
99620
- const classAttr = readAttr(tag.raw, "class") || "";
99621
- const styleAttr = readAttr(tag.raw, "style") || "";
99622
- const hasClip = classAttr.split(/\s+/).includes("clip");
99623
- const hasHiddenStyle = /visibility\s*:\s*hidden/i.test(styleAttr) || /opacity\s*:\s*0/i.test(styleAttr);
99624
- if (!hasClip && !hasHiddenStyle) {
99625
- const elementId = readAttr(tag.raw, "id") || void 0;
99626
- pushFinding({
99627
- code: "timed_element_missing_visibility_hidden",
99628
- severity: "info",
99629
- 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.`,
99630
- elementId,
99631
- fixHint: 'Add class="clip" (with CSS: .clip { visibility: hidden; }) or style="opacity:0" if the element should start hidden.',
99632
- snippet: truncateSnippet(tag.raw)
99633
- });
99634
- }
99635
- }
99636
- for (const tag of tags) {
99637
- if (readAttr(tag.raw, "data-layer") && !readAttr(tag.raw, "data-track-index")) {
99638
- const elementId = readAttr(tag.raw, "id") || void 0;
99639
- pushFinding({
99640
- code: "deprecated_data_layer",
99641
- severity: "warning",
99642
- message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> uses data-layer instead of data-track-index.`,
99643
- elementId,
99644
- fixHint: "Replace data-layer with data-track-index. The runtime reads data-track-index.",
99645
- snippet: truncateSnippet(tag.raw)
99646
- });
99647
- }
99648
- if (readAttr(tag.raw, "data-end") && !readAttr(tag.raw, "data-duration")) {
99649
- const elementId = readAttr(tag.raw, "id") || void 0;
99650
- pushFinding({
99651
- code: "deprecated_data_end",
99652
- severity: "warning",
99653
- message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> uses data-end without data-duration. Use data-duration in source HTML.`,
99654
- elementId,
99655
- fixHint: "Replace data-end with data-duration. The compiler generates data-end from data-duration automatically.",
99656
- snippet: truncateSnippet(tag.raw)
99657
- });
99658
- }
99659
- }
99660
- for (const script of scripts) {
99661
- const templateLiteralSelectorPattern = /(?:querySelector|querySelectorAll)\s*\(\s*`[^`]*\$\{[^}]+\}[^`]*`\s*\)/g;
99662
- let tlMatch;
99663
- while ((tlMatch = templateLiteralSelectorPattern.exec(script.content)) !== null) {
99664
- pushFinding({
99665
- code: "template_literal_selector",
99666
- severity: "error",
99667
- message: "querySelector uses a template literal variable (e.g. `${compId}`). The HTML bundler's CSS parser crashes on these. Use a hardcoded string instead.",
99668
- file: filePath,
99669
- fixHint: "Replace the template literal variable with a hardcoded string. The bundler's CSS parser cannot handle interpolated variables in script content.",
99670
- snippet: truncateSnippet(tlMatch[0])
99671
- });
99672
- }
99673
- }
99674
- {
99675
- const cssTranslateSelectors = /* @__PURE__ */ new Map();
99676
- const cssScaleSelectors = /* @__PURE__ */ new Map();
99677
- for (const style of styles) {
99678
- for (const [, selector, body] of style.content.matchAll(
99679
- /([#.][a-zA-Z0-9_-]+)\s*\{([^}]+)\}/g
99680
- )) {
99681
- const tMatch = body?.match(/transform\s*:\s*([^;]+)/);
99682
- if (!tMatch || !tMatch[1]) continue;
99683
- const transformVal = tMatch[1].trim();
99684
- if (/translate/i.test(transformVal)) {
99685
- cssTranslateSelectors.set((selector ?? "").trim(), transformVal);
99686
- }
99687
- if (/scale/i.test(transformVal)) {
99688
- cssScaleSelectors.set((selector ?? "").trim(), transformVal);
99689
- }
99690
- }
99691
- }
99692
- if (cssTranslateSelectors.size > 0 || cssScaleSelectors.size > 0) {
99693
- for (const script of scripts) {
99694
- if (!/gsap\.timeline/.test(script.content)) continue;
99695
- const windows = extractGsapWindows(script.content);
99696
- const conflicts = /* @__PURE__ */ new Map();
99697
- for (const win of windows) {
99698
- if (win.method === "fromTo") continue;
99699
- const sel = win.targetSelector;
99700
- const cssKey = sel.startsWith("#") || sel.startsWith(".") ? sel : `#${sel}`;
99701
- const translateProps = win.properties.filter(
99702
- (p) => ["x", "y", "xPercent", "yPercent"].includes(p)
99703
- );
99704
- const scaleProps = win.properties.filter((p) => p === "scale");
99705
- const cssFromTranslate = translateProps.length > 0 ? cssTranslateSelectors.get(cssKey) : void 0;
99706
- const cssFromScale = scaleProps.length > 0 ? cssScaleSelectors.get(cssKey) : void 0;
99707
- if (!cssFromTranslate && !cssFromScale) continue;
99708
- const existing = conflicts.get(sel) ?? {
99709
- cssTransform: [cssFromTranslate, cssFromScale].filter(Boolean).join(" "),
99710
- props: /* @__PURE__ */ new Set(),
99711
- raw: win.raw
99712
- };
99713
- for (const p of [...translateProps, ...scaleProps]) existing.props.add(p);
99714
- conflicts.set(sel, existing);
99715
- }
99716
- for (const [sel, { cssTransform, props, raw: raw2 }] of conflicts) {
99717
- const propList = [...props].join("/");
99718
- pushFinding({
99719
- code: "gsap_css_transform_conflict",
99720
- severity: "warning",
99721
- 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.`,
99722
- selector: sel,
99723
- 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.`,
99724
- snippet: truncateSnippet(raw2)
99725
- });
99726
- }
99613
+ return findings;
99614
+ },
99615
+ // media_missing_id + media_missing_src + media_preload_none
99616
+ ({ tags }) => {
99617
+ const findings = [];
99618
+ for (const tag of tags) {
99619
+ if (tag.name !== "video" && tag.name !== "audio") continue;
99620
+ const hasDataStart = readAttr(tag.raw, "data-start");
99621
+ const hasId = readAttr(tag.raw, "id");
99622
+ const hasSrc = readAttr(tag.raw, "src");
99623
+ if (hasDataStart && !hasId) {
99624
+ findings.push({
99625
+ code: "media_missing_id",
99626
+ severity: "error",
99627
+ 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.`,
99628
+ fixHint: `Add a unique id attribute: <${tag.name} id="my-${tag.name}" ...>`,
99629
+ snippet: truncateSnippet(tag.raw)
99630
+ });
99727
99631
  }
99728
- }
99729
- }
99730
- for (const script of scripts) {
99731
- const content = script.content;
99732
- const hasExitTween = /\.to\s*\([^,]+,\s*\{[^}]*opacity\s*:\s*0/.test(content);
99733
- const hasHardKill = /\.set\s*\([^,]+,\s*\{[^}]*(?:visibility\s*:\s*["']hidden["']|opacity\s*:\s*0)/.test(content);
99734
- const hasCaptionLoop = /forEach|\.forEach\s*\(/.test(content) && /createElement|caption|group|cg-/.test(content);
99735
- if (hasCaptionLoop && hasExitTween && !hasHardKill) {
99736
- pushFinding({
99737
- code: "caption_exit_missing_hard_kill",
99738
- severity: "warning",
99739
- 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.",
99740
- fixHint: 'Add `tl.set(groupEl, { opacity: 0, visibility: "hidden" }, group.end)` after every exit tl.to animation as a deterministic kill.'
99741
- });
99742
- }
99743
- }
99744
- for (const style of styles) {
99745
- const content = style.content;
99746
- const captionBlocks = content.matchAll(
99747
- /(\.caption[-_]?(?:group|container|text|line|word)|#caption[-_]?container)\s*\{([^}]+)\}/gi
99748
- );
99749
- for (const [, selector, body] of captionBlocks) {
99750
- if (!body) continue;
99751
- const hasNowrap = /white-space\s*:\s*nowrap/i.test(body);
99752
- const hasMaxWidth = /max-width/i.test(body);
99753
- if (hasNowrap && !hasMaxWidth) {
99754
- pushFinding({
99755
- code: "caption_text_overflow_risk",
99756
- severity: "warning",
99757
- selector: (selector ?? "").trim(),
99758
- message: `Caption selector "${(selector ?? "").trim()}" has white-space: nowrap but no max-width. Long phrases will clip off-screen.`,
99759
- fixHint: "Add max-width: 1600px (landscape) or max-width: 900px (portrait) and overflow: hidden."
99632
+ if (hasDataStart && hasId && !hasSrc) {
99633
+ findings.push({
99634
+ code: "media_missing_src",
99635
+ severity: "error",
99636
+ message: `<${tag.name} id="${hasId}"> has data-start but no src attribute. The renderer cannot load this media.`,
99637
+ elementId: hasId,
99638
+ fixHint: `Add a src attribute to the <${tag.name}> element directly. If using <source> children, the renderer still requires src on the parent element.`,
99639
+ snippet: truncateSnippet(tag.raw)
99760
99640
  });
99761
99641
  }
99762
- }
99763
- }
99764
- for (const style of styles) {
99765
- const content = style.content;
99766
- const captionBlocks = content.matchAll(
99767
- /(\.caption[-_]?(?:group|container|text|line)|#caption[-_]?container)\s*\{([^}]+)\}/gi
99768
- );
99769
- for (const [, selector, body] of captionBlocks) {
99770
- if (!body) continue;
99771
- if (/position\s*:\s*relative/i.test(body)) {
99772
- pushFinding({
99773
- code: "caption_container_relative_position",
99642
+ if (readAttr(tag.raw, "preload") === "none") {
99643
+ findings.push({
99644
+ code: "media_preload_none",
99774
99645
  severity: "warning",
99775
- selector: (selector ?? "").trim(),
99776
- message: `Caption selector "${(selector ?? "").trim()}" uses position: relative which causes overflow and breaks caption stacking.`,
99777
- fixHint: "Use position: absolute for all caption elements."
99646
+ 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.`,
99647
+ elementId: hasId || void 0,
99648
+ fixHint: `Remove preload="none" or change to preload="auto". The framework manages media loading.`,
99649
+ snippet: truncateSnippet(tag.raw)
99778
99650
  });
99779
99651
  }
99780
99652
  }
99653
+ return findings;
99781
99654
  }
99782
- {
99783
- const externalScriptRe = /<script\b[^>]*\bsrc=["'](https?:\/\/[^"']+)["'][^>]*>/gi;
99784
- let match2;
99785
- const seen2 = /* @__PURE__ */ new Set();
99786
- while ((match2 = externalScriptRe.exec(source2)) !== null) {
99787
- const src = match2[1] ?? "";
99788
- if (seen2.has(src)) continue;
99789
- seen2.add(src);
99790
- pushFinding({
99791
- code: "external_script_dependency",
99792
- severity: "info",
99793
- 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.`,
99794
- 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.",
99795
- snippet: truncateSnippet(match2[0] ?? "")
99796
- });
99797
- }
99798
- }
99799
- const errorCount = findings.filter((finding) => finding.severity === "error").length;
99800
- const warningCount = findings.filter((finding) => finding.severity === "warning").length;
99801
- const infoCount = findings.filter((finding) => finding.severity === "info").length;
99802
- return {
99803
- ok: errorCount === 0,
99804
- errorCount,
99805
- warningCount,
99806
- infoCount,
99807
- findings
99808
- };
99809
- }
99810
- function extractOpenTags(source2) {
99811
- const tags = [];
99812
- let match2;
99813
- while ((match2 = TAG_PATTERN.exec(source2)) !== null) {
99814
- const raw2 = match2[0];
99815
- if (raw2.startsWith("</") || raw2.startsWith("<!")) {
99816
- continue;
99817
- }
99818
- tags.push({
99819
- raw: raw2,
99820
- name: (match2[1] || "").toLowerCase(),
99821
- attrs: match2[2] || "",
99822
- index: match2.index
99823
- });
99824
- }
99825
- return tags;
99826
- }
99827
- function extractBlocks(source2, pattern) {
99828
- const blocks = [];
99829
- let match2;
99830
- while ((match2 = pattern.exec(source2)) !== null) {
99831
- blocks.push({
99832
- attrs: match2[1] || "",
99833
- content: match2[2] || "",
99834
- raw: match2[0],
99835
- index: match2.index
99836
- });
99837
- }
99838
- return blocks;
99839
- }
99840
- function findRootTag(source2) {
99841
- const bodyMatch = source2.match(/<body\b[^>]*>([\s\S]*?)<\/body>/i);
99842
- const bodyContent = bodyMatch ? bodyMatch[1] ?? source2 : source2;
99843
- const bodyTags = extractOpenTags(bodyContent);
99844
- for (const tag of bodyTags) {
99845
- if (["script", "style", "meta", "link", "title"].includes(tag.name)) {
99846
- continue;
99847
- }
99848
- return tag;
99849
- }
99850
- return null;
99851
- }
99852
- function readAttr(tagSource, attr) {
99853
- if (!tagSource) {
99854
- return null;
99855
- }
99856
- const escaped = attr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
99857
- const match2 = tagSource.match(new RegExp(`\\b${escaped}\\s*=\\s*["']([^"']+)["']`, "i"));
99858
- return match2?.[1] || null;
99859
- }
99860
- function collectCompositionIds(tags) {
99861
- const ids = /* @__PURE__ */ new Set();
99862
- for (const tag of tags) {
99863
- const compId = readAttr(tag.raw, "data-composition-id");
99864
- if (compId) {
99865
- ids.add(compId);
99866
- }
99867
- }
99868
- return ids;
99869
- }
99870
- function extractCompositionIdsFromCss(css) {
99871
- const ids = /* @__PURE__ */ new Set();
99872
- let match2;
99873
- while ((match2 = COMPOSITION_ID_IN_CSS_PATTERN.exec(css)) !== null) {
99874
- if (match2[1]) {
99875
- ids.add(match2[1]);
99876
- }
99877
- }
99878
- return [...ids];
99879
- }
99880
- function getInlineScriptSyntaxError(source2) {
99881
- if (!source2.trim()) {
99882
- return null;
99883
- }
99884
- try {
99885
- new Function(source2);
99886
- return null;
99887
- } catch (error) {
99888
- if (error instanceof Error) {
99889
- return error.message;
99890
- }
99891
- return String(error);
99892
- }
99893
- }
99894
- function isMediaTag(tagName19) {
99895
- return tagName19 === "video" || tagName19 === "audio" || tagName19 === "img";
99896
- }
99655
+ ];
99656
+
99657
+ // ../core/src/lint/rules/gsap.ts
99658
+ var META_GSAP_KEYS = /* @__PURE__ */ new Set(["duration", "ease", "repeat", "yoyo", "overwrite", "delay"]);
99897
99659
  function countClassUsage(tags) {
99898
99660
  const counts = /* @__PURE__ */ new Map();
99899
99661
  for (const tag of tags) {
99900
99662
  const classAttr = readAttr(tag.raw, "class");
99901
- if (!classAttr) {
99902
- continue;
99903
- }
99663
+ if (!classAttr) continue;
99904
99664
  for (const className of classAttr.split(/\s+/).filter(Boolean)) {
99905
99665
  counts.set(className, (counts.get(className) || 0) + 1);
99906
99666
  }
@@ -99912,13 +99672,9 @@ function readRegisteredTimelineCompositionId(script) {
99912
99672
  return match2?.[1] || null;
99913
99673
  }
99914
99674
  function extractGsapWindows(script) {
99915
- if (!/gsap\.timeline/.test(script)) {
99916
- return [];
99917
- }
99675
+ if (!/gsap\.timeline/.test(script)) return [];
99918
99676
  const parsed = parseGsapScript(script);
99919
- if (parsed.animations.length === 0) {
99920
- return [];
99921
- }
99677
+ if (parsed.animations.length === 0) return [];
99922
99678
  const windows = [];
99923
99679
  const timelineVar = parsed.timelineVar;
99924
99680
  const methodPattern = new RegExp(
@@ -99932,9 +99688,7 @@ function extractGsapWindows(script) {
99932
99688
  const meta = parseGsapWindowMeta(match2[1] ?? "", match2[2] ?? "");
99933
99689
  const animation = parsed.animations[index];
99934
99690
  index += 1;
99935
- if (!animation) {
99936
- continue;
99937
- }
99691
+ if (!animation) continue;
99938
99692
  windows.push({
99939
99693
  targetSelector: animation.targetSelector,
99940
99694
  position: animation.position,
@@ -99949,9 +99703,7 @@ function extractGsapWindows(script) {
99949
99703
  }
99950
99704
  function parseGsapWindowMeta(method, argsStr) {
99951
99705
  const selectorMatch = argsStr.match(/^\s*["']([^"']+)["']\s*,/);
99952
- if (!selectorMatch) {
99953
- return { effectiveDuration: 0, properties: [], overwriteAuto: false };
99954
- }
99706
+ if (!selectorMatch) return { effectiveDuration: 0, properties: [], overwriteAuto: false };
99955
99707
  const afterSelector = argsStr.slice(selectorMatch[0].length);
99956
99708
  let properties = {};
99957
99709
  let fromProperties = {};
@@ -99976,20 +99728,15 @@ function parseGsapWindowMeta(method, argsStr) {
99976
99728
  }
99977
99729
  const duration = numberValue(properties.duration) || 0;
99978
99730
  const repeat = numberValue(properties.repeat) || 0;
99979
- const yoyo = stringValue(properties.yoyo) === "true";
99980
99731
  const cycleCount = repeat > 0 ? repeat + 1 : 1;
99981
- const effectiveDuration = duration * cycleCount * (yoyo ? 1 : 1);
99732
+ const effectiveDuration = duration * cycleCount;
99982
99733
  const overwriteAuto = stringValue(properties.overwrite) === "auto";
99983
99734
  const propertyNames = /* @__PURE__ */ new Set();
99984
99735
  for (const key2 of Object.keys(fromProperties)) {
99985
- if (!META_GSAP_KEYS.has(key2)) {
99986
- propertyNames.add(key2);
99987
- }
99736
+ if (!META_GSAP_KEYS.has(key2)) propertyNames.add(key2);
99988
99737
  }
99989
99738
  for (const key2 of Object.keys(properties)) {
99990
- if (!META_GSAP_KEYS.has(key2)) {
99991
- propertyNames.add(key2);
99992
- }
99739
+ if (!META_GSAP_KEYS.has(key2)) propertyNames.add(key2);
99993
99740
  }
99994
99741
  return {
99995
99742
  effectiveDuration: method === "set" ? 0 : effectiveDuration,
@@ -100000,17 +99747,13 @@ function parseGsapWindowMeta(method, argsStr) {
100000
99747
  function parseLooseObjectLiteral(source2) {
100001
99748
  const result = {};
100002
99749
  const cleaned = source2.replace(/^\{|\}$/g, "").trim();
100003
- if (!cleaned) {
100004
- return result;
100005
- }
99750
+ if (!cleaned) return result;
100006
99751
  const propertyPattern = /(\w+)\s*:\s*("[^"]*"|'[^']*'|true|false|-?[\d.]+|[a-zA-Z_][\w.]*)/g;
100007
99752
  let match2;
100008
99753
  while ((match2 = propertyPattern.exec(cleaned)) !== null) {
100009
99754
  const key2 = match2[1];
100010
99755
  const rawValue = match2[2];
100011
- if (!key2 || rawValue == null) {
100012
- continue;
100013
- }
99756
+ if (!key2 || rawValue == null) continue;
100014
99757
  if (rawValue.startsWith('"') && rawValue.endsWith('"') || rawValue.startsWith("'") && rawValue.endsWith("'")) {
100015
99758
  result[key2] = rawValue.slice(1, -1);
100016
99759
  continue;
@@ -100021,26 +99764,19 @@ function parseLooseObjectLiteral(source2) {
100021
99764
  return result;
100022
99765
  }
100023
99766
  function findMatchingBrace2(source2, startIndex) {
100024
- if (startIndex < 0) {
100025
- return -1;
100026
- }
99767
+ if (startIndex < 0) return -1;
100027
99768
  let depth = 0;
100028
99769
  for (let i = startIndex; i < source2.length; i++) {
100029
- if (source2[i] === "{") {
100030
- depth += 1;
100031
- } else if (source2[i] === "}") {
99770
+ if (source2[i] === "{") depth += 1;
99771
+ else if (source2[i] === "}") {
100032
99772
  depth -= 1;
100033
- if (depth === 0) {
100034
- return i;
100035
- }
99773
+ if (depth === 0) return i;
100036
99774
  }
100037
99775
  }
100038
99776
  return -1;
100039
99777
  }
100040
99778
  function numberValue(value) {
100041
- if (typeof value === "number") {
100042
- return value;
100043
- }
99779
+ if (typeof value === "number") return value;
100044
99780
  if (typeof value === "string" && value.trim()) {
100045
99781
  const numeric = Number(value);
100046
99782
  return Number.isFinite(numeric) ? numeric : null;
@@ -100048,39 +99784,451 @@ function numberValue(value) {
100048
99784
  return null;
100049
99785
  }
100050
99786
  function stringValue(value) {
100051
- if (typeof value === "string") {
100052
- return value;
100053
- }
100054
- if (typeof value === "number") {
100055
- return String(value);
100056
- }
99787
+ if (typeof value === "string") return value;
99788
+ if (typeof value === "number") return String(value);
100057
99789
  return null;
100058
99790
  }
100059
99791
  function isSuspiciousGlobalSelector(selector) {
100060
- if (!selector) {
100061
- return false;
100062
- }
100063
- if (selector.includes("[data-composition-id=")) {
100064
- return false;
100065
- }
100066
- if (selector.startsWith("#")) {
100067
- return false;
100068
- }
99792
+ if (!selector) return false;
99793
+ if (selector.includes("[data-composition-id=")) return false;
99794
+ if (selector.startsWith("#")) return false;
100069
99795
  return selector.startsWith(".") || /^[a-z]/i.test(selector);
100070
99796
  }
100071
99797
  function getSingleClassSelector(selector) {
100072
99798
  const match2 = selector.trim().match(/^\.(?<name>[A-Za-z0-9_-]+)$/);
100073
99799
  return match2?.groups?.name || null;
100074
99800
  }
100075
- function truncateSnippet(value, maxLength = 220) {
100076
- const normalized = value.replace(/\s+/g, " ").trim();
100077
- if (!normalized) {
100078
- return void 0;
99801
+ var gsapRules = [
99802
+ // overlapping_gsap_tweens + gsap_animates_clip_element + unscoped_gsap_selector
99803
+ ({ tags, scripts, rootCompositionId }) => {
99804
+ const findings = [];
99805
+ const clipIds = /* @__PURE__ */ new Map();
99806
+ const clipClasses = /* @__PURE__ */ new Map();
99807
+ for (const tag of tags) {
99808
+ const classAttr = readAttr(tag.raw, "class") || "";
99809
+ const classes = classAttr.split(/\s+/).filter(Boolean);
99810
+ if (!classes.includes("clip")) continue;
99811
+ const id = readAttr(tag.raw, "id");
99812
+ const info = {
99813
+ tag: tag.name,
99814
+ id: id || "",
99815
+ classes: classAttr
99816
+ };
99817
+ if (id) clipIds.set(`#${id}`, info);
99818
+ for (const cls of classes) {
99819
+ if (cls !== "clip") clipClasses.set(`.${cls}`, info);
99820
+ }
99821
+ }
99822
+ const classUsage = countClassUsage(tags);
99823
+ for (const script of scripts) {
99824
+ const localTimelineCompId = readRegisteredTimelineCompositionId(script.content);
99825
+ const gsapWindows = extractGsapWindows(script.content);
99826
+ for (let i = 0; i < gsapWindows.length; i++) {
99827
+ const left2 = gsapWindows[i];
99828
+ if (!left2) continue;
99829
+ if (left2.end <= left2.position) continue;
99830
+ for (let j = i + 1; j < gsapWindows.length; j++) {
99831
+ const right2 = gsapWindows[j];
99832
+ if (!right2) continue;
99833
+ if (right2.end <= right2.position) continue;
99834
+ if (left2.targetSelector !== right2.targetSelector) continue;
99835
+ const overlapStart = Math.max(left2.position, right2.position);
99836
+ const overlapEnd = Math.min(left2.end, right2.end);
99837
+ if (overlapEnd <= overlapStart) continue;
99838
+ if (left2.overwriteAuto || right2.overwriteAuto) continue;
99839
+ const sharedProperties = left2.properties.filter(
99840
+ (prop2) => right2.properties.includes(prop2)
99841
+ );
99842
+ if (sharedProperties.length === 0) continue;
99843
+ findings.push({
99844
+ code: "overlapping_gsap_tweens",
99845
+ severity: "warning",
99846
+ message: `GSAP tweens overlap on "${left2.targetSelector}" for ${sharedProperties.join(", ")} between ${overlapStart.toFixed(2)}s and ${overlapEnd.toFixed(2)}s.`,
99847
+ selector: left2.targetSelector,
99848
+ fixHint: 'Shorten the earlier tween, move the later tween, or add `overwrite: "auto"`.',
99849
+ snippet: truncateSnippet(`${left2.raw}
99850
+ ${right2.raw}`)
99851
+ });
99852
+ }
99853
+ }
99854
+ for (const win of gsapWindows) {
99855
+ const sel = win.targetSelector;
99856
+ const clipInfo = clipIds.get(sel) || clipClasses.get(sel);
99857
+ if (!clipInfo) continue;
99858
+ const elDesc = `<${clipInfo.tag}${clipInfo.id ? ` id="${clipInfo.id}"` : ""} class="${clipInfo.classes}">`;
99859
+ findings.push({
99860
+ code: "gsap_animates_clip_element",
99861
+ severity: "error",
99862
+ message: `GSAP animation targets a clip element. Selector "${sel}" resolves to element ${elDesc}. The framework manages clip visibility \u2014 animate an inner wrapper instead.`,
99863
+ selector: sel,
99864
+ elementId: clipInfo.id || void 0,
99865
+ fixHint: "Wrap content in a child <div> and target that with GSAP.",
99866
+ snippet: truncateSnippet(win.raw)
99867
+ });
99868
+ }
99869
+ if (!localTimelineCompId || localTimelineCompId === rootCompositionId) continue;
99870
+ for (const win of gsapWindows) {
99871
+ if (!isSuspiciousGlobalSelector(win.targetSelector)) continue;
99872
+ const className = getSingleClassSelector(win.targetSelector);
99873
+ if (className && (classUsage.get(className) || 0) < 2) continue;
99874
+ findings.push({
99875
+ code: "unscoped_gsap_selector",
99876
+ severity: "warning",
99877
+ message: `Timeline "${localTimelineCompId}" uses unscoped selector "${win.targetSelector}" that will target elements in ALL compositions when bundled, causing data loss (opacity, transforms, etc.).`,
99878
+ selector: win.targetSelector,
99879
+ fixHint: `Scope the selector: \`[data-composition-id="${localTimelineCompId}"] ${win.targetSelector}\` or use a unique id.`,
99880
+ snippet: truncateSnippet(win.raw)
99881
+ });
99882
+ }
99883
+ }
99884
+ return findings;
99885
+ },
99886
+ // gsap_css_transform_conflict
99887
+ ({ styles, scripts }) => {
99888
+ const findings = [];
99889
+ const cssTranslateSelectors = /* @__PURE__ */ new Map();
99890
+ const cssScaleSelectors = /* @__PURE__ */ new Map();
99891
+ for (const style of styles) {
99892
+ for (const [, selector, body] of style.content.matchAll(
99893
+ /([#.][a-zA-Z0-9_-]+)\s*\{([^}]+)\}/g
99894
+ )) {
99895
+ const tMatch = body?.match(/transform\s*:\s*([^;]+)/);
99896
+ if (!tMatch || !tMatch[1]) continue;
99897
+ const transformVal = tMatch[1].trim();
99898
+ if (/translate/i.test(transformVal))
99899
+ cssTranslateSelectors.set((selector ?? "").trim(), transformVal);
99900
+ if (/scale/i.test(transformVal))
99901
+ cssScaleSelectors.set((selector ?? "").trim(), transformVal);
99902
+ }
99903
+ }
99904
+ if (cssTranslateSelectors.size === 0 && cssScaleSelectors.size === 0) return findings;
99905
+ for (const script of scripts) {
99906
+ if (!/gsap\.timeline/.test(script.content)) continue;
99907
+ const windows = extractGsapWindows(script.content);
99908
+ const conflicts = /* @__PURE__ */ new Map();
99909
+ for (const win of windows) {
99910
+ if (win.method === "fromTo") continue;
99911
+ const sel = win.targetSelector;
99912
+ const cssKey = sel.startsWith("#") || sel.startsWith(".") ? sel : `#${sel}`;
99913
+ const translateProps = win.properties.filter(
99914
+ (p) => ["x", "y", "xPercent", "yPercent"].includes(p)
99915
+ );
99916
+ const scaleProps = win.properties.filter((p) => p === "scale");
99917
+ const cssFromTranslate = translateProps.length > 0 ? cssTranslateSelectors.get(cssKey) : void 0;
99918
+ const cssFromScale = scaleProps.length > 0 ? cssScaleSelectors.get(cssKey) : void 0;
99919
+ if (!cssFromTranslate && !cssFromScale) continue;
99920
+ const existing = conflicts.get(sel) ?? {
99921
+ cssTransform: [cssFromTranslate, cssFromScale].filter(Boolean).join(" "),
99922
+ props: /* @__PURE__ */ new Set(),
99923
+ raw: win.raw
99924
+ };
99925
+ for (const p of [...translateProps, ...scaleProps]) existing.props.add(p);
99926
+ conflicts.set(sel, existing);
99927
+ }
99928
+ for (const [sel, { cssTransform, props, raw: raw2 }] of conflicts) {
99929
+ const propList = [...props].join("/");
99930
+ findings.push({
99931
+ code: "gsap_css_transform_conflict",
99932
+ severity: "warning",
99933
+ 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.`,
99934
+ selector: sel,
99935
+ 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.`,
99936
+ snippet: truncateSnippet(raw2)
99937
+ });
99938
+ }
99939
+ }
99940
+ return findings;
99941
+ },
99942
+ // missing_gsap_script
99943
+ ({ scripts }) => {
99944
+ const allScriptTexts = scripts.filter((s) => !/\bsrc\s*=/.test(s.attrs)).map((s) => s.content);
99945
+ const allScriptSrcs = scripts.map((s) => readAttr(`<script ${s.attrs}>`, "src") || "").filter(Boolean);
99946
+ const usesGsap = allScriptTexts.some(
99947
+ (t) => /gsap\.(to|from|fromTo|timeline|set|registerPlugin)\b/.test(t)
99948
+ );
99949
+ const hasGsapScript = allScriptSrcs.some((src) => /gsap/i.test(src));
99950
+ if (!usesGsap || hasGsapScript) return [];
99951
+ return [
99952
+ {
99953
+ code: "missing_gsap_script",
99954
+ severity: "error",
99955
+ message: "Composition uses GSAP but no GSAP script is loaded. The animation will not run.",
99956
+ fixHint: 'Add <script src="https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js"></script> before your animation script.'
99957
+ }
99958
+ ];
100079
99959
  }
100080
- if (normalized.length <= maxLength) {
100081
- return normalized;
99960
+ ];
99961
+
99962
+ // ../core/src/lint/rules/captions.ts
99963
+ var captionRules = [
99964
+ // caption_exit_missing_hard_kill
99965
+ ({ scripts }) => {
99966
+ const findings = [];
99967
+ for (const script of scripts) {
99968
+ const content = script.content;
99969
+ const hasExitTween = /\.to\s*\([^,]+,\s*\{[^}]*opacity\s*:\s*0/.test(content);
99970
+ const hasHardKill = /\.set\s*\([^,]+,\s*\{[^}]*(?:visibility\s*:\s*["']hidden["']|opacity\s*:\s*0)/.test(
99971
+ content
99972
+ );
99973
+ const hasCaptionLoop = /forEach|\.forEach\s*\(/.test(content) && /createElement|caption|group|cg-/.test(content);
99974
+ if (hasCaptionLoop && hasExitTween && !hasHardKill) {
99975
+ findings.push({
99976
+ code: "caption_exit_missing_hard_kill",
99977
+ severity: "warning",
99978
+ 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.",
99979
+ fixHint: 'Add `tl.set(groupEl, { opacity: 0, visibility: "hidden" }, group.end)` after every exit tl.to animation as a deterministic kill.'
99980
+ });
99981
+ }
99982
+ }
99983
+ return findings;
99984
+ },
99985
+ // caption_text_overflow_risk
99986
+ ({ styles }) => {
99987
+ const findings = [];
99988
+ for (const style of styles) {
99989
+ const captionBlocks = style.content.matchAll(
99990
+ /(\.caption[-_]?(?:group|container|text|line|word)|#caption[-_]?container)\s*\{([^}]+)\}/gi
99991
+ );
99992
+ for (const [, selector, body] of captionBlocks) {
99993
+ if (!body) continue;
99994
+ const hasNowrap = /white-space\s*:\s*nowrap/i.test(body);
99995
+ const hasMaxWidth = /max-width/i.test(body);
99996
+ if (hasNowrap && !hasMaxWidth) {
99997
+ findings.push({
99998
+ code: "caption_text_overflow_risk",
99999
+ severity: "warning",
100000
+ selector: (selector ?? "").trim(),
100001
+ message: `Caption selector "${(selector ?? "").trim()}" has white-space: nowrap but no max-width. Long phrases will clip off-screen.`,
100002
+ fixHint: "Add max-width: 1600px (landscape) or max-width: 900px (portrait) and overflow: hidden."
100003
+ });
100004
+ }
100005
+ }
100006
+ }
100007
+ return findings;
100008
+ },
100009
+ // caption_container_relative_position
100010
+ ({ styles }) => {
100011
+ const findings = [];
100012
+ for (const style of styles) {
100013
+ const captionBlocks = style.content.matchAll(
100014
+ /(\.caption[-_]?(?:group|container|text|line)|#caption[-_]?container)\s*\{([^}]+)\}/gi
100015
+ );
100016
+ for (const [, selector, body] of captionBlocks) {
100017
+ if (!body) continue;
100018
+ if (/position\s*:\s*relative/i.test(body)) {
100019
+ findings.push({
100020
+ code: "caption_container_relative_position",
100021
+ severity: "warning",
100022
+ selector: (selector ?? "").trim(),
100023
+ message: `Caption selector "${(selector ?? "").trim()}" uses position: relative which causes overflow and breaks caption stacking.`,
100024
+ fixHint: "Use position: absolute for all caption elements."
100025
+ });
100026
+ }
100027
+ }
100028
+ }
100029
+ return findings;
100030
+ }
100031
+ ];
100032
+
100033
+ // ../core/src/lint/rules/composition.ts
100034
+ var compositionRules = [
100035
+ // timed_element_missing_visibility_hidden
100036
+ ({ tags }) => {
100037
+ const findings = [];
100038
+ for (const tag of tags) {
100039
+ if (tag.name === "audio" || tag.name === "script" || tag.name === "style") continue;
100040
+ if (!readAttr(tag.raw, "data-start")) continue;
100041
+ if (readAttr(tag.raw, "data-composition-id")) continue;
100042
+ if (readAttr(tag.raw, "data-composition-src")) continue;
100043
+ const classAttr = readAttr(tag.raw, "class") || "";
100044
+ const styleAttr = readAttr(tag.raw, "style") || "";
100045
+ const hasClip = classAttr.split(/\s+/).includes("clip");
100046
+ const hasHiddenStyle = /visibility\s*:\s*hidden/i.test(styleAttr) || /opacity\s*:\s*0/i.test(styleAttr);
100047
+ if (!hasClip && !hasHiddenStyle) {
100048
+ const elementId = readAttr(tag.raw, "id") || void 0;
100049
+ findings.push({
100050
+ code: "timed_element_missing_visibility_hidden",
100051
+ severity: "info",
100052
+ 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.`,
100053
+ elementId,
100054
+ fixHint: 'Add class="clip" (with CSS: .clip { visibility: hidden; }) or style="opacity:0" if the element should start hidden.',
100055
+ snippet: truncateSnippet(tag.raw)
100056
+ });
100057
+ }
100058
+ }
100059
+ return findings;
100060
+ },
100061
+ // deprecated_data_layer + deprecated_data_end
100062
+ ({ tags }) => {
100063
+ const findings = [];
100064
+ for (const tag of tags) {
100065
+ if (readAttr(tag.raw, "data-layer") && !readAttr(tag.raw, "data-track-index")) {
100066
+ const elementId = readAttr(tag.raw, "id") || void 0;
100067
+ findings.push({
100068
+ code: "deprecated_data_layer",
100069
+ severity: "warning",
100070
+ message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> uses data-layer instead of data-track-index.`,
100071
+ elementId,
100072
+ fixHint: "Replace data-layer with data-track-index. The runtime reads data-track-index.",
100073
+ snippet: truncateSnippet(tag.raw)
100074
+ });
100075
+ }
100076
+ if (readAttr(tag.raw, "data-end") && !readAttr(tag.raw, "data-duration")) {
100077
+ const elementId = readAttr(tag.raw, "id") || void 0;
100078
+ findings.push({
100079
+ code: "deprecated_data_end",
100080
+ severity: "warning",
100081
+ message: `<${tag.name}${elementId ? ` id="${elementId}"` : ""}> uses data-end without data-duration. Use data-duration in source HTML.`,
100082
+ elementId,
100083
+ fixHint: "Replace data-end with data-duration. The compiler generates data-end from data-duration automatically.",
100084
+ snippet: truncateSnippet(tag.raw)
100085
+ });
100086
+ }
100087
+ }
100088
+ return findings;
100089
+ },
100090
+ // template_literal_selector
100091
+ ({ scripts }) => {
100092
+ const findings = [];
100093
+ for (const script of scripts) {
100094
+ const templateLiteralSelectorPattern = /(?:querySelector|querySelectorAll)\s*\(\s*`[^`]*\$\{[^}]+\}[^`]*`\s*\)/g;
100095
+ let tlMatch;
100096
+ while ((tlMatch = templateLiteralSelectorPattern.exec(script.content)) !== null) {
100097
+ findings.push({
100098
+ code: "template_literal_selector",
100099
+ severity: "error",
100100
+ message: "querySelector uses a template literal variable (e.g. `${compId}`). The HTML bundler's CSS parser crashes on these. Use a hardcoded string instead.",
100101
+ fixHint: "Replace the template literal variable with a hardcoded string. The bundler's CSS parser cannot handle interpolated variables in script content.",
100102
+ snippet: truncateSnippet(tlMatch[0])
100103
+ });
100104
+ }
100105
+ }
100106
+ return findings;
100107
+ },
100108
+ // external_script_dependency
100109
+ ({ source: source2 }) => {
100110
+ const findings = [];
100111
+ const externalScriptRe = /<script\b[^>]*\bsrc=["'](https?:\/\/[^"']+)["'][^>]*>/gi;
100112
+ let match2;
100113
+ const seen = /* @__PURE__ */ new Set();
100114
+ while ((match2 = externalScriptRe.exec(source2)) !== null) {
100115
+ const src = match2[1] ?? "";
100116
+ if (seen.has(src)) continue;
100117
+ seen.add(src);
100118
+ findings.push({
100119
+ code: "external_script_dependency",
100120
+ severity: "info",
100121
+ 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.`,
100122
+ 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.",
100123
+ snippet: truncateSnippet(match2[0] ?? "")
100124
+ });
100125
+ }
100126
+ return findings;
100127
+ }
100128
+ ];
100129
+
100130
+ // ../core/src/lint/rules/adapters.ts
100131
+ var adapterRules = [
100132
+ // missing_lottie_script
100133
+ ({ tags, scripts }) => {
100134
+ const allScriptTexts = scripts.filter((s) => !/\bsrc\s*=/.test(s.attrs)).map((s) => s.content);
100135
+ const allScriptSrcs = scripts.map((s) => readAttr(`<script ${s.attrs}>`, "src") || "").filter(Boolean);
100136
+ const hasLottieAttr = tags.some((t) => readAttr(t.raw, "data-lottie-src") !== null);
100137
+ const usesLottieApi = allScriptTexts.some(
100138
+ (t) => /lottie\.(loadAnimation|setSpeed|play|stop|destroy)\b/.test(t)
100139
+ );
100140
+ const hasLottieScript = allScriptSrcs.some((src) => /lottie/i.test(src));
100141
+ if (!(hasLottieAttr || usesLottieApi) || hasLottieScript) return [];
100142
+ return [
100143
+ {
100144
+ code: "missing_lottie_script",
100145
+ severity: "error",
100146
+ message: "Composition uses Lottie but no Lottie script is loaded. The animation will not render.",
100147
+ fixHint: 'Add <script src="https://cdn.jsdelivr.net/npm/lottie-web@5/build/player/lottie.min.js"></script> before your Lottie code.'
100148
+ }
100149
+ ];
100150
+ },
100151
+ // missing_three_script
100152
+ ({ scripts }) => {
100153
+ const allScriptTexts = scripts.filter((s) => !/\bsrc\s*=/.test(s.attrs)).map((s) => s.content);
100154
+ const allScriptSrcs = scripts.map((s) => readAttr(`<script ${s.attrs}>`, "src") || "").filter(Boolean);
100155
+ const usesThree = allScriptTexts.some((t) => /\bTHREE\./.test(t));
100156
+ const hasThreeScript = allScriptSrcs.some((src) => /three/i.test(src));
100157
+ if (!usesThree || hasThreeScript) return [];
100158
+ return [
100159
+ {
100160
+ code: "missing_three_script",
100161
+ severity: "error",
100162
+ message: "Composition uses Three.js but no Three.js script is loaded. The 3D scene will not render.",
100163
+ fixHint: 'Add <script src="https://cdn.jsdelivr.net/npm/three@0.160/build/three.min.js"></script> before your Three.js code.'
100164
+ }
100165
+ ];
100166
+ }
100167
+ ];
100168
+
100169
+ // ../core/src/lint/hyperframeLinter.ts
100170
+ var ALL_RULES = [
100171
+ ...coreRules,
100172
+ ...mediaRules,
100173
+ ...gsapRules,
100174
+ ...captionRules,
100175
+ ...compositionRules,
100176
+ ...adapterRules
100177
+ ];
100178
+ function lintHyperframeHtml(html, options = {}) {
100179
+ const ctx = buildLintContext(html, options);
100180
+ const findings = [];
100181
+ const seen = /* @__PURE__ */ new Set();
100182
+ for (const rule of ALL_RULES) {
100183
+ for (const finding of rule(ctx)) {
100184
+ const dedupeKey = [
100185
+ finding.code,
100186
+ finding.severity,
100187
+ finding.selector || "",
100188
+ finding.elementId || "",
100189
+ finding.message
100190
+ ].join("|");
100191
+ if (seen.has(dedupeKey)) continue;
100192
+ seen.add(dedupeKey);
100193
+ findings.push(options.filePath ? { ...finding, file: options.filePath } : finding);
100194
+ }
100195
+ }
100196
+ const errorCount = findings.filter((f) => f.severity === "error").length;
100197
+ const warningCount = findings.filter((f) => f.severity === "warning").length;
100198
+ const infoCount = findings.filter((f) => f.severity === "info").length;
100199
+ return {
100200
+ ok: errorCount === 0,
100201
+ errorCount,
100202
+ warningCount,
100203
+ infoCount,
100204
+ findings
100205
+ };
100206
+ }
100207
+
100208
+ // ../core/src/compiler/rewriteSubCompPaths.ts
100209
+ import { join as join4, resolve as resolve6, dirname as dirname4 } from "path";
100210
+ var PATH_ATTRS = ["src", "href"];
100211
+ function isAbsoluteOrSpecial(val) {
100212
+ return !val || val.startsWith("http://") || val.startsWith("https://") || val.startsWith("//") || val.startsWith("data:") || val.startsWith("#");
100213
+ }
100214
+ function needsRewrite(val) {
100215
+ return val.startsWith("../") || val === "..";
100216
+ }
100217
+ function rewriteAssetPaths(elements, compSrcPath, getAttr2, setAttr) {
100218
+ const compDir = dirname4(compSrcPath);
100219
+ if (!compDir || compDir === ".") return;
100220
+ for (const el of elements) {
100221
+ for (const attr of PATH_ATTRS) {
100222
+ const val = (getAttr2(el, attr) || "").trim();
100223
+ if (isAbsoluteOrSpecial(val)) continue;
100224
+ if (!needsRewrite(val)) continue;
100225
+ const rewritten = join4(compDir, val);
100226
+ const normalized = resolve6("/", rewritten).slice(1);
100227
+ if (normalized !== val) {
100228
+ setAttr(el, attr, normalized);
100229
+ }
100230
+ }
100082
100231
  }
100083
- return `${normalized.slice(0, maxLength - 3)}...`;
100084
100232
  }
100085
100233
 
100086
100234
  // ../core/src/inline-scripts/hyperframesRuntime.engine.ts
@@ -100448,9 +100596,9 @@ async function initializeSession(session) {
100448
100596
  }
100449
100597
  async function captureFrameErrorDiagnostics(session, frameIndex, time, error) {
100450
100598
  try {
100451
- const diagnosticsDir = join4(session.outputDir, "diagnostics");
100599
+ const diagnosticsDir = join5(session.outputDir, "diagnostics");
100452
100600
  if (!existsSync4(diagnosticsDir)) mkdirSync(diagnosticsDir, { recursive: true });
100453
- const base = join4(diagnosticsDir, `frame-error-${frameIndex}`);
100601
+ const base = join5(diagnosticsDir, `frame-error-${frameIndex}`);
100454
100602
  await session.page.screenshot({ path: `${base}.png`, type: "png", fullPage: true });
100455
100603
  const html = await session.page.content();
100456
100604
  writeFileSync(`${base}.html`, html, "utf-8");
@@ -100548,7 +100696,7 @@ async function captureFrame(session, frameIndex, time) {
100548
100696
  );
100549
100697
  const ext = options.format === "png" ? "png" : "jpg";
100550
100698
  const frameName = `frame_${String(frameIndex).padStart(6, "0")}.${ext}`;
100551
- const framePath = join4(outputDir, frameName);
100699
+ const framePath = join5(outputDir, frameName);
100552
100700
  writeFileSync(framePath, buffer);
100553
100701
  return { frameIndex, time: quantizedTime, path: framePath, captureTimeMs };
100554
100702
  }
@@ -100598,12 +100746,12 @@ function getCapturePerfSummary(session) {
100598
100746
  // ../engine/src/services/chunkEncoder.ts
100599
100747
  import { spawn as spawn5 } from "child_process";
100600
100748
  import { copyFileSync, existsSync as existsSync5, mkdirSync as mkdirSync2, readdirSync as readdirSync3, statSync as statSync3, writeFileSync as writeFileSync2 } from "fs";
100601
- import { join as join5, dirname as dirname4 } from "path";
100749
+ import { join as join6, dirname as dirname5 } from "path";
100602
100750
 
100603
100751
  // ../engine/src/utils/gpuEncoder.ts
100604
100752
  import { spawn as spawn3 } from "child_process";
100605
100753
  async function detectGpuEncoder() {
100606
- return new Promise((resolve12) => {
100754
+ return new Promise((resolve13) => {
100607
100755
  const ffmpeg = spawn3("ffmpeg", ["-encoders"], {
100608
100756
  stdio: ["pipe", "pipe", "pipe"]
100609
100757
  });
@@ -100612,13 +100760,13 @@ async function detectGpuEncoder() {
100612
100760
  stdout += data.toString();
100613
100761
  });
100614
100762
  ffmpeg.on("close", () => {
100615
- if (stdout.includes("h264_nvenc")) resolve12("nvenc");
100616
- else if (stdout.includes("h264_videotoolbox")) resolve12("videotoolbox");
100617
- else if (stdout.includes("h264_vaapi")) resolve12("vaapi");
100618
- else if (stdout.includes("h264_qsv")) resolve12("qsv");
100619
- else resolve12(null);
100763
+ if (stdout.includes("h264_nvenc")) resolve13("nvenc");
100764
+ else if (stdout.includes("h264_videotoolbox")) resolve13("videotoolbox");
100765
+ else if (stdout.includes("h264_vaapi")) resolve13("vaapi");
100766
+ else if (stdout.includes("h264_qsv")) resolve13("qsv");
100767
+ else resolve13(null);
100620
100768
  });
100621
- ffmpeg.on("error", () => resolve12(null));
100769
+ ffmpeg.on("error", () => resolve13(null));
100622
100770
  });
100623
100771
  }
100624
100772
  var cachedGpuEncoder = void 0;
@@ -100652,7 +100800,7 @@ async function runFfmpeg(args, opts) {
100652
100800
  const signal = opts?.signal;
100653
100801
  const timeout2 = opts?.timeout ?? DEFAULT_TIMEOUT2;
100654
100802
  const onStderr = opts?.onStderr;
100655
- return new Promise((resolve12) => {
100803
+ return new Promise((resolve13) => {
100656
100804
  const ffmpeg = spawn4("ffmpeg", args);
100657
100805
  let stderr = "";
100658
100806
  const onAbort = () => {
@@ -100678,7 +100826,7 @@ async function runFfmpeg(args, opts) {
100678
100826
  ffmpeg.on("close", (code) => {
100679
100827
  clearTimeout(timer2);
100680
100828
  if (signal) signal.removeEventListener("abort", onAbort);
100681
- resolve12({
100829
+ resolve13({
100682
100830
  success: !signal?.aborted && code === 0,
100683
100831
  exitCode: code,
100684
100832
  stderr,
@@ -100688,7 +100836,7 @@ async function runFfmpeg(args, opts) {
100688
100836
  ffmpeg.on("error", (err) => {
100689
100837
  clearTimeout(timer2);
100690
100838
  if (signal) signal.removeEventListener("abort", onAbort);
100691
- resolve12({
100839
+ resolve13({
100692
100840
  success: false,
100693
100841
  exitCode: null,
100694
100842
  stderr: err.message,
@@ -100784,7 +100932,7 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
100784
100932
  }
100785
100933
  async function encodeFramesFromDir(framesDir, framePattern, outputPath, options, signal, config2) {
100786
100934
  const startTime = Date.now();
100787
- const outputDir = dirname4(outputPath);
100935
+ const outputDir = dirname5(outputPath);
100788
100936
  if (!existsSync5(outputDir)) mkdirSync2(outputDir, { recursive: true });
100789
100937
  const files = readdirSync3(framesDir).filter((f) => f.match(/\.(jpg|jpeg|png)$/i));
100790
100938
  const frameCount = files.length;
@@ -100802,10 +100950,10 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
100802
100950
  if (options.useGpu) {
100803
100951
  gpuEncoder = await getCachedGpuEncoder();
100804
100952
  }
100805
- const inputPath = join5(framesDir, framePattern);
100953
+ const inputPath = join6(framesDir, framePattern);
100806
100954
  const inputArgs = ["-framerate", String(options.fps), "-i", inputPath];
100807
100955
  const args = buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder);
100808
- return new Promise((resolve12) => {
100956
+ return new Promise((resolve13) => {
100809
100957
  const ffmpeg = spawn5("ffmpeg", args);
100810
100958
  let stderr = "";
100811
100959
  const onAbort = () => {
@@ -100830,7 +100978,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
100830
100978
  if (signal) signal.removeEventListener("abort", onAbort);
100831
100979
  const durationMs = Date.now() - startTime;
100832
100980
  if (signal?.aborted) {
100833
- resolve12({
100981
+ resolve13({
100834
100982
  success: false,
100835
100983
  outputPath,
100836
100984
  durationMs,
@@ -100841,7 +100989,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
100841
100989
  return;
100842
100990
  }
100843
100991
  if (code !== 0) {
100844
- resolve12({
100992
+ resolve13({
100845
100993
  success: false,
100846
100994
  outputPath,
100847
100995
  durationMs,
@@ -100852,12 +101000,12 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
100852
101000
  return;
100853
101001
  }
100854
101002
  const fileSize = existsSync5(outputPath) ? statSync3(outputPath).size : 0;
100855
- resolve12({ success: true, outputPath, durationMs, framesEncoded: frameCount, fileSize });
101003
+ resolve13({ success: true, outputPath, durationMs, framesEncoded: frameCount, fileSize });
100856
101004
  });
100857
101005
  ffmpeg.on("error", (err) => {
100858
101006
  clearTimeout(timer2);
100859
101007
  if (signal) signal.removeEventListener("abort", onAbort);
100860
- resolve12({
101008
+ resolve13({
100861
101009
  success: false,
100862
101010
  outputPath,
100863
101011
  durationMs: Date.now() - startTime,
@@ -100883,7 +101031,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
100883
101031
  }
100884
101032
  const chunkSize = Math.max(30, Math.floor(chunkSizeFrames));
100885
101033
  const chunkCount = Math.ceil(files.length / chunkSize);
100886
- const chunkDir = join5(dirname4(outputPath), "chunk-encode");
101034
+ const chunkDir = join6(dirname5(outputPath), "chunk-encode");
100887
101035
  if (!existsSync5(chunkDir)) mkdirSync2(chunkDir, { recursive: true });
100888
101036
  const chunkPaths = [];
100889
101037
  for (let i = 0; i < chunkCount; i++) {
@@ -100900,8 +101048,8 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
100900
101048
  const startNumber = i * chunkSize;
100901
101049
  const framesInChunk = Math.min(chunkSize, files.length - startNumber);
100902
101050
  const ext = outputPath.endsWith(".webm") ? ".webm" : ".mp4";
100903
- const chunkPath = join5(chunkDir, `chunk_${String(i).padStart(4, "0")}${ext}`);
100904
- const inputPath = join5(framesDir, framePattern);
101051
+ const chunkPath = join6(chunkDir, `chunk_${String(i).padStart(4, "0")}${ext}`);
101052
+ const inputPath = join6(framesDir, framePattern);
100905
101053
  const inputArgs = [
100906
101054
  "-framerate",
100907
101055
  String(options.fps),
@@ -100915,18 +101063,18 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
100915
101063
  let gpuEncoder = null;
100916
101064
  if (options.useGpu) gpuEncoder = await getCachedGpuEncoder();
100917
101065
  const args = buildEncoderArgs(options, inputArgs, chunkPath, gpuEncoder);
100918
- const chunkResult = await new Promise((resolve12) => {
101066
+ const chunkResult = await new Promise((resolve13) => {
100919
101067
  const ffmpeg = spawn5("ffmpeg", args);
100920
101068
  let stderr = "";
100921
101069
  ffmpeg.stderr.on("data", (d) => {
100922
101070
  stderr += d.toString();
100923
101071
  });
100924
101072
  ffmpeg.on("close", (code) => {
100925
- if (code === 0) resolve12({ success: true });
100926
- else resolve12({ success: false, error: `Chunk ${i} encode failed: ${stderr.slice(-400)}` });
101073
+ if (code === 0) resolve13({ success: true });
101074
+ else resolve13({ success: false, error: `Chunk ${i} encode failed: ${stderr.slice(-400)}` });
100927
101075
  });
100928
101076
  ffmpeg.on("error", (err) => {
100929
- resolve12({ success: false, error: `Chunk ${i} encode error: ${err.message}` });
101077
+ resolve13({ success: false, error: `Chunk ${i} encode error: ${err.message}` });
100930
101078
  });
100931
101079
  });
100932
101080
  if (!chunkResult.success) {
@@ -100941,7 +101089,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
100941
101089
  }
100942
101090
  chunkPaths.push(chunkPath);
100943
101091
  }
100944
- const concatListPath = join5(chunkDir, "concat-list.txt");
101092
+ const concatListPath = join6(chunkDir, "concat-list.txt");
100945
101093
  const concatInput = chunkPaths.map((path12) => `file '${path12.replace(/'/g, "'\\''")}'`).join("\n");
100946
101094
  writeFileSync2(concatListPath, concatInput, "utf-8");
100947
101095
  const concatArgs = [
@@ -100956,18 +101104,18 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
100956
101104
  "-y",
100957
101105
  outputPath
100958
101106
  ];
100959
- const concatResult = await new Promise((resolve12) => {
101107
+ const concatResult = await new Promise((resolve13) => {
100960
101108
  const ffmpeg = spawn5("ffmpeg", concatArgs);
100961
101109
  let stderr = "";
100962
101110
  ffmpeg.stderr.on("data", (d) => {
100963
101111
  stderr += d.toString();
100964
101112
  });
100965
101113
  ffmpeg.on("close", (code) => {
100966
- if (code === 0) resolve12({ success: true });
100967
- else resolve12({ success: false, error: `Chunk concat failed: ${stderr.slice(-400)}` });
101114
+ if (code === 0) resolve13({ success: true });
101115
+ else resolve13({ success: false, error: `Chunk concat failed: ${stderr.slice(-400)}` });
100968
101116
  });
100969
101117
  ffmpeg.on("error", (err) => {
100970
- resolve12({ success: false, error: `Chunk concat error: ${err.message}` });
101118
+ resolve13({ success: false, error: `Chunk concat error: ${err.message}` });
100971
101119
  });
100972
101120
  });
100973
101121
  if (!concatResult.success) {
@@ -100990,7 +101138,7 @@ async function encodeFramesChunkedConcat(framesDir, framePattern, outputPath, op
100990
101138
  };
100991
101139
  }
100992
101140
  async function muxVideoWithAudio(videoPath, audioPath, outputPath, signal, config2) {
100993
- const outputDir = dirname4(outputPath);
101141
+ const outputDir = dirname5(outputPath);
100994
101142
  if (!existsSync5(outputDir)) mkdirSync2(outputDir, { recursive: true });
100995
101143
  const isWebm = outputPath.endsWith(".webm");
100996
101144
  const args = ["-i", videoPath, "-i", audioPath, "-c:v", "copy"];
@@ -101044,7 +101192,7 @@ async function applyFaststart(inputPath, outputPath, signal, config2) {
101044
101192
  // ../engine/src/services/streamingEncoder.ts
101045
101193
  import { spawn as spawn6 } from "child_process";
101046
101194
  import { existsSync as existsSync6, mkdirSync as mkdirSync3, statSync as statSync4 } from "fs";
101047
- import { dirname as dirname5 } from "path";
101195
+ import { dirname as dirname6 } from "path";
101048
101196
  function createFrameReorderBuffer(startFrame, endFrame) {
101049
101197
  let nextFrame = startFrame;
101050
101198
  let waiters = [];
@@ -101057,16 +101205,16 @@ function createFrameReorderBuffer(startFrame, endFrame) {
101057
101205
  }
101058
101206
  };
101059
101207
  return {
101060
- waitForFrame: (frame) => new Promise((resolve12) => {
101061
- waiters.push({ frame, resolve: resolve12 });
101208
+ waitForFrame: (frame) => new Promise((resolve13) => {
101209
+ waiters.push({ frame, resolve: resolve13 });
101062
101210
  resolveWaiters();
101063
101211
  }),
101064
101212
  advanceTo: (frame) => {
101065
101213
  nextFrame = frame;
101066
101214
  resolveWaiters();
101067
101215
  },
101068
- waitForAllDone: () => new Promise((resolve12) => {
101069
- waiters.push({ frame: endFrame, resolve: resolve12 });
101216
+ waitForAllDone: () => new Promise((resolve13) => {
101217
+ waiters.push({ frame: endFrame, resolve: resolve13 });
101070
101218
  resolveWaiters();
101071
101219
  })
101072
101220
  };
@@ -101151,7 +101299,7 @@ function buildStreamingArgs(options, outputPath, gpuEncoder = null) {
101151
101299
  return args;
101152
101300
  }
101153
101301
  async function spawnStreamingEncoder(outputPath, options, signal, config2) {
101154
- const outputDir = dirname5(outputPath);
101302
+ const outputDir = dirname6(outputPath);
101155
101303
  if (!existsSync6(outputDir)) mkdirSync3(outputDir, { recursive: true });
101156
101304
  let gpuEncoder = null;
101157
101305
  if (options.useGpu) {
@@ -101166,7 +101314,7 @@ async function spawnStreamingEncoder(outputPath, options, signal, config2) {
101166
101314
  let stderr = "";
101167
101315
  let exitCode = null;
101168
101316
  let exitPromiseResolve = null;
101169
- const exitPromise = new Promise((resolve12) => exitPromiseResolve = resolve12);
101317
+ const exitPromise = new Promise((resolve13) => exitPromiseResolve = resolve13);
101170
101318
  ffmpeg.stderr?.on("data", (data) => {
101171
101319
  stderr += data.toString();
101172
101320
  });
@@ -101210,8 +101358,8 @@ Process error: ${err.message}`;
101210
101358
  clearTimeout(timer2);
101211
101359
  if (signal) signal.removeEventListener("abort", onAbort);
101212
101360
  if (ffmpeg.stdin && !ffmpeg.stdin.destroyed) {
101213
- await new Promise((resolve12) => {
101214
- ffmpeg.stdin.end(() => resolve12());
101361
+ await new Promise((resolve13) => {
101362
+ ffmpeg.stdin.end(() => resolve13());
101215
101363
  });
101216
101364
  }
101217
101365
  await exitPromise;
@@ -101243,12 +101391,12 @@ Process error: ${err.message}`;
101243
101391
  // ../engine/src/services/videoFrameExtractor.ts
101244
101392
  import { spawn as spawn8 } from "child_process";
101245
101393
  import { existsSync as existsSync8, mkdirSync as mkdirSync5, readdirSync as readdirSync4, rmSync } from "fs";
101246
- import { join as join7 } from "path";
101394
+ import { join as join8 } from "path";
101247
101395
 
101248
101396
  // ../engine/src/utils/ffprobe.ts
101249
101397
  import { spawn as spawn7 } from "child_process";
101250
101398
  function runFfprobe(args) {
101251
- return new Promise((resolve12, reject) => {
101399
+ return new Promise((resolve13, reject) => {
101252
101400
  const proc = spawn7("ffprobe", args);
101253
101401
  let stdout = "";
101254
101402
  let stderr = "";
@@ -101262,7 +101410,7 @@ function runFfprobe(args) {
101262
101410
  if (code !== 0) {
101263
101411
  reject(new Error(`[FFmpeg] ffprobe exited with code ${code}: ${stderr}`));
101264
101412
  } else {
101265
- resolve12(stdout);
101413
+ resolve13(stdout);
101266
101414
  }
101267
101415
  });
101268
101416
  proc.on("error", (err) => {
@@ -101421,7 +101569,7 @@ async function analyzeKeyframeIntervalsUncached(filePath) {
101421
101569
  // ../engine/src/utils/urlDownloader.ts
101422
101570
  import { createWriteStream as createWriteStream2, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
101423
101571
  import { createHash } from "crypto";
101424
- import { join as join6, extname as extname2 } from "path";
101572
+ import { join as join7, extname as extname2 } from "path";
101425
101573
  import { Readable } from "stream";
101426
101574
  import { finished } from "stream/promises";
101427
101575
  var downloadPathCache = /* @__PURE__ */ new Map();
@@ -101445,7 +101593,7 @@ async function downloadToTemp(url, destDir, timeoutMs = 3e5) {
101445
101593
  mkdirSync4(destDir, { recursive: true });
101446
101594
  }
101447
101595
  const filename = getFilenameFromUrl(url);
101448
- const localPath = join6(destDir, filename);
101596
+ const localPath = join7(destDir, filename);
101449
101597
  if (existsSync7(localPath)) {
101450
101598
  downloadPathCache.set(url, localPath);
101451
101599
  return localPath;
@@ -101529,11 +101677,11 @@ function parseVideoElements(html) {
101529
101677
  async function extractVideoFramesRange(videoPath, videoId, startTime, duration, options, signal, config2) {
101530
101678
  const ffmpegProcessTimeout = config2?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
101531
101679
  const { fps, outputDir, quality = 95, format: format3 = "jpg" } = options;
101532
- const videoOutputDir = join7(outputDir, videoId);
101680
+ const videoOutputDir = join8(outputDir, videoId);
101533
101681
  if (!existsSync8(videoOutputDir)) mkdirSync5(videoOutputDir, { recursive: true });
101534
101682
  const metadata = await extractVideoMetadata(videoPath);
101535
101683
  const framePattern = `frame_%05d.${format3}`;
101536
- const outputPattern = join7(videoOutputDir, framePattern);
101684
+ const outputPattern = join8(videoOutputDir, framePattern);
101537
101685
  const args = [
101538
101686
  "-ss",
101539
101687
  String(startTime),
@@ -101548,7 +101696,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
101548
101696
  ];
101549
101697
  if (format3 === "png") args.push("-compression_level", "6");
101550
101698
  args.push("-y", outputPattern);
101551
- return new Promise((resolve12, reject) => {
101699
+ return new Promise((resolve13, reject) => {
101552
101700
  const ffmpeg = spawn8("ffmpeg", args);
101553
101701
  let stderr = "";
101554
101702
  const onAbort = () => {
@@ -101581,9 +101729,9 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
101581
101729
  const framePaths = /* @__PURE__ */ new Map();
101582
101730
  const files = readdirSync4(videoOutputDir).filter((f) => f.startsWith("frame_") && f.endsWith(`.${format3}`)).sort();
101583
101731
  files.forEach((file, index) => {
101584
- framePaths.set(index, join7(videoOutputDir, file));
101732
+ framePaths.set(index, join8(videoOutputDir, file));
101585
101733
  });
101586
- resolve12({
101734
+ resolve13({
101587
101735
  videoId,
101588
101736
  srcPath: videoPath,
101589
101737
  outputDir: videoOutputDir,
@@ -101618,10 +101766,10 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2)
101618
101766
  try {
101619
101767
  let videoPath = video.src;
101620
101768
  if (!videoPath.startsWith("/") && !isHttpUrl(videoPath)) {
101621
- videoPath = join7(baseDir, videoPath);
101769
+ videoPath = join8(baseDir, videoPath);
101622
101770
  }
101623
101771
  if (isHttpUrl(videoPath)) {
101624
- const downloadDir = join7(options.outputDir, "_downloads");
101772
+ const downloadDir = join8(options.outputDir, "_downloads");
101625
101773
  mkdirSync5(downloadDir, { recursive: true });
101626
101774
  videoPath = await downloadToTemp(videoPath, downloadDir);
101627
101775
  }
@@ -101865,7 +102013,7 @@ function createVideoFrameInjector(frameLookup, config2) {
101865
102013
 
101866
102014
  // ../engine/src/services/audioMixer.ts
101867
102015
  import { existsSync as existsSync9, mkdirSync as mkdirSync6, rmSync as rmSync2 } from "fs";
101868
- import { join as join8, dirname as dirname6 } from "path";
102016
+ import { join as join9, dirname as dirname7 } from "path";
101869
102017
  function parseAudioElements(html) {
101870
102018
  const elements = [];
101871
102019
  const { document: document2 } = parseHTML(html);
@@ -101915,7 +102063,7 @@ function parseAudioElements(html) {
101915
102063
  }
101916
102064
  async function extractAudioFromVideo(videoPath, outputPath, options, signal, config2) {
101917
102065
  const ffmpegProcessTimeout = config2?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
101918
- const outputDir = dirname6(outputPath);
102066
+ const outputDir = dirname7(outputPath);
101919
102067
  if (!existsSync9(outputDir)) mkdirSync6(outputDir, { recursive: true });
101920
102068
  const args = ["-i", videoPath];
101921
102069
  if (options?.startTime !== void 0) args.push("-ss", String(options.startTime));
@@ -101942,7 +102090,7 @@ async function extractAudioFromVideo(videoPath, outputPath, options, signal, con
101942
102090
  }
101943
102091
  async function prepareAudioTrack(srcPath, outputPath, mediaStart, duration, signal, config2) {
101944
102092
  const ffmpegProcessTimeout = config2?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
101945
- const outputDir = dirname6(outputPath);
102093
+ const outputDir = dirname7(outputPath);
101946
102094
  if (!existsSync9(outputDir)) mkdirSync6(outputDir, { recursive: true });
101947
102095
  const args = [
101948
102096
  "-ss",
@@ -101978,7 +102126,7 @@ async function prepareAudioTrack(srcPath, outputPath, mediaStart, duration, sign
101978
102126
  }
101979
102127
  async function generateSilence(outputPath, duration, signal, config2) {
101980
102128
  const ffmpegProcessTimeout = config2?.ffmpegProcessTimeout ?? DEFAULT_CONFIG.ffmpegProcessTimeout;
101981
- const outputDir = dirname6(outputPath);
102129
+ const outputDir = dirname7(outputPath);
101982
102130
  if (!existsSync9(outputDir)) mkdirSync6(outputDir, { recursive: true });
101983
102131
  const args = [
101984
102132
  "-f",
@@ -102021,7 +102169,7 @@ async function mixAudioTracks(tracks, outputPath, totalDuration, signal, config2
102021
102169
  error: result2.error
102022
102170
  };
102023
102171
  }
102024
- const outputDir = dirname6(outputPath);
102172
+ const outputDir = dirname7(outputPath);
102025
102173
  if (!existsSync9(outputDir)) mkdirSync6(outputDir, { recursive: true });
102026
102174
  const inputs = [];
102027
102175
  const filterParts = [];
@@ -102093,7 +102241,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
102093
102241
  try {
102094
102242
  let srcPath = element.src;
102095
102243
  if (!srcPath.startsWith("/") && !isHttpUrl(srcPath)) {
102096
- srcPath = join8(baseDir, srcPath);
102244
+ srcPath = join9(baseDir, srcPath);
102097
102245
  }
102098
102246
  if (isHttpUrl(srcPath)) {
102099
102247
  try {
@@ -102116,7 +102264,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
102116
102264
  }
102117
102265
  let audioSrcPath = srcPath;
102118
102266
  if (element.type === "video") {
102119
- const extractedPath = join8(workDir, `${element.id}-extracted.wav`);
102267
+ const extractedPath = join9(workDir, `${element.id}-extracted.wav`);
102120
102268
  const extractResult = await extractAudioFromVideo(
102121
102269
  srcPath,
102122
102270
  extractedPath,
@@ -102133,7 +102281,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
102133
102281
  }
102134
102282
  audioSrcPath = extractedPath;
102135
102283
  } else {
102136
- const trimmedPath = join8(workDir, `${element.id}-trimmed.wav`);
102284
+ const trimmedPath = join9(workDir, `${element.id}-trimmed.wav`);
102137
102285
  const prepResult = await prepareAudioTrack(
102138
102286
  srcPath,
102139
102287
  trimmedPath,
@@ -102178,7 +102326,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
102178
102326
  import { cpus, freemem, totalmem } from "os";
102179
102327
  import { existsSync as existsSync10, mkdirSync as mkdirSync7, readdirSync as readdirSync5 } from "fs";
102180
102328
  import { copyFile, rename as rename2 } from "fs/promises";
102181
- import { join as join9 } from "path";
102329
+ import { join as join10 } from "path";
102182
102330
  var MEMORY_PER_WORKER_MB = 256;
102183
102331
  var MIN_WORKERS = 1;
102184
102332
  var ABSOLUTE_MAX_WORKERS = 10;
@@ -102226,7 +102374,7 @@ function distributeFrames(totalFrames, workerCount, workDir) {
102226
102374
  workerId: i,
102227
102375
  startFrame,
102228
102376
  endFrame,
102229
- outputDir: join9(workDir, `worker-${i}`)
102377
+ outputDir: join10(workDir, `worker-${i}`)
102230
102378
  });
102231
102379
  }
102232
102380
  return tasks;
@@ -102333,8 +102481,8 @@ async function mergeWorkerFrames(workDir, tasks, outputDir) {
102333
102481
  }
102334
102482
  const files = readdirSync5(task.outputDir).filter((f) => f.startsWith("frame_") && (f.endsWith(".jpg") || f.endsWith(".png"))).sort();
102335
102483
  const copyTasks = files.map(async (file) => {
102336
- const sourcePath = join9(task.outputDir, file);
102337
- const targetPath = join9(outputDir, file);
102484
+ const sourcePath = join10(task.outputDir, file);
102485
+ const targetPath = join10(outputDir, file);
102338
102486
  try {
102339
102487
  await rename2(sourcePath, targetPath);
102340
102488
  } catch {
@@ -104828,7 +104976,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
104828
104976
  });
104829
104977
  if (!chunk) {
104830
104978
  if (i === 1) {
104831
- await new Promise((resolve12) => setTimeout(resolve12));
104979
+ await new Promise((resolve13) => setTimeout(resolve13));
104832
104980
  maxReadCount = 3;
104833
104981
  continue;
104834
104982
  }
@@ -104972,33 +105120,33 @@ var serve = (options, listeningListener) => {
104972
105120
  };
104973
105121
 
104974
105122
  // src/services/renderOrchestrator.ts
104975
- import { join as join12, dirname as dirname9, resolve as resolve8 } from "path";
105123
+ import { join as join13, dirname as dirname10, resolve as resolve9 } from "path";
104976
105124
  import { randomUUID } from "crypto";
104977
105125
  import { freemem as freemem2 } from "os";
104978
105126
  import { fileURLToPath as fileURLToPath3 } from "url";
104979
105127
 
104980
105128
  // src/services/fileServer.ts
104981
105129
  import { readFileSync as readFileSync6, existsSync as existsSync12, statSync as statSync5 } from "node:fs";
104982
- import { join as join10, extname as extname3 } from "node:path";
105130
+ import { join as join11, extname as extname3 } from "node:path";
104983
105131
 
104984
105132
  // src/services/hyperframeRuntimeLoader.ts
104985
105133
  import { createHash as createHash2 } from "node:crypto";
104986
105134
  import { existsSync as existsSync11, readFileSync as readFileSync5 } from "node:fs";
104987
- import { dirname as dirname7, resolve as resolve6 } from "node:path";
105135
+ import { dirname as dirname8, resolve as resolve7 } from "node:path";
104988
105136
  import { fileURLToPath as fileURLToPath2 } from "node:url";
104989
- var PRODUCER_DIR = dirname7(fileURLToPath2(import.meta.url));
104990
- var SIBLING_MANIFEST_PATH = resolve6(PRODUCER_DIR, "hyperframe.manifest.json");
104991
- var MODULE_RELATIVE_MANIFEST_PATH = resolve6(
105137
+ var PRODUCER_DIR = dirname8(fileURLToPath2(import.meta.url));
105138
+ var SIBLING_MANIFEST_PATH = resolve7(PRODUCER_DIR, "hyperframe.manifest.json");
105139
+ var MODULE_RELATIVE_MANIFEST_PATH = resolve7(
104992
105140
  PRODUCER_DIR,
104993
105141
  "../../../core/dist/hyperframe.manifest.json"
104994
105142
  );
104995
105143
  var CWD_RELATIVE_MANIFEST_PATHS = [
104996
105144
  // When bundled to a single file (dist/public-server.js), the manifest
104997
105145
  // is copied as a sibling by build.mjs
104998
- resolve6(PRODUCER_DIR, "hyperframe.manifest.json"),
104999
- resolve6(process.cwd(), "packages/core/dist/hyperframe.manifest.json"),
105000
- resolve6(process.cwd(), "../core/dist/hyperframe.manifest.json"),
105001
- resolve6(process.cwd(), "core/dist/hyperframe.manifest.json")
105146
+ resolve7(PRODUCER_DIR, "hyperframe.manifest.json"),
105147
+ resolve7(process.cwd(), "packages/core/dist/hyperframe.manifest.json"),
105148
+ resolve7(process.cwd(), "../core/dist/hyperframe.manifest.json"),
105149
+ resolve7(process.cwd(), "core/dist/hyperframe.manifest.json")
105002
105150
  ];
105003
105151
  function resolveHyperframeManifestPath() {
105004
105152
  if (process.env.PRODUCER_HYPERFRAME_MANIFEST_PATH) {
@@ -105034,7 +105182,7 @@ function resolveVerifiedHyperframeRuntime() {
105034
105182
  `[HyperframeRuntimeLoader] Invalid manifest at ${manifestPath}; missing iife artifact or sha256.`
105035
105183
  );
105036
105184
  }
105037
- const runtimePath = resolve6(dirname7(manifestPath), runtimeFileName);
105185
+ const runtimePath = resolve7(dirname8(manifestPath), runtimeFileName);
105038
105186
  if (!existsSync11(runtimePath)) {
105039
105187
  throw new Error(`[HyperframeRuntimeLoader] Missing runtime artifact at ${runtimePath}.`);
105040
105188
  }
@@ -105285,11 +105433,11 @@ function createFileServer2(options) {
105285
105433
  let requestPath = c.req.path;
105286
105434
  if (requestPath === "/") requestPath = "/index.html";
105287
105435
  const relativePath = requestPath.replace(/^\//, "");
105288
- const compiledPath = compiledDir ? join10(compiledDir, relativePath) : null;
105436
+ const compiledPath = compiledDir ? join11(compiledDir, relativePath) : null;
105289
105437
  const hasCompiledFile = Boolean(
105290
105438
  compiledPath && existsSync12(compiledPath) && statSync5(compiledPath).isFile()
105291
105439
  );
105292
- const filePath = hasCompiledFile ? compiledPath : join10(projectDir, relativePath);
105440
+ const filePath = hasCompiledFile ? compiledPath : join11(projectDir, relativePath);
105293
105441
  if (!existsSync12(filePath) || !statSync5(filePath).isFile()) {
105294
105442
  return c.text("Not found", 404);
105295
105443
  }
@@ -105307,22 +105455,29 @@ function createFileServer2(options) {
105307
105455
  headers: { "Content-Type": contentType }
105308
105456
  });
105309
105457
  });
105310
- return new Promise((resolve12) => {
105458
+ return new Promise((resolve13) => {
105459
+ const connections = /* @__PURE__ */ new Set();
105311
105460
  const server = serve({ fetch: app.fetch, port }, (info) => {
105312
- const actualPort = info.port;
105313
- const url = `http://localhost:${actualPort}`;
105314
- resolve12({
105315
- url,
105316
- port: actualPort,
105317
- close: () => server.close()
105461
+ resolve13({
105462
+ url: `http://localhost:${info.port}`,
105463
+ port: info.port,
105464
+ close: () => {
105465
+ for (const socket of connections) socket.destroy();
105466
+ connections.clear();
105467
+ server.close();
105468
+ }
105318
105469
  });
105319
105470
  });
105471
+ server.on("connection", (socket) => {
105472
+ connections.add(socket);
105473
+ socket.on("close", () => connections.delete(socket));
105474
+ });
105320
105475
  });
105321
105476
  }
105322
105477
 
105323
105478
  // src/services/htmlCompiler.ts
105324
105479
  import { readFileSync as readFileSync7, existsSync as existsSync13, mkdirSync as mkdirSync8 } from "fs";
105325
- import { join as join11, dirname as dirname8, resolve as resolve7 } from "path";
105480
+ import { join as join12, dirname as dirname9, resolve as resolve8 } from "path";
105326
105481
 
105327
105482
  // src/services/fontData.generated.ts
105328
105483
  var EMBEDDED_FONT_DATA = /* @__PURE__ */ new Map([
@@ -105575,7 +105730,7 @@ async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagNa
105575
105730
  return { duration: 0, resolvedPath: src };
105576
105731
  }
105577
105732
  } else if (!filePath.startsWith("/")) {
105578
- filePath = join11(baseDir, filePath);
105733
+ filePath = join12(baseDir, filePath);
105579
105734
  }
105580
105735
  if (!existsSync13(filePath)) {
105581
105736
  return { duration: 0, resolvedPath: filePath };
@@ -105641,7 +105796,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
105641
105796
  const elEnd = elEndRaw ? parseFloat(elEndRaw) : Infinity;
105642
105797
  const absoluteStart = parentOffset + elStart;
105643
105798
  const absoluteEnd = Math.min(parentEnd, isFinite(elEnd) ? parentOffset + elEnd : Infinity);
105644
- const filePath = resolve7(projectDir, srcPath);
105799
+ const filePath = resolve8(projectDir, srcPath);
105645
105800
  if (visited.has(filePath)) {
105646
105801
  continue;
105647
105802
  }
@@ -105657,7 +105812,7 @@ async function parseSubCompositions(html, projectDir, downloadDir, parentOffset
105657
105812
  workItems.map(async (item) => {
105658
105813
  const { html: compiledSub } = await compileHtmlFile(
105659
105814
  item.rawSubHtml,
105660
- dirname8(item.filePath),
105815
+ dirname9(item.filePath),
105661
105816
  downloadDir
105662
105817
  );
105663
105818
  const nested = await parseSubCompositions(
@@ -105836,12 +105991,13 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
105836
105991
  if (!hosts.length) return html;
105837
105992
  const collectedStyles = [];
105838
105993
  const collectedScripts = [];
105994
+ const collectedExternalScriptSrcs = [];
105839
105995
  for (const host of hosts) {
105840
105996
  const srcPath = host.getAttribute("data-composition-src");
105841
105997
  if (!srcPath) continue;
105842
105998
  let compHtml = subCompositions.get(srcPath) || null;
105843
105999
  if (!compHtml) {
105844
- const filePath = resolve7(projectDir, srcPath);
106000
+ const filePath = resolve8(projectDir, srcPath);
105845
106001
  if (existsSync13(filePath)) {
105846
106002
  compHtml = readFileSync7(filePath, "utf-8");
105847
106003
  }
@@ -105869,7 +106025,13 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
105869
106025
  }
105870
106026
  for (const scriptEl of contentDoc.querySelectorAll("script")) {
105871
106027
  const src = (scriptEl.getAttribute("src") || "").trim();
105872
- if (src) continue;
106028
+ if (src) {
106029
+ if (!collectedExternalScriptSrcs.includes(src)) {
106030
+ collectedExternalScriptSrcs.push(src);
106031
+ }
106032
+ scriptEl.remove();
106033
+ continue;
106034
+ }
105873
106035
  const content = (scriptEl.textContent || "").trim();
105874
106036
  if (content) {
105875
106037
  const scriptMountCompId = compId || inferredCompId || "";
@@ -105896,6 +106058,13 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
105896
106058
  }
105897
106059
  scriptEl.remove();
105898
106060
  }
106061
+ const rewriteTarget = innerRoot || contentDoc;
106062
+ rewriteAssetPaths(
106063
+ rewriteTarget.querySelectorAll("[src], [href]"),
106064
+ srcPath,
106065
+ (el, attr) => (el.getAttribute(attr) || "").trim(),
106066
+ (el, attr, val) => el.setAttribute(attr, val)
106067
+ );
105899
106068
  if (innerRoot) {
105900
106069
  const innerW = innerRoot.getAttribute("data-width");
105901
106070
  const innerH = innerRoot.getAttribute("data-height");
@@ -105939,6 +106108,21 @@ function inlineSubCompositions(html, subCompositions, projectDir) {
105939
106108
  styleEl.textContent = collectedStyles.join("\n\n");
105940
106109
  head.appendChild(styleEl);
105941
106110
  }
106111
+ if (collectedExternalScriptSrcs.length && body) {
106112
+ const existingScriptSrcs = new Set(
106113
+ Array.from(document2.querySelectorAll("script[src]")).map(
106114
+ (el) => (el.getAttribute("src") || "").trim()
106115
+ )
106116
+ );
106117
+ for (const src of collectedExternalScriptSrcs) {
106118
+ if (!existingScriptSrcs.has(src)) {
106119
+ const scriptEl = document2.createElement("script");
106120
+ scriptEl.setAttribute("src", src);
106121
+ body.appendChild(scriptEl);
106122
+ existingScriptSrcs.add(src);
106123
+ }
106124
+ }
106125
+ }
105942
106126
  if (collectedScripts.length && body) {
105943
106127
  const scriptEl = document2.createElement("script");
105944
106128
  scriptEl.textContent = collectedScripts.join("\n;\n");
@@ -105989,7 +106173,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
105989
106173
  const audios = dedupeElementsById([...subAudios, ...mainAudios]);
105990
106174
  for (const video of videos) {
105991
106175
  if (isHttpUrl(video.src)) continue;
105992
- const videoPath = resolve7(projectDir, video.src);
106176
+ const videoPath = resolve8(projectDir, video.src);
105993
106177
  const reencode = `ffmpeg -i "${video.src}" -c:v libx264 -r 30 -g 30 -keyint_min 30 -movflags +faststart -c:a copy output.mp4`;
105994
106178
  Promise.all([analyzeKeyframeIntervals(videoPath), extractVideoMetadata(videoPath)]).then(([analysis, metadata]) => {
105995
106179
  if (analysis.isProblematic) {
@@ -106231,12 +106415,12 @@ function installDebugLogger(logPath, log = defaultLogger) {
106231
106415
  };
106232
106416
  }
106233
106417
  function writeCompiledArtifacts(compiled, workDir, includeSummary) {
106234
- const compileDir = join12(workDir, "compiled");
106418
+ const compileDir = join13(workDir, "compiled");
106235
106419
  mkdirSync9(compileDir, { recursive: true });
106236
- writeFileSync3(join12(compileDir, "index.html"), compiled.html, "utf-8");
106420
+ writeFileSync3(join13(compileDir, "index.html"), compiled.html, "utf-8");
106237
106421
  for (const [srcPath, html] of compiled.subCompositions) {
106238
- const outPath = join12(compileDir, srcPath);
106239
- mkdirSync9(dirname9(outPath), { recursive: true });
106422
+ const outPath = join13(compileDir, srcPath);
106423
+ mkdirSync9(dirname10(outPath), { recursive: true });
106240
106424
  writeFileSync3(outPath, html, "utf-8");
106241
106425
  }
106242
106426
  if (includeSummary) {
@@ -106260,7 +106444,7 @@ function writeCompiledArtifacts(compiled, workDir, includeSummary) {
106260
106444
  })),
106261
106445
  subCompositions: Array.from(compiled.subCompositions.keys())
106262
106446
  };
106263
- writeFileSync3(join12(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
106447
+ writeFileSync3(join13(compileDir, "summary.json"), JSON.stringify(summary, null, 2), "utf-8");
106264
106448
  }
106265
106449
  }
106266
106450
  function createRenderJob(config2) {
@@ -106303,10 +106487,10 @@ function extractStandaloneEntryFromIndex(indexHtml, entryFile) {
106303
106487
  return document2.toString();
106304
106488
  }
106305
106489
  async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSignal) {
106306
- const moduleDir = dirname9(fileURLToPath3(import.meta.url));
106307
- const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve8(process.env.PRODUCER_RENDERS_DIR, "..") : resolve8(moduleDir, "../..");
106308
- const debugDir = join12(producerRoot, ".debug");
106309
- const workDir = job.config.debug ? join12(debugDir, job.id) : join12(dirname9(outputPath), `work-${job.id}`);
106490
+ const moduleDir = dirname10(fileURLToPath3(import.meta.url));
106491
+ const producerRoot = process.env.PRODUCER_RENDERS_DIR ? resolve9(process.env.PRODUCER_RENDERS_DIR, "..") : resolve9(moduleDir, "../..");
106492
+ const debugDir = join13(producerRoot, ".debug");
106493
+ const workDir = job.config.debug ? join13(debugDir, job.id) : join13(dirname10(outputPath), `work-${job.id}`);
106310
106494
  const pipelineStart = Date.now();
106311
106495
  const log = job.config.logger ?? defaultLogger;
106312
106496
  let fileServer = null;
@@ -106314,7 +106498,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106314
106498
  let lastBrowserConsole = [];
106315
106499
  let restoreLogger = null;
106316
106500
  const perfStages = {};
106317
- const perfOutputPath = join12(workDir, "perf-summary.json");
106501
+ const perfOutputPath = join13(workDir, "perf-summary.json");
106318
106502
  const cfg = { ...job.config.producerConfig ?? resolveConfig() };
106319
106503
  const outputFormat = job.config.format ?? "mp4";
106320
106504
  const isWebm = outputFormat === "webm";
@@ -106334,19 +106518,19 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106334
106518
  assertNotAborted();
106335
106519
  if (!existsSync14(workDir)) mkdirSync9(workDir, { recursive: true });
106336
106520
  if (job.config.debug) {
106337
- const logPath = join12(workDir, "render.log");
106521
+ const logPath = join13(workDir, "render.log");
106338
106522
  restoreLogger = installDebugLogger(logPath, log);
106339
106523
  }
106340
106524
  const entryFile = job.config.entryFile || "index.html";
106341
- let htmlPath = join12(projectDir, entryFile);
106525
+ let htmlPath = join13(projectDir, entryFile);
106342
106526
  if (!existsSync14(htmlPath)) {
106343
106527
  throw new Error(`Entry file not found: ${htmlPath}`);
106344
106528
  }
106345
106529
  assertNotAborted();
106346
106530
  const rawEntry = readFileSync8(htmlPath, "utf-8");
106347
106531
  if (entryFile !== "index.html" && rawEntry.trimStart().startsWith("<template")) {
106348
- const wrapperPath = join12(workDir, "standalone-entry.html");
106349
- const projectIndexPath = join12(projectDir, "index.html");
106532
+ const wrapperPath = join13(workDir, "standalone-entry.html");
106533
+ const projectIndexPath = join13(projectDir, "index.html");
106350
106534
  if (!existsSync14(projectIndexPath)) {
106351
106535
  throw new Error(
106352
106536
  `Template entry file "${entryFile}" requires a project index.html to extract its render shell.`
@@ -106370,7 +106554,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106370
106554
  const stage1Start = Date.now();
106371
106555
  updateJobStatus(job, "preprocessing", "Compiling composition", 5, onProgress);
106372
106556
  const compileStart = Date.now();
106373
- let compiled = await compileForRender(projectDir, htmlPath, join12(workDir, "downloads"));
106557
+ let compiled = await compileForRender(projectDir, htmlPath, join13(workDir, "downloads"));
106374
106558
  assertNotAborted();
106375
106559
  perfStages.compileOnlyMs = Date.now() - compileStart;
106376
106560
  writeCompiledArtifacts(compiled, workDir, Boolean(job.config.debug));
@@ -106399,7 +106583,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106399
106583
  reasons.push(`${compiled.unresolvedCompositions.length} unresolved composition(s)`);
106400
106584
  fileServer = await createFileServer2({
106401
106585
  projectDir,
106402
- compiledDir: join12(workDir, "compiled"),
106586
+ compiledDir: join13(workDir, "compiled"),
106403
106587
  port: 0
106404
106588
  });
106405
106589
  assertNotAborted();
@@ -106412,7 +106596,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106412
106596
  };
106413
106597
  probeSession = await createCaptureSession(
106414
106598
  fileServer.url,
106415
- join12(workDir, "probe"),
106599
+ join13(workDir, "probe"),
106416
106600
  captureOpts,
106417
106601
  null,
106418
106602
  cfg
@@ -106444,7 +106628,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106444
106628
  compiled,
106445
106629
  resolutions,
106446
106630
  projectDir,
106447
- join12(workDir, "downloads")
106631
+ join13(workDir, "downloads")
106448
106632
  );
106449
106633
  assertNotAborted();
106450
106634
  composition.videos = compiled.videos;
@@ -106541,7 +106725,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106541
106725
  const extractionResult = await extractAllVideoFrames(
106542
106726
  composition.videos,
106543
106727
  projectDir,
106544
- { fps: job.config.fps, outputDir: join12(workDir, "video-frames") },
106728
+ { fps: job.config.fps, outputDir: join13(workDir, "video-frames") },
106545
106729
  abortSignal
106546
106730
  );
106547
106731
  assertNotAborted();
@@ -106573,13 +106757,13 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106573
106757
  }
106574
106758
  const stage3Start = Date.now();
106575
106759
  updateJobStatus(job, "preprocessing", "Processing audio tracks", 20, onProgress);
106576
- const audioOutputPath = join12(workDir, "audio.aac");
106760
+ const audioOutputPath = join13(workDir, "audio.aac");
106577
106761
  let hasAudio = false;
106578
106762
  if (composition.audios.length > 0) {
106579
106763
  const audioResult = await processCompositionAudio(
106580
106764
  composition.audios,
106581
106765
  projectDir,
106582
- join12(workDir, "audio-work"),
106766
+ join13(workDir, "audio-work"),
106583
106767
  audioOutputPath,
106584
106768
  job.duration,
106585
106769
  abortSignal
@@ -106595,12 +106779,12 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106595
106779
  if (!fileServer) {
106596
106780
  fileServer = await createFileServer2({
106597
106781
  projectDir,
106598
- compiledDir: join12(workDir, "compiled"),
106782
+ compiledDir: join13(workDir, "compiled"),
106599
106783
  port: 0
106600
106784
  });
106601
106785
  assertNotAborted();
106602
106786
  }
106603
- const framesDir = join12(workDir, "captured-frames");
106787
+ const framesDir = join13(workDir, "captured-frames");
106604
106788
  if (!existsSync14(framesDir)) mkdirSync9(framesDir, { recursive: true });
106605
106789
  const captureOptions = {
106606
106790
  width,
@@ -106611,7 +106795,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106611
106795
  };
106612
106796
  const workerCount = calculateOptimalWorkers(job.totalFrames, job.config.workers, cfg);
106613
106797
  const videoExt = isWebm ? ".webm" : ".mp4";
106614
- const videoOnlyPath = join12(workDir, `video-only${videoExt}`);
106798
+ const videoOnlyPath = join13(workDir, `video-only${videoExt}`);
106615
106799
  const preset = getEncoderPreset(job.config.quality, outputFormat);
106616
106800
  job.framesRendered = 0;
106617
106801
  let streamingEncoder = null;
@@ -106890,7 +107074,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
106890
107074
  }
106891
107075
  if (job.config.debug) {
106892
107076
  if (existsSync14(outputPath)) {
106893
- const debugOutput = join12(workDir, isWebm ? "output.webm" : "output.mp4");
107077
+ const debugOutput = join13(workDir, isWebm ? "output.webm" : "output.mp4");
106894
107078
  copyFileSync2(outputPath, debugOutput);
106895
107079
  }
106896
107080
  } else {
@@ -106993,7 +107177,7 @@ import {
106993
107177
  rmSync as rmSync4,
106994
107178
  createReadStream as createReadStream2
106995
107179
  } from "node:fs";
106996
- import { resolve as resolve11, dirname as dirname10, join as join15 } from "node:path";
107180
+ import { resolve as resolve12, dirname as dirname11, join as join16 } from "node:path";
106997
107181
  import { tmpdir as tmpdir2 } from "node:os";
106998
107182
  import { parseArgs } from "node:util";
106999
107183
  import crypto2 from "node:crypto";
@@ -107149,7 +107333,7 @@ var streamSSE = (c, cb, onError) => {
107149
107333
 
107150
107334
  // src/services/hyperframeLint.ts
107151
107335
  import { existsSync as existsSync15, readFileSync as readFileSync9, statSync as statSync6 } from "node:fs";
107152
- import { resolve as resolve9, join as join13 } from "node:path";
107336
+ import { resolve as resolve10, join as join14 } from "node:path";
107153
107337
  function isStringRecord(value) {
107154
107338
  if (!value || typeof value !== "object" || Array.isArray(value)) {
107155
107339
  return false;
@@ -107176,7 +107360,7 @@ function pickEntryFile(files, preferredEntryFile) {
107176
107360
  return null;
107177
107361
  }
107178
107362
  function readProjectEntryFile(projectDir, preferredEntryFile) {
107179
- const absProjectDir = resolve9(projectDir);
107363
+ const absProjectDir = resolve10(projectDir);
107180
107364
  if (!existsSync15(absProjectDir) || !statSync6(absProjectDir).isDirectory()) {
107181
107365
  return { error: `Project directory not found: ${absProjectDir}` };
107182
107366
  }
@@ -107184,7 +107368,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
107184
107368
  (value) => typeof value === "string" && value.trim().length > 0
107185
107369
  );
107186
107370
  for (const entryFile of entryCandidates) {
107187
- const absoluteEntryPath = resolve9(absProjectDir, entryFile);
107371
+ const absoluteEntryPath = resolve10(absProjectDir, entryFile);
107188
107372
  if (!absoluteEntryPath.startsWith(absProjectDir)) {
107189
107373
  return { error: `Entry file must stay inside project directory: ${entryFile}` };
107190
107374
  }
@@ -107197,7 +107381,7 @@ function readProjectEntryFile(projectDir, preferredEntryFile) {
107197
107381
  }
107198
107382
  }
107199
107383
  return {
107200
- error: `No HTML entry file found in project directory: ${join13(absProjectDir, preferredEntryFile || "index.html")}`
107384
+ error: `No HTML entry file found in project directory: ${join14(absProjectDir, preferredEntryFile || "index.html")}`
107201
107385
  };
107202
107386
  }
107203
107387
  function prepareHyperframeLintBody(body) {
@@ -107238,13 +107422,13 @@ function runHyperframeLint(prepared) {
107238
107422
  }
107239
107423
 
107240
107424
  // src/utils/paths.ts
107241
- import { resolve as resolve10, basename as basename2, join as join14 } from "node:path";
107242
- var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve10(new URL(import.meta.url).pathname, "../../..", "renders");
107425
+ import { resolve as resolve11, basename as basename2, join as join15 } from "node:path";
107426
+ var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve11(new URL(import.meta.url).pathname, "../../..", "renders");
107243
107427
  function resolveRenderPaths(projectDir, outputPath, rendersDir = DEFAULT_RENDERS_DIR) {
107244
- const absoluteProjectDir = resolve10(projectDir);
107428
+ const absoluteProjectDir = resolve11(projectDir);
107245
107429
  const projectName = basename2(absoluteProjectDir);
107246
- const resolvedOutputPath = outputPath ?? join14(rendersDir, `${projectName}.mp4`);
107247
- const absoluteOutputPath = resolve10(resolvedOutputPath);
107430
+ const resolvedOutputPath = outputPath ?? join15(rendersDir, `${projectName}.mp4`);
107431
+ const absoluteOutputPath = resolve11(resolvedOutputPath);
107248
107432
  return { absoluteProjectDir, absoluteOutputPath };
107249
107433
  }
107250
107434
 
@@ -107264,12 +107448,12 @@ async function prepareRenderBody(body) {
107264
107448
  const options = parseRenderOptions(body);
107265
107449
  const projectDir = typeof body.projectDir === "string" ? body.projectDir : void 0;
107266
107450
  if (projectDir) {
107267
- const absProjectDir = resolve11(projectDir);
107451
+ const absProjectDir = resolve12(projectDir);
107268
107452
  if (!existsSync16(absProjectDir) || !statSync7(absProjectDir).isDirectory()) {
107269
107453
  return { error: `Project directory not found: ${absProjectDir}` };
107270
107454
  }
107271
107455
  const entry = options.entryFile || "index.html";
107272
- if (!existsSync16(resolve11(absProjectDir, entry))) {
107456
+ if (!existsSync16(resolve12(absProjectDir, entry))) {
107273
107457
  return { error: `Entry file "${entry}" not found in project directory: ${absProjectDir}` };
107274
107458
  }
107275
107459
  return { prepared: { input: { projectDir: absProjectDir, ...options } } };
@@ -107294,8 +107478,8 @@ async function prepareRenderBody(body) {
107294
107478
  }
107295
107479
  }
107296
107480
  const tempRoot = process.env.PRODUCER_TMP_PROJECT_DIR || tmpdir2();
107297
- const tempProjectDir = mkdtempSync(join15(tempRoot, "producer-project-"));
107298
- writeFileSync4(join15(tempProjectDir, "index.html"), htmlContent, "utf-8");
107481
+ const tempProjectDir = mkdtempSync(join16(tempRoot, "producer-project-"));
107482
+ writeFileSync4(join16(tempProjectDir, "index.html"), htmlContent, "utf-8");
107299
107483
  return {
107300
107484
  prepared: {
107301
107485
  input: {
@@ -107310,7 +107494,7 @@ function resolveOutputPath(projectDir, outputCandidate, rendersDir, log) {
107310
107494
  try {
107311
107495
  return resolveRenderPaths(projectDir, outputCandidate, rendersDir).absoluteOutputPath;
107312
107496
  } catch (error) {
107313
- const fallbackPath = resolve11(rendersDir, `producer-fallback-${Date.now()}.mp4`);
107497
+ const fallbackPath = resolve12(rendersDir, `producer-fallback-${Date.now()}.mp4`);
107314
107498
  log.warn("Failed to resolve output path, using fallback", {
107315
107499
  fallback: fallbackPath,
107316
107500
  error: error instanceof Error ? error.message : String(error)
@@ -107415,7 +107599,7 @@ function createRenderHandlers(options = {}) {
107415
107599
  rendersDir,
107416
107600
  log
107417
107601
  );
107418
- const outputDir = dirname10(absoluteOutputPath);
107602
+ const outputDir = dirname11(absoluteOutputPath);
107419
107603
  if (!existsSync16(outputDir)) mkdirSync10(outputDir, { recursive: true });
107420
107604
  log.info("render started", {
107421
107605
  requestId,
@@ -107524,7 +107708,7 @@ function createRenderHandlers(options = {}) {
107524
107708
  rendersDir,
107525
107709
  log
107526
107710
  );
107527
- const outputDir = dirname10(absoluteOutputPath);
107711
+ const outputDir = dirname11(absoluteOutputPath);
107528
107712
  if (!existsSync16(outputDir)) mkdirSync10(outputDir, { recursive: true });
107529
107713
  log.info("render-stream started", { requestId, projectDir: input2.projectDir });
107530
107714
  const job = createRenderJob({
@@ -107668,7 +107852,7 @@ function startServer(options = {}) {
107668
107852
  process.on("SIGINT", () => shutdown("SIGINT"));
107669
107853
  return server;
107670
107854
  }
107671
- var entryScript = process.argv[1] ? resolve11(process.argv[1]) : "";
107855
+ var entryScript = process.argv[1] ? resolve12(process.argv[1]) : "";
107672
107856
  var isPublicServerEntry = entryScript.endsWith("/public-server.js") || entryScript.endsWith("/src/server.ts");
107673
107857
  if (isPublicServerEntry) {
107674
107858
  const { values } = parseArgs({