@1sat/wallet-toolbox 0.0.66 → 0.0.69

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.
@@ -95,32 +95,33 @@ export async function createWebWallet(config) {
95
95
  // Add remote storage to the existing storage manager using public API
96
96
  await storage.addWalletStorageProvider(remoteClient);
97
97
  console.log("[createWebWallet] Remote storage connected successfully");
98
- // Pull changes from remote to sync with other devices
99
- console.log("[createWebWallet] Syncing from remote...");
100
- const syncResult = await storage.syncFromReader(identityPubKey, remoteClient);
101
- console.log(`[createWebWallet] Synced from remote: ${syncResult.inserts} inserts, ${syncResult.updates} updates`);
98
+ // Bidirectional sync: pull first, then push
99
+ // Pull builds idMap via natural key matching (reference for transactions)
100
+ // Push sends local changes to remote
101
+ console.log("[createWebWallet] Pulling from remote...");
102
+ const pullResult = await storage.syncFromReader(identityPubKey, remoteClient);
103
+ console.log(`[createWebWallet] Pulled: ${pullResult.inserts} inserts, ${pullResult.updates} updates`);
104
+ console.log("[createWebWallet] Pushing to remote...");
105
+ await storage.updateBackups(undefined, (msg) => {
106
+ console.log("[createWebWallet] Push:", msg);
107
+ return msg;
108
+ });
109
+ console.log("[createWebWallet] Push complete");
102
110
  }
103
111
  catch (err) {
104
112
  console.log("[createWebWallet] Remote storage connection failed:", err instanceof Error ? err.message : err);
105
113
  remoteClient = undefined;
106
114
  }
107
115
  }
108
- // Log storage state using public APIs
109
- const stores = storage.getStores();
116
+ // Log storage state for debugging
110
117
  console.log("[createWebWallet] Storage state:", {
111
118
  activeKey: storage.getActiveStore(),
112
- backups: storage.getBackupStores(),
113
- conflictingActives: storage.getConflictingStores(),
119
+ backups: storage.getBackupStores().length,
120
+ conflictingActives: storage.getConflictingStores().length,
114
121
  isActiveEnabled: storage.isActiveEnabled,
115
- allStores: stores.map((s) => ({
116
- name: s.storageName,
117
- key: s.storageIdentityKey.slice(0, 16) + "...",
118
- })),
119
122
  });
120
- // 7. Handle conflicting actives or sync to backups
121
- let conflictingStores = storage.getConflictingStores();
122
- let backupStores = storage.getBackupStores();
123
- if (conflictingStores.length > 0) {
123
+ // Handle conflicting actives - must resolve before wallet can function
124
+ if (storage.getConflictingStores().length > 0) {
124
125
  const localKey = storage.getActiveStore();
125
126
  console.log("[createWebWallet] Resolving conflicting actives...");
126
127
  try {
@@ -131,40 +132,50 @@ export async function createWebWallet(config) {
131
132
  console.log("[createWebWallet] Conflict resolution complete");
132
133
  }
133
134
  catch (err) {
134
- console.log("[createWebWallet] Conflict resolution failed:", err instanceof Error ? err.message : err);
135
- // FALLBACK: If conflict resolution fails, operate in local-only mode
136
- // This allows the wallet to function even when remote sync is broken
137
- console.log("[createWebWallet] Falling back to local-only mode (remote disabled)");
138
- // Recreate storage manager with only local storage to clear conflicts
139
- storage = new WalletStorageManager(identityPubKey, localStorage, []);
140
- await storage.makeAvailable();
141
- // Update the wallet's storage reference
142
- underlyingWallet.storage = storage;
135
+ console.log("[createWebWallet] Conflict resolution failed, falling back to local-only:", err instanceof Error ? err.message : err);
143
136
  remoteClient = undefined;
144
- // Refresh conflict state
145
- conflictingStores = storage.getConflictingStores();
146
- backupStores = storage.getBackupStores();
147
- console.log("[createWebWallet] Local-only mode active, isActiveEnabled:", storage.isActiveEnabled);
148
137
  }
149
138
  }
150
- else if (backupStores.length > 0) {
151
- // No conflicts - push local state to remote backup (fire-and-forget)
152
- console.log("[createWebWallet] Pushing local state to remote backup...");
153
- storage
154
- .updateBackups(undefined, (msg) => {
155
- console.log("[createWebWallet] Backup:", msg);
156
- return msg;
157
- })
158
- .then(() => {
159
- console.log("[createWebWallet] Backup complete");
160
- })
161
- .catch((err) => {
162
- console.log("[createWebWallet] Backup failed:", err instanceof Error ? err.message : err);
163
- });
139
+ // Helper to sync to remote backup using public updateBackups API
140
+ const syncToBackup = async (context) => {
141
+ if (storage.getBackupStores().length > 0) {
142
+ await storage.updateBackups(undefined, (msg) => {
143
+ console.log(`[createWebWallet] ${context}:`, msg);
144
+ return msg;
145
+ });
146
+ }
147
+ };
148
+ // 8. Intercept createAction/signAction to sync after immediate broadcasts
149
+ // With acceptDelayedBroadcast: false, broadcasts happen synchronously and
150
+ // bypass the monitor's onTransactionBroadcasted callback. We detect broadcasts
151
+ // by checking for txid in the result and sync to backup immediately.
152
+ if (remoteClient) {
153
+ const originalCreateAction = underlyingWallet.createAction.bind(underlyingWallet);
154
+ underlyingWallet.createAction = async (args) => {
155
+ const result = await originalCreateAction(args);
156
+ if (result.txid) {
157
+ console.log("[createWebWallet] Broadcast detected in createAction:", result.txid);
158
+ syncToBackup("Backup after createAction").catch((err) => {
159
+ console.warn("[createWebWallet] Failed to sync after createAction:", err);
160
+ });
161
+ }
162
+ return result;
163
+ };
164
+ const originalSignAction = underlyingWallet.signAction.bind(underlyingWallet);
165
+ underlyingWallet.signAction = async (args) => {
166
+ const result = await originalSignAction(args);
167
+ if (result.txid) {
168
+ console.log("[createWebWallet] Broadcast detected in signAction:", result.txid);
169
+ syncToBackup("Backup after signAction").catch((err) => {
170
+ console.warn("[createWebWallet] Failed to sync after signAction:", err);
171
+ });
172
+ }
173
+ return result;
174
+ };
164
175
  }
165
- // 8. Wrap with permissions manager
176
+ // 9. Wrap with permissions manager
166
177
  const wallet = new WalletPermissionsManager(underlyingWallet, adminOriginator, permissionsConfig);
167
- // 9. Create monitor (not started - consumer calls startTasks() when ready)
178
+ // 10. Create monitor (not started - consumer calls startTasks() when ready)
168
179
  const monitor = new Monitor({
169
180
  chain,
170
181
  services: oneSatServices,
@@ -178,26 +189,20 @@ export async function createWebWallet(config) {
178
189
  });
179
190
  monitor.addDefaultTasks();
180
191
  console.log("[createWebWallet] Monitor created with tasks:", monitor["_tasks"].map((t) => t.name));
181
- // Helper to sync to remote backup using public updateBackups API
182
- const syncToBackup = async (context) => {
183
- if (storage.getBackupStores().length > 0) {
184
- await storage.updateBackups(undefined, (msg) => {
185
- console.log(`[Monitor] ${context}:`, msg);
186
- return msg;
187
- });
188
- }
189
- };
190
- // 10. Wire up monitor callbacks - sync to remote first, then call user callbacks
192
+ // 11. Wire up monitor callbacks - sync to remote first, then call user callbacks
193
+ // Note: For delayed broadcasts, the monitor triggers these. For immediate broadcasts,
194
+ // the interception in step 8 handles the sync, but these still fire for the user callback.
191
195
  monitor.onTransactionBroadcasted = async (result) => {
192
- console.log("[Monitor] Transaction broadcasted:", result.txid);
196
+ console.log("[createWebWallet] Monitor detected broadcast:", result.txid);
193
197
  // Sync to remote backup first (if connected)
198
+ // Note: For immediate broadcasts, step 8 already synced, but this is harmless
194
199
  if (remoteClient) {
195
200
  try {
196
- await syncToBackup("Backup after broadcast");
197
- console.log("[Monitor] Synced to backup after broadcast");
201
+ await syncToBackup("Backup after monitor broadcast");
202
+ console.log("[createWebWallet] Synced to backup after monitor broadcast");
198
203
  }
199
204
  catch (err) {
200
- console.warn("[Monitor] Failed to sync after broadcast:", err);
205
+ console.warn("[createWebWallet] Failed to sync after monitor broadcast:", err);
201
206
  }
202
207
  }
203
208
  // Then call user callback (if provided)
@@ -206,20 +211,20 @@ export async function createWebWallet(config) {
206
211
  config.onTransactionBroadcasted(result.txid);
207
212
  }
208
213
  catch (err) {
209
- console.warn("[Monitor] User callback error after broadcast:", err);
214
+ console.warn("[createWebWallet] User callback error after broadcast:", err);
210
215
  }
211
216
  }
212
217
  };
213
218
  monitor.onTransactionProven = async (status) => {
214
- console.log("[Monitor] Transaction proven:", status.txid, "block", status.blockHeight);
219
+ console.log("[createWebWallet] Transaction proven:", status.txid, "block", status.blockHeight);
215
220
  // Sync to remote backup first (if connected)
216
221
  if (remoteClient) {
217
222
  try {
218
223
  await syncToBackup("Backup after confirmation");
219
- console.log("[Monitor] Synced to backup after confirmation");
224
+ console.log("[createWebWallet] Synced to backup after confirmation");
220
225
  }
221
226
  catch (err) {
222
- console.warn("[Monitor] Failed to sync after confirmation:", err);
227
+ console.warn("[createWebWallet] Failed to sync after confirmation:", err);
223
228
  }
224
229
  }
225
230
  // Then call user callback (if provided)
@@ -228,17 +233,17 @@ export async function createWebWallet(config) {
228
233
  config.onTransactionProven(status.txid, status.blockHeight);
229
234
  }
230
235
  catch (err) {
231
- console.warn("[Monitor] User callback error after proven:", err);
236
+ console.warn("[createWebWallet] User callback error after proven:", err);
232
237
  }
233
238
  }
234
239
  };
235
- // 11. Create cleanup function
240
+ // 12. Create cleanup function
236
241
  const destroy = async () => {
237
242
  monitor.stopTasks();
238
243
  await monitor.destroy();
239
244
  await underlyingWallet.destroy();
240
245
  };
241
- // 12. Create fullSync function if remote storage is connected
246
+ // 13. Create fullSync function if remote storage is connected
242
247
  const fullSyncFn = remoteClient
243
248
  ? async (onProgress) => {
244
249
  return fullSync({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1sat/wallet-toolbox",
3
- "version": "0.0.66",
3
+ "version": "0.0.69",
4
4
  "description": "BSV wallet library extending @bsv/wallet-toolbox with 1Sat Ordinals protocol support",
5
5
  "author": "1Sat Team",
6
6
  "license": "MIT",