@wenathlan/extension 1.1.42 → 1.1.43
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/README.md +5 -4
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +771 -9
- package/dist/index.js.map +4 -4
- package/dist/memory.d.ts +42 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/netwatch.d.ts +92 -0
- package/dist/netwatch.d.ts.map +1 -0
- package/dist/policy.d.ts +15 -0
- package/dist/policy.d.ts.map +1 -1
- package/dist/protocol.d.ts +23 -3
- package/dist/protocol.d.ts.map +1 -1
- package/dist/socketbus.d.ts +134 -0
- package/dist/socketbus.d.ts.map +1 -0
- package/dist/types.d.ts +183 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/extension/dist/background.js +3173 -1974
- package/extension/dist/background.js.map +4 -4
- package/extension/dist/manifest.json +1 -1
- package/extension/dist/pagebridge.js +20 -4
- package/extension/dist/pagebridge.js.map +2 -2
- package/extension/dist/popup.html +1 -1
- package/extension/dist/popup.js +11 -3
- package/extension/dist/popup.js.map +2 -2
- package/extension/dist/sidepanel.html +1 -1
- package/extension/dist/sidepanel.js +134 -3
- package/extension/dist/sidepanel.js.map +2 -2
- package/extension/manifest.json +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1672,6 +1672,87 @@ var sessionmemory = class {
|
|
|
1672
1672
|
async getsecret(storageid) {
|
|
1673
1673
|
return this.adapter.get(storageid);
|
|
1674
1674
|
}
|
|
1675
|
+
/** Stores one channel record of a socket or event stream, replacing the previous record of that id. */
|
|
1676
|
+
async addchannel(record2) {
|
|
1677
|
+
const records = (await this.adapter.get("channels") ?? []).filter((item) => item.id !== record2.id);
|
|
1678
|
+
await this.adapter.set("channels", [record2, ...records]);
|
|
1679
|
+
}
|
|
1680
|
+
/** Returns every stored channel record, newest first. */
|
|
1681
|
+
async getchannels() {
|
|
1682
|
+
return await this.adapter.get("channels") ?? [];
|
|
1683
|
+
}
|
|
1684
|
+
/** Returns one channel record by its id. */
|
|
1685
|
+
async getchannel(id) {
|
|
1686
|
+
return (await this.getchannels()).find((item) => item.id === id);
|
|
1687
|
+
}
|
|
1688
|
+
/** Queues one message envelope of a channel stream, keeping the arrival order for the waitmessage matchers. */
|
|
1689
|
+
async addmessage(envelope) {
|
|
1690
|
+
const records = (await this.adapter.get("messages") ?? []).filter((item) => !(item.channelid === envelope.channelid && item.sequence === envelope.sequence));
|
|
1691
|
+
await this.adapter.set("messages", [...records, envelope]);
|
|
1692
|
+
}
|
|
1693
|
+
/** Returns every queued message envelope, oldest first, optionally filtered by channel and stream. */
|
|
1694
|
+
async getmessages(channelid, stream) {
|
|
1695
|
+
const records = await this.adapter.get("messages") ?? [];
|
|
1696
|
+
return records.filter((item) => (channelid === void 0 || item.channelid === channelid) && (stream === void 0 || item.stream === stream));
|
|
1697
|
+
}
|
|
1698
|
+
/** Drops the matched message envelopes of one channel from the queue once a waitmessage step consumed them. */
|
|
1699
|
+
async drainmessages(sequences) {
|
|
1700
|
+
const records = await this.adapter.get("messages") ?? [];
|
|
1701
|
+
const kept = records.filter((item) => !sequences.some((match) => match.channelid === item.channelid && match.sequence === item.sequence));
|
|
1702
|
+
await this.adapter.set("messages", kept);
|
|
1703
|
+
}
|
|
1704
|
+
/** Stores one observed exchange record, replacing the previous record of that id. */
|
|
1705
|
+
async addexchange(record2) {
|
|
1706
|
+
const records = (await this.adapter.get("exchanges") ?? []).filter((item) => item.id !== record2.id);
|
|
1707
|
+
await this.adapter.set("exchanges", [record2, ...records]);
|
|
1708
|
+
}
|
|
1709
|
+
/** Returns every stored exchange record, newest first. */
|
|
1710
|
+
async getexchanges() {
|
|
1711
|
+
return await this.adapter.get("exchanges") ?? [];
|
|
1712
|
+
}
|
|
1713
|
+
/** Returns one exchange record by its id. */
|
|
1714
|
+
async getexchange(id) {
|
|
1715
|
+
return (await this.getexchanges()).find((item) => item.id === id);
|
|
1716
|
+
}
|
|
1717
|
+
/** Returns the exchange records filtered by run, origin and status; the status filter accepts one code or the failed class of every exchange with an error class. */
|
|
1718
|
+
async listexchanges(filter) {
|
|
1719
|
+
const records = await this.getexchanges();
|
|
1720
|
+
return records.filter((item) => (filter.runid === void 0 || item.runid === filter.runid) && (filter.origin === void 0 || item.origin === filter.origin) && (filter.status === void 0 || (filter.status === "failed" ? item.errorclass !== void 0 : item.status === filter.status)));
|
|
1721
|
+
}
|
|
1722
|
+
/** Stores one captured response body with its mime type and byte size; the user configured body retention window expires the oldest bodies while the exchange metadata always survives. */
|
|
1723
|
+
async addbody(record2) {
|
|
1724
|
+
const records = await this.getbodies();
|
|
1725
|
+
const retention = (await this.getsettings())?.bodyretention;
|
|
1726
|
+
const combined = [record2, ...records.filter((item) => item.ref !== record2.ref)];
|
|
1727
|
+
const stored = retention === void 0 ? combined : combined.map((item, index) => index < retention ? item : expirebodybytes(item));
|
|
1728
|
+
await this.adapter.set("bodies", stored);
|
|
1729
|
+
}
|
|
1730
|
+
/** Returns every captured body record, newest first. */
|
|
1731
|
+
async getbodies() {
|
|
1732
|
+
return await this.adapter.get("bodies") ?? [];
|
|
1733
|
+
}
|
|
1734
|
+
/** Returns one captured body record with its stored text by its reference. */
|
|
1735
|
+
async getbody(ref) {
|
|
1736
|
+
return (await this.getbodies()).find((item) => item.ref === ref);
|
|
1737
|
+
}
|
|
1738
|
+
/** Stores the page api map of one origin, replacing the previous map of that origin. */
|
|
1739
|
+
async setapimap(origin, entries) {
|
|
1740
|
+
const records = (await this.adapter.get("apimap") ?? []).filter((item) => item.origin !== origin);
|
|
1741
|
+
await this.adapter.set("apimap", [...entries, ...records]);
|
|
1742
|
+
}
|
|
1743
|
+
/** Returns every stored page api map entry, newest first. */
|
|
1744
|
+
async getapimap() {
|
|
1745
|
+
return await this.adapter.get("apimap") ?? [];
|
|
1746
|
+
}
|
|
1747
|
+
/** Stores one event stream subscription record, replacing the previous record of that id. */
|
|
1748
|
+
async setsubscription(record2) {
|
|
1749
|
+
const records = (await this.adapter.get("subscriptions") ?? []).filter((item) => item.id !== record2.id);
|
|
1750
|
+
await this.adapter.set("subscriptions", [record2, ...records]);
|
|
1751
|
+
}
|
|
1752
|
+
/** Returns every stored event stream subscription, newest first. */
|
|
1753
|
+
async getsubscriptions() {
|
|
1754
|
+
return await this.adapter.get("subscriptions") ?? [];
|
|
1755
|
+
}
|
|
1675
1756
|
};
|
|
1676
1757
|
function mediakindof(record2) {
|
|
1677
1758
|
if ("pages" in record2) return "pdf";
|
|
@@ -1706,14 +1787,423 @@ function expirecallbody(record2) {
|
|
|
1706
1787
|
void body;
|
|
1707
1788
|
return { ...metadata, bodyexpired: true };
|
|
1708
1789
|
}
|
|
1790
|
+
function expirebodybytes(record2) {
|
|
1791
|
+
const { body, ...metadata } = record2;
|
|
1792
|
+
void body;
|
|
1793
|
+
return { ...metadata, bodyexpired: true };
|
|
1794
|
+
}
|
|
1709
1795
|
function randomid() {
|
|
1710
1796
|
return crypto.randomUUID();
|
|
1711
1797
|
}
|
|
1712
1798
|
|
|
1799
|
+
// netwatch.ts
|
|
1800
|
+
var netwatchkinds = ["watchrequests", "readheaders", "capturebodies", "mapapi", "extractapi"];
|
|
1801
|
+
function resourcefacts(entries) {
|
|
1802
|
+
const facts = [];
|
|
1803
|
+
for (const entry of entries) {
|
|
1804
|
+
const url = typeof entry.name === "string" ? entry.name : "";
|
|
1805
|
+
if (!url) continue;
|
|
1806
|
+
const entrytype = typeof entry.entryType === "string" ? entry.entryType : "resource";
|
|
1807
|
+
if (entrytype !== "resource" && entrytype !== "navigation") continue;
|
|
1808
|
+
facts.push({
|
|
1809
|
+
url,
|
|
1810
|
+
initiator: typeof entry.initiatorType === "string" ? entry.initiatorType : "",
|
|
1811
|
+
entrytype,
|
|
1812
|
+
start: typeof entry.startTime === "number" && Number.isFinite(entry.startTime) ? entry.startTime : 0,
|
|
1813
|
+
duration: typeof entry.duration === "number" && Number.isFinite(entry.duration) ? entry.duration : 0,
|
|
1814
|
+
transfer: typeof entry.transferSize === "number" && Number.isFinite(entry.transferSize) ? entry.transferSize : 0,
|
|
1815
|
+
protocol: typeof entry.nextHopProtocol === "string" ? entry.nextHopProtocol : "",
|
|
1816
|
+
...typeof entry.responseStatus === "number" && Number.isInteger(entry.responseStatus) ? { status: entry.responseStatus } : {},
|
|
1817
|
+
...entry.failed === true ? { failed: true } : {}
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
return facts;
|
|
1821
|
+
}
|
|
1822
|
+
function failureclass(fact) {
|
|
1823
|
+
if (fact.status !== void 0 && fact.status >= 400) return { errorclass: "httperror", status: fact.status };
|
|
1824
|
+
if (fact.failed === true) return { errorclass: "networkerror", status: 0 };
|
|
1825
|
+
if ((fact.initiator === "fetch" || fact.initiator === "xmlhttprequest") && fact.duration > 0 && fact.transfer === 0 && fact.protocol === "") return { errorclass: "networkerror", status: 0 };
|
|
1826
|
+
return { status: fact.status ?? 0 };
|
|
1827
|
+
}
|
|
1828
|
+
function correlationid(runid, index) {
|
|
1829
|
+
return `${runid}-${index + 1}`;
|
|
1830
|
+
}
|
|
1831
|
+
function newexchange(input) {
|
|
1832
|
+
const verdict = failureclass(input.fact);
|
|
1833
|
+
let origin = "";
|
|
1834
|
+
try {
|
|
1835
|
+
origin = new URL(input.fact.url).origin;
|
|
1836
|
+
} catch {
|
|
1837
|
+
origin = "";
|
|
1838
|
+
}
|
|
1839
|
+
const method = input.fact.initiator === "fetch" || input.fact.initiator === "xmlhttprequest" ? "?" : "GET";
|
|
1840
|
+
const statusclass = verdict.status >= 100 && verdict.status < 600 ? verdict.status >= 200 && verdict.status < 300 ? "success" : verdict.status >= 300 && verdict.status < 400 ? "redirect" : verdict.status >= 400 && verdict.status < 500 ? "clienterror" : verdict.status >= 500 ? "servererror" : "informational" : "unknown";
|
|
1841
|
+
return { id: input.id, runid: input.runid, stepid: input.stepid, correlationid: input.correlationid, url: input.fact.url, origin, method, status: verdict.status, statusclass, ...verdict.errorclass !== void 0 ? { errorclass: verdict.errorclass } : {}, source: "page", ...input.fact.initiator ? { initiator: input.fact.initiator } : {}, timing: Math.round(input.fact.duration), bytes: input.fact.transfer, at: input.at };
|
|
1842
|
+
}
|
|
1843
|
+
function pairexchange(exchange, response) {
|
|
1844
|
+
if (exchange.correlationid !== response.correlationid) throw new Error(`The response ${response.correlationid} does not pair with the exchange ${exchange.correlationid}.`);
|
|
1845
|
+
return { ...exchange, status: response.status, statusclass: response.status >= 200 && response.status < 300 ? "success" : response.status >= 400 && response.status < 500 ? "clienterror" : response.status >= 500 ? "servererror" : response.status >= 300 && response.status < 400 ? "redirect" : "unknown", bytes: response.bytes, ...response.mime !== void 0 ? { mime: response.mime } : {}, ...response.bodyref !== void 0 ? { bodyref: response.bodyref } : {}, ...Object.keys(response.headers).length > 0 ? { responseheaders: response.headers } : {} };
|
|
1846
|
+
}
|
|
1847
|
+
function filterexchanges(exchanges, filter) {
|
|
1848
|
+
return exchanges.filter((exchange) => (filter.runid === void 0 || exchange.runid === filter.runid) && (filter.origin === void 0 || exchange.origin === filter.origin) && (filter.status === void 0 || (filter.status === "failed" ? exchange.errorclass !== void 0 : exchange.status === filter.status)));
|
|
1849
|
+
}
|
|
1850
|
+
function headerfilterof(value) {
|
|
1851
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return { allow: [], redact: [] };
|
|
1852
|
+
const entry = value;
|
|
1853
|
+
const names = (source) => Array.isArray(source) ? source.filter((name) => typeof name === "string" && name.trim().length > 0).map((name) => name.trim().toLowerCase()) : [];
|
|
1854
|
+
return { allow: names(entry.allow), redact: names(entry.redact) };
|
|
1855
|
+
}
|
|
1856
|
+
function capturedheaders(headers, filter) {
|
|
1857
|
+
const result = {};
|
|
1858
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
1859
|
+
const key = name.trim().toLowerCase();
|
|
1860
|
+
if (filter.allow.length > 0 && !filter.allow.includes(key)) continue;
|
|
1861
|
+
result[key] = filter.redact.includes(key) ? "[redacted]" : value;
|
|
1862
|
+
}
|
|
1863
|
+
return result;
|
|
1864
|
+
}
|
|
1865
|
+
function bodyfilterof(value) {
|
|
1866
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
1867
|
+
const entry = value;
|
|
1868
|
+
const filter = {};
|
|
1869
|
+
if (typeof entry.urlpattern === "string" && entry.urlpattern.trim()) filter.urlpattern = entry.urlpattern.trim();
|
|
1870
|
+
if (Array.isArray(entry.mimes)) filter.mimes = entry.mimes.filter((mime) => typeof mime === "string" && mime.trim().length > 0).map((mime) => mime.trim().toLowerCase());
|
|
1871
|
+
if (typeof entry.ceiling === "number" && Number.isFinite(entry.ceiling) && entry.ceiling >= 0) filter.ceiling = entry.ceiling;
|
|
1872
|
+
return filter;
|
|
1873
|
+
}
|
|
1874
|
+
function bodymatches(filter, exchange) {
|
|
1875
|
+
if (filter.urlpattern !== void 0 && !exchange.url.includes(filter.urlpattern)) return false;
|
|
1876
|
+
if (filter.mimes !== void 0 && filter.mimes.length > 0) {
|
|
1877
|
+
const mime = ((exchange.mime ?? "").split(";")[0] ?? "").trim().toLowerCase();
|
|
1878
|
+
if (!filter.mimes.includes(mime)) return false;
|
|
1879
|
+
}
|
|
1880
|
+
return true;
|
|
1881
|
+
}
|
|
1882
|
+
var privatemimes = /* @__PURE__ */ new Set(["text/html", "text/plain", "text/xml", "application/xml", "application/json", "text/json", "application/x-www-form-urlencoded", "application/graphql", "multipart/form-data"]);
|
|
1883
|
+
function privatemime(mime) {
|
|
1884
|
+
return privatemimes.has((mime.split(";")[0] ?? "").trim().toLowerCase());
|
|
1885
|
+
}
|
|
1886
|
+
function capturebody(input) {
|
|
1887
|
+
if (!bodymatches(input.filter, input.exchange)) return { refused: `The exchange ${input.exchange.correlationid} does not match the reviewed body filter.` };
|
|
1888
|
+
const ceiling = input.filter.ceiling;
|
|
1889
|
+
const stored = ceiling !== void 0 && input.body.length > ceiling ? input.body.slice(0, ceiling) : input.body;
|
|
1890
|
+
return { record: { ref: input.ref, runid: input.runid, correlationid: input.exchange.correlationid, url: input.exchange.url, mime: input.mime, bytes: stored.length, body: stored, at: input.at }, truncated: stored.length < input.body.length };
|
|
1891
|
+
}
|
|
1892
|
+
function payloadshapeof(body) {
|
|
1893
|
+
if (body === void 0) return [];
|
|
1894
|
+
try {
|
|
1895
|
+
const parsed = JSON.parse(body);
|
|
1896
|
+
const shape = (value) => value && typeof value === "object" && !Array.isArray(value) ? Object.keys(value) : [];
|
|
1897
|
+
if (Array.isArray(parsed)) return parsed.length > 0 ? shape(parsed[0]) : [];
|
|
1898
|
+
return shape(parsed);
|
|
1899
|
+
} catch {
|
|
1900
|
+
return [];
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
function isapicandidate(exchange) {
|
|
1904
|
+
if (exchange.initiator === "fetch" || exchange.initiator === "xmlhttprequest") return true;
|
|
1905
|
+
if (exchange.bodyref !== void 0) return true;
|
|
1906
|
+
try {
|
|
1907
|
+
return /\/api\/|\/graphql|\.json($|\?)|\/v\d+\//i.test(new URL(exchange.url).pathname);
|
|
1908
|
+
} catch {
|
|
1909
|
+
return false;
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
function apientries(exchanges, bodies) {
|
|
1913
|
+
const bodybyref = new Map(bodies.map((body) => [body.correlationid, body]));
|
|
1914
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1915
|
+
for (const exchange of exchanges) {
|
|
1916
|
+
if (!isapicandidate(exchange)) continue;
|
|
1917
|
+
let endpoint = exchange.url;
|
|
1918
|
+
let origin = exchange.origin;
|
|
1919
|
+
try {
|
|
1920
|
+
const parsed = new URL(exchange.url);
|
|
1921
|
+
endpoint = `${parsed.origin}${parsed.pathname}`;
|
|
1922
|
+
origin = parsed.origin;
|
|
1923
|
+
} catch {
|
|
1924
|
+
}
|
|
1925
|
+
const key = `${exchange.method} ${endpoint}`;
|
|
1926
|
+
const group = groups.get(key) ?? { endpoint, method: exchange.method, origin, mimes: /* @__PURE__ */ new Map(), frequency: 0, json: 0, captured: 0, shapes: /* @__PURE__ */ new Map(), correlationids: [] };
|
|
1927
|
+
group.frequency += 1;
|
|
1928
|
+
group.correlationids.push(exchange.correlationid);
|
|
1929
|
+
const body = exchange.bodyref !== void 0 ? bodybyref.get(exchange.correlationid) : void 0;
|
|
1930
|
+
const mime = body?.mime ?? exchange.mime ?? "";
|
|
1931
|
+
group.mimes.set(mime, (group.mimes.get(mime) ?? 0) + 1);
|
|
1932
|
+
if (body !== void 0) {
|
|
1933
|
+
group.captured += 1;
|
|
1934
|
+
const shape = payloadshapeof(body.body);
|
|
1935
|
+
if (shape.length > 0) group.json += 1;
|
|
1936
|
+
const shapekey = shape.join(",");
|
|
1937
|
+
group.shapes.set(shapekey, (group.shapes.get(shapekey) ?? 0) + 1);
|
|
1938
|
+
}
|
|
1939
|
+
groups.set(key, group);
|
|
1940
|
+
}
|
|
1941
|
+
return [...groups.values()].map((group) => {
|
|
1942
|
+
const mime = [...group.mimes.entries()].sort((left, right) => right[1] - left[1])[0]?.[0] ?? "";
|
|
1943
|
+
const modalshape = [...group.shapes.entries()].sort((left, right) => right[1] - left[1])[0];
|
|
1944
|
+
return { endpoint: group.endpoint, method: group.method, mime, frequency: group.frequency, payloadshape: (modalshape?.[0] ?? "").split(",").filter(Boolean), jsonshare: group.captured > 0 ? group.json / group.captured : 0, stability: group.captured > 0 ? (modalshape?.[1] ?? 0) / group.captured : 0, origin: group.origin, correlationids: group.correlationids };
|
|
1945
|
+
});
|
|
1946
|
+
}
|
|
1947
|
+
function rankapis(entries) {
|
|
1948
|
+
const score = (entry) => entry.frequency * (1 + entry.jsonshare + entry.stability);
|
|
1949
|
+
return [...entries].sort((left, right) => score(right) - score(left) || right.frequency - left.frequency);
|
|
1950
|
+
}
|
|
1951
|
+
function apireplayspecof(value) {
|
|
1952
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1953
|
+
const entry = value;
|
|
1954
|
+
if (typeof entry.endpoint !== "string" || !entry.endpoint.trim()) return void 0;
|
|
1955
|
+
const spec = { endpoint: entry.endpoint.trim() };
|
|
1956
|
+
if (typeof entry.verb === "string" && entry.verb.trim()) spec.verb = entry.verb.trim().toUpperCase();
|
|
1957
|
+
if (entry.overrides !== void 0 && entry.overrides !== null && typeof entry.overrides === "object" && !Array.isArray(entry.overrides)) {
|
|
1958
|
+
const overrides = {};
|
|
1959
|
+
for (const [name, override] of Object.entries(entry.overrides)) {
|
|
1960
|
+
if (typeof override === "string") overrides[name] = override;
|
|
1961
|
+
}
|
|
1962
|
+
spec.overrides = overrides;
|
|
1963
|
+
}
|
|
1964
|
+
if (Array.isArray(entry.paths)) spec.paths = entry.paths.filter((path) => typeof path === "string" && path.trim().length > 0);
|
|
1965
|
+
return spec;
|
|
1966
|
+
}
|
|
1967
|
+
function replayurl(spec) {
|
|
1968
|
+
const url = new URL(spec.endpoint);
|
|
1969
|
+
for (const [name, value] of Object.entries(spec.overrides ?? {})) url.searchParams.set(name, value);
|
|
1970
|
+
return url.toString();
|
|
1971
|
+
}
|
|
1972
|
+
function extractvalues(body, paths) {
|
|
1973
|
+
let parsed;
|
|
1974
|
+
try {
|
|
1975
|
+
parsed = JSON.parse(body);
|
|
1976
|
+
} catch {
|
|
1977
|
+
return paths.map((path) => ({ path, missing: true }));
|
|
1978
|
+
}
|
|
1979
|
+
const fields = readpath(parsed, paths.map((path) => ({ name: path, path, kind: "json" })));
|
|
1980
|
+
return fields.map((field) => ({ path: field.path, ...field.value !== void 0 ? { value: field.value } : {}, ...field.missing ? { missing: true } : {} }));
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
// socketbus.ts
|
|
1984
|
+
var socketkinds = ["opensocket", "sendmessage", "waitmessage", "subscribesse", "longpoll"];
|
|
1985
|
+
function channelorigin(url) {
|
|
1986
|
+
try {
|
|
1987
|
+
const parsed = new URL(url);
|
|
1988
|
+
const protocol = parsed.protocol === "wss:" ? "https:" : parsed.protocol === "ws:" ? "http:" : parsed.protocol;
|
|
1989
|
+
return `${protocol}//${parsed.host}`;
|
|
1990
|
+
} catch {
|
|
1991
|
+
return "";
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
function channeloptionsof(value) {
|
|
1995
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
1996
|
+
const entry = value;
|
|
1997
|
+
if (typeof entry.url !== "string" || !entry.url.trim()) return void 0;
|
|
1998
|
+
const options = {};
|
|
1999
|
+
if (Array.isArray(entry.protocols)) options.protocols = entry.protocols.filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
2000
|
+
if (typeof entry.reconnect === "number" && Number.isFinite(entry.reconnect)) options.reconnect = entry.reconnect;
|
|
2001
|
+
if (typeof entry.backoff === "number" && Number.isFinite(entry.backoff)) options.backoff = entry.backoff;
|
|
2002
|
+
if (typeof entry.backoffceiling === "number" && Number.isFinite(entry.backoffceiling)) options.backoffceiling = entry.backoffceiling;
|
|
2003
|
+
if (typeof entry.lifetime === "number" && Number.isFinite(entry.lifetime)) options.lifetime = entry.lifetime;
|
|
2004
|
+
return { url: entry.url.trim(), options };
|
|
2005
|
+
}
|
|
2006
|
+
function newchannel(input) {
|
|
2007
|
+
return { id: input.id, runid: input.runid, stepid: input.stepid, kind: input.kind, url: input.url, origin: channelorigin(input.url), state: "connecting", openedat: input.at, sent: 0, received: 0, reconnects: 0, ...input.protocols !== void 0 && input.protocols.length > 0 ? { protocols: [...input.protocols] } : {} };
|
|
2008
|
+
}
|
|
2009
|
+
function reconnectwaits(attempts, base, ceiling) {
|
|
2010
|
+
const count = Math.max(0, Math.floor(attempts));
|
|
2011
|
+
const waits = [];
|
|
2012
|
+
let wait = Math.max(0, base);
|
|
2013
|
+
for (let index = 0; index < count; index += 1) {
|
|
2014
|
+
waits.push(wait);
|
|
2015
|
+
const next = wait * 2;
|
|
2016
|
+
wait = ceiling !== void 0 && Number.isFinite(ceiling) && ceiling >= 0 ? Math.min(next, ceiling) : next;
|
|
2017
|
+
}
|
|
2018
|
+
return waits;
|
|
2019
|
+
}
|
|
2020
|
+
async function openchannel(input) {
|
|
2021
|
+
const sleep = input.sleep ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, Math.max(0, milliseconds))));
|
|
2022
|
+
const now = input.now ?? Date.now;
|
|
2023
|
+
const attempts = Math.max(1, Math.floor(input.options.reconnect ?? 0) + 1);
|
|
2024
|
+
const waits = reconnectwaits(attempts - 1, input.options.backoff ?? 0, input.options.backoffceiling);
|
|
2025
|
+
let record2 = { ...input.record, state: "connecting" };
|
|
2026
|
+
let lasterror = "";
|
|
2027
|
+
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
2028
|
+
try {
|
|
2029
|
+
const result = await input.connect(record2.url, record2.protocols ?? []);
|
|
2030
|
+
if (result.open) return { ...record2, state: "open", openedat: now() };
|
|
2031
|
+
lasterror = result.error ?? `closed with code ${result.code ?? 0}`;
|
|
2032
|
+
} catch (error) {
|
|
2033
|
+
lasterror = error instanceof Error ? error.message : String(error);
|
|
2034
|
+
}
|
|
2035
|
+
if (attempt < attempts - 1) {
|
|
2036
|
+
const wait = waits[attempt] ?? 0;
|
|
2037
|
+
if (wait > 0) await sleep(wait);
|
|
2038
|
+
record2 = { ...record2, reconnects: record2.reconnects + 1 };
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
return { ...record2, state: "failed", error: lasterror };
|
|
2042
|
+
}
|
|
2043
|
+
function closechannel(record2, at, error) {
|
|
2044
|
+
const state = error !== void 0 ? "failed" : "closed";
|
|
2045
|
+
return { ...record2, state, closedat: at, ...error !== void 0 ? { error } : {} };
|
|
2046
|
+
}
|
|
2047
|
+
function tagmessage(state, channelid, stream, payload, at) {
|
|
2048
|
+
const sequence = (state.sequences[channelid] ?? 0) + 1;
|
|
2049
|
+
const envelope = { channelid, stream, payload, sequence, at };
|
|
2050
|
+
return { state: { sequences: { ...state.sequences, [channelid]: sequence }, queue: state.queue }, envelope };
|
|
2051
|
+
}
|
|
2052
|
+
function publishmessage(state, channelid, stream, payload, at) {
|
|
2053
|
+
return tagmessage(state, channelid, stream, payload, at);
|
|
2054
|
+
}
|
|
2055
|
+
function receivemessage(state, channelid, stream, payload, at) {
|
|
2056
|
+
const tagged = tagmessage(state, channelid, stream, payload, at);
|
|
2057
|
+
return { state: { ...tagged.state, queue: [...state.queue, tagged.envelope] }, envelope: tagged.envelope };
|
|
2058
|
+
}
|
|
2059
|
+
function pathstep2(current, segment) {
|
|
2060
|
+
if (Array.isArray(current) && /^\d+$/.test(segment)) return current[Number.parseInt(segment, 10)];
|
|
2061
|
+
if (current && typeof current === "object" && !Array.isArray(current)) return current[segment];
|
|
2062
|
+
return void 0;
|
|
2063
|
+
}
|
|
2064
|
+
function matchmessage(filter, envelope) {
|
|
2065
|
+
if (!filter) return true;
|
|
2066
|
+
if (filter.stream !== void 0 && filter.stream !== envelope.stream) return false;
|
|
2067
|
+
if (filter.path !== void 0) {
|
|
2068
|
+
try {
|
|
2069
|
+
const parsed = JSON.parse(envelope.payload);
|
|
2070
|
+
let current = parsed;
|
|
2071
|
+
let missing = false;
|
|
2072
|
+
for (const segment of filter.path.split(".")) {
|
|
2073
|
+
const next = pathstep2(current, segment);
|
|
2074
|
+
if (next === void 0) {
|
|
2075
|
+
missing = true;
|
|
2076
|
+
break;
|
|
2077
|
+
}
|
|
2078
|
+
current = next;
|
|
2079
|
+
}
|
|
2080
|
+
if (missing) return false;
|
|
2081
|
+
} catch {
|
|
2082
|
+
return false;
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
return true;
|
|
2086
|
+
}
|
|
2087
|
+
function collectmessages(state, channelid, filter) {
|
|
2088
|
+
const limit = filter?.limit !== void 0 && Number.isFinite(filter.limit) && filter.limit >= 1 ? Math.floor(filter.limit) : Number.POSITIVE_INFINITY;
|
|
2089
|
+
const matched = [];
|
|
2090
|
+
const queue = [];
|
|
2091
|
+
for (const envelope of state.queue) {
|
|
2092
|
+
if (envelope.channelid === channelid && matched.length < limit && matchmessage(filter, envelope)) matched.push(envelope);
|
|
2093
|
+
else queue.push(envelope);
|
|
2094
|
+
}
|
|
2095
|
+
return { state: { sequences: state.sequences, queue }, matched };
|
|
2096
|
+
}
|
|
2097
|
+
function sequenceintegrity(envelopes) {
|
|
2098
|
+
const last = /* @__PURE__ */ new Map();
|
|
2099
|
+
const gaps = [];
|
|
2100
|
+
for (const envelope of envelopes) {
|
|
2101
|
+
const expected = (last.get(envelope.channelid) ?? 0) + 1;
|
|
2102
|
+
if (envelope.sequence !== expected) gaps.push({ channelid: envelope.channelid, expected, found: envelope.sequence });
|
|
2103
|
+
last.set(envelope.channelid, Math.max(envelope.sequence, expected));
|
|
2104
|
+
}
|
|
2105
|
+
return { ok: gaps.length === 0, gaps };
|
|
2106
|
+
}
|
|
2107
|
+
function messagefilterof(value) {
|
|
2108
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
2109
|
+
const entry = value;
|
|
2110
|
+
const filter = {};
|
|
2111
|
+
if (typeof entry.stream === "string" && entry.stream.trim()) filter.stream = entry.stream.trim();
|
|
2112
|
+
if (typeof entry.path === "string" && entry.path.trim()) filter.path = entry.path.trim();
|
|
2113
|
+
if (typeof entry.limit === "number" && Number.isFinite(entry.limit) && entry.limit >= 1) filter.limit = Math.floor(entry.limit);
|
|
2114
|
+
return filter;
|
|
2115
|
+
}
|
|
2116
|
+
function parsessetext(text2) {
|
|
2117
|
+
const separator = text2.lastIndexOf("\n\n");
|
|
2118
|
+
const complete = separator === -1 ? "" : text2.slice(0, separator + 2);
|
|
2119
|
+
const rest = separator === -1 ? text2 : text2.slice(separator + 2);
|
|
2120
|
+
const events = [];
|
|
2121
|
+
for (const block of complete.split(/\n\n/)) {
|
|
2122
|
+
const id = [];
|
|
2123
|
+
const names = [];
|
|
2124
|
+
const data = [];
|
|
2125
|
+
let retry;
|
|
2126
|
+
for (const line of block.split("\n")) {
|
|
2127
|
+
if (line === "" || line.startsWith(":")) continue;
|
|
2128
|
+
const colon = line.indexOf(":");
|
|
2129
|
+
const field = colon === -1 ? line : line.slice(0, colon);
|
|
2130
|
+
let value = colon === -1 ? "" : line.slice(colon + 1);
|
|
2131
|
+
if (value.startsWith(" ")) value = value.slice(1);
|
|
2132
|
+
if (field === "id" && value !== "") id.push(value);
|
|
2133
|
+
if (field === "event" && value !== "") names.push(value);
|
|
2134
|
+
if (field === "data") data.push(value);
|
|
2135
|
+
if (field === "retry" && /^\d+$/.test(value)) retry = Number.parseInt(value, 10);
|
|
2136
|
+
}
|
|
2137
|
+
if (id.length === 0 && names.length === 0 && data.length === 0) continue;
|
|
2138
|
+
events.push({ ...id.length > 0 ? { id: id[id.length - 1] } : {}, ...names.length > 0 ? { event: names[names.length - 1] } : {}, data: data.join("\n"), ...retry !== void 0 ? { retry } : {} });
|
|
2139
|
+
}
|
|
2140
|
+
return { events, rest };
|
|
2141
|
+
}
|
|
2142
|
+
function sserequestheaders(record2) {
|
|
2143
|
+
return { accept: "text/event-stream", ...record2.lasteventid !== void 0 && record2.lasteventid !== "" ? { "last-event-id": record2.lasteventid } : {} };
|
|
2144
|
+
}
|
|
2145
|
+
function subscriptionoptionsof(value) {
|
|
2146
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
2147
|
+
const entry = value;
|
|
2148
|
+
if (typeof entry.url !== "string" || !entry.url.trim()) return void 0;
|
|
2149
|
+
const cancel = entry.cancel;
|
|
2150
|
+
if (!cancel || typeof cancel !== "object" || Array.isArray(cancel)) return void 0;
|
|
2151
|
+
const cancelrecord = cancel;
|
|
2152
|
+
if (cancelrecord.kind !== "stop" && cancelrecord.kind !== "lifetime") return void 0;
|
|
2153
|
+
if (typeof cancelrecord.value !== "string" && typeof cancelrecord.value !== "number") return void 0;
|
|
2154
|
+
const result = { url: entry.url.trim(), cancel: { kind: cancelrecord.kind, value: cancelrecord.value } };
|
|
2155
|
+
if (typeof entry.lifetime === "number" && Number.isFinite(entry.lifetime) && entry.lifetime > 0) result.lifetime = entry.lifetime;
|
|
2156
|
+
if (typeof entry.lasteventid === "string" && entry.lasteventid.trim()) result.lasteventid = entry.lasteventid.trim();
|
|
2157
|
+
return result;
|
|
2158
|
+
}
|
|
2159
|
+
function pollcursorof(value) {
|
|
2160
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
2161
|
+
const entry = value;
|
|
2162
|
+
if (typeof entry.url !== "string" || !entry.url.trim()) return void 0;
|
|
2163
|
+
if (typeof entry.cursorfield !== "string" || !entry.cursorfield.trim()) return void 0;
|
|
2164
|
+
if (typeof entry.interval !== "number" || !Number.isFinite(entry.interval) || entry.interval <= 0) return void 0;
|
|
2165
|
+
const stop = entry.stop;
|
|
2166
|
+
if (!stop || typeof stop !== "object" || Array.isArray(stop)) return void 0;
|
|
2167
|
+
const stoprecord = stop;
|
|
2168
|
+
if (typeof stoprecord.field !== "string" || !stoprecord.field.trim()) return void 0;
|
|
2169
|
+
if (typeof stoprecord.equals !== "string") return void 0;
|
|
2170
|
+
const cursor = { url: entry.url.trim(), cursorfield: entry.cursorfield.trim(), interval: entry.interval, stop: { field: stoprecord.field.trim(), equals: stoprecord.equals } };
|
|
2171
|
+
if (typeof entry.maxpolls === "number" && Number.isFinite(entry.maxpolls) && entry.maxpolls >= 1) cursor.maxpolls = Math.floor(entry.maxpolls);
|
|
2172
|
+
if (typeof entry.param === "string" && entry.param.trim()) cursor.param = entry.param.trim();
|
|
2173
|
+
return cursor;
|
|
2174
|
+
}
|
|
2175
|
+
function cursorfrom(response, field) {
|
|
2176
|
+
let current = response;
|
|
2177
|
+
for (const segment of field.split(".")) {
|
|
2178
|
+
const next = pathstep2(current, segment);
|
|
2179
|
+
if (next === void 0) return void 0;
|
|
2180
|
+
current = next;
|
|
2181
|
+
}
|
|
2182
|
+
return current === void 0 || current === null ? void 0 : String(current);
|
|
2183
|
+
}
|
|
2184
|
+
function pollurl(cursor, value) {
|
|
2185
|
+
if (cursor.param === void 0 || value === void 0) {
|
|
2186
|
+
return { url: cursor.url, ...value !== void 0 ? { body: JSON.stringify({ [cursor.cursorfield]: value }) } : {} };
|
|
2187
|
+
}
|
|
2188
|
+
const url = new URL(cursor.url);
|
|
2189
|
+
url.searchParams.set(cursor.param, value);
|
|
2190
|
+
return { url: url.toString() };
|
|
2191
|
+
}
|
|
2192
|
+
function polldecision(input) {
|
|
2193
|
+
if (input.cancelled?.() === true) return { continue: false, reason: "The long poll loop was cancelled." };
|
|
2194
|
+
if (input.expiresat !== void 0 && input.now >= input.expiresat) return { continue: false, reason: "The long poll loop stopped at the reviewed plan expiry." };
|
|
2195
|
+
const stopvalue = cursorfrom(input.response, input.cursor.stop.field);
|
|
2196
|
+
if (stopvalue !== void 0 && stopvalue === input.cursor.stop.equals) return { continue: false, reason: `The stop condition matched ${input.cursor.stop.field} ${stopvalue}.` };
|
|
2197
|
+
if (input.cursor.maxpolls !== void 0 && input.polls + 1 >= input.cursor.maxpolls) return { continue: false, reason: `The long poll loop reached the reviewed poll ceiling of ${input.cursor.maxpolls}.` };
|
|
2198
|
+
const value = cursorfrom(input.response, input.cursor.cursorfield);
|
|
2199
|
+
const next = pollurl(input.cursor, value);
|
|
2200
|
+
return { continue: true, reason: "The long poll loop continues.", ...value !== void 0 ? { cursor: value } : {}, next: { ...next, wait: input.cursor.interval } };
|
|
2201
|
+
}
|
|
2202
|
+
|
|
1713
2203
|
// policy.ts
|
|
1714
|
-
var sensitiveactions = /* @__PURE__ */ new Set(["click", "type", "navigate", "select", "presskey", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "reload", "back", "forward", "writestorage", "setattribute", "removeattribute", "evaluate", "tabcreate", "tabactivate", "tabclose", "tabreload", "windowcreate", "windowclose", "windowresize", "downloadfile", "clickpoint", "shiftclick", "dismissdialog", "enterframe", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "openlink", "openprivate", "reloadcache", "stopnav", "followlink", "spanav", "rewritequery", "setfragment", "navlist", "navprofile", "handleauth", "printpdf", "prefetch", "preconnect", "deeplink", "reopentab", "pausenav", "navrate", "openclipboard", "batchopen", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "restorelayout", "reopenrun", "badgetab", "fillform", "filllabel", "fillplaceholder", "submitform", "retryform", "runwizard", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcard", "fillcode", "consentpassword", "exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "streamdisk", "paginateextract", "resumeextract", "batchdownload", "pausedownload", "resumedownload", "interceptmime", "readclipboard", "writeclipboard", "copyscreen", "quarantinedownload", "scanvirus", "cleanupartifacts", "recordscreen", "captureaudio", "downloadimages", "callrest", "callgraphql"]);
|
|
1715
|
-
var interactionactions = /* @__PURE__ */ new Set(["focus", "scroll", "hover", "clickdeep", "rightclick", "doubleclick", "scrollpage", "scrollby", "scrollend", "scrolltop", "fullscreen", "zoomset", "movepointer", "clicktext", "clickaria", "clickname", "expanddetails", "pierceshadow", "retryaction"]);
|
|
1716
|
-
var readactions = /* @__PURE__ */ new Set(["observe", "inspect", "extract", "wait", "waitfor", "waittext", "readattribute", "readstyle", "readgeometry", "readvalue", "readtext", "readhtml", "countelements", "readtable", "readlinks", "readimages", "readmeta", "readforms", "readstorage", "highlight", "tablist", "windowlist", "tabsnapshot", "mapclicks", "verifyvisible", "verifyenabled", "resolvexpath", "a11ytree", "readvisible", "readertree", "detectlists", "detecttables", "readjson", "watchmutate", "waitquiet", "watchbanner", "detectinfinitescroll", "detectvirtual", "detectlazy", "readscrollpos", "readlang", "readoutline", "countpages", "listshadow", "listframes", "classifypage", "fingerprintsection", "diffsnapshots", "readselection", "watchfocus", "detectsticky", "detectscrolllock", "readopengraph", "detectlanguage", "deriveselector", "waitload", "waiturl", "spawait", "detecthttp", "readredirects", "readfinalurl", "trailaudit", "navintent", "checksafe", "querytabs", "watchtab", "findclones", "searchtabs", "listaudio", "snapshotsession", "savelayout", "attachmeta", "detectfields", "generatevalues", "saveprofiles", "asksubmit", "readerrors", "skiphoneypot", "detectlogin", "detecttemplate", "handoffcaptcha", "scrapetable", "importcsv", "looprows", "transformvalues", "deduperows", "mergepages", "stamplerows", "previewgrid", "logprovenance", "verifydownload", "exportnetlog", "namecaptures", "shotview", "shotfullpage", "shotelement", "shotregion", "contactsheet", "capturepdf", "captureframe", "readmedia", "readassets", "probestream", "timelapse", "shotcanvas", "convertimage", "makethumbs", "fetchurl", "parsejson", "parsehtml"]);
|
|
2204
|
+
var sensitiveactions = /* @__PURE__ */ new Set(["click", "type", "navigate", "select", "presskey", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "reload", "back", "forward", "writestorage", "setattribute", "removeattribute", "evaluate", "tabcreate", "tabactivate", "tabclose", "tabreload", "windowcreate", "windowclose", "windowresize", "downloadfile", "clickpoint", "shiftclick", "dismissdialog", "enterframe", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "openlink", "openprivate", "reloadcache", "stopnav", "followlink", "spanav", "rewritequery", "setfragment", "navlist", "navprofile", "handleauth", "printpdf", "prefetch", "preconnect", "deeplink", "reopentab", "pausenav", "navrate", "openclipboard", "batchopen", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "restorelayout", "reopenrun", "badgetab", "fillform", "filllabel", "fillplaceholder", "submitform", "retryform", "runwizard", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcard", "fillcode", "consentpassword", "exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "streamdisk", "paginateextract", "resumeextract", "batchdownload", "pausedownload", "resumedownload", "interceptmime", "readclipboard", "writeclipboard", "copyscreen", "quarantinedownload", "scanvirus", "cleanupartifacts", "recordscreen", "captureaudio", "downloadimages", "callrest", "callgraphql", "sendmessage"]);
|
|
2205
|
+
var interactionactions = /* @__PURE__ */ new Set(["focus", "scroll", "hover", "clickdeep", "rightclick", "doubleclick", "scrollpage", "scrollby", "scrollend", "scrolltop", "fullscreen", "zoomset", "movepointer", "clicktext", "clickaria", "clickname", "expanddetails", "pierceshadow", "retryaction", "capturebodies"]);
|
|
2206
|
+
var readactions = /* @__PURE__ */ new Set(["observe", "inspect", "extract", "wait", "waitfor", "waittext", "readattribute", "readstyle", "readgeometry", "readvalue", "readtext", "readhtml", "countelements", "readtable", "readlinks", "readimages", "readmeta", "readforms", "readstorage", "highlight", "tablist", "windowlist", "tabsnapshot", "mapclicks", "verifyvisible", "verifyenabled", "resolvexpath", "a11ytree", "readvisible", "readertree", "detectlists", "detecttables", "readjson", "watchmutate", "waitquiet", "watchbanner", "detectinfinitescroll", "detectvirtual", "detectlazy", "readscrollpos", "readlang", "readoutline", "countpages", "listshadow", "listframes", "classifypage", "fingerprintsection", "diffsnapshots", "readselection", "watchfocus", "detectsticky", "detectscrolllock", "readopengraph", "detectlanguage", "deriveselector", "waitload", "waiturl", "spawait", "detecthttp", "readredirects", "readfinalurl", "trailaudit", "navintent", "checksafe", "querytabs", "watchtab", "findclones", "searchtabs", "listaudio", "snapshotsession", "savelayout", "attachmeta", "detectfields", "generatevalues", "saveprofiles", "asksubmit", "readerrors", "skiphoneypot", "detectlogin", "detecttemplate", "handoffcaptcha", "scrapetable", "importcsv", "looprows", "transformvalues", "deduperows", "mergepages", "stamplerows", "previewgrid", "logprovenance", "verifydownload", "exportnetlog", "namecaptures", "shotview", "shotfullpage", "shotelement", "shotregion", "contactsheet", "capturepdf", "captureframe", "readmedia", "readassets", "probestream", "timelapse", "shotcanvas", "convertimage", "makethumbs", "fetchurl", "parsejson", "parsehtml", "opensocket", "waitmessage", "watchrequests", "readheaders", "mapapi", "subscribesse", "longpoll", "extractapi"]);
|
|
1717
2207
|
var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
|
|
1718
2208
|
var watchactions = /* @__PURE__ */ new Set(["watchmutate", "watchbanner", "watchfocus", "watchtab"]);
|
|
1719
2209
|
var targetactions = /* @__PURE__ */ new Set(["inspect", "focus", "click", "type", "scroll", "select", "hover", "clickdeep", "rightclick", "doubleclick", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "readattribute", "readstyle", "readgeometry", "readvalue", "readtext", "readhtml", "countelements", "readtable", "highlight", "setattribute", "removeattribute", "waitfor", "shiftclick", "typetime", "appendtext", "setvalue", "typeedit", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "expanddetails", "verifyvisible", "verifyenabled", "pierceshadow", "deriveselector", "fingerprintsection", "submitform", "retryform", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcode", "consentpassword", "scrapetable", "paginateextract", "shotelement", "captureframe", "shotcanvas"]);
|
|
@@ -1726,6 +2216,8 @@ var filesactions = /* @__PURE__ */ new Set(["batchdownload", "pausedownload", "r
|
|
|
1726
2216
|
var captureactions = /* @__PURE__ */ new Set(["shotview", "shotfullpage", "shotelement", "shotregion", "contactsheet"]);
|
|
1727
2217
|
var mediaactions = /* @__PURE__ */ new Set(["capturepdf", "recordscreen", "captureaudio", "captureframe", "downloadimages", "shotcanvas", "probestream", "readmedia", "readassets", "timelapse", "convertimage", "makethumbs"]);
|
|
1728
2218
|
var httpactions = /* @__PURE__ */ new Set(["fetchurl", "parsejson", "parsehtml", "callrest", "callgraphql"]);
|
|
2219
|
+
var socketactions = /* @__PURE__ */ new Set(["opensocket", "sendmessage", "waitmessage", "subscribesse", "longpoll"]);
|
|
2220
|
+
var netwatchactions = /* @__PURE__ */ new Set(["watchrequests", "readheaders", "capturebodies", "mapapi", "extractapi"]);
|
|
1729
2221
|
var credentialheaders = /* @__PURE__ */ new Set(["authorization", "proxy-authorization", "cookie", "cookie2", "set-cookie", "api-key", "x-api-key", "x-auth-token", "x-session-token", "proxy-authorization"]);
|
|
1730
2222
|
var fieldkinds = ["text", "email", "phone", "date", "number", "select", "check", "radio", "file", "password", "card", "code"];
|
|
1731
2223
|
var layoutmutationactions = /* @__PURE__ */ new Set(["grouptabs", "colorgroup", "collapsegroup", "savelayout", "restorelayout"]);
|
|
@@ -2434,6 +2926,59 @@ function ismediakind(kind) {
|
|
|
2434
2926
|
function ishttpkind(kind) {
|
|
2435
2927
|
return httpactions.has(kind);
|
|
2436
2928
|
}
|
|
2929
|
+
function issocketkind(kind) {
|
|
2930
|
+
return socketactions.has(kind);
|
|
2931
|
+
}
|
|
2932
|
+
function isnetwatchkind(kind) {
|
|
2933
|
+
return netwatchactions.has(kind);
|
|
2934
|
+
}
|
|
2935
|
+
function resolvedrisk(step) {
|
|
2936
|
+
if (step.kind === "capturebodies") {
|
|
2937
|
+
let options = {};
|
|
2938
|
+
try {
|
|
2939
|
+
options = parseoptions(step);
|
|
2940
|
+
} catch {
|
|
2941
|
+
options = {};
|
|
2942
|
+
}
|
|
2943
|
+
const body = options.body;
|
|
2944
|
+
const mimes = body && typeof body === "object" && !Array.isArray(body) ? body.mimes : void 0;
|
|
2945
|
+
if (Array.isArray(mimes) && mimes.some((mime) => typeof mime === "string" && privatemime(mime))) return "sensitive";
|
|
2946
|
+
return "interaction";
|
|
2947
|
+
}
|
|
2948
|
+
if (step.kind === "extractapi") {
|
|
2949
|
+
let options = {};
|
|
2950
|
+
try {
|
|
2951
|
+
options = parseoptions(step);
|
|
2952
|
+
} catch {
|
|
2953
|
+
options = {};
|
|
2954
|
+
}
|
|
2955
|
+
const replay = options.replay;
|
|
2956
|
+
const verb = replay && typeof replay === "object" && !Array.isArray(replay) ? replay.verb : void 0;
|
|
2957
|
+
if (typeof verb === "string" && !["GET", "HEAD", "OPTIONS"].includes(verb.trim().toUpperCase())) return "sensitive";
|
|
2958
|
+
return "read";
|
|
2959
|
+
}
|
|
2960
|
+
return actionrisk(step.kind);
|
|
2961
|
+
}
|
|
2962
|
+
function socketgate(session, url) {
|
|
2963
|
+
let parsed;
|
|
2964
|
+
try {
|
|
2965
|
+
parsed = new URL(url);
|
|
2966
|
+
} catch {
|
|
2967
|
+
return { allowed: false, reason: "The channel needs a valid url before it can be reviewed." };
|
|
2968
|
+
}
|
|
2969
|
+
if (parsed.protocol !== "wss:" && parsed.protocol !== "https:") return { allowed: false, reason: "Channels use wss websocket urls or https event stream urls only." };
|
|
2970
|
+
if (parsed.username || parsed.password) return { allowed: false, reason: "Channel credentials are not allowed in the url." };
|
|
2971
|
+
const origin = channelorigin(url);
|
|
2972
|
+
if (!origingranted(session, origin)) return { allowed: false, reason: `The channel to ${origin} stays outside the session origin grants.` };
|
|
2973
|
+
return { allowed: true };
|
|
2974
|
+
}
|
|
2975
|
+
function watchgate(session, settings, now) {
|
|
2976
|
+
if (!session || session.stoppedat) return { allowed: false, reason: "No active browser session exists for the request watch." };
|
|
2977
|
+
if (session.expiresat <= now) return { allowed: false, reason: "The browser session has expired and cannot watch requests." };
|
|
2978
|
+
if (session.pausedat) return { allowed: false, reason: "The browser session is paused and cannot watch requests." };
|
|
2979
|
+
if (settings?.webrequestgrant !== true) return { allowed: false, reason: "Request watching needs the webrequest grant in the review panel first; the observation derives from the page timing buffers and adds no manifest permission." };
|
|
2980
|
+
return { allowed: true };
|
|
2981
|
+
}
|
|
2437
2982
|
function origincheck(session, url) {
|
|
2438
2983
|
let parsed;
|
|
2439
2984
|
try {
|
|
@@ -2599,6 +3144,108 @@ function fetchnumeric(options, key) {
|
|
|
2599
3144
|
function isrecordingkind(kind) {
|
|
2600
3145
|
return kind === "recordscreen" || kind === "captureaudio";
|
|
2601
3146
|
}
|
|
3147
|
+
function validatesocketgrammar(step, options) {
|
|
3148
|
+
const kind = step.kind;
|
|
3149
|
+
if (kind === "opensocket") {
|
|
3150
|
+
const channel = channeloptionsof(options.socket);
|
|
3151
|
+
if (!channel) return { allowed: false, reason: "A reviewed socket with a url is required in options.socket." };
|
|
3152
|
+
if (channel.options.reconnect !== void 0 && !Number.isInteger(channel.options.reconnect)) return { allowed: false, reason: "The reviewed socket reconnect budget must be an integer attempt count with no code ceiling." };
|
|
3153
|
+
for (const label of ["backoff", "backoffceiling"]) {
|
|
3154
|
+
const value = channel.options[label];
|
|
3155
|
+
if (value !== void 0 && (typeof value !== "number" || !Number.isFinite(value) || value < 0)) return { allowed: false, reason: `The reviewed socket ${label} must be zero or a positive number of milliseconds with no code ceiling.` };
|
|
3156
|
+
}
|
|
3157
|
+
if (channel.options.lifetime !== void 0 && (typeof channel.options.lifetime !== "number" || !Number.isFinite(channel.options.lifetime) || channel.options.lifetime <= 0)) return { allowed: false, reason: "The reviewed socket lifetime window must be a positive number of milliseconds." };
|
|
3158
|
+
}
|
|
3159
|
+
if (kind === "sendmessage") {
|
|
3160
|
+
const message = options.message;
|
|
3161
|
+
if (!message || typeof message !== "object" || Array.isArray(message)) return { allowed: false, reason: "A reviewed message with a channel, stream and payload is required in options.message." };
|
|
3162
|
+
const envelope = message;
|
|
3163
|
+
if (!isnonempty(envelope.channel)) return { allowed: false, reason: "The reviewed message needs the open channel id in options.message.channel." };
|
|
3164
|
+
if (envelope.stream !== void 0 && !isnonempty(envelope.stream)) return { allowed: false, reason: "The reviewed message stream name must be a non-empty string." };
|
|
3165
|
+
if (typeof envelope.payload !== "string") return { allowed: false, reason: "The reviewed message payload must be a string." };
|
|
3166
|
+
}
|
|
3167
|
+
if (kind === "waitmessage") {
|
|
3168
|
+
if (options.filter !== void 0) {
|
|
3169
|
+
const filter = options.filter;
|
|
3170
|
+
if (!filter || typeof filter !== "object" || Array.isArray(filter)) return { allowed: false, reason: "The reviewed message filter must be an object of stream, path and limit." };
|
|
3171
|
+
const reviewed = filter;
|
|
3172
|
+
if (reviewed.stream !== void 0 && !isnonempty(reviewed.stream)) return { allowed: false, reason: "The reviewed message filter stream name must be a non-empty string." };
|
|
3173
|
+
if (reviewed.path !== void 0 && (typeof reviewed.path !== "string" || !validpath(reviewed.path.trim()))) return { allowed: false, reason: "The reviewed message filter path must be a dotted path of non-empty segments." };
|
|
3174
|
+
if (reviewed.limit !== void 0 && (typeof reviewed.limit !== "number" || !Number.isInteger(reviewed.limit) || reviewed.limit < 1)) return { allowed: false, reason: "The reviewed message match limit must be a positive integer with no code ceiling." };
|
|
3175
|
+
}
|
|
3176
|
+
if (options.wait !== void 0 && (typeof options.wait !== "number" || !Number.isFinite(options.wait) || options.wait < 0)) return { allowed: false, reason: "The reviewed message wait budget must be zero or a positive number of milliseconds." };
|
|
3177
|
+
}
|
|
3178
|
+
if (kind === "subscribesse") {
|
|
3179
|
+
const subscription = subscriptionoptionsof(options.subscription);
|
|
3180
|
+
if (!subscription) return { allowed: false, reason: "A reviewed subscription with an event stream url and a cancellation path is required in options.subscription." };
|
|
3181
|
+
const rawlifetime = options.subscription && typeof options.subscription === "object" && !Array.isArray(options.subscription) ? options.subscription.lifetime : void 0;
|
|
3182
|
+
if (rawlifetime !== void 0 && (typeof rawlifetime !== "number" || !Number.isFinite(rawlifetime) || rawlifetime <= 0)) return { allowed: false, reason: "The reviewed subscription lifetime window must be a positive number of milliseconds." };
|
|
3183
|
+
}
|
|
3184
|
+
if (kind === "longpoll") {
|
|
3185
|
+
const cursor = pollcursorof(options.poll);
|
|
3186
|
+
if (!cursor) return { allowed: false, reason: "A reviewed poll cursor with a url, cursor field, interval and stop condition is required in options.poll." };
|
|
3187
|
+
const wait = options.wait;
|
|
3188
|
+
if (wait !== void 0 && (typeof wait !== "number" || !Number.isFinite(wait) || wait < 0)) return { allowed: false, reason: "The reviewed long poll wait budget must be zero or a positive number of milliseconds." };
|
|
3189
|
+
if (wait !== void 0 && cursor.interval > wait) return { allowed: false, reason: `The long poll interval of ${cursor.interval} milliseconds exceeds the reviewed wait budget of ${wait} milliseconds; review a wider budget or a shorter interval.` };
|
|
3190
|
+
}
|
|
3191
|
+
return { allowed: true };
|
|
3192
|
+
}
|
|
3193
|
+
function validatenetwatchgrammar(step, options) {
|
|
3194
|
+
const kind = step.kind;
|
|
3195
|
+
if (kind === "watchrequests") {
|
|
3196
|
+
if (options.watch !== void 0) {
|
|
3197
|
+
const watch = options.watch;
|
|
3198
|
+
if (!watch || typeof watch !== "object" || Array.isArray(watch)) return { allowed: false, reason: "The reviewed watch window must be an object." };
|
|
3199
|
+
const reviewed = watch;
|
|
3200
|
+
if (reviewed.window !== void 0 && (typeof reviewed.window !== "number" || !Number.isFinite(reviewed.window) || reviewed.window < 0)) return { allowed: false, reason: "The reviewed watch window must be zero or a positive number of milliseconds." };
|
|
3201
|
+
}
|
|
3202
|
+
if (options.limit !== void 0 && (typeof options.limit !== "number" || !Number.isInteger(options.limit) || options.limit < 1)) return { allowed: false, reason: "The reviewed watch match limit must be a positive integer with no code ceiling." };
|
|
3203
|
+
}
|
|
3204
|
+
if (kind === "readheaders") {
|
|
3205
|
+
const headers = options.headers;
|
|
3206
|
+
if (!headers || typeof headers !== "object" || Array.isArray(headers)) return { allowed: false, reason: "A reviewed header filter with a name allowlist and a redaction list is required in options.headers." };
|
|
3207
|
+
const reviewed = headers;
|
|
3208
|
+
if (!Array.isArray(reviewed.allow) || reviewed.allow.length === 0 || !reviewed.allow.every((name) => isnonempty(name))) return { allowed: false, reason: "The reviewed header allowlist must be a non-empty list of header names." };
|
|
3209
|
+
if (!Array.isArray(reviewed.redact) || reviewed.redact.length === 0 || !reviewed.redact.every((name) => isnonempty(name))) return { allowed: false, reason: "Header capture requires a reviewed redaction list before any header value is stored." };
|
|
3210
|
+
}
|
|
3211
|
+
if (kind === "capturebodies") {
|
|
3212
|
+
const body = options.body;
|
|
3213
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) return { allowed: false, reason: "A reviewed body filter with a url pattern, mime list and byte ceiling is required in options.body." };
|
|
3214
|
+
const reviewed = body;
|
|
3215
|
+
if (reviewed.urlpattern !== void 0 && !isnonempty(reviewed.urlpattern)) return { allowed: false, reason: "The reviewed body url pattern must be a non-empty string." };
|
|
3216
|
+
if (reviewed.mimes !== void 0 && (!Array.isArray(reviewed.mimes) || reviewed.mimes.length === 0 || !reviewed.mimes.every((mime) => isnonempty(mime)))) return { allowed: false, reason: "The reviewed body mime list must be a non-empty list of mime types." };
|
|
3217
|
+
if (reviewed.ceiling !== void 0 && (typeof reviewed.ceiling !== "number" || !Number.isFinite(reviewed.ceiling) || reviewed.ceiling < 0)) return { allowed: false, reason: "The reviewed body byte ceiling must be zero or a positive number of bytes with no code ceiling." };
|
|
3218
|
+
}
|
|
3219
|
+
if (kind === "mapapi") {
|
|
3220
|
+
if (options.limit !== void 0 && (typeof options.limit !== "number" || !Number.isInteger(options.limit) || options.limit < 1)) return { allowed: false, reason: "The reviewed mapapi match limit must be a positive integer with no code ceiling." };
|
|
3221
|
+
}
|
|
3222
|
+
if (kind === "extractapi") {
|
|
3223
|
+
const replay = apireplayspecof(options.replay);
|
|
3224
|
+
if (!replay) return { allowed: false, reason: "A reviewed replay spec with an endpoint is required in options.replay." };
|
|
3225
|
+
if (!ishttpsurl(replay.endpoint)) return { allowed: false, reason: "The reviewed replay endpoint must be an HTTPS url." };
|
|
3226
|
+
if (replay.verb !== void 0 && !["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"].includes(replay.verb)) return { allowed: false, reason: "The reviewed replay verb must be a known HTTP verb." };
|
|
3227
|
+
for (const path of replay.paths ?? []) {
|
|
3228
|
+
if (!validpath(path.trim())) return { allowed: false, reason: `The reviewed replay extraction path ${path} must be a dotted path of non-empty segments.` };
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
return { allowed: true };
|
|
3232
|
+
}
|
|
3233
|
+
function sockettarget(step) {
|
|
3234
|
+
let options = {};
|
|
3235
|
+
try {
|
|
3236
|
+
options = parseoptions(step);
|
|
3237
|
+
} catch {
|
|
3238
|
+
options = {};
|
|
3239
|
+
}
|
|
3240
|
+
for (const key of ["socket", "subscription", "poll"]) {
|
|
3241
|
+
const value = options[key];
|
|
3242
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
3243
|
+
const url = value.url;
|
|
3244
|
+
if (typeof url === "string" && url.trim()) return url.trim();
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
return void 0;
|
|
3248
|
+
}
|
|
2602
3249
|
function mediagate(session, tabid, origin, now) {
|
|
2603
3250
|
if (!session || session.stoppedat) return { allowed: false, reason: "No active browser session exists for the media capture." };
|
|
2604
3251
|
if (session.expiresat <= now) return { allowed: false, reason: "The browser session has expired and cannot capture media." };
|
|
@@ -2956,6 +3603,14 @@ function validatestep(step, origin) {
|
|
|
2956
3603
|
const httpcheck = validatehttpgrammar(step, options);
|
|
2957
3604
|
if (!httpcheck.allowed) return httpcheck;
|
|
2958
3605
|
}
|
|
3606
|
+
if (issocketkind(step.kind)) {
|
|
3607
|
+
const socketcheck = validatesocketgrammar(step, options);
|
|
3608
|
+
if (!socketcheck.allowed) return socketcheck;
|
|
3609
|
+
}
|
|
3610
|
+
if (isnetwatchkind(step.kind)) {
|
|
3611
|
+
const netwatchcheck = validatenetwatchgrammar(step, options);
|
|
3612
|
+
if (!netwatchcheck.allowed) return netwatchcheck;
|
|
3613
|
+
}
|
|
2959
3614
|
if (step.kind === "tabcreate") {
|
|
2960
3615
|
if (options.background !== void 0 && typeof options.background !== "boolean") return { allowed: false, reason: "The reviewed background flag must be a boolean." };
|
|
2961
3616
|
if (options.window !== void 0 && (typeof options.window !== "number" || !Number.isInteger(options.window) || options.window < 0)) return { allowed: false, reason: "The reviewed target window id must be a non-negative integer." };
|
|
@@ -3046,6 +3701,30 @@ function canexecute(input) {
|
|
|
3046
3701
|
if (!consentgate.allowed) return consentgate;
|
|
3047
3702
|
}
|
|
3048
3703
|
}
|
|
3704
|
+
if (issocketkind(input.step.kind)) {
|
|
3705
|
+
const channelurl = sockettarget(input.step);
|
|
3706
|
+
if (channelurl !== void 0) {
|
|
3707
|
+
const channelgate = socketgate(input.session, channelurl);
|
|
3708
|
+
if (!channelgate.allowed) return channelgate;
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3711
|
+
if (input.step.kind === "watchrequests") {
|
|
3712
|
+
const watchgatecheck = watchgate(input.session, input.settings, now);
|
|
3713
|
+
if (!watchgatecheck.allowed) return watchgatecheck;
|
|
3714
|
+
}
|
|
3715
|
+
if (input.step.kind === "extractapi") {
|
|
3716
|
+
let replayoptions = {};
|
|
3717
|
+
try {
|
|
3718
|
+
replayoptions = parseoptions(input.step);
|
|
3719
|
+
} catch {
|
|
3720
|
+
replayoptions = {};
|
|
3721
|
+
}
|
|
3722
|
+
const replay = apireplayspecof(replayoptions.replay);
|
|
3723
|
+
if (replay !== void 0) {
|
|
3724
|
+
const replaygate = origincheck(input.session, replay.endpoint);
|
|
3725
|
+
if (!replaygate.allowed) return replaygate;
|
|
3726
|
+
}
|
|
3727
|
+
}
|
|
3049
3728
|
if (input.step.kind === "openlink" || input.step.kind === "openprivate" || input.step.kind === "batchopen" || input.step.kind === "prefetch" || input.step.kind === "deeplink" || input.step.kind === "reopentab") {
|
|
3050
3729
|
let options = {};
|
|
3051
3730
|
try {
|
|
@@ -3067,7 +3746,7 @@ function canexecute(input) {
|
|
|
3067
3746
|
}
|
|
3068
3747
|
|
|
3069
3748
|
// version.ts
|
|
3070
|
-
var packageversion = "1.1.
|
|
3749
|
+
var packageversion = "1.1.43";
|
|
3071
3750
|
|
|
3072
3751
|
// types.ts
|
|
3073
3752
|
var protocolversion = packageversion;
|
|
@@ -3088,6 +3767,10 @@ function parseproposal(value, origin, grants) {
|
|
|
3088
3767
|
const planinput = record(root.plan);
|
|
3089
3768
|
const stepsinput = planinput.steps;
|
|
3090
3769
|
if (!Array.isArray(stepsinput) || stepsinput.length === 0) throw new Error("A plan needs at least one step.");
|
|
3770
|
+
const createdat = Date.now();
|
|
3771
|
+
const expiresat = typeof planinput.expiresat === "number" ? planinput.expiresat : createdat + 10 * 60 * 1e3;
|
|
3772
|
+
if (expiresat <= createdat) throw new Error("Plan expiry must be in the future.");
|
|
3773
|
+
const planwindow = expiresat - createdat;
|
|
3091
3774
|
const steps = stepsinput.map((input, index) => {
|
|
3092
3775
|
const candidate = record(input);
|
|
3093
3776
|
const kind = text(candidate.kind, `step ${index + 1} kind`);
|
|
@@ -3095,7 +3778,7 @@ function parseproposal(value, origin, grants) {
|
|
|
3095
3778
|
id: typeof candidate.id === "string" ? candidate.id : crypto.randomUUID(),
|
|
3096
3779
|
kind,
|
|
3097
3780
|
summary: text(candidate.summary, `step ${index + 1} summary`),
|
|
3098
|
-
risk:
|
|
3781
|
+
risk: resolvedrisk(stepof(kind, candidate, index)),
|
|
3099
3782
|
...typeof candidate.target === "string" ? { target: candidate.target } : {},
|
|
3100
3783
|
...typeof candidate.value === "string" ? { value: candidate.value } : {},
|
|
3101
3784
|
...typeof candidate.options === "string" ? { options: candidate.options } : {}
|
|
@@ -3113,6 +3796,29 @@ function parseproposal(value, origin, grants) {
|
|
|
3113
3796
|
});
|
|
3114
3797
|
if (!granted) throw new Error(`The fetch request to ${target} targets an origin outside the grants.`);
|
|
3115
3798
|
}
|
|
3799
|
+
const channelurl = sockettarget(step);
|
|
3800
|
+
if (channelurl !== void 0) {
|
|
3801
|
+
const channeloriginvalue = channeloriginof(channelurl);
|
|
3802
|
+
const granted = covered.some((pattern) => {
|
|
3803
|
+
try {
|
|
3804
|
+
return new URL(channelurl).origin === new URL(pattern).origin || channeloriginvalue === new URL(pattern).origin;
|
|
3805
|
+
} catch {
|
|
3806
|
+
return false;
|
|
3807
|
+
}
|
|
3808
|
+
});
|
|
3809
|
+
if (!granted) throw new Error(`The channel to ${channelurl} targets an origin outside the grants.`);
|
|
3810
|
+
}
|
|
3811
|
+
let lifetime;
|
|
3812
|
+
try {
|
|
3813
|
+
const options = parseoptions(step);
|
|
3814
|
+
for (const key of ["socket", "subscription"]) {
|
|
3815
|
+
const value2 = options[key];
|
|
3816
|
+
if (value2 && typeof value2 === "object" && !Array.isArray(value2) && typeof value2.lifetime === "number") lifetime = value2.lifetime;
|
|
3817
|
+
}
|
|
3818
|
+
} catch {
|
|
3819
|
+
lifetime = void 0;
|
|
3820
|
+
}
|
|
3821
|
+
if (lifetime !== void 0 && lifetime > planwindow) throw new Error(`The channel lifetime of ${lifetime} milliseconds exceeds the reviewed plan window of ${planwindow} milliseconds.`);
|
|
3116
3822
|
return step;
|
|
3117
3823
|
});
|
|
3118
3824
|
for (const step of steps) {
|
|
@@ -3125,8 +3831,6 @@ function parseproposal(value, origin, grants) {
|
|
|
3125
3831
|
const review = submitreviewgranted(steps, step.id);
|
|
3126
3832
|
if (!review.allowed) throw new Error(review.reason);
|
|
3127
3833
|
}
|
|
3128
|
-
const createdat = Date.now();
|
|
3129
|
-
const expiresat = typeof planinput.expiresat === "number" ? planinput.expiresat : createdat + 10 * 60 * 1e3;
|
|
3130
3834
|
const plan = {
|
|
3131
3835
|
id: typeof planinput.id === "string" ? planinput.id : crypto.randomUUID(),
|
|
3132
3836
|
objective: text(planinput.objective, "objective"),
|
|
@@ -3136,14 +3840,24 @@ function parseproposal(value, origin, grants) {
|
|
|
3136
3840
|
expiresat,
|
|
3137
3841
|
state: "pending"
|
|
3138
3842
|
};
|
|
3139
|
-
if (plan.expiresat <= createdat) throw new Error("Plan expiry must be in the future.");
|
|
3140
3843
|
return { version: protocolversion, plan };
|
|
3141
3844
|
}
|
|
3845
|
+
function stepof(kind, candidate, index) {
|
|
3846
|
+
return { id: typeof candidate.id === "string" ? candidate.id : `candidate${index + 1}`, kind, summary: typeof candidate.summary === "string" ? candidate.summary : "", risk: "read", ...typeof candidate.options === "string" ? { options: candidate.options } : {} };
|
|
3847
|
+
}
|
|
3848
|
+
function channeloriginof(url) {
|
|
3849
|
+
try {
|
|
3850
|
+
const parsed = new URL(url);
|
|
3851
|
+
return `${parsed.protocol === "wss:" ? "https:" : parsed.protocol}//${parsed.host}`;
|
|
3852
|
+
} catch {
|
|
3853
|
+
return "";
|
|
3854
|
+
}
|
|
3855
|
+
}
|
|
3142
3856
|
function requestbody(input) {
|
|
3143
3857
|
return JSON.stringify({ version: protocolversion, objective: input.objective, session: input.session, observation: input.observation, capabilities: input.capabilities });
|
|
3144
3858
|
}
|
|
3145
3859
|
function outcomeresponse(input) {
|
|
3146
|
-
return JSON.stringify({ version: protocolversion, planid: input.plan.id, planstate: input.plan.state, outcome: input.outcome, ...input.resolvedtarget ? { resolvedtarget: input.resolvedtarget } : {}, ...input.capture ? { capture: input.capture } : {}, ...input.media ? { media: input.media } : {}, ...input.transport ? { transport: input.transport } : {} });
|
|
3860
|
+
return JSON.stringify({ version: protocolversion, planid: input.plan.id, planstate: input.plan.state, outcome: input.outcome, ...input.resolvedtarget ? { resolvedtarget: input.resolvedtarget } : {}, ...input.capture ? { capture: input.capture } : {}, ...input.media ? { media: input.media } : {}, ...input.transport ? { transport: input.transport } : {}, ...input.network ? { network: input.network } : {} });
|
|
3147
3861
|
}
|
|
3148
3862
|
function mapresponse(input) {
|
|
3149
3863
|
return JSON.stringify({ version: protocolversion, planid: input.plan.id, planstate: input.plan.state, map: input.map });
|
|
@@ -3234,10 +3948,17 @@ function callsreport(input) {
|
|
|
3234
3948
|
});
|
|
3235
3949
|
return { version: protocolversion, calls };
|
|
3236
3950
|
}
|
|
3951
|
+
function exchangesreport(input) {
|
|
3952
|
+
return { version: protocolversion, exchanges: input.exchanges, channels: input.channels, subscriptions: input.subscriptions, apimap: input.apimap };
|
|
3953
|
+
}
|
|
3237
3954
|
export {
|
|
3238
3955
|
annotationplanof,
|
|
3956
|
+
apientries,
|
|
3957
|
+
apireplayspecof,
|
|
3239
3958
|
assetentries,
|
|
3240
3959
|
blendrows,
|
|
3960
|
+
bodyfilterof,
|
|
3961
|
+
bodymatches,
|
|
3241
3962
|
buildname,
|
|
3242
3963
|
buildpdf,
|
|
3243
3964
|
buildsheet,
|
|
@@ -3246,6 +3967,8 @@ export {
|
|
|
3246
3967
|
callrest,
|
|
3247
3968
|
callsreport,
|
|
3248
3969
|
canexecute,
|
|
3970
|
+
capturebody,
|
|
3971
|
+
capturedheaders,
|
|
3249
3972
|
captureelement,
|
|
3250
3973
|
captureformats,
|
|
3251
3974
|
capturekinds,
|
|
@@ -3256,9 +3979,15 @@ export {
|
|
|
3256
3979
|
capturestitched,
|
|
3257
3980
|
capturetargets,
|
|
3258
3981
|
capturevisible,
|
|
3982
|
+
channeloptionsof,
|
|
3983
|
+
channelorigin,
|
|
3984
|
+
closechannel,
|
|
3985
|
+
collectmessages,
|
|
3259
3986
|
convertdirectiveof,
|
|
3987
|
+
correlationid,
|
|
3260
3988
|
croprect,
|
|
3261
3989
|
crossesviewport,
|
|
3990
|
+
cursorfrom,
|
|
3262
3991
|
datasetresponse,
|
|
3263
3992
|
dedupeimages,
|
|
3264
3993
|
actionrisk as deriveactionrisk,
|
|
@@ -3266,9 +3995,13 @@ export {
|
|
|
3266
3995
|
downloadreport,
|
|
3267
3996
|
errorreportresponse,
|
|
3268
3997
|
eventresponse,
|
|
3998
|
+
exchangesreport,
|
|
3269
3999
|
extractionreport,
|
|
4000
|
+
extractvalues,
|
|
4001
|
+
failureclass,
|
|
3270
4002
|
fetchoptionsof,
|
|
3271
4003
|
fetchrequestof,
|
|
4004
|
+
filterexchanges,
|
|
3272
4005
|
finishrecording,
|
|
3273
4006
|
fixedheadermatch,
|
|
3274
4007
|
formreportresponse,
|
|
@@ -3276,6 +4009,7 @@ export {
|
|
|
3276
4009
|
generatedvalueallowed,
|
|
3277
4010
|
graphqlopenvelope,
|
|
3278
4011
|
graphqlrequestof,
|
|
4012
|
+
headerfilterof,
|
|
3279
4013
|
heldkeysreport,
|
|
3280
4014
|
hostpattern,
|
|
3281
4015
|
htmlqueriesof,
|
|
@@ -3284,54 +4018,81 @@ export {
|
|
|
3284
4018
|
imagematches,
|
|
3285
4019
|
imagenames,
|
|
3286
4020
|
isformkind,
|
|
4021
|
+
isnetwatchkind,
|
|
4022
|
+
issocketkind,
|
|
3287
4023
|
iswatchkind,
|
|
3288
4024
|
jsonpathrulesof,
|
|
3289
4025
|
lapseframes,
|
|
3290
4026
|
lapseplanof,
|
|
3291
4027
|
layoutreport,
|
|
3292
4028
|
mapresponse,
|
|
4029
|
+
matchmessage,
|
|
3293
4030
|
mediaentries,
|
|
3294
4031
|
mediakinds,
|
|
3295
4032
|
mediareport,
|
|
4033
|
+
messagefilterof,
|
|
3296
4034
|
navstateresponse,
|
|
3297
4035
|
netlogreport,
|
|
4036
|
+
netwatchkinds,
|
|
4037
|
+
newchannel,
|
|
4038
|
+
newexchange,
|
|
3298
4039
|
newrecording,
|
|
3299
4040
|
normalizeendpoint,
|
|
3300
4041
|
observationmodeof,
|
|
3301
4042
|
observationresponse,
|
|
4043
|
+
openchannel,
|
|
3302
4044
|
outcomeresponse,
|
|
4045
|
+
pairexchange,
|
|
3303
4046
|
pairstates,
|
|
3304
4047
|
parsehtmlbody,
|
|
3305
4048
|
parseproposal,
|
|
4049
|
+
parsessetext,
|
|
3306
4050
|
passwordconsentgranted,
|
|
4051
|
+
payloadshapeof,
|
|
3307
4052
|
payloadvalid,
|
|
3308
4053
|
payloadwithdefaults,
|
|
3309
4054
|
pdfoptionsof,
|
|
3310
4055
|
pdfpagesize,
|
|
3311
4056
|
pdfsegments,
|
|
3312
4057
|
pdftextlayout,
|
|
4058
|
+
pollcursorof,
|
|
4059
|
+
polldecision,
|
|
4060
|
+
pollurl,
|
|
4061
|
+
privatemime,
|
|
3313
4062
|
profilegrantgranted,
|
|
3314
4063
|
protocolversion,
|
|
3315
4064
|
provenancereport,
|
|
4065
|
+
publishmessage,
|
|
3316
4066
|
quarantinereport,
|
|
3317
4067
|
randomid,
|
|
4068
|
+
rankapis,
|
|
3318
4069
|
readpath,
|
|
3319
4070
|
readstream,
|
|
4071
|
+
receivemessage,
|
|
4072
|
+
reconnectwaits,
|
|
3320
4073
|
recordingoptionsof,
|
|
3321
4074
|
regionsteps,
|
|
4075
|
+
replayurl,
|
|
3322
4076
|
requestbody,
|
|
3323
4077
|
resolutionverdict,
|
|
4078
|
+
resolvedrisk,
|
|
4079
|
+
resourcefacts,
|
|
3324
4080
|
safetyresponse,
|
|
3325
4081
|
scaledrect,
|
|
3326
4082
|
seamweights,
|
|
3327
4083
|
selectorresponse,
|
|
3328
4084
|
sendfetch,
|
|
4085
|
+
sequenceintegrity,
|
|
3329
4086
|
sessionmemory,
|
|
3330
4087
|
signalsreport,
|
|
4088
|
+
socketgate,
|
|
4089
|
+
socketkinds,
|
|
4090
|
+
sserequestheaders,
|
|
3331
4091
|
statusclassof,
|
|
3332
4092
|
streamsummaries,
|
|
3333
4093
|
streamwindowof,
|
|
3334
4094
|
submitreviewgranted,
|
|
4095
|
+
subscriptionoptionsof,
|
|
3335
4096
|
tabreportresponse,
|
|
3336
4097
|
templateurl,
|
|
3337
4098
|
thumbdirectiveof,
|
|
@@ -3344,6 +4105,7 @@ export {
|
|
|
3344
4105
|
validatestep,
|
|
3345
4106
|
validatetargetref,
|
|
3346
4107
|
validatevaluegen,
|
|
4108
|
+
watchgate,
|
|
3347
4109
|
wizardreport
|
|
3348
4110
|
};
|
|
3349
4111
|
//# sourceMappingURL=index.js.map
|