taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 79f0e4637717d0b600343a366d7e8120b1ff3b36
parent 13120f507aaff31d9af336a7ef06216c5c88b2e0
Author: Florian Dold <dold@taler.net>
Date:   Thu, 20 Aug 2026 17:45:49 +0200

wallet-core: report database migration errors

Diffstat:
Mpackages/taler-util/src/notifications.ts | 2++
Mpackages/taler-wallet-core/src/db-indexeddb.ts | 2++
Mpackages/taler-wallet-core/src/db-native-migration.test.ts | 20+++++++++++++++++++-
Mpackages/taler-wallet-core/src/db-native-migration.ts | 8+++++++-
4 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/packages/taler-util/src/notifications.ts b/packages/taler-util/src/notifications.ts @@ -396,6 +396,8 @@ export interface DatabaseMaintenanceProgressNotification { processedRecords?: number; /** Total records in the whole migration, known before copying starts. */ totalRecords?: number; + /** Why the maintenance operation failed. Present when phase is failed. */ + error?: TalerErrorDetail; } export type WalletNotification = diff --git a/packages/taler-wallet-core/src/db-indexeddb.ts b/packages/taler-wallet-core/src/db-indexeddb.ts @@ -80,6 +80,7 @@ import { checkDbInvariant, codecForAny, encodeCrock, + getErrorDetailFromException, hash, j2s, stringToBytes, @@ -2211,6 +2212,7 @@ export async function applyFixups( step: fixupInstruction.name, completedSteps: index, totalSteps: walletDbFixups.length, + error: getErrorDetailFromException(e), }); } throw e; diff --git a/packages/taler-wallet-core/src/db-native-migration.test.ts b/packages/taler-wallet-core/src/db-native-migration.test.ts @@ -37,7 +37,11 @@ import { Sqlite3Database, } from "@gnu-taler/idb-bridge"; import { createNodeHelperSqlite3Impl } from "@gnu-taler/idb-bridge/node-helper-sqlite3-impl"; -import { NotificationType, WalletNotification } from "@gnu-taler/taler-util"; +import { + DatabaseMaintenanceProgressNotification, + NotificationType, + WalletNotification, +} from "@gnu-taler/taler-util"; import { dropExpiredMigrationBackup, @@ -324,7 +328,9 @@ test("native migration: an interrupted attempt restarts after reopening", async // progress. This leaves the same durable state as process termination: // untouched IndexedDB tables, a running marker and partial native rows. let interruptionInjected = false; + const progress: WalletNotification[] = []; first.handle.setNotificationSink((n) => { + progress.push(n); if ( !interruptionInjected && n.type === NotificationType.DatabaseMaintenanceProgress && @@ -344,6 +350,18 @@ test("native migration: an interrupted attempt restarts after reopening", async interruptionInjected, "migration was not interrupted after a copy", ); + const failed = progress.find( + (n): n is DatabaseMaintenanceProgressNotification => + n.type === NotificationType.DatabaseMaintenanceProgress && + n.operation === "indexeddb-to-native-migration" && + n.phase === "failed", + ); + assert.ok(failed, "interrupted migration did not report failure"); + assert.match( + failed.error?.hint ?? "", + /simulated migration interruption/, + "failed migration notification did not include the exception", + ); const interrupted = await inspectWalletDbFileDetails(first.db); assert.strictEqual(interrupted.kind, "indexeddb"); assert.ok(interrupted.nativeRecords > 0, "no partial native copy was left"); diff --git a/packages/taler-wallet-core/src/db-native-migration.ts b/packages/taler-wallet-core/src/db-native-migration.ts @@ -45,7 +45,12 @@ * away. {@link restoreMigrationBackup} is that statement. */ -import { Duration, Logger, NotificationType } from "@gnu-taler/taler-util"; +import { + Duration, + getErrorDetailFromException, + Logger, + NotificationType, +} from "@gnu-taler/taler-util"; import type { Sqlite3Database } from "@gnu-taler/idb-bridge"; import { @@ -459,6 +464,7 @@ export async function migrateWalletDbToNative( phase: "failed", completedSteps: 0, totalSteps: DB_CONVERSION_STEP_COUNT, + error: getErrorDetailFromException(e), }); throw e; }