@phantom/browser-sdk 1.0.0-beta.14 → 1.0.0-beta.15
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 +22 -10
- package/dist/index.d.ts +20 -8
- package/dist/index.js +296 -187
- package/dist/index.mjs +296 -187
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -93,24 +93,36 @@ const ethResult = await sdk.ethereum.sendTransaction({
|
|
|
93
93
|
|
|
94
94
|
### Connection Options
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
The `connect()` method automatically switches between providers based on the authentication method you specify:
|
|
97
97
|
|
|
98
98
|
```typescript
|
|
99
|
-
//
|
|
99
|
+
// Connect with current provider (no switching)
|
|
100
100
|
const result = await sdk.connect();
|
|
101
101
|
|
|
102
|
-
//
|
|
102
|
+
// Connect with injected provider (Phantom extension)
|
|
103
|
+
// Automatically switches to injected provider if not already using it
|
|
103
104
|
const result = await sdk.connect({
|
|
104
|
-
|
|
105
|
-
provider: "google",
|
|
106
|
-
},
|
|
105
|
+
provider: "injected",
|
|
107
106
|
});
|
|
108
107
|
|
|
109
|
-
//
|
|
108
|
+
// Connect with Google authentication (embedded provider)
|
|
109
|
+
// Automatically switches to embedded provider if not already using it
|
|
110
110
|
const result = await sdk.connect({
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
provider: "google",
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Connect with Apple authentication (embedded provider)
|
|
115
|
+
// Automatically switches to embedded provider if not already using it
|
|
116
|
+
const result = await sdk.connect({
|
|
117
|
+
provider: "apple",
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
// Connect with Phantom authentication (embedded provider)
|
|
122
|
+
// Uses Phantom extension or mobile app for authentication
|
|
123
|
+
// Automatically switches to embedded provider if not already using it
|
|
124
|
+
const result = await sdk.connect({
|
|
125
|
+
provider: "phantom",
|
|
114
126
|
});
|
|
115
127
|
```
|
|
116
128
|
|
package/dist/index.d.ts
CHANGED
|
@@ -52,14 +52,33 @@ declare const DebugCategory: {
|
|
|
52
52
|
readonly SESSION: "Session";
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Phantom extension app.login API types
|
|
57
|
+
*/
|
|
58
|
+
interface PhantomAppLoginOptions {
|
|
59
|
+
publicKey: string;
|
|
60
|
+
appId: string;
|
|
61
|
+
sessionId: string;
|
|
62
|
+
}
|
|
63
|
+
interface PhantomAppLoginResult {
|
|
64
|
+
walletId: string;
|
|
65
|
+
organizationId: string;
|
|
66
|
+
accountDerivationIndex?: number;
|
|
67
|
+
expiresInMs?: number;
|
|
68
|
+
}
|
|
69
|
+
interface PhantomApp {
|
|
70
|
+
login(options: PhantomAppLoginOptions): Promise<PhantomAppLoginResult>;
|
|
71
|
+
}
|
|
55
72
|
declare global {
|
|
56
73
|
interface Window {
|
|
57
74
|
phantom?: {
|
|
58
75
|
solana?: unknown;
|
|
59
76
|
ethereum?: unknown;
|
|
60
|
-
|
|
77
|
+
app?: PhantomApp;
|
|
78
|
+
} | undefined;
|
|
61
79
|
}
|
|
62
80
|
}
|
|
81
|
+
|
|
63
82
|
interface InjectedProviderConfig {
|
|
64
83
|
addressTypes: AddressType[];
|
|
65
84
|
}
|
|
@@ -105,9 +124,6 @@ interface ProviderPreference {
|
|
|
105
124
|
type: "injected" | "embedded";
|
|
106
125
|
embeddedWalletType?: "app-wallet" | "user-wallet";
|
|
107
126
|
}
|
|
108
|
-
interface SwitchProviderOptions {
|
|
109
|
-
embeddedWalletType?: "app-wallet" | "user-wallet" | (string & Record<never, never>);
|
|
110
|
-
}
|
|
111
127
|
|
|
112
128
|
/**
|
|
113
129
|
* Browser SDK with chain-specific API
|
|
@@ -141,10 +157,6 @@ declare class BrowserSDK {
|
|
|
141
157
|
* Disconnect from the wallet
|
|
142
158
|
*/
|
|
143
159
|
disconnect(): Promise<void>;
|
|
144
|
-
/**
|
|
145
|
-
* Switch between provider types (injected vs embedded)
|
|
146
|
-
*/
|
|
147
|
-
switchProvider(type: "injected" | "embedded", options?: SwitchProviderOptions): Promise<void>;
|
|
148
160
|
/**
|
|
149
161
|
* Check if the SDK is connected to a wallet
|
|
150
162
|
*/
|
package/dist/index.js
CHANGED
|
@@ -901,6 +901,47 @@ var BrowserStorage = class {
|
|
|
901
901
|
};
|
|
902
902
|
});
|
|
903
903
|
}
|
|
904
|
+
async getShouldClearPreviousSession() {
|
|
905
|
+
debug.log(DebugCategory.STORAGE, "Getting shouldClearPreviousSession flag from IndexedDB");
|
|
906
|
+
const db = await this.getDB();
|
|
907
|
+
return new Promise((resolve, reject) => {
|
|
908
|
+
const transaction = db.transaction([this.storeName], "readonly");
|
|
909
|
+
const store = transaction.objectStore(this.storeName);
|
|
910
|
+
const request = store.get("shouldClearPreviousSession");
|
|
911
|
+
request.onsuccess = () => {
|
|
912
|
+
const shouldClear = request.result ?? false;
|
|
913
|
+
debug.log(DebugCategory.STORAGE, "Retrieved shouldClearPreviousSession flag from IndexedDB", {
|
|
914
|
+
shouldClear
|
|
915
|
+
});
|
|
916
|
+
resolve(shouldClear);
|
|
917
|
+
};
|
|
918
|
+
request.onerror = () => {
|
|
919
|
+
debug.error(DebugCategory.STORAGE, "Failed to get shouldClearPreviousSession flag from IndexedDB", {
|
|
920
|
+
error: request.error
|
|
921
|
+
});
|
|
922
|
+
reject(request.error);
|
|
923
|
+
};
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
async setShouldClearPreviousSession(should) {
|
|
927
|
+
debug.log(DebugCategory.STORAGE, "Setting shouldClearPreviousSession flag in IndexedDB", { should });
|
|
928
|
+
const db = await this.getDB();
|
|
929
|
+
return new Promise((resolve, reject) => {
|
|
930
|
+
const transaction = db.transaction([this.storeName], "readwrite");
|
|
931
|
+
const store = transaction.objectStore(this.storeName);
|
|
932
|
+
const request = store.put(should, "shouldClearPreviousSession");
|
|
933
|
+
request.onsuccess = () => {
|
|
934
|
+
debug.log(DebugCategory.STORAGE, "Successfully set shouldClearPreviousSession flag in IndexedDB");
|
|
935
|
+
resolve();
|
|
936
|
+
};
|
|
937
|
+
request.onerror = () => {
|
|
938
|
+
debug.error(DebugCategory.STORAGE, "Failed to set shouldClearPreviousSession flag in IndexedDB", {
|
|
939
|
+
error: request.error
|
|
940
|
+
});
|
|
941
|
+
reject(request.error);
|
|
942
|
+
};
|
|
943
|
+
});
|
|
944
|
+
}
|
|
904
945
|
};
|
|
905
946
|
|
|
906
947
|
// src/providers/embedded/adapters/url-params.ts
|
|
@@ -914,6 +955,147 @@ var browserUrlParamsAccessor = new BrowserURLParamsAccessor();
|
|
|
914
955
|
|
|
915
956
|
// src/providers/embedded/adapters/auth.ts
|
|
916
957
|
var import_constants = require("@phantom/constants");
|
|
958
|
+
|
|
959
|
+
// src/utils/browser-detection.ts
|
|
960
|
+
function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
|
|
961
|
+
let name = "unknown";
|
|
962
|
+
let version = "unknown";
|
|
963
|
+
if (!userAgent || typeof userAgent !== "string") {
|
|
964
|
+
return { name, version, userAgent: "unknown" };
|
|
965
|
+
}
|
|
966
|
+
try {
|
|
967
|
+
if (userAgent.includes("Edg/")) {
|
|
968
|
+
name = "edge";
|
|
969
|
+
const match = userAgent.match(/Edg\/([0-9]+(?:\.[0-9]+)*)/);
|
|
970
|
+
if (match)
|
|
971
|
+
version = match[1].split(".")[0];
|
|
972
|
+
} else if (userAgent.includes("OPR/") || userAgent.includes("Opera/")) {
|
|
973
|
+
name = "opera";
|
|
974
|
+
const match = userAgent.match(/(?:OPR|Opera)\/([0-9]+(?:\.[0-9]+)*)/);
|
|
975
|
+
if (match)
|
|
976
|
+
version = match[1].split(".")[0];
|
|
977
|
+
} else if (userAgent.includes("SamsungBrowser/")) {
|
|
978
|
+
name = "samsung";
|
|
979
|
+
const match = userAgent.match(/SamsungBrowser\/([0-9]+(?:\.[0-9]+)*)/);
|
|
980
|
+
if (match)
|
|
981
|
+
version = match[1].split(".")[0];
|
|
982
|
+
} else if (userAgent.includes("DuckDuckGo/")) {
|
|
983
|
+
name = "duckduckgo";
|
|
984
|
+
const match = userAgent.match(/DuckDuckGo\/([0-9]+(?:\.[0-9]+)*)/);
|
|
985
|
+
if (match)
|
|
986
|
+
version = match[1].split(".")[0];
|
|
987
|
+
} else if (userAgent.includes("Chrome/") && hasBraveAPI) {
|
|
988
|
+
name = "brave";
|
|
989
|
+
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
990
|
+
if (match)
|
|
991
|
+
version = match[1].split(".")[0];
|
|
992
|
+
} else if (userAgent.includes("Mobile/") || userAgent.includes("Android")) {
|
|
993
|
+
if (userAgent.includes("Chrome/")) {
|
|
994
|
+
name = "chrome-mobile";
|
|
995
|
+
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
996
|
+
if (match)
|
|
997
|
+
version = match[1].split(".")[0];
|
|
998
|
+
} else if (userAgent.includes("Firefox/")) {
|
|
999
|
+
name = "firefox-mobile";
|
|
1000
|
+
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1001
|
+
if (match)
|
|
1002
|
+
version = match[1].split(".")[0];
|
|
1003
|
+
} else if (userAgent.includes("Safari/") && userAgent.includes("Mobile/")) {
|
|
1004
|
+
name = "safari-mobile";
|
|
1005
|
+
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1006
|
+
if (match)
|
|
1007
|
+
version = match[1].split(".")[0];
|
|
1008
|
+
} else {
|
|
1009
|
+
name = "mobile";
|
|
1010
|
+
}
|
|
1011
|
+
} else if (userAgent.includes("Chrome/")) {
|
|
1012
|
+
name = "chrome";
|
|
1013
|
+
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1014
|
+
if (match)
|
|
1015
|
+
version = match[1].split(".")[0];
|
|
1016
|
+
} else if (userAgent.includes("Firefox/")) {
|
|
1017
|
+
name = "firefox";
|
|
1018
|
+
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1019
|
+
if (match)
|
|
1020
|
+
version = match[1].split(".")[0];
|
|
1021
|
+
} else if (userAgent.includes("Safari/") && !userAgent.includes("Chrome/")) {
|
|
1022
|
+
name = "safari";
|
|
1023
|
+
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1024
|
+
if (match)
|
|
1025
|
+
version = match[1].split(".")[0];
|
|
1026
|
+
}
|
|
1027
|
+
if (name === "unknown") {
|
|
1028
|
+
const patterns = [
|
|
1029
|
+
{ regex: /Chrome\/([0-9]+)/, name: "chrome" },
|
|
1030
|
+
{ regex: /Firefox\/([0-9]+)/, name: "firefox" },
|
|
1031
|
+
{ regex: /Safari\/([0-9]+)/, name: "safari" },
|
|
1032
|
+
{ regex: /Edge\/([0-9]+)/, name: "edge" },
|
|
1033
|
+
{ regex: /Opera\/([0-9]+)/, name: "opera" }
|
|
1034
|
+
];
|
|
1035
|
+
for (const pattern of patterns) {
|
|
1036
|
+
const match = userAgent.match(pattern.regex);
|
|
1037
|
+
if (match) {
|
|
1038
|
+
name = pattern.name;
|
|
1039
|
+
version = match[1];
|
|
1040
|
+
break;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
} catch (error) {
|
|
1045
|
+
}
|
|
1046
|
+
return { name, version, userAgent };
|
|
1047
|
+
}
|
|
1048
|
+
function detectBrowser() {
|
|
1049
|
+
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
1050
|
+
return { name: "unknown", version: "unknown", userAgent: "unknown" };
|
|
1051
|
+
}
|
|
1052
|
+
const userAgent = window.navigator.userAgent;
|
|
1053
|
+
const hasBraveAPI = !!navigator.brave;
|
|
1054
|
+
return parseBrowserFromUserAgent(userAgent, hasBraveAPI);
|
|
1055
|
+
}
|
|
1056
|
+
function getPlatformName() {
|
|
1057
|
+
const { name, version } = detectBrowser();
|
|
1058
|
+
return version !== "unknown" ? `${name}-v${version}` : name;
|
|
1059
|
+
}
|
|
1060
|
+
function getBrowserDisplayName() {
|
|
1061
|
+
const { name, version } = detectBrowser();
|
|
1062
|
+
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
1063
|
+
return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
|
|
1064
|
+
}
|
|
1065
|
+
function isMobileDevice() {
|
|
1066
|
+
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
1067
|
+
return false;
|
|
1068
|
+
}
|
|
1069
|
+
const userAgent = window.navigator.userAgent.toLowerCase();
|
|
1070
|
+
const mobilePatterns = [
|
|
1071
|
+
/android/,
|
|
1072
|
+
/iphone|ipad|ipod/,
|
|
1073
|
+
/blackberry/,
|
|
1074
|
+
/windows phone/,
|
|
1075
|
+
/mobile/,
|
|
1076
|
+
/tablet/,
|
|
1077
|
+
/silk/,
|
|
1078
|
+
/kindle/,
|
|
1079
|
+
/opera mini/,
|
|
1080
|
+
/opera mobi/
|
|
1081
|
+
];
|
|
1082
|
+
const isMobileUA = mobilePatterns.some((pattern) => pattern.test(userAgent));
|
|
1083
|
+
let isSmallScreen = false;
|
|
1084
|
+
try {
|
|
1085
|
+
isSmallScreen = window.screen.width <= 768 || window.screen.height <= 768;
|
|
1086
|
+
} catch (error) {
|
|
1087
|
+
isSmallScreen = false;
|
|
1088
|
+
}
|
|
1089
|
+
let isTouchDevice = false;
|
|
1090
|
+
try {
|
|
1091
|
+
isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
1092
|
+
} catch (error) {
|
|
1093
|
+
isTouchDevice = false;
|
|
1094
|
+
}
|
|
1095
|
+
return isMobileUA || isSmallScreen && isTouchDevice;
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
// src/providers/embedded/adapters/auth.ts
|
|
917
1099
|
var BrowserAuthProvider = class {
|
|
918
1100
|
constructor(urlParamsAccessor) {
|
|
919
1101
|
this.urlParamsAccessor = urlParamsAccessor;
|
|
@@ -935,8 +1117,7 @@ var BrowserAuthProvider = class {
|
|
|
935
1117
|
publicKey: phantomOptions.publicKey,
|
|
936
1118
|
appId: phantomOptions.appId,
|
|
937
1119
|
provider: phantomOptions.provider,
|
|
938
|
-
authUrl: phantomOptions.authUrl
|
|
939
|
-
hasCustomData: !!phantomOptions.customAuthData
|
|
1120
|
+
authUrl: phantomOptions.authUrl
|
|
940
1121
|
});
|
|
941
1122
|
const baseUrl = phantomOptions.authUrl || import_constants.DEFAULT_AUTH_URL;
|
|
942
1123
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Using auth URL", { baseUrl });
|
|
@@ -945,8 +1126,12 @@ var BrowserAuthProvider = class {
|
|
|
945
1126
|
app_id: phantomOptions.appId,
|
|
946
1127
|
redirect_uri: phantomOptions.redirectUrl || (typeof window !== "undefined" ? this.getValidatedCurrentUrl() : ""),
|
|
947
1128
|
session_id: phantomOptions.sessionId,
|
|
948
|
-
|
|
949
|
-
|
|
1129
|
+
// OAuth session management - defaults to allow refresh unless explicitly clearing after logout
|
|
1130
|
+
clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
|
|
1131
|
+
allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
|
|
1132
|
+
sdk_version: "1.0.0-beta.15",
|
|
1133
|
+
sdk_type: "browser",
|
|
1134
|
+
platform: detectBrowser().name
|
|
950
1135
|
});
|
|
951
1136
|
if (phantomOptions.provider) {
|
|
952
1137
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Provider specified, will skip selection", {
|
|
@@ -957,10 +1142,6 @@ var BrowserAuthProvider = class {
|
|
|
957
1142
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "No provider specified, defaulting to Google");
|
|
958
1143
|
params.append("provider", "google");
|
|
959
1144
|
}
|
|
960
|
-
if (phantomOptions.customAuthData) {
|
|
961
|
-
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Adding custom auth data");
|
|
962
|
-
params.append("authData", JSON.stringify(phantomOptions.customAuthData));
|
|
963
|
-
}
|
|
964
1145
|
const authContext = {
|
|
965
1146
|
publicKey: phantomOptions.publicKey,
|
|
966
1147
|
appId: phantomOptions.appId,
|
|
@@ -1031,12 +1212,14 @@ var BrowserAuthProvider = class {
|
|
|
1031
1212
|
});
|
|
1032
1213
|
const organizationId = this.urlParamsAccessor.getParam("organization_id");
|
|
1033
1214
|
const expiresInMs = this.urlParamsAccessor.getParam("expires_in_ms");
|
|
1215
|
+
const authUserId = this.urlParamsAccessor.getParam("auth_user_id");
|
|
1034
1216
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Auth redirect parameters", {
|
|
1035
1217
|
walletId,
|
|
1036
1218
|
organizationId,
|
|
1037
1219
|
sessionId,
|
|
1038
1220
|
accountDerivationIndex,
|
|
1039
|
-
expiresInMs
|
|
1221
|
+
expiresInMs,
|
|
1222
|
+
authUserId
|
|
1040
1223
|
});
|
|
1041
1224
|
if (!organizationId) {
|
|
1042
1225
|
debug.error(DebugCategory.PHANTOM_CONNECT_AUTH, "Missing organization_id in auth response");
|
|
@@ -1050,9 +1233,9 @@ var BrowserAuthProvider = class {
|
|
|
1050
1233
|
return {
|
|
1051
1234
|
walletId,
|
|
1052
1235
|
organizationId,
|
|
1053
|
-
userInfo: context,
|
|
1054
1236
|
accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : 0,
|
|
1055
|
-
expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0
|
|
1237
|
+
expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0,
|
|
1238
|
+
authUserId: authUserId || void 0
|
|
1056
1239
|
};
|
|
1057
1240
|
} catch (error) {
|
|
1058
1241
|
sessionStorage.removeItem("phantom-auth-context");
|
|
@@ -1061,6 +1244,54 @@ var BrowserAuthProvider = class {
|
|
|
1061
1244
|
}
|
|
1062
1245
|
};
|
|
1063
1246
|
|
|
1247
|
+
// src/providers/embedded/adapters/phantom-app.ts
|
|
1248
|
+
var import_browser_injected_sdk2 = require("@phantom/browser-injected-sdk");
|
|
1249
|
+
var BrowserPhantomAppProvider = class {
|
|
1250
|
+
/**
|
|
1251
|
+
* Check if the Phantom extension is installed in the browser
|
|
1252
|
+
*/
|
|
1253
|
+
isAvailable() {
|
|
1254
|
+
return (0, import_browser_injected_sdk2.isPhantomExtensionInstalled)();
|
|
1255
|
+
}
|
|
1256
|
+
/**
|
|
1257
|
+
* Authenticate using the Phantom browser extension
|
|
1258
|
+
*/
|
|
1259
|
+
async authenticate(options) {
|
|
1260
|
+
if (!this.isAvailable()) {
|
|
1261
|
+
throw new Error(
|
|
1262
|
+
"Phantom extension is not installed. Please install the Phantom browser extension to use this authentication method."
|
|
1263
|
+
);
|
|
1264
|
+
}
|
|
1265
|
+
if (!window.phantom?.app?.login || typeof window.phantom.app.login !== "function") {
|
|
1266
|
+
throw new Error(
|
|
1267
|
+
"Phantom extension authentication is not yet implemented. The extension needs to expose an app.login API (window.phantom.app.login)."
|
|
1268
|
+
);
|
|
1269
|
+
}
|
|
1270
|
+
try {
|
|
1271
|
+
const result = await window.phantom.app.login({
|
|
1272
|
+
publicKey: options.publicKey,
|
|
1273
|
+
appId: options.appId,
|
|
1274
|
+
sessionId: options.sessionId
|
|
1275
|
+
});
|
|
1276
|
+
if (!result || !result.walletId || !result.organizationId) {
|
|
1277
|
+
throw new Error("Invalid authentication response from Phantom extension");
|
|
1278
|
+
}
|
|
1279
|
+
return {
|
|
1280
|
+
walletId: result.walletId,
|
|
1281
|
+
organizationId: result.organizationId,
|
|
1282
|
+
provider: "phantom",
|
|
1283
|
+
accountDerivationIndex: result.accountDerivationIndex ?? 0,
|
|
1284
|
+
expiresInMs: result.expiresInMs ?? 0
|
|
1285
|
+
};
|
|
1286
|
+
} catch (error) {
|
|
1287
|
+
if (error instanceof Error) {
|
|
1288
|
+
throw error;
|
|
1289
|
+
}
|
|
1290
|
+
throw new Error(`Phantom extension authentication failed: ${String(error)}`);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
};
|
|
1294
|
+
|
|
1064
1295
|
// src/providers/embedded/adapters/logger.ts
|
|
1065
1296
|
var BrowserLogger = class {
|
|
1066
1297
|
info(category, message, data) {
|
|
@@ -1077,145 +1308,6 @@ var BrowserLogger = class {
|
|
|
1077
1308
|
}
|
|
1078
1309
|
};
|
|
1079
1310
|
|
|
1080
|
-
// src/utils/browser-detection.ts
|
|
1081
|
-
function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
|
|
1082
|
-
let name = "unknown";
|
|
1083
|
-
let version = "unknown";
|
|
1084
|
-
if (!userAgent || typeof userAgent !== "string") {
|
|
1085
|
-
return { name, version, userAgent: "unknown" };
|
|
1086
|
-
}
|
|
1087
|
-
try {
|
|
1088
|
-
if (userAgent.includes("Edg/")) {
|
|
1089
|
-
name = "edge";
|
|
1090
|
-
const match = userAgent.match(/Edg\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1091
|
-
if (match)
|
|
1092
|
-
version = match[1].split(".")[0];
|
|
1093
|
-
} else if (userAgent.includes("OPR/") || userAgent.includes("Opera/")) {
|
|
1094
|
-
name = "opera";
|
|
1095
|
-
const match = userAgent.match(/(?:OPR|Opera)\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1096
|
-
if (match)
|
|
1097
|
-
version = match[1].split(".")[0];
|
|
1098
|
-
} else if (userAgent.includes("SamsungBrowser/")) {
|
|
1099
|
-
name = "samsung";
|
|
1100
|
-
const match = userAgent.match(/SamsungBrowser\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1101
|
-
if (match)
|
|
1102
|
-
version = match[1].split(".")[0];
|
|
1103
|
-
} else if (userAgent.includes("DuckDuckGo/")) {
|
|
1104
|
-
name = "duckduckgo";
|
|
1105
|
-
const match = userAgent.match(/DuckDuckGo\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1106
|
-
if (match)
|
|
1107
|
-
version = match[1].split(".")[0];
|
|
1108
|
-
} else if (userAgent.includes("Chrome/") && hasBraveAPI) {
|
|
1109
|
-
name = "brave";
|
|
1110
|
-
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1111
|
-
if (match)
|
|
1112
|
-
version = match[1].split(".")[0];
|
|
1113
|
-
} else if (userAgent.includes("Mobile/") || userAgent.includes("Android")) {
|
|
1114
|
-
if (userAgent.includes("Chrome/")) {
|
|
1115
|
-
name = "chrome-mobile";
|
|
1116
|
-
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1117
|
-
if (match)
|
|
1118
|
-
version = match[1].split(".")[0];
|
|
1119
|
-
} else if (userAgent.includes("Firefox/")) {
|
|
1120
|
-
name = "firefox-mobile";
|
|
1121
|
-
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1122
|
-
if (match)
|
|
1123
|
-
version = match[1].split(".")[0];
|
|
1124
|
-
} else if (userAgent.includes("Safari/") && userAgent.includes("Mobile/")) {
|
|
1125
|
-
name = "safari-mobile";
|
|
1126
|
-
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1127
|
-
if (match)
|
|
1128
|
-
version = match[1].split(".")[0];
|
|
1129
|
-
} else {
|
|
1130
|
-
name = "mobile";
|
|
1131
|
-
}
|
|
1132
|
-
} else if (userAgent.includes("Chrome/")) {
|
|
1133
|
-
name = "chrome";
|
|
1134
|
-
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1135
|
-
if (match)
|
|
1136
|
-
version = match[1].split(".")[0];
|
|
1137
|
-
} else if (userAgent.includes("Firefox/")) {
|
|
1138
|
-
name = "firefox";
|
|
1139
|
-
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1140
|
-
if (match)
|
|
1141
|
-
version = match[1].split(".")[0];
|
|
1142
|
-
} else if (userAgent.includes("Safari/") && !userAgent.includes("Chrome/")) {
|
|
1143
|
-
name = "safari";
|
|
1144
|
-
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1145
|
-
if (match)
|
|
1146
|
-
version = match[1].split(".")[0];
|
|
1147
|
-
}
|
|
1148
|
-
if (name === "unknown") {
|
|
1149
|
-
const patterns = [
|
|
1150
|
-
{ regex: /Chrome\/([0-9]+)/, name: "chrome" },
|
|
1151
|
-
{ regex: /Firefox\/([0-9]+)/, name: "firefox" },
|
|
1152
|
-
{ regex: /Safari\/([0-9]+)/, name: "safari" },
|
|
1153
|
-
{ regex: /Edge\/([0-9]+)/, name: "edge" },
|
|
1154
|
-
{ regex: /Opera\/([0-9]+)/, name: "opera" }
|
|
1155
|
-
];
|
|
1156
|
-
for (const pattern of patterns) {
|
|
1157
|
-
const match = userAgent.match(pattern.regex);
|
|
1158
|
-
if (match) {
|
|
1159
|
-
name = pattern.name;
|
|
1160
|
-
version = match[1];
|
|
1161
|
-
break;
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
} catch (error) {
|
|
1166
|
-
}
|
|
1167
|
-
return { name, version, userAgent };
|
|
1168
|
-
}
|
|
1169
|
-
function detectBrowser() {
|
|
1170
|
-
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
1171
|
-
return { name: "unknown", version: "unknown", userAgent: "unknown" };
|
|
1172
|
-
}
|
|
1173
|
-
const userAgent = window.navigator.userAgent;
|
|
1174
|
-
const hasBraveAPI = !!navigator.brave;
|
|
1175
|
-
return parseBrowserFromUserAgent(userAgent, hasBraveAPI);
|
|
1176
|
-
}
|
|
1177
|
-
function getPlatformName() {
|
|
1178
|
-
const { name, version } = detectBrowser();
|
|
1179
|
-
return version !== "unknown" ? `${name}-v${version}` : name;
|
|
1180
|
-
}
|
|
1181
|
-
function getBrowserDisplayName() {
|
|
1182
|
-
const { name, version } = detectBrowser();
|
|
1183
|
-
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
1184
|
-
return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
|
|
1185
|
-
}
|
|
1186
|
-
function isMobileDevice() {
|
|
1187
|
-
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
1188
|
-
return false;
|
|
1189
|
-
}
|
|
1190
|
-
const userAgent = window.navigator.userAgent.toLowerCase();
|
|
1191
|
-
const mobilePatterns = [
|
|
1192
|
-
/android/,
|
|
1193
|
-
/iphone|ipad|ipod/,
|
|
1194
|
-
/blackberry/,
|
|
1195
|
-
/windows phone/,
|
|
1196
|
-
/mobile/,
|
|
1197
|
-
/tablet/,
|
|
1198
|
-
/silk/,
|
|
1199
|
-
/kindle/,
|
|
1200
|
-
/opera mini/,
|
|
1201
|
-
/opera mobi/
|
|
1202
|
-
];
|
|
1203
|
-
const isMobileUA = mobilePatterns.some((pattern) => pattern.test(userAgent));
|
|
1204
|
-
let isSmallScreen = false;
|
|
1205
|
-
try {
|
|
1206
|
-
isSmallScreen = window.screen.width <= 768 || window.screen.height <= 768;
|
|
1207
|
-
} catch (error) {
|
|
1208
|
-
isSmallScreen = false;
|
|
1209
|
-
}
|
|
1210
|
-
let isTouchDevice = false;
|
|
1211
|
-
try {
|
|
1212
|
-
isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
1213
|
-
} catch (error) {
|
|
1214
|
-
isTouchDevice = false;
|
|
1215
|
-
}
|
|
1216
|
-
return isMobileUA || isSmallScreen && isTouchDevice;
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
1311
|
// src/providers/embedded/index.ts
|
|
1220
1312
|
var import_constants2 = require("@phantom/constants");
|
|
1221
1313
|
var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvider {
|
|
@@ -1232,6 +1324,7 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
|
|
|
1232
1324
|
const platform = {
|
|
1233
1325
|
storage: new BrowserStorage(),
|
|
1234
1326
|
authProvider: new BrowserAuthProvider(urlParamsAccessor),
|
|
1327
|
+
phantomAppProvider: new BrowserPhantomAppProvider(),
|
|
1235
1328
|
urlParamsAccessor,
|
|
1236
1329
|
stamper,
|
|
1237
1330
|
name: platformName,
|
|
@@ -1244,7 +1337,7 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
|
|
|
1244
1337
|
// Full user agent for more detailed info
|
|
1245
1338
|
[import_constants2.ANALYTICS_HEADERS.APP_ID]: config.appId,
|
|
1246
1339
|
[import_constants2.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
|
|
1247
|
-
[import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.
|
|
1340
|
+
[import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.15"
|
|
1248
1341
|
// Replaced at build time
|
|
1249
1342
|
}
|
|
1250
1343
|
};
|
|
@@ -1257,6 +1350,25 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
|
|
|
1257
1350
|
|
|
1258
1351
|
// src/ProviderManager.ts
|
|
1259
1352
|
var import_constants3 = require("@phantom/constants");
|
|
1353
|
+
|
|
1354
|
+
// src/utils/auth-callback.ts
|
|
1355
|
+
function isAuthFailureCallback(searchParams) {
|
|
1356
|
+
if (typeof window === "undefined" && !searchParams)
|
|
1357
|
+
return false;
|
|
1358
|
+
const params = searchParams || new URLSearchParams(window.location.search);
|
|
1359
|
+
const responseType = params.get("response_type");
|
|
1360
|
+
const sessionId = params.get("session_id");
|
|
1361
|
+
return responseType === "failure" && !!sessionId;
|
|
1362
|
+
}
|
|
1363
|
+
function isAuthCallbackUrl(searchParams) {
|
|
1364
|
+
if (typeof window === "undefined" && !searchParams)
|
|
1365
|
+
return false;
|
|
1366
|
+
const params = searchParams || new URLSearchParams(window.location.search);
|
|
1367
|
+
const sessionId = params.get("session_id");
|
|
1368
|
+
return !!(sessionId && (params.has("response_type") || params.has("wallet_id")));
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
// src/ProviderManager.ts
|
|
1260
1372
|
var ProviderManager = class {
|
|
1261
1373
|
// Track which providers have forwarding set up
|
|
1262
1374
|
constructor(config) {
|
|
@@ -1322,12 +1434,35 @@ var ProviderManager = class {
|
|
|
1322
1434
|
}
|
|
1323
1435
|
/**
|
|
1324
1436
|
* Connect using the current provider
|
|
1437
|
+
* Automatically switches provider based on authOptions.provider if specified
|
|
1325
1438
|
*/
|
|
1326
1439
|
async connect(authOptions) {
|
|
1327
1440
|
debug.info(DebugCategory.PROVIDER_MANAGER, "Starting connection", {
|
|
1328
1441
|
currentProviderKey: this.currentProviderKey,
|
|
1329
1442
|
authOptions: authOptions ? { provider: authOptions.provider, hasJwtToken: !!authOptions.jwtToken } : void 0
|
|
1330
1443
|
});
|
|
1444
|
+
if (authOptions?.provider) {
|
|
1445
|
+
const requestedProvider = authOptions.provider;
|
|
1446
|
+
let targetProviderType = null;
|
|
1447
|
+
if (requestedProvider === "injected") {
|
|
1448
|
+
targetProviderType = "injected";
|
|
1449
|
+
} else if (["google", "apple", "jwt", "phantom"].includes(requestedProvider)) {
|
|
1450
|
+
targetProviderType = "embedded";
|
|
1451
|
+
}
|
|
1452
|
+
if (targetProviderType) {
|
|
1453
|
+
const currentInfo = this.getCurrentProviderInfo();
|
|
1454
|
+
if (currentInfo?.type !== targetProviderType) {
|
|
1455
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Auto-switching provider based on auth options", {
|
|
1456
|
+
from: currentInfo?.type,
|
|
1457
|
+
to: targetProviderType,
|
|
1458
|
+
requestedProvider
|
|
1459
|
+
});
|
|
1460
|
+
this.switchProvider(targetProviderType, {
|
|
1461
|
+
embeddedWalletType: currentInfo?.embeddedWalletType || this.config.embeddedWalletType
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1331
1466
|
if (!this.currentProvider) {
|
|
1332
1467
|
debug.error(DebugCategory.PROVIDER_MANAGER, "No provider selected");
|
|
1333
1468
|
throw new Error("No provider selected");
|
|
@@ -1373,6 +1508,10 @@ var ProviderManager = class {
|
|
|
1373
1508
|
*/
|
|
1374
1509
|
async autoConnect() {
|
|
1375
1510
|
debug.log(DebugCategory.PROVIDER_MANAGER, "Starting auto-connect with fallback strategy");
|
|
1511
|
+
if (isAuthFailureCallback()) {
|
|
1512
|
+
debug.warn(DebugCategory.PROVIDER_MANAGER, "Auth failure detected in URL, skipping autoConnect fallback");
|
|
1513
|
+
return false;
|
|
1514
|
+
}
|
|
1376
1515
|
const embeddedWalletType = this.config.embeddedWalletType || "user-wallet";
|
|
1377
1516
|
const embeddedKey = this.getProviderKey("embedded", embeddedWalletType);
|
|
1378
1517
|
if (this.providers.has(embeddedKey)) {
|
|
@@ -1398,6 +1537,10 @@ var ProviderManager = class {
|
|
|
1398
1537
|
debug.log(DebugCategory.PROVIDER_MANAGER, "Embedded auto-connect failed", {
|
|
1399
1538
|
error: error.message
|
|
1400
1539
|
});
|
|
1540
|
+
if (isAuthCallbackUrl()) {
|
|
1541
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "In auth callback URL, not attempting injected fallback");
|
|
1542
|
+
return false;
|
|
1543
|
+
}
|
|
1401
1544
|
}
|
|
1402
1545
|
}
|
|
1403
1546
|
const injectedKey = this.getProviderKey("injected");
|
|
@@ -1575,35 +1718,17 @@ var ProviderManager = class {
|
|
|
1575
1718
|
console.error("Failed to save provider preference:", error);
|
|
1576
1719
|
}
|
|
1577
1720
|
}
|
|
1578
|
-
/**
|
|
1579
|
-
* Restore provider preference from localStorage
|
|
1580
|
-
*/
|
|
1581
|
-
/*
|
|
1582
|
-
private restoreProviderPreference(): void {
|
|
1583
|
-
try {
|
|
1584
|
-
const saved = localStorage.getItem("phantom-provider-preference");
|
|
1585
|
-
if (saved) {
|
|
1586
|
-
const preference: ProviderPreference = JSON.parse(saved);
|
|
1587
|
-
this.switchProvider(preference.type, {
|
|
1588
|
-
embeddedWalletType: preference.embeddedWalletType,
|
|
1589
|
-
});
|
|
1590
|
-
}
|
|
1591
|
-
} catch (error) {
|
|
1592
|
-
// Ignore localStorage errors - just use default provider
|
|
1593
|
-
console.error("Failed to restore provider preference:", error);
|
|
1594
|
-
}
|
|
1595
|
-
}*/
|
|
1596
1721
|
};
|
|
1597
1722
|
|
|
1598
1723
|
// src/waitForPhantomExtension.ts
|
|
1599
|
-
var
|
|
1724
|
+
var import_browser_injected_sdk3 = require("@phantom/browser-injected-sdk");
|
|
1600
1725
|
async function waitForPhantomExtension(timeoutMs = 3e3) {
|
|
1601
1726
|
return new Promise((resolve) => {
|
|
1602
1727
|
const startTime = Date.now();
|
|
1603
1728
|
const checkInterval = 100;
|
|
1604
1729
|
const checkForExtension = () => {
|
|
1605
1730
|
try {
|
|
1606
|
-
if ((0,
|
|
1731
|
+
if ((0, import_browser_injected_sdk3.isPhantomExtensionInstalled)()) {
|
|
1607
1732
|
resolve(true);
|
|
1608
1733
|
return;
|
|
1609
1734
|
}
|
|
@@ -1696,22 +1821,6 @@ var BrowserSDK = class {
|
|
|
1696
1821
|
throw error;
|
|
1697
1822
|
}
|
|
1698
1823
|
}
|
|
1699
|
-
/**
|
|
1700
|
-
* Switch between provider types (injected vs embedded)
|
|
1701
|
-
*/
|
|
1702
|
-
async switchProvider(type, options) {
|
|
1703
|
-
debug.info(DebugCategory.BROWSER_SDK, "Switching provider", { type, options });
|
|
1704
|
-
try {
|
|
1705
|
-
await this.providerManager.switchProvider(type, options);
|
|
1706
|
-
debug.info(DebugCategory.BROWSER_SDK, "Provider switch successful", { type });
|
|
1707
|
-
} catch (error) {
|
|
1708
|
-
debug.error(DebugCategory.BROWSER_SDK, "Provider switch failed", {
|
|
1709
|
-
type,
|
|
1710
|
-
error: error.message
|
|
1711
|
-
});
|
|
1712
|
-
throw error;
|
|
1713
|
-
}
|
|
1714
|
-
}
|
|
1715
1824
|
// ===== STATE QUERIES =====
|
|
1716
1825
|
/**
|
|
1717
1826
|
* Check if the SDK is connected to a wallet
|
package/dist/index.mjs
CHANGED
|
@@ -865,6 +865,47 @@ var BrowserStorage = class {
|
|
|
865
865
|
};
|
|
866
866
|
});
|
|
867
867
|
}
|
|
868
|
+
async getShouldClearPreviousSession() {
|
|
869
|
+
debug.log(DebugCategory.STORAGE, "Getting shouldClearPreviousSession flag from IndexedDB");
|
|
870
|
+
const db = await this.getDB();
|
|
871
|
+
return new Promise((resolve, reject) => {
|
|
872
|
+
const transaction = db.transaction([this.storeName], "readonly");
|
|
873
|
+
const store = transaction.objectStore(this.storeName);
|
|
874
|
+
const request = store.get("shouldClearPreviousSession");
|
|
875
|
+
request.onsuccess = () => {
|
|
876
|
+
const shouldClear = request.result ?? false;
|
|
877
|
+
debug.log(DebugCategory.STORAGE, "Retrieved shouldClearPreviousSession flag from IndexedDB", {
|
|
878
|
+
shouldClear
|
|
879
|
+
});
|
|
880
|
+
resolve(shouldClear);
|
|
881
|
+
};
|
|
882
|
+
request.onerror = () => {
|
|
883
|
+
debug.error(DebugCategory.STORAGE, "Failed to get shouldClearPreviousSession flag from IndexedDB", {
|
|
884
|
+
error: request.error
|
|
885
|
+
});
|
|
886
|
+
reject(request.error);
|
|
887
|
+
};
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
async setShouldClearPreviousSession(should) {
|
|
891
|
+
debug.log(DebugCategory.STORAGE, "Setting shouldClearPreviousSession flag in IndexedDB", { should });
|
|
892
|
+
const db = await this.getDB();
|
|
893
|
+
return new Promise((resolve, reject) => {
|
|
894
|
+
const transaction = db.transaction([this.storeName], "readwrite");
|
|
895
|
+
const store = transaction.objectStore(this.storeName);
|
|
896
|
+
const request = store.put(should, "shouldClearPreviousSession");
|
|
897
|
+
request.onsuccess = () => {
|
|
898
|
+
debug.log(DebugCategory.STORAGE, "Successfully set shouldClearPreviousSession flag in IndexedDB");
|
|
899
|
+
resolve();
|
|
900
|
+
};
|
|
901
|
+
request.onerror = () => {
|
|
902
|
+
debug.error(DebugCategory.STORAGE, "Failed to set shouldClearPreviousSession flag in IndexedDB", {
|
|
903
|
+
error: request.error
|
|
904
|
+
});
|
|
905
|
+
reject(request.error);
|
|
906
|
+
};
|
|
907
|
+
});
|
|
908
|
+
}
|
|
868
909
|
};
|
|
869
910
|
|
|
870
911
|
// src/providers/embedded/adapters/url-params.ts
|
|
@@ -878,6 +919,147 @@ var browserUrlParamsAccessor = new BrowserURLParamsAccessor();
|
|
|
878
919
|
|
|
879
920
|
// src/providers/embedded/adapters/auth.ts
|
|
880
921
|
import { DEFAULT_AUTH_URL } from "@phantom/constants";
|
|
922
|
+
|
|
923
|
+
// src/utils/browser-detection.ts
|
|
924
|
+
function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
|
|
925
|
+
let name = "unknown";
|
|
926
|
+
let version = "unknown";
|
|
927
|
+
if (!userAgent || typeof userAgent !== "string") {
|
|
928
|
+
return { name, version, userAgent: "unknown" };
|
|
929
|
+
}
|
|
930
|
+
try {
|
|
931
|
+
if (userAgent.includes("Edg/")) {
|
|
932
|
+
name = "edge";
|
|
933
|
+
const match = userAgent.match(/Edg\/([0-9]+(?:\.[0-9]+)*)/);
|
|
934
|
+
if (match)
|
|
935
|
+
version = match[1].split(".")[0];
|
|
936
|
+
} else if (userAgent.includes("OPR/") || userAgent.includes("Opera/")) {
|
|
937
|
+
name = "opera";
|
|
938
|
+
const match = userAgent.match(/(?:OPR|Opera)\/([0-9]+(?:\.[0-9]+)*)/);
|
|
939
|
+
if (match)
|
|
940
|
+
version = match[1].split(".")[0];
|
|
941
|
+
} else if (userAgent.includes("SamsungBrowser/")) {
|
|
942
|
+
name = "samsung";
|
|
943
|
+
const match = userAgent.match(/SamsungBrowser\/([0-9]+(?:\.[0-9]+)*)/);
|
|
944
|
+
if (match)
|
|
945
|
+
version = match[1].split(".")[0];
|
|
946
|
+
} else if (userAgent.includes("DuckDuckGo/")) {
|
|
947
|
+
name = "duckduckgo";
|
|
948
|
+
const match = userAgent.match(/DuckDuckGo\/([0-9]+(?:\.[0-9]+)*)/);
|
|
949
|
+
if (match)
|
|
950
|
+
version = match[1].split(".")[0];
|
|
951
|
+
} else if (userAgent.includes("Chrome/") && hasBraveAPI) {
|
|
952
|
+
name = "brave";
|
|
953
|
+
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
954
|
+
if (match)
|
|
955
|
+
version = match[1].split(".")[0];
|
|
956
|
+
} else if (userAgent.includes("Mobile/") || userAgent.includes("Android")) {
|
|
957
|
+
if (userAgent.includes("Chrome/")) {
|
|
958
|
+
name = "chrome-mobile";
|
|
959
|
+
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
960
|
+
if (match)
|
|
961
|
+
version = match[1].split(".")[0];
|
|
962
|
+
} else if (userAgent.includes("Firefox/")) {
|
|
963
|
+
name = "firefox-mobile";
|
|
964
|
+
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
965
|
+
if (match)
|
|
966
|
+
version = match[1].split(".")[0];
|
|
967
|
+
} else if (userAgent.includes("Safari/") && userAgent.includes("Mobile/")) {
|
|
968
|
+
name = "safari-mobile";
|
|
969
|
+
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
970
|
+
if (match)
|
|
971
|
+
version = match[1].split(".")[0];
|
|
972
|
+
} else {
|
|
973
|
+
name = "mobile";
|
|
974
|
+
}
|
|
975
|
+
} else if (userAgent.includes("Chrome/")) {
|
|
976
|
+
name = "chrome";
|
|
977
|
+
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
978
|
+
if (match)
|
|
979
|
+
version = match[1].split(".")[0];
|
|
980
|
+
} else if (userAgent.includes("Firefox/")) {
|
|
981
|
+
name = "firefox";
|
|
982
|
+
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
983
|
+
if (match)
|
|
984
|
+
version = match[1].split(".")[0];
|
|
985
|
+
} else if (userAgent.includes("Safari/") && !userAgent.includes("Chrome/")) {
|
|
986
|
+
name = "safari";
|
|
987
|
+
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
988
|
+
if (match)
|
|
989
|
+
version = match[1].split(".")[0];
|
|
990
|
+
}
|
|
991
|
+
if (name === "unknown") {
|
|
992
|
+
const patterns = [
|
|
993
|
+
{ regex: /Chrome\/([0-9]+)/, name: "chrome" },
|
|
994
|
+
{ regex: /Firefox\/([0-9]+)/, name: "firefox" },
|
|
995
|
+
{ regex: /Safari\/([0-9]+)/, name: "safari" },
|
|
996
|
+
{ regex: /Edge\/([0-9]+)/, name: "edge" },
|
|
997
|
+
{ regex: /Opera\/([0-9]+)/, name: "opera" }
|
|
998
|
+
];
|
|
999
|
+
for (const pattern of patterns) {
|
|
1000
|
+
const match = userAgent.match(pattern.regex);
|
|
1001
|
+
if (match) {
|
|
1002
|
+
name = pattern.name;
|
|
1003
|
+
version = match[1];
|
|
1004
|
+
break;
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
} catch (error) {
|
|
1009
|
+
}
|
|
1010
|
+
return { name, version, userAgent };
|
|
1011
|
+
}
|
|
1012
|
+
function detectBrowser() {
|
|
1013
|
+
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
1014
|
+
return { name: "unknown", version: "unknown", userAgent: "unknown" };
|
|
1015
|
+
}
|
|
1016
|
+
const userAgent = window.navigator.userAgent;
|
|
1017
|
+
const hasBraveAPI = !!navigator.brave;
|
|
1018
|
+
return parseBrowserFromUserAgent(userAgent, hasBraveAPI);
|
|
1019
|
+
}
|
|
1020
|
+
function getPlatformName() {
|
|
1021
|
+
const { name, version } = detectBrowser();
|
|
1022
|
+
return version !== "unknown" ? `${name}-v${version}` : name;
|
|
1023
|
+
}
|
|
1024
|
+
function getBrowserDisplayName() {
|
|
1025
|
+
const { name, version } = detectBrowser();
|
|
1026
|
+
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
1027
|
+
return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
|
|
1028
|
+
}
|
|
1029
|
+
function isMobileDevice() {
|
|
1030
|
+
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
1031
|
+
return false;
|
|
1032
|
+
}
|
|
1033
|
+
const userAgent = window.navigator.userAgent.toLowerCase();
|
|
1034
|
+
const mobilePatterns = [
|
|
1035
|
+
/android/,
|
|
1036
|
+
/iphone|ipad|ipod/,
|
|
1037
|
+
/blackberry/,
|
|
1038
|
+
/windows phone/,
|
|
1039
|
+
/mobile/,
|
|
1040
|
+
/tablet/,
|
|
1041
|
+
/silk/,
|
|
1042
|
+
/kindle/,
|
|
1043
|
+
/opera mini/,
|
|
1044
|
+
/opera mobi/
|
|
1045
|
+
];
|
|
1046
|
+
const isMobileUA = mobilePatterns.some((pattern) => pattern.test(userAgent));
|
|
1047
|
+
let isSmallScreen = false;
|
|
1048
|
+
try {
|
|
1049
|
+
isSmallScreen = window.screen.width <= 768 || window.screen.height <= 768;
|
|
1050
|
+
} catch (error) {
|
|
1051
|
+
isSmallScreen = false;
|
|
1052
|
+
}
|
|
1053
|
+
let isTouchDevice = false;
|
|
1054
|
+
try {
|
|
1055
|
+
isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
1056
|
+
} catch (error) {
|
|
1057
|
+
isTouchDevice = false;
|
|
1058
|
+
}
|
|
1059
|
+
return isMobileUA || isSmallScreen && isTouchDevice;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
// src/providers/embedded/adapters/auth.ts
|
|
881
1063
|
var BrowserAuthProvider = class {
|
|
882
1064
|
constructor(urlParamsAccessor) {
|
|
883
1065
|
this.urlParamsAccessor = urlParamsAccessor;
|
|
@@ -899,8 +1081,7 @@ var BrowserAuthProvider = class {
|
|
|
899
1081
|
publicKey: phantomOptions.publicKey,
|
|
900
1082
|
appId: phantomOptions.appId,
|
|
901
1083
|
provider: phantomOptions.provider,
|
|
902
|
-
authUrl: phantomOptions.authUrl
|
|
903
|
-
hasCustomData: !!phantomOptions.customAuthData
|
|
1084
|
+
authUrl: phantomOptions.authUrl
|
|
904
1085
|
});
|
|
905
1086
|
const baseUrl = phantomOptions.authUrl || DEFAULT_AUTH_URL;
|
|
906
1087
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Using auth URL", { baseUrl });
|
|
@@ -909,8 +1090,12 @@ var BrowserAuthProvider = class {
|
|
|
909
1090
|
app_id: phantomOptions.appId,
|
|
910
1091
|
redirect_uri: phantomOptions.redirectUrl || (typeof window !== "undefined" ? this.getValidatedCurrentUrl() : ""),
|
|
911
1092
|
session_id: phantomOptions.sessionId,
|
|
912
|
-
|
|
913
|
-
|
|
1093
|
+
// OAuth session management - defaults to allow refresh unless explicitly clearing after logout
|
|
1094
|
+
clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
|
|
1095
|
+
allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
|
|
1096
|
+
sdk_version: "1.0.0-beta.15",
|
|
1097
|
+
sdk_type: "browser",
|
|
1098
|
+
platform: detectBrowser().name
|
|
914
1099
|
});
|
|
915
1100
|
if (phantomOptions.provider) {
|
|
916
1101
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Provider specified, will skip selection", {
|
|
@@ -921,10 +1106,6 @@ var BrowserAuthProvider = class {
|
|
|
921
1106
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "No provider specified, defaulting to Google");
|
|
922
1107
|
params.append("provider", "google");
|
|
923
1108
|
}
|
|
924
|
-
if (phantomOptions.customAuthData) {
|
|
925
|
-
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Adding custom auth data");
|
|
926
|
-
params.append("authData", JSON.stringify(phantomOptions.customAuthData));
|
|
927
|
-
}
|
|
928
1109
|
const authContext = {
|
|
929
1110
|
publicKey: phantomOptions.publicKey,
|
|
930
1111
|
appId: phantomOptions.appId,
|
|
@@ -995,12 +1176,14 @@ var BrowserAuthProvider = class {
|
|
|
995
1176
|
});
|
|
996
1177
|
const organizationId = this.urlParamsAccessor.getParam("organization_id");
|
|
997
1178
|
const expiresInMs = this.urlParamsAccessor.getParam("expires_in_ms");
|
|
1179
|
+
const authUserId = this.urlParamsAccessor.getParam("auth_user_id");
|
|
998
1180
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Auth redirect parameters", {
|
|
999
1181
|
walletId,
|
|
1000
1182
|
organizationId,
|
|
1001
1183
|
sessionId,
|
|
1002
1184
|
accountDerivationIndex,
|
|
1003
|
-
expiresInMs
|
|
1185
|
+
expiresInMs,
|
|
1186
|
+
authUserId
|
|
1004
1187
|
});
|
|
1005
1188
|
if (!organizationId) {
|
|
1006
1189
|
debug.error(DebugCategory.PHANTOM_CONNECT_AUTH, "Missing organization_id in auth response");
|
|
@@ -1014,9 +1197,9 @@ var BrowserAuthProvider = class {
|
|
|
1014
1197
|
return {
|
|
1015
1198
|
walletId,
|
|
1016
1199
|
organizationId,
|
|
1017
|
-
userInfo: context,
|
|
1018
1200
|
accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : 0,
|
|
1019
|
-
expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0
|
|
1201
|
+
expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0,
|
|
1202
|
+
authUserId: authUserId || void 0
|
|
1020
1203
|
};
|
|
1021
1204
|
} catch (error) {
|
|
1022
1205
|
sessionStorage.removeItem("phantom-auth-context");
|
|
@@ -1025,6 +1208,54 @@ var BrowserAuthProvider = class {
|
|
|
1025
1208
|
}
|
|
1026
1209
|
};
|
|
1027
1210
|
|
|
1211
|
+
// src/providers/embedded/adapters/phantom-app.ts
|
|
1212
|
+
import { isPhantomExtensionInstalled } from "@phantom/browser-injected-sdk";
|
|
1213
|
+
var BrowserPhantomAppProvider = class {
|
|
1214
|
+
/**
|
|
1215
|
+
* Check if the Phantom extension is installed in the browser
|
|
1216
|
+
*/
|
|
1217
|
+
isAvailable() {
|
|
1218
|
+
return isPhantomExtensionInstalled();
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* Authenticate using the Phantom browser extension
|
|
1222
|
+
*/
|
|
1223
|
+
async authenticate(options) {
|
|
1224
|
+
if (!this.isAvailable()) {
|
|
1225
|
+
throw new Error(
|
|
1226
|
+
"Phantom extension is not installed. Please install the Phantom browser extension to use this authentication method."
|
|
1227
|
+
);
|
|
1228
|
+
}
|
|
1229
|
+
if (!window.phantom?.app?.login || typeof window.phantom.app.login !== "function") {
|
|
1230
|
+
throw new Error(
|
|
1231
|
+
"Phantom extension authentication is not yet implemented. The extension needs to expose an app.login API (window.phantom.app.login)."
|
|
1232
|
+
);
|
|
1233
|
+
}
|
|
1234
|
+
try {
|
|
1235
|
+
const result = await window.phantom.app.login({
|
|
1236
|
+
publicKey: options.publicKey,
|
|
1237
|
+
appId: options.appId,
|
|
1238
|
+
sessionId: options.sessionId
|
|
1239
|
+
});
|
|
1240
|
+
if (!result || !result.walletId || !result.organizationId) {
|
|
1241
|
+
throw new Error("Invalid authentication response from Phantom extension");
|
|
1242
|
+
}
|
|
1243
|
+
return {
|
|
1244
|
+
walletId: result.walletId,
|
|
1245
|
+
organizationId: result.organizationId,
|
|
1246
|
+
provider: "phantom",
|
|
1247
|
+
accountDerivationIndex: result.accountDerivationIndex ?? 0,
|
|
1248
|
+
expiresInMs: result.expiresInMs ?? 0
|
|
1249
|
+
};
|
|
1250
|
+
} catch (error) {
|
|
1251
|
+
if (error instanceof Error) {
|
|
1252
|
+
throw error;
|
|
1253
|
+
}
|
|
1254
|
+
throw new Error(`Phantom extension authentication failed: ${String(error)}`);
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
};
|
|
1258
|
+
|
|
1028
1259
|
// src/providers/embedded/adapters/logger.ts
|
|
1029
1260
|
var BrowserLogger = class {
|
|
1030
1261
|
info(category, message, data) {
|
|
@@ -1041,145 +1272,6 @@ var BrowserLogger = class {
|
|
|
1041
1272
|
}
|
|
1042
1273
|
};
|
|
1043
1274
|
|
|
1044
|
-
// src/utils/browser-detection.ts
|
|
1045
|
-
function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
|
|
1046
|
-
let name = "unknown";
|
|
1047
|
-
let version = "unknown";
|
|
1048
|
-
if (!userAgent || typeof userAgent !== "string") {
|
|
1049
|
-
return { name, version, userAgent: "unknown" };
|
|
1050
|
-
}
|
|
1051
|
-
try {
|
|
1052
|
-
if (userAgent.includes("Edg/")) {
|
|
1053
|
-
name = "edge";
|
|
1054
|
-
const match = userAgent.match(/Edg\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1055
|
-
if (match)
|
|
1056
|
-
version = match[1].split(".")[0];
|
|
1057
|
-
} else if (userAgent.includes("OPR/") || userAgent.includes("Opera/")) {
|
|
1058
|
-
name = "opera";
|
|
1059
|
-
const match = userAgent.match(/(?:OPR|Opera)\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1060
|
-
if (match)
|
|
1061
|
-
version = match[1].split(".")[0];
|
|
1062
|
-
} else if (userAgent.includes("SamsungBrowser/")) {
|
|
1063
|
-
name = "samsung";
|
|
1064
|
-
const match = userAgent.match(/SamsungBrowser\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1065
|
-
if (match)
|
|
1066
|
-
version = match[1].split(".")[0];
|
|
1067
|
-
} else if (userAgent.includes("DuckDuckGo/")) {
|
|
1068
|
-
name = "duckduckgo";
|
|
1069
|
-
const match = userAgent.match(/DuckDuckGo\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1070
|
-
if (match)
|
|
1071
|
-
version = match[1].split(".")[0];
|
|
1072
|
-
} else if (userAgent.includes("Chrome/") && hasBraveAPI) {
|
|
1073
|
-
name = "brave";
|
|
1074
|
-
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1075
|
-
if (match)
|
|
1076
|
-
version = match[1].split(".")[0];
|
|
1077
|
-
} else if (userAgent.includes("Mobile/") || userAgent.includes("Android")) {
|
|
1078
|
-
if (userAgent.includes("Chrome/")) {
|
|
1079
|
-
name = "chrome-mobile";
|
|
1080
|
-
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1081
|
-
if (match)
|
|
1082
|
-
version = match[1].split(".")[0];
|
|
1083
|
-
} else if (userAgent.includes("Firefox/")) {
|
|
1084
|
-
name = "firefox-mobile";
|
|
1085
|
-
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1086
|
-
if (match)
|
|
1087
|
-
version = match[1].split(".")[0];
|
|
1088
|
-
} else if (userAgent.includes("Safari/") && userAgent.includes("Mobile/")) {
|
|
1089
|
-
name = "safari-mobile";
|
|
1090
|
-
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1091
|
-
if (match)
|
|
1092
|
-
version = match[1].split(".")[0];
|
|
1093
|
-
} else {
|
|
1094
|
-
name = "mobile";
|
|
1095
|
-
}
|
|
1096
|
-
} else if (userAgent.includes("Chrome/")) {
|
|
1097
|
-
name = "chrome";
|
|
1098
|
-
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1099
|
-
if (match)
|
|
1100
|
-
version = match[1].split(".")[0];
|
|
1101
|
-
} else if (userAgent.includes("Firefox/")) {
|
|
1102
|
-
name = "firefox";
|
|
1103
|
-
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1104
|
-
if (match)
|
|
1105
|
-
version = match[1].split(".")[0];
|
|
1106
|
-
} else if (userAgent.includes("Safari/") && !userAgent.includes("Chrome/")) {
|
|
1107
|
-
name = "safari";
|
|
1108
|
-
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1109
|
-
if (match)
|
|
1110
|
-
version = match[1].split(".")[0];
|
|
1111
|
-
}
|
|
1112
|
-
if (name === "unknown") {
|
|
1113
|
-
const patterns = [
|
|
1114
|
-
{ regex: /Chrome\/([0-9]+)/, name: "chrome" },
|
|
1115
|
-
{ regex: /Firefox\/([0-9]+)/, name: "firefox" },
|
|
1116
|
-
{ regex: /Safari\/([0-9]+)/, name: "safari" },
|
|
1117
|
-
{ regex: /Edge\/([0-9]+)/, name: "edge" },
|
|
1118
|
-
{ regex: /Opera\/([0-9]+)/, name: "opera" }
|
|
1119
|
-
];
|
|
1120
|
-
for (const pattern of patterns) {
|
|
1121
|
-
const match = userAgent.match(pattern.regex);
|
|
1122
|
-
if (match) {
|
|
1123
|
-
name = pattern.name;
|
|
1124
|
-
version = match[1];
|
|
1125
|
-
break;
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
} catch (error) {
|
|
1130
|
-
}
|
|
1131
|
-
return { name, version, userAgent };
|
|
1132
|
-
}
|
|
1133
|
-
function detectBrowser() {
|
|
1134
|
-
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
1135
|
-
return { name: "unknown", version: "unknown", userAgent: "unknown" };
|
|
1136
|
-
}
|
|
1137
|
-
const userAgent = window.navigator.userAgent;
|
|
1138
|
-
const hasBraveAPI = !!navigator.brave;
|
|
1139
|
-
return parseBrowserFromUserAgent(userAgent, hasBraveAPI);
|
|
1140
|
-
}
|
|
1141
|
-
function getPlatformName() {
|
|
1142
|
-
const { name, version } = detectBrowser();
|
|
1143
|
-
return version !== "unknown" ? `${name}-v${version}` : name;
|
|
1144
|
-
}
|
|
1145
|
-
function getBrowserDisplayName() {
|
|
1146
|
-
const { name, version } = detectBrowser();
|
|
1147
|
-
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
1148
|
-
return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
|
|
1149
|
-
}
|
|
1150
|
-
function isMobileDevice() {
|
|
1151
|
-
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
1152
|
-
return false;
|
|
1153
|
-
}
|
|
1154
|
-
const userAgent = window.navigator.userAgent.toLowerCase();
|
|
1155
|
-
const mobilePatterns = [
|
|
1156
|
-
/android/,
|
|
1157
|
-
/iphone|ipad|ipod/,
|
|
1158
|
-
/blackberry/,
|
|
1159
|
-
/windows phone/,
|
|
1160
|
-
/mobile/,
|
|
1161
|
-
/tablet/,
|
|
1162
|
-
/silk/,
|
|
1163
|
-
/kindle/,
|
|
1164
|
-
/opera mini/,
|
|
1165
|
-
/opera mobi/
|
|
1166
|
-
];
|
|
1167
|
-
const isMobileUA = mobilePatterns.some((pattern) => pattern.test(userAgent));
|
|
1168
|
-
let isSmallScreen = false;
|
|
1169
|
-
try {
|
|
1170
|
-
isSmallScreen = window.screen.width <= 768 || window.screen.height <= 768;
|
|
1171
|
-
} catch (error) {
|
|
1172
|
-
isSmallScreen = false;
|
|
1173
|
-
}
|
|
1174
|
-
let isTouchDevice = false;
|
|
1175
|
-
try {
|
|
1176
|
-
isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
1177
|
-
} catch (error) {
|
|
1178
|
-
isTouchDevice = false;
|
|
1179
|
-
}
|
|
1180
|
-
return isMobileUA || isSmallScreen && isTouchDevice;
|
|
1181
|
-
}
|
|
1182
|
-
|
|
1183
1275
|
// src/providers/embedded/index.ts
|
|
1184
1276
|
import { ANALYTICS_HEADERS } from "@phantom/constants";
|
|
1185
1277
|
var EmbeddedProvider = class extends CoreEmbeddedProvider {
|
|
@@ -1196,6 +1288,7 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
|
|
|
1196
1288
|
const platform = {
|
|
1197
1289
|
storage: new BrowserStorage(),
|
|
1198
1290
|
authProvider: new BrowserAuthProvider(urlParamsAccessor),
|
|
1291
|
+
phantomAppProvider: new BrowserPhantomAppProvider(),
|
|
1199
1292
|
urlParamsAccessor,
|
|
1200
1293
|
stamper,
|
|
1201
1294
|
name: platformName,
|
|
@@ -1208,7 +1301,7 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
|
|
|
1208
1301
|
// Full user agent for more detailed info
|
|
1209
1302
|
[ANALYTICS_HEADERS.APP_ID]: config.appId,
|
|
1210
1303
|
[ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
|
|
1211
|
-
[ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.
|
|
1304
|
+
[ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.15"
|
|
1212
1305
|
// Replaced at build time
|
|
1213
1306
|
}
|
|
1214
1307
|
};
|
|
@@ -1221,6 +1314,25 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
|
|
|
1221
1314
|
|
|
1222
1315
|
// src/ProviderManager.ts
|
|
1223
1316
|
import { DEFAULT_WALLET_API_URL, DEFAULT_EMBEDDED_WALLET_TYPE, DEFAULT_AUTH_URL as DEFAULT_AUTH_URL2 } from "@phantom/constants";
|
|
1317
|
+
|
|
1318
|
+
// src/utils/auth-callback.ts
|
|
1319
|
+
function isAuthFailureCallback(searchParams) {
|
|
1320
|
+
if (typeof window === "undefined" && !searchParams)
|
|
1321
|
+
return false;
|
|
1322
|
+
const params = searchParams || new URLSearchParams(window.location.search);
|
|
1323
|
+
const responseType = params.get("response_type");
|
|
1324
|
+
const sessionId = params.get("session_id");
|
|
1325
|
+
return responseType === "failure" && !!sessionId;
|
|
1326
|
+
}
|
|
1327
|
+
function isAuthCallbackUrl(searchParams) {
|
|
1328
|
+
if (typeof window === "undefined" && !searchParams)
|
|
1329
|
+
return false;
|
|
1330
|
+
const params = searchParams || new URLSearchParams(window.location.search);
|
|
1331
|
+
const sessionId = params.get("session_id");
|
|
1332
|
+
return !!(sessionId && (params.has("response_type") || params.has("wallet_id")));
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
// src/ProviderManager.ts
|
|
1224
1336
|
var ProviderManager = class {
|
|
1225
1337
|
// Track which providers have forwarding set up
|
|
1226
1338
|
constructor(config) {
|
|
@@ -1286,12 +1398,35 @@ var ProviderManager = class {
|
|
|
1286
1398
|
}
|
|
1287
1399
|
/**
|
|
1288
1400
|
* Connect using the current provider
|
|
1401
|
+
* Automatically switches provider based on authOptions.provider if specified
|
|
1289
1402
|
*/
|
|
1290
1403
|
async connect(authOptions) {
|
|
1291
1404
|
debug.info(DebugCategory.PROVIDER_MANAGER, "Starting connection", {
|
|
1292
1405
|
currentProviderKey: this.currentProviderKey,
|
|
1293
1406
|
authOptions: authOptions ? { provider: authOptions.provider, hasJwtToken: !!authOptions.jwtToken } : void 0
|
|
1294
1407
|
});
|
|
1408
|
+
if (authOptions?.provider) {
|
|
1409
|
+
const requestedProvider = authOptions.provider;
|
|
1410
|
+
let targetProviderType = null;
|
|
1411
|
+
if (requestedProvider === "injected") {
|
|
1412
|
+
targetProviderType = "injected";
|
|
1413
|
+
} else if (["google", "apple", "jwt", "phantom"].includes(requestedProvider)) {
|
|
1414
|
+
targetProviderType = "embedded";
|
|
1415
|
+
}
|
|
1416
|
+
if (targetProviderType) {
|
|
1417
|
+
const currentInfo = this.getCurrentProviderInfo();
|
|
1418
|
+
if (currentInfo?.type !== targetProviderType) {
|
|
1419
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Auto-switching provider based on auth options", {
|
|
1420
|
+
from: currentInfo?.type,
|
|
1421
|
+
to: targetProviderType,
|
|
1422
|
+
requestedProvider
|
|
1423
|
+
});
|
|
1424
|
+
this.switchProvider(targetProviderType, {
|
|
1425
|
+
embeddedWalletType: currentInfo?.embeddedWalletType || this.config.embeddedWalletType
|
|
1426
|
+
});
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1295
1430
|
if (!this.currentProvider) {
|
|
1296
1431
|
debug.error(DebugCategory.PROVIDER_MANAGER, "No provider selected");
|
|
1297
1432
|
throw new Error("No provider selected");
|
|
@@ -1337,6 +1472,10 @@ var ProviderManager = class {
|
|
|
1337
1472
|
*/
|
|
1338
1473
|
async autoConnect() {
|
|
1339
1474
|
debug.log(DebugCategory.PROVIDER_MANAGER, "Starting auto-connect with fallback strategy");
|
|
1475
|
+
if (isAuthFailureCallback()) {
|
|
1476
|
+
debug.warn(DebugCategory.PROVIDER_MANAGER, "Auth failure detected in URL, skipping autoConnect fallback");
|
|
1477
|
+
return false;
|
|
1478
|
+
}
|
|
1340
1479
|
const embeddedWalletType = this.config.embeddedWalletType || "user-wallet";
|
|
1341
1480
|
const embeddedKey = this.getProviderKey("embedded", embeddedWalletType);
|
|
1342
1481
|
if (this.providers.has(embeddedKey)) {
|
|
@@ -1362,6 +1501,10 @@ var ProviderManager = class {
|
|
|
1362
1501
|
debug.log(DebugCategory.PROVIDER_MANAGER, "Embedded auto-connect failed", {
|
|
1363
1502
|
error: error.message
|
|
1364
1503
|
});
|
|
1504
|
+
if (isAuthCallbackUrl()) {
|
|
1505
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "In auth callback URL, not attempting injected fallback");
|
|
1506
|
+
return false;
|
|
1507
|
+
}
|
|
1365
1508
|
}
|
|
1366
1509
|
}
|
|
1367
1510
|
const injectedKey = this.getProviderKey("injected");
|
|
@@ -1539,35 +1682,17 @@ var ProviderManager = class {
|
|
|
1539
1682
|
console.error("Failed to save provider preference:", error);
|
|
1540
1683
|
}
|
|
1541
1684
|
}
|
|
1542
|
-
/**
|
|
1543
|
-
* Restore provider preference from localStorage
|
|
1544
|
-
*/
|
|
1545
|
-
/*
|
|
1546
|
-
private restoreProviderPreference(): void {
|
|
1547
|
-
try {
|
|
1548
|
-
const saved = localStorage.getItem("phantom-provider-preference");
|
|
1549
|
-
if (saved) {
|
|
1550
|
-
const preference: ProviderPreference = JSON.parse(saved);
|
|
1551
|
-
this.switchProvider(preference.type, {
|
|
1552
|
-
embeddedWalletType: preference.embeddedWalletType,
|
|
1553
|
-
});
|
|
1554
|
-
}
|
|
1555
|
-
} catch (error) {
|
|
1556
|
-
// Ignore localStorage errors - just use default provider
|
|
1557
|
-
console.error("Failed to restore provider preference:", error);
|
|
1558
|
-
}
|
|
1559
|
-
}*/
|
|
1560
1685
|
};
|
|
1561
1686
|
|
|
1562
1687
|
// src/waitForPhantomExtension.ts
|
|
1563
|
-
import { isPhantomExtensionInstalled } from "@phantom/browser-injected-sdk";
|
|
1688
|
+
import { isPhantomExtensionInstalled as isPhantomExtensionInstalled2 } from "@phantom/browser-injected-sdk";
|
|
1564
1689
|
async function waitForPhantomExtension(timeoutMs = 3e3) {
|
|
1565
1690
|
return new Promise((resolve) => {
|
|
1566
1691
|
const startTime = Date.now();
|
|
1567
1692
|
const checkInterval = 100;
|
|
1568
1693
|
const checkForExtension = () => {
|
|
1569
1694
|
try {
|
|
1570
|
-
if (
|
|
1695
|
+
if (isPhantomExtensionInstalled2()) {
|
|
1571
1696
|
resolve(true);
|
|
1572
1697
|
return;
|
|
1573
1698
|
}
|
|
@@ -1660,22 +1785,6 @@ var BrowserSDK = class {
|
|
|
1660
1785
|
throw error;
|
|
1661
1786
|
}
|
|
1662
1787
|
}
|
|
1663
|
-
/**
|
|
1664
|
-
* Switch between provider types (injected vs embedded)
|
|
1665
|
-
*/
|
|
1666
|
-
async switchProvider(type, options) {
|
|
1667
|
-
debug.info(DebugCategory.BROWSER_SDK, "Switching provider", { type, options });
|
|
1668
|
-
try {
|
|
1669
|
-
await this.providerManager.switchProvider(type, options);
|
|
1670
|
-
debug.info(DebugCategory.BROWSER_SDK, "Provider switch successful", { type });
|
|
1671
|
-
} catch (error) {
|
|
1672
|
-
debug.error(DebugCategory.BROWSER_SDK, "Provider switch failed", {
|
|
1673
|
-
type,
|
|
1674
|
-
error: error.message
|
|
1675
|
-
});
|
|
1676
|
-
throw error;
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
1788
|
// ===== STATE QUERIES =====
|
|
1680
1789
|
/**
|
|
1681
1790
|
* Check if the SDK is connected to a wallet
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phantom/browser-sdk",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.15",
|
|
4
4
|
"description": "Browser SDK for Phantom Wallet",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"@phantom/base64url": "^1.0.0-beta.7",
|
|
32
32
|
"@phantom/browser-injected-sdk": "^1.0.0-beta.5",
|
|
33
33
|
"@phantom/chain-interfaces": "^1.0.0-beta.7",
|
|
34
|
-
"@phantom/client": "^1.0.0-beta.
|
|
34
|
+
"@phantom/client": "^1.0.0-beta.15",
|
|
35
35
|
"@phantom/constants": "^1.0.0-beta.7",
|
|
36
|
-
"@phantom/embedded-provider-core": "^1.0.0-beta.
|
|
36
|
+
"@phantom/embedded-provider-core": "^1.0.0-beta.15",
|
|
37
37
|
"@phantom/indexed-db-stamper": "^1.0.0-beta.1",
|
|
38
38
|
"@phantom/parsers": "^1.0.0-beta.7",
|
|
39
39
|
"@phantom/sdk-types": "^1.0.0-beta.7",
|