@flrande/bak-extension 0.3.4 → 0.3.6
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/.bak-e2e-build-stamp +1 -1
- package/dist/background.global.js +121 -8
- package/package.json +2 -2
- package/src/background.ts +47 -7
- package/src/workspace.ts +111 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
2026-03-
|
|
1
|
+
2026-03-09T12:16:27.259Z
|
|
@@ -96,6 +96,16 @@
|
|
|
96
96
|
repairActions.push("pruned-missing-tabs");
|
|
97
97
|
}
|
|
98
98
|
state.tabIds = tabs.map((tab) => tab.id);
|
|
99
|
+
if (state.windowId !== null) {
|
|
100
|
+
const ownership = await this.inspectWorkspaceWindowOwnership(state, state.windowId);
|
|
101
|
+
if (ownership.foreignTabs.length > 0) {
|
|
102
|
+
const migrated = await this.moveWorkspaceIntoDedicatedWindow(state, ownership, initialUrl);
|
|
103
|
+
window = migrated.window;
|
|
104
|
+
tabs = migrated.tabs;
|
|
105
|
+
state.tabIds = tabs.map((tab) => tab.id);
|
|
106
|
+
repairActions.push("migrated-dirty-window");
|
|
107
|
+
}
|
|
108
|
+
}
|
|
99
109
|
if (tabs.length === 0) {
|
|
100
110
|
const primary = await this.createWorkspaceTab({
|
|
101
111
|
windowId: state.windowId,
|
|
@@ -189,7 +199,7 @@
|
|
|
189
199
|
const desiredUrl = options.url ?? DEFAULT_WORKSPACE_URL;
|
|
190
200
|
let reusablePrimaryTab = await this.resolveReusablePrimaryTab(
|
|
191
201
|
state,
|
|
192
|
-
ensured.created || ensured.repairActions.includes("recreated-window") || ensured.repairActions.includes("created-primary-tab")
|
|
202
|
+
ensured.created || ensured.repairActions.includes("recreated-window") || ensured.repairActions.includes("created-primary-tab") || ensured.repairActions.includes("migrated-dirty-window")
|
|
193
203
|
);
|
|
194
204
|
let createdTab;
|
|
195
205
|
try {
|
|
@@ -527,6 +537,79 @@
|
|
|
527
537
|
}
|
|
528
538
|
return null;
|
|
529
539
|
}
|
|
540
|
+
async inspectWorkspaceWindowOwnership(state, windowId) {
|
|
541
|
+
const windowTabs = await this.waitForWindowTabs(windowId, 500);
|
|
542
|
+
const trackedIds = new Set(this.collectCandidateTabIds(state));
|
|
543
|
+
return {
|
|
544
|
+
workspaceTabs: windowTabs.filter((tab) => trackedIds.has(tab.id) || state.groupId !== null && tab.groupId === state.groupId),
|
|
545
|
+
foreignTabs: windowTabs.filter((tab) => !trackedIds.has(tab.id) && (state.groupId === null || tab.groupId !== state.groupId))
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
async moveWorkspaceIntoDedicatedWindow(state, ownership, initialUrl) {
|
|
549
|
+
const sourceTabs = this.orderWorkspaceTabsForMigration(state, ownership.workspaceTabs);
|
|
550
|
+
const seedUrl = sourceTabs[0]?.url ?? initialUrl;
|
|
551
|
+
const window = await this.browser.createWindow({
|
|
552
|
+
url: seedUrl || DEFAULT_WORKSPACE_URL,
|
|
553
|
+
focused: false
|
|
554
|
+
});
|
|
555
|
+
const recreatedTabs = await this.waitForWindowTabs(window.id);
|
|
556
|
+
const firstTab = recreatedTabs[0] ?? null;
|
|
557
|
+
const tabIdMap = /* @__PURE__ */ new Map();
|
|
558
|
+
if (sourceTabs[0] && firstTab) {
|
|
559
|
+
tabIdMap.set(sourceTabs[0].id, firstTab.id);
|
|
560
|
+
}
|
|
561
|
+
for (const sourceTab of sourceTabs.slice(1)) {
|
|
562
|
+
const recreated = await this.createWorkspaceTab({
|
|
563
|
+
windowId: window.id,
|
|
564
|
+
url: sourceTab.url,
|
|
565
|
+
active: false
|
|
566
|
+
});
|
|
567
|
+
recreatedTabs.push(recreated);
|
|
568
|
+
tabIdMap.set(sourceTab.id, recreated.id);
|
|
569
|
+
}
|
|
570
|
+
const nextPrimaryTabId = (state.primaryTabId !== null ? tabIdMap.get(state.primaryTabId) : void 0) ?? firstTab?.id ?? recreatedTabs[0]?.id ?? null;
|
|
571
|
+
const nextActiveTabId = (state.activeTabId !== null ? tabIdMap.get(state.activeTabId) : void 0) ?? nextPrimaryTabId ?? recreatedTabs[0]?.id ?? null;
|
|
572
|
+
if (nextActiveTabId !== null) {
|
|
573
|
+
await this.browser.updateTab(nextActiveTabId, { active: true });
|
|
574
|
+
}
|
|
575
|
+
state.windowId = window.id;
|
|
576
|
+
state.groupId = null;
|
|
577
|
+
state.tabIds = recreatedTabs.map((tab) => tab.id);
|
|
578
|
+
state.primaryTabId = nextPrimaryTabId;
|
|
579
|
+
state.activeTabId = nextActiveTabId;
|
|
580
|
+
for (const workspaceTab of ownership.workspaceTabs) {
|
|
581
|
+
await this.browser.closeTab(workspaceTab.id);
|
|
582
|
+
}
|
|
583
|
+
return {
|
|
584
|
+
window,
|
|
585
|
+
tabs: await this.readTrackedTabs(state.tabIds, state.windowId)
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
orderWorkspaceTabsForMigration(state, tabs) {
|
|
589
|
+
const ordered = [];
|
|
590
|
+
const seen = /* @__PURE__ */ new Set();
|
|
591
|
+
const pushById = (tabId) => {
|
|
592
|
+
if (typeof tabId !== "number") {
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
const tab = tabs.find((candidate) => candidate.id === tabId);
|
|
596
|
+
if (!tab || seen.has(tab.id)) {
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
ordered.push(tab);
|
|
600
|
+
seen.add(tab.id);
|
|
601
|
+
};
|
|
602
|
+
pushById(state.primaryTabId);
|
|
603
|
+
pushById(state.activeTabId);
|
|
604
|
+
for (const tab of tabs) {
|
|
605
|
+
if (seen.has(tab.id)) {
|
|
606
|
+
continue;
|
|
607
|
+
}
|
|
608
|
+
ordered.push(tab);
|
|
609
|
+
seen.add(tab.id);
|
|
610
|
+
}
|
|
611
|
+
return ordered;
|
|
612
|
+
}
|
|
530
613
|
async recoverWorkspaceTabs(state, existingTabs) {
|
|
531
614
|
if (state.windowId === null) {
|
|
532
615
|
return existingTabs;
|
|
@@ -980,6 +1063,32 @@
|
|
|
980
1063
|
}
|
|
981
1064
|
throw new Error(`tab url timeout: ${tabId} -> ${expectedUrl}`);
|
|
982
1065
|
}
|
|
1066
|
+
async function finalizeOpenedWorkspaceTab(opened, expectedUrl) {
|
|
1067
|
+
if (expectedUrl && expectedUrl !== "about:blank") {
|
|
1068
|
+
await waitForTabUrl(opened.tab.id, expectedUrl).catch(() => void 0);
|
|
1069
|
+
}
|
|
1070
|
+
let refreshedTab = opened.tab;
|
|
1071
|
+
try {
|
|
1072
|
+
const rawTab = await chrome.tabs.get(opened.tab.id);
|
|
1073
|
+
const pendingUrl = "pendingUrl" in rawTab && typeof rawTab.pendingUrl === "string" ? rawTab.pendingUrl : "";
|
|
1074
|
+
const currentUrl = rawTab.url ?? "";
|
|
1075
|
+
const effectiveUrl = currentUrl && currentUrl !== "about:blank" ? currentUrl : pendingUrl && pendingUrl !== "about:blank" ? pendingUrl : currentUrl || pendingUrl || opened.tab.url;
|
|
1076
|
+
refreshedTab = {
|
|
1077
|
+
...toTabInfo(rawTab),
|
|
1078
|
+
url: effectiveUrl
|
|
1079
|
+
};
|
|
1080
|
+
} catch {
|
|
1081
|
+
refreshedTab = await workspaceBrowser.getTab(opened.tab.id) ?? opened.tab;
|
|
1082
|
+
}
|
|
1083
|
+
const refreshedWorkspace = await workspaceManager.getWorkspaceInfo(opened.workspace.id) ?? {
|
|
1084
|
+
...opened.workspace,
|
|
1085
|
+
tabs: opened.workspace.tabs.map((tab) => tab.id === refreshedTab.id ? refreshedTab : tab)
|
|
1086
|
+
};
|
|
1087
|
+
return {
|
|
1088
|
+
workspace: refreshedWorkspace,
|
|
1089
|
+
tab: refreshedTab
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
983
1092
|
async function withTab(target = {}, options = {}) {
|
|
984
1093
|
const requireSupportedAutomationUrl = options.requireSupportedAutomationUrl !== false;
|
|
985
1094
|
const validate = (tab2) => {
|
|
@@ -1179,19 +1288,21 @@
|
|
|
1179
1288
|
}
|
|
1180
1289
|
case "tabs.new": {
|
|
1181
1290
|
if (typeof params.workspaceId === "string" || params.windowId === void 0) {
|
|
1291
|
+
const expectedUrl = params.url ?? "about:blank";
|
|
1182
1292
|
const opened = await preserveHumanFocus(true, async () => {
|
|
1183
1293
|
return await workspaceManager.openTab({
|
|
1184
1294
|
workspaceId: typeof params.workspaceId === "string" ? params.workspaceId : DEFAULT_WORKSPACE_ID,
|
|
1185
|
-
url:
|
|
1295
|
+
url: expectedUrl,
|
|
1186
1296
|
active: params.active === true,
|
|
1187
1297
|
focus: false
|
|
1188
1298
|
});
|
|
1189
1299
|
});
|
|
1300
|
+
const stabilized = await finalizeOpenedWorkspaceTab(opened, expectedUrl);
|
|
1190
1301
|
return {
|
|
1191
|
-
tabId:
|
|
1192
|
-
windowId:
|
|
1193
|
-
groupId:
|
|
1194
|
-
workspaceId:
|
|
1302
|
+
tabId: stabilized.tab.id,
|
|
1303
|
+
windowId: stabilized.tab.windowId,
|
|
1304
|
+
groupId: stabilized.workspace.groupId,
|
|
1305
|
+
workspaceId: stabilized.workspace.id
|
|
1195
1306
|
};
|
|
1196
1307
|
}
|
|
1197
1308
|
const tab = await chrome.tabs.create({
|
|
@@ -1232,14 +1343,16 @@
|
|
|
1232
1343
|
};
|
|
1233
1344
|
}
|
|
1234
1345
|
case "workspace.openTab": {
|
|
1235
|
-
|
|
1346
|
+
const expectedUrl = typeof params.url === "string" ? params.url : void 0;
|
|
1347
|
+
const opened = await preserveHumanFocus(params.focus !== true, async () => {
|
|
1236
1348
|
return await workspaceManager.openTab({
|
|
1237
1349
|
workspaceId: typeof params.workspaceId === "string" ? params.workspaceId : void 0,
|
|
1238
|
-
url:
|
|
1350
|
+
url: expectedUrl,
|
|
1239
1351
|
active: params.active === true,
|
|
1240
1352
|
focus: params.focus === true
|
|
1241
1353
|
});
|
|
1242
1354
|
});
|
|
1355
|
+
return await finalizeOpenedWorkspaceTab(opened, expectedUrl);
|
|
1243
1356
|
}
|
|
1244
1357
|
case "workspace.listTabs": {
|
|
1245
1358
|
return await workspaceManager.listTabs(typeof params.workspaceId === "string" ? params.workspaceId : void 0);
|
package/package.json
CHANGED
package/src/background.ts
CHANGED
|
@@ -390,6 +390,42 @@ async function waitForTabUrl(tabId: number, expectedUrl: string, timeoutMs = 10_
|
|
|
390
390
|
throw new Error(`tab url timeout: ${tabId} -> ${expectedUrl}`);
|
|
391
391
|
}
|
|
392
392
|
|
|
393
|
+
async function finalizeOpenedWorkspaceTab(
|
|
394
|
+
opened: Awaited<ReturnType<WorkspaceManager['openTab']>>,
|
|
395
|
+
expectedUrl?: string
|
|
396
|
+
): Promise<Awaited<ReturnType<WorkspaceManager['openTab']>>> {
|
|
397
|
+
if (expectedUrl && expectedUrl !== 'about:blank') {
|
|
398
|
+
await waitForTabUrl(opened.tab.id, expectedUrl).catch(() => undefined);
|
|
399
|
+
}
|
|
400
|
+
let refreshedTab = opened.tab;
|
|
401
|
+
try {
|
|
402
|
+
const rawTab = await chrome.tabs.get(opened.tab.id);
|
|
403
|
+
const pendingUrl = 'pendingUrl' in rawTab && typeof rawTab.pendingUrl === 'string' ? rawTab.pendingUrl : '';
|
|
404
|
+
const currentUrl = rawTab.url ?? '';
|
|
405
|
+
const effectiveUrl =
|
|
406
|
+
currentUrl && currentUrl !== 'about:blank'
|
|
407
|
+
? currentUrl
|
|
408
|
+
: pendingUrl && pendingUrl !== 'about:blank'
|
|
409
|
+
? pendingUrl
|
|
410
|
+
: currentUrl || pendingUrl || opened.tab.url;
|
|
411
|
+
refreshedTab = {
|
|
412
|
+
...toTabInfo(rawTab),
|
|
413
|
+
url: effectiveUrl
|
|
414
|
+
};
|
|
415
|
+
} catch {
|
|
416
|
+
refreshedTab = (await workspaceBrowser.getTab(opened.tab.id)) ?? opened.tab;
|
|
417
|
+
}
|
|
418
|
+
const refreshedWorkspace = (await workspaceManager.getWorkspaceInfo(opened.workspace.id)) ?? {
|
|
419
|
+
...opened.workspace,
|
|
420
|
+
tabs: opened.workspace.tabs.map((tab) => (tab.id === refreshedTab.id ? refreshedTab : tab))
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
return {
|
|
424
|
+
workspace: refreshedWorkspace,
|
|
425
|
+
tab: refreshedTab
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
|
|
393
429
|
interface WithTabOptions {
|
|
394
430
|
requireSupportedAutomationUrl?: boolean;
|
|
395
431
|
}
|
|
@@ -634,19 +670,21 @@ async function handleRequest(request: CliRequest): Promise<unknown> {
|
|
|
634
670
|
}
|
|
635
671
|
case 'tabs.new': {
|
|
636
672
|
if (typeof params.workspaceId === 'string' || params.windowId === undefined) {
|
|
673
|
+
const expectedUrl = (params.url as string | undefined) ?? 'about:blank';
|
|
637
674
|
const opened = await preserveHumanFocus(true, async () => {
|
|
638
675
|
return await workspaceManager.openTab({
|
|
639
676
|
workspaceId: typeof params.workspaceId === 'string' ? params.workspaceId : DEFAULT_WORKSPACE_ID,
|
|
640
|
-
url:
|
|
677
|
+
url: expectedUrl,
|
|
641
678
|
active: params.active === true,
|
|
642
679
|
focus: false
|
|
643
680
|
});
|
|
644
681
|
});
|
|
682
|
+
const stabilized = await finalizeOpenedWorkspaceTab(opened, expectedUrl);
|
|
645
683
|
return {
|
|
646
|
-
tabId:
|
|
647
|
-
windowId:
|
|
648
|
-
groupId:
|
|
649
|
-
workspaceId:
|
|
684
|
+
tabId: stabilized.tab.id,
|
|
685
|
+
windowId: stabilized.tab.windowId,
|
|
686
|
+
groupId: stabilized.workspace.groupId,
|
|
687
|
+
workspaceId: stabilized.workspace.id
|
|
650
688
|
};
|
|
651
689
|
}
|
|
652
690
|
const tab = await chrome.tabs.create({
|
|
@@ -687,14 +725,16 @@ async function handleRequest(request: CliRequest): Promise<unknown> {
|
|
|
687
725
|
};
|
|
688
726
|
}
|
|
689
727
|
case 'workspace.openTab': {
|
|
690
|
-
|
|
728
|
+
const expectedUrl = typeof params.url === 'string' ? params.url : undefined;
|
|
729
|
+
const opened = await preserveHumanFocus(params.focus !== true, async () => {
|
|
691
730
|
return await workspaceManager.openTab({
|
|
692
731
|
workspaceId: typeof params.workspaceId === 'string' ? params.workspaceId : undefined,
|
|
693
|
-
url:
|
|
732
|
+
url: expectedUrl,
|
|
694
733
|
active: params.active === true,
|
|
695
734
|
focus: params.focus === true
|
|
696
735
|
});
|
|
697
736
|
});
|
|
737
|
+
return await finalizeOpenedWorkspaceTab(opened, expectedUrl);
|
|
698
738
|
}
|
|
699
739
|
case 'workspace.listTabs': {
|
|
700
740
|
return await workspaceManager.listTabs(typeof params.workspaceId === 'string' ? params.workspaceId : undefined);
|
package/src/workspace.ts
CHANGED
|
@@ -79,6 +79,11 @@ export interface WorkspaceBrowser {
|
|
|
79
79
|
updateGroup(groupId: number, options: { title?: string; color?: WorkspaceColor; collapsed?: boolean }): Promise<WorkspaceGroup>;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
interface WorkspaceWindowOwnership {
|
|
83
|
+
workspaceTabs: WorkspaceTab[];
|
|
84
|
+
foreignTabs: WorkspaceTab[];
|
|
85
|
+
}
|
|
86
|
+
|
|
82
87
|
export interface WorkspaceEnsureOptions {
|
|
83
88
|
workspaceId?: string;
|
|
84
89
|
focus?: boolean;
|
|
@@ -165,6 +170,17 @@ export class WorkspaceManager {
|
|
|
165
170
|
}
|
|
166
171
|
state.tabIds = tabs.map((tab) => tab.id);
|
|
167
172
|
|
|
173
|
+
if (state.windowId !== null) {
|
|
174
|
+
const ownership = await this.inspectWorkspaceWindowOwnership(state, state.windowId);
|
|
175
|
+
if (ownership.foreignTabs.length > 0) {
|
|
176
|
+
const migrated = await this.moveWorkspaceIntoDedicatedWindow(state, ownership, initialUrl);
|
|
177
|
+
window = migrated.window;
|
|
178
|
+
tabs = migrated.tabs;
|
|
179
|
+
state.tabIds = tabs.map((tab) => tab.id);
|
|
180
|
+
repairActions.push('migrated-dirty-window');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
168
184
|
if (tabs.length === 0) {
|
|
169
185
|
const primary = await this.createWorkspaceTab({
|
|
170
186
|
windowId: state.windowId,
|
|
@@ -267,7 +283,10 @@ export class WorkspaceManager {
|
|
|
267
283
|
const desiredUrl = options.url ?? DEFAULT_WORKSPACE_URL;
|
|
268
284
|
let reusablePrimaryTab = await this.resolveReusablePrimaryTab(
|
|
269
285
|
state,
|
|
270
|
-
ensured.created ||
|
|
286
|
+
ensured.created ||
|
|
287
|
+
ensured.repairActions.includes('recreated-window') ||
|
|
288
|
+
ensured.repairActions.includes('created-primary-tab') ||
|
|
289
|
+
ensured.repairActions.includes('migrated-dirty-window')
|
|
271
290
|
);
|
|
272
291
|
|
|
273
292
|
let createdTab: WorkspaceTab;
|
|
@@ -647,6 +666,97 @@ export class WorkspaceManager {
|
|
|
647
666
|
return null;
|
|
648
667
|
}
|
|
649
668
|
|
|
669
|
+
private async inspectWorkspaceWindowOwnership(state: WorkspaceRecord, windowId: number): Promise<WorkspaceWindowOwnership> {
|
|
670
|
+
const windowTabs = await this.waitForWindowTabs(windowId, 500);
|
|
671
|
+
const trackedIds = new Set(this.collectCandidateTabIds(state));
|
|
672
|
+
return {
|
|
673
|
+
workspaceTabs: windowTabs.filter((tab) => trackedIds.has(tab.id) || (state.groupId !== null && tab.groupId === state.groupId)),
|
|
674
|
+
foreignTabs: windowTabs.filter((tab) => !trackedIds.has(tab.id) && (state.groupId === null || tab.groupId !== state.groupId))
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
private async moveWorkspaceIntoDedicatedWindow(
|
|
679
|
+
state: WorkspaceRecord,
|
|
680
|
+
ownership: WorkspaceWindowOwnership,
|
|
681
|
+
initialUrl: string
|
|
682
|
+
): Promise<{ window: WorkspaceWindow; tabs: WorkspaceTab[] }> {
|
|
683
|
+
const sourceTabs = this.orderWorkspaceTabsForMigration(state, ownership.workspaceTabs);
|
|
684
|
+
const seedUrl = sourceTabs[0]?.url ?? initialUrl;
|
|
685
|
+
const window = await this.browser.createWindow({
|
|
686
|
+
url: seedUrl || DEFAULT_WORKSPACE_URL,
|
|
687
|
+
focused: false
|
|
688
|
+
});
|
|
689
|
+
const recreatedTabs = await this.waitForWindowTabs(window.id);
|
|
690
|
+
const firstTab = recreatedTabs[0] ?? null;
|
|
691
|
+
const tabIdMap = new Map<number, number>();
|
|
692
|
+
if (sourceTabs[0] && firstTab) {
|
|
693
|
+
tabIdMap.set(sourceTabs[0].id, firstTab.id);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
for (const sourceTab of sourceTabs.slice(1)) {
|
|
697
|
+
const recreated = await this.createWorkspaceTab({
|
|
698
|
+
windowId: window.id,
|
|
699
|
+
url: sourceTab.url,
|
|
700
|
+
active: false
|
|
701
|
+
});
|
|
702
|
+
recreatedTabs.push(recreated);
|
|
703
|
+
tabIdMap.set(sourceTab.id, recreated.id);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
const nextPrimaryTabId =
|
|
707
|
+
(state.primaryTabId !== null ? tabIdMap.get(state.primaryTabId) : undefined) ??
|
|
708
|
+
firstTab?.id ??
|
|
709
|
+
recreatedTabs[0]?.id ??
|
|
710
|
+
null;
|
|
711
|
+
const nextActiveTabId =
|
|
712
|
+
(state.activeTabId !== null ? tabIdMap.get(state.activeTabId) : undefined) ?? nextPrimaryTabId ?? recreatedTabs[0]?.id ?? null;
|
|
713
|
+
if (nextActiveTabId !== null) {
|
|
714
|
+
await this.browser.updateTab(nextActiveTabId, { active: true });
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
state.windowId = window.id;
|
|
718
|
+
state.groupId = null;
|
|
719
|
+
state.tabIds = recreatedTabs.map((tab) => tab.id);
|
|
720
|
+
state.primaryTabId = nextPrimaryTabId;
|
|
721
|
+
state.activeTabId = nextActiveTabId;
|
|
722
|
+
|
|
723
|
+
for (const workspaceTab of ownership.workspaceTabs) {
|
|
724
|
+
await this.browser.closeTab(workspaceTab.id);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
return {
|
|
728
|
+
window,
|
|
729
|
+
tabs: await this.readTrackedTabs(state.tabIds, state.windowId)
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
private orderWorkspaceTabsForMigration(state: WorkspaceRecord, tabs: WorkspaceTab[]): WorkspaceTab[] {
|
|
734
|
+
const ordered: WorkspaceTab[] = [];
|
|
735
|
+
const seen = new Set<number>();
|
|
736
|
+
const pushById = (tabId: number | null): void => {
|
|
737
|
+
if (typeof tabId !== 'number') {
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
const tab = tabs.find((candidate) => candidate.id === tabId);
|
|
741
|
+
if (!tab || seen.has(tab.id)) {
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
ordered.push(tab);
|
|
745
|
+
seen.add(tab.id);
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
pushById(state.primaryTabId);
|
|
749
|
+
pushById(state.activeTabId);
|
|
750
|
+
for (const tab of tabs) {
|
|
751
|
+
if (seen.has(tab.id)) {
|
|
752
|
+
continue;
|
|
753
|
+
}
|
|
754
|
+
ordered.push(tab);
|
|
755
|
+
seen.add(tab.id);
|
|
756
|
+
}
|
|
757
|
+
return ordered;
|
|
758
|
+
}
|
|
759
|
+
|
|
650
760
|
private async recoverWorkspaceTabs(state: WorkspaceRecord, existingTabs: WorkspaceTab[]): Promise<WorkspaceTab[]> {
|
|
651
761
|
if (state.windowId === null) {
|
|
652
762
|
return existingTabs;
|