@thru/wallet-store 0.2.1 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -77,7 +77,7 @@ declare class ConnectedAppsStorage {
77
77
  declare function getUnifiedDB(): Promise<IDBPDatabase>;
78
78
 
79
79
  declare const DB_NAME = "thru-wallet";
80
- declare const DB_VERSION = 1;
80
+ declare const DB_VERSION = 3;
81
81
  declare enum StoreName {
82
82
  CONNECTED_APPS = "connectedApps",
83
83
  ACCOUNTS = "accounts",
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { openDB } from 'idb';
4
4
 
5
5
  // src/schema.ts
6
6
  var DB_NAME = "thru-wallet";
7
- var DB_VERSION = 1;
7
+ var DB_VERSION = 3;
8
8
  var StoreName = /* @__PURE__ */ ((StoreName2) => {
9
9
  StoreName2["CONNECTED_APPS"] = "connectedApps";
10
10
  StoreName2["ACCOUNTS"] = "accounts";
@@ -12,12 +12,18 @@ var StoreName = /* @__PURE__ */ ((StoreName2) => {
12
12
  return StoreName2;
13
13
  })(StoreName || {});
14
14
  function initializeSchema(db) {
15
- const connectedApps = db.createObjectStore("connectedApps" /* CONNECTED_APPS */, { keyPath: "key" });
16
- connectedApps.createIndex("by-account", "accountId", { unique: false });
17
- connectedApps.createIndex("by-updated", "updatedAt", { unique: false });
18
- const accounts = db.createObjectStore("accounts" /* ACCOUNTS */, { keyPath: "index" });
19
- accounts.createIndex("by-created", "createdAt", { unique: false });
20
- db.createObjectStore("passkeyProfiles" /* PASSKEY_PROFILES */, { keyPath: "id" });
15
+ if (!db.objectStoreNames.contains("connectedApps" /* CONNECTED_APPS */)) {
16
+ const connectedApps = db.createObjectStore("connectedApps" /* CONNECTED_APPS */, { keyPath: "key" });
17
+ connectedApps.createIndex("by-account", "accountId", { unique: false });
18
+ connectedApps.createIndex("by-updated", "updatedAt", { unique: false });
19
+ }
20
+ if (!db.objectStoreNames.contains("accounts" /* ACCOUNTS */)) {
21
+ const accounts = db.createObjectStore("accounts" /* ACCOUNTS */, { keyPath: "index" });
22
+ accounts.createIndex("by-created", "createdAt", { unique: false });
23
+ }
24
+ if (!db.objectStoreNames.contains("passkeyProfiles" /* PASSKEY_PROFILES */)) {
25
+ db.createObjectStore("passkeyProfiles" /* PASSKEY_PROFILES */, { keyPath: "id" });
26
+ }
21
27
  }
22
28
 
23
29
  // src/db.ts
@@ -210,7 +216,8 @@ async function savePasskeyProfiles(store) {
210
216
  await tx.store.put(settings);
211
217
  await tx.done;
212
218
  return true;
213
- } catch {
219
+ } catch (error) {
220
+ console.error("[wallet-store] Failed to save passkey profiles:", error);
214
221
  return false;
215
222
  }
216
223
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/schema.ts","../src/db.ts","../src/account-store.ts","../src/connected-apps-store.ts","../src/passkey-profiles.ts"],"names":["StoreName","STORE_NAME"],"mappings":"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","file":"index.js","sourcesContent":["import type { AppMetadata } from '@thru/chain-interfaces';\n\nexport const DB_NAME = 'thru-wallet';\nexport const DB_VERSION = 1;\n\nexport enum StoreName {\n CONNECTED_APPS = 'connectedApps',\n ACCOUNTS = 'accounts',\n PASSKEY_PROFILES = 'passkeyProfiles',\n}\n\nexport interface ConnectedAppData {\n key: string; // `${accountId}:${appId}`\n accountId: number;\n appId: string;\n origin: string;\n metadata: AppMetadata;\n connectedAt: number;\n updatedAt: number;\n}\n\n/**\n * Initialize database schema.\n */\nexport function initializeSchema(db: IDBDatabase): void {\n const connectedApps = db.createObjectStore(StoreName.CONNECTED_APPS, { keyPath: 'key' });\n connectedApps.createIndex('by-account', 'accountId', { unique: false });\n connectedApps.createIndex('by-updated', 'updatedAt', { unique: false });\n\n const accounts = db.createObjectStore(StoreName.ACCOUNTS, { keyPath: 'index' });\n accounts.createIndex('by-created', 'createdAt', { unique: false });\n\n db.createObjectStore(StoreName.PASSKEY_PROFILES, { keyPath: 'id' });\n}\n","import { openDB, type IDBPDatabase } from 'idb';\nimport { DB_NAME, DB_VERSION, initializeSchema } from './schema';\n\nlet dbPromise: Promise<IDBPDatabase> | null = null;\n\n/**\n * Returns the shared unified database connection.\n */\nexport function getUnifiedDB(): Promise<IDBPDatabase> {\n if (!dbPromise) {\n dbPromise = openDB(DB_NAME, DB_VERSION, {\n upgrade(db) {\n initializeSchema(db as unknown as IDBDatabase);\n },\n });\n }\n return dbPromise;\n}\n","import { getUnifiedDB } from './db';\nimport { StoreName } from './schema';\nimport { StoredAccount } from './types';\n\nconst STORE_NAME = StoreName.ACCOUNTS;\n\n/**\n * Account storage management using the unified IndexedDB.\n * Stores metadata for each derived account (but NOT private keys).\n */\nexport class AccountStorage {\n /**\n * Save a new account to storage\n */\n static async saveAccount(account: StoredAccount): Promise<void> {\n const db = await getUnifiedDB();\n await db.put(STORE_NAME, account);\n }\n\n /**\n * Get all accounts, sorted by index (ascending)\n */\n static async getAccounts(): Promise<StoredAccount[]> {\n const db = await getUnifiedDB();\n const accounts = await db.getAll(STORE_NAME) as StoredAccount[];\n return accounts.sort((a, b) => a.index - b.index);\n }\n\n /**\n * Get a specific account by index\n */\n static async getAccount(index: number): Promise<StoredAccount | null> {\n const db = await getUnifiedDB();\n const account = await db.get(STORE_NAME, index) as StoredAccount | undefined;\n return account || null;\n }\n\n /**\n * Update an account's label\n */\n static async updateAccountLabel(index: number, label: string): Promise<void> {\n const db = await getUnifiedDB();\n const account = await db.get(STORE_NAME, index) as StoredAccount | undefined;\n\n if (!account) {\n throw new Error(`Account ${index} not found`);\n }\n\n account.label = label;\n await db.put(STORE_NAME, account);\n }\n\n /**\n * Get the next available account index\n */\n static async getNextAccountIndex(): Promise<number> {\n const accounts = await this.getAccounts();\n\n if (accounts.length === 0) {\n return 0;\n }\n\n const maxIndex = Math.max(...accounts.map(a => a.index));\n return maxIndex + 1;\n }\n\n /**\n * Check if any accounts exist\n */\n static async hasAccounts(): Promise<boolean> {\n const db = await getUnifiedDB();\n const count = await db.count(STORE_NAME);\n return count > 0;\n }\n\n /**\n * Get total number of accounts\n */\n static async getAccountCount(): Promise<number> {\n const db = await getUnifiedDB();\n return await db.count(STORE_NAME);\n }\n\n /**\n * Clear all accounts (use with caution!)\n */\n static async clearAccounts(): Promise<void> {\n const db = await getUnifiedDB();\n await db.clear(STORE_NAME);\n }\n}\n","import { getUnifiedDB } from './db';\nimport {\n StoreName,\n type ConnectedAppData,\n} from './schema';\nimport type { ConnectedApp, AppMetadata } from '@thru/chain-interfaces';\n\nconst STORE_NAME = StoreName.CONNECTED_APPS;\n\nfunction createKey(accountId: number, appId: string): string {\n return `${accountId}:${appId}`;\n}\n\nfunction toDomain(record: ConnectedAppData): ConnectedApp {\n return {\n accountId: record.accountId,\n appId: record.appId,\n origin: record.origin,\n metadata: record.metadata,\n connectedAt: record.connectedAt,\n updatedAt: record.updatedAt,\n };\n}\n\nexport interface ConnectedAppUpsert {\n accountId: number;\n appId: string;\n origin: string;\n metadata: AppMetadata;\n}\n\n/**\n * Storage helper for connected dApps per account\n */\nexport class ConnectedAppsStorage {\n private static async getDB() {\n return getUnifiedDB();\n }\n\n static async upsert(app: ConnectedAppUpsert): Promise<ConnectedApp> {\n const db = await this.getDB();\n const key = createKey(app.accountId, app.appId);\n const existing = (await db.get(STORE_NAME, key)) as ConnectedAppData | undefined;\n const now = Date.now();\n\n const record: ConnectedAppData = {\n key,\n accountId: app.accountId,\n appId: app.appId,\n origin: app.origin,\n metadata: app.metadata,\n connectedAt: existing?.connectedAt ?? now,\n updatedAt: now,\n };\n\n await db.put(STORE_NAME, record);\n return toDomain(record);\n }\n\n static async listByAccount(accountId: number): Promise<ConnectedApp[]> {\n const db = await this.getDB();\n const records = (await db.getAllFromIndex(STORE_NAME, 'by-account', IDBKeyRange.only(accountId))) as ConnectedAppData[];\n return records\n .sort((a, b) => b.updatedAt - a.updatedAt)\n .map(toDomain);\n }\n\n static async remove(accountId: number, appId: string): Promise<void> {\n const db = await this.getDB();\n await db.delete(STORE_NAME, createKey(accountId, appId));\n }\n\n static async clear(): Promise<void> {\n const db = await this.getDB();\n await db.clear(STORE_NAME);\n }\n\n static async get(accountId: number, appId: string): Promise<ConnectedApp | null> {\n const db = await this.getDB();\n const record = (await db.get(STORE_NAME, createKey(accountId, appId))) as ConnectedAppData | undefined;\n return record ? toDomain(record) : null;\n }\n}\n","import { getUnifiedDB } from './db';\nimport { StoreName } from './schema';\nimport type { PasskeyProfileRecord, PasskeyStoreSettings } from './types';\n\nconst CURRENT_PROFILE_VERSION = 1;\nconst SETTINGS_KEY = 'settings';\n\nexport interface PasskeyMetadata {\n credentialId: string;\n publicKeyX: string;\n publicKeyY: string;\n rpId: string;\n label?: string;\n createdAt: string;\n lastUsedAt: string;\n}\n\nexport interface PasskeyProfile {\n id: string;\n label: string;\n passkey: PasskeyMetadata | null;\n createdAt: string;\n lastUsedAt: string | null;\n}\n\nexport interface PasskeyProfileStore {\n profiles: PasskeyProfile[];\n selectedIndex: number;\n}\n\n/**\n * Load all passkey profiles and settings from IndexedDB.\n * Returns null if no profiles exist or if the DB is unavailable.\n */\nexport async function loadPasskeyProfiles(): Promise<PasskeyProfileStore | null> {\n if (typeof window === 'undefined') return null;\n\n try {\n const db = await getUnifiedDB();\n const allRecords = await db.getAll(StoreName.PASSKEY_PROFILES);\n\n let settings: PasskeyStoreSettings | null = null;\n const profiles: PasskeyProfile[] = [];\n\n for (const record of allRecords) {\n if (record.id === SETTINGS_KEY) {\n settings = record as PasskeyStoreSettings;\n } else if (record.id) {\n profiles.push(record as PasskeyProfile);\n }\n }\n\n if (profiles.length === 0) return null;\n\n // Run schema migration if needed\n if (settings && settings.version < CURRENT_PROFILE_VERSION) {\n migrateProfiles(profiles, settings.version);\n settings = { ...settings, version: CURRENT_PROFILE_VERSION };\n await db.put(StoreName.PASSKEY_PROFILES, settings);\n }\n\n return {\n profiles,\n selectedIndex: settings?.selectedIndex ?? 0,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Save all passkey profiles and settings to IndexedDB.\n * Returns true on success, false on failure.\n */\nexport async function savePasskeyProfiles(store: PasskeyProfileStore): Promise<boolean> {\n if (typeof window === 'undefined') return false;\n\n try {\n const db = await getUnifiedDB();\n const tx = db.transaction(StoreName.PASSKEY_PROFILES, 'readwrite');\n\n // Clear all existing records\n await tx.store.clear();\n\n // Write profiles\n for (const profile of store.profiles) {\n await tx.store.put(profile as PasskeyProfileRecord);\n }\n\n // Write settings\n const settings: PasskeyStoreSettings = {\n id: SETTINGS_KEY,\n selectedIndex: store.selectedIndex,\n version: CURRENT_PROFILE_VERSION,\n };\n await tx.store.put(settings);\n\n await tx.done;\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Create a default profile store with one empty profile.\n */\nexport function createDefaultProfileStore(): PasskeyProfileStore {\n const now = new Date().toISOString();\n const profileId = typeof crypto !== 'undefined' && 'randomUUID' in crypto\n ? crypto.randomUUID()\n : String(Date.now());\n\n return {\n profiles: [\n {\n id: profileId,\n label: 'Default Profile',\n passkey: null,\n createdAt: now,\n lastUsedAt: null,\n },\n ],\n selectedIndex: 0,\n };\n}\n\n/**\n * Update a profile's passkey metadata (pure in-memory transform).\n */\nexport function updateProfilePasskey(\n store: PasskeyProfileStore,\n profileIndex: number,\n passkey: PasskeyMetadata\n): PasskeyProfileStore {\n const updatedProfiles = [...store.profiles];\n const current = updatedProfiles[profileIndex];\n if (!current) {\n return store;\n }\n\n updatedProfiles[profileIndex] = {\n ...current,\n passkey,\n lastUsedAt: passkey.lastUsedAt,\n };\n\n return {\n ...store,\n profiles: updatedProfiles,\n };\n}\n\n/**\n * Update lastUsedAt timestamp for a profile's passkey (pure in-memory transform).\n */\nexport function updatePasskeyLastUsed(\n store: PasskeyProfileStore,\n profileIndex: number\n): PasskeyProfileStore {\n const updatedProfiles = [...store.profiles];\n const current = updatedProfiles[profileIndex];\n if (!current?.passkey) {\n return store;\n }\n\n const now = new Date().toISOString();\n updatedProfiles[profileIndex] = {\n ...current,\n passkey: {\n ...current.passkey,\n lastUsedAt: now,\n },\n lastUsedAt: now,\n };\n\n return {\n ...store,\n profiles: updatedProfiles,\n };\n}\n\n/**\n * Migrate profile data from an older schema version to current.\n * Mutates profiles in-place for efficiency.\n */\nfunction migrateProfiles(_profiles: PasskeyProfile[], _fromVersion: number): void {\n // Currently at version 1, no migrations needed yet.\n // Future migrations would go here:\n // if (fromVersion < 2) { ... }\n}\n"]}
1
+ {"version":3,"sources":["../src/schema.ts","../src/db.ts","../src/account-store.ts","../src/connected-apps-store.ts","../src/passkey-profiles.ts"],"names":["StoreName","STORE_NAME"],"mappings":"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","file":"index.js","sourcesContent":["import type { AppMetadata } from '@thru/chain-interfaces';\n\nexport const DB_NAME = 'thru-wallet';\nexport const DB_VERSION = 3;\n\nexport enum StoreName {\n CONNECTED_APPS = 'connectedApps',\n ACCOUNTS = 'accounts',\n PASSKEY_PROFILES = 'passkeyProfiles',\n}\n\nexport interface ConnectedAppData {\n key: string; // `${accountId}:${appId}`\n accountId: number;\n appId: string;\n origin: string;\n metadata: AppMetadata;\n connectedAt: number;\n updatedAt: number;\n}\n\n/**\n * Initialize database schema.\n */\nexport function initializeSchema(db: IDBDatabase): void {\n if (!db.objectStoreNames.contains(StoreName.CONNECTED_APPS)) {\n const connectedApps = db.createObjectStore(StoreName.CONNECTED_APPS, { keyPath: 'key' });\n connectedApps.createIndex('by-account', 'accountId', { unique: false });\n connectedApps.createIndex('by-updated', 'updatedAt', { unique: false });\n }\n\n if (!db.objectStoreNames.contains(StoreName.ACCOUNTS)) {\n const accounts = db.createObjectStore(StoreName.ACCOUNTS, { keyPath: 'index' });\n accounts.createIndex('by-created', 'createdAt', { unique: false });\n }\n\n if (!db.objectStoreNames.contains(StoreName.PASSKEY_PROFILES)) {\n db.createObjectStore(StoreName.PASSKEY_PROFILES, { keyPath: 'id' });\n }\n}\n","import { openDB, type IDBPDatabase } from 'idb';\nimport { DB_NAME, DB_VERSION, initializeSchema } from './schema';\n\nlet dbPromise: Promise<IDBPDatabase> | null = null;\n\n/**\n * Returns the shared unified database connection.\n */\nexport function getUnifiedDB(): Promise<IDBPDatabase> {\n if (!dbPromise) {\n dbPromise = openDB(DB_NAME, DB_VERSION, {\n upgrade(db) {\n initializeSchema(db as unknown as IDBDatabase);\n },\n });\n }\n return dbPromise;\n}\n","import { getUnifiedDB } from './db';\nimport { StoreName } from './schema';\nimport { StoredAccount } from './types';\n\nconst STORE_NAME = StoreName.ACCOUNTS;\n\n/**\n * Account storage management using the unified IndexedDB.\n * Stores metadata for each derived account (but NOT private keys).\n */\nexport class AccountStorage {\n /**\n * Save a new account to storage\n */\n static async saveAccount(account: StoredAccount): Promise<void> {\n const db = await getUnifiedDB();\n await db.put(STORE_NAME, account);\n }\n\n /**\n * Get all accounts, sorted by index (ascending)\n */\n static async getAccounts(): Promise<StoredAccount[]> {\n const db = await getUnifiedDB();\n const accounts = await db.getAll(STORE_NAME) as StoredAccount[];\n return accounts.sort((a, b) => a.index - b.index);\n }\n\n /**\n * Get a specific account by index\n */\n static async getAccount(index: number): Promise<StoredAccount | null> {\n const db = await getUnifiedDB();\n const account = await db.get(STORE_NAME, index) as StoredAccount | undefined;\n return account || null;\n }\n\n /**\n * Update an account's label\n */\n static async updateAccountLabel(index: number, label: string): Promise<void> {\n const db = await getUnifiedDB();\n const account = await db.get(STORE_NAME, index) as StoredAccount | undefined;\n\n if (!account) {\n throw new Error(`Account ${index} not found`);\n }\n\n account.label = label;\n await db.put(STORE_NAME, account);\n }\n\n /**\n * Get the next available account index\n */\n static async getNextAccountIndex(): Promise<number> {\n const accounts = await this.getAccounts();\n\n if (accounts.length === 0) {\n return 0;\n }\n\n const maxIndex = Math.max(...accounts.map(a => a.index));\n return maxIndex + 1;\n }\n\n /**\n * Check if any accounts exist\n */\n static async hasAccounts(): Promise<boolean> {\n const db = await getUnifiedDB();\n const count = await db.count(STORE_NAME);\n return count > 0;\n }\n\n /**\n * Get total number of accounts\n */\n static async getAccountCount(): Promise<number> {\n const db = await getUnifiedDB();\n return await db.count(STORE_NAME);\n }\n\n /**\n * Clear all accounts (use with caution!)\n */\n static async clearAccounts(): Promise<void> {\n const db = await getUnifiedDB();\n await db.clear(STORE_NAME);\n }\n}\n","import { getUnifiedDB } from './db';\nimport {\n StoreName,\n type ConnectedAppData,\n} from './schema';\nimport type { ConnectedApp, AppMetadata } from '@thru/chain-interfaces';\n\nconst STORE_NAME = StoreName.CONNECTED_APPS;\n\nfunction createKey(accountId: number, appId: string): string {\n return `${accountId}:${appId}`;\n}\n\nfunction toDomain(record: ConnectedAppData): ConnectedApp {\n return {\n accountId: record.accountId,\n appId: record.appId,\n origin: record.origin,\n metadata: record.metadata,\n connectedAt: record.connectedAt,\n updatedAt: record.updatedAt,\n };\n}\n\nexport interface ConnectedAppUpsert {\n accountId: number;\n appId: string;\n origin: string;\n metadata: AppMetadata;\n}\n\n/**\n * Storage helper for connected dApps per account\n */\nexport class ConnectedAppsStorage {\n private static async getDB() {\n return getUnifiedDB();\n }\n\n static async upsert(app: ConnectedAppUpsert): Promise<ConnectedApp> {\n const db = await this.getDB();\n const key = createKey(app.accountId, app.appId);\n const existing = (await db.get(STORE_NAME, key)) as ConnectedAppData | undefined;\n const now = Date.now();\n\n const record: ConnectedAppData = {\n key,\n accountId: app.accountId,\n appId: app.appId,\n origin: app.origin,\n metadata: app.metadata,\n connectedAt: existing?.connectedAt ?? now,\n updatedAt: now,\n };\n\n await db.put(STORE_NAME, record);\n return toDomain(record);\n }\n\n static async listByAccount(accountId: number): Promise<ConnectedApp[]> {\n const db = await this.getDB();\n const records = (await db.getAllFromIndex(STORE_NAME, 'by-account', IDBKeyRange.only(accountId))) as ConnectedAppData[];\n return records\n .sort((a, b) => b.updatedAt - a.updatedAt)\n .map(toDomain);\n }\n\n static async remove(accountId: number, appId: string): Promise<void> {\n const db = await this.getDB();\n await db.delete(STORE_NAME, createKey(accountId, appId));\n }\n\n static async clear(): Promise<void> {\n const db = await this.getDB();\n await db.clear(STORE_NAME);\n }\n\n static async get(accountId: number, appId: string): Promise<ConnectedApp | null> {\n const db = await this.getDB();\n const record = (await db.get(STORE_NAME, createKey(accountId, appId))) as ConnectedAppData | undefined;\n return record ? toDomain(record) : null;\n }\n}\n","import { getUnifiedDB } from './db';\nimport { StoreName } from './schema';\nimport type { PasskeyProfileRecord, PasskeyStoreSettings } from './types';\n\nconst CURRENT_PROFILE_VERSION = 1;\nconst SETTINGS_KEY = 'settings';\n\nexport interface PasskeyMetadata {\n credentialId: string;\n publicKeyX: string;\n publicKeyY: string;\n rpId: string;\n label?: string;\n createdAt: string;\n lastUsedAt: string;\n}\n\nexport interface PasskeyProfile {\n id: string;\n label: string;\n passkey: PasskeyMetadata | null;\n createdAt: string;\n lastUsedAt: string | null;\n}\n\nexport interface PasskeyProfileStore {\n profiles: PasskeyProfile[];\n selectedIndex: number;\n}\n\n/**\n * Load all passkey profiles and settings from IndexedDB.\n * Returns null if no profiles exist or if the DB is unavailable.\n */\nexport async function loadPasskeyProfiles(): Promise<PasskeyProfileStore | null> {\n if (typeof window === 'undefined') return null;\n\n try {\n const db = await getUnifiedDB();\n const allRecords = await db.getAll(StoreName.PASSKEY_PROFILES);\n\n let settings: PasskeyStoreSettings | null = null;\n const profiles: PasskeyProfile[] = [];\n\n for (const record of allRecords) {\n if (record.id === SETTINGS_KEY) {\n settings = record as PasskeyStoreSettings;\n } else if (record.id) {\n profiles.push(record as PasskeyProfile);\n }\n }\n\n if (profiles.length === 0) return null;\n\n // Run schema migration if needed\n if (settings && settings.version < CURRENT_PROFILE_VERSION) {\n migrateProfiles(profiles, settings.version);\n settings = { ...settings, version: CURRENT_PROFILE_VERSION };\n await db.put(StoreName.PASSKEY_PROFILES, settings);\n }\n\n return {\n profiles,\n selectedIndex: settings?.selectedIndex ?? 0,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Save all passkey profiles and settings to IndexedDB.\n * Returns true on success, false on failure.\n */\nexport async function savePasskeyProfiles(store: PasskeyProfileStore): Promise<boolean> {\n if (typeof window === 'undefined') return false;\n\n try {\n const db = await getUnifiedDB();\n const tx = db.transaction(StoreName.PASSKEY_PROFILES, 'readwrite');\n\n // Clear all existing records\n await tx.store.clear();\n\n // Write profiles\n for (const profile of store.profiles) {\n await tx.store.put(profile as PasskeyProfileRecord);\n }\n\n // Write settings\n const settings: PasskeyStoreSettings = {\n id: SETTINGS_KEY,\n selectedIndex: store.selectedIndex,\n version: CURRENT_PROFILE_VERSION,\n };\n await tx.store.put(settings);\n\n await tx.done;\n return true;\n } catch (error) {\n console.error('[wallet-store] Failed to save passkey profiles:', error);\n return false;\n }\n}\n\n/**\n * Create a default profile store with one empty profile.\n */\nexport function createDefaultProfileStore(): PasskeyProfileStore {\n const now = new Date().toISOString();\n const profileId = typeof crypto !== 'undefined' && 'randomUUID' in crypto\n ? crypto.randomUUID()\n : String(Date.now());\n\n return {\n profiles: [\n {\n id: profileId,\n label: 'Default Profile',\n passkey: null,\n createdAt: now,\n lastUsedAt: null,\n },\n ],\n selectedIndex: 0,\n };\n}\n\n/**\n * Update a profile's passkey metadata (pure in-memory transform).\n */\nexport function updateProfilePasskey(\n store: PasskeyProfileStore,\n profileIndex: number,\n passkey: PasskeyMetadata\n): PasskeyProfileStore {\n const updatedProfiles = [...store.profiles];\n const current = updatedProfiles[profileIndex];\n if (!current) {\n return store;\n }\n\n updatedProfiles[profileIndex] = {\n ...current,\n passkey,\n lastUsedAt: passkey.lastUsedAt,\n };\n\n return {\n ...store,\n profiles: updatedProfiles,\n };\n}\n\n/**\n * Update lastUsedAt timestamp for a profile's passkey (pure in-memory transform).\n */\nexport function updatePasskeyLastUsed(\n store: PasskeyProfileStore,\n profileIndex: number\n): PasskeyProfileStore {\n const updatedProfiles = [...store.profiles];\n const current = updatedProfiles[profileIndex];\n if (!current?.passkey) {\n return store;\n }\n\n const now = new Date().toISOString();\n updatedProfiles[profileIndex] = {\n ...current,\n passkey: {\n ...current.passkey,\n lastUsedAt: now,\n },\n lastUsedAt: now,\n };\n\n return {\n ...store,\n profiles: updatedProfiles,\n };\n}\n\n/**\n * Migrate profile data from an older schema version to current.\n * Mutates profiles in-place for efficiency.\n */\nfunction migrateProfiles(_profiles: PasskeyProfile[], _fromVersion: number): void {\n // Currently at version 1, no migrations needed yet.\n // Future migrations would go here:\n // if (fromVersion < 2) { ... }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thru/wallet-store",
3
- "version": "0.2.1",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "idb": "^8.0.3",
15
- "@thru/chain-interfaces": "0.2.1"
15
+ "@thru/chain-interfaces": "0.2.4"
16
16
  },
17
17
  "scripts": {
18
18
  "build": "tsup",
@@ -97,7 +97,8 @@ export async function savePasskeyProfiles(store: PasskeyProfileStore): Promise<b
97
97
 
98
98
  await tx.done;
99
99
  return true;
100
- } catch {
100
+ } catch (error) {
101
+ console.error('[wallet-store] Failed to save passkey profiles:', error);
101
102
  return false;
102
103
  }
103
104
  }
package/src/schema.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { AppMetadata } from '@thru/chain-interfaces';
2
2
 
3
3
  export const DB_NAME = 'thru-wallet';
4
- export const DB_VERSION = 1;
4
+ export const DB_VERSION = 3;
5
5
 
6
6
  export enum StoreName {
7
7
  CONNECTED_APPS = 'connectedApps',
@@ -23,12 +23,18 @@ export interface ConnectedAppData {
23
23
  * Initialize database schema.
24
24
  */
25
25
  export function initializeSchema(db: IDBDatabase): void {
26
- const connectedApps = db.createObjectStore(StoreName.CONNECTED_APPS, { keyPath: 'key' });
27
- connectedApps.createIndex('by-account', 'accountId', { unique: false });
28
- connectedApps.createIndex('by-updated', 'updatedAt', { unique: false });
26
+ if (!db.objectStoreNames.contains(StoreName.CONNECTED_APPS)) {
27
+ const connectedApps = db.createObjectStore(StoreName.CONNECTED_APPS, { keyPath: 'key' });
28
+ connectedApps.createIndex('by-account', 'accountId', { unique: false });
29
+ connectedApps.createIndex('by-updated', 'updatedAt', { unique: false });
30
+ }
29
31
 
30
- const accounts = db.createObjectStore(StoreName.ACCOUNTS, { keyPath: 'index' });
31
- accounts.createIndex('by-created', 'createdAt', { unique: false });
32
+ if (!db.objectStoreNames.contains(StoreName.ACCOUNTS)) {
33
+ const accounts = db.createObjectStore(StoreName.ACCOUNTS, { keyPath: 'index' });
34
+ accounts.createIndex('by-created', 'createdAt', { unique: false });
35
+ }
32
36
 
33
- db.createObjectStore(StoreName.PASSKEY_PROFILES, { keyPath: 'id' });
37
+ if (!db.objectStoreNames.contains(StoreName.PASSKEY_PROFILES)) {
38
+ db.createObjectStore(StoreName.PASSKEY_PROFILES, { keyPath: 'id' });
39
+ }
34
40
  }