@felan-ai/ext-browser 0.3.0 → 0.4.0
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/NOTICE +4 -4
- package/README.md +22 -7
- package/dist/attachment.d.ts +49 -0
- package/dist/attachment.d.ts.map +1 -0
- package/dist/attachment.js +417 -0
- package/dist/attachment.js.map +1 -0
- package/dist/authorization.d.ts +29 -0
- package/dist/authorization.d.ts.map +1 -0
- package/dist/authorization.js +2 -0
- package/dist/authorization.js.map +1 -0
- package/dist/cli.d.ts +5 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +85 -101
- package/dist/cli.js.map +1 -1
- package/dist/command-policy.d.ts +8 -0
- package/dist/command-policy.d.ts.map +1 -0
- package/dist/command-policy.js +338 -0
- package/dist/command-policy.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +226 -115
- package/dist/index.js.map +1 -1
- package/dist/installer.d.ts +8 -8
- package/dist/installer.js +9 -9
- package/package.json +2 -2
package/NOTICE
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
@felan-ai/ext-browser
|
|
2
2
|
Copyright (c) 2026 Felan contributors
|
|
3
3
|
|
|
4
|
-
This package integrates with, but does not include, agent-browser 0.
|
|
4
|
+
This package integrates with, but does not include, agent-browser 0.37.1 from
|
|
5
5
|
https://github.com/vercel-labs/agent-browser, distributed under the Apache License 2.0.
|
|
6
|
-
The reviewed upstream release is v0.
|
|
7
|
-
|
|
6
|
+
The reviewed upstream release is v0.37.1 at tag commit
|
|
7
|
+
72007a6788d863611b23bed0b59d0d659c638d8e and its npm archive is identified by
|
|
8
8
|
SHA-512 integrity
|
|
9
|
-
|
|
9
|
+
NDojTSXrIq7zS090T0VwI1uzBryZWvewgxXvS0swj8/5GGnziBZLmyhEkfETO8n4n3DsJpZbZkq9F/MV2rIQKw==.
|
|
10
10
|
|
|
11
11
|
The optional managed installer downloads agent-browser only after explicit
|
|
12
12
|
host-owned confirmation. It verifies the immutable npm archive and selected
|
package/README.md
CHANGED
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
# @felan-ai/ext-browser
|
|
2
2
|
|
|
3
|
-
Portable Felan browser automation backed by the reviewed `agent-browser 0.
|
|
3
|
+
Portable Felan browser automation backed by the reviewed `agent-browser 0.37.1`
|
|
4
4
|
CLI. The package does not vendor the upstream Rust daemon or Chrome. It probes
|
|
5
5
|
the exact reviewed CLI on Felan's `AgentRuntime` and otherwise remains safely
|
|
6
6
|
unavailable.
|
|
7
7
|
|
|
8
8
|
## Tool
|
|
9
9
|
|
|
10
|
-
The extension registers
|
|
10
|
+
The extension registers the ordinary `browser` tool and, when its host supplies
|
|
11
|
+
authorization, a separate `browser_authorize` control-plane tool.
|
|
12
|
+
|
|
13
|
+
`browser_authorize` supports `authorize`, `status`, and `revoke`. Authorization
|
|
14
|
+
is interactive, held only for the current session, and opens a fresh strict
|
|
15
|
+
pinned tab in the existing Chrome session. The host supplies a transient
|
|
16
|
+
validated loopback CDP endpoint; it never returns cookies, profile paths, CDP
|
|
17
|
+
endpoints, or unrelated tab data. Direct `connect`, `--cdp`, and
|
|
18
|
+
`--auto-connect` arguments are rejected by `browser`.
|
|
19
|
+
|
|
20
|
+
The `browser` tool has two operations:
|
|
11
21
|
|
|
12
22
|
- `skill` runs the installed CLI's `skills get <name>` command. Start with
|
|
13
23
|
`core`, use `full: true` for the complete command reference, and request a
|
|
@@ -40,8 +50,13 @@ returns native image content. Text-only models or unreadable/invalid staged
|
|
|
40
50
|
images receive a bounded text fallback instead. Model-selected screenshot
|
|
41
51
|
paths remain text-only and are never opened automatically.
|
|
42
52
|
|
|
43
|
-
The owned browser session is closed during session shutdown.
|
|
44
|
-
|
|
53
|
+
The owned browser session is closed during session shutdown. Revocation and
|
|
54
|
+
shutdown disconnect an attached session without closing the user's Chrome.
|
|
55
|
+
CDP attachment remains browser-level authority; pinned-tab and origin checks
|
|
56
|
+
are defense in depth, not a network sandbox. Felan makes one connection attempt
|
|
57
|
+
per approval and retries setup only after an explicit user action.
|
|
58
|
+
|
|
59
|
+
A managed CLI install sets a one-hour daemon idle timeout; it does not install Chrome. Run
|
|
45
60
|
the explicit `agent-browser install` action when a local Chrome for Testing
|
|
46
61
|
binary is needed.
|
|
47
62
|
|
|
@@ -79,8 +94,8 @@ The extension owns literal-argv validation, session namespacing, bounded output,
|
|
|
79
94
|
version-matched skill retrieval, screenshot validation, and safe text/image
|
|
80
95
|
fallbacks. Hosts own credentials, attachment authorization, dependency
|
|
81
96
|
installation, and browser policy. Page content, CLI output, and bundled skill
|
|
82
|
-
text are untrusted. Existing
|
|
83
|
-
|
|
97
|
+
text are untrusted. Existing-browser attachment requires `browser_authorize`;
|
|
98
|
+
noninteractive hosts fail closed.
|
|
84
99
|
|
|
85
100
|
## Related documentation
|
|
86
101
|
|
|
@@ -90,6 +105,6 @@ explicit authorization unless the current request already grants that action.
|
|
|
90
105
|
|
|
91
106
|
## Attribution
|
|
92
107
|
|
|
93
|
-
The integration is reviewed against `agent-browser` 0.
|
|
108
|
+
The integration is reviewed against `agent-browser` 0.37.1. The package does
|
|
94
109
|
not vendor its daemon or Chrome. See [NOTICE](NOTICE) and [LICENSE](LICENSE) for
|
|
95
110
|
the immutable upstream release, digests, and TypeBox attribution.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AgentRuntime, ExtensionContext } from '@felan-ai/agent-core';
|
|
2
|
+
import type { BrowserAuthorizationHost, BrowserAuthorizationLease } from './authorization.js';
|
|
3
|
+
import type { BrowserCliResult, BrowserSessionScope } from './cli.js';
|
|
4
|
+
import type { AgentBrowserInvocation } from './installer.js';
|
|
5
|
+
type AttachmentState = 'pending' | 'authorized' | 'blocked' | 'revoked';
|
|
6
|
+
export interface BrowserAttachment {
|
|
7
|
+
readonly root: BrowserSessionScope;
|
|
8
|
+
readonly scope: BrowserSessionScope;
|
|
9
|
+
readonly origin: string;
|
|
10
|
+
readonly controller: AbortController;
|
|
11
|
+
readonly rejectedLeases: Set<BrowserAuthorizationLease>;
|
|
12
|
+
state: AttachmentState;
|
|
13
|
+
authorization: Promise<AuthorizationResult>;
|
|
14
|
+
invocation?: AgentBrowserInvocation;
|
|
15
|
+
lease?: BrowserAuthorizationLease;
|
|
16
|
+
endpoint?: string;
|
|
17
|
+
targetId?: string;
|
|
18
|
+
daemonPid?: number;
|
|
19
|
+
attempted: boolean;
|
|
20
|
+
started: boolean;
|
|
21
|
+
verified: boolean;
|
|
22
|
+
nativeOperation?: Promise<BrowserCliResult>;
|
|
23
|
+
cleanup?: Promise<boolean>;
|
|
24
|
+
cleanupVerified: boolean;
|
|
25
|
+
removeLeaseListener?: () => void;
|
|
26
|
+
}
|
|
27
|
+
export interface AuthorizationResult {
|
|
28
|
+
readonly state: 'authorized' | 'cancelled' | 'unavailable' | 'idle' | 'blocked' | 'revoked';
|
|
29
|
+
readonly message?: string;
|
|
30
|
+
readonly reused?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export declare class BrowserAttachments {
|
|
33
|
+
#private;
|
|
34
|
+
readonly runtime: AgentRuntime;
|
|
35
|
+
readonly host: BrowserAuthorizationHost | undefined;
|
|
36
|
+
readonly getInvocation: (signal?: AbortSignal) => Promise<AgentBrowserInvocation>;
|
|
37
|
+
constructor(runtime: AgentRuntime, host: BrowserAuthorizationHost | undefined, getInvocation: (signal?: AbortSignal) => Promise<AgentBrowserInvocation>);
|
|
38
|
+
current(root: BrowserSessionScope): BrowserAttachment | undefined;
|
|
39
|
+
assertActive(attempt: BrowserAttachment): void;
|
|
40
|
+
status(root: BrowserSessionScope): Promise<AuthorizationResult>;
|
|
41
|
+
authorize(root: BrowserSessionScope, origin: string, context: ExtensionContext, signal?: AbortSignal): Promise<AuthorizationResult>;
|
|
42
|
+
verify(attempt: BrowserAttachment, signal?: AbortSignal): Promise<void>;
|
|
43
|
+
invalidate(attempt: BrowserAttachment): Promise<boolean>;
|
|
44
|
+
revoke(root: BrowserSessionScope): Promise<AuthorizationResult>;
|
|
45
|
+
close(): Promise<boolean>;
|
|
46
|
+
}
|
|
47
|
+
export declare function successData(result: BrowserCliResult): Record<string, unknown>;
|
|
48
|
+
export {};
|
|
49
|
+
//# sourceMappingURL=attachment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment.d.ts","sourceRoot":"","sources":["../src/attachment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import { createBrowserAttachmentScope, runBrowserCli } from './cli.js';
|
|
2
|
+
export class BrowserAttachments {
|
|
3
|
+
runtime;
|
|
4
|
+
host;
|
|
5
|
+
getInvocation;
|
|
6
|
+
#attempts = new Map();
|
|
7
|
+
#history = new Set();
|
|
8
|
+
#closed = false;
|
|
9
|
+
constructor(runtime, host, getInvocation) {
|
|
10
|
+
this.runtime = runtime;
|
|
11
|
+
this.host = host;
|
|
12
|
+
this.getInvocation = getInvocation;
|
|
13
|
+
}
|
|
14
|
+
current(root) {
|
|
15
|
+
if (this.#closed)
|
|
16
|
+
throw new Error('Browser session is closed.');
|
|
17
|
+
const attempt = this.#attempts.get(scopeKey(root));
|
|
18
|
+
if (!attempt)
|
|
19
|
+
return undefined;
|
|
20
|
+
this.assertActive(attempt);
|
|
21
|
+
return attempt;
|
|
22
|
+
}
|
|
23
|
+
assertActive(attempt) {
|
|
24
|
+
if (this.#closed || this.#attempts.get(scopeKey(attempt.root)) !== attempt
|
|
25
|
+
|| attempt.state !== 'authorized' || attempt.controller.signal.aborted || attempt.lease?.signal.aborted
|
|
26
|
+
|| this.#uncleanPrevious(attempt.root, attempt)) {
|
|
27
|
+
throw new Error('Existing-browser authorization is inactive or quarantined; authorize again before using browser.');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async status(root) {
|
|
31
|
+
const attempt = this.#attempts.get(scopeKey(root));
|
|
32
|
+
if (!attempt)
|
|
33
|
+
return { state: 'idle' };
|
|
34
|
+
if (this.#uncleanPrevious(root, attempt))
|
|
35
|
+
return { state: 'unavailable', message: 'Previous browser cleanup is unconfirmed.' };
|
|
36
|
+
if (attempt.state === 'authorized') {
|
|
37
|
+
try {
|
|
38
|
+
await this.verify(attempt);
|
|
39
|
+
return { state: 'authorized' };
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return { state: 'blocked', message: 'Existing-browser authorization is no longer active.' };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (attempt.state === 'revoked' && !attempt.cleanupVerified) {
|
|
46
|
+
return { state: 'unavailable', message: 'Browser access is blocked, but cleanup is unconfirmed.' };
|
|
47
|
+
}
|
|
48
|
+
return { state: attempt.state === 'revoked' ? 'revoked' : 'blocked' };
|
|
49
|
+
}
|
|
50
|
+
async authorize(root, origin, context, signal) {
|
|
51
|
+
if (this.#closed || signal?.aborted)
|
|
52
|
+
return { state: 'cancelled' };
|
|
53
|
+
if (!this.host)
|
|
54
|
+
return { state: 'unavailable', message: 'Existing-browser authorization is unavailable in this host.' };
|
|
55
|
+
const key = scopeKey(root);
|
|
56
|
+
const previous = this.#attempts.get(key);
|
|
57
|
+
if (previous?.state === 'pending') {
|
|
58
|
+
if (previous.origin !== origin)
|
|
59
|
+
return { state: 'unavailable', message: 'Another browser authorization request is already in progress.' };
|
|
60
|
+
try {
|
|
61
|
+
return await (signal ? abortable(previous.authorization, signal) : previous.authorization);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return { state: 'cancelled', message: 'This authorization request was cancelled.' };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (previous?.state === 'authorized') {
|
|
68
|
+
if (previous.origin !== origin)
|
|
69
|
+
return { state: 'unavailable', message: 'Revoke the current browser authorization before authorizing a different origin.' };
|
|
70
|
+
try {
|
|
71
|
+
await this.verify(previous, signal);
|
|
72
|
+
return { state: 'authorized', reused: true };
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return { state: 'unavailable', message: 'Existing-browser authorization was lost. Request authorization again.' };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if ((previous && !previous.cleanupVerified) || this.#uncleanPrevious(root, previous)) {
|
|
79
|
+
return { state: 'unavailable', message: 'Previous browser cleanup is unconfirmed. Revoke again before requesting authorization.' };
|
|
80
|
+
}
|
|
81
|
+
const attempt = {
|
|
82
|
+
root: { ...root },
|
|
83
|
+
scope: createBrowserAttachmentScope(this.runtime, context.sessionManager.getSessionId()),
|
|
84
|
+
origin,
|
|
85
|
+
controller: new AbortController(),
|
|
86
|
+
rejectedLeases: new Set(),
|
|
87
|
+
state: 'pending',
|
|
88
|
+
authorization: Promise.resolve({ state: 'unavailable' }),
|
|
89
|
+
attempted: false,
|
|
90
|
+
started: false,
|
|
91
|
+
verified: false,
|
|
92
|
+
cleanupVerified: false,
|
|
93
|
+
};
|
|
94
|
+
this.#attempts.set(key, attempt);
|
|
95
|
+
this.#history.add(attempt);
|
|
96
|
+
attempt.authorization = this.#authorize(attempt, context, signal);
|
|
97
|
+
return attempt.authorization;
|
|
98
|
+
}
|
|
99
|
+
async #authorize(attempt, context, signal) {
|
|
100
|
+
const authorizationSignal = attempt.controller.signal;
|
|
101
|
+
const onAbort = () => attempt.controller.abort();
|
|
102
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
103
|
+
if (signal?.aborted)
|
|
104
|
+
onAbort();
|
|
105
|
+
const timeout = setTimeout(() => attempt.controller.abort(), 120_000);
|
|
106
|
+
try {
|
|
107
|
+
const outcome = await abortable(this.host.authorize({
|
|
108
|
+
origin: attempt.origin,
|
|
109
|
+
signal: authorizationSignal,
|
|
110
|
+
extensionContext: context,
|
|
111
|
+
attach: (connection, lease) => this.#attach(attempt, connection, lease, authorizationSignal),
|
|
112
|
+
}), authorizationSignal);
|
|
113
|
+
if (outcome.status === 'authorized' && attempt.verified && this.#isCurrent(attempt) && !authorizationSignal.aborted) {
|
|
114
|
+
await this.#observe(attempt, authorizationSignal);
|
|
115
|
+
authorizationSignal.throwIfAborted();
|
|
116
|
+
if (!this.#isCurrent(attempt))
|
|
117
|
+
throw new Error('Authorization request is no longer active.');
|
|
118
|
+
attempt.state = 'authorized';
|
|
119
|
+
return { state: 'authorized' };
|
|
120
|
+
}
|
|
121
|
+
await this.invalidate(attempt);
|
|
122
|
+
return outcome.status === 'cancelled'
|
|
123
|
+
? { state: 'cancelled', message: 'Existing-browser authorization was cancelled.' }
|
|
124
|
+
: { state: 'unavailable', message: 'Chrome authorization did not complete a verified attachment.' };
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
const cancelled = signal?.aborted || this.#closed || attempt.state === 'revoked';
|
|
128
|
+
await this.invalidate(attempt);
|
|
129
|
+
return cancelled
|
|
130
|
+
? { state: 'cancelled', message: 'Existing-browser authorization was cancelled.' }
|
|
131
|
+
: { state: 'unavailable', message: 'Chrome authorization could not be completed.' };
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
clearTimeout(timeout);
|
|
135
|
+
signal?.removeEventListener('abort', onAbort);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async #attach(attempt, connection, lease, signal) {
|
|
139
|
+
if (attempt.attempted || !this.#isCurrent(attempt) || signal.aborted) {
|
|
140
|
+
if (lease && lease !== attempt.lease)
|
|
141
|
+
await this.#rejectLease(attempt, lease);
|
|
142
|
+
return { ready: false, reason: 'Chrome attachment is no longer available for this request.' };
|
|
143
|
+
}
|
|
144
|
+
attempt.attempted = true;
|
|
145
|
+
if (!lease || typeof lease.close !== 'function' || !lease.signal || lease.signal.aborted) {
|
|
146
|
+
if (lease)
|
|
147
|
+
await this.#rejectLease(attempt, lease);
|
|
148
|
+
return { ready: false, reason: 'The host must provide a revocable single-connection browser lease.' };
|
|
149
|
+
}
|
|
150
|
+
attempt.lease = lease;
|
|
151
|
+
const onDisconnect = () => { void this.invalidate(attempt); };
|
|
152
|
+
lease.signal.addEventListener('abort', onDisconnect, { once: true });
|
|
153
|
+
attempt.removeLeaseListener = () => lease.signal.removeEventListener('abort', onDisconnect);
|
|
154
|
+
try {
|
|
155
|
+
attempt.endpoint = validateConnection(connection);
|
|
156
|
+
attempt.invocation = await this.getInvocation(signal);
|
|
157
|
+
signal.throwIfAborted();
|
|
158
|
+
if (!this.#isCurrent(attempt))
|
|
159
|
+
throw new Error('Authorization request is no longer active.');
|
|
160
|
+
attempt.started = true;
|
|
161
|
+
attempt.nativeOperation = runBrowserCli(this.runtime, attempt.invocation, [
|
|
162
|
+
'open', attempt.origin, '--cdp', attempt.endpoint, '--pin-tab', '--no-auto-dialog', '--no-webmcp',
|
|
163
|
+
], attempt.scope, { internalAttachment: true, timeoutMs: 120_000, signal });
|
|
164
|
+
const result = await attempt.nativeOperation;
|
|
165
|
+
successData(result);
|
|
166
|
+
await this.#observe(attempt, signal);
|
|
167
|
+
signal.throwIfAborted();
|
|
168
|
+
if (!this.#isCurrent(attempt))
|
|
169
|
+
throw new Error('Authorization request is no longer active.');
|
|
170
|
+
attempt.verified = true;
|
|
171
|
+
return { ready: true };
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
await this.invalidate(attempt);
|
|
175
|
+
return { ready: false, reason: 'Chrome did not complete the verified existing-browser connection.' };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
async verify(attempt, signal) {
|
|
179
|
+
try {
|
|
180
|
+
this.assertActive(attempt);
|
|
181
|
+
await this.#observe(attempt, signal);
|
|
182
|
+
this.assertActive(attempt);
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
await this.invalidate(attempt);
|
|
186
|
+
throw new Error('Existing-browser authorization was lost or its target changed. No further browser action is permitted.');
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async #observe(attempt, signal) {
|
|
190
|
+
const combined = AbortSignal.any([attempt.controller.signal, ...(signal ? [signal] : [])]);
|
|
191
|
+
const read = async (args) => {
|
|
192
|
+
combined.throwIfAborted();
|
|
193
|
+
if (!attempt.invocation || !this.#isCurrent(attempt))
|
|
194
|
+
throw new Error('Attachment is inactive.');
|
|
195
|
+
await this.host?.checkExecution?.();
|
|
196
|
+
combined.throwIfAborted();
|
|
197
|
+
if (!this.#isCurrent(attempt))
|
|
198
|
+
throw new Error('Attachment is inactive.');
|
|
199
|
+
const result = await runBrowserCli(this.runtime, attempt.invocation, args, attempt.scope, {
|
|
200
|
+
signal: combined, timeoutMs: 15_000, internalAttachment: true,
|
|
201
|
+
...(args[0] === 'session' || attempt.endpoint === undefined ? {} : { attachmentEndpoint: attempt.endpoint }),
|
|
202
|
+
});
|
|
203
|
+
combined.throwIfAborted();
|
|
204
|
+
return successData(result);
|
|
205
|
+
};
|
|
206
|
+
const info = await read(['session', 'info']);
|
|
207
|
+
const runtime = info.runtime;
|
|
208
|
+
if (info.active !== true || !isRecord(runtime) || runtime.browserLaunched !== true
|
|
209
|
+
|| !Number.isSafeInteger(info.pid) || Number(info.pid) <= 0 || runtime.backgroundPid !== info.pid
|
|
210
|
+
|| (info.runtimeError !== undefined && info.runtimeError !== null)
|
|
211
|
+
|| (attempt.daemonPid !== undefined && info.pid !== attempt.daemonPid)) {
|
|
212
|
+
throw new Error('Browser daemon identity changed.');
|
|
213
|
+
}
|
|
214
|
+
const connection = await read(['get', 'cdp-url']);
|
|
215
|
+
if (connection.cdpUrl !== attempt.endpoint)
|
|
216
|
+
throw new Error('Browser connection identity changed.');
|
|
217
|
+
const pages = await read(['tab', 'list']);
|
|
218
|
+
if (!Array.isArray(pages.tabs))
|
|
219
|
+
throw new Error('Browser target observation is invalid.');
|
|
220
|
+
const active = pages.tabs.filter((tab) => isRecord(tab) && tab.active === true);
|
|
221
|
+
const tab = active[0];
|
|
222
|
+
if (active.length !== 1 || !tab || typeof tab.targetId !== 'string' || !tab.targetId
|
|
223
|
+
|| (attempt.targetId !== undefined && tab.targetId !== attempt.targetId)
|
|
224
|
+
|| originOf(tab.url) !== attempt.origin)
|
|
225
|
+
throw new Error('Pinned browser target changed.');
|
|
226
|
+
const location = await read(['get', 'url']);
|
|
227
|
+
if (originOf(location.url) !== attempt.origin)
|
|
228
|
+
throw new Error('Browser left its authorized origin.');
|
|
229
|
+
attempt.daemonPid = Number(info.pid);
|
|
230
|
+
attempt.targetId = tab.targetId;
|
|
231
|
+
}
|
|
232
|
+
async invalidate(attempt) {
|
|
233
|
+
if (attempt.state !== 'revoked')
|
|
234
|
+
attempt.state = 'blocked';
|
|
235
|
+
attempt.controller.abort();
|
|
236
|
+
return this.#cleanup(attempt);
|
|
237
|
+
}
|
|
238
|
+
async revoke(root) {
|
|
239
|
+
const attempts = [...this.#history].filter(attempt => scopeKey(attempt.root) === scopeKey(root));
|
|
240
|
+
if (attempts.length === 0)
|
|
241
|
+
return { state: 'revoked' };
|
|
242
|
+
const outcomes = await Promise.all(attempts.map(async (attempt) => {
|
|
243
|
+
attempt.state = 'revoked';
|
|
244
|
+
attempt.controller.abort();
|
|
245
|
+
return this.#retryCleanup(attempt);
|
|
246
|
+
}));
|
|
247
|
+
return outcomes.every(Boolean)
|
|
248
|
+
? { state: 'revoked', message: 'Existing-browser authorization revoked. Request authorization before using this browser again.' }
|
|
249
|
+
: { state: 'unavailable', message: 'Browser access is blocked, but cleanup is unconfirmed. Retry revoke; do not reconnect.' };
|
|
250
|
+
}
|
|
251
|
+
async #retryCleanup(attempt) {
|
|
252
|
+
if (attempt.cleanup && !attempt.cleanupVerified) {
|
|
253
|
+
const previous = attempt.cleanup;
|
|
254
|
+
await previous;
|
|
255
|
+
if (!attempt.cleanupVerified && attempt.cleanup === previous)
|
|
256
|
+
delete attempt.cleanup;
|
|
257
|
+
}
|
|
258
|
+
return this.#cleanup(attempt);
|
|
259
|
+
}
|
|
260
|
+
async #rejectLease(attempt, lease) {
|
|
261
|
+
attempt.rejectedLeases.add(lease);
|
|
262
|
+
attempt.cleanupVerified = false;
|
|
263
|
+
if (attempt.state !== 'revoked')
|
|
264
|
+
attempt.state = 'blocked';
|
|
265
|
+
attempt.controller.abort();
|
|
266
|
+
await this.#retryCleanup(attempt);
|
|
267
|
+
if (!attempt.cleanupVerified) {
|
|
268
|
+
const current = this.#attempts.get(scopeKey(attempt.root));
|
|
269
|
+
if (current && current !== attempt)
|
|
270
|
+
await this.invalidate(current);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
#cleanup(attempt) {
|
|
274
|
+
if (attempt.cleanup)
|
|
275
|
+
return attempt.cleanup;
|
|
276
|
+
attempt.removeLeaseListener?.();
|
|
277
|
+
attempt.cleanup = (async () => {
|
|
278
|
+
let clean = !attempt.lease || await closeLease(attempt.lease);
|
|
279
|
+
for (const lease of attempt.rejectedLeases) {
|
|
280
|
+
if (await closeLease(lease))
|
|
281
|
+
attempt.rejectedLeases.delete(lease);
|
|
282
|
+
else
|
|
283
|
+
clean = false;
|
|
284
|
+
}
|
|
285
|
+
if (attempt.nativeOperation) {
|
|
286
|
+
try {
|
|
287
|
+
await abortable(attempt.nativeOperation.then(() => { }, () => { }), AbortSignal.timeout(15_000));
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
clean = false;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (attempt.started && attempt.invocation) {
|
|
294
|
+
try {
|
|
295
|
+
await this.host?.checkExecution?.();
|
|
296
|
+
const result = await runBrowserCli(this.runtime, attempt.invocation, ['close'], attempt.scope, {
|
|
297
|
+
timeoutMs: 15_000, internalAttachment: true,
|
|
298
|
+
});
|
|
299
|
+
successData(result);
|
|
300
|
+
const deadline = AbortSignal.timeout(5_000);
|
|
301
|
+
for (;;) {
|
|
302
|
+
deadline.throwIfAborted();
|
|
303
|
+
await this.host?.checkExecution?.();
|
|
304
|
+
const status = successData(await runBrowserCli(this.runtime, attempt.invocation, ['session', 'info'], attempt.scope, {
|
|
305
|
+
timeoutMs: 5_000, internalAttachment: true, signal: deadline,
|
|
306
|
+
}));
|
|
307
|
+
if (status.active === false && status.pid === null && status.runtime === null
|
|
308
|
+
&& (status.runtimeError === undefined || status.runtimeError === null))
|
|
309
|
+
break;
|
|
310
|
+
if (status.active !== true || (status.runtime !== null
|
|
311
|
+
&& (!isRecord(status.runtime) || status.runtime.browserLaunched !== false))) {
|
|
312
|
+
clean = false;
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
// Native close acknowledges before its delayed daemon shutdown notification.
|
|
316
|
+
await abortable(new Promise(resolve => setTimeout(resolve, 50)), deadline);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
clean = false;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
attempt.cleanupVerified = clean && attempt.rejectedLeases.size === 0;
|
|
324
|
+
return attempt.cleanupVerified;
|
|
325
|
+
})();
|
|
326
|
+
return attempt.cleanup;
|
|
327
|
+
}
|
|
328
|
+
async close() {
|
|
329
|
+
this.#closed = true;
|
|
330
|
+
const outcomes = await Promise.all([...this.#history].map(async (attempt) => {
|
|
331
|
+
attempt.state = 'blocked';
|
|
332
|
+
attempt.controller.abort();
|
|
333
|
+
return this.#retryCleanup(attempt);
|
|
334
|
+
}));
|
|
335
|
+
return outcomes.every(Boolean);
|
|
336
|
+
}
|
|
337
|
+
#isCurrent(attempt) {
|
|
338
|
+
return !this.#closed && this.#attempts.get(scopeKey(attempt.root)) === attempt
|
|
339
|
+
&& !attempt.controller.signal.aborted && !attempt.lease?.signal.aborted
|
|
340
|
+
&& !this.#uncleanPrevious(attempt.root, attempt)
|
|
341
|
+
&& (attempt.state === 'pending' || attempt.state === 'authorized');
|
|
342
|
+
}
|
|
343
|
+
#uncleanPrevious(root, current) {
|
|
344
|
+
return [...this.#history].some(attempt => attempt !== current
|
|
345
|
+
&& scopeKey(attempt.root) === scopeKey(root) && !attempt.cleanupVerified);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
function validateConnection(connection) {
|
|
349
|
+
const { port, webSocketPath } = connection ?? {};
|
|
350
|
+
if (!Number.isInteger(port) || port < 1 || port > 65_535 || typeof webSocketPath !== 'string'
|
|
351
|
+
|| webSocketPath.length > 4_096
|
|
352
|
+
|| !/^\/(?:devtools\/browser(?:\/(?!\.{1,2}$)[A-Za-z0-9._-]+)?|felan-browser\/(?!\.{1,2}$)[A-Za-z0-9._-]+)$/u.test(webSocketPath)) {
|
|
353
|
+
throw new Error('Chrome authorization returned an invalid connection.');
|
|
354
|
+
}
|
|
355
|
+
return `ws://127.0.0.1:${port}${webSocketPath}`;
|
|
356
|
+
}
|
|
357
|
+
function scopeKey(scope) {
|
|
358
|
+
return `${scope.namespace}/${scope.session}`;
|
|
359
|
+
}
|
|
360
|
+
function originOf(value) {
|
|
361
|
+
if (typeof value !== 'string')
|
|
362
|
+
return undefined;
|
|
363
|
+
try {
|
|
364
|
+
return new URL(value).origin;
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
return undefined;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function isRecord(value) {
|
|
371
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
372
|
+
}
|
|
373
|
+
export function successData(result) {
|
|
374
|
+
if (result.code !== 0 || result.killed || result.outputTruncated)
|
|
375
|
+
throw new Error('Browser command did not complete.');
|
|
376
|
+
let response;
|
|
377
|
+
try {
|
|
378
|
+
response = JSON.parse(result.stdout);
|
|
379
|
+
}
|
|
380
|
+
catch {
|
|
381
|
+
throw new Error('Browser response was invalid JSON.');
|
|
382
|
+
}
|
|
383
|
+
if (!isRecord(response) || response.success !== true)
|
|
384
|
+
throw new Error('Browser response was not successful.');
|
|
385
|
+
return isRecord(response.data) ? response.data : {};
|
|
386
|
+
}
|
|
387
|
+
async function closeLease(lease) {
|
|
388
|
+
try {
|
|
389
|
+
await abortable(lease.close(), AbortSignal.timeout(5_000));
|
|
390
|
+
return lease.signal.aborted;
|
|
391
|
+
}
|
|
392
|
+
catch {
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
async function abortable(promise, signal) {
|
|
397
|
+
if (signal.aborted) {
|
|
398
|
+
void promise.catch(() => { });
|
|
399
|
+
throw new Error('Browser operation was cancelled.');
|
|
400
|
+
}
|
|
401
|
+
let onAbort;
|
|
402
|
+
try {
|
|
403
|
+
return await Promise.race([
|
|
404
|
+
promise,
|
|
405
|
+
new Promise((_resolve, reject) => {
|
|
406
|
+
onAbort = () => reject(new Error('Browser operation was cancelled.'));
|
|
407
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
408
|
+
if (signal.aborted)
|
|
409
|
+
onAbort();
|
|
410
|
+
}),
|
|
411
|
+
]);
|
|
412
|
+
}
|
|
413
|
+
finally {
|
|
414
|
+
signal.removeEventListener('abort', onAbort);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
//# sourceMappingURL=attachment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attachment.js","sourceRoot":"","sources":["../src/attachment.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,4BAA4B,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAkCvE,MAAM,OAAO,kBAAkB;IAMlB;IACA;IACA;IAPF,SAAS,GAAG,IAAI,GAAG,EAA6B,CAAC;IACjD,QAAQ,GAAG,IAAI,GAAG,EAAqB,CAAC;IACjD,OAAO,GAAG,KAAK,CAAC;IAEhB,YACW,OAAqB,EACrB,IAA0C,EAC1C,aAAwE;QAFxE,YAAO,GAAP,OAAO,CAAc;QACrB,SAAI,GAAJ,IAAI,CAAsC;QAC1C,kBAAa,GAAb,aAAa,CAA2D;IAChF,CAAC;IAEJ,OAAO,CAAC,IAAyB;QAC/B,IAAI,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QACnD,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAC/B,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAC3B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,YAAY,CAAC,OAA0B;QACrC,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,OAAO;eACrE,OAAO,CAAC,KAAK,KAAK,YAAY,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,OAAO;eACpG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CAAC,kGAAkG,CAAC,CAAC;QACtH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAyB;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QACnD,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC;YAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,0CAA0C,EAAE,CAAC;QAC/H,IAAI,OAAO,CAAC,KAAK,KAAK,YAAY,EAAE,CAAC;YACnC,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAC3B,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;YACjC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,qDAAqD,EAAE,CAAC;YAC9F,CAAC;QACH,CAAC;QACD,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;YAC5D,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,wDAAwD,EAAE,CAAC;QACrG,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;IACxE,CAAC;IAED,KAAK,CAAC,SAAS,CACb,IAAyB,EACzB,MAAc,EACd,OAAyB,EACzB,MAAoB;QAEpB,IAAI,IAAI,CAAC,OAAO,IAAI,MAAM,EAAE,OAAO;YAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;QACnE,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,6DAA6D,EAAE,CAAC;QACxH,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC3B,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACzC,IAAI,QAAQ,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;YAClC,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM;gBAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,+DAA+D,EAAE,CAAC;YAC1I,IAAI,CAAC;gBACH,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;YAC7F,CAAC;YAAC,MAAM,CAAC;gBAAC,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,2CAA2C,EAAE,CAAC;YAAC,CAAC;QAClG,CAAC;QACD,IAAI,QAAQ,EAAE,KAAK,KAAK,YAAY,EAAE,CAAC;YACrC,IAAI,QAAQ,CAAC,MAAM,KAAK,MAAM;gBAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,iFAAiF,EAAE,CAAC;YAC5J,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;gBACpC,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YAC/C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,uEAAuE,EAAE,CAAC;YACpH,CAAC;QACH,CAAC;QACD,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;YACrF,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,wFAAwF,EAAE,CAAC;QACrI,CAAC;QAED,MAAM,OAAO,GAAsB;YACjC,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE;YACjB,KAAK,EAAE,4BAA4B,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC,YAAY,EAAE,CAAC;YACxF,MAAM;YACN,UAAU,EAAE,IAAI,eAAe,EAAE;YACjC,cAAc,EAAE,IAAI,GAAG,EAAE;YACzB,KAAK,EAAE,SAAS;YAChB,aAAa,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;YACxD,SAAS,EAAE,KAAK;YAChB,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,KAAK;YACf,eAAe,EAAE,KAAK;SACvB,CAAC;QACF,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACjC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3B,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAClE,OAAO,OAAO,CAAC,aAAa,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,OAA0B,EAAE,OAAyB,EAAE,MAAoB;QAC1F,MAAM,mBAAmB,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC;QACtD,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QACjD,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,IAAI,MAAM,EAAE,OAAO;YAAE,OAAO,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,CAAC;QACtE,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,IAAK,CAAC,SAAS,CAAC;gBACnD,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,MAAM,EAAE,mBAAmB;gBAC3B,gBAAgB,EAAE,OAAO;gBACzB,MAAM,EAAE,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,mBAAmB,CAAC;aAC7F,CAAC,EAAE,mBAAmB,CAAC,CAAC;YACzB,IAAI,OAAO,CAAC,MAAM,KAAK,YAAY,IAAI,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,CAAC;gBACpH,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;gBAClD,mBAAmB,CAAC,cAAc,EAAE,CAAC;gBACrC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;oBAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;gBAC7F,OAAO,CAAC,KAAK,GAAG,YAAY,CAAC;gBAC7B,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;YACjC,CAAC;YACD,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAC/B,OAAO,OAAO,CAAC,MAAM,KAAK,WAAW;gBACnC,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,+CAA+C,EAAE;gBAClF,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,8DAA8D,EAAE,CAAC;QACxG,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,SAAS,GAAG,MAAM,EAAE,OAAO,IAAI,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC;YACjF,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAC/B,OAAO,SAAS;gBACd,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,+CAA+C,EAAE;gBAClF,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,8CAA8C,EAAE,CAAC;QACxF,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CACX,OAA0B,EAC1B,UAA0C,EAC1C,KAA4C,EAC5C,MAAmB;QAEnB,IAAI,OAAO,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACrE,IAAI,KAAK,IAAI,KAAK,KAAK,OAAO,CAAC,KAAK;gBAAE,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC9E,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,4DAA4D,EAAE,CAAC;QAChG,CAAC;QACD,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,UAAU,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACzF,IAAI,KAAK;gBAAE,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACnD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,oEAAoE,EAAE,CAAC;QACxG,CAAC;QACD,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;QACtB,MAAM,YAAY,GAAG,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9D,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACrE,OAAO,CAAC,mBAAmB,GAAG,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QAC5F,IAAI,CAAC;YACH,OAAO,CAAC,QAAQ,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;YAClD,OAAO,CAAC,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;YACtD,MAAM,CAAC,cAAc,EAAE,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAC7F,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;YACvB,OAAO,CAAC,eAAe,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE;gBACxE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,EAAE,WAAW,EAAE,kBAAkB,EAAE,aAAa;aAClG,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAC5E,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,eAAe,CAAC;YAC7C,WAAW,CAAC,MAAM,CAAC,CAAC;YACpB,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACrC,MAAM,CAAC,cAAc,EAAE,CAAC;YACxB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAC7F,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;YACxB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAC/B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,mEAAmE,EAAE,CAAC;QACvG,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAA0B,EAAE,MAAoB;QAC3D,IAAI,CAAC;YACH,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAC3B,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YACrC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,wGAAwG,CAAC,CAAC;QAC5H,CAAC;IACH,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAA0B,EAAE,MAAoB;QAC7D,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3F,MAAM,IAAI,GAAG,KAAK,EAAE,IAAc,EAAE,EAAE;YACpC,QAAQ,CAAC,cAAc,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YACjG,MAAM,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,CAAC;YACpC,QAAQ,CAAC,cAAc,EAAE,CAAC;YAC1B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;YAC1E,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE;gBACxF,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,IAAI;gBAC7D,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;aAC7G,CAAC,CAAC;YACH,QAAQ,CAAC,cAAc,EAAE,CAAC;YAC1B,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC;QAC7B,CAAC,CAAC;QACF,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,eAAe,KAAK,IAAI;eAC7E,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,aAAa,KAAK,IAAI,CAAC,GAAG;eAC9F,CAAC,IAAI,CAAC,YAAY,KAAK,SAAS,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC;eAC/D,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,KAAK,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YACzE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC;QACD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;QAClD,IAAI,UAAU,CAAC,MAAM,KAAK,OAAO,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QACpG,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC1F,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAY,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC;QACzF,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAwC,CAAC;QAC7D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,QAAQ;eAC/E,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,CAAC,QAAQ,CAAC;eACrE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QAC7F,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QAC5C,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACtG,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrC,OAAO,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,OAA0B;QACzC,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC;QAC3D,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAyB;QACpC,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QACjG,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;QACvD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAC,OAAO,EAAC,EAAE;YAC9D,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC;YAC1B,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC,CAAC;QACJ,OAAO,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;YAC5B,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,gGAAgG,EAAE;YACjI,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,wFAAwF,EAAE,CAAC;IAClI,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAA0B;QAC5C,IAAI,OAAO,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;YAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;YACjC,MAAM,QAAQ,CAAC;YACf,IAAI,CAAC,OAAO,CAAC,eAAe,IAAI,OAAO,CAAC,OAAO,KAAK,QAAQ;gBAAE,OAAO,OAAO,CAAC,OAAO,CAAC;QACvF,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAA0B,EAAE,KAAgC;QAC7E,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClC,OAAO,CAAC,eAAe,GAAG,KAAK,CAAC;QAChC,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;YAAE,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC;QAC3D,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QAC3B,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YAC3D,IAAI,OAAO,IAAI,OAAO,KAAK,OAAO;gBAAE,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,OAA0B;QACjC,IAAI,OAAO,CAAC,OAAO;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC;QAC5C,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;QAChC,OAAO,CAAC,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE;YAC5B,IAAI,KAAK,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,MAAM,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC9D,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;gBAC3C,IAAI,MAAM,UAAU,CAAC,KAAK,CAAC;oBAAE,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;;oBAC7D,KAAK,GAAG,KAAK,CAAC;YACrB,CAAC;YACD,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;gBAC5B,IAAI,CAAC;oBACH,MAAM,SAAS,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;gBACjG,CAAC;gBAAC,MAAM,CAAC;oBAAC,KAAK,GAAG,KAAK,CAAC;gBAAC,CAAC;YAC5B,CAAC;YACD,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;gBAC1C,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,CAAC;oBACpC,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,KAAK,EAAE;wBAC7F,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,IAAI;qBAC5C,CAAC,CAAC;oBACH,WAAW,CAAC,MAAM,CAAC,CAAC;oBACpB,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;oBAC5C,SAAS,CAAC;wBACR,QAAQ,CAAC,cAAc,EAAE,CAAC;wBAC1B,MAAM,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,CAAC;wBACpC,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,KAAK,EAAE;4BACnH,SAAS,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ;yBAC7D,CAAC,CAAC,CAAC;wBACJ,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK,IAAI,MAAM,CAAC,GAAG,KAAK,IAAI,IAAI,MAAM,CAAC,OAAO,KAAK,IAAI;+BACxE,CAAC,MAAM,CAAC,YAAY,KAAK,SAAS,IAAI,MAAM,CAAC,YAAY,KAAK,IAAI,CAAC;4BAAE,MAAM;wBAChF,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,KAAK,IAAI;+BACjD,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,eAAe,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;4BAC9E,KAAK,GAAG,KAAK,CAAC;4BACd,MAAM;wBACR,CAAC;wBACD,6EAA6E;wBAC7E,MAAM,SAAS,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;oBAC7E,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBAAC,KAAK,GAAG,KAAK,CAAC;gBAAC,CAAC;YAC5B,CAAC;YACD,OAAO,CAAC,eAAe,GAAG,KAAK,IAAI,OAAO,CAAC,cAAc,CAAC,IAAI,KAAK,CAAC,CAAC;YACrE,OAAO,OAAO,CAAC,eAAe,CAAC;QACjC,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,OAAO,CAAC,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,KAAK,EAAC,OAAO,EAAC,EAAE;YACxE,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC;YAC1B,OAAO,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC,CAAC;QACJ,OAAO,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,UAAU,CAAC,OAA0B;QACnC,OAAO,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,OAAO;eACzE,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,OAAO;eACpE,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;eAC7C,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,KAAK,KAAK,YAAY,CAAC,CAAC;IACvE,CAAC;IAED,gBAAgB,CAAC,IAAyB,EAAE,OAA2B;QACrE,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,KAAK,OAAO;eACxD,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAC9E,CAAC;CACF;AAED,SAAS,kBAAkB,CAAC,UAA0C;IACpE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,GAAG,UAAU,IAAI,EAAE,CAAC;IACjD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,MAAM,IAAI,OAAO,aAAa,KAAK,QAAQ;WACxF,aAAa,CAAC,MAAM,GAAG,KAAK;WAC5B,CAAC,yGAAyG,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;QACpI,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,kBAAkB,IAAI,GAAG,aAAa,EAAE,CAAC;AAClD,CAAC;AAED,SAAS,QAAQ,CAAC,KAA0B;IAC1C,OAAO,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;AAC/C,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAChD,IAAI,CAAC;QAAC,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,SAAS,CAAC;IAAC,CAAC;AACnE,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAwB;IAClD,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,eAAe;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvH,IAAI,QAAiB,CAAC;IACtB,IAAI,CAAC;QAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IAAC,CAAC;IAC9G,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,OAAO,KAAK,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC9G,OAAO,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;AACtD,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,KAAgC;IACxD,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3D,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,KAAK,CAAC;IAAC,CAAC;AAC3B,CAAC;AAED,KAAK,UAAU,SAAS,CAAI,OAAmB,EAAE,MAAmB;IAClE,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,KAAK,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,OAAoB,CAAC;IACzB,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC;YACxB,OAAO;YACP,IAAI,OAAO,CAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE;gBACtC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC,CAAC;gBACtE,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC1D,IAAI,MAAM,CAAC,OAAO;oBAAE,OAAO,EAAE,CAAC;YAChC,CAAC,CAAC;SACH,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ExtensionContext } from '@felan-ai/agent-core';
|
|
2
|
+
export interface BrowserAuthorizationConnection {
|
|
3
|
+
readonly port: number;
|
|
4
|
+
readonly webSocketPath: string;
|
|
5
|
+
}
|
|
6
|
+
export interface BrowserAuthorizationAttachment {
|
|
7
|
+
readonly ready: boolean;
|
|
8
|
+
readonly reason?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface BrowserAuthorizationLease {
|
|
11
|
+
readonly signal: AbortSignal;
|
|
12
|
+
close(): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export interface BrowserAuthorizationRequest {
|
|
15
|
+
readonly origin: string;
|
|
16
|
+
readonly signal: AbortSignal;
|
|
17
|
+
readonly extensionContext: ExtensionContext;
|
|
18
|
+
readonly attach: (connection: BrowserAuthorizationConnection, lease?: BrowserAuthorizationLease) => Promise<BrowserAuthorizationAttachment>;
|
|
19
|
+
}
|
|
20
|
+
export type BrowserAuthorizationOutcome = {
|
|
21
|
+
readonly status: 'authorized' | 'cancelled' | 'unavailable';
|
|
22
|
+
readonly message?: string;
|
|
23
|
+
};
|
|
24
|
+
export interface BrowserAuthorizationHost {
|
|
25
|
+
/** Inherited CLI configuration can select an attached browser even for an isolated command. */
|
|
26
|
+
checkExecution?(): void | Promise<void>;
|
|
27
|
+
authorize(request: BrowserAuthorizationRequest): Promise<BrowserAuthorizationOutcome>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=authorization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorization.d.ts","sourceRoot":"","sources":["../src/authorization.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE,CACf,UAAU,EAAE,8BAA8B,EAC1C,KAAK,CAAC,EAAE,yBAAyB,KAC9B,OAAO,CAAC,8BAA8B,CAAC,CAAC;CAC9C;AAED,MAAM,MAAM,2BAA2B,GACnC;IAAE,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW,GAAG,aAAa,CAAC;IAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/F,MAAM,WAAW,wBAAwB;IACvC,+FAA+F;IAC/F,cAAc,CAAC,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,SAAS,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,CAAC,2BAA2B,CAAC,CAAC;CACvF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorization.js","sourceRoot":"","sources":["../src/authorization.ts"],"names":[],"mappings":""}
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AgentRuntime } from '@felan-ai/agent-core';
|
|
2
2
|
import type { AgentBrowserInvocation } from './installer.js';
|
|
3
|
+
export { findBrowserCommand } from './command-policy.js';
|
|
3
4
|
export declare const MAX_BROWSER_OUTPUT_CHARACTERS = 44000;
|
|
4
5
|
export declare const MAX_BROWSER_SKILL_OUTPUT_CHARACTERS = 100000;
|
|
5
6
|
export declare const DEFAULT_BROWSER_TIMEOUT_MS = 60000;
|
|
@@ -22,13 +23,16 @@ export interface PreparedBrowserCommand {
|
|
|
22
23
|
readonly generatedScreenshotPath?: string;
|
|
23
24
|
}
|
|
24
25
|
export declare function createBrowserSessionScope(runtime: AgentRuntime, sessionId: string): BrowserSessionScope;
|
|
26
|
+
export declare function createBrowserAttachmentScope(runtime: AgentRuntime, sessionId: string): BrowserSessionScope;
|
|
25
27
|
export declare function prepareBrowserCommand(runtime: AgentRuntime, args: readonly string[]): PreparedBrowserCommand;
|
|
26
28
|
export declare function runBrowserCli(runtime: AgentRuntime, invocation: AgentBrowserInvocation, args: readonly string[], scope: BrowserSessionScope, options?: {
|
|
27
29
|
readonly signal?: AbortSignal;
|
|
28
30
|
readonly timeoutMs?: number;
|
|
29
31
|
readonly json?: boolean;
|
|
30
32
|
readonly prepareScreenshot?: boolean;
|
|
33
|
+
readonly attached?: boolean;
|
|
34
|
+
readonly attachmentEndpoint?: string;
|
|
35
|
+
readonly internalAttachment?: boolean;
|
|
31
36
|
}): Promise<BrowserCliResult>;
|
|
32
37
|
export declare function runBrowserSkill(runtime: AgentRuntime, invocation: AgentBrowserInvocation, skill: string, full: boolean, signal?: AbortSignal, timeoutMs?: number): Promise<BrowserCliResult>;
|
|
33
|
-
export declare function findBrowserCommand(args: readonly string[]): string | undefined;
|
|
34
38
|
//# sourceMappingURL=cli.d.ts.map
|