fix: graceful recovery for IDB schema version conflict
When matrix-sdk is briefly upgraded then reverted, the local IndexedDB schema version is higher than the SDK expects. Detect the VersionError DOMException and show a clear 'Clear local data and reload' button instead of a cryptic error message.
This commit is contained in:
@@ -19,6 +19,7 @@ import React, { MouseEventHandler, ReactNode, useCallback, useEffect, useState }
|
|||||||
import {
|
import {
|
||||||
clearCacheAndReload,
|
clearCacheAndReload,
|
||||||
clearLoginData,
|
clearLoginData,
|
||||||
|
IDB_VERSION_CONFLICT,
|
||||||
initClient,
|
initClient,
|
||||||
logoutClient,
|
logoutClient,
|
||||||
startClient,
|
startClient,
|
||||||
@@ -201,16 +202,34 @@ export function ClientRoot({ children }: ClientRootProps) {
|
|||||||
<Dialog>
|
<Dialog>
|
||||||
<Box direction="Column" gap="400" style={{ padding: config.space.S400 }}>
|
<Box direction="Column" gap="400" style={{ padding: config.space.S400 }}>
|
||||||
{loadState.status === AsyncStatus.Error && (
|
{loadState.status === AsyncStatus.Error && (
|
||||||
<Text>{`Failed to load. ${loadState.error.message}`}</Text>
|
<>
|
||||||
|
{loadState.error.message === IDB_VERSION_CONFLICT ? (
|
||||||
|
<>
|
||||||
|
<Text>
|
||||||
|
Local data is from a newer app version and cannot be read. Clear local
|
||||||
|
data to continue (you will need to log in again).
|
||||||
|
</Text>
|
||||||
|
<Button variant="Critical" onClick={clearLoginData}>
|
||||||
|
<Text as="span" size="B400">
|
||||||
|
Clear local data and reload
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Text>{`Failed to load. ${loadState.error.message}`}</Text>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
{startState.status === AsyncStatus.Error && (
|
{startState.status === AsyncStatus.Error && (
|
||||||
<Text>{`Failed to start. ${startState.error.message}`}</Text>
|
<Text>{`Failed to start. ${startState.error.message}`}</Text>
|
||||||
)}
|
)}
|
||||||
<Button variant="Critical" onClick={mx ? () => startMatrix(mx) : loadMatrix}>
|
{loadState.error?.message !== IDB_VERSION_CONFLICT && (
|
||||||
<Text as="span" size="B400">
|
<Button variant="Critical" onClick={mx ? () => startMatrix(mx) : loadMatrix}>
|
||||||
Retry
|
<Text as="span" size="B400">
|
||||||
</Text>
|
Retry
|
||||||
</Button>
|
</Text>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ type Session = {
|
|||||||
deviceId: string;
|
deviceId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Thrown when the local IndexedDB has a higher schema version than this SDK expects.
|
||||||
|
// This happens after a downgrade (e.g. matrix-js-sdk was briefly upgraded and then reverted).
|
||||||
|
export const IDB_VERSION_CONFLICT = 'IDB_VERSION_CONFLICT';
|
||||||
|
|
||||||
export const initClient = async (session: Session): Promise<MatrixClient> => {
|
export const initClient = async (session: Session): Promise<MatrixClient> => {
|
||||||
const indexedDBStore = new IndexedDBStore({
|
const indexedDBStore = new IndexedDBStore({
|
||||||
indexedDB: global.indexedDB,
|
indexedDB: global.indexedDB,
|
||||||
@@ -32,7 +36,15 @@ export const initClient = async (session: Session): Promise<MatrixClient> => {
|
|||||||
verificationMethods: ['m.sas.v1'],
|
verificationMethods: ['m.sas.v1'],
|
||||||
});
|
});
|
||||||
|
|
||||||
await indexedDBStore.startup();
|
try {
|
||||||
|
await indexedDBStore.startup();
|
||||||
|
} catch (e) {
|
||||||
|
// IDB VersionError = local DB was written by a newer SDK version (schema downgrade).
|
||||||
|
if (e instanceof DOMException && e.name === 'VersionError') {
|
||||||
|
throw new Error(IDB_VERSION_CONFLICT);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
await mx.initRustCrypto();
|
await mx.initRustCrypto();
|
||||||
|
|
||||||
mx.setMaxListeners(50);
|
mx.setMaxListeners(50);
|
||||||
|
|||||||
Reference in New Issue
Block a user