diff --git a/source/background.ts b/source/background.ts index 454f71c..8429440 100644 --- a/source/background.ts +++ b/source/background.ts @@ -4,12 +4,14 @@ import { getManifest, getNextQItem, getSettings, + migrate, newQItemID, QItem, QMessage, removeQItem, saveSettings, - updateBadge + updateBadge, + versionAsNumber } from '.'; let timeoutID: number | null = null; @@ -61,17 +63,28 @@ browser.runtime.onMessage.addListener(async (request: QMessage) => { browser.runtime.onInstalled.addListener(async () => { const manifest = getManifest(); const settings = await getSettings(); + const versionGotUpdated = + versionAsNumber(manifest.version) > versionAsNumber(settings.latestVersion); + + if (versionGotUpdated) { + // Set the previous sync storage data in the local storage as a backup. + const previous = await browser.storage.sync.get(); + await browser.storage.local.clear(); + await browser.storage.local.set(previous); + + // Then migrate the sync storage data and update it. + const next = migrate(settings.latestVersion, previous); + next.latestVersion = manifest.version; + next.versionGotUpdated = versionGotUpdated; + + await browser.storage.sync.clear(); + await browser.storage.sync.set(next); + } // Open the options page when: // * The extension is first installed or is updated. // * In development, for convenience. - if ( - manifest.version !== settings.latestVersion || - manifest.nodeEnv === 'development' - ) { - settings.latestVersion = manifest.version; - settings.versionGotUpdated = true; - await saveSettings(settings); + if (versionGotUpdated || manifest.nodeEnv === 'development') { await openOptionsPage(); } }); diff --git a/source/utilities/index.ts b/source/utilities/index.ts index 6054ff2..6b3afef 100644 --- a/source/utilities/index.ts +++ b/source/utilities/index.ts @@ -73,5 +73,14 @@ export async function updateBadge(settings?: Settings): Promise { ]); } +/** + * Returns a version string as a number by removing the periods. + * @param version + */ +export function versionAsNumber(version: string): number { + return Number(version.replace(/\./g, '')); +} + export * from './components'; +export * from './migrations'; export * from './settings'; diff --git a/source/utilities/migrations/2020-11-26.ts b/source/utilities/migrations/2020-11-26.ts new file mode 100644 index 0000000..638d623 --- /dev/null +++ b/source/utilities/migrations/2020-11-26.ts @@ -0,0 +1,24 @@ +import {Migration, QItem} from '../..'; + +export const migration_2020_11_26: Migration = { + date: new Date('2020-11-26T14:32:00.000Z'), + version: '0.1.7', + upgrade +}; + +/** + * This upgrades the sync settings to use 'qi'-named objects for QItems instead + * of them being in an array. + * Relevant commit: a668da05a179851b2a1117ef2d6aa9cef48d4964 + */ +function upgrade(previous: Record): Record { + const items: QItem[] = previous.queue ?? []; + const next: Record = previous; + delete next.queue; + + for (const item of items) { + next['qi' + item.id.toString()] = item; + } + + return next; +} diff --git a/source/utilities/migrations/index.ts b/source/utilities/migrations/index.ts new file mode 100644 index 0000000..7e60af4 --- /dev/null +++ b/source/utilities/migrations/index.ts @@ -0,0 +1,30 @@ +import {log, versionAsNumber} from '../..'; +import {migration_2020_11_26} from './2020-11-26'; + +export type Migration = { + date: Date; + version: string; + upgrade: (previous: Record) => Record; +}; + +const migrations: Migration[] = [migration_2020_11_26]; + +export function migrate( + latestVersion: string, + previous: Record +): Record { + let next = previous; + + for (const migration of migrations) { + // If the saved version is >= the version from the migration, we've already + // handled it previously, so skip it. + if (versionAsNumber(latestVersion) >= versionAsNumber(migration.version)) { + continue; + } + + log(`Running migration ${migration.date.toISOString()}`); + next = migration.upgrade(previous); + } + + return next; +}