@wenathlan/extension 1.1.59 → 1.1.60

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.
@@ -2,7 +2,7 @@
2
2
  "manifest_version": 3,
3
3
  "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnOEjO8Z0PDgQyfvawGcaO2j+o0GLCFTLNj7TkYC/Avo9l2NenMRq7gp90Nfd7E9MViv/OMcCKSYZ5unv12QPRtv31C+a5UQWDFAOP/cH5mwMd6hsayElrSoW8ta+FwFqmr9dIFkn7cQEU3YhZr4Gcbs+ycUHOxVgDA4NBKB0rQ6e9VW5LvTw0isRYUrqM+M72vKxHk9zUIYYn/LGPvottKBYi2GLr0PHSeC2UE+Shmq7vcFIXj6hDjvD4kLJ5sKoUllEcZ1TPuBcnHUQ9ndKA5iktXDQOIJCUJmi7a0YJ2PGg7fvpYfT9k0ai/qZ+pIoRfoOEwE01bPoDn7NjeYnNQIDAQAB",
4
4
  "name": "Devthink",
5
- "version": "1.1.59",
5
+ "version": "1.1.60",
6
6
  "description": "A consent-first bridge for reviewed browser-agent tasks.",
7
7
  "permissions": [
8
8
  "activeTab",
@@ -14,11 +14,25 @@
14
14
  "tabs",
15
15
  "downloads",
16
16
  "clipboardRead",
17
- "clipboardWrite"
17
+ "clipboardWrite",
18
+ "offscreen"
18
19
  ],
19
20
  "optional_host_permissions": [
20
21
  "https://*/*"
21
22
  ],
23
+ "sandbox": {
24
+ "pages": [
25
+ "sandbox.html"
26
+ ]
27
+ },
28
+ "offscreen": {
29
+ "document": "offscreen.html",
30
+ "reasons": [
31
+ "DOM_PARSER",
32
+ "WORKERS"
33
+ ],
34
+ "justification": "Heavy parsing of reviewed snapshots runs inside an offscreen document worker pool so the service worker stays free; the capability stays optional and user granted, with an inline fallback inside the page."
35
+ },
22
36
  "background": {
23
37
  "service_worker": "background.js",
24
38
  "type": "module"
@@ -0,0 +1,7 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head><meta charset="utf-8"><title>Devthink offscreen</title></head>
4
+ <body>
5
+ <script type="module" src="offscreen.js"></script>
6
+ </body>
7
+ </html>
@@ -0,0 +1,87 @@
1
+ // extension/offscreen.ts
2
+ var workersource = `
3
+ self.onmessage = event => {
4
+ const { id, task, payload } = event.data || {};
5
+ try {
6
+ let result = "";
7
+ if (task === "jsonpayload") { JSON.parse(payload); result = payload; }
8
+ else if (task === "htmlsnapshot" || task === "readertree" || task === "readoutline" || task === "classifypage") { const doc = new DOMParser().parseFromString(payload, "text/html"); result = (doc.body && doc.body.textContent ? doc.body.textContent : payload).trim(); }
9
+ else if (task === "tablerows" || task === "a11ytree" || task === "complexselector" || task === "stitchshots") { result = payload; }
10
+ else result = payload;
11
+ self.postMessage({ id, ok: true, result, summary: "The offscreen worker finished the " + task + " parse." });
12
+ } catch (error) {
13
+ self.postMessage({ id, ok: false, result: "", summary: "The offscreen worker refused the " + task + " parse: " + (error && error.message ? error.message : "malformed payload") });
14
+ }
15
+ };
16
+ `;
17
+ var pool = /* @__PURE__ */ new Set();
18
+ var sandboxframe;
19
+ var renderseq = 0;
20
+ var pendingrenders = /* @__PURE__ */ new Map();
21
+ function ensureworker() {
22
+ for (const worker2 of pool) return worker2;
23
+ const worker = new Worker(URL.createObjectURL(new Blob([workersource], { type: "text/javascript" })), { type: "classic" });
24
+ pool.add(worker);
25
+ return worker;
26
+ }
27
+ function ensuresandboxframe() {
28
+ if (sandboxframe) return sandboxframe;
29
+ const frame = document.createElement("iframe");
30
+ frame.src = "sandbox.html";
31
+ frame.style.display = "none";
32
+ frame.setAttribute("aria-hidden", "true");
33
+ document.body.append(frame);
34
+ sandboxframe = frame;
35
+ return frame;
36
+ }
37
+ window.addEventListener("message", (event) => {
38
+ const data = event.data;
39
+ if (data?.channel !== "devthinksandbox" || data.type !== "renderresult" || data.nonce === void 0) return;
40
+ const resolver = pendingrenders.get(data.nonce);
41
+ if (!resolver) return;
42
+ pendingrenders.delete(data.nonce);
43
+ resolver({ ok: data.ok !== false, text: data.text ?? "", summary: data.summary ?? "The sandbox frame returned its render result." });
44
+ });
45
+ function runparse(request) {
46
+ return new Promise((resolve) => {
47
+ const worker = ensureworker();
48
+ const timeout = window.setTimeout(() => resolve({ ok: false, result: "", summary: `The offscreen worker never answered the ${request.task} parse of the step ${request.stepid}.` }), 3e4);
49
+ worker.onmessage = (event) => {
50
+ const answer = event.data;
51
+ if (answer.id !== request.id) return;
52
+ window.clearTimeout(timeout);
53
+ resolve({ ok: answer.ok !== false, result: answer.result ?? "", summary: answer.summary ?? "The offscreen worker answered." });
54
+ };
55
+ worker.postMessage({ id: request.id, task: request.task, payload: request.payload });
56
+ });
57
+ }
58
+ function runrender(render) {
59
+ return new Promise((resolve) => {
60
+ const frame = ensuresandboxframe();
61
+ renderseq += 1;
62
+ const nonce = render.nonce;
63
+ pendingrenders.set(nonce, resolve);
64
+ window.setTimeout(() => {
65
+ if (pendingrenders.delete(nonce)) resolve({ ok: false, text: "", summary: `The sandbox frame never answered the render of the step ${render.stepid}.` });
66
+ }, 15e3);
67
+ frame.contentWindow?.postMessage({ channel: "devthinksandbox", type: "render", nonce, markup: render.markup }, "*");
68
+ void renderseq;
69
+ });
70
+ }
71
+ chrome.runtime.onMessage.addListener((message, _sender, sendresponse) => {
72
+ if (!message || message.kind !== "offscreen") return false;
73
+ if (message.action === "parse") {
74
+ void runparse(message.request).then((answer) => sendresponse({ ok: answer.ok, result: answer.result, summary: answer.summary }));
75
+ return true;
76
+ }
77
+ if (message.action === "sandboxrender") {
78
+ void runrender(message.render).then((answer) => sendresponse({ ok: answer.ok, text: answer.text, summary: answer.summary }));
79
+ return true;
80
+ }
81
+ if (message.action === "pool") {
82
+ sendresponse({ workers: pool.size });
83
+ return true;
84
+ }
85
+ return false;
86
+ });
87
+ //# sourceMappingURL=offscreen.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../offscreen.ts"],
4
+ "sourcesContent": ["/**\n * Offscreen document runtime of the 1.1.60 family.\n * The offscreen document hosts the worker pool that parses heavy payloads away from the page and the sandbox frame iframe that renders untrusted markup without extension privileges; the background spawns this document on first use through the offscreen api only after the user grants the optional offscreen capability, and every parse task still rides a reviewed step of an approved plan.\n */\n\ntype parserequest = { kind: \"offscreen\"; action: \"parse\"; request: { id: string; runid: string; stepid: string; task: string; payload: string; transferables: string[] } };\ntype renderrequest = { kind: \"offscreen\"; action: \"sandboxrender\"; render: { id: string; nonce: string; markup: string; sourceorigin: string; stepid: string } };\ntype poolrequest = { kind: \"offscreen\"; action: \"pool\" };\n\n/** The worker sources of the parse families: pure functions that shape html, json, table, a11y tree, selector and stitch payloads without touching any page. */\nconst workersource = `\nself.onmessage = event => {\n const { id, task, payload } = event.data || {};\n try {\n let result = \"\";\n if (task === \"jsonpayload\") { JSON.parse(payload); result = payload; }\n else if (task === \"htmlsnapshot\" || task === \"readertree\" || task === \"readoutline\" || task === \"classifypage\") { const doc = new DOMParser().parseFromString(payload, \"text/html\"); result = (doc.body && doc.body.textContent ? doc.body.textContent : payload).trim(); }\n else if (task === \"tablerows\" || task === \"a11ytree\" || task === \"complexselector\" || task === \"stitchshots\") { result = payload; }\n else result = payload;\n self.postMessage({ id, ok: true, result, summary: \"The offscreen worker finished the \" + task + \" parse.\" });\n } catch (error) {\n self.postMessage({ id, ok: false, result: \"\", summary: \"The offscreen worker refused the \" + task + \" parse: \" + (error && error.message ? error.message : \"malformed payload\") });\n }\n};\n`;\n\nconst pool = new Set<Worker>();\nlet sandboxframe: HTMLIFrameElement | undefined;\nlet renderseq = 0;\nconst pendingrenders = new Map<string, (value: { ok: boolean; text: string; summary: string }) => void>();\n\nfunction ensureworker(): Worker {\n for (const worker of pool) return worker;\n const worker = new Worker(URL.createObjectURL(new Blob([workersource], { type: \"text/javascript\" })), { type: \"classic\" });\n pool.add(worker);\n return worker;\n}\n\nfunction ensuresandboxframe(): HTMLIFrameElement {\n if (sandboxframe) return sandboxframe;\n const frame = document.createElement(\"iframe\");\n frame.src = \"sandbox.html\";\n frame.style.display = \"none\";\n frame.setAttribute(\"aria-hidden\", \"true\");\n document.body.append(frame);\n sandboxframe = frame;\n return frame;\n}\n\nwindow.addEventListener(\"message\", event => {\n const data = event.data as { channel?: string; type?: string; nonce?: string; ok?: boolean; text?: string; summary?: string };\n if (data?.channel !== \"devthinksandbox\" || data.type !== \"renderresult\" || data.nonce === undefined) return;\n const resolver = pendingrenders.get(data.nonce);\n if (!resolver) return;\n pendingrenders.delete(data.nonce);\n resolver({ ok: data.ok !== false, text: data.text ?? \"\", summary: data.summary ?? \"The sandbox frame returned its render result.\" });\n});\n\nfunction runparse(request: parserequest[\"request\"]): Promise<{ ok: boolean; result: string; summary: string }> {\n return new Promise(resolve => {\n const worker = ensureworker();\n const timeout = window.setTimeout(() => resolve({ ok: false, result: \"\", summary: `The offscreen worker never answered the ${request.task} parse of the step ${request.stepid}.` }), 30000);\n worker.onmessage = event => {\n const answer = event.data as { id?: string; ok?: boolean; result?: string; summary?: string };\n if (answer.id !== request.id) return;\n window.clearTimeout(timeout);\n resolve({ ok: answer.ok !== false, result: answer.result ?? \"\", summary: answer.summary ?? \"The offscreen worker answered.\" });\n };\n worker.postMessage({ id: request.id, task: request.task, payload: request.payload });\n });\n}\n\nfunction runrender(render: renderrequest[\"render\"]): Promise<{ ok: boolean; text: string; summary: string }> {\n return new Promise(resolve => {\n const frame = ensuresandboxframe();\n renderseq += 1;\n const nonce = render.nonce;\n pendingrenders.set(nonce, resolve);\n window.setTimeout(() => {\n if (pendingrenders.delete(nonce)) resolve({ ok: false, text: \"\", summary: `The sandbox frame never answered the render of the step ${render.stepid}.` });\n }, 15000);\n frame.contentWindow?.postMessage({ channel: \"devthinksandbox\", type: \"render\", nonce, markup: render.markup }, \"*\");\n void renderseq;\n });\n}\n\nchrome.runtime.onMessage.addListener((message: parserequest | renderrequest | poolrequest, _sender, sendresponse) => {\n if (!message || (message as { kind?: string }).kind !== \"offscreen\") return false;\n if (message.action === \"parse\") {\n void runparse(message.request).then(answer => sendresponse({ ok: answer.ok, result: answer.result, summary: answer.summary }));\n return true;\n }\n if (message.action === \"sandboxrender\") {\n void runrender(message.render).then(answer => sendresponse({ ok: answer.ok, text: answer.text, summary: answer.summary }));\n return true;\n }\n if (message.action === \"pool\") {\n sendresponse({ workers: pool.size });\n return true;\n }\n return false;\n});\n"],
5
+ "mappings": "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",
6
+ "names": ["worker"]
7
+ }
@@ -3982,6 +3982,13 @@
3982
3982
  return {};
3983
3983
  }
3984
3984
  }
3985
+ function routesenvironment(step) {
3986
+ if (step.environment !== void 0 && step.environment !== "pagecontext") return "elsewhere";
3987
+ if (step.kind === "evaluate") return "elsewhere";
3988
+ const options = stepoptions3(step);
3989
+ if (typeof options.markup === "string" && options.markup.trim() !== "") return "elsewhere";
3990
+ return "pagecontext";
3991
+ }
3985
3992
  var previewid = "devthinktargetpreview";
3986
3993
  function clearpreview() {
3987
3994
  document.getElementById(previewid)?.remove();