@phantom/browser-sdk 1.0.0-beta.13 → 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 +23 -20
- package/dist/index.d.ts +21 -13
- package/dist/index.js +364 -212
- package/dist/index.mjs +364 -212
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -472,7 +472,6 @@ var InjectedProvider = class {
|
|
|
472
472
|
const result = {
|
|
473
473
|
addresses: this.addresses,
|
|
474
474
|
status: "completed"
|
|
475
|
-
// walletId is not applicable for injected providers
|
|
476
475
|
};
|
|
477
476
|
this.emit("connect", {
|
|
478
477
|
addresses: this.addresses,
|
|
@@ -866,6 +865,47 @@ var BrowserStorage = class {
|
|
|
866
865
|
};
|
|
867
866
|
});
|
|
868
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
|
+
}
|
|
869
909
|
};
|
|
870
910
|
|
|
871
911
|
// src/providers/embedded/adapters/url-params.ts
|
|
@@ -879,6 +919,147 @@ var browserUrlParamsAccessor = new BrowserURLParamsAccessor();
|
|
|
879
919
|
|
|
880
920
|
// src/providers/embedded/adapters/auth.ts
|
|
881
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
|
|
882
1063
|
var BrowserAuthProvider = class {
|
|
883
1064
|
constructor(urlParamsAccessor) {
|
|
884
1065
|
this.urlParamsAccessor = urlParamsAccessor;
|
|
@@ -900,8 +1081,7 @@ var BrowserAuthProvider = class {
|
|
|
900
1081
|
publicKey: phantomOptions.publicKey,
|
|
901
1082
|
appId: phantomOptions.appId,
|
|
902
1083
|
provider: phantomOptions.provider,
|
|
903
|
-
authUrl: phantomOptions.authUrl
|
|
904
|
-
hasCustomData: !!phantomOptions.customAuthData
|
|
1084
|
+
authUrl: phantomOptions.authUrl
|
|
905
1085
|
});
|
|
906
1086
|
const baseUrl = phantomOptions.authUrl || DEFAULT_AUTH_URL;
|
|
907
1087
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Using auth URL", { baseUrl });
|
|
@@ -910,8 +1090,12 @@ var BrowserAuthProvider = class {
|
|
|
910
1090
|
app_id: phantomOptions.appId,
|
|
911
1091
|
redirect_uri: phantomOptions.redirectUrl || (typeof window !== "undefined" ? this.getValidatedCurrentUrl() : ""),
|
|
912
1092
|
session_id: phantomOptions.sessionId,
|
|
913
|
-
|
|
914
|
-
|
|
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
|
|
915
1099
|
});
|
|
916
1100
|
if (phantomOptions.provider) {
|
|
917
1101
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Provider specified, will skip selection", {
|
|
@@ -922,10 +1106,6 @@ var BrowserAuthProvider = class {
|
|
|
922
1106
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "No provider specified, defaulting to Google");
|
|
923
1107
|
params.append("provider", "google");
|
|
924
1108
|
}
|
|
925
|
-
if (phantomOptions.customAuthData) {
|
|
926
|
-
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Adding custom auth data");
|
|
927
|
-
params.append("authData", JSON.stringify(phantomOptions.customAuthData));
|
|
928
|
-
}
|
|
929
1109
|
const authContext = {
|
|
930
1110
|
publicKey: phantomOptions.publicKey,
|
|
931
1111
|
appId: phantomOptions.appId,
|
|
@@ -996,12 +1176,14 @@ var BrowserAuthProvider = class {
|
|
|
996
1176
|
});
|
|
997
1177
|
const organizationId = this.urlParamsAccessor.getParam("organization_id");
|
|
998
1178
|
const expiresInMs = this.urlParamsAccessor.getParam("expires_in_ms");
|
|
1179
|
+
const authUserId = this.urlParamsAccessor.getParam("auth_user_id");
|
|
999
1180
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Auth redirect parameters", {
|
|
1000
1181
|
walletId,
|
|
1001
1182
|
organizationId,
|
|
1002
1183
|
sessionId,
|
|
1003
1184
|
accountDerivationIndex,
|
|
1004
|
-
expiresInMs
|
|
1185
|
+
expiresInMs,
|
|
1186
|
+
authUserId
|
|
1005
1187
|
});
|
|
1006
1188
|
if (!organizationId) {
|
|
1007
1189
|
debug.error(DebugCategory.PHANTOM_CONNECT_AUTH, "Missing organization_id in auth response");
|
|
@@ -1015,9 +1197,9 @@ var BrowserAuthProvider = class {
|
|
|
1015
1197
|
return {
|
|
1016
1198
|
walletId,
|
|
1017
1199
|
organizationId,
|
|
1018
|
-
userInfo: context,
|
|
1019
1200
|
accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : 0,
|
|
1020
|
-
expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0
|
|
1201
|
+
expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0,
|
|
1202
|
+
authUserId: authUserId || void 0
|
|
1021
1203
|
};
|
|
1022
1204
|
} catch (error) {
|
|
1023
1205
|
sessionStorage.removeItem("phantom-auth-context");
|
|
@@ -1026,6 +1208,54 @@ var BrowserAuthProvider = class {
|
|
|
1026
1208
|
}
|
|
1027
1209
|
};
|
|
1028
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
|
+
|
|
1029
1259
|
// src/providers/embedded/adapters/logger.ts
|
|
1030
1260
|
var BrowserLogger = class {
|
|
1031
1261
|
info(category, message, data) {
|
|
@@ -1042,145 +1272,6 @@ var BrowserLogger = class {
|
|
|
1042
1272
|
}
|
|
1043
1273
|
};
|
|
1044
1274
|
|
|
1045
|
-
// src/utils/browser-detection.ts
|
|
1046
|
-
function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
|
|
1047
|
-
let name = "unknown";
|
|
1048
|
-
let version = "unknown";
|
|
1049
|
-
if (!userAgent || typeof userAgent !== "string") {
|
|
1050
|
-
return { name, version, userAgent: "unknown" };
|
|
1051
|
-
}
|
|
1052
|
-
try {
|
|
1053
|
-
if (userAgent.includes("Edg/")) {
|
|
1054
|
-
name = "edge";
|
|
1055
|
-
const match = userAgent.match(/Edg\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1056
|
-
if (match)
|
|
1057
|
-
version = match[1].split(".")[0];
|
|
1058
|
-
} else if (userAgent.includes("OPR/") || userAgent.includes("Opera/")) {
|
|
1059
|
-
name = "opera";
|
|
1060
|
-
const match = userAgent.match(/(?:OPR|Opera)\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1061
|
-
if (match)
|
|
1062
|
-
version = match[1].split(".")[0];
|
|
1063
|
-
} else if (userAgent.includes("SamsungBrowser/")) {
|
|
1064
|
-
name = "samsung";
|
|
1065
|
-
const match = userAgent.match(/SamsungBrowser\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1066
|
-
if (match)
|
|
1067
|
-
version = match[1].split(".")[0];
|
|
1068
|
-
} else if (userAgent.includes("DuckDuckGo/")) {
|
|
1069
|
-
name = "duckduckgo";
|
|
1070
|
-
const match = userAgent.match(/DuckDuckGo\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1071
|
-
if (match)
|
|
1072
|
-
version = match[1].split(".")[0];
|
|
1073
|
-
} else if (userAgent.includes("Chrome/") && hasBraveAPI) {
|
|
1074
|
-
name = "brave";
|
|
1075
|
-
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1076
|
-
if (match)
|
|
1077
|
-
version = match[1].split(".")[0];
|
|
1078
|
-
} else if (userAgent.includes("Mobile/") || userAgent.includes("Android")) {
|
|
1079
|
-
if (userAgent.includes("Chrome/")) {
|
|
1080
|
-
name = "chrome-mobile";
|
|
1081
|
-
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1082
|
-
if (match)
|
|
1083
|
-
version = match[1].split(".")[0];
|
|
1084
|
-
} else if (userAgent.includes("Firefox/")) {
|
|
1085
|
-
name = "firefox-mobile";
|
|
1086
|
-
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1087
|
-
if (match)
|
|
1088
|
-
version = match[1].split(".")[0];
|
|
1089
|
-
} else if (userAgent.includes("Safari/") && userAgent.includes("Mobile/")) {
|
|
1090
|
-
name = "safari-mobile";
|
|
1091
|
-
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1092
|
-
if (match)
|
|
1093
|
-
version = match[1].split(".")[0];
|
|
1094
|
-
} else {
|
|
1095
|
-
name = "mobile";
|
|
1096
|
-
}
|
|
1097
|
-
} else if (userAgent.includes("Chrome/")) {
|
|
1098
|
-
name = "chrome";
|
|
1099
|
-
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1100
|
-
if (match)
|
|
1101
|
-
version = match[1].split(".")[0];
|
|
1102
|
-
} else if (userAgent.includes("Firefox/")) {
|
|
1103
|
-
name = "firefox";
|
|
1104
|
-
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1105
|
-
if (match)
|
|
1106
|
-
version = match[1].split(".")[0];
|
|
1107
|
-
} else if (userAgent.includes("Safari/") && !userAgent.includes("Chrome/")) {
|
|
1108
|
-
name = "safari";
|
|
1109
|
-
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1110
|
-
if (match)
|
|
1111
|
-
version = match[1].split(".")[0];
|
|
1112
|
-
}
|
|
1113
|
-
if (name === "unknown") {
|
|
1114
|
-
const patterns = [
|
|
1115
|
-
{ regex: /Chrome\/([0-9]+)/, name: "chrome" },
|
|
1116
|
-
{ regex: /Firefox\/([0-9]+)/, name: "firefox" },
|
|
1117
|
-
{ regex: /Safari\/([0-9]+)/, name: "safari" },
|
|
1118
|
-
{ regex: /Edge\/([0-9]+)/, name: "edge" },
|
|
1119
|
-
{ regex: /Opera\/([0-9]+)/, name: "opera" }
|
|
1120
|
-
];
|
|
1121
|
-
for (const pattern of patterns) {
|
|
1122
|
-
const match = userAgent.match(pattern.regex);
|
|
1123
|
-
if (match) {
|
|
1124
|
-
name = pattern.name;
|
|
1125
|
-
version = match[1];
|
|
1126
|
-
break;
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
} catch (error) {
|
|
1131
|
-
}
|
|
1132
|
-
return { name, version, userAgent };
|
|
1133
|
-
}
|
|
1134
|
-
function detectBrowser() {
|
|
1135
|
-
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
1136
|
-
return { name: "unknown", version: "unknown", userAgent: "unknown" };
|
|
1137
|
-
}
|
|
1138
|
-
const userAgent = window.navigator.userAgent;
|
|
1139
|
-
const hasBraveAPI = !!navigator.brave;
|
|
1140
|
-
return parseBrowserFromUserAgent(userAgent, hasBraveAPI);
|
|
1141
|
-
}
|
|
1142
|
-
function getPlatformName() {
|
|
1143
|
-
const { name, version } = detectBrowser();
|
|
1144
|
-
return version !== "unknown" ? `${name}-v${version}` : name;
|
|
1145
|
-
}
|
|
1146
|
-
function getBrowserDisplayName() {
|
|
1147
|
-
const { name, version } = detectBrowser();
|
|
1148
|
-
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
1149
|
-
return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
|
|
1150
|
-
}
|
|
1151
|
-
function isMobileDevice() {
|
|
1152
|
-
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
1153
|
-
return false;
|
|
1154
|
-
}
|
|
1155
|
-
const userAgent = window.navigator.userAgent.toLowerCase();
|
|
1156
|
-
const mobilePatterns = [
|
|
1157
|
-
/android/,
|
|
1158
|
-
/iphone|ipad|ipod/,
|
|
1159
|
-
/blackberry/,
|
|
1160
|
-
/windows phone/,
|
|
1161
|
-
/mobile/,
|
|
1162
|
-
/tablet/,
|
|
1163
|
-
/silk/,
|
|
1164
|
-
/kindle/,
|
|
1165
|
-
/opera mini/,
|
|
1166
|
-
/opera mobi/
|
|
1167
|
-
];
|
|
1168
|
-
const isMobileUA = mobilePatterns.some((pattern) => pattern.test(userAgent));
|
|
1169
|
-
let isSmallScreen = false;
|
|
1170
|
-
try {
|
|
1171
|
-
isSmallScreen = window.screen.width <= 768 || window.screen.height <= 768;
|
|
1172
|
-
} catch (error) {
|
|
1173
|
-
isSmallScreen = false;
|
|
1174
|
-
}
|
|
1175
|
-
let isTouchDevice = false;
|
|
1176
|
-
try {
|
|
1177
|
-
isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
1178
|
-
} catch (error) {
|
|
1179
|
-
isTouchDevice = false;
|
|
1180
|
-
}
|
|
1181
|
-
return isMobileUA || isSmallScreen && isTouchDevice;
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
1275
|
// src/providers/embedded/index.ts
|
|
1185
1276
|
import { ANALYTICS_HEADERS } from "@phantom/constants";
|
|
1186
1277
|
var EmbeddedProvider = class extends CoreEmbeddedProvider {
|
|
@@ -1197,6 +1288,7 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
|
|
|
1197
1288
|
const platform = {
|
|
1198
1289
|
storage: new BrowserStorage(),
|
|
1199
1290
|
authProvider: new BrowserAuthProvider(urlParamsAccessor),
|
|
1291
|
+
phantomAppProvider: new BrowserPhantomAppProvider(),
|
|
1200
1292
|
urlParamsAccessor,
|
|
1201
1293
|
stamper,
|
|
1202
1294
|
name: platformName,
|
|
@@ -1209,7 +1301,7 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
|
|
|
1209
1301
|
// Full user agent for more detailed info
|
|
1210
1302
|
[ANALYTICS_HEADERS.APP_ID]: config.appId,
|
|
1211
1303
|
[ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
|
|
1212
|
-
[ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.
|
|
1304
|
+
[ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.15"
|
|
1213
1305
|
// Replaced at build time
|
|
1214
1306
|
}
|
|
1215
1307
|
};
|
|
@@ -1222,13 +1314,31 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
|
|
|
1222
1314
|
|
|
1223
1315
|
// src/ProviderManager.ts
|
|
1224
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
|
|
1225
1336
|
var ProviderManager = class {
|
|
1226
1337
|
// Track which providers have forwarding set up
|
|
1227
1338
|
constructor(config) {
|
|
1228
1339
|
this.providers = /* @__PURE__ */ new Map();
|
|
1229
1340
|
this.currentProvider = null;
|
|
1230
1341
|
this.currentProviderKey = null;
|
|
1231
|
-
this.walletId = null;
|
|
1232
1342
|
// Event management for forwarding provider events
|
|
1233
1343
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
1234
1344
|
this.providerForwardingSetup = /* @__PURE__ */ new WeakSet();
|
|
@@ -1264,7 +1374,6 @@ var ProviderManager = class {
|
|
|
1264
1374
|
}
|
|
1265
1375
|
this.currentProvider = this.providers.get(key);
|
|
1266
1376
|
this.currentProviderKey = key;
|
|
1267
|
-
this.walletId = null;
|
|
1268
1377
|
this.ensureProviderEventForwarding();
|
|
1269
1378
|
return this.currentProvider;
|
|
1270
1379
|
}
|
|
@@ -1289,26 +1398,46 @@ var ProviderManager = class {
|
|
|
1289
1398
|
}
|
|
1290
1399
|
/**
|
|
1291
1400
|
* Connect using the current provider
|
|
1401
|
+
* Automatically switches provider based on authOptions.provider if specified
|
|
1292
1402
|
*/
|
|
1293
1403
|
async connect(authOptions) {
|
|
1294
1404
|
debug.info(DebugCategory.PROVIDER_MANAGER, "Starting connection", {
|
|
1295
1405
|
currentProviderKey: this.currentProviderKey,
|
|
1296
1406
|
authOptions: authOptions ? { provider: authOptions.provider, hasJwtToken: !!authOptions.jwtToken } : void 0
|
|
1297
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
|
+
}
|
|
1298
1430
|
if (!this.currentProvider) {
|
|
1299
1431
|
debug.error(DebugCategory.PROVIDER_MANAGER, "No provider selected");
|
|
1300
1432
|
throw new Error("No provider selected");
|
|
1301
1433
|
}
|
|
1302
1434
|
debug.log(DebugCategory.PROVIDER_MANAGER, "Delegating to provider connect method");
|
|
1303
1435
|
const result = await this.currentProvider.connect(authOptions);
|
|
1304
|
-
this.walletId = result.walletId || null;
|
|
1305
1436
|
debug.log(DebugCategory.PROVIDER_MANAGER, "Connection successful, saving preferences", {
|
|
1306
|
-
walletId: this.walletId,
|
|
1307
1437
|
addressCount: result.addresses?.length || 0
|
|
1308
1438
|
});
|
|
1309
1439
|
this.saveProviderPreference();
|
|
1310
1440
|
debug.info(DebugCategory.PROVIDER_MANAGER, "Connect completed", {
|
|
1311
|
-
walletId: this.walletId,
|
|
1312
1441
|
addresses: result.addresses
|
|
1313
1442
|
});
|
|
1314
1443
|
return result;
|
|
@@ -1320,7 +1449,6 @@ var ProviderManager = class {
|
|
|
1320
1449
|
if (!this.currentProvider)
|
|
1321
1450
|
return;
|
|
1322
1451
|
await this.currentProvider.disconnect();
|
|
1323
|
-
this.walletId = null;
|
|
1324
1452
|
}
|
|
1325
1453
|
/**
|
|
1326
1454
|
* Get addresses from current provider
|
|
@@ -1338,10 +1466,69 @@ var ProviderManager = class {
|
|
|
1338
1466
|
return this.currentProvider?.isConnected() ?? false;
|
|
1339
1467
|
}
|
|
1340
1468
|
/**
|
|
1341
|
-
*
|
|
1469
|
+
* Attempt auto-connect with fallback strategy
|
|
1470
|
+
* Tries embedded provider first if it exists, then injected provider
|
|
1471
|
+
* Returns true if any provider successfully connected
|
|
1342
1472
|
*/
|
|
1343
|
-
|
|
1344
|
-
|
|
1473
|
+
async autoConnect() {
|
|
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
|
+
}
|
|
1479
|
+
const embeddedWalletType = this.config.embeddedWalletType || "user-wallet";
|
|
1480
|
+
const embeddedKey = this.getProviderKey("embedded", embeddedWalletType);
|
|
1481
|
+
if (this.providers.has(embeddedKey)) {
|
|
1482
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Trying auto-connect with existing embedded provider");
|
|
1483
|
+
const embeddedProvider = this.providers.get(embeddedKey);
|
|
1484
|
+
try {
|
|
1485
|
+
const previousProvider = this.currentProvider;
|
|
1486
|
+
const previousKey = this.currentProviderKey;
|
|
1487
|
+
this.currentProvider = embeddedProvider;
|
|
1488
|
+
this.currentProviderKey = embeddedKey;
|
|
1489
|
+
this.ensureProviderEventForwarding();
|
|
1490
|
+
await embeddedProvider.autoConnect();
|
|
1491
|
+
if (embeddedProvider.isConnected()) {
|
|
1492
|
+
debug.info(DebugCategory.PROVIDER_MANAGER, "Embedded auto-connect successful");
|
|
1493
|
+
this.saveProviderPreference();
|
|
1494
|
+
return true;
|
|
1495
|
+
} else {
|
|
1496
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Embedded provider did not connect, restoring previous provider");
|
|
1497
|
+
this.currentProvider = previousProvider;
|
|
1498
|
+
this.currentProviderKey = previousKey;
|
|
1499
|
+
}
|
|
1500
|
+
} catch (error) {
|
|
1501
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Embedded auto-connect failed", {
|
|
1502
|
+
error: error.message
|
|
1503
|
+
});
|
|
1504
|
+
if (isAuthCallbackUrl()) {
|
|
1505
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "In auth callback URL, not attempting injected fallback");
|
|
1506
|
+
return false;
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
const injectedKey = this.getProviderKey("injected");
|
|
1511
|
+
if (this.providers.has(injectedKey)) {
|
|
1512
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Trying auto-connect with existing injected provider");
|
|
1513
|
+
const injectedProvider = this.providers.get(injectedKey);
|
|
1514
|
+
try {
|
|
1515
|
+
this.currentProvider = injectedProvider;
|
|
1516
|
+
this.currentProviderKey = injectedKey;
|
|
1517
|
+
this.ensureProviderEventForwarding();
|
|
1518
|
+
await injectedProvider.autoConnect();
|
|
1519
|
+
if (injectedProvider.isConnected()) {
|
|
1520
|
+
debug.info(DebugCategory.PROVIDER_MANAGER, "Injected auto-connect successful");
|
|
1521
|
+
this.saveProviderPreference();
|
|
1522
|
+
return true;
|
|
1523
|
+
}
|
|
1524
|
+
} catch (error) {
|
|
1525
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Injected auto-connect failed", {
|
|
1526
|
+
error: error.message
|
|
1527
|
+
});
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Auto-connect failed for all existing providers");
|
|
1531
|
+
return false;
|
|
1345
1532
|
}
|
|
1346
1533
|
/**
|
|
1347
1534
|
* Add event listener - stores callback and ensures current provider forwards events to ProviderManager
|
|
@@ -1424,11 +1611,17 @@ var ProviderManager = class {
|
|
|
1424
1611
|
}
|
|
1425
1612
|
/**
|
|
1426
1613
|
* Set default provider based on initial config
|
|
1614
|
+
* Creates both embedded and injected providers for autoConnect fallback
|
|
1427
1615
|
*/
|
|
1428
1616
|
setDefaultProvider() {
|
|
1429
1617
|
const defaultType = this.config.providerType || "embedded";
|
|
1430
1618
|
const defaultEmbeddedType = this.config.embeddedWalletType || "user-wallet";
|
|
1431
|
-
this.
|
|
1619
|
+
if (this.config.appId) {
|
|
1620
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Creating embedded provider");
|
|
1621
|
+
this.createProvider("embedded", defaultEmbeddedType);
|
|
1622
|
+
}
|
|
1623
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Creating injected provider");
|
|
1624
|
+
this.createProvider("injected");
|
|
1432
1625
|
this.switchProvider(defaultType, { embeddedWalletType: defaultEmbeddedType });
|
|
1433
1626
|
}
|
|
1434
1627
|
/**
|
|
@@ -1489,35 +1682,17 @@ var ProviderManager = class {
|
|
|
1489
1682
|
console.error("Failed to save provider preference:", error);
|
|
1490
1683
|
}
|
|
1491
1684
|
}
|
|
1492
|
-
/**
|
|
1493
|
-
* Restore provider preference from localStorage
|
|
1494
|
-
*/
|
|
1495
|
-
/*
|
|
1496
|
-
private restoreProviderPreference(): void {
|
|
1497
|
-
try {
|
|
1498
|
-
const saved = localStorage.getItem("phantom-provider-preference");
|
|
1499
|
-
if (saved) {
|
|
1500
|
-
const preference: ProviderPreference = JSON.parse(saved);
|
|
1501
|
-
this.switchProvider(preference.type, {
|
|
1502
|
-
embeddedWalletType: preference.embeddedWalletType,
|
|
1503
|
-
});
|
|
1504
|
-
}
|
|
1505
|
-
} catch (error) {
|
|
1506
|
-
// Ignore localStorage errors - just use default provider
|
|
1507
|
-
console.error("Failed to restore provider preference:", error);
|
|
1508
|
-
}
|
|
1509
|
-
}*/
|
|
1510
1685
|
};
|
|
1511
1686
|
|
|
1512
1687
|
// src/waitForPhantomExtension.ts
|
|
1513
|
-
import { isPhantomExtensionInstalled } from "@phantom/browser-injected-sdk";
|
|
1688
|
+
import { isPhantomExtensionInstalled as isPhantomExtensionInstalled2 } from "@phantom/browser-injected-sdk";
|
|
1514
1689
|
async function waitForPhantomExtension(timeoutMs = 3e3) {
|
|
1515
1690
|
return new Promise((resolve) => {
|
|
1516
1691
|
const startTime = Date.now();
|
|
1517
1692
|
const checkInterval = 100;
|
|
1518
1693
|
const checkForExtension = () => {
|
|
1519
1694
|
try {
|
|
1520
|
-
if (
|
|
1695
|
+
if (isPhantomExtensionInstalled2()) {
|
|
1521
1696
|
resolve(true);
|
|
1522
1697
|
return;
|
|
1523
1698
|
}
|
|
@@ -1589,7 +1764,6 @@ var BrowserSDK = class {
|
|
|
1589
1764
|
const result = await this.providerManager.connect(options);
|
|
1590
1765
|
debug.info(DebugCategory.BROWSER_SDK, "Connection successful", {
|
|
1591
1766
|
addressCount: result.addresses.length,
|
|
1592
|
-
walletId: result.walletId,
|
|
1593
1767
|
status: result.status
|
|
1594
1768
|
});
|
|
1595
1769
|
return result;
|
|
@@ -1611,22 +1785,6 @@ var BrowserSDK = class {
|
|
|
1611
1785
|
throw error;
|
|
1612
1786
|
}
|
|
1613
1787
|
}
|
|
1614
|
-
/**
|
|
1615
|
-
* Switch between provider types (injected vs embedded)
|
|
1616
|
-
*/
|
|
1617
|
-
async switchProvider(type, options) {
|
|
1618
|
-
debug.info(DebugCategory.BROWSER_SDK, "Switching provider", { type, options });
|
|
1619
|
-
try {
|
|
1620
|
-
await this.providerManager.switchProvider(type, options);
|
|
1621
|
-
debug.info(DebugCategory.BROWSER_SDK, "Provider switch successful", { type });
|
|
1622
|
-
} catch (error) {
|
|
1623
|
-
debug.error(DebugCategory.BROWSER_SDK, "Provider switch failed", {
|
|
1624
|
-
type,
|
|
1625
|
-
error: error.message
|
|
1626
|
-
});
|
|
1627
|
-
throw error;
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
1788
|
// ===== STATE QUERIES =====
|
|
1631
1789
|
/**
|
|
1632
1790
|
* Check if the SDK is connected to a wallet
|
|
@@ -1646,12 +1804,6 @@ var BrowserSDK = class {
|
|
|
1646
1804
|
getCurrentProviderInfo() {
|
|
1647
1805
|
return this.providerManager.getCurrentProviderInfo();
|
|
1648
1806
|
}
|
|
1649
|
-
/**
|
|
1650
|
-
* Get the wallet ID (for embedded wallets)
|
|
1651
|
-
*/
|
|
1652
|
-
getWalletId() {
|
|
1653
|
-
return this.providerManager.getWalletId();
|
|
1654
|
-
}
|
|
1655
1807
|
// ===== UTILITY METHODS =====
|
|
1656
1808
|
/**
|
|
1657
1809
|
* Check if Phantom extension is installed
|
|
@@ -1678,17 +1830,17 @@ var BrowserSDK = class {
|
|
|
1678
1830
|
/**
|
|
1679
1831
|
* Attempt auto-connection using existing session
|
|
1680
1832
|
* Should be called after setting up event listeners
|
|
1681
|
-
*
|
|
1833
|
+
* Tries embedded provider first, then injected provider as fallback
|
|
1682
1834
|
*/
|
|
1683
1835
|
async autoConnect() {
|
|
1684
|
-
debug.log(DebugCategory.BROWSER_SDK, "Attempting auto-connect");
|
|
1685
|
-
const
|
|
1686
|
-
if (
|
|
1687
|
-
|
|
1688
|
-
} else {
|
|
1689
|
-
debug.warn(DebugCategory.BROWSER_SDK, "Current provider does not support auto-connect", {
|
|
1836
|
+
debug.log(DebugCategory.BROWSER_SDK, "Attempting auto-connect with fallback strategy");
|
|
1837
|
+
const result = await this.providerManager.autoConnect();
|
|
1838
|
+
if (result) {
|
|
1839
|
+
debug.info(DebugCategory.BROWSER_SDK, "Auto-connect successful", {
|
|
1690
1840
|
providerType: this.getCurrentProviderInfo()?.type
|
|
1691
1841
|
});
|
|
1842
|
+
} else {
|
|
1843
|
+
debug.log(DebugCategory.BROWSER_SDK, "Auto-connect failed for all providers");
|
|
1692
1844
|
}
|
|
1693
1845
|
}
|
|
1694
1846
|
/**
|