@zixt/host 0.0.156 → 0.0.157
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +327 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ import { homedir as homedir6 } from "node:os";
|
|
|
28
28
|
// package.json
|
|
29
29
|
var package_default = {
|
|
30
30
|
name: "@zixt/host",
|
|
31
|
-
version: "0.0.
|
|
31
|
+
version: "0.0.157",
|
|
32
32
|
type: "module",
|
|
33
33
|
exports: {
|
|
34
34
|
".": "./src/client.ts",
|
|
@@ -14881,6 +14881,23 @@ var BrowserFramePayload = external_exports.object({
|
|
|
14881
14881
|
width: external_exports.number().int().min(1).max(3840),
|
|
14882
14882
|
height: external_exports.number().int().min(1).max(2160)
|
|
14883
14883
|
}).strict();
|
|
14884
|
+
var BrowserCookie = external_exports.object({
|
|
14885
|
+
name: external_exports.string().min(1).max(256),
|
|
14886
|
+
value: external_exports.string().max(8192),
|
|
14887
|
+
domain: external_exports.string().min(1).max(253),
|
|
14888
|
+
path: external_exports.string().min(1).max(2048),
|
|
14889
|
+
expires: external_exports.number().finite().min(-1).max(253402300799),
|
|
14890
|
+
httpOnly: external_exports.boolean(),
|
|
14891
|
+
secure: external_exports.boolean(),
|
|
14892
|
+
sameSite: external_exports.enum(["Strict", "Lax", "None"]),
|
|
14893
|
+
/** Chromium partition key for CHIPS cookies, when present. */
|
|
14894
|
+
partitionKey: external_exports.string().min(1).max(2048).optional()
|
|
14895
|
+
}).strict();
|
|
14896
|
+
var BROWSER_MAX_SYNCED_COOKIES = 512;
|
|
14897
|
+
var BrowserCookieState = external_exports.object({
|
|
14898
|
+
revision: external_exports.number().int().min(0),
|
|
14899
|
+
cookies: external_exports.array(BrowserCookie).max(BROWSER_MAX_SYNCED_COOKIES)
|
|
14900
|
+
}).strict();
|
|
14884
14901
|
var inputCoordinate = external_exports.number().min(0).max(16384);
|
|
14885
14902
|
var BrowserMouseButton = external_exports.enum(["left", "middle", "right"]);
|
|
14886
14903
|
var BrowserInputEvent = external_exports.discriminatedUnion("kind", [
|
|
@@ -14940,7 +14957,7 @@ var BrowserSessionProjection = external_exports.object({
|
|
|
14940
14957
|
canStart: external_exports.boolean(),
|
|
14941
14958
|
/** Member-safe reason when canStart is false. */
|
|
14942
14959
|
reason: external_exports.string().max(300).optional(),
|
|
14943
|
-
/** Present only when active work
|
|
14960
|
+
/** Present only when active work uses a different local profile Machine. */
|
|
14944
14961
|
profileContext: BrowserProfileContext.optional()
|
|
14945
14962
|
}).strict();
|
|
14946
14963
|
var StartBrowserSessionRequest = external_exports.object({ url: external_exports.string().min(1).max(2e3).optional() }).strict();
|
|
@@ -18338,7 +18355,7 @@ var ListTasksResponse = external_exports.object({
|
|
|
18338
18355
|
}).strict();
|
|
18339
18356
|
|
|
18340
18357
|
// ../../packages/contracts/src/protocol.ts
|
|
18341
|
-
var PROTOCOL_VERSION =
|
|
18358
|
+
var PROTOCOL_VERSION = 14;
|
|
18342
18359
|
var BROWSER_PROFILE_INVENTORY_PAGE_SIZE = 200;
|
|
18343
18360
|
var HELLO_UNWOUND_ASSIGNMENT_LIMIT = 1e3;
|
|
18344
18361
|
var TASK_CANCEL_ACK_EVENT = "zixt.task.cancel.acknowledged";
|
|
@@ -19512,6 +19529,44 @@ var BrowserSessionEndedFrame = external_exports.object({
|
|
|
19512
19529
|
agentId: AgentId,
|
|
19513
19530
|
reason: BrowserSessionEndReason
|
|
19514
19531
|
});
|
|
19532
|
+
var BrowserCookieSyncFrame = external_exports.object({
|
|
19533
|
+
type: external_exports.literal("browser.cookies.sync"),
|
|
19534
|
+
requestId: external_exports.string().min(1).max(200),
|
|
19535
|
+
projectId: ProjectId,
|
|
19536
|
+
taskId: TaskId,
|
|
19537
|
+
agentId: AgentId,
|
|
19538
|
+
browserSessionId: external_exports.string().min(1).max(200),
|
|
19539
|
+
/** Omitted only by a Machine that has not received the canonical jar yet. */
|
|
19540
|
+
baseRevision: external_exports.number().int().min(0).optional(),
|
|
19541
|
+
cookies: external_exports.array(BrowserCookie).max(BROWSER_MAX_SYNCED_COOKIES)
|
|
19542
|
+
}).strict();
|
|
19543
|
+
var BrowserCookieSyncResultFrame = external_exports.discriminatedUnion("ok", [
|
|
19544
|
+
external_exports.object({
|
|
19545
|
+
type: external_exports.literal("browser.cookies.result"),
|
|
19546
|
+
requestId: external_exports.string().min(1).max(200),
|
|
19547
|
+
projectId: ProjectId,
|
|
19548
|
+
taskId: TaskId,
|
|
19549
|
+
agentId: AgentId,
|
|
19550
|
+
browserSessionId: external_exports.string().min(1).max(200),
|
|
19551
|
+
ok: external_exports.literal(true),
|
|
19552
|
+
/** False asks the Host to reconcile its local changes over this newer jar. */
|
|
19553
|
+
accepted: external_exports.boolean(),
|
|
19554
|
+
state: BrowserCookieState,
|
|
19555
|
+
error: external_exports.never().optional()
|
|
19556
|
+
}).strict(),
|
|
19557
|
+
external_exports.object({
|
|
19558
|
+
type: external_exports.literal("browser.cookies.result"),
|
|
19559
|
+
requestId: external_exports.string().min(1).max(200),
|
|
19560
|
+
projectId: ProjectId,
|
|
19561
|
+
taskId: TaskId,
|
|
19562
|
+
agentId: AgentId,
|
|
19563
|
+
browserSessionId: external_exports.string().min(1).max(200),
|
|
19564
|
+
ok: external_exports.literal(false),
|
|
19565
|
+
accepted: external_exports.never().optional(),
|
|
19566
|
+
state: external_exports.never().optional(),
|
|
19567
|
+
error: external_exports.string().min(1).max(300)
|
|
19568
|
+
}).strict()
|
|
19569
|
+
]);
|
|
19515
19570
|
var BrowserCredentialRequestFrame = external_exports.object({
|
|
19516
19571
|
type: external_exports.literal("browser.credential.request"),
|
|
19517
19572
|
projectId: ProjectId,
|
|
@@ -19939,6 +19994,7 @@ var HostToCloudFrame = external_exports.discriminatedUnion("type", [
|
|
|
19939
19994
|
BrowserStateFrame,
|
|
19940
19995
|
BrowserScreencastFrame,
|
|
19941
19996
|
BrowserSessionEndedFrame,
|
|
19997
|
+
BrowserCookieSyncFrame,
|
|
19942
19998
|
BrowserCredentialRequestFrame,
|
|
19943
19999
|
BrowserProfilePurged,
|
|
19944
20000
|
PingFrame,
|
|
@@ -19946,6 +20002,7 @@ var HostToCloudFrame = external_exports.discriminatedUnion("type", [
|
|
|
19946
20002
|
]);
|
|
19947
20003
|
var CloudToHostFrame = external_exports.discriminatedUnion("type", [
|
|
19948
20004
|
HelloAckFrame,
|
|
20005
|
+
BrowserCookieSyncResultFrame,
|
|
19949
20006
|
DeliverFrame,
|
|
19950
20007
|
ConnectionProbeFrame,
|
|
19951
20008
|
ApiOperationCallFrame,
|
|
@@ -25813,6 +25870,8 @@ var HostClient = class _HostClient {
|
|
|
25813
25870
|
operationGrantWaiters = /* @__PURE__ */ new Map();
|
|
25814
25871
|
/** Project/Task-qualified, socket-generation-bound web_login exchanges. */
|
|
25815
25872
|
browserCredentialWaiters = /* @__PURE__ */ new Map();
|
|
25873
|
+
/** Project-scoped, socket-generation-bound Browser cookie exchanges. */
|
|
25874
|
+
browserCookieSyncWaiters = /* @__PURE__ */ new Map();
|
|
25816
25875
|
/** True only after the connected cloud's helloAck advertised the feature. */
|
|
25817
25876
|
browserFeatureActive = false;
|
|
25818
25877
|
workingContextFeatureActive = false;
|
|
@@ -25978,6 +26037,13 @@ var HostClient = class _HostClient {
|
|
|
25978
26037
|
waiter.deny("No sign-in was attempted: this machine lost its connection to Zixt.");
|
|
25979
26038
|
}
|
|
25980
26039
|
}
|
|
26040
|
+
rejectBrowserCookieSyncWaiters() {
|
|
26041
|
+
for (const [requestId, waiter] of this.browserCookieSyncWaiters) {
|
|
26042
|
+
clearTimeout(waiter.timer);
|
|
26043
|
+
this.browserCookieSyncWaiters.delete(requestId);
|
|
26044
|
+
waiter.deny("Browser cookie synchronization lost its Zixt connection.");
|
|
26045
|
+
}
|
|
26046
|
+
}
|
|
25981
26047
|
async unwindAllRuns(reason, stopReason) {
|
|
25982
26048
|
const runs = [...this.activeRuns.values()];
|
|
25983
26049
|
const unwindingAssignments = [...this.activeAssignments.values()];
|
|
@@ -26017,6 +26083,7 @@ var HostClient = class _HostClient {
|
|
|
26017
26083
|
}
|
|
26018
26084
|
this.rejectOperationGrantWaiters();
|
|
26019
26085
|
this.rejectBrowserCredentialWaiters();
|
|
26086
|
+
this.rejectBrowserCookieSyncWaiters();
|
|
26020
26087
|
for (const deadline of this.authorityExpiryTimers.values()) clearTimeout(deadline.timer);
|
|
26021
26088
|
this.cancels.clear();
|
|
26022
26089
|
this.secretGrants.clear();
|
|
@@ -26369,10 +26436,46 @@ var HostClient = class _HostClient {
|
|
|
26369
26436
|
* frame at a non-advertising cloud would each close the socket outright.
|
|
26370
26437
|
*/
|
|
26371
26438
|
sendBrowserFrame(frame) {
|
|
26372
|
-
if (!this.browserFeatureActive) return;
|
|
26439
|
+
if (!this.browserFeatureActive) return false;
|
|
26373
26440
|
const projectId = frame.type === "browser.state" ? frame.state.projectId : frame.type === "browser.frame" ? frame.frame.projectId : frame.projectId;
|
|
26374
|
-
if (this.purgingProjects.has(projectId)) return;
|
|
26375
|
-
this.send(frame);
|
|
26441
|
+
if (this.purgingProjects.has(projectId)) return false;
|
|
26442
|
+
return this.send(frame);
|
|
26443
|
+
}
|
|
26444
|
+
requestBrowserCookieSync(input) {
|
|
26445
|
+
const socket = this.ws;
|
|
26446
|
+
if (!socket || !this.browserFeatureActive || !this.protocolReady) {
|
|
26447
|
+
return Promise.reject(
|
|
26448
|
+
new Error("Browser cookie synchronization has no live Zixt connection.")
|
|
26449
|
+
);
|
|
26450
|
+
}
|
|
26451
|
+
const requestId = crypto.randomUUID();
|
|
26452
|
+
return new Promise((resolve24, reject3) => {
|
|
26453
|
+
const timer = setTimeout(() => {
|
|
26454
|
+
if (this.browserCookieSyncWaiters.delete(requestId)) {
|
|
26455
|
+
reject3(new Error("Zixt did not answer Browser cookie synchronization in time."));
|
|
26456
|
+
}
|
|
26457
|
+
}, 3e4);
|
|
26458
|
+
timer.unref?.();
|
|
26459
|
+
this.browserCookieSyncWaiters.set(requestId, {
|
|
26460
|
+
projectId: input.projectId,
|
|
26461
|
+
taskId: input.taskId,
|
|
26462
|
+
agentId: input.agentId,
|
|
26463
|
+
browserSessionId: input.browserSessionId,
|
|
26464
|
+
socket,
|
|
26465
|
+
timer,
|
|
26466
|
+
accept: resolve24,
|
|
26467
|
+
deny: (reason) => reject3(new Error(reason))
|
|
26468
|
+
});
|
|
26469
|
+
if (!this.sendBrowserFrame({
|
|
26470
|
+
type: "browser.cookies.sync",
|
|
26471
|
+
requestId,
|
|
26472
|
+
...input
|
|
26473
|
+
})) {
|
|
26474
|
+
clearTimeout(timer);
|
|
26475
|
+
this.browserCookieSyncWaiters.delete(requestId);
|
|
26476
|
+
reject3(new Error("Browser cookie synchronization has no live Zixt connection."));
|
|
26477
|
+
}
|
|
26478
|
+
});
|
|
26376
26479
|
}
|
|
26377
26480
|
replaceablePendingUp(message) {
|
|
26378
26481
|
return message.type === "host.report" || message.type === "task.working_context" || message.type === "task.runner_runtime" || message.type === "task.title" || message.type === "task.event" && message.event.ephemeral === true;
|
|
@@ -26594,7 +26697,8 @@ var HostClient = class _HostClient {
|
|
|
26594
26697
|
taskId,
|
|
26595
26698
|
agentId,
|
|
26596
26699
|
reason
|
|
26597
|
-
})
|
|
26700
|
+
}),
|
|
26701
|
+
syncCookies: (input) => this.requestBrowserCookieSync(input)
|
|
26598
26702
|
});
|
|
26599
26703
|
} else {
|
|
26600
26704
|
this.opts.browser?.attach(null);
|
|
@@ -26708,6 +26812,17 @@ var HostClient = class _HostClient {
|
|
|
26708
26812
|
waiter.accept(grant);
|
|
26709
26813
|
return;
|
|
26710
26814
|
}
|
|
26815
|
+
case "browser.cookies.result": {
|
|
26816
|
+
const waiter = this.browserCookieSyncWaiters.get(frame.requestId);
|
|
26817
|
+
if (!waiter || waiter.socket !== sourceSocket || waiter.projectId !== frame.projectId || waiter.taskId !== frame.taskId || waiter.agentId !== frame.agentId || waiter.browserSessionId !== frame.browserSessionId) {
|
|
26818
|
+
return;
|
|
26819
|
+
}
|
|
26820
|
+
clearTimeout(waiter.timer);
|
|
26821
|
+
this.browserCookieSyncWaiters.delete(frame.requestId);
|
|
26822
|
+
if (frame.ok) waiter.accept({ accepted: frame.accepted, state: frame.state });
|
|
26823
|
+
else waiter.deny(frame.error);
|
|
26824
|
+
return;
|
|
26825
|
+
}
|
|
26711
26826
|
case "browser.open": {
|
|
26712
26827
|
if (!this.acceptsVolatileProjectWork(frame.projectId, frame.projectWorkFenceRevision)) {
|
|
26713
26828
|
return;
|
|
@@ -32486,6 +32601,7 @@ function createDemoBrowserAdapterFactory() {
|
|
|
32486
32601
|
const tabs = [newDemoTab()];
|
|
32487
32602
|
let activeIndex = 0;
|
|
32488
32603
|
let sink = null;
|
|
32604
|
+
let cookies = [];
|
|
32489
32605
|
const listeners = [];
|
|
32490
32606
|
const frame = () => ({
|
|
32491
32607
|
jpegBase64: DEMO_FRAME_JPEG_BASE64,
|
|
@@ -32629,6 +32745,12 @@ function createDemoBrowserAdapterFactory() {
|
|
|
32629
32745
|
}
|
|
32630
32746
|
emit();
|
|
32631
32747
|
},
|
|
32748
|
+
async cookies() {
|
|
32749
|
+
return cookies.map((cookie) => ({ ...cookie }));
|
|
32750
|
+
},
|
|
32751
|
+
async replaceCookies(next) {
|
|
32752
|
+
cookies = next.map((cookie) => ({ ...cookie }));
|
|
32753
|
+
},
|
|
32632
32754
|
async close() {
|
|
32633
32755
|
sink = null;
|
|
32634
32756
|
}
|
|
@@ -44384,6 +44506,10 @@ var BrowserManager = class {
|
|
|
44384
44506
|
deniedAuthorizations = /* @__PURE__ */ new Map();
|
|
44385
44507
|
/** Serializes profile lifecycle and session open/close per teammate. */
|
|
44386
44508
|
locks = /* @__PURE__ */ new Map();
|
|
44509
|
+
/** Last cloud-canonical jar observed for each exact Project teammate. */
|
|
44510
|
+
cookieStates = /* @__PURE__ */ new Map();
|
|
44511
|
+
cookieSyncTails = /* @__PURE__ */ new Map();
|
|
44512
|
+
cookieSyncTimers = /* @__PURE__ */ new Map();
|
|
44387
44513
|
events = null;
|
|
44388
44514
|
profileRoot;
|
|
44389
44515
|
profileStateRoot;
|
|
@@ -44400,8 +44526,15 @@ var BrowserManager = class {
|
|
|
44400
44526
|
attach(events) {
|
|
44401
44527
|
this.events = events;
|
|
44402
44528
|
if (!events) return;
|
|
44529
|
+
const scheduledProfiles = /* @__PURE__ */ new Set();
|
|
44403
44530
|
for (const session of this.sessions.values()) {
|
|
44404
|
-
if (
|
|
44531
|
+
if (session.closed) continue;
|
|
44532
|
+
events.state(this.stateOf(session));
|
|
44533
|
+
const profileKey = this.profileKey(session.projectId, session.agentId);
|
|
44534
|
+
if (!scheduledProfiles.has(profileKey)) {
|
|
44535
|
+
scheduledProfiles.add(profileKey);
|
|
44536
|
+
this.scheduleCookieSync(session, 0);
|
|
44537
|
+
}
|
|
44405
44538
|
}
|
|
44406
44539
|
}
|
|
44407
44540
|
capability() {
|
|
@@ -44486,6 +44619,39 @@ var BrowserManager = class {
|
|
|
44486
44619
|
profileKey(projectId, agentId) {
|
|
44487
44620
|
return `${projectId}:${agentId}`;
|
|
44488
44621
|
}
|
|
44622
|
+
cookieKey(cookie) {
|
|
44623
|
+
return `${cookie.name}\0${cookie.domain}\0${cookie.path}\0${cookie.partitionKey ?? ""}`;
|
|
44624
|
+
}
|
|
44625
|
+
normalizedCookies(cookies) {
|
|
44626
|
+
return [
|
|
44627
|
+
...new Map(cookies.map((cookie) => [this.cookieKey(cookie), { ...cookie }])).values()
|
|
44628
|
+
].sort((left, right) => this.cookieKey(left).localeCompare(this.cookieKey(right)));
|
|
44629
|
+
}
|
|
44630
|
+
cookiesEqual(left, right) {
|
|
44631
|
+
return JSON.stringify(this.normalizedCookies(left)) === JSON.stringify(this.normalizedCookies(right));
|
|
44632
|
+
}
|
|
44633
|
+
/**
|
|
44634
|
+
* Rebase only the changes this Machine made since its last canonical jar
|
|
44635
|
+
* over the newer jar returned by another Machine. Unchanged cookies retain
|
|
44636
|
+
* the remote value; local additions, changes, and deletions win per cookie.
|
|
44637
|
+
*/
|
|
44638
|
+
mergeCookieChanges(base, local, remote) {
|
|
44639
|
+
const baseByKey = new Map(base.map((cookie) => [this.cookieKey(cookie), cookie]));
|
|
44640
|
+
const localByKey = new Map(local.map((cookie) => [this.cookieKey(cookie), cookie]));
|
|
44641
|
+
const merged = new Map(remote.map((cookie) => [this.cookieKey(cookie), { ...cookie }]));
|
|
44642
|
+
for (const [key, baseCookie] of baseByKey) {
|
|
44643
|
+
const localCookie = localByKey.get(key);
|
|
44644
|
+
if (!localCookie) {
|
|
44645
|
+
merged.delete(key);
|
|
44646
|
+
} else if (!this.cookiesEqual([baseCookie], [localCookie])) {
|
|
44647
|
+
merged.set(key, { ...localCookie });
|
|
44648
|
+
}
|
|
44649
|
+
}
|
|
44650
|
+
for (const [key, localCookie] of localByKey) {
|
|
44651
|
+
if (!baseByKey.has(key)) merged.set(key, { ...localCookie });
|
|
44652
|
+
}
|
|
44653
|
+
return this.normalizedCookies([...merged.values()]);
|
|
44654
|
+
}
|
|
44489
44655
|
exactChild(root, child) {
|
|
44490
44656
|
const canonicalRoot = resolve16(root);
|
|
44491
44657
|
const target = resolve16(canonicalRoot, child);
|
|
@@ -44606,6 +44772,85 @@ var BrowserManager = class {
|
|
|
44606
44772
|
throw error52;
|
|
44607
44773
|
}
|
|
44608
44774
|
}
|
|
44775
|
+
synchronizeCookies(session) {
|
|
44776
|
+
const profileKey = this.profileKey(session.projectId, session.agentId);
|
|
44777
|
+
const tail = this.cookieSyncTails.get(profileKey) ?? Promise.resolve();
|
|
44778
|
+
const next = tail.then(async () => {
|
|
44779
|
+
if (session.closed) return;
|
|
44780
|
+
const synchronize = this.events?.syncCookies;
|
|
44781
|
+
if (!synchronize) return;
|
|
44782
|
+
let baseline = this.cookieStates.get(profileKey);
|
|
44783
|
+
let observedLocal = this.normalizedCookies(await session.adapter.cookies());
|
|
44784
|
+
let desired = observedLocal;
|
|
44785
|
+
for (let attempt = 0; attempt < 8; attempt++) {
|
|
44786
|
+
if (desired.length > BROWSER_MAX_SYNCED_COOKIES) {
|
|
44787
|
+
throw new Error(
|
|
44788
|
+
`the browser profile has more than ${BROWSER_MAX_SYNCED_COOKIES} cookies and cannot be synchronized safely`
|
|
44789
|
+
);
|
|
44790
|
+
}
|
|
44791
|
+
const result = await synchronize({
|
|
44792
|
+
projectId: session.projectId,
|
|
44793
|
+
taskId: session.taskId,
|
|
44794
|
+
agentId: session.agentId,
|
|
44795
|
+
browserSessionId: session.browserSessionId,
|
|
44796
|
+
...baseline ? { baseRevision: baseline.revision } : {},
|
|
44797
|
+
cookies: desired
|
|
44798
|
+
});
|
|
44799
|
+
if (result.accepted) {
|
|
44800
|
+
const canonical = {
|
|
44801
|
+
revision: result.state.revision,
|
|
44802
|
+
cookies: this.normalizedCookies(result.state.cookies)
|
|
44803
|
+
};
|
|
44804
|
+
this.cookieStates.set(profileKey, canonical);
|
|
44805
|
+
const current2 = this.normalizedCookies(await session.adapter.cookies());
|
|
44806
|
+
if (!this.cookiesEqual(current2, observedLocal)) {
|
|
44807
|
+
baseline = canonical;
|
|
44808
|
+
desired = this.mergeCookieChanges(observedLocal, current2, canonical.cookies);
|
|
44809
|
+
observedLocal = current2;
|
|
44810
|
+
continue;
|
|
44811
|
+
}
|
|
44812
|
+
if (!this.cookiesEqual(current2, canonical.cookies)) {
|
|
44813
|
+
await session.adapter.replaceCookies(canonical.cookies);
|
|
44814
|
+
}
|
|
44815
|
+
return;
|
|
44816
|
+
}
|
|
44817
|
+
const remote = {
|
|
44818
|
+
revision: result.state.revision,
|
|
44819
|
+
cookies: this.normalizedCookies(result.state.cookies)
|
|
44820
|
+
};
|
|
44821
|
+
if (!baseline) {
|
|
44822
|
+
this.cookieStates.set(profileKey, remote);
|
|
44823
|
+
await session.adapter.replaceCookies(remote.cookies);
|
|
44824
|
+
return;
|
|
44825
|
+
}
|
|
44826
|
+
const current = this.normalizedCookies(await session.adapter.cookies());
|
|
44827
|
+
const currentDesired = this.cookiesEqual(current, observedLocal) ? desired : this.mergeCookieChanges(observedLocal, current, desired);
|
|
44828
|
+
desired = this.mergeCookieChanges(baseline.cookies, currentDesired, remote.cookies);
|
|
44829
|
+
baseline = remote;
|
|
44830
|
+
observedLocal = current;
|
|
44831
|
+
}
|
|
44832
|
+
throw new Error("browser cookies changed too many times while synchronizing");
|
|
44833
|
+
});
|
|
44834
|
+
const tracked = next.finally(() => {
|
|
44835
|
+
if (this.cookieSyncTails.get(profileKey) === tracked) this.cookieSyncTails.delete(profileKey);
|
|
44836
|
+
});
|
|
44837
|
+
this.cookieSyncTails.set(profileKey, tracked);
|
|
44838
|
+
return next;
|
|
44839
|
+
}
|
|
44840
|
+
scheduleCookieSync(session, delayMs = 250) {
|
|
44841
|
+
if (session.closed || !this.events?.syncCookies) return;
|
|
44842
|
+
const profileKey = this.profileKey(session.projectId, session.agentId);
|
|
44843
|
+
const existing = this.cookieSyncTimers.get(profileKey);
|
|
44844
|
+
if (existing) clearTimeout(existing);
|
|
44845
|
+
const timer = setTimeout(() => {
|
|
44846
|
+
if (this.cookieSyncTimers.get(profileKey) !== timer) return;
|
|
44847
|
+
this.cookieSyncTimers.delete(profileKey);
|
|
44848
|
+
void this.synchronizeCookies(session).catch(() => {
|
|
44849
|
+
});
|
|
44850
|
+
}, delayMs);
|
|
44851
|
+
timer.unref?.();
|
|
44852
|
+
this.cookieSyncTimers.set(profileKey, timer);
|
|
44853
|
+
}
|
|
44609
44854
|
/**
|
|
44610
44855
|
* Ensure a live session for this Task. An existing session is adopted
|
|
44611
44856
|
* as-is (the cloud-minted id loses to the live one — the cloud reconciles
|
|
@@ -44683,8 +44928,20 @@ var BrowserManager = class {
|
|
|
44683
44928
|
closeFailed: false
|
|
44684
44929
|
};
|
|
44685
44930
|
this.sessions.set(taskKey, session);
|
|
44931
|
+
try {
|
|
44932
|
+
await this.synchronizeCookies(session);
|
|
44933
|
+
} catch (error52) {
|
|
44934
|
+
session.closed = true;
|
|
44935
|
+
this.sessions.delete(taskKey);
|
|
44936
|
+
await adapter.close().catch(() => {
|
|
44937
|
+
});
|
|
44938
|
+
throw error52;
|
|
44939
|
+
}
|
|
44686
44940
|
adapter.onStateChanged(() => {
|
|
44687
|
-
if (!session.closed)
|
|
44941
|
+
if (!session.closed) {
|
|
44942
|
+
this.events?.state(this.stateOf(session));
|
|
44943
|
+
this.scheduleCookieSync(session);
|
|
44944
|
+
}
|
|
44688
44945
|
});
|
|
44689
44946
|
this.armIdleTimer(session);
|
|
44690
44947
|
this.events?.state(this.stateOf(session));
|
|
@@ -44714,6 +44971,14 @@ var BrowserManager = class {
|
|
|
44714
44971
|
return;
|
|
44715
44972
|
}
|
|
44716
44973
|
if (!session || session.closed && !session.closeFailed) return;
|
|
44974
|
+
const profileKey = this.profileKey(session.projectId, session.agentId);
|
|
44975
|
+
const pendingCookieTimer = this.cookieSyncTimers.get(profileKey);
|
|
44976
|
+
if (pendingCookieTimer) {
|
|
44977
|
+
clearTimeout(pendingCookieTimer);
|
|
44978
|
+
this.cookieSyncTimers.delete(profileKey);
|
|
44979
|
+
}
|
|
44980
|
+
await this.synchronizeCookies(session).catch(() => {
|
|
44981
|
+
});
|
|
44717
44982
|
session.closed = true;
|
|
44718
44983
|
session.closeFailed = false;
|
|
44719
44984
|
if (session.frameTimer) clearTimeout(session.frameTimer);
|
|
@@ -44763,6 +45028,12 @@ var BrowserManager = class {
|
|
|
44763
45028
|
force: true,
|
|
44764
45029
|
maxRetries: 3
|
|
44765
45030
|
});
|
|
45031
|
+
const profileKey = this.profileKey(projectId, agentId);
|
|
45032
|
+
const timer = this.cookieSyncTimers.get(profileKey);
|
|
45033
|
+
if (timer) clearTimeout(timer);
|
|
45034
|
+
this.cookieSyncTimers.delete(profileKey);
|
|
45035
|
+
this.cookieSyncTails.delete(profileKey);
|
|
45036
|
+
this.cookieStates.delete(profileKey);
|
|
44766
45037
|
await this.syncDirectory(this.projectProfileRoot(projectId));
|
|
44767
45038
|
});
|
|
44768
45039
|
}
|
|
@@ -44797,6 +45068,17 @@ var BrowserManager = class {
|
|
|
44797
45068
|
this.deniedAuthorizations.forEach((_revision, key) => {
|
|
44798
45069
|
if (key.startsWith(`${projectId}:`)) this.deniedAuthorizations.delete(key);
|
|
44799
45070
|
});
|
|
45071
|
+
this.cookieSyncTimers.forEach((timer, key) => {
|
|
45072
|
+
if (!key.startsWith(`${projectId}:`)) return;
|
|
45073
|
+
clearTimeout(timer);
|
|
45074
|
+
this.cookieSyncTimers.delete(key);
|
|
45075
|
+
});
|
|
45076
|
+
this.cookieSyncTails.forEach((_tail, key) => {
|
|
45077
|
+
if (key.startsWith(`${projectId}:`)) this.cookieSyncTails.delete(key);
|
|
45078
|
+
});
|
|
45079
|
+
this.cookieStates.forEach((_state, key) => {
|
|
45080
|
+
if (key.startsWith(`${projectId}:`)) this.cookieStates.delete(key);
|
|
45081
|
+
});
|
|
44800
45082
|
await this.syncDirectory(this.profileRoot);
|
|
44801
45083
|
await this.syncDirectory(this.profileStateRoot);
|
|
44802
45084
|
}
|
|
@@ -44865,6 +45147,11 @@ var BrowserManager = class {
|
|
|
44865
45147
|
const next = session.inputQueue.then(work, work);
|
|
44866
45148
|
session.inputQueue = next.catch(() => {
|
|
44867
45149
|
});
|
|
45150
|
+
void next.then(
|
|
45151
|
+
() => this.scheduleCookieSync(session),
|
|
45152
|
+
() => {
|
|
45153
|
+
}
|
|
45154
|
+
);
|
|
44868
45155
|
return next;
|
|
44869
45156
|
}
|
|
44870
45157
|
/** Tool surface: every call ensures the session and counts as activity. */
|
|
@@ -45666,6 +45953,37 @@ function createPlaywrightBrowserAdapterFactory(dependencies = {}) {
|
|
|
45666
45953
|
}
|
|
45667
45954
|
}
|
|
45668
45955
|
},
|
|
45956
|
+
async cookies() {
|
|
45957
|
+
return (await context.cookies()).map((cookie) => ({
|
|
45958
|
+
name: cookie.name,
|
|
45959
|
+
value: cookie.value,
|
|
45960
|
+
domain: cookie.domain,
|
|
45961
|
+
path: cookie.path,
|
|
45962
|
+
expires: cookie.expires,
|
|
45963
|
+
httpOnly: cookie.httpOnly,
|
|
45964
|
+
secure: cookie.secure,
|
|
45965
|
+
sameSite: cookie.sameSite,
|
|
45966
|
+
...cookie.partitionKey ? { partitionKey: cookie.partitionKey } : {}
|
|
45967
|
+
}));
|
|
45968
|
+
},
|
|
45969
|
+
async replaceCookies(cookies) {
|
|
45970
|
+
await context.clearCookies();
|
|
45971
|
+
if (cookies.length > 0) {
|
|
45972
|
+
await context.addCookies(
|
|
45973
|
+
cookies.map((cookie) => ({
|
|
45974
|
+
name: cookie.name,
|
|
45975
|
+
value: cookie.value,
|
|
45976
|
+
domain: cookie.domain,
|
|
45977
|
+
path: cookie.path,
|
|
45978
|
+
expires: cookie.expires,
|
|
45979
|
+
httpOnly: cookie.httpOnly,
|
|
45980
|
+
secure: cookie.secure,
|
|
45981
|
+
sameSite: cookie.sameSite,
|
|
45982
|
+
...cookie.partitionKey !== void 0 ? { partitionKey: cookie.partitionKey } : {}
|
|
45983
|
+
}))
|
|
45984
|
+
);
|
|
45985
|
+
}
|
|
45986
|
+
},
|
|
45669
45987
|
async close() {
|
|
45670
45988
|
closed = true;
|
|
45671
45989
|
for (const tab of [...tabs]) {
|