@gjsify/iframe 0.10.0 → 0.12.0
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/lib/esm/console-capture.js +24 -0
- package/lib/esm/dom-queries.js +1 -0
- package/lib/esm/eval.js +1 -0
- package/lib/esm/iframe-bridge.js +1 -1
- package/lib/esm/message-bridge.js +5 -5
- package/lib/esm/promisify.js +1 -0
- package/lib/types/console-capture.d.ts +34 -0
- package/lib/types/console-capture.spec.d.ts +2 -0
- package/lib/types/dom-queries.d.ts +36 -0
- package/lib/types/dom-queries.spec.d.ts +2 -0
- package/lib/types/eval.d.ts +30 -0
- package/lib/types/eval.spec.d.ts +2 -0
- package/lib/types/iframe-bridge.d.ts +618 -55
- package/lib/types/message-bridge.d.ts +27 -1
- package/lib/types/promisify.d.ts +1 -0
- package/lib/types/types/index.d.ts +24 -0
- package/package.json +6 -6
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";const e=[`log`,`warn`,`error`,`info`,`debug`];function buildConsoleCaptureScript(t){return`(function(){
|
|
2
|
+
var handler = window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers[${JSON.stringify(t)}];
|
|
3
|
+
if (!handler) return;
|
|
4
|
+
if (window.__gjsifyConsoleHook) return;
|
|
5
|
+
window.__gjsifyConsoleHook = true;
|
|
6
|
+
function stringify(a){
|
|
7
|
+
if (typeof a === 'string') return a;
|
|
8
|
+
if (a instanceof Error) return (a.name || 'Error') + ': ' + (a.message || '');
|
|
9
|
+
try { return JSON.stringify(a); }
|
|
10
|
+
catch (_e) { try { return String(a); } catch (_e2) { return '[unserializable]'; } }
|
|
11
|
+
}
|
|
12
|
+
var levels = ${JSON.stringify(e)};
|
|
13
|
+
for (var i = 0; i < levels.length; i++) {
|
|
14
|
+
(function(level){
|
|
15
|
+
var orig = (console[level] && console[level].bind) ? console[level].bind(console) : function(){};
|
|
16
|
+
console[level] = function(){
|
|
17
|
+
var args = Array.prototype.slice.call(arguments);
|
|
18
|
+
try { handler.postMessage(JSON.stringify({ __gjsifyConsole: level, args: args.map(stringify) })); }
|
|
19
|
+
catch (_e) {}
|
|
20
|
+
return orig.apply(console, arguments);
|
|
21
|
+
};
|
|
22
|
+
})(levels[i]);
|
|
23
|
+
}
|
|
24
|
+
})();`}function parseConsoleEnvelope(e){if(typeof e!=`object`||!e)return null;let t=e.__gjsifyConsole;if(typeof t!=`string`)return null;let n=e.args;return{level:t,args:Array.isArray(n)?n.map(e=>typeof e==`string`?e:String(e)):[]}}var ConsoleBuffer=class{constructor(e=1e3){this._max=e,this._entries=[]}push(e){this._entries.push(e),this._entries.length>this._max&&this._entries.splice(0,this._entries.length-this._max)}list(){return this._entries.slice()}clear(){this._entries=[]}};export{ConsoleBuffer,buildConsoleCaptureScript,parseConsoleEnvelope};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";function buildGetLinksExpression(){return`Array.prototype.slice.call(document.querySelectorAll('a[href]')).map(function(a){return {href:a.href,text:(a.textContent||'').trim(),title:a.getAttribute('title')||''};})`}function buildQueryDomExpression(e,t=200){return`Array.prototype.slice.call(document.querySelectorAll(${JSON.stringify(e)})).slice(0,${Math.max(0,Math.floor(t))}).map(function(el){var r=el.getBoundingClientRect();return {tagName:el.tagName,id:el.id||"",className:(typeof el.className==="string"?el.className:""),text:(el.textContent||"").trim().slice(0,200),href:(el.getAttribute&&el.getAttribute("href"))||undefined,visible:!!(r.width||r.height)};})`}function buildClickElementExpression(e){return`(function(){var t=${JSON.stringify(e)};var el=null;try{el=document.querySelector(t);}catch(_e){el=null;}if(!el){var links=Array.prototype.slice.call(document.querySelectorAll("a"));for(var i=0;i<links.length;i++){if((links[i].textContent||"").trim()===t){el=links[i];break;}}}if(!el)return false;el.click();return true;})()`}export{buildClickElementExpression,buildGetLinksExpression,buildQueryDomExpression};
|
package/lib/esm/eval.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";function buildEvalScript(e){return`(function(){try{var __v=(`+e+`);if(__v===undefined)return JSON.stringify({__gjsifyEval:'undefined'});return JSON.stringify({__gjsifyEval:'ok',value:__v});}catch(__e){return JSON.stringify({__gjsifyEval:'error',message:String((__e&&__e.message)||__e)});}})()`}function parseEvalResult(e){if(e==null)return;let t;try{t=JSON.parse(e)}catch{return}if(typeof t!=`object`||!t)return;let n=t.__gjsifyEval;if(n===`error`){let e=t.message,n=Error(typeof e==`string`?e:`evaluateJavaScript failed`);throw n.name=`EvalError`,n}if(n!==`undefined`&&n===`ok`)return t.value}export{buildEvalScript,parseEvalResult};
|
package/lib/esm/iframe-bridge.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{buildClickElementExpression as e,buildGetLinksExpression as t,buildQueryDomExpression as n}from"./dom-queries.js";import{buildEvalScript as r,parseEvalResult as i}from"./eval.js";import{iframeWidget as a,windowProxy as o}from"./property-symbol.js";import{HTMLIFrameElement as s}from"./html-iframe-element.js";import{IFrameWindowProxy as c}from"./iframe-window-proxy.js";import"./promisify.js";import{MessageBridge as l}from"./message-bridge.js";import{notifyElementResize as u}from"@gjsify/dom-elements";import d from"gi://GLib?version=2.0";import f from"gi://GObject";import p from"gi://WebKit?version=6.0";const m=f.registerClass({GTypeName:`GjsifyIFrameBridge`},class IFrameBridge extends p.WebView{constructor(e){let{enableDeveloperExtras:t,enableJavascript:n,captureConsole:r,...i}=e??{},u=new p.UserContentManager,d=new p.Settings;d.enable_javascript=n??!0,d.enable_developer_extras=t??!0,super({...i,user_content_manager:u,settings:d}),this._readyCallbacks=[],this._navigationWaiters=[],this._lastLoadError=null,this._loadErrorCallbacks=[],this._options={enableDeveloperExtras:t,enableJavascript:n,captureConsole:r},this._iframe=new s,this._iframe[a]=this,this._messageBridge=new l(this,{captureConsole:r});let f=new c(this._messageBridge);this._iframe[o]=f,this._messageBridge.setWindowProxy(f),this.connect(`load-changed`,(e,t)=>{switch(t){case p.LoadEvent.STARTED:this._lastLoadError=null;break;case p.LoadEvent.COMMITTED:{let e=this.get_uri();e&&this._messageBridge.updateUri(e);break}case p.LoadEvent.FINISHED:this._iframe._onLoad();for(let e of this._readyCallbacks)e(this._iframe);this._readyCallbacks=[],this._settleNavigationWaiters(null);break}}),this.connect(`load-failed`,(e,t,n,r)=>{let i={uri:n,message:r?.message??`load failed`};this._lastLoadError=i;for(let e of this._loadErrorCallbacks)e(i);return this._iframe._onError(),this._settleNavigationWaiters(Error(`load failed for ${n}: ${i.message}`)),!1}),this.connect(`unrealize`,()=>{this._messageBridge.destroy();let e=this._iframe[o];e&&e._close(),this._iframe[a]=null,this._iframe[o]=null})}vfunc_size_allocate(e,t,n){super.vfunc_size_allocate(e,t,n),u(this._iframe,e,t)}get iframeElement(){return this._iframe}onReady(e){this._readyCallbacks.push(e)}loadUri(e){this._iframe.setAttribute(`src`,e),this.load_uri(e)}loadHtml(e,t){this._iframe.setAttribute(`srcdoc`,e),this.load_html(e,t??`about:srcdoc`)}postMessage(e,t=`*`){this._messageBridge.sendToWebView(e,t)}goBack(){this.go_back()}goForward(){this.go_forward()}get canGoBack(){return this.can_go_back()}get canGoForward(){return this.can_go_forward()}get currentUri(){return this.get_uri()??`about:blank`}get pageTitle(){return this.get_title()??``}get lastLoadError(){return this._lastLoadError}onLoadError(e){this._loadErrorCallbacks.push(e)}async evaluateJavaScript(e){return i((await this.evaluate_javascript(r(e),-1,null,null,null))?.to_string()??null)}async takeScreenshot(e=`full`){let t=e===`visible`?p.SnapshotRegion.VISIBLE:p.SnapshotRegion.FULL_DOCUMENT,n=(await this.get_snapshot(t,p.SnapshotOptions.NONE,null)).save_to_png_bytes().get_data();return n?new Uint8Array(n):new Uint8Array}waitForNavigation(e=3e4){return new Promise((t,n)=>{let r={resolve:t,reject:n,sourceId:null};e>0&&(r.sourceId=d.timeout_add(d.PRIORITY_DEFAULT,e,()=>{let t=this._navigationWaiters.indexOf(r);return t!==-1&&this._navigationWaiters.splice(t,1),r.sourceId=null,n(Error(`waitForNavigation: timed out after ${e}ms`)),d.SOURCE_REMOVE})),this._navigationWaiters.push(r)})}_settleNavigationWaiters(e){if(this._navigationWaiters.length===0)return;let t=this._navigationWaiters;this._navigationWaiters=[];for(let n of t)n.sourceId!==null&&(d.source_remove(n.sourceId),n.sourceId=null),e?n.reject(e):n.resolve()}getViewportSize(){return{width:this.get_allocated_width(),height:this.get_allocated_height()}}setViewportSize(e,t){this.set_size_request(e,t)}getConsoleLogs(){return this._messageBridge.getConsoleLogs()}clearConsoleLogs(){this._messageBridge.clearConsoleLogs()}onConsole(e){this._messageBridge.onConsole(e)}async getLinks(){let e=await this.evaluateJavaScript(t());return Array.isArray(e)?e:[]}async queryDom(e,t=200){let r=await this.evaluateJavaScript(n(e,t));return Array.isArray(r)?r:[]}async clickElement(t){return await this.evaluateJavaScript(e(t))===!0}installGlobals(){Object.defineProperty(globalThis,`HTMLIFrameElement`,{value:s,writable:!0,configurable:!0})}});export{m as IFrameBridge};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{
|
|
2
|
-
var handler = window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers['${
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{ConsoleBuffer as e,buildConsoleCaptureScript as t,parseConsoleEnvelope as n}from"./console-capture.js";import"./promisify.js";import{BridgePortTransport as r}from"./iframe-message-channel.js";import{BINARY_SERIALIZER_INJECTED_SRC as i,decodeBinariesFromJson as a,encodeBinariesForJson as o}from"./serialize.js";import{MessageEvent as s}from"@gjsify/dom-events";import c from"gi://WebKit?version=6.0";const l=`gjsify-iframe`,u=`https://gjsify.local`;function normaliseTargetOrigin(e){if(e===`*`)return`*`;if(e===`/`)return null;try{return new URL(e).origin}catch{let t=Error(`Invalid target origin '${e}'`);throw t.name=`SyntaxError`,t}}const BOOTSTRAP_SCRIPT_FOR_TEST=()=>d,d=`(function() {
|
|
2
|
+
var handler = window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers['${l}'];
|
|
3
3
|
if (!handler) return;
|
|
4
4
|
|
|
5
5
|
// Idempotency guard: WebKit auto-injects this script at INJECTION_TIME.START
|
|
@@ -11,9 +11,9 @@ import"./_virtual/_rolldown/runtime.js";import{BridgePortTransport as e}from"./i
|
|
|
11
11
|
// __gjsifyBridge.origPostMessage would loop forever.
|
|
12
12
|
if (window.__gjsifyBridge && window.__gjsifyBridge.__bridgeVersion === 1) return;
|
|
13
13
|
|
|
14
|
-
var GJS_HOST_ORIGIN = '${
|
|
14
|
+
var GJS_HOST_ORIGIN = '${u}';
|
|
15
15
|
|
|
16
|
-
${
|
|
16
|
+
${i}
|
|
17
17
|
|
|
18
18
|
// Per-WebView registry of proxy ports created during GJS → WebView
|
|
19
19
|
// postMessage. Keyed by the GJS-allocated portId. Each entry has a
|
|
@@ -133,4 +133,4 @@ import"./_virtual/_rolldown/runtime.js";import{BridgePortTransport as e}from"./i
|
|
|
133
133
|
postMessage: bridgePostMessage,
|
|
134
134
|
origPostMessage: origPostMessage,
|
|
135
135
|
};
|
|
136
|
-
})();`;var MessageBridge=class{_getTransport(){return this._transport===null&&(this._transport=new
|
|
136
|
+
})();`;var MessageBridge=class{_getTransport(){return this._transport===null&&(this._transport=new r(this)),this._transport}constructor(t,n){this._windowProxy=null,this._currentUri=`about:blank`,this._signalId=null,this._ports=new Map,this._nextPortId=1,this._transport=null,this._consoleBuffer=new e,this._consoleCallbacks=[],this._webView=t,this._captureConsole=n?.captureConsole??!1,this._userContentManager=t.get_user_content_manager(),this._setupReceiver(),this._injectBootstrapScript(),this._captureConsole&&this._injectConsoleCaptureScript()}getConsoleLogs(){return this._consoleBuffer.list()}clearConsoleLogs(){this._consoleBuffer.clear()}onConsole(e){this._consoleCallbacks.push(e)}_recordConsole(e){this._consoleBuffer.push(e);for(let t of this._consoleCallbacks)t(e)}setWindowProxy(e){this._windowProxy=e}updateUri(e){this._currentUri=e}getLocation(){let e;try{e=new URL(this._currentUri).origin}catch{e=`null`}return{href:this._currentUri,origin:e}}_registerTransferredPort(e){if(e._transferred)throw Error(`MessagePort: already transferred`);let t=e._partner;if(!t)throw Error(`MessagePort: partner missing — port already transferred or closed`);let n=this._nextPortId++;return e._transferred=!0,e._partner=null,t._partner=null,t._transport=this._getTransport(),t._portId=n,this._ports.set(n,t),n}_sendPortMessage(e,t){let n=o(t),r=JSON.stringify(n),a=`(function(){${i}var p = window.__gjsifyPortRegistry && window.__gjsifyPortRegistry[${e}]; if (p) p.deliver(__decodeBin(JSON.parse(${JSON.stringify(r)})));})();`;this._webView.evaluate_javascript(a,-1,null,null,null).catch(()=>{})}_closePort(e){this._ports.delete(e);let t=`(function(){ if (window.__gjsifyPortRegistry) delete window.__gjsifyPortRegistry[${e}]; })();`;this._webView.evaluate_javascript(t,-1,null,null,null).catch(()=>{})}sendToWebView(e,t,n){let r=normaliseTargetOrigin(t);if(r!==`*`){let e=this.getLocation().origin;if((r??`https://gjsify.local`)!==e)return}let a=e;if(n&&n.length>0){let t=new Map;for(let e of n){let n=this._registerTransferredPort(e);t.set(e,n)}a=substitutePorts(e,t)}let s=o(a),c=JSON.stringify(s),l=JSON.stringify(u),d=`(function(){${i}var d = __decodeBin(JSON.parse(${JSON.stringify(c)})); if (window.__gjsifySubstitutePorts) d = window.__gjsifySubstitutePorts(d); window.dispatchEvent(new MessageEvent('message', { data: d, origin: ${l} }));})();`;this._webView.evaluate_javascript(d,-1,null,null,null).catch(()=>{})}destroy(){this._signalId!==null&&(this._userContentManager.disconnect(this._signalId),this._signalId=null),this._userContentManager.unregister_script_message_handler(l,null),this._windowProxy=null}_setupReceiver(){this._userContentManager.register_script_message_handler(l,null),this._signalId=this._userContentManager.connect(`script-message-received::${l}`,(e,t)=>{try{let e=t.to_string(),r=JSON.parse(e),i=n(r);if(i){this._recordConsole(i);return}if(typeof r.__gjsifyPortMessage==`number`){let e=r,t=this._ports.get(e.__gjsifyPortMessage);t&&t._receive(a(e.payload));return}if(typeof r.__gjsifyPortClose==`number`){let e=r,t=this._ports.get(e.__gjsifyPortClose);t&&t.close(),this._ports.delete(e.__gjsifyPortClose);return}if(!this._windowProxy)return;let o=r,c=o.targetOrigin;if(c!==`*`&&c!==`https://gjsify.local`)return;let l=new s(`message`,{data:a(o.data),origin:o.origin});this._windowProxy.dispatchEvent(l)}catch(e){console.error(`[IFrame MessageBridge] Error processing message:`,e)}})}_injectBootstrapScript(){let e=new c.UserScript(d,c.UserContentInjectedFrames.ALL_FRAMES,c.UserScriptInjectionTime.START,null,null);this._userContentManager.add_script(e)}_injectConsoleCaptureScript(){let e=new c.UserScript(t(l),c.UserContentInjectedFrames.ALL_FRAMES,c.UserScriptInjectionTime.START,null,null);this._userContentManager.add_script(e)}};function substitutePorts(e,t){let n=new WeakMap;function walk(e){if(typeof e!=`object`||!e)return e;if(e[Symbol.toStringTag]===`MessagePort`&&t.has(e))return{__gjsifyPort:t.get(e)};if(n.has(e))return n.get(e);if(Array.isArray(e)){let t=[];n.set(e,t);for(let n=0;n<e.length;n++)t[n]=walk(e[n]);return t}if(Object.prototype.toString.call(e).slice(8,-1)===`Object`){let t={};n.set(e,t);for(let n of Object.keys(e))t[n]=walk(e[n]);return t}return e}return walk(e)}export{BOOTSTRAP_SCRIPT_FOR_TEST,u as GJS_HOST_ORIGIN,MessageBridge,normaliseTargetOrigin};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"gi://WebKit?version=6.0";import t from"gi://Gio?version=2.0";t._promisify(e.WebView.prototype,`evaluate_javascript`,`evaluate_javascript_finish`),t._promisify(e.WebView.prototype,`get_snapshot`,`get_snapshot_finish`);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ConsoleLogEntry } from './types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Build the self-contained in-page UserScript that mirrors `console.*` to the
|
|
4
|
+
* host via `window.webkit.messageHandlers[channelName]`.
|
|
5
|
+
*
|
|
6
|
+
* Self-contained (acquires its own handler reference, own idempotency guard) so
|
|
7
|
+
* it can be injected as a separate UserScript independent of the postMessage
|
|
8
|
+
* bootstrap — it is opt-in (`captureConsole`), so it must not be entangled with
|
|
9
|
+
* the always-injected bridge script. ES5 to match the bootstrap's style.
|
|
10
|
+
*
|
|
11
|
+
* Each forwarded entry is `{__gjsifyConsole: level, args: string[]}` — args are
|
|
12
|
+
* stringified in-page (objects via JSON, Errors as `name: message`) so the host
|
|
13
|
+
* never has to traverse a live JS graph across the bridge.
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildConsoleCaptureScript(channelName: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Parse a received envelope into a {@link ConsoleLogEntry}, or null when it is
|
|
18
|
+
* not a console envelope. Defensive — a tampered page must not crash the host:
|
|
19
|
+
* non-string args are coerced to strings, a missing args array becomes empty.
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseConsoleEnvelope(envelope: unknown): ConsoleLogEntry | null;
|
|
22
|
+
/**
|
|
23
|
+
* Bounded ring buffer of console entries. Keeps at most `max` (oldest dropped),
|
|
24
|
+
* so a chatty page can't grow host memory without bound.
|
|
25
|
+
*/
|
|
26
|
+
export declare class ConsoleBuffer {
|
|
27
|
+
private readonly _max;
|
|
28
|
+
private _entries;
|
|
29
|
+
constructor(_max?: number);
|
|
30
|
+
push(entry: ConsoleLogEntry): void;
|
|
31
|
+
/** A copy of the buffered entries (oldest first). */
|
|
32
|
+
list(): ConsoleLogEntry[];
|
|
33
|
+
clear(): void;
|
|
34
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** A link harvested by {@link buildGetLinksExpression}. */
|
|
2
|
+
export interface LinkInfo {
|
|
3
|
+
/** Resolved absolute href. */
|
|
4
|
+
href: string;
|
|
5
|
+
/** Trimmed visible text. */
|
|
6
|
+
text: string;
|
|
7
|
+
/** `title` attribute (empty when absent). */
|
|
8
|
+
title: string;
|
|
9
|
+
}
|
|
10
|
+
/** Element metadata returned by {@link buildQueryDomExpression}. */
|
|
11
|
+
export interface ElementInfo {
|
|
12
|
+
tagName: string;
|
|
13
|
+
id: string;
|
|
14
|
+
className: string;
|
|
15
|
+
/** Trimmed text content, capped to keep payloads small. */
|
|
16
|
+
text: string;
|
|
17
|
+
/** `href` attribute when present. */
|
|
18
|
+
href?: string;
|
|
19
|
+
/** True when the element has a non-zero bounding box. */
|
|
20
|
+
visible: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** Expression: every `<a href>` on the page as {@link LinkInfo}[]. */
|
|
23
|
+
export declare function buildGetLinksExpression(): string;
|
|
24
|
+
/**
|
|
25
|
+
* Expression: `querySelectorAll(selector)` mapped to {@link ElementInfo}[],
|
|
26
|
+
* capped at `limit` to bound the payload.
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildQueryDomExpression(selector: string, limit?: number): string;
|
|
29
|
+
/**
|
|
30
|
+
* Expression (returns boolean): click the first element matching `selectorOrText`
|
|
31
|
+
* — tried first as a CSS selector, then as exact trimmed `<a>` link text. Returns
|
|
32
|
+
* false when nothing matches. An invalid selector is caught and falls through to
|
|
33
|
+
* the text match. The caller awaits navigation separately (register
|
|
34
|
+
* `waitForNavigation()` before invoking, since a fast nav could finish first).
|
|
35
|
+
*/
|
|
36
|
+
export declare function buildClickElementExpression(selectorOrText: string): string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** JSON envelope the in-page wrapper returns. */
|
|
2
|
+
export type EvalResult = {
|
|
3
|
+
__gjsifyEval: 'ok';
|
|
4
|
+
value: unknown;
|
|
5
|
+
} | {
|
|
6
|
+
__gjsifyEval: 'undefined';
|
|
7
|
+
} | {
|
|
8
|
+
__gjsifyEval: 'error';
|
|
9
|
+
message: string;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Wrap a user expression so its value comes back as a JSON string.
|
|
13
|
+
*
|
|
14
|
+
* The wrapper always evaluates to a JSON string of one {@link EvalResult}
|
|
15
|
+
* shape — `ok` with the JSON-serialised value, `undefined` when the value is
|
|
16
|
+
* `undefined`, or `error` with the thrown message. A value that is not
|
|
17
|
+
* JSON-serialisable (function, circular object) collapses to `undefined`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildEvalScript(expression: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Parse the JSON string returned by {@link buildEvalScript} (read off the
|
|
22
|
+
* JSCValue via `to_string()`).
|
|
23
|
+
*
|
|
24
|
+
* - `ok` → the deserialised value.
|
|
25
|
+
* - `undefined` → `undefined`.
|
|
26
|
+
* - `error` → throws an `Error` (name `EvalError`) carrying the page message.
|
|
27
|
+
* - malformed / `null` / non-envelope JSON → `undefined` (defensive — a
|
|
28
|
+
* tampered page or a non-wrapper result must not crash the host).
|
|
29
|
+
*/
|
|
30
|
+
export declare function parseEvalResult(json: string | null | undefined): unknown;
|