@flrande/bak-extension 0.3.2 → 0.3.4

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.
@@ -1 +1 @@
1
- 2026-03-09T04:50:59.948Z
1
+ 2026-03-09T06:27:35.243Z
@@ -169,10 +169,12 @@
169
169
  };
170
170
  }
171
171
  async openTab(options = {}) {
172
+ const workspaceId = this.normalizeWorkspaceId(options.workspaceId);
173
+ const hadWorkspace = await this.loadWorkspaceRecord(workspaceId) !== null;
172
174
  const ensured = await this.ensureWorkspace({
173
- workspaceId: options.workspaceId,
175
+ workspaceId,
174
176
  focus: false,
175
- initialUrl: options.url ?? DEFAULT_WORKSPACE_URL
177
+ initialUrl: hadWorkspace ? options.url ?? DEFAULT_WORKSPACE_URL : DEFAULT_WORKSPACE_URL
176
178
  });
177
179
  let state = { ...ensured.workspace, tabIds: [...ensured.workspace.tabIds], tabs: [...ensured.workspace.tabs] };
178
180
  if (state.windowId !== null && state.tabs.length === 0) {
@@ -204,7 +206,7 @@
204
206
  throw error;
205
207
  }
206
208
  const repaired = await this.ensureWorkspace({
207
- workspaceId: options.workspaceId,
209
+ workspaceId,
208
210
  focus: false,
209
211
  initialUrl: desiredUrl
210
212
  });
@@ -328,13 +330,13 @@
328
330
  await this.storage.save(null);
329
331
  return { ok: true };
330
332
  }
333
+ await this.storage.save(null);
331
334
  if (state.windowId !== null) {
332
335
  const existingWindow = await this.browser.getWindow(state.windowId);
333
336
  if (existingWindow) {
334
337
  await this.browser.closeWindow(state.windowId);
335
338
  }
336
339
  }
337
- await this.storage.save(null);
338
340
  return { ok: true };
339
341
  }
340
342
  async resolveTarget(options = {}) {
@@ -597,17 +599,31 @@
597
599
  };
598
600
  }
599
601
  async resolveReusablePrimaryTab(workspace, allowReuse) {
600
- if (!allowReuse || workspace.windowId === null) {
602
+ if (workspace.windowId === null) {
601
603
  return null;
602
604
  }
603
605
  if (workspace.primaryTabId !== null) {
604
606
  const trackedPrimary = workspace.tabs.find((tab) => tab.id === workspace.primaryTabId) ?? await this.waitForTrackedTab(workspace.primaryTabId, workspace.windowId);
605
- if (trackedPrimary) {
607
+ if (trackedPrimary && (allowReuse || this.isReusableBlankWorkspaceTab(trackedPrimary, workspace))) {
606
608
  return trackedPrimary;
607
609
  }
608
610
  }
609
611
  const windowTabs = await this.waitForWindowTabs(workspace.windowId, 750);
610
- return windowTabs.length === 1 ? windowTabs[0] : null;
612
+ if (windowTabs.length !== 1) {
613
+ return null;
614
+ }
615
+ const candidate = windowTabs[0];
616
+ if (allowReuse || this.isReusableBlankWorkspaceTab(candidate, workspace)) {
617
+ return candidate;
618
+ }
619
+ return null;
620
+ }
621
+ isReusableBlankWorkspaceTab(tab, workspace) {
622
+ if (workspace.tabIds.length > 1) {
623
+ return false;
624
+ }
625
+ const normalizedUrl = tab.url.trim().toLowerCase();
626
+ return normalizedUrl === "" || normalizedUrl === DEFAULT_WORKSPACE_URL;
611
627
  }
612
628
  async waitForWindow(windowId, timeoutMs = 750) {
613
629
  const deadline = Date.now() + timeoutMs;
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@flrande/bak-extension",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "type": "module",
5
5
  "dependencies": {
6
- "@flrande/bak-protocol": "0.3.2"
6
+ "@flrande/bak-protocol": "0.3.4"
7
7
  },
8
8
  "devDependencies": {
9
9
  "@types/chrome": "^0.1.14",
package/src/workspace.ts CHANGED
@@ -247,10 +247,12 @@ export class WorkspaceManager {
247
247
  }
248
248
 
249
249
  async openTab(options: WorkspaceOpenTabOptions = {}): Promise<{ workspace: WorkspaceInfo; tab: WorkspaceTab }> {
250
+ const workspaceId = this.normalizeWorkspaceId(options.workspaceId);
251
+ const hadWorkspace = (await this.loadWorkspaceRecord(workspaceId)) !== null;
250
252
  const ensured = await this.ensureWorkspace({
251
- workspaceId: options.workspaceId,
253
+ workspaceId,
252
254
  focus: false,
253
- initialUrl: options.url ?? DEFAULT_WORKSPACE_URL
255
+ initialUrl: hadWorkspace ? options.url ?? DEFAULT_WORKSPACE_URL : DEFAULT_WORKSPACE_URL
254
256
  });
255
257
  let state = { ...ensured.workspace, tabIds: [...ensured.workspace.tabIds], tabs: [...ensured.workspace.tabs] };
256
258
  if (state.windowId !== null && state.tabs.length === 0) {
@@ -285,7 +287,7 @@ export class WorkspaceManager {
285
287
  throw error;
286
288
  }
287
289
  const repaired = await this.ensureWorkspace({
288
- workspaceId: options.workspaceId,
290
+ workspaceId,
289
291
  focus: false,
290
292
  initialUrl: desiredUrl
291
293
  });
@@ -419,13 +421,15 @@ export class WorkspaceManager {
419
421
  await this.storage.save(null);
420
422
  return { ok: true };
421
423
  }
424
+ // Clear persisted state before closing the window so tab/window removal
425
+ // listeners cannot race and resurrect an empty workspace record.
426
+ await this.storage.save(null);
422
427
  if (state.windowId !== null) {
423
428
  const existingWindow = await this.browser.getWindow(state.windowId);
424
429
  if (existingWindow) {
425
430
  await this.browser.closeWindow(state.windowId);
426
431
  }
427
432
  }
428
- await this.storage.save(null);
429
433
  return { ok: true };
430
434
  }
431
435
 
@@ -728,17 +732,32 @@ export class WorkspaceManager {
728
732
  }
729
733
 
730
734
  private async resolveReusablePrimaryTab(workspace: WorkspaceInfo, allowReuse: boolean): Promise<WorkspaceTab | null> {
731
- if (!allowReuse || workspace.windowId === null) {
735
+ if (workspace.windowId === null) {
732
736
  return null;
733
737
  }
734
738
  if (workspace.primaryTabId !== null) {
735
739
  const trackedPrimary = workspace.tabs.find((tab) => tab.id === workspace.primaryTabId) ?? (await this.waitForTrackedTab(workspace.primaryTabId, workspace.windowId));
736
- if (trackedPrimary) {
740
+ if (trackedPrimary && (allowReuse || this.isReusableBlankWorkspaceTab(trackedPrimary, workspace))) {
737
741
  return trackedPrimary;
738
742
  }
739
743
  }
740
744
  const windowTabs = await this.waitForWindowTabs(workspace.windowId, 750);
741
- return windowTabs.length === 1 ? windowTabs[0]! : null;
745
+ if (windowTabs.length !== 1) {
746
+ return null;
747
+ }
748
+ const candidate = windowTabs[0]!;
749
+ if (allowReuse || this.isReusableBlankWorkspaceTab(candidate, workspace)) {
750
+ return candidate;
751
+ }
752
+ return null;
753
+ }
754
+
755
+ private isReusableBlankWorkspaceTab(tab: WorkspaceTab, workspace: WorkspaceInfo): boolean {
756
+ if (workspace.tabIds.length > 1) {
757
+ return false;
758
+ }
759
+ const normalizedUrl = tab.url.trim().toLowerCase();
760
+ return normalizedUrl === '' || normalizedUrl === DEFAULT_WORKSPACE_URL;
742
761
  }
743
762
 
744
763
  private async waitForWindow(windowId: number, timeoutMs = 750): Promise<WorkspaceWindow | null> {