@armory-sh/client-web3 0.2.23-alpha.23.76 → 0.2.23-alpha.23.78

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.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { Web3BaseWalletAccount, Web3BaseWallet } from 'web3-types';
2
1
  import { NetworkConfig, CustomToken, PaymentPayloadV2, PaymentRequirementsV2, SettlementResponseV2, NetworkId, TokenId, ArmoryPaymentResult, ValidationError } from '@armory-sh/base';
2
+ import { ClientHook } from '@armory-sh/base/types/hooks';
3
+ import { Web3BaseWalletAccount, Web3BaseWallet } from 'web3-types';
3
4
 
4
5
  type Web3Account = Web3BaseWalletAccount | Web3BaseWallet<Web3BaseWalletAccount>;
5
6
  /** Token configuration - can use pre-configured tokens from @armory-sh/tokens */
@@ -15,6 +16,7 @@ interface Web3ClientConfig {
15
16
  domainName?: string;
16
17
  /** Override EIP-712 domain version for custom tokens */
17
18
  domainVersion?: string;
19
+ hooks?: ClientHook<Web3Account>[];
18
20
  }
19
21
  interface PaymentSignatureResult {
20
22
  signature?: {
@@ -66,34 +68,6 @@ interface Web3EIP712Domain {
66
68
  [key: string]: string | number;
67
69
  }
68
70
 
69
- declare const createX402Client: (config: Web3ClientConfig) => Web3X402Client;
70
-
71
- /**
72
- * Create an x402 transport layer for handling payment-required responses
73
- */
74
- declare const createX402Transport: (options: X402TransportOptions) => X402Transport;
75
-
76
- declare const createEIP712Domain: (chainId: number | string, contractAddress: string, domainName?: string, domainVersion?: string) => Web3EIP712Domain;
77
- declare const createTransferWithAuthorization: (params: Web3TransferWithAuthorization) => Record<string, string>;
78
- declare const validateTransferWithAuthorization: (message: Web3TransferWithAuthorization) => boolean;
79
- declare const parseSignature: (signature: string) => {
80
- v: number;
81
- r: string;
82
- s: string;
83
- };
84
- declare const concatenateSignature: (v: number, r: string, s: string) => string;
85
- declare const adjustVForChainId: (v: number, chainId: number) => number;
86
- declare const signTypedData: (_account: Web3BaseWalletAccount | Web3BaseWallet<Web3BaseWalletAccount>, _domain: Web3EIP712Domain, _message: Record<string, string>) => Promise<{
87
- v: number;
88
- r: string;
89
- s: string;
90
- }>;
91
- declare const signWithPrivateKey: (_privateKey: string, _domain: Web3EIP712Domain, _message: Record<string, string>) => Promise<{
92
- v: number;
93
- r: string;
94
- s: string;
95
- }>;
96
-
97
71
  /**
98
72
  * Simple one-line payment API for Armory (Web3)
99
73
  * Focus on DX/UX - "everything just magically works"
@@ -204,4 +178,32 @@ interface ArmoryInstance {
204
178
  }
205
179
  declare const createArmory: (config: ArmoryConfig) => ArmoryInstance;
206
180
 
181
+ declare const createX402Client: (config: Web3ClientConfig) => Web3X402Client;
182
+
183
+ declare const createEIP712Domain: (chainId: number | string, contractAddress: string, domainName?: string, domainVersion?: string) => Web3EIP712Domain;
184
+ declare const createTransferWithAuthorization: (params: Web3TransferWithAuthorization) => Record<string, string>;
185
+ declare const validateTransferWithAuthorization: (message: Web3TransferWithAuthorization) => boolean;
186
+ declare const parseSignature: (signature: string) => {
187
+ v: number;
188
+ r: string;
189
+ s: string;
190
+ };
191
+ declare const concatenateSignature: (v: number, r: string, s: string) => string;
192
+ declare const adjustVForChainId: (v: number, chainId: number) => number;
193
+ declare const signTypedData: (_account: Web3BaseWalletAccount | Web3BaseWallet<Web3BaseWalletAccount>, _domain: Web3EIP712Domain, _message: Record<string, string>) => Promise<{
194
+ v: number;
195
+ r: string;
196
+ s: string;
197
+ }>;
198
+ declare const signWithPrivateKey: (_privateKey: string, _domain: Web3EIP712Domain, _message: Record<string, string>) => Promise<{
199
+ v: number;
200
+ r: string;
201
+ s: string;
202
+ }>;
203
+
204
+ /**
205
+ * Create an x402 transport layer for handling payment-required responses
206
+ */
207
+ declare const createX402Transport: (options: X402TransportOptions) => X402Transport;
208
+
207
209
  export { type ArmoryConfig, type ArmoryInstance, type HttpMethod, type NormalizedWallet, type PaymentOptions, type SimpleWalletInput, adjustVForChainId, armoryDelete, armoryGet, armoryPatch, armoryPay, armoryPost, armoryPut, concatenateSignature, createArmory, createEIP712Domain, createTransferWithAuthorization, createX402Client, createX402Transport, getNetworks, getTokens, getWalletAddress, normalizeWallet, parseSignature, signTypedData, signWithPrivateKey, validateNetwork, validateToken, validateTransferWithAuthorization };
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
- import { Web3 } from 'web3';
2
1
  import { encodePaymentV2, validatePaymentConfig, isValidationError, resolveNetwork, resolveToken, V2_HEADERS, getNetworkConfig, getNetworkByChainId, networkToCaip2, combineSignatureV2, normalizeBase64Url, decodeBase64ToUtf8, isX402V2PaymentRequired } from '@armory-sh/base';
2
+ import { runOnPaymentRequiredHooks, selectRequirementWithHooks, runBeforeSignPaymentHooks, runAfterPaymentResponseHooks } from '@armory-sh/base/client-hooks-runtime';
3
+ import { Web3 } from 'web3';
3
4
 
4
5
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
5
6
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -74,7 +75,9 @@ var validateTransferWithAuthorization = (message) => {
74
75
  var parseSignature = (signature) => {
75
76
  const hexSig = signature.startsWith("0x") ? signature.slice(2) : signature;
76
77
  if (hexSig.length !== 130) {
77
- throw new Error(`Invalid signature length: ${hexSig.length} (expected 130)`);
78
+ throw new Error(
79
+ `Invalid signature length: ${hexSig.length} (expected 130)`
80
+ );
78
81
  }
79
82
  return {
80
83
  r: `0x${hexSig.slice(0, 64)}`,
@@ -196,7 +199,8 @@ var getAddress = (account) => {
196
199
  };
197
200
  var parseSignature2 = (signature) => {
198
201
  const hexSig = signature.startsWith("0x") ? signature.slice(2) : signature;
199
- if (hexSig.length !== 130) throw new Error(`Invalid signature length: ${hexSig.length}`);
202
+ if (hexSig.length !== 130)
203
+ throw new Error(`Invalid signature length: ${hexSig.length}`);
200
204
  return {
201
205
  r: `0x${hexSig.slice(0, 64)}`,
202
206
  s: `0x${hexSig.slice(64, 128)}`,
@@ -222,7 +226,9 @@ var signTypedDataWrapper = async (account, domain, message) => {
222
226
  return parseSignature2(sig);
223
227
  }
224
228
  if ("privateKey" in account && typeof account.privateKey === "string") {
225
- throw new Error("Direct private key signing not implemented. Use wallet provider with signTypedData.");
229
+ throw new Error(
230
+ "Direct private key signing not implemented. Use wallet provider with signTypedData."
231
+ );
226
232
  }
227
233
  throw new Error("Account does not support EIP-712 signing.");
228
234
  };
@@ -237,12 +243,17 @@ var signPaymentV2 = async (state, network, params) => {
237
243
  maxTimeoutSeconds: expiry - Math.floor(Date.now() / 1e3)
238
244
  };
239
245
  const domainExtra = defaultAccepted.extra;
240
- const requirementDomainName = defaultAccepted.name ?? (domainExtra && typeof domainExtra === "object" && typeof domainExtra["name"] === "string" ? domainExtra["name"] : void 0);
241
- const requirementDomainVersion = defaultAccepted.version ?? (domainExtra && typeof domainExtra === "object" && typeof domainExtra["version"] === "string" ? domainExtra["version"] : void 0);
246
+ const requirementDomainName = defaultAccepted.name ?? (domainExtra && typeof domainExtra === "object" && typeof domainExtra.name === "string" ? domainExtra.name : void 0);
247
+ const requirementDomainVersion = defaultAccepted.version ?? (domainExtra && typeof domainExtra === "object" && typeof domainExtra.version === "string" ? domainExtra.version : void 0);
242
248
  const effectiveDomainName = state.domainName ?? requirementDomainName;
243
249
  const effectiveDomainVersion = state.domainVersion ?? requirementDomainVersion;
244
250
  const chainId = parseInt(defaultAccepted.network.split(":")[1], 10);
245
- const domain = createEIP712Domain(chainId, defaultAccepted.asset, effectiveDomainName, effectiveDomainVersion);
251
+ const domain = createEIP712Domain(
252
+ chainId,
253
+ defaultAccepted.asset,
254
+ effectiveDomainName,
255
+ effectiveDomainVersion
256
+ );
246
257
  const nowSeconds = Math.floor(Date.now() / 1e3);
247
258
  const validAfterHex = `0x${(nowSeconds - 600).toString(16)}`;
248
259
  const message = createTransferWithAuthorization({
@@ -290,6 +301,7 @@ var extractNetworkFromRequirements = (requirements) => {
290
301
  };
291
302
  var createX402Client = (config) => {
292
303
  const state = createClientState(config);
304
+ const hooks = config.hooks;
293
305
  const fetch2 = async (url, init) => {
294
306
  let response = await fetch2(url, init);
295
307
  if (response.status === 402) {
@@ -299,7 +311,22 @@ var createX402Client = (config) => {
299
311
  throw new Error("No supported payment scheme found in requirements");
300
312
  }
301
313
  const from = getAddress(state.account);
302
- const req = selectedRequirements;
314
+ const paymentRequiredContext = {
315
+ url,
316
+ requestInit: init,
317
+ accepts: parsed.requirements,
318
+ requirements: selectedRequirements,
319
+ selectedRequirement: selectedRequirements,
320
+ serverExtensions: void 0,
321
+ fromAddress: from,
322
+ nonce: `0x${Date.now().toString(16).padStart(64, "0")}`,
323
+ validBefore: Math.floor(Date.now() / 1e3) + selectedRequirements.maxTimeoutSeconds
324
+ };
325
+ await runOnPaymentRequiredHooks(hooks, paymentRequiredContext);
326
+ const req = await selectRequirementWithHooks(
327
+ hooks,
328
+ paymentRequiredContext
329
+ );
303
330
  const to = typeof req.payTo === "string" ? req.payTo : "0x0000000000000000000000000000000000000000";
304
331
  const network = extractNetworkFromRequirements(req);
305
332
  const result = await signPaymentV2(state, network, {
@@ -310,9 +337,25 @@ var createX402Client = (config) => {
310
337
  expiry: Math.floor(Date.now() / 1e3) + req.maxTimeoutSeconds,
311
338
  accepted: req
312
339
  });
340
+ await runBeforeSignPaymentHooks(hooks, {
341
+ payload: result.payload,
342
+ requirements: req,
343
+ wallet: state.account,
344
+ paymentContext: paymentRequiredContext
345
+ });
313
346
  const paymentHeaders = new Headers(init?.headers);
314
- paymentHeaders.set(V2_HEADERS.PAYMENT_SIGNATURE, encodePaymentV2(result.payload));
347
+ paymentHeaders.set(
348
+ V2_HEADERS.PAYMENT_SIGNATURE,
349
+ encodePaymentV2(result.payload)
350
+ );
315
351
  response = await fetch2(url, { ...init, headers: paymentHeaders });
352
+ await runAfterPaymentResponseHooks(hooks, {
353
+ payload: result.payload,
354
+ requirements: req,
355
+ wallet: state.account,
356
+ paymentContext: paymentRequiredContext,
357
+ response
358
+ });
316
359
  }
317
360
  return response;
318
361
  };
@@ -323,7 +366,9 @@ var createX402Client = (config) => {
323
366
  getVersion: () => state.version,
324
367
  signPayment: async (options) => {
325
368
  const network = state.network ?? (() => {
326
- throw new Error("Network must be configured for manual payment signing");
369
+ throw new Error(
370
+ "Network must be configured for manual payment signing"
371
+ );
327
372
  })();
328
373
  const from = getAddress(state.account);
329
374
  const to = options.to;
@@ -334,14 +379,22 @@ var createX402Client = (config) => {
334
379
  },
335
380
  createPaymentHeaders: async (options) => {
336
381
  const network = state.network ?? (() => {
337
- throw new Error("Network must be configured for manual payment signing");
382
+ throw new Error(
383
+ "Network must be configured for manual payment signing"
384
+ );
338
385
  })();
339
386
  const from = getAddress(state.account);
340
387
  const to = options.to;
341
388
  const amount = options.amount.toString();
342
389
  const nonce = options.nonce ?? crypto.randomUUID();
343
390
  const expiry = options.expiry ?? Math.floor(Date.now() / 1e3) + DEFAULT_EXPIRY_SECONDS;
344
- const result = await signPaymentV2(state, network, { from, to, amount, nonce, expiry });
391
+ const result = await signPaymentV2(state, network, {
392
+ from,
393
+ to,
394
+ amount,
395
+ nonce,
396
+ expiry
397
+ });
345
398
  const headers = new Headers();
346
399
  headers.set("PAYMENT-SIGNATURE", encodePaymentV2(result.payload));
347
400
  return headers;
@@ -364,69 +417,8 @@ var createX402Client = (config) => {
364
417
  }
365
418
  };
366
419
  };
367
- var DEFAULT_MAX_RETRIES = 3;
368
- var createPaymentHeaders = (payload, _version) => {
369
- const headers = new Headers();
370
- headers.set(V2_HEADERS.PAYMENT_SIGNATURE, encodePaymentV2(payload));
371
- return headers;
372
- };
373
- var isPaymentRelatedError = (error) => error.message.includes("402") || error.message.includes("payment") || error.message.includes("signature") || error.message.includes("Payment");
374
- var backoff = (attempt) => {
375
- const baseDelay = Math.min(1e3 * Math.pow(2, attempt - 1), 1e4);
376
- const jitter = Math.random() * 100;
377
- return new Promise((resolve) => setTimeout(resolve, baseDelay + jitter));
378
- };
379
- var handlePaymentRequired = async (response, client) => {
380
- detectX402Version(response, client.getVersion());
381
- const parsed = await parsePaymentRequired(response);
382
- const selectedRequirements = parsed.requirements[0];
383
- if (!selectedRequirements) {
384
- throw new Error("No supported payment scheme found in requirements");
385
- }
386
- const req = selectedRequirements;
387
- const result = await client.handlePaymentRequired(req);
388
- return createPaymentHeaders(result.payload);
389
- };
390
- var mergePaymentHeaders = (init = {}, paymentHeaders) => {
391
- const existingHeaders = new Headers(init.headers);
392
- for (const [key, value] of paymentHeaders.entries()) {
393
- existingHeaders.set(key, value);
394
- }
395
- return { ...init, headers: existingHeaders };
396
- };
397
- var createX402Transport = (options) => {
398
- const client = options.client;
399
- const autoSign = options.autoSign ?? true;
400
- const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
401
- return {
402
- getClient: () => client,
403
- fetch: async (url, init) => {
404
- let attempt = 0;
405
- let lastError;
406
- while (attempt < maxRetries) {
407
- attempt++;
408
- try {
409
- const response = await fetch(url, init);
410
- if (isPaymentRequiredResponse(response) && autoSign) {
411
- const paymentHeaders = await handlePaymentRequired(response, client);
412
- const newInit = mergePaymentHeaders(init, paymentHeaders);
413
- return await fetch(url, newInit);
414
- }
415
- return response;
416
- } catch (error) {
417
- lastError = error instanceof Error ? error : new Error(String(error));
418
- if (!isPaymentRelatedError(lastError)) {
419
- throw lastError;
420
- }
421
- if (attempt < maxRetries) {
422
- await backoff(attempt);
423
- }
424
- }
425
- }
426
- throw lastError ?? new Error("Max retries exceeded");
427
- }
428
- };
429
- };
420
+
421
+ // src/payment-api.ts
430
422
  var normalizeWallet = (wallet) => {
431
423
  if (typeof wallet === "object" && wallet !== null && "account" in wallet) {
432
424
  return wallet.account;
@@ -495,19 +487,37 @@ var armoryPay = async (wallet, url, network, token, options) => {
495
487
  }
496
488
  };
497
489
  var armoryGet = (wallet, url, network, token, options) => {
498
- return armoryPay(wallet, url, network, token, { ...options, method: "GET" });
490
+ return armoryPay(wallet, url, network, token, {
491
+ ...options,
492
+ method: "GET"
493
+ });
499
494
  };
500
495
  var armoryPost = (wallet, url, network, token, body, options) => {
501
- return armoryPay(wallet, url, network, token, { ...options, method: "POST", body });
496
+ return armoryPay(wallet, url, network, token, {
497
+ ...options,
498
+ method: "POST",
499
+ body
500
+ });
502
501
  };
503
502
  var armoryPut = (wallet, url, network, token, body, options) => {
504
- return armoryPay(wallet, url, network, token, { ...options, method: "PUT", body });
503
+ return armoryPay(wallet, url, network, token, {
504
+ ...options,
505
+ method: "PUT",
506
+ body
507
+ });
505
508
  };
506
509
  var armoryDelete = (wallet, url, network, token, options) => {
507
- return armoryPay(wallet, url, network, token, { ...options, method: "DELETE" });
510
+ return armoryPay(wallet, url, network, token, {
511
+ ...options,
512
+ method: "DELETE"
513
+ });
508
514
  };
509
515
  var armoryPatch = (wallet, url, network, token, body, options) => {
510
- return armoryPay(wallet, url, network, token, { ...options, method: "PATCH", body });
516
+ return armoryPay(wallet, url, network, token, {
517
+ ...options,
518
+ method: "PATCH",
519
+ body
520
+ });
511
521
  };
512
522
  var getWalletAddress = (wallet) => {
513
523
  const account = normalizeWallet(wallet);
@@ -523,7 +533,7 @@ var validateNetwork = (network) => {
523
533
  return { success: true, network: resolved.config.name };
524
534
  };
525
535
  var validateToken = (token, network) => {
526
- let resolvedNetwork = void 0;
536
+ let resolvedNetwork;
527
537
  if (network) {
528
538
  const networkResult = resolveNetwork(network);
529
539
  if (isValidationError(networkResult)) {
@@ -551,7 +561,13 @@ var getTokens = () => {
551
561
  };
552
562
 
553
563
  // src/armory-api.ts
554
- var ALL_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "DELETE", "PATCH"]);
564
+ var ALL_METHODS = /* @__PURE__ */ new Set([
565
+ "GET",
566
+ "POST",
567
+ "PUT",
568
+ "DELETE",
569
+ "PATCH"
570
+ ]);
555
571
  var arrayify = (value) => {
556
572
  if (value === void 0) return void 0;
557
573
  return Array.isArray(value) ? value : [value];
@@ -607,5 +623,71 @@ var createArmory = (config) => {
607
623
  call: (url) => makeRequest(url, "GET")
608
624
  };
609
625
  };
626
+ var DEFAULT_MAX_RETRIES = 3;
627
+ var createPaymentHeaders = (payload, _version) => {
628
+ const headers = new Headers();
629
+ headers.set(V2_HEADERS.PAYMENT_SIGNATURE, encodePaymentV2(payload));
630
+ return headers;
631
+ };
632
+ var isPaymentRelatedError = (error) => error.message.includes("402") || error.message.includes("payment") || error.message.includes("signature") || error.message.includes("Payment");
633
+ var backoff = (attempt) => {
634
+ const baseDelay = Math.min(1e3 * 2 ** (attempt - 1), 1e4);
635
+ const jitter = Math.random() * 100;
636
+ return new Promise((resolve) => setTimeout(resolve, baseDelay + jitter));
637
+ };
638
+ var handlePaymentRequired = async (response, client) => {
639
+ detectX402Version(response, client.getVersion());
640
+ const parsed = await parsePaymentRequired(response);
641
+ const selectedRequirements = parsed.requirements[0];
642
+ if (!selectedRequirements) {
643
+ throw new Error("No supported payment scheme found in requirements");
644
+ }
645
+ const req = selectedRequirements;
646
+ const result = await client.handlePaymentRequired(req);
647
+ return createPaymentHeaders(result.payload);
648
+ };
649
+ var mergePaymentHeaders = (init = {}, paymentHeaders) => {
650
+ const existingHeaders = new Headers(init.headers);
651
+ for (const [key, value] of paymentHeaders.entries()) {
652
+ existingHeaders.set(key, value);
653
+ }
654
+ return { ...init, headers: existingHeaders };
655
+ };
656
+ var createX402Transport = (options) => {
657
+ const client = options.client;
658
+ const autoSign = options.autoSign ?? true;
659
+ const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
660
+ return {
661
+ getClient: () => client,
662
+ fetch: async (url, init) => {
663
+ let attempt = 0;
664
+ let lastError;
665
+ while (attempt < maxRetries) {
666
+ attempt++;
667
+ try {
668
+ const response = await fetch(url, init);
669
+ if (isPaymentRequiredResponse(response) && autoSign) {
670
+ const paymentHeaders = await handlePaymentRequired(
671
+ response,
672
+ client
673
+ );
674
+ const newInit = mergePaymentHeaders(init, paymentHeaders);
675
+ return await fetch(url, newInit);
676
+ }
677
+ return response;
678
+ } catch (error) {
679
+ lastError = error instanceof Error ? error : new Error(String(error));
680
+ if (!isPaymentRelatedError(lastError)) {
681
+ throw lastError;
682
+ }
683
+ if (attempt < maxRetries) {
684
+ await backoff(attempt);
685
+ }
686
+ }
687
+ }
688
+ throw lastError ?? new Error("Max retries exceeded");
689
+ }
690
+ };
691
+ };
610
692
 
611
693
  export { adjustVForChainId, armoryDelete, armoryGet, armoryPatch, armoryPay, armoryPost, armoryPut, concatenateSignature, createArmory, createEIP712Domain, createTransferWithAuthorization, createX402Client, createX402Transport, getNetworks, getTokens, getWalletAddress, normalizeWallet, parseSignature, signTypedData, signWithPrivateKey, validateNetwork, validateToken, validateTransferWithAuthorization };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@armory-sh/client-web3",
3
- "version": "0.2.23-alpha.23.76",
3
+ "version": "0.2.23-alpha.23.78",
4
4
  "license": "MIT",
5
5
  "author": "Sawyer Cutler <sawyer@dirtroad.dev>",
6
6
  "keywords": [
@@ -46,7 +46,7 @@
46
46
  "directory": "packages/client-web3"
47
47
  },
48
48
  "dependencies": {
49
- "@armory-sh/base": "0.2.27-alpha.23.76",
49
+ "@armory-sh/base": "0.2.27-alpha.23.78",
50
50
  "web3": "4.16.0",
51
51
  "web3-types": "1.10.0"
52
52
  },
@@ -56,6 +56,8 @@
56
56
  },
57
57
  "scripts": {
58
58
  "build": "rm -rf dist && tsup",
59
+ "lint": "bun run build",
60
+ "format": "bun run lint",
59
61
  "test": "bun test",
60
62
  "example": "bun run examples/"
61
63
  }