@shadow-corp/nearconnect 1.0.0

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.
Files changed (179) hide show
  1. package/README.md +546 -0
  2. package/build/InjectedWallet.d.ts +22 -0
  3. package/build/InjectedWallet.js +58 -0
  4. package/build/InjectedWallet.js.map +1 -0
  5. package/build/NearConnector.d.ts +151 -0
  6. package/build/NearConnector.js +536 -0
  7. package/build/NearConnector.js.map +1 -0
  8. package/build/ParentFrameWallet.d.ts +22 -0
  9. package/build/ParentFrameWallet.js +66 -0
  10. package/build/ParentFrameWallet.js.map +1 -0
  11. package/build/SandboxedWallet/code.d.ts +7 -0
  12. package/build/SandboxedWallet/code.js +324 -0
  13. package/build/SandboxedWallet/code.js.map +1 -0
  14. package/build/SandboxedWallet/executor.d.ts +23 -0
  15. package/build/SandboxedWallet/executor.js +338 -0
  16. package/build/SandboxedWallet/executor.js.map +1 -0
  17. package/build/SandboxedWallet/iframe.d.ts +18 -0
  18. package/build/SandboxedWallet/iframe.js +78 -0
  19. package/build/SandboxedWallet/iframe.js.map +1 -0
  20. package/build/SandboxedWallet/index.d.ts +24 -0
  21. package/build/SandboxedWallet/index.js +54 -0
  22. package/build/SandboxedWallet/index.js.map +1 -0
  23. package/build/actions/index.d.ts +3 -0
  24. package/build/actions/index.js +105 -0
  25. package/build/actions/index.js.map +1 -0
  26. package/build/actions/types.d.ts +76 -0
  27. package/build/actions/types.js +3 -0
  28. package/build/actions/types.js.map +1 -0
  29. package/build/connection/health.d.ts +213 -0
  30. package/build/connection/health.js +391 -0
  31. package/build/connection/health.js.map +1 -0
  32. package/build/connection/index.d.ts +4 -0
  33. package/build/connection/index.js +48 -0
  34. package/build/connection/index.js.map +1 -0
  35. package/build/connection/reconnect.d.ts +261 -0
  36. package/build/connection/reconnect.js +454 -0
  37. package/build/connection/reconnect.js.map +1 -0
  38. package/build/connection/retry.d.ts +187 -0
  39. package/build/connection/retry.js +427 -0
  40. package/build/connection/retry.js.map +1 -0
  41. package/build/connection/state.d.ts +222 -0
  42. package/build/connection/state.js +431 -0
  43. package/build/connection/state.js.map +1 -0
  44. package/build/errors.d.ts +177 -0
  45. package/build/errors.js +546 -0
  46. package/build/errors.js.map +1 -0
  47. package/build/hardware/errors.d.ts +36 -0
  48. package/build/hardware/errors.js +127 -0
  49. package/build/hardware/errors.js.map +1 -0
  50. package/build/hardware/index.d.ts +7 -0
  51. package/build/hardware/index.js +39 -0
  52. package/build/hardware/index.js.map +1 -0
  53. package/build/hardware/near-app.d.ts +95 -0
  54. package/build/hardware/near-app.js +291 -0
  55. package/build/hardware/near-app.js.map +1 -0
  56. package/build/hardware/transport.d.ts +94 -0
  57. package/build/hardware/transport.js +267 -0
  58. package/build/hardware/transport.js.map +1 -0
  59. package/build/hardware/types.d.ts +98 -0
  60. package/build/hardware/types.js +72 -0
  61. package/build/hardware/types.js.map +1 -0
  62. package/build/helpers/analytics.d.ts +191 -0
  63. package/build/helpers/analytics.js +304 -0
  64. package/build/helpers/analytics.js.map +1 -0
  65. package/build/helpers/base58.d.ts +6 -0
  66. package/build/helpers/base58.js +47 -0
  67. package/build/helpers/base58.js.map +1 -0
  68. package/build/helpers/events.d.ts +42 -0
  69. package/build/helpers/events.js +68 -0
  70. package/build/helpers/events.js.map +1 -0
  71. package/build/helpers/html.d.ts +8 -0
  72. package/build/helpers/html.js +30 -0
  73. package/build/helpers/html.js.map +1 -0
  74. package/build/helpers/indexdb.d.ts +14 -0
  75. package/build/helpers/indexdb.js +166 -0
  76. package/build/helpers/indexdb.js.map +1 -0
  77. package/build/helpers/manifest.d.ts +147 -0
  78. package/build/helpers/manifest.js +329 -0
  79. package/build/helpers/manifest.js.map +1 -0
  80. package/build/helpers/queue.d.ts +11 -0
  81. package/build/helpers/queue.js +48 -0
  82. package/build/helpers/queue.js.map +1 -0
  83. package/build/helpers/session.d.ts +119 -0
  84. package/build/helpers/session.js +289 -0
  85. package/build/helpers/session.js.map +1 -0
  86. package/build/helpers/simulation.d.ts +128 -0
  87. package/build/helpers/simulation.js +441 -0
  88. package/build/helpers/simulation.js.map +1 -0
  89. package/build/helpers/storage.d.ts +58 -0
  90. package/build/helpers/storage.js +190 -0
  91. package/build/helpers/storage.js.map +1 -0
  92. package/build/helpers/trust.d.ts +157 -0
  93. package/build/helpers/trust.js +340 -0
  94. package/build/helpers/trust.js.map +1 -0
  95. package/build/helpers/url.d.ts +1 -0
  96. package/build/helpers/url.js +13 -0
  97. package/build/helpers/url.js.map +1 -0
  98. package/build/helpers/uuid.d.ts +1 -0
  99. package/build/helpers/uuid.js +14 -0
  100. package/build/helpers/uuid.js.map +1 -0
  101. package/build/index.d.ts +21 -0
  102. package/build/index.js +167 -0
  103. package/build/index.js.map +1 -0
  104. package/build/popups/IframeWalletPopup.d.ts +16 -0
  105. package/build/popups/IframeWalletPopup.js +38 -0
  106. package/build/popups/IframeWalletPopup.js.map +1 -0
  107. package/build/popups/NearWalletsPopup.d.ts +25 -0
  108. package/build/popups/NearWalletsPopup.js +153 -0
  109. package/build/popups/NearWalletsPopup.js.map +1 -0
  110. package/build/popups/Popup.d.ts +22 -0
  111. package/build/popups/Popup.js +94 -0
  112. package/build/popups/Popup.js.map +1 -0
  113. package/build/popups/styles.d.ts +1 -0
  114. package/build/popups/styles.js +257 -0
  115. package/build/popups/styles.js.map +1 -0
  116. package/build/security/audit-log.d.ts +123 -0
  117. package/build/security/audit-log.js +268 -0
  118. package/build/security/audit-log.js.map +1 -0
  119. package/build/security/csp.d.ts +68 -0
  120. package/build/security/csp.js +328 -0
  121. package/build/security/csp.js.map +1 -0
  122. package/build/security/index.d.ts +10 -0
  123. package/build/security/index.js +42 -0
  124. package/build/security/index.js.map +1 -0
  125. package/build/security/origin-guard.d.ts +90 -0
  126. package/build/security/origin-guard.js +244 -0
  127. package/build/security/origin-guard.js.map +1 -0
  128. package/build/security/rate-limiter.d.ts +84 -0
  129. package/build/security/rate-limiter.js +212 -0
  130. package/build/security/rate-limiter.js.map +1 -0
  131. package/build/security/secure-storage.d.ts +77 -0
  132. package/build/security/secure-storage.js +242 -0
  133. package/build/security/secure-storage.js.map +1 -0
  134. package/build/security/transaction-guard.d.ts +71 -0
  135. package/build/security/transaction-guard.js +239 -0
  136. package/build/security/transaction-guard.js.map +1 -0
  137. package/build/types.d.ts +508 -0
  138. package/build/types.js +3 -0
  139. package/build/types.js.map +1 -0
  140. package/build/ui/AccountSwitcherModal.d.ts +53 -0
  141. package/build/ui/AccountSwitcherModal.js +239 -0
  142. package/build/ui/AccountSwitcherModal.js.map +1 -0
  143. package/build/ui/Modal.d.ts +84 -0
  144. package/build/ui/Modal.js +278 -0
  145. package/build/ui/Modal.js.map +1 -0
  146. package/build/ui/TransactionModal.d.ts +84 -0
  147. package/build/ui/TransactionModal.js +406 -0
  148. package/build/ui/TransactionModal.js.map +1 -0
  149. package/build/ui/WalletSelectorModal.d.ts +97 -0
  150. package/build/ui/WalletSelectorModal.js +481 -0
  151. package/build/ui/WalletSelectorModal.js.map +1 -0
  152. package/build/ui/icons.d.ts +19 -0
  153. package/build/ui/icons.js +65 -0
  154. package/build/ui/icons.js.map +1 -0
  155. package/build/ui/index.d.ts +10 -0
  156. package/build/ui/index.js +31 -0
  157. package/build/ui/index.js.map +1 -0
  158. package/build/ui/styles.d.ts +5 -0
  159. package/build/ui/styles.js +973 -0
  160. package/build/ui/styles.js.map +1 -0
  161. package/build/ui/theme.d.ts +133 -0
  162. package/build/ui/theme.js +204 -0
  163. package/build/ui/theme.js.map +1 -0
  164. package/build/wallets/external/index.d.ts +4 -0
  165. package/build/wallets/external/index.js +9 -0
  166. package/build/wallets/external/index.js.map +1 -0
  167. package/build/wallets/external/manager.d.ts +152 -0
  168. package/build/wallets/external/manager.js +586 -0
  169. package/build/wallets/external/manager.js.map +1 -0
  170. package/build/wallets/privileged/index.d.ts +5 -0
  171. package/build/wallets/privileged/index.js +12 -0
  172. package/build/wallets/privileged/index.js.map +1 -0
  173. package/build/wallets/privileged/ledger.d.ts +132 -0
  174. package/build/wallets/privileged/ledger.js +563 -0
  175. package/build/wallets/privileged/ledger.js.map +1 -0
  176. package/build/wallets/privileged/manager.d.ts +54 -0
  177. package/build/wallets/privileged/manager.js +174 -0
  178. package/build/wallets/privileged/manager.js.map +1 -0
  179. package/package.json +33 -0
@@ -0,0 +1,151 @@
1
+ import { EventEmitter } from "./helpers/events";
2
+ import { DataStorage } from "./helpers/storage";
3
+ import { SessionManager, Session } from "./helpers/session";
4
+ import IndexedDB from "./helpers/indexdb";
5
+ import { WalletManifest, Network, WalletFeatures, Logger, NearWalletBase, AbstractWalletConnect, Account } from "./types";
6
+ import { EventMap } from "./types";
7
+ /**
8
+ * Connected account with wallet metadata
9
+ */
10
+ export interface ConnectedAccount extends Account {
11
+ walletId: string;
12
+ walletName: string;
13
+ walletIcon?: string;
14
+ network: Network;
15
+ connectedAt: number;
16
+ }
17
+ interface PersistenceOptions {
18
+ enabled?: boolean;
19
+ storage?: DataStorage;
20
+ storageKey?: string;
21
+ maxAge?: number;
22
+ autoReconnect?: boolean;
23
+ }
24
+ interface NearConnectorOptions {
25
+ providers?: {
26
+ mainnet?: string[];
27
+ testnet?: string[];
28
+ };
29
+ features?: Partial<WalletFeatures>;
30
+ excludedWallets?: string[];
31
+ autoConnect?: boolean;
32
+ network?: Network;
33
+ manifest?: string | {
34
+ wallets: WalletManifest[];
35
+ version: string;
36
+ };
37
+ walletConnect?: Promise<AbstractWalletConnect> | AbstractWalletConnect;
38
+ events?: EventEmitter<EventMap>;
39
+ storage?: DataStorage;
40
+ logger?: Logger;
41
+ /**
42
+ * Session persistence options for auto-reconnect on page reload
43
+ */
44
+ persistence?: PersistenceOptions;
45
+ /**
46
+ * @deprecated
47
+ * Some wallets allow adding a limited-access key to a contract as soon as the user connects their wallet.
48
+ * This enables the app to sign non-payable transactions without requiring wallet approval each time.
49
+ * However, this approach requires the user to submit an on-chain transaction during the initial connection, which may negatively affect the user experience.
50
+ * A better practice is to add the limited-access key after the user has already begun actively interacting with your application.
51
+ */
52
+ signIn?: {
53
+ contractId?: string;
54
+ methodNames?: Array<string>;
55
+ };
56
+ }
57
+ export declare class NearConnector {
58
+ private storage;
59
+ readonly events: EventEmitter<EventMap>;
60
+ readonly db: IndexedDB;
61
+ readonly session: SessionManager;
62
+ logger?: Logger;
63
+ wallets: NearWalletBase[];
64
+ manifest: {
65
+ wallets: WalletManifest[];
66
+ version: string;
67
+ };
68
+ features: Partial<WalletFeatures>;
69
+ network: Network;
70
+ providers: {
71
+ mainnet?: string[];
72
+ testnet?: string[];
73
+ };
74
+ signInData?: {
75
+ contractId?: string;
76
+ methodNames?: Array<string>;
77
+ };
78
+ walletConnect?: Promise<AbstractWalletConnect> | AbstractWalletConnect;
79
+ excludedWallets: string[];
80
+ autoConnect?: boolean;
81
+ private persistenceEnabled;
82
+ private connectedAccounts;
83
+ private activeAccountId;
84
+ readonly whenManifestLoaded: Promise<void>;
85
+ readonly whenSessionRestored: Promise<Session | null>;
86
+ constructor(options?: NearConnectorOptions);
87
+ get availableWallets(): NearWalletBase[];
88
+ private _handleNearWalletInjected;
89
+ private _loadManifest;
90
+ switchNetwork(network: "mainnet" | "testnet", signInData?: {
91
+ contractId?: string;
92
+ methodNames?: Array<string>;
93
+ }): Promise<void>;
94
+ registerWallet(manifest: WalletManifest): Promise<void>;
95
+ registerDebugWallet(json: string | WalletManifest): Promise<WalletManifest>;
96
+ removeDebugWallet(id: string): Promise<void>;
97
+ selectWallet(): Promise<string>;
98
+ connect(id?: string): Promise<NearWalletBase>;
99
+ disconnect(wallet?: NearWalletBase): Promise<void>;
100
+ getConnectedWallet(): Promise<{
101
+ wallet: NearWalletBase;
102
+ accounts: Account[];
103
+ }>;
104
+ wallet(id?: string | null): Promise<NearWalletBase>;
105
+ on<K extends keyof EventMap>(event: K, callback: (payload: EventMap[K]) => void): void;
106
+ once<K extends keyof EventMap>(event: K, callback: (payload: EventMap[K]) => void): void;
107
+ off<K extends keyof EventMap>(event: K, callback: (payload: EventMap[K]) => void): void;
108
+ removeAllListeners<K extends keyof EventMap>(event?: K): void;
109
+ /**
110
+ * Get all connected accounts across all wallets
111
+ */
112
+ getConnectedAccounts(): ConnectedAccount[];
113
+ /**
114
+ * Get the currently active account
115
+ */
116
+ getActiveAccount(): ConnectedAccount | null;
117
+ /**
118
+ * Switch to a different connected account
119
+ */
120
+ switchAccount(accountId: string): Promise<ConnectedAccount>;
121
+ /**
122
+ * Add a new account by connecting another wallet
123
+ * Returns the newly added accounts
124
+ */
125
+ addAccount(walletId?: string): Promise<ConnectedAccount[]>;
126
+ /**
127
+ * Remove a connected account
128
+ */
129
+ removeAccount(accountId: string): Promise<void>;
130
+ /**
131
+ * Check if multi-account mode has any accounts
132
+ */
133
+ hasConnectedAccounts(): boolean;
134
+ /**
135
+ * Get accounts for a specific wallet
136
+ */
137
+ getAccountsForWallet(walletId: string): ConnectedAccount[];
138
+ /**
139
+ * Load multi-account state from storage
140
+ */
141
+ private loadMultiAccountState;
142
+ /**
143
+ * Save multi-account state to storage
144
+ */
145
+ private saveMultiAccountState;
146
+ /**
147
+ * Clear all connected accounts
148
+ */
149
+ clearAllAccounts(): Promise<void>;
150
+ }
151
+ export {};
@@ -0,0 +1,536 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.NearConnector = void 0;
7
+ const events_1 = require("./helpers/events");
8
+ const NearWalletsPopup_1 = require("./popups/NearWalletsPopup");
9
+ const storage_1 = require("./helpers/storage");
10
+ const session_1 = require("./helpers/session");
11
+ const indexdb_1 = __importDefault(require("./helpers/indexdb"));
12
+ const ParentFrameWallet_1 = require("./ParentFrameWallet");
13
+ const InjectedWallet_1 = require("./InjectedWallet");
14
+ const SandboxedWallet_1 = require("./SandboxedWallet");
15
+ const errors_1 = require("./errors");
16
+ const defaultManifests = [
17
+ "https://raw.githubusercontent.com/hot-dao/near-selector/refs/heads/main/repository/manifest.json",
18
+ "https://cdn.jsdelivr.net/gh/azbang/hot-connector/repository/manifest.json",
19
+ ];
20
+ const MULTI_ACCOUNT_STORAGE_KEY = "near-connect-accounts";
21
+ class NearConnector {
22
+ storage;
23
+ events;
24
+ db;
25
+ session;
26
+ logger;
27
+ wallets = [];
28
+ manifest = { wallets: [], version: "1.0.0" };
29
+ features = {};
30
+ network = "mainnet";
31
+ providers = { mainnet: [], testnet: [] };
32
+ signInData;
33
+ walletConnect;
34
+ excludedWallets = [];
35
+ autoConnect;
36
+ persistenceEnabled;
37
+ // Multi-account state
38
+ connectedAccounts = [];
39
+ activeAccountId = null;
40
+ whenManifestLoaded;
41
+ whenSessionRestored;
42
+ constructor(options) {
43
+ this.db = new indexdb_1.default("hot-connector", "wallets");
44
+ this.storage = options?.storage ?? new storage_1.LocalStorage();
45
+ this.events = options?.events ?? new events_1.EventEmitter();
46
+ this.logger = options?.logger;
47
+ this.network = options?.network ?? "mainnet";
48
+ this.walletConnect = options?.walletConnect;
49
+ this.autoConnect = options?.autoConnect ?? true;
50
+ this.providers = options?.providers ?? { mainnet: [], testnet: [] };
51
+ this.excludedWallets = options?.excludedWallets ?? [];
52
+ this.features = options?.features ?? {};
53
+ this.signInData = options?.signIn;
54
+ // Session persistence
55
+ this.persistenceEnabled = options?.persistence?.enabled ?? true;
56
+ this.session = new session_1.SessionManager({
57
+ storage: options?.persistence?.storage ?? this.storage,
58
+ storageKey: options?.persistence?.storageKey,
59
+ maxAge: options?.persistence?.maxAge,
60
+ autoReconnect: options?.persistence?.autoReconnect ?? true,
61
+ onSessionRestored: (session) => {
62
+ this.logger?.log("Session restored", session);
63
+ this.events.emit("session:restored", { session });
64
+ },
65
+ onSessionExpired: (session) => {
66
+ this.logger?.log("Session expired", session);
67
+ this.events.emit("session:expired", { session });
68
+ },
69
+ onSessionCleared: () => {
70
+ this.logger?.log("Session cleared");
71
+ },
72
+ });
73
+ this.whenManifestLoaded = new Promise(async (resolve) => {
74
+ if (options?.manifest == null || typeof options.manifest === "string") {
75
+ this.manifest = await this._loadManifest(options?.manifest).catch(() => ({ wallets: [], version: "1.0.0" }));
76
+ }
77
+ else {
78
+ this.manifest = options?.manifest ?? { wallets: [], version: "1.0.0" };
79
+ }
80
+ const set = new Set(this.excludedWallets);
81
+ set.delete("hot-wallet"); // always include hot-wallet
82
+ this.manifest.wallets = this.manifest.wallets.filter((wallet) => {
83
+ // Remove wallet with walletConnect permission but no projectId is provided
84
+ if (wallet.permissions.walletConnect && !this.walletConnect)
85
+ return false;
86
+ if (set.has(wallet.id))
87
+ return false; // excluded wallets
88
+ return true;
89
+ });
90
+ await new Promise((resolve) => setTimeout(resolve, 100));
91
+ resolve();
92
+ });
93
+ if (typeof window !== "undefined") {
94
+ window.addEventListener("near-wallet-injected", this._handleNearWalletInjected);
95
+ window.dispatchEvent(new Event("near-selector-ready"));
96
+ window.addEventListener("message", async (event) => {
97
+ if (event.data.type === "near-wallet-injected") {
98
+ await this.whenManifestLoaded.catch(() => { });
99
+ this.wallets = this.wallets.filter((wallet) => wallet.manifest.id !== event.data.manifest.id);
100
+ this.wallets.unshift(new ParentFrameWallet_1.ParentFrameWallet(this, event.data.manifest));
101
+ this.events.emit("selector:walletsChanged", {});
102
+ if (this.autoConnect)
103
+ this.connect(event.data.manifest.id);
104
+ }
105
+ });
106
+ }
107
+ this.whenManifestLoaded.then(() => {
108
+ if (typeof window !== "undefined") {
109
+ window.parent.postMessage({ type: "near-selector-ready" }, "*");
110
+ }
111
+ this.manifest.wallets.forEach((wallet) => this.registerWallet(wallet));
112
+ this.storage.get("debug-wallets").then((json) => {
113
+ const debugWallets = JSON.parse(json ?? "[]");
114
+ debugWallets.forEach((wallet) => this.registerDebugWallet(wallet));
115
+ });
116
+ });
117
+ // Try to restore session after manifest loads
118
+ this.whenSessionRestored = this.whenManifestLoaded.then(async () => {
119
+ if (!this.persistenceEnabled)
120
+ return null;
121
+ // Load multi-account state
122
+ await this.loadMultiAccountState();
123
+ const session = await this.session.tryRestore();
124
+ if (session) {
125
+ // Validate wallet still exists and try to reconnect
126
+ try {
127
+ const wallet = this.wallets.find((w) => w.manifest.id === session.walletId);
128
+ if (wallet) {
129
+ const accounts = await wallet.getAccounts({ network: session.network });
130
+ if (accounts?.length) {
131
+ this.network = session.network;
132
+ await this.storage.set("selected-wallet", session.walletId);
133
+ this.events.emit("wallet:signIn", { wallet, accounts, success: true });
134
+ return session;
135
+ }
136
+ }
137
+ // Wallet not found or no accounts - clear stale session
138
+ await this.session.clear();
139
+ }
140
+ catch (e) {
141
+ this.logger?.log("Failed to restore session", e);
142
+ await this.session.clear();
143
+ }
144
+ }
145
+ return null;
146
+ });
147
+ }
148
+ get availableWallets() {
149
+ const wallets = this.wallets.filter((wallet) => {
150
+ return Object.entries(this.features).every(([key, value]) => {
151
+ if (value && !wallet.manifest.features?.[key])
152
+ return false;
153
+ return true;
154
+ });
155
+ });
156
+ return wallets.filter((wallet) => {
157
+ if (this.network === "testnet" && !wallet.manifest.features?.testnet)
158
+ return false;
159
+ return true;
160
+ });
161
+ }
162
+ _handleNearWalletInjected = (event) => {
163
+ this.wallets = this.wallets.filter((wallet) => wallet.manifest.id !== event.detail.manifest.id);
164
+ this.wallets.unshift(new InjectedWallet_1.InjectedWallet(this, event.detail));
165
+ this.events.emit("selector:walletsChanged", {});
166
+ };
167
+ async _loadManifest(manifestUrl) {
168
+ const manifestEndpoints = manifestUrl ? [manifestUrl] : defaultManifests;
169
+ for (const endpoint of manifestEndpoints) {
170
+ const res = await fetch(endpoint).catch(() => null);
171
+ if (!res || !res.ok)
172
+ continue;
173
+ return await res.json(); // TODO: Validate this
174
+ }
175
+ throw new errors_1.WalletError({
176
+ code: errors_1.ErrorCode.MANIFEST_LOAD_FAILED,
177
+ message: "Failed to load wallet manifest from any endpoint",
178
+ });
179
+ }
180
+ async switchNetwork(network, signInData) {
181
+ if (this.network === network)
182
+ return;
183
+ await this.disconnect().catch(() => { });
184
+ if (signInData)
185
+ this.signInData = signInData;
186
+ this.network = network;
187
+ await this.connect();
188
+ }
189
+ async registerWallet(manifest) {
190
+ if (manifest.type !== "sandbox")
191
+ throw new Error("Only sandbox wallets are supported");
192
+ if (this.wallets.find((wallet) => wallet.manifest.id === manifest.id))
193
+ return;
194
+ this.wallets.push(new SandboxedWallet_1.SandboxWallet(this, manifest));
195
+ this.events.emit("selector:walletsChanged", {});
196
+ }
197
+ async registerDebugWallet(json) {
198
+ const manifest = typeof json === "string" ? JSON.parse(json) : json;
199
+ if (manifest.type !== "sandbox")
200
+ throw new Error("Only sandbox wallets type are supported");
201
+ if (!manifest.id)
202
+ throw new Error("Manifest must have an id");
203
+ if (!manifest.name)
204
+ throw new Error("Manifest must have a name");
205
+ if (!manifest.icon)
206
+ throw new Error("Manifest must have an icon");
207
+ if (!manifest.website)
208
+ throw new Error("Manifest must have a website");
209
+ if (!manifest.version)
210
+ throw new Error("Manifest must have a version");
211
+ if (!manifest.executor)
212
+ throw new Error("Manifest must have an executor");
213
+ if (!manifest.features)
214
+ throw new Error("Manifest must have features");
215
+ if (!manifest.permissions)
216
+ throw new Error("Manifest must have permissions");
217
+ if (this.wallets.find((wallet) => wallet.manifest.id === manifest.id))
218
+ throw new Error("Wallet already registered");
219
+ manifest.debug = true;
220
+ this.wallets.unshift(new SandboxedWallet_1.SandboxWallet(this, manifest));
221
+ this.events.emit("selector:walletsChanged", {});
222
+ const debugWallets = this.wallets.filter((wallet) => wallet.manifest.debug).map((wallet) => wallet.manifest);
223
+ this.storage.set("debug-wallets", JSON.stringify(debugWallets));
224
+ return manifest;
225
+ }
226
+ async removeDebugWallet(id) {
227
+ this.wallets = this.wallets.filter((wallet) => wallet.manifest.id !== id);
228
+ const debugWallets = this.wallets.filter((wallet) => wallet.manifest.debug).map((wallet) => wallet.manifest);
229
+ this.storage.set("debug-wallets", JSON.stringify(debugWallets));
230
+ this.events.emit("selector:walletsChanged", {});
231
+ }
232
+ async selectWallet() {
233
+ await this.whenManifestLoaded.catch(() => { });
234
+ return new Promise((resolve, reject) => {
235
+ const popup = new NearWalletsPopup_1.NearWalletsPopup({
236
+ wallets: this.availableWallets.map((wallet) => wallet.manifest),
237
+ onRemoveDebugManifest: async (id) => this.removeDebugWallet(id),
238
+ onAddDebugManifest: async (wallet) => this.registerDebugWallet(wallet),
239
+ onReject: () => {
240
+ const error = new errors_1.UserRejectedError(undefined, "wallet selection");
241
+ reject(error);
242
+ popup.destroy();
243
+ },
244
+ onSelect: (id) => (resolve(id), popup.destroy()),
245
+ });
246
+ popup.create();
247
+ });
248
+ }
249
+ async connect(id) {
250
+ await this.whenManifestLoaded.catch(() => { });
251
+ if (!id)
252
+ id = await this.selectWallet();
253
+ try {
254
+ const wallet = await this.wallet(id);
255
+ this.logger?.log(`Wallet available to connect`, wallet);
256
+ await this.storage.set("selected-wallet", id);
257
+ this.logger?.log(`Set preferred wallet, try to signIn`, id);
258
+ const accounts = await wallet.signIn({
259
+ contractId: this.signInData?.contractId,
260
+ methodNames: this.signInData?.methodNames,
261
+ network: this.network,
262
+ });
263
+ if (!accounts?.length) {
264
+ throw new errors_1.WalletError({
265
+ code: errors_1.ErrorCode.NO_ACCOUNTS,
266
+ message: "Wallet returned no accounts after sign in",
267
+ walletId: id,
268
+ });
269
+ }
270
+ this.logger?.log(`Signed in to wallet`, id, accounts);
271
+ // Save session for persistence
272
+ if (this.persistenceEnabled) {
273
+ await this.session.save({
274
+ walletId: id,
275
+ accounts,
276
+ network: this.network,
277
+ });
278
+ }
279
+ this.events.emit("wallet:signIn", { wallet, accounts, success: true });
280
+ return wallet;
281
+ }
282
+ catch (e) {
283
+ const walletError = (0, errors_1.wrapError)(e, id);
284
+ this.logger?.log("Failed to connect to wallet", walletError);
285
+ this.events.emit("wallet:error", { error: walletError, walletId: id, action: "connect" });
286
+ throw walletError;
287
+ }
288
+ }
289
+ async disconnect(wallet) {
290
+ try {
291
+ if (!wallet)
292
+ wallet = await this.wallet();
293
+ await wallet.signOut({ network: this.network });
294
+ await this.storage.remove("selected-wallet");
295
+ // Clear persisted session
296
+ if (this.persistenceEnabled) {
297
+ await this.session.clear();
298
+ }
299
+ this.events.emit("wallet:signOut", { success: true });
300
+ }
301
+ catch (e) {
302
+ const walletError = (0, errors_1.wrapError)(e, wallet?.manifest.id);
303
+ this.logger?.log("Failed to disconnect wallet", walletError);
304
+ this.events.emit("wallet:error", { error: walletError, walletId: wallet?.manifest.id, action: "disconnect" });
305
+ throw walletError;
306
+ }
307
+ }
308
+ async getConnectedWallet() {
309
+ await this.whenManifestLoaded.catch(() => { });
310
+ const id = await this.storage.get("selected-wallet");
311
+ const wallet = this.wallets.find((wallet) => wallet.manifest.id === id);
312
+ if (!wallet) {
313
+ throw new errors_1.WalletError({
314
+ code: errors_1.ErrorCode.NO_ACTIVE_SESSION,
315
+ message: "No wallet currently selected",
316
+ });
317
+ }
318
+ const accounts = await wallet.getAccounts();
319
+ if (!accounts?.length) {
320
+ throw new errors_1.WalletError({
321
+ code: errors_1.ErrorCode.NO_ACCOUNTS,
322
+ message: "No accounts found in connected wallet",
323
+ walletId: id ?? undefined,
324
+ });
325
+ }
326
+ return { wallet, accounts };
327
+ }
328
+ async wallet(id) {
329
+ await this.whenManifestLoaded.catch(() => { });
330
+ if (!id) {
331
+ return this.getConnectedWallet()
332
+ .then(({ wallet }) => wallet)
333
+ .catch(async (e) => {
334
+ await this.storage.remove("selected-wallet");
335
+ if (e instanceof errors_1.WalletError)
336
+ throw e;
337
+ throw new errors_1.WalletError({
338
+ code: errors_1.ErrorCode.NO_ACCOUNTS,
339
+ message: "No accounts found",
340
+ originalError: e instanceof Error ? e : undefined,
341
+ });
342
+ });
343
+ }
344
+ const wallet = this.wallets.find((wallet) => wallet.manifest.id === id);
345
+ if (!wallet) {
346
+ // Try to find install URL from manifest
347
+ const manifestWallet = this.manifest.wallets.find((w) => w.id === id);
348
+ throw new errors_1.WalletNotFoundError(id, manifestWallet?.website);
349
+ }
350
+ return wallet;
351
+ }
352
+ on(event, callback) {
353
+ this.events.on(event, callback);
354
+ }
355
+ once(event, callback) {
356
+ this.events.once(event, callback);
357
+ }
358
+ off(event, callback) {
359
+ this.events.off(event, callback);
360
+ }
361
+ removeAllListeners(event) {
362
+ this.events.removeAllListeners(event);
363
+ }
364
+ // ===== Multi-Account Management =====
365
+ /**
366
+ * Get all connected accounts across all wallets
367
+ */
368
+ getConnectedAccounts() {
369
+ return [...this.connectedAccounts];
370
+ }
371
+ /**
372
+ * Get the currently active account
373
+ */
374
+ getActiveAccount() {
375
+ if (!this.activeAccountId)
376
+ return null;
377
+ return this.connectedAccounts.find((a) => a.accountId === this.activeAccountId) ?? null;
378
+ }
379
+ /**
380
+ * Switch to a different connected account
381
+ */
382
+ async switchAccount(accountId) {
383
+ const account = this.connectedAccounts.find((a) => a.accountId === accountId);
384
+ if (!account) {
385
+ throw new errors_1.WalletError({
386
+ code: errors_1.ErrorCode.NO_ACCOUNTS,
387
+ message: `Account ${accountId} is not connected`,
388
+ });
389
+ }
390
+ // Switch network if needed
391
+ if (account.network !== this.network) {
392
+ this.network = account.network;
393
+ }
394
+ // Update selected wallet
395
+ await this.storage.set("selected-wallet", account.walletId);
396
+ this.activeAccountId = accountId;
397
+ await this.saveMultiAccountState();
398
+ this.events.emit("account:switched", { account, previousAccountId: this.activeAccountId });
399
+ return account;
400
+ }
401
+ /**
402
+ * Add a new account by connecting another wallet
403
+ * Returns the newly added accounts
404
+ */
405
+ async addAccount(walletId) {
406
+ await this.whenManifestLoaded.catch(() => { });
407
+ if (!walletId) {
408
+ walletId = await this.selectWallet();
409
+ }
410
+ const wallet = await this.wallet(walletId);
411
+ const accounts = await wallet.signIn({
412
+ contractId: this.signInData?.contractId,
413
+ methodNames: this.signInData?.methodNames,
414
+ network: this.network,
415
+ });
416
+ if (!accounts?.length) {
417
+ throw new errors_1.WalletError({
418
+ code: errors_1.ErrorCode.NO_ACCOUNTS,
419
+ message: "Wallet returned no accounts after sign in",
420
+ walletId,
421
+ });
422
+ }
423
+ const newAccounts = [];
424
+ for (const account of accounts) {
425
+ // Check if account already connected
426
+ const existing = this.connectedAccounts.find((a) => a.accountId === account.accountId);
427
+ if (existing) {
428
+ this.logger?.log(`Account ${account.accountId} already connected`);
429
+ continue;
430
+ }
431
+ const connectedAccount = {
432
+ ...account,
433
+ walletId,
434
+ walletName: wallet.manifest.name,
435
+ walletIcon: wallet.manifest.icon,
436
+ network: this.network,
437
+ connectedAt: Date.now(),
438
+ };
439
+ this.connectedAccounts.push(connectedAccount);
440
+ newAccounts.push(connectedAccount);
441
+ }
442
+ // Set first new account as active if no active account
443
+ if (!this.activeAccountId && newAccounts.length > 0) {
444
+ this.activeAccountId = newAccounts[0].accountId;
445
+ await this.storage.set("selected-wallet", walletId);
446
+ }
447
+ await this.saveMultiAccountState();
448
+ this.events.emit("account:added", { accounts: newAccounts });
449
+ return newAccounts;
450
+ }
451
+ /**
452
+ * Remove a connected account
453
+ */
454
+ async removeAccount(accountId) {
455
+ const accountIndex = this.connectedAccounts.findIndex((a) => a.accountId === accountId);
456
+ if (accountIndex === -1) {
457
+ throw new errors_1.WalletError({
458
+ code: errors_1.ErrorCode.NO_ACCOUNTS,
459
+ message: `Account ${accountId} is not connected`,
460
+ });
461
+ }
462
+ const account = this.connectedAccounts[accountIndex];
463
+ this.connectedAccounts.splice(accountIndex, 1);
464
+ // If removing active account, switch to another
465
+ if (this.activeAccountId === accountId) {
466
+ if (this.connectedAccounts.length > 0) {
467
+ this.activeAccountId = this.connectedAccounts[0].accountId;
468
+ await this.storage.set("selected-wallet", this.connectedAccounts[0].walletId);
469
+ }
470
+ else {
471
+ this.activeAccountId = null;
472
+ await this.storage.remove("selected-wallet");
473
+ }
474
+ }
475
+ await this.saveMultiAccountState();
476
+ this.events.emit("account:removed", { account });
477
+ }
478
+ /**
479
+ * Check if multi-account mode has any accounts
480
+ */
481
+ hasConnectedAccounts() {
482
+ return this.connectedAccounts.length > 0;
483
+ }
484
+ /**
485
+ * Get accounts for a specific wallet
486
+ */
487
+ getAccountsForWallet(walletId) {
488
+ return this.connectedAccounts.filter((a) => a.walletId === walletId);
489
+ }
490
+ /**
491
+ * Load multi-account state from storage
492
+ */
493
+ async loadMultiAccountState() {
494
+ try {
495
+ const raw = await this.storage.get(MULTI_ACCOUNT_STORAGE_KEY);
496
+ if (!raw)
497
+ return;
498
+ const state = JSON.parse(raw);
499
+ this.connectedAccounts = state.accounts ?? [];
500
+ this.activeAccountId = state.activeAccountId;
501
+ }
502
+ catch (e) {
503
+ this.logger?.log("Failed to load multi-account state", e);
504
+ }
505
+ }
506
+ /**
507
+ * Save multi-account state to storage
508
+ */
509
+ async saveMultiAccountState() {
510
+ try {
511
+ const state = {
512
+ accounts: this.connectedAccounts,
513
+ activeAccountId: this.activeAccountId,
514
+ };
515
+ await this.storage.set(MULTI_ACCOUNT_STORAGE_KEY, JSON.stringify(state));
516
+ }
517
+ catch (e) {
518
+ this.logger?.log("Failed to save multi-account state", e);
519
+ }
520
+ }
521
+ /**
522
+ * Clear all connected accounts
523
+ */
524
+ async clearAllAccounts() {
525
+ this.connectedAccounts = [];
526
+ this.activeAccountId = null;
527
+ await this.storage.remove(MULTI_ACCOUNT_STORAGE_KEY);
528
+ await this.storage.remove("selected-wallet");
529
+ if (this.persistenceEnabled) {
530
+ await this.session.clear();
531
+ }
532
+ this.events.emit("account:cleared", {});
533
+ }
534
+ }
535
+ exports.NearConnector = NearConnector;
536
+ //# sourceMappingURL=NearConnector.js.map