diff --git a/packages/wallet-sdk/src/index.ts b/packages/wallet-sdk/src/index.ts
index 2a57b93a63..348920b71b 100644
--- a/packages/wallet-sdk/src/index.ts
+++ b/packages/wallet-sdk/src/index.ts
@@ -2,8 +2,9 @@
import { CoinbaseWalletSDK } from './CoinbaseWalletSDK.js';
export default CoinbaseWalletSDK;
-export type { AppMetadata, Preference, ProviderInterface } from ':core/provider/interface.js';
+export type { AppMetadata, Preference, ProviderInterface, SubAccountOptions } from ':core/provider/interface.js';
export type { CoinbaseWalletProvider } from './CoinbaseWalletProvider.js';
export { CoinbaseWalletSDK } from './CoinbaseWalletSDK.js';
export { createCoinbaseWalletSDK } from './createCoinbaseWalletSDK.js';
export { getCryptoKeyAccount, removeCryptoKey } from './kms/crypto-key/index.js';
+
diff --git a/packages/wallet-sdk/src/sign/walletlink/relay/connection/HeartbeatWorker.js b/packages/wallet-sdk/src/sign/walletlink/relay/connection/HeartbeatWorker.js
deleted file mode 100644
index f772671838..0000000000
--- a/packages/wallet-sdk/src/sign/walletlink/relay/connection/HeartbeatWorker.js
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (c) 2018-2025 Coinbase, Inc.
-
-/**
- * This worker is used to send heartbeat messages to the main thread.
- * It is used to keep the websocket connection alive when the webpage is backgrounded.
- *
- */
-
-// Define the heartbeat interval constant directly in the worker to avoid import issues
-const HEARTBEAT_INTERVAL = 10000;
-
-let heartbeatInterval;
-
-// Listen for messages from the main thread
-self.addEventListener('message', (event) => {
- const { type } = event.data;
-
- switch (type) {
- case 'start':
- startHeartbeat();
- break;
- case 'stop':
- stopHeartbeat();
- break;
- default:
- console.warn('Unknown message type received by HeartbeatWorker:', type);
- }
-});
-
-function startHeartbeat() {
- // Clear any existing interval
- if (heartbeatInterval) {
- clearInterval(heartbeatInterval);
- }
-
- // Start the heartbeat interval
- heartbeatInterval = setInterval(() => {
- // Send heartbeat message to main thread
- const response = { type: 'heartbeat' };
- self.postMessage(response);
- }, HEARTBEAT_INTERVAL);
-
- // Send confirmation that heartbeat started
- const response = { type: 'started' };
- self.postMessage(response);
-}
-
-function stopHeartbeat() {
- if (heartbeatInterval) {
- clearInterval(heartbeatInterval);
- heartbeatInterval = undefined;
- }
-
- // Send confirmation that heartbeat stopped
- const response = { type: 'stopped' };
- self.postMessage(response);
-}
-
-// Handle worker termination
-self.addEventListener('beforeunload', () => {
- stopHeartbeat();
-});
\ No newline at end of file
diff --git a/packages/wallet-sdk/src/sign/walletlink/relay/connection/HeartbeatWorker.test.ts b/packages/wallet-sdk/src/sign/walletlink/relay/connection/HeartbeatWorker.test.ts
deleted file mode 100644
index 026ce2fd4a..0000000000
--- a/packages/wallet-sdk/src/sign/walletlink/relay/connection/HeartbeatWorker.test.ts
+++ /dev/null
@@ -1,234 +0,0 @@
-import '@vitest/web-worker';
-import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
-
-describe('HeartbeatWorker', () => {
- let worker: Worker;
-
- beforeEach(async () => {
- // Create a new worker instance for each test
- worker = new Worker(new URL('./HeartbeatWorker.js', import.meta.url));
- });
-
- afterEach(() => {
- if (worker) {
- worker.terminate();
- }
- });
-
- describe('Message Handling', () => {
- it('should start heartbeat and send confirmation', async () => {
- const messagePromise = new Promise((resolve) => {
- worker.addEventListener('message', resolve, { once: true });
- });
-
- worker.postMessage({ type: 'start' });
-
- const event = await messagePromise;
- expect(event.data).toEqual({ type: 'started' });
- });
-
- it('should send heartbeat messages at regular intervals', async () => {
- worker.postMessage({ type: 'start' });
-
- await new Promise((resolve) => {
- worker.addEventListener('message', (event) => {
- if (event.data.type === 'started') {
- resolve();
- }
- }, { once: true });
- });
-
- const heartbeats: MessageEvent[] = [];
- const heartbeatPromise = new Promise((resolve) => {
- let count = 0;
- worker.addEventListener('message', (event) => {
- if (event.data.type === 'heartbeat') {
- heartbeats.push(event);
- count++;
- if (count >= 2) {
- resolve();
- }
- }
- });
- });
-
- // Wait for at least 2 heartbeat messages (this will take ~20 seconds in real time)
- // For testing, we'll use a shorter timeout and verify the structure
- await Promise.race([
- heartbeatPromise,
- new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout waiting for heartbeats')), 25000))
- ]);
-
- expect(heartbeats.length).toBeGreaterThanOrEqual(2);
- heartbeats.forEach(event => {
- expect(event.data).toEqual({ type: 'heartbeat' });
- });
- }, 30000); // 30 second timeout for this test
-
- it('should stop heartbeat and send confirmation', async () => {
- worker.postMessage({ type: 'start' });
-
- await new Promise((resolve) => {
- worker.addEventListener('message', (event) => {
- if (event.data.type === 'started') {
- resolve();
- }
- }, { once: true });
- });
-
- const stopPromise = new Promise((resolve) => {
- worker.addEventListener('message', (event) => {
- if (event.data.type === 'stopped') {
- resolve(event);
- }
- }, { once: true });
- });
-
- worker.postMessage({ type: 'stop' });
-
- const event = await stopPromise;
- expect(event.data).toEqual({ type: 'stopped' });
- });
-
- it('should handle unknown message types gracefully', async () => {
- const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
-
- worker.postMessage({ type: 'unknown' });
-
- // Give the worker time to process the message
- await new Promise(resolve => setTimeout(resolve, 100));
-
- // Note: We can't directly verify console.warn was called in the worker context
- // but we can verify the worker doesn't crash or send unexpected messages
-
- const messagePromise = new Promise((resolve) => {
- worker.addEventListener('message', resolve, { once: true });
- });
-
- worker.postMessage({ type: 'start' });
- const event = await messagePromise;
- expect(event.data).toEqual({ type: 'started' });
-
- consoleSpy.mockRestore();
- });
- });
-
- describe('Heartbeat Interval Management', () => {
- it('should handle restart without issues', async () => {
- worker.postMessage({ type: 'start' });
-
- await new Promise((resolve) => {
- worker.addEventListener('message', (event) => {
- if (event.data.type === 'started') {
- resolve();
- }
- }, { once: true });
- });
-
- // Start again (should clear previous interval)
- const secondStartPromise = new Promise((resolve) => {
- worker.addEventListener('message', (event) => {
- if (event.data.type === 'started') {
- resolve(event);
- }
- }, { once: true });
- });
-
- worker.postMessage({ type: 'start' });
- const event = await secondStartPromise;
- expect(event.data).toEqual({ type: 'started' });
- });
-
- it('should stop cleanly even when no heartbeat is running', async () => {
- const stopPromise = new Promise((resolve) => {
- worker.addEventListener('message', resolve, { once: true });
- });
-
- // Stop without starting first
- worker.postMessage({ type: 'stop' });
-
- const event = await stopPromise;
- expect(event.data).toEqual({ type: 'stopped' });
- });
- });
-
- describe('Message Flow', () => {
- it('should handle complete start-heartbeat-stop cycle', async () => {
- const messages: any[] = [];
-
- worker.addEventListener('message', (event) => {
- messages.push(event.data);
- });
-
- worker.postMessage({ type: 'start' });
-
- await new Promise((resolve) => {
- const checkMessages = () => {
- if (messages.some(msg => msg.type === 'started')) {
- resolve();
- } else {
- setTimeout(checkMessages, 10);
- }
- };
- checkMessages();
- });
-
- await new Promise((resolve) => {
- const checkMessages = () => {
- if (messages.some(msg => msg.type === 'heartbeat')) {
- resolve();
- } else {
- setTimeout(checkMessages, 100);
- }
- };
- checkMessages();
- });
-
- worker.postMessage({ type: 'stop' });
-
- await new Promise((resolve) => {
- const checkMessages = () => {
- if (messages.some(msg => msg.type === 'stopped')) {
- resolve();
- } else {
- setTimeout(checkMessages, 10);
- }
- };
- checkMessages();
- });
-
- // Verify we got all expected message types
- expect(messages.some(msg => msg.type === 'started')).toBe(true);
- expect(messages.some(msg => msg.type === 'heartbeat')).toBe(true);
- expect(messages.some(msg => msg.type === 'stopped')).toBe(true);
- }, 15000); // 15 second timeout
-
- it('should use correct heartbeat interval timing', async () => {
- const heartbeatTimes: number[] = [];
-
- worker.addEventListener('message', (event) => {
- if (event.data.type === 'heartbeat') {
- heartbeatTimes.push(Date.now());
- }
- });
-
- worker.postMessage({ type: 'start' });
-
- await new Promise((resolve) => {
- const checkHeartbeats = () => {
- if (heartbeatTimes.length >= 2) {
- resolve();
- } else {
- setTimeout(checkHeartbeats, 100);
- }
- };
- checkHeartbeats();
- });
-
- // Verify the interval is approximately 10 seconds (allow some tolerance)
- const interval = heartbeatTimes[1] - heartbeatTimes[0];
- expect(interval).toBeGreaterThan(9500); // 9.5 seconds minimum
- expect(interval).toBeLessThan(10500); // 10.5 seconds maximum
- }, 25000); // 25 second timeout
- });
-});
\ No newline at end of file