@arkade-os/sdk 0.3.0-alpha.5 → 0.3.0-alpha.6

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.
@@ -52,7 +52,7 @@ class WalletRepositoryImpl {
52
52
  try {
53
53
  const parsed = JSON.parse(stored);
54
54
  const vtxos = parsed.map(deserializeVtxo);
55
- this.cache.vtxos.set(address, vtxos);
55
+ this.cache.vtxos.set(address, vtxos.slice());
56
56
  return vtxos.slice();
57
57
  }
58
58
  catch (error) {
@@ -70,7 +70,7 @@ class WalletRepositoryImpl {
70
70
  else {
71
71
  vtxos.push(vtxo);
72
72
  }
73
- this.cache.vtxos.set(address, vtxos);
73
+ this.cache.vtxos.set(address, vtxos.slice());
74
74
  await this.storage.setItem(`vtxos:${address}`, JSON.stringify(vtxos.map(serializeVtxo)));
75
75
  }
76
76
  async saveVtxos(address, vtxos) {
@@ -84,14 +84,14 @@ class WalletRepositoryImpl {
84
84
  storedVtxos.push(vtxo);
85
85
  }
86
86
  }
87
- this.cache.vtxos.set(address, storedVtxos);
87
+ this.cache.vtxos.set(address, storedVtxos.slice());
88
88
  await this.storage.setItem(`vtxos:${address}`, JSON.stringify(storedVtxos.map(serializeVtxo)));
89
89
  }
90
90
  async removeVtxo(address, vtxoId) {
91
91
  const vtxos = await this.getVtxos(address);
92
92
  const [txid, vout] = vtxoId.split(":");
93
93
  const filtered = vtxos.filter((v) => !(v.txid === txid && v.vout === parseInt(vout, 10)));
94
- this.cache.vtxos.set(address, filtered);
94
+ this.cache.vtxos.set(address, filtered.slice());
95
95
  await this.storage.setItem(`vtxos:${address}`, JSON.stringify(filtered.map(serializeVtxo)));
96
96
  }
97
97
  async clearVtxos(address) {
@@ -69,4 +69,12 @@ var Request;
69
69
  return message.type === "GET_STATUS";
70
70
  }
71
71
  Request.isGetStatus = isGetStatus;
72
+ function isClear(message) {
73
+ return message.type === "CLEAR";
74
+ }
75
+ Request.isClear = isClear;
76
+ function isReloadWallet(message) {
77
+ return message.type === "RELOAD_WALLET";
78
+ }
79
+ Request.isReloadWallet = isReloadWallet;
72
80
  })(Request || (exports.Request = Request = {}));
@@ -175,4 +175,16 @@ var Response;
175
175
  };
176
176
  }
177
177
  Response.clearResponse = clearResponse;
178
+ function isWalletReloaded(response) {
179
+ return response.type === "WALLET_RELOADED";
180
+ }
181
+ Response.isWalletReloaded = isWalletReloaded;
182
+ function walletReloaded(id, success) {
183
+ return {
184
+ type: "WALLET_RELOADED",
185
+ success,
186
+ id,
187
+ };
188
+ }
189
+ Response.walletReloaded = walletReloaded;
178
190
  })(Response || (exports.Response = Response = {}));
@@ -8,10 +8,7 @@ const walletRepository_1 = require("../../repositories/walletRepository");
8
8
  const contractRepository_1 = require("../../repositories/contractRepository");
9
9
  const utils_1 = require("./utils");
10
10
  const isPrivateKeyIdentity = (identity) => {
11
- return (identity.toHex !== undefined &&
12
- typeof identity.toHex === "function" &&
13
- typeof identity.toHex() === "string" &&
14
- identity.toHex().length > 0);
11
+ return typeof identity.toHex === "function";
15
12
  };
16
13
  class UnexpectedResponseError extends Error {
17
14
  constructor(response) {
@@ -290,6 +287,17 @@ class ServiceWorkerWallet {
290
287
  throw new Error(`Settlement failed: ${error}`);
291
288
  }
292
289
  }
290
+ async reload() {
291
+ const message = {
292
+ type: "RELOAD_WALLET",
293
+ id: getRandomId(),
294
+ };
295
+ const response = await this.sendMessage(message);
296
+ if (response_1.Response.isWalletReloaded(response)) {
297
+ return response.success;
298
+ }
299
+ throw new UnexpectedResponseError(response);
300
+ }
293
301
  }
294
302
  exports.ServiceWorkerWallet = ServiceWorkerWallet;
295
303
  function getRandomId() {
@@ -110,13 +110,22 @@ class Worker {
110
110
  this.incomingFundsSubscription();
111
111
  // subscribe for incoming funds and notify all clients when new funds arrive
112
112
  this.incomingFundsSubscription = await this.wallet.notifyIncomingFunds(async (funds) => {
113
- if (funds.type === "vtxo" && funds.vtxos.length > 0) {
114
- // extend vtxos with taproot scripts
115
- const extendedVtxos = funds.vtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this.wallet, vtxo));
113
+ if (funds.type === "vtxo") {
114
+ const newVtxos = funds.newVtxos.length > 0
115
+ ? funds.newVtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this.wallet, vtxo))
116
+ : [];
117
+ const spentVtxos = funds.spentVtxos.length > 0
118
+ ? funds.spentVtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this.wallet, vtxo))
119
+ : [];
120
+ if ([...newVtxos, ...spentVtxos].length === 0)
121
+ return;
116
122
  // save vtxos using unified repository
117
- await this.walletRepository.saveVtxos(address, funds.vtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this.wallet, vtxo)));
123
+ await this.walletRepository.saveVtxos(address, [
124
+ ...newVtxos,
125
+ ...spentVtxos,
126
+ ]);
118
127
  // notify all clients about the vtxo update
119
- this.sendMessageToAllClients("VTXO_UPDATE", JSON.stringify(extendedVtxos));
128
+ this.sendMessageToAllClients("VTXO_UPDATE", JSON.stringify({ newVtxos, spentVtxos }));
120
129
  }
121
130
  if (funds.type === "utxo" && funds.coins.length > 0) {
122
131
  // notify all clients about the utxo update
@@ -498,6 +507,10 @@ class Worker {
498
507
  await this.handleClear(event);
499
508
  break;
500
509
  }
510
+ case "RELOAD_WALLET": {
511
+ await this.handleReloadWallet(event);
512
+ break;
513
+ }
501
514
  default:
502
515
  event.source?.postMessage(response_1.Response.error(message.id, "Unknown message type"));
503
516
  }
@@ -514,5 +527,27 @@ class Worker {
514
527
  });
515
528
  });
516
529
  }
530
+ async handleReloadWallet(event) {
531
+ const message = event.data;
532
+ console.log("RELOAD_WALLET message received", message);
533
+ if (!request_1.Request.isReloadWallet(message)) {
534
+ console.error("Invalid RELOAD_WALLET message format", message);
535
+ event.source?.postMessage(response_1.Response.error(message.id, "Invalid RELOAD_WALLET message format"));
536
+ return;
537
+ }
538
+ if (!this.wallet) {
539
+ console.error("Wallet not initialized");
540
+ event.source?.postMessage(response_1.Response.walletReloaded(message.id, false));
541
+ return;
542
+ }
543
+ try {
544
+ await this.onWalletInitialized();
545
+ event.source?.postMessage(response_1.Response.walletReloaded(message.id, true));
546
+ }
547
+ catch (error) {
548
+ console.error("Error reloading wallet:", error);
549
+ event.source?.postMessage(response_1.Response.walletReloaded(message.id, false));
550
+ }
551
+ }
517
552
  }
518
553
  exports.Worker = Worker;
@@ -679,7 +679,8 @@ class Wallet {
679
679
  if (update.newVtxos?.length > 0) {
680
680
  eventCallback({
681
681
  type: "vtxo",
682
- vtxos: update.newVtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this, vtxo)),
682
+ newVtxos: update.newVtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this, vtxo)),
683
+ spentVtxos: update.spentVtxos.map((vtxo) => (0, utils_1.extendVirtualCoin)(this, vtxo)),
683
684
  });
684
685
  }
685
686
  }
@@ -49,7 +49,7 @@ export class WalletRepositoryImpl {
49
49
  try {
50
50
  const parsed = JSON.parse(stored);
51
51
  const vtxos = parsed.map(deserializeVtxo);
52
- this.cache.vtxos.set(address, vtxos);
52
+ this.cache.vtxos.set(address, vtxos.slice());
53
53
  return vtxos.slice();
54
54
  }
55
55
  catch (error) {
@@ -67,7 +67,7 @@ export class WalletRepositoryImpl {
67
67
  else {
68
68
  vtxos.push(vtxo);
69
69
  }
70
- this.cache.vtxos.set(address, vtxos);
70
+ this.cache.vtxos.set(address, vtxos.slice());
71
71
  await this.storage.setItem(`vtxos:${address}`, JSON.stringify(vtxos.map(serializeVtxo)));
72
72
  }
73
73
  async saveVtxos(address, vtxos) {
@@ -81,14 +81,14 @@ export class WalletRepositoryImpl {
81
81
  storedVtxos.push(vtxo);
82
82
  }
83
83
  }
84
- this.cache.vtxos.set(address, storedVtxos);
84
+ this.cache.vtxos.set(address, storedVtxos.slice());
85
85
  await this.storage.setItem(`vtxos:${address}`, JSON.stringify(storedVtxos.map(serializeVtxo)));
86
86
  }
87
87
  async removeVtxo(address, vtxoId) {
88
88
  const vtxos = await this.getVtxos(address);
89
89
  const [txid, vout] = vtxoId.split(":");
90
90
  const filtered = vtxos.filter((v) => !(v.txid === txid && v.vout === parseInt(vout, 10)));
91
- this.cache.vtxos.set(address, filtered);
91
+ this.cache.vtxos.set(address, filtered.slice());
92
92
  await this.storage.setItem(`vtxos:${address}`, JSON.stringify(filtered.map(serializeVtxo)));
93
93
  }
94
94
  async clearVtxos(address) {
@@ -66,4 +66,12 @@ export var Request;
66
66
  return message.type === "GET_STATUS";
67
67
  }
68
68
  Request.isGetStatus = isGetStatus;
69
+ function isClear(message) {
70
+ return message.type === "CLEAR";
71
+ }
72
+ Request.isClear = isClear;
73
+ function isReloadWallet(message) {
74
+ return message.type === "RELOAD_WALLET";
75
+ }
76
+ Request.isReloadWallet = isReloadWallet;
69
77
  })(Request || (Request = {}));
@@ -172,4 +172,16 @@ export var Response;
172
172
  };
173
173
  }
174
174
  Response.clearResponse = clearResponse;
175
+ function isWalletReloaded(response) {
176
+ return response.type === "WALLET_RELOADED";
177
+ }
178
+ Response.isWalletReloaded = isWalletReloaded;
179
+ function walletReloaded(id, success) {
180
+ return {
181
+ type: "WALLET_RELOADED",
182
+ success,
183
+ id,
184
+ };
185
+ }
186
+ Response.walletReloaded = walletReloaded;
175
187
  })(Response || (Response = {}));
@@ -5,10 +5,7 @@ import { WalletRepositoryImpl } from '../../repositories/walletRepository.js';
5
5
  import { ContractRepositoryImpl } from '../../repositories/contractRepository.js';
6
6
  import { setupServiceWorker } from './utils.js';
7
7
  const isPrivateKeyIdentity = (identity) => {
8
- return (identity.toHex !== undefined &&
9
- typeof identity.toHex === "function" &&
10
- typeof identity.toHex() === "string" &&
11
- identity.toHex().length > 0);
8
+ return typeof identity.toHex === "function";
12
9
  };
13
10
  class UnexpectedResponseError extends Error {
14
11
  constructor(response) {
@@ -287,6 +284,17 @@ export class ServiceWorkerWallet {
287
284
  throw new Error(`Settlement failed: ${error}`);
288
285
  }
289
286
  }
287
+ async reload() {
288
+ const message = {
289
+ type: "RELOAD_WALLET",
290
+ id: getRandomId(),
291
+ };
292
+ const response = await this.sendMessage(message);
293
+ if (Response.isWalletReloaded(response)) {
294
+ return response.success;
295
+ }
296
+ throw new UnexpectedResponseError(response);
297
+ }
290
298
  }
291
299
  function getRandomId() {
292
300
  const randomValue = crypto.getRandomValues(new Uint8Array(16));
@@ -107,13 +107,22 @@ export class Worker {
107
107
  this.incomingFundsSubscription();
108
108
  // subscribe for incoming funds and notify all clients when new funds arrive
109
109
  this.incomingFundsSubscription = await this.wallet.notifyIncomingFunds(async (funds) => {
110
- if (funds.type === "vtxo" && funds.vtxos.length > 0) {
111
- // extend vtxos with taproot scripts
112
- const extendedVtxos = funds.vtxos.map((vtxo) => extendVirtualCoin(this.wallet, vtxo));
110
+ if (funds.type === "vtxo") {
111
+ const newVtxos = funds.newVtxos.length > 0
112
+ ? funds.newVtxos.map((vtxo) => extendVirtualCoin(this.wallet, vtxo))
113
+ : [];
114
+ const spentVtxos = funds.spentVtxos.length > 0
115
+ ? funds.spentVtxos.map((vtxo) => extendVirtualCoin(this.wallet, vtxo))
116
+ : [];
117
+ if ([...newVtxos, ...spentVtxos].length === 0)
118
+ return;
113
119
  // save vtxos using unified repository
114
- await this.walletRepository.saveVtxos(address, funds.vtxos.map((vtxo) => extendVirtualCoin(this.wallet, vtxo)));
120
+ await this.walletRepository.saveVtxos(address, [
121
+ ...newVtxos,
122
+ ...spentVtxos,
123
+ ]);
115
124
  // notify all clients about the vtxo update
116
- this.sendMessageToAllClients("VTXO_UPDATE", JSON.stringify(extendedVtxos));
125
+ this.sendMessageToAllClients("VTXO_UPDATE", JSON.stringify({ newVtxos, spentVtxos }));
117
126
  }
118
127
  if (funds.type === "utxo" && funds.coins.length > 0) {
119
128
  // notify all clients about the utxo update
@@ -495,6 +504,10 @@ export class Worker {
495
504
  await this.handleClear(event);
496
505
  break;
497
506
  }
507
+ case "RELOAD_WALLET": {
508
+ await this.handleReloadWallet(event);
509
+ break;
510
+ }
498
511
  default:
499
512
  event.source?.postMessage(Response.error(message.id, "Unknown message type"));
500
513
  }
@@ -511,4 +524,26 @@ export class Worker {
511
524
  });
512
525
  });
513
526
  }
527
+ async handleReloadWallet(event) {
528
+ const message = event.data;
529
+ console.log("RELOAD_WALLET message received", message);
530
+ if (!Request.isReloadWallet(message)) {
531
+ console.error("Invalid RELOAD_WALLET message format", message);
532
+ event.source?.postMessage(Response.error(message.id, "Invalid RELOAD_WALLET message format"));
533
+ return;
534
+ }
535
+ if (!this.wallet) {
536
+ console.error("Wallet not initialized");
537
+ event.source?.postMessage(Response.walletReloaded(message.id, false));
538
+ return;
539
+ }
540
+ try {
541
+ await this.onWalletInitialized();
542
+ event.source?.postMessage(Response.walletReloaded(message.id, true));
543
+ }
544
+ catch (error) {
545
+ console.error("Error reloading wallet:", error);
546
+ event.source?.postMessage(Response.walletReloaded(message.id, false));
547
+ }
548
+ }
514
549
  }
@@ -642,7 +642,8 @@ export class Wallet {
642
642
  if (update.newVtxos?.length > 0) {
643
643
  eventCallback({
644
644
  type: "vtxo",
645
- vtxos: update.newVtxos.map((vtxo) => extendVirtualCoin(this, vtxo)),
645
+ newVtxos: update.newVtxos.map((vtxo) => extendVirtualCoin(this, vtxo)),
646
+ spentVtxos: update.spentVtxos.map((vtxo) => extendVirtualCoin(this, vtxo)),
646
647
  });
647
648
  }
648
649
  }
@@ -3,7 +3,7 @@ import { SettleParams, SendBitcoinParams, GetVtxosFilter } from "..";
3
3
  * Request is the namespace that contains the request types for the service worker.
4
4
  */
5
5
  export declare namespace Request {
6
- type Type = "INIT_WALLET" | "SETTLE" | "GET_ADDRESS" | "GET_BOARDING_ADDRESS" | "GET_BALANCE" | "GET_VTXOS" | "GET_VIRTUAL_COINS" | "GET_BOARDING_UTXOS" | "SEND_BITCOIN" | "GET_TRANSACTION_HISTORY" | "GET_STATUS" | "CLEAR";
6
+ type Type = "INIT_WALLET" | "RELOAD_WALLET" | "SETTLE" | "GET_ADDRESS" | "GET_BOARDING_ADDRESS" | "GET_BALANCE" | "GET_VTXOS" | "GET_VIRTUAL_COINS" | "GET_BOARDING_UTXOS" | "SEND_BITCOIN" | "GET_TRANSACTION_HISTORY" | "GET_STATUS" | "CLEAR";
7
7
  interface Base {
8
8
  type: Type;
9
9
  id: string;
@@ -62,4 +62,9 @@ export declare namespace Request {
62
62
  interface Clear extends Base {
63
63
  type: "CLEAR";
64
64
  }
65
+ function isClear(message: Base): message is Clear;
66
+ interface ReloadWallet extends Base {
67
+ type: "RELOAD_WALLET";
68
+ }
69
+ function isReloadWallet(message: Base): message is ReloadWallet;
65
70
  }
@@ -4,7 +4,7 @@ import { SettlementEvent } from "../../providers/ark";
4
4
  * Response is the namespace that contains the response types for the service worker.
5
5
  */
6
6
  export declare namespace Response {
7
- type Type = "WALLET_INITIALIZED" | "SETTLE_EVENT" | "SETTLE_SUCCESS" | "ADDRESS" | "BOARDING_ADDRESS" | "BALANCE" | "VTXOS" | "VIRTUAL_COINS" | "BOARDING_UTXOS" | "SEND_BITCOIN_SUCCESS" | "TRANSACTION_HISTORY" | "WALLET_STATUS" | "ERROR" | "CLEAR_RESPONSE";
7
+ type Type = "WALLET_INITIALIZED" | "WALLET_RELOADED" | "SETTLE_EVENT" | "SETTLE_SUCCESS" | "ADDRESS" | "BOARDING_ADDRESS" | "BALANCE" | "VTXOS" | "VIRTUAL_COINS" | "BOARDING_UTXOS" | "SEND_BITCOIN_SUCCESS" | "TRANSACTION_HISTORY" | "WALLET_STATUS" | "ERROR" | "CLEAR_RESPONSE";
8
8
  interface Base {
9
9
  type: Type;
10
10
  success: boolean;
@@ -101,4 +101,9 @@ export declare namespace Response {
101
101
  }
102
102
  function isClearResponse(response: Base): response is ClearResponse;
103
103
  function clearResponse(id: string, success: boolean): ClearResponse;
104
+ interface WalletReloaded extends Base {
105
+ type: "WALLET_RELOADED";
106
+ }
107
+ function isWalletReloaded(response: Base): response is WalletReloaded;
108
+ function walletReloaded(id: string, success: boolean): WalletReloaded;
104
109
  }
@@ -93,5 +93,6 @@ export declare class ServiceWorkerWallet implements IWallet {
93
93
  getVtxos(filter?: GetVtxosFilter): Promise<ExtendedVirtualCoin[]>;
94
94
  sendBitcoin(params: SendBitcoinParams): Promise<string>;
95
95
  settle(params?: SettleParams, callback?: (event: SettlementEvent) => void): Promise<string>;
96
+ reload(): Promise<boolean>;
96
97
  }
97
98
  export {};
@@ -40,4 +40,5 @@ export declare class Worker {
40
40
  private handleGetStatus;
41
41
  private handleMessage;
42
42
  private sendMessageToAllClients;
43
+ private handleReloadWallet;
43
44
  }
@@ -15,7 +15,8 @@ export type IncomingFunds = {
15
15
  coins: Coin[];
16
16
  } | {
17
17
  type: "vtxo";
18
- vtxos: ExtendedVirtualCoin[];
18
+ newVtxos: ExtendedVirtualCoin[];
19
+ spentVtxos: ExtendedVirtualCoin[];
19
20
  };
20
21
  /**
21
22
  * Main wallet implementation for Bitcoin transactions with Ark protocol support.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkade-os/sdk",
3
- "version": "0.3.0-alpha.5",
3
+ "version": "0.3.0-alpha.6",
4
4
  "description": "Bitcoin wallet SDK with Taproot and Ark integration",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",