@phantom/browser-sdk 1.0.0-beta.0 → 1.0.0-beta.10
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.
- package/README.md +110 -122
- package/dist/index.d.ts +67 -16
- package/dist/index.js +538 -163
- package/dist/index.mjs +541 -167
- package/package.json +11 -9
package/dist/index.js
CHANGED
|
@@ -20,23 +20,27 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
|
-
AddressType: () =>
|
|
23
|
+
AddressType: () => import_client5.AddressType,
|
|
24
24
|
BrowserSDK: () => BrowserSDK,
|
|
25
|
-
DEFAULT_AUTH_URL: () => DEFAULT_AUTH_URL,
|
|
26
|
-
DEFAULT_WALLET_API_URL: () => DEFAULT_WALLET_API_URL,
|
|
27
25
|
DebugCategory: () => DebugCategory,
|
|
28
26
|
DebugLevel: () => DebugLevel,
|
|
29
|
-
NetworkId: () =>
|
|
27
|
+
NetworkId: () => import_constants5.NetworkId,
|
|
30
28
|
debug: () => debug,
|
|
31
29
|
detectBrowser: () => detectBrowser,
|
|
32
30
|
getBrowserDisplayName: () => getBrowserDisplayName,
|
|
31
|
+
getDeeplinkToPhantom: () => getDeeplinkToPhantom,
|
|
33
32
|
getPlatformName: () => getPlatformName,
|
|
34
|
-
|
|
33
|
+
isMobileDevice: () => isMobileDevice,
|
|
34
|
+
parseBrowserFromUserAgent: () => parseBrowserFromUserAgent,
|
|
35
|
+
waitForPhantomExtension: () => waitForPhantomExtension
|
|
35
36
|
});
|
|
36
37
|
module.exports = __toCommonJS(src_exports);
|
|
37
38
|
|
|
38
|
-
// src/
|
|
39
|
+
// src/types.ts
|
|
39
40
|
var import_client = require("@phantom/client");
|
|
41
|
+
|
|
42
|
+
// src/providers/injected/index.ts
|
|
43
|
+
var import_client4 = require("@phantom/client");
|
|
40
44
|
var import_browser_injected_sdk = require("@phantom/browser-injected-sdk");
|
|
41
45
|
var import_solana = require("@phantom/browser-injected-sdk/solana");
|
|
42
46
|
var import_ethereum = require("@phantom/browser-injected-sdk/ethereum");
|
|
@@ -117,97 +121,206 @@ var DebugCategory = {
|
|
|
117
121
|
};
|
|
118
122
|
|
|
119
123
|
// src/providers/injected/chains/SolanaChain.ts
|
|
120
|
-
var
|
|
124
|
+
var import_eventemitter3 = require("eventemitter3");
|
|
125
|
+
var import_client2 = require("@phantom/client");
|
|
121
126
|
var import_buffer = require("buffer");
|
|
122
127
|
var InjectedSolanaChain = class {
|
|
123
|
-
constructor(phantom) {
|
|
128
|
+
constructor(phantom, callbacks) {
|
|
129
|
+
this._connected = false;
|
|
130
|
+
this._publicKey = null;
|
|
131
|
+
this.eventEmitter = new import_eventemitter3.EventEmitter();
|
|
124
132
|
this.phantom = phantom;
|
|
133
|
+
this.callbacks = callbacks;
|
|
134
|
+
this.setupEventListeners();
|
|
135
|
+
this.syncInitialState();
|
|
136
|
+
}
|
|
137
|
+
// Wallet adapter compliant properties
|
|
138
|
+
get connected() {
|
|
139
|
+
return this._connected;
|
|
140
|
+
}
|
|
141
|
+
get publicKey() {
|
|
142
|
+
return this._publicKey;
|
|
143
|
+
}
|
|
144
|
+
// Connection methods - delegate to provider
|
|
145
|
+
connect(_options) {
|
|
146
|
+
if (!this.callbacks.isConnected()) {
|
|
147
|
+
return Promise.reject(new Error("Provider not connected. Call provider connect first."));
|
|
148
|
+
}
|
|
149
|
+
const addresses = this.callbacks.getAddresses();
|
|
150
|
+
const solanaAddress = addresses.find((addr) => addr.addressType === import_client2.AddressType.solana);
|
|
151
|
+
if (!solanaAddress) {
|
|
152
|
+
return Promise.reject(new Error("Solana not enabled for this provider"));
|
|
153
|
+
}
|
|
154
|
+
this.updateConnectionState(true, solanaAddress.address);
|
|
155
|
+
return Promise.resolve({ publicKey: solanaAddress.address });
|
|
125
156
|
}
|
|
157
|
+
async disconnect() {
|
|
158
|
+
await this.callbacks.disconnect();
|
|
159
|
+
}
|
|
160
|
+
// Standard wallet adapter methods
|
|
126
161
|
async signMessage(message) {
|
|
127
162
|
const messageBytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
|
|
128
163
|
const result = await this.phantom.solana.signMessage(messageBytes);
|
|
129
|
-
const signature = result.signature instanceof Uint8Array ? import_buffer.Buffer.from(result.signature).toString("base64") : result.signature;
|
|
130
164
|
return {
|
|
131
|
-
signature,
|
|
132
|
-
|
|
165
|
+
signature: result.signature instanceof Uint8Array ? result.signature : new Uint8Array(import_buffer.Buffer.from(result.signature, "base64")),
|
|
166
|
+
publicKey: this._publicKey || ""
|
|
133
167
|
};
|
|
134
168
|
}
|
|
135
|
-
signTransaction(
|
|
136
|
-
|
|
169
|
+
async signTransaction(transaction) {
|
|
170
|
+
if (!this.callbacks.isConnected()) {
|
|
171
|
+
return Promise.reject(new Error("Provider not connected. Call provider connect first."));
|
|
172
|
+
}
|
|
173
|
+
try {
|
|
174
|
+
const result = await this.phantom.solana.signTransaction(transaction);
|
|
175
|
+
return result;
|
|
176
|
+
} catch (error) {
|
|
177
|
+
return Promise.reject(error);
|
|
178
|
+
}
|
|
137
179
|
}
|
|
138
180
|
async signAndSendTransaction(transaction) {
|
|
139
181
|
const result = await this.phantom.solana.signAndSendTransaction(transaction);
|
|
140
|
-
return {
|
|
141
|
-
hash: result.signature,
|
|
142
|
-
rawTransaction: result.signature,
|
|
143
|
-
blockExplorer: (0, import_constants.getExplorerUrl)(import_constants.NetworkId.SOLANA_MAINNET, "transaction", result.signature)
|
|
144
|
-
};
|
|
182
|
+
return { signature: result.signature };
|
|
145
183
|
}
|
|
146
|
-
async
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
184
|
+
async signAllTransactions(transactions) {
|
|
185
|
+
if (!this.callbacks.isConnected()) {
|
|
186
|
+
return Promise.reject(new Error("Provider not connected. Call provider connect first."));
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
const result = await this.phantom.solana.signAllTransactions(transactions);
|
|
190
|
+
return result;
|
|
191
|
+
} catch (error) {
|
|
192
|
+
return Promise.reject(error);
|
|
150
193
|
}
|
|
151
|
-
return { publicKey: address };
|
|
152
|
-
}
|
|
153
|
-
async disconnect() {
|
|
154
|
-
return await this.phantom.solana.disconnect();
|
|
155
|
-
}
|
|
156
|
-
async switchNetwork(_network) {
|
|
157
194
|
}
|
|
158
|
-
async
|
|
195
|
+
async signAndSendAllTransactions(transactions) {
|
|
196
|
+
if (!this.callbacks.isConnected()) {
|
|
197
|
+
return Promise.reject(new Error("Provider not connected. Call provider connect first."));
|
|
198
|
+
}
|
|
159
199
|
try {
|
|
160
|
-
const
|
|
161
|
-
return
|
|
162
|
-
} catch {
|
|
163
|
-
return
|
|
200
|
+
const result = await this.phantom.solana.signAndSendAllTransactions(transactions);
|
|
201
|
+
return { signatures: result.signatures };
|
|
202
|
+
} catch (error) {
|
|
203
|
+
return Promise.reject(error);
|
|
164
204
|
}
|
|
165
205
|
}
|
|
206
|
+
switchNetwork(_network) {
|
|
207
|
+
return Promise.resolve();
|
|
208
|
+
}
|
|
209
|
+
// Legacy methods
|
|
210
|
+
getPublicKey() {
|
|
211
|
+
return Promise.resolve(this._publicKey);
|
|
212
|
+
}
|
|
166
213
|
isConnected() {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
214
|
+
return this._connected && this.callbacks.isConnected();
|
|
215
|
+
}
|
|
216
|
+
setupEventListeners() {
|
|
217
|
+
this.phantom.solana.addEventListener("connect", (publicKey) => {
|
|
218
|
+
this.updateConnectionState(true, publicKey);
|
|
219
|
+
this.eventEmitter.emit("connect", publicKey);
|
|
220
|
+
});
|
|
221
|
+
this.phantom.solana.addEventListener("disconnect", () => {
|
|
222
|
+
this.updateConnectionState(false, null);
|
|
223
|
+
this.eventEmitter.emit("disconnect");
|
|
224
|
+
});
|
|
225
|
+
this.phantom.solana.addEventListener("accountChanged", (publicKey) => {
|
|
226
|
+
this._publicKey = publicKey;
|
|
227
|
+
this.eventEmitter.emit("accountChanged", publicKey);
|
|
228
|
+
});
|
|
229
|
+
this.callbacks.on("connect", (data) => {
|
|
230
|
+
const solanaAddress = data.addresses?.find((addr) => addr.addressType === import_client2.AddressType.solana);
|
|
231
|
+
if (solanaAddress) {
|
|
232
|
+
this.updateConnectionState(true, solanaAddress.address);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
this.callbacks.on("disconnect", () => {
|
|
236
|
+
this.updateConnectionState(false, null);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
syncInitialState() {
|
|
240
|
+
if (this.callbacks.isConnected()) {
|
|
241
|
+
const solanaAddress = this.callbacks.getAddresses().find((addr) => addr.addressType === import_client2.AddressType.solana);
|
|
242
|
+
if (solanaAddress) {
|
|
243
|
+
this.updateConnectionState(true, solanaAddress.address);
|
|
244
|
+
}
|
|
171
245
|
}
|
|
172
246
|
}
|
|
247
|
+
updateConnectionState(connected, publicKey) {
|
|
248
|
+
this._connected = connected;
|
|
249
|
+
this._publicKey = publicKey;
|
|
250
|
+
}
|
|
251
|
+
// Event methods for interface compliance
|
|
252
|
+
on(event, listener) {
|
|
253
|
+
this.eventEmitter.on(event, listener);
|
|
254
|
+
}
|
|
255
|
+
off(event, listener) {
|
|
256
|
+
this.eventEmitter.off(event, listener);
|
|
257
|
+
}
|
|
173
258
|
};
|
|
174
259
|
|
|
175
260
|
// src/providers/injected/chains/EthereumChain.ts
|
|
176
|
-
var
|
|
261
|
+
var import_eventemitter32 = require("eventemitter3");
|
|
262
|
+
var import_client3 = require("@phantom/client");
|
|
177
263
|
var InjectedEthereumChain = class {
|
|
178
|
-
constructor(phantom) {
|
|
264
|
+
constructor(phantom, callbacks) {
|
|
265
|
+
this._connected = false;
|
|
266
|
+
this._chainId = "0x1";
|
|
267
|
+
this._accounts = [];
|
|
268
|
+
this.eventEmitter = new import_eventemitter32.EventEmitter();
|
|
179
269
|
this.phantom = phantom;
|
|
270
|
+
this.callbacks = callbacks;
|
|
271
|
+
this.setupEventListeners();
|
|
272
|
+
this.syncInitialState();
|
|
273
|
+
}
|
|
274
|
+
// EIP-1193 compliant properties
|
|
275
|
+
get connected() {
|
|
276
|
+
return this._connected;
|
|
277
|
+
}
|
|
278
|
+
get chainId() {
|
|
279
|
+
return this._chainId;
|
|
280
|
+
}
|
|
281
|
+
get accounts() {
|
|
282
|
+
return this._accounts;
|
|
180
283
|
}
|
|
284
|
+
// EIP-1193 core method with eth_signTransaction support
|
|
181
285
|
async request(args) {
|
|
286
|
+
if (args.method === "eth_signTransaction") {
|
|
287
|
+
const [transaction] = args.params;
|
|
288
|
+
const result = await this.signTransaction(transaction);
|
|
289
|
+
return result;
|
|
290
|
+
}
|
|
182
291
|
const provider = await this.phantom.ethereum.getProvider();
|
|
183
292
|
return await provider.request(args);
|
|
184
293
|
}
|
|
294
|
+
// Connection methods - delegate to provider
|
|
295
|
+
connect() {
|
|
296
|
+
if (!this.callbacks.isConnected()) {
|
|
297
|
+
return Promise.reject(new Error("Provider not connected. Call provider connect first."));
|
|
298
|
+
}
|
|
299
|
+
const addresses = this.callbacks.getAddresses();
|
|
300
|
+
const ethAddresses = addresses.filter((addr) => addr.addressType === import_client3.AddressType.ethereum).map((addr) => addr.address);
|
|
301
|
+
this.updateConnectionState(true, ethAddresses);
|
|
302
|
+
return Promise.resolve(ethAddresses);
|
|
303
|
+
}
|
|
304
|
+
async disconnect() {
|
|
305
|
+
await this.callbacks.disconnect();
|
|
306
|
+
}
|
|
307
|
+
// Standard compliant methods (return raw values, not wrapped objects)
|
|
185
308
|
async signPersonalMessage(message, address) {
|
|
186
|
-
|
|
187
|
-
return {
|
|
188
|
-
signature,
|
|
189
|
-
rawSignature: signature
|
|
190
|
-
};
|
|
309
|
+
return await this.phantom.ethereum.signPersonalMessage(message, address);
|
|
191
310
|
}
|
|
192
311
|
async signTypedData(typedData, address) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
};
|
|
312
|
+
return await this.phantom.ethereum.signTypedData(typedData, address);
|
|
313
|
+
}
|
|
314
|
+
async signTransaction(transaction) {
|
|
315
|
+
return await this.phantom.ethereum.signTransaction(transaction);
|
|
198
316
|
}
|
|
199
317
|
async sendTransaction(transaction) {
|
|
200
|
-
|
|
201
|
-
const chainId = await this.getChainId();
|
|
202
|
-
const networkId = (0, import_constants2.chainIdToNetworkId)(chainId) || import_constants2.NetworkId.ETHEREUM_MAINNET;
|
|
203
|
-
return {
|
|
204
|
-
hash,
|
|
205
|
-
rawTransaction: hash,
|
|
206
|
-
blockExplorer: (0, import_constants2.getExplorerUrl)(networkId, "transaction", hash)
|
|
207
|
-
};
|
|
318
|
+
return await this.phantom.ethereum.sendTransaction(transaction);
|
|
208
319
|
}
|
|
209
320
|
async switchChain(chainId) {
|
|
210
|
-
|
|
321
|
+
await this.phantom.ethereum.switchChain(`0x${chainId.toString(16)}`);
|
|
322
|
+
this._chainId = `0x${chainId.toString(16)}`;
|
|
323
|
+
this.eventEmitter.emit("chainChanged", this._chainId);
|
|
211
324
|
}
|
|
212
325
|
async getChainId() {
|
|
213
326
|
const chainId = await this.phantom.ethereum.getChainId();
|
|
@@ -217,12 +330,56 @@ var InjectedEthereumChain = class {
|
|
|
217
330
|
return await this.phantom.ethereum.getAccounts();
|
|
218
331
|
}
|
|
219
332
|
isConnected() {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
333
|
+
return this._connected && this.callbacks.isConnected();
|
|
334
|
+
}
|
|
335
|
+
setupEventListeners() {
|
|
336
|
+
this.phantom.ethereum.addEventListener("connect", (accounts) => {
|
|
337
|
+
this.updateConnectionState(true, accounts);
|
|
338
|
+
this.eventEmitter.emit("connect", { chainId: this._chainId });
|
|
339
|
+
this.eventEmitter.emit("accountsChanged", accounts);
|
|
340
|
+
});
|
|
341
|
+
this.phantom.ethereum.addEventListener("disconnect", () => {
|
|
342
|
+
this.updateConnectionState(false, []);
|
|
343
|
+
this.eventEmitter.emit("disconnect", { code: 4900, message: "Provider disconnected" });
|
|
344
|
+
this.eventEmitter.emit("accountsChanged", []);
|
|
345
|
+
});
|
|
346
|
+
this.phantom.ethereum.addEventListener("accountsChanged", (accounts) => {
|
|
347
|
+
this._accounts = accounts;
|
|
348
|
+
this.eventEmitter.emit("accountsChanged", accounts);
|
|
349
|
+
});
|
|
350
|
+
this.phantom.ethereum.addEventListener("chainChanged", (chainId) => {
|
|
351
|
+
this._chainId = chainId;
|
|
352
|
+
this.eventEmitter.emit("chainChanged", chainId);
|
|
353
|
+
});
|
|
354
|
+
this.callbacks.on("connect", (data) => {
|
|
355
|
+
const ethAddresses = data.addresses?.filter((addr) => addr.addressType === import_client3.AddressType.ethereum)?.map((addr) => addr.address) || [];
|
|
356
|
+
if (ethAddresses.length > 0) {
|
|
357
|
+
this.updateConnectionState(true, ethAddresses);
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
this.callbacks.on("disconnect", () => {
|
|
361
|
+
this.updateConnectionState(false, []);
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
syncInitialState() {
|
|
365
|
+
if (this.callbacks.isConnected()) {
|
|
366
|
+
const ethAddresses = this.callbacks.getAddresses().filter((addr) => addr.addressType === import_client3.AddressType.ethereum).map((addr) => addr.address);
|
|
367
|
+
if (ethAddresses.length > 0) {
|
|
368
|
+
this.updateConnectionState(true, ethAddresses);
|
|
369
|
+
}
|
|
224
370
|
}
|
|
225
371
|
}
|
|
372
|
+
updateConnectionState(connected, accounts) {
|
|
373
|
+
this._connected = connected;
|
|
374
|
+
this._accounts = accounts;
|
|
375
|
+
}
|
|
376
|
+
// Event methods for interface compliance
|
|
377
|
+
on(event, listener) {
|
|
378
|
+
this.eventEmitter.on(event, listener);
|
|
379
|
+
}
|
|
380
|
+
off(event, listener) {
|
|
381
|
+
this.eventEmitter.off(event, listener);
|
|
382
|
+
}
|
|
226
383
|
};
|
|
227
384
|
|
|
228
385
|
// src/providers/injected/index.ts
|
|
@@ -238,11 +395,11 @@ var InjectedProvider = class {
|
|
|
238
395
|
this.addressTypes = config.addressTypes;
|
|
239
396
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Address types configured", { addressTypes: this.addressTypes });
|
|
240
397
|
const plugins = [(0, import_browser_injected_sdk.createExtensionPlugin)()];
|
|
241
|
-
if (this.addressTypes.includes(
|
|
398
|
+
if (this.addressTypes.includes(import_client4.AddressType.solana)) {
|
|
242
399
|
plugins.push((0, import_solana.createSolanaPlugin)());
|
|
243
400
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana plugin added");
|
|
244
401
|
}
|
|
245
|
-
if (this.addressTypes.includes(
|
|
402
|
+
if (this.addressTypes.includes(import_client4.AddressType.ethereum)) {
|
|
246
403
|
plugins.push((0, import_ethereum.createEthereumPlugin)());
|
|
247
404
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum plugin added");
|
|
248
405
|
}
|
|
@@ -252,17 +409,24 @@ var InjectedProvider = class {
|
|
|
252
409
|
pluginCount: plugins.length
|
|
253
410
|
});
|
|
254
411
|
this.phantom = (0, import_browser_injected_sdk.createPhantom)({ plugins });
|
|
412
|
+
const callbacks = this.createCallbacks();
|
|
413
|
+
if (this.addressTypes.includes(import_client4.AddressType.solana)) {
|
|
414
|
+
this._solanaChain = new InjectedSolanaChain(this.phantom, callbacks);
|
|
415
|
+
}
|
|
416
|
+
if (this.addressTypes.includes(import_client4.AddressType.ethereum)) {
|
|
417
|
+
this._ethereumChain = new InjectedEthereumChain(this.phantom, callbacks);
|
|
418
|
+
}
|
|
255
419
|
debug.info(DebugCategory.INJECTED_PROVIDER, "InjectedProvider initialized");
|
|
256
420
|
}
|
|
257
421
|
/**
|
|
258
422
|
* Access to Solana chain operations
|
|
259
423
|
*/
|
|
260
424
|
get solana() {
|
|
261
|
-
if (!this.addressTypes.includes(
|
|
425
|
+
if (!this.addressTypes.includes(import_client4.AddressType.solana)) {
|
|
262
426
|
throw new Error("Solana not enabled for this provider");
|
|
263
427
|
}
|
|
264
428
|
if (!this._solanaChain) {
|
|
265
|
-
|
|
429
|
+
throw new Error("Solana chain not initialized");
|
|
266
430
|
}
|
|
267
431
|
return this._solanaChain;
|
|
268
432
|
}
|
|
@@ -270,11 +434,11 @@ var InjectedProvider = class {
|
|
|
270
434
|
* Access to Ethereum chain operations
|
|
271
435
|
*/
|
|
272
436
|
get ethereum() {
|
|
273
|
-
if (!this.addressTypes.includes(
|
|
437
|
+
if (!this.addressTypes.includes(import_client4.AddressType.ethereum)) {
|
|
274
438
|
throw new Error("Ethereum not enabled for this provider");
|
|
275
439
|
}
|
|
276
440
|
if (!this._ethereumChain) {
|
|
277
|
-
|
|
441
|
+
throw new Error("Ethereum chain not initialized");
|
|
278
442
|
}
|
|
279
443
|
return this._ethereumChain;
|
|
280
444
|
}
|
|
@@ -300,28 +464,28 @@ var InjectedProvider = class {
|
|
|
300
464
|
}
|
|
301
465
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Phantom extension detected");
|
|
302
466
|
const connectedAddresses = [];
|
|
303
|
-
if (this.addressTypes.includes(
|
|
467
|
+
if (this.addressTypes.includes(import_client4.AddressType.solana)) {
|
|
304
468
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana connection");
|
|
305
469
|
try {
|
|
306
|
-
const
|
|
307
|
-
if (
|
|
470
|
+
const publicKey = await this.phantom.solana.connect();
|
|
471
|
+
if (publicKey) {
|
|
308
472
|
connectedAddresses.push({
|
|
309
|
-
addressType:
|
|
310
|
-
address:
|
|
473
|
+
addressType: import_client4.AddressType.solana,
|
|
474
|
+
address: publicKey
|
|
311
475
|
});
|
|
312
|
-
debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", { address:
|
|
476
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", { address: publicKey });
|
|
313
477
|
}
|
|
314
478
|
} catch (err) {
|
|
315
479
|
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana", { error: err });
|
|
316
480
|
}
|
|
317
481
|
}
|
|
318
|
-
if (this.addressTypes.includes(
|
|
482
|
+
if (this.addressTypes.includes(import_client4.AddressType.ethereum)) {
|
|
319
483
|
try {
|
|
320
|
-
const accounts = await this.ethereum.
|
|
484
|
+
const accounts = await this.phantom.ethereum.connect();
|
|
321
485
|
if (accounts && accounts.length > 0) {
|
|
322
486
|
connectedAddresses.push(
|
|
323
487
|
...accounts.map((address) => ({
|
|
324
|
-
addressType:
|
|
488
|
+
addressType: import_client4.AddressType.ethereum,
|
|
325
489
|
address
|
|
326
490
|
}))
|
|
327
491
|
);
|
|
@@ -363,19 +527,17 @@ var InjectedProvider = class {
|
|
|
363
527
|
}
|
|
364
528
|
async disconnect() {
|
|
365
529
|
debug.info(DebugCategory.INJECTED_PROVIDER, "Starting injected provider disconnect");
|
|
366
|
-
if (this.addressTypes.includes(
|
|
530
|
+
if (this.addressTypes.includes(import_client4.AddressType.solana)) {
|
|
367
531
|
try {
|
|
368
|
-
await this.solana.disconnect();
|
|
532
|
+
await this.phantom.solana.disconnect();
|
|
369
533
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnected successfully");
|
|
370
534
|
} catch (err) {
|
|
371
535
|
debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to disconnect Solana", { error: err });
|
|
372
536
|
}
|
|
373
537
|
}
|
|
374
|
-
if (this.addressTypes.includes(
|
|
538
|
+
if (this.addressTypes.includes(import_client4.AddressType.ethereum)) {
|
|
375
539
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnected (no-op)");
|
|
376
540
|
}
|
|
377
|
-
this._solanaChain = void 0;
|
|
378
|
-
this._ethereumChain = void 0;
|
|
379
541
|
this.browserInjectedCleanupFunctions.forEach((cleanup) => cleanup());
|
|
380
542
|
this.browserInjectedCleanupFunctions = [];
|
|
381
543
|
this.connected = false;
|
|
@@ -385,6 +547,87 @@ var InjectedProvider = class {
|
|
|
385
547
|
});
|
|
386
548
|
debug.info(DebugCategory.INJECTED_PROVIDER, "Injected provider disconnected successfully");
|
|
387
549
|
}
|
|
550
|
+
/**
|
|
551
|
+
* Attempt auto-connection using onlyIfTrusted parameter
|
|
552
|
+
* This will only connect if the dApp is already trusted by the user
|
|
553
|
+
* Should be called after setting up event listeners
|
|
554
|
+
*/
|
|
555
|
+
async autoConnect() {
|
|
556
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting auto-connect with onlyIfTrusted=true");
|
|
557
|
+
this.emit("connect_start", {
|
|
558
|
+
source: "auto-connect",
|
|
559
|
+
providerType: "injected"
|
|
560
|
+
});
|
|
561
|
+
try {
|
|
562
|
+
if (!this.phantom.extension?.isInstalled?.()) {
|
|
563
|
+
debug.warn(DebugCategory.INJECTED_PROVIDER, "Phantom wallet extension not found for auto-connect");
|
|
564
|
+
this.emit("connect_error", {
|
|
565
|
+
error: "Phantom wallet not found",
|
|
566
|
+
source: "auto-connect"
|
|
567
|
+
});
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
const connectedAddresses = [];
|
|
571
|
+
if (this.addressTypes.includes(import_client4.AddressType.solana)) {
|
|
572
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Solana auto-connect");
|
|
573
|
+
try {
|
|
574
|
+
const publicKey = await this.phantom.solana.connect({ onlyIfTrusted: true });
|
|
575
|
+
if (publicKey) {
|
|
576
|
+
connectedAddresses.push({
|
|
577
|
+
addressType: import_client4.AddressType.solana,
|
|
578
|
+
address: publicKey
|
|
579
|
+
});
|
|
580
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "Solana auto-connected successfully", { address: publicKey });
|
|
581
|
+
}
|
|
582
|
+
} catch (err) {
|
|
583
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana auto-connect failed (expected if not trusted)", { error: err });
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
if (this.addressTypes.includes(import_client4.AddressType.ethereum)) {
|
|
587
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Attempting Ethereum auto-connect");
|
|
588
|
+
try {
|
|
589
|
+
const accounts = await this.phantom.ethereum.connect({ onlyIfTrusted: true });
|
|
590
|
+
if (accounts && accounts.length > 0) {
|
|
591
|
+
connectedAddresses.push(
|
|
592
|
+
...accounts.map((address) => ({
|
|
593
|
+
addressType: import_client4.AddressType.ethereum,
|
|
594
|
+
address
|
|
595
|
+
}))
|
|
596
|
+
);
|
|
597
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "Ethereum auto-connected successfully", { addresses: accounts });
|
|
598
|
+
}
|
|
599
|
+
} catch (err) {
|
|
600
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum auto-connect failed (expected if not trusted)", { error: err });
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
if (connectedAddresses.length === 0) {
|
|
604
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Auto-connect failed: no trusted connections available");
|
|
605
|
+
this.emit("connect_error", {
|
|
606
|
+
error: "No trusted connections available",
|
|
607
|
+
source: "auto-connect"
|
|
608
|
+
});
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
this.addresses = connectedAddresses;
|
|
612
|
+
this.connected = true;
|
|
613
|
+
this.emit("connect", {
|
|
614
|
+
addresses: this.addresses,
|
|
615
|
+
source: "auto-connect"
|
|
616
|
+
});
|
|
617
|
+
debug.info(DebugCategory.INJECTED_PROVIDER, "Auto-connect successful", {
|
|
618
|
+
addressCount: connectedAddresses.length,
|
|
619
|
+
addresses: connectedAddresses.map((addr) => ({ type: addr.addressType, address: addr.address.substring(0, 8) + "..." }))
|
|
620
|
+
});
|
|
621
|
+
} catch (error) {
|
|
622
|
+
debug.log(DebugCategory.INJECTED_PROVIDER, "Auto-connect failed with error", {
|
|
623
|
+
error: error instanceof Error ? error.message : String(error)
|
|
624
|
+
});
|
|
625
|
+
this.emit("connect_error", {
|
|
626
|
+
error: error instanceof Error ? error.message : "Auto-connect failed",
|
|
627
|
+
source: "auto-connect"
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
}
|
|
388
631
|
getAddresses() {
|
|
389
632
|
return this.addresses;
|
|
390
633
|
}
|
|
@@ -448,10 +691,10 @@ var InjectedProvider = class {
|
|
|
448
691
|
}
|
|
449
692
|
setupBrowserInjectedEvents() {
|
|
450
693
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up browser-injected-sdk event listeners");
|
|
451
|
-
if (this.addressTypes.includes(
|
|
694
|
+
if (this.addressTypes.includes(import_client4.AddressType.solana)) {
|
|
452
695
|
this.setupSolanaEvents();
|
|
453
696
|
}
|
|
454
|
-
if (this.addressTypes.includes(
|
|
697
|
+
if (this.addressTypes.includes(import_client4.AddressType.ethereum)) {
|
|
455
698
|
this.setupEthereumEvents();
|
|
456
699
|
}
|
|
457
700
|
}
|
|
@@ -459,8 +702,8 @@ var InjectedProvider = class {
|
|
|
459
702
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Solana event listeners");
|
|
460
703
|
const handleSolanaConnect = (publicKey) => {
|
|
461
704
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana connect event received", { publicKey });
|
|
462
|
-
const solanaAddress = { addressType:
|
|
463
|
-
if (!this.addresses.find((addr) => addr.addressType ===
|
|
705
|
+
const solanaAddress = { addressType: import_client4.AddressType.solana, address: publicKey };
|
|
706
|
+
if (!this.addresses.find((addr) => addr.addressType === import_client4.AddressType.solana)) {
|
|
464
707
|
this.addresses.push(solanaAddress);
|
|
465
708
|
}
|
|
466
709
|
this.connected = true;
|
|
@@ -471,19 +714,19 @@ var InjectedProvider = class {
|
|
|
471
714
|
};
|
|
472
715
|
const handleSolanaDisconnect = () => {
|
|
473
716
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana disconnect event received");
|
|
474
|
-
this.addresses = this.addresses.filter((addr) => addr.addressType !==
|
|
475
|
-
this.connected =
|
|
717
|
+
this.addresses = this.addresses.filter((addr) => addr.addressType !== import_client4.AddressType.solana);
|
|
718
|
+
this.connected = false;
|
|
476
719
|
this.emit("disconnect", {
|
|
477
720
|
source: "injected-extension"
|
|
478
721
|
});
|
|
479
722
|
};
|
|
480
723
|
const handleSolanaAccountChanged = (publicKey) => {
|
|
481
724
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Solana account changed event received", { publicKey });
|
|
482
|
-
const solanaIndex = this.addresses.findIndex((addr) => addr.addressType ===
|
|
725
|
+
const solanaIndex = this.addresses.findIndex((addr) => addr.addressType === import_client4.AddressType.solana);
|
|
483
726
|
if (solanaIndex >= 0) {
|
|
484
|
-
this.addresses[solanaIndex] = { addressType:
|
|
727
|
+
this.addresses[solanaIndex] = { addressType: import_client4.AddressType.solana, address: publicKey };
|
|
485
728
|
} else {
|
|
486
|
-
this.addresses.push({ addressType:
|
|
729
|
+
this.addresses.push({ addressType: import_client4.AddressType.solana, address: publicKey });
|
|
487
730
|
}
|
|
488
731
|
this.emit("connect", {
|
|
489
732
|
addresses: this.addresses,
|
|
@@ -493,22 +736,20 @@ var InjectedProvider = class {
|
|
|
493
736
|
const cleanupConnect = this.phantom.solana.addEventListener("connect", handleSolanaConnect);
|
|
494
737
|
const cleanupDisconnect = this.phantom.solana.addEventListener("disconnect", handleSolanaDisconnect);
|
|
495
738
|
const cleanupAccountChanged = this.phantom.solana.addEventListener("accountChanged", handleSolanaAccountChanged);
|
|
496
|
-
this.browserInjectedCleanupFunctions.push(
|
|
497
|
-
cleanupConnect,
|
|
498
|
-
cleanupDisconnect,
|
|
499
|
-
cleanupAccountChanged
|
|
500
|
-
);
|
|
739
|
+
this.browserInjectedCleanupFunctions.push(cleanupConnect, cleanupDisconnect, cleanupAccountChanged);
|
|
501
740
|
}
|
|
502
741
|
setupEthereumEvents() {
|
|
503
742
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Setting up Ethereum event listeners");
|
|
504
743
|
const handleEthereumConnect = (accounts) => {
|
|
505
744
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum connect event received", { accounts });
|
|
506
|
-
this.addresses = this.addresses.filter((addr) => addr.addressType !==
|
|
745
|
+
this.addresses = this.addresses.filter((addr) => addr.addressType !== import_client4.AddressType.ethereum);
|
|
507
746
|
if (accounts && accounts.length > 0) {
|
|
508
|
-
this.addresses.push(
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
747
|
+
this.addresses.push(
|
|
748
|
+
...accounts.map((address) => ({
|
|
749
|
+
addressType: import_client4.AddressType.ethereum,
|
|
750
|
+
address
|
|
751
|
+
}))
|
|
752
|
+
);
|
|
512
753
|
}
|
|
513
754
|
this.connected = this.addresses.length > 0;
|
|
514
755
|
this.emit("connect", {
|
|
@@ -518,34 +759,63 @@ var InjectedProvider = class {
|
|
|
518
759
|
};
|
|
519
760
|
const handleEthereumDisconnect = () => {
|
|
520
761
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum disconnect event received");
|
|
521
|
-
this.addresses = this.addresses.filter((addr) => addr.addressType !==
|
|
522
|
-
this.connected =
|
|
762
|
+
this.addresses = this.addresses.filter((addr) => addr.addressType !== import_client4.AddressType.ethereum);
|
|
763
|
+
this.connected = false;
|
|
523
764
|
this.emit("disconnect", {
|
|
524
765
|
source: "injected-extension"
|
|
525
766
|
});
|
|
526
767
|
};
|
|
527
768
|
const handleEthereumAccountsChanged = (accounts) => {
|
|
528
769
|
debug.log(DebugCategory.INJECTED_PROVIDER, "Ethereum accounts changed event received", { accounts });
|
|
529
|
-
this.addresses = this.addresses.filter((addr) => addr.addressType !==
|
|
770
|
+
this.addresses = this.addresses.filter((addr) => addr.addressType !== import_client4.AddressType.ethereum);
|
|
530
771
|
if (accounts && accounts.length > 0) {
|
|
531
|
-
this.addresses.push(
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
772
|
+
this.addresses.push(
|
|
773
|
+
...accounts.map((address) => ({
|
|
774
|
+
addressType: import_client4.AddressType.ethereum,
|
|
775
|
+
address
|
|
776
|
+
}))
|
|
777
|
+
);
|
|
778
|
+
this.emit("connect", {
|
|
779
|
+
addresses: this.addresses,
|
|
780
|
+
source: "injected-extension-account-change"
|
|
781
|
+
});
|
|
782
|
+
} else {
|
|
783
|
+
this.connected = false;
|
|
784
|
+
this.emit("disconnect", {
|
|
785
|
+
source: "injected-extension-account-change"
|
|
786
|
+
});
|
|
535
787
|
}
|
|
536
|
-
this.emit("connect", {
|
|
537
|
-
addresses: this.addresses,
|
|
538
|
-
source: "injected-extension-account-change"
|
|
539
|
-
});
|
|
540
788
|
};
|
|
541
789
|
const cleanupConnect = this.phantom.ethereum.addEventListener("connect", handleEthereumConnect);
|
|
542
790
|
const cleanupDisconnect = this.phantom.ethereum.addEventListener("disconnect", handleEthereumDisconnect);
|
|
543
|
-
const cleanupAccountsChanged = this.phantom.ethereum.addEventListener(
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
cleanupDisconnect,
|
|
547
|
-
cleanupAccountsChanged
|
|
791
|
+
const cleanupAccountsChanged = this.phantom.ethereum.addEventListener(
|
|
792
|
+
"accountsChanged",
|
|
793
|
+
handleEthereumAccountsChanged
|
|
548
794
|
);
|
|
795
|
+
this.browserInjectedCleanupFunctions.push(cleanupConnect, cleanupDisconnect, cleanupAccountsChanged);
|
|
796
|
+
}
|
|
797
|
+
createCallbacks() {
|
|
798
|
+
return {
|
|
799
|
+
connect: async () => {
|
|
800
|
+
const result = await this.connect();
|
|
801
|
+
return result.addresses;
|
|
802
|
+
},
|
|
803
|
+
disconnect: async () => {
|
|
804
|
+
await this.disconnect();
|
|
805
|
+
},
|
|
806
|
+
isConnected: () => {
|
|
807
|
+
return this.isConnected();
|
|
808
|
+
},
|
|
809
|
+
getAddresses: () => {
|
|
810
|
+
return this.getAddresses();
|
|
811
|
+
},
|
|
812
|
+
on: (event, callback) => {
|
|
813
|
+
this.on(event, callback);
|
|
814
|
+
},
|
|
815
|
+
off: (event, callback) => {
|
|
816
|
+
this.off(event, callback);
|
|
817
|
+
}
|
|
818
|
+
};
|
|
549
819
|
}
|
|
550
820
|
};
|
|
551
821
|
|
|
@@ -643,15 +913,19 @@ var BrowserURLParamsAccessor = class {
|
|
|
643
913
|
};
|
|
644
914
|
var browserUrlParamsAccessor = new BrowserURLParamsAccessor();
|
|
645
915
|
|
|
646
|
-
// src/constants.ts
|
|
647
|
-
var DEFAULT_AUTH_URL = "https://connect.phantom.app";
|
|
648
|
-
var DEFAULT_WALLET_API_URL = "https://api.phantom.app/v1/wallets";
|
|
649
|
-
|
|
650
916
|
// src/providers/embedded/adapters/auth.ts
|
|
917
|
+
var import_constants = require("@phantom/constants");
|
|
651
918
|
var BrowserAuthProvider = class {
|
|
652
919
|
constructor(urlParamsAccessor) {
|
|
653
920
|
this.urlParamsAccessor = urlParamsAccessor;
|
|
654
921
|
}
|
|
922
|
+
getValidatedCurrentUrl() {
|
|
923
|
+
const currentUrl = window.location.href;
|
|
924
|
+
if (!currentUrl.startsWith("http:") && !currentUrl.startsWith("https:")) {
|
|
925
|
+
throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported");
|
|
926
|
+
}
|
|
927
|
+
return currentUrl;
|
|
928
|
+
}
|
|
655
929
|
authenticate(options) {
|
|
656
930
|
return new Promise((resolve) => {
|
|
657
931
|
if ("jwtToken" in options) {
|
|
@@ -660,23 +934,20 @@ var BrowserAuthProvider = class {
|
|
|
660
934
|
const phantomOptions = options;
|
|
661
935
|
debug.info(DebugCategory.PHANTOM_CONNECT_AUTH, "Starting Phantom Connect authentication", {
|
|
662
936
|
organizationId: phantomOptions.organizationId,
|
|
663
|
-
|
|
937
|
+
appId: phantomOptions.appId,
|
|
664
938
|
provider: phantomOptions.provider,
|
|
665
939
|
authUrl: phantomOptions.authUrl,
|
|
666
940
|
hasCustomData: !!phantomOptions.customAuthData
|
|
667
941
|
});
|
|
668
|
-
const baseUrl = phantomOptions.authUrl || DEFAULT_AUTH_URL;
|
|
942
|
+
const baseUrl = phantomOptions.authUrl || import_constants.DEFAULT_AUTH_URL;
|
|
669
943
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Using auth URL", { baseUrl });
|
|
670
944
|
const params = new URLSearchParams({
|
|
671
945
|
organization_id: phantomOptions.organizationId,
|
|
672
|
-
|
|
673
|
-
redirect_uri: phantomOptions.redirectUrl || (typeof window !== "undefined" ?
|
|
946
|
+
app_id: phantomOptions.appId,
|
|
947
|
+
redirect_uri: phantomOptions.redirectUrl || (typeof window !== "undefined" ? this.getValidatedCurrentUrl() : ""),
|
|
674
948
|
session_id: phantomOptions.sessionId,
|
|
675
949
|
clear_previous_session: true.toString(),
|
|
676
|
-
|
|
677
|
-
// Optional app name
|
|
678
|
-
app_logo: phantomOptions.appLogo || ""
|
|
679
|
-
// Optional app logo URL
|
|
950
|
+
sdk_version: "1.0.0-beta.10"
|
|
680
951
|
});
|
|
681
952
|
if (phantomOptions.provider) {
|
|
682
953
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Provider specified, will skip selection", {
|
|
@@ -693,7 +964,7 @@ var BrowserAuthProvider = class {
|
|
|
693
964
|
}
|
|
694
965
|
const authContext = {
|
|
695
966
|
organizationId: phantomOptions.organizationId,
|
|
696
|
-
|
|
967
|
+
appId: phantomOptions.appId,
|
|
697
968
|
provider: phantomOptions.provider,
|
|
698
969
|
sessionId: phantomOptions.sessionId
|
|
699
970
|
};
|
|
@@ -701,6 +972,9 @@ var BrowserAuthProvider = class {
|
|
|
701
972
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Stored auth context in session storage", { authContext });
|
|
702
973
|
const authUrl = `${baseUrl}?${params.toString()}`;
|
|
703
974
|
debug.info(DebugCategory.PHANTOM_CONNECT_AUTH, "Redirecting to Phantom Connect", { authUrl });
|
|
975
|
+
if (!authUrl.startsWith("https:")) {
|
|
976
|
+
throw new Error("Invalid auth URL - only HTTPS URLs are allowed for authentication");
|
|
977
|
+
}
|
|
704
978
|
window.location.href = authUrl;
|
|
705
979
|
resolve();
|
|
706
980
|
});
|
|
@@ -789,7 +1063,7 @@ function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
|
|
|
789
1063
|
let name = "unknown";
|
|
790
1064
|
let version = "unknown";
|
|
791
1065
|
if (!userAgent || typeof userAgent !== "string") {
|
|
792
|
-
return { name, version };
|
|
1066
|
+
return { name, version, userAgent: "unknown" };
|
|
793
1067
|
}
|
|
794
1068
|
try {
|
|
795
1069
|
if (userAgent.includes("Edg/")) {
|
|
@@ -871,11 +1145,11 @@ function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
|
|
|
871
1145
|
}
|
|
872
1146
|
} catch (error) {
|
|
873
1147
|
}
|
|
874
|
-
return { name, version };
|
|
1148
|
+
return { name, version, userAgent };
|
|
875
1149
|
}
|
|
876
1150
|
function detectBrowser() {
|
|
877
1151
|
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
878
|
-
return { name: "unknown", version: "unknown" };
|
|
1152
|
+
return { name: "unknown", version: "unknown", userAgent: "unknown" };
|
|
879
1153
|
}
|
|
880
1154
|
const userAgent = window.navigator.userAgent;
|
|
881
1155
|
const hasBraveAPI = !!navigator.brave;
|
|
@@ -890,25 +1164,70 @@ function getBrowserDisplayName() {
|
|
|
890
1164
|
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
891
1165
|
return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
|
|
892
1166
|
}
|
|
1167
|
+
function isMobileDevice() {
|
|
1168
|
+
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
1169
|
+
return false;
|
|
1170
|
+
}
|
|
1171
|
+
const userAgent = window.navigator.userAgent.toLowerCase();
|
|
1172
|
+
const mobilePatterns = [
|
|
1173
|
+
/android/,
|
|
1174
|
+
/iphone|ipad|ipod/,
|
|
1175
|
+
/blackberry/,
|
|
1176
|
+
/windows phone/,
|
|
1177
|
+
/mobile/,
|
|
1178
|
+
/tablet/,
|
|
1179
|
+
/silk/,
|
|
1180
|
+
/kindle/,
|
|
1181
|
+
/opera mini/,
|
|
1182
|
+
/opera mobi/
|
|
1183
|
+
];
|
|
1184
|
+
const isMobileUA = mobilePatterns.some((pattern) => pattern.test(userAgent));
|
|
1185
|
+
let isSmallScreen = false;
|
|
1186
|
+
try {
|
|
1187
|
+
isSmallScreen = window.screen.width <= 768 || window.screen.height <= 768;
|
|
1188
|
+
} catch (error) {
|
|
1189
|
+
isSmallScreen = false;
|
|
1190
|
+
}
|
|
1191
|
+
let isTouchDevice = false;
|
|
1192
|
+
try {
|
|
1193
|
+
isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
1194
|
+
} catch (error) {
|
|
1195
|
+
isTouchDevice = false;
|
|
1196
|
+
}
|
|
1197
|
+
return isMobileUA || isSmallScreen && isTouchDevice;
|
|
1198
|
+
}
|
|
893
1199
|
|
|
894
1200
|
// src/providers/embedded/index.ts
|
|
1201
|
+
var import_constants2 = require("@phantom/constants");
|
|
895
1202
|
var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvider {
|
|
896
1203
|
constructor(config) {
|
|
897
1204
|
debug.log(DebugCategory.EMBEDDED_PROVIDER, "Initializing Browser EmbeddedProvider", { config });
|
|
898
1205
|
const urlParamsAccessor = new BrowserURLParamsAccessor();
|
|
899
1206
|
const stamper = new import_indexed_db_stamper.IndexedDbStamper({
|
|
900
|
-
dbName: `phantom-embedded-sdk-${config.
|
|
1207
|
+
dbName: `phantom-embedded-sdk-${config.appId}`,
|
|
901
1208
|
storeName: "crypto-keys",
|
|
902
1209
|
keyName: "signing-key"
|
|
903
1210
|
});
|
|
904
1211
|
const platformName = getPlatformName();
|
|
1212
|
+
const { name: browserName, version } = detectBrowser();
|
|
905
1213
|
const platform = {
|
|
906
1214
|
storage: new BrowserStorage(),
|
|
907
1215
|
authProvider: new BrowserAuthProvider(urlParamsAccessor),
|
|
908
1216
|
urlParamsAccessor,
|
|
909
1217
|
stamper,
|
|
910
|
-
name: platformName
|
|
1218
|
+
name: platformName,
|
|
911
1219
|
// Use detected browser name and version for identification
|
|
1220
|
+
analyticsHeaders: {
|
|
1221
|
+
[import_constants2.ANALYTICS_HEADERS.SDK_TYPE]: "browser",
|
|
1222
|
+
[import_constants2.ANALYTICS_HEADERS.PLATFORM]: browserName,
|
|
1223
|
+
// firefox, chrome, safari, etc.
|
|
1224
|
+
[import_constants2.ANALYTICS_HEADERS.PLATFORM_VERSION]: version,
|
|
1225
|
+
// Full user agent for more detailed info
|
|
1226
|
+
[import_constants2.ANALYTICS_HEADERS.APP_ID]: config.appId,
|
|
1227
|
+
[import_constants2.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
|
|
1228
|
+
[import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.10"
|
|
1229
|
+
// Replaced at build time
|
|
1230
|
+
}
|
|
912
1231
|
};
|
|
913
1232
|
debug.log(DebugCategory.EMBEDDED_PROVIDER, "Detected platform", { platformName });
|
|
914
1233
|
const logger = new BrowserLogger();
|
|
@@ -918,6 +1237,7 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
|
|
|
918
1237
|
};
|
|
919
1238
|
|
|
920
1239
|
// src/ProviderManager.ts
|
|
1240
|
+
var import_constants3 = require("@phantom/constants");
|
|
921
1241
|
var ProviderManager = class {
|
|
922
1242
|
// Track which providers have forwarding set up
|
|
923
1243
|
constructor(config) {
|
|
@@ -936,6 +1256,15 @@ var ProviderManager = class {
|
|
|
936
1256
|
currentProviderKey: this.currentProviderKey
|
|
937
1257
|
});
|
|
938
1258
|
}
|
|
1259
|
+
getValidatedCurrentUrl() {
|
|
1260
|
+
if (typeof window === "undefined")
|
|
1261
|
+
return "";
|
|
1262
|
+
const currentUrl = window.location.href;
|
|
1263
|
+
if (!currentUrl.startsWith("http:") && !currentUrl.startsWith("https:")) {
|
|
1264
|
+
throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported");
|
|
1265
|
+
}
|
|
1266
|
+
return currentUrl;
|
|
1267
|
+
}
|
|
939
1268
|
/**
|
|
940
1269
|
* Switch to a different provider type
|
|
941
1270
|
*/
|
|
@@ -967,7 +1296,8 @@ var ProviderManager = class {
|
|
|
967
1296
|
getCurrentProviderInfo() {
|
|
968
1297
|
if (!this.currentProviderKey)
|
|
969
1298
|
return null;
|
|
970
|
-
const
|
|
1299
|
+
const parts = this.currentProviderKey.split("-");
|
|
1300
|
+
const [type, embeddedWalletType] = parts;
|
|
971
1301
|
return {
|
|
972
1302
|
type,
|
|
973
1303
|
embeddedWalletType
|
|
@@ -1091,7 +1421,13 @@ var ProviderManager = class {
|
|
|
1091
1421
|
return;
|
|
1092
1422
|
}
|
|
1093
1423
|
debug.log(DebugCategory.PROVIDER_MANAGER, "Setting up event forwarding from current provider");
|
|
1094
|
-
const eventsToForward = [
|
|
1424
|
+
const eventsToForward = [
|
|
1425
|
+
"connect_start",
|
|
1426
|
+
"connect",
|
|
1427
|
+
"connect_error",
|
|
1428
|
+
"disconnect",
|
|
1429
|
+
"error"
|
|
1430
|
+
];
|
|
1095
1431
|
for (const event of eventsToForward) {
|
|
1096
1432
|
const forwardingCallback = (data) => {
|
|
1097
1433
|
debug.log(DebugCategory.PROVIDER_MANAGER, "Forwarding event from provider", { event, data });
|
|
@@ -1107,7 +1443,7 @@ var ProviderManager = class {
|
|
|
1107
1443
|
*/
|
|
1108
1444
|
setDefaultProvider() {
|
|
1109
1445
|
const defaultType = this.config.providerType || "embedded";
|
|
1110
|
-
const defaultEmbeddedType = this.config.embeddedWalletType || "
|
|
1446
|
+
const defaultEmbeddedType = this.config.embeddedWalletType || "user-wallet";
|
|
1111
1447
|
this.createProvider(defaultType, defaultEmbeddedType);
|
|
1112
1448
|
this.switchProvider(defaultType, { embeddedWalletType: defaultEmbeddedType });
|
|
1113
1449
|
}
|
|
@@ -1121,24 +1457,27 @@ var ProviderManager = class {
|
|
|
1121
1457
|
let provider;
|
|
1122
1458
|
if (type === "injected") {
|
|
1123
1459
|
provider = new InjectedProvider({
|
|
1124
|
-
|
|
1125
|
-
addressTypes: this.config.addressTypes
|
|
1460
|
+
addressTypes: this.config.addressTypes || [import_client.AddressType.solana]
|
|
1126
1461
|
});
|
|
1127
|
-
} else {
|
|
1128
|
-
if (!this.config.
|
|
1129
|
-
throw new Error("
|
|
1462
|
+
} else if (type === "embedded") {
|
|
1463
|
+
if (!this.config.appId) {
|
|
1464
|
+
throw new Error("appId is required for embedded provider");
|
|
1130
1465
|
}
|
|
1466
|
+
const apiBaseUrl = this.config.apiBaseUrl || import_constants3.DEFAULT_WALLET_API_URL;
|
|
1467
|
+
const authUrl = this.config.authOptions?.authUrl || import_constants3.DEFAULT_AUTH_URL;
|
|
1131
1468
|
provider = new EmbeddedProvider({
|
|
1132
|
-
apiBaseUrl
|
|
1133
|
-
|
|
1134
|
-
authOptions:
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1469
|
+
apiBaseUrl,
|
|
1470
|
+
appId: this.config.appId,
|
|
1471
|
+
authOptions: {
|
|
1472
|
+
...this.config.authOptions || {},
|
|
1473
|
+
authUrl,
|
|
1474
|
+
redirectUrl: this.config.authOptions?.redirectUrl || this.getValidatedCurrentUrl()
|
|
1475
|
+
},
|
|
1476
|
+
embeddedWalletType: embeddedWalletType || import_constants3.DEFAULT_EMBEDDED_WALLET_TYPE,
|
|
1477
|
+
addressTypes: this.config.addressTypes || [import_client.AddressType.solana]
|
|
1141
1478
|
});
|
|
1479
|
+
} else {
|
|
1480
|
+
throw new Error(`Unsupported provider type: ${type}`);
|
|
1142
1481
|
}
|
|
1143
1482
|
this.providers.set(key, provider);
|
|
1144
1483
|
}
|
|
@@ -1148,8 +1487,10 @@ var ProviderManager = class {
|
|
|
1148
1487
|
getProviderKey(type, embeddedWalletType) {
|
|
1149
1488
|
if (type === "injected") {
|
|
1150
1489
|
return "injected";
|
|
1490
|
+
} else if (type === "embedded") {
|
|
1491
|
+
return `embedded-${embeddedWalletType || "app-wallet"}`;
|
|
1151
1492
|
}
|
|
1152
|
-
|
|
1493
|
+
throw new Error(`Unsupported provider type: ${type}`);
|
|
1153
1494
|
}
|
|
1154
1495
|
/**
|
|
1155
1496
|
* Save provider preference to localStorage
|
|
@@ -1184,8 +1525,33 @@ var ProviderManager = class {
|
|
|
1184
1525
|
}*/
|
|
1185
1526
|
};
|
|
1186
1527
|
|
|
1187
|
-
// src/
|
|
1528
|
+
// src/waitForPhantomExtension.ts
|
|
1188
1529
|
var import_browser_injected_sdk2 = require("@phantom/browser-injected-sdk");
|
|
1530
|
+
async function waitForPhantomExtension(timeoutMs = 3e3) {
|
|
1531
|
+
return new Promise((resolve) => {
|
|
1532
|
+
const startTime = Date.now();
|
|
1533
|
+
const checkInterval = 100;
|
|
1534
|
+
const checkForExtension = () => {
|
|
1535
|
+
try {
|
|
1536
|
+
if ((0, import_browser_injected_sdk2.isPhantomExtensionInstalled)()) {
|
|
1537
|
+
resolve(true);
|
|
1538
|
+
return;
|
|
1539
|
+
}
|
|
1540
|
+
} catch (error) {
|
|
1541
|
+
}
|
|
1542
|
+
const elapsed = Date.now() - startTime;
|
|
1543
|
+
if (elapsed >= timeoutMs) {
|
|
1544
|
+
resolve(false);
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
setTimeout(checkForExtension, checkInterval);
|
|
1548
|
+
};
|
|
1549
|
+
checkForExtension();
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
// src/BrowserSDK.ts
|
|
1554
|
+
var import_constants4 = require("@phantom/constants");
|
|
1189
1555
|
var BrowserSDK = class {
|
|
1190
1556
|
constructor(config) {
|
|
1191
1557
|
debug.info(DebugCategory.BROWSER_SDK, "Initializing BrowserSDK", {
|
|
@@ -1197,7 +1563,7 @@ var BrowserSDK = class {
|
|
|
1197
1563
|
debug.error(DebugCategory.BROWSER_SDK, "Invalid providerType", { providerType: config.providerType });
|
|
1198
1564
|
throw new Error(`Invalid providerType: ${config.providerType}. Must be "injected" or "embedded".`);
|
|
1199
1565
|
}
|
|
1200
|
-
const embeddedWalletType = config.embeddedWalletType ||
|
|
1566
|
+
const embeddedWalletType = config.embeddedWalletType || import_constants4.DEFAULT_EMBEDDED_WALLET_TYPE;
|
|
1201
1567
|
if (config.providerType === "embedded" && !["app-wallet", "user-wallet"].includes(embeddedWalletType)) {
|
|
1202
1568
|
debug.error(DebugCategory.BROWSER_SDK, "Invalid embeddedWalletType", {
|
|
1203
1569
|
embeddedWalletType: config.embeddedWalletType
|
|
@@ -1306,8 +1672,8 @@ var BrowserSDK = class {
|
|
|
1306
1672
|
/**
|
|
1307
1673
|
* Check if Phantom extension is installed
|
|
1308
1674
|
*/
|
|
1309
|
-
static isPhantomInstalled() {
|
|
1310
|
-
return (
|
|
1675
|
+
static async isPhantomInstalled(timeoutMs) {
|
|
1676
|
+
return waitForPhantomExtension(timeoutMs);
|
|
1311
1677
|
}
|
|
1312
1678
|
/**
|
|
1313
1679
|
* Add event listener for provider events (connect, connect_start, connect_error, disconnect, error)
|
|
@@ -1333,7 +1699,7 @@ var BrowserSDK = class {
|
|
|
1333
1699
|
async autoConnect() {
|
|
1334
1700
|
debug.log(DebugCategory.BROWSER_SDK, "Attempting auto-connect");
|
|
1335
1701
|
const currentProvider = this.providerManager.getCurrentProvider();
|
|
1336
|
-
if (currentProvider
|
|
1702
|
+
if (currentProvider) {
|
|
1337
1703
|
await currentProvider.autoConnect();
|
|
1338
1704
|
} else {
|
|
1339
1705
|
debug.warn(DebugCategory.BROWSER_SDK, "Current provider does not support auto-connect", {
|
|
@@ -1474,15 +1840,24 @@ var BrowserSDK = class {
|
|
|
1474
1840
|
debug.info(DebugCategory.BROWSER_SDK, "Got supported auto-confirm chains", { result });
|
|
1475
1841
|
return result;
|
|
1476
1842
|
} catch (error) {
|
|
1477
|
-
debug.error(DebugCategory.BROWSER_SDK, "Failed to get supported auto-confirm chains", {
|
|
1843
|
+
debug.error(DebugCategory.BROWSER_SDK, "Failed to get supported auto-confirm chains", {
|
|
1844
|
+
error: error.message
|
|
1845
|
+
});
|
|
1478
1846
|
throw error;
|
|
1479
1847
|
}
|
|
1480
1848
|
}
|
|
1481
1849
|
};
|
|
1482
1850
|
|
|
1483
|
-
// src/
|
|
1484
|
-
|
|
1851
|
+
// src/utils/deeplink.ts
|
|
1852
|
+
function getDeeplinkToPhantom(ref) {
|
|
1853
|
+
if (!window.location.href.startsWith("http:") && !window.location.href.startsWith("https:")) {
|
|
1854
|
+
throw new Error("Invalid URL protocol - only HTTP/HTTPS URLs are supported for deeplinks");
|
|
1855
|
+
}
|
|
1856
|
+
const currentUrl = encodeURIComponent(window.location.href);
|
|
1857
|
+
const refParam = ref ? `?ref=${encodeURIComponent(ref)}` : "";
|
|
1858
|
+
return `https://phantom.app/ul/browse/${currentUrl}${refParam}`;
|
|
1859
|
+
}
|
|
1485
1860
|
|
|
1486
1861
|
// src/index.ts
|
|
1487
|
-
var
|
|
1488
|
-
var
|
|
1862
|
+
var import_constants5 = require("@phantom/constants");
|
|
1863
|
+
var import_client5 = require("@phantom/client");
|