@elizaos/plugin-browser 2.0.3-beta.2 → 2.0.3-beta.4
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/actions/browser.d.ts.map +1 -1
- package/dist/actions/browser.js +264 -7
- package/dist/actions/browser.js.map +1 -1
- package/dist/actions/wait-for-url-predicate.d.ts +34 -0
- package/dist/actions/wait-for-url-predicate.d.ts.map +1 -0
- package/dist/actions/wait-for-url-predicate.js +33 -0
- package/dist/actions/wait-for-url-predicate.js.map +1 -0
- package/dist/actions/wait-for-url.d.ts +64 -0
- package/dist/actions/wait-for-url.d.ts.map +1 -0
- package/dist/actions/wait-for-url.js +89 -0
- package/dist/actions/wait-for-url.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -8
- package/dist/index.js.map +1 -1
- package/dist/parity/browser-matrix.d.ts +45 -0
- package/dist/parity/browser-matrix.d.ts.map +1 -0
- package/dist/parity/browser-matrix.js +361 -0
- package/dist/parity/browser-matrix.js.map +1 -0
- package/dist/parity/index.d.ts +5 -0
- package/dist/parity/index.d.ts.map +1 -0
- package/dist/parity/index.js +13 -0
- package/dist/parity/index.js.map +1 -0
- package/dist/routes/workspace.d.ts.map +1 -1
- package/dist/routes/workspace.js +42 -2
- package/dist/routes/workspace.js.map +1 -1
- package/dist/workspace/browser-capture.d.ts.map +1 -1
- package/dist/workspace/browser-capture.js +33 -1
- package/dist/workspace/browser-capture.js.map +1 -1
- package/dist/workspace/browser-workspace-desktop.d.ts.map +1 -1
- package/dist/workspace/browser-workspace-desktop.js +19 -5
- package/dist/workspace/browser-workspace-desktop.js.map +1 -1
- package/dist/workspace/browser-workspace-errors.d.ts +62 -0
- package/dist/workspace/browser-workspace-errors.d.ts.map +1 -0
- package/dist/workspace/browser-workspace-errors.js +69 -0
- package/dist/workspace/browser-workspace-errors.js.map +1 -0
- package/dist/workspace/browser-workspace-helpers.d.ts.map +1 -1
- package/dist/workspace/browser-workspace-helpers.js +29 -8
- package/dist/workspace/browser-workspace-helpers.js.map +1 -1
- package/dist/workspace/browser-workspace-web.d.ts.map +1 -1
- package/dist/workspace/browser-workspace-web.js +20 -6
- package/dist/workspace/browser-workspace-web.js.map +1 -1
- package/dist/workspace/index.d.ts +1 -0
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/workspace/index.js +1 -0
- package/dist/workspace/index.js.map +1 -1
- package/package.json +5 -4
- package/registry-entry.json +75 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
function toMessage(error) {
|
|
2
|
+
return error instanceof Error ? error.message : String(error);
|
|
3
|
+
}
|
|
4
|
+
function isBrowserWorkspaceError(value) {
|
|
5
|
+
return value instanceof Error && "browserWorkspaceErrorCode" in value && typeof value.browserWorkspaceErrorCode === "string";
|
|
6
|
+
}
|
|
7
|
+
function createBrowserWorkspaceError(code, operation, message, details, status) {
|
|
8
|
+
const error = new Error(message);
|
|
9
|
+
error.name = "BrowserWorkspaceError";
|
|
10
|
+
error.browserWorkspaceErrorCode = code;
|
|
11
|
+
error.operation = operation;
|
|
12
|
+
if (details !== void 0) error.details = details;
|
|
13
|
+
if (status !== void 0) error.status = status;
|
|
14
|
+
return error;
|
|
15
|
+
}
|
|
16
|
+
function classifyBrowserWorkspaceErrorCode(error) {
|
|
17
|
+
if (isBrowserWorkspaceError(error)) return error.browserWorkspaceErrorCode;
|
|
18
|
+
const message = toMessage(error);
|
|
19
|
+
if (/rejected invalid URL|only supports http\/https/i.test(message)) {
|
|
20
|
+
return "invalid_url";
|
|
21
|
+
}
|
|
22
|
+
if (/\(404\)|Tab .+ was not found/i.test(message)) {
|
|
23
|
+
return "tab_not_found";
|
|
24
|
+
}
|
|
25
|
+
if (/requires a current tab/i.test(message)) {
|
|
26
|
+
return "target_missing";
|
|
27
|
+
}
|
|
28
|
+
if (/only available in the desktop app|desktop bridge is unavailable/i.test(
|
|
29
|
+
message
|
|
30
|
+
)) {
|
|
31
|
+
return "desktop_only";
|
|
32
|
+
}
|
|
33
|
+
if (/arbitrary (script execution|user script) is disabled|not supported on the web backend/i.test(
|
|
34
|
+
message
|
|
35
|
+
)) {
|
|
36
|
+
return "script_forbidden";
|
|
37
|
+
}
|
|
38
|
+
if (/do not allow raw cookie, token, storage, or state export/i.test(message)) {
|
|
39
|
+
return "connector_secret_export_forbidden";
|
|
40
|
+
}
|
|
41
|
+
if (/Unknown browser snapshot element ref/i.test(message)) {
|
|
42
|
+
return "unknown_element_ref";
|
|
43
|
+
}
|
|
44
|
+
if (/timed out|timeout|\bETIMEDOUT\b/i.test(message)) {
|
|
45
|
+
return "timeout";
|
|
46
|
+
}
|
|
47
|
+
return "command_failed";
|
|
48
|
+
}
|
|
49
|
+
function tagBrowserWorkspaceError(error, operation) {
|
|
50
|
+
if (isBrowserWorkspaceError(error)) return error;
|
|
51
|
+
if (error instanceof Error) {
|
|
52
|
+
const tagged = error;
|
|
53
|
+
tagged.browserWorkspaceErrorCode = classifyBrowserWorkspaceErrorCode(error);
|
|
54
|
+
tagged.operation = operation;
|
|
55
|
+
return tagged;
|
|
56
|
+
}
|
|
57
|
+
return createBrowserWorkspaceError(
|
|
58
|
+
classifyBrowserWorkspaceErrorCode(error),
|
|
59
|
+
operation,
|
|
60
|
+
toMessage(error)
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
classifyBrowserWorkspaceErrorCode,
|
|
65
|
+
createBrowserWorkspaceError,
|
|
66
|
+
isBrowserWorkspaceError,
|
|
67
|
+
tagBrowserWorkspaceError
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=browser-workspace-errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/workspace/browser-workspace-errors.ts"],"sourcesContent":["/**\n * Structured browser-workspace error contract (issue #9476).\n *\n * The workspace command path (`executeBrowserWorkspaceCommand` and the helpers\n * in `browser-workspace-helpers.ts`) throws bare `new Error(...)` for many\n * distinct failure modes — an invalid URL, a missing tab, a desktop-only\n * subaction, a forbidden user script, a connector secret-export attempt — so\n * callers today must regex the human-readable message to react. This mirrors the\n * CUA `screenshot-errors.ts` contract: a machine-readable\n * {@link BrowserWorkspaceErrorCode} added **additively** via\n * {@link tagBrowserWorkspaceError} (annotates the existing Error in place,\n * preserving its identity/message) plus a pure {@link classifyBrowserWorkspaceErrorCode}\n * that maps the well-known thrown-message shapes to a code — one testable source\n * of truth. This increment is the contract + classifier only; wiring\n * `tagBrowserWorkspaceError` into the `executeBrowserWorkspaceCommand` catch\n * boundary is a follow-up.\n */\n\nexport type BrowserWorkspaceErrorCode =\n /** URL rejected: not a valid URL, or not http/https. */\n | \"invalid_url\"\n /** The referenced tab id does not exist (404). */\n | \"tab_not_found\"\n /** The subaction needs a current/target tab and none was available. */\n | \"target_missing\"\n /** The subaction is only available in the desktop app / bridge. */\n | \"desktop_only\"\n /** Arbitrary user/JSDOM script execution is disabled (GHSA-mhhr-9ph9-64j7). */\n | \"script_forbidden\"\n /** A connector session tried to export raw cookies/tokens/storage/state. */\n | \"connector_secret_export_forbidden\"\n /** A snapshot element ref is stale/unknown (re-snapshot needed). */\n | \"unknown_element_ref\"\n /** The operation exceeded its timeout. */\n | \"timeout\"\n /** Any other workspace command failure. */\n | \"command_failed\";\n\n/** An `Error` carrying a machine-readable {@link BrowserWorkspaceErrorCode}. */\nexport interface BrowserWorkspaceError extends Error {\n readonly browserWorkspaceErrorCode: BrowserWorkspaceErrorCode;\n /** The workspace operation that failed (e.g. `navigate`, `eval`). */\n readonly operation: string;\n /** Underlying message, when this wraps a lower-level failure. */\n readonly details?: string;\n /** HTTP status from an upstream workspace bridge, when available. */\n readonly status?: number;\n}\n\ntype Mutable<T> = { -readonly [K in keyof T]: T[K] };\n\nfunction toMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport function isBrowserWorkspaceError(\n value: unknown,\n): value is BrowserWorkspaceError {\n return (\n value instanceof Error &&\n \"browserWorkspaceErrorCode\" in value &&\n typeof (value as { browserWorkspaceErrorCode?: unknown })\n .browserWorkspaceErrorCode === \"string\"\n );\n}\n\nexport function createBrowserWorkspaceError(\n code: BrowserWorkspaceErrorCode,\n operation: string,\n message: string,\n details?: string,\n status?: number,\n): BrowserWorkspaceError {\n const error = new Error(message) as Mutable<BrowserWorkspaceError>;\n error.name = \"BrowserWorkspaceError\";\n error.browserWorkspaceErrorCode = code;\n error.operation = operation;\n if (details !== undefined) error.details = details;\n if (status !== undefined) error.status = status;\n return error;\n}\n\n/**\n * Map any thrown value to a {@link BrowserWorkspaceErrorCode} from the\n * well-known message shapes the workspace helpers throw. Already-tagged errors\n * return their own code. Pure — the single source of truth for the mapping.\n */\nexport function classifyBrowserWorkspaceErrorCode(\n error: unknown,\n): BrowserWorkspaceErrorCode {\n if (isBrowserWorkspaceError(error)) return error.browserWorkspaceErrorCode;\n const message = toMessage(error);\n\n if (/rejected invalid URL|only supports http\\/https/i.test(message)) {\n return \"invalid_url\";\n }\n if (/\\(404\\)|Tab .+ was not found/i.test(message)) {\n return \"tab_not_found\";\n }\n if (/requires a current tab/i.test(message)) {\n return \"target_missing\";\n }\n if (\n /only available in the desktop app|desktop bridge is unavailable/i.test(\n message,\n )\n ) {\n return \"desktop_only\";\n }\n if (\n /arbitrary (script execution|user script) is disabled|not supported on the web backend/i.test(\n message,\n )\n ) {\n return \"script_forbidden\";\n }\n if (\n /do not allow raw cookie, token, storage, or state export/i.test(message)\n ) {\n return \"connector_secret_export_forbidden\";\n }\n if (/Unknown browser snapshot element ref/i.test(message)) {\n return \"unknown_element_ref\";\n }\n if (/timed out|timeout|\\bETIMEDOUT\\b/i.test(message)) {\n return \"timeout\";\n }\n return \"command_failed\";\n}\n\n/**\n * Tag an existing thrown value with its {@link BrowserWorkspaceErrorCode} +\n * operation, **in place and additively** (preserves the original Error identity\n * and message). Idempotent: re-tagging keeps the first code. A non-Error value\n * is wrapped in a fresh `BrowserWorkspaceError`.\n */\nexport function tagBrowserWorkspaceError(\n error: unknown,\n operation: string,\n): BrowserWorkspaceError {\n if (isBrowserWorkspaceError(error)) return error; // idempotent\n if (error instanceof Error) {\n const tagged = error as Mutable<BrowserWorkspaceError>;\n tagged.browserWorkspaceErrorCode = classifyBrowserWorkspaceErrorCode(error);\n tagged.operation = operation;\n return tagged;\n }\n return createBrowserWorkspaceError(\n classifyBrowserWorkspaceErrorCode(error),\n operation,\n toMessage(error),\n );\n}\n"],"mappings":"AAmDA,SAAS,UAAU,OAAwB;AACzC,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;AAEO,SAAS,wBACd,OACgC;AAChC,SACE,iBAAiB,SACjB,+BAA+B,SAC/B,OAAQ,MACL,8BAA8B;AAErC;AAEO,SAAS,4BACd,MACA,WACA,SACA,SACA,QACuB;AACvB,QAAM,QAAQ,IAAI,MAAM,OAAO;AAC/B,QAAM,OAAO;AACb,QAAM,4BAA4B;AAClC,QAAM,YAAY;AAClB,MAAI,YAAY,OAAW,OAAM,UAAU;AAC3C,MAAI,WAAW,OAAW,OAAM,SAAS;AACzC,SAAO;AACT;AAOO,SAAS,kCACd,OAC2B;AAC3B,MAAI,wBAAwB,KAAK,EAAG,QAAO,MAAM;AACjD,QAAM,UAAU,UAAU,KAAK;AAE/B,MAAI,kDAAkD,KAAK,OAAO,GAAG;AACnE,WAAO;AAAA,EACT;AACA,MAAI,gCAAgC,KAAK,OAAO,GAAG;AACjD,WAAO;AAAA,EACT;AACA,MAAI,0BAA0B,KAAK,OAAO,GAAG;AAC3C,WAAO;AAAA,EACT;AACA,MACE,mEAAmE;AAAA,IACjE;AAAA,EACF,GACA;AACA,WAAO;AAAA,EACT;AACA,MACE,yFAAyF;AAAA,IACvF;AAAA,EACF,GACA;AACA,WAAO;AAAA,EACT;AACA,MACE,4DAA4D,KAAK,OAAO,GACxE;AACA,WAAO;AAAA,EACT;AACA,MAAI,wCAAwC,KAAK,OAAO,GAAG;AACzD,WAAO;AAAA,EACT;AACA,MAAI,mCAAmC,KAAK,OAAO,GAAG;AACpD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAQO,SAAS,yBACd,OACA,WACuB;AACvB,MAAI,wBAAwB,KAAK,EAAG,QAAO;AAC3C,MAAI,iBAAiB,OAAO;AAC1B,UAAM,SAAS;AACf,WAAO,4BAA4B,kCAAkC,KAAK;AAC1E,WAAO,YAAY;AACnB,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,kCAAkC,KAAK;AAAA,IACvC;AAAA,IACA,UAAU,KAAK;AAAA,EACjB;AACF;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-workspace-helpers.d.ts","sourceRoot":"","sources":["../../src/workspace/browser-workspace-helpers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"browser-workspace-helpers.d.ts","sourceRoot":"","sources":["../../src/workspace/browser-workspace-helpers.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,uBAAuB,EACvB,oBAAoB,EACpB,yBAAyB,EAC1B,MAAM,8BAA8B,CAAC;AAEtC,eAAO,MAAM,kBAAkB,QAAS,CAAC;AACzC,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAC5C,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAC7D,eAAO,MAAM,4CAA4C,uBACnC,CAAC;AACvB,eAAO,MAAM,kCAAkC,2DACW,CAAC;AAC3D,eAAO,MAAM,yBAAyB,KAAoC,CAAC;AAE3E,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAM1E;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAIpE;AAED,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,OAAO,GACb,MAAM,GAAG,SAAS,CASpB;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA0BhE;AAED,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAU9D;AAgCD,wBAAgB,yCAAyC,CACvD,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,MAAM,CAWR;AAED,wBAAgB,oCAAoC,CAClD,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACnC,OAAO,CAKT;AAED,wBAAgB,uCAAuC,CACrD,OAAO,EAAE,IAAI,CACX,uBAAuB,EACvB,oBAAoB,GAAG,mBAAmB,GAAG,WAAW,CACzD,EACD,iBAAiB,EAAE,MAAM,GACxB,MAAM,CAWR;AAED,wBAAgB,iDAAiD,CAC/D,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACpC,SAAS,EAAE,MAAM,GAChB,IAAI,CASN;AAED,wBAAgB,wCAAwC,CACtD,SAAS,EAAE,yBAAyB,GACnC,MAAM,CAER;AAED,wBAAgB,mCAAmC,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAMxE;AAED,wBAAgB,wCAAwC,CACtD,SAAS,EAAE,yBAAyB,GACnC,KAAK,CAMP;AAED,wBAAsB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAErD;AAED,wBAAsB,yBAAyB,CAC7C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GAAG,UAAU,GAC5B,OAAO,CAAC,MAAM,CAAC,CAKjB;AAED,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,uBAAuB,GAC/B,uBAAuB,CA2BzB;AAED,wBAAgB,yCAAyC,CACvD,OAAO,EAAE,uBAAuB,EAChC,IAAI,EAAE,oBAAoB,EAC1B,KAAK,EAAE,MAAM,GACZ,uBAAuB,CA4BzB;AAED,wBAAgB,qCAAqC,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED,gGAAgG;AAChG,eAAO,MAAM,wCAAwC,wSACkP,CAAC;AAExS,eAAO,MAAM,uCAAuC,oIAC+E,CAAC;AAEpI,wBAAgB,mCAAmC,CACjD,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAKT;AAED,wBAAgB,uCAAuC,CACrD,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,IAAI,EAAE,oBAAoB,EAC1B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,IAAI,CAkBN;AAED,wBAAgB,+CAA+C,CAC7D,OAAO,EAAE,MAAM,GAAG,MAAM,GACvB,KAAK,CAUP;AAED,wBAAgB,6CAA6C,CAC3D,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,OAAO,EAAE,MAAM,GAAG,MAAM,GACvB,IAAI,CAIN"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fsp from "node:fs/promises";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { createBrowserWorkspaceError } from "./browser-workspace-errors.js";
|
|
3
4
|
import { resolveBrowserWorkspaceElementRef } from "./browser-workspace-state.js";
|
|
4
5
|
const DEFAULT_TIMEOUT_MS = 12e3;
|
|
5
6
|
const DEFAULT_WAIT_INTERVAL_MS = 120;
|
|
@@ -36,10 +37,16 @@ function assertBrowserWorkspaceUrl(rawUrl) {
|
|
|
36
37
|
try {
|
|
37
38
|
parsed = new URL(trimmed);
|
|
38
39
|
} catch {
|
|
39
|
-
throw
|
|
40
|
+
throw createBrowserWorkspaceError(
|
|
41
|
+
"invalid_url",
|
|
42
|
+
"url_validation",
|
|
43
|
+
`browser workspace rejected invalid URL: ${rawUrl}`
|
|
44
|
+
);
|
|
40
45
|
}
|
|
41
46
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
42
|
-
throw
|
|
47
|
+
throw createBrowserWorkspaceError(
|
|
48
|
+
"invalid_url",
|
|
49
|
+
"url_validation",
|
|
43
50
|
`browser workspace only supports http/https URLs, got ${parsed.protocol}`
|
|
44
51
|
);
|
|
45
52
|
}
|
|
@@ -102,7 +109,9 @@ function assertBrowserWorkspaceConnectorSecretsNotExported(partition, operation)
|
|
|
102
109
|
if (!isConnectorBrowserWorkspacePartition(partition)) {
|
|
103
110
|
return;
|
|
104
111
|
}
|
|
105
|
-
throw
|
|
112
|
+
throw createBrowserWorkspaceError(
|
|
113
|
+
"connector_secret_export_forbidden",
|
|
114
|
+
operation,
|
|
106
115
|
`Connector browser sessions do not allow raw cookie, token, storage, or state export (${operation}). Use the returned partition/profile/session handle instead.`
|
|
107
116
|
);
|
|
108
117
|
}
|
|
@@ -110,12 +119,16 @@ function createBrowserWorkspaceDesktopOnlyMessage(subaction) {
|
|
|
110
119
|
return `Eliza browser workspace ${subaction} is only available in the desktop app.`;
|
|
111
120
|
}
|
|
112
121
|
function createBrowserWorkspaceNotFoundError(tabId) {
|
|
113
|
-
return
|
|
122
|
+
return createBrowserWorkspaceError(
|
|
123
|
+
"tab_not_found",
|
|
124
|
+
"tab_lookup",
|
|
114
125
|
`Browser workspace request failed (404): Tab ${tabId} was not found.`
|
|
115
126
|
);
|
|
116
127
|
}
|
|
117
128
|
function createBrowserWorkspaceCommandTargetError(subaction) {
|
|
118
|
-
return
|
|
129
|
+
return createBrowserWorkspaceError(
|
|
130
|
+
"target_missing",
|
|
131
|
+
subaction,
|
|
119
132
|
`Eliza browser workspace ${subaction} requires a current tab. Open or show a tab first, or pass an explicit id.`
|
|
120
133
|
);
|
|
121
134
|
}
|
|
@@ -155,7 +168,9 @@ function resolveBrowserWorkspaceCommandElementRefs(command, mode, tabId) {
|
|
|
155
168
|
match[1]
|
|
156
169
|
);
|
|
157
170
|
if (!resolvedSelector) {
|
|
158
|
-
throw
|
|
171
|
+
throw createBrowserWorkspaceError(
|
|
172
|
+
"unknown_element_ref",
|
|
173
|
+
"element_ref",
|
|
159
174
|
`Unknown browser snapshot element ref ${match[1]}. Run snapshot or inspect again before reusing element refs.`
|
|
160
175
|
);
|
|
161
176
|
}
|
|
@@ -184,14 +199,20 @@ function assertBrowserWorkspaceUserScriptAllowed(script, context, mode, env = pr
|
|
|
184
199
|
}
|
|
185
200
|
if (!isBrowserWorkspaceUserScriptAllowed(env)) {
|
|
186
201
|
const suffix = context === "eval" ? "Eval subactions with a user `script` are disabled by default." : "Wait conditions with a user `script` are disabled by default.";
|
|
187
|
-
throw
|
|
202
|
+
throw createBrowserWorkspaceError(
|
|
203
|
+
"script_forbidden",
|
|
204
|
+
context,
|
|
188
205
|
`${BROWSER_WORKSPACE_USER_SCRIPT_FORBIDDEN} ${suffix} Set ELIZA_BROWSER_WORKSPACE_ALLOW_USER_SCRIPT=1 only on trusted single-user hosts.`
|
|
189
206
|
);
|
|
190
207
|
}
|
|
191
208
|
}
|
|
192
209
|
function createBrowserWorkspaceJsdomScriptExecutionError(context) {
|
|
193
210
|
const suffix = context === "eval" ? "Eval subactions are not supported on the web backend." : "Wait conditions with `script` are not supported on the web backend.";
|
|
194
|
-
return
|
|
211
|
+
return createBrowserWorkspaceError(
|
|
212
|
+
"script_forbidden",
|
|
213
|
+
context,
|
|
214
|
+
`${BROWSER_WORKSPACE_JSDOM_SCRIPT_FORBIDDEN} ${suffix}`
|
|
215
|
+
);
|
|
195
216
|
}
|
|
196
217
|
function assertBrowserWorkspaceJsdomScriptNotRequested(script, context) {
|
|
197
218
|
if (script?.trim()) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/workspace/browser-workspace-helpers.ts"],"sourcesContent":["import * as fsp from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { resolveBrowserWorkspaceElementRef } from \"./browser-workspace-state.js\";\nimport type {\n BrowserWorkspaceCommand,\n BrowserWorkspaceMode,\n BrowserWorkspaceSubaction,\n} from \"./browser-workspace-types.js\";\n\nexport const DEFAULT_TIMEOUT_MS = 12_000;\nexport const DEFAULT_WAIT_INTERVAL_MS = 120;\nexport const DEFAULT_WEB_PARTITION = \"persist:eliza-browser\";\nexport const CONNECTOR_BROWSER_WORKSPACE_PARTITION_PREFIX =\n \"persist:connector-\";\nexport const DESKTOP_BRIDGE_UNAVAILABLE_MESSAGE =\n \"Eliza browser workspace desktop bridge is unavailable.\";\nexport const browserWorkspacePageFetch = globalThis.fetch.bind(globalThis);\n\nexport function normalizeEnvValue(value: string | undefined): string | null {\n if (typeof value !== \"string\") {\n return null;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n}\n\nexport function normalizeBrowserWorkspaceText(value: unknown): string {\n return String(value ?? \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nexport function parseBrowserWorkspaceNumberLike(\n value: unknown,\n): number | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return value;\n }\n if (typeof value !== \"string\") {\n return undefined;\n }\n const parsed = Number.parseFloat(value.trim());\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nexport function assertBrowserWorkspaceUrl(rawUrl: string): string {\n const trimmed = rawUrl.trim();\n if (trimmed === \"about:blank\") {\n return trimmed;\n }\n\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n throw new Error(`browser workspace rejected invalid URL: ${rawUrl}`);\n }\n\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n throw new Error(\n `browser workspace only supports http/https URLs, got ${parsed.protocol}`,\n );\n }\n\n return parsed.toString();\n}\n\nexport function inferBrowserWorkspaceTitle(url: string): string {\n if (url === \"about:blank\") {\n return \"New Tab\";\n }\n\n try {\n return new URL(url).hostname.replace(/^www\\./, \"\") || \"Eliza Browser\";\n } catch {\n return \"Eliza Browser\";\n }\n}\n\nfunction normalizeConnectorBrowserWorkspaceSegment(\n value: string,\n fieldName: string,\n): string {\n const normalized = value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .replace(/-{2,}/g, \"-\")\n .slice(0, 64);\n if (!normalized) {\n throw new Error(`Eliza browser connector session requires ${fieldName}.`);\n }\n return normalized;\n}\n\nfunction hashConnectorBrowserWorkspacePartitionKey(\n provider: string,\n accountId: string,\n): string {\n const input = `${provider.trim().toLowerCase()}\\0${accountId.trim().toLowerCase()}`;\n let hash = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n hash ^= input.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193) >>> 0;\n }\n return hash.toString(36).padStart(7, \"0\");\n}\n\nexport function resolveConnectorBrowserWorkspacePartition(\n provider: string,\n accountId: string,\n): string {\n const providerSegment = normalizeConnectorBrowserWorkspaceSegment(\n provider,\n \"provider\",\n );\n const accountSegment = normalizeConnectorBrowserWorkspaceSegment(\n accountId,\n \"accountId\",\n );\n const suffix = hashConnectorBrowserWorkspacePartitionKey(provider, accountId);\n return `${CONNECTOR_BROWSER_WORKSPACE_PARTITION_PREFIX}${providerSegment}-${accountSegment}-${suffix}`;\n}\n\nexport function isConnectorBrowserWorkspacePartition(\n partition: string | null | undefined,\n): boolean {\n return (partition ?? \"\")\n .trim()\n .toLowerCase()\n .startsWith(CONNECTOR_BROWSER_WORKSPACE_PARTITION_PREFIX);\n}\n\nexport function resolveBrowserWorkspaceCommandPartition(\n command: Pick<\n BrowserWorkspaceCommand,\n \"connectorAccountId\" | \"connectorProvider\" | \"partition\"\n >,\n fallbackPartition: string,\n): string {\n const explicitPartition = command.partition?.trim();\n if (explicitPartition) {\n return explicitPartition;\n }\n const provider = command.connectorProvider?.trim();\n const accountId = command.connectorAccountId?.trim();\n if (provider && accountId) {\n return resolveConnectorBrowserWorkspacePartition(provider, accountId);\n }\n return fallbackPartition;\n}\n\nexport function assertBrowserWorkspaceConnectorSecretsNotExported(\n partition: string | null | undefined,\n operation: string,\n): void {\n if (!isConnectorBrowserWorkspacePartition(partition)) {\n return;\n }\n throw new Error(\n `Connector browser sessions do not allow raw cookie, token, storage, or state export (${operation}). Use the returned partition/profile/session handle instead.`,\n );\n}\n\nexport function createBrowserWorkspaceDesktopOnlyMessage(\n subaction: BrowserWorkspaceSubaction,\n): string {\n return `Eliza browser workspace ${subaction} is only available in the desktop app.`;\n}\n\nexport function createBrowserWorkspaceNotFoundError(tabId: string): Error {\n return new Error(\n `Browser workspace request failed (404): Tab ${tabId} was not found.`,\n );\n}\n\nexport function createBrowserWorkspaceCommandTargetError(\n subaction: BrowserWorkspaceSubaction,\n): Error {\n return new Error(\n `Eliza browser workspace ${subaction} requires a current tab. Open or show a tab first, or pass an explicit id.`,\n );\n}\n\nexport async function sleep(ms: number): Promise<void> {\n await new Promise<void>((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function writeBrowserWorkspaceFile(\n filePath: string,\n contents: string | Uint8Array,\n): Promise<string> {\n const resolved = path.resolve(filePath);\n await fsp.mkdir(path.dirname(resolved), { recursive: true });\n await fsp.writeFile(resolved, contents);\n return resolved;\n}\n\nexport function normalizeBrowserWorkspaceCommand(\n command: BrowserWorkspaceCommand,\n): BrowserWorkspaceCommand {\n const raw = command as BrowserWorkspaceCommand & Record<string, unknown>;\n const normalizedSubaction =\n typeof raw.subaction === \"string\"\n ? raw.subaction.trim().toLowerCase()\n : typeof raw.operation === \"string\"\n ? raw.operation.trim().toLowerCase()\n : \"\";\n const subaction =\n normalizedSubaction === \"goto\"\n ? \"navigate\"\n : normalizedSubaction === \"read\"\n ? \"get\"\n : command.subaction;\n const timeoutMs =\n parseBrowserWorkspaceNumberLike(command.timeoutMs) ??\n parseBrowserWorkspaceNumberLike(raw.ms) ??\n parseBrowserWorkspaceNumberLike(raw.milliseconds);\n\n return {\n ...command,\n subaction,\n timeoutMs,\n steps: Array.isArray(command.steps)\n ? command.steps.map((step) => normalizeBrowserWorkspaceCommand(step))\n : command.steps,\n };\n}\n\nexport function resolveBrowserWorkspaceCommandElementRefs(\n command: BrowserWorkspaceCommand,\n mode: BrowserWorkspaceMode,\n tabId: string,\n): BrowserWorkspaceCommand {\n const selector = command.selector?.trim();\n if (!selector) {\n return command;\n }\n\n const match = selector.match(/^(@e\\d+)([\\s\\S]*)$/i);\n if (!match?.[1]) {\n return command;\n }\n\n const resolvedSelector = resolveBrowserWorkspaceElementRef(\n mode,\n tabId,\n match[1],\n );\n if (!resolvedSelector) {\n throw new Error(\n `Unknown browser snapshot element ref ${match[1]}. Run snapshot or inspect again before reusing element refs.`,\n );\n }\n\n return {\n ...command,\n selector: `${resolvedSelector}${match[2] ?? \"\"}`,\n };\n}\n\nexport function buildBrowserWorkspaceCssStringLiteral(value: string): string {\n return JSON.stringify(value);\n}\n\n/** GHSA-mhhr-9ph9-64j7 / elizaOS/eliza#6767 — arbitrary script must not run in Node (JSDOM). */\nexport const BROWSER_WORKSPACE_JSDOM_SCRIPT_FORBIDDEN =\n \"Browser workspace arbitrary script execution is disabled in the JSDOM (web) backend because it runs in the Node.js agent process via unsafe eval patterns (GHSA-mhhr-9ph9-64j7). Use structured subactions (click, fill, get, wait on selector/url/text) or desktop browser workspace mode instead.\";\n\nexport const BROWSER_WORKSPACE_USER_SCRIPT_FORBIDDEN =\n \"Browser workspace arbitrary user script is disabled (GHSA-mhhr-9ph9-64j7). Use structured browser workspace subactions instead.\";\n\nexport function isBrowserWorkspaceUserScriptAllowed(\n env: NodeJS.ProcessEnv = process.env,\n): boolean {\n const flag = normalizeEnvValue(\n env.ELIZA_BROWSER_WORKSPACE_ALLOW_USER_SCRIPT,\n )?.toLowerCase();\n return flag === \"1\" || flag === \"true\" || flag === \"yes\";\n}\n\nexport function assertBrowserWorkspaceUserScriptAllowed(\n script: string | undefined,\n context: \"eval\" | \"wait\",\n mode: BrowserWorkspaceMode,\n env: NodeJS.ProcessEnv = process.env,\n): void {\n if (!script?.trim()) {\n return;\n }\n if (mode === \"web\") {\n throw createBrowserWorkspaceJsdomScriptExecutionError(context);\n }\n if (!isBrowserWorkspaceUserScriptAllowed(env)) {\n const suffix =\n context === \"eval\"\n ? \"Eval subactions with a user `script` are disabled by default.\"\n : \"Wait conditions with a user `script` are disabled by default.\";\n throw new Error(\n `${BROWSER_WORKSPACE_USER_SCRIPT_FORBIDDEN} ${suffix} Set ELIZA_BROWSER_WORKSPACE_ALLOW_USER_SCRIPT=1 only on trusted single-user hosts.`,\n );\n }\n}\n\nexport function createBrowserWorkspaceJsdomScriptExecutionError(\n context: \"eval\" | \"wait\",\n): Error {\n const suffix =\n context === \"eval\"\n ? \"Eval subactions are not supported on the web backend.\"\n : \"Wait conditions with `script` are not supported on the web backend.\";\n return new Error(`${BROWSER_WORKSPACE_JSDOM_SCRIPT_FORBIDDEN} ${suffix}`);\n}\n\nexport function assertBrowserWorkspaceJsdomScriptNotRequested(\n script: string | undefined,\n context: \"eval\" | \"wait\",\n): void {\n if (script?.trim()) {\n throw createBrowserWorkspaceJsdomScriptExecutionError(context);\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/workspace/browser-workspace-helpers.ts"],"sourcesContent":["import * as fsp from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { createBrowserWorkspaceError } from \"./browser-workspace-errors.js\";\nimport { resolveBrowserWorkspaceElementRef } from \"./browser-workspace-state.js\";\nimport type {\n BrowserWorkspaceCommand,\n BrowserWorkspaceMode,\n BrowserWorkspaceSubaction,\n} from \"./browser-workspace-types.js\";\n\nexport const DEFAULT_TIMEOUT_MS = 12_000;\nexport const DEFAULT_WAIT_INTERVAL_MS = 120;\nexport const DEFAULT_WEB_PARTITION = \"persist:eliza-browser\";\nexport const CONNECTOR_BROWSER_WORKSPACE_PARTITION_PREFIX =\n \"persist:connector-\";\nexport const DESKTOP_BRIDGE_UNAVAILABLE_MESSAGE =\n \"Eliza browser workspace desktop bridge is unavailable.\";\nexport const browserWorkspacePageFetch = globalThis.fetch.bind(globalThis);\n\nexport function normalizeEnvValue(value: string | undefined): string | null {\n if (typeof value !== \"string\") {\n return null;\n }\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : null;\n}\n\nexport function normalizeBrowserWorkspaceText(value: unknown): string {\n return String(value ?? \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nexport function parseBrowserWorkspaceNumberLike(\n value: unknown,\n): number | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return value;\n }\n if (typeof value !== \"string\") {\n return undefined;\n }\n const parsed = Number.parseFloat(value.trim());\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nexport function assertBrowserWorkspaceUrl(rawUrl: string): string {\n const trimmed = rawUrl.trim();\n if (trimmed === \"about:blank\") {\n return trimmed;\n }\n\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n throw createBrowserWorkspaceError(\n \"invalid_url\",\n \"url_validation\",\n `browser workspace rejected invalid URL: ${rawUrl}`,\n );\n }\n\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n throw createBrowserWorkspaceError(\n \"invalid_url\",\n \"url_validation\",\n `browser workspace only supports http/https URLs, got ${parsed.protocol}`,\n );\n }\n\n return parsed.toString();\n}\n\nexport function inferBrowserWorkspaceTitle(url: string): string {\n if (url === \"about:blank\") {\n return \"New Tab\";\n }\n\n try {\n return new URL(url).hostname.replace(/^www\\./, \"\") || \"Eliza Browser\";\n } catch {\n return \"Eliza Browser\";\n }\n}\n\nfunction normalizeConnectorBrowserWorkspaceSegment(\n value: string,\n fieldName: string,\n): string {\n const normalized = value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\")\n .replace(/-{2,}/g, \"-\")\n .slice(0, 64);\n if (!normalized) {\n throw new Error(`Eliza browser connector session requires ${fieldName}.`);\n }\n return normalized;\n}\n\nfunction hashConnectorBrowserWorkspacePartitionKey(\n provider: string,\n accountId: string,\n): string {\n const input = `${provider.trim().toLowerCase()}\\0${accountId.trim().toLowerCase()}`;\n let hash = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n hash ^= input.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193) >>> 0;\n }\n return hash.toString(36).padStart(7, \"0\");\n}\n\nexport function resolveConnectorBrowserWorkspacePartition(\n provider: string,\n accountId: string,\n): string {\n const providerSegment = normalizeConnectorBrowserWorkspaceSegment(\n provider,\n \"provider\",\n );\n const accountSegment = normalizeConnectorBrowserWorkspaceSegment(\n accountId,\n \"accountId\",\n );\n const suffix = hashConnectorBrowserWorkspacePartitionKey(provider, accountId);\n return `${CONNECTOR_BROWSER_WORKSPACE_PARTITION_PREFIX}${providerSegment}-${accountSegment}-${suffix}`;\n}\n\nexport function isConnectorBrowserWorkspacePartition(\n partition: string | null | undefined,\n): boolean {\n return (partition ?? \"\")\n .trim()\n .toLowerCase()\n .startsWith(CONNECTOR_BROWSER_WORKSPACE_PARTITION_PREFIX);\n}\n\nexport function resolveBrowserWorkspaceCommandPartition(\n command: Pick<\n BrowserWorkspaceCommand,\n \"connectorAccountId\" | \"connectorProvider\" | \"partition\"\n >,\n fallbackPartition: string,\n): string {\n const explicitPartition = command.partition?.trim();\n if (explicitPartition) {\n return explicitPartition;\n }\n const provider = command.connectorProvider?.trim();\n const accountId = command.connectorAccountId?.trim();\n if (provider && accountId) {\n return resolveConnectorBrowserWorkspacePartition(provider, accountId);\n }\n return fallbackPartition;\n}\n\nexport function assertBrowserWorkspaceConnectorSecretsNotExported(\n partition: string | null | undefined,\n operation: string,\n): void {\n if (!isConnectorBrowserWorkspacePartition(partition)) {\n return;\n }\n throw createBrowserWorkspaceError(\n \"connector_secret_export_forbidden\",\n operation,\n `Connector browser sessions do not allow raw cookie, token, storage, or state export (${operation}). Use the returned partition/profile/session handle instead.`,\n );\n}\n\nexport function createBrowserWorkspaceDesktopOnlyMessage(\n subaction: BrowserWorkspaceSubaction,\n): string {\n return `Eliza browser workspace ${subaction} is only available in the desktop app.`;\n}\n\nexport function createBrowserWorkspaceNotFoundError(tabId: string): Error {\n return createBrowserWorkspaceError(\n \"tab_not_found\",\n \"tab_lookup\",\n `Browser workspace request failed (404): Tab ${tabId} was not found.`,\n );\n}\n\nexport function createBrowserWorkspaceCommandTargetError(\n subaction: BrowserWorkspaceSubaction,\n): Error {\n return createBrowserWorkspaceError(\n \"target_missing\",\n subaction,\n `Eliza browser workspace ${subaction} requires a current tab. Open or show a tab first, or pass an explicit id.`,\n );\n}\n\nexport async function sleep(ms: number): Promise<void> {\n await new Promise<void>((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function writeBrowserWorkspaceFile(\n filePath: string,\n contents: string | Uint8Array,\n): Promise<string> {\n const resolved = path.resolve(filePath);\n await fsp.mkdir(path.dirname(resolved), { recursive: true });\n await fsp.writeFile(resolved, contents);\n return resolved;\n}\n\nexport function normalizeBrowserWorkspaceCommand(\n command: BrowserWorkspaceCommand,\n): BrowserWorkspaceCommand {\n const raw = command as BrowserWorkspaceCommand & Record<string, unknown>;\n const normalizedSubaction =\n typeof raw.subaction === \"string\"\n ? raw.subaction.trim().toLowerCase()\n : typeof raw.operation === \"string\"\n ? raw.operation.trim().toLowerCase()\n : \"\";\n const subaction =\n normalizedSubaction === \"goto\"\n ? \"navigate\"\n : normalizedSubaction === \"read\"\n ? \"get\"\n : command.subaction;\n const timeoutMs =\n parseBrowserWorkspaceNumberLike(command.timeoutMs) ??\n parseBrowserWorkspaceNumberLike(raw.ms) ??\n parseBrowserWorkspaceNumberLike(raw.milliseconds);\n\n return {\n ...command,\n subaction,\n timeoutMs,\n steps: Array.isArray(command.steps)\n ? command.steps.map((step) => normalizeBrowserWorkspaceCommand(step))\n : command.steps,\n };\n}\n\nexport function resolveBrowserWorkspaceCommandElementRefs(\n command: BrowserWorkspaceCommand,\n mode: BrowserWorkspaceMode,\n tabId: string,\n): BrowserWorkspaceCommand {\n const selector = command.selector?.trim();\n if (!selector) {\n return command;\n }\n\n const match = selector.match(/^(@e\\d+)([\\s\\S]*)$/i);\n if (!match?.[1]) {\n return command;\n }\n\n const resolvedSelector = resolveBrowserWorkspaceElementRef(\n mode,\n tabId,\n match[1],\n );\n if (!resolvedSelector) {\n throw createBrowserWorkspaceError(\n \"unknown_element_ref\",\n \"element_ref\",\n `Unknown browser snapshot element ref ${match[1]}. Run snapshot or inspect again before reusing element refs.`,\n );\n }\n\n return {\n ...command,\n selector: `${resolvedSelector}${match[2] ?? \"\"}`,\n };\n}\n\nexport function buildBrowserWorkspaceCssStringLiteral(value: string): string {\n return JSON.stringify(value);\n}\n\n/** GHSA-mhhr-9ph9-64j7 / elizaOS/eliza#6767 — arbitrary script must not run in Node (JSDOM). */\nexport const BROWSER_WORKSPACE_JSDOM_SCRIPT_FORBIDDEN =\n \"Browser workspace arbitrary script execution is disabled in the JSDOM (web) backend because it runs in the Node.js agent process via unsafe eval patterns (GHSA-mhhr-9ph9-64j7). Use structured subactions (click, fill, get, wait on selector/url/text) or desktop browser workspace mode instead.\";\n\nexport const BROWSER_WORKSPACE_USER_SCRIPT_FORBIDDEN =\n \"Browser workspace arbitrary user script is disabled (GHSA-mhhr-9ph9-64j7). Use structured browser workspace subactions instead.\";\n\nexport function isBrowserWorkspaceUserScriptAllowed(\n env: NodeJS.ProcessEnv = process.env,\n): boolean {\n const flag = normalizeEnvValue(\n env.ELIZA_BROWSER_WORKSPACE_ALLOW_USER_SCRIPT,\n )?.toLowerCase();\n return flag === \"1\" || flag === \"true\" || flag === \"yes\";\n}\n\nexport function assertBrowserWorkspaceUserScriptAllowed(\n script: string | undefined,\n context: \"eval\" | \"wait\",\n mode: BrowserWorkspaceMode,\n env: NodeJS.ProcessEnv = process.env,\n): void {\n if (!script?.trim()) {\n return;\n }\n if (mode === \"web\") {\n throw createBrowserWorkspaceJsdomScriptExecutionError(context);\n }\n if (!isBrowserWorkspaceUserScriptAllowed(env)) {\n const suffix =\n context === \"eval\"\n ? \"Eval subactions with a user `script` are disabled by default.\"\n : \"Wait conditions with a user `script` are disabled by default.\";\n throw createBrowserWorkspaceError(\n \"script_forbidden\",\n context,\n `${BROWSER_WORKSPACE_USER_SCRIPT_FORBIDDEN} ${suffix} Set ELIZA_BROWSER_WORKSPACE_ALLOW_USER_SCRIPT=1 only on trusted single-user hosts.`,\n );\n }\n}\n\nexport function createBrowserWorkspaceJsdomScriptExecutionError(\n context: \"eval\" | \"wait\",\n): Error {\n const suffix =\n context === \"eval\"\n ? \"Eval subactions are not supported on the web backend.\"\n : \"Wait conditions with `script` are not supported on the web backend.\";\n return createBrowserWorkspaceError(\n \"script_forbidden\",\n context,\n `${BROWSER_WORKSPACE_JSDOM_SCRIPT_FORBIDDEN} ${suffix}`,\n );\n}\n\nexport function assertBrowserWorkspaceJsdomScriptNotRequested(\n script: string | undefined,\n context: \"eval\" | \"wait\",\n): void {\n if (script?.trim()) {\n throw createBrowserWorkspaceJsdomScriptExecutionError(context);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-workspace-web.d.ts","sourceRoot":"","sources":["../../src/workspace/browser-workspace-web.ts"],"names":[],"mappings":"AAqEA,OAAO,KAAK,EACV,uBAAuB,EACvB,6BAA6B,EAE7B,2BAA2B,EAC5B,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"browser-workspace-web.d.ts","sourceRoot":"","sources":["../../src/workspace/browser-workspace-web.ts"],"names":[],"mappings":"AAqEA,OAAO,KAAK,EACV,uBAAuB,EACvB,6BAA6B,EAE7B,2BAA2B,EAC5B,MAAM,8BAA8B,CAAC;AAiBtC,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,MAAM,GACZ,2BAA2B,CAM7B;AAED,wBAAgB,qCAAqC,IAAI,2BAA2B,GAAG,IAAI,CAgB1F;AAED,wBAAgB,kCAAkC,CAChD,OAAO,EAAE,uBAAuB,GAC/B,MAAM,CASR;AAED,wBAAsB,wCAAwC,CAC5D,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,6BAA6B,GAAG,IAAI,CAAC,CAqwB/C;AAED,wBAAsB,oCAAoC,CACxD,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,6BAA6B,CAAC,CAqlBxC"}
|
|
@@ -29,9 +29,9 @@ import {
|
|
|
29
29
|
} from "./browser-workspace-forms.js";
|
|
30
30
|
import {
|
|
31
31
|
assertBrowserWorkspaceConnectorSecretsNotExported,
|
|
32
|
-
createBrowserWorkspaceJsdomScriptExecutionError,
|
|
33
32
|
assertBrowserWorkspaceJsdomScriptNotRequested,
|
|
34
33
|
createBrowserWorkspaceCommandTargetError,
|
|
34
|
+
createBrowserWorkspaceJsdomScriptExecutionError,
|
|
35
35
|
createBrowserWorkspaceNotFoundError,
|
|
36
36
|
DEFAULT_TIMEOUT_MS,
|
|
37
37
|
DEFAULT_WAIT_INTERVAL_MS,
|
|
@@ -67,6 +67,13 @@ import {
|
|
|
67
67
|
webWorkspaceState,
|
|
68
68
|
withWebStateLock
|
|
69
69
|
} from "./browser-workspace-state.js";
|
|
70
|
+
function safeWebStorageArea(getArea) {
|
|
71
|
+
try {
|
|
72
|
+
return getArea();
|
|
73
|
+
} catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
70
77
|
function getWebBrowserWorkspaceTabIndex(tabId) {
|
|
71
78
|
return webWorkspaceState.tabs.findIndex((tab) => tab.id === tabId);
|
|
72
79
|
}
|
|
@@ -377,7 +384,14 @@ async function executeWebBrowserWorkspaceUtilityCommand(command) {
|
|
|
377
384
|
tab.partition,
|
|
378
385
|
"storage"
|
|
379
386
|
);
|
|
380
|
-
const area =
|
|
387
|
+
const area = safeWebStorageArea(
|
|
388
|
+
() => command.storageArea === "session" ? dom.window.sessionStorage : dom.window.localStorage
|
|
389
|
+
);
|
|
390
|
+
if (!area) {
|
|
391
|
+
throw new Error(
|
|
392
|
+
"Eliza browser workspace storage is unavailable for this page's origin (e.g. about:blank). Navigate to a real page first."
|
|
393
|
+
);
|
|
394
|
+
}
|
|
381
395
|
const action = command.storageAction ?? "get";
|
|
382
396
|
if (action === "clear") {
|
|
383
397
|
area.clear();
|
|
@@ -766,13 +780,13 @@ async function executeWebBrowserWorkspaceUtilityCommand(command) {
|
|
|
766
780
|
value: { loaded: true }
|
|
767
781
|
};
|
|
768
782
|
}
|
|
783
|
+
const localArea = safeWebStorageArea(() => dom.window.localStorage);
|
|
784
|
+
const sessionArea = safeWebStorageArea(() => dom.window.sessionStorage);
|
|
769
785
|
const payload = {
|
|
770
786
|
clipboard: browserWorkspaceClipboardText,
|
|
771
787
|
cookies: readBrowserWorkspaceCookies(document),
|
|
772
|
-
localStorage: readBrowserWorkspaceStorage(
|
|
773
|
-
sessionStorage: readBrowserWorkspaceStorage(
|
|
774
|
-
dom.window.sessionStorage
|
|
775
|
-
),
|
|
788
|
+
localStorage: localArea ? readBrowserWorkspaceStorage(localArea) : {},
|
|
789
|
+
sessionStorage: sessionArea ? readBrowserWorkspaceStorage(sessionArea) : {},
|
|
776
790
|
settings: runtime.settings,
|
|
777
791
|
url: tab.url
|
|
778
792
|
};
|