@arkade-os/sdk 0.4.0-next.1 → 0.4.0-next.2

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.
@@ -169,12 +169,20 @@ class ServiceWorkerReadonlyWallet {
169
169
  // send a message and wait for a response
170
170
  async sendMessage(request) {
171
171
  return new Promise((resolve, reject) => {
172
+ const cleanup = () => {
173
+ clearTimeout(timeoutId);
174
+ navigator.serviceWorker.removeEventListener("message", messageHandler);
175
+ };
176
+ const timeoutId = setTimeout(() => {
177
+ cleanup();
178
+ reject(new Error(`Service worker message timed out (${request.type})`));
179
+ }, 30000);
172
180
  const messageHandler = (event) => {
173
181
  const response = event.data;
174
182
  if (request.id !== response.id) {
175
183
  return;
176
184
  }
177
- navigator.serviceWorker.removeEventListener("message", messageHandler);
185
+ cleanup();
178
186
  if (response.error) {
179
187
  reject(response.error);
180
188
  }
@@ -107,8 +107,19 @@ class MessageBus {
107
107
  }
108
108
  }
109
109
  async waitForInit(config) {
110
- if (this.initialized)
111
- return;
110
+ if (this.initialized) {
111
+ // Stop existing handlers before re-initializing.
112
+ // This handles the case where CLEAR was called, which nullifies
113
+ // handler state (readonlyWallet, etc.) without resetting the
114
+ // initialized flag. Without this, handlers never get start()
115
+ // called again and all messages fail with "not initialized".
116
+ //
117
+ // Clear the flag first so onMessage() rejects incoming messages
118
+ // during the stop/start window instead of routing them to
119
+ // half-reset handlers. Restored to true after start() completes.
120
+ this.initialized = false;
121
+ await Promise.all(Array.from(this.handlers.values()).map((h) => h.stop().catch(() => { })));
122
+ }
112
123
  const services = await this.buildServicesFn(config);
113
124
  // Start all handlers
114
125
  for (const updater of this.handlers.values()) {
@@ -168,6 +179,15 @@ class MessageBus {
168
179
  if (!this.initialized) {
169
180
  if (this.debug)
170
181
  console.warn("Event received before initialization, dropping", event.data);
182
+ // Send error response so the caller's promise rejects instead of
183
+ // hanging forever. This happens when the browser kills and restarts
184
+ // the service worker — the new instance has initialized=false and
185
+ // messages arrive before INITIALIZE_MESSAGE_BUS is re-sent.
186
+ event.source?.postMessage({
187
+ id,
188
+ tag: tag ?? "unknown",
189
+ error: new Error("MessageBus not initialized"),
190
+ });
171
191
  return;
172
192
  }
173
193
  if (!id || !tag) {
@@ -166,12 +166,20 @@ export class ServiceWorkerReadonlyWallet {
166
166
  // send a message and wait for a response
167
167
  async sendMessage(request) {
168
168
  return new Promise((resolve, reject) => {
169
+ const cleanup = () => {
170
+ clearTimeout(timeoutId);
171
+ navigator.serviceWorker.removeEventListener("message", messageHandler);
172
+ };
173
+ const timeoutId = setTimeout(() => {
174
+ cleanup();
175
+ reject(new Error(`Service worker message timed out (${request.type})`));
176
+ }, 30000);
169
177
  const messageHandler = (event) => {
170
178
  const response = event.data;
171
179
  if (request.id !== response.id) {
172
180
  return;
173
181
  }
174
- navigator.serviceWorker.removeEventListener("message", messageHandler);
182
+ cleanup();
175
183
  if (response.error) {
176
184
  reject(response.error);
177
185
  }
@@ -104,8 +104,19 @@ export class MessageBus {
104
104
  }
105
105
  }
106
106
  async waitForInit(config) {
107
- if (this.initialized)
108
- return;
107
+ if (this.initialized) {
108
+ // Stop existing handlers before re-initializing.
109
+ // This handles the case where CLEAR was called, which nullifies
110
+ // handler state (readonlyWallet, etc.) without resetting the
111
+ // initialized flag. Without this, handlers never get start()
112
+ // called again and all messages fail with "not initialized".
113
+ //
114
+ // Clear the flag first so onMessage() rejects incoming messages
115
+ // during the stop/start window instead of routing them to
116
+ // half-reset handlers. Restored to true after start() completes.
117
+ this.initialized = false;
118
+ await Promise.all(Array.from(this.handlers.values()).map((h) => h.stop().catch(() => { })));
119
+ }
109
120
  const services = await this.buildServicesFn(config);
110
121
  // Start all handlers
111
122
  for (const updater of this.handlers.values()) {
@@ -165,6 +176,15 @@ export class MessageBus {
165
176
  if (!this.initialized) {
166
177
  if (this.debug)
167
178
  console.warn("Event received before initialization, dropping", event.data);
179
+ // Send error response so the caller's promise rejects instead of
180
+ // hanging forever. This happens when the browser kills and restarts
181
+ // the service worker — the new instance has initialized=false and
182
+ // messages arrive before INITIALIZE_MESSAGE_BUS is re-sent.
183
+ event.source?.postMessage({
184
+ id,
185
+ tag: tag ?? "unknown",
186
+ error: new Error("MessageBus not initialized"),
187
+ });
168
188
  return;
169
189
  }
170
190
  if (!id || !tag) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arkade-os/sdk",
3
- "version": "0.4.0-next.1",
3
+ "version": "0.4.0-next.2",
4
4
  "description": "Bitcoin wallet SDK with Taproot and Ark integration",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",