@phantom/browser-sdk 1.0.5 → 1.0.7

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 CHANGED
@@ -985,6 +985,46 @@ function toggleDebug(enabled: boolean) {
985
985
  }
986
986
  ```
987
987
 
988
+ ## Dapp-Sponsored Transactions (presignTransaction)
989
+
990
+ Pass `presignTransaction` directly to `signAndSendTransaction` for calls that need co-signing. Calls without it proceed normally — it is never applied globally.
991
+
992
+ > **Important:** Phantom embedded wallets do not accept pre-signed transactions. If your use case requires a second signer (e.g. your app as the fee payer), that signing must happen via this option, after Phantom has constructed and validated the transaction. This restriction does not apply to injected providers (e.g. the Phantom browser extension).
993
+
994
+ > **Note:** `presignTransaction` only fires for Solana transactions via the embedded provider. EVM transactions and injected providers are unaffected.
995
+
996
+ ### Transaction format
997
+
998
+ The `transaction` string is **base64url-encoded** (URL-safe base64 without `=` padding, using `-` and `_` instead of `+` and `/`).
999
+
1000
+ The SDK exports `base64urlDecode` and `base64urlEncode` utilities:
1001
+
1002
+ ```ts
1003
+ import { base64urlDecode, base64urlEncode } from "@phantom/browser-sdk";
1004
+ ```
1005
+
1006
+ ### Example: Dapp fee payer
1007
+
1008
+ ```ts
1009
+ import { base64urlDecode, base64urlEncode } from "@phantom/browser-sdk";
1010
+ import { Keypair, VersionedTransaction } from "@solana/web3.js";
1011
+
1012
+ const feePayerKeypair = Keypair.fromSecretKey(/* your fee payer secret key */);
1013
+
1014
+ // This call co-signs as fee payer
1015
+ const result = await sdk.solana.signAndSendTransaction(transaction, {
1016
+ presignTransaction: async (tx, context) => {
1017
+ const txBytes = base64urlDecode(tx);
1018
+ const versionedTx = VersionedTransaction.deserialize(txBytes);
1019
+ versionedTx.sign([feePayerKeypair]);
1020
+ return base64urlEncode(versionedTx.serialize());
1021
+ },
1022
+ });
1023
+
1024
+ // This call has no co-signer
1025
+ const result2 = await sdk.solana.signAndSendTransaction(otherTransaction);
1026
+ ```
1027
+
988
1028
  ## Transaction Examples
989
1029
 
990
1030
  ### Solana Transactions
package/dist/index.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import { EmbeddedProviderConfig, EmbeddedProviderAuthType, ConnectResult as ConnectResult$1, WalletAddress, EmbeddedProviderEvent, EventCallback } from '@phantom/embedded-provider-core';
2
2
  export { ConnectErrorEventData, ConnectEventData, ConnectStartEventData, DisconnectEventData, EmbeddedProviderEvent, EmbeddedProviderEventMap, EventCallback, SignAndSendTransactionParams, SignMessageParams, SignMessageResult, SignedTransaction, WalletAddress } from '@phantom/embedded-provider-core';
3
3
  import { IEthereumChain, ISolanaChain } from '@phantom/chain-interfaces';
4
- export { EthTransactionRequest, IEthereumChain, ISolanaChain } from '@phantom/chain-interfaces';
4
+ export { EthTransactionRequest, IEthereumChain, ISolanaChain, SignAndSendTransactionOptions } from '@phantom/chain-interfaces';
5
5
  import { AddressType } from '@phantom/client';
6
- export { AddressType } from '@phantom/client';
6
+ export { AddressType, PresignTransactionContext } from '@phantom/client';
7
7
  import { AutoConfirmEnableParams, AutoConfirmResult, AutoConfirmSupportedChainsResult } from '@phantom/browser-injected-sdk/auto-confirm';
8
8
  export { AutoConfirmEnableParams, AutoConfirmResult, AutoConfirmSupportedChainsResult } from '@phantom/browser-injected-sdk/auto-confirm';
9
9
  export { NetworkId, PHANTOM_ICON } from '@phantom/constants';
10
+ export { base64urlDecode, base64urlEncode } from '@phantom/base64url';
10
11
 
11
12
  declare enum DebugLevel {
12
13
  ERROR = 0,
package/dist/index.js CHANGED
@@ -34,8 +34,10 @@ __export(src_exports, {
34
34
  BrowserSDK: () => BrowserSDK,
35
35
  DebugCategory: () => DebugCategory,
36
36
  DebugLevel: () => DebugLevel,
37
- NetworkId: () => import_constants7.NetworkId,
38
- PHANTOM_ICON: () => import_constants8.PHANTOM_ICON,
37
+ NetworkId: () => import_constants8.NetworkId,
38
+ PHANTOM_ICON: () => import_constants9.PHANTOM_ICON,
39
+ base64urlDecode: () => import_base64url2.base64urlDecode,
40
+ base64urlEncode: () => import_base64url2.base64urlEncode,
39
41
  debug: () => debug,
40
42
  detectBrowser: () => detectBrowser,
41
43
  getBrowserDisplayName: () => getBrowserDisplayName,
@@ -2764,7 +2766,7 @@ var BrowserAuthProvider = class {
2764
2766
  // OAuth session management - defaults to allow refresh unless explicitly clearing after logout
2765
2767
  clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
2766
2768
  allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
2767
- sdk_version: "1.0.5",
2769
+ sdk_version: "1.0.7",
2768
2770
  sdk_type: "browser",
2769
2771
  platform: detectBrowser().name,
2770
2772
  algorithm: phantomOptions.algorithm || import_constants3.DEFAULT_AUTHENTICATOR_ALGORITHM
@@ -2965,14 +2967,14 @@ var Auth2AuthProvider = class {
2965
2967
  const description = this.urlParamsAccessor.getParam("error_description");
2966
2968
  throw new Error(`Auth2 callback error: ${description ?? error}`);
2967
2969
  }
2968
- const { idToken, bearerToken, authUserId, expiresInMs } = await (0, import_auth2.exchangeAuthCode)({
2970
+ const { idToken, bearerToken, authUserId, expiresInMs, refreshToken } = await (0, import_auth2.exchangeAuthCode)({
2969
2971
  authApiBaseUrl: this.auth2ProviderOptions.authApiBaseUrl,
2970
2972
  clientId: this.auth2ProviderOptions.clientId,
2971
2973
  redirectUri: this.auth2ProviderOptions.redirectUri,
2972
2974
  code,
2973
2975
  codeVerifier
2974
2976
  });
2975
- await this.stamper.setIdToken(idToken);
2977
+ await this.stamper.setTokens({ idToken, bearerToken, refreshToken, expiresInMs });
2976
2978
  await this.storage.saveSession({
2977
2979
  ...session,
2978
2980
  status: "completed",
@@ -2999,19 +3001,27 @@ var Auth2AuthProvider = class {
2999
3001
  var import_bs582 = __toESM(require("bs58"));
3000
3002
  var import_base64url = require("@phantom/base64url");
3001
3003
  var import_sdk_types = require("@phantom/sdk-types");
3004
+ var import_auth22 = require("@phantom/auth2");
3005
+ var import_constants4 = require("@phantom/constants");
3002
3006
  var STORE_NAME = "crypto-keys";
3003
3007
  var ACTIVE_KEY = "auth2-p256-signing-key";
3004
3008
  var Auth2Stamper = class {
3005
3009
  /**
3006
3010
  * @param dbName - IndexedDB database name (use a unique name per app to
3007
3011
  * avoid key collisions with other stampers, e.g. `phantom-auth2-<appId>`).
3012
+ * @param refreshConfig - When provided, the stamper will automatically refresh
3013
+ * the id_token using the refresh_token before it expires.
3008
3014
  */
3009
- constructor(dbName) {
3015
+ constructor(dbName, refreshConfig) {
3010
3016
  this.dbName = dbName;
3017
+ this.refreshConfig = refreshConfig;
3011
3018
  this.db = null;
3012
3019
  this._keyPair = null;
3013
3020
  this._keyInfo = null;
3014
3021
  this._idToken = null;
3022
+ this._bearerToken = null;
3023
+ this._refreshToken = null;
3024
+ this._tokenExpiresAt = null;
3015
3025
  this.algorithm = import_sdk_types.Algorithm.secp256r1;
3016
3026
  this.type = "OIDC";
3017
3027
  }
@@ -3024,6 +3034,15 @@ var Auth2Stamper = class {
3024
3034
  if (stored.idToken) {
3025
3035
  this._idToken = stored.idToken;
3026
3036
  }
3037
+ if (stored.bearerToken) {
3038
+ this._bearerToken = stored.bearerToken;
3039
+ }
3040
+ if (stored.refreshToken) {
3041
+ this._refreshToken = stored.refreshToken;
3042
+ }
3043
+ if (stored.tokenExpiresAt) {
3044
+ this._tokenExpiresAt = stored.tokenExpiresAt;
3045
+ }
3027
3046
  return this._keyInfo;
3028
3047
  }
3029
3048
  return this.generateAndStore();
@@ -3035,19 +3054,61 @@ var Auth2Stamper = class {
3035
3054
  return this._keyPair;
3036
3055
  }
3037
3056
  /**
3038
- * Arms the stamper with the OIDC id token for subsequent KMS stamp() calls.
3057
+ * Returns the current token state (refreshing proactively if near expiry),
3058
+ * or null if no token has been set yet.
3059
+ */
3060
+ async getTokens() {
3061
+ if (this.refreshConfig && this._refreshToken && this._tokenExpiresAt !== null && Date.now() >= this._tokenExpiresAt - import_constants4.TOKEN_REFRESH_BUFFER_MS) {
3062
+ const refreshed = await (0, import_auth22.refreshToken)({
3063
+ authApiBaseUrl: this.refreshConfig.authApiBaseUrl,
3064
+ clientId: this.refreshConfig.clientId,
3065
+ redirectUri: this.refreshConfig.redirectUri,
3066
+ refreshToken: this._refreshToken
3067
+ });
3068
+ await this.setTokens(refreshed);
3069
+ }
3070
+ if (!this._idToken || !this._bearerToken) {
3071
+ return null;
3072
+ }
3073
+ return {
3074
+ idToken: this._idToken,
3075
+ bearerToken: this._bearerToken,
3076
+ refreshToken: this._refreshToken ?? void 0
3077
+ };
3078
+ }
3079
+ /**
3080
+ * Arms the stamper with the OIDC token data for subsequent KMS stamp() calls.
3081
+ *
3082
+ * Persists the tokens to IndexedDB alongside the key pair so that
3083
+ * auto-connect can restore them on the next page load without a new login.
3039
3084
  *
3040
- * Persists the token to IndexedDB alongside the key pair so that
3041
- * auto-connect can restore it on the next page load without a new login.
3085
+ * @param refreshToken - When provided alongside a `refreshConfig`, enables
3086
+ * silent token refresh before the token expires.
3087
+ * @param expiresInMs - Token lifetime in milliseconds (from `expires_in * 1000`).
3088
+ * Used to compute the absolute expiry time for proactive refresh.
3042
3089
  */
3043
- async setIdToken(idToken) {
3090
+ async setTokens({
3091
+ idToken,
3092
+ bearerToken,
3093
+ refreshToken,
3094
+ expiresInMs
3095
+ }) {
3044
3096
  if (!this.db) {
3045
3097
  await this.openDB();
3046
3098
  }
3047
3099
  this._idToken = idToken;
3100
+ this._bearerToken = bearerToken;
3101
+ this._refreshToken = refreshToken ?? null;
3102
+ this._tokenExpiresAt = expiresInMs != null ? Date.now() + expiresInMs : null;
3048
3103
  const existing = await this.loadRecord();
3049
3104
  if (existing) {
3050
- await this.storeRecord({ ...existing, idToken });
3105
+ await this.storeRecord({
3106
+ ...existing,
3107
+ idToken,
3108
+ bearerToken,
3109
+ refreshToken,
3110
+ tokenExpiresAt: this._tokenExpiresAt ?? void 0
3111
+ });
3051
3112
  }
3052
3113
  }
3053
3114
  async stamp(params) {
@@ -3080,6 +3141,9 @@ var Auth2Stamper = class {
3080
3141
  this._keyPair = null;
3081
3142
  this._keyInfo = null;
3082
3143
  this._idToken = null;
3144
+ this._bearerToken = null;
3145
+ this._refreshToken = null;
3146
+ this._tokenExpiresAt = null;
3083
3147
  }
3084
3148
  // Auth2 doesn't use key rotation; provide minimal no-op implementations.
3085
3149
  async rotateKeyPair() {
@@ -3276,28 +3340,32 @@ var BrowserPhantomAppProvider = class {
3276
3340
 
3277
3341
  // src/providers/embedded/adapters/logger.ts
3278
3342
  var BrowserLogger = class {
3279
- info(category, message, data) {
3280
- debug.info(category, message, data);
3343
+ info(message, ...args) {
3344
+ debug.info(message, args.length > 0 ? String(args[0]) : "", args[1]);
3281
3345
  }
3282
- warn(category, message, data) {
3283
- debug.warn(category, message, data);
3346
+ warn(message, ...args) {
3347
+ debug.warn(message, args.length > 0 ? String(args[0]) : "", args[1]);
3284
3348
  }
3285
- error(category, message, data) {
3286
- debug.error(category, message, data);
3349
+ error(message, ...args) {
3350
+ debug.error(message, args.length > 0 ? String(args[0]) : "", args[1]);
3287
3351
  }
3288
- log(category, message, data) {
3289
- debug.log(category, message, data);
3352
+ debug(message, ...args) {
3353
+ debug.log(message, args.length > 0 ? String(args[0]) : "", args[1]);
3290
3354
  }
3291
3355
  };
3292
3356
 
3293
3357
  // src/providers/embedded/index.ts
3294
- var import_constants4 = require("@phantom/constants");
3358
+ var import_constants5 = require("@phantom/constants");
3295
3359
  var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvider {
3296
3360
  constructor(config) {
3297
3361
  debug.log(DebugCategory.EMBEDDED_PROVIDER, "Initializing Browser EmbeddedProvider", { config });
3298
3362
  const urlParamsAccessor = new BrowserURLParamsAccessor();
3299
3363
  const storage = new BrowserStorage();
3300
- const stamper = config.unstable__auth2Options ? new Auth2Stamper(`phantom-auth2-${config.appId}`) : new import_indexed_db_stamper.IndexedDbStamper({
3364
+ const stamper = config.unstable__auth2Options ? new Auth2Stamper(`phantom-auth2-${config.appId}`, {
3365
+ authApiBaseUrl: config.unstable__auth2Options.authApiBaseUrl,
3366
+ clientId: config.unstable__auth2Options.clientId,
3367
+ redirectUri: config.authOptions?.redirectUrl ?? ""
3368
+ }) : new import_indexed_db_stamper.IndexedDbStamper({
3301
3369
  dbName: `phantom-embedded-sdk-${config.appId}`,
3302
3370
  storeName: "crypto-keys",
3303
3371
  keyName: "signing-key"
@@ -3328,13 +3396,13 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
3328
3396
  name: platformName,
3329
3397
  // Use detected browser name and version for identification
3330
3398
  analyticsHeaders: {
3331
- [import_constants4.ANALYTICS_HEADERS.SDK_TYPE]: "browser",
3332
- [import_constants4.ANALYTICS_HEADERS.PLATFORM]: "ext-sdk",
3333
- [import_constants4.ANALYTICS_HEADERS.PLATFORM_VERSION]: version,
3334
- [import_constants4.ANALYTICS_HEADERS.CLIENT]: browserName,
3335
- [import_constants4.ANALYTICS_HEADERS.APP_ID]: config.appId,
3336
- [import_constants4.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
3337
- [import_constants4.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.5"
3399
+ [import_constants5.ANALYTICS_HEADERS.SDK_TYPE]: "browser",
3400
+ [import_constants5.ANALYTICS_HEADERS.PLATFORM]: "ext-sdk",
3401
+ [import_constants5.ANALYTICS_HEADERS.PLATFORM_VERSION]: version,
3402
+ [import_constants5.ANALYTICS_HEADERS.CLIENT]: browserName,
3403
+ [import_constants5.ANALYTICS_HEADERS.APP_ID]: config.appId,
3404
+ [import_constants5.ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
3405
+ [import_constants5.ANALYTICS_HEADERS.SDK_VERSION]: "1.0.7"
3338
3406
  // Replaced at build time
3339
3407
  }
3340
3408
  };
@@ -3351,7 +3419,7 @@ var EmbeddedProvider = class extends import_embedded_provider_core.EmbeddedProvi
3351
3419
 
3352
3420
  // src/ProviderManager.ts
3353
3421
  var import_embedded_provider_core2 = require("@phantom/embedded-provider-core");
3354
- var import_constants5 = require("@phantom/constants");
3422
+ var import_constants6 = require("@phantom/constants");
3355
3423
 
3356
3424
  // src/utils/auth-callback.ts
3357
3425
  function isAuthFailureCallback(searchParams) {
@@ -3742,8 +3810,8 @@ var ProviderManager = class {
3742
3810
  if (!this.config.appId) {
3743
3811
  throw new Error("appId is required for embedded provider");
3744
3812
  }
3745
- const apiBaseUrl = this.config.apiBaseUrl || import_constants5.DEFAULT_WALLET_API_URL;
3746
- const authUrl = this.config.authOptions?.authUrl || import_constants5.DEFAULT_AUTH_URL;
3813
+ const apiBaseUrl = this.config.apiBaseUrl || import_constants6.DEFAULT_WALLET_API_URL;
3814
+ const authUrl = this.config.authOptions?.authUrl || import_constants6.DEFAULT_AUTH_URL;
3747
3815
  provider = new EmbeddedProvider({
3748
3816
  apiBaseUrl,
3749
3817
  appId: this.config.appId,
@@ -3753,7 +3821,7 @@ var ProviderManager = class {
3753
3821
  redirectUrl: this.config.authOptions?.redirectUrl || this.getValidatedCurrentUrl()
3754
3822
  },
3755
3823
  unstable__auth2Options: this.config.unstable__auth2Options,
3756
- embeddedWalletType: embeddedWalletType || import_constants5.DEFAULT_EMBEDDED_WALLET_TYPE,
3824
+ embeddedWalletType: embeddedWalletType || import_constants6.DEFAULT_EMBEDDED_WALLET_TYPE,
3757
3825
  addressTypes: this.config.addressTypes || [import_client.AddressType.solana]
3758
3826
  });
3759
3827
  } else {
@@ -3789,7 +3857,7 @@ var ProviderManager = class {
3789
3857
 
3790
3858
  // src/BrowserSDK.ts
3791
3859
  var import_embedded_provider_core3 = require("@phantom/embedded-provider-core");
3792
- var import_constants6 = require("@phantom/constants");
3860
+ var import_constants7 = require("@phantom/constants");
3793
3861
  var BROWSER_SDK_PROVIDER_TYPES = [
3794
3862
  ...import_embedded_provider_core3.EMBEDDED_PROVIDER_AUTH_TYPES,
3795
3863
  "injected",
@@ -3825,7 +3893,7 @@ var BrowserSDK = class {
3825
3893
  });
3826
3894
  throw new Error("appId is required when using embedded providers (google, apple, phantom, etc.)");
3827
3895
  }
3828
- const embeddedWalletType = config.embeddedWalletType || import_constants6.DEFAULT_EMBEDDED_WALLET_TYPE;
3896
+ const embeddedWalletType = config.embeddedWalletType || import_constants7.DEFAULT_EMBEDDED_WALLET_TYPE;
3829
3897
  if (!["app-wallet", "user-wallet"].includes(embeddedWalletType)) {
3830
3898
  debug.error(DebugCategory.BROWSER_SDK, "Invalid embeddedWalletType", {
3831
3899
  embeddedWalletType: config.embeddedWalletType
@@ -4100,6 +4168,7 @@ var BrowserSDK = class {
4100
4168
  };
4101
4169
 
4102
4170
  // src/index.ts
4103
- var import_constants7 = require("@phantom/constants");
4104
- var import_client5 = require("@phantom/client");
4105
4171
  var import_constants8 = require("@phantom/constants");
4172
+ var import_client5 = require("@phantom/client");
4173
+ var import_base64url2 = require("@phantom/base64url");
4174
+ var import_constants9 = require("@phantom/constants");
package/dist/index.mjs CHANGED
@@ -2714,7 +2714,7 @@ var BrowserAuthProvider = class {
2714
2714
  // OAuth session management - defaults to allow refresh unless explicitly clearing after logout
2715
2715
  clear_previous_session: (phantomOptions.clearPreviousSession ?? false).toString(),
2716
2716
  allow_refresh: (phantomOptions.allowRefresh ?? true).toString(),
2717
- sdk_version: "1.0.5",
2717
+ sdk_version: "1.0.7",
2718
2718
  sdk_type: "browser",
2719
2719
  platform: detectBrowser().name,
2720
2720
  algorithm: phantomOptions.algorithm || DEFAULT_AUTHENTICATOR_ALGORITHM
@@ -2920,14 +2920,14 @@ var Auth2AuthProvider = class {
2920
2920
  const description = this.urlParamsAccessor.getParam("error_description");
2921
2921
  throw new Error(`Auth2 callback error: ${description ?? error}`);
2922
2922
  }
2923
- const { idToken, bearerToken, authUserId, expiresInMs } = await exchangeAuthCode({
2923
+ const { idToken, bearerToken, authUserId, expiresInMs, refreshToken } = await exchangeAuthCode({
2924
2924
  authApiBaseUrl: this.auth2ProviderOptions.authApiBaseUrl,
2925
2925
  clientId: this.auth2ProviderOptions.clientId,
2926
2926
  redirectUri: this.auth2ProviderOptions.redirectUri,
2927
2927
  code,
2928
2928
  codeVerifier
2929
2929
  });
2930
- await this.stamper.setIdToken(idToken);
2930
+ await this.stamper.setTokens({ idToken, bearerToken, refreshToken, expiresInMs });
2931
2931
  await this.storage.saveSession({
2932
2932
  ...session,
2933
2933
  status: "completed",
@@ -2954,19 +2954,27 @@ var Auth2AuthProvider = class {
2954
2954
  import bs582 from "bs58";
2955
2955
  import { base64urlEncode } from "@phantom/base64url";
2956
2956
  import { Algorithm } from "@phantom/sdk-types";
2957
+ import { refreshToken as refreshTokenRequest } from "@phantom/auth2";
2958
+ import { TOKEN_REFRESH_BUFFER_MS } from "@phantom/constants";
2957
2959
  var STORE_NAME = "crypto-keys";
2958
2960
  var ACTIVE_KEY = "auth2-p256-signing-key";
2959
2961
  var Auth2Stamper = class {
2960
2962
  /**
2961
2963
  * @param dbName - IndexedDB database name (use a unique name per app to
2962
2964
  * avoid key collisions with other stampers, e.g. `phantom-auth2-<appId>`).
2965
+ * @param refreshConfig - When provided, the stamper will automatically refresh
2966
+ * the id_token using the refresh_token before it expires.
2963
2967
  */
2964
- constructor(dbName) {
2968
+ constructor(dbName, refreshConfig) {
2965
2969
  this.dbName = dbName;
2970
+ this.refreshConfig = refreshConfig;
2966
2971
  this.db = null;
2967
2972
  this._keyPair = null;
2968
2973
  this._keyInfo = null;
2969
2974
  this._idToken = null;
2975
+ this._bearerToken = null;
2976
+ this._refreshToken = null;
2977
+ this._tokenExpiresAt = null;
2970
2978
  this.algorithm = Algorithm.secp256r1;
2971
2979
  this.type = "OIDC";
2972
2980
  }
@@ -2979,6 +2987,15 @@ var Auth2Stamper = class {
2979
2987
  if (stored.idToken) {
2980
2988
  this._idToken = stored.idToken;
2981
2989
  }
2990
+ if (stored.bearerToken) {
2991
+ this._bearerToken = stored.bearerToken;
2992
+ }
2993
+ if (stored.refreshToken) {
2994
+ this._refreshToken = stored.refreshToken;
2995
+ }
2996
+ if (stored.tokenExpiresAt) {
2997
+ this._tokenExpiresAt = stored.tokenExpiresAt;
2998
+ }
2982
2999
  return this._keyInfo;
2983
3000
  }
2984
3001
  return this.generateAndStore();
@@ -2990,19 +3007,61 @@ var Auth2Stamper = class {
2990
3007
  return this._keyPair;
2991
3008
  }
2992
3009
  /**
2993
- * Arms the stamper with the OIDC id token for subsequent KMS stamp() calls.
3010
+ * Returns the current token state (refreshing proactively if near expiry),
3011
+ * or null if no token has been set yet.
3012
+ */
3013
+ async getTokens() {
3014
+ if (this.refreshConfig && this._refreshToken && this._tokenExpiresAt !== null && Date.now() >= this._tokenExpiresAt - TOKEN_REFRESH_BUFFER_MS) {
3015
+ const refreshed = await refreshTokenRequest({
3016
+ authApiBaseUrl: this.refreshConfig.authApiBaseUrl,
3017
+ clientId: this.refreshConfig.clientId,
3018
+ redirectUri: this.refreshConfig.redirectUri,
3019
+ refreshToken: this._refreshToken
3020
+ });
3021
+ await this.setTokens(refreshed);
3022
+ }
3023
+ if (!this._idToken || !this._bearerToken) {
3024
+ return null;
3025
+ }
3026
+ return {
3027
+ idToken: this._idToken,
3028
+ bearerToken: this._bearerToken,
3029
+ refreshToken: this._refreshToken ?? void 0
3030
+ };
3031
+ }
3032
+ /**
3033
+ * Arms the stamper with the OIDC token data for subsequent KMS stamp() calls.
2994
3034
  *
2995
- * Persists the token to IndexedDB alongside the key pair so that
2996
- * auto-connect can restore it on the next page load without a new login.
3035
+ * Persists the tokens to IndexedDB alongside the key pair so that
3036
+ * auto-connect can restore them on the next page load without a new login.
3037
+ *
3038
+ * @param refreshToken - When provided alongside a `refreshConfig`, enables
3039
+ * silent token refresh before the token expires.
3040
+ * @param expiresInMs - Token lifetime in milliseconds (from `expires_in * 1000`).
3041
+ * Used to compute the absolute expiry time for proactive refresh.
2997
3042
  */
2998
- async setIdToken(idToken) {
3043
+ async setTokens({
3044
+ idToken,
3045
+ bearerToken,
3046
+ refreshToken,
3047
+ expiresInMs
3048
+ }) {
2999
3049
  if (!this.db) {
3000
3050
  await this.openDB();
3001
3051
  }
3002
3052
  this._idToken = idToken;
3053
+ this._bearerToken = bearerToken;
3054
+ this._refreshToken = refreshToken ?? null;
3055
+ this._tokenExpiresAt = expiresInMs != null ? Date.now() + expiresInMs : null;
3003
3056
  const existing = await this.loadRecord();
3004
3057
  if (existing) {
3005
- await this.storeRecord({ ...existing, idToken });
3058
+ await this.storeRecord({
3059
+ ...existing,
3060
+ idToken,
3061
+ bearerToken,
3062
+ refreshToken,
3063
+ tokenExpiresAt: this._tokenExpiresAt ?? void 0
3064
+ });
3006
3065
  }
3007
3066
  }
3008
3067
  async stamp(params) {
@@ -3035,6 +3094,9 @@ var Auth2Stamper = class {
3035
3094
  this._keyPair = null;
3036
3095
  this._keyInfo = null;
3037
3096
  this._idToken = null;
3097
+ this._bearerToken = null;
3098
+ this._refreshToken = null;
3099
+ this._tokenExpiresAt = null;
3038
3100
  }
3039
3101
  // Auth2 doesn't use key rotation; provide minimal no-op implementations.
3040
3102
  async rotateKeyPair() {
@@ -3231,17 +3293,17 @@ var BrowserPhantomAppProvider = class {
3231
3293
 
3232
3294
  // src/providers/embedded/adapters/logger.ts
3233
3295
  var BrowserLogger = class {
3234
- info(category, message, data) {
3235
- debug.info(category, message, data);
3296
+ info(message, ...args) {
3297
+ debug.info(message, args.length > 0 ? String(args[0]) : "", args[1]);
3236
3298
  }
3237
- warn(category, message, data) {
3238
- debug.warn(category, message, data);
3299
+ warn(message, ...args) {
3300
+ debug.warn(message, args.length > 0 ? String(args[0]) : "", args[1]);
3239
3301
  }
3240
- error(category, message, data) {
3241
- debug.error(category, message, data);
3302
+ error(message, ...args) {
3303
+ debug.error(message, args.length > 0 ? String(args[0]) : "", args[1]);
3242
3304
  }
3243
- log(category, message, data) {
3244
- debug.log(category, message, data);
3305
+ debug(message, ...args) {
3306
+ debug.log(message, args.length > 0 ? String(args[0]) : "", args[1]);
3245
3307
  }
3246
3308
  };
3247
3309
 
@@ -3252,7 +3314,11 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
3252
3314
  debug.log(DebugCategory.EMBEDDED_PROVIDER, "Initializing Browser EmbeddedProvider", { config });
3253
3315
  const urlParamsAccessor = new BrowserURLParamsAccessor();
3254
3316
  const storage = new BrowserStorage();
3255
- const stamper = config.unstable__auth2Options ? new Auth2Stamper(`phantom-auth2-${config.appId}`) : new IndexedDbStamper({
3317
+ const stamper = config.unstable__auth2Options ? new Auth2Stamper(`phantom-auth2-${config.appId}`, {
3318
+ authApiBaseUrl: config.unstable__auth2Options.authApiBaseUrl,
3319
+ clientId: config.unstable__auth2Options.clientId,
3320
+ redirectUri: config.authOptions?.redirectUrl ?? ""
3321
+ }) : new IndexedDbStamper({
3256
3322
  dbName: `phantom-embedded-sdk-${config.appId}`,
3257
3323
  storeName: "crypto-keys",
3258
3324
  keyName: "signing-key"
@@ -3289,7 +3355,7 @@ var EmbeddedProvider = class extends CoreEmbeddedProvider {
3289
3355
  [ANALYTICS_HEADERS.CLIENT]: browserName,
3290
3356
  [ANALYTICS_HEADERS.APP_ID]: config.appId,
3291
3357
  [ANALYTICS_HEADERS.WALLET_TYPE]: config.embeddedWalletType,
3292
- [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.5"
3358
+ [ANALYTICS_HEADERS.SDK_VERSION]: "1.0.7"
3293
3359
  // Replaced at build time
3294
3360
  }
3295
3361
  };
@@ -4059,6 +4125,7 @@ var BrowserSDK = class {
4059
4125
  // src/index.ts
4060
4126
  import { NetworkId } from "@phantom/constants";
4061
4127
  import { AddressType as AddressType4 } from "@phantom/client";
4128
+ import { base64urlEncode as base64urlEncode2, base64urlDecode } from "@phantom/base64url";
4062
4129
  import { PHANTOM_ICON as PHANTOM_ICON3 } from "@phantom/constants";
4063
4130
  export {
4064
4131
  AddressType4 as AddressType,
@@ -4067,6 +4134,8 @@ export {
4067
4134
  DebugLevel,
4068
4135
  NetworkId,
4069
4136
  PHANTOM_ICON3 as PHANTOM_ICON,
4137
+ base64urlDecode,
4138
+ base64urlEncode2 as base64urlEncode,
4070
4139
  debug,
4071
4140
  detectBrowser,
4072
4141
  getBrowserDisplayName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phantom/browser-sdk",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Browser SDK for Phantom Wallet",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,16 +33,16 @@
33
33
  "prettier": "prettier --write \"src/**/*.{ts,tsx}\""
34
34
  },
35
35
  "dependencies": {
36
- "@phantom/auth2": "^1.0.1",
37
- "@phantom/base64url": "^1.0.5",
38
- "@phantom/browser-injected-sdk": "^1.0.5",
39
- "@phantom/chain-interfaces": "^1.0.5",
40
- "@phantom/client": "^1.0.5",
41
- "@phantom/constants": "^1.0.5",
42
- "@phantom/embedded-provider-core": "^1.0.5",
43
- "@phantom/indexed-db-stamper": "^1.0.5",
44
- "@phantom/parsers": "^1.0.5",
45
- "@phantom/sdk-types": "^1.0.5",
36
+ "@phantom/auth2": "^1.0.2",
37
+ "@phantom/base64url": "^1.0.7",
38
+ "@phantom/browser-injected-sdk": "^1.0.7",
39
+ "@phantom/chain-interfaces": "^1.0.7",
40
+ "@phantom/client": "^1.0.7",
41
+ "@phantom/constants": "^1.0.7",
42
+ "@phantom/embedded-provider-core": "^1.0.7",
43
+ "@phantom/indexed-db-stamper": "^1.0.7",
44
+ "@phantom/parsers": "^1.0.7",
45
+ "@phantom/sdk-types": "^1.0.7",
46
46
  "axios": "^1.10.0",
47
47
  "bs58": "^6.0.0",
48
48
  "buffer": "^6.0.3",