477a00db1a
Testing / remote-protocol-compat (0.9.5) (push) Successful in 48s
Testing / remote-protocol-compat (0.9.3) (push) Successful in 47s
Build & Publish Package / publish (push) Successful in 46s
Package Extension / package-extension (push) Successful in 59s
Testing / test (push) Failing after 50s
- Add a neutral WebExtension API adapter that uses Firefox browser.* or Chromium chrome.* without mutating globals. - Switch extension runtime code to the adapter and add Firefox-specific typings for tabs, windows, tab groups, storage, scripting, and native messaging ports. - Fix Firefox temporary add-on instructions to load the packaged manifest with background.scripts instead of the Chromium service worker manifest. - Detect Firefox in clients.list via runtime.getBrowserInfo and keep Chromium user-agent fallback support. - Make navigate.open wait briefly for Firefox to replace initial about:blank with the requested URL. - Add JS coverage for API selection, clients.list browser detection, and Firefox navigate.open URL polling. - Bump package and extension version to 0.15.2.
57 lines
2.0 KiB
TypeScript
57 lines
2.0 KiB
TypeScript
import { webExtApi as api } from '../browser-api';
|
|
import type { Tab, TabGroup } from '../types';
|
|
import { normalizeGroupColor, queryTabGroups } from '../core';
|
|
import type { SessionTab, StoredSession } from '../types';
|
|
|
|
export function buildSessionSnapshot(tabs: Tab[], groups: TabGroup[]): SessionTab[] {
|
|
const groupById = new Map(groups.map(group => [group.id, group]));
|
|
return tabs
|
|
.filter(tab => Boolean(tab.url || tab.pendingUrl))
|
|
.sort((a, b) => (a.windowId - b.windowId) || (a.index - b.index))
|
|
.map(tab => {
|
|
const entry: SessionTab = { url: tab.url || tab.pendingUrl };
|
|
if (tab.pinned) entry.pinned = true;
|
|
if (tab.groupId >= 0) {
|
|
const group = groupById.get(tab.groupId);
|
|
entry.group = {
|
|
key: `${tab.windowId}:${tab.groupId}`,
|
|
title: group?.title || "",
|
|
color: normalizeGroupColor(group?.color),
|
|
collapsed: Boolean(group?.collapsed),
|
|
};
|
|
}
|
|
return entry;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Snapshot the current windows/tabs/groups into a ready-to-store session plus
|
|
* its change-detection signature. Shared by session.save and the autosave path.
|
|
*/
|
|
export async function captureCurrentSession(): Promise<{ session: StoredSession; signature: string; tabCount: number }> {
|
|
const tabs = await api.tabs.query({});
|
|
const groups = await queryTabGroups({});
|
|
const sessionTabs = buildSessionSnapshot(tabs, groups);
|
|
const signature = sessionSignature(sessionTabs);
|
|
const session: StoredSession = {
|
|
tabs: sessionTabs,
|
|
urls: sessionTabs.map(tab => tab.url),
|
|
savedAt: Date.now(),
|
|
signature,
|
|
};
|
|
return { session, signature, tabCount: sessionTabs.length };
|
|
}
|
|
|
|
export function sessionSignature(sessionTabs: SessionTab[]) {
|
|
return JSON.stringify(sessionTabs.map(tab => ({
|
|
url: tab.url,
|
|
pinned: Boolean(tab.pinned),
|
|
group: tab.group ? {
|
|
key: tab.group.key || "",
|
|
title: tab.group.title || "",
|
|
color: normalizeGroupColor(tab.group.color),
|
|
collapsed: Boolean(tab.group.collapsed),
|
|
} : null,
|
|
})));
|
|
}
|