@grabbit-labs/dynafetch 0.2.3 → 0.2.4

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.
Binary file
Binary file
Binary file
Binary file
Binary file
package/dist/index.js CHANGED
@@ -325,7 +325,8 @@ async function withDynafetchSession(options, run) {
325
325
  try {
326
326
  return await sessionStore.run({ sessionId: session.sessionId }, run);
327
327
  } finally {
328
- callWorker("closeSession", { sessionId: session.sessionId }).catch(() => {
328
+ const closeTimeoutMs = Math.min(resolveRpcTimeoutMs(options), 5e3);
329
+ await callWorker("closeSession", { sessionId: session.sessionId }, closeTimeoutMs).catch(() => {
329
330
  });
330
331
  transport.release();
331
332
  }
@@ -876,6 +877,7 @@ var Executor = class {
876
877
  this.esbuildModule = null;
877
878
  this.originalGlobalMessageChannel = void 0;
878
879
  this.originalGlobalMessagePort = void 0;
880
+ this.activeTimerHandles = /* @__PURE__ */ new Set();
879
881
  // Simple telemetry counters (useful for debugging).
880
882
  this.telemetry_stubbed = 0;
881
883
  this.telemetry_proxy = 0;
@@ -977,6 +979,23 @@ var Executor = class {
977
979
  }
978
980
  }
979
981
  }
982
+ clearTrackedTimers(window) {
983
+ for (const handle of this.activeTimerHandles) {
984
+ try {
985
+ window.clearTimeout?.(handle);
986
+ } catch {
987
+ }
988
+ try {
989
+ window.clearInterval?.(handle);
990
+ } catch {
991
+ }
992
+ try {
993
+ handle?.unref?.();
994
+ } catch {
995
+ }
996
+ }
997
+ this.activeTimerHandles.clear();
998
+ }
980
999
  applyDefaults(quiescence, moduleWaitMsOverride) {
981
1000
  const hardMaxCap = this.clampMs(Number(process.env.PHANTOM_QUIESCENCE_MAX_CAP_MS ?? 8e3), 500, 6e4);
982
1001
  const minWaitMs = this.clampMs(quiescence?.minWaitMs ?? 75, 0, 1e4);
@@ -1414,14 +1433,66 @@ var Executor = class {
1414
1433
  };
1415
1434
  }
1416
1435
  const g = globalThis;
1417
- if (!window.Headers && g.Headers) window.Headers = g.Headers;
1418
- if (!window.Request && g.Request) window.Request = g.Request;
1419
- if (!window.Response && g.Response) window.Response = g.Response;
1420
- if (!window.AbortController && g.AbortController) window.AbortController = g.AbortController;
1421
- if (!window.AbortSignal && g.AbortSignal) window.AbortSignal = g.AbortSignal;
1436
+ if (g.Headers) window.Headers = g.Headers;
1437
+ if (g.Response) window.Response = g.Response;
1438
+ if (g.AbortController) window.AbortController = g.AbortController;
1439
+ if (g.AbortSignal) window.AbortSignal = g.AbortSignal;
1422
1440
  if (!window.TextEncoder && g.TextEncoder) window.TextEncoder = g.TextEncoder;
1423
1441
  if (!window.TextDecoder && g.TextDecoder) window.TextDecoder = g.TextDecoder;
1424
1442
  if (!window.structuredClone && g.structuredClone) window.structuredClone = g.structuredClone.bind(g);
1443
+ const normalizeUrlForRequest = (value) => {
1444
+ if (typeof value !== "string") return value;
1445
+ try {
1446
+ return new URL(value, window.location.href).toString();
1447
+ } catch {
1448
+ return value;
1449
+ }
1450
+ };
1451
+ const normalizeAbortSignalForRequest = (signal) => {
1452
+ if (!signal || !g.AbortController || !g.AbortSignal) return signal;
1453
+ if (signal instanceof g.AbortSignal) return signal;
1454
+ if (typeof signal.aborted !== "boolean") return void 0;
1455
+ const controller = new g.AbortController();
1456
+ if (signal.aborted) {
1457
+ try {
1458
+ controller.abort(signal.reason);
1459
+ } catch {
1460
+ controller.abort();
1461
+ }
1462
+ return controller.signal;
1463
+ }
1464
+ if (typeof signal.addEventListener === "function") {
1465
+ try {
1466
+ signal.addEventListener("abort", () => {
1467
+ try {
1468
+ controller.abort(signal.reason);
1469
+ } catch {
1470
+ controller.abort();
1471
+ }
1472
+ }, { once: true });
1473
+ } catch {
1474
+ }
1475
+ }
1476
+ return controller.signal;
1477
+ };
1478
+ if (g.Request) {
1479
+ const NativeRequest = g.Request;
1480
+ const RequestShim = class Request extends NativeRequest {
1481
+ constructor(input, init) {
1482
+ const normalizedInput = typeof input === "string" ? normalizeUrlForRequest(input) : input instanceof URL ? normalizeUrlForRequest(input.toString()) : input;
1483
+ const normalizedInit = init && typeof init === "object" ? {
1484
+ ...init,
1485
+ signal: normalizeAbortSignalForRequest(init.signal)
1486
+ } : init;
1487
+ super(normalizedInput, normalizedInit);
1488
+ }
1489
+ };
1490
+ try {
1491
+ Object.setPrototypeOf(RequestShim, NativeRequest);
1492
+ } catch {
1493
+ }
1494
+ window.Request = RequestShim;
1495
+ }
1425
1496
  const makeStorage = () => {
1426
1497
  const store = /* @__PURE__ */ new Map();
1427
1498
  return {
@@ -1620,8 +1691,41 @@ var Executor = class {
1620
1691
  };
1621
1692
  const _setTimeout = window.setTimeout?.bind(window);
1622
1693
  const _setInterval = window.setInterval?.bind(window);
1623
- if (_setTimeout) window.setTimeout = (cb, ms, ...rest) => _setTimeout(wrapCb(cb), ms, ...rest);
1624
- if (_setInterval) window.setInterval = (cb, ms, ...rest) => _setInterval(wrapCb(cb), ms, ...rest);
1694
+ const _clearTimeout = window.clearTimeout?.bind(window);
1695
+ const _clearInterval = window.clearInterval?.bind(window);
1696
+ if (_setTimeout) {
1697
+ window.setTimeout = (cb, ms, ...rest) => {
1698
+ let handle;
1699
+ const wrapped = wrapCb((...args) => {
1700
+ this.activeTimerHandles.delete(handle);
1701
+ return typeof cb === "function" ? cb(...args) : cb;
1702
+ });
1703
+ handle = _setTimeout(wrapped, ms, ...rest);
1704
+ this.activeTimerHandles.add(handle);
1705
+ handle?.unref?.();
1706
+ return handle;
1707
+ };
1708
+ }
1709
+ if (_setInterval) {
1710
+ window.setInterval = (cb, ms, ...rest) => {
1711
+ const handle = _setInterval(wrapCb(cb), ms, ...rest);
1712
+ this.activeTimerHandles.add(handle);
1713
+ handle?.unref?.();
1714
+ return handle;
1715
+ };
1716
+ }
1717
+ if (_clearTimeout) {
1718
+ window.clearTimeout = (handle) => {
1719
+ this.activeTimerHandles.delete(handle);
1720
+ return _clearTimeout(handle);
1721
+ };
1722
+ }
1723
+ if (_clearInterval) {
1724
+ window.clearInterval = (handle) => {
1725
+ this.activeTimerHandles.delete(handle);
1726
+ return _clearInterval(handle);
1727
+ };
1728
+ }
1625
1729
  if (window.queueMicrotask) {
1626
1730
  const _q = window.queueMicrotask.bind(window);
1627
1731
  window.queueMicrotask = (cb) => _q(wrapCb(cb));
@@ -1731,7 +1835,7 @@ var Executor = class {
1731
1835
  try {
1732
1836
  const virtualConsole = new VirtualConsole();
1733
1837
  virtualConsole.on("log", (...args) => log("[JSDOM Log]", ...args));
1734
- virtualConsole.on("error", (...args) => console.error("[JSDOM Error]", ...args));
1838
+ virtualConsole.on("error", (...args) => warn("[JSDOM Error]", ...args));
1735
1839
  virtualConsole.on("warn", (...args) => warn("[JSDOM Warn]", ...args));
1736
1840
  const cookieJar = new CookieJar();
1737
1841
  this.harvestData.cookies.forEach((c) => {
@@ -2139,10 +2243,6 @@ var Executor = class {
2139
2243
  log(`[Executor] Quiescence reached in ${Date.now() - quiescenceStart}ms ${reason}`);
2140
2244
  const renderedHtml = this.serializeDocument(window);
2141
2245
  this.windowClosed = true;
2142
- try {
2143
- window.close();
2144
- } catch {
2145
- }
2146
2246
  const result = {
2147
2247
  logs: this.logs,
2148
2248
  matchedRequests: this.earlyMatches,
@@ -2153,6 +2253,7 @@ var Executor = class {
2153
2253
  };
2154
2254
  const shutdownGraceMs = this.clampMs(Number(process.env.PHANTOM_SHUTDOWN_GRACE_MS ?? 50), 10, 5e3);
2155
2255
  await new Promise((r) => setTimeout(r, shutdownGraceMs));
2256
+ this.clearTrackedTimers(window);
2156
2257
  this.unrefNewMessagePorts(initialActiveHandles);
2157
2258
  return result;
2158
2259
  } finally {
@@ -2259,6 +2360,12 @@ var Executor = class {
2259
2360
  };
2260
2361
  window.__phantom = {
2261
2362
  fetch: async (input, opts = {}) => {
2363
+ if (that.windowClosed) {
2364
+ return new (window.Response || global.Response)("", {
2365
+ status: 200,
2366
+ headers: toSafeResponseHeaders({})
2367
+ });
2368
+ }
2262
2369
  const norm = await normalizeFetchInput(input, opts);
2263
2370
  const start = Date.now();
2264
2371
  const headers = {
@@ -2336,6 +2443,7 @@ var Executor = class {
2336
2443
  }
2337
2444
  },
2338
2445
  dynamicImport: async (url) => {
2446
+ if (that.windowClosed) return {};
2339
2447
  const fullUrl = new URL(url, window.location.href).toString();
2340
2448
  const start = Date.now();
2341
2449
  const logEntry = {
@@ -2448,6 +2556,12 @@ var Executor = class {
2448
2556
  this.onloadend?.({ type: "loadend" });
2449
2557
  }
2450
2558
  async send(body) {
2559
+ if (that.windowClosed) {
2560
+ this.readyState = 4;
2561
+ this.status = 0;
2562
+ this.onloadend?.({ type: "loadend" });
2563
+ return;
2564
+ }
2451
2565
  const start = Date.now();
2452
2566
  const headers = {
2453
2567
  "User-Agent": window.navigator.userAgent,