@wenathlan/extension 1.1.53 → 1.1.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4587,6 +4587,61 @@ var sessionmemory = class {
4587
4587
  async removeworkflowversion(id, version) {
4588
4588
  await this.adapter.set("workflowrecords", (await this.getworkflowrecordversions()).filter((entry) => !(entry.id === id && entry.version === version)));
4589
4589
  }
4590
+ /** Returns every stored mcp client record, newest first. */
4591
+ async getclients() {
4592
+ return await this.adapter.get("mcpclients") ?? [];
4593
+ }
4594
+ /** Upserts one mcp client record by its id so one clientrecord stays per connected transport. */
4595
+ async setclient(client) {
4596
+ const records = (await this.getclients()).filter((entry) => entry.id !== client.id);
4597
+ await this.adapter.set("mcpclients", [client, ...records]);
4598
+ }
4599
+ /** Returns the connected client records — every client whose disconnect time is absent. */
4600
+ async listclients() {
4601
+ return (await this.getclients()).filter((client) => client.disconnectedat === void 0);
4602
+ }
4603
+ /** Stores the negotiated capability set of one client on its record. */
4604
+ async setclientcapabilities(id, capabilities) {
4605
+ await this.adapter.set("mcpclients", (await this.getclients()).map((client) => client.id === id ? { ...client, capabilities } : client));
4606
+ }
4607
+ /** Drops every stored client record when the server stops. */
4608
+ async clearclients() {
4609
+ await this.adapter.set("mcpclients", []);
4610
+ }
4611
+ /** Records one stdio bridge launch event with its process id; a restart marker distinguishes the relaunch of a dead client process. */
4612
+ async addbridgelaunch(launch) {
4613
+ await this.adapter.set("mcbridgelaunches", [launch, ...await this.adapter.get("mcbridgelaunches") ?? []]);
4614
+ }
4615
+ /** Returns every stdio bridge launch event, newest first. */
4616
+ async listbridgelaunches() {
4617
+ return await this.adapter.get("mcbridgelaunches") ?? [];
4618
+ }
4619
+ /** Returns the user configured mcp server config; an absent record keeps the documented localhost default. */
4620
+ async getmcpconfig() {
4621
+ return this.adapter.get("mcpconfig");
4622
+ }
4623
+ /** Stores the user configured mcp server config: bind address, port, transports, frame size, queue depth and enablement all stay user choices. */
4624
+ async setmcpconfig(config) {
4625
+ return this.adapter.set("mcpconfig", config);
4626
+ }
4627
+ /** Returns the persisted mcp server runtime state. */
4628
+ async getmcpstate() {
4629
+ return this.adapter.get("mcpstate");
4630
+ }
4631
+ /** Stores the mcp server runtime state with the stdio bridge status. */
4632
+ async setmcpstate(state) {
4633
+ return this.adapter.set("mcpstate", state);
4634
+ }
4635
+ /** Records one mcp tool call — the client, the tool, the origin and the outcome without any payload — under the user configured call retention with no code ceiling. */
4636
+ async addtoolcall(record2) {
4637
+ const records = await this.listtoolcalls();
4638
+ const retention = (await this.getmcpconfig())?.callretention;
4639
+ await this.adapter.set("mcptoolcalls", retention === void 0 ? [record2, ...records] : [record2, ...records].slice(0, retention));
4640
+ }
4641
+ /** Returns every stored mcp tool call record, newest first. */
4642
+ async listtoolcalls() {
4643
+ return await this.adapter.get("mcptoolcalls") ?? [];
4644
+ }
4590
4645
  };
4591
4646
  function mediakindof(record2) {
4592
4647
  if ("pages" in record2) return "pdf";
@@ -4630,313 +4685,333 @@ function randomid() {
4630
4685
  return crypto.randomUUID();
4631
4686
  }
4632
4687
 
4633
- // netauth.ts
4634
- function oauthflowof(value) {
4635
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
4636
- const options = value;
4637
- if (typeof options.provider !== "string" || !options.provider.trim()) return void 0;
4638
- if (typeof options.authorizeurl !== "string" || !options.authorizeurl.trim()) return void 0;
4639
- if (typeof options.tokenurl !== "string" || !options.tokenurl.trim()) return void 0;
4640
- if (!Array.isArray(options.scopes) || options.scopes.length === 0 || !options.scopes.every((item) => typeof item === "string" && item.trim().length > 0)) return void 0;
4641
- if (typeof options.redirectorigin !== "string" || !options.redirectorigin.trim()) return void 0;
4642
- return { provider: options.provider.trim(), authorizeurl: options.authorizeurl.trim(), tokenurl: options.tokenurl.trim(), scopes: options.scopes.map((item) => item.trim()), redirectorigin: options.redirectorigin.trim() };
4688
+ // version.ts
4689
+ var packageversion = "1.1.54";
4690
+
4691
+ // types.ts
4692
+ var protocolversion = packageversion;
4693
+
4694
+ // toolcatalog.ts
4695
+ var toolcatalogversion = 1;
4696
+ var toolnamespaces = ["browser", "workflow", "memory", "system"];
4697
+ var domainkinds = {
4698
+ browser: ["observe", "extract", "readtext", "readtable", "readlinks", "a11ytree", "tablist", "windowlist", "click", "type", "presskey", "navigate", "back", "forward", "reload", "tabcreate", "tabactivate", "tabclose", "windowcreate", "windowclose", "windowresize"],
4699
+ workflow: ["composeworkflow", "runworkflow", "dryrun", "eventrule"],
4700
+ memory: ["listruns", "extractvars", "trailaudit"],
4701
+ system: ["observe", "readmeta"]
4702
+ };
4703
+ function toolschemaof(properties) {
4704
+ return { type: "object", properties, required: Object.entries(properties).filter(([, property]) => property.required === true).map(([name]) => name) };
4643
4705
  }
4644
- function authorizeurl(flow, state) {
4645
- const url = new URL(flow.authorizeurl);
4646
- url.searchParams.set("response_type", "code");
4647
- url.searchParams.set("redirect_uri", flow.redirectorigin);
4648
- url.searchParams.set("scope", flow.scopes.join(" "));
4649
- url.searchParams.set("state", state);
4650
- return url.toString();
4706
+ function readtool(name, kind, description, inputs = {}) {
4707
+ return { name, version: toolcatalogversion, description, inputschema: toolschemaof({ target: { type: "string", description: "Reviewed css selector the tool addresses." }, value: { type: "string", description: "Reviewed literal value the tool carries." }, options: { type: "object", description: "Reviewed json options of the wrapped action kind with the empty default.", default: {} }, ...inputs }), kind, risk: "read" };
4651
4708
  }
4652
- function capturecode(url, redirectorigin, state) {
4653
- let parsed;
4654
- try {
4655
- parsed = new URL(url);
4656
- } catch {
4657
- return { error: "The redirect url does not parse for the code capture." };
4658
- }
4659
- const granted = redirectorigin.includes("/", redirectorigin.indexOf("://") + 3) ? `${parsed.origin}${parsed.pathname}`.startsWith(redirectorigin) : parsed.origin === redirectorigin;
4660
- if (!granted) return { error: `The redirect landed on ${parsed.origin} outside the granted redirect origin ${redirectorigin}.` };
4661
- const returned = parsed.searchParams.get("state");
4662
- if (returned !== state) return { error: "The redirect state token does not match the reviewed flow." };
4663
- const error = parsed.searchParams.get("error");
4664
- if (error) return { error: `The provider refused the flow: ${error}.` };
4665
- const code = parsed.searchParams.get("code");
4666
- if (!code) return { error: "The redirect carries no authorization code." };
4667
- return { code };
4709
+ function gatedtool(name, kind, risk, description, review) {
4710
+ return { name, version: toolcatalogversion, description, inputschema: toolschemaof({ stepid: { type: "string", description: "Id of the approved plan step this tool executes.", required: true } }), kind, risk, consentmeta: { review } };
4668
4711
  }
4669
- function parsetokens(body) {
4670
- let parsed;
4671
- try {
4672
- parsed = JSON.parse(body);
4673
- } catch {
4674
- return void 0;
4675
- }
4676
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
4677
- const record2 = parsed;
4678
- const tokens = {};
4679
- if (typeof record2.access_token === "string" && record2.access_token) tokens.accesstoken = record2.access_token;
4680
- if (typeof record2.refresh_token === "string" && record2.refresh_token) tokens.refreshtoken = record2.refresh_token;
4681
- if (typeof record2.expires_in === "number" && Number.isFinite(record2.expires_in) && record2.expires_in >= 0) tokens.expiresin = record2.expires_in;
4682
- if (typeof record2.scope === "string" && record2.scope.trim()) tokens.scopes = record2.scope.trim().split(/\s+/);
4683
- if (tokens.accesstoken === void 0 && tokens.refreshtoken === void 0) return void 0;
4684
- return tokens;
4712
+ function browserdomain() {
4713
+ return {
4714
+ namespace: "browser",
4715
+ version: toolcatalogversion,
4716
+ tools: [
4717
+ readtool("browser.snapshot", "observe", "Captures the semantic snapshot of the active tab: url, title, text preview, forms and interactive elements. Read only with no side effects; runs under the dryrun risk class once the session is approved."),
4718
+ readtool("browser.extract", "extract", "Extracts the reviewed structured data of the page. Read only with no side effects."),
4719
+ readtool("browser.readtext", "readtext", "Reads the text of the addressed element. Read only with no side effects.", { target: { type: "string", description: "Reviewed css selector of the element to read.", required: true } }),
4720
+ readtool("browser.readtable", "readtable", "Reads the rows of the addressed data table. Read only with no side effects.", { target: { type: "string", description: "Reviewed css selector of the table to read.", required: true } }),
4721
+ readtool("browser.readlinks", "readlinks", "Reads the link inventory of the page. Read only with no side effects."),
4722
+ readtool("browser.a11ytree", "a11ytree", "Reads the accessibility tree of the page. Read only with no side effects."),
4723
+ readtool("browser.tablist", "tablist", "Lists the open tabs. Read only with no side effects."),
4724
+ readtool("browser.windowlist", "windowlist", "Lists the open windows. Read only with no side effects."),
4725
+ gatedtool("browser.click", "click", "sensitive", "Clicks the addressed element. Sensitive: it changes page state, so it executes exactly one approved plan step.", "The click runs only as the approved plan step it names; a paired client can never widen the reviewed target or options."),
4726
+ gatedtool("browser.type", "type", "sensitive", "Types the reviewed text into the addressed element. Sensitive: it changes page state, so it executes exactly one approved plan step.", "The typing runs only as the approved plan step it names; the reviewed target, text and options stay fixed."),
4727
+ gatedtool("browser.presskey", "presskey", "sensitive", "Presses the reviewed key. Sensitive: it changes page state, so it executes exactly one approved plan step.", "The key press runs only as the approved plan step it names."),
4728
+ gatedtool("browser.navigate", "navigate", "sensitive", "Navigates the active tab to the reviewed url. Sensitive: it changes browser state, so it executes exactly one approved plan step.", "The navigation runs only as the approved plan step it names and stays inside the session origin grants."),
4729
+ gatedtool("browser.back", "back", "sensitive", "Navigates back in the history of the active tab. Sensitive: it changes browser state, so it executes exactly one approved plan step.", "The history navigation runs only as the approved plan step it names."),
4730
+ gatedtool("browser.forward", "forward", "sensitive", "Navigates forward in the history of the active tab. Sensitive: it changes browser state, so it executes exactly one approved plan step.", "The history navigation runs only as the approved plan step it names."),
4731
+ gatedtool("browser.reload", "reload", "sensitive", "Reloads the active tab. Sensitive: it changes browser state, so it executes exactly one approved plan step.", "The reload runs only as the approved plan step it names."),
4732
+ gatedtool("browser.tabcreate", "tabcreate", "sensitive", "Opens a new tab. Sensitive: it changes browser state, so it executes exactly one approved plan step.", "The tab creation runs only as the approved plan step it names."),
4733
+ gatedtool("browser.tabactivate", "tabactivate", "sensitive", "Activates the reviewed tab. Sensitive: it moves focus, so it executes exactly one approved plan step.", "The tab activation runs only as the approved plan step it names."),
4734
+ gatedtool("browser.tabclose", "tabclose", "sensitive", "Closes the reviewed tab. Sensitive: it destroys browser state, so it executes exactly one approved plan step.", "The tab close runs only as the approved plan step it names."),
4735
+ gatedtool("browser.windowcreate", "windowcreate", "sensitive", "Opens a new window. Sensitive: it changes browser state, so it executes exactly one approved plan step.", "The window creation runs only as the approved plan step it names."),
4736
+ gatedtool("browser.windowclose", "windowclose", "sensitive", "Closes the reviewed window. Sensitive: it destroys browser state, so it executes exactly one approved plan step.", "The window close runs only as the approved plan step it names."),
4737
+ gatedtool("browser.windowresize", "windowresize", "sensitive", "Resizes the reviewed window. Sensitive: it changes browser state, so it executes exactly one approved plan step.", "The window resize runs only as the approved plan step it names.")
4738
+ ]
4739
+ };
4685
4740
  }
4686
- function tokenrequest(flow, input) {
4687
- if (input.refreshtoken !== void 0) return { url: flow.tokenurl, body: urlencodeform([{ name: "grant_type", value: "refresh_token" }, { name: "refresh_token", value: input.refreshtoken }]) };
4688
- return { url: flow.tokenurl, body: urlencodeform([{ name: "grant_type", value: "authorization_code" }, { name: "code", value: input.code ?? "" }, { name: "redirect_uri", value: flow.redirectorigin }]) };
4741
+ function workflowdomain() {
4742
+ return {
4743
+ namespace: "workflow",
4744
+ version: toolcatalogversion,
4745
+ tools: [
4746
+ readtool("workflow.list", "composeworkflow", "Lists the composed workflows with their names, versions, origins and step counts. Read only with no side effects."),
4747
+ readtool("workflow.dryrun", "dryrun", "Runs a composed workflow as a dry run: read steps project their would be outcome and every step with side effects is refused. Read only with no side effects."),
4748
+ gatedtool("workflow.run", "runworkflow", "sensitive", "Runs a composed workflow for real. Sensitive: it executes every step of the workflow, so it executes exactly one approved runworkflow plan step with its explicit run review.", "The workflow run needs the explicit run review: the approved runworkflow plan step with its expanded step list shown before the first step executes."),
4749
+ gatedtool("workflow.triggers", "eventrule", "sensitive", "Lists the armed trigger rules with their schedules, cooldowns and fire counters so a client can inspect what launches runs automatically. Sensitive by its trigger family: automatic launchers stay behind the arm review class.", "The trigger listing runs behind the approved plan review because trigger rules launch runs automatically.")
4750
+ ]
4751
+ };
4689
4752
  }
4690
- function revocationruleof(value) {
4691
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
4692
- const options = value;
4693
- if (!Array.isArray(options.tokenids) || options.tokenids.length === 0 || !options.tokenids.every((item) => typeof item === "string" && item.trim().length > 0)) return void 0;
4694
- if (typeof options.reason !== "string" || !options.reason.trim()) return void 0;
4695
- return { tokenids: options.tokenids.map((item) => item.trim()), reason: options.reason.trim(), revokedat: Date.now() };
4753
+ function memorydomain() {
4754
+ return {
4755
+ namespace: "memory",
4756
+ version: toolcatalogversion,
4757
+ tools: [
4758
+ readtool("memory.list", "listruns", "Lists the stored workflow run records with their states and step cursors from local memory. Read only with no page access.", { target: { type: "string", description: "Unused by the memory read; kept for schema uniformity." }, value: { type: "string", description: "Unused by the memory read; kept for schema uniformity." }, state: { type: "string", description: "Optional reviewed run state filter of the listing.", default: "" } }),
4759
+ readtool("memory.variables", "extractvars", "Reads the stored variable scopes of a run from local memory. Read only with no page access."),
4760
+ readtool("memory.audit", "trailaudit", "Reads the audit summary of the session trail from local memory. Read only with no page access.")
4761
+ ]
4762
+ };
4696
4763
  }
4697
- function formpayloadof(value) {
4698
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
4699
- const options = value;
4700
- if (typeof options.url !== "string" || !options.url.trim()) return void 0;
4701
- if (!Array.isArray(options.fields) || options.fields.length === 0) return void 0;
4702
- const fields = [];
4703
- for (const item of options.fields) {
4704
- if (!item || typeof item !== "object" || Array.isArray(item)) return void 0;
4705
- const field = item;
4706
- if (typeof field.name !== "string" || !field.name.trim()) return void 0;
4707
- if (typeof field.value !== "string") return void 0;
4708
- fields.push({ name: field.name.trim(), value: field.value });
4709
- }
4710
- return { url: options.url.trim(), fields };
4764
+ function systemdomain() {
4765
+ return {
4766
+ namespace: "system",
4767
+ version: toolcatalogversion,
4768
+ tools: [
4769
+ readtool("system.status", "observe", "Reports the mcp server status, the session state and the connected clients. Read only with no side effects."),
4770
+ readtool("system.version", "readmeta", "Reports the protocol version, the catalog version and the extension version. Read only with no side effects."),
4771
+ readtool("system.capabilities", "observe", "Reports the optional browser capabilities the user has granted. Read only with no side effects.")
4772
+ ]
4773
+ };
4711
4774
  }
4712
- function urlencodeform(fields) {
4713
- return fields.map((field) => `${formencode(field.name)}=${formencode(field.value)}`).join("&");
4775
+ function buildtoolcatalog() {
4776
+ return { version: toolcatalogversion, domains: [browserdomain(), workflowdomain(), memorydomain(), systemdomain()] };
4714
4777
  }
4715
- function formencode(value) {
4716
- const bytes = [...new TextEncoder().encode(value)];
4717
- return bytes.map((byte) => byte >= 65 && byte <= 90 || byte >= 97 && byte <= 122 || byte >= 48 && byte <= 57 || byte === 45 || byte === 95 || byte === 46 || byte === 126 ? String.fromCharCode(byte) : `%${byte.toString(16).toUpperCase().padStart(2, "0")}`).join("");
4778
+ function alltools(catalog) {
4779
+ return catalog.domains.flatMap((domain) => domain.tools);
4718
4780
  }
4719
- function multipartpayloadof(value) {
4720
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
4721
- const options = value;
4722
- if (typeof options.url !== "string" || !options.url.trim()) return void 0;
4723
- if (!Array.isArray(options.files) || options.files.length === 0) return void 0;
4724
- const fields = [];
4725
- for (const item of Array.isArray(options.fields) ? options.fields : []) {
4726
- if (!item || typeof item !== "object" || Array.isArray(item)) return void 0;
4727
- const field = item;
4728
- if (typeof field.name !== "string" || !field.name.trim()) return void 0;
4729
- if (typeof field.value !== "string") return void 0;
4730
- fields.push({ name: field.name.trim(), value: field.value });
4731
- }
4732
- const files = [];
4733
- for (const item of options.files) {
4734
- if (!item || typeof item !== "object" || Array.isArray(item)) return void 0;
4735
- const file = item;
4736
- if (typeof file.name !== "string" || !file.name.trim()) return void 0;
4737
- if (typeof file.filename !== "string" || !file.filename.trim()) return void 0;
4738
- if (typeof file.mime !== "string" || !file.mime.trim()) return void 0;
4739
- if (typeof file.content !== "string") return void 0;
4740
- if (file.reviewed !== true) return void 0;
4741
- files.push({ name: file.name.trim(), filename: file.filename.trim(), mime: file.mime.trim(), content: file.content, reviewed: true });
4742
- }
4743
- const payload = { url: options.url.trim(), fields, files, ...typeof options.boundary === "string" && options.boundary.trim() ? { boundary: options.boundary.trim() } : {} };
4744
- return payload;
4781
+ function toolname(namespace, base) {
4782
+ return `${namespace}.${base}`;
4745
4783
  }
4746
- function newboundary() {
4747
- return `----devthink${Math.random().toString(16).slice(2)}${Date.now().toString(16)}`;
4784
+ function resolvetool(catalog, name) {
4785
+ if (name.includes(".")) return alltools(catalog).find((tool) => tool.name === name);
4786
+ const matches = alltools(catalog).filter((tool) => tool.name.split(".")[1] === name);
4787
+ return matches.length === 1 ? matches[0] : void 0;
4748
4788
  }
4749
- function multipartchunks(payload) {
4750
- const boundary = payload.boundary ?? newboundary();
4751
- const chunks = [];
4752
- for (const field of payload.fields) chunks.push(`--${boundary}\r
4753
- content-disposition: form-data; name="${field.name}"\r
4754
- \r
4755
- ${field.value}\r
4756
- `);
4757
- for (const file of payload.files) chunks.push(`--${boundary}\r
4758
- content-disposition: form-data; name="${file.name}"; filename="${file.filename}"\r
4759
- content-type: ${file.mime}\r
4760
- \r
4761
- ${file.content}\r
4762
- `);
4763
- chunks.push(`--${boundary}--\r
4764
- `);
4765
- return { chunks, boundary, bytes: chunks.reduce((total, chunk) => total + chunk.length, 0) };
4789
+ function namespaceof(name) {
4790
+ const head = name.split(".")[0];
4791
+ return toolnamespaces.includes(head) ? head : void 0;
4766
4792
  }
4767
-
4768
- // netcontrol.ts
4769
- var controlkinds = ["blockrequest", "mockresponse", "rewriteheaders", "setcookies", "readcookies", "clearcookies", "authflow", "saveapikey", "routeproxy", "postform", "postfiles"];
4770
- function patternorigin(pattern) {
4771
- const trimmed = pattern.trim();
4772
- if (!trimmed.startsWith("https://")) return void 0;
4773
- const rest = trimmed.slice("https://".length);
4774
- const host = rest.split("/")[0] ?? "";
4775
- if (!host.trim()) return void 0;
4776
- return `https://${host.toLowerCase()}`;
4793
+ function toolsbynamespace(catalog) {
4794
+ return catalog.domains.map((domain) => ({ namespace: domain.namespace, version: domain.version, tools: domain.tools }));
4777
4795
  }
4778
- function matchurlpattern(pattern, url) {
4779
- const origin = patternorigin(pattern);
4780
- if (!origin) return false;
4781
- let parsed;
4796
+
4797
+ // socketbus.ts
4798
+ var socketkinds = ["opensocket", "sendmessage", "waitmessage", "subscribesse", "longpoll"];
4799
+ function channelorigin(url) {
4782
4800
  try {
4783
- parsed = new URL(url);
4801
+ const parsed = new URL(url);
4802
+ const protocol = parsed.protocol === "wss:" ? "https:" : parsed.protocol === "ws:" ? "http:" : parsed.protocol;
4803
+ return `${protocol}//${parsed.host}`;
4784
4804
  } catch {
4785
- return false;
4805
+ return "";
4786
4806
  }
4787
- if (parsed.origin !== origin) return false;
4788
- const patternpath = pattern.trim().slice(origin.length);
4789
- if (patternpath === "" || patternpath === "/") return true;
4790
- const segments = patternpath.split("/").filter((segment) => segment !== "");
4791
- if (segments.includes("**")) return true;
4792
- const pathsegments = parsed.pathname.split("/").filter((segment) => segment !== "");
4793
- if (segments.length !== pathsegments.length) return false;
4794
- return segments.every((segment, index) => segment === pathsegments[index] || segment.includes("*") && new RegExp(`^${segment.split("*").map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join(".*")}$`).test(pathsegments[index] ?? ""));
4795
4807
  }
4796
- function blockruleof(value) {
4808
+ function channeloptionsof(value) {
4797
4809
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
4798
- const options = value;
4799
- if (typeof options.urlpattern !== "string" || !options.urlpattern.trim()) return void 0;
4800
- const rule = { urlpattern: options.urlpattern.trim() };
4801
- if (Array.isArray(options.resourcetypes)) {
4802
- const types = options.resourcetypes.filter((item) => typeof item === "string" && item.trim().length > 0);
4803
- if (types.length === 0) return void 0;
4804
- rule.resourcetypes = types;
4810
+ const entry = value;
4811
+ if (typeof entry.url !== "string" || !entry.url.trim()) return void 0;
4812
+ const options = {};
4813
+ if (Array.isArray(entry.protocols)) options.protocols = entry.protocols.filter((item) => typeof item === "string" && item.trim().length > 0);
4814
+ if (typeof entry.reconnect === "number" && Number.isFinite(entry.reconnect)) options.reconnect = entry.reconnect;
4815
+ if (typeof entry.backoff === "number" && Number.isFinite(entry.backoff)) options.backoff = entry.backoff;
4816
+ if (typeof entry.backoffceiling === "number" && Number.isFinite(entry.backoffceiling)) options.backoffceiling = entry.backoffceiling;
4817
+ if (typeof entry.lifetime === "number" && Number.isFinite(entry.lifetime)) options.lifetime = entry.lifetime;
4818
+ return { url: entry.url.trim(), options };
4819
+ }
4820
+ function newchannel(input) {
4821
+ 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] } : {} };
4822
+ }
4823
+ function reconnectwaits(attempts, base, ceiling) {
4824
+ const count = Math.max(0, Math.floor(attempts));
4825
+ const waits = [];
4826
+ let wait = Math.max(0, base);
4827
+ for (let index = 0; index < count; index += 1) {
4828
+ waits.push(wait);
4829
+ const next = wait * 2;
4830
+ wait = ceiling !== void 0 && Number.isFinite(ceiling) && ceiling >= 0 ? Math.min(next, ceiling) : next;
4805
4831
  }
4806
- return rule;
4832
+ return waits;
4807
4833
  }
4808
- function newblockrule(input) {
4809
- return { id: input.id, runid: input.runid, stepid: input.stepid, urlpattern: input.urlpattern, ...input.resourcetypes !== void 0 ? { resourcetypes: input.resourcetypes } : {}, hits: 0, registeredat: input.at };
4834
+ async function openchannel(input) {
4835
+ const sleep = input.sleep ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, Math.max(0, milliseconds))));
4836
+ const now = input.now ?? Date.now;
4837
+ const attempts = Math.max(1, Math.floor(input.options.reconnect ?? 0) + 1);
4838
+ const waits = reconnectwaits(attempts - 1, input.options.backoff ?? 0, input.options.backoffceiling);
4839
+ let record2 = { ...input.record, state: "connecting" };
4840
+ let lasterror = "";
4841
+ for (let attempt = 0; attempt < attempts; attempt += 1) {
4842
+ try {
4843
+ const result = await input.connect(record2.url, record2.protocols ?? []);
4844
+ if (result.open) return { ...record2, state: "open", openedat: now() };
4845
+ lasterror = result.error ?? `closed with code ${result.code ?? 0}`;
4846
+ } catch (error) {
4847
+ lasterror = error instanceof Error ? error.message : String(error);
4848
+ }
4849
+ if (attempt < attempts - 1) {
4850
+ const wait = waits[attempt] ?? 0;
4851
+ if (wait > 0) await sleep(wait);
4852
+ record2 = { ...record2, reconnects: record2.reconnects + 1 };
4853
+ }
4854
+ }
4855
+ return { ...record2, state: "failed", error: lasterror };
4810
4856
  }
4811
- function mockspecof(value) {
4812
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
4813
- const options = value;
4814
- if (typeof options.urlpattern !== "string" || !options.urlpattern.trim()) return void 0;
4815
- if (typeof options.status !== "number" || !Number.isInteger(options.status) || options.status < 100 || options.status > 599) return void 0;
4816
- const hasbody = typeof options.body === "string";
4817
- const bodyref = typeof options.bodyref === "string" ? options.bodyref.trim() : "";
4818
- if (!hasbody && bodyref === "") return void 0;
4819
- const spec = { urlpattern: options.urlpattern.trim(), status: options.status };
4820
- if (hasbody) spec.body = options.body;
4821
- if (bodyref !== "") spec.bodyref = bodyref;
4822
- if (options.headers && typeof options.headers === "object" && !Array.isArray(options.headers)) spec.headers = options.headers;
4823
- if (options.reviewed === true) spec.reviewed = true;
4824
- return spec;
4857
+ function closechannel(record2, at, error) {
4858
+ const state = error !== void 0 ? "failed" : "closed";
4859
+ return { ...record2, state, closedat: at, ...error !== void 0 ? { error } : {} };
4825
4860
  }
4826
- function newmockspec(input) {
4827
- return { id: input.id, runid: input.runid, stepid: input.stepid, urlpattern: input.urlpattern, status: input.status, ...input.headers !== void 0 ? { headers: input.headers } : {}, ...input.body !== void 0 ? { body: input.body } : {}, ...input.bodyref !== void 0 ? { bodyref: input.bodyref } : {}, reviewed: input.reviewed, hits: 0, registeredat: input.at };
4861
+ function tagmessage(state, channelid, stream, payload, at) {
4862
+ const sequence = (state.sequences[channelid] ?? 0) + 1;
4863
+ const envelope = { channelid, stream, payload, sequence, at };
4864
+ return { state: { sequences: { ...state.sequences, [channelid]: sequence }, queue: state.queue }, envelope };
4828
4865
  }
4829
- function mockfor(url, specs) {
4830
- return specs.find((spec) => spec.revertedat === void 0 && matchurlpattern(spec.urlpattern, url));
4866
+ function publishmessage(state, channelid, stream, payload, at) {
4867
+ return tagmessage(state, channelid, stream, payload, at);
4831
4868
  }
4832
- function headeruleof(value) {
4833
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
4834
- const options = value;
4835
- if (typeof options.urlpattern !== "string" || !options.urlpattern.trim()) return void 0;
4836
- if (typeof options.name !== "string" || !options.name.trim()) return void 0;
4837
- if (options.operation !== "set" && options.operation !== "append" && options.operation !== "remove") return void 0;
4838
- if (options.operation === "remove" && options.value !== void 0) return void 0;
4839
- if (options.operation !== "remove" && typeof options.value !== "string") return void 0;
4840
- const rule = { urlpattern: options.urlpattern.trim(), name: options.name.trim(), operation: options.operation };
4841
- if (options.operation !== "remove") rule.value = typeof options.value === "string" ? options.value : "";
4842
- return rule;
4869
+ function receivemessage(state, channelid, stream, payload, at) {
4870
+ const tagged = tagmessage(state, channelid, stream, payload, at);
4871
+ return { state: { ...tagged.state, queue: [...state.queue, tagged.envelope] }, envelope: tagged.envelope };
4843
4872
  }
4844
- function newheaderule(input) {
4845
- return { id: input.id, runid: input.runid, stepid: input.stepid, urlpattern: input.urlpattern, name: input.name, operation: input.operation, ...input.value !== void 0 ? { value: input.value } : {}, hits: 0, registeredat: input.at };
4873
+ function pathstep2(current, segment) {
4874
+ if (Array.isArray(current) && /^\d+$/.test(segment)) return current[Number.parseInt(segment, 10)];
4875
+ if (current && typeof current === "object" && !Array.isArray(current)) return current[segment];
4876
+ return void 0;
4846
4877
  }
4847
- function applyheaderules(url, headers, rules) {
4848
- const rewritten = { ...headers };
4849
- const applied = [];
4850
- for (const rule of rules) {
4851
- if (rule.revertedat !== void 0) continue;
4852
- if (!matchurlpattern(rule.urlpattern, url)) continue;
4853
- const name = rule.name;
4854
- if (rule.operation === "remove") {
4855
- delete rewritten[name];
4856
- applied.push(rule);
4857
- continue;
4878
+ function matchmessage(filter, envelope) {
4879
+ if (!filter) return true;
4880
+ if (filter.stream !== void 0 && filter.stream !== envelope.stream) return false;
4881
+ if (filter.path !== void 0) {
4882
+ try {
4883
+ const parsed = JSON.parse(envelope.payload);
4884
+ let current = parsed;
4885
+ let missing = false;
4886
+ for (const segment of filter.path.split(".")) {
4887
+ const next = pathstep2(current, segment);
4888
+ if (next === void 0) {
4889
+ missing = true;
4890
+ break;
4891
+ }
4892
+ current = next;
4893
+ }
4894
+ if (missing) return false;
4895
+ } catch {
4896
+ return false;
4858
4897
  }
4859
- const value = rule.value ?? "";
4860
- if (rule.operation === "set") rewritten[name] = value;
4861
- else rewritten[name] = rewritten[name] !== void 0 ? `${rewritten[name]}, ${value}` : value;
4862
- applied.push(rule);
4863
4898
  }
4864
- return { headers: rewritten, applied };
4899
+ return true;
4865
4900
  }
4866
- function revertrule(rule, at) {
4867
- if (rule.revertedat !== void 0) return rule;
4868
- return { ...rule, revertedat: at };
4901
+ function collectmessages(state, channelid, filter) {
4902
+ const limit = filter?.limit !== void 0 && Number.isFinite(filter.limit) && filter.limit >= 1 ? Math.floor(filter.limit) : Number.POSITIVE_INFINITY;
4903
+ const matched = [];
4904
+ const queue = [];
4905
+ for (const envelope of state.queue) {
4906
+ if (envelope.channelid === channelid && matched.length < limit && matchmessage(filter, envelope)) matched.push(envelope);
4907
+ else queue.push(envelope);
4908
+ }
4909
+ return { state: { sequences: state.sequences, queue }, matched };
4869
4910
  }
4870
- function cookierecordof(value) {
4871
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
4872
- const options = value;
4873
- if (typeof options.name !== "string" || !options.name.trim()) return void 0;
4874
- if (typeof options.domain !== "string" || !options.domain.trim()) return void 0;
4875
- if (typeof options.path !== "string" || !options.path.trim()) return void 0;
4876
- if (typeof options.value !== "string") return void 0;
4877
- const record2 = { name: options.name.trim(), domain: options.domain.trim().toLowerCase(), path: options.path.trim(), value: options.value };
4878
- if (typeof options.expiresat === "number" && Number.isFinite(options.expiresat)) record2.expiresat = options.expiresat;
4879
- return record2;
4911
+ function sequenceintegrity(envelopes) {
4912
+ const last = /* @__PURE__ */ new Map();
4913
+ const gaps = [];
4914
+ for (const envelope of envelopes) {
4915
+ const expected = (last.get(envelope.channelid) ?? 0) + 1;
4916
+ if (envelope.sequence !== expected) gaps.push({ channelid: envelope.channelid, expected, found: envelope.sequence });
4917
+ last.set(envelope.channelid, Math.max(envelope.sequence, expected));
4918
+ }
4919
+ return { ok: gaps.length === 0, gaps };
4880
4920
  }
4881
- function cookiedomaingranted(domain, grants) {
4882
- const host = domain.trim().toLowerCase().replace(/^\./, "");
4883
- return grants.some((grant) => {
4884
- let granthost = "";
4885
- try {
4886
- granthost = new URL(grant).hostname.toLowerCase();
4887
- } catch {
4888
- return false;
4921
+ function messagefilterof(value) {
4922
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
4923
+ const entry = value;
4924
+ const filter = {};
4925
+ if (typeof entry.stream === "string" && entry.stream.trim()) filter.stream = entry.stream.trim();
4926
+ if (typeof entry.path === "string" && entry.path.trim()) filter.path = entry.path.trim();
4927
+ if (typeof entry.limit === "number" && Number.isFinite(entry.limit) && entry.limit >= 1) filter.limit = Math.floor(entry.limit);
4928
+ return filter;
4929
+ }
4930
+ function parsessetext(text2) {
4931
+ const separator = text2.lastIndexOf("\n\n");
4932
+ const complete = separator === -1 ? "" : text2.slice(0, separator + 2);
4933
+ const rest = separator === -1 ? text2 : text2.slice(separator + 2);
4934
+ const events = [];
4935
+ for (const block of complete.split(/\n\n/)) {
4936
+ const id = [];
4937
+ const names = [];
4938
+ const data = [];
4939
+ let retry;
4940
+ for (const line of block.split("\n")) {
4941
+ if (line === "" || line.startsWith(":")) continue;
4942
+ const colon = line.indexOf(":");
4943
+ const field = colon === -1 ? line : line.slice(0, colon);
4944
+ let value = colon === -1 ? "" : line.slice(colon + 1);
4945
+ if (value.startsWith(" ")) value = value.slice(1);
4946
+ if (field === "id" && value !== "") id.push(value);
4947
+ if (field === "event" && value !== "") names.push(value);
4948
+ if (field === "data") data.push(value);
4949
+ if (field === "retry" && /^\d+$/.test(value)) retry = Number.parseInt(value, 10);
4889
4950
  }
4890
- return host === granthost || host.endsWith(`.${granthost}`);
4891
- });
4951
+ if (id.length === 0 && names.length === 0 && data.length === 0) continue;
4952
+ 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 } : {} });
4953
+ }
4954
+ return { events, rest };
4892
4955
  }
4893
- function redactedcookies(records) {
4894
- return records.map((record2) => ({ name: record2.name, domain: record2.domain, path: record2.path, ...record2.expiresat !== void 0 ? { expiresat: record2.expiresat } : {} }));
4956
+ function sserequestheaders(record2) {
4957
+ return { accept: "text/event-stream", ...record2.lasteventid !== void 0 && record2.lasteventid !== "" ? { "last-event-id": record2.lasteventid } : {} };
4958
+ }
4959
+ function subscriptionoptionsof(value) {
4960
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
4961
+ const entry = value;
4962
+ if (typeof entry.url !== "string" || !entry.url.trim()) return void 0;
4963
+ const cancel = entry.cancel;
4964
+ if (!cancel || typeof cancel !== "object" || Array.isArray(cancel)) return void 0;
4965
+ const cancelrecord = cancel;
4966
+ if (cancelrecord.kind !== "stop" && cancelrecord.kind !== "lifetime") return void 0;
4967
+ if (typeof cancelrecord.value !== "string" && typeof cancelrecord.value !== "number") return void 0;
4968
+ const result = { url: entry.url.trim(), cancel: { kind: cancelrecord.kind, value: cancelrecord.value } };
4969
+ if (typeof entry.lifetime === "number" && Number.isFinite(entry.lifetime) && entry.lifetime > 0) result.lifetime = entry.lifetime;
4970
+ if (typeof entry.lasteventid === "string" && entry.lasteventid.trim()) result.lasteventid = entry.lasteventid.trim();
4971
+ return result;
4895
4972
  }
4896
- function proxyrouteof(value) {
4973
+ function pollcursorof(value) {
4897
4974
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
4898
- const options = value;
4899
- if (options.scheme !== "http" && options.scheme !== "https" && options.scheme !== "socks4" && options.scheme !== "socks5") return void 0;
4900
- if (typeof options.host !== "string" || !options.host.trim()) return void 0;
4901
- if (typeof options.port !== "number" || !Number.isInteger(options.port) || options.port < 1 || options.port > 65535) return void 0;
4902
- if (!Array.isArray(options.bypass) || options.bypass.length === 0 || !options.bypass.every((item) => typeof item === "string" && item.trim().length > 0)) return void 0;
4903
- return { scheme: options.scheme, host: options.host.trim(), port: options.port, bypass: options.bypass.map((item) => item.trim()) };
4975
+ const entry = value;
4976
+ if (typeof entry.url !== "string" || !entry.url.trim()) return void 0;
4977
+ if (typeof entry.cursorfield !== "string" || !entry.cursorfield.trim()) return void 0;
4978
+ if (typeof entry.interval !== "number" || !Number.isFinite(entry.interval) || entry.interval <= 0) return void 0;
4979
+ const stop = entry.stop;
4980
+ if (!stop || typeof stop !== "object" || Array.isArray(stop)) return void 0;
4981
+ const stoprecord = stop;
4982
+ if (typeof stoprecord.field !== "string" || !stoprecord.field.trim()) return void 0;
4983
+ if (typeof stoprecord.equals !== "string") return void 0;
4984
+ const cursor = { url: entry.url.trim(), cursorfield: entry.cursorfield.trim(), interval: entry.interval, stop: { field: stoprecord.field.trim(), equals: stoprecord.equals } };
4985
+ if (typeof entry.maxpolls === "number" && Number.isFinite(entry.maxpolls) && entry.maxpolls >= 1) cursor.maxpolls = Math.floor(entry.maxpolls);
4986
+ if (typeof entry.param === "string" && entry.param.trim()) cursor.param = entry.param.trim();
4987
+ return cursor;
4904
4988
  }
4905
- function ratelimitreadof(headers, origin, now) {
4906
- const pick = (name) => {
4907
- for (const key of Object.keys(headers)) {
4908
- if (key.toLowerCase() !== name) continue;
4909
- const value = Number(headers[key]);
4910
- return Number.isFinite(value) && value >= 0 ? value : void 0;
4911
- }
4912
- return void 0;
4913
- };
4914
- const remaining = pick("x-ratelimit-remaining");
4915
- const limit = pick("x-ratelimit-limit");
4916
- const reset = pick("x-ratelimit-reset");
4917
- if (remaining === void 0 && limit === void 0 && reset === void 0) return void 0;
4918
- const read = { origin, ...remaining !== void 0 ? { remaining } : {}, ...limit !== void 0 ? { limit } : {}, resetat: now, at: now };
4919
- if (reset !== void 0) read.resetat = reset > Math.floor(now / 1e3) ? reset * 1e3 : now + reset * 1e3;
4920
- return read;
4989
+ function cursorfrom(response, field) {
4990
+ let current = response;
4991
+ for (const segment of field.split(".")) {
4992
+ const next = pathstep2(current, segment);
4993
+ if (next === void 0) return void 0;
4994
+ current = next;
4995
+ }
4996
+ return current === void 0 || current === null ? void 0 : String(current);
4921
4997
  }
4922
- function retryafterof(status, headers) {
4923
- if (status !== 429 && status !== 503) return void 0;
4924
- for (const key of Object.keys(headers)) {
4925
- if (key.toLowerCase() !== "retry-after") continue;
4926
- const raw = headers[key];
4927
- if (raw === void 0) continue;
4928
- const value = raw.trim();
4929
- const seconds = Number(value);
4930
- if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
4931
- const date = Date.parse(value);
4932
- if (Number.isFinite(date)) return Math.max(0, date - Date.now());
4933
- return void 0;
4998
+ function pollurl(cursor, value) {
4999
+ if (cursor.param === void 0 || value === void 0) {
5000
+ return { url: cursor.url, ...value !== void 0 ? { body: JSON.stringify({ [cursor.cursorfield]: value }) } : {} };
4934
5001
  }
4935
- return void 0;
5002
+ const url = new URL(cursor.url);
5003
+ url.searchParams.set(cursor.param, value);
5004
+ return { url: url.toString() };
4936
5005
  }
4937
- function ratelimitwait(state, now) {
4938
- if (!state) return 0;
4939
- return Math.max(0, state.resetat - now);
5006
+ function polldecision(input) {
5007
+ if (input.cancelled?.() === true) return { continue: false, reason: "The long poll loop was cancelled." };
5008
+ if (input.expiresat !== void 0 && input.now >= input.expiresat) return { continue: false, reason: "The long poll loop stopped at the reviewed plan expiry." };
5009
+ const stopvalue = cursorfrom(input.response, input.cursor.stop.field);
5010
+ if (stopvalue !== void 0 && stopvalue === input.cursor.stop.equals) return { continue: false, reason: `The stop condition matched ${input.cursor.stop.field} ${stopvalue}.` };
5011
+ 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}.` };
5012
+ const value = cursorfrom(input.response, input.cursor.cursorfield);
5013
+ const next = pollurl(input.cursor, value);
5014
+ return { continue: true, reason: "The long poll loop continues.", ...value !== void 0 ? { cursor: value } : {}, next: { ...next, wait: input.cursor.interval } };
4940
5015
  }
4941
5016
 
4942
5017
  // netwatch.ts
@@ -5043,84 +5118,258 @@ function payloadshapeof(body) {
5043
5118
  return [];
5044
5119
  }
5045
5120
  }
5046
- function isapicandidate(exchange) {
5047
- if (exchange.initiator === "fetch" || exchange.initiator === "xmlhttprequest") return true;
5048
- if (exchange.bodyref !== void 0) return true;
5049
- try {
5050
- return /\/api\/|\/graphql|\.json($|\?)|\/v\d+\//i.test(new URL(exchange.url).pathname);
5051
- } catch {
5052
- return false;
5053
- }
5121
+ function isapicandidate(exchange) {
5122
+ if (exchange.initiator === "fetch" || exchange.initiator === "xmlhttprequest") return true;
5123
+ if (exchange.bodyref !== void 0) return true;
5124
+ try {
5125
+ return /\/api\/|\/graphql|\.json($|\?)|\/v\d+\//i.test(new URL(exchange.url).pathname);
5126
+ } catch {
5127
+ return false;
5128
+ }
5129
+ }
5130
+ function apientries(exchanges, bodies) {
5131
+ const bodybyref = new Map(bodies.map((body) => [body.correlationid, body]));
5132
+ const groups = /* @__PURE__ */ new Map();
5133
+ for (const exchange of exchanges) {
5134
+ if (!isapicandidate(exchange)) continue;
5135
+ let endpoint = exchange.url;
5136
+ let origin = exchange.origin;
5137
+ try {
5138
+ const parsed = new URL(exchange.url);
5139
+ endpoint = `${parsed.origin}${parsed.pathname}`;
5140
+ origin = parsed.origin;
5141
+ } catch {
5142
+ }
5143
+ const key = `${exchange.method} ${endpoint}`;
5144
+ 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: [] };
5145
+ group.frequency += 1;
5146
+ group.correlationids.push(exchange.correlationid);
5147
+ const body = exchange.bodyref !== void 0 ? bodybyref.get(exchange.correlationid) : void 0;
5148
+ const mime = body?.mime ?? exchange.mime ?? "";
5149
+ group.mimes.set(mime, (group.mimes.get(mime) ?? 0) + 1);
5150
+ if (body !== void 0) {
5151
+ group.captured += 1;
5152
+ const shape = payloadshapeof(body.body);
5153
+ if (shape.length > 0) group.json += 1;
5154
+ const shapekey = shape.join(",");
5155
+ group.shapes.set(shapekey, (group.shapes.get(shapekey) ?? 0) + 1);
5156
+ }
5157
+ groups.set(key, group);
5158
+ }
5159
+ return [...groups.values()].map((group) => {
5160
+ const mime = [...group.mimes.entries()].sort((left, right) => right[1] - left[1])[0]?.[0] ?? "";
5161
+ const modalshape = [...group.shapes.entries()].sort((left, right) => right[1] - left[1])[0];
5162
+ 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 };
5163
+ });
5164
+ }
5165
+ function rankapis(entries) {
5166
+ const score = (entry) => entry.frequency * (1 + entry.jsonshare + entry.stability);
5167
+ return [...entries].sort((left, right) => score(right) - score(left) || right.frequency - left.frequency);
5168
+ }
5169
+ function apireplayspecof(value) {
5170
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
5171
+ const entry = value;
5172
+ if (typeof entry.endpoint !== "string" || !entry.endpoint.trim()) return void 0;
5173
+ const spec = { endpoint: entry.endpoint.trim() };
5174
+ if (typeof entry.verb === "string" && entry.verb.trim()) spec.verb = entry.verb.trim().toUpperCase();
5175
+ if (entry.overrides !== void 0 && entry.overrides !== null && typeof entry.overrides === "object" && !Array.isArray(entry.overrides)) {
5176
+ const overrides = {};
5177
+ for (const [name, override] of Object.entries(entry.overrides)) {
5178
+ if (typeof override === "string") overrides[name] = override;
5179
+ }
5180
+ spec.overrides = overrides;
5181
+ }
5182
+ if (Array.isArray(entry.paths)) spec.paths = entry.paths.filter((path) => typeof path === "string" && path.trim().length > 0);
5183
+ return spec;
5184
+ }
5185
+ function replayurl(spec) {
5186
+ const url = new URL(spec.endpoint);
5187
+ for (const [name, value] of Object.entries(spec.overrides ?? {})) url.searchParams.set(name, value);
5188
+ return url.toString();
5189
+ }
5190
+ function extractvalues(body, paths) {
5191
+ let parsed;
5192
+ try {
5193
+ parsed = JSON.parse(body);
5194
+ } catch {
5195
+ return paths.map((path) => ({ path, missing: true }));
5196
+ }
5197
+ const fields = readpath(parsed, paths.map((path) => ({ name: path, path, kind: "json" })));
5198
+ return fields.map((field) => ({ path: field.path, ...field.value !== void 0 ? { value: field.value } : {}, ...field.missing ? { missing: true } : {} }));
5199
+ }
5200
+
5201
+ // netcontrol.ts
5202
+ var controlkinds = ["blockrequest", "mockresponse", "rewriteheaders", "setcookies", "readcookies", "clearcookies", "authflow", "saveapikey", "routeproxy", "postform", "postfiles"];
5203
+ function patternorigin(pattern) {
5204
+ const trimmed = pattern.trim();
5205
+ if (!trimmed.startsWith("https://")) return void 0;
5206
+ const rest = trimmed.slice("https://".length);
5207
+ const host = rest.split("/")[0] ?? "";
5208
+ if (!host.trim()) return void 0;
5209
+ return `https://${host.toLowerCase()}`;
5210
+ }
5211
+ function matchurlpattern(pattern, url) {
5212
+ const origin = patternorigin(pattern);
5213
+ if (!origin) return false;
5214
+ let parsed;
5215
+ try {
5216
+ parsed = new URL(url);
5217
+ } catch {
5218
+ return false;
5219
+ }
5220
+ if (parsed.origin !== origin) return false;
5221
+ const patternpath = pattern.trim().slice(origin.length);
5222
+ if (patternpath === "" || patternpath === "/") return true;
5223
+ const segments = patternpath.split("/").filter((segment) => segment !== "");
5224
+ if (segments.includes("**")) return true;
5225
+ const pathsegments = parsed.pathname.split("/").filter((segment) => segment !== "");
5226
+ if (segments.length !== pathsegments.length) return false;
5227
+ return segments.every((segment, index) => segment === pathsegments[index] || segment.includes("*") && new RegExp(`^${segment.split("*").map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join(".*")}$`).test(pathsegments[index] ?? ""));
5228
+ }
5229
+ function blockruleof(value) {
5230
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
5231
+ const options = value;
5232
+ if (typeof options.urlpattern !== "string" || !options.urlpattern.trim()) return void 0;
5233
+ const rule = { urlpattern: options.urlpattern.trim() };
5234
+ if (Array.isArray(options.resourcetypes)) {
5235
+ const types = options.resourcetypes.filter((item) => typeof item === "string" && item.trim().length > 0);
5236
+ if (types.length === 0) return void 0;
5237
+ rule.resourcetypes = types;
5238
+ }
5239
+ return rule;
5240
+ }
5241
+ function newblockrule(input) {
5242
+ return { id: input.id, runid: input.runid, stepid: input.stepid, urlpattern: input.urlpattern, ...input.resourcetypes !== void 0 ? { resourcetypes: input.resourcetypes } : {}, hits: 0, registeredat: input.at };
5243
+ }
5244
+ function mockspecof(value) {
5245
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
5246
+ const options = value;
5247
+ if (typeof options.urlpattern !== "string" || !options.urlpattern.trim()) return void 0;
5248
+ if (typeof options.status !== "number" || !Number.isInteger(options.status) || options.status < 100 || options.status > 599) return void 0;
5249
+ const hasbody = typeof options.body === "string";
5250
+ const bodyref = typeof options.bodyref === "string" ? options.bodyref.trim() : "";
5251
+ if (!hasbody && bodyref === "") return void 0;
5252
+ const spec = { urlpattern: options.urlpattern.trim(), status: options.status };
5253
+ if (hasbody) spec.body = options.body;
5254
+ if (bodyref !== "") spec.bodyref = bodyref;
5255
+ if (options.headers && typeof options.headers === "object" && !Array.isArray(options.headers)) spec.headers = options.headers;
5256
+ if (options.reviewed === true) spec.reviewed = true;
5257
+ return spec;
5258
+ }
5259
+ function newmockspec(input) {
5260
+ return { id: input.id, runid: input.runid, stepid: input.stepid, urlpattern: input.urlpattern, status: input.status, ...input.headers !== void 0 ? { headers: input.headers } : {}, ...input.body !== void 0 ? { body: input.body } : {}, ...input.bodyref !== void 0 ? { bodyref: input.bodyref } : {}, reviewed: input.reviewed, hits: 0, registeredat: input.at };
5261
+ }
5262
+ function mockfor(url, specs) {
5263
+ return specs.find((spec) => spec.revertedat === void 0 && matchurlpattern(spec.urlpattern, url));
5264
+ }
5265
+ function headeruleof(value) {
5266
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
5267
+ const options = value;
5268
+ if (typeof options.urlpattern !== "string" || !options.urlpattern.trim()) return void 0;
5269
+ if (typeof options.name !== "string" || !options.name.trim()) return void 0;
5270
+ if (options.operation !== "set" && options.operation !== "append" && options.operation !== "remove") return void 0;
5271
+ if (options.operation === "remove" && options.value !== void 0) return void 0;
5272
+ if (options.operation !== "remove" && typeof options.value !== "string") return void 0;
5273
+ const rule = { urlpattern: options.urlpattern.trim(), name: options.name.trim(), operation: options.operation };
5274
+ if (options.operation !== "remove") rule.value = typeof options.value === "string" ? options.value : "";
5275
+ return rule;
5276
+ }
5277
+ function newheaderule(input) {
5278
+ return { id: input.id, runid: input.runid, stepid: input.stepid, urlpattern: input.urlpattern, name: input.name, operation: input.operation, ...input.value !== void 0 ? { value: input.value } : {}, hits: 0, registeredat: input.at };
5279
+ }
5280
+ function applyheaderules(url, headers, rules) {
5281
+ const rewritten = { ...headers };
5282
+ const applied = [];
5283
+ for (const rule of rules) {
5284
+ if (rule.revertedat !== void 0) continue;
5285
+ if (!matchurlpattern(rule.urlpattern, url)) continue;
5286
+ const name = rule.name;
5287
+ if (rule.operation === "remove") {
5288
+ delete rewritten[name];
5289
+ applied.push(rule);
5290
+ continue;
5291
+ }
5292
+ const value = rule.value ?? "";
5293
+ if (rule.operation === "set") rewritten[name] = value;
5294
+ else rewritten[name] = rewritten[name] !== void 0 ? `${rewritten[name]}, ${value}` : value;
5295
+ applied.push(rule);
5296
+ }
5297
+ return { headers: rewritten, applied };
5298
+ }
5299
+ function revertrule(rule, at) {
5300
+ if (rule.revertedat !== void 0) return rule;
5301
+ return { ...rule, revertedat: at };
5054
5302
  }
5055
- function apientries(exchanges, bodies) {
5056
- const bodybyref = new Map(bodies.map((body) => [body.correlationid, body]));
5057
- const groups = /* @__PURE__ */ new Map();
5058
- for (const exchange of exchanges) {
5059
- if (!isapicandidate(exchange)) continue;
5060
- let endpoint = exchange.url;
5061
- let origin = exchange.origin;
5303
+ function cookierecordof(value) {
5304
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
5305
+ const options = value;
5306
+ if (typeof options.name !== "string" || !options.name.trim()) return void 0;
5307
+ if (typeof options.domain !== "string" || !options.domain.trim()) return void 0;
5308
+ if (typeof options.path !== "string" || !options.path.trim()) return void 0;
5309
+ if (typeof options.value !== "string") return void 0;
5310
+ const record2 = { name: options.name.trim(), domain: options.domain.trim().toLowerCase(), path: options.path.trim(), value: options.value };
5311
+ if (typeof options.expiresat === "number" && Number.isFinite(options.expiresat)) record2.expiresat = options.expiresat;
5312
+ return record2;
5313
+ }
5314
+ function cookiedomaingranted(domain, grants) {
5315
+ const host = domain.trim().toLowerCase().replace(/^\./, "");
5316
+ return grants.some((grant) => {
5317
+ let granthost = "";
5062
5318
  try {
5063
- const parsed = new URL(exchange.url);
5064
- endpoint = `${parsed.origin}${parsed.pathname}`;
5065
- origin = parsed.origin;
5319
+ granthost = new URL(grant).hostname.toLowerCase();
5066
5320
  } catch {
5321
+ return false;
5067
5322
  }
5068
- const key = `${exchange.method} ${endpoint}`;
5069
- 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: [] };
5070
- group.frequency += 1;
5071
- group.correlationids.push(exchange.correlationid);
5072
- const body = exchange.bodyref !== void 0 ? bodybyref.get(exchange.correlationid) : void 0;
5073
- const mime = body?.mime ?? exchange.mime ?? "";
5074
- group.mimes.set(mime, (group.mimes.get(mime) ?? 0) + 1);
5075
- if (body !== void 0) {
5076
- group.captured += 1;
5077
- const shape = payloadshapeof(body.body);
5078
- if (shape.length > 0) group.json += 1;
5079
- const shapekey = shape.join(",");
5080
- group.shapes.set(shapekey, (group.shapes.get(shapekey) ?? 0) + 1);
5081
- }
5082
- groups.set(key, group);
5083
- }
5084
- return [...groups.values()].map((group) => {
5085
- const mime = [...group.mimes.entries()].sort((left, right) => right[1] - left[1])[0]?.[0] ?? "";
5086
- const modalshape = [...group.shapes.entries()].sort((left, right) => right[1] - left[1])[0];
5087
- 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 };
5323
+ return host === granthost || host.endsWith(`.${granthost}`);
5088
5324
  });
5089
5325
  }
5090
- function rankapis(entries) {
5091
- const score = (entry) => entry.frequency * (1 + entry.jsonshare + entry.stability);
5092
- return [...entries].sort((left, right) => score(right) - score(left) || right.frequency - left.frequency);
5326
+ function redactedcookies(records) {
5327
+ return records.map((record2) => ({ name: record2.name, domain: record2.domain, path: record2.path, ...record2.expiresat !== void 0 ? { expiresat: record2.expiresat } : {} }));
5093
5328
  }
5094
- function apireplayspecof(value) {
5329
+ function proxyrouteof(value) {
5095
5330
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
5096
- const entry = value;
5097
- if (typeof entry.endpoint !== "string" || !entry.endpoint.trim()) return void 0;
5098
- const spec = { endpoint: entry.endpoint.trim() };
5099
- if (typeof entry.verb === "string" && entry.verb.trim()) spec.verb = entry.verb.trim().toUpperCase();
5100
- if (entry.overrides !== void 0 && entry.overrides !== null && typeof entry.overrides === "object" && !Array.isArray(entry.overrides)) {
5101
- const overrides = {};
5102
- for (const [name, override] of Object.entries(entry.overrides)) {
5103
- if (typeof override === "string") overrides[name] = override;
5104
- }
5105
- spec.overrides = overrides;
5106
- }
5107
- if (Array.isArray(entry.paths)) spec.paths = entry.paths.filter((path) => typeof path === "string" && path.trim().length > 0);
5108
- return spec;
5331
+ const options = value;
5332
+ if (options.scheme !== "http" && options.scheme !== "https" && options.scheme !== "socks4" && options.scheme !== "socks5") return void 0;
5333
+ if (typeof options.host !== "string" || !options.host.trim()) return void 0;
5334
+ if (typeof options.port !== "number" || !Number.isInteger(options.port) || options.port < 1 || options.port > 65535) return void 0;
5335
+ if (!Array.isArray(options.bypass) || options.bypass.length === 0 || !options.bypass.every((item) => typeof item === "string" && item.trim().length > 0)) return void 0;
5336
+ return { scheme: options.scheme, host: options.host.trim(), port: options.port, bypass: options.bypass.map((item) => item.trim()) };
5109
5337
  }
5110
- function replayurl(spec) {
5111
- const url = new URL(spec.endpoint);
5112
- for (const [name, value] of Object.entries(spec.overrides ?? {})) url.searchParams.set(name, value);
5113
- return url.toString();
5338
+ function ratelimitreadof(headers, origin, now) {
5339
+ const pick = (name) => {
5340
+ for (const key of Object.keys(headers)) {
5341
+ if (key.toLowerCase() !== name) continue;
5342
+ const value = Number(headers[key]);
5343
+ return Number.isFinite(value) && value >= 0 ? value : void 0;
5344
+ }
5345
+ return void 0;
5346
+ };
5347
+ const remaining = pick("x-ratelimit-remaining");
5348
+ const limit = pick("x-ratelimit-limit");
5349
+ const reset = pick("x-ratelimit-reset");
5350
+ if (remaining === void 0 && limit === void 0 && reset === void 0) return void 0;
5351
+ const read = { origin, ...remaining !== void 0 ? { remaining } : {}, ...limit !== void 0 ? { limit } : {}, resetat: now, at: now };
5352
+ if (reset !== void 0) read.resetat = reset > Math.floor(now / 1e3) ? reset * 1e3 : now + reset * 1e3;
5353
+ return read;
5114
5354
  }
5115
- function extractvalues(body, paths) {
5116
- let parsed;
5117
- try {
5118
- parsed = JSON.parse(body);
5119
- } catch {
5120
- return paths.map((path) => ({ path, missing: true }));
5355
+ function retryafterof(status, headers) {
5356
+ if (status !== 429 && status !== 503) return void 0;
5357
+ for (const key of Object.keys(headers)) {
5358
+ if (key.toLowerCase() !== "retry-after") continue;
5359
+ const raw = headers[key];
5360
+ if (raw === void 0) continue;
5361
+ const value = raw.trim();
5362
+ const seconds = Number(value);
5363
+ if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1e3;
5364
+ const date = Date.parse(value);
5365
+ if (Number.isFinite(date)) return Math.max(0, date - Date.now());
5366
+ return void 0;
5121
5367
  }
5122
- const fields = readpath(parsed, paths.map((path) => ({ name: path, path, kind: "json" })));
5123
- return fields.map((field) => ({ path: field.path, ...field.value !== void 0 ? { value: field.value } : {}, ...field.missing ? { missing: true } : {} }));
5368
+ return void 0;
5369
+ }
5370
+ function ratelimitwait(state, now) {
5371
+ if (!state) return 0;
5372
+ return Math.max(0, state.resetat - now);
5124
5373
  }
5125
5374
 
5126
5375
  // trigger.ts
@@ -5518,224 +5767,139 @@ function ruleoriginsgranted(rule, workfloworigins) {
5518
5767
  return ruleorigins(rule).every((origin) => granted.has(origin));
5519
5768
  }
5520
5769
 
5521
- // socketbus.ts
5522
- var socketkinds = ["opensocket", "sendmessage", "waitmessage", "subscribesse", "longpoll"];
5523
- function channelorigin(url) {
5524
- try {
5525
- const parsed = new URL(url);
5526
- const protocol = parsed.protocol === "wss:" ? "https:" : parsed.protocol === "ws:" ? "http:" : parsed.protocol;
5527
- return `${protocol}//${parsed.host}`;
5528
- } catch {
5529
- return "";
5530
- }
5531
- }
5532
- function channeloptionsof(value) {
5770
+ // netauth.ts
5771
+ function oauthflowof(value) {
5533
5772
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
5534
- const entry = value;
5535
- if (typeof entry.url !== "string" || !entry.url.trim()) return void 0;
5536
- const options = {};
5537
- if (Array.isArray(entry.protocols)) options.protocols = entry.protocols.filter((item) => typeof item === "string" && item.trim().length > 0);
5538
- if (typeof entry.reconnect === "number" && Number.isFinite(entry.reconnect)) options.reconnect = entry.reconnect;
5539
- if (typeof entry.backoff === "number" && Number.isFinite(entry.backoff)) options.backoff = entry.backoff;
5540
- if (typeof entry.backoffceiling === "number" && Number.isFinite(entry.backoffceiling)) options.backoffceiling = entry.backoffceiling;
5541
- if (typeof entry.lifetime === "number" && Number.isFinite(entry.lifetime)) options.lifetime = entry.lifetime;
5542
- return { url: entry.url.trim(), options };
5543
- }
5544
- function newchannel(input) {
5545
- 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] } : {} };
5546
- }
5547
- function reconnectwaits(attempts, base, ceiling) {
5548
- const count = Math.max(0, Math.floor(attempts));
5549
- const waits = [];
5550
- let wait = Math.max(0, base);
5551
- for (let index = 0; index < count; index += 1) {
5552
- waits.push(wait);
5553
- const next = wait * 2;
5554
- wait = ceiling !== void 0 && Number.isFinite(ceiling) && ceiling >= 0 ? Math.min(next, ceiling) : next;
5555
- }
5556
- return waits;
5557
- }
5558
- async function openchannel(input) {
5559
- const sleep = input.sleep ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, Math.max(0, milliseconds))));
5560
- const now = input.now ?? Date.now;
5561
- const attempts = Math.max(1, Math.floor(input.options.reconnect ?? 0) + 1);
5562
- const waits = reconnectwaits(attempts - 1, input.options.backoff ?? 0, input.options.backoffceiling);
5563
- let record2 = { ...input.record, state: "connecting" };
5564
- let lasterror = "";
5565
- for (let attempt = 0; attempt < attempts; attempt += 1) {
5566
- try {
5567
- const result = await input.connect(record2.url, record2.protocols ?? []);
5568
- if (result.open) return { ...record2, state: "open", openedat: now() };
5569
- lasterror = result.error ?? `closed with code ${result.code ?? 0}`;
5570
- } catch (error) {
5571
- lasterror = error instanceof Error ? error.message : String(error);
5572
- }
5573
- if (attempt < attempts - 1) {
5574
- const wait = waits[attempt] ?? 0;
5575
- if (wait > 0) await sleep(wait);
5576
- record2 = { ...record2, reconnects: record2.reconnects + 1 };
5577
- }
5578
- }
5579
- return { ...record2, state: "failed", error: lasterror };
5580
- }
5581
- function closechannel(record2, at, error) {
5582
- const state = error !== void 0 ? "failed" : "closed";
5583
- return { ...record2, state, closedat: at, ...error !== void 0 ? { error } : {} };
5584
- }
5585
- function tagmessage(state, channelid, stream, payload, at) {
5586
- const sequence = (state.sequences[channelid] ?? 0) + 1;
5587
- const envelope = { channelid, stream, payload, sequence, at };
5588
- return { state: { sequences: { ...state.sequences, [channelid]: sequence }, queue: state.queue }, envelope };
5589
- }
5590
- function publishmessage(state, channelid, stream, payload, at) {
5591
- return tagmessage(state, channelid, stream, payload, at);
5592
- }
5593
- function receivemessage(state, channelid, stream, payload, at) {
5594
- const tagged = tagmessage(state, channelid, stream, payload, at);
5595
- return { state: { ...tagged.state, queue: [...state.queue, tagged.envelope] }, envelope: tagged.envelope };
5773
+ const options = value;
5774
+ if (typeof options.provider !== "string" || !options.provider.trim()) return void 0;
5775
+ if (typeof options.authorizeurl !== "string" || !options.authorizeurl.trim()) return void 0;
5776
+ if (typeof options.tokenurl !== "string" || !options.tokenurl.trim()) return void 0;
5777
+ if (!Array.isArray(options.scopes) || options.scopes.length === 0 || !options.scopes.every((item) => typeof item === "string" && item.trim().length > 0)) return void 0;
5778
+ if (typeof options.redirectorigin !== "string" || !options.redirectorigin.trim()) return void 0;
5779
+ return { provider: options.provider.trim(), authorizeurl: options.authorizeurl.trim(), tokenurl: options.tokenurl.trim(), scopes: options.scopes.map((item) => item.trim()), redirectorigin: options.redirectorigin.trim() };
5596
5780
  }
5597
- function pathstep2(current, segment) {
5598
- if (Array.isArray(current) && /^\d+$/.test(segment)) return current[Number.parseInt(segment, 10)];
5599
- if (current && typeof current === "object" && !Array.isArray(current)) return current[segment];
5600
- return void 0;
5781
+ function authorizeurl(flow, state) {
5782
+ const url = new URL(flow.authorizeurl);
5783
+ url.searchParams.set("response_type", "code");
5784
+ url.searchParams.set("redirect_uri", flow.redirectorigin);
5785
+ url.searchParams.set("scope", flow.scopes.join(" "));
5786
+ url.searchParams.set("state", state);
5787
+ return url.toString();
5601
5788
  }
5602
- function matchmessage(filter, envelope) {
5603
- if (!filter) return true;
5604
- if (filter.stream !== void 0 && filter.stream !== envelope.stream) return false;
5605
- if (filter.path !== void 0) {
5606
- try {
5607
- const parsed = JSON.parse(envelope.payload);
5608
- let current = parsed;
5609
- let missing = false;
5610
- for (const segment of filter.path.split(".")) {
5611
- const next = pathstep2(current, segment);
5612
- if (next === void 0) {
5613
- missing = true;
5614
- break;
5615
- }
5616
- current = next;
5617
- }
5618
- if (missing) return false;
5619
- } catch {
5620
- return false;
5621
- }
5789
+ function capturecode(url, redirectorigin, state) {
5790
+ let parsed;
5791
+ try {
5792
+ parsed = new URL(url);
5793
+ } catch {
5794
+ return { error: "The redirect url does not parse for the code capture." };
5622
5795
  }
5623
- return true;
5796
+ const granted = redirectorigin.includes("/", redirectorigin.indexOf("://") + 3) ? `${parsed.origin}${parsed.pathname}`.startsWith(redirectorigin) : parsed.origin === redirectorigin;
5797
+ if (!granted) return { error: `The redirect landed on ${parsed.origin} outside the granted redirect origin ${redirectorigin}.` };
5798
+ const returned = parsed.searchParams.get("state");
5799
+ if (returned !== state) return { error: "The redirect state token does not match the reviewed flow." };
5800
+ const error = parsed.searchParams.get("error");
5801
+ if (error) return { error: `The provider refused the flow: ${error}.` };
5802
+ const code = parsed.searchParams.get("code");
5803
+ if (!code) return { error: "The redirect carries no authorization code." };
5804
+ return { code };
5624
5805
  }
5625
- function collectmessages(state, channelid, filter) {
5626
- const limit = filter?.limit !== void 0 && Number.isFinite(filter.limit) && filter.limit >= 1 ? Math.floor(filter.limit) : Number.POSITIVE_INFINITY;
5627
- const matched = [];
5628
- const queue = [];
5629
- for (const envelope of state.queue) {
5630
- if (envelope.channelid === channelid && matched.length < limit && matchmessage(filter, envelope)) matched.push(envelope);
5631
- else queue.push(envelope);
5806
+ function parsetokens(body) {
5807
+ let parsed;
5808
+ try {
5809
+ parsed = JSON.parse(body);
5810
+ } catch {
5811
+ return void 0;
5632
5812
  }
5633
- return { state: { sequences: state.sequences, queue }, matched };
5813
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return void 0;
5814
+ const record2 = parsed;
5815
+ const tokens = {};
5816
+ if (typeof record2.access_token === "string" && record2.access_token) tokens.accesstoken = record2.access_token;
5817
+ if (typeof record2.refresh_token === "string" && record2.refresh_token) tokens.refreshtoken = record2.refresh_token;
5818
+ if (typeof record2.expires_in === "number" && Number.isFinite(record2.expires_in) && record2.expires_in >= 0) tokens.expiresin = record2.expires_in;
5819
+ if (typeof record2.scope === "string" && record2.scope.trim()) tokens.scopes = record2.scope.trim().split(/\s+/);
5820
+ if (tokens.accesstoken === void 0 && tokens.refreshtoken === void 0) return void 0;
5821
+ return tokens;
5634
5822
  }
5635
- function sequenceintegrity(envelopes) {
5636
- const last = /* @__PURE__ */ new Map();
5637
- const gaps = [];
5638
- for (const envelope of envelopes) {
5639
- const expected = (last.get(envelope.channelid) ?? 0) + 1;
5640
- if (envelope.sequence !== expected) gaps.push({ channelid: envelope.channelid, expected, found: envelope.sequence });
5641
- last.set(envelope.channelid, Math.max(envelope.sequence, expected));
5642
- }
5643
- return { ok: gaps.length === 0, gaps };
5823
+ function tokenrequest(flow, input) {
5824
+ if (input.refreshtoken !== void 0) return { url: flow.tokenurl, body: urlencodeform([{ name: "grant_type", value: "refresh_token" }, { name: "refresh_token", value: input.refreshtoken }]) };
5825
+ return { url: flow.tokenurl, body: urlencodeform([{ name: "grant_type", value: "authorization_code" }, { name: "code", value: input.code ?? "" }, { name: "redirect_uri", value: flow.redirectorigin }]) };
5644
5826
  }
5645
- function messagefilterof(value) {
5646
- if (!value || typeof value !== "object" || Array.isArray(value)) return {};
5647
- const entry = value;
5648
- const filter = {};
5649
- if (typeof entry.stream === "string" && entry.stream.trim()) filter.stream = entry.stream.trim();
5650
- if (typeof entry.path === "string" && entry.path.trim()) filter.path = entry.path.trim();
5651
- if (typeof entry.limit === "number" && Number.isFinite(entry.limit) && entry.limit >= 1) filter.limit = Math.floor(entry.limit);
5652
- return filter;
5827
+ function revocationruleof(value) {
5828
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
5829
+ const options = value;
5830
+ if (!Array.isArray(options.tokenids) || options.tokenids.length === 0 || !options.tokenids.every((item) => typeof item === "string" && item.trim().length > 0)) return void 0;
5831
+ if (typeof options.reason !== "string" || !options.reason.trim()) return void 0;
5832
+ return { tokenids: options.tokenids.map((item) => item.trim()), reason: options.reason.trim(), revokedat: Date.now() };
5653
5833
  }
5654
- function parsessetext(text2) {
5655
- const separator = text2.lastIndexOf("\n\n");
5656
- const complete = separator === -1 ? "" : text2.slice(0, separator + 2);
5657
- const rest = separator === -1 ? text2 : text2.slice(separator + 2);
5658
- const events = [];
5659
- for (const block of complete.split(/\n\n/)) {
5660
- const id = [];
5661
- const names = [];
5662
- const data = [];
5663
- let retry;
5664
- for (const line of block.split("\n")) {
5665
- if (line === "" || line.startsWith(":")) continue;
5666
- const colon = line.indexOf(":");
5667
- const field = colon === -1 ? line : line.slice(0, colon);
5668
- let value = colon === -1 ? "" : line.slice(colon + 1);
5669
- if (value.startsWith(" ")) value = value.slice(1);
5670
- if (field === "id" && value !== "") id.push(value);
5671
- if (field === "event" && value !== "") names.push(value);
5672
- if (field === "data") data.push(value);
5673
- if (field === "retry" && /^\d+$/.test(value)) retry = Number.parseInt(value, 10);
5674
- }
5675
- if (id.length === 0 && names.length === 0 && data.length === 0) continue;
5676
- 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 } : {} });
5834
+ function formpayloadof(value) {
5835
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
5836
+ const options = value;
5837
+ if (typeof options.url !== "string" || !options.url.trim()) return void 0;
5838
+ if (!Array.isArray(options.fields) || options.fields.length === 0) return void 0;
5839
+ const fields = [];
5840
+ for (const item of options.fields) {
5841
+ if (!item || typeof item !== "object" || Array.isArray(item)) return void 0;
5842
+ const field = item;
5843
+ if (typeof field.name !== "string" || !field.name.trim()) return void 0;
5844
+ if (typeof field.value !== "string") return void 0;
5845
+ fields.push({ name: field.name.trim(), value: field.value });
5677
5846
  }
5678
- return { events, rest };
5847
+ return { url: options.url.trim(), fields };
5679
5848
  }
5680
- function sserequestheaders(record2) {
5681
- return { accept: "text/event-stream", ...record2.lasteventid !== void 0 && record2.lasteventid !== "" ? { "last-event-id": record2.lasteventid } : {} };
5849
+ function urlencodeform(fields) {
5850
+ return fields.map((field) => `${formencode(field.name)}=${formencode(field.value)}`).join("&");
5682
5851
  }
5683
- function subscriptionoptionsof(value) {
5684
- if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
5685
- const entry = value;
5686
- if (typeof entry.url !== "string" || !entry.url.trim()) return void 0;
5687
- const cancel = entry.cancel;
5688
- if (!cancel || typeof cancel !== "object" || Array.isArray(cancel)) return void 0;
5689
- const cancelrecord = cancel;
5690
- if (cancelrecord.kind !== "stop" && cancelrecord.kind !== "lifetime") return void 0;
5691
- if (typeof cancelrecord.value !== "string" && typeof cancelrecord.value !== "number") return void 0;
5692
- const result = { url: entry.url.trim(), cancel: { kind: cancelrecord.kind, value: cancelrecord.value } };
5693
- if (typeof entry.lifetime === "number" && Number.isFinite(entry.lifetime) && entry.lifetime > 0) result.lifetime = entry.lifetime;
5694
- if (typeof entry.lasteventid === "string" && entry.lasteventid.trim()) result.lasteventid = entry.lasteventid.trim();
5695
- return result;
5852
+ function formencode(value) {
5853
+ const bytes = [...new TextEncoder().encode(value)];
5854
+ return bytes.map((byte) => byte >= 65 && byte <= 90 || byte >= 97 && byte <= 122 || byte >= 48 && byte <= 57 || byte === 45 || byte === 95 || byte === 46 || byte === 126 ? String.fromCharCode(byte) : `%${byte.toString(16).toUpperCase().padStart(2, "0")}`).join("");
5696
5855
  }
5697
- function pollcursorof(value) {
5856
+ function multipartpayloadof(value) {
5698
5857
  if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
5699
- const entry = value;
5700
- if (typeof entry.url !== "string" || !entry.url.trim()) return void 0;
5701
- if (typeof entry.cursorfield !== "string" || !entry.cursorfield.trim()) return void 0;
5702
- if (typeof entry.interval !== "number" || !Number.isFinite(entry.interval) || entry.interval <= 0) return void 0;
5703
- const stop = entry.stop;
5704
- if (!stop || typeof stop !== "object" || Array.isArray(stop)) return void 0;
5705
- const stoprecord = stop;
5706
- if (typeof stoprecord.field !== "string" || !stoprecord.field.trim()) return void 0;
5707
- if (typeof stoprecord.equals !== "string") return void 0;
5708
- const cursor = { url: entry.url.trim(), cursorfield: entry.cursorfield.trim(), interval: entry.interval, stop: { field: stoprecord.field.trim(), equals: stoprecord.equals } };
5709
- if (typeof entry.maxpolls === "number" && Number.isFinite(entry.maxpolls) && entry.maxpolls >= 1) cursor.maxpolls = Math.floor(entry.maxpolls);
5710
- if (typeof entry.param === "string" && entry.param.trim()) cursor.param = entry.param.trim();
5711
- return cursor;
5712
- }
5713
- function cursorfrom(response, field) {
5714
- let current = response;
5715
- for (const segment of field.split(".")) {
5716
- const next = pathstep2(current, segment);
5717
- if (next === void 0) return void 0;
5718
- current = next;
5858
+ const options = value;
5859
+ if (typeof options.url !== "string" || !options.url.trim()) return void 0;
5860
+ if (!Array.isArray(options.files) || options.files.length === 0) return void 0;
5861
+ const fields = [];
5862
+ for (const item of Array.isArray(options.fields) ? options.fields : []) {
5863
+ if (!item || typeof item !== "object" || Array.isArray(item)) return void 0;
5864
+ const field = item;
5865
+ if (typeof field.name !== "string" || !field.name.trim()) return void 0;
5866
+ if (typeof field.value !== "string") return void 0;
5867
+ fields.push({ name: field.name.trim(), value: field.value });
5719
5868
  }
5720
- return current === void 0 || current === null ? void 0 : String(current);
5721
- }
5722
- function pollurl(cursor, value) {
5723
- if (cursor.param === void 0 || value === void 0) {
5724
- return { url: cursor.url, ...value !== void 0 ? { body: JSON.stringify({ [cursor.cursorfield]: value }) } : {} };
5869
+ const files = [];
5870
+ for (const item of options.files) {
5871
+ if (!item || typeof item !== "object" || Array.isArray(item)) return void 0;
5872
+ const file = item;
5873
+ if (typeof file.name !== "string" || !file.name.trim()) return void 0;
5874
+ if (typeof file.filename !== "string" || !file.filename.trim()) return void 0;
5875
+ if (typeof file.mime !== "string" || !file.mime.trim()) return void 0;
5876
+ if (typeof file.content !== "string") return void 0;
5877
+ if (file.reviewed !== true) return void 0;
5878
+ files.push({ name: file.name.trim(), filename: file.filename.trim(), mime: file.mime.trim(), content: file.content, reviewed: true });
5725
5879
  }
5726
- const url = new URL(cursor.url);
5727
- url.searchParams.set(cursor.param, value);
5728
- return { url: url.toString() };
5880
+ const payload = { url: options.url.trim(), fields, files, ...typeof options.boundary === "string" && options.boundary.trim() ? { boundary: options.boundary.trim() } : {} };
5881
+ return payload;
5729
5882
  }
5730
- function polldecision(input) {
5731
- if (input.cancelled?.() === true) return { continue: false, reason: "The long poll loop was cancelled." };
5732
- if (input.expiresat !== void 0 && input.now >= input.expiresat) return { continue: false, reason: "The long poll loop stopped at the reviewed plan expiry." };
5733
- const stopvalue = cursorfrom(input.response, input.cursor.stop.field);
5734
- if (stopvalue !== void 0 && stopvalue === input.cursor.stop.equals) return { continue: false, reason: `The stop condition matched ${input.cursor.stop.field} ${stopvalue}.` };
5735
- 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}.` };
5736
- const value = cursorfrom(input.response, input.cursor.cursorfield);
5737
- const next = pollurl(input.cursor, value);
5738
- return { continue: true, reason: "The long poll loop continues.", ...value !== void 0 ? { cursor: value } : {}, next: { ...next, wait: input.cursor.interval } };
5883
+ function newboundary() {
5884
+ return `----devthink${Math.random().toString(16).slice(2)}${Date.now().toString(16)}`;
5885
+ }
5886
+ function multipartchunks(payload) {
5887
+ const boundary = payload.boundary ?? newboundary();
5888
+ const chunks = [];
5889
+ for (const field of payload.fields) chunks.push(`--${boundary}\r
5890
+ content-disposition: form-data; name="${field.name}"\r
5891
+ \r
5892
+ ${field.value}\r
5893
+ `);
5894
+ for (const file of payload.files) chunks.push(`--${boundary}\r
5895
+ content-disposition: form-data; name="${file.name}"; filename="${file.filename}"\r
5896
+ content-type: ${file.mime}\r
5897
+ \r
5898
+ ${file.content}\r
5899
+ `);
5900
+ chunks.push(`--${boundary}--\r
5901
+ `);
5902
+ return { chunks, boundary, bytes: chunks.reduce((total, chunk) => total + chunk.length, 0) };
5739
5903
  }
5740
5904
 
5741
5905
  // runtimeline.ts
@@ -5930,7 +6094,7 @@ function consolediff(input) {
5930
6094
  // policy.ts
5931
6095
  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", "blockrequest", "mockresponse", "rewriteheaders", "setcookies", "clearcookies", "authflow", "saveapikey", "routeproxy", "postform", "postfiles", "attachcdp", "detachcdp", "cdpcmd", "overridescript", "heapshot", "profilecpu", "capturesourcemaps", "emulatedevice", "emulatenetwork", "emulatelocate", "setuseragent", "overridepermission", "restoresession", "exportsessions", "importsessions", "runworkflow", "visitrule", "urlrule", "menurule", "keyrule", "buttonrule", "cronrule", "intervalrule", "urllistrule", "webhookrule", "eventrule"]);
5932
6096
  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", "setbreakpoint", "stepcode", "watchexpr", "loop", "repeatuntil", "whileloop", "foreach", "parallel", "trycatch"]);
5933
- 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", "readcookies", "watchconsole", "watcherrors", "watchtasks", "watchcdp", "measureflow", "trackmemory", "watchshifts", "traceload", "annotatetrace", "replaytrace", "blackboxscripts", "persiststate", "capturesession", "namedsessions", "diffsessions", "searchsessions", "composeworkflow", "savetemplate", "dryrun", "delay", "waitelement", "compute", "extractvars", "condition", "branch"]);
6097
+ 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", "readcookies", "watchconsole", "watcherrors", "watchtasks", "watchcdp", "measureflow", "trackmemory", "watchshifts", "traceload", "annotatetrace", "replaytrace", "blackboxscripts", "persiststate", "capturesession", "namedsessions", "diffsessions", "searchsessions", "composeworkflow", "savetemplate", "dryrun", "delay", "waitelement", "compute", "extractvars", "listruns", "condition", "branch"]);
5934
6098
  var allowedactions = /* @__PURE__ */ new Set([...sensitiveactions, ...interactionactions, ...readactions]);
5935
6099
  var watchactions = /* @__PURE__ */ new Set(["watchmutate", "watchbanner", "watchfocus", "watchtab"]);
5936
6100
  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"]);
@@ -8731,12 +8895,247 @@ function watchdogconfigvalid(config) {
8731
8895
  if (config.zombiewindow !== void 0 && (typeof config.zombiewindow !== "number" || !Number.isFinite(config.zombiewindow) || config.zombiewindow <= 0)) return { allowed: false, reason: "The watchdog zombie window, when configured, must be a positive number of milliseconds with no code ceiling." };
8732
8896
  return { allowed: true };
8733
8897
  }
8898
+ function validatetoolcatalog(catalog) {
8899
+ if (!Array.isArray(catalog.domains) || catalog.domains.length === 0) return { allowed: false, reason: "The tool catalog needs its tool domains." };
8900
+ const seen = /* @__PURE__ */ new Set();
8901
+ for (const domain of catalog.domains) {
8902
+ if (!toolnamespaces.includes(domain.namespace)) return { allowed: false, reason: `The tool domain ${String(domain.namespace)} is not a reviewed namespace.` };
8903
+ if (!Array.isArray(domain.tools) || domain.tools.length === 0) return { allowed: false, reason: `The ${domain.namespace} domain exposes no tools.` };
8904
+ for (const tool of domain.tools) {
8905
+ if (typeof tool.name !== "string" || !tool.name.startsWith(`${domain.namespace}.`)) return { allowed: false, reason: `The tool ${String(tool.name)} does not carry its ${domain.namespace} namespace prefix.` };
8906
+ if (seen.has(tool.name)) return { allowed: false, reason: `The tool name ${tool.name} is not unique across the catalog.` };
8907
+ seen.add(tool.name);
8908
+ if (!allowedactions.has(tool.kind)) return { allowed: false, reason: `The tool ${tool.name} wraps ${String(tool.kind)} which is outside the reviewed action kind grammar.` };
8909
+ if (!domainkinds[domain.namespace].includes(tool.kind)) return { allowed: false, reason: `The tool ${tool.name} wraps ${String(tool.kind)} which does not belong to the ${domain.namespace} domain.` };
8910
+ if (typeof tool.description !== "string" || tool.description.trim() === "") return { allowed: false, reason: `The tool ${tool.name} needs its plain language description.` };
8911
+ const schema = tool.inputschema;
8912
+ if (!schema || schema.type !== "object" || schema.properties === void 0 || schema.properties === null || typeof schema.properties !== "object" || Array.isArray(schema.properties) || Object.keys(schema.properties).length === 0) return { allowed: false, reason: `The tool ${tool.name} needs its json schema inputs of at least one typed property.` };
8913
+ for (const [name, property] of Object.entries(schema.properties)) {
8914
+ if (!["string", "number", "boolean", "object", "array"].includes(property.type)) return { allowed: false, reason: `The ${tool.name} input ${name} carries an untyped property.` };
8915
+ if (typeof property.description !== "string" || property.description.trim() === "") return { allowed: false, reason: `The ${tool.name} input ${name} needs its plain language description.` };
8916
+ }
8917
+ for (const name of schema.required) {
8918
+ if (!(name in schema.properties)) return { allowed: false, reason: `The tool ${tool.name} marks ${name} required outside its properties.` };
8919
+ }
8920
+ }
8921
+ }
8922
+ return { allowed: true };
8923
+ }
8924
+ function toolriskgrade(tool) {
8925
+ const grade = actionrisk(tool.kind);
8926
+ if (grade !== tool.risk) return { allowed: false, reason: `The tool ${tool.name} declares the ${tool.risk} grade while its kind ${String(tool.kind)} grades ${grade}.` };
8927
+ return { allowed: true };
8928
+ }
8929
+ function toolconsentrequired(tool) {
8930
+ if (tool.risk === "read") return { allowed: true };
8931
+ if (tool.consentmeta === void 0 || typeof tool.consentmeta.review !== "string" || tool.consentmeta.review.trim() === "") return { allowed: false, reason: `The tool ${tool.name} has side effects and needs its consent metadata with the review requirement.` };
8932
+ return { allowed: true };
8933
+ }
8934
+ function serverbindgate(config) {
8935
+ const bind = config.bind !== void 0 && config.bind.trim() !== "" ? config.bind.trim() : "127.0.0.1";
8936
+ const local = bind === "127.0.0.1" || bind === "localhost" || bind === "::1";
8937
+ if (!local && config.remote !== true) return { allowed: false, reason: `The bind ${bind} leaves localhost and grades sensitive: the explicit remote review must approve it first.` };
8938
+ return { allowed: true };
8939
+ }
8940
+ function toolversionfloor(tool, floor) {
8941
+ if (typeof floor === "number" && Number.isFinite(floor) && tool.version < floor) return { allowed: false, reason: `The tool ${tool.name} of version ${tool.version} stays below the negotiated compatibility floor of ${floor}.` };
8942
+ return { allowed: true };
8943
+ }
8944
+ function serverenablementgate(config) {
8945
+ if (config.enabled !== true) return { allowed: false, reason: "The mcp server starts only after the user enables it; the protocol surface stays closed by default." };
8946
+ const bind = serverbindgate(config);
8947
+ if (!bind.allowed) return bind;
8948
+ if (!Array.isArray(config.transports) || config.transports.length === 0) return { allowed: false, reason: "The mcp server needs at least one allowed transport of stdio or http." };
8949
+ if (!config.transports.every((transport) => transport === "stdio" || transport === "http")) return { allowed: false, reason: "The allowed transports of the mcp server are stdio and http." };
8950
+ if (typeof config.port !== "number" || !Number.isFinite(config.port) || config.port <= 0 || config.port > 65535) return { allowed: false, reason: "The http listener port must be a valid port number." };
8951
+ if (config.framesize !== void 0 && (typeof config.framesize !== "number" || !Number.isFinite(config.framesize) || config.framesize <= 0)) return { allowed: false, reason: "The user configured frame size must stay a positive number with no code ceiling." };
8952
+ if (config.queuedepth !== void 0 && (typeof config.queuedepth !== "number" || !Number.isFinite(config.queuedepth) || config.queuedepth <= 0)) return { allowed: false, reason: "The user configured queue depth must stay a positive number with no code ceiling." };
8953
+ return { allowed: true };
8954
+ }
8955
+ function toolnamespacegate(tool) {
8956
+ const namespace = tool.name.split(".")[0];
8957
+ if (!toolnamespaces.includes(namespace)) return { allowed: false, reason: `The tool ${tool.name} carries no reviewed namespace prefix.` };
8958
+ if (!domainkinds[namespace].includes(tool.kind)) return { allowed: false, reason: `The tool ${tool.name} wraps ${String(tool.kind)} which does not belong to the ${namespace} domain.` };
8959
+ return { allowed: true };
8960
+ }
8961
+ function tooldispatchgate(input) {
8962
+ if (input.client.disconnectedat !== void 0) return { allowed: false, reason: "The mcp client is disconnected and its tool calls are refused." };
8963
+ if (!input.client.paired) return { allowed: false, reason: "The mcp client waits for the user pairing approval; unpaired clients never dispatch tools." };
8964
+ if (!input.session || input.session.stoppedat || input.session.pausedat) return { allowed: false, reason: "Tool dispatch needs the live browser session behind the consent gates." };
8965
+ if (input.session.expiresat <= input.now) return { allowed: false, reason: "The browser session has expired and tool dispatch is refused." };
8966
+ if (!input.plan || input.plan.state !== "approved") return { allowed: false, reason: "Tool dispatch needs the approved plan review before any tool runs." };
8967
+ if (!origingranted(input.session, input.origin)) return { allowed: false, reason: `The tool call origin ${input.origin} stays outside the session grants and is refused.` };
8968
+ if (input.tool.risk === "read") return { allowed: true };
8969
+ if (input.stepid === void 0 || input.stepid.trim() === "") return { allowed: false, reason: `The ${input.tool.name} tool has side effects and needs the id of the approved plan step it executes.` };
8970
+ const step = input.plan.steps.find((candidate) => candidate.id === input.stepid);
8971
+ if (step === void 0) return { allowed: false, reason: `The tool call names the step ${input.stepid} which the approved plan does not carry.` };
8972
+ if (step.kind !== input.tool.kind) return { allowed: false, reason: `The tool call names the step ${input.stepid} whose kind ${String(step.kind)} does not match the ${input.tool.name} tool.` };
8973
+ return { allowed: true };
8974
+ }
8734
8975
 
8735
- // version.ts
8736
- var packageversion = "1.1.53";
8737
-
8738
- // types.ts
8739
- var protocolversion = packageversion;
8976
+ // mcpserver.ts
8977
+ var localhostbind = "127.0.0.1";
8978
+ var defaultmcpport = 7436;
8979
+ var rpcerrornumbers = { parse: -32700, method: -32601, params: -32602, internal: -32603, consentrefused: -32001 };
8980
+ function rpcerrorof(code, message, data) {
8981
+ return { code, message, ...data !== void 0 ? { data } : {} };
8982
+ }
8983
+ function rpcerrorcodeof(number) {
8984
+ const entry = Object.entries(rpcerrornumbers).find(([, value]) => value === number);
8985
+ return entry?.[0];
8986
+ }
8987
+ function defaultmcpconfig() {
8988
+ return { port: defaultmcpport, transports: ["stdio", "http"], enabled: false };
8989
+ }
8990
+ function unwraphttppost(value) {
8991
+ if (value && typeof value === "object" && !Array.isArray(value)) {
8992
+ const candidate = value;
8993
+ if (candidate.transport === "http" && candidate.frame && typeof candidate.frame === "object" && !Array.isArray(candidate.frame)) return candidate.frame;
8994
+ }
8995
+ return value;
8996
+ }
8997
+ function parseframe(raw) {
8998
+ const parsed = unwraphttppost(JSON.parse(raw));
8999
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("A json rpc frame must be an object.");
9000
+ return parsed;
9001
+ }
9002
+ function parsewire(raw) {
9003
+ return raw.split("\n").map((line) => line.trim()).filter((line) => line.length > 0).map((line) => parseframe(line));
9004
+ }
9005
+ function serializeframe(frame) {
9006
+ return JSON.stringify(frame);
9007
+ }
9008
+ function wireformat(frame, format) {
9009
+ return format === "newline" ? `${serializeframe(frame)}
9010
+ ` : JSON.stringify({ transport: "http", frame });
9011
+ }
9012
+ function validateframe(frame, methods, config) {
9013
+ if (frame.jsonrpc !== "2.0") return rpcerrorof("parse", "The frame must carry the jsonrpc 2.0 tag.");
9014
+ if (frame.id !== void 0 && typeof frame.id !== "number" && typeof frame.id !== "string" && frame.id !== null) return rpcerrorof("parse", "The frame id must be a number, a string or null.");
9015
+ if (frame.method === void 0 || frame.method.trim() === "") return rpcerrorof("method", "The frame carries no method to route.");
9016
+ if (!methods.some((entry) => entry.method === frame.method)) return rpcerrorof("method", `The server routes no method named ${frame.method}.`);
9017
+ if (frame.params !== void 0 && (typeof frame.params !== "object" || Array.isArray(frame.params))) return rpcerrorof("params", "The frame params must be an object.");
9018
+ if (config?.framesize !== void 0 && serializeframe(frame).length > config.framesize) return rpcerrorof("params", `The serialized frame exceeds the user configured frame size of ${config.framesize} characters.`);
9019
+ return void 0;
9020
+ }
9021
+ function respond(input) {
9022
+ return { jsonrpc: "2.0", ...input.id === void 0 ? input.error !== void 0 ? { id: null } : {} : { id: input.id }, ...input.error !== void 0 ? { error: input.error } : { result: input.result } };
9023
+ }
9024
+ function servermethods() {
9025
+ return [
9026
+ { method: "initialize", handler: "initialize", description: "Completes the mcp handshake and returns the server info." },
9027
+ { method: "ping", handler: "ping", description: "Answers keepalive frames with pong." },
9028
+ { method: "tools/list", handler: "listtools", description: "Returns every tool with its version and json schema inputs." },
9029
+ { method: "negotiate", handler: "negotiate", description: "Exchanges capability sets with the client." },
9030
+ { method: "tools/call", handler: "dispatch", description: "Invokes one tool behind the consent gates." }
9031
+ ];
9032
+ }
9033
+ function servercapabilities(input) {
9034
+ return { protocolversion, name: "devthink", version: protocolversion, toolversion: input.catalog.version, tools: alltools(input.catalog).length, namespaces: toolnamespaces, transports: input.config.transports };
9035
+ }
9036
+ function initialize(input) {
9037
+ void input.params;
9038
+ return { serverinfo: servercapabilities({ config: input.config, catalog: input.catalog }), protocolversion, instructions: "Devthink serves browser tools behind the human review gates: read only tools run once a session is approved while every tool with side effects executes exactly the approved plan step it names. No endpoint, provider or key is hardcoded; the user pairs every client." };
9039
+ }
9040
+ function ping(input) {
9041
+ return { pong: true, at: input.now };
9042
+ }
9043
+ function listtools(catalog) {
9044
+ return { tools: alltools(catalog).map((tool) => ({ name: tool.name, version: tool.version, description: tool.description, inputschema: tool.inputschema, risk: tool.risk, ...tool.consentmeta !== void 0 ? { consentmeta: tool.consentmeta.review } : {} })) };
9045
+ }
9046
+ function negotiate(input) {
9047
+ const client = input.client;
9048
+ if (client?.protocolversion !== void 0 && client.protocolversion !== input.server.protocolversion) return { agreed: false, mismatch: `The client speaks protocol version ${String(client.protocolversion)} while the server offers ${input.server.protocolversion}.` };
9049
+ if (client?.toolversion !== void 0 && client.toolversion > input.server.toolversion) return { agreed: false, mismatch: `The client requires tool version ${String(client.toolversion)} while the server offers ${String(input.server.toolversion)}.` };
9050
+ if (client?.transports !== void 0 && client.transports.some((transport) => !input.server.transports.includes(transport))) return { agreed: false, mismatch: "The client requires a transport the server configuration does not allow." };
9051
+ return { agreed: true, capabilities: input.server };
9052
+ }
9053
+ function connectclient(input) {
9054
+ return { id: input.id ?? `client-${input.now}`, transport: input.transport, paired: false, connectedat: input.now };
9055
+ }
9056
+ function pairclient(clients, id, approved, now) {
9057
+ return clients.map((client) => client.id !== id || client.disconnectedat !== void 0 ? client : approved ? { ...client, paired: true, pairedat: now } : { ...client, paired: false, disconnectedat: now });
9058
+ }
9059
+ function disconnectclient(clients, id, now) {
9060
+ return clients.map((client) => client.id === id && client.disconnectedat === void 0 ? { ...client, disconnectedat: now } : client);
9061
+ }
9062
+ function enqueuerequest(input) {
9063
+ if (input.depth !== void 0 && input.queue.length + 1 > input.depth) return void 0;
9064
+ return [...input.queue, input.frame];
9065
+ }
9066
+ function nextrequest(queue) {
9067
+ return queue.length === 0 ? void 0 : { frame: queue[0], remaining: queue.slice(1) };
9068
+ }
9069
+ async function dispatchtool(input) {
9070
+ const params = input.params;
9071
+ if (!params || typeof params !== "object" || Array.isArray(params)) return { error: rpcerrorof("params", "The tool call needs its params object.") };
9072
+ if (typeof params.name !== "string" || !params.name.trim()) return { error: rpcerrorof("params", "The tool call needs the namespaced name of the tool it invokes.") };
9073
+ const tool = resolvetool(input.catalog, params.name.trim());
9074
+ if (tool === void 0) return { error: rpcerrorof("params", `The catalog holds no unambiguous tool named ${params.name.trim()}.`) };
9075
+ const floor = input.client.capabilities?.toolversion ?? input.catalog.version;
9076
+ if (tool.version < floor) return { error: rpcerrorof("params", `The tool ${tool.name} of version ${tool.version} stays below the negotiated compatibility floor of ${floor}.`) };
9077
+ const stepid = typeof params.stepid === "string" ? params.stepid : void 0;
9078
+ const gate = tooldispatchgate({ client: input.client, tool, session: input.session, plan: input.plan, origin: input.origin, ...stepid !== void 0 ? { stepid } : {}, now: input.now });
9079
+ if (!gate.allowed) return { error: rpcerrorof("consentrefused", gate.reason ?? "The consent gates refused the tool call.") };
9080
+ const step = tool.risk === "read" ? { id: `mcp-${input.client.id}-${input.now}`, kind: tool.kind, summary: tool.description.split(".")[0] ?? tool.description, risk: "read", ...typeof params.target === "string" ? { target: params.target } : {}, ...typeof params.value === "string" ? { value: params.value } : {}, ...params.options !== void 0 && typeof params.options === "object" && !Array.isArray(params.options) ? { options: JSON.stringify(params.options) } : {} } : input.plan?.steps.find((candidate) => candidate.id === stepid);
9081
+ if (step === void 0) return { error: rpcerrorof("consentrefused", "The tool call names a step the approved plan does not carry.") };
9082
+ try {
9083
+ const result = await input.execute(step);
9084
+ return { result, step };
9085
+ } catch (error) {
9086
+ return { error: rpcerrorof("internal", error instanceof Error ? error.message : String(error)) };
9087
+ }
9088
+ }
9089
+ async function handleframe(input) {
9090
+ if (input.raw !== void 0 && input.config.framesize !== void 0 && input.raw.length > input.config.framesize) return respond({ id: null, error: rpcerrorof("params", `The wire frame exceeds the user configured frame size of ${input.config.framesize} characters.`) });
9091
+ let frame;
9092
+ if (input.raw !== void 0) {
9093
+ try {
9094
+ frame = parseframe(input.raw);
9095
+ } catch {
9096
+ return respond({ id: null, error: rpcerrorof("parse", "The wire frame does not parse as json.") });
9097
+ }
9098
+ } else if (input.frame !== void 0) {
9099
+ frame = input.frame;
9100
+ } else {
9101
+ return respond({ id: null, error: rpcerrorof("parse", "The server received no frame to route.") });
9102
+ }
9103
+ const invalid = validateframe(frame, servermethods(), input.config);
9104
+ if (invalid !== void 0) return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, error: invalid });
9105
+ const entry = servermethods().find((candidate) => candidate.method === frame.method);
9106
+ if (entry === void 0) return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, error: rpcerrorof("method", `The server routes no method named ${String(frame.method)}.`) });
9107
+ const params = frame.params;
9108
+ if (entry.handler === "initialize") return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, result: initialize({ ...params !== void 0 ? { params } : {}, config: input.config, catalog: input.catalog }) });
9109
+ if (entry.handler === "ping") return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, result: ping({ now: input.now }) });
9110
+ if (entry.handler === "listtools") return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, result: listtools(input.catalog) });
9111
+ if (entry.handler === "negotiate") {
9112
+ const server = servercapabilities({ config: input.config, catalog: input.catalog });
9113
+ const clientcaps = params?.capabilities && typeof params.capabilities === "object" && !Array.isArray(params.capabilities) ? params.capabilities : void 0;
9114
+ const outcome = negotiate({ ...clientcaps !== void 0 ? { client: clientcaps } : {}, server });
9115
+ return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, ...outcome.agreed ? { result: outcome.capabilities } : { error: rpcerrorof("params", outcome.mismatch ?? "The capability negotiation did not agree.") } });
9116
+ }
9117
+ const dispatched = await dispatchtool({ ...params !== void 0 ? { params } : {}, client: input.client, catalog: input.catalog, ...input.session !== void 0 ? { session: input.session } : {}, ...input.plan !== void 0 ? { plan: input.plan } : {}, origin: input.origin, now: input.now, execute: input.execute });
9118
+ return respond({ ...frame.id !== void 0 ? { id: frame.id } : {}, ...dispatched.error !== void 0 ? { error: dispatched.error } : { result: dispatched.result } });
9119
+ }
9120
+ function bindlocalhost(config) {
9121
+ const bind = config.bind !== void 0 && config.bind.trim() !== "" ? config.bind.trim() : localhostbind;
9122
+ return { bind, port: config.port, localhost: bind === localhostbind || bind === "localhost" || bind === "::1" };
9123
+ }
9124
+ function launchbridge(input) {
9125
+ return { id: input.id ?? `bridge-${input.now}`, host: input.host, connected: true, ...input.pid !== void 0 ? { pid: input.pid } : {}, startedat: input.now, restarts: 0, received: 0, sent: 0 };
9126
+ }
9127
+ function relayframe(input) {
9128
+ return { ...input.bridge, connected: true, received: input.bridge.received + (input.direction === "inbound" ? 1 : 0), sent: input.bridge.sent + (input.direction === "outbound" ? 1 : 0), lastframeat: input.now };
9129
+ }
9130
+ function restartbridge(input) {
9131
+ return { ...input.bridge, connected: true, pid: input.pid, restarts: input.bridge.restarts + 1, startedat: input.now };
9132
+ }
9133
+ function framedlog(event, at, fields) {
9134
+ return JSON.stringify({ at, event, ...fields ?? {} });
9135
+ }
9136
+ function toolcallevent(input) {
9137
+ return { id: input.id, clientid: input.clientid, tool: input.tool, origin: input.origin, ok: input.ok, ...input.code !== void 0 ? { code: input.code } : {}, at: input.now };
9138
+ }
8740
9139
 
8741
9140
  // protocol.ts
8742
9141
  function record(value) {
@@ -9133,7 +9532,7 @@ function requestbody(input) {
9133
9532
  return JSON.stringify({ version: protocolversion, objective: input.objective, session: input.session, observation: input.observation, capabilities: input.capabilities });
9134
9533
  }
9135
9534
  function outcomeresponse(input) {
9136
- 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 } : {}, ...input.control ? { control: input.control } : {}, ...input.timeline ? { timeline: input.timeline } : {}, ...input.cdp ? { cdp: input.cdp } : {}, ...input.profile ? { profile: input.profile } : {}, ...input.emulation ? { emulation: input.emulation } : {}, ...input.session ? { session: input.session } : {}, ...input.workflow ? { workflow: { runid: input.workflow.runid, state: input.workflow.state, ...input.workflow.dryrun === true ? { dryrun: true } : {}, produced: input.workflow.produced, consumed: input.workflow.consumed, ...input.workflow.timeout !== void 0 ? { timeout: input.workflow.timeout } : {}, ...input.workflow.retry !== void 0 ? { retry: input.workflow.retry } : {} } } : {}, ...input.trigger ? { trigger: { ruleid: input.trigger.ruleid, kind: input.trigger.kind, enabled: input.trigger.enabled, ...input.trigger.nextfireat !== void 0 ? { nextfireat: input.trigger.nextfireat } : {} } } : {} });
9535
+ 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 } : {}, ...input.control ? { control: input.control } : {}, ...input.timeline ? { timeline: input.timeline } : {}, ...input.cdp ? { cdp: input.cdp } : {}, ...input.profile ? { profile: input.profile } : {}, ...input.emulation ? { emulation: input.emulation } : {}, ...input.session ? { session: input.session } : {}, ...input.workflow ? { workflow: { runid: input.workflow.runid, state: input.workflow.state, ...input.workflow.dryrun === true ? { dryrun: true } : {}, produced: input.workflow.produced, consumed: input.workflow.consumed, ...input.workflow.timeout !== void 0 ? { timeout: input.workflow.timeout } : {}, ...input.workflow.retry !== void 0 ? { retry: input.workflow.retry } : {} } } : {}, ...input.trigger ? { trigger: { ruleid: input.trigger.ruleid, kind: input.trigger.kind, enabled: input.trigger.enabled, ...input.trigger.nextfireat !== void 0 ? { nextfireat: input.trigger.nextfireat } : {} } } : {}, ...input.tool ? { tool: { clientid: input.tool.clientid, tool: input.tool.tool, origin: input.tool.origin, ok: input.tool.ok, ...input.tool.code !== void 0 ? { code: input.tool.code } : {} } } : {} });
9137
9536
  }
9138
9537
  function mapresponse(input) {
9139
9538
  return JSON.stringify({ version: protocolversion, planid: input.plan.id, planstate: input.plan.state, map: input.map });
@@ -9330,6 +9729,12 @@ function triggerfired(input) {
9330
9729
  function manualrunpreview(input) {
9331
9730
  return { version: protocolversion, manualrun: input.preview, ...input.workflowname !== void 0 ? { workflowname: input.workflowname } : {} };
9332
9731
  }
9732
+ function toolcallframe(input) {
9733
+ return { jsonrpc: "2.0", id: input.id, method: "tools/call", params: { ...input.params ?? {}, name: input.name } };
9734
+ }
9735
+ function toolresultframe(input) {
9736
+ return { jsonrpc: "2.0", id: input.id, ...input.error !== void 0 ? { error: input.error } : { result: input.result } };
9737
+ }
9333
9738
  var workflowfileversion = 1;
9334
9739
  function editorstate(input) {
9335
9740
  const editor = { versions: input.versions, diffs: input.diffs ?? [], history: input.history, breakpoints: input.breakpoints ?? [], overrides: input.overrides, imports: input.imports, backgroundruns: input.backgroundruns ?? {}, watchdog: { ...input.watchdog.config !== void 0 ? { config: input.watchdog.config } : {}, events: input.watchdog.events } };
@@ -10071,6 +10476,7 @@ export {
10071
10476
  agentgrammarvalid,
10072
10477
  agentpresetof,
10073
10478
  allowlistcovers,
10479
+ alltools,
10074
10480
  annotatetrace,
10075
10481
  annotationof,
10076
10482
  annotationplanof,
@@ -10095,6 +10501,7 @@ export {
10095
10501
  authreport,
10096
10502
  autointervalof,
10097
10503
  backoffdelay,
10504
+ bindlocalhost,
10098
10505
  bindparam,
10099
10506
  bindvariables,
10100
10507
  blackboxedurls,
@@ -10117,6 +10524,7 @@ export {
10117
10524
  buildsheet,
10118
10525
  buildsteplibrary,
10119
10526
  buildstitchplan,
10527
+ buildtoolcatalog,
10120
10528
  callgraphql,
10121
10529
  callrest,
10122
10530
  callsreport,
@@ -10151,6 +10559,7 @@ export {
10151
10559
  composeworkflow,
10152
10560
  conditionof,
10153
10561
  confirmmanualrun,
10562
+ connectclient,
10154
10563
  consolecapture,
10155
10564
  consoleconsentcovers,
10156
10565
  consolediff,
@@ -10180,6 +10589,8 @@ export {
10180
10589
  debugwaitbudgetallowed,
10181
10590
  dedupeimages,
10182
10591
  defaultloopbound,
10592
+ defaultmcpconfig,
10593
+ defaultmcpport,
10183
10594
  defaulttriggercooldown,
10184
10595
  delayjitter,
10185
10596
  actionrisk as deriveactionrisk,
@@ -10189,6 +10600,9 @@ export {
10189
10600
  diffreviewgrade,
10190
10601
  diffsessionrecords,
10191
10602
  diffversions,
10603
+ disconnectclient,
10604
+ dispatchtool,
10605
+ domainkinds,
10192
10606
  downloadreport,
10193
10607
  drainqueue,
10194
10608
  dryrunprojection,
@@ -10202,6 +10616,7 @@ export {
10202
10616
  emulationretentionwindow,
10203
10617
  emulationstackallowed,
10204
10618
  emulationstateof,
10619
+ enqueuerequest,
10205
10620
  errorcapture,
10206
10621
  errorreportresponse,
10207
10622
  evaluatecondition,
@@ -10237,6 +10652,7 @@ export {
10237
10652
  foreachof,
10238
10653
  formpayloadof,
10239
10654
  formreportresponse,
10655
+ framedlog,
10240
10656
  frameinterval,
10241
10657
  generatedvalueallowed,
10242
10658
  graphqlopenvelope,
@@ -10244,6 +10660,7 @@ export {
10244
10660
  groupselect,
10245
10661
  growsampleof,
10246
10662
  growthtrend,
10663
+ handleframe,
10247
10664
  headerfilterof,
10248
10665
  headeruleof,
10249
10666
  heapintervalallowed,
@@ -10259,6 +10676,7 @@ export {
10259
10676
  importpresetlibrary,
10260
10677
  importsessionfile,
10261
10678
  importworkflow,
10679
+ initialize,
10262
10680
  iscdpkind,
10263
10681
  iscontrolflowkind,
10264
10682
  iscontrolkind,
@@ -10277,11 +10695,14 @@ export {
10277
10695
  jsonpathrulesof,
10278
10696
  lapseframes,
10279
10697
  lapseplanof,
10698
+ launchbridge,
10280
10699
  layernames,
10281
10700
  layoutreport,
10282
10701
  levelrank,
10283
10702
  listdue,
10703
+ listtools,
10284
10704
  loadworkflow,
10705
+ localhostbind,
10285
10706
  locationconsentcovers,
10286
10707
  locationconsentgate,
10287
10708
  locationpresetof,
@@ -10308,7 +10729,9 @@ export {
10308
10729
  mockspecof,
10309
10730
  multipartchunks,
10310
10731
  multipartpayloadof,
10732
+ namespaceof,
10311
10733
  navstateresponse,
10734
+ negotiate,
10312
10735
  netfailureentryof,
10313
10736
  netlogreport,
10314
10737
  netwatchkinds,
@@ -10323,6 +10746,7 @@ export {
10323
10746
  newsessiondiff,
10324
10747
  newsessionrecord,
10325
10748
  newworkflowrun,
10749
+ nextrequest,
10326
10750
  normalizeendpoint,
10327
10751
  oauthflowof,
10328
10752
  observationmodeof,
@@ -10332,15 +10756,18 @@ export {
10332
10756
  outcomeresponse,
10333
10757
  overrideinputof,
10334
10758
  overridematches,
10759
+ pairclient,
10335
10760
  pairexchange,
10336
10761
  pairstates,
10337
10762
  palettecategories,
10338
10763
  palettenodes,
10339
10764
  parallelof,
10765
+ parseframe,
10340
10766
  parsehtmlbody,
10341
10767
  parseproposal,
10342
10768
  parsessetext,
10343
10769
  parsetokens,
10770
+ parsewire,
10344
10771
  parseworkflowproposal,
10345
10772
  passwordconsentgranted,
10346
10773
  patternorigin,
@@ -10359,6 +10786,7 @@ export {
10359
10786
  permissionnamevalid,
10360
10787
  permissionstates,
10361
10788
  permissionstatevalid,
10789
+ ping,
10362
10790
  planallowlist,
10363
10791
  pollcursorof,
10364
10792
  polldecision,
@@ -10395,6 +10823,7 @@ export {
10395
10823
  regexruleof,
10396
10824
  regionsteps,
10397
10825
  rejectioncapture,
10826
+ relayframe,
10398
10827
  removeedge,
10399
10828
  removenode,
10400
10829
  renderminimap,
@@ -10405,8 +10834,11 @@ export {
10405
10834
  requestbody,
10406
10835
  resolutionverdict,
10407
10836
  resolvedrisk,
10837
+ resolvetool,
10408
10838
  resolvevariable,
10409
10839
  resourcefacts,
10840
+ respond,
10841
+ restartbridge,
10410
10842
  restoreoriginsgranted,
10411
10843
  restoreplanof,
10412
10844
  restorereviewgranted,
@@ -10421,6 +10853,9 @@ export {
10421
10853
  rewritesourcelocation,
10422
10854
  rotatelogs,
10423
10855
  rotationruleof,
10856
+ rpcerrorcodeof,
10857
+ rpcerrornumbers,
10858
+ rpcerrorof,
10424
10859
  ruleorigins,
10425
10860
  ruleoriginsgranted,
10426
10861
  runcatch,
@@ -10455,6 +10890,11 @@ export {
10455
10890
  sequenceintegrity,
10456
10891
  serializearg,
10457
10892
  serializecdpcommand,
10893
+ serializeframe,
10894
+ serverbindgate,
10895
+ servercapabilities,
10896
+ serverenablementgate,
10897
+ servermethods,
10458
10898
  sessionfileversion,
10459
10899
  sessionfolderof,
10460
10900
  sessionfolderunique,
@@ -10507,6 +10947,19 @@ export {
10507
10947
  timelinesources,
10508
10948
  timezonevalid,
10509
10949
  tokenrequest,
10950
+ toolcallevent,
10951
+ toolcallframe,
10952
+ toolcatalogversion,
10953
+ toolconsentrequired,
10954
+ tooldispatchgate,
10955
+ toolname,
10956
+ toolnamespacegate,
10957
+ toolnamespaces,
10958
+ toolresultframe,
10959
+ toolriskgrade,
10960
+ toolsbynamespace,
10961
+ toolschemaof,
10962
+ toolversionfloor,
10510
10963
  tracecategories,
10511
10964
  traceceilingof,
10512
10965
  tracestart,
@@ -10532,10 +10985,12 @@ export {
10532
10985
  validatecontrolpayload,
10533
10986
  validatefieldmatch,
10534
10987
  validateformrecord,
10988
+ validateframe,
10535
10989
  validateregexrule,
10536
10990
  validatesiteoverride,
10537
10991
  validatestep,
10538
10992
  validatetargetref,
10993
+ validatetoolcatalog,
10539
10994
  validatevaluegen,
10540
10995
  validateworkflow,
10541
10996
  verifywebhook,
@@ -10549,6 +11004,7 @@ export {
10549
11004
  watchgate,
10550
11005
  webhooksecretok,
10551
11006
  whileof,
11007
+ wireformat,
10552
11008
  wizardreport,
10553
11009
  workflowblockof,
10554
11010
  workflowfileversion,