@armory-sh/client-web3 0.2.14 → 0.2.16

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,5 @@
1
1
  import { Web3BaseWalletAccount, Web3BaseWallet } from 'web3-types';
2
- import { NetworkConfig, CustomToken, PaymentPayloadV2, PaymentRequirementsV2, SettlementResponseV2 } from '@armory-sh/base';
2
+ import { NetworkConfig, CustomToken, PaymentPayloadV2, PaymentRequirementsV2, SettlementResponseV2, NetworkId, TokenId, ArmoryPaymentResult, ValidationError } from '@armory-sh/base';
3
3
  export { EIP3009Authorization, PaymentPayloadV2, PaymentRequirementsV2, SchemePayloadV2, SettlementResponseV2 } from '@armory-sh/base';
4
4
 
5
5
  type Web3Account = Web3BaseWalletAccount | Web3BaseWallet<Web3BaseWalletAccount>;
@@ -7,7 +7,7 @@ type Web3Account = Web3BaseWalletAccount | Web3BaseWallet<Web3BaseWalletAccount>
7
7
  type Token = CustomToken;
8
8
  interface Web3ClientConfig {
9
9
  account: Web3Account;
10
- network: NetworkConfig | string;
10
+ network?: NetworkConfig | string;
11
11
  version?: 2;
12
12
  rpcUrl?: string;
13
13
  /** Pre-configured token object (overrides individual fields below) */
@@ -44,7 +44,7 @@ interface X402Transport {
44
44
  interface Web3X402Client {
45
45
  fetch(url: string | Request, init?: RequestInit): Promise<Response>;
46
46
  getAccount(): Web3Account;
47
- getNetwork(): NetworkConfig;
47
+ getNetwork(): NetworkConfig | undefined;
48
48
  getVersion(): 2;
49
49
  signPayment(options: PaymentSignOptions): Promise<PaymentSignatureResult>;
50
50
  createPaymentHeaders(options: PaymentSignOptions): Promise<Headers>;
@@ -95,4 +95,114 @@ declare const signWithPrivateKey: (_privateKey: string, _domain: Web3EIP712Domai
95
95
  s: string;
96
96
  }>;
97
97
 
98
- export { adjustVForChainId, concatenateSignature, createEIP712Domain, createTransferWithAuthorization, createX402Client, createX402Transport, parseSignature, signTypedData, signWithPrivateKey, validateTransferWithAuthorization };
98
+ /**
99
+ * Simple one-line payment API for Armory (Web3)
100
+ * Focus on DX/UX - "everything just magically works"
101
+ */
102
+
103
+ /**
104
+ * Simple wallet input - accepts wallet directly or wrapped for backward compatibility
105
+ */
106
+ type SimpleWalletInput = Web3Account | {
107
+ account: Web3Account;
108
+ };
109
+ /**
110
+ * Normalized wallet (internal use)
111
+ */
112
+ type NormalizedWallet = Web3Account;
113
+ /**
114
+ * Normalize wallet input to internal format
115
+ */
116
+ declare const normalizeWallet: (wallet: SimpleWalletInput) => NormalizedWallet;
117
+ /**
118
+ * Make a payment-protected API request with one line of code
119
+ */
120
+ declare const armoryPay: <T = unknown>(wallet: SimpleWalletInput, url: string, network: NetworkId, token: TokenId, options?: {
121
+ /** Request method (default: GET) */
122
+ method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
123
+ /** Request body (for POST/PUT/PATCH) */
124
+ body?: unknown;
125
+ /** Request headers */
126
+ headers?: Record<string, string>;
127
+ /** Protocol version (V2 only) */
128
+ version?: 2;
129
+ /** Payment amount in token units (default: from 402 header) */
130
+ amount?: string;
131
+ }) => Promise<ArmoryPaymentResult<T>>;
132
+ /**
133
+ * Make a GET request with payment
134
+ */
135
+ declare const armoryGet: <T = unknown>(wallet: SimpleWalletInput, url: string, network: NetworkId, token: TokenId, options?: Omit<Parameters<typeof armoryPay>[4], "method">) => Promise<ArmoryPaymentResult<T>>;
136
+ /**
137
+ * Make a POST request with payment
138
+ */
139
+ declare const armoryPost: <T = unknown>(wallet: SimpleWalletInput, url: string, network: NetworkId, token: TokenId, body?: unknown, options?: Omit<Parameters<typeof armoryPay>[4], "method" | "body">) => Promise<ArmoryPaymentResult<T>>;
140
+ /**
141
+ * Make a PUT request with payment
142
+ */
143
+ declare const armoryPut: <T = unknown>(wallet: SimpleWalletInput, url: string, network: NetworkId, token: TokenId, body?: unknown, options?: Omit<Parameters<typeof armoryPay>[4], "method" | "body">) => Promise<ArmoryPaymentResult<T>>;
144
+ /**
145
+ * Make a DELETE request with payment
146
+ */
147
+ declare const armoryDelete: <T = unknown>(wallet: SimpleWalletInput, url: string, network: NetworkId, token: TokenId, options?: Omit<Parameters<typeof armoryPay>[4], "method">) => Promise<ArmoryPaymentResult<T>>;
148
+ /**
149
+ * Make a PATCH request with payment
150
+ */
151
+ declare const armoryPatch: <T = unknown>(wallet: SimpleWalletInput, url: string, network: NetworkId, token: TokenId, body?: unknown, options?: Omit<Parameters<typeof armoryPay>[4], "method" | "body">) => Promise<ArmoryPaymentResult<T>>;
152
+ /**
153
+ * Get the wallet address from a SimpleWalletInput
154
+ */
155
+ declare const getWalletAddress: (wallet: SimpleWalletInput) => string;
156
+ /**
157
+ * Validate a network identifier without making a request
158
+ */
159
+ declare const validateNetwork: (network: NetworkId) => ValidationError | {
160
+ success: true;
161
+ network: string;
162
+ };
163
+ /**
164
+ * Validate a token identifier without making a request
165
+ */
166
+ declare const validateToken: (token: TokenId, network?: NetworkId) => ValidationError | {
167
+ success: true;
168
+ token: string;
169
+ network: string;
170
+ };
171
+ /**
172
+ * Get list of available networks
173
+ */
174
+ declare const getNetworks: () => string[];
175
+ /**
176
+ * Get list of available tokens
177
+ */
178
+ declare const getTokens: () => string[];
179
+
180
+ /**
181
+ * Armory API - Simplified payment interface (Web3)
182
+ * Provides a configurable object with method-based payment functions
183
+ */
184
+
185
+ type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
186
+ interface ArmoryConfig {
187
+ wallet: SimpleWalletInput;
188
+ methods?: HttpMethod[] | HttpMethod;
189
+ tokens?: TokenId[] | TokenId;
190
+ chains?: NetworkId[] | NetworkId;
191
+ debug?: boolean;
192
+ }
193
+ interface PaymentOptions {
194
+ method?: HttpMethod;
195
+ body?: unknown;
196
+ }
197
+ interface ArmoryInstance {
198
+ get<T>(url: string, body?: unknown): Promise<ArmoryPaymentResult<T>>;
199
+ post<T>(url: string, body?: unknown): Promise<ArmoryPaymentResult<T>>;
200
+ put<T>(url: string, body?: unknown): Promise<ArmoryPaymentResult<T>>;
201
+ delete<T>(url: string): Promise<ArmoryPaymentResult<T>>;
202
+ patch<T>(url: string, body?: unknown): Promise<ArmoryPaymentResult<T>>;
203
+ pay<T>(url: string, options?: PaymentOptions): Promise<ArmoryPaymentResult<T>>;
204
+ call<T>(url: string): Promise<ArmoryPaymentResult<T>>;
205
+ }
206
+ declare const createArmory: (config: ArmoryConfig) => ArmoryInstance;
207
+
208
+ 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,7 +1,15 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
1
8
  // src/client.ts
2
9
  import { Web3 } from "web3";
3
10
  import {
4
11
  getNetworkConfig,
12
+ getNetworkByChainId,
5
13
  encodePaymentV2,
6
14
  networkToCaip2,
7
15
  combineSignatureV2,
@@ -181,15 +189,15 @@ var extractDomainConfig = (config) => {
181
189
  };
182
190
  };
183
191
  var createClientState = (config) => {
184
- const network = typeof config.network === "string" ? getNetworkConfig(config.network) ?? (() => {
192
+ const network = config.network ? typeof config.network === "string" ? getNetworkConfig(config.network) ?? (() => {
185
193
  throw new Error(`Unknown network: ${config.network}`);
186
- })() : config.network;
194
+ })() : config.network : void 0;
187
195
  const { domainName, domainVersion } = extractDomainConfig(config);
188
196
  return {
189
197
  account: config.account,
190
198
  version: config.version ?? 2,
191
199
  network,
192
- web3: new Web3(config.rpcUrl ?? network.rpcUrl),
200
+ web3: config.rpcUrl ? new Web3(config.rpcUrl) : network ? new Web3(network.rpcUrl) : new Web3(),
193
201
  domainName,
194
202
  domainVersion
195
203
  };
@@ -231,9 +239,9 @@ var signTypedDataWrapper = async (account, domain, message) => {
231
239
  }
232
240
  throw new Error("Account does not support EIP-712 signing.");
233
241
  };
234
- var signPaymentV2 = async (state, params) => {
242
+ var signPaymentV2 = async (state, network, params) => {
235
243
  const { from, to, amount, nonce, expiry, accepted } = params;
236
- const { network, domainName, domainVersion } = state;
244
+ const { domainName, domainVersion } = state;
237
245
  const domain = createEIP712Domain(network.chainId, network.usdcAddress, domainName, domainVersion);
238
246
  const message = createTransferWithAuthorization({
239
247
  from,
@@ -273,6 +281,19 @@ var signPaymentV2 = async (state, params) => {
273
281
  payload: x402Payload
274
282
  };
275
283
  };
284
+ var extractNetworkFromRequirements = (requirements) => {
285
+ const caip2Network = requirements.network;
286
+ const match = caip2Network.match(/^eip155:(\d+)$/);
287
+ if (!match) {
288
+ throw new Error(`Invalid CAIP-2 network format: ${caip2Network}`);
289
+ }
290
+ const chainId = parseInt(match[1], 10);
291
+ const network = getNetworkByChainId(chainId);
292
+ if (!network) {
293
+ throw new Error(`Unsupported chain ID: ${chainId}`);
294
+ }
295
+ return network;
296
+ };
276
297
  var createX402Client = (config) => {
277
298
  const state = createClientState(config);
278
299
  const fetch2 = async (url, init) => {
@@ -287,7 +308,8 @@ var createX402Client = (config) => {
287
308
  const from = getAddress(state.account);
288
309
  const req = selectedRequirements;
289
310
  const to = typeof req.payTo === "string" ? req.payTo : "0x0000000000000000000000000000000000000000";
290
- const result = await signPaymentV2(state, {
311
+ const network = extractNetworkFromRequirements(req);
312
+ const result = await signPaymentV2(state, network, {
291
313
  from,
292
314
  to,
293
315
  amount: req.amount,
@@ -307,20 +329,26 @@ var createX402Client = (config) => {
307
329
  getNetwork: () => state.network,
308
330
  getVersion: () => state.version,
309
331
  signPayment: async (options) => {
332
+ const network = state.network ?? (() => {
333
+ throw new Error("Network must be configured for manual payment signing");
334
+ })();
310
335
  const from = getAddress(state.account);
311
336
  const to = options.to;
312
337
  const amount = options.amount.toString();
313
338
  const nonce = options.nonce ?? crypto.randomUUID();
314
339
  const expiry = options.expiry ?? Math.floor(Date.now() / 1e3) + DEFAULT_EXPIRY_SECONDS;
315
- return signPaymentV2(state, { from, to, amount, nonce, expiry });
340
+ return signPaymentV2(state, network, { from, to, amount, nonce, expiry });
316
341
  },
317
342
  createPaymentHeaders: async (options) => {
343
+ const network = state.network ?? (() => {
344
+ throw new Error("Network must be configured for manual payment signing");
345
+ })();
318
346
  const from = getAddress(state.account);
319
347
  const to = options.to;
320
348
  const amount = options.amount.toString();
321
349
  const nonce = options.nonce ?? crypto.randomUUID();
322
350
  const expiry = options.expiry ?? Math.floor(Date.now() / 1e3) + DEFAULT_EXPIRY_SECONDS;
323
- const result = await signPaymentV2(state, { from, to, amount, nonce, expiry });
351
+ const result = await signPaymentV2(state, network, { from, to, amount, nonce, expiry });
324
352
  const headers = new Headers();
325
353
  headers.set("PAYMENT-SIGNATURE", encodePaymentV2(result.payload));
326
354
  return headers;
@@ -328,7 +356,8 @@ var createX402Client = (config) => {
328
356
  handlePaymentRequired: async (requirements) => {
329
357
  const from = getAddress(state.account);
330
358
  const to = typeof requirements.payTo === "string" ? requirements.payTo : "0x0000000000000000000000000000000000000000";
331
- return signPaymentV2(state, {
359
+ const network = extractNetworkFromRequirements(requirements);
360
+ return signPaymentV2(state, network, {
332
361
  from,
333
362
  to,
334
363
  amount: requirements.amount,
@@ -411,15 +440,216 @@ var createX402Transport = (options) => {
411
440
  }
412
441
  };
413
442
  };
443
+
444
+ // src/payment-api.ts
445
+ import {
446
+ resolveNetwork,
447
+ resolveToken,
448
+ validatePaymentConfig,
449
+ isValidationError
450
+ } from "@armory-sh/base";
451
+ var normalizeWallet = (wallet) => {
452
+ if (typeof wallet === "object" && wallet !== null && "account" in wallet) {
453
+ return wallet.account;
454
+ }
455
+ return wallet;
456
+ };
457
+ var armoryPay = async (wallet, url, network, token, options) => {
458
+ try {
459
+ const account = normalizeWallet(wallet);
460
+ const config = validatePaymentConfig(network, token);
461
+ if (isValidationError(config)) {
462
+ return {
463
+ success: false,
464
+ code: config.code,
465
+ message: config.message,
466
+ details: config
467
+ };
468
+ }
469
+ const client = createX402Client({
470
+ account,
471
+ network: config.network.config.name,
472
+ version: options?.version ?? 2,
473
+ token: config.token.config
474
+ });
475
+ const method = options?.method ?? "GET";
476
+ const headers = new Headers(options?.headers ?? {});
477
+ let response;
478
+ if (method === "GET") {
479
+ response = await client.fetch(url, { method, headers });
480
+ } else {
481
+ response = await client.fetch(url, {
482
+ method,
483
+ headers,
484
+ body: JSON.stringify(options?.body)
485
+ });
486
+ }
487
+ if (response.status === 402) {
488
+ return {
489
+ success: false,
490
+ code: "PAYMENT_REQUIRED",
491
+ message: "Payment required but could not be completed automatically"
492
+ };
493
+ }
494
+ if (!response.ok) {
495
+ const error = await response.text();
496
+ return {
497
+ success: false,
498
+ code: "PAYMENT_DECLINED",
499
+ message: `Request failed: ${response.status} ${error}`
500
+ };
501
+ }
502
+ const data = await response.json();
503
+ const txHash = response.headers.get("X-PAYMENT-RESPONSE") || response.headers.get("PAYMENT-RESPONSE");
504
+ return {
505
+ success: true,
506
+ data,
507
+ ...txHash && { txHash }
508
+ };
509
+ } catch (error) {
510
+ return {
511
+ success: false,
512
+ code: "NETWORK_ERROR",
513
+ message: error instanceof Error ? error.message : "Unknown error occurred",
514
+ details: error
515
+ };
516
+ }
517
+ };
518
+ var armoryGet = (wallet, url, network, token, options) => {
519
+ return armoryPay(wallet, url, network, token, { ...options, method: "GET" });
520
+ };
521
+ var armoryPost = (wallet, url, network, token, body, options) => {
522
+ return armoryPay(wallet, url, network, token, { ...options, method: "POST", body });
523
+ };
524
+ var armoryPut = (wallet, url, network, token, body, options) => {
525
+ return armoryPay(wallet, url, network, token, { ...options, method: "PUT", body });
526
+ };
527
+ var armoryDelete = (wallet, url, network, token, options) => {
528
+ return armoryPay(wallet, url, network, token, { ...options, method: "DELETE" });
529
+ };
530
+ var armoryPatch = (wallet, url, network, token, body, options) => {
531
+ return armoryPay(wallet, url, network, token, { ...options, method: "PATCH", body });
532
+ };
533
+ var getWalletAddress = (wallet) => {
534
+ const account = normalizeWallet(wallet);
535
+ if ("address" in account) return account.address;
536
+ if (Array.isArray(account) && account[0]) return account[0].address;
537
+ throw new Error("Unable to get address from account");
538
+ };
539
+ var validateNetwork = (network) => {
540
+ const resolved = resolveNetwork(network);
541
+ if (isValidationError(resolved)) {
542
+ return resolved;
543
+ }
544
+ return { success: true, network: resolved.config.name };
545
+ };
546
+ var validateToken = (token, network) => {
547
+ let resolvedNetwork = void 0;
548
+ if (network) {
549
+ const networkResult = resolveNetwork(network);
550
+ if (isValidationError(networkResult)) {
551
+ return networkResult;
552
+ }
553
+ resolvedNetwork = networkResult;
554
+ }
555
+ const resolved = resolveToken(token, resolvedNetwork);
556
+ if (isValidationError(resolved)) {
557
+ return resolved;
558
+ }
559
+ return {
560
+ success: true,
561
+ token: resolved.config.symbol,
562
+ network: resolved.network.config.name
563
+ };
564
+ };
565
+ var getNetworks = () => {
566
+ const { getAvailableNetworks } = __require("@armory-sh/base");
567
+ return getAvailableNetworks();
568
+ };
569
+ var getTokens = () => {
570
+ const { getAvailableTokens } = __require("@armory-sh/base");
571
+ return getAvailableTokens();
572
+ };
573
+
574
+ // src/armory-api.ts
575
+ var ALL_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "DELETE", "PATCH"]);
576
+ var arrayify = (value) => {
577
+ if (value === void 0) return void 0;
578
+ return Array.isArray(value) ? value : [value];
579
+ };
580
+ var normalizeArmoryConfig = (config) => ({
581
+ wallet: normalizeWallet(config.wallet),
582
+ allowedMethods: config.methods ? new Set(arrayify(config.methods)) : ALL_METHODS,
583
+ allowedTokens: arrayify(config.tokens) ?? [],
584
+ allowedChains: arrayify(config.chains) ?? [],
585
+ debug: config.debug ?? false
586
+ });
587
+ var createArmory = (config) => {
588
+ const internal = normalizeArmoryConfig(config);
589
+ const makeRequest = async (url, method, body) => {
590
+ try {
591
+ const headers = new Headers();
592
+ const response = await fetch(url, {
593
+ method,
594
+ headers,
595
+ body: body !== void 0 ? JSON.stringify(body) : void 0
596
+ });
597
+ if (!response.ok) {
598
+ const error = await response.text();
599
+ return {
600
+ success: false,
601
+ code: "PAYMENT_DECLINED",
602
+ message: `Request failed: ${response.status} ${error}`
603
+ };
604
+ }
605
+ const data = await response.json();
606
+ const txHash = response.headers.get("X-PAYMENT-RESPONSE") || response.headers.get("PAYMENT-RESPONSE");
607
+ return {
608
+ success: true,
609
+ data,
610
+ ...txHash && { txHash }
611
+ };
612
+ } catch (error) {
613
+ return {
614
+ success: false,
615
+ code: "NETWORK_ERROR",
616
+ message: error instanceof Error ? error.message : "Unknown error occurred",
617
+ details: error
618
+ };
619
+ }
620
+ };
621
+ return {
622
+ get: (url, body) => makeRequest(url, "GET", body),
623
+ post: (url, body) => makeRequest(url, "POST", body),
624
+ put: (url, body) => makeRequest(url, "PUT", body),
625
+ delete: (url) => makeRequest(url, "DELETE"),
626
+ patch: (url, body) => makeRequest(url, "PATCH", body),
627
+ pay: (url, options) => makeRequest(url, options?.method ?? "GET", options?.body),
628
+ call: (url) => makeRequest(url, "GET")
629
+ };
630
+ };
414
631
  export {
415
632
  adjustVForChainId,
633
+ armoryDelete,
634
+ armoryGet,
635
+ armoryPatch,
636
+ armoryPay,
637
+ armoryPost,
638
+ armoryPut,
416
639
  concatenateSignature,
640
+ createArmory,
417
641
  createEIP712Domain,
418
642
  createTransferWithAuthorization,
419
643
  createX402Client,
420
644
  createX402Transport,
645
+ getNetworks,
646
+ getTokens,
647
+ getWalletAddress,
648
+ normalizeWallet,
421
649
  parseSignature,
422
650
  signTypedData,
423
651
  signWithPrivateKey,
652
+ validateNetwork,
653
+ validateToken,
424
654
  validateTransferWithAuthorization
425
655
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@armory-sh/client-web3",
3
- "version": "0.2.14",
3
+ "version": "0.2.16",
4
4
  "license": "MIT",
5
5
  "author": "Sawyer Cutler <sawyer@dirtroad.dev>",
6
6
  "type": "module",
@@ -27,7 +27,7 @@
27
27
  "directory": "packages/client-web3"
28
28
  },
29
29
  "dependencies": {
30
- "@armory-sh/base": "^0.2.18",
30
+ "@armory-sh/base": "^0.2.20",
31
31
  "web3": "4.16.0",
32
32
  "web3-types": "1.10.0"
33
33
  },