I’ve been digging around, and I can’t seem to figure out how to (within an extension) force a user’s sync storage to sync immediately. If I want this to happen, I have to manually go to my toolbar and click tools > Sync Now. Is there some way to do this that I’m just not finding?
I am currently just writing some JS that runs when the browser is on a particular website. My goal is to have data in my addon sync across devices for this website, but I’ve found that sometimes the automatic sync doesn’t happen quickly enough before I close the tab. I’d like to be able to ensure that a sync event happens.
As far as I know, there’s no way for an add-on to force Firefox to sync. I think they’d likely run into issues with add-ons causing Firefox sync to update too often if they gave that control.
As long as whatever you want to sync is written to the sync storage area using the Storage API, it should be automatically synced whenever the sync service refreshes, whether or not the tab is still open.
Gotcha. Does sync storage know to take only the most recent values? The problem I am having is that switching devices sometimes causes the storage sync to get overwritten by old data when it was loaded in before updating.
From what I can tell by the experiments I’ve conducted long time ago, the storage is pretty simple and it doesn’t check any dates so if you are not careful, you can override data easily.
The good news is, it will merge data stored on the TOP level. So if you store {"a": 0} on one device and {"b": 1} on the other one - both at the same time, then no matter who will sync first / second, the result in both should be {"a": 0, "b": 1}.
So if you are worried about conflicts, make sure to use different top level object for each device.
Also, the synchronization interval is pretty high on Firefox - something between few seconds to few minutes.
When you say to use different top-level objects for each device, is this usually done with some ID in local storage to retrieve the right?
And is there a typical way that these different device-specific objects can be chosen to determine which is the most recent in order to update them all, or do I need to implement that myself?
Could be, if you need to track which device did the change.
It all depends on your use case. You can for example generate UUID on each device (or just use a time stamp as ID, that should be unique enough).
The problem is only if two devices are writing to the same top level object, so as long as you are writing to the device specific object or to a unique object, you are fine. You can also read all other objects.
I had a following issue - I wanted to send text data from one device to another. Each device had own object in the store, let’s say like this:
If I wanted to send message from “123” to “124”, I couldn’t modify the other device object, because that’s against the rule above.
So instead I’ve created a new object:
Then when the device 124 synchronizes, it will load all store keys with “message_” prefix, check which of them are for him and move them from the top level to it’s own store object. That way no collisions can happen as long as the numbers are unique enough (I’ve been using timestamp for each message key).
EDIT:
You can also keep things in the top level, but there is a quota of 512 items, so that can be an issue.
I was actually using the getURL function as well, BUT !!! there is huge catch in Chrome where it uses the main Extension ID which is same on every device on every PC of every user! So you really should avoid it. Also in Safari it returns a different value every time you restart Safari. So as you can see, the value can be static / fixed / random , depending on the browser.
Also the crypto.randomUUID() I’ve mentioned is not available in current Firefox ESR 91.
So one has to use some polyfill .
I use this now:
// source: https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid
export function getRandomUUID() {
// @ts-ignore: TS doesn't know `randomUUID` yet, but it's supported by FF 95 and Chrome 92
if (crypto.randomUUID) return crypto.randomUUID();
return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, c => {
const x = parseInt(c);
return (x ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> x / 4)
.toString(16);
});
}