@phantom/react-native-sdk 1.0.6 → 2.0.0-beta.0

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.js CHANGED
@@ -31,8 +31,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  AddressType: () => import_client.AddressType,
34
- NetworkId: () => import_constants5.NetworkId,
34
+ NetworkId: () => import_constants2.NetworkId,
35
35
  PhantomProvider: () => PhantomProvider,
36
+ base64urlDecode: () => import_base64url.base64urlDecode,
37
+ base64urlEncode: () => import_base64url.base64urlEncode,
36
38
  darkTheme: () => import_wallet_sdk_ui6.darkTheme,
37
39
  lightTheme: () => import_wallet_sdk_ui6.lightTheme,
38
40
  useAccounts: () => useAccounts,
@@ -48,7 +50,7 @@ module.exports = __toCommonJS(src_exports);
48
50
  // src/PhantomProvider.tsx
49
51
  var import_react8 = require("react");
50
52
  var import_embedded_provider_core = require("@phantom/embedded-provider-core");
51
- var import_constants4 = require("@phantom/constants");
53
+ var import_constants = require("@phantom/constants");
52
54
  var import_wallet_sdk_ui5 = require("@phantom/wallet-sdk-ui");
53
55
 
54
56
  // src/ModalProvider.tsx
@@ -530,110 +532,8 @@ var ExpoSecureStorage = class {
530
532
  }
531
533
  };
532
534
 
533
- // src/providers/embedded/auth.ts
534
- var WebBrowser = __toESM(require("expo-web-browser"));
535
- var import_react_native5 = require("react-native");
536
- var import_constants = require("@phantom/constants");
537
- var ExpoAuthProvider = class {
538
- async authenticate(options) {
539
- if ("jwtToken" in options) {
540
- return;
541
- }
542
- const phantomOptions = options;
543
- const { authUrl, redirectUrl, publicKey, sessionId, provider, appId } = phantomOptions;
544
- if (!redirectUrl) {
545
- throw new Error("redirectUrl is required for web browser authentication");
546
- }
547
- if (!publicKey || !sessionId || !appId) {
548
- throw new Error("publicKey, sessionId and appId are required for authentication");
549
- }
550
- try {
551
- const baseUrl = authUrl || import_constants.DEFAULT_AUTH_URL;
552
- const params = new URLSearchParams({
553
- public_key: publicKey,
554
- app_id: appId,
555
- redirect_uri: redirectUrl,
556
- session_id: sessionId,
557
- // OAuth session management - defaults to allow refresh unless explicitly clearing after logout
558
- clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
559
- allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
560
- sdk_version: "1.0.6",
561
- sdk_type: "react-native",
562
- platform: import_react_native5.Platform.OS
563
- });
564
- if (provider) {
565
- console.log("[ExpoAuthProvider] Provider specified, will skip selection", { provider });
566
- params.append("provider", provider);
567
- } else {
568
- console.log("[ExpoAuthProvider] No provider specified, defaulting to Google");
569
- params.append("provider", "google");
570
- }
571
- const fullAuthUrl = `${baseUrl}?${params.toString()}`;
572
- console.log("[ExpoAuthProvider] Starting authentication", {
573
- baseUrl,
574
- redirectUrl,
575
- publicKey,
576
- sessionId,
577
- provider
578
- });
579
- await WebBrowser.warmUpAsync();
580
- const result = await WebBrowser.openAuthSessionAsync(fullAuthUrl, redirectUrl, {
581
- // Use system browser on iOS for ASWebAuthenticationSession
582
- preferEphemeralSession: false
583
- });
584
- console.log("[ExpoAuthProvider] Authentication result", {
585
- type: result.type,
586
- url: result.type === "success" && result.url ? result.url.substring(0, 100) + "..." : void 0
587
- });
588
- if (result.type === "success" && result.url) {
589
- const url = new URL(result.url);
590
- const walletId = url.searchParams.get("wallet_id");
591
- const organizationId = url.searchParams.get("organization_id");
592
- const accountDerivationIndex = url.searchParams.get("selected_account_index");
593
- const expiresInMs = url.searchParams.get("expires_in_ms");
594
- const authUserId = url.searchParams.get("auth_user_id");
595
- if (!walletId) {
596
- throw new Error("Authentication failed: no walletId in redirect URL");
597
- }
598
- if (!organizationId) {
599
- console.error("[ExpoAuthProvider] Missing organizationId in redirect URL", { url: result.url });
600
- throw new Error("Authentication failed: no organizationId in redirect URL");
601
- }
602
- console.log("[ExpoAuthProvider] Auth redirect parameters", {
603
- walletId,
604
- organizationId,
605
- provider,
606
- accountDerivationIndex,
607
- expiresInMs,
608
- authUserId
609
- });
610
- return {
611
- walletId,
612
- organizationId,
613
- provider: provider || void 0,
614
- accountDerivationIndex: accountDerivationIndex ? parseInt(accountDerivationIndex) : 0,
615
- expiresInMs: expiresInMs ? parseInt(expiresInMs) : 0,
616
- authUserId: authUserId || void 0
617
- };
618
- } else if (result.type === "cancel") {
619
- throw new Error("User cancelled authentication");
620
- } else {
621
- throw new Error("Authentication failed");
622
- }
623
- } catch (error) {
624
- console.error("[ExpoAuthProvider] Authentication error", error);
625
- throw error;
626
- } finally {
627
- await WebBrowser.coolDownAsync();
628
- }
629
- }
630
- isAvailable() {
631
- return Promise.resolve(true);
632
- }
633
- };
634
-
635
535
  // src/providers/embedded/ExpoAuth2AuthProvider.ts
636
- var WebBrowser2 = __toESM(require("expo-web-browser"));
536
+ var WebBrowser = __toESM(require("expo-web-browser"));
637
537
  var import_auth2 = require("@phantom/auth2");
638
538
  var ExpoAuth2AuthProvider = class {
639
539
  constructor(stamper, auth2ProviderOptions, kmsClientOptions) {
@@ -649,246 +549,111 @@ var ExpoAuth2AuthProvider = class {
649
549
  * so the token exchange and KMS calls all happen here before returning AuthResult.
650
550
  */
651
551
  async authenticate(options) {
652
- if (!this.stamper.getKeyInfo()) {
653
- await this.stamper.init();
654
- }
655
- const keyPair = this.stamper.getCryptoKeyPair();
656
- if (!keyPair) {
657
- throw new Error("Stamper key pair not found.");
658
- }
659
- const codeVerifier = (0, import_auth2.createCodeVerifier)();
660
- const url = await (0, import_auth2.createConnectStartUrl)({
661
- keyPair,
662
- connectLoginUrl: this.auth2ProviderOptions.connectLoginUrl,
663
- clientId: this.auth2ProviderOptions.clientId,
664
- redirectUri: this.auth2ProviderOptions.redirectUri,
552
+ const { url, codeVerifier } = await (0, import_auth2.prepareAuth2Flow)({
553
+ stamper: this.stamper,
554
+ auth2Options: this.auth2ProviderOptions,
665
555
  sessionId: options.sessionId,
666
- provider: options.provider,
667
- codeVerifier,
668
- // The P-256 ephemeral key is unique per wallet, so no additional salt is needed.
669
- salt: ""
556
+ provider: options.provider
670
557
  });
671
- await WebBrowser2.warmUpAsync();
558
+ await WebBrowser.warmUpAsync();
672
559
  let result;
673
560
  try {
674
- result = await WebBrowser2.openAuthSessionAsync(url, this.auth2ProviderOptions.redirectUri);
561
+ result = await WebBrowser.openAuthSessionAsync(url, this.auth2ProviderOptions.redirectUri);
675
562
  } finally {
676
- await WebBrowser2.coolDownAsync();
563
+ await WebBrowser.coolDownAsync();
677
564
  }
678
565
  if (!result.url) {
679
566
  throw new Error("Authentication failed");
680
567
  }
681
568
  const callbackUrl = new URL(result.url);
682
- const state = callbackUrl.searchParams.get("state");
683
- if (state && state !== options.sessionId) {
684
- throw new Error("Auth2 state mismatch \u2014 possible CSRF attack.");
685
- }
686
- const error = callbackUrl.searchParams.get("error");
687
- if (error) {
688
- const description = callbackUrl.searchParams.get("error_description");
689
- throw new Error(`Auth2 callback error: ${description ?? error}`);
690
- }
691
- const code = callbackUrl.searchParams.get("code");
692
- if (!code) {
693
- throw new Error("Auth2 callback missing authorization code");
694
- }
695
- const { idToken, bearerToken, authUserId, expiresInMs, refreshToken } = await (0, import_auth2.exchangeAuthCode)({
696
- authApiBaseUrl: this.auth2ProviderOptions.authApiBaseUrl,
697
- clientId: this.auth2ProviderOptions.clientId,
698
- redirectUri: this.auth2ProviderOptions.redirectUri,
569
+ const code = (0, import_auth2.validateAuth2Callback)({
570
+ getParam: (key) => callbackUrl.searchParams.get(key),
571
+ expectedSessionId: options.sessionId
572
+ });
573
+ return (0, import_auth2.completeAuth2Exchange)({
574
+ stamper: this.stamper,
575
+ kms: this.kms,
576
+ auth2Options: this.auth2ProviderOptions,
699
577
  code,
700
- codeVerifier
578
+ codeVerifier,
579
+ provider: options.provider
701
580
  });
702
- await this.stamper.setTokens({ idToken, bearerToken, refreshToken, expiresInMs });
703
- const { organizationId, walletId } = await this.kms.discoverOrganizationAndWalletId(bearerToken, authUserId);
704
- return {
705
- walletId,
706
- organizationId,
707
- provider: options.provider,
708
- accountDerivationIndex: 0,
709
- // discoverWalletId uses derivation index of 0.
710
- expiresInMs,
711
- authUserId,
712
- bearerToken
713
- };
714
581
  }
715
582
  };
716
583
 
717
- // src/providers/embedded/ExpoAuth2Stamper.ts
584
+ // src/PhantomProvider.tsx
585
+ var import_auth22 = require("@phantom/auth2");
586
+
587
+ // src/providers/embedded/SecureStoreAuth2StamperStorage.ts
718
588
  var SecureStore2 = __toESM(require("expo-secure-store"));
719
589
  var import_bs58 = __toESM(require("bs58"));
720
590
  var import_buffer = require("buffer");
721
- var import_base64url = require("@phantom/base64url");
722
- var import_sdk_types = require("@phantom/sdk-types");
723
- var import_auth22 = require("@phantom/auth2");
724
- var import_constants2 = require("@phantom/constants");
725
- var ExpoAuth2Stamper = class {
726
- /**
727
- * @param storageKey - expo-secure-store key used to persist the P-256 private key.
728
- * Use a unique key per app, e.g. `phantom-auth2-<appId>`.
729
- * @param refreshConfig - When provided, the stamper will automatically refresh
730
- * the id_token using the refresh_token before it expires.
731
- */
732
- constructor(storageKey, refreshConfig) {
591
+ var SecureStoreAuth2StamperStorage = class {
592
+ constructor(storageKey) {
733
593
  this.storageKey = storageKey;
734
- this.refreshConfig = refreshConfig;
735
- this._keyPair = null;
736
- this._keyInfo = null;
737
- this._idToken = null;
738
- this._bearerToken = null;
739
- this._refreshToken = null;
740
- this._tokenExpiresAt = null;
741
- this.algorithm = import_sdk_types.Algorithm.secp256r1;
742
- this.type = "OIDC";
594
+ this.requiresExtractableKeys = true;
743
595
  }
744
- async init() {
745
- const stored = await this.loadRecord();
746
- if (stored) {
747
- this._keyPair = {
748
- privateKey: await this.importPrivateKey(stored.privateKeyPkcs8),
749
- publicKey: await this.importPublicKeyFromBase58(stored.keyInfo.publicKey)
750
- };
751
- this._keyInfo = stored.keyInfo;
752
- if (stored.idToken) {
753
- this._idToken = stored.idToken;
754
- }
755
- if (stored.bearerToken) {
756
- this._bearerToken = stored.bearerToken;
757
- }
758
- if (stored.refreshToken) {
759
- this._refreshToken = stored.refreshToken;
760
- }
761
- if (stored.tokenExpiresAt) {
762
- this._tokenExpiresAt = stored.tokenExpiresAt;
763
- }
764
- return this._keyInfo;
596
+ async load() {
597
+ const raw = await SecureStore2.getItemAsync(this.storageKey);
598
+ if (raw === null) {
599
+ return null;
765
600
  }
766
- return this.generateAndStore();
767
- }
768
- getKeyInfo() {
769
- return this._keyInfo;
770
- }
771
- getCryptoKeyPair() {
772
- return this._keyPair;
773
- }
774
- /**
775
- * Returns the current token state (refreshing proactively if near expiry),
776
- * or null if no token has been set yet.
777
- */
778
- async getTokens() {
779
- if (this.refreshConfig && this._refreshToken && this._tokenExpiresAt !== null && Date.now() >= this._tokenExpiresAt - import_constants2.TOKEN_REFRESH_BUFFER_MS) {
780
- const refreshed = await (0, import_auth22.refreshToken)({
781
- authApiBaseUrl: this.refreshConfig.authApiBaseUrl,
782
- clientId: this.refreshConfig.clientId,
783
- redirectUri: this.refreshConfig.redirectUri,
784
- refreshToken: this._refreshToken
785
- });
786
- await this.setTokens(refreshed);
601
+ let record;
602
+ try {
603
+ record = JSON.parse(raw);
604
+ } catch (err) {
605
+ await SecureStore2.deleteItemAsync(this.storageKey);
606
+ throw new Error(`SecureStoreAuth2StamperStorage: corrupt stored record (JSON parse failed): ${err}`);
787
607
  }
788
- if (!this._idToken || !this._bearerToken) {
789
- return null;
608
+ let privateKey;
609
+ let publicKey;
610
+ try {
611
+ privateKey = await this.importPrivateKey(record.privateKeyPkcs8);
612
+ publicKey = await this.importPublicKeyFromBase58(record.keyInfo.publicKey);
613
+ } catch (err) {
614
+ await SecureStore2.deleteItemAsync(this.storageKey);
615
+ throw new Error(`SecureStoreAuth2StamperStorage: corrupt stored record (key import failed): ${err}`);
790
616
  }
791
617
  return {
792
- idToken: this._idToken,
793
- bearerToken: this._bearerToken,
794
- refreshToken: this._refreshToken ?? void 0
618
+ keyPair: { privateKey, publicKey },
619
+ keyInfo: record.keyInfo,
620
+ accessToken: record.accessToken,
621
+ idType: record.idType,
622
+ refreshToken: record.refreshToken,
623
+ tokenExpiresAt: record.tokenExpiresAt
795
624
  };
796
625
  }
797
- /**
798
- * Arms the stamper with the OIDC token data for subsequent KMS stamp() calls.
799
- *
800
- * Persists the tokens to SecureStore alongside the key pair so that
801
- * auto-connect can restore them on the next app launch without a new login.
802
- *
803
- * @param refreshToken - When provided alongside a `refreshConfig`, enables
804
- * silent token refresh before the token expires.
805
- * @param expiresInMs - Token lifetime in milliseconds (from `expires_in * 1000`).
806
- * Used to compute the absolute expiry time for proactive refresh.
807
- */
808
- async setTokens({
809
- idToken,
810
- bearerToken,
811
- refreshToken,
812
- expiresInMs
813
- }) {
814
- this._idToken = idToken;
815
- this._bearerToken = bearerToken;
816
- this._refreshToken = refreshToken ?? null;
817
- this._tokenExpiresAt = expiresInMs != null ? Date.now() + expiresInMs : null;
818
- const existing = await this.loadRecord();
819
- if (existing) {
820
- await this.storeRecord({
821
- ...existing,
822
- idToken,
823
- bearerToken,
824
- refreshToken,
825
- tokenExpiresAt: this._tokenExpiresAt ?? void 0
826
- });
827
- }
828
- }
829
- async stamp(params) {
830
- if (!this._keyPair || !this._keyInfo || this._idToken === null) {
831
- throw new Error("ExpoAuth2Stamper not initialized. Call init() first.");
832
- }
833
- const signatureRaw = await crypto.subtle.sign(
834
- { name: "ECDSA", hash: "SHA-256" },
835
- this._keyPair.privateKey,
836
- new Uint8Array(params.data)
837
- );
838
- const rawPublicKey = import_bs58.default.decode(this._keyInfo.publicKey);
839
- const stampData = {
840
- kind: this.type,
841
- idToken: this._idToken,
842
- publicKey: (0, import_base64url.base64urlEncode)(rawPublicKey),
843
- algorithm: this.algorithm,
844
- // The P-256 ephemeral key is unique per wallet, so no additional salt is needed.
845
- salt: "",
846
- signature: (0, import_base64url.base64urlEncode)(new Uint8Array(signatureRaw))
626
+ async save(record) {
627
+ const pkcs8Buffer = await crypto.subtle.exportKey("pkcs8", record.keyPair.privateKey);
628
+ const privateKeyPkcs8 = import_buffer.Buffer.from(pkcs8Buffer).toString("base64");
629
+ const serialized = {
630
+ privateKeyPkcs8,
631
+ keyInfo: record.keyInfo,
632
+ accessToken: record.accessToken,
633
+ idType: record.idType,
634
+ refreshToken: record.refreshToken,
635
+ tokenExpiresAt: record.tokenExpiresAt
847
636
  };
848
- return (0, import_base64url.base64urlEncode)(new TextEncoder().encode(JSON.stringify(stampData)));
849
- }
850
- async resetKeyPair() {
851
- await this.clear();
852
- return this.generateAndStore();
637
+ await SecureStore2.setItemAsync(this.storageKey, JSON.stringify(serialized), {
638
+ requireAuthentication: false
639
+ });
853
640
  }
854
641
  async clear() {
855
- await this.clearStoredRecord();
856
- this._keyPair = null;
857
- this._keyInfo = null;
858
- this._idToken = null;
859
- this._bearerToken = null;
860
- this._refreshToken = null;
861
- this._tokenExpiresAt = null;
862
- }
863
- // Auth2 doesn't use key rotation; minimal no-op implementations.
864
- async rotateKeyPair() {
865
- return this.init();
866
- }
867
- // eslint-disable-next-line @typescript-eslint/require-await
868
- async commitRotation(authenticatorId) {
869
- if (this._keyInfo) {
870
- this._keyInfo.authenticatorId = authenticatorId;
642
+ try {
643
+ await SecureStore2.deleteItemAsync(this.storageKey);
644
+ } catch {
871
645
  }
872
646
  }
873
- async rollbackRotation() {
874
- }
875
- async generateAndStore() {
876
- const keyPair = await crypto.subtle.generateKey(
647
+ async importPrivateKey(pkcs8Base64) {
648
+ const pkcs8Bytes = import_buffer.Buffer.from(pkcs8Base64, "base64");
649
+ return crypto.subtle.importKey(
650
+ "pkcs8",
651
+ pkcs8Bytes,
877
652
  { name: "ECDSA", namedCurve: "P-256" },
878
- true,
879
- // extractable needed to export PKCS#8 for SecureStore
880
- ["sign", "verify"]
653
+ this.requiresExtractableKeys,
654
+ // extractable so save() can re-export via pkcs8
655
+ ["sign"]
881
656
  );
882
- const rawPublicKey = new Uint8Array(await crypto.subtle.exportKey("raw", keyPair.publicKey));
883
- const publicKeyBase58 = import_bs58.default.encode(rawPublicKey);
884
- const keyIdBuffer = await crypto.subtle.digest("SHA-256", rawPublicKey.buffer);
885
- const keyId = (0, import_base64url.base64urlEncode)(new Uint8Array(keyIdBuffer)).substring(0, 16);
886
- this._keyPair = keyPair;
887
- this._keyInfo = { keyId, publicKey: publicKeyBase58, createdAt: Date.now() };
888
- const pkcs8Buffer = await crypto.subtle.exportKey("pkcs8", keyPair.privateKey);
889
- const privateKeyPkcs8 = import_buffer.Buffer.from(pkcs8Buffer).toString("base64");
890
- await this.storeRecord({ privateKeyPkcs8, keyInfo: this._keyInfo });
891
- return this._keyInfo;
892
657
  }
893
658
  async importPublicKeyFromBase58(base58PublicKey) {
894
659
  const rawBytes = import_bs58.default.decode(base58PublicKey);
@@ -901,38 +666,10 @@ var ExpoAuth2Stamper = class {
901
666
  ["verify"]
902
667
  );
903
668
  }
904
- async importPrivateKey(pkcs8Base64) {
905
- const pkcs8Bytes = import_buffer.Buffer.from(pkcs8Base64, "base64");
906
- return crypto.subtle.importKey(
907
- "pkcs8",
908
- pkcs8Bytes,
909
- { name: "ECDSA", namedCurve: "P-256" },
910
- false,
911
- // non-extractable once loaded into memory
912
- ["sign"]
913
- );
914
- }
915
- async loadRecord() {
916
- try {
917
- const raw = await SecureStore2.getItemAsync(this.storageKey);
918
- return raw ? JSON.parse(raw) : null;
919
- } catch {
920
- return null;
921
- }
922
- }
923
- async storeRecord(record) {
924
- await SecureStore2.setItemAsync(this.storageKey, JSON.stringify(record), { requireAuthentication: false });
925
- }
926
- async clearStoredRecord() {
927
- try {
928
- await SecureStore2.deleteItemAsync(this.storageKey);
929
- } catch {
930
- }
931
- }
932
669
  };
933
670
 
934
671
  // src/providers/embedded/url-params.ts
935
- var import_react_native6 = require("react-native");
672
+ var import_react_native5 = require("react-native");
936
673
  var ExpoURLParamsAccessor = class {
937
674
  constructor() {
938
675
  this.listeners = /* @__PURE__ */ new Set();
@@ -944,7 +681,7 @@ var ExpoURLParamsAccessor = class {
944
681
  }
945
682
  async getInitialParams() {
946
683
  try {
947
- const url = await import_react_native6.Linking.getInitialURL();
684
+ const url = await import_react_native5.Linking.getInitialURL();
948
685
  if (!url) {
949
686
  return null;
950
687
  }
@@ -960,7 +697,7 @@ var ExpoURLParamsAccessor = class {
960
697
  if (this.subscription) {
961
698
  return;
962
699
  }
963
- this.subscription = import_react_native6.Linking.addEventListener("url", ({ url }) => {
700
+ this.subscription = import_react_native5.Linking.addEventListener("url", ({ url }) => {
964
701
  const params = this.parseURLParams(url);
965
702
  if (params && Object.keys(params).length > 0) {
966
703
  this.currentParams = { ...this.currentParams, ...params };
@@ -999,180 +736,6 @@ var ExpoURLParamsAccessor = class {
999
736
  }
1000
737
  };
1001
738
 
1002
- // src/providers/embedded/stamper.ts
1003
- var SecureStore3 = __toESM(require("expo-secure-store"));
1004
- var import_api_key_stamper = require("@phantom/api-key-stamper");
1005
- var import_constants3 = require("@phantom/constants");
1006
- var import_crypto = require("@phantom/crypto");
1007
- var import_base64url2 = require("@phantom/base64url");
1008
- var ReactNativeStamper = class {
1009
- // Optional for PKI, required for OIDC
1010
- constructor(config = {}) {
1011
- this.activeKeyRecord = null;
1012
- this.pendingKeyRecord = null;
1013
- this.algorithm = import_constants3.DEFAULT_AUTHENTICATOR_ALGORITHM;
1014
- this.type = "PKI";
1015
- this.keyPrefix = config.keyPrefix || "phantom-rn-stamper";
1016
- this.appId = config.appId || "default";
1017
- }
1018
- /**
1019
- * Initialize the stamper and generate/load cryptographic keys
1020
- */
1021
- async init() {
1022
- this.activeKeyRecord = await this.loadActiveKeyRecord();
1023
- if (!this.activeKeyRecord) {
1024
- this.activeKeyRecord = await this.generateAndStoreNewKeyRecord("active");
1025
- }
1026
- this.pendingKeyRecord = await this.loadPendingKeyRecord();
1027
- return this.activeKeyRecord.keyInfo;
1028
- }
1029
- /**
1030
- * Get the current key information
1031
- */
1032
- getKeyInfo() {
1033
- return this.activeKeyRecord?.keyInfo || null;
1034
- }
1035
- /**
1036
- * Generate and store a new key pair, replacing any existing keys
1037
- */
1038
- async resetKeyPair() {
1039
- await this.clear();
1040
- this.activeKeyRecord = await this.generateAndStoreNewKeyRecord("active");
1041
- this.pendingKeyRecord = null;
1042
- return this.activeKeyRecord.keyInfo;
1043
- }
1044
- /**
1045
- * Create X-Phantom-Stamp header value using stored secret key
1046
- * @param params - Parameters object with data to sign and optional override params
1047
- * @returns Complete X-Phantom-Stamp header value
1048
- */
1049
- async stamp(params) {
1050
- if (!this.activeKeyRecord) {
1051
- throw new Error("Stamper not initialized. Call init() first.");
1052
- }
1053
- const apiKeyStamper = new import_api_key_stamper.ApiKeyStamper({ apiSecretKey: this.activeKeyRecord.secretKey });
1054
- return await apiKeyStamper.stamp(params);
1055
- }
1056
- /**
1057
- * Clear all stored keys from SecureStore
1058
- */
1059
- async clear() {
1060
- const activeKey = this.getActiveKeyName();
1061
- const pendingKey = this.getPendingKeyName();
1062
- try {
1063
- await SecureStore3.deleteItemAsync(activeKey);
1064
- } catch (error) {
1065
- }
1066
- try {
1067
- await SecureStore3.deleteItemAsync(pendingKey);
1068
- } catch (error) {
1069
- }
1070
- this.activeKeyRecord = null;
1071
- this.pendingKeyRecord = null;
1072
- }
1073
- /**
1074
- * Generate a new keypair for rotation without making it active
1075
- */
1076
- async rotateKeyPair() {
1077
- this.pendingKeyRecord = await this.generateAndStoreNewKeyRecord("pending");
1078
- return this.pendingKeyRecord.keyInfo;
1079
- }
1080
- /**
1081
- * Switch to the pending keypair, making it active and cleaning up the old one
1082
- */
1083
- async commitRotation(authenticatorId) {
1084
- if (!this.pendingKeyRecord) {
1085
- throw new Error("No pending keypair to commit");
1086
- }
1087
- if (this.activeKeyRecord) {
1088
- try {
1089
- await SecureStore3.deleteItemAsync(this.getActiveKeyName());
1090
- } catch (error) {
1091
- }
1092
- }
1093
- this.pendingKeyRecord.status = "active";
1094
- this.pendingKeyRecord.authenticatorId = authenticatorId;
1095
- this.pendingKeyRecord.keyInfo.authenticatorId = authenticatorId;
1096
- this.activeKeyRecord = this.pendingKeyRecord;
1097
- this.pendingKeyRecord = null;
1098
- await this.storeKeyRecord(this.activeKeyRecord, "active");
1099
- try {
1100
- await SecureStore3.deleteItemAsync(this.getPendingKeyName());
1101
- } catch (error) {
1102
- }
1103
- }
1104
- /**
1105
- * Discard the pending keypair on rotation failure
1106
- */
1107
- async rollbackRotation() {
1108
- if (!this.pendingKeyRecord) {
1109
- return;
1110
- }
1111
- try {
1112
- await SecureStore3.deleteItemAsync(this.getPendingKeyName());
1113
- } catch (error) {
1114
- }
1115
- this.pendingKeyRecord = null;
1116
- }
1117
- async generateAndStoreNewKeyRecord(type) {
1118
- const keypair = (0, import_crypto.generateKeyPair)();
1119
- const keyId = this.createKeyId(keypair.publicKey);
1120
- const now = Date.now();
1121
- const keyInfo = {
1122
- keyId,
1123
- publicKey: keypair.publicKey,
1124
- createdAt: now
1125
- };
1126
- const record = {
1127
- keyInfo,
1128
- secretKey: keypair.secretKey,
1129
- createdAt: now,
1130
- expiresAt: 0,
1131
- // Not used anymore, kept for backward compatibility
1132
- status: type
1133
- };
1134
- await this.storeKeyRecord(record, type);
1135
- return record;
1136
- }
1137
- createKeyId(publicKey) {
1138
- return (0, import_base64url2.base64urlEncode)(new TextEncoder().encode(publicKey)).substring(0, 16);
1139
- }
1140
- async storeKeyRecord(record, type) {
1141
- const keyName = type === "active" ? this.getActiveKeyName() : this.getPendingKeyName();
1142
- await SecureStore3.setItemAsync(keyName, JSON.stringify(record), {
1143
- requireAuthentication: false
1144
- });
1145
- }
1146
- async loadActiveKeyRecord() {
1147
- try {
1148
- const activeKey = this.getActiveKeyName();
1149
- const storedRecord = await SecureStore3.getItemAsync(activeKey);
1150
- if (storedRecord) {
1151
- return JSON.parse(storedRecord);
1152
- }
1153
- } catch (error) {
1154
- }
1155
- return null;
1156
- }
1157
- async loadPendingKeyRecord() {
1158
- try {
1159
- const pendingKey = this.getPendingKeyName();
1160
- const storedRecord = await SecureStore3.getItemAsync(pendingKey);
1161
- if (storedRecord) {
1162
- return JSON.parse(storedRecord);
1163
- }
1164
- } catch (error) {
1165
- }
1166
- return null;
1167
- }
1168
- getActiveKeyName() {
1169
- return `${this.keyPrefix}-${this.appId}-active`;
1170
- }
1171
- getPendingKeyName() {
1172
- return `${this.keyPrefix}-${this.appId}-pending`;
1173
- }
1174
- };
1175
-
1176
739
  // src/providers/embedded/logger.ts
1177
740
  var ExpoLogger = class {
1178
741
  constructor(enabled = false) {
@@ -1215,7 +778,7 @@ var ReactNativePhantomAppProvider = class {
1215
778
  };
1216
779
 
1217
780
  // src/PhantomProvider.tsx
1218
- var import_react_native7 = require("react-native");
781
+ var import_react_native6 = require("react-native");
1219
782
  var import_jsx_runtime6 = require("react/jsx-runtime");
1220
783
  function PhantomProvider({ children, config, debugConfig, theme, appIcon, appName }) {
1221
784
  const [isConnected, setIsConnected] = (0, import_react8.useState)(false);
@@ -1228,12 +791,12 @@ function PhantomProvider({ children, config, debugConfig, theme, appIcon, appNam
1228
791
  const redirectUrl = config.authOptions?.redirectUrl || `${config.scheme}://phantom-auth-callback`;
1229
792
  return {
1230
793
  ...config,
1231
- apiBaseUrl: config.apiBaseUrl || import_constants4.DEFAULT_WALLET_API_URL,
1232
- embeddedWalletType: config.embeddedWalletType || import_constants4.DEFAULT_EMBEDDED_WALLET_TYPE,
794
+ apiBaseUrl: config.apiBaseUrl || import_constants.DEFAULT_WALLET_API_URL,
795
+ embeddedWalletType: config.embeddedWalletType || import_constants.DEFAULT_EMBEDDED_WALLET_TYPE,
1233
796
  authOptions: {
1234
- ...config.authOptions || {},
1235
797
  redirectUrl,
1236
- authUrl: config.authOptions?.authUrl || import_constants4.DEFAULT_AUTH_URL
798
+ authUrl: config.authOptions?.authUrl || import_constants.DEFAULT_AUTH_URL,
799
+ authApiBaseUrl: config.authOptions?.authApiBaseUrl || import_constants.DEFAULT_AUTH_API_BASE_URL
1237
800
  }
1238
801
  };
1239
802
  }, [config]);
@@ -1241,28 +804,25 @@ function PhantomProvider({ children, config, debugConfig, theme, appIcon, appNam
1241
804
  const storage = new ExpoSecureStorage();
1242
805
  const urlParamsAccessor = new ExpoURLParamsAccessor();
1243
806
  const logger = new ExpoLogger(debugConfig?.enabled || false);
1244
- const stamper = config.unstable__auth2Options && config.authOptions?.redirectUrl ? new ExpoAuth2Stamper(`phantom-auth2-${memoizedConfig.appId}`, {
1245
- authApiBaseUrl: config.unstable__auth2Options.authApiBaseUrl,
1246
- clientId: config.unstable__auth2Options.clientId,
1247
- redirectUri: config.authOptions.redirectUrl
1248
- }) : new ReactNativeStamper({
1249
- keyPrefix: `phantom-rn-${memoizedConfig.appId}`,
1250
- appId: memoizedConfig.appId
807
+ const stamper = new import_auth22.Auth2Stamper(new SecureStoreAuth2StamperStorage(`phantom-auth2-${memoizedConfig.appId}`), {
808
+ authApiBaseUrl: memoizedConfig.authOptions.authApiBaseUrl,
809
+ clientId: memoizedConfig.appId,
810
+ redirectUri: memoizedConfig.authOptions.redirectUrl
1251
811
  });
1252
- const authProvider = config.unstable__auth2Options && config.authOptions?.authUrl && config.authOptions?.redirectUrl && config.apiBaseUrl && stamper instanceof ExpoAuth2Stamper ? new ExpoAuth2AuthProvider(
812
+ const authProvider = new ExpoAuth2AuthProvider(
1253
813
  stamper,
1254
814
  {
1255
- redirectUri: config.authOptions.redirectUrl,
1256
- connectLoginUrl: config.authOptions.authUrl,
1257
- clientId: config.unstable__auth2Options.clientId,
1258
- authApiBaseUrl: config.unstable__auth2Options.authApiBaseUrl
815
+ redirectUri: memoizedConfig.authOptions.redirectUrl,
816
+ connectLoginUrl: memoizedConfig.authOptions.authUrl,
817
+ clientId: memoizedConfig.appId,
818
+ authApiBaseUrl: memoizedConfig.authOptions.authApiBaseUrl
1259
819
  },
1260
820
  {
1261
- apiBaseUrl: config.apiBaseUrl,
1262
- appId: config.appId
821
+ apiBaseUrl: memoizedConfig.apiBaseUrl,
822
+ appId: memoizedConfig.appId
1263
823
  }
1264
- ) : new ExpoAuthProvider();
1265
- const platformName = `${import_react_native7.Platform.OS}-${import_react_native7.Platform.Version}`;
824
+ );
825
+ const platformName = `${import_react_native6.Platform.OS}-${import_react_native6.Platform.Version}`;
1266
826
  const platform = {
1267
827
  storage,
1268
828
  authProvider,
@@ -1271,13 +831,13 @@ function PhantomProvider({ children, config, debugConfig, theme, appIcon, appNam
1271
831
  phantomAppProvider: new ReactNativePhantomAppProvider(),
1272
832
  name: platformName,
1273
833
  analyticsHeaders: {
1274
- [import_constants4.ANALYTICS_HEADERS.SDK_TYPE]: "react-native",
1275
- [import_constants4.ANALYTICS_HEADERS.PLATFORM]: "ext-sdk",
1276
- [import_constants4.ANALYTICS_HEADERS.PLATFORM_VERSION]: `${import_react_native7.Platform.Version}`,
1277
- [import_constants4.ANALYTICS_HEADERS.CLIENT]: import_react_native7.Platform.OS,
1278
- [import_constants4.ANALYTICS_HEADERS.APP_ID]: config.appId,
1279
- [import_constants4.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
1280
- [import_constants4.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.6"
834
+ [import_constants.ANALYTICS_HEADERS.SDK_TYPE]: "react-native",
835
+ [import_constants.ANALYTICS_HEADERS.PLATFORM]: "ext-sdk",
836
+ [import_constants.ANALYTICS_HEADERS.PLATFORM_VERSION]: `${import_react_native6.Platform.Version}`,
837
+ [import_constants.ANALYTICS_HEADERS.CLIENT]: import_react_native6.Platform.OS,
838
+ [import_constants.ANALYTICS_HEADERS.APP_ID]: config.appId,
839
+ [import_constants.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
840
+ [import_constants.ANALYTICS_HEADERS.SDK_VERSION]: "2.0.0-beta.0"
1281
841
  // Replaced at build time
1282
842
  }
1283
843
  };
@@ -1391,13 +951,16 @@ function useEthereum() {
1391
951
 
1392
952
  // src/index.ts
1393
953
  var import_client = require("@phantom/client");
1394
- var import_constants5 = require("@phantom/constants");
954
+ var import_constants2 = require("@phantom/constants");
955
+ var import_base64url = require("@phantom/base64url");
1395
956
  var import_wallet_sdk_ui6 = require("@phantom/wallet-sdk-ui");
1396
957
  // Annotate the CommonJS export names for ESM import in node:
1397
958
  0 && (module.exports = {
1398
959
  AddressType,
1399
960
  NetworkId,
1400
961
  PhantomProvider,
962
+ base64urlDecode,
963
+ base64urlEncode,
1401
964
  darkTheme,
1402
965
  lightTheme,
1403
966
  useAccounts,