@dev-blinq/cucumber_client 1.0.1585-dev → 1.0.1587-dev
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/bin/client/recorderv3/services.js +296 -38
- package/package.json +1 -1
|
@@ -219,27 +219,54 @@ export class RemoteBrowserService extends EventEmitter {
|
|
|
219
219
|
super();
|
|
220
220
|
this.CDP_CONNECT_URL = CDP_CONNECT_URL;
|
|
221
221
|
this.context = context;
|
|
222
|
+
this.log("🚀 RemoteBrowserService initialized", { CDP_CONNECT_URL });
|
|
222
223
|
this.initializeListeners();
|
|
223
224
|
}
|
|
225
|
+
log(message, data) {
|
|
226
|
+
const timestamp = new Date().toISOString();
|
|
227
|
+
console.log(`[${timestamp}] [RemoteBrowserService] ${message}`, data ? JSON.stringify(data, null, 2) : "");
|
|
228
|
+
}
|
|
224
229
|
async initializeListeners() {
|
|
230
|
+
this.log("📡 Initializing listeners");
|
|
225
231
|
// Listen for new pages
|
|
226
232
|
this.context.on("page", async (page) => {
|
|
233
|
+
this.log("🆕 New page event triggered", { url: page.url() });
|
|
227
234
|
const id = await this.getPageId(page);
|
|
235
|
+
this.log("🔍 Got page ID from CDP", { id, url: page.url() });
|
|
228
236
|
if (id) {
|
|
229
237
|
this.pages.set(id, page);
|
|
238
|
+
this.log("✅ Page added to internal map", {
|
|
239
|
+
id,
|
|
240
|
+
url: page.url(),
|
|
241
|
+
totalPages: this.pages.size,
|
|
242
|
+
allPageIds: Array.from(this.pages.keys()),
|
|
243
|
+
});
|
|
230
244
|
await this.syncState();
|
|
231
245
|
}
|
|
246
|
+
else {
|
|
247
|
+
this.log("❌ Failed to get page ID, page not added to map", { url: page.url() });
|
|
248
|
+
}
|
|
232
249
|
// Listen for page updates
|
|
233
250
|
page.on("load", async () => {
|
|
251
|
+
this.log("🔄 Page load event", { id, url: page.url() });
|
|
234
252
|
await this.syncState();
|
|
235
253
|
});
|
|
236
254
|
page.on("close", async () => {
|
|
255
|
+
this.log("🗑️ Page close event", { id, url: page.url() });
|
|
237
256
|
if (id) {
|
|
238
257
|
this.pages.delete(id);
|
|
258
|
+
this.log("✅ Page removed from internal map", {
|
|
259
|
+
id,
|
|
260
|
+
remainingPages: this.pages.size,
|
|
261
|
+
allPageIds: Array.from(this.pages.keys()),
|
|
262
|
+
});
|
|
239
263
|
if (this._selectedPageId === id) {
|
|
240
|
-
// Select first available page
|
|
241
264
|
const firstPage = Array.from(this.pages.keys())[0];
|
|
242
265
|
this._selectedPageId = firstPage || null;
|
|
266
|
+
this.log("🔄 Selected page changed after close", {
|
|
267
|
+
oldSelectedId: id,
|
|
268
|
+
newSelectedId: this._selectedPageId,
|
|
269
|
+
});
|
|
243
270
|
}
|
|
244
271
|
await this.syncState();
|
|
245
272
|
}
|
|
@@ -247,155 +274,386 @@ export class RemoteBrowserService extends EventEmitter {
|
|
|
247
274
|
});
|
|
248
275
|
// Initialize with existing pages
|
|
249
276
|
const existingPages = this.context.pages();
|
|
277
|
+
this.log("📄 Found existing pages", { count: existingPages.length });
|
|
250
278
|
for (const page of existingPages) {
|
|
251
279
|
const id = await this.getPageId(page);
|
|
280
|
+
this.log("🔍 Processing existing page", { id, url: page.url() });
|
|
252
281
|
if (id) {
|
|
253
282
|
this.pages.set(id, page);
|
|
283
|
+
this.log("✅ Existing page added to map", {
|
|
284
|
+
id,
|
|
285
|
+
url: page.url(),
|
|
286
|
+
totalPages: this.pages.size,
|
|
287
|
+
});
|
|
254
288
|
}
|
|
255
|
-
// page.on("framenavigated", async () => {
|
|
256
|
-
// await new Promise((resolve) => setTimeout(resolve, 1000)); // wait for a bit
|
|
257
|
-
// await this.syncState();
|
|
258
|
-
// });
|
|
259
289
|
}
|
|
260
290
|
// Set initial selected page
|
|
261
291
|
if (this.pages.size > 0 && !this._selectedPageId) {
|
|
262
292
|
this._selectedPageId = Array.from(this.pages.keys())[0];
|
|
293
|
+
this.log("🎯 Initial selected page set", { selectedPageId: this._selectedPageId });
|
|
263
294
|
}
|
|
295
|
+
this.log("✅ Initialization complete", {
|
|
296
|
+
totalPages: this.pages.size,
|
|
297
|
+
selectedPageId: this._selectedPageId,
|
|
298
|
+
allPageIds: Array.from(this.pages.keys()),
|
|
299
|
+
});
|
|
264
300
|
await this.syncState();
|
|
265
301
|
}
|
|
266
302
|
async getPageId(page) {
|
|
267
303
|
try {
|
|
268
|
-
const debugData = await this.getDebugURLs();
|
|
269
304
|
const pageUrl = page.url();
|
|
305
|
+
this.log("🔍 Getting page ID", { pageUrl });
|
|
306
|
+
// Try to get the CDP target ID directly from the page
|
|
307
|
+
// This is more reliable than URL matching
|
|
308
|
+
try {
|
|
309
|
+
const cdpSession = await page.context().newCDPSession(page);
|
|
310
|
+
const { targetInfo } = await cdpSession.send("Target.getTargetInfo");
|
|
311
|
+
await cdpSession.detach();
|
|
312
|
+
if (targetInfo && targetInfo.targetId) {
|
|
313
|
+
this.log("✅ Got target ID from CDP session", {
|
|
314
|
+
targetId: targetInfo.targetId,
|
|
315
|
+
url: pageUrl,
|
|
316
|
+
});
|
|
317
|
+
return targetInfo.targetId;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
catch (cdpError) {
|
|
321
|
+
this.log("⚠️ Failed to get target ID from CDP session, falling back to URL matching", {
|
|
322
|
+
error: cdpError instanceof Error ? cdpError.message : String(cdpError),
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
const debugData = await this.getDebugURLs();
|
|
326
|
+
this.log("📊 CDP debug data received", {
|
|
327
|
+
totalPages: debugData.length,
|
|
328
|
+
pages: debugData.map((p) => ({ id: p.id, type: p.type, url: p.url })),
|
|
329
|
+
});
|
|
330
|
+
// Exact match
|
|
270
331
|
for (const pageData of debugData) {
|
|
271
332
|
if (pageData.type === "page" && pageData.url === pageUrl) {
|
|
333
|
+
this.log("✅ Found exact URL match", {
|
|
334
|
+
id: pageData.id,
|
|
335
|
+
url: pageUrl,
|
|
336
|
+
});
|
|
272
337
|
return pageData.id;
|
|
273
338
|
}
|
|
274
339
|
}
|
|
275
|
-
|
|
340
|
+
this.log("⚠️ No exact match found, trying normalized URLs", { pageUrl });
|
|
341
|
+
// Normalized match
|
|
276
342
|
const normalizeUrl = (url) => {
|
|
277
343
|
try {
|
|
278
344
|
const u = new URL(url);
|
|
279
|
-
|
|
345
|
+
const normalized = u.hostname.replace(/^www\./, "") + u.pathname + u.search;
|
|
346
|
+
this.log("🔧 Normalized URL", { original: url, normalized });
|
|
347
|
+
return normalized;
|
|
280
348
|
}
|
|
281
349
|
catch {
|
|
350
|
+
this.log("❌ Failed to normalize URL", { url });
|
|
282
351
|
return url;
|
|
283
352
|
}
|
|
284
353
|
};
|
|
285
354
|
const normalizedPageUrl = normalizeUrl(pageUrl);
|
|
286
355
|
for (const pageData of debugData) {
|
|
287
|
-
if (pageData.type === "page"
|
|
288
|
-
|
|
356
|
+
if (pageData.type === "page") {
|
|
357
|
+
const normalizedDebugUrl = normalizeUrl(pageData.url);
|
|
358
|
+
if (normalizedDebugUrl === normalizedPageUrl) {
|
|
359
|
+
this.log("✅ Found normalized URL match", {
|
|
360
|
+
id: pageData.id,
|
|
361
|
+
pageUrl: normalizedPageUrl,
|
|
362
|
+
debugUrl: normalizedDebugUrl,
|
|
363
|
+
});
|
|
364
|
+
return pageData.id;
|
|
365
|
+
}
|
|
289
366
|
}
|
|
290
367
|
}
|
|
368
|
+
this.log("❌ No match found for page", {
|
|
369
|
+
pageUrl,
|
|
370
|
+
normalizedPageUrl,
|
|
371
|
+
availablePages: debugData.filter((p) => p.type === "page").map((p) => p.url),
|
|
372
|
+
});
|
|
291
373
|
return null;
|
|
292
374
|
}
|
|
293
375
|
catch (error) {
|
|
294
|
-
|
|
376
|
+
this.log("❌ Error getting page ID", {
|
|
377
|
+
error: error instanceof Error ? error.message : String(error),
|
|
378
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
379
|
+
});
|
|
295
380
|
return null;
|
|
296
381
|
}
|
|
297
382
|
}
|
|
298
383
|
async getDebugURLs() {
|
|
299
384
|
const url = `${this.CDP_CONNECT_URL}/json`;
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
385
|
+
this.log("📡 Fetching debug URLs", { url });
|
|
386
|
+
try {
|
|
387
|
+
const response = await fetch(url);
|
|
388
|
+
if (!response.ok) {
|
|
389
|
+
this.log("❌ Failed to fetch debug URLs", {
|
|
390
|
+
status: response.status,
|
|
391
|
+
statusText: response.statusText,
|
|
392
|
+
});
|
|
393
|
+
throw new Error("Error while fetching debug URL");
|
|
394
|
+
}
|
|
395
|
+
const data = await response.json();
|
|
396
|
+
this.log("✅ Debug URLs fetched successfully", {
|
|
397
|
+
count: data.length,
|
|
398
|
+
pages: data.map((p) => ({ id: p.id, type: p.type, url: p.url })),
|
|
399
|
+
});
|
|
400
|
+
return data;
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
this.log("❌ Exception while fetching debug URLs", {
|
|
404
|
+
error: error instanceof Error ? error.message : String(error),
|
|
405
|
+
});
|
|
406
|
+
throw error;
|
|
303
407
|
}
|
|
304
|
-
return response.json();
|
|
305
408
|
}
|
|
306
409
|
async syncState() {
|
|
307
410
|
try {
|
|
411
|
+
this.log("🔄 Starting state sync");
|
|
308
412
|
const state = await this.getState();
|
|
309
|
-
|
|
413
|
+
this.log("✅ State sync complete", {
|
|
414
|
+
pagesCount: state.pages.length,
|
|
415
|
+
selectedPageId: state.selectedPageId,
|
|
416
|
+
pages: state.pages.map((p) => ({ id: p.id, title: p.title, url: p.url })),
|
|
417
|
+
});
|
|
310
418
|
this.emit("BrowserService.stateSync", state);
|
|
311
419
|
}
|
|
312
420
|
catch (error) {
|
|
313
|
-
|
|
421
|
+
this.log("❌ Error syncing state", {
|
|
422
|
+
error: error instanceof Error ? error.message : String(error),
|
|
423
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
424
|
+
});
|
|
314
425
|
}
|
|
315
426
|
}
|
|
316
427
|
async getState() {
|
|
428
|
+
this.log("📊 Getting current state", {
|
|
429
|
+
internalPagesCount: this.pages.size,
|
|
430
|
+
internalPageIds: Array.from(this.pages.keys()),
|
|
431
|
+
selectedPageId: this._selectedPageId,
|
|
432
|
+
});
|
|
317
433
|
const debugData = await this.getDebugURLs();
|
|
318
|
-
|
|
434
|
+
this.log("📊 Debug data for state", {
|
|
435
|
+
debugPagesCount: debugData.length,
|
|
436
|
+
debugPages: debugData.map((p) => ({ id: p.id, type: p.type, url: p.url })),
|
|
437
|
+
});
|
|
319
438
|
const pagesData = [];
|
|
320
|
-
|
|
321
|
-
|
|
439
|
+
const updatedPages = new Map();
|
|
440
|
+
const matchedDebugIds = new Set(); // Track which CDP IDs we've already matched
|
|
441
|
+
let updatedSelectedPageId = this._selectedPageId;
|
|
442
|
+
for (const [oldId, page] of this.pages.entries()) {
|
|
443
|
+
this.log("🔍 Processing page from internal map", {
|
|
444
|
+
oldId,
|
|
445
|
+
url: page.url(),
|
|
446
|
+
});
|
|
447
|
+
// Try to get the current CDP target ID directly from the page
|
|
448
|
+
let currentId = null;
|
|
449
|
+
try {
|
|
450
|
+
const cdpSession = await page.context().newCDPSession(page);
|
|
451
|
+
const { targetInfo } = await cdpSession.send("Target.getTargetInfo");
|
|
452
|
+
await cdpSession.detach();
|
|
453
|
+
if (targetInfo && targetInfo.targetId) {
|
|
454
|
+
currentId = targetInfo.targetId;
|
|
455
|
+
this.log("✅ Got current target ID from CDP session", {
|
|
456
|
+
oldId,
|
|
457
|
+
currentId,
|
|
458
|
+
url: page.url(),
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
catch (cdpError) {
|
|
463
|
+
this.log("⚠️ Failed to get target ID from CDP session", {
|
|
464
|
+
oldId,
|
|
465
|
+
error: cdpError instanceof Error ? cdpError.message : String(cdpError),
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
// If we got the current ID from CDP session, use it
|
|
469
|
+
let debugInfo = currentId ? debugData.find((d) => d.id === currentId) : null;
|
|
470
|
+
// Fallback 1: Try to find by old ID
|
|
471
|
+
if (!debugInfo) {
|
|
472
|
+
debugInfo = debugData.find((d) => d.id === oldId && !matchedDebugIds.has(d.id));
|
|
473
|
+
}
|
|
474
|
+
// Fallback 2: Try to find by URL (only if not already matched)
|
|
475
|
+
if (!debugInfo) {
|
|
476
|
+
this.log("⚠️ Page ID not found in CDP, attempting to match by URL", {
|
|
477
|
+
oldId,
|
|
478
|
+
pageUrl: page.url(),
|
|
479
|
+
});
|
|
480
|
+
debugInfo = debugData.find((d) => d.type === "page" && d.url === page.url() && !matchedDebugIds.has(d.id));
|
|
481
|
+
if (debugInfo) {
|
|
482
|
+
this.log("✅ Found page by URL match, updating ID", {
|
|
483
|
+
oldId,
|
|
484
|
+
newId: debugInfo.id,
|
|
485
|
+
url: page.url(),
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
else {
|
|
490
|
+
this.log("✅ Found matching debug info by ID", {
|
|
491
|
+
id: debugInfo.id,
|
|
492
|
+
debugUrl: debugInfo.url,
|
|
493
|
+
pageUrl: page.url(),
|
|
494
|
+
});
|
|
495
|
+
}
|
|
322
496
|
if (debugInfo) {
|
|
497
|
+
// Mark this CDP ID as matched to avoid duplicate matches
|
|
498
|
+
matchedDebugIds.add(debugInfo.id);
|
|
499
|
+
// Update selected page ID if this was the selected page and ID changed
|
|
500
|
+
if (oldId === this._selectedPageId && oldId !== debugInfo.id) {
|
|
501
|
+
updatedSelectedPageId = debugInfo.id;
|
|
502
|
+
this.log("🔄 Updated selected page ID", {
|
|
503
|
+
oldId,
|
|
504
|
+
newId: debugInfo.id,
|
|
505
|
+
});
|
|
506
|
+
}
|
|
323
507
|
try {
|
|
324
|
-
|
|
325
|
-
id,
|
|
508
|
+
const pageData = {
|
|
509
|
+
id: debugInfo.id,
|
|
326
510
|
title: await page.title(),
|
|
327
511
|
url: page.url(),
|
|
328
512
|
wsDebuggerUrl: debugInfo.webSocketDebuggerUrl || "",
|
|
329
|
-
}
|
|
513
|
+
};
|
|
514
|
+
pagesData.push(pageData);
|
|
515
|
+
updatedPages.set(debugInfo.id, page);
|
|
516
|
+
this.log("✅ Page added to state", pageData);
|
|
330
517
|
}
|
|
331
518
|
catch (error) {
|
|
332
|
-
|
|
519
|
+
this.log("❌ Error getting page data", {
|
|
520
|
+
id: oldId,
|
|
521
|
+
error: error instanceof Error ? error.message : String(error),
|
|
522
|
+
});
|
|
333
523
|
}
|
|
334
524
|
}
|
|
525
|
+
else {
|
|
526
|
+
this.log("⚠️ No matching debug info found by ID or URL", {
|
|
527
|
+
oldId,
|
|
528
|
+
pageUrl: page.url(),
|
|
529
|
+
availableDebugIds: debugData.map((d) => d.id),
|
|
530
|
+
availableDebugUrls: debugData.map((d) => d.url),
|
|
531
|
+
});
|
|
532
|
+
}
|
|
335
533
|
}
|
|
336
|
-
|
|
534
|
+
// Update the internal pages map with current CDP IDs
|
|
535
|
+
if (updatedPages.size !== this.pages.size || updatedSelectedPageId !== this._selectedPageId) {
|
|
536
|
+
this.log("🔄 Updating internal state with new CDP IDs", {
|
|
537
|
+
oldPagesCount: this.pages.size,
|
|
538
|
+
newPagesCount: updatedPages.size,
|
|
539
|
+
oldSelectedId: this._selectedPageId,
|
|
540
|
+
newSelectedId: updatedSelectedPageId,
|
|
541
|
+
});
|
|
542
|
+
this.pages = updatedPages;
|
|
543
|
+
this._selectedPageId = updatedSelectedPageId;
|
|
544
|
+
}
|
|
545
|
+
const state = {
|
|
337
546
|
pages: pagesData,
|
|
338
547
|
selectedPageId: this._selectedPageId,
|
|
339
548
|
};
|
|
549
|
+
this.log("📦 Final state", state);
|
|
550
|
+
return state;
|
|
340
551
|
}
|
|
341
552
|
async createTab(url = "about:blank") {
|
|
342
553
|
try {
|
|
343
|
-
|
|
554
|
+
this.log("🆕 Creating new tab", { url });
|
|
344
555
|
const page = await this.context.newPage();
|
|
556
|
+
this.log("✅ New page created by Playwright", { url: page.url() });
|
|
345
557
|
if (typeof url === "string" && url !== "about:blank") {
|
|
558
|
+
this.log("🌐 Navigating to URL", { url });
|
|
346
559
|
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
560
|
+
this.log("✅ Navigation complete", { finalUrl: page.url() });
|
|
347
561
|
}
|
|
348
|
-
// Wait
|
|
349
|
-
|
|
562
|
+
// Wait for CDP to register the page
|
|
563
|
+
this.log("⏳ Waiting for CDP registration...");
|
|
564
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
350
565
|
const id = await this.getPageId(page);
|
|
566
|
+
this.log("🔍 Retrieved page ID after wait", { id, url: page.url() });
|
|
351
567
|
if (id) {
|
|
352
568
|
this.pages.set(id, page);
|
|
353
569
|
this._selectedPageId = id;
|
|
354
|
-
|
|
570
|
+
this.log("✅ Tab created successfully", {
|
|
571
|
+
id,
|
|
572
|
+
url: page.url(),
|
|
573
|
+
totalPages: this.pages.size,
|
|
574
|
+
allPageIds: Array.from(this.pages.keys()),
|
|
575
|
+
selectedPageId: this._selectedPageId,
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
else {
|
|
579
|
+
this.log("❌ Failed to get page ID for new tab", { url: page.url() });
|
|
580
|
+
// Try to get debug data to see what's available
|
|
581
|
+
const debugData = await this.getDebugURLs();
|
|
582
|
+
this.log("🔍 Current CDP state after failed ID retrieval", {
|
|
583
|
+
debugPages: debugData.map((p) => ({ id: p.id, url: p.url, type: p.type })),
|
|
584
|
+
});
|
|
355
585
|
}
|
|
356
586
|
await this.syncState();
|
|
357
587
|
}
|
|
358
588
|
catch (error) {
|
|
359
|
-
|
|
589
|
+
this.log("❌ Error creating tab", {
|
|
590
|
+
url,
|
|
591
|
+
error: error instanceof Error ? error.message : String(error),
|
|
592
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
593
|
+
});
|
|
360
594
|
throw error;
|
|
361
595
|
}
|
|
362
596
|
}
|
|
363
597
|
async closeTab(pageId) {
|
|
364
598
|
try {
|
|
365
|
-
|
|
599
|
+
this.log("🗑️ Closing tab", { pageId });
|
|
366
600
|
const page = this.pages.get(pageId);
|
|
367
601
|
if (page) {
|
|
602
|
+
this.log("✅ Found page to close", { pageId, url: page.url() });
|
|
368
603
|
await page.close();
|
|
369
|
-
|
|
604
|
+
this.log("✅ Page closed successfully", { pageId });
|
|
370
605
|
}
|
|
371
606
|
else {
|
|
372
|
-
|
|
607
|
+
this.log("⚠️ Page not found", {
|
|
608
|
+
pageId,
|
|
609
|
+
availablePageIds: Array.from(this.pages.keys()),
|
|
610
|
+
});
|
|
373
611
|
}
|
|
374
612
|
}
|
|
375
613
|
catch (error) {
|
|
376
|
-
|
|
614
|
+
this.log("❌ Error closing tab", {
|
|
615
|
+
pageId,
|
|
616
|
+
error: error instanceof Error ? error.message : String(error),
|
|
617
|
+
});
|
|
377
618
|
throw error;
|
|
378
619
|
}
|
|
379
620
|
}
|
|
380
621
|
async selectTab(pageId) {
|
|
381
622
|
try {
|
|
382
|
-
|
|
623
|
+
this.log("🎯 Selecting tab", { pageId });
|
|
383
624
|
const page = this.pages.get(pageId);
|
|
384
625
|
if (page) {
|
|
385
626
|
this._selectedPageId = pageId;
|
|
386
627
|
await page.bringToFront();
|
|
628
|
+
this.log("✅ Tab selected successfully", {
|
|
629
|
+
pageId,
|
|
630
|
+
url: page.url(),
|
|
631
|
+
selectedPageId: this._selectedPageId,
|
|
632
|
+
});
|
|
387
633
|
await this.syncState();
|
|
388
634
|
}
|
|
389
635
|
else {
|
|
390
|
-
|
|
636
|
+
this.log("⚠️ Page not found for selection", {
|
|
637
|
+
pageId,
|
|
638
|
+
availablePageIds: Array.from(this.pages.keys()),
|
|
639
|
+
});
|
|
391
640
|
}
|
|
392
641
|
}
|
|
393
642
|
catch (error) {
|
|
394
|
-
|
|
643
|
+
this.log("❌ Error selecting tab", {
|
|
644
|
+
pageId,
|
|
645
|
+
error: error instanceof Error ? error.message : String(error),
|
|
646
|
+
});
|
|
395
647
|
throw error;
|
|
396
648
|
}
|
|
397
649
|
}
|
|
398
650
|
getSelectedPage() {
|
|
399
|
-
|
|
651
|
+
const page = this._selectedPageId ? this.pages.get(this._selectedPageId) || null : null;
|
|
652
|
+
this.log("🔍 Getting selected page", {
|
|
653
|
+
selectedPageId: this._selectedPageId,
|
|
654
|
+
found: !!page,
|
|
655
|
+
url: page?.url(),
|
|
656
|
+
});
|
|
657
|
+
return page;
|
|
400
658
|
}
|
|
401
659
|
}
|