@agentcash/router 1.1.0 → 1.1.2

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.cjs CHANGED
@@ -366,6 +366,11 @@ var RouteRegistry = class {
366
366
  // src/orchestrate.ts
367
367
  var import_server2 = require("next/server");
368
368
 
369
+ // src/auth/normalize-wallet.ts
370
+ function normalizeWalletAddress(address) {
371
+ return address.startsWith("0x") ? address.toLowerCase() : address;
372
+ }
373
+
369
374
  // src/plugin.ts
370
375
  function createDefaultContext(meta) {
371
376
  const ctx = {
@@ -877,6 +882,23 @@ function getRequirementNetwork(requirements, fallback) {
877
882
  const network = requirements?.network;
878
883
  return typeof network === "string" ? network : fallback;
879
884
  }
885
+ function siwxSignatureType(network) {
886
+ return network.startsWith("solana:") ? "ed25519" : "eip191";
887
+ }
888
+ function getSupportedChains(x402Accepts, fallbackNetwork) {
889
+ const seen = /* @__PURE__ */ new Set();
890
+ const chains = [];
891
+ for (const accept of x402Accepts) {
892
+ if (accept.network && !seen.has(accept.network)) {
893
+ seen.add(accept.network);
894
+ chains.push({ chainId: accept.network, type: siwxSignatureType(accept.network) });
895
+ }
896
+ }
897
+ if (chains.length === 0) {
898
+ chains.push({ chainId: fallbackNetwork, type: siwxSignatureType(fallbackNetwork) });
899
+ }
900
+ return chains;
901
+ }
880
902
  function createRequestHandler(routeEntry, handler, deps) {
881
903
  async function invoke(request, meta, pluginCtx, wallet, account, parsedBody) {
882
904
  const ctx = {
@@ -1004,12 +1026,14 @@ function createRequestHandler(routeEntry, handler, deps) {
1004
1026
  if (!siwxHeader && routeEntry.authMode === "siwx") {
1005
1027
  const url = new URL(request.url);
1006
1028
  const nonce = crypto.randomUUID().replace(/-/g, "");
1029
+ const supportedChains = getSupportedChains(deps.x402Accepts, deps.network);
1030
+ const primaryChain = supportedChains[0];
1007
1031
  const siwxInfo = {
1008
1032
  domain: url.hostname,
1009
1033
  uri: request.url,
1010
1034
  version: "1",
1011
- chainId: deps.network,
1012
- type: "eip191",
1035
+ chainId: primaryChain.chainId,
1036
+ type: primaryChain.type,
1013
1037
  nonce,
1014
1038
  issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
1015
1039
  expirationTime: new Date(Date.now() + SIWX_CHALLENGE_EXPIRY_MS).toISOString(),
@@ -1033,7 +1057,7 @@ function createRequestHandler(routeEntry, handler, deps) {
1033
1057
  "sign-in-with-x": {
1034
1058
  info: siwxInfo,
1035
1059
  // supportedChains at top level required by MCP tools for chain detection
1036
- supportedChains: [{ chainId: deps.network, type: "eip191" }],
1060
+ supportedChains,
1037
1061
  ...siwxSchema ? { schema: siwxSchema } : {}
1038
1062
  }
1039
1063
  }
@@ -1069,7 +1093,7 @@ function createRequestHandler(routeEntry, handler, deps) {
1069
1093
  return response;
1070
1094
  }
1071
1095
  } else {
1072
- const wallet = siwx.wallet.toLowerCase();
1096
+ const wallet = normalizeWalletAddress(siwx.wallet);
1073
1097
  pluginCtx.setVerifiedWallet(wallet);
1074
1098
  if (routeEntry.authMode === "siwx") {
1075
1099
  firePluginHook(deps.plugin, "onAuthVerified", pluginCtx, {
@@ -1171,7 +1195,7 @@ function createRequestHandler(routeEntry, handler, deps) {
1171
1195
  if (!verify?.valid) return await build402(request, routeEntry, deps, meta, pluginCtx);
1172
1196
  const { payload: verifyPayload, requirements: verifyRequirements } = verify;
1173
1197
  const matchedNetwork = getRequirementNetwork(verifyRequirements, deps.network);
1174
- const wallet = verify.payer.toLowerCase();
1198
+ const wallet = normalizeWalletAddress(verify.payer);
1175
1199
  pluginCtx.setVerifiedWallet(wallet);
1176
1200
  firePluginHook(deps.plugin, "onPaymentVerified", pluginCtx, {
1177
1201
  protocol: "x402",
@@ -1194,6 +1218,12 @@ function createRequestHandler(routeEntry, handler, deps) {
1194
1218
  verifyPayload,
1195
1219
  verifyRequirements
1196
1220
  );
1221
+ if (!settle.result?.success) {
1222
+ const reason = settle.result?.errorReason || "x402 settlement returned success=false";
1223
+ const error = new Error(reason);
1224
+ error.errorReason = reason;
1225
+ throw error;
1226
+ }
1197
1227
  if (routeEntry.siwxEnabled) {
1198
1228
  try {
1199
1229
  await deps.entitlementStore.grant(routeEntry.key, wallet);
@@ -1218,6 +1248,7 @@ function createRequestHandler(routeEntry, handler, deps) {
1218
1248
  message: err instanceof Error ? err.message : String(err),
1219
1249
  route: routeEntry.key,
1220
1250
  network: matchedNetwork,
1251
+ errorReason: errObj.errorReason,
1221
1252
  facilitatorStatus: errObj.response?.status,
1222
1253
  facilitatorBody: errObj.response?.data ?? errObj.response?.body
1223
1254
  });
@@ -1266,7 +1297,7 @@ function createRequestHandler(routeEntry, handler, deps) {
1266
1297
  const rawSource = credential?.source ?? "";
1267
1298
  const didParts = rawSource.split(":");
1268
1299
  const lastPart = didParts[didParts.length - 1];
1269
- const wallet = ((0, import_viem.isAddress)(lastPart) ? (0, import_viem.getAddress)(lastPart) : rawSource).toLowerCase();
1300
+ const wallet = normalizeWalletAddress((0, import_viem.isAddress)(lastPart) ? (0, import_viem.getAddress)(lastPart) : rawSource);
1270
1301
  pluginCtx.setVerifiedWallet(wallet);
1271
1302
  firePluginHook(deps.plugin, "onPaymentVerified", pluginCtx, {
1272
1303
  protocol: "mpp",
@@ -1762,16 +1793,16 @@ var MemoryEntitlementStore = class {
1762
1793
  async has(route, wallet) {
1763
1794
  const wallets = this.routeToWallets.get(route);
1764
1795
  if (!wallets) return false;
1765
- return wallets.has(wallet.toLowerCase());
1796
+ return wallets.has(normalizeWalletAddress(wallet));
1766
1797
  }
1767
1798
  async grant(route, wallet) {
1768
- const normalizedWallet = wallet.toLowerCase();
1799
+ const normalized = normalizeWalletAddress(wallet);
1769
1800
  let wallets = this.routeToWallets.get(route);
1770
1801
  if (!wallets) {
1771
1802
  wallets = /* @__PURE__ */ new Set();
1772
1803
  this.routeToWallets.set(route, wallets);
1773
1804
  }
1774
- wallets.add(normalizedWallet);
1805
+ wallets.add(normalized);
1775
1806
  }
1776
1807
  };
1777
1808
  function detectRedisClientType2(client) {
@@ -1794,26 +1825,26 @@ function createRedisEntitlementStore(client, options) {
1794
1825
  return {
1795
1826
  async has(route, wallet) {
1796
1827
  const key = `${prefix}${route}`;
1797
- const normalizedWallet = wallet.toLowerCase();
1828
+ const normalized = normalizeWalletAddress(wallet);
1798
1829
  if (clientType === "upstash") {
1799
1830
  const redis2 = client;
1800
- const result2 = await redis2.sismember(key, normalizedWallet);
1831
+ const result2 = await redis2.sismember(key, normalized);
1801
1832
  return result2 === 1 || result2 === true;
1802
1833
  }
1803
1834
  const redis = client;
1804
- const result = await redis.sismember(key, normalizedWallet);
1835
+ const result = await redis.sismember(key, normalized);
1805
1836
  return result === 1;
1806
1837
  },
1807
1838
  async grant(route, wallet) {
1808
1839
  const key = `${prefix}${route}`;
1809
- const normalizedWallet = wallet.toLowerCase();
1840
+ const normalized = normalizeWalletAddress(wallet);
1810
1841
  if (clientType === "upstash") {
1811
1842
  const redis2 = client;
1812
- await redis2.sadd(key, normalizedWallet);
1843
+ await redis2.sadd(key, normalized);
1813
1844
  return;
1814
1845
  }
1815
1846
  const redis = client;
1816
- await redis.sadd(key, normalizedWallet);
1847
+ await redis.sadd(key, normalized);
1817
1848
  }
1818
1849
  };
1819
1850
  }
package/dist/index.js CHANGED
@@ -327,6 +327,11 @@ var RouteRegistry = class {
327
327
  // src/orchestrate.ts
328
328
  import { NextResponse as NextResponse2 } from "next/server";
329
329
 
330
+ // src/auth/normalize-wallet.ts
331
+ function normalizeWalletAddress(address) {
332
+ return address.startsWith("0x") ? address.toLowerCase() : address;
333
+ }
334
+
330
335
  // src/plugin.ts
331
336
  function createDefaultContext(meta) {
332
337
  const ctx = {
@@ -838,6 +843,23 @@ function getRequirementNetwork(requirements, fallback) {
838
843
  const network = requirements?.network;
839
844
  return typeof network === "string" ? network : fallback;
840
845
  }
846
+ function siwxSignatureType(network) {
847
+ return network.startsWith("solana:") ? "ed25519" : "eip191";
848
+ }
849
+ function getSupportedChains(x402Accepts, fallbackNetwork) {
850
+ const seen = /* @__PURE__ */ new Set();
851
+ const chains = [];
852
+ for (const accept of x402Accepts) {
853
+ if (accept.network && !seen.has(accept.network)) {
854
+ seen.add(accept.network);
855
+ chains.push({ chainId: accept.network, type: siwxSignatureType(accept.network) });
856
+ }
857
+ }
858
+ if (chains.length === 0) {
859
+ chains.push({ chainId: fallbackNetwork, type: siwxSignatureType(fallbackNetwork) });
860
+ }
861
+ return chains;
862
+ }
841
863
  function createRequestHandler(routeEntry, handler, deps) {
842
864
  async function invoke(request, meta, pluginCtx, wallet, account, parsedBody) {
843
865
  const ctx = {
@@ -965,12 +987,14 @@ function createRequestHandler(routeEntry, handler, deps) {
965
987
  if (!siwxHeader && routeEntry.authMode === "siwx") {
966
988
  const url = new URL(request.url);
967
989
  const nonce = crypto.randomUUID().replace(/-/g, "");
990
+ const supportedChains = getSupportedChains(deps.x402Accepts, deps.network);
991
+ const primaryChain = supportedChains[0];
968
992
  const siwxInfo = {
969
993
  domain: url.hostname,
970
994
  uri: request.url,
971
995
  version: "1",
972
- chainId: deps.network,
973
- type: "eip191",
996
+ chainId: primaryChain.chainId,
997
+ type: primaryChain.type,
974
998
  nonce,
975
999
  issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
976
1000
  expirationTime: new Date(Date.now() + SIWX_CHALLENGE_EXPIRY_MS).toISOString(),
@@ -994,7 +1018,7 @@ function createRequestHandler(routeEntry, handler, deps) {
994
1018
  "sign-in-with-x": {
995
1019
  info: siwxInfo,
996
1020
  // supportedChains at top level required by MCP tools for chain detection
997
- supportedChains: [{ chainId: deps.network, type: "eip191" }],
1021
+ supportedChains,
998
1022
  ...siwxSchema ? { schema: siwxSchema } : {}
999
1023
  }
1000
1024
  }
@@ -1030,7 +1054,7 @@ function createRequestHandler(routeEntry, handler, deps) {
1030
1054
  return response;
1031
1055
  }
1032
1056
  } else {
1033
- const wallet = siwx.wallet.toLowerCase();
1057
+ const wallet = normalizeWalletAddress(siwx.wallet);
1034
1058
  pluginCtx.setVerifiedWallet(wallet);
1035
1059
  if (routeEntry.authMode === "siwx") {
1036
1060
  firePluginHook(deps.plugin, "onAuthVerified", pluginCtx, {
@@ -1132,7 +1156,7 @@ function createRequestHandler(routeEntry, handler, deps) {
1132
1156
  if (!verify?.valid) return await build402(request, routeEntry, deps, meta, pluginCtx);
1133
1157
  const { payload: verifyPayload, requirements: verifyRequirements } = verify;
1134
1158
  const matchedNetwork = getRequirementNetwork(verifyRequirements, deps.network);
1135
- const wallet = verify.payer.toLowerCase();
1159
+ const wallet = normalizeWalletAddress(verify.payer);
1136
1160
  pluginCtx.setVerifiedWallet(wallet);
1137
1161
  firePluginHook(deps.plugin, "onPaymentVerified", pluginCtx, {
1138
1162
  protocol: "x402",
@@ -1155,6 +1179,12 @@ function createRequestHandler(routeEntry, handler, deps) {
1155
1179
  verifyPayload,
1156
1180
  verifyRequirements
1157
1181
  );
1182
+ if (!settle.result?.success) {
1183
+ const reason = settle.result?.errorReason || "x402 settlement returned success=false";
1184
+ const error = new Error(reason);
1185
+ error.errorReason = reason;
1186
+ throw error;
1187
+ }
1158
1188
  if (routeEntry.siwxEnabled) {
1159
1189
  try {
1160
1190
  await deps.entitlementStore.grant(routeEntry.key, wallet);
@@ -1179,6 +1209,7 @@ function createRequestHandler(routeEntry, handler, deps) {
1179
1209
  message: err instanceof Error ? err.message : String(err),
1180
1210
  route: routeEntry.key,
1181
1211
  network: matchedNetwork,
1212
+ errorReason: errObj.errorReason,
1182
1213
  facilitatorStatus: errObj.response?.status,
1183
1214
  facilitatorBody: errObj.response?.data ?? errObj.response?.body
1184
1215
  });
@@ -1227,7 +1258,7 @@ function createRequestHandler(routeEntry, handler, deps) {
1227
1258
  const rawSource = credential?.source ?? "";
1228
1259
  const didParts = rawSource.split(":");
1229
1260
  const lastPart = didParts[didParts.length - 1];
1230
- const wallet = (isAddress(lastPart) ? getAddress(lastPart) : rawSource).toLowerCase();
1261
+ const wallet = normalizeWalletAddress(isAddress(lastPart) ? getAddress(lastPart) : rawSource);
1231
1262
  pluginCtx.setVerifiedWallet(wallet);
1232
1263
  firePluginHook(deps.plugin, "onPaymentVerified", pluginCtx, {
1233
1264
  protocol: "mpp",
@@ -1723,16 +1754,16 @@ var MemoryEntitlementStore = class {
1723
1754
  async has(route, wallet) {
1724
1755
  const wallets = this.routeToWallets.get(route);
1725
1756
  if (!wallets) return false;
1726
- return wallets.has(wallet.toLowerCase());
1757
+ return wallets.has(normalizeWalletAddress(wallet));
1727
1758
  }
1728
1759
  async grant(route, wallet) {
1729
- const normalizedWallet = wallet.toLowerCase();
1760
+ const normalized = normalizeWalletAddress(wallet);
1730
1761
  let wallets = this.routeToWallets.get(route);
1731
1762
  if (!wallets) {
1732
1763
  wallets = /* @__PURE__ */ new Set();
1733
1764
  this.routeToWallets.set(route, wallets);
1734
1765
  }
1735
- wallets.add(normalizedWallet);
1766
+ wallets.add(normalized);
1736
1767
  }
1737
1768
  };
1738
1769
  function detectRedisClientType2(client) {
@@ -1755,26 +1786,26 @@ function createRedisEntitlementStore(client, options) {
1755
1786
  return {
1756
1787
  async has(route, wallet) {
1757
1788
  const key = `${prefix}${route}`;
1758
- const normalizedWallet = wallet.toLowerCase();
1789
+ const normalized = normalizeWalletAddress(wallet);
1759
1790
  if (clientType === "upstash") {
1760
1791
  const redis2 = client;
1761
- const result2 = await redis2.sismember(key, normalizedWallet);
1792
+ const result2 = await redis2.sismember(key, normalized);
1762
1793
  return result2 === 1 || result2 === true;
1763
1794
  }
1764
1795
  const redis = client;
1765
- const result = await redis.sismember(key, normalizedWallet);
1796
+ const result = await redis.sismember(key, normalized);
1766
1797
  return result === 1;
1767
1798
  },
1768
1799
  async grant(route, wallet) {
1769
1800
  const key = `${prefix}${route}`;
1770
- const normalizedWallet = wallet.toLowerCase();
1801
+ const normalized = normalizeWalletAddress(wallet);
1771
1802
  if (clientType === "upstash") {
1772
1803
  const redis2 = client;
1773
- await redis2.sadd(key, normalizedWallet);
1804
+ await redis2.sadd(key, normalized);
1774
1805
  return;
1775
1806
  }
1776
1807
  const redis = client;
1777
- await redis.sadd(key, normalizedWallet);
1808
+ await redis.sadd(key, normalized);
1778
1809
  }
1779
1810
  };
1780
1811
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentcash/router",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Unified route builder for Next.js App Router APIs with x402, MPP, SIWX, and API key auth",
5
5
  "type": "module",
6
6
  "exports": {