diff --git a/prefs/zen/sync.yaml b/prefs/zen/sync.yaml
deleted file mode 100644
index dff75e481..000000000
--- a/prefs/zen/sync.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-- name: services.sync.engine.spaces
- value: true
- condition: "@IS_TWILIGHT@"
-
-- name: services.sync.engine.spaces
- value: false
- locked: true
- condition: "!@IS_TWILIGHT@"
diff --git a/prefs/zen/workspaces.yaml b/prefs/zen/workspaces.yaml
index dfa8b7d6c..24aaf887c 100644
--- a/prefs/zen/workspaces.yaml
+++ b/prefs/zen/workspaces.yaml
@@ -32,6 +32,9 @@
- name: zen.workspaces.scroll-modifier-key
value: ctrl
+- name: services.sync.engine.workspaces
+ value: false
+
- name: zen.workspaces.separate-essentials
value: true
diff --git a/src/browser/components/preferences/config/account-sync-mjs.patch b/src/browser/components/preferences/config/account-sync-mjs.patch
deleted file mode 100644
index ce14b3e05..000000000
--- a/src/browser/components/preferences/config/account-sync-mjs.patch
+++ /dev/null
@@ -1,20 +0,0 @@
-diff --git a/browser/components/preferences/config/account-sync.mjs b/browser/components/preferences/config/account-sync.mjs
-index b503987a08e2ce64bfc01c4e3a21e5e19ef834f0..b1c03a0b219fd3eddd93c1deaeb18ab79c85f168 100644
---- a/browser/components/preferences/config/account-sync.mjs
-+++ b/browser/components/preferences/config/account-sync.mjs
-@@ -42,6 +42,7 @@ Preferences.addAll([
- { id: "services.sync.engine.creditcards", type: "bool" },
- { id: "services.sync.engine.addons", type: "bool" },
- { id: "services.sync.engine.prefs", type: "bool" },
-+ { id: "services.sync.engine.spaces", type: "bool" },
- ]);
-
- /**
-@@ -546,6 +547,7 @@ const SYNC_ENGINE_SETTINGS = [
- type: "payments",
- },
- { id: "syncAddons", pref: "services.sync.engine.addons", type: "addons" },
-+ { id: "syncSpaces", pref: "services.sync.engine.spaces", type: "workspaces" },
- { id: "syncSettings", pref: "services.sync.engine.prefs", type: "settings" },
- ];
-
diff --git a/src/browser/components/preferences/dialogs/syncChooseWhatToSync-js.patch b/src/browser/components/preferences/dialogs/syncChooseWhatToSync-js.patch
index da89f90fb..e066aca21 100644
--- a/src/browser/components/preferences/dialogs/syncChooseWhatToSync-js.patch
+++ b/src/browser/components/preferences/dialogs/syncChooseWhatToSync-js.patch
@@ -6,7 +6,7 @@ index 64aa0d98a0622c01f3dcfff1a04bfcda368354d2..2013e04b0881ad2295d6897b91e1573c
{ id: "services.sync.engine.passwords", type: "bool" },
{ id: "services.sync.engine.addresses", type: "bool" },
{ id: "services.sync.engine.creditcards", type: "bool" },
-+ { id: "services.sync.engine.spaces", type: "bool" },
++ { id: "services.sync.engine.workspaces", type: "bool" },
]);
let gSyncChooseWhatToSync = {
diff --git a/src/browser/components/preferences/dialogs/syncChooseWhatToSync-xhtml.patch b/src/browser/components/preferences/dialogs/syncChooseWhatToSync-xhtml.patch
index 0ebce7576..3b0ab370d 100644
--- a/src/browser/components/preferences/dialogs/syncChooseWhatToSync-xhtml.patch
+++ b/src/browser/components/preferences/dialogs/syncChooseWhatToSync-xhtml.patch
@@ -20,7 +20,7 @@ index a893c5ec3d007820d98f5d92dd039640faa2c181..9cbd00102e44ccf98b37845474d92d57
+
+
+
diff --git a/src/browser/components/preferences/sync-inc-xhtml.patch b/src/browser/components/preferences/sync-inc-xhtml.patch
index 4b6e6306d..06944335a 100644
--- a/src/browser/components/preferences/sync-inc-xhtml.patch
+++ b/src/browser/components/preferences/sync-inc-xhtml.patch
@@ -6,7 +6,7 @@ index c379e1a5f82692406a92d9fcd3bca2769dfac5b2..af037dd3d995813d966524ac44a3795d
-+
++
+
+
+
diff --git a/src/services/sync/modules/service-sys-mjs.patch b/src/services/sync/modules/service-sys-mjs.patch
deleted file mode 100644
index daf57720d..000000000
--- a/src/services/sync/modules/service-sys-mjs.patch
+++ /dev/null
@@ -1,15 +0,0 @@
-diff --git a/services/sync/modules/service.sys.mjs b/services/sync/modules/service.sys.mjs
-index 4f4efe572909441abdd81909282936702c225621..81ab06a9414ed656b644a21b40b683f06a4f8dbf 100644
---- a/services/sync/modules/service.sys.mjs
-+++ b/services/sync/modules/service.sys.mjs
-@@ -99,6 +99,10 @@ function getEngineModules() {
- whenTrue: "ExtensionStorageEngineKinto",
- whenFalse: "ExtensionStorageEngineBridge",
- };
-+ result.Spaces = {
-+ module: "resource:///modules/zen/ZenWorkspacesSync.sys.mjs",
-+ symbol: "ZenWorkspacesEngine",
-+ };
- return result;
- }
-
diff --git a/src/toolkit/components/contextualidentity/ContextualIdentityService-sys-mjs.patch b/src/toolkit/components/contextualidentity/ContextualIdentityService-sys-mjs.patch
deleted file mode 100644
index 1b108254d..000000000
--- a/src/toolkit/components/contextualidentity/ContextualIdentityService-sys-mjs.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.sys.mjs b/toolkit/components/contextualidentity/ContextualIdentityService.sys.mjs
-index 5702ff28cc22206f5ce16584dac8a78d816562ce..3d08ecc97ce5995b30d8a4af0c33df329b428008 100644
---- a/toolkit/components/contextualidentity/ContextualIdentityService.sys.mjs
-+++ b/toolkit/components/contextualidentity/ContextualIdentityService.sys.mjs
-@@ -270,11 +270,29 @@ _ContextualIdentityService.prototype = {
- });
- },
-
-- create(name, icon, color) {
-+ create(name, icon, color, id = null) {
- this.ensureDataReady();
-
-- // Retrieve the next userContextId available.
-- let userContextId = ++this._lastUserContextId;
-+ if (id !== null) {
-+ id = typeof id == "string" ? Number(id) : id;
-+ if (!Number.isSafeInteger(id) || id <= 0) {
-+ throw new Error(`Invalid userContextId '${id}'`);
-+ }
-+ }
-+
-+ let userContextId;
-+ if (
-+ id !== null &&
-+ !this._identities.some(identity => identity.userContextId === id)
-+ ) {
-+ userContextId = id;
-+ this._lastUserContextId = Math.max(
-+ this._lastUserContextId,
-+ userContextId
-+ );
-+ } else {
-+ userContextId = ++this._lastUserContextId;
-+ }
-
- // Throw an error if the next userContextId available is invalid (the one associated to
- // MAX_USER_CONTEXT_ID is already reserved to "userContextIdInternal.webextStorageLocal", which
diff --git a/src/zen/moz.build b/src/zen/moz.build
index 4e3e80ecb..8b1426065 100644
--- a/src/zen/moz.build
+++ b/src/zen/moz.build
@@ -20,5 +20,4 @@ DIRS += [
"share",
"spaces",
"space-routing",
- "sync",
]
diff --git a/src/zen/sessionstore/ZenSessionManager.sys.mjs b/src/zen/sessionstore/ZenSessionManager.sys.mjs
index bccec81c6..39f2d0eb2 100644
--- a/src/zen/sessionstore/ZenSessionManager.sys.mjs
+++ b/src/zen/sessionstore/ZenSessionManager.sys.mjs
@@ -10,7 +10,6 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
ZenLiveFoldersManager:
"resource:///modules/zen/ZenLiveFoldersManager.sys.mjs",
- ZenSyncStore: "resource:///modules/zen/ZenSyncManager.sys.mjs",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
SessionStartup: "resource:///modules/sessionstore/SessionStartup.sys.mjs",
@@ -610,7 +609,6 @@ export class nsZenSessionManager {
}
);
this.#collectWindowData(windows);
- lazy.ZenSyncStore.notifyAboutChanges();
// This would save the data to disk asynchronously or when quitting the app.
let sidebar = this.#sidebarWithoutCloning;
this.#file.data = sidebar;
@@ -624,15 +622,6 @@ export class nsZenSessionManager {
this.log(`Saving Zen session data with ${sidebar.tabs?.length || 0} tabs`);
}
- /**
- * Returns the sidebar data object.
- *
- * @returns {object}
- */
- getSidebarData() {
- return this.#sidebarWithoutCloning;
- }
-
/**
* Called when the last known backup should be deleted and a new one
* created. This uses the #deferredBackupTask to debounce clusters of
diff --git a/src/zen/spaces/ZenSpaceManager.mjs b/src/zen/spaces/ZenSpaceManager.mjs
index 6ae2e4abe..b4b087e2b 100644
--- a/src/zen/spaces/ZenSpaceManager.mjs
+++ b/src/zen/spaces/ZenSpaceManager.mjs
@@ -11,7 +11,6 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
- ZenSyncStore: "resource:///modules/zen/ZenSyncManager.sys.mjs",
});
ChromeUtils.defineLazyGetter(lazy, "browserBackgroundElement", () => {
@@ -149,7 +148,7 @@ class nsZenWorkspaces {
if (!this.privateWindowOrDisabled) {
const observerFunction = async () => {
delete this._workspaceBookmarksCache;
- await this.#initializeWorkspaceBookmarks();
+ await this.workspaceBookmarks();
this._invalidateBookmarkContainers();
};
Services.obs.addObserver(observerFunction, "workspace-bookmarks-updated");
@@ -169,63 +168,6 @@ class nsZenWorkspaces {
}
}
- /**
- * Applies live sync changes: updates workspace cache, removes deleted items,
- * then creates/updates pulled items.
- *
- * @param {{ spaces: Array}} pulled Reconcile-pulled items.
- * @param {{ spaces: Array}} removals Items to remove.
- */
- async _applySyncChanges(pulled, removals = {}) {
- if (!this.shouldHaveWorkspaces || this.privateWindowOrDisabled) {
- return;
- }
- await this.promiseInitialized;
-
- // 1. Update workspace cache (remove deleted, merge pulled)
- const removedSpaceIds = new Set((removals.spaces || []).map(s => s.uuid));
- if (removedSpaceIds.size || pulled.spaces?.length) {
- const localMap = new Map(
- this.getWorkspaces()
- .filter(w => !removedSpaceIds.has(w.uuid))
- .map(w => [w.uuid, w])
- );
- for (const space of pulled.spaces || []) {
- if (!space?.uuid) {
- continue;
- }
- const existing = localMap.get(space.uuid);
- localMap.set(space.uuid, existing ? { ...existing, ...space } : space);
- }
- await this.propagateWorkspaces(
- this.#getOrderedWorkspacesByPosition(Array.from(localMap.values()))
- );
- this.#propagateWorkspaceData();
- }
- }
-
- #getOrderedWorkspacesByPosition(workspaces) {
- return [...workspaces]
- .map((workspace, index) => ({ workspace, index }))
- .sort((a, b) => {
- const aPosition =
- typeof a.workspace.position === "number"
- ? a.workspace.position
- : a.index;
- const bPosition =
- typeof b.workspace.position === "number"
- ? b.workspace.position
- : b.index;
- return aPosition - bPosition || a.index - b.index;
- })
- .map(({ workspace }) => {
- // strip the position property that comes from pulled workspaces
- const rest = { ...workspace };
- delete rest.position;
- return rest;
- });
- }
-
#afterLoadInit() {
const onResize = (...args) => {
requestAnimationFrame(() => {
@@ -749,17 +691,17 @@ class nsZenWorkspaces {
return spacesForSS;
}
- async #initializeWorkspaceBookmarks() {
+ async workspaceBookmarks() {
if (this.privateWindowOrDisabled) {
this._workspaceBookmarksCache = {
bookmarks: [],
lastChangeTimestamp: 0,
};
- return;
+ return this._workspaceBookmarksCache;
}
if (this._workspaceBookmarksCache) {
- return;
+ return this._workspaceBookmarksCache;
}
const [bookmarks, lastChangeTimestamp] = await Promise.all([
@@ -768,6 +710,8 @@ class nsZenWorkspaces {
]);
this._workspaceBookmarksCache = { bookmarks, lastChangeTimestamp };
+
+ return this._workspaceCache;
}
restoreWorkspacesFromSessionStore(aWinData = {}) {
@@ -827,7 +771,7 @@ class nsZenWorkspaces {
return (async () => {
await this.#waitForPromises();
this.#afterLoadInit();
- await this.#initializeWorkspaceBookmarks();
+ await this.workspaceBookmarks();
await this.changeWorkspace(activeWorkspace, { onInit: true });
this.#fixTabPositions();
this.onWindowResize();
@@ -853,13 +797,6 @@ class nsZenWorkspaces {
})();
}
- #markWorkspaceChanged(workspaceId) {
- lazy.ZenSyncStore.markItemChanged({
- type: "space",
- id: workspaceId,
- });
- }
-
async selectStartPage() {
if (!this.workspaceEnabled || gZenUIManager.testingEnabled) {
return;
@@ -1277,19 +1214,12 @@ class nsZenWorkspaces {
} else {
workspacesData.push(workspaceData);
}
- // mark item as changed for sync
- this.#markWorkspaceChanged(workspaceData.uuid);
-
this.#propagateWorkspaceData();
}
removeWorkspace(windowID) {
let { promise, resolve } = Promise.withResolvers();
this.#deleteWorkspaceOwnedTabs(windowID);
-
- // mark item as changed for sync
- this.#markWorkspaceChanged(windowID);
-
let workspacesData = this.getWorkspaces();
// Remove the workspace from the cache
workspacesData = workspacesData.filter(
@@ -1421,50 +1351,30 @@ class nsZenWorkspaces {
if (this.privateWindowOrDisabled) {
return;
}
- const workspaces = this.getWorkspaces();
- // Track previous positions so we only notify observers for workspaces whose
- // position changed during the reorder.
- const previousPositions = new Map(
- workspaces.map((workspace, index) => [workspace.uuid, index])
- );
-
+ const workspaces = this._workspaceCache;
const workspace = workspaces.find(w => w.uuid === id);
if (!workspace) {
console.warn(`Workspace with ID ${id} not found for reordering.`);
return;
}
-
// Remove the workspace from its current position
const currentIndex = workspaces.indexOf(workspace);
if (currentIndex === -1) {
console.warn(`Workspace with ID ${id} not found in the list.`);
return;
}
-
+ workspaces.splice(currentIndex, 1);
// Insert the workspace at the new position
- if (newPosition < 0 || newPosition >= workspaces.length) {
+ if (newPosition < 0 || newPosition > workspaces.length) {
console.warn(
`Invalid position ${newPosition} for reordering workspace with ID ${id}.`
);
return;
}
-
- workspaces.splice(currentIndex, 1);
workspaces.splice(newPosition, 0, workspace);
-
// Propagate the changes if the order has changed
if (currentIndex !== newPosition) {
- this._workspaceCache = workspaces;
-
- for (const [i, ws] of workspaces.entries()) {
- if (previousPositions.get(ws.uuid) === i) {
- continue;
- }
- // mark item as changed for sync
- this.#markWorkspaceChanged(ws.uuid);
- }
-
- this.#propagateWorkspaceData(workspaces);
+ this.#propagateWorkspaceData();
}
}
@@ -2450,7 +2360,7 @@ class nsZenWorkspaces {
for (const tab of gBrowser.tabs) {
if (
!tab.hasAttribute("zen-workspace-id") &&
- !tab.hasAttribute("zen-essential")
+ !tab.hasAttribute("zen-workspace-id")
) {
tab.setAttribute("zen-workspace-id", workspace.uuid);
}
diff --git a/src/zen/sync/ZenSyncManager.sys.mjs b/src/zen/sync/ZenSyncManager.sys.mjs
deleted file mode 100644
index 1b454da81..000000000
--- a/src/zen/sync/ZenSyncManager.sys.mjs
+++ /dev/null
@@ -1,160 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const lazy = {};
-
-ChromeUtils.defineESModuleGetters(lazy, {
- ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
- ContextualIdentityService:
- "resource://gre/modules/ContextualIdentityService.sys.mjs",
- ZenWindowSync: "resource:///modules/zen/ZenWindowSync.sys.mjs",
-});
-
-function normalizeUserContextId(value) {
- const normalized = typeof value === "string" ? Number(value) : value;
- if (!Number.isSafeInteger(normalized) || normalized <= 0) {
- return null;
- }
- return normalized;
-}
-
-class ZenSyncManager {
- getSidebarData() {
- return lazy.ZenSessionStore.getSidebarData();
- }
-
- /**
- * Whether to ignore changes to items. This is used to prevent
- * infinite loops when applying incoming sync changes.
- *
- * @type {boolean}
- */
- #ignoreChanges = false;
-
- #changedItems = new Map();
-
- markItemChanged(item) {
- if (item.type && item.id && !this.#ignoreChanges) {
- const key = `${item.type}~${item.id}`;
- this.#changedItems.set(key, { type: item.type, id: item.id });
- }
- }
-
- #getChangedItems() {
- return Array.from(this.#changedItems.values());
- }
-
- #clearChangedItems() {
- this.#changedItems.clear();
- }
-
- notifyAboutChanges() {
- const changedItems = this.#getChangedItems();
-
- for (const item of changedItems) {
- Services.obs.notifyObservers(
- { wrappedJSObject: item },
- "zen-workspace-item-changed"
- );
- }
- this.#clearChangedItems();
- }
-
- async applyIncomingBatch(pulled, removals) {
- try {
- this.#ignoreChanges = true;
- this.#applyIncomingContainers(
- pulled.containers || [],
- removals.containers || []
- );
-
- const win = lazy.ZenWindowSync.firstSyncedWindow;
- if (win?.gZenWorkspaces) {
- await win.gZenWorkspaces._applySyncChanges(pulled, removals);
- }
- } catch (e) {
- console.error("ZenSyncManager: Failed to apply incoming sync data:", e);
- throw e;
- } finally {
- this.#ignoreChanges = false;
- }
- }
-
- #applyIncomingContainers(pulledContainers, removedContainers) {
- const localContainersById = new Map(
- lazy.ContextualIdentityService.getPublicIdentities().map(container => [
- container.userContextId,
- container,
- ])
- );
-
- for (const container of pulledContainers) {
- if (!container.name) {
- continue;
- }
-
- const userContextId = normalizeUserContextId(container.userContextId);
- if (userContextId === null) {
- console.warn(
- "ZenSyncManager: Ignoring incoming container with invalid userContextId",
- { container }
- );
- continue;
- }
-
- const existsLocally = localContainersById.has(userContextId);
-
- if (existsLocally) {
- lazy.ContextualIdentityService.update(
- userContextId,
- container.name,
- container.icon,
- container.color
- );
- continue;
- }
-
- const createdIdentity = lazy.ContextualIdentityService.create(
- container.name,
- container.icon,
- container.color,
- userContextId
- );
- if (createdIdentity) {
- localContainersById.set(createdIdentity.userContextId, createdIdentity);
- }
- if (createdIdentity && createdIdentity.userContextId !== userContextId) {
- console.warn("ZenSyncManager: Container sync created unexpected ID", {
- requestedId: userContextId,
- createdId: createdIdentity.userContextId,
- name: container.name,
- });
- }
- }
-
- for (const container of removedContainers) {
- const userContextId = normalizeUserContextId(container.userContextId);
- if (userContextId === null) {
- console.warn(
- "ZenSyncManager: Ignoring container removal with invalid userContextId",
- { container }
- );
- continue;
- }
-
- if (!localContainersById.has(userContextId)) {
- continue;
- }
-
- try {
- lazy.ContextualIdentityService.remove(userContextId);
- localContainersById.delete(userContextId);
- } catch {
- // Container may already be gone locally.
- }
- }
- }
-}
-
-export const ZenSyncStore = new ZenSyncManager();
diff --git a/src/zen/sync/ZenWorkspacesSync.sys.mjs b/src/zen/sync/ZenWorkspacesSync.sys.mjs
deleted file mode 100644
index 175319169..000000000
--- a/src/zen/sync/ZenWorkspacesSync.sys.mjs
+++ /dev/null
@@ -1,404 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-import {
- Store,
- SyncEngine,
- Tracker,
-} from "resource://services-sync/engines.sys.mjs";
-import { CryptoWrapper } from "resource://services-sync/record.sys.mjs";
-import { SCORE_INCREMENT_XLARGE } from "resource://services-sync/constants.sys.mjs";
-
-const lazy = {};
-
-ChromeUtils.defineESModuleGetters(lazy, {
- ZenSyncStore: "resource:///modules/zen/ZenSyncManager.sys.mjs",
- ContextualIdentityService:
- "resource://gre/modules/ContextualIdentityService.sys.mjs",
-});
-
-const RECORD_ID_PREFIX_BY_TYPE = Object.freeze({
- space: "s",
- container: "c",
-});
-
-const RECORD_TYPE_BY_PREFIX = Object.freeze({
- s: "space",
- c: "container",
-});
-
-/**
- * Sync record wrapper for workspace and container items stored in the
- * Workspaces engine collection.
- */
-export class ZenWorkspacesRecord extends CryptoWrapper {
- _logName = "Sync.Record.ZenWorkspaces";
-}
-
-ZenWorkspacesRecord.prototype.type = "workspaces";
-
-function parseRecordId(id) {
- const sep = id.indexOf("~");
- if (sep === -1) {
- return null;
- }
- const prefix = id.slice(0, sep);
- const key = id.slice(sep + 1);
- return { type: RECORD_TYPE_BY_PREFIX[prefix] || prefix, key };
-}
-
-function createRecordId(type, id) {
- const prefix = RECORD_ID_PREFIX_BY_TYPE[type];
- if (!prefix) {
- throw new Error(`Unknown Workspaces Sync record type: ${type}`);
- }
- return `${prefix}~${id}`;
-}
-
-function normalizeUserContextId(value) {
- const normalized = typeof value === "string" ? Number(value) : value;
- if (!Number.isSafeInteger(normalized) || normalized <= 0) {
- return null;
- }
- return normalized;
-}
-
-/**
- * Strips the sync-envelope fields (`id` and `type`) from incoming record data
- * and restores the item's real identity key where needed
- *
- * @param {object} data
- */
-function stripSyncFields(data) {
- const rest = { ...data };
- delete rest.id;
- delete rest.type;
- return rest;
-}
-
-/**
- * Sync store implementation that serializes local workspace and container
- * state into records and applies incoming remote changes.
- */
-class ZenWorkspacesStore extends Store {
- constructor(name, engine) {
- super(name, engine);
- }
-
- async getAllIDs() {
- const ids = {};
- const sidebar = lazy.ZenSyncStore.getSidebarData();
-
- for (const space of sidebar.spaces || []) {
- if (space.uuid) {
- ids[createRecordId("space", space.uuid)] = true;
- }
- }
-
- for (const c of lazy.ContextualIdentityService.getPublicIdentities()) {
- ids[createRecordId("container", c.userContextId)] = true;
- }
-
- return ids;
- }
-
- async itemExists(id) {
- const parsed = parseRecordId(id);
- if (!parsed) {
- return false;
- }
- const sidebar = lazy.ZenSyncStore.getSidebarData();
-
- switch (parsed.type) {
- case "space":
- return (sidebar.spaces || []).some(s => s.uuid === parsed.key);
- case "container":
- return lazy.ContextualIdentityService.getPublicIdentities().some(
- c => String(c.userContextId) === parsed.key
- );
- default:
- return false;
- }
- }
-
- async createRecord(id, collection) {
- const record = new ZenWorkspacesRecord(collection, id);
- const parsed = parseRecordId(id);
- if (!parsed) {
- record.deleted = true;
- return record;
- }
-
- const sidebar = lazy.ZenSyncStore.getSidebarData();
-
- switch (parsed.type) {
- case "space": {
- const spaces = sidebar.spaces || [];
- const idx = spaces.findIndex(s => s.uuid === parsed.key);
- if (idx === -1) {
- record.deleted = true;
- return record;
- }
- const rest = { ...spaces[idx] };
- delete rest.syncStatus;
- record.cleartext = { id, type: "space", ...rest, position: idx };
- break;
- }
-
- case "container": {
- const container =
- lazy.ContextualIdentityService.getPublicIdentities().find(
- c => String(c.userContextId) === parsed.key
- );
- if (!container) {
- record.deleted = true;
- return record;
- }
- record.cleartext = {
- id,
- type: "container",
- userContextId: container.userContextId,
- name: container.name,
- icon: container.icon,
- color: container.color,
- };
- break;
- }
-
- default:
- record.deleted = true;
- }
-
- return record;
- }
-
- async applyIncomingBatch(records, _countTelemetry) {
- const pulled = { spaces: [], containers: [] };
- const removals = { spaces: [], containers: [] };
-
- for (const record of records) {
- if (record.deleted) {
- this._collectRemoval(record.id, removals);
- continue;
- }
- const data = record.cleartext;
- if (!data?.type) {
- continue;
- }
- const clean = stripSyncFields(data);
- switch (data.type) {
- case "space":
- pulled.spaces.push(clean);
- break;
- case "container":
- pulled.containers.push(clean);
- break;
- }
- }
-
- // Suppress change tracking while applying incoming data to prevent
- // feedback loops where applied items get re-uploaded immediately.
- this.engine._tracker.ignoreAll = true;
- try {
- await lazy.ZenSyncStore.applyIncomingBatch(pulled, removals);
- } finally {
- this.engine._tracker.ignoreAll = false;
- }
- return [];
- }
-
- _collectRemoval(id, removals) {
- const parsed = parseRecordId(id);
- if (!parsed) {
- return;
- }
- switch (parsed.type) {
- case "space":
- removals.spaces.push({ uuid: parsed.key });
- break;
- case "container": {
- const userContextId = normalizeUserContextId(parsed.key);
- if (userContextId === null) {
- console.warn(
- "ZenWorkspacesStore: Ignoring container removal with invalid userContextId",
- { id }
- );
- break;
- }
- removals.containers.push({ userContextId });
- break;
- }
- }
- }
-
- async create(record) {
- await this._applySingle(record);
- }
-
- async update(record) {
- await this._applySingle(record);
- }
-
- async _applySingle(record) {
- this.engine._tracker.ignoreAll = true;
- try {
- if (record.deleted) {
- const removals = { spaces: [], containers: [] };
- this._collectRemoval(record.id, removals);
- await lazy.ZenSyncStore.applyIncomingBatch(
- { spaces: [], containers: [] },
- removals
- );
- return;
- }
- const data = record.cleartext;
- if (!data?.type) {
- return;
- }
- const clean = stripSyncFields(data);
- const pulled = { spaces: [], containers: [] };
- switch (data.type) {
- case "space":
- pulled.spaces.push(clean);
- break;
- case "container":
- pulled.containers.push(clean);
- break;
- }
- await lazy.ZenSyncStore.applyIncomingBatch(pulled, {
- spaces: [],
- containers: [],
- });
- } finally {
- this.engine._tracker.ignoreAll = false;
- }
- }
-
- async remove() {
- // No-op: never delete user data on wipe
- }
-
- async wipe() {
- // No-op: never delete user data on wipe
- }
-
- changeItemID() {
- // No-op
- }
-}
-
-/**
- * Sync tracker that watches workspace and contextual identity observers and
- * marks the corresponding record IDs as changed.
- */
-class ZenWorkspacesTracker extends Tracker {
- #changedIDs = {};
- #ignoreAll = false;
-
- get ignoreAll() {
- return this.#ignoreAll;
- }
-
- set ignoreAll(value) {
- this.#ignoreAll = value;
- }
-
- onStart() {
- Services.obs.addObserver(this, "zen-workspace-item-changed");
- Services.obs.addObserver(this, "contextual-identity-created");
- Services.obs.addObserver(this, "contextual-identity-updated");
- Services.obs.addObserver(this, "contextual-identity-deleted");
- }
-
- onStop() {
- Services.obs.removeObserver(this, "zen-workspace-item-changed");
- Services.obs.removeObserver(this, "contextual-identity-created");
- Services.obs.removeObserver(this, "contextual-identity-updated");
- Services.obs.removeObserver(this, "contextual-identity-deleted");
- }
-
- observe(subject, topic, _data) {
- if (this.#ignoreAll) {
- return;
- }
- if (topic === "zen-workspace-item-changed") {
- const type = subject?.wrappedJSObject?.type;
- const id = subject?.wrappedJSObject?.id;
- if (type && id) {
- this._trackChange({ type, id });
- }
- } else if (topic.startsWith("contextual-identity-")) {
- const id = subject?.wrappedJSObject?.userContextId;
- if (id && normalizeUserContextId(id) !== null) {
- this._trackChange({ type: "container", id });
- }
- }
- }
-
- _trackChange(data) {
- if (data.type && data.id) {
- const id = createRecordId(data.type, data.id);
- this.#changedIDs[id] = Date.now() / 1000;
- this.score += SCORE_INCREMENT_XLARGE;
- }
- }
-
- async getChangedIDs() {
- return { ...this.#changedIDs };
- }
-
- async addChangedID(id, when) {
- this.#changedIDs[id] = when;
- return true;
- }
-
- async removeChangedID(...ids) {
- for (const id of ids) {
- delete this.#changedIDs[id];
- }
- return true;
- }
-
- clearChangedIDs() {
- this.#changedIDs = {};
- }
-}
-
-/**
- * Sync engine entrypoint that wires the Workspaces record, store, and tracker
- * implementations into Firefox Sync.
- */
-export class ZenWorkspacesEngine extends SyncEngine {
- static get name() {
- return "Workspaces";
- }
-
- constructor(service) {
- super("Workspaces", service);
- }
-
- get _storeObj() {
- return ZenWorkspacesStore;
- }
-
- get _trackerObj() {
- return ZenWorkspacesTracker;
- }
-
- get _recordObj() {
- return ZenWorkspacesRecord;
- }
-
- get version() {
- return 2;
- }
-
- get syncPriority() {
- return 8;
- }
-
- get allowSkippedRecord() {
- return false;
- }
-}
diff --git a/src/zen/sync/moz.build b/src/zen/sync/moz.build
deleted file mode 100644
index d10ad7a19..000000000
--- a/src/zen/sync/moz.build
+++ /dev/null
@@ -1,8 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-EXTRA_JS_MODULES.zen += [
- "ZenSyncManager.sys.mjs",
- "ZenWorkspacesSync.sys.mjs",
-]
diff --git a/tools/ffprefs/src/main.rs b/tools/ffprefs/src/main.rs
index 20724730d..ac11c8e5b 100644
--- a/tools/ffprefs/src/main.rs
+++ b/tools/ffprefs/src/main.rs
@@ -346,17 +346,6 @@ fn expand_pref_values(prefs: &mut [Preference]) {
}
pref.value = new_value.clone();
}
- // Also change the condition if it contains placeholders
- if let Some(condition) = &pref.condition {
- let mut new_condition = condition.clone();
- for (key, value) in &env_values {
- let placeholder = format!("@{}@", key);
- if new_condition.contains(&placeholder) {
- new_condition = new_condition.replace(&placeholder, if *value { "1" } else { "0" });
- }
- pref.condition = Some(new_condition.clone());
- }
- }
}
}