gologin-agent-browser-cli 0.1.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.

Potentially problematic release.


This version of gologin-agent-browser-cli might be problematic. Click here for more details.

Files changed (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +220 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +352 -0
  5. package/dist/commands/check.d.ts +2 -0
  6. package/dist/commands/check.js +17 -0
  7. package/dist/commands/click.d.ts +2 -0
  8. package/dist/commands/click.js +17 -0
  9. package/dist/commands/close.d.ts +2 -0
  10. package/dist/commands/close.js +12 -0
  11. package/dist/commands/current.d.ts +2 -0
  12. package/dist/commands/current.js +9 -0
  13. package/dist/commands/dblclick.d.ts +2 -0
  14. package/dist/commands/dblclick.js +17 -0
  15. package/dist/commands/fill.d.ts +2 -0
  16. package/dist/commands/fill.js +18 -0
  17. package/dist/commands/find.d.ts +2 -0
  18. package/dist/commands/find.js +86 -0
  19. package/dist/commands/focus.d.ts +2 -0
  20. package/dist/commands/focus.js +17 -0
  21. package/dist/commands/get.d.ts +2 -0
  22. package/dist/commands/get.js +19 -0
  23. package/dist/commands/hover.d.ts +2 -0
  24. package/dist/commands/hover.js +17 -0
  25. package/dist/commands/open.d.ts +2 -0
  26. package/dist/commands/open.js +67 -0
  27. package/dist/commands/pdf.d.ts +2 -0
  28. package/dist/commands/pdf.js +18 -0
  29. package/dist/commands/press.d.ts +2 -0
  30. package/dist/commands/press.js +19 -0
  31. package/dist/commands/screenshot.d.ts +2 -0
  32. package/dist/commands/screenshot.js +20 -0
  33. package/dist/commands/scroll.d.ts +2 -0
  34. package/dist/commands/scroll.js +25 -0
  35. package/dist/commands/scrollIntoView.d.ts +2 -0
  36. package/dist/commands/scrollIntoView.js +17 -0
  37. package/dist/commands/select.d.ts +2 -0
  38. package/dist/commands/select.js +18 -0
  39. package/dist/commands/sessions.d.ts +2 -0
  40. package/dist/commands/sessions.js +15 -0
  41. package/dist/commands/shared.d.ts +3 -0
  42. package/dist/commands/shared.js +13 -0
  43. package/dist/commands/snapshot.d.ts +2 -0
  44. package/dist/commands/snapshot.js +16 -0
  45. package/dist/commands/type.d.ts +2 -0
  46. package/dist/commands/type.js +18 -0
  47. package/dist/commands/uncheck.d.ts +2 -0
  48. package/dist/commands/uncheck.js +17 -0
  49. package/dist/commands/upload.d.ts +2 -0
  50. package/dist/commands/upload.js +18 -0
  51. package/dist/commands/wait.d.ts +2 -0
  52. package/dist/commands/wait.js +41 -0
  53. package/dist/daemon/browser.d.ts +37 -0
  54. package/dist/daemon/browser.js +557 -0
  55. package/dist/daemon/refStore.d.ts +9 -0
  56. package/dist/daemon/refStore.js +26 -0
  57. package/dist/daemon/server.d.ts +1 -0
  58. package/dist/daemon/server.js +235 -0
  59. package/dist/daemon/sessionManager.d.ts +50 -0
  60. package/dist/daemon/sessionManager.js +512 -0
  61. package/dist/daemon/snapshot.d.ts +8 -0
  62. package/dist/daemon/snapshot.js +285 -0
  63. package/dist/lib/config.d.ts +3 -0
  64. package/dist/lib/config.js +58 -0
  65. package/dist/lib/errors.d.ts +12 -0
  66. package/dist/lib/errors.js +63 -0
  67. package/dist/lib/types.d.ts +301 -0
  68. package/dist/lib/types.js +2 -0
  69. package/dist/lib/utils.d.ts +27 -0
  70. package/dist/lib/utils.js +165 -0
  71. package/examples/agent-flow.sh +19 -0
  72. package/package.json +59 -0
@@ -0,0 +1,512 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SessionManager = void 0;
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const errors_1 = require("../lib/errors");
10
+ const utils_1 = require("../lib/utils");
11
+ const browser_1 = require("./browser");
12
+ const refStore_1 = require("./refStore");
13
+ const snapshot_1 = require("./snapshot");
14
+ class SessionManager {
15
+ config;
16
+ sessions = new Map();
17
+ activeSessionId;
18
+ refStore = new refStore_1.RefStore();
19
+ constructor(config) {
20
+ this.config = config;
21
+ }
22
+ nowIso() {
23
+ return new Date().toISOString();
24
+ }
25
+ requireToken() {
26
+ if (!this.config.token) {
27
+ throw new errors_1.AppError("TOKEN_MISSING", "GOLOGIN_TOKEN is required for open", 400);
28
+ }
29
+ return this.config.token;
30
+ }
31
+ sessionExpired(session) {
32
+ if (session.idleTimeoutMs === undefined) {
33
+ return false;
34
+ }
35
+ const lastActivityAt = Date.parse(session.lastActivityAt);
36
+ if (Number.isNaN(lastActivityAt)) {
37
+ return false;
38
+ }
39
+ return Date.now() - lastActivityAt > session.idleTimeoutMs;
40
+ }
41
+ async destroySession(session) {
42
+ await (0, browser_1.closeSessionHandles)(session).catch(() => undefined);
43
+ this.sessions.delete(session.sessionId);
44
+ this.refStore.clear(session.sessionId);
45
+ if (session.autoCreatedProfile && session.profileId && this.config.token) {
46
+ await (0, browser_1.deleteProfile)(this.config.token, session.profileId).catch(() => undefined);
47
+ }
48
+ if (this.activeSessionId === session.sessionId) {
49
+ this.activeSessionId = Array.from(this.sessions.keys()).at(-1);
50
+ }
51
+ }
52
+ async getSessionOrThrow(sessionId) {
53
+ const resolvedId = sessionId ?? this.activeSessionId;
54
+ if (!resolvedId) {
55
+ throw new errors_1.AppError("SESSION_NOT_FOUND", "no active session", 404);
56
+ }
57
+ const session = this.sessions.get(resolvedId);
58
+ if (!session) {
59
+ throw new errors_1.AppError("SESSION_NOT_FOUND", `session ${resolvedId} does not exist`, 404, { sessionId: resolvedId });
60
+ }
61
+ if (this.sessionExpired(session)) {
62
+ const idleTimeoutMs = session.idleTimeoutMs;
63
+ await this.destroySession(session);
64
+ throw new errors_1.AppError("SESSION_EXPIRED", `session ${resolvedId} expired after ${idleTimeoutMs}ms of inactivity`, 404, { sessionId: resolvedId, idleTimeoutMs });
65
+ }
66
+ return session;
67
+ }
68
+ async evictExpiredSessions() {
69
+ for (const session of Array.from(this.sessions.values())) {
70
+ if (this.sessionExpired(session)) {
71
+ await this.destroySession(session);
72
+ }
73
+ }
74
+ }
75
+ toSummary(session) {
76
+ return {
77
+ sessionId: session.sessionId,
78
+ profileId: session.profileId,
79
+ url: session.currentUrl,
80
+ active: session.sessionId === this.activeSessionId,
81
+ hasSnapshot: session.hasSnapshot,
82
+ staleSnapshot: session.staleSnapshot,
83
+ liveViewUrl: session.liveViewUrl,
84
+ proxy: session.proxy,
85
+ createdAt: session.createdAt,
86
+ lastActivityAt: session.lastActivityAt,
87
+ idleTimeoutMs: session.idleTimeoutMs,
88
+ lastScreenshotPath: session.lastScreenshotPath,
89
+ lastPdfPath: session.lastPdfPath
90
+ };
91
+ }
92
+ touchSession(session) {
93
+ session.currentUrl = session.page.url();
94
+ session.lastActivityAt = this.nowIso();
95
+ this.activeSessionId = session.sessionId;
96
+ }
97
+ markSessionState(session, staleSnapshot = session.staleSnapshot) {
98
+ this.touchSession(session);
99
+ session.staleSnapshot = staleSnapshot;
100
+ }
101
+ validateIdleTimeout(idleTimeoutMs) {
102
+ if (idleTimeoutMs === undefined) {
103
+ return;
104
+ }
105
+ if (!Number.isInteger(idleTimeoutMs) || idleTimeoutMs <= 0) {
106
+ throw new errors_1.AppError("BAD_REQUEST", "--idle-timeout-ms must be a positive integer", 400);
107
+ }
108
+ }
109
+ async resolveTargetLocator(session, target) {
110
+ if ((0, utils_1.isRefTarget)(target)) {
111
+ const descriptor = this.refStore.get(session.sessionId, target);
112
+ if (!descriptor) {
113
+ throw new errors_1.AppError("REF_NOT_FOUND", `ref ${target} is not available in session ${session.sessionId}`, 404, {
114
+ ref: target,
115
+ sessionId: session.sessionId
116
+ });
117
+ }
118
+ return (0, browser_1.resolveDescriptorLocator)(session.page, descriptor);
119
+ }
120
+ return (0, browser_1.resolveSelectorLocator)(session.page, target, this.config.actionTimeoutMs);
121
+ }
122
+ async runTargetAction(session, target, action, value) {
123
+ const locator = await this.resolveTargetLocator(session, target);
124
+ await (0, browser_1.performLocatorAction)(session.page, locator, action, this.config.actionTimeoutMs, value);
125
+ this.markSessionState(session, true);
126
+ return {
127
+ sessionId: session.sessionId,
128
+ url: session.currentUrl,
129
+ staleSnapshot: true
130
+ };
131
+ }
132
+ async open(request) {
133
+ const token = this.requireToken();
134
+ this.validateIdleTimeout(request.idleTimeoutMs);
135
+ if (request.profileId && request.proxy) {
136
+ throw new errors_1.AppError("BAD_REQUEST", "proxy flags cannot be combined with --profile", 400);
137
+ }
138
+ if (request.sessionId && this.sessions.has(request.sessionId)) {
139
+ const existing = await this.getSessionOrThrow(request.sessionId);
140
+ if (request.profileId && existing.profileId && request.profileId !== existing.profileId) {
141
+ throw new errors_1.AppError("BAD_REQUEST", `session ${existing.sessionId} already uses profile ${existing.profileId}`, 400);
142
+ }
143
+ if (request.proxy) {
144
+ throw new errors_1.AppError("BAD_REQUEST", `session ${existing.sessionId} already exists; proxy cannot be changed`, 400);
145
+ }
146
+ if (request.idleTimeoutMs !== undefined) {
147
+ existing.idleTimeoutMs = request.idleTimeoutMs;
148
+ }
149
+ existing.currentUrl = await (0, browser_1.navigatePage)(existing.page, request.url, this.config.navigationTimeoutMs);
150
+ existing.hasSnapshot = false;
151
+ existing.staleSnapshot = true;
152
+ existing.lastActivityAt = this.nowIso();
153
+ this.refStore.clear(existing.sessionId);
154
+ this.activeSessionId = existing.sessionId;
155
+ return {
156
+ sessionId: existing.sessionId,
157
+ profileId: existing.profileId,
158
+ url: existing.currentUrl,
159
+ liveViewUrl: existing.liveViewUrl,
160
+ proxy: existing.proxy,
161
+ idleTimeoutMs: existing.idleTimeoutMs
162
+ };
163
+ }
164
+ let profileId = request.profileId ?? this.config.defaultProfileId;
165
+ let autoCreatedProfile = false;
166
+ let resolvedProxy;
167
+ const sessionId = request.sessionId ?? (0, utils_1.generateSessionId)(this.sessions.keys());
168
+ const createdAt = this.nowIso();
169
+ if (!profileId) {
170
+ const created = await (0, browser_1.createManagedProfile)(token, sessionId, request.proxy);
171
+ profileId = created.profileId;
172
+ resolvedProxy = created.proxy;
173
+ autoCreatedProfile = true;
174
+ }
175
+ try {
176
+ const connection = await (0, browser_1.connectToBrowser)(this.config, token, profileId);
177
+ const currentUrl = await (0, browser_1.navigatePage)(connection.page, request.url, this.config.navigationTimeoutMs);
178
+ const lastActivityAt = this.nowIso();
179
+ if (!resolvedProxy && profileId) {
180
+ resolvedProxy = await (0, browser_1.getCloudProfileProxy)(token, profileId).catch(() => undefined);
181
+ }
182
+ const session = {
183
+ sessionId,
184
+ profileId,
185
+ autoCreatedProfile,
186
+ connectUrl: connection.connectUrl,
187
+ browser: connection.browser,
188
+ context: connection.context,
189
+ page: connection.page,
190
+ currentUrl,
191
+ hasSnapshot: false,
192
+ staleSnapshot: false,
193
+ proxy: resolvedProxy,
194
+ createdAt,
195
+ lastActivityAt,
196
+ idleTimeoutMs: request.idleTimeoutMs
197
+ };
198
+ this.sessions.set(sessionId, session);
199
+ this.activeSessionId = sessionId;
200
+ this.refStore.clear(sessionId);
201
+ return {
202
+ sessionId,
203
+ profileId,
204
+ url: currentUrl,
205
+ proxy: session.proxy,
206
+ idleTimeoutMs: session.idleTimeoutMs
207
+ };
208
+ }
209
+ catch (error) {
210
+ if (autoCreatedProfile && profileId) {
211
+ await (0, browser_1.deleteProfile)(token, profileId).catch(() => undefined);
212
+ }
213
+ throw error;
214
+ }
215
+ }
216
+ async snapshot(sessionId, interactive = false) {
217
+ const session = await this.getSessionOrThrow(sessionId);
218
+ const snapshot = await (0, snapshot_1.buildSnapshot)(session.page, { interactive });
219
+ this.refStore.set(session.sessionId, snapshot.refs);
220
+ session.currentUrl = session.page.url();
221
+ session.hasSnapshot = true;
222
+ session.staleSnapshot = false;
223
+ session.lastActivityAt = this.nowIso();
224
+ this.activeSessionId = session.sessionId;
225
+ return {
226
+ sessionId: session.sessionId,
227
+ url: session.currentUrl,
228
+ items: snapshot.items
229
+ };
230
+ }
231
+ async click(sessionId, target) {
232
+ return this.runTargetAction(await this.getSessionOrThrow(sessionId), target, "click");
233
+ }
234
+ async type(sessionId, target, text) {
235
+ return this.runTargetAction(await this.getSessionOrThrow(sessionId), target, "type", text);
236
+ }
237
+ async fill(sessionId, target, text) {
238
+ return this.runTargetAction(await this.getSessionOrThrow(sessionId), target, "fill", text);
239
+ }
240
+ async hover(sessionId, target) {
241
+ return this.runTargetAction(await this.getSessionOrThrow(sessionId), target, "hover");
242
+ }
243
+ async focus(sessionId, target) {
244
+ return this.runTargetAction(await this.getSessionOrThrow(sessionId), target, "focus");
245
+ }
246
+ async doubleClick(sessionId, target) {
247
+ return this.runTargetAction(await this.getSessionOrThrow(sessionId), target, "dblclick");
248
+ }
249
+ async select(sessionId, target, value) {
250
+ return this.runTargetAction(await this.getSessionOrThrow(sessionId), target, "select", value);
251
+ }
252
+ async check(sessionId, target) {
253
+ return this.runTargetAction(await this.getSessionOrThrow(sessionId), target, "check");
254
+ }
255
+ async uncheck(sessionId, target) {
256
+ return this.runTargetAction(await this.getSessionOrThrow(sessionId), target, "uncheck");
257
+ }
258
+ async press(sessionId, key, target) {
259
+ const session = await this.getSessionOrThrow(sessionId);
260
+ if (target) {
261
+ const locator = await this.resolveTargetLocator(session, target);
262
+ await locator.focus({ timeout: this.config.actionTimeoutMs });
263
+ }
264
+ await (0, browser_1.pressKey)(session.page, key, this.config.actionTimeoutMs);
265
+ this.markSessionState(session, true);
266
+ return {
267
+ sessionId: session.sessionId,
268
+ url: session.currentUrl,
269
+ staleSnapshot: true
270
+ };
271
+ }
272
+ async scroll(sessionId, direction, pixels = 500, target) {
273
+ const session = await this.getSessionOrThrow(sessionId);
274
+ if (target) {
275
+ const locator = await this.resolveTargetLocator(session, target);
276
+ await (0, browser_1.scrollElement)(locator, direction, pixels);
277
+ }
278
+ else {
279
+ await (0, browser_1.scrollPage)(session.page, direction, pixels);
280
+ }
281
+ this.markSessionState(session);
282
+ return {
283
+ sessionId: session.sessionId,
284
+ url: session.currentUrl,
285
+ target,
286
+ direction,
287
+ pixels
288
+ };
289
+ }
290
+ async scrollIntoView(sessionId, target) {
291
+ const session = await this.getSessionOrThrow(sessionId);
292
+ const locator = await this.resolveTargetLocator(session, target);
293
+ await (0, browser_1.scrollLocatorIntoView)(locator, this.config.actionTimeoutMs);
294
+ this.markSessionState(session);
295
+ return {
296
+ sessionId: session.sessionId,
297
+ url: session.currentUrl,
298
+ staleSnapshot: session.staleSnapshot
299
+ };
300
+ }
301
+ async upload(sessionId, target, files) {
302
+ const session = await this.getSessionOrThrow(sessionId);
303
+ const locator = await this.resolveTargetLocator(session, target);
304
+ try {
305
+ await (0, browser_1.uploadFiles)(locator, files, this.config.actionTimeoutMs);
306
+ }
307
+ catch (error) {
308
+ throw new errors_1.AppError("UPLOAD_FAILED", error instanceof Error ? error.message : String(error), 500, {
309
+ files
310
+ });
311
+ }
312
+ this.markSessionState(session, true);
313
+ return {
314
+ sessionId: session.sessionId,
315
+ url: session.currentUrl,
316
+ staleSnapshot: true,
317
+ files
318
+ };
319
+ }
320
+ async wait(sessionId, request) {
321
+ const session = await this.getSessionOrThrow(sessionId);
322
+ const timeoutMs = request.timeoutMs ?? this.config.navigationTimeoutMs;
323
+ if (request.timeoutMs && !request.target && !request.text && !request.urlPattern && !request.loadState) {
324
+ await new Promise((resolve) => setTimeout(resolve, request.timeoutMs));
325
+ this.markSessionState(session);
326
+ return {
327
+ sessionId: session.sessionId,
328
+ url: session.currentUrl,
329
+ waitedFor: `${request.timeoutMs}ms`
330
+ };
331
+ }
332
+ if (request.target) {
333
+ const locator = await this.resolveTargetLocator(session, request.target);
334
+ await (0, browser_1.waitForTarget)(locator, timeoutMs);
335
+ this.markSessionState(session);
336
+ return {
337
+ sessionId: session.sessionId,
338
+ url: session.currentUrl,
339
+ waitedFor: request.target
340
+ };
341
+ }
342
+ if (request.text) {
343
+ await (0, browser_1.waitForPageText)(session.page, request.text, timeoutMs);
344
+ this.markSessionState(session);
345
+ return {
346
+ sessionId: session.sessionId,
347
+ url: session.currentUrl,
348
+ waitedFor: `text:${request.text}`
349
+ };
350
+ }
351
+ if (request.urlPattern) {
352
+ await (0, browser_1.waitForPageUrl)(session.page, request.urlPattern, timeoutMs);
353
+ this.markSessionState(session);
354
+ return {
355
+ sessionId: session.sessionId,
356
+ url: session.currentUrl,
357
+ waitedFor: `url:${request.urlPattern}`
358
+ };
359
+ }
360
+ if (request.loadState) {
361
+ await (0, browser_1.waitForPageLoad)(session.page, request.loadState, timeoutMs);
362
+ this.markSessionState(session);
363
+ return {
364
+ sessionId: session.sessionId,
365
+ url: session.currentUrl,
366
+ waitedFor: `load:${request.loadState}`
367
+ };
368
+ }
369
+ throw new errors_1.AppError("BAD_REQUEST", "wait requires a target, timeout, --text, --url, or --load", 400);
370
+ }
371
+ async get(sessionId, kind, target) {
372
+ const session = await this.getSessionOrThrow(sessionId);
373
+ if (kind === "url") {
374
+ this.markSessionState(session);
375
+ return {
376
+ sessionId: session.sessionId,
377
+ url: session.currentUrl,
378
+ value: session.currentUrl
379
+ };
380
+ }
381
+ if (kind === "title") {
382
+ const value = await session.page.title();
383
+ this.markSessionState(session);
384
+ return {
385
+ sessionId: session.sessionId,
386
+ url: session.currentUrl,
387
+ value
388
+ };
389
+ }
390
+ if (!target) {
391
+ throw new errors_1.AppError("BAD_REQUEST", `get ${kind} requires a target`, 400);
392
+ }
393
+ const locator = await this.resolveTargetLocator(session, target);
394
+ const value = await (0, browser_1.readLocatorValue)(locator, kind, this.config.actionTimeoutMs);
395
+ this.markSessionState(session);
396
+ return {
397
+ sessionId: session.sessionId,
398
+ url: session.currentUrl,
399
+ value
400
+ };
401
+ }
402
+ async find(sessionId, request) {
403
+ const session = await this.getSessionOrThrow(sessionId);
404
+ const locator = await (0, browser_1.resolveSemanticLocator)(session.page, request.locator, this.config.actionTimeoutMs);
405
+ const value = await (0, browser_1.performLocatorAction)(session.page, locator, request.action, this.config.actionTimeoutMs, request.value);
406
+ const staleSnapshot = (0, browser_1.actionMutatesSnapshot)(request.action);
407
+ this.markSessionState(session, staleSnapshot ? true : session.staleSnapshot);
408
+ return {
409
+ sessionId: session.sessionId,
410
+ url: session.currentUrl,
411
+ staleSnapshot: session.staleSnapshot,
412
+ value
413
+ };
414
+ }
415
+ async screenshot(sessionId, targetPath, annotate = false) {
416
+ const session = await this.getSessionOrThrow(sessionId);
417
+ try {
418
+ node_fs_1.default.mkdirSync(node_path_1.default.dirname(targetPath), { recursive: true });
419
+ if (annotate) {
420
+ const snapshot = await (0, snapshot_1.buildSnapshot)(session.page, { interactive: true });
421
+ this.refStore.set(session.sessionId, snapshot.refs);
422
+ session.hasSnapshot = true;
423
+ session.staleSnapshot = false;
424
+ const labels = [];
425
+ for (const descriptor of snapshot.refs) {
426
+ const locator = await (0, browser_1.resolveDescriptorLocator)(session.page, descriptor).catch(() => undefined);
427
+ if (!locator) {
428
+ continue;
429
+ }
430
+ const box = await locator.boundingBox().catch(() => null);
431
+ if (!box) {
432
+ continue;
433
+ }
434
+ labels.push({
435
+ ref: descriptor.ref,
436
+ x: box.x,
437
+ y: box.y
438
+ });
439
+ }
440
+ await (0, browser_1.annotatePageWithRefs)(session.page, labels);
441
+ }
442
+ await session.page.screenshot({
443
+ path: targetPath,
444
+ fullPage: true
445
+ });
446
+ if (annotate) {
447
+ await (0, browser_1.clearPageAnnotations)(session.page).catch(() => undefined);
448
+ }
449
+ }
450
+ catch (error) {
451
+ if (annotate) {
452
+ await (0, browser_1.clearPageAnnotations)(session.page).catch(() => undefined);
453
+ }
454
+ throw new errors_1.AppError("SCREENSHOT_FAILED", error instanceof Error ? error.message : String(error), 500, {
455
+ path: targetPath
456
+ });
457
+ }
458
+ session.lastScreenshotPath = targetPath;
459
+ this.touchSession(session);
460
+ return {
461
+ sessionId: session.sessionId,
462
+ path: targetPath,
463
+ url: session.currentUrl,
464
+ annotated: annotate
465
+ };
466
+ }
467
+ async pdf(sessionId, targetPath) {
468
+ const session = await this.getSessionOrThrow(sessionId);
469
+ try {
470
+ node_fs_1.default.mkdirSync(node_path_1.default.dirname(targetPath), { recursive: true });
471
+ await (0, browser_1.savePdf)(session.page, targetPath);
472
+ }
473
+ catch (error) {
474
+ throw new errors_1.AppError("PDF_FAILED", error instanceof Error ? error.message : String(error), 500, {
475
+ path: targetPath
476
+ });
477
+ }
478
+ session.lastPdfPath = targetPath;
479
+ this.markSessionState(session);
480
+ return {
481
+ sessionId: session.sessionId,
482
+ path: targetPath,
483
+ url: session.currentUrl
484
+ };
485
+ }
486
+ async close(sessionId) {
487
+ const session = await this.getSessionOrThrow(sessionId);
488
+ await this.destroySession(session);
489
+ return {
490
+ sessionId: session.sessionId,
491
+ closed: true
492
+ };
493
+ }
494
+ async listSessions() {
495
+ await this.evictExpiredSessions();
496
+ return {
497
+ activeSessionId: this.activeSessionId,
498
+ sessions: Array.from(this.sessions.values()).map((session) => this.toSummary(session))
499
+ };
500
+ }
501
+ async currentSession() {
502
+ return this.toSummary(await this.getSessionOrThrow());
503
+ }
504
+ async closeAll() {
505
+ for (const session of Array.from(this.sessions.values())) {
506
+ await this.destroySession(session);
507
+ }
508
+ this.sessions.clear();
509
+ this.activeSessionId = undefined;
510
+ }
511
+ }
512
+ exports.SessionManager = SessionManager;
@@ -0,0 +1,8 @@
1
+ import type { Page } from "playwright";
2
+ import type { RawSnapshotCandidate, SnapshotBuildResult } from "../lib/types";
3
+ type SnapshotOptions = {
4
+ interactive?: boolean;
5
+ };
6
+ export declare function buildSnapshotModel(rawCandidates: RawSnapshotCandidate[], options?: SnapshotOptions): SnapshotBuildResult;
7
+ export declare function buildSnapshot(page: Page, options?: SnapshotOptions): Promise<SnapshotBuildResult>;
8
+ export {};