@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.js
CHANGED
|
@@ -508,7 +508,6 @@ var InjectedProvider = class {
|
|
|
508
508
|
const result = {
|
|
509
509
|
addresses: this.addresses,
|
|
510
510
|
status: "completed"
|
|
511
|
-
// walletId is not applicable for injected providers
|
|
512
511
|
};
|
|
513
512
|
this.emit("connect", {
|
|
514
513
|
addresses: this.addresses,
|
|
@@ -902,6 +901,47 @@ var BrowserStorage = class {
|
|
|
902
901
|
};
|
|
903
902
|
});
|
|
904
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
|
+
}
|
|
905
945
|
};
|
|
906
946
|
|
|
907
947
|
// src/providers/embedded/adapters/url-params.ts
|
|
@@ -915,6 +955,147 @@ var browserUrlParamsAccessor = new BrowserURLParamsAccessor();
|
|
|
915
955
|
|
|
916
956
|
// src/providers/embedded/adapters/auth.ts
|
|
917
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
|
|
918
1099
|
var BrowserAuthProvider = class {
|
|
919
1100
|
constructor(urlParamsAccessor) {
|
|
920
1101
|
this.urlParamsAccessor = urlParamsAccessor;
|
|
@@ -936,8 +1117,7 @@ var BrowserAuthProvider = class {
|
|
|
936
1117
|
publicKey: phantomOptions.publicKey,
|
|
937
1118
|
appId: phantomOptions.appId,
|
|
938
1119
|
provider: phantomOptions.provider,
|
|
939
|
-
authUrl: phantomOptions.authUrl
|
|
940
|
-
hasCustomData: !!phantomOptions.customAuthData
|
|
1120
|
+
authUrl: phantomOptions.authUrl
|
|
941
1121
|
});
|
|
942
1122
|
const baseUrl = phantomOptions.authUrl || import_constants.DEFAULT_AUTH_URL;
|
|
943
1123
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Using auth URL", { baseUrl });
|
|
@@ -946,8 +1126,12 @@ var BrowserAuthProvider = class {
|
|
|
946
1126
|
app_id: phantomOptions.appId,
|
|
947
1127
|
redirect_uri: phantomOptions.redirectUrl || (typeof window !== "undefined" ? this.getValidatedCurrentUrl() : ""),
|
|
948
1128
|
session_id: phantomOptions.sessionId,
|
|
949
|
-
|
|
950
|
-
|
|
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
|
|
951
1135
|
});
|
|
952
1136
|
if (phantomOptions.provider) {
|
|
953
1137
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Provider specified, will skip selection", {
|
|
@@ -958,10 +1142,6 @@ var BrowserAuthProvider = class {
|
|
|
958
1142
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "No provider specified, defaulting to Google");
|
|
959
1143
|
params.append("provider", "google");
|
|
960
1144
|
}
|
|
961
|
-
if (phantomOptions.customAuthData) {
|
|
962
|
-
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Adding custom auth data");
|
|
963
|
-
params.append("authData", JSON.stringify(phantomOptions.customAuthData));
|
|
964
|
-
}
|
|
965
1145
|
const authContext = {
|
|
966
1146
|
publicKey: phantomOptions.publicKey,
|
|
967
1147
|
appId: phantomOptions.appId,
|
|
@@ -1032,12 +1212,14 @@ var BrowserAuthProvider = class {
|
|
|
1032
1212
|
});
|
|
1033
1213
|
const organizationId = this.urlParamsAccessor.getParam("organization_id");
|
|
1034
1214
|
const expiresInMs = this.urlParamsAccessor.getParam("expires_in_ms");
|
|
1215
|
+
const authUserId = this.urlParamsAccessor.getParam("auth_user_id");
|
|
1035
1216
|
debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Auth redirect parameters", {
|
|
1036
1217
|
walletId,
|
|
1037
1218
|
organizationId,
|
|
1038
1219
|
sessionId,
|
|
1039
1220
|
accountDerivationIndex,
|
|
1040
|
-
expiresInMs
|
|
1221
|
+
expiresInMs,
|
|
1222
|
+
authUserId
|
|
1041
1223
|
});
|
|
1042
1224
|
if (!organizationId) {
|
|
1043
1225
|
debug.error(DebugCategory.PHANTOM_CONNECT_AUTH, "Missing organization_id in auth response");
|
|
@@ -1051,9 +1233,9 @@ var BrowserAuthProvider = class {
|
|
|
1051
1233
|
return {
|
|
1052
1234
|
walletId,
|
|
1053
1235
|
organizationId,
|
|
1054
|
-
userInfo: context,
|
|
1055
1236
|
accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : 0,
|
|
1056
|
-
expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0
|
|
1237
|
+
expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0,
|
|
1238
|
+
authUserId: authUserId || void 0
|
|
1057
1239
|
};
|
|
1058
1240
|
} catch (error) {
|
|
1059
1241
|
sessionStorage.removeItem("phantom-auth-context");
|
|
@@ -1062,6 +1244,54 @@ var BrowserAuthProvider = class {
|
|
|
1062
1244
|
}
|
|
1063
1245
|
};
|
|
1064
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
|
+
|
|
1065
1295
|
// src/providers/embedded/adapters/logger.ts
|
|
1066
1296
|
var BrowserLogger = class {
|
|
1067
1297
|
info(category, message, data) {
|
|
@@ -1078,145 +1308,6 @@ var BrowserLogger = class {
|
|
|
1078
1308
|
}
|
|
1079
1309
|
};
|
|
1080
1310
|
|
|
1081
|
-
// src/utils/browser-detection.ts
|
|
1082
|
-
function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
|
|
1083
|
-
let name = "unknown";
|
|
1084
|
-
let version = "unknown";
|
|
1085
|
-
if (!userAgent || typeof userAgent !== "string") {
|
|
1086
|
-
return { name, version, userAgent: "unknown" };
|
|
1087
|
-
}
|
|
1088
|
-
try {
|
|
1089
|
-
if (userAgent.includes("Edg/")) {
|
|
1090
|
-
name = "edge";
|
|
1091
|
-
const match = userAgent.match(/Edg\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1092
|
-
if (match)
|
|
1093
|
-
version = match[1].split(".")[0];
|
|
1094
|
-
} else if (userAgent.includes("OPR/") || userAgent.includes("Opera/")) {
|
|
1095
|
-
name = "opera";
|
|
1096
|
-
const match = userAgent.match(/(?:OPR|Opera)\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1097
|
-
if (match)
|
|
1098
|
-
version = match[1].split(".")[0];
|
|
1099
|
-
} else if (userAgent.includes("SamsungBrowser/")) {
|
|
1100
|
-
name = "samsung";
|
|
1101
|
-
const match = userAgent.match(/SamsungBrowser\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1102
|
-
if (match)
|
|
1103
|
-
version = match[1].split(".")[0];
|
|
1104
|
-
} else if (userAgent.includes("DuckDuckGo/")) {
|
|
1105
|
-
name = "duckduckgo";
|
|
1106
|
-
const match = userAgent.match(/DuckDuckGo\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1107
|
-
if (match)
|
|
1108
|
-
version = match[1].split(".")[0];
|
|
1109
|
-
} else if (userAgent.includes("Chrome/") && hasBraveAPI) {
|
|
1110
|
-
name = "brave";
|
|
1111
|
-
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1112
|
-
if (match)
|
|
1113
|
-
version = match[1].split(".")[0];
|
|
1114
|
-
} else if (userAgent.includes("Mobile/") || userAgent.includes("Android")) {
|
|
1115
|
-
if (userAgent.includes("Chrome/")) {
|
|
1116
|
-
name = "chrome-mobile";
|
|
1117
|
-
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1118
|
-
if (match)
|
|
1119
|
-
version = match[1].split(".")[0];
|
|
1120
|
-
} else if (userAgent.includes("Firefox/")) {
|
|
1121
|
-
name = "firefox-mobile";
|
|
1122
|
-
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1123
|
-
if (match)
|
|
1124
|
-
version = match[1].split(".")[0];
|
|
1125
|
-
} else if (userAgent.includes("Safari/") && userAgent.includes("Mobile/")) {
|
|
1126
|
-
name = "safari-mobile";
|
|
1127
|
-
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1128
|
-
if (match)
|
|
1129
|
-
version = match[1].split(".")[0];
|
|
1130
|
-
} else {
|
|
1131
|
-
name = "mobile";
|
|
1132
|
-
}
|
|
1133
|
-
} else if (userAgent.includes("Chrome/")) {
|
|
1134
|
-
name = "chrome";
|
|
1135
|
-
const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1136
|
-
if (match)
|
|
1137
|
-
version = match[1].split(".")[0];
|
|
1138
|
-
} else if (userAgent.includes("Firefox/")) {
|
|
1139
|
-
name = "firefox";
|
|
1140
|
-
const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1141
|
-
if (match)
|
|
1142
|
-
version = match[1].split(".")[0];
|
|
1143
|
-
} else if (userAgent.includes("Safari/") && !userAgent.includes("Chrome/")) {
|
|
1144
|
-
name = "safari";
|
|
1145
|
-
const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
|
|
1146
|
-
if (match)
|
|
1147
|
-
version = match[1].split(".")[0];
|
|
1148
|
-
}
|
|
1149
|
-
if (name === "unknown") {
|
|
1150
|
-
const patterns = [
|
|
1151
|
-
{ regex: /Chrome\/([0-9]+)/, name: "chrome" },
|
|
1152
|
-
{ regex: /Firefox\/([0-9]+)/, name: "firefox" },
|
|
1153
|
-
{ regex: /Safari\/([0-9]+)/, name: "safari" },
|
|
1154
|
-
{ regex: /Edge\/([0-9]+)/, name: "edge" },
|
|
1155
|
-
{ regex: /Opera\/([0-9]+)/, name: "opera" }
|
|
1156
|
-
];
|
|
1157
|
-
for (const pattern of patterns) {
|
|
1158
|
-
const match = userAgent.match(pattern.regex);
|
|
1159
|
-
if (match) {
|
|
1160
|
-
name = pattern.name;
|
|
1161
|
-
version = match[1];
|
|
1162
|
-
break;
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
}
|
|
1166
|
-
} catch (error) {
|
|
1167
|
-
}
|
|
1168
|
-
return { name, version, userAgent };
|
|
1169
|
-
}
|
|
1170
|
-
function detectBrowser() {
|
|
1171
|
-
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
1172
|
-
return { name: "unknown", version: "unknown", userAgent: "unknown" };
|
|
1173
|
-
}
|
|
1174
|
-
const userAgent = window.navigator.userAgent;
|
|
1175
|
-
const hasBraveAPI = !!navigator.brave;
|
|
1176
|
-
return parseBrowserFromUserAgent(userAgent, hasBraveAPI);
|
|
1177
|
-
}
|
|
1178
|
-
function getPlatformName() {
|
|
1179
|
-
const { name, version } = detectBrowser();
|
|
1180
|
-
return version !== "unknown" ? `${name}-v${version}` : name;
|
|
1181
|
-
}
|
|
1182
|
-
function getBrowserDisplayName() {
|
|
1183
|
-
const { name, version } = detectBrowser();
|
|
1184
|
-
const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
1185
|
-
return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
|
|
1186
|
-
}
|
|
1187
|
-
function isMobileDevice() {
|
|
1188
|
-
if (typeof window === "undefined" || !window.navigator?.userAgent) {
|
|
1189
|
-
return false;
|
|
1190
|
-
}
|
|
1191
|
-
const userAgent = window.navigator.userAgent.toLowerCase();
|
|
1192
|
-
const mobilePatterns = [
|
|
1193
|
-
/android/,
|
|
1194
|
-
/iphone|ipad|ipod/,
|
|
1195
|
-
/blackberry/,
|
|
1196
|
-
/windows phone/,
|
|
1197
|
-
/mobile/,
|
|
1198
|
-
/tablet/,
|
|
1199
|
-
/silk/,
|
|
1200
|
-
/kindle/,
|
|
1201
|
-
/opera mini/,
|
|
1202
|
-
/opera mobi/
|
|
1203
|
-
];
|
|
1204
|
-
const isMobileUA = mobilePatterns.some((pattern) => pattern.test(userAgent));
|
|
1205
|
-
let isSmallScreen = false;
|
|
1206
|
-
try {
|
|
1207
|
-
isSmallScreen = window.screen.width <= 768 || window.screen.height <= 768;
|
|
1208
|
-
} catch (error) {
|
|
1209
|
-
isSmallScreen = false;
|
|
1210
|
-
}
|
|
1211
|
-
let isTouchDevice = false;
|
|
1212
|
-
try {
|
|
1213
|
-
isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
|
|
1214
|
-
} catch (error) {
|
|
1215
|
-
isTouchDevice = false;
|
|
1216
|
-
}
|
|
1217
|
-
return isMobileUA || isSmallScreen && isTouchDevice;
|
|
1218
|
-
}
|
|
1219
|
-
|
|
1220
1311
|
// src/providers/embedded/index.ts
|
|
1221
1312
|
var import_constants2 = require("@phantom/constants");
|
|
1222
1313
|
var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvider {
|
|
@@ -1233,6 +1324,7 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
|
|
|
1233
1324
|
const platform = {
|
|
1234
1325
|
storage: new BrowserStorage(),
|
|
1235
1326
|
authProvider: new BrowserAuthProvider(urlParamsAccessor),
|
|
1327
|
+
phantomAppProvider: new BrowserPhantomAppProvider(),
|
|
1236
1328
|
urlParamsAccessor,
|
|
1237
1329
|
stamper,
|
|
1238
1330
|
name: platformName,
|
|
@@ -1245,7 +1337,7 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
|
|
|
1245
1337
|
// Full user agent for more detailed info
|
|
1246
1338
|
[import_constants2.ANALYTICS_HEADERS.APP_ID]: config.appId,
|
|
1247
1339
|
[import_constants2.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
|
|
1248
|
-
[import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.
|
|
1340
|
+
[import_constants2.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.15"
|
|
1249
1341
|
// Replaced at build time
|
|
1250
1342
|
}
|
|
1251
1343
|
};
|
|
@@ -1258,13 +1350,31 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
|
|
|
1258
1350
|
|
|
1259
1351
|
// src/ProviderManager.ts
|
|
1260
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
|
|
1261
1372
|
var ProviderManager = class {
|
|
1262
1373
|
// Track which providers have forwarding set up
|
|
1263
1374
|
constructor(config) {
|
|
1264
1375
|
this.providers = /* @__PURE__ */ new Map();
|
|
1265
1376
|
this.currentProvider = null;
|
|
1266
1377
|
this.currentProviderKey = null;
|
|
1267
|
-
this.walletId = null;
|
|
1268
1378
|
// Event management for forwarding provider events
|
|
1269
1379
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
1270
1380
|
this.providerForwardingSetup = /* @__PURE__ */ new WeakSet();
|
|
@@ -1300,7 +1410,6 @@ var ProviderManager = class {
|
|
|
1300
1410
|
}
|
|
1301
1411
|
this.currentProvider = this.providers.get(key);
|
|
1302
1412
|
this.currentProviderKey = key;
|
|
1303
|
-
this.walletId = null;
|
|
1304
1413
|
this.ensureProviderEventForwarding();
|
|
1305
1414
|
return this.currentProvider;
|
|
1306
1415
|
}
|
|
@@ -1325,26 +1434,46 @@ var ProviderManager = class {
|
|
|
1325
1434
|
}
|
|
1326
1435
|
/**
|
|
1327
1436
|
* Connect using the current provider
|
|
1437
|
+
* Automatically switches provider based on authOptions.provider if specified
|
|
1328
1438
|
*/
|
|
1329
1439
|
async connect(authOptions) {
|
|
1330
1440
|
debug.info(DebugCategory.PROVIDER_MANAGER, "Starting connection", {
|
|
1331
1441
|
currentProviderKey: this.currentProviderKey,
|
|
1332
1442
|
authOptions: authOptions ? { provider: authOptions.provider, hasJwtToken: !!authOptions.jwtToken } : void 0
|
|
1333
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
|
+
}
|
|
1334
1466
|
if (!this.currentProvider) {
|
|
1335
1467
|
debug.error(DebugCategory.PROVIDER_MANAGER, "No provider selected");
|
|
1336
1468
|
throw new Error("No provider selected");
|
|
1337
1469
|
}
|
|
1338
1470
|
debug.log(DebugCategory.PROVIDER_MANAGER, "Delegating to provider connect method");
|
|
1339
1471
|
const result = await this.currentProvider.connect(authOptions);
|
|
1340
|
-
this.walletId = result.walletId || null;
|
|
1341
1472
|
debug.log(DebugCategory.PROVIDER_MANAGER, "Connection successful, saving preferences", {
|
|
1342
|
-
walletId: this.walletId,
|
|
1343
1473
|
addressCount: result.addresses?.length || 0
|
|
1344
1474
|
});
|
|
1345
1475
|
this.saveProviderPreference();
|
|
1346
1476
|
debug.info(DebugCategory.PROVIDER_MANAGER, "Connect completed", {
|
|
1347
|
-
walletId: this.walletId,
|
|
1348
1477
|
addresses: result.addresses
|
|
1349
1478
|
});
|
|
1350
1479
|
return result;
|
|
@@ -1356,7 +1485,6 @@ var ProviderManager = class {
|
|
|
1356
1485
|
if (!this.currentProvider)
|
|
1357
1486
|
return;
|
|
1358
1487
|
await this.currentProvider.disconnect();
|
|
1359
|
-
this.walletId = null;
|
|
1360
1488
|
}
|
|
1361
1489
|
/**
|
|
1362
1490
|
* Get addresses from current provider
|
|
@@ -1374,10 +1502,69 @@ var ProviderManager = class {
|
|
|
1374
1502
|
return this.currentProvider?.isConnected() ?? false;
|
|
1375
1503
|
}
|
|
1376
1504
|
/**
|
|
1377
|
-
*
|
|
1505
|
+
* Attempt auto-connect with fallback strategy
|
|
1506
|
+
* Tries embedded provider first if it exists, then injected provider
|
|
1507
|
+
* Returns true if any provider successfully connected
|
|
1378
1508
|
*/
|
|
1379
|
-
|
|
1380
|
-
|
|
1509
|
+
async autoConnect() {
|
|
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
|
+
}
|
|
1515
|
+
const embeddedWalletType = this.config.embeddedWalletType || "user-wallet";
|
|
1516
|
+
const embeddedKey = this.getProviderKey("embedded", embeddedWalletType);
|
|
1517
|
+
if (this.providers.has(embeddedKey)) {
|
|
1518
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Trying auto-connect with existing embedded provider");
|
|
1519
|
+
const embeddedProvider = this.providers.get(embeddedKey);
|
|
1520
|
+
try {
|
|
1521
|
+
const previousProvider = this.currentProvider;
|
|
1522
|
+
const previousKey = this.currentProviderKey;
|
|
1523
|
+
this.currentProvider = embeddedProvider;
|
|
1524
|
+
this.currentProviderKey = embeddedKey;
|
|
1525
|
+
this.ensureProviderEventForwarding();
|
|
1526
|
+
await embeddedProvider.autoConnect();
|
|
1527
|
+
if (embeddedProvider.isConnected()) {
|
|
1528
|
+
debug.info(DebugCategory.PROVIDER_MANAGER, "Embedded auto-connect successful");
|
|
1529
|
+
this.saveProviderPreference();
|
|
1530
|
+
return true;
|
|
1531
|
+
} else {
|
|
1532
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Embedded provider did not connect, restoring previous provider");
|
|
1533
|
+
this.currentProvider = previousProvider;
|
|
1534
|
+
this.currentProviderKey = previousKey;
|
|
1535
|
+
}
|
|
1536
|
+
} catch (error) {
|
|
1537
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Embedded auto-connect failed", {
|
|
1538
|
+
error: error.message
|
|
1539
|
+
});
|
|
1540
|
+
if (isAuthCallbackUrl()) {
|
|
1541
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "In auth callback URL, not attempting injected fallback");
|
|
1542
|
+
return false;
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
const injectedKey = this.getProviderKey("injected");
|
|
1547
|
+
if (this.providers.has(injectedKey)) {
|
|
1548
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Trying auto-connect with existing injected provider");
|
|
1549
|
+
const injectedProvider = this.providers.get(injectedKey);
|
|
1550
|
+
try {
|
|
1551
|
+
this.currentProvider = injectedProvider;
|
|
1552
|
+
this.currentProviderKey = injectedKey;
|
|
1553
|
+
this.ensureProviderEventForwarding();
|
|
1554
|
+
await injectedProvider.autoConnect();
|
|
1555
|
+
if (injectedProvider.isConnected()) {
|
|
1556
|
+
debug.info(DebugCategory.PROVIDER_MANAGER, "Injected auto-connect successful");
|
|
1557
|
+
this.saveProviderPreference();
|
|
1558
|
+
return true;
|
|
1559
|
+
}
|
|
1560
|
+
} catch (error) {
|
|
1561
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Injected auto-connect failed", {
|
|
1562
|
+
error: error.message
|
|
1563
|
+
});
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Auto-connect failed for all existing providers");
|
|
1567
|
+
return false;
|
|
1381
1568
|
}
|
|
1382
1569
|
/**
|
|
1383
1570
|
* Add event listener - stores callback and ensures current provider forwards events to ProviderManager
|
|
@@ -1460,11 +1647,17 @@ var ProviderManager = class {
|
|
|
1460
1647
|
}
|
|
1461
1648
|
/**
|
|
1462
1649
|
* Set default provider based on initial config
|
|
1650
|
+
* Creates both embedded and injected providers for autoConnect fallback
|
|
1463
1651
|
*/
|
|
1464
1652
|
setDefaultProvider() {
|
|
1465
1653
|
const defaultType = this.config.providerType || "embedded";
|
|
1466
1654
|
const defaultEmbeddedType = this.config.embeddedWalletType || "user-wallet";
|
|
1467
|
-
this.
|
|
1655
|
+
if (this.config.appId) {
|
|
1656
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Creating embedded provider");
|
|
1657
|
+
this.createProvider("embedded", defaultEmbeddedType);
|
|
1658
|
+
}
|
|
1659
|
+
debug.log(DebugCategory.PROVIDER_MANAGER, "Creating injected provider");
|
|
1660
|
+
this.createProvider("injected");
|
|
1468
1661
|
this.switchProvider(defaultType, { embeddedWalletType: defaultEmbeddedType });
|
|
1469
1662
|
}
|
|
1470
1663
|
/**
|
|
@@ -1525,35 +1718,17 @@ var ProviderManager = class {
|
|
|
1525
1718
|
console.error("Failed to save provider preference:", error);
|
|
1526
1719
|
}
|
|
1527
1720
|
}
|
|
1528
|
-
/**
|
|
1529
|
-
* Restore provider preference from localStorage
|
|
1530
|
-
*/
|
|
1531
|
-
/*
|
|
1532
|
-
private restoreProviderPreference(): void {
|
|
1533
|
-
try {
|
|
1534
|
-
const saved = localStorage.getItem("phantom-provider-preference");
|
|
1535
|
-
if (saved) {
|
|
1536
|
-
const preference: ProviderPreference = JSON.parse(saved);
|
|
1537
|
-
this.switchProvider(preference.type, {
|
|
1538
|
-
embeddedWalletType: preference.embeddedWalletType,
|
|
1539
|
-
});
|
|
1540
|
-
}
|
|
1541
|
-
} catch (error) {
|
|
1542
|
-
// Ignore localStorage errors - just use default provider
|
|
1543
|
-
console.error("Failed to restore provider preference:", error);
|
|
1544
|
-
}
|
|
1545
|
-
}*/
|
|
1546
1721
|
};
|
|
1547
1722
|
|
|
1548
1723
|
// src/waitForPhantomExtension.ts
|
|
1549
|
-
var
|
|
1724
|
+
var import_browser_injected_sdk3 = require("@phantom/browser-injected-sdk");
|
|
1550
1725
|
async function waitForPhantomExtension(timeoutMs = 3e3) {
|
|
1551
1726
|
return new Promise((resolve) => {
|
|
1552
1727
|
const startTime = Date.now();
|
|
1553
1728
|
const checkInterval = 100;
|
|
1554
1729
|
const checkForExtension = () => {
|
|
1555
1730
|
try {
|
|
1556
|
-
if ((0,
|
|
1731
|
+
if ((0, import_browser_injected_sdk3.isPhantomExtensionInstalled)()) {
|
|
1557
1732
|
resolve(true);
|
|
1558
1733
|
return;
|
|
1559
1734
|
}
|
|
@@ -1625,7 +1800,6 @@ var BrowserSDK = class {
|
|
|
1625
1800
|
const result = await this.providerManager.connect(options);
|
|
1626
1801
|
debug.info(DebugCategory.BROWSER_SDK, "Connection successful", {
|
|
1627
1802
|
addressCount: result.addresses.length,
|
|
1628
|
-
walletId: result.walletId,
|
|
1629
1803
|
status: result.status
|
|
1630
1804
|
});
|
|
1631
1805
|
return result;
|
|
@@ -1647,22 +1821,6 @@ var BrowserSDK = class {
|
|
|
1647
1821
|
throw error;
|
|
1648
1822
|
}
|
|
1649
1823
|
}
|
|
1650
|
-
/**
|
|
1651
|
-
* Switch between provider types (injected vs embedded)
|
|
1652
|
-
*/
|
|
1653
|
-
async switchProvider(type, options) {
|
|
1654
|
-
debug.info(DebugCategory.BROWSER_SDK, "Switching provider", { type, options });
|
|
1655
|
-
try {
|
|
1656
|
-
await this.providerManager.switchProvider(type, options);
|
|
1657
|
-
debug.info(DebugCategory.BROWSER_SDK, "Provider switch successful", { type });
|
|
1658
|
-
} catch (error) {
|
|
1659
|
-
debug.error(DebugCategory.BROWSER_SDK, "Provider switch failed", {
|
|
1660
|
-
type,
|
|
1661
|
-
error: error.message
|
|
1662
|
-
});
|
|
1663
|
-
throw error;
|
|
1664
|
-
}
|
|
1665
|
-
}
|
|
1666
1824
|
// ===== STATE QUERIES =====
|
|
1667
1825
|
/**
|
|
1668
1826
|
* Check if the SDK is connected to a wallet
|
|
@@ -1682,12 +1840,6 @@ var BrowserSDK = class {
|
|
|
1682
1840
|
getCurrentProviderInfo() {
|
|
1683
1841
|
return this.providerManager.getCurrentProviderInfo();
|
|
1684
1842
|
}
|
|
1685
|
-
/**
|
|
1686
|
-
* Get the wallet ID (for embedded wallets)
|
|
1687
|
-
*/
|
|
1688
|
-
getWalletId() {
|
|
1689
|
-
return this.providerManager.getWalletId();
|
|
1690
|
-
}
|
|
1691
1843
|
// ===== UTILITY METHODS =====
|
|
1692
1844
|
/**
|
|
1693
1845
|
* Check if Phantom extension is installed
|
|
@@ -1714,17 +1866,17 @@ var BrowserSDK = class {
|
|
|
1714
1866
|
/**
|
|
1715
1867
|
* Attempt auto-connection using existing session
|
|
1716
1868
|
* Should be called after setting up event listeners
|
|
1717
|
-
*
|
|
1869
|
+
* Tries embedded provider first, then injected provider as fallback
|
|
1718
1870
|
*/
|
|
1719
1871
|
async autoConnect() {
|
|
1720
|
-
debug.log(DebugCategory.BROWSER_SDK, "Attempting auto-connect");
|
|
1721
|
-
const
|
|
1722
|
-
if (
|
|
1723
|
-
|
|
1724
|
-
} else {
|
|
1725
|
-
debug.warn(DebugCategory.BROWSER_SDK, "Current provider does not support auto-connect", {
|
|
1872
|
+
debug.log(DebugCategory.BROWSER_SDK, "Attempting auto-connect with fallback strategy");
|
|
1873
|
+
const result = await this.providerManager.autoConnect();
|
|
1874
|
+
if (result) {
|
|
1875
|
+
debug.info(DebugCategory.BROWSER_SDK, "Auto-connect successful", {
|
|
1726
1876
|
providerType: this.getCurrentProviderInfo()?.type
|
|
1727
1877
|
});
|
|
1878
|
+
} else {
|
|
1879
|
+
debug.log(DebugCategory.BROWSER_SDK, "Auto-connect failed for all providers");
|
|
1728
1880
|
}
|
|
1729
1881
|
}
|
|
1730
1882
|
/**
|