sandboxedjs 0.2.18 → 0.2.20

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
@@ -6858,9 +6858,9 @@ var WasiHost = class {
6858
6858
  if (!(oflags & O_CREAT)) throw new WasiError(WASI_ENOENT);
6859
6859
  vfs.writeFile(abs, new Uint8Array(0), { cred, mode: 420 });
6860
6860
  }
6861
- const truncate = (oflags & O_TRUNC) !== 0;
6862
- const data = truncate ? new Uint8Array(0) : vfs.readFile(abs, cred);
6863
- if (truncate) vfs.writeFile(abs, data, { cred });
6861
+ const truncate2 = (oflags & O_TRUNC) !== 0;
6862
+ const data = truncate2 ? new Uint8Array(0) : vfs.readFile(abs, cred);
6863
+ if (truncate2) vfs.writeFile(abs, data, { cred });
6864
6864
  const size = data.length;
6865
6865
  const rights = rightsBase === 0n ? RIGHTS_ALL : rightsBase;
6866
6866
  const append = (fdflags & FD_APPEND) !== 0;
@@ -21103,7 +21103,7 @@ var wheels_default = {
21103
21103
 
21104
21104
  // package.json
21105
21105
  var package_default = {
21106
- version: "0.2.18"};
21106
+ version: "0.2.20"};
21107
21107
 
21108
21108
  // src/python/extension-abi.ts
21109
21109
  var EXTENSION_ABI = {
@@ -23913,7 +23913,7 @@ async function resolve2(options) {
23913
23913
  const clauses = (state.constraints.get(name) ?? []).flatMap((entry) => entry.spec.map((s) => `${s.op}${s.version}`)).sort();
23914
23914
  return `${name}|${[...new Set(clauses)].join(",")}`;
23915
23915
  };
23916
- const search2 = async (queue, state) => {
23916
+ const search3 = async (queue, state) => {
23917
23917
  checkBudget();
23918
23918
  if (queue.length === 0) return state;
23919
23919
  const [edge, ...rest] = queue;
@@ -23921,7 +23921,7 @@ async function resolve2(options) {
23921
23921
  const name = requirement.name;
23922
23922
  if (!markerApplies(requirement.marker, environment, extras)) {
23923
23923
  if (requirement.marker) skipped.push({ name, marker: requirement.marker });
23924
- return search2(rest, state);
23924
+ return search3(rest, state);
23925
23925
  }
23926
23926
  const previous = state.constraints.get(name) ?? [];
23927
23927
  const constraints = new Map(state.constraints);
@@ -23938,7 +23938,7 @@ async function resolve2(options) {
23938
23938
  explain(name, next.constraints, already.version)
23939
23939
  );
23940
23940
  }
23941
- return search2(rest, next);
23941
+ return search3(rest, next);
23942
23942
  }
23943
23943
  const signature = signatureOf(name, next);
23944
23944
  const learned = nogoods.get(signature);
@@ -24001,7 +24001,7 @@ async function resolve2(options) {
24001
24001
  const chosen = new Map(next.chosen);
24002
24002
  chosen.set(name, { ...candidate, requires });
24003
24003
  try {
24004
- return await search2([...edges, ...rest], { chosen, constraints: next.constraints });
24004
+ return await search3([...edges, ...rest], { chosen, constraints: next.constraints });
24005
24005
  } catch (error) {
24006
24006
  if (!(error instanceof ResolutionError)) throw error;
24007
24007
  if (/cancelled|budget/.test(error.message)) throw error;
@@ -24016,7 +24016,7 @@ async function resolve2(options) {
24016
24016
  if (specifiers.length === 0 || !markerApplies(marker, environment, root.extras)) continue;
24017
24017
  seeded.set(name, [...seeded.get(name) ?? [], { spec: specifiers, origin: root.origin }]);
24018
24018
  }
24019
- const solved = await search2(roots, { chosen: /* @__PURE__ */ new Map(), constraints: seeded });
24019
+ const solved = await search3(roots, { chosen: /* @__PURE__ */ new Map(), constraints: seeded });
24020
24020
  const distributions = [...solved.chosen.values()].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
24021
24021
  const reported = new Map(skipped.map((s) => [`${s.name}\0${s.marker}`, s]));
24022
24022
  return { distributions, skipped: [...reported.values()] };
@@ -24263,7 +24263,7 @@ function consoleScripts(text2) {
24263
24263
  return result;
24264
24264
  }
24265
24265
  function consoleLauncher(target) {
24266
- const [module, attribute = ""] = target.split(":", 2);
24266
+ const [module, attribute2 = ""] = target.split(":", 2);
24267
24267
  return `#!/usr/bin/python3
24268
24268
  import sys
24269
24269
  from importlib import import_module
@@ -24271,7 +24271,7 @@ from importlib import import_module
24271
24271
 
24272
24272
  def _entry():
24273
24273
  entry = import_module(${JSON.stringify(module)})
24274
- for part in ${JSON.stringify(attribute)}.split('.'):
24274
+ for part in ${JSON.stringify(attribute2)}.split('.'):
24275
24275
  if part:
24276
24276
  entry = getattr(entry, part)
24277
24277
  return entry
@@ -27648,7 +27648,7 @@ var defaultRealmFactory = async (hooks) => {
27648
27648
  vm = void 0;
27649
27649
  }
27650
27650
  if (vm?.createContext) {
27651
- const context = vm.createContext({ console: console2, setTimeout, clearTimeout, setInterval, clearInterval, queueMicrotask });
27651
+ const context = vm.createContext({ console: console2, URL, setTimeout, clearTimeout, setInterval, clearInterval, queueMicrotask });
27652
27652
  return { evaluate: (source) => vm.runInContext(source, context), dispose: () => {
27653
27653
  } };
27654
27654
  }
@@ -27775,6 +27775,28 @@ var CdpServer = class {
27775
27775
  return {};
27776
27776
  case "Runtime.runIfWaitingForDebugger":
27777
27777
  return {};
27778
+ case "Input.insertText": {
27779
+ const target = page ?? this.pages.values().next().value;
27780
+ if (!target) return {};
27781
+ for (const context of target.contexts.values()) context.realm.evaluate(`(() => { const element = document.activeElement; if (!element || element === document.body) return; element.value = (element.value || '') + ${JSON.stringify(String(params.text ?? ""))}; element.dispatchEvent(new Event('input', { bubbles: true })); })()`);
27782
+ return {};
27783
+ }
27784
+ case "Input.dispatchKeyEvent": {
27785
+ const target = page ?? this.pages.values().next().value;
27786
+ if (!target) return {};
27787
+ if (params.type === "char" || params.type === "keyDown" && params.text) {
27788
+ for (const context of target.contexts.values()) context.realm.evaluate(`(() => { const element = document.activeElement; if (!element || element === document.body) return; const text = ${JSON.stringify(String(params.text ?? ""))}; element.value = (element.value || '') + text; element.dispatchEvent(new KeyboardEvent('keydown', { key: text, bubbles: true })); element.dispatchEvent(new Event('input', { bubbles: true })); })()`);
27789
+ }
27790
+ return {};
27791
+ }
27792
+ case "Input.dispatchMouseEvent": {
27793
+ const target = page ?? this.pages.values().next().value;
27794
+ if (!target) return {};
27795
+ if (params.type === "mouseReleased") {
27796
+ for (const context of target.contexts.values()) context.realm.evaluate(`document.elementFromPoint(${Number(params.x) || 0}, ${Number(params.y) || 0})?.click()`);
27797
+ }
27798
+ return {};
27799
+ }
27778
27800
  }
27779
27801
  const [, name = ""] = method.split(".");
27780
27802
  if (name === "enable" || name === "disable" || /^set[A-Z]/.test(name)) return {};
@@ -27796,7 +27818,8 @@ var CdpServer = class {
27796
27818
  url: "about:blank",
27797
27819
  loader: 1,
27798
27820
  contexts: /* @__PURE__ */ new Map(),
27799
- worlds: /* @__PURE__ */ new Set()
27821
+ worlds: /* @__PURE__ */ new Set(),
27822
+ document: void 0
27800
27823
  };
27801
27824
  this.pages.set(page.sessionId, page);
27802
27825
  this.options.send({
@@ -27846,6 +27869,22 @@ var CdpServer = class {
27846
27869
  timestamp: Date.now()
27847
27870
  })
27848
27871
  });
27872
+ if (page.document) realm.evaluate(domBootstrap(page.document));
27873
+ if (page.document) {
27874
+ for (const script of documentScripts(page.document.root)) {
27875
+ try {
27876
+ realm.evaluate(`document.currentScript = document.__nodeByPath(${JSON.stringify(script.path)});
27877
+ ${script.code}
27878
+ //# sourceURL=${script.url}`);
27879
+ } catch (error) {
27880
+ this.event(page, "Runtime.exceptionThrown", {
27881
+ timestamp: Date.now(),
27882
+ exceptionDetails: { text: String(error), lineNumber: 0, columnNumber: 0 }
27883
+ });
27884
+ }
27885
+ }
27886
+ realm.evaluate("document.currentScript = null");
27887
+ }
27849
27888
  const context = { id, name, isDefault, realm, objects: /* @__PURE__ */ new Map(), nextObject: 0 };
27850
27889
  page.contexts.set(id, context);
27851
27890
  this.announceContext(page, context);
@@ -27881,6 +27920,13 @@ var CdpServer = class {
27881
27920
  return DEFERRED;
27882
27921
  }
27883
27922
  async commitNavigation(page, url) {
27923
+ if (this.options.navigate && /^(https?|data):/i.test(url)) {
27924
+ const loaded = await this.options.navigate(url);
27925
+ url = loaded.url;
27926
+ page.document = loaded.document;
27927
+ } else {
27928
+ page.document = void 0;
27929
+ }
27884
27930
  page.loader += 1;
27885
27931
  page.url = url;
27886
27932
  this.destroyContexts(page, true);
@@ -27913,14 +27959,22 @@ var CdpServer = class {
27913
27959
  callFunctionOn(page, params) {
27914
27960
  const context = params.objectId ? this.contextOfObject(page, params.objectId) : this.contextFor(page, params.executionContextId);
27915
27961
  const receiver = params.objectId ? context.objects.get(params.objectId) : void 0;
27916
- const args = (params.arguments ?? []).map((argument) => this.argument(page, argument));
27962
+ const args = (params.arguments ?? []).map((argument) => this.argument(page, argument, context));
27917
27963
  return this.settle(context, () => {
27918
27964
  const fn = context.realm.evaluate(`(${params.functionDeclaration})`);
27919
27965
  return fn.apply(receiver, args);
27920
27966
  }, params);
27921
27967
  }
27922
- argument(page, argument) {
27923
- if (argument.objectId) return this.contextOfObject(page, argument.objectId).objects.get(argument.objectId);
27968
+ argument(page, argument, target) {
27969
+ if (argument.objectId) {
27970
+ const source = this.contextOfObject(page, argument.objectId);
27971
+ const value = source.objects.get(argument.objectId);
27972
+ if (target && source !== target && value && typeof value === "object" && "__vireoPath" in value) {
27973
+ const path = value.__vireoPath;
27974
+ return target.realm.evaluate(`document.__nodeByPath(${JSON.stringify(path)})`);
27975
+ }
27976
+ return value;
27977
+ }
27924
27978
  if (argument.unserializableValue !== void 0) {
27925
27979
  const raw = String(argument.unserializableValue);
27926
27980
  if (raw === "NaN") return NaN;
@@ -27970,83 +28024,321 @@ var CdpServer = class {
27970
28024
  return { type, objectId, className, description: type === "function" ? "function" : className, ...subtype ? { subtype } : {} };
27971
28025
  }
27972
28026
  };
28027
+ function documentScripts(root) {
28028
+ const scripts = [];
28029
+ const visit = (node2, path) => {
28030
+ if (node2.type === "element" && node2.name === "script") {
28031
+ const type = node2.attrs?.type?.trim().toLowerCase();
28032
+ if (!type || type === "text/javascript" || type === "application/javascript") {
28033
+ const inline = (node2.children ?? []).filter((child) => child.type === "text").map((child) => child.text ?? "").join("");
28034
+ scripts.push({ path, code: node2.resourceText ?? inline, url: node2.attrs?.src ?? "vireo:inline-script" });
28035
+ }
28036
+ }
28037
+ node2.children?.forEach((child, index) => visit(child, [...path, index]));
28038
+ };
28039
+ visit(root, []);
28040
+ return scripts;
28041
+ }
28042
+ function domBootstrap(document2) {
28043
+ return `(() => {
28044
+ const snapshot = ${JSON.stringify(document2)};
28045
+ const escapeText = value => String(value).replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;');
28046
+ const escapeAttr = value => escapeText(value).replaceAll('"', '&quot;');
28047
+ class VireoNode {
28048
+ constructor(data, parent = null) {
28049
+ this.__data = data; this.parentNode = parent;
28050
+ this.__listeners = new Map();
28051
+ this.childNodes = (data.children || []).map(child => new VireoNode(child, this));
28052
+ }
28053
+ get nodeType() { return this.__data.type === 'document' ? 9 : this.__data.type === 'text' ? 3 : 1; }
28054
+ get nodeName() { return this.nodeType === 9 ? '#document' : this.nodeType === 3 ? '#text' : this.__data.name.toUpperCase(); }
28055
+ get textContent() { return this.nodeType === 3 ? this.__data.text : this.childNodes.map(node => node.textContent).join(''); }
28056
+ set textContent(value) { if (this.nodeType === 3) this.__data.text = String(value); else { const child = new VireoNode({ type:'text', text:String(value) }, this); this.childNodes = [child]; } notify(this, 'characterData'); }
28057
+ get children() { return this.childNodes.filter(node => node.nodeType === 1); }
28058
+ get firstChild() { return this.childNodes[0] || null; }
28059
+ get parentElement() { return this.parentNode?.nodeType === 1 ? this.parentNode : null; }
28060
+ get ownerDocument() { let node = this; while (node.parentNode) node = node.parentNode; return node.nodeType === 9 ? node : null; }
28061
+ getRootNode() { let node = this; while (node.parentNode) node = node.parentNode; return node; }
28062
+ get isConnected() { let node = this; while (node.parentNode) node = node.parentNode; return node.nodeType === 9; }
28063
+ contains(other) { for (let node = other; node; node = node.parentNode) if (node === this) return true; return false; }
28064
+ addEventListener(type, listener) { const set = this.__listeners.get(type) || new Set(); set.add(listener); this.__listeners.set(type, set); }
28065
+ removeEventListener(type, listener) { this.__listeners.get(type)?.delete(listener); }
28066
+ dispatchEvent(event) { for (const listener of this.__listeners.get(event.type) || []) listener.call(this, event); return true; }
28067
+ querySelector(selector) { return query(this, selector)[0] || null; }
28068
+ querySelectorAll(selector) { return query(this, selector); }
28069
+ appendChild(child) { child.remove(); child.parentNode = this; this.childNodes.push(child); notify(this, 'childList'); return child; }
28070
+ append(...items) { for (const item of items) this.appendChild(typeof item === 'string' ? document.createTextNode(item) : item); }
28071
+ prepend(...items) { for (const item of items.reverse()) { const child = typeof item === 'string' ? document.createTextNode(item) : item; child.remove(); child.parentNode = this; this.childNodes.unshift(child); } notify(this, 'childList'); }
28072
+ removeChild(child) { const index = this.childNodes.indexOf(child); if (index < 0) throw new Error('NotFoundError'); this.childNodes.splice(index, 1); child.parentNode = null; notify(this, 'childList'); return child; }
28073
+ remove() { this.parentNode?.removeChild(this); }
28074
+ replaceChildren(...items) { for (const child of this.childNodes) child.parentNode = null; this.childNodes = []; this.append(...items); }
28075
+ insertBefore(child, reference) { if (reference == null) return this.appendChild(child); const index = this.childNodes.indexOf(reference); if (index < 0) throw new Error('NotFoundError'); child.remove(); child.parentNode = this; this.childNodes.splice(index, 0, child); notify(this, 'childList'); return child; }
28076
+ }
28077
+ class VireoElement extends VireoNode {}
28078
+ Object.assign(VireoNode, { ELEMENT_NODE: 1, TEXT_NODE: 3, DOCUMENT_NODE: 9 });
28079
+ Object.defineProperties(VireoNode.prototype, {
28080
+ tagName: { get() { return this.nodeType === 1 ? this.__data.name.toUpperCase() : undefined; } },
28081
+ localName: { get() { return this.nodeType === 1 ? this.__data.name : undefined; } },
28082
+ namespaceURI: { get() { return this.nodeType === 1 ? 'http://www.w3.org/1999/xhtml' : null; } },
28083
+ id: { get() { return this.getAttribute?.('id') || ''; }, set(value) { this.setAttribute('id', value); } },
28084
+ className: { get() { return this.getAttribute?.('class') || ''; }, set(value) { this.setAttribute('class', value); } },
28085
+ classList: { get() { const node = this; const values = () => node.className.split(/\\s+/).filter(Boolean); return { add(...names) { node.className = [...new Set([...values(), ...names])].join(' '); }, remove(...names) { node.className = values().filter(value => !names.includes(value)).join(' '); }, contains(name) { return values().includes(name); }, toggle(name, force) { const present = values().includes(name); const next = force === undefined ? !present : Boolean(force); next ? this.add(name) : this.remove(name); return next; }, toString() { return node.className; } }; } },
28086
+ innerText: { get() { return this.textContent.replace(/\\s+/g, ' ').trim(); } },
28087
+ attributes: { get() { return Object.entries(this.__data.attrs || {}).map(([name, value]) => ({ name, value })); } },
28088
+ innerHTML: { get() { return this.childNodes.map(serialize).join(''); } },
28089
+ outerHTML: { get() { return serialize(this); } },
28090
+ value: { get() { return this.__value ?? this.getAttribute?.('value') ?? ''; }, set(value) { this.__value = String(value); this.setAttribute?.('value', this.__value); } },
28091
+ selectionStart: { get() { return this.__selectionStart ?? 0; }, set(value) { this.__selectionStart = Number(value); } },
28092
+ selectionEnd: { get() { return this.__selectionEnd ?? this.value.length; }, set(value) { this.__selectionEnd = Number(value); } },
28093
+ checked: { get() { return this.__checked ?? this.hasAttribute?.('checked') ?? false; }, set(value) { this.__checked = Boolean(value); } },
28094
+ disabled: { get() { return this.hasAttribute?.('disabled') ?? false; }, set(value) { value ? this.setAttribute('disabled', '') : this.removeAttribute('disabled'); } },
28095
+ readOnly: { get() { return this.hasAttribute?.('readonly') ?? false; }, set(value) { value ? this.setAttribute('readonly', '') : this.removeAttribute('readonly'); } },
28096
+ type: { get() { return this.getAttribute?.('type') || ''; }, set(value) { this.setAttribute('type', value); } },
28097
+ isContentEditable: { get() { return this.getAttribute?.('contenteditable') === 'true'; } },
28098
+ contentDocument: { get() { return this.__contentDocument || null; } },
28099
+ contentWindow: { get() { return this.__contentDocument?.defaultView || null; } },
28100
+ });
28101
+ VireoNode.prototype.getAttribute = function(name) { const attrs = this.__data.attrs || {}; return Object.hasOwn(attrs, name) ? attrs[name] : null; };
28102
+ VireoNode.prototype.hasAttribute = function(name) { return this.getAttribute(name) !== null; };
28103
+ VireoNode.prototype.setAttribute = function(name, value) { (this.__data.attrs ||= {})[String(name)] = String(value); notify(this, 'attributes'); };
28104
+ VireoNode.prototype.removeAttribute = function(name) { delete (this.__data.attrs ||= {})[String(name)]; notify(this, 'attributes'); };
28105
+ VireoNode.prototype.matches = function(selector) { return matches(this, selector); };
28106
+ VireoNode.prototype.focus = function() { document.activeElement = this; this.dispatchEvent(new Event('focus')); };
28107
+ VireoNode.prototype.blur = function() { if (document.activeElement === this) document.activeElement = document.body; this.dispatchEvent(new Event('blur')); };
28108
+ VireoNode.prototype.click = function() { this.focus(); if (this.localName === 'input' && ['checkbox','radio'].includes(this.getAttribute('type'))) this.checked = !this.checked; this.dispatchEvent(new MouseEvent('click', { bubbles: true })); };
28109
+ VireoNode.prototype.getBoundingClientRect = function() { const all = descendants(document).filter(node => node.nodeType === 1); const index = Math.max(0, all.indexOf(this)); const top = index * 24; return { x: 0, y: top, top, left: 0, width: 800, height: 20, right: 800, bottom: top + 20, toJSON() { return { x:0, y:top, width:800, height:20, top, left:0, right:800, bottom:top+20 }; } }; };
28110
+ VireoNode.prototype.getClientRects = function() { return [this.getBoundingClientRect()]; };
28111
+ VireoNode.prototype.scrollIntoView = function() {};
28112
+ VireoNode.prototype.select = function() { this.selectionStart = 0; this.selectionEnd = this.value.length; };
28113
+ VireoNode.prototype.setSelectionRange = function(start, end) { this.selectionStart = start; this.selectionEnd = end; };
28114
+ VireoNode.prototype.submit = function() { this.dispatchEvent(new Event('submit', { bubbles: true })); };
28115
+ VireoNode.prototype.requestSubmit = function() { this.submit(); };
28116
+ const make = (data, parent = null, path = []) => {
28117
+ const node = data.type === 'element' ? new VireoElement(data, parent) : new VireoNode(data, parent);
28118
+ node.__vireoPath = path;
28119
+ node.childNodes = (data.children || []).map((child, index) => make(child, node, [...path, index]));
28120
+ if (data.contentDocument) node.__pendingContentDocument = data.contentDocument;
28121
+ return node;
28122
+ };
28123
+ const root = make(snapshot.root, null, []);
28124
+ function descendants(node) { return node.childNodes.flatMap(child => [child, ...descendants(child)]); }
28125
+ function matches(node, selector) {
28126
+ if (node.nodeType !== 1) return false;
28127
+ const part = selector.trim();
28128
+ const attr = /\\[([\\w:-]+)(?:=["']?([^\\]"']+)["']?)?\\]/.exec(part);
28129
+ const id = /#([\\w-]+)/.exec(part); const classes = [...part.matchAll(/\\.([\\w-]+)/g)].map(m => m[1]);
28130
+ const tag = /^([a-z][\\w-]*|\\*)/i.exec(part)?.[1];
28131
+ return (!tag || tag === '*' || node.localName === tag.toLowerCase())
28132
+ && (!id || node.id === id[1])
28133
+ && classes.every(name => node.className.split(/\\s+/).includes(name))
28134
+ && (!attr || (node.hasAttribute(attr[1]) && (attr[2] === undefined || node.getAttribute(attr[1]) === attr[2])));
28135
+ }
28136
+ function query(node, selector) {
28137
+ const groups = selector.split(',').map(value => value.trim()).filter(Boolean); const out = [];
28138
+ for (const group of groups) {
28139
+ let scope = [node];
28140
+ for (const part of group.split(/\\s+/)) scope = scope.flatMap(parent => descendants(parent).filter(child => matches(child, part)));
28141
+ for (const match of scope) if (!out.includes(match)) out.push(match);
28142
+ }
28143
+ return out;
28144
+ }
28145
+ function serialize(node) {
28146
+ if (node.nodeType === 3) return escapeText(node.textContent);
28147
+ if (node.nodeType === 9) return node.childNodes.map(serialize).join('');
28148
+ const attrs = Object.entries(node.__data.attrs || {}).map(([k,v]) => ' ' + k + '="' + escapeAttr(v) + '"').join('');
28149
+ return '<' + node.localName + attrs + '>' + node.childNodes.map(serialize).join('') + '</' + node.localName + '>';
28150
+ }
28151
+ const document = root;
28152
+ document.URL = snapshot.url; document.documentURI = snapshot.url; document.readyState = 'complete';
28153
+ document.title = snapshot.title;
28154
+ document.documentElement = document.querySelector('html'); document.head = document.querySelector('head'); document.body = document.querySelector('body');
28155
+ document.getElementById = id => document.querySelector('#' + id);
28156
+ document.createElement = name => make({ type:'element', name:String(name).toLowerCase(), attrs:{}, children:[] });
28157
+ document.createTextNode = text => make({ type:'text', text:String(text) });
28158
+ document.activeElement = document.body;
28159
+ document.hasFocus = () => true;
28160
+ document.elementFromPoint = (_x, y) => descendants(document).filter(node => node.nodeType === 1).find(node => { const rect = node.getBoundingClientRect(); return y >= rect.top && y <= rect.bottom; }) || document.body;
28161
+ document.__nodeByPath = path => path.reduce((node, index) => node?.childNodes[index], document);
28162
+ const listeners = new Map();
28163
+ globalThis.addEventListener = (type, listener) => { const set = listeners.get(type) || new Set(); set.add(listener); listeners.set(type, set); };
28164
+ globalThis.removeEventListener = (type, listener) => listeners.get(type)?.delete(listener);
28165
+ globalThis.dispatchEvent = event => { for (const listener of listeners.get(event.type) || []) listener.call(globalThis, event); return true; };
28166
+ const observers = new Set();
28167
+ const notify = (target, type) => queueMicrotask(() => { for (const observer of observers) observer.callback([{ target, type }], observer); });
28168
+ class MutationObserver { constructor(callback) { this.callback = callback; } observe() { observers.add(this); } disconnect() { observers.delete(this); } takeRecords() { return []; } }
28169
+ class Event { constructor(type, init = {}) { this.type = type; Object.assign(this, init); } }
28170
+ class CustomEvent extends Event { constructor(type, init = {}) { super(type, init); this.detail = init.detail; } }
28171
+ class MouseEvent extends Event {}
28172
+ class KeyboardEvent extends Event {}
28173
+ const requestAnimationFrame = callback => setTimeout(() => callback(Date.now()), 0);
28174
+ const cancelAnimationFrame = id => clearTimeout(id);
28175
+ const getComputedStyle = element => ({ display: element.hasAttribute?.('hidden') ? 'none' : 'block', visibility: 'visible', opacity: '1', pointerEvents: 'auto', getPropertyValue() { return ''; } });
28176
+ Object.assign(globalThis, { window: globalThis, self: globalThis, document, Node: VireoNode, Element: VireoElement, HTMLElement: VireoElement, HTMLInputElement: VireoElement, HTMLTextAreaElement: VireoElement, HTMLSelectElement: VireoElement, HTMLButtonElement: VireoElement, HTMLFormElement: VireoElement, Event, CustomEvent, MouseEvent, KeyboardEvent, MutationObserver, requestAnimationFrame, cancelAnimationFrame, getComputedStyle, innerWidth: 1280, innerHeight: 720, scrollX: 0, scrollY: 0, location: new URL(snapshot.url), navigator: { userAgent: ${JSON.stringify(VIRTUAL_USER_AGENT)} } });
28177
+ document.defaultView = globalThis;
28178
+ for (const frame of document.querySelectorAll('iframe')) if (frame.__pendingContentDocument) frame.__contentDocument = buildNestedDocument(frame.__pendingContentDocument);
28179
+ function buildNestedDocument(childSnapshot) {
28180
+ const child = make(childSnapshot.root); child.URL = childSnapshot.url; child.title = childSnapshot.title; child.readyState = 'complete';
28181
+ child.documentElement = child.querySelector('html'); child.head = child.querySelector('head'); child.body = child.querySelector('body'); child.defaultView = { document: child, frameElement: null, location: new URL(childSnapshot.url) }; return child;
28182
+ }
28183
+ })()`;
28184
+ }
27973
28185
  var DEFERRED = /* @__PURE__ */ Symbol("reply already sent");
27974
28186
 
27975
- // src/browser/chrome-command.ts
27976
- var USAGE = "chrome --remote-debugging-pipe [chromium flags\u2026]";
27977
- async function run2(ctx) {
27978
- if (ctx.args.includes("--version")) {
27979
- ctx.line(`Chromium ${VIRTUAL_CHROMIUM_VERSION} (SandboxedJs virtual browser)`);
27980
- return 0;
27981
- }
27982
- if (!ctx.args.includes("--remote-debugging-pipe")) {
27983
- return ctx.fail(
27984
- "only --remote-debugging-pipe is supported: this is the SandboxedJs virtual browser, driven through the DevTools protocol (Playwright, Puppeteer), not an interactive Chromium"
27985
- );
27986
- }
27987
- const input = ctx.proc.fds.get(3);
27988
- const output = ctx.proc.fds.get(4);
27989
- if (!input || !output) {
27990
- return ctx.fail("--remote-debugging-pipe needs descriptors 3 and 4 open as pipes (stdio: ['ignore','pipe','pipe','pipe','pipe'])");
27991
- }
27992
- let closed = false;
27993
- const server = new CdpServer({
27994
- send: (message) => {
27995
- if (output.closed) return;
27996
- output.write(`${JSON.stringify(message)}\0`);
27997
- },
27998
- onClose: () => {
27999
- closed = true;
28000
- input.close();
28187
+ // src/browser/search-command.ts
28188
+ var DEFAULT_SEARCH_ENDPOINT = "https://html.duckduckgo.com/html/?q=";
28189
+ var USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
28190
+ function decodeEntities(value) {
28191
+ const named = {
28192
+ amp: "&",
28193
+ apos: "'",
28194
+ gt: ">",
28195
+ hellip: "\u2026",
28196
+ lt: "<",
28197
+ nbsp: " ",
28198
+ quot: '"'
28199
+ };
28200
+ return value.replace(/&(#x[\da-f]+|#\d+|[a-z][\da-z]+);/gi, (whole, entity) => {
28201
+ if (entity[0] === "#") {
28202
+ const hex = entity[1]?.toLowerCase() === "x";
28203
+ const code = Number.parseInt(entity.slice(hex ? 2 : 1), hex ? 16 : 10);
28204
+ return Number.isFinite(code) ? String.fromCodePoint(code) : whole;
28001
28205
  }
28206
+ return named[entity.toLowerCase()] ?? whole;
28002
28207
  });
28003
- ctx.stderr.write(`
28004
- DevTools listening on pipe (SandboxedJs virtual browser ${VIRTUAL_CHROMIUM_VERSION})
28005
- `);
28006
- const decoder9 = new TextDecoder();
28007
- let pending = "";
28008
- const aborted = new Promise((resolve3) => ctx.signal.addEventListener("abort", () => resolve3(null), { once: true }));
28208
+ }
28209
+ function plainText(html) {
28210
+ return decodeEntities(html.replace(/<[^>]*>/g, " ")).replace(/\s+/g, " ").trim();
28211
+ }
28212
+ function attribute(tag2, name) {
28213
+ const match2 = new RegExp(`\\b${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s>]+))`, "i").exec(tag2);
28214
+ return match2 ? decodeEntities(match2[1] ?? match2[2] ?? match2[3] ?? "") : void 0;
28215
+ }
28216
+ function absoluteUrl(raw, base2) {
28009
28217
  try {
28010
- while (!closed) {
28011
- const chunk = await Promise.race([input.read(), aborted]);
28012
- if (chunk === null) break;
28013
- pending += decoder9.decode(chunk, { stream: true });
28014
- let end;
28015
- while ((end = pending.indexOf("\0")) >= 0) {
28016
- const frame = pending.slice(0, end);
28017
- pending = pending.slice(end + 1);
28018
- if (!frame) continue;
28019
- let message;
28020
- try {
28021
- message = JSON.parse(frame);
28022
- } catch {
28023
- ctx.warn(`dropping malformed DevTools message: ${frame.slice(0, 80)}`);
28024
- continue;
28025
- }
28026
- void server.dispatch(message);
28027
- }
28028
- }
28029
- } finally {
28030
- server.dispose();
28031
- output.end();
28218
+ const url = new URL(raw, base2);
28219
+ if (!/^https?:$/.test(url.protocol)) return void 0;
28220
+ return url.toString();
28221
+ } catch {
28222
+ return void 0;
28032
28223
  }
28033
- return 0;
28034
28224
  }
28035
- function browserCommands() {
28036
- return [
28037
- defineCommand({
28038
- name: "chrome",
28039
- aliases: ["chromium", "chromium-browser", "google-chrome", "chrome-headless-shell"],
28040
- summary: "SandboxedJs virtual browser, driven over the DevTools protocol",
28041
- usage: USAGE,
28042
- run: run2
28043
- })
28044
- ];
28225
+ function resultUrl(raw, base2) {
28226
+ const resolved = absoluteUrl(raw, base2);
28227
+ if (!resolved) return void 0;
28228
+ const url = new URL(resolved);
28229
+ const redirected = url.searchParams.get("uddg");
28230
+ return redirected ? absoluteUrl(redirected, base2) : resolved;
28045
28231
  }
28046
-
28047
- // src/apps/pm.ts
28048
- init_binary();
28049
- init_zip();
28232
+ function parseSearchResults(html, base2 = "https://html.duckduckgo.com/") {
28233
+ const results = [];
28234
+ const anchors = /<a\b[^>]*class\s*=\s*["'][^"']*\bresult__a\b[^"']*["'][^>]*>[\s\S]*?<\/a>/gi;
28235
+ for (const match2 of html.matchAll(anchors)) {
28236
+ const tag2 = /^<a\b[^>]*>/i.exec(match2[0])?.[0] ?? "";
28237
+ const url = resultUrl(attribute(tag2, "href") ?? "", base2);
28238
+ if (!url) continue;
28239
+ const title = plainText(match2[0]);
28240
+ const tail2 = html.slice((match2.index ?? 0) + match2[0].length, (match2.index ?? 0) + match2[0].length + 4e3);
28241
+ const snippetMatch = /<(?:a|div)\b[^>]*class\s*=\s*["'][^"']*\bresult__snippet\b[^"']*["'][^>]*>([\s\S]*?)<\/(?:a|div)>/i.exec(tail2);
28242
+ results.push({ title, url, snippet: snippetMatch ? plainText(snippetMatch[1]) : "" });
28243
+ }
28244
+ return results;
28245
+ }
28246
+ function extractPage(html, url, status = 200) {
28247
+ const titleMatch = /<title\b[^>]*>([\s\S]*?)<\/title>/i.exec(html);
28248
+ const links = [];
28249
+ for (const match2 of html.matchAll(/<a\b[^>]*>[\s\S]*?<\/a>/gi)) {
28250
+ const tag2 = /^<a\b[^>]*>/i.exec(match2[0])?.[0] ?? "";
28251
+ const href = absoluteUrl(attribute(tag2, "href") ?? "", url);
28252
+ const text2 = plainText(match2[0]);
28253
+ if (href && text2 && !links.some((link) => link.url === href)) links.push({ text: text2, url: href });
28254
+ if (links.length >= 50) break;
28255
+ }
28256
+ const visible2 = html.replace(/<!--([\s\S]*?)-->/g, " ").replace(/<head\b[^>]*>[\s\S]*?<\/head>/gi, " ").replace(/<title\b[^>]*>[\s\S]*?<\/title>/gi, " ").replace(/<(script|style|noscript|svg|template)\b[^>]*>[\s\S]*?<\/\1>/gi, " ").replace(/<(br|hr)\b[^>]*>|<\/(p|div|article|section|main|header|footer|li|h[1-6])>/gi, "\n");
28257
+ return {
28258
+ type: "page",
28259
+ url,
28260
+ status,
28261
+ title: titleMatch ? plainText(titleMatch[1]) : "",
28262
+ text: decodeEntities(visible2.replace(/<[^>]*>/g, " ")).replace(/[ \t\f\v]+/g, " ").replace(/ *\n */g, "\n").replace(/\n{3,}/g, "\n\n").trim(),
28263
+ links
28264
+ };
28265
+ }
28266
+ function targetUrl(raw) {
28267
+ try {
28268
+ if (/^https?:\/\//i.test(raw)) return new URL(raw);
28269
+ if (/^(localhost|127\.0\.0\.1|\[::1\])(?::\d+)?(?:\/|$)/i.test(raw)) return new URL(`http://${raw}`);
28270
+ if (/^[\w.-]+\.[a-z]{2,}(?::\d+)?(?:\/|$)/i.test(raw)) return new URL(`https://${raw}`);
28271
+ } catch {
28272
+ }
28273
+ return void 0;
28274
+ }
28275
+ async function get(ctx, url, redirects = 5) {
28276
+ let current2 = url;
28277
+ for (let n = 0; ; n++) {
28278
+ const result = await performRequest(ctx, current2, {
28279
+ method: "GET",
28280
+ headers: { accept: "text/html,application/xhtml+xml,text/plain;q=0.9,*/*;q=0.1", "user-agent": USER_AGENT }
28281
+ });
28282
+ const location2 = result.headers.location;
28283
+ if (result.status < 300 || result.status >= 400 || !location2) return result;
28284
+ if (n >= redirects) throw new Error("too many redirects");
28285
+ current2 = new URL(location2, current2);
28286
+ }
28287
+ }
28288
+ function truncate(text2, max) {
28289
+ return text2.length <= max ? text2 : `${text2.slice(0, Math.max(0, max - 1)).trimEnd()}\u2026`;
28290
+ }
28291
+ var search = defineCommand({
28292
+ name: "search",
28293
+ path: "/usr/bin/search",
28294
+ summary: "search the web or read a URL headlessly",
28295
+ usage: "search [--json] [-n count] [--max-chars count] <query or URL>",
28296
+ manual: "Searches DuckDuckGo's HTML endpoint for a query, or fetches and extracts readable text from an HTTP(S) URL. Outbound access must be enabled. This text browser does not execute page JavaScript.",
28297
+ async run(ctx) {
28298
+ const args = parseArgs(ctx.args, [
28299
+ { long: "json" },
28300
+ { short: "n", long: "count", arg: true, default: "5" },
28301
+ { long: "max-chars", arg: true, default: "12000" }
28302
+ ]);
28303
+ const raw = args.positional.join(" ").trim();
28304
+ if (!raw) return ctx.fail("missing query or URL", 2);
28305
+ const count = Math.max(1, Math.min(20, args.num("count", 5) ?? 5));
28306
+ const maxChars = Math.max(200, Math.min(1e5, args.num("max-chars", 12e3) ?? 12e3));
28307
+ try {
28308
+ const direct = targetUrl(raw);
28309
+ if (direct) {
28310
+ const response2 = await get(ctx, direct);
28311
+ const contentType = response2.headers["content-type"] ?? "";
28312
+ const decoded = new TextDecoder().decode(response2.body);
28313
+ const page = /html|xhtml/i.test(contentType) || /^\s*</.test(decoded) ? extractPage(decoded, response2.url, response2.status) : { type: "page", url: response2.url, status: response2.status, title: "", text: decoded, links: [] };
28314
+ page.text = truncate(page.text, maxChars);
28315
+ if (args.has("json")) ctx.line(JSON.stringify(page, null, 2));
28316
+ else {
28317
+ ctx.line(`# ${page.title || page.url}`);
28318
+ ctx.line(`URL: ${page.url}`);
28319
+ ctx.line(`Status: ${page.status}`);
28320
+ ctx.line();
28321
+ ctx.line(page.text);
28322
+ }
28323
+ return response2.status >= 400 ? 22 : 0;
28324
+ }
28325
+ const endpoint = ctx.env.SEARCH_ENDPOINT || DEFAULT_SEARCH_ENDPOINT;
28326
+ const response = await get(ctx, new URL(`${endpoint}${encodeURIComponent(raw)}`));
28327
+ const results = parseSearchResults(new TextDecoder().decode(response.body), response.url).slice(0, count);
28328
+ const output = { type: "search", query: raw, results };
28329
+ if (args.has("json")) ctx.line(JSON.stringify(output, null, 2));
28330
+ else if (!results.length) ctx.line("No search results found.");
28331
+ else results.forEach((result, index) => {
28332
+ ctx.line(`${index + 1}. ${result.title}`);
28333
+ ctx.line(` ${result.url}`);
28334
+ if (result.snippet) ctx.line(` ${result.snippet}`);
28335
+ });
28336
+ return response.status >= 400 ? 22 : 0;
28337
+ } catch (error) {
28338
+ return ctx.fail(error instanceof Error ? error.message : String(error), 1);
28339
+ }
28340
+ }
28341
+ });
28050
28342
 
28051
28343
  // src/apps/registry.ts
28052
28344
  var APPS_ROOT = "/opt";
@@ -28143,8 +28435,242 @@ function validateManifest2(manifest, source) {
28143
28435
  throw new AppRegistryError(`${source}: a service needs an integer port`);
28144
28436
  }
28145
28437
  }
28438
+ if (app.browserEngine) {
28439
+ if (app.browserEngine.abi !== "sandboxedjs-browser-engine-v1") {
28440
+ throw new AppRegistryError(`${source}: unsupported browser engine ABI ${JSON.stringify(app.browserEngine.abi)}`);
28441
+ }
28442
+ if (typeof app.browserEngine.wasm !== "string" || !safeRelativePath(app.browserEngine.wasm)) {
28443
+ throw new AppRegistryError(`${source}: browserEngine.wasm must be a safe package-relative path`);
28444
+ }
28445
+ if (typeof app.browserEngine.product !== "string" || !app.browserEngine.product) {
28446
+ throw new AppRegistryError(`${source}: browserEngine.product is required`);
28447
+ }
28448
+ }
28146
28449
  return app;
28147
28450
  }
28451
+ function safeRelativePath(path) {
28452
+ return path !== "" && !path.startsWith("/") && !path.split("/").some((part) => part === "" || part === "." || part === "..");
28453
+ }
28454
+
28455
+ // src/browser/vireo.ts
28456
+ var VIREO_APP = "vireo";
28457
+ var VireoEngine = class _VireoEngine {
28458
+ constructor(product, wasm) {
28459
+ this.product = product;
28460
+ this.wasm = wasm;
28461
+ }
28462
+ product;
28463
+ wasm;
28464
+ static async load(ctx) {
28465
+ const app = installedVireo(ctx);
28466
+ if (!app?.browserEngine) return null;
28467
+ const manifest = app.browserEngine;
28468
+ const bytes2 = ctx.vfs.readFile(`${app.root}/${manifest.wasm}`, ctx.cred);
28469
+ const loaded = await WebAssembly.instantiate(bytes2, {});
28470
+ const instance = loaded instanceof WebAssembly.Instance ? loaded : loaded.instance;
28471
+ const wasm = instance.exports;
28472
+ for (const name of ["memory", "vireo_alloc", "vireo_load_html", "vireo_snapshot_pointer", "vireo_snapshot_length", "vireo_free_document"]) {
28473
+ if (!(name in wasm)) throw new Error(`Vireo's ${manifest.abi} module does not export ${name}`);
28474
+ }
28475
+ return new _VireoEngine(manifest.product, wasm);
28476
+ }
28477
+ parse(html, url) {
28478
+ const urlBytes = new TextEncoder().encode(url);
28479
+ const htmlPointer = this.copy(html);
28480
+ const urlPointer = this.copy(urlBytes);
28481
+ const handle = this.wasm.vireo_load_html(htmlPointer, html.length, urlPointer, urlBytes.length);
28482
+ if (!handle) throw new Error("Vireo could not parse the document");
28483
+ try {
28484
+ const pointer = this.wasm.vireo_snapshot_pointer(handle);
28485
+ const length = this.wasm.vireo_snapshot_length(handle);
28486
+ if (!pointer || !length) throw new Error("Vireo returned an empty document snapshot");
28487
+ const json = new TextDecoder().decode(new Uint8Array(this.wasm.memory.buffer, pointer, length).slice());
28488
+ return JSON.parse(json);
28489
+ } finally {
28490
+ this.wasm.vireo_free_document(handle);
28491
+ }
28492
+ }
28493
+ copy(bytes2) {
28494
+ if (!bytes2.length) return 0;
28495
+ const pointer = this.wasm.vireo_alloc(bytes2.length);
28496
+ if (!pointer) throw new Error("Vireo ran out of memory");
28497
+ new Uint8Array(this.wasm.memory.buffer, pointer, bytes2.length).set(bytes2);
28498
+ return pointer;
28499
+ }
28500
+ };
28501
+ function installedVireo(ctx) {
28502
+ try {
28503
+ const state = JSON.parse(ctx.vfs.readText(APP_STATE, ctx.cred));
28504
+ return state.apps?.find((app) => app.name === VIREO_APP);
28505
+ } catch {
28506
+ return void 0;
28507
+ }
28508
+ }
28509
+ async function ensureVireo(ctx) {
28510
+ const present = await VireoEngine.load(ctx);
28511
+ if (present) return present;
28512
+ if (ctx.env.SBX_VIREO_AUTOINSTALL === "0") return null;
28513
+ const result = await ctx.kernel.run(["pm", "install", VIREO_APP], {
28514
+ cwd: ctx.cwd,
28515
+ env: ctx.env,
28516
+ cred: ctx.cred,
28517
+ ppid: ctx.proc.pid,
28518
+ timeoutMs: 12e4
28519
+ });
28520
+ if (result.exitCode !== 0) {
28521
+ ctx.warn(`Vireo is not installed and automatic installation failed: ${(result.stderr || result.stdout).trim()}`);
28522
+ return null;
28523
+ }
28524
+ return VireoEngine.load(ctx);
28525
+ }
28526
+
28527
+ // src/browser/chrome-command.ts
28528
+ var USAGE = "chrome --remote-debugging-pipe [chromium flags\u2026]";
28529
+ async function run2(ctx) {
28530
+ if (ctx.args.includes("--version")) {
28531
+ ctx.line(`Chromium ${VIRTUAL_CHROMIUM_VERSION} (SandboxedJs virtual browser)`);
28532
+ return 0;
28533
+ }
28534
+ if (!ctx.args.includes("--remote-debugging-pipe")) {
28535
+ return ctx.fail(
28536
+ "only --remote-debugging-pipe is supported: this is the SandboxedJs virtual browser, driven through the DevTools protocol (Playwright, Puppeteer), not an interactive Chromium"
28537
+ );
28538
+ }
28539
+ const input = ctx.proc.fds.get(3);
28540
+ const output = ctx.proc.fds.get(4);
28541
+ if (!input || !output) {
28542
+ return ctx.fail("--remote-debugging-pipe needs descriptors 3 and 4 open as pipes (stdio: ['ignore','pipe','pipe','pipe','pipe'])");
28543
+ }
28544
+ const vireo = await ensureVireo(ctx);
28545
+ let closed = false;
28546
+ const server = new CdpServer({
28547
+ send: (message) => {
28548
+ if (output.closed) return;
28549
+ output.write(`${JSON.stringify(message)}\0`);
28550
+ },
28551
+ onClose: () => {
28552
+ closed = true;
28553
+ input.close();
28554
+ },
28555
+ ...vireo ? {
28556
+ navigate: (rawUrl) => loadDocument(ctx, vireo, rawUrl)
28557
+ } : {}
28558
+ });
28559
+ ctx.stderr.write(`
28560
+ DevTools listening on pipe (${vireo?.product ?? `SandboxedJs virtual browser ${VIRTUAL_CHROMIUM_VERSION}`})
28561
+ `);
28562
+ const decoder9 = new TextDecoder();
28563
+ let pending = "";
28564
+ const aborted = new Promise((resolve3) => ctx.signal.addEventListener("abort", () => resolve3(null), { once: true }));
28565
+ try {
28566
+ while (!closed) {
28567
+ const chunk = await Promise.race([input.read(), aborted]);
28568
+ if (chunk === null) break;
28569
+ pending += decoder9.decode(chunk, { stream: true });
28570
+ let end;
28571
+ while ((end = pending.indexOf("\0")) >= 0) {
28572
+ const frame = pending.slice(0, end);
28573
+ pending = pending.slice(end + 1);
28574
+ if (!frame) continue;
28575
+ let message;
28576
+ try {
28577
+ message = JSON.parse(frame);
28578
+ } catch {
28579
+ ctx.warn(`dropping malformed DevTools message: ${frame.slice(0, 80)}`);
28580
+ continue;
28581
+ }
28582
+ void server.dispatch(message);
28583
+ }
28584
+ }
28585
+ } finally {
28586
+ server.dispose();
28587
+ output.end();
28588
+ }
28589
+ return 0;
28590
+ }
28591
+ async function requestResource(ctx, rawUrl, accept) {
28592
+ let url = new URL(rawUrl);
28593
+ let response;
28594
+ for (let redirects = 0; ; redirects += 1) {
28595
+ response = await performRequest(ctx, url, {
28596
+ method: "GET",
28597
+ headers: { accept, "user-agent": "Mozilla/5.0 (X11; Linux x86_64) Vireo/0.2" }
28598
+ });
28599
+ const location2 = response.headers.location;
28600
+ if (response.status < 300 || response.status >= 400 || !location2) break;
28601
+ if (redirects >= 5) throw new Error("net::ERR_TOO_MANY_REDIRECTS");
28602
+ url = new URL(location2, url);
28603
+ }
28604
+ if (response.status >= 400) throw new Error(`HTTP ${response.status} ${response.statusText}`);
28605
+ return { response, url: response.url || url.toString() };
28606
+ }
28607
+ async function loadDocument(ctx, engine, rawUrl, depth = 0) {
28608
+ if (rawUrl.startsWith("data:")) {
28609
+ const comma = rawUrl.indexOf(",");
28610
+ if (comma < 0) throw new Error("net::ERR_INVALID_URL");
28611
+ const metadata = rawUrl.slice(5, comma);
28612
+ const raw = rawUrl.slice(comma + 1);
28613
+ const text2 = /;base64(?:;|$)/i.test(metadata) ? new TextDecoder().decode(Uint8Array.from(atob(raw), (character) => character.charCodeAt(0))) : decodeURIComponent(raw);
28614
+ const document3 = engine.parse(new TextEncoder().encode(text2), rawUrl);
28615
+ await loadSubresources(ctx, engine, document3.root, rawUrl, depth);
28616
+ return { url: rawUrl, document: document3 };
28617
+ }
28618
+ const loaded = await requestResource(ctx, rawUrl, "text/html,application/xhtml+xml");
28619
+ const document2 = engine.parse(loaded.response.body, loaded.url);
28620
+ await loadSubresources(ctx, engine, document2.root, loaded.url, depth);
28621
+ return { url: loaded.url, document: document2 };
28622
+ }
28623
+ async function loadSubresources(ctx, engine, node2, baseUrl, depth) {
28624
+ const tasks = [];
28625
+ if (node2.type === "element" && node2.name === "script" && node2.attrs?.src) {
28626
+ tasks.push((async () => {
28627
+ try {
28628
+ const resource = await requestResource(ctx, new URL(node2.attrs.src, baseUrl).toString(), "text/javascript,application/javascript,*/*;q=0.1");
28629
+ node2.resourceText = new TextDecoder().decode(resource.response.body);
28630
+ node2.attrs.src = resource.url;
28631
+ } catch {
28632
+ node2.resourceText = "";
28633
+ }
28634
+ })());
28635
+ }
28636
+ if (node2.type === "element" && node2.name === "link" && /stylesheet/i.test(node2.attrs?.rel ?? "") && node2.attrs?.href) {
28637
+ tasks.push((async () => {
28638
+ try {
28639
+ const resource = await requestResource(ctx, new URL(node2.attrs.href, baseUrl).toString(), "text/css,*/*;q=0.1");
28640
+ node2.resourceText = new TextDecoder().decode(resource.response.body);
28641
+ node2.attrs.href = resource.url;
28642
+ } catch {
28643
+ node2.resourceText = "";
28644
+ }
28645
+ })());
28646
+ }
28647
+ if (depth < 3 && node2.type === "element" && node2.name === "iframe" && node2.attrs?.src) {
28648
+ tasks.push((async () => {
28649
+ try {
28650
+ node2.contentDocument = (await loadDocument(ctx, engine, new URL(node2.attrs.src, baseUrl).toString(), depth + 1)).document;
28651
+ } catch {
28652
+ }
28653
+ })());
28654
+ }
28655
+ for (const child of node2.children ?? []) tasks.push(loadSubresources(ctx, engine, child, baseUrl, depth));
28656
+ await Promise.all(tasks);
28657
+ }
28658
+ function browserCommands() {
28659
+ return [
28660
+ defineCommand({
28661
+ name: "chrome",
28662
+ aliases: ["chromium", "chromium-browser", "google-chrome", "chrome-headless-shell"],
28663
+ summary: "SandboxedJs virtual browser, driven over the DevTools protocol",
28664
+ usage: USAGE,
28665
+ run: run2
28666
+ }),
28667
+ search
28668
+ ];
28669
+ }
28670
+
28671
+ // src/apps/pm.ts
28672
+ init_binary();
28673
+ init_zip();
28148
28674
 
28149
28675
  // src/apps/sbjs.ts
28150
28676
  init_binary();
@@ -28332,7 +28858,7 @@ since. It does not say the program is safe to run.`,
28332
28858
  case "info":
28333
28859
  return await info(ctx, rest);
28334
28860
  case "search":
28335
- return await search(ctx, rest);
28861
+ return await search2(ctx, rest);
28336
28862
  case "available":
28337
28863
  return await available(ctx);
28338
28864
  case "trust":
@@ -28682,7 +29208,7 @@ async function info(ctx, args) {
28682
29208
  }
28683
29209
  return 0;
28684
29210
  }
28685
- async function search(ctx, args) {
29211
+ async function search2(ctx, args) {
28686
29212
  const term = (args[0] ?? "").toLowerCase();
28687
29213
  const index = await fetchIndex(ctx);
28688
29214
  const matches3 = index.apps.filter(
@@ -30233,9 +30759,9 @@ var vmModule = {
30233
30759
  measureMemory: async () => ({ total: { jsMemoryEstimate: 0, jsMemoryRange: [0, 0] } })
30234
30760
  };
30235
30761
  var vm_module_default = vmModule;
30236
- function define(proto, name, get) {
30762
+ function define(proto, name, get2) {
30237
30763
  if (Object.getOwnPropertyDescriptor(proto, name)) return;
30238
- Object.defineProperty(proto, name, { configurable: true, enumerable: false, get });
30764
+ Object.defineProperty(proto, name, { configurable: true, enumerable: false, get: get2 });
30239
30765
  }
30240
30766
  var installed = false;
30241
30767
  function installWebStreamAdapters(stream) {
@@ -32142,7 +32668,7 @@ function createHttpModule(router, owner, options = {}, defaultProtocol = "http:"
32142
32668
  if (callback) req.on("response", callback);
32143
32669
  return req;
32144
32670
  };
32145
- const get = (input, second, third) => {
32671
+ const get2 = (input, second, third) => {
32146
32672
  const req = request(input, second, third);
32147
32673
  req.end();
32148
32674
  return req;
@@ -32150,7 +32676,7 @@ function createHttpModule(router, owner, options = {}, defaultProtocol = "http:"
32150
32676
  return {
32151
32677
  createServer,
32152
32678
  request,
32153
- get,
32679
+ get: get2,
32154
32680
  Server: VirtualHttpServer,
32155
32681
  ServerResponse: VirtualServerResponse,
32156
32682
  IncomingMessage: VirtualIncomingMessage,
@@ -39413,7 +39939,7 @@ var str = (s) => {
39413
39939
  var section = (id, data) => [id, ...leb(data.length), ...data];
39414
39940
  function compileInstruction({ op, next }) {
39415
39941
  const c = [];
39416
- const get = (r) => c.push(35, r);
39942
+ const get2 = (r) => c.push(35, r);
39417
39943
  const constant = (n) => c.push(66, ...signed(BigInt.asIntN(64, n)));
39418
39944
  if (op.kind === "jump") {
39419
39945
  c.push(65, ...signed(BigInt.asIntN(32, BigInt(op.target))));
@@ -39425,13 +39951,13 @@ function compileInstruction({ op, next }) {
39425
39951
  } else {
39426
39952
  if ("dst" in op) {
39427
39953
  if (op.kind !== "mov") {
39428
- get(op.dst);
39954
+ get2(op.dst);
39429
39955
  if (!op.wide) {
39430
39956
  constant(0xffffffffn);
39431
39957
  c.push(131);
39432
39958
  }
39433
39959
  }
39434
- if (op.src !== void 0) get(op.src);
39960
+ if (op.src !== void 0) get2(op.src);
39435
39961
  else constant(op.imm);
39436
39962
  if (!op.wide) {
39437
39963
  constant(0xffffffffn);
@@ -39446,7 +39972,7 @@ function compileInstruction({ op, next }) {
39446
39972
  else {
39447
39973
  c.push(36, op.dst);
39448
39974
  if (op.kind !== "mov") {
39449
- get(op.dst);
39975
+ get2(op.dst);
39450
39976
  c.push(80, 36, 16);
39451
39977
  }
39452
39978
  }
@@ -39495,7 +40021,7 @@ async function execute2(ctx, source, translated, budget) {
39495
40021
  const image = { ...source, memory: source.memory.slice() };
39496
40022
  const globals = Array.from({ length: 17 }, (_, i) => new WebAssembly.Global({ value: i === 16 ? "i32" : "i64", mutable: true }, i === 16 ? 0 : 0n));
39497
40023
  const registers = Object.fromEntries(globals.map((g, i) => [String(i), g]));
39498
- const get = (r) => globals[r].value;
40024
+ const get2 = (r) => globals[r].value;
39499
40025
  const set = (r, n) => {
39500
40026
  globals[r].value = u64(n);
39501
40027
  };
@@ -39527,15 +40053,15 @@ async function execute2(ctx, source, translated, budget) {
39527
40053
  if (!op.condition || (op.condition === "zero" ? globals[16].value !== 0 : globals[16].value === 0)) pc = op.target;
39528
40054
  } else if ("dst" in op) {
39529
40055
  const width = op.wide ? 64 : 32;
39530
- const a = BigInt.asUintN(width, get(op.dst));
39531
- const b = BigInt.asUintN(width, op.src !== void 0 ? get(op.src) : op.imm);
40056
+ const a = BigInt.asUintN(width, get2(op.dst));
40057
+ const b = BigInt.asUintN(width, op.src !== void 0 ? get2(op.src) : op.imm);
39532
40058
  const value = BigInt.asUintN(width, op.kind === "mov" ? b : op.kind === "xor" ? a ^ b : op.kind === "add" ? a + b : a - b);
39533
40059
  if (op.kind !== "mov") globals[16].value = Number(value === 0n);
39534
40060
  if (op.kind !== "cmp") set(op.dst, value);
39535
40061
  }
39536
40062
  }
39537
40063
  if (op.kind === "syscall") {
39538
- const number = get(0), fd = get(7), address = get(6), length = get(2);
40064
+ const number = get2(0), fd = get2(7), address = get2(6), length = get2(2);
39539
40065
  set(1, BigInt(next));
39540
40066
  set(11, 2n | (globals[16].value ? 64n : 0n));
39541
40067
  if (number === 60n || number === 231n) return Number(fd & 255n);