@x402/extensions 2.3.0 → 2.3.1

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.
@@ -315,10 +315,10 @@ interface EVMSigner {
315
315
  address?: string;
316
316
  }
317
317
  /**
318
- * Signer interface for Solana SIWX message signing.
319
- * Compatible with @solana/wallet-adapter and Phantom/Solflare wallet APIs.
318
+ * Wallet adapter style Solana signer.
319
+ * Compatible with @solana/wallet-adapter, Phantom/Solflare wallet APIs.
320
320
  */
321
- interface SolanaSigner {
321
+ interface WalletAdapterSigner {
322
322
  /** Sign a message and return raw signature bytes */
323
323
  signMessage: (message: Uint8Array) => Promise<Uint8Array>;
324
324
  /** Solana public key (Base58 encoded string or PublicKey-like object) */
@@ -326,6 +326,23 @@ interface SolanaSigner {
326
326
  toBase58: () => string;
327
327
  };
328
328
  }
329
+ /**
330
+ * Solana Kit KeyPairSigner style.
331
+ * Compatible with createKeyPairSignerFromBytes and generateKeyPairSigner from @solana/kit.
332
+ */
333
+ type SolanaKitSigner = {
334
+ /** Solana address (Base58 encoded string) */
335
+ address: string;
336
+ /** Sign messages - accepts messages with content and signatures */
337
+ signMessages: (messages: Array<{
338
+ content: Uint8Array;
339
+ signatures: Record<string, unknown>;
340
+ }>) => Promise<Array<Record<string, Uint8Array>>>;
341
+ };
342
+ /**
343
+ * Union type for Solana signers - supports both wallet adapter and @solana/kit.
344
+ */
345
+ type SolanaSigner = WalletAdapterSigner | SolanaKitSigner;
329
346
  /**
330
347
  * Union type for SIWX signers - supports both EVM and Solana wallets.
331
348
  */
@@ -339,6 +356,7 @@ type SIWxSigner = EVMSigner | SolanaSigner;
339
356
  declare function getEVMAddress(signer: EVMSigner): string;
340
357
  /**
341
358
  * Get address from a Solana signer.
359
+ * Supports both wallet adapter (publicKey) and @solana/kit (address) interfaces.
342
360
  *
343
361
  * @param signer - Solana wallet signer instance
344
362
  * @returns The wallet address as a Base58 string
@@ -356,6 +374,7 @@ declare function signEVMMessage(message: string, signer: EVMSigner): Promise<str
356
374
  /**
357
375
  * Sign a message with a Solana wallet.
358
376
  * Returns Base58-encoded signature.
377
+ * Supports both wallet adapter (signMessage) and @solana/kit (signMessages) interfaces.
359
378
  *
360
379
  * @param message - The message to sign
361
380
  * @param signer - Solana wallet signer instance
@@ -490,6 +509,14 @@ declare function decodeBase58(encoded: string): Uint8Array;
490
509
  * @returns Base58 encoded string
491
510
  */
492
511
  declare function encodeBase58(bytes: Uint8Array): string;
512
+ /**
513
+ * Detect if a signer is Solana-compatible.
514
+ * Checks for Solana-specific properties that don't exist on EVM signers.
515
+ *
516
+ * @param signer - The signer to check
517
+ * @returns true if the signer is a Solana signer
518
+ */
519
+ declare function isSolanaSigner(signer: SIWxSigner): boolean;
493
520
 
494
521
  /**
495
522
  * Server-side declaration helper for SIWX extension
@@ -869,6 +896,14 @@ declare function formatSIWEMessage(info: CompleteSIWxInfo, address: string): str
869
896
  * ```
870
897
  */
871
898
  declare function verifyEVMSignature(message: string, address: string, signature: string, verifier?: EVMMessageVerifier): Promise<boolean>;
899
+ /**
900
+ * Detect if a signer is EVM-compatible.
901
+ * Checks for EVM-specific properties.
902
+ *
903
+ * @param signer - The signer to check
904
+ * @returns true if the signer is an EVM signer
905
+ */
906
+ declare function isEVMSigner(signer: SIWxSigner): boolean;
872
907
 
873
908
  /**
874
909
  * Storage interface for SIWX payment tracking.
@@ -1029,8 +1064,9 @@ declare function createSIWxRequestHook(options: CreateSIWxHookOptions): (context
1029
1064
  /**
1030
1065
  * Creates an onPaymentRequired hook for client-side SIWX authentication.
1031
1066
  *
1032
- * Uses the network from payment requirements to select the appropriate chain
1033
- * from the server's supportedChains.
1067
+ * Matches the signer type to a compatible chain in supportedChains.
1068
+ * For EVM signers: matches any eip191 chain
1069
+ * For Solana signers: matches any ed25519 chain
1034
1070
  *
1035
1071
  * @param signer - Wallet signer for creating SIWX proofs
1036
1072
  * @returns Hook function for x402HTTPClient.onPaymentRequired()
@@ -1052,4 +1088,4 @@ declare function createSIWxClientHook(signer: SIWxSigner): (context: {
1052
1088
  headers: Record<string, string>;
1053
1089
  } | void>;
1054
1090
 
1055
- export { type CompleteSIWxInfo, type CreateSIWxHookOptions, type DeclareSIWxOptions, type EVMMessageVerifier, type EVMSigner, InMemorySIWxStorage, SIGN_IN_WITH_X, type SIWxExtension, type SIWxExtensionInfo, type SIWxExtensionSchema, type SIWxHookEvent, type SIWxPayload, SIWxPayloadSchema, type SIWxSigner, type SIWxStorage, type SIWxValidationOptions, type SIWxValidationResult, type SIWxVerifyOptions, type SIWxVerifyResult, SOLANA_DEVNET, SOLANA_MAINNET, SOLANA_TESTNET, type SignatureScheme, type SignatureType, type SolanaSigner, type SupportedChain, buildSIWxSchema, createSIWxClientHook, createSIWxMessage, createSIWxPayload, createSIWxRequestHook, createSIWxSettleHook, declareSIWxExtension, decodeBase58, encodeBase58, encodeSIWxHeader, extractEVMChainId, extractSolanaChainReference, formatSIWEMessage, formatSIWSMessage, getEVMAddress, getSolanaAddress, parseSIWxHeader, signEVMMessage, signSolanaMessage, siwxResourceServerExtension, validateSIWxMessage, verifyEVMSignature, verifySIWxSignature, verifySolanaSignature, wrapFetchWithSIWx };
1091
+ export { type CompleteSIWxInfo, type CreateSIWxHookOptions, type DeclareSIWxOptions, type EVMMessageVerifier, type EVMSigner, InMemorySIWxStorage, SIGN_IN_WITH_X, type SIWxExtension, type SIWxExtensionInfo, type SIWxExtensionSchema, type SIWxHookEvent, type SIWxPayload, SIWxPayloadSchema, type SIWxSigner, type SIWxStorage, type SIWxValidationOptions, type SIWxValidationResult, type SIWxVerifyOptions, type SIWxVerifyResult, SOLANA_DEVNET, SOLANA_MAINNET, SOLANA_TESTNET, type SignatureScheme, type SignatureType, type SolanaSigner, type SupportedChain, buildSIWxSchema, createSIWxClientHook, createSIWxMessage, createSIWxPayload, createSIWxRequestHook, createSIWxSettleHook, declareSIWxExtension, decodeBase58, encodeBase58, encodeSIWxHeader, extractEVMChainId, extractSolanaChainReference, formatSIWEMessage, formatSIWSMessage, getEVMAddress, getSolanaAddress, isEVMSigner, isSolanaSigner, parseSIWxHeader, signEVMMessage, signSolanaMessage, siwxResourceServerExtension, validateSIWxMessage, verifyEVMSignature, verifySIWxSignature, verifySolanaSignature, wrapFetchWithSIWx };
@@ -52,6 +52,8 @@ __export(sign_in_with_x_exports, {
52
52
  formatSIWSMessage: () => formatSIWSMessage,
53
53
  getEVMAddress: () => getEVMAddress,
54
54
  getSolanaAddress: () => getSolanaAddress,
55
+ isEVMSigner: () => isEVMSigner,
56
+ isSolanaSigner: () => isSolanaSigner,
55
57
  parseSIWxHeader: () => parseSIWxHeader,
56
58
  signEVMMessage: () => signEVMMessage,
57
59
  signSolanaMessage: () => signSolanaMessage,
@@ -138,6 +140,21 @@ function decodeBase58(encoded) {
138
140
  function encodeBase58(bytes) {
139
141
  return import_base.base58.encode(bytes);
140
142
  }
143
+ function isSolanaSigner(signer) {
144
+ if ("signMessages" in signer && typeof signer.signMessages === "function") {
145
+ return true;
146
+ }
147
+ if ("publicKey" in signer && signer.publicKey) {
148
+ const pk = signer.publicKey;
149
+ if (typeof pk === "object" && pk !== null && "toBase58" in pk) {
150
+ return true;
151
+ }
152
+ if (typeof pk === "string" && !pk.startsWith("0x")) {
153
+ return true;
154
+ }
155
+ }
156
+ return false;
157
+ }
141
158
 
142
159
  // src/sign-in-with-x/schema.ts
143
160
  function buildSIWxSchema() {
@@ -402,6 +419,30 @@ async function verifyEVMSignature(message, address, signature, verifier) {
402
419
  }
403
420
  return (0, import_viem.verifyMessage)(args);
404
421
  }
422
+ function isEVMSigner(signer) {
423
+ if ("signMessages" in signer && typeof signer.signMessages === "function") {
424
+ return false;
425
+ }
426
+ if ("publicKey" in signer && signer.publicKey) {
427
+ const pk = signer.publicKey;
428
+ if (typeof pk === "object" && pk !== null && "toBase58" in pk) {
429
+ return false;
430
+ }
431
+ if (typeof pk === "string" && !pk.startsWith("0x")) {
432
+ return false;
433
+ }
434
+ }
435
+ if ("account" in signer && signer.account && typeof signer.account === "object") {
436
+ const account = signer.account;
437
+ if (account.address && account.address.startsWith("0x")) {
438
+ return true;
439
+ }
440
+ }
441
+ if ("address" in signer && typeof signer.address === "string" && signer.address.startsWith("0x")) {
442
+ return true;
443
+ }
444
+ return false;
445
+ }
405
446
 
406
447
  // src/sign-in-with-x/verify.ts
407
448
  async function verifySIWxSignature(payload, options) {
@@ -538,8 +579,14 @@ function getEVMAddress(signer) {
538
579
  throw new Error("EVM signer missing address");
539
580
  }
540
581
  function getSolanaAddress(signer) {
541
- const pk = signer.publicKey;
542
- return typeof pk === "string" ? pk : pk.toBase58();
582
+ if ("address" in signer && signer.address) {
583
+ return signer.address;
584
+ }
585
+ if ("publicKey" in signer) {
586
+ const pk = signer.publicKey;
587
+ return typeof pk === "string" ? pk : pk.toBase58();
588
+ }
589
+ throw new Error("Solana signer missing address or publicKey");
543
590
  }
544
591
  async function signEVMMessage(message, signer) {
545
592
  if (signer.account) {
@@ -549,8 +596,17 @@ async function signEVMMessage(message, signer) {
549
596
  }
550
597
  async function signSolanaMessage(message, signer) {
551
598
  const messageBytes = new TextEncoder().encode(message);
552
- const signatureBytes = await signer.signMessage(messageBytes);
553
- return encodeBase58(signatureBytes);
599
+ if ("signMessages" in signer) {
600
+ const results = await signer.signMessages([{ content: messageBytes, signatures: {} }]);
601
+ const sigDict = results[0];
602
+ const signatureBytes = Object.values(sigDict)[0];
603
+ return encodeBase58(signatureBytes);
604
+ }
605
+ if ("signMessage" in signer) {
606
+ const signatureBytes = await signer.signMessage(messageBytes);
607
+ return encodeBase58(signatureBytes);
608
+ }
609
+ throw new Error("Solana signer missing signMessage or signMessages method");
554
610
  }
555
611
 
556
612
  // src/sign-in-with-x/client.ts
@@ -723,15 +779,15 @@ function createSIWxRequestHook(options) {
723
779
  };
724
780
  }
725
781
  function createSIWxClientHook(signer) {
782
+ const signerIsSolana = isSolanaSigner(signer);
783
+ const expectedSignatureType = signerIsSolana ? "ed25519" : "eip191";
726
784
  return async (context) => {
727
785
  const extensions = context.paymentRequired.extensions ?? {};
728
786
  const siwxExtension = extensions[SIGN_IN_WITH_X];
729
787
  if (!siwxExtension?.supportedChains) return;
730
788
  try {
731
- const paymentNetwork = context.paymentRequired.accepts?.[0]?.network;
732
- if (!paymentNetwork) return;
733
789
  const matchingChain = siwxExtension.supportedChains.find(
734
- (chain) => chain.chainId === paymentNetwork
790
+ (chain) => chain.type === expectedSignatureType
735
791
  );
736
792
  if (!matchingChain) {
737
793
  return;
@@ -772,6 +828,8 @@ function createSIWxClientHook(signer) {
772
828
  formatSIWSMessage,
773
829
  getEVMAddress,
774
830
  getSolanaAddress,
831
+ isEVMSigner,
832
+ isSolanaSigner,
775
833
  parseSIWxHeader,
776
834
  signEVMMessage,
777
835
  signSolanaMessage,