agents 0.27.0 → 0.28.1
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/abortable-C1SpfVoi.js +21 -0
- package/dist/abortable-C1SpfVoi.js.map +1 -0
- package/dist/{agent-routing-Bhdbvf7s.d.ts → agent-routing-BMvWTFEp.d.ts} +21 -15
- package/dist/agent-routing.d.ts +1 -1
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-bJZwBMfq.d.ts → agent-tools-ohoewW-B.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/ai-ahruGw7e.d.ts +239 -0
- package/dist/{ai-sdk-OoGkFy3s.js → ai-sdk-C2iTAwUd.js} +44 -18
- package/dist/ai-sdk-C2iTAwUd.js.map +1 -0
- package/dist/browser/ai.d.ts +8 -227
- package/dist/browser/ai.js +259 -1
- package/dist/browser/ai.js.map +1 -0
- package/dist/browser/index.d.ts +56 -46
- package/dist/browser/index.js +4 -361
- package/dist/browser/{ai-sdk.d.ts → tools/ai-sdk.d.ts} +7 -7
- package/dist/browser/{ai-sdk.js → tools/ai-sdk.js} +5 -4
- package/dist/browser/tools/ai-sdk.js.map +1 -0
- package/dist/browser/tools/pi.d.ts +111 -0
- package/dist/browser/tools/pi.js +119 -0
- package/dist/browser/tools/pi.js.map +1 -0
- package/dist/browser/{tanstack-ai.d.ts → tools/tanstack-ai.d.ts} +39 -37
- package/dist/browser/{tanstack-ai.js → tools/tanstack-ai.js} +73 -59
- package/dist/browser/tools/tanstack-ai.js.map +1 -0
- package/dist/browser-CEdNlsaD.js +481 -0
- package/dist/browser-CEdNlsaD.js.map +1 -0
- package/dist/{browser-tmkcAAI3.d.ts → browser-D30VlpcA.d.ts} +63 -37
- package/dist/{browser-tool-CBqs6hqa.js → browser-tool-4iomavs_.js} +145 -49
- package/dist/browser-tool-4iomavs_.js.map +1 -0
- package/dist/{browser-tool-Bn-nzJQI.d.ts → browser-tool-vtrPOV8e.d.ts} +24 -5
- package/dist/{capability-B4WbF81e.js → capability-DBAKc6UZ.js} +1 -3
- package/dist/capability-DBAKc6UZ.js.map +1 -0
- package/dist/{capability-runner-O5VbQzqg.d.ts → capability-runner-BiVUtjqC.d.ts} +1 -7
- package/dist/chat/index.d.ts +4 -4
- package/dist/chat/index.js +1 -1
- package/dist/chat-sdk/index.d.ts +1 -1
- package/dist/chat-sdk/index.js +1 -1
- package/dist/{client-1tEQ1Oqz.js → client-BnYbNT3z.js} +3 -4
- package/dist/client-BnYbNT3z.js.map +1 -0
- package/dist/{client-DS3Dz9l0.d.ts → client-Bp-JwL3p.d.ts} +2 -2
- package/dist/client.d.ts +1 -1
- package/dist/{connector-58XDGvc3.js → connector-CtZylXdk.js} +3 -603
- package/dist/connector-CtZylXdk.js.map +1 -0
- package/dist/{connector-Cl-VqPmA.d.ts → connector-DEXzVoaY.d.ts} +9 -374
- package/dist/{conversations-DH0ut_8n.d.ts → conversations-FjHDRZyD.d.ts} +4 -4
- package/dist/{current-agent-C07C5o5Y.d.ts → current-agent-CKgT5d1O.d.ts} +3 -5
- package/dist/current-agent-DhoDkSnH.js.map +1 -1
- package/dist/{durable-object-lifecycle-DRqp475_.d.ts → durable-object-lifecycle-DOI_bzCH.d.ts} +2 -2
- package/dist/experimental/channels/index.d.ts +2 -2
- package/dist/experimental/channels/index.js +2 -2
- package/dist/experimental/channels/web/index.d.ts +2 -2
- package/dist/experimental/channels/web/index.js +1 -1
- package/dist/{gateway-BDC07gYO.d.ts → gateway-BFO6vRDn.d.ts} +2 -2
- package/dist/{handler-stateless-VvrWSAVA.js → handler-stateless-Bly_nSH3.js} +12 -3
- package/dist/handler-stateless-Bly_nSH3.js.map +1 -0
- package/dist/harness/ai-sdk/index.d.ts +2 -2
- package/dist/harness/ai-sdk/index.js +1 -1
- package/dist/harness/container/index.d.ts +2 -2
- package/dist/harness/container/index.js +3 -3
- package/dist/harness/opencode/index.d.ts +183 -7
- package/dist/harness/opencode/index.js +355 -24
- package/dist/harness/opencode/index.js.map +1 -1
- package/dist/harness/pi/index.d.ts +2 -2
- package/dist/harness/pi/index.js +3 -3
- package/dist/harness/store/index.d.ts +1 -1
- package/dist/harness/store/index.js +1 -1
- package/dist/harness/think/index.d.ts +2 -2
- package/dist/harness/think/index.js +363 -171
- package/dist/harness/think/index.js.map +1 -1
- package/dist/{images-Ce9SCu3X.js → images-C4hiIexM.js} +46 -4
- package/dist/images-C4hiIexM.js.map +1 -0
- package/dist/{index-D0A5tbWu.d.ts → index-BEL3ZV-s.d.ts} +2 -6
- package/dist/{index-Ib_4dwOo.d.ts → index-CBt8oRJt.d.ts} +3 -5
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/input-schema-BQykTEp_.js +20 -0
- package/dist/input-schema-BQykTEp_.js.map +1 -0
- package/dist/{input-schema-DNrpTu49.js → input-schema-xBofjBKC.js} +3 -3
- package/dist/input-schema-xBofjBKC.js.map +1 -0
- package/dist/internal_context.d.ts +1 -1
- package/dist/lifecycle/index.d.ts +3 -3
- package/dist/lifecycle/index.js +2 -2
- package/dist/{lifecycle-CFu6OV03.js → lifecycle-DGorpAmA.js} +2 -4
- package/dist/lifecycle-DGorpAmA.js.map +1 -0
- package/dist/mcp/client/index.d.ts +1 -1
- package/dist/mcp/client/index.js +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +18 -4
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server/index.js +1 -1
- package/dist/models/ai-sdk/index.d.ts +45 -17
- package/dist/models/ai-sdk/index.js +1 -1
- package/dist/models/opencode/index.d.ts +2 -2
- package/dist/models/opencode/index.js +1 -1
- package/dist/models/pi-ai/index.d.ts +8 -3
- package/dist/models/pi-ai/index.js +6 -6
- package/dist/models/pi-ai/index.js.map +1 -1
- package/dist/{options-pwTNq9z6.d.ts → options-CiIsJHXR.d.ts} +2 -6
- package/dist/queue/index.d.ts +1 -1
- package/dist/queue/index.js +1 -1
- package/dist/{queue-BB-zfIYF.js → queue-CcIjVYTE.js} +2 -2
- package/dist/{queue-BB-zfIYF.js.map → queue-CcIjVYTE.js.map} +1 -1
- package/dist/react.d.ts +2 -2
- package/dist/routing/index.d.ts +2 -2
- package/dist/routing/index.js +1 -1
- package/dist/{scheduler-CrFCnv_J.d.ts → scheduler-BCLESHSC.d.ts} +2 -12
- package/dist/{scheduler-DZ3xQfeK.js → scheduler-FIHv2-kJ.js} +2 -4
- package/dist/scheduler-FIHv2-kJ.js.map +1 -0
- package/dist/schedules/index.d.ts +1 -1
- package/dist/schedules/index.js +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/session-store-Do4xkDcf.js +606 -0
- package/dist/session-store-Do4xkDcf.js.map +1 -0
- package/dist/session-store-DoPY12xM.d.ts +383 -0
- package/dist/sessions/index.d.ts +1 -1
- package/dist/sessions/index.js +1 -1
- package/dist/{sessions-B9pNuxdT.js → sessions-_vN5BEZX.js} +2 -2
- package/dist/{sessions-B9pNuxdT.js.map → sessions-_vN5BEZX.js.map} +1 -1
- package/dist/{settings-C45hDliX.js → settings-BjAiPd6Z.js} +7 -4
- package/dist/settings-BjAiPd6Z.js.map +1 -0
- package/dist/{settings-NgGwF7Qt.d.ts → settings-DnD__xuE.d.ts} +22 -4
- package/dist/{src-DgCbZtIR.js → src-CQxJFv4l.js} +8 -8
- package/dist/src-CQxJFv4l.js.map +1 -0
- package/dist/state/index.d.ts +1 -1
- package/dist/state/index.js +1 -3
- package/dist/state/index.js.map +1 -1
- package/dist/{store-DLeqKuj3.d.ts → store-BKM4Xm9M.d.ts} +23 -1
- package/dist/{store-vgcPYo8K.js → store-CslVzfN7.js} +28 -2
- package/dist/store-CslVzfN7.js.map +1 -0
- package/dist/streams/index.d.ts +1 -1
- package/dist/streams/index.js +1 -1
- package/dist/{streams-CITClVer.js → streams-lsHMJhRW.js} +2 -2
- package/dist/{streams-CITClVer.js.map → streams-lsHMJhRW.js.map} +1 -1
- package/dist/{streams-fbG61qM8.d.ts → streams-vrCtbUIn.d.ts} +2 -2
- package/dist/sub-routing.d.ts +1 -1
- package/dist/tasks/index.d.ts +1 -1
- package/dist/tasks/index.js +1 -1
- package/dist/{tasks-CkTZNaV1.js → tasks-BN_5AWqI.js} +2 -2
- package/dist/{tasks-CkTZNaV1.js.map → tasks-BN_5AWqI.js.map} +1 -1
- package/dist/{tasks-PtlB4Uyn.d.ts → tasks-E89KdwkS.d.ts} +2 -2
- package/dist/{tool-BPJEbwaX.d.ts → tool-CTp72Jb_.d.ts} +4 -4
- package/dist/tool-CxKsvxjm.js +1126 -0
- package/dist/tool-CxKsvxjm.js.map +1 -0
- package/dist/tool-DoVberpN.d.ts +301 -0
- package/dist/{tool-3PA8xjB_.js → tool-VF0qiO7q.js} +7 -18
- package/dist/tool-VF0qiO7q.js.map +1 -0
- package/dist/tool-helpers-O5BDVEAY.js +58 -0
- package/dist/tool-helpers-O5BDVEAY.js.map +1 -0
- package/dist/{transport-k2mFrtL8.d.ts → transport-DCyarnwm.d.ts} +2 -2
- package/dist/voice/index.d.ts +2 -2
- package/dist/web/fetch/index.d.ts +89 -0
- package/dist/web/fetch/index.js +20 -0
- package/dist/web/fetch/index.js.map +1 -0
- package/dist/web/fetch/tools/ai-sdk.d.ts +80 -0
- package/dist/web/fetch/tools/ai-sdk.js +47 -0
- package/dist/web/fetch/tools/ai-sdk.js.map +1 -0
- package/dist/web/fetch/tools/pi.d.ts +84 -0
- package/dist/web/fetch/tools/pi.js +88 -0
- package/dist/web/fetch/tools/pi.js.map +1 -0
- package/dist/web/fetch/tools/tanstack-ai.d.ts +78 -0
- package/dist/web/fetch/tools/tanstack-ai.js +45 -0
- package/dist/web/fetch/tools/tanstack-ai.js.map +1 -0
- package/dist/{websearch → web/search}/index.d.ts +1 -1
- package/dist/{websearch → web/search}/index.js +1 -1
- package/dist/{websearch → web/search}/tools/ai-sdk.d.ts +2 -2
- package/dist/{websearch → web/search}/tools/ai-sdk.js +3 -3
- package/dist/web/search/tools/ai-sdk.js.map +1 -0
- package/dist/{websearch → web/search}/tools/pi.d.ts +3 -3
- package/dist/{websearch → web/search}/tools/pi.js +2 -2
- package/dist/web/search/tools/pi.js.map +1 -0
- package/dist/{websearch → web/search}/tools/tanstack-ai.d.ts +2 -2
- package/dist/{websearch → web/search}/tools/tanstack-ai.js +3 -3
- package/dist/web/search/tools/tanstack-ai.js.map +1 -0
- package/dist/websockets/index.d.ts +2 -2
- package/dist/websockets/index.js +1 -1
- package/dist/{websockets-CmENGb-Z.js → websockets-C3zy8YR0.js} +3 -5
- package/dist/websockets-C3zy8YR0.js.map +1 -0
- package/dist/workflow-types.d.ts +1 -1
- package/dist/workflows.d.ts +1 -1
- package/dist/workflows.js +1 -1
- package/docs/browse-the-web.md +26 -1
- package/docs/fetch-the-web.md +276 -0
- package/docs/harnesses/pi.md +25 -0
- package/docs/index.md +99 -76
- package/docs/lifecycle.md +2 -3
- package/docs/mcp-client.md +1 -1
- package/docs/mcp-servers.md +1 -1
- package/docs/models-pi-ai.md +11 -0
- package/docs/models.md +45 -3
- package/docs/queue.md +2 -3
- package/docs/scheduling.md +2 -6
- package/docs/search-the-web.md +2 -0
- package/package.json +52 -27
- package/dist/ai-fm7xx1BK.js +0 -312
- package/dist/ai-fm7xx1BK.js.map +0 -1
- package/dist/ai-sdk-OoGkFy3s.js.map +0 -1
- package/dist/browser/ai-sdk.js.map +0 -1
- package/dist/browser/index.js.map +0 -1
- package/dist/browser/tanstack-ai.js.map +0 -1
- package/dist/browser-tool-CBqs6hqa.js.map +0 -1
- package/dist/capability-B4WbF81e.js.map +0 -1
- package/dist/client-1tEQ1Oqz.js.map +0 -1
- package/dist/connector-58XDGvc3.js.map +0 -1
- package/dist/handler-stateless-VvrWSAVA.js.map +0 -1
- package/dist/images-Ce9SCu3X.js.map +0 -1
- package/dist/input-schema-DNrpTu49.js.map +0 -1
- package/dist/lifecycle-CFu6OV03.js.map +0 -1
- package/dist/scheduler-DZ3xQfeK.js.map +0 -1
- package/dist/settings-C45hDliX.js.map +0 -1
- package/dist/src-DgCbZtIR.js.map +0 -1
- package/dist/store-vgcPYo8K.js.map +0 -1
- package/dist/tool-3PA8xjB_.js.map +0 -1
- package/dist/websearch/tools/ai-sdk.js.map +0 -1
- package/dist/websearch/tools/pi.js.map +0 -1
- package/dist/websearch/tools/tanstack-ai.js.map +0 -1
- package/dist/websockets-CmENGb-Z.js.map +0 -1
|
@@ -0,0 +1,606 @@
|
|
|
1
|
+
import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "./classPrivateFieldGet2-DZBYAB34.js";
|
|
2
|
+
import { t as _classPrivateMethodInitSpec } from "./classPrivateMethodInitSpec-qMjJ6sHQ.js";
|
|
3
|
+
import { Validator } from "@cfworker/json-schema";
|
|
4
|
+
//#region src/browser/cdp-connection.ts
|
|
5
|
+
const DEFAULT_TIMEOUT_MS = 1e4;
|
|
6
|
+
/** JSON-RPC's "method not found" code, which Chrome also uses for CDP. */
|
|
7
|
+
const CDP_METHOD_NOT_FOUND = -32601;
|
|
8
|
+
/** The browser answered a command with a JSON-RPC error. */
|
|
9
|
+
var CdpProtocolError = class extends Error {
|
|
10
|
+
constructor(method, code, message) {
|
|
11
|
+
super(`CDP error ${code ?? "unknown"}: ${message} for ${method}`);
|
|
12
|
+
this.name = "CdpProtocolError";
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.method = method;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const MAX_DEBUG_ENTRIES = 400;
|
|
18
|
+
var _socket = /* @__PURE__ */ new WeakMap();
|
|
19
|
+
var _nextId = /* @__PURE__ */ new WeakMap();
|
|
20
|
+
var _pending = /* @__PURE__ */ new WeakMap();
|
|
21
|
+
var _debugLog = /* @__PURE__ */ new WeakMap();
|
|
22
|
+
var _defaultTimeoutMs = /* @__PURE__ */ new WeakMap();
|
|
23
|
+
var _dispose = /* @__PURE__ */ new WeakMap();
|
|
24
|
+
var _disposed = /* @__PURE__ */ new WeakMap();
|
|
25
|
+
var _onActivity = /* @__PURE__ */ new WeakMap();
|
|
26
|
+
var _CdpConnection_brand = /* @__PURE__ */ new WeakSet();
|
|
27
|
+
/**
|
|
28
|
+
* One Chrome DevTools Protocol connection over an open WebSocket. Manages
|
|
29
|
+
* command correlation, timeouts, per-tab CDP sessions, and a debug event
|
|
30
|
+
* ring buffer.
|
|
31
|
+
*
|
|
32
|
+
* Used host-side (not in the sandbox) — the sandbox calls into this
|
|
33
|
+
* via DynamicWorkerExecutor's ToolDispatcher RPC.
|
|
34
|
+
*/
|
|
35
|
+
var CdpConnection = class {
|
|
36
|
+
constructor(socket, optionsOrTimeoutMs, onClose, sessionId) {
|
|
37
|
+
_classPrivateMethodInitSpec(this, _CdpConnection_brand);
|
|
38
|
+
_classPrivateFieldInitSpec(this, _socket, void 0);
|
|
39
|
+
_classPrivateFieldInitSpec(this, _nextId, 1);
|
|
40
|
+
_classPrivateFieldInitSpec(this, _pending, /* @__PURE__ */ new Map());
|
|
41
|
+
_classPrivateFieldInitSpec(this, _debugLog, []);
|
|
42
|
+
_classPrivateFieldInitSpec(this, _defaultTimeoutMs, void 0);
|
|
43
|
+
_classPrivateFieldInitSpec(this, _dispose, void 0);
|
|
44
|
+
_classPrivateFieldInitSpec(this, _disposed, false);
|
|
45
|
+
_classPrivateFieldInitSpec(this, _onActivity, void 0);
|
|
46
|
+
const options = typeof optionsOrTimeoutMs === "object" ? optionsOrTimeoutMs : {
|
|
47
|
+
timeoutMs: optionsOrTimeoutMs,
|
|
48
|
+
onClose,
|
|
49
|
+
sessionId
|
|
50
|
+
};
|
|
51
|
+
_classPrivateFieldSet2(_socket, this, socket);
|
|
52
|
+
_classPrivateFieldSet2(_defaultTimeoutMs, this, options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
53
|
+
_classPrivateFieldSet2(_dispose, this, options.onClose);
|
|
54
|
+
this.sessionId = options.sessionId;
|
|
55
|
+
_classPrivateFieldSet2(_onActivity, this, options.onActivity);
|
|
56
|
+
socket.addEventListener("message", (event) => _assertClassBrand(_CdpConnection_brand, this, _handleMessage).call(this, event));
|
|
57
|
+
socket.addEventListener("error", () => {
|
|
58
|
+
_assertClassBrand(_CdpConnection_brand, this, _rejectAll).call(this, /* @__PURE__ */ new Error("CDP socket error"));
|
|
59
|
+
_assertClassBrand(_CdpConnection_brand, this, _runDispose).call(this);
|
|
60
|
+
});
|
|
61
|
+
socket.addEventListener("close", () => {
|
|
62
|
+
_assertClassBrand(_CdpConnection_brand, this, _rejectAll).call(this, /* @__PURE__ */ new Error("CDP connection closed"));
|
|
63
|
+
_assertClassBrand(_CdpConnection_brand, this, _runDispose).call(this);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
send(method, params, options = {}) {
|
|
67
|
+
var _this$nextId, _this$nextId2;
|
|
68
|
+
_classPrivateFieldGet2(_onActivity, this)?.call(this);
|
|
69
|
+
const id = (_classPrivateFieldSet2(_nextId, this, (_this$nextId = _classPrivateFieldGet2(_nextId, this), _this$nextId2 = _this$nextId++, _this$nextId)), _this$nextId2);
|
|
70
|
+
const timeoutMs = options.timeoutMs ?? _classPrivateFieldGet2(_defaultTimeoutMs, this);
|
|
71
|
+
const sessionId = typeof options.sessionId === "string" && options.sessionId.length > 0 ? options.sessionId : void 0;
|
|
72
|
+
const domain = typeof method === "string" ? method.split(".")[0] : "";
|
|
73
|
+
if (!sessionId && domain && !["Browser", "Target"].includes(domain)) _assertClassBrand(_CdpConnection_brand, this, _recordDebug).call(this, "warning", {
|
|
74
|
+
id,
|
|
75
|
+
method,
|
|
76
|
+
reason: "target-scoped method sent without sessionId"
|
|
77
|
+
});
|
|
78
|
+
const result = new Promise((resolve, reject) => {
|
|
79
|
+
const startedAt = performance.now();
|
|
80
|
+
const timeoutId = setTimeout(() => {
|
|
81
|
+
_classPrivateFieldGet2(_pending, this).delete(id);
|
|
82
|
+
reject(/* @__PURE__ */ new Error(`CDP command timed out after ${timeoutMs}ms: ${method}`));
|
|
83
|
+
}, timeoutMs);
|
|
84
|
+
_classPrivateFieldGet2(_pending, this).set(id, {
|
|
85
|
+
resolve,
|
|
86
|
+
reject,
|
|
87
|
+
timeoutId,
|
|
88
|
+
method,
|
|
89
|
+
sessionId,
|
|
90
|
+
startedAt
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
_assertClassBrand(_CdpConnection_brand, this, _recordDebug).call(this, "send", {
|
|
94
|
+
id,
|
|
95
|
+
method,
|
|
96
|
+
sessionId,
|
|
97
|
+
timeoutMs
|
|
98
|
+
});
|
|
99
|
+
try {
|
|
100
|
+
_classPrivateFieldGet2(_socket, this).send(JSON.stringify({
|
|
101
|
+
id,
|
|
102
|
+
method,
|
|
103
|
+
params,
|
|
104
|
+
sessionId
|
|
105
|
+
}));
|
|
106
|
+
} catch (error) {
|
|
107
|
+
const pending = _classPrivateFieldGet2(_pending, this).get(id);
|
|
108
|
+
if (pending) {
|
|
109
|
+
clearTimeout(pending.timeoutId);
|
|
110
|
+
_classPrivateFieldGet2(_pending, this).delete(id);
|
|
111
|
+
pending.reject(error instanceof Error ? error : new Error(String(error)));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
async attachToTarget(targetId, options = {}) {
|
|
117
|
+
if (typeof targetId !== "string" || !targetId) throw new Error("attachToTarget requires a targetId — list open tabs with send('Target.getTargets') or create one with send('Target.createTarget', { url })");
|
|
118
|
+
const sessionId = (await this.send("Target.attachToTarget", {
|
|
119
|
+
targetId,
|
|
120
|
+
flatten: true
|
|
121
|
+
}, { timeoutMs: options.timeoutMs }))?.sessionId ?? "";
|
|
122
|
+
if (!sessionId) throw new Error(`Target.attachToTarget did not return a sessionId for target ${targetId}`);
|
|
123
|
+
_assertClassBrand(_CdpConnection_brand, this, _recordDebug).call(this, "attach", {
|
|
124
|
+
targetId,
|
|
125
|
+
sessionId
|
|
126
|
+
});
|
|
127
|
+
return sessionId;
|
|
128
|
+
}
|
|
129
|
+
getDebugLog(limit = 50) {
|
|
130
|
+
const normalized = Number.isFinite(limit) ? Math.max(1, Math.floor(limit)) : 50;
|
|
131
|
+
return _classPrivateFieldGet2(_debugLog, this).slice(-normalized);
|
|
132
|
+
}
|
|
133
|
+
clearDebugLog() {
|
|
134
|
+
_classPrivateFieldSet2(_debugLog, this, []);
|
|
135
|
+
}
|
|
136
|
+
disconnect() {
|
|
137
|
+
_assertClassBrand(_CdpConnection_brand, this, _rejectAll).call(this, /* @__PURE__ */ new Error("CDP session disconnected"));
|
|
138
|
+
try {
|
|
139
|
+
_classPrivateFieldGet2(_socket, this).close(1e3, "Done");
|
|
140
|
+
} catch {}
|
|
141
|
+
}
|
|
142
|
+
close() {
|
|
143
|
+
this.disconnect();
|
|
144
|
+
_assertClassBrand(_CdpConnection_brand, this, _runDispose).call(this);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* Run the dispose callback exactly once, on the first terminal event —
|
|
149
|
+
* an explicit {@link close}, peer closure, or a socket error.
|
|
150
|
+
*/
|
|
151
|
+
function _runDispose() {
|
|
152
|
+
if (_classPrivateFieldGet2(_disposed, this)) return;
|
|
153
|
+
_classPrivateFieldSet2(_disposed, this, true);
|
|
154
|
+
_classPrivateFieldGet2(_dispose, this)?.call(this);
|
|
155
|
+
}
|
|
156
|
+
function _rejectAll(error) {
|
|
157
|
+
for (const [id, pending] of _classPrivateFieldGet2(_pending, this).entries()) {
|
|
158
|
+
clearTimeout(pending.timeoutId);
|
|
159
|
+
_classPrivateFieldGet2(_pending, this).delete(id);
|
|
160
|
+
pending.reject(error);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function _handleMessage(event) {
|
|
164
|
+
if (typeof event.data !== "string") return;
|
|
165
|
+
let payload;
|
|
166
|
+
try {
|
|
167
|
+
payload = JSON.parse(event.data);
|
|
168
|
+
} catch {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
_assertClassBrand(_CdpConnection_brand, this, _recordDebug).call(this, "receive", {
|
|
172
|
+
id: payload.id,
|
|
173
|
+
method: payload.method,
|
|
174
|
+
sessionId: payload.sessionId,
|
|
175
|
+
hasError: !!payload.error
|
|
176
|
+
});
|
|
177
|
+
if (typeof payload.id !== "number") return;
|
|
178
|
+
const pending = _classPrivateFieldGet2(_pending, this).get(payload.id);
|
|
179
|
+
if (!pending) return;
|
|
180
|
+
clearTimeout(pending.timeoutId);
|
|
181
|
+
_classPrivateFieldGet2(_pending, this).delete(payload.id);
|
|
182
|
+
if (payload.error) {
|
|
183
|
+
const err = payload.error;
|
|
184
|
+
pending.reject(new CdpProtocolError(pending.method, typeof err.code === "number" ? err.code : void 0, err.message ?? "CDP error"));
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
pending.resolve(payload.result);
|
|
188
|
+
}
|
|
189
|
+
function _recordDebug(type, data) {
|
|
190
|
+
_classPrivateFieldGet2(_debugLog, this).push({
|
|
191
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
192
|
+
type,
|
|
193
|
+
...data
|
|
194
|
+
});
|
|
195
|
+
if (_classPrivateFieldGet2(_debugLog, this).length > MAX_DEBUG_ENTRIES) _classPrivateFieldGet2(_debugLog, this).splice(0, _classPrivateFieldGet2(_debugLog, this).length - MAX_DEBUG_ENTRIES);
|
|
196
|
+
}
|
|
197
|
+
const LOCALHOST_HOSTS = /* @__PURE__ */ new Set([
|
|
198
|
+
"localhost",
|
|
199
|
+
"127.0.0.1",
|
|
200
|
+
"0.0.0.0",
|
|
201
|
+
"::1",
|
|
202
|
+
"[::1]"
|
|
203
|
+
]);
|
|
204
|
+
/**
|
|
205
|
+
* Connect to a browser via a CDP base URL (e.g. http://localhost:9222).
|
|
206
|
+
* Discovers the WebSocket debugger URL via /json/version,
|
|
207
|
+
* rewrites localhost URLs to the base URL host, and opens the WebSocket.
|
|
208
|
+
*
|
|
209
|
+
* Useful for local development with `chrome --remote-debugging-port=9222`
|
|
210
|
+
* or when connecting through a tunnel.
|
|
211
|
+
*/
|
|
212
|
+
async function connectUrl(baseUrl, options) {
|
|
213
|
+
const endpoint = new URL("/json/version", baseUrl).toString();
|
|
214
|
+
const response = await fetch(endpoint, { headers: options?.headers });
|
|
215
|
+
if (!response.ok) throw new Error(`Failed to discover CDP endpoint at ${endpoint}: ${response.status}`);
|
|
216
|
+
const payload = await response.json();
|
|
217
|
+
if (!payload.webSocketDebuggerUrl) throw new Error("CDP /json/version did not include webSocketDebuggerUrl");
|
|
218
|
+
let wsUrl = payload.webSocketDebuggerUrl;
|
|
219
|
+
const parsed = new URL(wsUrl);
|
|
220
|
+
if (LOCALHOST_HOSTS.has(parsed.hostname)) {
|
|
221
|
+
const base = new URL(baseUrl);
|
|
222
|
+
parsed.hostname = base.hostname;
|
|
223
|
+
parsed.port = base.port;
|
|
224
|
+
parsed.protocol = base.protocol;
|
|
225
|
+
} else parsed.protocol = parsed.protocol === "wss:" ? "https:" : "http:";
|
|
226
|
+
const fetchUrl = parsed.toString();
|
|
227
|
+
const wsResponse = await fetch(fetchUrl, { headers: {
|
|
228
|
+
...options?.headers,
|
|
229
|
+
Upgrade: "websocket"
|
|
230
|
+
} });
|
|
231
|
+
const ws = wsResponse.webSocket;
|
|
232
|
+
if (!ws) throw new Error(`Failed to establish CDP WebSocket at ${fetchUrl} (status ${wsResponse.status})`);
|
|
233
|
+
ws.accept();
|
|
234
|
+
return new CdpConnection(ws, { timeoutMs: options?.timeoutMs });
|
|
235
|
+
}
|
|
236
|
+
/** @deprecated Renamed to {@link CdpConnection}. */
|
|
237
|
+
const CdpSession = CdpConnection;
|
|
238
|
+
//#endregion
|
|
239
|
+
//#region src/browser/browser-run.ts
|
|
240
|
+
var BrowserRenderingError = class extends Error {
|
|
241
|
+
constructor(message, status) {
|
|
242
|
+
super(message);
|
|
243
|
+
this.status = status;
|
|
244
|
+
this.name = "BrowserRenderingError";
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
/**
|
|
248
|
+
* Whether an error means the platform session is gone: Browser Run uses 404
|
|
249
|
+
* for unknown ids and 410 after `keep_alive` expiry.
|
|
250
|
+
*/
|
|
251
|
+
function isMissingBrowserSession(error) {
|
|
252
|
+
return error instanceof BrowserRenderingError && (error.status === 404 || error.status === 410);
|
|
253
|
+
}
|
|
254
|
+
function browserSessionEndpoint(sessionId, options) {
|
|
255
|
+
const path = sessionId ? `/v1/devtools/browser/${sessionId}` : "/v1/devtools/browser";
|
|
256
|
+
const url = new URL(`https://localhost${path}`);
|
|
257
|
+
if (options?.keepAliveMs !== void 0) url.searchParams.set("keep_alive", String(options.keepAliveMs));
|
|
258
|
+
if (options?.includeTargets) url.searchParams.set("targets", "true");
|
|
259
|
+
if (options?.recording) url.searchParams.set("recording", "true");
|
|
260
|
+
if (options?.browser) url.searchParams.set("browser", options.browser);
|
|
261
|
+
return url.toString();
|
|
262
|
+
}
|
|
263
|
+
async function parseBrowserSessionInfo(response) {
|
|
264
|
+
const payload = await response.json();
|
|
265
|
+
const sessionId = typeof payload.sessionId === "string" ? payload.sessionId : "";
|
|
266
|
+
if (!sessionId) throw new Error("Browser Rendering response did not include a sessionId");
|
|
267
|
+
return {
|
|
268
|
+
sessionId,
|
|
269
|
+
targets: Array.isArray(payload.targets) ? payload.targets : void 0,
|
|
270
|
+
webSocketDebuggerUrl: typeof payload.webSocketDebuggerUrl === "string" ? payload.webSocketDebuggerUrl : void 0
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
async function createBrowserSession(browser, options) {
|
|
274
|
+
const response = await browser.fetch(browserSessionEndpoint(void 0, options), {
|
|
275
|
+
method: "POST",
|
|
276
|
+
headers: { "Content-Type": "application/json" },
|
|
277
|
+
body: JSON.stringify(options?.guardrails ? { guardrails: options.guardrails } : {})
|
|
278
|
+
});
|
|
279
|
+
if (!response.ok) throw new BrowserRenderingError(`Failed to create Browser Rendering session: ${response.status}`, response.status);
|
|
280
|
+
return parseBrowserSessionInfo(response);
|
|
281
|
+
}
|
|
282
|
+
async function listBrowserTargets(browser, sessionId) {
|
|
283
|
+
const response = await browser.fetch(`https://localhost/v1/devtools/browser/${sessionId}/json/list`);
|
|
284
|
+
if (!response.ok) throw new BrowserRenderingError(`Failed to list Browser Rendering targets for ${sessionId}: ${response.status}`, response.status);
|
|
285
|
+
const payload = await response.json();
|
|
286
|
+
return Array.isArray(payload) ? payload : [];
|
|
287
|
+
}
|
|
288
|
+
async function deleteBrowserSession(browser, sessionId) {
|
|
289
|
+
const response = await browser.fetch(`https://localhost/v1/devtools/browser/${sessionId}`, { method: "DELETE" });
|
|
290
|
+
if (!response.ok && response.status !== 404) throw new BrowserRenderingError(`Failed to delete Browser Rendering session ${sessionId}: ${response.status}`, response.status);
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Connect to a Browser Rendering session and delete it when closed.
|
|
294
|
+
*/
|
|
295
|
+
async function connectBrowser(browser, options) {
|
|
296
|
+
const normalizedOptions = typeof options === "number" ? { timeoutMs: options } : options ?? {};
|
|
297
|
+
if (normalizedOptions.browser === "kitesurf") {
|
|
298
|
+
const smuggled = normalizedOptions;
|
|
299
|
+
if (smuggled.keepAliveMs || smuggled.includeTargets || smuggled.recording) throw new Error("Kitesurf does not support keepAliveMs, includeTargets, or recording");
|
|
300
|
+
}
|
|
301
|
+
const response = await browser.fetch(browserSessionEndpoint(void 0, normalizedOptions.browser === "kitesurf" ? { browser: "kitesurf" } : {
|
|
302
|
+
keepAliveMs: normalizedOptions.keepAliveMs,
|
|
303
|
+
includeTargets: normalizedOptions.includeTargets,
|
|
304
|
+
recording: normalizedOptions.recording
|
|
305
|
+
}), { headers: { Upgrade: "websocket" } });
|
|
306
|
+
const ws = response.webSocket;
|
|
307
|
+
if (!ws) throw new Error("Browser Rendering binding did not return a WebSocket. Ensure the 'browser' binding is configured in wrangler.jsonc.");
|
|
308
|
+
if (normalizedOptions.browser === "kitesurf") {
|
|
309
|
+
ws.accept();
|
|
310
|
+
return new CdpConnection(ws, { timeoutMs: normalizedOptions.timeoutMs });
|
|
311
|
+
}
|
|
312
|
+
const sessionId = response.headers.get("cf-browser-session-id");
|
|
313
|
+
if (!sessionId) throw new Error("Browser Rendering binding did not include a session ID when opening the CDP WebSocket");
|
|
314
|
+
ws.accept();
|
|
315
|
+
return new CdpConnection(ws, {
|
|
316
|
+
timeoutMs: normalizedOptions.timeoutMs,
|
|
317
|
+
onClose: () => {
|
|
318
|
+
deleteBrowserSession(browser, sessionId).catch((error) => {
|
|
319
|
+
console.warn(`[agents/browser] Failed to delete one-shot Browser Run session ${sessionId}`, error);
|
|
320
|
+
});
|
|
321
|
+
},
|
|
322
|
+
sessionId
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Fetch a Browser Run [session recording](https://developers.cloudflare.com/browser-run/features/session-recording/)
|
|
327
|
+
* by session id, via the Browser Rendering REST API.
|
|
328
|
+
*
|
|
329
|
+
* A recording is only available **after** the session closes (explicit
|
|
330
|
+
* `closeSession()`, idle `keep_alive` expiry, or sweep) and is retained for 30
|
|
331
|
+
* days. Capture the session id while the session is alive — e.g. from
|
|
332
|
+
* `connector.liveView()`/`sessionInfo()` — then call this once it has ended.
|
|
333
|
+
*
|
|
334
|
+
* Unlike the binding-based helpers, this hits `api.cloudflare.com` directly, so
|
|
335
|
+
* it needs an account id and an API token with `Browser Rendering` read access
|
|
336
|
+
* (the Workers Browser Run binding cannot read recordings).
|
|
337
|
+
*/
|
|
338
|
+
async function getBrowserRecording(options) {
|
|
339
|
+
const { accountId, apiToken, sessionId } = options;
|
|
340
|
+
const response = await (options.fetchImpl ?? fetch)(`https://api.cloudflare.com/client/v4/accounts/${accountId}/browser-rendering/recording/${sessionId}`, { headers: { Authorization: `Bearer ${apiToken}` } });
|
|
341
|
+
if (!response.ok) throw new BrowserRenderingError(`Failed to fetch Browser Run recording for ${sessionId}: ${response.status}`, response.status);
|
|
342
|
+
const payload = await response.json();
|
|
343
|
+
return "result" in payload && payload.result ? payload.result : payload;
|
|
344
|
+
}
|
|
345
|
+
async function connectBrowserSession(browser, sessionId, options) {
|
|
346
|
+
const normalized = typeof options === "number" ? { timeoutMs: options } : options ?? {};
|
|
347
|
+
const response = await browser.fetch(browserSessionEndpoint(sessionId), { headers: { Upgrade: "websocket" } });
|
|
348
|
+
const ws = response.webSocket;
|
|
349
|
+
if (!ws) throw new BrowserRenderingError(`Browser Rendering binding did not return a WebSocket for session ${sessionId} (${response.status})`, response.status);
|
|
350
|
+
ws.accept();
|
|
351
|
+
return new CdpConnection(ws, {
|
|
352
|
+
timeoutMs: normalized.timeoutMs,
|
|
353
|
+
onClose: normalized.onClose,
|
|
354
|
+
sessionId,
|
|
355
|
+
onActivity: normalized.onActivity
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
//#endregion
|
|
359
|
+
//#region src/browser/connector-validation.ts
|
|
360
|
+
function formatToolValidationError(connector, tool, errors) {
|
|
361
|
+
const specific = errors.filter((error) => error.keyword !== "properties");
|
|
362
|
+
return `Invalid arguments for ${connector}.${tool}${(specific.length > 0 ? specific : errors).map((error) => {
|
|
363
|
+
const location = error.instanceLocation.replace(/^#\/?/, "").replaceAll("~1", "/").replaceAll("~0", "~").replaceAll("/", ".");
|
|
364
|
+
return `${location ? ` at ${location}` : ""}: ${error.error}`;
|
|
365
|
+
}).join(";")}`;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Validate a connector tool's arguments against its input schema before it
|
|
369
|
+
* runs, so the model gets a precise error instead of a failure deep inside
|
|
370
|
+
* browser work. An omitted argument counts as `{}`: argumentless tools are
|
|
371
|
+
* documented as `cdp.spec()`.
|
|
372
|
+
*/
|
|
373
|
+
function validateConnectorArgs(connector, name, tool) {
|
|
374
|
+
if (!tool.inputSchema) return tool;
|
|
375
|
+
const schema = tool.inputSchema;
|
|
376
|
+
const validator = new Validator(schema, "7", false);
|
|
377
|
+
return {
|
|
378
|
+
...tool,
|
|
379
|
+
execute: async (args, ctx) => {
|
|
380
|
+
const input = args === void 0 ? {} : args;
|
|
381
|
+
const result = validator.validate(input);
|
|
382
|
+
if (!result.valid) throw new Error(formatToolValidationError(connector, name, result.errors));
|
|
383
|
+
return await tool.execute(input, ctx);
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
//#endregion
|
|
388
|
+
//#region src/browser/live-view.ts
|
|
389
|
+
/**
|
|
390
|
+
* Browser Run mints `devtoolsFrontendUrl`s (the Live View links) that are
|
|
391
|
+
* valid for ~5 minutes. We surface the window so callers can decide how long
|
|
392
|
+
* a shared link is good for before re-listing targets.
|
|
393
|
+
*/
|
|
394
|
+
const LIVE_VIEW_URL_TTL_MS = 300 * 1e3;
|
|
395
|
+
/**
|
|
396
|
+
* Rewrite the hosted Live View UI's `mode` query param (`tab` | `devtools`).
|
|
397
|
+
* The raw `devtoolsFrontendUrl` is returned unchanged when no mode is asked
|
|
398
|
+
* for or the URL can't be parsed.
|
|
399
|
+
*/
|
|
400
|
+
function applyLiveViewMode(rawUrl, mode) {
|
|
401
|
+
if (!mode) return rawUrl;
|
|
402
|
+
try {
|
|
403
|
+
const url = new URL(rawUrl);
|
|
404
|
+
url.searchParams.set("mode", mode === "devtools" ? "devtools" : "tab");
|
|
405
|
+
return url.toString();
|
|
406
|
+
} catch {
|
|
407
|
+
return rawUrl;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Project a fresh target listing into Live View links — one per tab that has
|
|
412
|
+
* a `devtoolsFrontendUrl`. Pure; the caller supplies just-listed targets.
|
|
413
|
+
*/
|
|
414
|
+
function createLiveView(sessionId, targets, mode) {
|
|
415
|
+
return {
|
|
416
|
+
sessionId,
|
|
417
|
+
targets: targets.filter((target) => target.devtoolsFrontendUrl).map((target) => ({
|
|
418
|
+
targetId: target.id,
|
|
419
|
+
url: applyLiveViewMode(target.devtoolsFrontendUrl, mode),
|
|
420
|
+
pageUrl: target.url,
|
|
421
|
+
title: target.title,
|
|
422
|
+
type: target.type
|
|
423
|
+
})),
|
|
424
|
+
expiresInMs: LIVE_VIEW_URL_TTL_MS
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
//#endregion
|
|
428
|
+
//#region src/browser/spec.ts
|
|
429
|
+
const MISSING_BROWSER_CONFIG = "Either 'browser' (Fetcher binding) or 'cdpUrl' must be provided";
|
|
430
|
+
const urlSpecCache = /* @__PURE__ */ new Map();
|
|
431
|
+
const bindingSpecCache = /* @__PURE__ */ new WeakMap();
|
|
432
|
+
const CACHE_TTL_MS = 300 * 1e3;
|
|
433
|
+
/** Qualify a same-domain `$ref` (`"FrameId"` → `"Page.FrameId"`). */
|
|
434
|
+
function qualifyRef(domain, ref) {
|
|
435
|
+
if (ref === void 0) return void 0;
|
|
436
|
+
return ref.includes(".") ? ref : `${domain}.${ref}`;
|
|
437
|
+
}
|
|
438
|
+
function normalizeItems(domain, items) {
|
|
439
|
+
if (!items) return void 0;
|
|
440
|
+
return {
|
|
441
|
+
type: items.type,
|
|
442
|
+
$ref: qualifyRef(domain, items.$ref),
|
|
443
|
+
enum: items.enum
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
function normalizeFields(domain, fields) {
|
|
447
|
+
return (fields ?? []).map((field) => ({
|
|
448
|
+
name: field.name,
|
|
449
|
+
description: field.description,
|
|
450
|
+
optional: field.optional,
|
|
451
|
+
experimental: field.experimental,
|
|
452
|
+
deprecated: field.deprecated,
|
|
453
|
+
type: field.type,
|
|
454
|
+
$ref: qualifyRef(domain, field.$ref),
|
|
455
|
+
enum: field.enum,
|
|
456
|
+
items: normalizeItems(domain, field.items)
|
|
457
|
+
}));
|
|
458
|
+
}
|
|
459
|
+
function normalizeCdpSpec(spec) {
|
|
460
|
+
return { domains: (spec.domains ?? []).map(({ domain, ...raw }) => ({
|
|
461
|
+
name: domain,
|
|
462
|
+
description: raw.description,
|
|
463
|
+
experimental: raw.experimental,
|
|
464
|
+
deprecated: raw.deprecated,
|
|
465
|
+
commands: (raw.commands ?? []).map((command) => ({
|
|
466
|
+
name: command.name,
|
|
467
|
+
method: `${domain}.${command.name}`,
|
|
468
|
+
description: command.description,
|
|
469
|
+
experimental: command.experimental,
|
|
470
|
+
deprecated: command.deprecated,
|
|
471
|
+
parameters: normalizeFields(domain, command.parameters),
|
|
472
|
+
returns: normalizeFields(domain, command.returns)
|
|
473
|
+
})),
|
|
474
|
+
events: (raw.events ?? []).map((event) => ({
|
|
475
|
+
name: event.name,
|
|
476
|
+
event: `${domain}.${event.name}`,
|
|
477
|
+
description: event.description,
|
|
478
|
+
experimental: event.experimental,
|
|
479
|
+
deprecated: event.deprecated,
|
|
480
|
+
parameters: normalizeFields(domain, event.parameters)
|
|
481
|
+
})),
|
|
482
|
+
types: (raw.types ?? []).map((type) => ({
|
|
483
|
+
id: type.id,
|
|
484
|
+
name: `${domain}.${type.id}`,
|
|
485
|
+
description: type.description,
|
|
486
|
+
experimental: type.experimental,
|
|
487
|
+
deprecated: type.deprecated,
|
|
488
|
+
type: type.type,
|
|
489
|
+
enum: type.enum,
|
|
490
|
+
properties: normalizeFields(domain, type.properties),
|
|
491
|
+
items: normalizeItems(domain, type.items)
|
|
492
|
+
}))
|
|
493
|
+
})) };
|
|
494
|
+
}
|
|
495
|
+
function getSpecCacheKey(source, headers) {
|
|
496
|
+
const headerEntries = Object.entries(headers ?? {}).sort(([a], [b]) => a.localeCompare(b));
|
|
497
|
+
return `${source}:${JSON.stringify(headerEntries)}`;
|
|
498
|
+
}
|
|
499
|
+
async function getCachedSpec(cache, key, load) {
|
|
500
|
+
const cached = cache.get(key);
|
|
501
|
+
if (cached && Date.now() - cached.cachedAt < CACHE_TTL_MS) return cached.spec;
|
|
502
|
+
const spec = normalizeCdpSpec(await load());
|
|
503
|
+
cache.set(key, {
|
|
504
|
+
spec,
|
|
505
|
+
cachedAt: Date.now()
|
|
506
|
+
});
|
|
507
|
+
return spec;
|
|
508
|
+
}
|
|
509
|
+
async function fetchCdpSpecFromUrl(cdpBaseUrl, headers) {
|
|
510
|
+
const endpoint = new URL("/json/protocol", cdpBaseUrl).toString();
|
|
511
|
+
return getCachedSpec(urlSpecCache, getSpecCacheKey(endpoint, headers), async () => {
|
|
512
|
+
const response = await fetch(endpoint, { headers });
|
|
513
|
+
if (!response.ok) throw new Error(`Failed to fetch CDP spec from ${endpoint}: ${response.status}`);
|
|
514
|
+
return await response.json();
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
async function fetchCdpSpecFromSession(browser, sessionId) {
|
|
518
|
+
return getCachedSpec(bindingSpecCache, browser, async () => {
|
|
519
|
+
const response = await browser.fetch(`https://localhost/v1/devtools/browser/${sessionId}/json/protocol`);
|
|
520
|
+
if (!response.ok) throw new Error(`Failed to fetch CDP spec from Browser Rendering: ${response.status}`);
|
|
521
|
+
return await response.json();
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
async function fetchCdpSpecFromBrowser(browser) {
|
|
525
|
+
return getCachedSpec(bindingSpecCache, browser, async () => {
|
|
526
|
+
const createResponse = await browser.fetch("https://localhost/v1/devtools/browser", { method: "POST" });
|
|
527
|
+
if (!createResponse.ok) throw new Error(`Failed to create Browser Rendering session for protocol fetch: ${createResponse.status}`);
|
|
528
|
+
const sessionId = (await createResponse.json()).sessionId;
|
|
529
|
+
if (!sessionId) throw new Error("Browser Rendering session response did not include a sessionId");
|
|
530
|
+
try {
|
|
531
|
+
const response = await browser.fetch(`https://localhost/v1/devtools/browser/${sessionId}/json/protocol`);
|
|
532
|
+
if (!response.ok) throw new Error(`Failed to fetch CDP spec from Browser Rendering: ${response.status}`);
|
|
533
|
+
return await response.json();
|
|
534
|
+
} finally {
|
|
535
|
+
try {
|
|
536
|
+
await browser.fetch(`https://localhost/v1/devtools/browser/${sessionId}`, { method: "DELETE" });
|
|
537
|
+
} catch {}
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
/** Load the (cached) searchable CDP spec for a browser source. */
|
|
542
|
+
async function loadCdpSpec(source) {
|
|
543
|
+
if (source.cdpUrl) return fetchCdpSpecFromUrl(source.cdpUrl, source.cdpHeaders);
|
|
544
|
+
if (source.browser && source.sessionId) return fetchCdpSpecFromSession(source.browser, source.sessionId);
|
|
545
|
+
if (source.browser) return fetchCdpSpecFromBrowser(source.browser);
|
|
546
|
+
throw new Error(MISSING_BROWSER_CONFIG);
|
|
547
|
+
}
|
|
548
|
+
//#endregion
|
|
549
|
+
//#region src/browser/session-store.ts
|
|
550
|
+
var _DurableBrowserSessionStore_brand = /* @__PURE__ */ new WeakSet();
|
|
551
|
+
var DurableBrowserSessionStore = class {
|
|
552
|
+
constructor(storage) {
|
|
553
|
+
this.storage = storage;
|
|
554
|
+
_classPrivateMethodInitSpec(this, _DurableBrowserSessionStore_brand);
|
|
555
|
+
}
|
|
556
|
+
async acquireLock(key) {
|
|
557
|
+
let queues = _queues._.get(this.storage);
|
|
558
|
+
if (!queues) {
|
|
559
|
+
queues = /* @__PURE__ */ new Map();
|
|
560
|
+
_queues._.set(this.storage, queues);
|
|
561
|
+
}
|
|
562
|
+
const previous = queues.get(key) ?? Promise.resolve();
|
|
563
|
+
let releaseQueue = () => void 0;
|
|
564
|
+
const current = previous.then(() => new Promise((resolve) => {
|
|
565
|
+
releaseQueue = resolve;
|
|
566
|
+
}));
|
|
567
|
+
queues.set(key, current);
|
|
568
|
+
await previous;
|
|
569
|
+
let released = false;
|
|
570
|
+
return { release: () => {
|
|
571
|
+
if (released) return;
|
|
572
|
+
released = true;
|
|
573
|
+
if (queues.get(key) === current) queues.delete(key);
|
|
574
|
+
releaseQueue();
|
|
575
|
+
} };
|
|
576
|
+
}
|
|
577
|
+
async get(key) {
|
|
578
|
+
return this.storage.get(_assertClassBrand(_DurableBrowserSessionStore_brand, this, _storageKey).call(this, key));
|
|
579
|
+
}
|
|
580
|
+
async set(key, session) {
|
|
581
|
+
await this.storage.put(_assertClassBrand(_DurableBrowserSessionStore_brand, this, _storageKey).call(this, key), session);
|
|
582
|
+
}
|
|
583
|
+
async delete(key) {
|
|
584
|
+
await this.storage.delete(_assertClassBrand(_DurableBrowserSessionStore_brand, this, _storageKey).call(this, key));
|
|
585
|
+
}
|
|
586
|
+
async list(prefix) {
|
|
587
|
+
const storagePrefix = _assertClassBrand(_DurableBrowserSessionStore_brand, this, _storageKey).call(this, prefix);
|
|
588
|
+
const entries = await this.storage.list({ prefix: storagePrefix });
|
|
589
|
+
const result = /* @__PURE__ */ new Map();
|
|
590
|
+
for (const [storageKey, value] of entries) result.set(storageKey.slice(16), value);
|
|
591
|
+
return result;
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
function _storageKey(key) {
|
|
595
|
+
return `browser-session:${key}`;
|
|
596
|
+
}
|
|
597
|
+
var _queues = { _: /* @__PURE__ */ new WeakMap() };
|
|
598
|
+
/**
|
|
599
|
+
* Default idle window used by {@link BrowserConnector.sweep} for the shared
|
|
600
|
+
* (reuse/promoted) session entry.
|
|
601
|
+
*/
|
|
602
|
+
const DEFAULT_SWEEP_IDLE_MS = 600 * 1e3;
|
|
603
|
+
//#endregion
|
|
604
|
+
export { CdpConnection as _, applyLiveViewMode as a, connectUrl as b, BrowserRenderingError as c, createBrowserSession as d, deleteBrowserSession as f, CDP_METHOD_NOT_FOUND as g, listBrowserTargets as h, LIVE_VIEW_URL_TTL_MS as i, connectBrowser as l, isMissingBrowserSession as m, DurableBrowserSessionStore as n, createLiveView as o, getBrowserRecording as p, loadCdpSpec as r, validateConnectorArgs as s, DEFAULT_SWEEP_IDLE_MS as t, connectBrowserSession as u, CdpProtocolError as v, CdpSession as y };
|
|
605
|
+
|
|
606
|
+
//# sourceMappingURL=session-store-Do4xkDcf.js.map
|