magpie-html 0.1.2 → 0.1.3

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