magpie-html 0.1.2 → 0.1.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.
package/dist/index.cjs CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  var readability = require('@mozilla/readability');
4
4
  var linkedom = require('linkedom');
5
+ var vm4 = require('vm');
6
+ var timers = require('timers');
7
+
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ var vm4__default = /*#__PURE__*/_interopDefault(vm4);
5
11
 
6
12
  // src/content/quality.ts
7
13
  function countWords(text) {
@@ -832,6 +838,32 @@ function parseAtomDate(dateString) {
832
838
  }
833
839
 
834
840
  // src/feed/atom/extract-entry.ts
841
+ function extractAtomDate(element) {
842
+ let dateText = element.querySelector("updated")?.textContent;
843
+ if (dateText) {
844
+ const parsed = parseAtomDate(dateText);
845
+ if (parsed) return parsed;
846
+ }
847
+ dateText = element.querySelector("modified")?.textContent;
848
+ if (dateText) {
849
+ const parsed = parseAtomDate(dateText);
850
+ if (parsed) return parsed;
851
+ }
852
+ dateText = element.querySelector("issued")?.textContent;
853
+ if (dateText) {
854
+ const parsed = parseAtomDate(dateText);
855
+ if (parsed) return parsed;
856
+ }
857
+ const dcDateElements = element.children.filter((child) => child.tagName === "dc:date");
858
+ if (dcDateElements.length > 0) {
859
+ dateText = dcDateElements[0].textContent;
860
+ if (dateText) {
861
+ const parsed = parseAtomDate(dateText);
862
+ if (parsed) return parsed;
863
+ }
864
+ }
865
+ return null;
866
+ }
835
867
  function extractPerson(element) {
836
868
  const name = element.querySelector("name")?.textContent;
837
869
  if (!name) {
@@ -974,13 +1006,11 @@ function extractEntry(entryElement) {
974
1006
  if (!title) {
975
1007
  throw new Error("Invalid Atom entry: missing required <title> element");
976
1008
  }
977
- const updatedRaw = entryElement.querySelector("updated")?.textContent;
978
- if (!updatedRaw) {
979
- throw new Error("Invalid Atom entry: missing required <updated> element");
980
- }
981
- const updated = parseAtomDate(updatedRaw);
1009
+ const updated = extractAtomDate(entryElement);
982
1010
  if (!updated) {
983
- throw new Error("Invalid Atom entry: invalid <updated> date");
1011
+ throw new Error(
1012
+ "Invalid Atom entry: missing or invalid date (tried <updated>, <modified>, <issued>, <dc:date>)"
1013
+ );
984
1014
  }
985
1015
  const entry = {
986
1016
  id: cleanText(id),
@@ -1230,6 +1260,32 @@ function parseXML(xml) {
1230
1260
  }
1231
1261
 
1232
1262
  // src/feed/atom/extract-feed.ts
1263
+ function extractAtomDate2(element) {
1264
+ let dateText = element.querySelector("updated")?.textContent;
1265
+ if (dateText) {
1266
+ const parsed = parseAtomDate(dateText);
1267
+ if (parsed) return parsed;
1268
+ }
1269
+ dateText = element.querySelector("modified")?.textContent;
1270
+ if (dateText) {
1271
+ const parsed = parseAtomDate(dateText);
1272
+ if (parsed) return parsed;
1273
+ }
1274
+ dateText = element.querySelector("issued")?.textContent;
1275
+ if (dateText) {
1276
+ const parsed = parseAtomDate(dateText);
1277
+ if (parsed) return parsed;
1278
+ }
1279
+ const dcDateElements = element.children.filter((child) => child.tagName === "dc:date");
1280
+ if (dcDateElements.length > 0) {
1281
+ dateText = dcDateElements[0].textContent;
1282
+ if (dateText) {
1283
+ const parsed = parseAtomDate(dateText);
1284
+ if (parsed) return parsed;
1285
+ }
1286
+ }
1287
+ return null;
1288
+ }
1233
1289
  function extractPerson2(element) {
1234
1290
  const name = element.querySelector("name")?.textContent;
1235
1291
  if (!name) {
@@ -1377,13 +1433,11 @@ function extractFeed(xml) {
1377
1433
  if (!title) {
1378
1434
  throw new Error("Invalid Atom feed: missing required <title> element");
1379
1435
  }
1380
- const updatedRaw = feed.querySelector("updated")?.textContent;
1381
- if (!updatedRaw) {
1382
- throw new Error("Invalid Atom feed: missing required <updated> element");
1383
- }
1384
- const updated = parseAtomDate(updatedRaw);
1436
+ const updated = extractAtomDate2(feed);
1385
1437
  if (!updated) {
1386
- throw new Error("Invalid Atom feed: invalid <updated> date");
1438
+ throw new Error(
1439
+ "Invalid Atom feed: missing or invalid date (tried <updated>, <modified>, <issued>, <dc:date>)"
1440
+ );
1387
1441
  }
1388
1442
  const result = {
1389
1443
  id: cleanText(id),
@@ -2445,13 +2499,12 @@ async function pluck(input, init) {
2445
2499
  const startTime = Date.now();
2446
2500
  const options = normalizeOptions2(init);
2447
2501
  const originalUrl = typeof input === "string" || input instanceof URL ? String(input) : input.url;
2448
- const abortController = new AbortController();
2449
- const timeoutId = setTimeout(() => abortController.abort(), options.timeout);
2502
+ const signal = AbortSignal.timeout(options.timeout);
2450
2503
  try {
2451
2504
  const { response, redirectChain, redirectDuration } = await followRedirects(
2452
2505
  input,
2453
2506
  options,
2454
- abortController.signal
2507
+ signal
2455
2508
  );
2456
2509
  const finalUrl = response.url;
2457
2510
  if (options.throwOnHttpError && !response.ok) {
@@ -2488,15 +2541,13 @@ async function pluck(input, init) {
2488
2541
  if (error instanceof PluckTimeoutError || error instanceof PluckNetworkError) {
2489
2542
  throw error;
2490
2543
  }
2491
- if (error.name === "AbortError") {
2544
+ if (error.name === "TimeoutError") {
2492
2545
  throw new PluckTimeoutError(`Request timeout after ${options.timeout}ms`, options.timeout);
2493
2546
  }
2494
2547
  if (error instanceof TypeError) {
2495
2548
  throw new PluckNetworkError(`Network error: ${error.message}`, error);
2496
2549
  }
2497
2550
  throw error;
2498
- } finally {
2499
- clearTimeout(timeoutId);
2500
2551
  }
2501
2552
  }
2502
2553
  function normalizeOptions2(init) {
@@ -5048,6 +5099,1718 @@ function extractVerification(doc) {
5048
5099
  Object.entries(metadata).filter(([_, value]) => value !== void 0)
5049
5100
  );
5050
5101
  }
5102
+
5103
+ // src/swoop/errors.ts
5104
+ var SwoopError = class extends Error {
5105
+ name = "SwoopError";
5106
+ };
5107
+ var SwoopEnvironmentError = class extends SwoopError {
5108
+ name = "SwoopEnvironmentError";
5109
+ };
5110
+ var SwoopTimeoutError = class extends SwoopError {
5111
+ name = "SwoopTimeoutError";
5112
+ };
5113
+ var SwoopExecutionError = class extends SwoopError {
5114
+ name = "SwoopExecutionError";
5115
+ };
5116
+ var SwoopSecurityError = class extends SwoopError {
5117
+ name = "SwoopSecurityError";
5118
+ };
5119
+
5120
+ // src/swoop/console.ts
5121
+ function createConsoleCapture(now = () => Date.now()) {
5122
+ const entries = [];
5123
+ const formatError = (err) => {
5124
+ const parts = [];
5125
+ parts.push(`${err.name}: ${err.message}${err.stack ? `
5126
+ ${err.stack}` : ""}`.trim());
5127
+ try {
5128
+ const props = {};
5129
+ for (const key of Object.getOwnPropertyNames(err)) {
5130
+ if (key === "name" || key === "message" || key === "stack") continue;
5131
+ props[key] = err[key];
5132
+ }
5133
+ if (Object.keys(props).length > 0) {
5134
+ parts.push(`props: ${JSON.stringify(props)}`);
5135
+ }
5136
+ } catch {
5137
+ }
5138
+ return parts.join("\n");
5139
+ };
5140
+ const record = (level, args) => {
5141
+ const msg = args.map((a) => {
5142
+ try {
5143
+ if (a instanceof Error) return formatError(a);
5144
+ if (typeof a === "string") return a;
5145
+ return String(a);
5146
+ } catch {
5147
+ return "[unstringifiable]";
5148
+ }
5149
+ }).join(" ");
5150
+ const argStrings = args.map((a) => {
5151
+ try {
5152
+ if (a instanceof Error) return formatError(a);
5153
+ if (typeof a === "string") return a;
5154
+ return String(a);
5155
+ } catch {
5156
+ return "[unstringifiable]";
5157
+ }
5158
+ });
5159
+ entries.push({ level, message: msg, args: argStrings, time: now() });
5160
+ };
5161
+ return { entries, record };
5162
+ }
5163
+ function installAsyncEnv(init) {
5164
+ const { globalObj } = init;
5165
+ const hostSetTimeout = timers.setTimeout;
5166
+ const hostClearTimeout = timers.clearTimeout;
5167
+ const hostSetInterval = timers.setInterval;
5168
+ const hostClearInterval = timers.clearInterval;
5169
+ const hostSetImmediate = timers.setImmediate;
5170
+ const hostClearImmediate = timers.clearImmediate;
5171
+ const activeTimeouts = /* @__PURE__ */ new Set();
5172
+ const activeIntervals = /* @__PURE__ */ new Set();
5173
+ const activeImmediates = /* @__PURE__ */ new Set();
5174
+ let lastAsyncActivityAt = Date.now();
5175
+ const noteAsyncActivity = () => {
5176
+ lastAsyncActivityAt = Date.now();
5177
+ if (init.debugProbes) {
5178
+ try {
5179
+ globalObj.__swoopStats.lastAsyncActivityAt = lastAsyncActivityAt;
5180
+ } catch {
5181
+ }
5182
+ }
5183
+ };
5184
+ globalObj.__swoop_requestIdleCallback = (cb, _opts) => {
5185
+ return hostSetTimeout(() => {
5186
+ try {
5187
+ noteAsyncActivity();
5188
+ cb({
5189
+ didTimeout: false,
5190
+ timeRemaining: () => 0
5191
+ });
5192
+ } catch {
5193
+ }
5194
+ }, 0);
5195
+ };
5196
+ globalObj.__swoop_cancelIdleCallback = (handle) => hostClearTimeout(handle);
5197
+ globalObj.__swoop_setTimeout = (...args) => {
5198
+ const handle = hostSetTimeout(() => {
5199
+ activeTimeouts.delete(handle);
5200
+ noteAsyncActivity();
5201
+ if (init.debugProbes) {
5202
+ try {
5203
+ globalObj.__swoopStats.timers.timeoutFired++;
5204
+ } catch {
5205
+ }
5206
+ }
5207
+ args[0]?.call?.(globalObj);
5208
+ }, args[1]);
5209
+ activeTimeouts.add(handle);
5210
+ if (init.debugProbes) {
5211
+ try {
5212
+ globalObj.__swoopStats.timers.timeoutScheduled++;
5213
+ } catch {
5214
+ }
5215
+ }
5216
+ return handle;
5217
+ };
5218
+ globalObj.__swoop_clearTimeout = (handle) => {
5219
+ activeTimeouts.delete(handle);
5220
+ hostClearTimeout(handle);
5221
+ };
5222
+ globalObj.__swoop_setInterval = (...args) => {
5223
+ const handle = hostSetInterval(() => {
5224
+ noteAsyncActivity();
5225
+ if (init.debugProbes) {
5226
+ try {
5227
+ globalObj.__swoopStats.timers.intervalFired++;
5228
+ } catch {
5229
+ }
5230
+ }
5231
+ args[0]?.call?.(globalObj);
5232
+ }, args[1]);
5233
+ activeIntervals.add(handle);
5234
+ if (init.debugProbes) {
5235
+ try {
5236
+ globalObj.__swoopStats.timers.intervalScheduled++;
5237
+ } catch {
5238
+ }
5239
+ }
5240
+ return handle;
5241
+ };
5242
+ globalObj.__swoop_clearInterval = (handle) => {
5243
+ activeIntervals.delete(handle);
5244
+ hostClearInterval(handle);
5245
+ };
5246
+ globalObj.__swoop_queueMicrotask = (cb) => {
5247
+ try {
5248
+ process.nextTick(() => {
5249
+ noteAsyncActivity();
5250
+ cb.call(globalObj);
5251
+ });
5252
+ } catch {
5253
+ hostSetTimeout(() => {
5254
+ noteAsyncActivity();
5255
+ cb.call(globalObj);
5256
+ }, 0);
5257
+ }
5258
+ };
5259
+ globalObj.__swoop_setImmediate = (cb, ...args) => {
5260
+ const handle = hostSetImmediate(() => {
5261
+ activeImmediates.delete(handle);
5262
+ try {
5263
+ noteAsyncActivity();
5264
+ cb.call(globalObj, ...args);
5265
+ } catch {
5266
+ }
5267
+ });
5268
+ activeImmediates.add(handle);
5269
+ return handle;
5270
+ };
5271
+ globalObj.__swoop_clearImmediate = (handle) => {
5272
+ activeImmediates.delete(handle);
5273
+ hostClearImmediate(handle);
5274
+ };
5275
+ globalObj.__swoop_requestAnimationFrame = (cb) => {
5276
+ if (init.debugProbes) {
5277
+ try {
5278
+ globalObj.__swoopStats.timers.rafScheduled++;
5279
+ } catch {
5280
+ }
5281
+ }
5282
+ const id = hostSetTimeout(() => {
5283
+ if (init.debugProbes) {
5284
+ try {
5285
+ globalObj.__swoopStats.timers.rafFired++;
5286
+ } catch {
5287
+ }
5288
+ }
5289
+ noteAsyncActivity();
5290
+ cb.call(globalObj, Date.now());
5291
+ }, 16);
5292
+ return id;
5293
+ };
5294
+ globalObj.__swoop_cancelAnimationFrame = (id) => hostClearTimeout(id);
5295
+ const cleanup = () => {
5296
+ for (const h of activeTimeouts) hostClearTimeout(h);
5297
+ for (const h of activeIntervals) hostClearInterval(h);
5298
+ for (const h of activeImmediates) hostClearImmediate(h);
5299
+ };
5300
+ return {
5301
+ hostSetTimeout,
5302
+ hostClearTimeout,
5303
+ hostSetInterval,
5304
+ hostClearInterval,
5305
+ hostSetImmediate,
5306
+ hostClearImmediate,
5307
+ noteAsyncActivity,
5308
+ getLastAsyncActivityAt: () => lastAsyncActivityAt,
5309
+ cleanup
5310
+ };
5311
+ }
5312
+
5313
+ // src/swoop/env/base.ts
5314
+ function computeBaseForResolve(finalUrl, document) {
5315
+ const pageUrl = new URL(finalUrl);
5316
+ const baseEl = document?.querySelector?.("base") ?? null;
5317
+ const baseTagHref = baseEl?.getAttribute?.("href") ?? null;
5318
+ const baseForResolve = (() => {
5319
+ try {
5320
+ return baseTagHref ? new URL(String(baseTagHref), finalUrl) : pageUrl;
5321
+ } catch {
5322
+ return pageUrl;
5323
+ }
5324
+ })();
5325
+ return { baseForResolve, baseTagHref, baseEl };
5326
+ }
5327
+ function patchDocumentBaseURI(document, baseForResolve) {
5328
+ try {
5329
+ Object.defineProperty(document, "baseURI", {
5330
+ configurable: true,
5331
+ get: () => baseForResolve.href
5332
+ });
5333
+ } catch {
5334
+ }
5335
+ }
5336
+ function patchBaseElementHref(baseEl, baseForResolve) {
5337
+ try {
5338
+ if (baseEl) {
5339
+ Object.defineProperty(baseEl, "href", {
5340
+ configurable: true,
5341
+ get: () => baseForResolve.href,
5342
+ set: (_v) => {
5343
+ }
5344
+ });
5345
+ }
5346
+ } catch {
5347
+ }
5348
+ }
5349
+
5350
+ // src/swoop/env/browser.ts
5351
+ function installBrowserShims(init) {
5352
+ const { globalObj, domWindow, documentBaseUriForDom } = init;
5353
+ const doc = init.document ?? globalObj.document;
5354
+ try {
5355
+ if (doc && doc.defaultView == null) doc.defaultView = globalObj;
5356
+ } catch {
5357
+ }
5358
+ try {
5359
+ if (doc && doc.baseURI == null) doc.baseURI = documentBaseUriForDom;
5360
+ } catch {
5361
+ }
5362
+ globalObj.navigator ??= {};
5363
+ globalObj.navigator.language ??= "en";
5364
+ globalObj.navigator.languages ??= [globalObj.navigator.language];
5365
+ globalObj.navigator.onLine ??= true;
5366
+ globalObj.screen ??= {
5367
+ width: 1280,
5368
+ height: 720,
5369
+ availWidth: 1280,
5370
+ availHeight: 720,
5371
+ colorDepth: 24
5372
+ };
5373
+ globalObj.devicePixelRatio ??= 1;
5374
+ globalObj.innerWidth ??= globalObj.screen.width ?? 1280;
5375
+ globalObj.innerHeight ??= globalObj.screen.height ?? 720;
5376
+ globalObj.MessageChannel ??= globalThis.MessageChannel;
5377
+ globalObj.MessagePort ??= globalThis.MessagePort;
5378
+ globalObj.MessageEvent ??= globalThis.MessageEvent;
5379
+ globalObj.BroadcastChannel ??= globalThis.BroadcastChannel;
5380
+ globalObj.getComputedStyle ??= (el) => {
5381
+ const style = el?.style ?? {};
5382
+ return new Proxy(style, {
5383
+ get(target, prop) {
5384
+ if (prop === "getPropertyValue") return (name) => target?.[name] ?? "";
5385
+ return target[prop] ?? "";
5386
+ }
5387
+ });
5388
+ };
5389
+ globalObj.PopStateEvent ??= class PopStateEvent extends (globalObj.Event ?? Event) {
5390
+ state;
5391
+ constructor(type, init2) {
5392
+ super(type, init2);
5393
+ this.state = init2?.state;
5394
+ }
5395
+ };
5396
+ globalObj.HashChangeEvent ??= class HashChangeEvent extends (globalObj.Event ?? Event) {
5397
+ oldURL;
5398
+ newURL;
5399
+ constructor(type, init2) {
5400
+ super(type, init2);
5401
+ this.oldURL = init2?.oldURL ?? "";
5402
+ this.newURL = init2?.newURL ?? "";
5403
+ }
5404
+ };
5405
+ globalObj.matchMedia ??= (query) => {
5406
+ const listeners = /* @__PURE__ */ new Set();
5407
+ const mql = {
5408
+ matches: false,
5409
+ media: String(query ?? ""),
5410
+ onchange: null,
5411
+ addListener: (cb) => {
5412
+ if (typeof cb === "function") listeners.add(cb);
5413
+ },
5414
+ removeListener: (cb) => {
5415
+ listeners.delete(cb);
5416
+ },
5417
+ addEventListener: (type, cb) => {
5418
+ if (String(type) === "change" && typeof cb === "function") listeners.add(cb);
5419
+ },
5420
+ removeEventListener: (type, cb) => {
5421
+ if (String(type) === "change") listeners.delete(cb);
5422
+ },
5423
+ dispatchEvent: (evt) => {
5424
+ try {
5425
+ for (const cb of listeners) cb.call(mql, evt);
5426
+ if (typeof mql.onchange === "function") mql.onchange.call(mql, evt);
5427
+ } catch {
5428
+ }
5429
+ return true;
5430
+ }
5431
+ };
5432
+ return mql;
5433
+ };
5434
+ globalObj.IntersectionObserver ??= class IntersectionObserver {
5435
+ observe(_el) {
5436
+ }
5437
+ unobserve(_el) {
5438
+ }
5439
+ disconnect() {
5440
+ }
5441
+ takeRecords() {
5442
+ return [];
5443
+ }
5444
+ };
5445
+ globalObj.ResizeObserver ??= class ResizeObserver {
5446
+ observe(_el) {
5447
+ }
5448
+ unobserve(_el) {
5449
+ }
5450
+ disconnect() {
5451
+ }
5452
+ };
5453
+ globalObj.MutationObserver ??= class MutationObserver {
5454
+ observe(_target, _options) {
5455
+ }
5456
+ disconnect() {
5457
+ }
5458
+ takeRecords() {
5459
+ return [];
5460
+ }
5461
+ };
5462
+ globalObj.URL ??= URL;
5463
+ globalObj.URLSearchParams ??= URLSearchParams;
5464
+ globalObj.WebAssembly ??= WebAssembly;
5465
+ globalObj.TextEncoder ??= TextEncoder;
5466
+ globalObj.TextDecoder ??= TextDecoder;
5467
+ globalObj.Headers ??= globalThis.Headers;
5468
+ globalObj.Request ??= globalThis.Request;
5469
+ globalObj.Response ??= globalThis.Response;
5470
+ globalObj.crypto ??= globalThis.crypto;
5471
+ globalObj.performance ??= globalThis.performance;
5472
+ globalObj.structuredClone ??= globalThis.structuredClone;
5473
+ globalObj.Blob ??= globalThis.Blob;
5474
+ globalObj.FormData ??= globalThis.FormData;
5475
+ globalObj.File ??= globalThis.File;
5476
+ globalObj.ReadableStream ??= globalThis.ReadableStream;
5477
+ globalObj.atob ??= (data) => Buffer.from(data, "base64").toString("binary");
5478
+ globalObj.btoa ??= (data) => Buffer.from(data, "binary").toString("base64");
5479
+ globalObj.WebSocket ??= class WebSocket {
5480
+ constructor() {
5481
+ throw new Error("swoop: WebSocket is not implemented");
5482
+ }
5483
+ };
5484
+ globalObj.EventSource ??= class EventSource {
5485
+ constructor() {
5486
+ throw new Error("swoop: EventSource is not implemented");
5487
+ }
5488
+ };
5489
+ globalObj.Worker ??= class Worker {
5490
+ constructor() {
5491
+ throw new Error("swoop: Worker is not implemented");
5492
+ }
5493
+ };
5494
+ globalObj.SharedWorker ??= class SharedWorker {
5495
+ constructor() {
5496
+ throw new Error("swoop: SharedWorker is not implemented");
5497
+ }
5498
+ };
5499
+ globalObj.indexedDB ??= void 0;
5500
+ globalObj.caches ??= void 0;
5501
+ globalObj.Notification ??= void 0;
5502
+ globalObj.Document ??= domWindow.Document;
5503
+ globalObj.HTMLDocument ??= domWindow.HTMLDocument ?? init.document?.constructor;
5504
+ globalObj.Element ??= domWindow.Element;
5505
+ globalObj.HTMLElement ??= domWindow.HTMLElement;
5506
+ globalObj.Node ??= domWindow.Node;
5507
+ globalObj.NodeFilter ??= domWindow.NodeFilter ?? {
5508
+ FILTER_ACCEPT: 1,
5509
+ FILTER_REJECT: 2,
5510
+ FILTER_SKIP: 3,
5511
+ SHOW_ALL: 4294967295,
5512
+ SHOW_ELEMENT: 1,
5513
+ SHOW_ATTRIBUTE: 2,
5514
+ SHOW_TEXT: 4,
5515
+ SHOW_CDATA_SECTION: 8,
5516
+ SHOW_ENTITY_REFERENCE: 16,
5517
+ SHOW_ENTITY: 32,
5518
+ SHOW_PROCESSING_INSTRUCTION: 64,
5519
+ SHOW_COMMENT: 128,
5520
+ SHOW_DOCUMENT: 256,
5521
+ SHOW_DOCUMENT_TYPE: 512,
5522
+ SHOW_DOCUMENT_FRAGMENT: 1024,
5523
+ SHOW_NOTATION: 2048
5524
+ };
5525
+ }
5526
+
5527
+ // src/swoop/env/cookie.ts
5528
+ function installCookieJar(document) {
5529
+ let cookieJar = "";
5530
+ try {
5531
+ Object.defineProperty(document, "cookie", {
5532
+ configurable: true,
5533
+ get() {
5534
+ return cookieJar;
5535
+ },
5536
+ set(value) {
5537
+ if (typeof value === "string" && value.length > 0) {
5538
+ cookieJar = cookieJar ? `${cookieJar}; ${value}` : value;
5539
+ }
5540
+ }
5541
+ });
5542
+ } catch {
5543
+ }
5544
+ }
5545
+
5546
+ // src/swoop/env/fetch.ts
5547
+ function installFetchShim(init) {
5548
+ let pendingFetches = 0;
5549
+ init.globalObj.__swoop_fetch = typeof init.hostFetch === "function" ? (...args) => {
5550
+ init.noteAsyncActivity();
5551
+ pendingFetches++;
5552
+ try {
5553
+ const input = args[0];
5554
+ const initReq = args[1];
5555
+ let resolvedInput = input;
5556
+ if (typeof input === "string") {
5557
+ resolvedInput = new URL(input, init.baseForResolveHref).href;
5558
+ } else if (input instanceof URL) {
5559
+ resolvedInput = input.href;
5560
+ } else if (typeof input.url === "string") {
5561
+ try {
5562
+ resolvedInput = new URL(input.url, init.baseForResolveHref).href;
5563
+ } catch {
5564
+ }
5565
+ }
5566
+ if (init.debugFetch) {
5567
+ init.recordDebug(["[fetch]", resolvedInput]);
5568
+ }
5569
+ const controller = new AbortController();
5570
+ const timeoutHandle = init.hostSetTimeout(() => controller.abort(), init.remainingMs());
5571
+ const mergedInit = { ...initReq, signal: controller.signal };
5572
+ const p = init.hostFetch(resolvedInput, mergedInit).finally(() => {
5573
+ init.hostClearTimeout(timeoutHandle);
5574
+ });
5575
+ return p.finally(() => {
5576
+ try {
5577
+ init.queueMicrotask(() => {
5578
+ pendingFetches--;
5579
+ init.noteAsyncActivity();
5580
+ });
5581
+ } catch {
5582
+ pendingFetches--;
5583
+ init.noteAsyncActivity();
5584
+ }
5585
+ });
5586
+ } catch (err) {
5587
+ pendingFetches--;
5588
+ init.noteAsyncActivity();
5589
+ throw err;
5590
+ }
5591
+ } : void 0;
5592
+ return {
5593
+ getPendingFetches: () => pendingFetches
5594
+ };
5595
+ }
5596
+
5597
+ // src/swoop/env/navigation.ts
5598
+ function createNavigationShims(init) {
5599
+ const { pageUrl } = init;
5600
+ const resolveAndSetHref = (href) => {
5601
+ try {
5602
+ const next = new URL(href, pageUrl.href);
5603
+ pageUrl.href = next.href;
5604
+ init.onNavigate?.(pageUrl.href);
5605
+ } catch {
5606
+ }
5607
+ };
5608
+ const location = {};
5609
+ try {
5610
+ Object.defineProperties(location, {
5611
+ href: { get: () => pageUrl.href, set: (v) => resolveAndSetHref(String(v)) },
5612
+ origin: { get: () => pageUrl.origin },
5613
+ protocol: {
5614
+ get: () => pageUrl.protocol,
5615
+ set: (v) => {
5616
+ pageUrl.protocol = String(v);
5617
+ }
5618
+ },
5619
+ host: {
5620
+ get: () => pageUrl.host,
5621
+ set: (v) => {
5622
+ pageUrl.host = String(v);
5623
+ }
5624
+ },
5625
+ hostname: {
5626
+ get: () => pageUrl.hostname,
5627
+ set: (v) => {
5628
+ pageUrl.hostname = String(v);
5629
+ }
5630
+ },
5631
+ port: {
5632
+ get: () => pageUrl.port,
5633
+ set: (v) => {
5634
+ pageUrl.port = String(v);
5635
+ }
5636
+ },
5637
+ pathname: { get: () => pageUrl.pathname, set: (v) => resolveAndSetHref(String(v)) },
5638
+ search: {
5639
+ get: () => pageUrl.search,
5640
+ set: (v) => {
5641
+ pageUrl.search = String(v);
5642
+ }
5643
+ },
5644
+ hash: {
5645
+ get: () => pageUrl.hash,
5646
+ set: (v) => {
5647
+ pageUrl.hash = String(v);
5648
+ }
5649
+ }
5650
+ });
5651
+ } catch {
5652
+ }
5653
+ location.toString = () => pageUrl.href;
5654
+ location.assign = (href) => resolveAndSetHref(href);
5655
+ location.replace = (href) => resolveAndSetHref(href);
5656
+ location.reload = () => {
5657
+ };
5658
+ let historyState = null;
5659
+ const history = {
5660
+ get state() {
5661
+ return historyState;
5662
+ },
5663
+ pushState: (state, _title, url) => {
5664
+ historyState = state;
5665
+ if (url != null) resolveAndSetHref(String(url));
5666
+ try {
5667
+ init.onPopState?.(state);
5668
+ } catch {
5669
+ }
5670
+ },
5671
+ replaceState: (state, _title, url) => {
5672
+ historyState = state;
5673
+ if (url != null) resolveAndSetHref(String(url));
5674
+ },
5675
+ back: () => {
5676
+ },
5677
+ forward: () => {
5678
+ },
5679
+ go: (_delta) => {
5680
+ }
5681
+ };
5682
+ return { location, history };
5683
+ }
5684
+
5685
+ // src/swoop/env/permissive.ts
5686
+ function installPermissiveShims(globalObj) {
5687
+ const makeStorage = () => {
5688
+ const store = /* @__PURE__ */ new Map();
5689
+ return {
5690
+ get length() {
5691
+ return store.size;
5692
+ },
5693
+ clear() {
5694
+ store.clear();
5695
+ },
5696
+ getItem(key) {
5697
+ return store.has(String(key)) ? store.get(String(key)) : null;
5698
+ },
5699
+ key(index) {
5700
+ return Array.from(store.keys())[index] ?? null;
5701
+ },
5702
+ removeItem(key) {
5703
+ store.delete(String(key));
5704
+ },
5705
+ setItem(key, value) {
5706
+ store.set(String(key), String(value));
5707
+ }
5708
+ };
5709
+ };
5710
+ globalObj.localStorage ??= makeStorage();
5711
+ globalObj.sessionStorage ??= makeStorage();
5712
+ globalObj.scrollTo ??= () => {
5713
+ };
5714
+ try {
5715
+ if (globalObj.HTMLElement?.prototype && !globalObj.HTMLElement.prototype.getBoundingClientRect) {
5716
+ globalObj.HTMLElement.prototype.getBoundingClientRect = () => ({
5717
+ x: 0,
5718
+ y: 0,
5719
+ width: 0,
5720
+ height: 0,
5721
+ top: 0,
5722
+ left: 0,
5723
+ right: 0,
5724
+ bottom: 0,
5725
+ toJSON() {
5726
+ }
5727
+ });
5728
+ }
5729
+ } catch {
5730
+ }
5731
+ globalObj.process ??= { env: { NODE_ENV: "production" } };
5732
+ }
5733
+
5734
+ // src/swoop/env/xhr.ts
5735
+ function installXMLHttpRequest(init) {
5736
+ const g = init.globalObj;
5737
+ if (g.XMLHttpRequest) return;
5738
+ class Xhr {
5739
+ // readyState constants
5740
+ static UNSENT = 0;
5741
+ static OPENED = 1;
5742
+ static HEADERS_RECEIVED = 2;
5743
+ static LOADING = 3;
5744
+ static DONE = 4;
5745
+ UNSENT = 0;
5746
+ OPENED = 1;
5747
+ HEADERS_RECEIVED = 2;
5748
+ LOADING = 3;
5749
+ DONE = 4;
5750
+ readyState = 0;
5751
+ status = 0;
5752
+ statusText = "";
5753
+ responseType = "";
5754
+ response = null;
5755
+ responseText = "";
5756
+ timeout = 0;
5757
+ withCredentials = false;
5758
+ onreadystatechange = null;
5759
+ onload = null;
5760
+ onerror = null;
5761
+ ontimeout = null;
5762
+ onabort = null;
5763
+ _method = "GET";
5764
+ _url = "";
5765
+ _headers = /* @__PURE__ */ new Map();
5766
+ _respHeaders = null;
5767
+ _listeners = /* @__PURE__ */ new Map();
5768
+ _controller = null;
5769
+ addEventListener(type, cb) {
5770
+ const t = String(type);
5771
+ const set = this._listeners.get(t) ?? /* @__PURE__ */ new Set();
5772
+ set.add(cb);
5773
+ this._listeners.set(t, set);
5774
+ }
5775
+ removeEventListener(type, cb) {
5776
+ const t = String(type);
5777
+ this._listeners.get(t)?.delete(cb);
5778
+ }
5779
+ _dispatch(type) {
5780
+ const ev = { type, target: this, currentTarget: this };
5781
+ this._listeners.get(type)?.forEach((cb) => {
5782
+ try {
5783
+ cb(ev);
5784
+ } catch {
5785
+ }
5786
+ });
5787
+ }
5788
+ _setReadyState(n) {
5789
+ this.readyState = n;
5790
+ try {
5791
+ this.onreadystatechange?.();
5792
+ } catch {
5793
+ }
5794
+ this._dispatch("readystatechange");
5795
+ }
5796
+ open(method, url, async = true) {
5797
+ this._method = String(method ?? "GET").toUpperCase();
5798
+ this._url = String(url ?? "");
5799
+ this._headers.clear();
5800
+ this._respHeaders = null;
5801
+ this._controller = null;
5802
+ this._setReadyState(1);
5803
+ }
5804
+ setRequestHeader(name, value) {
5805
+ this._headers.set(String(name), String(value));
5806
+ }
5807
+ getResponseHeader(name) {
5808
+ try {
5809
+ return this._respHeaders?.get(String(name)) ?? null;
5810
+ } catch {
5811
+ return null;
5812
+ }
5813
+ }
5814
+ getAllResponseHeaders() {
5815
+ try {
5816
+ if (!this._respHeaders) return "";
5817
+ let out = "";
5818
+ this._respHeaders.forEach((v, k) => {
5819
+ out += `${k}: ${v}\r
5820
+ `;
5821
+ });
5822
+ return out;
5823
+ } catch {
5824
+ return "";
5825
+ }
5826
+ }
5827
+ overrideMimeType(_mime) {
5828
+ }
5829
+ abort() {
5830
+ try {
5831
+ this._controller?.abort();
5832
+ } catch {
5833
+ }
5834
+ try {
5835
+ this.onabort?.();
5836
+ } catch {
5837
+ }
5838
+ this._dispatch("abort");
5839
+ }
5840
+ send(body) {
5841
+ const doFetch = async () => {
5842
+ const url = init.resolveUrl(this._url);
5843
+ const controller = new AbortController();
5844
+ this._controller = controller;
5845
+ let timeoutHandle;
5846
+ const ms = Math.min(this.timeout || 0, init.remainingMs());
5847
+ if (ms > 0) {
5848
+ timeoutHandle = init.hostSetTimeout(() => controller.abort(), ms);
5849
+ }
5850
+ try {
5851
+ const headers = {};
5852
+ for (const [k, v] of this._headers.entries()) headers[k] = v;
5853
+ if (!init.fetch) throw new Error("swoop: host fetch is unavailable in this Node runtime");
5854
+ const resp = await init.fetch(url, {
5855
+ method: this._method,
5856
+ headers,
5857
+ body,
5858
+ signal: controller.signal
5859
+ // credentials/withCredentials ignored (Node fetch differs); best-effort.
5860
+ });
5861
+ this._respHeaders = resp.headers;
5862
+ this.status = resp.status;
5863
+ this.statusText = resp.statusText ?? "";
5864
+ this._setReadyState(2);
5865
+ this._setReadyState(3);
5866
+ if (this.responseType === "arraybuffer") {
5867
+ this.response = await resp.arrayBuffer();
5868
+ this.responseText = "";
5869
+ } else if (this.responseType === "blob") {
5870
+ this.response = resp.blob ? await resp.blob() : await resp.arrayBuffer();
5871
+ this.responseText = "";
5872
+ } else {
5873
+ const text = await resp.text();
5874
+ this.responseText = text;
5875
+ if (this.responseType === "json") {
5876
+ try {
5877
+ this.response = JSON.parse(text);
5878
+ } catch {
5879
+ this.response = null;
5880
+ }
5881
+ } else {
5882
+ this.response = text;
5883
+ }
5884
+ }
5885
+ this._setReadyState(4);
5886
+ try {
5887
+ this.onload?.();
5888
+ } catch {
5889
+ }
5890
+ this._dispatch("load");
5891
+ this._dispatch("loadend");
5892
+ } catch {
5893
+ this._setReadyState(4);
5894
+ const aborted = this._controller?.signal?.aborted;
5895
+ if (aborted) {
5896
+ try {
5897
+ this.ontimeout?.();
5898
+ } catch {
5899
+ }
5900
+ this._dispatch("timeout");
5901
+ } else {
5902
+ try {
5903
+ this.onerror?.();
5904
+ } catch {
5905
+ }
5906
+ this._dispatch("error");
5907
+ }
5908
+ this._dispatch("loadend");
5909
+ } finally {
5910
+ if (timeoutHandle) init.hostClearTimeout(timeoutHandle);
5911
+ }
5912
+ };
5913
+ void doFetch();
5914
+ }
5915
+ }
5916
+ g.XMLHttpRequest = Xhr;
5917
+ }
5918
+ function synthesizeLifecycle(context, timeoutMs = 50) {
5919
+ vm4__default.default.runInContext(
5920
+ `
5921
+ try {
5922
+ const EventCtor = (globalThis.Event || (globalThis.window && globalThis.window.Event));
5923
+ const dispatchDoc = (type) => { try { document.dispatchEvent(new EventCtor(type)); } catch {} };
5924
+ const dispatchWin = (type) => { try { window.dispatchEvent(new EventCtor(type)); } catch {} };
5925
+
5926
+ if (typeof document.readyState !== "string") {
5927
+ try { document.readyState = "loading"; } catch {}
5928
+ }
5929
+
5930
+ dispatchDoc("readystatechange");
5931
+ try { document.readyState = "interactive"; } catch {}
5932
+ dispatchDoc("readystatechange");
5933
+ dispatchDoc("DOMContentLoaded");
5934
+ try { document.readyState = "complete"; } catch {}
5935
+ dispatchDoc("readystatechange");
5936
+
5937
+ try {
5938
+ if (typeof document.visibilityState !== "string") document.visibilityState = "visible";
5939
+ if (typeof document.hidden !== "boolean") document.hidden = false;
5940
+ if (typeof document.hasFocus !== "function") document.hasFocus = () => true;
5941
+ } catch {}
5942
+ dispatchDoc("visibilitychange");
5943
+
5944
+ dispatchWin("pageshow");
5945
+ dispatchWin("load");
5946
+
5947
+ try { window.dispatchEvent(new PopStateEvent("popstate", { state: (history && history.state) })); } catch {}
5948
+ try {
5949
+ const href = String((location && location.href) || "");
5950
+ window.dispatchEvent(new HashChangeEvent("hashchange", { oldURL: href, newURL: href }));
5951
+ } catch {}
5952
+ } catch {}
5953
+ `,
5954
+ context,
5955
+ { timeout: timeoutMs }
5956
+ );
5957
+ }
5958
+
5959
+ // src/swoop/probes.ts
5960
+ function installDebugProbes(init) {
5961
+ const { globalObj, hostSetTimeout } = init;
5962
+ globalObj.__swoopStats = {
5963
+ startedAt: Date.now(),
5964
+ domOps: /* @__PURE__ */ Object.create(null),
5965
+ mutations: 0,
5966
+ lastDomActivityAt: 0,
5967
+ listeners: /* @__PURE__ */ Object.create(null),
5968
+ timers: {
5969
+ timeoutScheduled: 0,
5970
+ timeoutFired: 0,
5971
+ intervalScheduled: 0,
5972
+ intervalFired: 0,
5973
+ rafScheduled: 0,
5974
+ rafFired: 0
5975
+ },
5976
+ nav: {
5977
+ pushState: 0,
5978
+ replaceState: 0,
5979
+ lastHref: null
5980
+ },
5981
+ appRootSamples: []
5982
+ };
5983
+ const bump = (name) => {
5984
+ const s = globalObj.__swoopStats;
5985
+ s.domOps[name] = (s.domOps[name] ?? 0) + 1;
5986
+ s.lastDomActivityAt = Date.now();
5987
+ };
5988
+ const bumpListener = (type) => {
5989
+ const s = globalObj.__swoopStats;
5990
+ s.listeners[type] = (s.listeners[type] ?? 0) + 1;
5991
+ };
5992
+ const wrapProto = (proto, fn) => {
5993
+ const orig = proto?.[fn];
5994
+ if (typeof orig !== "function") return;
5995
+ proto[fn] = function(...args) {
5996
+ bump(fn);
5997
+ return orig.apply(this, args);
5998
+ };
5999
+ };
6000
+ wrapProto(globalObj.Node?.prototype, "appendChild");
6001
+ wrapProto(globalObj.Node?.prototype, "insertBefore");
6002
+ wrapProto(globalObj.Node?.prototype, "removeChild");
6003
+ wrapProto(globalObj.Element?.prototype, "setAttribute");
6004
+ wrapProto(globalObj.Element?.prototype, "removeAttribute");
6005
+ wrapProto(globalObj.Element?.prototype, "append");
6006
+ wrapProto(globalObj.Element?.prototype, "prepend");
6007
+ const wrapAddListener = (target, label) => {
6008
+ const orig = target?.addEventListener;
6009
+ if (typeof orig !== "function") return;
6010
+ target.addEventListener = function(type, listener, options) {
6011
+ try {
6012
+ bumpListener(`${label}:${String(type)}`);
6013
+ } catch {
6014
+ }
6015
+ return orig.call(this, type, listener, options);
6016
+ };
6017
+ };
6018
+ wrapAddListener(globalObj, "window");
6019
+ wrapAddListener(globalObj.document, "document");
6020
+ const MO = globalObj.MutationObserver;
6021
+ if (typeof MO === "function") {
6022
+ const mo = new MO(() => {
6023
+ globalObj.__swoopStats.mutations++;
6024
+ globalObj.__swoopStats.lastDomActivityAt = Date.now();
6025
+ });
6026
+ try {
6027
+ mo.observe(globalObj.document?.documentElement, {
6028
+ subtree: true,
6029
+ childList: true,
6030
+ attributes: true,
6031
+ characterData: true
6032
+ });
6033
+ } catch {
6034
+ }
6035
+ }
6036
+ const sample = () => {
6037
+ try {
6038
+ const el = globalObj.document?.querySelector?.("app-root");
6039
+ const len = el?.innerHTML?.length ?? 0;
6040
+ const opacity = el?.getAttribute?.("style")?.includes("opacity") ? String(el.getAttribute("style")) : null;
6041
+ globalObj.__swoopStats.appRootSamples.push({ t: Date.now(), len, opacity });
6042
+ } catch {
6043
+ }
6044
+ };
6045
+ sample();
6046
+ hostSetTimeout(sample, 250);
6047
+ hostSetTimeout(sample, 1e3);
6048
+ hostSetTimeout(sample, 2500);
6049
+ hostSetTimeout(sample, 4500);
6050
+ }
6051
+ function emitDebugProbes(globalObj, recordDebug, now = () => Date.now()) {
6052
+ const stats = globalObj.__swoopStats;
6053
+ if (!stats) return;
6054
+ const appRootHtml = (() => {
6055
+ try {
6056
+ const el = globalObj.document?.querySelector?.("app-root");
6057
+ const raw = el?.innerHTML ?? "";
6058
+ return String(raw).slice(0, 400);
6059
+ } catch {
6060
+ return null;
6061
+ }
6062
+ })();
6063
+ recordDebug([
6064
+ "[swoop probes]",
6065
+ JSON.stringify({
6066
+ mutations: stats.mutations ?? 0,
6067
+ lastDomActivityMsAgo: stats.lastDomActivityAt && typeof stats.lastDomActivityAt === "number" ? now() - stats.lastDomActivityAt : null,
6068
+ topDomOps: Object.entries(stats.domOps ?? {}).sort((a, b) => b[1] - a[1]).slice(0, 15),
6069
+ topListeners: Object.entries(stats.listeners ?? {}).sort((a, b) => b[1] - a[1]).slice(0, 20),
6070
+ timers: stats.timers ?? null,
6071
+ lastAsyncActivityMsAgo: stats.lastAsyncActivityAt && typeof stats.lastAsyncActivityAt === "number" ? now() - stats.lastAsyncActivityAt : null,
6072
+ nav: stats.nav ?? null,
6073
+ location: (() => {
6074
+ try {
6075
+ return {
6076
+ href: String(globalObj.location?.href ?? ""),
6077
+ pathname: String(globalObj.location?.pathname ?? ""),
6078
+ search: String(globalObj.location?.search ?? ""),
6079
+ hash: String(globalObj.location?.hash ?? ""),
6080
+ baseURI: String(globalObj.document?.baseURI ?? "")
6081
+ };
6082
+ } catch {
6083
+ return null;
6084
+ }
6085
+ })(),
6086
+ appRootSamples: stats.appRootSamples ?? [],
6087
+ appRootHtmlHead: appRootHtml
6088
+ })
6089
+ ]);
6090
+ }
6091
+
6092
+ // src/swoop/scripts/loader.ts
6093
+ function isScriptEl(node) {
6094
+ return node?.tagName?.toLowerCase?.() === "script";
6095
+ }
6096
+ function createScriptLoader(init) {
6097
+ const loadedScriptSrcs = /* @__PURE__ */ new Set();
6098
+ let pendingScriptLoads = 0;
6099
+ let debugScriptEvents = 0;
6100
+ const debugScript = (...args) => {
6101
+ if (debugScriptEvents++ > init.maxDebugEvents) return;
6102
+ init.debug(args);
6103
+ };
6104
+ const loadScriptElement = async (scriptEl, parentUrlForResolve) => {
6105
+ const rawSrc = scriptEl?.src || scriptEl?.getAttribute?.("src");
6106
+ if (!rawSrc) return;
6107
+ let resolvedSrc;
6108
+ try {
6109
+ resolvedSrc = new URL(String(rawSrc), init.baseForResolveHref).href;
6110
+ } catch {
6111
+ return;
6112
+ }
6113
+ if (loadedScriptSrcs.has(resolvedSrc)) return;
6114
+ loadedScriptSrcs.add(resolvedSrc);
6115
+ init.noteAsyncActivity();
6116
+ pendingScriptLoads++;
6117
+ const type = (scriptEl?.type || scriptEl?.getAttribute?.("type") || "").toString().trim().toLowerCase();
6118
+ const isModule = type === "module";
6119
+ debugScript("[swoop] load <script>", resolvedSrc, isModule ? "module" : "classic");
6120
+ try {
6121
+ if (isModule) {
6122
+ await init.runModuleScript(resolvedSrc, parentUrlForResolve);
6123
+ } else {
6124
+ const code = await init.fetchText(resolvedSrc);
6125
+ init.runClassicScript(code, resolvedSrc);
6126
+ }
6127
+ try {
6128
+ if (typeof scriptEl?.onload === "function")
6129
+ scriptEl.onload(new (init.globalObj.Event ?? Event)("load"));
6130
+ } catch {
6131
+ try {
6132
+ scriptEl.onload?.();
6133
+ } catch {
6134
+ }
6135
+ }
6136
+ try {
6137
+ scriptEl?.dispatchEvent?.(new (init.globalObj.Event ?? Event)("load"));
6138
+ } catch {
6139
+ }
6140
+ } catch (e) {
6141
+ try {
6142
+ init.onError?.(resolvedSrc, e);
6143
+ } catch {
6144
+ }
6145
+ try {
6146
+ if (typeof scriptEl?.onerror === "function") scriptEl.onerror(e);
6147
+ } catch {
6148
+ try {
6149
+ scriptEl.onerror?.();
6150
+ } catch {
6151
+ }
6152
+ }
6153
+ try {
6154
+ scriptEl?.dispatchEvent?.(new (init.globalObj.Event ?? Event)("error"));
6155
+ } catch {
6156
+ }
6157
+ } finally {
6158
+ pendingScriptLoads--;
6159
+ init.noteAsyncActivity();
6160
+ }
6161
+ };
6162
+ const scheduleScriptLoad = (node, label) => {
6163
+ init.hostSetTimeout(() => {
6164
+ void loadScriptElement(node, `${init.pageUrlHref}#${label}`);
6165
+ }, 0);
6166
+ };
6167
+ const patchScriptInsertion = (container, label) => {
6168
+ if (!container) return;
6169
+ const origAppendChild = container.appendChild?.bind(container);
6170
+ const origInsertBefore = container.insertBefore?.bind(container);
6171
+ const origAppend = container.append?.bind(container);
6172
+ const origPrepend = container.prepend?.bind(container);
6173
+ if (typeof origAppendChild === "function") {
6174
+ container.appendChild = (node) => {
6175
+ const ret = origAppendChild(node);
6176
+ if (isScriptEl(node)) scheduleScriptLoad(node, `${label}.appendChild`);
6177
+ return ret;
6178
+ };
6179
+ }
6180
+ if (typeof origInsertBefore === "function") {
6181
+ container.insertBefore = (node, ref) => {
6182
+ const ret = origInsertBefore(node, ref);
6183
+ if (isScriptEl(node)) scheduleScriptLoad(node, `${label}.insertBefore`);
6184
+ return ret;
6185
+ };
6186
+ }
6187
+ if (typeof origAppend === "function") {
6188
+ container.append = (...nodes) => {
6189
+ const ret = origAppend(...nodes);
6190
+ for (const n of nodes) if (isScriptEl(n)) scheduleScriptLoad(n, `${label}.append`);
6191
+ return ret;
6192
+ };
6193
+ }
6194
+ if (typeof origPrepend === "function") {
6195
+ container.prepend = (...nodes) => {
6196
+ const ret = origPrepend(...nodes);
6197
+ for (const n of nodes) if (isScriptEl(n)) scheduleScriptLoad(n, `${label}.prepend`);
6198
+ return ret;
6199
+ };
6200
+ }
6201
+ };
6202
+ const install = () => {
6203
+ patchScriptInsertion(init.globalObj.document?.head, "head");
6204
+ patchScriptInsertion(init.globalObj.document?.body, "body");
6205
+ try {
6206
+ const elProto = init.globalObj.Element?.prototype;
6207
+ const origSetAttr = elProto?.setAttribute;
6208
+ if (typeof origSetAttr === "function") {
6209
+ elProto.setAttribute = function(name, value) {
6210
+ const ret = origSetAttr.call(this, name, value);
6211
+ try {
6212
+ if (this?.tagName?.toLowerCase?.() === "script" && typeof name === "string" && name.toLowerCase() === "src") {
6213
+ scheduleScriptLoad(this, "script.setAttribute(src)");
6214
+ }
6215
+ } catch {
6216
+ }
6217
+ return ret;
6218
+ };
6219
+ }
6220
+ } catch {
6221
+ }
6222
+ try {
6223
+ const doc = init.globalObj.document;
6224
+ const origCreateElement = doc?.createElement?.bind(doc);
6225
+ if (typeof origCreateElement === "function") {
6226
+ doc.createElement = (tagName, ...rest) => {
6227
+ const el = origCreateElement(tagName, ...rest);
6228
+ try {
6229
+ if (typeof tagName === "string" && tagName.toLowerCase() === "script") {
6230
+ const desc = Object.getOwnPropertyDescriptor(el, "src");
6231
+ if (!desc || desc.configurable) {
6232
+ let _src = el.getAttribute?.("src") ?? "";
6233
+ Object.defineProperty(el, "src", {
6234
+ configurable: true,
6235
+ enumerable: true,
6236
+ get: () => _src,
6237
+ set: (v) => {
6238
+ _src = String(v);
6239
+ try {
6240
+ el.setAttribute?.("src", _src);
6241
+ } catch {
6242
+ }
6243
+ scheduleScriptLoad(el, "script.src=");
6244
+ }
6245
+ });
6246
+ }
6247
+ }
6248
+ } catch {
6249
+ }
6250
+ return el;
6251
+ };
6252
+ }
6253
+ } catch {
6254
+ }
6255
+ };
6256
+ return {
6257
+ getPendingScriptLoads: () => pendingScriptLoads,
6258
+ install
6259
+ };
6260
+ }
6261
+ function isNodeRuntime() {
6262
+ return typeof process !== "undefined" && typeof process.versions === "object" && typeof process.versions.node === "string";
6263
+ }
6264
+ function sleep(ms) {
6265
+ return new Promise((resolve) => timers.setTimeout(resolve, ms));
6266
+ }
6267
+ function normalizeInit(init) {
6268
+ return {
6269
+ engine: init?.engine ?? "vm",
6270
+ pluck: init?.pluck ?? {},
6271
+ executeScripts: init?.executeScripts ?? true,
6272
+ timeout: init?.timeout ?? 3e3,
6273
+ waitStrategy: init?.waitStrategy ?? "networkidle",
6274
+ idleTime: init?.idleTime ?? 250,
6275
+ pollInterval: init?.pollInterval ?? 25,
6276
+ maxScripts: init?.maxScripts ?? 64,
6277
+ forwardConsole: init?.forwardConsole ?? false,
6278
+ permissiveShims: init?.permissiveShims ?? true,
6279
+ debugFetch: init?.debugFetch ?? false,
6280
+ debugProbes: init?.debugProbes ?? false
6281
+ };
6282
+ }
6283
+ function defineWindowInContext(context, timeoutMs = 50) {
6284
+ vm4__default.default.runInContext(
6285
+ `
6286
+ globalThis.Window ??= function Window() {};
6287
+ try { globalThis.Window.prototype = Object.getPrototypeOf(globalThis); } catch {}
6288
+ `,
6289
+ context,
6290
+ { timeout: timeoutMs }
6291
+ );
6292
+ }
6293
+ function ensureRealmFunctionIntrinsic(context, timeoutMs = 50) {
6294
+ vm4__default.default.runInContext(
6295
+ `
6296
+ try { globalThis.Function = (function(){}).constructor; } catch {}
6297
+ `,
6298
+ context,
6299
+ { timeout: timeoutMs }
6300
+ );
6301
+ }
6302
+ function installRealmWrappers(context, timeoutMs = 50) {
6303
+ vm4__default.default.runInContext(
6304
+ `
6305
+ // timers
6306
+ if (typeof globalThis.__swoop_setTimeout === "function") {
6307
+ globalThis.setTimeout = (...args) => globalThis.__swoop_setTimeout(...args);
6308
+ }
6309
+ if (typeof globalThis.__swoop_clearTimeout === "function") {
6310
+ globalThis.clearTimeout = (...args) => globalThis.__swoop_clearTimeout(...args);
6311
+ }
6312
+ if (typeof globalThis.__swoop_setInterval === "function") {
6313
+ globalThis.setInterval = (...args) => globalThis.__swoop_setInterval(...args);
6314
+ }
6315
+ if (typeof globalThis.__swoop_clearInterval === "function") {
6316
+ globalThis.clearInterval = (...args) => globalThis.__swoop_clearInterval(...args);
6317
+ }
6318
+ if (typeof globalThis.__swoop_setImmediate === "function") {
6319
+ globalThis.setImmediate = (...args) => globalThis.__swoop_setImmediate(...args);
6320
+ }
6321
+ if (typeof globalThis.__swoop_clearImmediate === "function") {
6322
+ globalThis.clearImmediate = (...args) => globalThis.__swoop_clearImmediate(...args);
6323
+ }
6324
+
6325
+ // microtasks / raf / idle
6326
+ if (typeof globalThis.__swoop_queueMicrotask === "function") {
6327
+ globalThis.queueMicrotask = (...args) => globalThis.__swoop_queueMicrotask(...args);
6328
+ }
6329
+ if (typeof globalThis.__swoop_requestAnimationFrame === "function") {
6330
+ globalThis.requestAnimationFrame = (...args) => globalThis.__swoop_requestAnimationFrame(...args);
6331
+ }
6332
+ if (typeof globalThis.__swoop_cancelAnimationFrame === "function") {
6333
+ globalThis.cancelAnimationFrame = (...args) => globalThis.__swoop_cancelAnimationFrame(...args);
6334
+ }
6335
+ if (typeof globalThis.__swoop_requestIdleCallback === "function") {
6336
+ globalThis.requestIdleCallback = (...args) => globalThis.__swoop_requestIdleCallback(...args);
6337
+ }
6338
+ if (typeof globalThis.__swoop_cancelIdleCallback === "function") {
6339
+ globalThis.cancelIdleCallback = (...args) => globalThis.__swoop_cancelIdleCallback(...args);
6340
+ }
6341
+
6342
+ // fetch
6343
+ if (typeof globalThis.__swoop_fetch === "function") {
6344
+ globalThis.fetch = (...args) => globalThis.__swoop_fetch(...args);
6345
+ }
6346
+ `,
6347
+ context,
6348
+ { timeout: timeoutMs }
6349
+ );
6350
+ }
6351
+ function createModuleLoader(init) {
6352
+ const SourceTextModule = vm4__default.default.SourceTextModule;
6353
+ const moduleCache = /* @__PURE__ */ new Map();
6354
+ const pluckFn = init.pluckFn ?? pluck;
6355
+ const loadModule = async (specifier, referencingUrl) => {
6356
+ if (init.remainingMs() <= 0)
6357
+ throw new Error("swoop() time budget exhausted while loading modules");
6358
+ const resolved = new URL(specifier, referencingUrl).href;
6359
+ const cached = moduleCache.get(resolved);
6360
+ if (cached) return cached;
6361
+ if (!SourceTextModule) {
6362
+ throw new Error(
6363
+ "Module scripts require Node `--experimental-vm-modules` (vm.SourceTextModule is unavailable)."
6364
+ );
6365
+ }
6366
+ const modRes = await pluckFn(resolved, {
6367
+ ...init.pluckInit,
6368
+ timeout: Math.min(init.pluckInit.timeout ?? 3e4, init.remainingMs()),
6369
+ strictContentType: false,
6370
+ throwOnHttpError: true
6371
+ });
6372
+ const rawSource = await modRes.textUtf8();
6373
+ const mod = new SourceTextModule(rawSource, {
6374
+ context: init.context,
6375
+ identifier: resolved,
6376
+ initializeImportMeta: (meta) => {
6377
+ meta.url = resolved;
6378
+ },
6379
+ importModuleDynamically: async (spec) => {
6380
+ const child = await loadModule(spec, resolved);
6381
+ await child.link(linkerFor(resolved));
6382
+ await child.evaluate();
6383
+ return child;
6384
+ }
6385
+ });
6386
+ moduleCache.set(resolved, mod);
6387
+ return mod;
6388
+ };
6389
+ const linkerFor = (referencingUrl) => async (specifier) => {
6390
+ return await loadModule(specifier, referencingUrl);
6391
+ };
6392
+ return { loadModule, linkerFor };
6393
+ }
6394
+
6395
+ // src/swoop/wait.ts
6396
+ async function waitForSettle(init) {
6397
+ if (init.strategy === "timeout") {
6398
+ await init.sleep(Math.max(0, init.deadlineMs - init.now()));
6399
+ return { timedOut: init.now() >= init.deadlineMs };
6400
+ }
6401
+ while (init.now() < init.deadlineMs) {
6402
+ if (init.getPendingFetches() === 0 && init.getPendingScriptLoads() === 0 && init.now() - init.getLastAsyncActivityAt() >= init.idleTimeMs) {
6403
+ return { timedOut: false };
6404
+ }
6405
+ await init.sleep(init.pollIntervalMs);
6406
+ }
6407
+ return { timedOut: true };
6408
+ }
6409
+
6410
+ // src/swoop/engines/vm.ts
6411
+ async function runVmEngine(args) {
6412
+ const { entries: realmConsole, record } = createConsoleCapture();
6413
+ const remainingMs = () => Math.max(0, args.deadline - Date.now());
6414
+ const { window, document } = linkedom.parseHTML(args.html, { url: args.finalUrl });
6415
+ const pageUrl = new URL(args.finalUrl);
6416
+ const { baseForResolve, baseEl } = computeBaseForResolve(args.finalUrl, document);
6417
+ patchDocumentBaseURI(document, baseForResolve);
6418
+ patchBaseElementHref(baseEl, baseForResolve);
6419
+ const documentBaseUriForDom = baseForResolve.href;
6420
+ try {
6421
+ document.readyState ??= "loading";
6422
+ } catch {
6423
+ }
6424
+ const domWindow = window;
6425
+ const globalObj = Object.create(domWindow);
6426
+ globalObj.window = globalObj;
6427
+ globalObj.self = globalObj;
6428
+ globalObj.globalThis = globalObj;
6429
+ globalObj.document = document;
6430
+ try {
6431
+ Object.defineProperty(document, "defaultView", { value: globalObj, configurable: true });
6432
+ } catch {
6433
+ }
6434
+ const { location: locationShim, history: historyShim } = createNavigationShims({
6435
+ pageUrl,
6436
+ onNavigate: (href) => {
6437
+ if (!args.options.debugProbes) return;
6438
+ try {
6439
+ globalObj.__swoopStats.nav.lastHref = String(href);
6440
+ } catch {
6441
+ }
6442
+ },
6443
+ onPopState: (state) => {
6444
+ if (args.options.debugProbes) {
6445
+ try {
6446
+ globalObj.__swoopStats.nav.pushState++;
6447
+ } catch {
6448
+ }
6449
+ }
6450
+ try {
6451
+ globalObj.dispatchEvent?.(new (globalObj.PopStateEvent ?? Event)("popstate", { state }));
6452
+ } catch {
6453
+ }
6454
+ }
6455
+ });
6456
+ try {
6457
+ Object.defineProperty(document, "location", {
6458
+ configurable: true,
6459
+ get: () => locationShim,
6460
+ set: (v) => {
6461
+ try {
6462
+ locationShim.href = String(v);
6463
+ } catch {
6464
+ }
6465
+ }
6466
+ });
6467
+ } catch {
6468
+ }
6469
+ globalObj.location = locationShim;
6470
+ globalObj.history = historyShim;
6471
+ installBrowserShims({ globalObj, domWindow, document, documentBaseUriForDom });
6472
+ installCookieJar(document);
6473
+ const asyncEnv = installAsyncEnv({ globalObj, debugProbes: args.options.debugProbes });
6474
+ const noteAsyncActivity = asyncEnv.noteAsyncActivity;
6475
+ const hostSetTimeout = asyncEnv.hostSetTimeout;
6476
+ const hostClearTimeout = asyncEnv.hostClearTimeout;
6477
+ if (args.options.debugProbes) {
6478
+ try {
6479
+ installDebugProbes({ globalObj, hostSetTimeout });
6480
+ } catch {
6481
+ }
6482
+ }
6483
+ const fetchShim = installFetchShim({
6484
+ globalObj,
6485
+ hostFetch: args.hostFetch,
6486
+ baseForResolveHref: baseForResolve.href,
6487
+ remainingMs,
6488
+ hostSetTimeout,
6489
+ hostClearTimeout,
6490
+ noteAsyncActivity,
6491
+ debugFetch: args.options.debugFetch,
6492
+ recordDebug: (a) => record("debug", a),
6493
+ queueMicrotask: (cb) => globalObj.__swoop_queueMicrotask(cb)
6494
+ });
6495
+ const addEventListener = domWindow.addEventListener?.bind(domWindow);
6496
+ const removeEventListener = domWindow.removeEventListener?.bind(domWindow);
6497
+ const dispatchEvent = domWindow.dispatchEvent?.bind(domWindow);
6498
+ if (typeof addEventListener === "function") globalObj.addEventListener = addEventListener;
6499
+ if (typeof removeEventListener === "function")
6500
+ globalObj.removeEventListener = removeEventListener;
6501
+ if (typeof dispatchEvent === "function") globalObj.dispatchEvent = dispatchEvent;
6502
+ globalObj.console = {
6503
+ debug: (...a) => record("debug", a),
6504
+ info: (...a) => record("info", a),
6505
+ warn: (...a) => record("warn", a),
6506
+ error: (...a) => record("error", a),
6507
+ log: (...a) => record("log", a)
6508
+ };
6509
+ if (args.options.forwardConsole) {
6510
+ for (const level of ["debug", "info", "warn", "error", "log"]) {
6511
+ const original = console[level]?.bind(console);
6512
+ if (typeof original === "function") {
6513
+ const wrapped = globalObj.console[level];
6514
+ globalObj.console[level] = (...a) => {
6515
+ wrapped(...a);
6516
+ original(...a);
6517
+ };
6518
+ }
6519
+ }
6520
+ }
6521
+ try {
6522
+ globalObj.onerror = (message, source, line, col, error) => {
6523
+ record("error", ["[window.onerror]", message, source, line, col, error]);
6524
+ };
6525
+ } catch {
6526
+ }
6527
+ try {
6528
+ globalObj.onunhandledrejection = (event) => {
6529
+ record("error", ["[unhandledrejection]", event?.reason]);
6530
+ };
6531
+ } catch {
6532
+ }
6533
+ try {
6534
+ globalObj.addEventListener?.("error", (event) => {
6535
+ record("error", [
6536
+ "[error event]",
6537
+ event?.message,
6538
+ event?.filename,
6539
+ event?.lineno,
6540
+ event?.colno,
6541
+ event?.error instanceof Error ? `${event.error.name}: ${event.error.message}
6542
+ ${event.error.stack ?? ""}`.trim() : event?.error
6543
+ ]);
6544
+ });
6545
+ } catch {
6546
+ }
6547
+ if (args.options.permissiveShims) {
6548
+ installPermissiveShims(globalObj);
6549
+ if (!globalObj.XMLHttpRequest) {
6550
+ installXMLHttpRequest({
6551
+ globalObj,
6552
+ resolveUrl: (u) => {
6553
+ try {
6554
+ return new URL(u, baseForResolve.href).href;
6555
+ } catch {
6556
+ return u;
6557
+ }
6558
+ },
6559
+ remainingMs,
6560
+ hostSetTimeout,
6561
+ hostClearTimeout,
6562
+ fetch: args.hostFetch
6563
+ });
6564
+ }
6565
+ }
6566
+ const context = vm4__default.default.createContext(globalObj, { name: "magpie-html/swoop" });
6567
+ defineWindowInContext(context);
6568
+ ensureRealmFunctionIntrinsic(context);
6569
+ installRealmWrappers(context);
6570
+ const { loadModule, linkerFor } = createModuleLoader({
6571
+ context,
6572
+ remainingMs,
6573
+ pluckInit: args.options.pluck
6574
+ });
6575
+ const scriptLoader = createScriptLoader({
6576
+ globalObj,
6577
+ pageUrlHref: pageUrl.href,
6578
+ baseForResolveHref: baseForResolve.href,
6579
+ remainingMs,
6580
+ hostSetTimeout,
6581
+ totalBudgetMs: args.totalBudgetMs,
6582
+ maxDebugEvents: args.options.debugProbes ? 80 : 0,
6583
+ debug: (a) => {
6584
+ if (!args.options.debugProbes) return;
6585
+ record("debug", a);
6586
+ },
6587
+ onError: (resolvedSrc, err) => {
6588
+ const e = err;
6589
+ record("error", ["[swoop] script load failed", resolvedSrc, e?.message || String(e)]);
6590
+ },
6591
+ noteAsyncActivity,
6592
+ fetchText: async (url) => {
6593
+ const sres = await pluck(url, {
6594
+ ...args.options.pluck,
6595
+ timeout: Math.min(args.options.pluck.timeout ?? 3e4, remainingMs()),
6596
+ strictContentType: false,
6597
+ throwOnHttpError: true
6598
+ });
6599
+ return await sres.textUtf8();
6600
+ },
6601
+ runClassicScript: (code, filename) => {
6602
+ const script = new vm4__default.default.Script(code, { filename });
6603
+ script.runInContext(context, { timeout: args.totalBudgetMs });
6604
+ },
6605
+ runModuleScript: async (resolvedSrc, parentUrlForResolve) => {
6606
+ const mod = await loadModule(resolvedSrc, parentUrlForResolve);
6607
+ await mod.link(linkerFor(resolvedSrc));
6608
+ await mod.evaluate();
6609
+ }
6610
+ });
6611
+ scriptLoader.install();
6612
+ const getPendingScriptLoads = () => scriptLoader.getPendingScriptLoads();
6613
+ const engineErrors = [];
6614
+ const classicScripts = args.scripts.filter((s) => !s.isModule);
6615
+ const moduleScriptsInOrder = args.scripts.filter((s) => s.isModule);
6616
+ for (const s of [...classicScripts, ...moduleScriptsInOrder]) {
6617
+ if (remainingMs() <= 0) {
6618
+ engineErrors.push({
6619
+ stage: "wait",
6620
+ message: `Hard time budget (${args.totalBudgetMs}ms) exceeded while executing scripts; returning snapshot.`
6621
+ });
6622
+ break;
6623
+ }
6624
+ const scriptUrl = s.kind === "external" ? s.url : `${args.finalUrl}#inline`;
6625
+ try {
6626
+ if (s.isModule) {
6627
+ const modCode = s.code;
6628
+ const SourceTextModule = vm4__default.default.SourceTextModule;
6629
+ if (!SourceTextModule) {
6630
+ throw new Error(
6631
+ "Module scripts require Node `--experimental-vm-modules` (vm.SourceTextModule is unavailable)."
6632
+ );
6633
+ }
6634
+ const mod = new SourceTextModule(modCode, {
6635
+ context,
6636
+ identifier: scriptUrl,
6637
+ initializeImportMeta: (meta) => {
6638
+ meta.url = scriptUrl;
6639
+ },
6640
+ importModuleDynamically: async (spec) => {
6641
+ const child = await loadModule(spec, scriptUrl);
6642
+ await child.link(linkerFor(scriptUrl));
6643
+ await child.evaluate();
6644
+ return child;
6645
+ }
6646
+ });
6647
+ const timeoutP = (label) => sleep(remainingMs()).then(() => {
6648
+ throw new Error(`swoop() time budget exhausted during ${label}`);
6649
+ });
6650
+ const linkP = mod.link(linkerFor(scriptUrl));
6651
+ try {
6652
+ await Promise.race([linkP, timeoutP("module link")]);
6653
+ } catch (e) {
6654
+ void linkP.catch?.(() => {
6655
+ });
6656
+ throw e;
6657
+ }
6658
+ const evalP = mod.evaluate();
6659
+ try {
6660
+ await Promise.race([evalP, timeoutP("module evaluate")]);
6661
+ } catch (e) {
6662
+ void evalP.catch?.(() => {
6663
+ });
6664
+ throw e;
6665
+ }
6666
+ } else {
6667
+ const script = new vm4__default.default.Script(s.code, { filename: scriptUrl });
6668
+ script.runInContext(context, { timeout: args.totalBudgetMs });
6669
+ }
6670
+ } catch (err) {
6671
+ const e = err;
6672
+ engineErrors.push({
6673
+ stage: "script",
6674
+ scriptUrl: s.kind === "external" ? s.url : void 0,
6675
+ message: e.message || String(e),
6676
+ stack: e.stack
6677
+ });
6678
+ }
6679
+ }
6680
+ try {
6681
+ synthesizeLifecycle(context, Math.min(50, remainingMs()));
6682
+ } catch {
6683
+ }
6684
+ const settle = await waitForSettle({
6685
+ strategy: args.options.waitStrategy === "timeout" || typeof globalObj.fetch !== "function" ? "timeout" : "networkidle",
6686
+ deadlineMs: args.deadline,
6687
+ idleTimeMs: args.options.idleTime,
6688
+ pollIntervalMs: args.options.pollInterval,
6689
+ sleep,
6690
+ now: () => Date.now(),
6691
+ getPendingFetches: () => fetchShim.getPendingFetches(),
6692
+ getPendingScriptLoads,
6693
+ getLastAsyncActivityAt: () => asyncEnv.getLastAsyncActivityAt()
6694
+ });
6695
+ if (settle.timedOut && args.options.waitStrategy === "networkidle" && typeof globalObj.fetch === "function") {
6696
+ engineErrors.push({
6697
+ stage: "wait",
6698
+ message: `Hard time budget (${args.totalBudgetMs}ms) exceeded waiting for network idle; returning snapshot.`
6699
+ });
6700
+ }
6701
+ const snapshot = document.documentElement?.outerHTML ?? "";
6702
+ if (args.options.debugProbes) {
6703
+ try {
6704
+ emitDebugProbes(globalObj, (a) => record("debug", a));
6705
+ } catch {
6706
+ }
6707
+ }
6708
+ asyncEnv.cleanup();
6709
+ return { snapshot, consoleEntries: realmConsole, engineErrors };
6710
+ }
6711
+
6712
+ // src/swoop/scripts/discover.ts
6713
+ function isExecutableScriptType(type) {
6714
+ if (!type) return true;
6715
+ const t = type.trim().toLowerCase();
6716
+ if (t === "") return true;
6717
+ if (t === "text/javascript") return true;
6718
+ if (t === "application/javascript") return true;
6719
+ if (t === "application/ecmascript") return true;
6720
+ if (t === "text/ecmascript") return true;
6721
+ return false;
6722
+ }
6723
+ function isModuleScript(type) {
6724
+ return (type ?? "").trim().toLowerCase() === "module";
6725
+ }
6726
+ async function discoverAndFetchScripts(html, finalUrl, init, pluckFn = pluck) {
6727
+ const errors = [];
6728
+ const scripts = [];
6729
+ if (!init.executeScripts) return { scripts, errors };
6730
+ const doc = parseHTML(html, finalUrl);
6731
+ const baseHref = doc.querySelector("base[href]")?.getAttribute("href") ?? null;
6732
+ const baseUrl = baseHref ? new URL(baseHref, finalUrl).href : finalUrl;
6733
+ const scriptEls = Array.from(doc.querySelectorAll("script"));
6734
+ for (const el of scriptEls.slice(0, init.maxScripts)) {
6735
+ const type = el.getAttribute("type");
6736
+ const isModule = isModuleScript(type);
6737
+ if (!isModule && !isExecutableScriptType(type)) continue;
6738
+ const src = el.getAttribute("src");
6739
+ if (src) {
6740
+ const scriptUrl = new URL(src, baseUrl).href;
6741
+ try {
6742
+ const res = await pluckFn(scriptUrl, {
6743
+ ...init.pluck,
6744
+ strictContentType: false,
6745
+ throwOnHttpError: true
6746
+ });
6747
+ const code2 = await res.textUtf8();
6748
+ scripts.push({ kind: "external", url: scriptUrl, code: code2, isModule });
6749
+ } catch (err) {
6750
+ const e = err;
6751
+ errors.push({
6752
+ stage: "script",
6753
+ scriptUrl,
6754
+ message: `Failed to fetch external script: ${e.message || String(e)}`,
6755
+ stack: e.stack
6756
+ });
6757
+ }
6758
+ continue;
6759
+ }
6760
+ const code = el.textContent ?? "";
6761
+ if (code.trim().length === 0) continue;
6762
+ scripts.push({ kind: "inline", code, isModule });
6763
+ }
6764
+ return { scripts, errors };
6765
+ }
6766
+
6767
+ // src/swoop/swoop.ts
6768
+ var HOST_FETCH = typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0;
6769
+ async function swoop(url, init) {
6770
+ const start = Date.now();
6771
+ const options = normalizeInit(init);
6772
+ const totalBudgetMs = Math.min(options.timeout, 5e3);
6773
+ const deadline = start + totalBudgetMs;
6774
+ if (!isNodeRuntime()) {
6775
+ throw new SwoopEnvironmentError("swoop() is currently Node.js-only.");
6776
+ }
6777
+ const res = await pluck(String(url), {
6778
+ ...options.pluck,
6779
+ timeout: Math.min(options.pluck.timeout ?? 3e4, totalBudgetMs),
6780
+ strictContentType: false,
6781
+ throwOnHttpError: true
6782
+ });
6783
+ const html = await res.textUtf8();
6784
+ const finalUrl = res.finalUrl;
6785
+ const { scripts, errors: preErrors } = await discoverAndFetchScripts(html, finalUrl, options);
6786
+ let snapshot = "";
6787
+ let consoleEntries = [];
6788
+ let engineErrors = [];
6789
+ const r = await runVmEngine({
6790
+ finalUrl,
6791
+ html,
6792
+ scripts,
6793
+ options,
6794
+ totalBudgetMs,
6795
+ deadline,
6796
+ hostFetch: HOST_FETCH
6797
+ });
6798
+ snapshot = r.snapshot;
6799
+ consoleEntries = r.consoleEntries;
6800
+ engineErrors = r.engineErrors;
6801
+ const end = Date.now();
6802
+ return {
6803
+ url: finalUrl,
6804
+ html: snapshot,
6805
+ console: consoleEntries,
6806
+ errors: [...preErrors, ...engineErrors],
6807
+ timing: {
6808
+ start,
6809
+ end,
6810
+ duration: end - start
6811
+ }
6812
+ };
6813
+ }
5051
6814
  /**
5052
6815
  * Enhanced fetch types for web scraping.
5053
6816
  *
@@ -5154,6 +6917,11 @@ exports.PluckNetworkError = PluckNetworkError;
5154
6917
  exports.PluckRedirectError = PluckRedirectError;
5155
6918
  exports.PluckSizeError = PluckSizeError;
5156
6919
  exports.PluckTimeoutError = PluckTimeoutError;
6920
+ exports.SwoopEnvironmentError = SwoopEnvironmentError;
6921
+ exports.SwoopError = SwoopError;
6922
+ exports.SwoopExecutionError = SwoopExecutionError;
6923
+ exports.SwoopSecurityError = SwoopSecurityError;
6924
+ exports.SwoopTimeoutError = SwoopTimeoutError;
5157
6925
  exports.assessContentQuality = assessContentQuality;
5158
6926
  exports.calculateReadingTime = calculateReadingTime;
5159
6927
  exports.countWords = countWords;
@@ -5193,5 +6961,6 @@ exports.isRSS = isRSS;
5193
6961
  exports.parseFeed = parseFeed;
5194
6962
  exports.parseHTML = parseHTML;
5195
6963
  exports.pluck = pluck;
6964
+ exports.swoop = swoop;
5196
6965
  //# sourceMappingURL=index.cjs.map
5197
6966
  //# sourceMappingURL=index.cjs.map