@flrande/bak-extension 0.3.1 → 0.3.2
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 +74 -1
- package/package.json +2 -2
- package/src/workspace.ts +83 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
2026-03-09T04:
|
|
1
|
+
2026-03-09T04:50:59.948Z
|
|
@@ -52,8 +52,19 @@
|
|
|
52
52
|
const persisted = await this.storage.load();
|
|
53
53
|
const created = !persisted;
|
|
54
54
|
let state = this.normalizeState(persisted, workspaceId);
|
|
55
|
+
const originalWindowId = state.windowId;
|
|
55
56
|
let window = state.windowId !== null ? await this.waitForWindow(state.windowId) : null;
|
|
56
57
|
let tabs = [];
|
|
58
|
+
if (!window) {
|
|
59
|
+
const rebound = await this.rebindWorkspaceWindow(state);
|
|
60
|
+
if (rebound) {
|
|
61
|
+
window = rebound.window;
|
|
62
|
+
tabs = rebound.tabs;
|
|
63
|
+
if (originalWindowId !== rebound.window.id) {
|
|
64
|
+
repairActions.push("rebound-window");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
57
68
|
if (!window) {
|
|
58
69
|
const createdWindow = await this.browser.createWindow({
|
|
59
70
|
url: initialUrl,
|
|
@@ -163,7 +174,15 @@
|
|
|
163
174
|
focus: false,
|
|
164
175
|
initialUrl: options.url ?? DEFAULT_WORKSPACE_URL
|
|
165
176
|
});
|
|
166
|
-
let state = { ...ensured.workspace };
|
|
177
|
+
let state = { ...ensured.workspace, tabIds: [...ensured.workspace.tabIds], tabs: [...ensured.workspace.tabs] };
|
|
178
|
+
if (state.windowId !== null && state.tabs.length === 0) {
|
|
179
|
+
const rebound = await this.rebindWorkspaceWindow(state);
|
|
180
|
+
if (rebound) {
|
|
181
|
+
state.windowId = rebound.window.id;
|
|
182
|
+
state.tabs = rebound.tabs;
|
|
183
|
+
state.tabIds = [...new Set(rebound.tabs.map((tab2) => tab2.id))];
|
|
184
|
+
}
|
|
185
|
+
}
|
|
167
186
|
const active = options.active === true;
|
|
168
187
|
const desiredUrl = options.url ?? DEFAULT_WORKSPACE_URL;
|
|
169
188
|
let reusablePrimaryTab = await this.resolveReusablePrimaryTab(
|
|
@@ -452,6 +471,60 @@
|
|
|
452
471
|
)).filter((tab) => tab !== null);
|
|
453
472
|
return tabs;
|
|
454
473
|
}
|
|
474
|
+
async readLooseTrackedTabs(tabIds) {
|
|
475
|
+
const tabs = (await Promise.all(
|
|
476
|
+
tabIds.map(async (tabId) => {
|
|
477
|
+
return await this.browser.getTab(tabId);
|
|
478
|
+
})
|
|
479
|
+
)).filter((tab) => tab !== null);
|
|
480
|
+
return tabs;
|
|
481
|
+
}
|
|
482
|
+
collectCandidateTabIds(state) {
|
|
483
|
+
return [...new Set(state.tabIds.concat([state.activeTabId, state.primaryTabId].filter((value) => typeof value === "number")))];
|
|
484
|
+
}
|
|
485
|
+
async rebindWorkspaceWindow(state) {
|
|
486
|
+
const candidateWindowIds = [];
|
|
487
|
+
const pushWindowId = (windowId) => {
|
|
488
|
+
if (typeof windowId !== "number") {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
if (!candidateWindowIds.includes(windowId)) {
|
|
492
|
+
candidateWindowIds.push(windowId);
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
const group = state.groupId !== null ? await this.browser.getGroup(state.groupId) : null;
|
|
496
|
+
pushWindowId(group?.windowId);
|
|
497
|
+
const trackedTabs = await this.readLooseTrackedTabs(this.collectCandidateTabIds(state));
|
|
498
|
+
for (const tab of trackedTabs) {
|
|
499
|
+
pushWindowId(tab.windowId);
|
|
500
|
+
}
|
|
501
|
+
for (const candidateWindowId of candidateWindowIds) {
|
|
502
|
+
const window = await this.waitForWindow(candidateWindowId);
|
|
503
|
+
if (!window) {
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
let tabs = await this.readTrackedTabs(this.collectCandidateTabIds(state), candidateWindowId);
|
|
507
|
+
if (tabs.length === 0 && group?.id !== null && group?.windowId === candidateWindowId) {
|
|
508
|
+
const windowTabs = await this.waitForWindowTabs(candidateWindowId, 750);
|
|
509
|
+
tabs = windowTabs.filter((tab) => tab.groupId === group.id);
|
|
510
|
+
}
|
|
511
|
+
if (tabs.length === 0) {
|
|
512
|
+
tabs = trackedTabs.filter((tab) => tab.windowId === candidateWindowId);
|
|
513
|
+
}
|
|
514
|
+
state.windowId = candidateWindowId;
|
|
515
|
+
if (tabs.length > 0) {
|
|
516
|
+
state.tabIds = [...new Set(tabs.map((tab) => tab.id))];
|
|
517
|
+
if (state.primaryTabId === null || !state.tabIds.includes(state.primaryTabId)) {
|
|
518
|
+
state.primaryTabId = tabs[0]?.id ?? null;
|
|
519
|
+
}
|
|
520
|
+
if (state.activeTabId === null || !state.tabIds.includes(state.activeTabId)) {
|
|
521
|
+
state.activeTabId = tabs.find((tab) => tab.active)?.id ?? state.primaryTabId;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return { window, tabs };
|
|
525
|
+
}
|
|
526
|
+
return null;
|
|
527
|
+
}
|
|
455
528
|
async recoverWorkspaceTabs(state, existingTabs) {
|
|
456
529
|
if (state.windowId === null) {
|
|
457
530
|
return existingTabs;
|
package/package.json
CHANGED
package/src/workspace.ts
CHANGED
|
@@ -119,8 +119,19 @@ export class WorkspaceManager {
|
|
|
119
119
|
const created = !persisted;
|
|
120
120
|
let state = this.normalizeState(persisted, workspaceId);
|
|
121
121
|
|
|
122
|
+
const originalWindowId = state.windowId;
|
|
122
123
|
let window = state.windowId !== null ? await this.waitForWindow(state.windowId) : null;
|
|
123
124
|
let tabs: WorkspaceTab[] = [];
|
|
125
|
+
if (!window) {
|
|
126
|
+
const rebound = await this.rebindWorkspaceWindow(state);
|
|
127
|
+
if (rebound) {
|
|
128
|
+
window = rebound.window;
|
|
129
|
+
tabs = rebound.tabs;
|
|
130
|
+
if (originalWindowId !== rebound.window.id) {
|
|
131
|
+
repairActions.push('rebound-window');
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
124
135
|
if (!window) {
|
|
125
136
|
const createdWindow = await this.browser.createWindow({
|
|
126
137
|
url: initialUrl,
|
|
@@ -241,7 +252,15 @@ export class WorkspaceManager {
|
|
|
241
252
|
focus: false,
|
|
242
253
|
initialUrl: options.url ?? DEFAULT_WORKSPACE_URL
|
|
243
254
|
});
|
|
244
|
-
let state = { ...ensured.workspace };
|
|
255
|
+
let state = { ...ensured.workspace, tabIds: [...ensured.workspace.tabIds], tabs: [...ensured.workspace.tabs] };
|
|
256
|
+
if (state.windowId !== null && state.tabs.length === 0) {
|
|
257
|
+
const rebound = await this.rebindWorkspaceWindow(state);
|
|
258
|
+
if (rebound) {
|
|
259
|
+
state.windowId = rebound.window.id;
|
|
260
|
+
state.tabs = rebound.tabs;
|
|
261
|
+
state.tabIds = [...new Set(rebound.tabs.map((tab) => tab.id))];
|
|
262
|
+
}
|
|
263
|
+
}
|
|
245
264
|
const active = options.active === true;
|
|
246
265
|
const desiredUrl = options.url ?? DEFAULT_WORKSPACE_URL;
|
|
247
266
|
let reusablePrimaryTab = await this.resolveReusablePrimaryTab(
|
|
@@ -561,6 +580,69 @@ export class WorkspaceManager {
|
|
|
561
580
|
return tabs;
|
|
562
581
|
}
|
|
563
582
|
|
|
583
|
+
private async readLooseTrackedTabs(tabIds: number[]): Promise<WorkspaceTab[]> {
|
|
584
|
+
const tabs = (
|
|
585
|
+
await Promise.all(
|
|
586
|
+
tabIds.map(async (tabId) => {
|
|
587
|
+
return await this.browser.getTab(tabId);
|
|
588
|
+
})
|
|
589
|
+
)
|
|
590
|
+
).filter((tab): tab is WorkspaceTab => tab !== null);
|
|
591
|
+
return tabs;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
private collectCandidateTabIds(state: WorkspaceRecord): number[] {
|
|
595
|
+
return [...new Set(state.tabIds.concat([state.activeTabId, state.primaryTabId].filter((value): value is number => typeof value === 'number')))];
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
private async rebindWorkspaceWindow(state: WorkspaceRecord): Promise<{ window: WorkspaceWindow; tabs: WorkspaceTab[] } | null> {
|
|
599
|
+
const candidateWindowIds: number[] = [];
|
|
600
|
+
const pushWindowId = (windowId: number | null | undefined): void => {
|
|
601
|
+
if (typeof windowId !== 'number') {
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
if (!candidateWindowIds.includes(windowId)) {
|
|
605
|
+
candidateWindowIds.push(windowId);
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
const group = state.groupId !== null ? await this.browser.getGroup(state.groupId) : null;
|
|
610
|
+
pushWindowId(group?.windowId);
|
|
611
|
+
|
|
612
|
+
const trackedTabs = await this.readLooseTrackedTabs(this.collectCandidateTabIds(state));
|
|
613
|
+
for (const tab of trackedTabs) {
|
|
614
|
+
pushWindowId(tab.windowId);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
for (const candidateWindowId of candidateWindowIds) {
|
|
618
|
+
const window = await this.waitForWindow(candidateWindowId);
|
|
619
|
+
if (!window) {
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
let tabs = await this.readTrackedTabs(this.collectCandidateTabIds(state), candidateWindowId);
|
|
623
|
+
if (tabs.length === 0 && group?.id !== null && group?.windowId === candidateWindowId) {
|
|
624
|
+
const windowTabs = await this.waitForWindowTabs(candidateWindowId, 750);
|
|
625
|
+
tabs = windowTabs.filter((tab) => tab.groupId === group.id);
|
|
626
|
+
}
|
|
627
|
+
if (tabs.length === 0) {
|
|
628
|
+
tabs = trackedTabs.filter((tab) => tab.windowId === candidateWindowId);
|
|
629
|
+
}
|
|
630
|
+
state.windowId = candidateWindowId;
|
|
631
|
+
if (tabs.length > 0) {
|
|
632
|
+
state.tabIds = [...new Set(tabs.map((tab) => tab.id))];
|
|
633
|
+
if (state.primaryTabId === null || !state.tabIds.includes(state.primaryTabId)) {
|
|
634
|
+
state.primaryTabId = tabs[0]?.id ?? null;
|
|
635
|
+
}
|
|
636
|
+
if (state.activeTabId === null || !state.tabIds.includes(state.activeTabId)) {
|
|
637
|
+
state.activeTabId = tabs.find((tab) => tab.active)?.id ?? state.primaryTabId;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
return { window, tabs };
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
return null;
|
|
644
|
+
}
|
|
645
|
+
|
|
564
646
|
private async recoverWorkspaceTabs(state: WorkspaceRecord, existingTabs: WorkspaceTab[]): Promise<WorkspaceTab[]> {
|
|
565
647
|
if (state.windowId === null) {
|
|
566
648
|
return existingTabs;
|