@phantom/browser-sdk 1.0.0-beta.14 → 1.0.0-beta.16

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/dist/index.mjs CHANGED
@@ -440,7 +440,12 @@ var InjectedProvider = class {
440
440
  debug.info(DebugCategory.INJECTED_PROVIDER, "Solana connected successfully", { address: publicKey });
441
441
  }
442
442
  } catch (err) {
443
- debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana", { error: err });
443
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Solana, stopping", { error: err });
444
+ this.emit("connect_error", {
445
+ error: err instanceof Error ? err.message : "Failed to connect",
446
+ source: "manual-connect"
447
+ });
448
+ throw err;
444
449
  }
445
450
  }
446
451
  if (this.addressTypes.includes(AddressType4.ethereum)) {
@@ -456,7 +461,12 @@ var InjectedProvider = class {
456
461
  debug.info(DebugCategory.INJECTED_PROVIDER, "Ethereum connected successfully", { addresses: accounts });
457
462
  }
458
463
  } catch (err) {
459
- debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum", { error: err });
464
+ debug.warn(DebugCategory.INJECTED_PROVIDER, "Failed to connect Ethereum, stopping", { error: err });
465
+ this.emit("connect_error", {
466
+ error: err instanceof Error ? err.message : "Failed to connect",
467
+ source: "manual-connect"
468
+ });
469
+ throw err;
460
470
  }
461
471
  }
462
472
  if (connectedAddresses.length === 0) {
@@ -865,6 +875,47 @@ var BrowserStorage = class {
865
875
  };
866
876
  });
867
877
  }
878
+ async getShouldClearPreviousSession() {
879
+ debug.log(DebugCategory.STORAGE, "Getting shouldClearPreviousSession flag from IndexedDB");
880
+ const db = await this.getDB();
881
+ return new Promise((resolve, reject) => {
882
+ const transaction = db.transaction([this.storeName], "readonly");
883
+ const store = transaction.objectStore(this.storeName);
884
+ const request = store.get("shouldClearPreviousSession");
885
+ request.onsuccess = () => {
886
+ const shouldClear = request.result ?? false;
887
+ debug.log(DebugCategory.STORAGE, "Retrieved shouldClearPreviousSession flag from IndexedDB", {
888
+ shouldClear
889
+ });
890
+ resolve(shouldClear);
891
+ };
892
+ request.onerror = () => {
893
+ debug.error(DebugCategory.STORAGE, "Failed to get shouldClearPreviousSession flag from IndexedDB", {
894
+ error: request.error
895
+ });
896
+ reject(request.error);
897
+ };
898
+ });
899
+ }
900
+ async setShouldClearPreviousSession(should) {
901
+ debug.log(DebugCategory.STORAGE, "Setting shouldClearPreviousSession flag in IndexedDB", { should });
902
+ const db = await this.getDB();
903
+ return new Promise((resolve, reject) => {
904
+ const transaction = db.transaction([this.storeName], "readwrite");
905
+ const store = transaction.objectStore(this.storeName);
906
+ const request = store.put(should, "shouldClearPreviousSession");
907
+ request.onsuccess = () => {
908
+ debug.log(DebugCategory.STORAGE, "Successfully set shouldClearPreviousSession flag in IndexedDB");
909
+ resolve();
910
+ };
911
+ request.onerror = () => {
912
+ debug.error(DebugCategory.STORAGE, "Failed to set shouldClearPreviousSession flag in IndexedDB", {
913
+ error: request.error
914
+ });
915
+ reject(request.error);
916
+ };
917
+ });
918
+ }
868
919
  };
869
920
 
870
921
  // src/providers/embedded/adapters/url-params.ts
@@ -878,6 +929,147 @@ var browserUrlParamsAccessor = new BrowserURLParamsAccessor();
878
929
 
879
930
  // src/providers/embedded/adapters/auth.ts
880
931
  import { DEFAULT_AUTH_URL } from "@phantom/constants";
932
+
933
+ // src/utils/browser-detection.ts
934
+ function parseBrowserFromUserAgent(userAgent, hasBraveAPI) {
935
+ let name = "unknown";
936
+ let version = "unknown";
937
+ if (!userAgent || typeof userAgent !== "string") {
938
+ return { name, version, userAgent: "unknown" };
939
+ }
940
+ try {
941
+ if (userAgent.includes("Edg/")) {
942
+ name = "edge";
943
+ const match = userAgent.match(/Edg\/([0-9]+(?:\.[0-9]+)*)/);
944
+ if (match)
945
+ version = match[1].split(".")[0];
946
+ } else if (userAgent.includes("OPR/") || userAgent.includes("Opera/")) {
947
+ name = "opera";
948
+ const match = userAgent.match(/(?:OPR|Opera)\/([0-9]+(?:\.[0-9]+)*)/);
949
+ if (match)
950
+ version = match[1].split(".")[0];
951
+ } else if (userAgent.includes("SamsungBrowser/")) {
952
+ name = "samsung";
953
+ const match = userAgent.match(/SamsungBrowser\/([0-9]+(?:\.[0-9]+)*)/);
954
+ if (match)
955
+ version = match[1].split(".")[0];
956
+ } else if (userAgent.includes("DuckDuckGo/")) {
957
+ name = "duckduckgo";
958
+ const match = userAgent.match(/DuckDuckGo\/([0-9]+(?:\.[0-9]+)*)/);
959
+ if (match)
960
+ version = match[1].split(".")[0];
961
+ } else if (userAgent.includes("Chrome/") && hasBraveAPI) {
962
+ name = "brave";
963
+ const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
964
+ if (match)
965
+ version = match[1].split(".")[0];
966
+ } else if (userAgent.includes("Mobile/") || userAgent.includes("Android")) {
967
+ if (userAgent.includes("Chrome/")) {
968
+ name = "chrome-mobile";
969
+ const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
970
+ if (match)
971
+ version = match[1].split(".")[0];
972
+ } else if (userAgent.includes("Firefox/")) {
973
+ name = "firefox-mobile";
974
+ const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
975
+ if (match)
976
+ version = match[1].split(".")[0];
977
+ } else if (userAgent.includes("Safari/") && userAgent.includes("Mobile/")) {
978
+ name = "safari-mobile";
979
+ const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
980
+ if (match)
981
+ version = match[1].split(".")[0];
982
+ } else {
983
+ name = "mobile";
984
+ }
985
+ } else if (userAgent.includes("Chrome/")) {
986
+ name = "chrome";
987
+ const match = userAgent.match(/Chrome\/([0-9]+(?:\.[0-9]+)*)/);
988
+ if (match)
989
+ version = match[1].split(".")[0];
990
+ } else if (userAgent.includes("Firefox/")) {
991
+ name = "firefox";
992
+ const match = userAgent.match(/Firefox\/([0-9]+(?:\.[0-9]+)*)/);
993
+ if (match)
994
+ version = match[1].split(".")[0];
995
+ } else if (userAgent.includes("Safari/") && !userAgent.includes("Chrome/")) {
996
+ name = "safari";
997
+ const match = userAgent.match(/Version\/([0-9]+(?:\.[0-9]+)*)/);
998
+ if (match)
999
+ version = match[1].split(".")[0];
1000
+ }
1001
+ if (name === "unknown") {
1002
+ const patterns = [
1003
+ { regex: /Chrome\/([0-9]+)/, name: "chrome" },
1004
+ { regex: /Firefox\/([0-9]+)/, name: "firefox" },
1005
+ { regex: /Safari\/([0-9]+)/, name: "safari" },
1006
+ { regex: /Edge\/([0-9]+)/, name: "edge" },
1007
+ { regex: /Opera\/([0-9]+)/, name: "opera" }
1008
+ ];
1009
+ for (const pattern of patterns) {
1010
+ const match = userAgent.match(pattern.regex);
1011
+ if (match) {
1012
+ name = pattern.name;
1013
+ version = match[1];
1014
+ break;
1015
+ }
1016
+ }
1017
+ }
1018
+ } catch (error) {
1019
+ }
1020
+ return { name, version, userAgent };
1021
+ }
1022
+ function detectBrowser() {
1023
+ if (typeof window === "undefined" || !window.navigator?.userAgent) {
1024
+ return { name: "unknown", version: "unknown", userAgent: "unknown" };
1025
+ }
1026
+ const userAgent = window.navigator.userAgent;
1027
+ const hasBraveAPI = !!navigator.brave;
1028
+ return parseBrowserFromUserAgent(userAgent, hasBraveAPI);
1029
+ }
1030
+ function getPlatformName() {
1031
+ const { name, version } = detectBrowser();
1032
+ return version !== "unknown" ? `${name}-v${version}` : name;
1033
+ }
1034
+ function getBrowserDisplayName() {
1035
+ const { name, version } = detectBrowser();
1036
+ const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
1037
+ return version !== "unknown" ? `${capitalizedName} ${version}` : capitalizedName;
1038
+ }
1039
+ function isMobileDevice() {
1040
+ if (typeof window === "undefined" || !window.navigator?.userAgent) {
1041
+ return false;
1042
+ }
1043
+ const userAgent = window.navigator.userAgent.toLowerCase();
1044
+ const mobilePatterns = [
1045
+ /android/,
1046
+ /iphone|ipad|ipod/,
1047
+ /blackberry/,
1048
+ /windows phone/,
1049
+ /mobile/,
1050
+ /tablet/,
1051
+ /silk/,
1052
+ /kindle/,
1053
+ /opera mini/,
1054
+ /opera mobi/
1055
+ ];
1056
+ const isMobileUA = mobilePatterns.some((pattern) => pattern.test(userAgent));
1057
+ let isSmallScreen = false;
1058
+ try {
1059
+ isSmallScreen = window.screen.width <= 768 || window.screen.height <= 768;
1060
+ } catch (error) {
1061
+ isSmallScreen = false;
1062
+ }
1063
+ let isTouchDevice = false;
1064
+ try {
1065
+ isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
1066
+ } catch (error) {
1067
+ isTouchDevice = false;
1068
+ }
1069
+ return isMobileUA || isSmallScreen && isTouchDevice;
1070
+ }
1071
+
1072
+ // src/providers/embedded/adapters/auth.ts
881
1073
  var BrowserAuthProvider = class {
882
1074
  constructor(urlParamsAccessor) {
883
1075
  this.urlParamsAccessor = urlParamsAccessor;
@@ -899,8 +1091,7 @@ var BrowserAuthProvider = class {
899
1091
  publicKey: phantomOptions.publicKey,
900
1092
  appId: phantomOptions.appId,
901
1093
  provider: phantomOptions.provider,
902
- authUrl: phantomOptions.authUrl,
903
- hasCustomData: !!phantomOptions.customAuthData
1094
+ authUrl: phantomOptions.authUrl
904
1095
  });
905
1096
  const baseUrl = phantomOptions.authUrl || DEFAULT_AUTH_URL;
906
1097
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Using auth URL", { baseUrl });
@@ -909,8 +1100,12 @@ var BrowserAuthProvider = class {
909
1100
  app_id: phantomOptions.appId,
910
1101
  redirect_uri: phantomOptions.redirectUrl || (typeof window !== "undefined" ? this.getValidatedCurrentUrl() : ""),
911
1102
  session_id: phantomOptions.sessionId,
912
- clear_previous_session: true.toString(),
913
- sdk_version: "1.0.0-beta.14"
1103
+ // OAuth session management - defaults to allow refresh unless explicitly clearing after logout
1104
+ clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
1105
+ allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
1106
+ sdk_version: "1.0.0-beta.16",
1107
+ sdk_type: "browser",
1108
+ platform: detectBrowser().name
914
1109
  });
915
1110
  if (phantomOptions.provider) {
916
1111
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Provider specified, will skip selection", {
@@ -921,10 +1116,6 @@ var BrowserAuthProvider = class {
921
1116
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "No provider specified, defaulting to Google");
922
1117
  params.append("provider", "google");
923
1118
  }
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
1119
  const authContext = {
929
1120
  publicKey: phantomOptions.publicKey,
930
1121
  appId: phantomOptions.appId,
@@ -995,12 +1186,14 @@ var BrowserAuthProvider = class {
995
1186
  });
996
1187
  const organizationId = this.urlParamsAccessor.getParam("organization_id");
997
1188
  const expiresInMs = this.urlParamsAccessor.getParam("expires_in_ms");
1189
+ const authUserId = this.urlParamsAccessor.getParam("auth_user_id");
998
1190
  debug.log(DebugCategory.PHANTOM_CONNECT_AUTH, "Auth redirect parameters", {
999
1191
  walletId,
1000
1192
  organizationId,
1001
1193
  sessionId,
1002
1194
  accountDerivationIndex,
1003
- expiresInMs
1195
+ expiresInMs,
1196
+ authUserId
1004
1197
  });
1005
1198
  if (!organizationId) {
1006
1199
  debug.error(DebugCategory.PHANTOM_CONNECT_AUTH, "Missing organization_id in auth response");
@@ -1014,9 +1207,9 @@ var BrowserAuthProvider = class {
1014
1207
  return {
1015
1208
  walletId,
1016
1209
  organizationId,
1017
- userInfo: context,
1018
1210
  accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : 0,
1019
- expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0
1211
+ expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0,
1212
+ authUserId: authUserId || void 0
1020
1213
  };
1021
1214
  } catch (error) {
1022
1215
  sessionStorage.removeItem("phantom-auth-context");
@@ -1025,6 +1218,74 @@ var BrowserAuthProvider = class {
1025
1218
  }
1026
1219
  };
1027
1220
 
1221
+ // src/providers/embedded/adapters/phantom-app.ts
1222
+ import { isPhantomExtensionInstalled } from "@phantom/browser-injected-sdk";
1223
+ var BrowserPhantomAppProvider = class {
1224
+ /**
1225
+ * Check if the Phantom extension is installed in the browser
1226
+ */
1227
+ isAvailable() {
1228
+ return isPhantomExtensionInstalled();
1229
+ }
1230
+ /**
1231
+ * Authenticate using the Phantom browser extension
1232
+ */
1233
+ async authenticate(options) {
1234
+ if (!this.isAvailable()) {
1235
+ throw new Error(
1236
+ "Phantom extension is not installed. Please install the Phantom browser extension to use this authentication method."
1237
+ );
1238
+ }
1239
+ if (!window.phantom?.app?.login || typeof window.phantom.app.login !== "function") {
1240
+ throw new Error(
1241
+ "Phantom extension authentication is not yet implemented. The extension needs to expose an app.login API (window.phantom.app.login)."
1242
+ );
1243
+ }
1244
+ try {
1245
+ if (!window.phantom?.app?.features || typeof window.phantom.app.features !== "function") {
1246
+ throw new Error(
1247
+ "Phantom Login is not available. The extension does not support the features API."
1248
+ );
1249
+ }
1250
+ const features = await window.phantom.app.features();
1251
+ if (!Array.isArray(features) || !features.includes("phantom_login")) {
1252
+ throw new Error(
1253
+ "Phantom Login is not available. Please update your Phantom extension to use this authentication method."
1254
+ );
1255
+ }
1256
+ } catch (error) {
1257
+ if (error instanceof Error) {
1258
+ throw error;
1259
+ }
1260
+ throw new Error(
1261
+ "Failed to check Phantom Login availability. Please ensure you have the latest version of the Phantom extension."
1262
+ );
1263
+ }
1264
+ try {
1265
+ const result = await window.phantom.app.login({
1266
+ publicKey: options.publicKey,
1267
+ appId: options.appId,
1268
+ sessionId: options.sessionId
1269
+ });
1270
+ if (!result || !result.walletId || !result.organizationId) {
1271
+ throw new Error("Invalid authentication response from Phantom extension");
1272
+ }
1273
+ return {
1274
+ walletId: result.walletId,
1275
+ organizationId: result.organizationId,
1276
+ provider: "phantom",
1277
+ accountDerivationIndex: result.accountDerivationIndex ?? 0,
1278
+ expiresInMs: result.expiresInMs ?? 0
1279
+ };
1280
+ } catch (error) {
1281
+ if (error instanceof Error) {
1282
+ throw error;
1283
+ }
1284
+ throw new Error(`Phantom extension authentication failed: ${String(error)}`);
1285
+ }
1286
+ }
1287
+ };
1288
+
1028
1289
  // src/providers/embedded/adapters/logger.ts
1029
1290
  var BrowserLogger = class {
1030
1291
  info(category, message, data) {
@@ -1041,145 +1302,6 @@ var BrowserLogger = class {
1041
1302
  }
1042
1303
  };
1043
1304
 
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
1305
  // src/providers/embedded/index.ts
1184
1306
  import { ANALYTICS_HEADERS } from "@phantom/constants";
1185
1307
  var EmbeddedProvider = class extends CoreEmbeddedProvider {
@@ -1196,6 +1318,7 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
1196
1318
  const platform = {
1197
1319
  storage: new BrowserStorage(),
1198
1320
  authProvider: new BrowserAuthProvider(urlParamsAccessor),
1321
+ phantomAppProvider: new BrowserPhantomAppProvider(),
1199
1322
  urlParamsAccessor,
1200
1323
  stamper,
1201
1324
  name: platformName,
@@ -1208,7 +1331,7 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
1208
1331
  // Full user agent for more detailed info
1209
1332
  [ANALYTICS_HEADERS.APP_ID]: config.appId,
1210
1333
  [ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
1211
- [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.14"
1334
+ [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.0-beta.16"
1212
1335
  // Replaced at build time
1213
1336
  }
1214
1337
  };
@@ -1221,6 +1344,25 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
1221
1344
 
1222
1345
  // src/ProviderManager.ts
1223
1346
  import { DEFAULT_WALLET_API_URL, DEFAULT_EMBEDDED_WALLET_TYPE, DEFAULT_AUTH_URL as DEFAULT_AUTH_URL2 } from "@phantom/constants";
1347
+
1348
+ // src/utils/auth-callback.ts
1349
+ function isAuthFailureCallback(searchParams) {
1350
+ if (typeof window === "undefined" && !searchParams)
1351
+ return false;
1352
+ const params = searchParams || new URLSearchParams(window.location.search);
1353
+ const responseType = params.get("response_type");
1354
+ const sessionId = params.get("session_id");
1355
+ return responseType === "failure" && !!sessionId;
1356
+ }
1357
+ function isAuthCallbackUrl(searchParams) {
1358
+ if (typeof window === "undefined" && !searchParams)
1359
+ return false;
1360
+ const params = searchParams || new URLSearchParams(window.location.search);
1361
+ const sessionId = params.get("session_id");
1362
+ return !!(sessionId && (params.has("response_type") || params.has("wallet_id")));
1363
+ }
1364
+
1365
+ // src/ProviderManager.ts
1224
1366
  var ProviderManager = class {
1225
1367
  // Track which providers have forwarding set up
1226
1368
  constructor(config) {
@@ -1286,24 +1428,53 @@ var ProviderManager = class {
1286
1428
  }
1287
1429
  /**
1288
1430
  * Connect using the current provider
1431
+ * Automatically switches provider based on authOptions.provider if specified
1289
1432
  */
1290
1433
  async connect(authOptions) {
1291
1434
  debug.info(DebugCategory.PROVIDER_MANAGER, "Starting connection", {
1292
1435
  currentProviderKey: this.currentProviderKey,
1293
1436
  authOptions: authOptions ? { provider: authOptions.provider, hasJwtToken: !!authOptions.jwtToken } : void 0
1294
1437
  });
1438
+ if (authOptions?.provider) {
1439
+ const requestedProvider = authOptions.provider;
1440
+ let targetProviderType = null;
1441
+ if (requestedProvider === "injected") {
1442
+ targetProviderType = "injected";
1443
+ } else if (["google", "apple", "jwt", "phantom"].includes(requestedProvider)) {
1444
+ targetProviderType = "embedded";
1445
+ }
1446
+ if (targetProviderType) {
1447
+ const currentInfo = this.getCurrentProviderInfo();
1448
+ if (currentInfo?.type !== targetProviderType) {
1449
+ debug.log(DebugCategory.PROVIDER_MANAGER, "Auto-switching provider based on auth options", {
1450
+ from: currentInfo?.type,
1451
+ to: targetProviderType,
1452
+ requestedProvider
1453
+ });
1454
+ const switchOptions = {};
1455
+ if (targetProviderType === "embedded") {
1456
+ switchOptions.embeddedWalletType = currentInfo?.embeddedWalletType || this.config.embeddedWalletType;
1457
+ }
1458
+ this.switchProvider(targetProviderType, switchOptions);
1459
+ }
1460
+ }
1461
+ }
1295
1462
  if (!this.currentProvider) {
1296
1463
  debug.error(DebugCategory.PROVIDER_MANAGER, "No provider selected");
1297
1464
  throw new Error("No provider selected");
1298
1465
  }
1299
1466
  debug.log(DebugCategory.PROVIDER_MANAGER, "Delegating to provider connect method");
1300
1467
  const result = await this.currentProvider.connect(authOptions);
1468
+ const providerInfo = this.getCurrentProviderInfo();
1469
+ result.providerType = providerInfo?.type;
1301
1470
  debug.log(DebugCategory.PROVIDER_MANAGER, "Connection successful, saving preferences", {
1302
- addressCount: result.addresses?.length || 0
1471
+ addressCount: result.addresses?.length || 0,
1472
+ providerType: result.providerType
1303
1473
  });
1304
1474
  this.saveProviderPreference();
1305
1475
  debug.info(DebugCategory.PROVIDER_MANAGER, "Connect completed", {
1306
- addresses: result.addresses
1476
+ addresses: result.addresses,
1477
+ providerType: result.providerType
1307
1478
  });
1308
1479
  return result;
1309
1480
  }
@@ -1337,6 +1508,10 @@ var ProviderManager = class {
1337
1508
  */
1338
1509
  async autoConnect() {
1339
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
+ }
1340
1515
  const embeddedWalletType = this.config.embeddedWalletType || "user-wallet";
1341
1516
  const embeddedKey = this.getProviderKey("embedded", embeddedWalletType);
1342
1517
  if (this.providers.has(embeddedKey)) {
@@ -1362,6 +1537,10 @@ var ProviderManager = class {
1362
1537
  debug.log(DebugCategory.PROVIDER_MANAGER, "Embedded auto-connect failed", {
1363
1538
  error: error.message
1364
1539
  });
1540
+ if (isAuthCallbackUrl()) {
1541
+ debug.log(DebugCategory.PROVIDER_MANAGER, "In auth callback URL, not attempting injected fallback");
1542
+ return false;
1543
+ }
1365
1544
  }
1366
1545
  }
1367
1546
  const injectedKey = this.getProviderKey("injected");
@@ -1479,7 +1658,11 @@ var ProviderManager = class {
1479
1658
  }
1480
1659
  debug.log(DebugCategory.PROVIDER_MANAGER, "Creating injected provider");
1481
1660
  this.createProvider("injected");
1482
- this.switchProvider(defaultType, { embeddedWalletType: defaultEmbeddedType });
1661
+ const switchOptions = {};
1662
+ if (defaultType === "embedded") {
1663
+ switchOptions.embeddedWalletType = defaultEmbeddedType;
1664
+ }
1665
+ this.switchProvider(defaultType, switchOptions);
1483
1666
  }
1484
1667
  /**
1485
1668
  * Create a provider instance
@@ -1539,35 +1722,17 @@ var ProviderManager = class {
1539
1722
  console.error("Failed to save provider preference:", error);
1540
1723
  }
1541
1724
  }
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
1725
  };
1561
1726
 
1562
1727
  // src/waitForPhantomExtension.ts
1563
- import { isPhantomExtensionInstalled } from "@phantom/browser-injected-sdk";
1728
+ import { isPhantomExtensionInstalled as isPhantomExtensionInstalled2 } from "@phantom/browser-injected-sdk";
1564
1729
  async function waitForPhantomExtension(timeoutMs = 3e3) {
1565
1730
  return new Promise((resolve) => {
1566
1731
  const startTime = Date.now();
1567
1732
  const checkInterval = 100;
1568
1733
  const checkForExtension = () => {
1569
1734
  try {
1570
- if (isPhantomExtensionInstalled()) {
1735
+ if (isPhantomExtensionInstalled2()) {
1571
1736
  resolve(true);
1572
1737
  return;
1573
1738
  }
@@ -1660,22 +1825,6 @@ var BrowserSDK = class {
1660
1825
  throw error;
1661
1826
  }
1662
1827
  }
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
1828
  // ===== STATE QUERIES =====
1680
1829
  /**
1681
1830
  * Check if the SDK is connected to a wallet
@@ -1885,6 +2034,49 @@ function getDeeplinkToPhantom(ref) {
1885
2034
  return `https://phantom.app/ul/browse/${currentUrl}${refParam}`;
1886
2035
  }
1887
2036
 
2037
+ // src/isPhantomLoginAvailable.ts
2038
+ import { isPhantomExtensionInstalled as isPhantomExtensionInstalled3 } from "@phantom/browser-injected-sdk";
2039
+ async function isPhantomLoginAvailable(timeoutMs = 3e3) {
2040
+ const extensionInstalled = await waitForExtension(timeoutMs);
2041
+ if (!extensionInstalled) {
2042
+ return false;
2043
+ }
2044
+ try {
2045
+ if (!window.phantom?.app?.features || typeof window.phantom.app.features !== "function") {
2046
+ return false;
2047
+ }
2048
+ const features = await window.phantom.app.features();
2049
+ if (!Array.isArray(features)) {
2050
+ return false;
2051
+ }
2052
+ return features.includes("phantom_login");
2053
+ } catch (error) {
2054
+ return false;
2055
+ }
2056
+ }
2057
+ async function waitForExtension(timeoutMs) {
2058
+ return new Promise((resolve) => {
2059
+ const startTime = Date.now();
2060
+ const checkInterval = 100;
2061
+ const checkForExtension = () => {
2062
+ try {
2063
+ if (isPhantomExtensionInstalled3()) {
2064
+ resolve(true);
2065
+ return;
2066
+ }
2067
+ } catch (error) {
2068
+ }
2069
+ const elapsed = Date.now() - startTime;
2070
+ if (elapsed >= timeoutMs) {
2071
+ resolve(false);
2072
+ return;
2073
+ }
2074
+ setTimeout(checkForExtension, checkInterval);
2075
+ };
2076
+ checkForExtension();
2077
+ });
2078
+ }
2079
+
1888
2080
  // src/index.ts
1889
2081
  import { NetworkId } from "@phantom/constants";
1890
2082
  import { AddressType as AddressType5 } from "@phantom/client";
@@ -1900,6 +2092,7 @@ export {
1900
2092
  getDeeplinkToPhantom,
1901
2093
  getPlatformName,
1902
2094
  isMobileDevice,
2095
+ isPhantomLoginAvailable,
1903
2096
  parseBrowserFromUserAgent,
1904
2097
  waitForPhantomExtension
1905
2098
  };