@t402/wdk-protocol 2.5.0 → 2.6.0
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/cjs/index.d.ts +28 -1
- package/dist/cjs/index.js +170 -53
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.d.mts +28 -1
- package/dist/esm/index.mjs +169 -53
- package/dist/esm/index.mjs.map +1 -1
- package/package.json +15 -7
package/dist/cjs/index.d.ts
CHANGED
|
@@ -69,17 +69,21 @@ interface T402FetchResult {
|
|
|
69
69
|
*
|
|
70
70
|
* Uses the real t402 protocol client infrastructure with EVM mechanism support.
|
|
71
71
|
* Payment payloads are properly signed using EIP-3009 authorization.
|
|
72
|
+
* Supports multi-chain registration for EVM and non-EVM chain families.
|
|
72
73
|
*/
|
|
73
74
|
declare class T402Protocol {
|
|
74
75
|
private httpClient;
|
|
75
76
|
private wdk;
|
|
76
77
|
private facilitator;
|
|
77
78
|
private chains;
|
|
79
|
+
private _registeredFamilies;
|
|
78
80
|
private constructor();
|
|
79
81
|
/**
|
|
80
82
|
* Create a new T402Protocol instance.
|
|
81
83
|
*
|
|
82
84
|
* This is async because it needs to initialize the WDK signer.
|
|
85
|
+
* Registers the primary EVM signer plus detects additional chain families
|
|
86
|
+
* from the configured chains list.
|
|
83
87
|
*
|
|
84
88
|
* @param wdk - An initialized T402WDK instance
|
|
85
89
|
* @param config - Protocol configuration
|
|
@@ -99,6 +103,11 @@ declare class T402Protocol {
|
|
|
99
103
|
* @returns The final response and optional payment receipt
|
|
100
104
|
*/
|
|
101
105
|
fetch(url: string | URL, init?: RequestInit): Promise<T402FetchResult>;
|
|
106
|
+
/**
|
|
107
|
+
* Emit an event on the underlying WDK event system.
|
|
108
|
+
* Silently no-ops if the WDK doesn't support events.
|
|
109
|
+
*/
|
|
110
|
+
private _emitOnWdk;
|
|
102
111
|
/**
|
|
103
112
|
* Extract payment requirements from a URL
|
|
104
113
|
*
|
|
@@ -140,6 +149,17 @@ declare class T402Protocol {
|
|
|
140
149
|
* Get the configured chains
|
|
141
150
|
*/
|
|
142
151
|
getChains(): string[];
|
|
152
|
+
/**
|
|
153
|
+
* Get the set of registered chain families (e.g., 'evm', 'ton', 'solana')
|
|
154
|
+
*/
|
|
155
|
+
getRegisteredFamilies(): Set<string>;
|
|
156
|
+
/**
|
|
157
|
+
* Check if this protocol instance can handle a given CAIP-2 network.
|
|
158
|
+
*
|
|
159
|
+
* @param network - CAIP-2 network identifier (e.g., "eip155:42161", "ton:mainnet")
|
|
160
|
+
* @returns True if the required chain family is registered
|
|
161
|
+
*/
|
|
162
|
+
canHandleNetwork(network: string): boolean;
|
|
143
163
|
}
|
|
144
164
|
|
|
145
165
|
/**
|
|
@@ -175,6 +195,13 @@ declare function getEvmChainName(network: string): string | undefined;
|
|
|
175
195
|
* @returns True if the network is an EVM chain
|
|
176
196
|
*/
|
|
177
197
|
declare function isEvmNetwork(network: string): boolean;
|
|
198
|
+
/**
|
|
199
|
+
* Detect chain family from a human-readable chain name.
|
|
200
|
+
*
|
|
201
|
+
* @param chainName - Chain name (e.g., "ethereum", "ton", "solana")
|
|
202
|
+
* @returns The chain family, or undefined if not recognized
|
|
203
|
+
*/
|
|
204
|
+
declare function detectChainFamilyFromName(chainName: string): ChainFamily | undefined;
|
|
178
205
|
|
|
179
206
|
/**
|
|
180
207
|
* HTTP client utilities for 402 payment handling
|
|
@@ -190,4 +217,4 @@ declare function isEvmNetwork(network: string): boolean;
|
|
|
190
217
|
*/
|
|
191
218
|
declare function extractPaymentRequired(response: Response): PaymentRequired;
|
|
192
219
|
|
|
193
|
-
export { type ChainFamily, EVM_CHAIN_MAP, type PaymentReceipt, type T402FetchResult, T402Protocol, type T402ProtocolConfig, detectChainFamily, extractPaymentRequired, getEvmChainName, isEvmNetwork };
|
|
220
|
+
export { type ChainFamily, EVM_CHAIN_MAP, type PaymentReceipt, type T402FetchResult, T402Protocol, type T402ProtocolConfig, detectChainFamily, detectChainFamilyFromName, extractPaymentRequired, getEvmChainName, isEvmNetwork };
|
package/dist/cjs/index.js
CHANGED
|
@@ -25,6 +25,7 @@ __export(src_exports, {
|
|
|
25
25
|
EVM_CHAIN_MAP: () => EVM_CHAIN_MAP,
|
|
26
26
|
T402Protocol: () => T402Protocol,
|
|
27
27
|
detectChainFamily: () => detectChainFamily,
|
|
28
|
+
detectChainFamilyFromName: () => detectChainFamilyFromName,
|
|
28
29
|
extractPaymentRequired: () => extractPaymentRequired,
|
|
29
30
|
getEvmChainName: () => getEvmChainName,
|
|
30
31
|
isEvmNetwork: () => isEvmNetwork
|
|
@@ -54,6 +55,76 @@ function extractPaymentRequired(response) {
|
|
|
54
55
|
);
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
// src/signer-factory.ts
|
|
59
|
+
var CAIP2_EVM = "eip155:";
|
|
60
|
+
var CAIP2_TON = "ton:";
|
|
61
|
+
var CAIP2_SOLANA = "solana:";
|
|
62
|
+
var CAIP2_TRON = "tron:";
|
|
63
|
+
var CAIP2_NEAR = "near:";
|
|
64
|
+
var CAIP2_APTOS = "aptos:";
|
|
65
|
+
var CAIP2_TEZOS = "tezos:";
|
|
66
|
+
var CAIP2_POLKADOT = "polkadot:";
|
|
67
|
+
var CAIP2_STACKS = "stacks:";
|
|
68
|
+
var CAIP2_COSMOS = "cosmos:";
|
|
69
|
+
function detectChainFamily(network) {
|
|
70
|
+
if (network.startsWith(CAIP2_EVM)) return "evm";
|
|
71
|
+
if (network.startsWith(CAIP2_TON)) return "ton";
|
|
72
|
+
if (network.startsWith(CAIP2_SOLANA)) return "solana";
|
|
73
|
+
if (network.startsWith(CAIP2_TRON)) return "tron";
|
|
74
|
+
if (network.startsWith(CAIP2_NEAR)) return "near";
|
|
75
|
+
if (network.startsWith(CAIP2_APTOS)) return "aptos";
|
|
76
|
+
if (network.startsWith(CAIP2_TEZOS)) return "tezos";
|
|
77
|
+
if (network.startsWith(CAIP2_POLKADOT)) return "polkadot";
|
|
78
|
+
if (network.startsWith(CAIP2_STACKS)) return "stacks";
|
|
79
|
+
if (network.startsWith(CAIP2_COSMOS)) return "cosmos";
|
|
80
|
+
throw new Error(`Unsupported network: ${network}. Cannot detect chain family from CAIP-2 prefix.`);
|
|
81
|
+
}
|
|
82
|
+
var EVM_CHAIN_MAP = {
|
|
83
|
+
ethereum: "eip155:1",
|
|
84
|
+
base: "eip155:8453",
|
|
85
|
+
arbitrum: "eip155:42161",
|
|
86
|
+
optimism: "eip155:10",
|
|
87
|
+
polygon: "eip155:137",
|
|
88
|
+
avalanche: "eip155:43114",
|
|
89
|
+
ink: "eip155:57073",
|
|
90
|
+
berachain: "eip155:80094",
|
|
91
|
+
unichain: "eip155:130"
|
|
92
|
+
};
|
|
93
|
+
function getEvmChainName(network) {
|
|
94
|
+
for (const [name, caip2] of Object.entries(EVM_CHAIN_MAP)) {
|
|
95
|
+
if (caip2 === network) return name;
|
|
96
|
+
}
|
|
97
|
+
return void 0;
|
|
98
|
+
}
|
|
99
|
+
function isEvmNetwork(network) {
|
|
100
|
+
return network.startsWith(CAIP2_EVM);
|
|
101
|
+
}
|
|
102
|
+
var CHAIN_NAME_TO_FAMILY = {
|
|
103
|
+
// EVM chains
|
|
104
|
+
ethereum: "evm",
|
|
105
|
+
arbitrum: "evm",
|
|
106
|
+
base: "evm",
|
|
107
|
+
polygon: "evm",
|
|
108
|
+
optimism: "evm",
|
|
109
|
+
avalanche: "evm",
|
|
110
|
+
ink: "evm",
|
|
111
|
+
berachain: "evm",
|
|
112
|
+
unichain: "evm",
|
|
113
|
+
// Non-EVM chains
|
|
114
|
+
ton: "ton",
|
|
115
|
+
solana: "solana",
|
|
116
|
+
tron: "tron",
|
|
117
|
+
near: "near",
|
|
118
|
+
aptos: "aptos",
|
|
119
|
+
tezos: "tezos",
|
|
120
|
+
polkadot: "polkadot",
|
|
121
|
+
stacks: "stacks",
|
|
122
|
+
cosmos: "cosmos"
|
|
123
|
+
};
|
|
124
|
+
function detectChainFamilyFromName(chainName) {
|
|
125
|
+
return CHAIN_NAME_TO_FAMILY[chainName.toLowerCase()];
|
|
126
|
+
}
|
|
127
|
+
|
|
57
128
|
// src/protocol.ts
|
|
58
129
|
var DEFAULT_FACILITATOR = "https://facilitator.t402.io";
|
|
59
130
|
var T402Protocol = class _T402Protocol {
|
|
@@ -62,6 +133,7 @@ var T402Protocol = class _T402Protocol {
|
|
|
62
133
|
__publicField(this, "wdk");
|
|
63
134
|
__publicField(this, "facilitator");
|
|
64
135
|
__publicField(this, "chains");
|
|
136
|
+
__publicField(this, "_registeredFamilies", /* @__PURE__ */ new Set());
|
|
65
137
|
this.wdk = wdk;
|
|
66
138
|
this.httpClient = httpClient;
|
|
67
139
|
this.facilitator = config.facilitator ?? DEFAULT_FACILITATOR;
|
|
@@ -71,18 +143,35 @@ var T402Protocol = class _T402Protocol {
|
|
|
71
143
|
* Create a new T402Protocol instance.
|
|
72
144
|
*
|
|
73
145
|
* This is async because it needs to initialize the WDK signer.
|
|
146
|
+
* Registers the primary EVM signer plus detects additional chain families
|
|
147
|
+
* from the configured chains list.
|
|
74
148
|
*
|
|
75
149
|
* @param wdk - An initialized T402WDK instance
|
|
76
150
|
* @param config - Protocol configuration
|
|
77
151
|
* @returns A configured T402Protocol instance
|
|
78
152
|
*/
|
|
79
153
|
static async create(wdk, config = {}) {
|
|
80
|
-
const chainName = config.chains?.[0] ?? "ethereum";
|
|
81
|
-
const signer = await wdk.getSigner(chainName);
|
|
82
154
|
const client = new import_client.t402Client();
|
|
83
|
-
|
|
155
|
+
const registeredFamilies = /* @__PURE__ */ new Set();
|
|
156
|
+
const chainName = config.chains?.[0] ?? "ethereum";
|
|
157
|
+
try {
|
|
158
|
+
const signer = await wdk.getSigner(chainName);
|
|
159
|
+
(0, import_client2.registerExactEvmScheme)(client, { signer });
|
|
160
|
+
registeredFamilies.add("evm");
|
|
161
|
+
} catch {
|
|
162
|
+
}
|
|
163
|
+
if (config.chains) {
|
|
164
|
+
for (const chain of config.chains) {
|
|
165
|
+
const family = detectChainFamilyFromName(chain);
|
|
166
|
+
if (family) {
|
|
167
|
+
registeredFamilies.add(family);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
84
171
|
const httpClient = new import_http2.t402HTTPClient(client);
|
|
85
|
-
|
|
172
|
+
const protocol = new _T402Protocol(wdk, httpClient, config);
|
|
173
|
+
protocol._registeredFamilies = registeredFamilies;
|
|
174
|
+
return protocol;
|
|
86
175
|
}
|
|
87
176
|
/**
|
|
88
177
|
* Fetch a URL with automatic 402 payment handling.
|
|
@@ -97,6 +186,7 @@ var T402Protocol = class _T402Protocol {
|
|
|
97
186
|
* @returns The final response and optional payment receipt
|
|
98
187
|
*/
|
|
99
188
|
async fetch(url, init) {
|
|
189
|
+
const urlStr = url.toString();
|
|
100
190
|
const response = await fetch(url, init);
|
|
101
191
|
if (response.status !== 402) {
|
|
102
192
|
return { response };
|
|
@@ -104,22 +194,75 @@ var T402Protocol = class _T402Protocol {
|
|
|
104
194
|
const paymentRequired = this.httpClient.getPaymentRequiredResponse(
|
|
105
195
|
(name) => response.headers.get(name)
|
|
106
196
|
);
|
|
107
|
-
const
|
|
197
|
+
const network = paymentRequired.accepts?.[0]?.network ?? "";
|
|
198
|
+
const amount = paymentRequired.accepts?.[0]?.amount ?? "";
|
|
199
|
+
this._emitOnWdk("payment:start", { url: urlStr, network, amount });
|
|
200
|
+
let paymentPayload;
|
|
201
|
+
try {
|
|
202
|
+
paymentPayload = await this.httpClient.createPaymentPayload(paymentRequired);
|
|
203
|
+
} catch (error) {
|
|
204
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
205
|
+
this._emitOnWdk("payment:failed", { url: urlStr, error: errMsg });
|
|
206
|
+
throw error;
|
|
207
|
+
}
|
|
208
|
+
this._emitOnWdk("payment:signed", {
|
|
209
|
+
url: urlStr,
|
|
210
|
+
scheme: paymentPayload.accepted.scheme,
|
|
211
|
+
network: paymentPayload.accepted.network
|
|
212
|
+
});
|
|
108
213
|
const paymentHeaders = this.httpClient.encodePaymentSignatureHeader(paymentPayload);
|
|
109
214
|
const headers = new Headers(init?.headers);
|
|
110
215
|
for (const [key, value] of Object.entries(paymentHeaders)) {
|
|
111
216
|
headers.set(key, value);
|
|
112
217
|
}
|
|
113
218
|
const retryResponse = await fetch(url, { ...init, headers });
|
|
219
|
+
this._emitOnWdk("payment:submitted", { url: urlStr, statusCode: retryResponse.status });
|
|
220
|
+
const success = retryResponse.status !== 402;
|
|
114
221
|
const receipt = {
|
|
115
|
-
success
|
|
222
|
+
success,
|
|
116
223
|
network: paymentPayload.accepted.network,
|
|
117
224
|
scheme: paymentPayload.accepted.scheme,
|
|
118
225
|
amount: paymentPayload.accepted.amount,
|
|
119
226
|
payTo: paymentPayload.accepted.payTo
|
|
120
227
|
};
|
|
228
|
+
let chainFamily = "evm";
|
|
229
|
+
try {
|
|
230
|
+
chainFamily = detectChainFamily(paymentPayload.accepted.network);
|
|
231
|
+
} catch {
|
|
232
|
+
}
|
|
233
|
+
const enrichedReceipt = {
|
|
234
|
+
id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
235
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
236
|
+
url: urlStr,
|
|
237
|
+
network: paymentPayload.accepted.network,
|
|
238
|
+
scheme: paymentPayload.accepted.scheme,
|
|
239
|
+
amount: paymentPayload.accepted.amount,
|
|
240
|
+
payTo: paymentPayload.accepted.payTo,
|
|
241
|
+
success,
|
|
242
|
+
chainFamily
|
|
243
|
+
};
|
|
244
|
+
try {
|
|
245
|
+
await this.wdk.getReceiptStore().save(enrichedReceipt);
|
|
246
|
+
} catch {
|
|
247
|
+
}
|
|
248
|
+
if (success) {
|
|
249
|
+
this._emitOnWdk("payment:complete", { url: urlStr, success: true, receipt });
|
|
250
|
+
} else {
|
|
251
|
+
this._emitOnWdk("payment:failed", { url: urlStr, error: "Payment rejected (still 402)" });
|
|
252
|
+
}
|
|
121
253
|
return { response: retryResponse, receipt };
|
|
122
254
|
}
|
|
255
|
+
/**
|
|
256
|
+
* Emit an event on the underlying WDK event system.
|
|
257
|
+
* Silently no-ops if the WDK doesn't support events.
|
|
258
|
+
*/
|
|
259
|
+
_emitOnWdk(event, data) {
|
|
260
|
+
try {
|
|
261
|
+
const wdk = this.wdk;
|
|
262
|
+
wdk.emit?.(event, data);
|
|
263
|
+
} catch {
|
|
264
|
+
}
|
|
265
|
+
}
|
|
123
266
|
/**
|
|
124
267
|
* Extract payment requirements from a URL
|
|
125
268
|
*
|
|
@@ -184,59 +327,33 @@ var T402Protocol = class _T402Protocol {
|
|
|
184
327
|
getChains() {
|
|
185
328
|
return [...this.chains];
|
|
186
329
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
var CAIP2_SOLANA = "solana:";
|
|
193
|
-
var CAIP2_TRON = "tron:";
|
|
194
|
-
var CAIP2_NEAR = "near:";
|
|
195
|
-
var CAIP2_APTOS = "aptos:";
|
|
196
|
-
var CAIP2_TEZOS = "tezos:";
|
|
197
|
-
var CAIP2_POLKADOT = "polkadot:";
|
|
198
|
-
var CAIP2_STACKS = "stacks:";
|
|
199
|
-
var CAIP2_COSMOS = "cosmos:";
|
|
200
|
-
function detectChainFamily(network) {
|
|
201
|
-
if (network.startsWith(CAIP2_EVM)) return "evm";
|
|
202
|
-
if (network.startsWith(CAIP2_TON)) return "ton";
|
|
203
|
-
if (network.startsWith(CAIP2_SOLANA)) return "solana";
|
|
204
|
-
if (network.startsWith(CAIP2_TRON)) return "tron";
|
|
205
|
-
if (network.startsWith(CAIP2_NEAR)) return "near";
|
|
206
|
-
if (network.startsWith(CAIP2_APTOS)) return "aptos";
|
|
207
|
-
if (network.startsWith(CAIP2_TEZOS)) return "tezos";
|
|
208
|
-
if (network.startsWith(CAIP2_POLKADOT)) return "polkadot";
|
|
209
|
-
if (network.startsWith(CAIP2_STACKS)) return "stacks";
|
|
210
|
-
if (network.startsWith(CAIP2_COSMOS)) return "cosmos";
|
|
211
|
-
throw new Error(
|
|
212
|
-
`Unsupported network: ${network}. Cannot detect chain family from CAIP-2 prefix.`
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
var EVM_CHAIN_MAP = {
|
|
216
|
-
ethereum: "eip155:1",
|
|
217
|
-
base: "eip155:8453",
|
|
218
|
-
arbitrum: "eip155:42161",
|
|
219
|
-
optimism: "eip155:10",
|
|
220
|
-
polygon: "eip155:137",
|
|
221
|
-
avalanche: "eip155:43114",
|
|
222
|
-
ink: "eip155:57073",
|
|
223
|
-
berachain: "eip155:80094",
|
|
224
|
-
unichain: "eip155:130"
|
|
225
|
-
};
|
|
226
|
-
function getEvmChainName(network) {
|
|
227
|
-
for (const [name, caip2] of Object.entries(EVM_CHAIN_MAP)) {
|
|
228
|
-
if (caip2 === network) return name;
|
|
330
|
+
/**
|
|
331
|
+
* Get the set of registered chain families (e.g., 'evm', 'ton', 'solana')
|
|
332
|
+
*/
|
|
333
|
+
getRegisteredFamilies() {
|
|
334
|
+
return new Set(this._registeredFamilies);
|
|
229
335
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
336
|
+
/**
|
|
337
|
+
* Check if this protocol instance can handle a given CAIP-2 network.
|
|
338
|
+
*
|
|
339
|
+
* @param network - CAIP-2 network identifier (e.g., "eip155:42161", "ton:mainnet")
|
|
340
|
+
* @returns True if the required chain family is registered
|
|
341
|
+
*/
|
|
342
|
+
canHandleNetwork(network) {
|
|
343
|
+
try {
|
|
344
|
+
const family = detectChainFamily(network);
|
|
345
|
+
return this._registeredFamilies.has(family);
|
|
346
|
+
} catch {
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
};
|
|
235
351
|
// Annotate the CommonJS export names for ESM import in node:
|
|
236
352
|
0 && (module.exports = {
|
|
237
353
|
EVM_CHAIN_MAP,
|
|
238
354
|
T402Protocol,
|
|
239
355
|
detectChainFamily,
|
|
356
|
+
detectChainFamilyFromName,
|
|
240
357
|
extractPaymentRequired,
|
|
241
358
|
getEvmChainName,
|
|
242
359
|
isEvmNetwork
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts","../../src/protocol.ts","../../src/http-client.ts","../../src/signer-factory.ts"],"sourcesContent":["/**\n * @module @t402/wdk-protocol\n *\n * T402 payment protocol for Tether WDK wallet apps.\n *\n * Enables any WDK-based wallet to handle HTTP 402 payments:\n *\n * @example\n * ```typescript\n * import { T402Protocol } from '@t402/wdk-protocol';\n * import { T402WDK } from '@t402/wdk';\n *\n * const wdk = new T402WDK(seedPhrase, { arbitrum: rpcUrl });\n * const t402 = await T402Protocol.create(wdk, {\n * chains: ['ethereum', 'arbitrum'],\n * });\n *\n * // Auto-pay for 402 resources\n * const { response, receipt } = await t402.fetch('https://api.example.com/premium');\n * ```\n */\n\n// Main class\nexport { T402Protocol } from './protocol.js'\n\n// Chain detection utilities\nexport {\n detectChainFamily,\n isEvmNetwork,\n getEvmChainName,\n EVM_CHAIN_MAP,\n type ChainFamily,\n} from './signer-factory.js'\n\n// HTTP client utilities\nexport { extractPaymentRequired } from './http-client.js'\n\n// Types\nexport type { T402ProtocolConfig, PaymentReceipt, T402FetchResult } from './types.js'\n","/**\n * T402Protocol - Main class for WDK apps to add T402 payment capability\n *\n * Uses the real t402 client infrastructure (t402Client + mechanism-specific\n * scheme clients) for proper payment payload creation and signing.\n *\n * @example\n * ```typescript\n * import { T402Protocol } from '@t402/wdk-protocol';\n * import { T402WDK } from '@t402/wdk';\n *\n * const wdk = new T402WDK(seedPhrase, { arbitrum: rpcUrl });\n * const t402 = await T402Protocol.create(wdk, {\n * chains: ['ethereum', 'arbitrum'],\n * });\n *\n * // Auto-pay for HTTP 402 resources\n * const { response, receipt } = await t402.fetch('https://api.example.com/premium');\n * ```\n */\n\nimport { t402Client } from '@t402/core/client'\nimport { t402HTTPClient } from '@t402/core/http'\nimport type { PaymentRequired, PaymentPayload } from '@t402/core/types'\nimport { registerExactEvmScheme } from '@t402/evm/exact/client'\nimport type { T402WDK } from '@t402/wdk'\n\nimport { extractPaymentRequired } from './http-client.js'\nimport type { T402ProtocolConfig, T402FetchResult, PaymentReceipt } from './types.js'\n\nconst DEFAULT_FACILITATOR = 'https://facilitator.t402.io'\n\n/**\n * T402Protocol enables any WDK wallet app to handle HTTP 402 payments.\n *\n * Uses the real t402 protocol client infrastructure with EVM mechanism support.\n * Payment payloads are properly signed using EIP-3009 authorization.\n */\nexport class T402Protocol {\n private httpClient: t402HTTPClient\n private wdk: T402WDK\n private facilitator: string\n private chains: string[]\n\n private constructor(\n wdk: T402WDK,\n httpClient: t402HTTPClient,\n config: T402ProtocolConfig,\n ) {\n this.wdk = wdk\n this.httpClient = httpClient\n this.facilitator = config.facilitator ?? DEFAULT_FACILITATOR\n this.chains = config.chains ?? []\n }\n\n /**\n * Create a new T402Protocol instance.\n *\n * This is async because it needs to initialize the WDK signer.\n *\n * @param wdk - An initialized T402WDK instance\n * @param config - Protocol configuration\n * @returns A configured T402Protocol instance\n */\n static async create(wdk: T402WDK, config: T402ProtocolConfig = {}): Promise<T402Protocol> {\n // Get an EVM signer from WDK for the first available chain\n const chainName = config.chains?.[0] ?? 'ethereum'\n const signer = await wdk.getSigner(chainName)\n\n // Create t402 client with EVM exact scheme\n const client = new t402Client()\n registerExactEvmScheme(client, { signer })\n\n const httpClient = new t402HTTPClient(client)\n\n return new T402Protocol(wdk, httpClient, config)\n }\n\n /**\n * Fetch a URL with automatic 402 payment handling.\n *\n * 1. Makes the initial request\n * 2. If 402, extracts payment requirements\n * 3. Creates a properly signed payment payload (EIP-3009 for EVM)\n * 4. Retries the request with the signed payment header\n *\n * @param url - URL to fetch\n * @param init - Standard fetch RequestInit options\n * @returns The final response and optional payment receipt\n */\n async fetch(url: string | URL, init?: RequestInit): Promise<T402FetchResult> {\n // Make initial request\n const response = await fetch(url, init)\n\n // If not 402, return as-is\n if (response.status !== 402) {\n return { response }\n }\n\n // Extract payment requirements from 402 response\n const paymentRequired = this.httpClient.getPaymentRequiredResponse(\n (name: string) => response.headers.get(name),\n )\n\n // Create signed payment payload using mechanism-specific logic\n const paymentPayload = await this.httpClient.createPaymentPayload(paymentRequired)\n\n // Build retry headers\n const paymentHeaders = this.httpClient.encodePaymentSignatureHeader(paymentPayload)\n const headers = new Headers(init?.headers)\n for (const [key, value] of Object.entries(paymentHeaders)) {\n headers.set(key, value)\n }\n\n // Retry with payment\n const retryResponse = await fetch(url, { ...init, headers })\n\n const receipt: PaymentReceipt = {\n success: retryResponse.status !== 402,\n network: paymentPayload.accepted.network,\n scheme: paymentPayload.accepted.scheme,\n amount: paymentPayload.accepted.amount,\n payTo: paymentPayload.accepted.payTo,\n }\n\n return { response: retryResponse, receipt }\n }\n\n /**\n * Extract payment requirements from a URL\n *\n * @param url - URL to check for payment requirements\n * @param init - Standard fetch RequestInit options\n * @returns The PaymentRequired object from the 402 response\n * @throws Error if the response is not 402\n */\n async getRequirements(url: string | URL, init?: RequestInit): Promise<PaymentRequired> {\n const response = await fetch(url, init)\n if (response.status !== 402) {\n throw new Error(`Expected 402 response, got ${response.status}`)\n }\n return extractPaymentRequired(response)\n }\n\n /**\n * Sign a payment for specific requirements using the t402 client infrastructure\n *\n * @param paymentRequired - The full PaymentRequired context\n * @returns A properly signed PaymentPayload (e.g., EIP-3009 for EVM)\n */\n async signPayment(paymentRequired: PaymentRequired): Promise<PaymentPayload> {\n return this.httpClient.createPaymentPayload(paymentRequired)\n }\n\n /**\n * Submit a request with a pre-signed payment payload\n *\n * @param url - URL to request\n * @param paymentPayload - The signed payment payload\n * @param init - Standard fetch RequestInit options\n * @returns The HTTP response\n */\n async submitPayment(\n url: string | URL,\n paymentPayload: PaymentPayload,\n init?: RequestInit,\n ): Promise<Response> {\n const paymentHeaders = this.httpClient.encodePaymentSignatureHeader(paymentPayload)\n const headers = new Headers(init?.headers)\n for (const [key, value] of Object.entries(paymentHeaders)) {\n headers.set(key, value)\n }\n\n return fetch(url, { ...init, headers })\n }\n\n /**\n * Get the underlying t402 HTTP client for advanced usage\n */\n getHttpClient(): t402HTTPClient {\n return this.httpClient\n }\n\n /**\n * Get the underlying WDK instance\n */\n getWdk(): T402WDK {\n return this.wdk\n }\n\n /**\n * Get the facilitator URL\n */\n getFacilitator(): string {\n return this.facilitator\n }\n\n /**\n * Get the configured chains\n */\n getChains(): string[] {\n return [...this.chains]\n }\n}\n","/**\n * HTTP client utilities for 402 payment handling\n */\n\nimport { decodePaymentRequiredHeader } from '@t402/core/http'\nimport type { PaymentRequired } from '@t402/core/types'\n\n/** V2 header names */\nconst HEADER_PAYMENT_REQUIRED = 'payment-required'\n\n/** V1 header names (fallback) */\nconst HEADER_X_PAYMENT = 'x-payment'\n\n/**\n * Extract PaymentRequired from a 402 response.\n * Tries V2 header first, then falls back to V1.\n *\n * @param response - The HTTP response with status 402\n * @returns The parsed PaymentRequired object\n * @throws Error if no valid payment header is found\n */\nexport function extractPaymentRequired(response: Response): PaymentRequired {\n // Try V2 header\n const v2Header = response.headers.get(HEADER_PAYMENT_REQUIRED)\n if (v2Header) {\n return decodePaymentRequiredHeader(v2Header)\n }\n\n // Try V1 header\n const v1Header = response.headers.get(HEADER_X_PAYMENT)\n if (v1Header) {\n return decodePaymentRequiredHeader(v1Header)\n }\n\n throw new Error(\n 'No payment requirements found in 402 response. ' +\n `Expected \"${HEADER_PAYMENT_REQUIRED}\" or \"${HEADER_X_PAYMENT}\" header.`,\n )\n}\n","/**\n * Chain detection utilities for CAIP-2 network identifiers\n */\n\n/**\n * CAIP-2 namespace prefixes\n */\nconst CAIP2_EVM = 'eip155:'\nconst CAIP2_TON = 'ton:'\nconst CAIP2_SOLANA = 'solana:'\nconst CAIP2_TRON = 'tron:'\nconst CAIP2_NEAR = 'near:'\nconst CAIP2_APTOS = 'aptos:'\nconst CAIP2_TEZOS = 'tezos:'\nconst CAIP2_POLKADOT = 'polkadot:'\nconst CAIP2_STACKS = 'stacks:'\nconst CAIP2_COSMOS = 'cosmos:'\n\n/**\n * Chain family detected from CAIP-2 network identifier\n */\nexport type ChainFamily =\n | 'evm'\n | 'ton'\n | 'solana'\n | 'tron'\n | 'near'\n | 'aptos'\n | 'tezos'\n | 'polkadot'\n | 'stacks'\n | 'cosmos'\n\n/**\n * Detect chain family from a CAIP-2 network identifier\n *\n * @param network - CAIP-2 network identifier (e.g., \"eip155:1\", \"ton:mainnet\")\n * @returns The chain family\n * @throws Error if network prefix is not recognized\n */\nexport function detectChainFamily(network: string): ChainFamily {\n if (network.startsWith(CAIP2_EVM)) return 'evm'\n if (network.startsWith(CAIP2_TON)) return 'ton'\n if (network.startsWith(CAIP2_SOLANA)) return 'solana'\n if (network.startsWith(CAIP2_TRON)) return 'tron'\n if (network.startsWith(CAIP2_NEAR)) return 'near'\n if (network.startsWith(CAIP2_APTOS)) return 'aptos'\n if (network.startsWith(CAIP2_TEZOS)) return 'tezos'\n if (network.startsWith(CAIP2_POLKADOT)) return 'polkadot'\n if (network.startsWith(CAIP2_STACKS)) return 'stacks'\n if (network.startsWith(CAIP2_COSMOS)) return 'cosmos'\n\n throw new Error(\n `Unsupported network: ${network}. Cannot detect chain family from CAIP-2 prefix.`,\n )\n}\n\n/**\n * Map of EVM chain names to CAIP-2 identifiers\n */\nexport const EVM_CHAIN_MAP: Record<string, string> = {\n ethereum: 'eip155:1',\n base: 'eip155:8453',\n arbitrum: 'eip155:42161',\n optimism: 'eip155:10',\n polygon: 'eip155:137',\n avalanche: 'eip155:43114',\n ink: 'eip155:57073',\n berachain: 'eip155:80094',\n unichain: 'eip155:130',\n}\n\n/**\n * Get EVM chain name from CAIP-2 network identifier\n *\n * @param network - CAIP-2 network (e.g., \"eip155:42161\")\n * @returns Chain name (e.g., \"arbitrum\") or undefined\n */\nexport function getEvmChainName(network: string): string | undefined {\n for (const [name, caip2] of Object.entries(EVM_CHAIN_MAP)) {\n if (caip2 === network) return name\n }\n return undefined\n}\n\n/**\n * Check if a network is an EVM chain\n *\n * @param network - CAIP-2 network identifier\n * @returns True if the network is an EVM chain\n */\nexport function isEvmNetwork(network: string): boolean {\n return network.startsWith(CAIP2_EVM)\n}\n"],"mappings":"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","names":["import_http","import_client"]}
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts","../../src/protocol.ts","../../src/http-client.ts","../../src/signer-factory.ts"],"sourcesContent":["/**\n * @module @t402/wdk-protocol\n *\n * T402 payment protocol for Tether WDK wallet apps.\n *\n * Enables any WDK-based wallet to handle HTTP 402 payments:\n *\n * @example\n * ```typescript\n * import { T402Protocol } from '@t402/wdk-protocol';\n * import { T402WDK } from '@t402/wdk';\n *\n * const wdk = new T402WDK(seedPhrase, { arbitrum: rpcUrl });\n * const t402 = await T402Protocol.create(wdk, {\n * chains: ['ethereum', 'arbitrum'],\n * });\n *\n * // Auto-pay for 402 resources\n * const { response, receipt } = await t402.fetch('https://api.example.com/premium');\n * ```\n */\n\n// Main class\nexport { T402Protocol } from './protocol.js'\n\n// Chain detection utilities\nexport {\n detectChainFamily,\n detectChainFamilyFromName,\n isEvmNetwork,\n getEvmChainName,\n EVM_CHAIN_MAP,\n type ChainFamily,\n} from './signer-factory.js'\n\n// HTTP client utilities\nexport { extractPaymentRequired } from './http-client.js'\n\n// Types\nexport type { T402ProtocolConfig, PaymentReceipt, T402FetchResult } from './types.js'\n","/**\n * T402Protocol - Main class for WDK apps to add T402 payment capability\n *\n * Uses the real t402 client infrastructure (t402Client + mechanism-specific\n * scheme clients) for proper payment payload creation and signing.\n *\n * @example\n * ```typescript\n * import { T402Protocol } from '@t402/wdk-protocol';\n * import { T402WDK } from '@t402/wdk';\n *\n * const wdk = new T402WDK(seedPhrase, { arbitrum: rpcUrl });\n * const t402 = await T402Protocol.create(wdk, {\n * chains: ['ethereum', 'arbitrum'],\n * });\n *\n * // Auto-pay for HTTP 402 resources\n * const { response, receipt } = await t402.fetch('https://api.example.com/premium');\n * ```\n */\n\nimport { t402Client } from '@t402/core/client'\nimport { t402HTTPClient } from '@t402/core/http'\nimport type { PaymentRequired, PaymentPayload } from '@t402/core/types'\nimport { registerExactEvmScheme } from '@t402/evm/exact/client'\nimport type { T402WDK } from '@t402/wdk'\nimport type { EnrichedReceipt } from '@t402/wdk'\n\nimport { extractPaymentRequired } from './http-client.js'\nimport { detectChainFamily, detectChainFamilyFromName } from './signer-factory.js'\nimport type { T402ProtocolConfig, T402FetchResult, PaymentReceipt } from './types.js'\n\nconst DEFAULT_FACILITATOR = 'https://facilitator.t402.io'\n\n/**\n * T402Protocol enables any WDK wallet app to handle HTTP 402 payments.\n *\n * Uses the real t402 protocol client infrastructure with EVM mechanism support.\n * Payment payloads are properly signed using EIP-3009 authorization.\n * Supports multi-chain registration for EVM and non-EVM chain families.\n */\nexport class T402Protocol {\n private httpClient: t402HTTPClient\n private wdk: T402WDK\n private facilitator: string\n private chains: string[]\n private _registeredFamilies: Set<string> = new Set()\n\n private constructor(wdk: T402WDK, httpClient: t402HTTPClient, config: T402ProtocolConfig) {\n this.wdk = wdk\n this.httpClient = httpClient\n this.facilitator = config.facilitator ?? DEFAULT_FACILITATOR\n this.chains = config.chains ?? []\n }\n\n /**\n * Create a new T402Protocol instance.\n *\n * This is async because it needs to initialize the WDK signer.\n * Registers the primary EVM signer plus detects additional chain families\n * from the configured chains list.\n *\n * @param wdk - An initialized T402WDK instance\n * @param config - Protocol configuration\n * @returns A configured T402Protocol instance\n */\n static async create(wdk: T402WDK, config: T402ProtocolConfig = {}): Promise<T402Protocol> {\n const client = new t402Client()\n const registeredFamilies = new Set<string>()\n\n // Register EVM (primary chain)\n const chainName = config.chains?.[0] ?? 'ethereum'\n try {\n const signer = await wdk.getSigner(chainName)\n registerExactEvmScheme(client, { signer })\n registeredFamilies.add('evm')\n } catch {\n // EVM not available — non-EVM-only config\n }\n\n // Detect additional chain families from configured chains\n if (config.chains) {\n for (const chain of config.chains) {\n const family = detectChainFamilyFromName(chain)\n if (family) {\n registeredFamilies.add(family)\n }\n }\n }\n\n const httpClient = new t402HTTPClient(client)\n const protocol = new T402Protocol(wdk, httpClient, config)\n protocol._registeredFamilies = registeredFamilies\n\n return protocol\n }\n\n /**\n * Fetch a URL with automatic 402 payment handling.\n *\n * 1. Makes the initial request\n * 2. If 402, extracts payment requirements\n * 3. Creates a properly signed payment payload (EIP-3009 for EVM)\n * 4. Retries the request with the signed payment header\n *\n * @param url - URL to fetch\n * @param init - Standard fetch RequestInit options\n * @returns The final response and optional payment receipt\n */\n async fetch(url: string | URL, init?: RequestInit): Promise<T402FetchResult> {\n const urlStr = url.toString()\n\n // Make initial request\n const response = await fetch(url, init)\n\n // If not 402, return as-is\n if (response.status !== 402) {\n return { response }\n }\n\n // Extract payment requirements from 402 response\n const paymentRequired = this.httpClient.getPaymentRequiredResponse((name: string) =>\n response.headers.get(name),\n )\n\n const network = paymentRequired.accepts?.[0]?.network ?? ''\n const amount = paymentRequired.accepts?.[0]?.amount ?? ''\n\n // Emit payment:start\n this._emitOnWdk('payment:start', { url: urlStr, network, amount })\n\n // Create signed payment payload using mechanism-specific logic\n let paymentPayload: PaymentPayload\n try {\n paymentPayload = await this.httpClient.createPaymentPayload(paymentRequired)\n } catch (error) {\n const errMsg = error instanceof Error ? error.message : String(error)\n this._emitOnWdk('payment:failed', { url: urlStr, error: errMsg })\n throw error\n }\n\n this._emitOnWdk('payment:signed', {\n url: urlStr,\n scheme: paymentPayload.accepted.scheme,\n network: paymentPayload.accepted.network,\n })\n\n // Build retry headers\n const paymentHeaders = this.httpClient.encodePaymentSignatureHeader(paymentPayload)\n const headers = new Headers(init?.headers)\n for (const [key, value] of Object.entries(paymentHeaders)) {\n headers.set(key, value)\n }\n\n // Retry with payment\n const retryResponse = await fetch(url, { ...init, headers })\n\n this._emitOnWdk('payment:submitted', { url: urlStr, statusCode: retryResponse.status })\n\n const success = retryResponse.status !== 402\n const receipt: PaymentReceipt = {\n success,\n network: paymentPayload.accepted.network,\n scheme: paymentPayload.accepted.scheme,\n amount: paymentPayload.accepted.amount,\n payTo: paymentPayload.accepted.payTo,\n }\n\n // Determine chain family for the enriched receipt\n let chainFamily = 'evm'\n try {\n chainFamily = detectChainFamily(paymentPayload.accepted.network)\n } catch {\n // default to 'evm' if detection fails\n }\n\n // Save enriched receipt to the WDK receipt store\n const enrichedReceipt: EnrichedReceipt = {\n id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n timestamp: new Date().toISOString(),\n url: urlStr,\n network: paymentPayload.accepted.network,\n scheme: paymentPayload.accepted.scheme,\n amount: paymentPayload.accepted.amount,\n payTo: paymentPayload.accepted.payTo,\n success,\n chainFamily,\n }\n\n try {\n await this.wdk.getReceiptStore().save(enrichedReceipt)\n } catch {\n // Receipt save failure is non-fatal\n }\n\n if (success) {\n this._emitOnWdk('payment:complete', { url: urlStr, success: true, receipt })\n } else {\n this._emitOnWdk('payment:failed', { url: urlStr, error: 'Payment rejected (still 402)' })\n }\n\n return { response: retryResponse, receipt }\n }\n\n /**\n * Emit an event on the underlying WDK event system.\n * Silently no-ops if the WDK doesn't support events.\n */\n private _emitOnWdk(event: string, data: unknown): void {\n try {\n const wdk = this.wdk as unknown as {\n emit?(event: string, data: unknown): boolean\n }\n wdk.emit?.(event, data)\n } catch {\n // Non-fatal: WDK may not have events support\n }\n }\n\n /**\n * Extract payment requirements from a URL\n *\n * @param url - URL to check for payment requirements\n * @param init - Standard fetch RequestInit options\n * @returns The PaymentRequired object from the 402 response\n * @throws Error if the response is not 402\n */\n async getRequirements(url: string | URL, init?: RequestInit): Promise<PaymentRequired> {\n const response = await fetch(url, init)\n if (response.status !== 402) {\n throw new Error(`Expected 402 response, got ${response.status}`)\n }\n return extractPaymentRequired(response)\n }\n\n /**\n * Sign a payment for specific requirements using the t402 client infrastructure\n *\n * @param paymentRequired - The full PaymentRequired context\n * @returns A properly signed PaymentPayload (e.g., EIP-3009 for EVM)\n */\n async signPayment(paymentRequired: PaymentRequired): Promise<PaymentPayload> {\n return this.httpClient.createPaymentPayload(paymentRequired)\n }\n\n /**\n * Submit a request with a pre-signed payment payload\n *\n * @param url - URL to request\n * @param paymentPayload - The signed payment payload\n * @param init - Standard fetch RequestInit options\n * @returns The HTTP response\n */\n async submitPayment(\n url: string | URL,\n paymentPayload: PaymentPayload,\n init?: RequestInit,\n ): Promise<Response> {\n const paymentHeaders = this.httpClient.encodePaymentSignatureHeader(paymentPayload)\n const headers = new Headers(init?.headers)\n for (const [key, value] of Object.entries(paymentHeaders)) {\n headers.set(key, value)\n }\n\n return fetch(url, { ...init, headers })\n }\n\n /**\n * Get the underlying t402 HTTP client for advanced usage\n */\n getHttpClient(): t402HTTPClient {\n return this.httpClient\n }\n\n /**\n * Get the underlying WDK instance\n */\n getWdk(): T402WDK {\n return this.wdk\n }\n\n /**\n * Get the facilitator URL\n */\n getFacilitator(): string {\n return this.facilitator\n }\n\n /**\n * Get the configured chains\n */\n getChains(): string[] {\n return [...this.chains]\n }\n\n /**\n * Get the set of registered chain families (e.g., 'evm', 'ton', 'solana')\n */\n getRegisteredFamilies(): Set<string> {\n return new Set(this._registeredFamilies)\n }\n\n /**\n * Check if this protocol instance can handle a given CAIP-2 network.\n *\n * @param network - CAIP-2 network identifier (e.g., \"eip155:42161\", \"ton:mainnet\")\n * @returns True if the required chain family is registered\n */\n canHandleNetwork(network: string): boolean {\n try {\n const family = detectChainFamily(network)\n return this._registeredFamilies.has(family)\n } catch {\n return false\n }\n }\n}\n","/**\n * HTTP client utilities for 402 payment handling\n */\n\nimport { decodePaymentRequiredHeader } from '@t402/core/http'\nimport type { PaymentRequired } from '@t402/core/types'\n\n/** V2 header names */\nconst HEADER_PAYMENT_REQUIRED = 'payment-required'\n\n/** V1 header names (fallback) */\nconst HEADER_X_PAYMENT = 'x-payment'\n\n/**\n * Extract PaymentRequired from a 402 response.\n * Tries V2 header first, then falls back to V1.\n *\n * @param response - The HTTP response with status 402\n * @returns The parsed PaymentRequired object\n * @throws Error if no valid payment header is found\n */\nexport function extractPaymentRequired(response: Response): PaymentRequired {\n // Try V2 header\n const v2Header = response.headers.get(HEADER_PAYMENT_REQUIRED)\n if (v2Header) {\n return decodePaymentRequiredHeader(v2Header)\n }\n\n // Try V1 header\n const v1Header = response.headers.get(HEADER_X_PAYMENT)\n if (v1Header) {\n return decodePaymentRequiredHeader(v1Header)\n }\n\n throw new Error(\n 'No payment requirements found in 402 response. ' +\n `Expected \"${HEADER_PAYMENT_REQUIRED}\" or \"${HEADER_X_PAYMENT}\" header.`,\n )\n}\n","/**\n * Chain detection utilities for CAIP-2 network identifiers\n */\n\n/**\n * CAIP-2 namespace prefixes\n */\nconst CAIP2_EVM = 'eip155:'\nconst CAIP2_TON = 'ton:'\nconst CAIP2_SOLANA = 'solana:'\nconst CAIP2_TRON = 'tron:'\nconst CAIP2_NEAR = 'near:'\nconst CAIP2_APTOS = 'aptos:'\nconst CAIP2_TEZOS = 'tezos:'\nconst CAIP2_POLKADOT = 'polkadot:'\nconst CAIP2_STACKS = 'stacks:'\nconst CAIP2_COSMOS = 'cosmos:'\n\n/**\n * Chain family detected from CAIP-2 network identifier\n */\nexport type ChainFamily =\n | 'evm'\n | 'ton'\n | 'solana'\n | 'tron'\n | 'near'\n | 'aptos'\n | 'tezos'\n | 'polkadot'\n | 'stacks'\n | 'cosmos'\n\n/**\n * Detect chain family from a CAIP-2 network identifier\n *\n * @param network - CAIP-2 network identifier (e.g., \"eip155:1\", \"ton:mainnet\")\n * @returns The chain family\n * @throws Error if network prefix is not recognized\n */\nexport function detectChainFamily(network: string): ChainFamily {\n if (network.startsWith(CAIP2_EVM)) return 'evm'\n if (network.startsWith(CAIP2_TON)) return 'ton'\n if (network.startsWith(CAIP2_SOLANA)) return 'solana'\n if (network.startsWith(CAIP2_TRON)) return 'tron'\n if (network.startsWith(CAIP2_NEAR)) return 'near'\n if (network.startsWith(CAIP2_APTOS)) return 'aptos'\n if (network.startsWith(CAIP2_TEZOS)) return 'tezos'\n if (network.startsWith(CAIP2_POLKADOT)) return 'polkadot'\n if (network.startsWith(CAIP2_STACKS)) return 'stacks'\n if (network.startsWith(CAIP2_COSMOS)) return 'cosmos'\n\n throw new Error(`Unsupported network: ${network}. Cannot detect chain family from CAIP-2 prefix.`)\n}\n\n/**\n * Map of EVM chain names to CAIP-2 identifiers\n */\nexport const EVM_CHAIN_MAP: Record<string, string> = {\n ethereum: 'eip155:1',\n base: 'eip155:8453',\n arbitrum: 'eip155:42161',\n optimism: 'eip155:10',\n polygon: 'eip155:137',\n avalanche: 'eip155:43114',\n ink: 'eip155:57073',\n berachain: 'eip155:80094',\n unichain: 'eip155:130',\n}\n\n/**\n * Get EVM chain name from CAIP-2 network identifier\n *\n * @param network - CAIP-2 network (e.g., \"eip155:42161\")\n * @returns Chain name (e.g., \"arbitrum\") or undefined\n */\nexport function getEvmChainName(network: string): string | undefined {\n for (const [name, caip2] of Object.entries(EVM_CHAIN_MAP)) {\n if (caip2 === network) return name\n }\n return undefined\n}\n\n/**\n * Check if a network is an EVM chain\n *\n * @param network - CAIP-2 network identifier\n * @returns True if the network is an EVM chain\n */\nexport function isEvmNetwork(network: string): boolean {\n return network.startsWith(CAIP2_EVM)\n}\n\n/**\n * Map of human-readable chain names to their chain family\n */\nconst CHAIN_NAME_TO_FAMILY: Record<string, ChainFamily> = {\n // EVM chains\n ethereum: 'evm',\n arbitrum: 'evm',\n base: 'evm',\n polygon: 'evm',\n optimism: 'evm',\n avalanche: 'evm',\n ink: 'evm',\n berachain: 'evm',\n unichain: 'evm',\n // Non-EVM chains\n ton: 'ton',\n solana: 'solana',\n tron: 'tron',\n near: 'near',\n aptos: 'aptos',\n tezos: 'tezos',\n polkadot: 'polkadot',\n stacks: 'stacks',\n cosmos: 'cosmos',\n}\n\n/**\n * Detect chain family from a human-readable chain name.\n *\n * @param chainName - Chain name (e.g., \"ethereum\", \"ton\", \"solana\")\n * @returns The chain family, or undefined if not recognized\n */\nexport function detectChainFamilyFromName(chainName: string): ChainFamily | undefined {\n return CHAIN_NAME_TO_FAMILY[chainName.toLowerCase()]\n}\n"],"mappings":"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","names":["import_http","import_client"]}
|
package/dist/esm/index.d.mts
CHANGED
|
@@ -69,17 +69,21 @@ interface T402FetchResult {
|
|
|
69
69
|
*
|
|
70
70
|
* Uses the real t402 protocol client infrastructure with EVM mechanism support.
|
|
71
71
|
* Payment payloads are properly signed using EIP-3009 authorization.
|
|
72
|
+
* Supports multi-chain registration for EVM and non-EVM chain families.
|
|
72
73
|
*/
|
|
73
74
|
declare class T402Protocol {
|
|
74
75
|
private httpClient;
|
|
75
76
|
private wdk;
|
|
76
77
|
private facilitator;
|
|
77
78
|
private chains;
|
|
79
|
+
private _registeredFamilies;
|
|
78
80
|
private constructor();
|
|
79
81
|
/**
|
|
80
82
|
* Create a new T402Protocol instance.
|
|
81
83
|
*
|
|
82
84
|
* This is async because it needs to initialize the WDK signer.
|
|
85
|
+
* Registers the primary EVM signer plus detects additional chain families
|
|
86
|
+
* from the configured chains list.
|
|
83
87
|
*
|
|
84
88
|
* @param wdk - An initialized T402WDK instance
|
|
85
89
|
* @param config - Protocol configuration
|
|
@@ -99,6 +103,11 @@ declare class T402Protocol {
|
|
|
99
103
|
* @returns The final response and optional payment receipt
|
|
100
104
|
*/
|
|
101
105
|
fetch(url: string | URL, init?: RequestInit): Promise<T402FetchResult>;
|
|
106
|
+
/**
|
|
107
|
+
* Emit an event on the underlying WDK event system.
|
|
108
|
+
* Silently no-ops if the WDK doesn't support events.
|
|
109
|
+
*/
|
|
110
|
+
private _emitOnWdk;
|
|
102
111
|
/**
|
|
103
112
|
* Extract payment requirements from a URL
|
|
104
113
|
*
|
|
@@ -140,6 +149,17 @@ declare class T402Protocol {
|
|
|
140
149
|
* Get the configured chains
|
|
141
150
|
*/
|
|
142
151
|
getChains(): string[];
|
|
152
|
+
/**
|
|
153
|
+
* Get the set of registered chain families (e.g., 'evm', 'ton', 'solana')
|
|
154
|
+
*/
|
|
155
|
+
getRegisteredFamilies(): Set<string>;
|
|
156
|
+
/**
|
|
157
|
+
* Check if this protocol instance can handle a given CAIP-2 network.
|
|
158
|
+
*
|
|
159
|
+
* @param network - CAIP-2 network identifier (e.g., "eip155:42161", "ton:mainnet")
|
|
160
|
+
* @returns True if the required chain family is registered
|
|
161
|
+
*/
|
|
162
|
+
canHandleNetwork(network: string): boolean;
|
|
143
163
|
}
|
|
144
164
|
|
|
145
165
|
/**
|
|
@@ -175,6 +195,13 @@ declare function getEvmChainName(network: string): string | undefined;
|
|
|
175
195
|
* @returns True if the network is an EVM chain
|
|
176
196
|
*/
|
|
177
197
|
declare function isEvmNetwork(network: string): boolean;
|
|
198
|
+
/**
|
|
199
|
+
* Detect chain family from a human-readable chain name.
|
|
200
|
+
*
|
|
201
|
+
* @param chainName - Chain name (e.g., "ethereum", "ton", "solana")
|
|
202
|
+
* @returns The chain family, or undefined if not recognized
|
|
203
|
+
*/
|
|
204
|
+
declare function detectChainFamilyFromName(chainName: string): ChainFamily | undefined;
|
|
178
205
|
|
|
179
206
|
/**
|
|
180
207
|
* HTTP client utilities for 402 payment handling
|
|
@@ -190,4 +217,4 @@ declare function isEvmNetwork(network: string): boolean;
|
|
|
190
217
|
*/
|
|
191
218
|
declare function extractPaymentRequired(response: Response): PaymentRequired;
|
|
192
219
|
|
|
193
|
-
export { type ChainFamily, EVM_CHAIN_MAP, type PaymentReceipt, type T402FetchResult, T402Protocol, type T402ProtocolConfig, detectChainFamily, extractPaymentRequired, getEvmChainName, isEvmNetwork };
|
|
220
|
+
export { type ChainFamily, EVM_CHAIN_MAP, type PaymentReceipt, type T402FetchResult, T402Protocol, type T402ProtocolConfig, detectChainFamily, detectChainFamilyFromName, extractPaymentRequired, getEvmChainName, isEvmNetwork };
|
package/dist/esm/index.mjs
CHANGED
|
@@ -25,6 +25,76 @@ function extractPaymentRequired(response) {
|
|
|
25
25
|
);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
// src/signer-factory.ts
|
|
29
|
+
var CAIP2_EVM = "eip155:";
|
|
30
|
+
var CAIP2_TON = "ton:";
|
|
31
|
+
var CAIP2_SOLANA = "solana:";
|
|
32
|
+
var CAIP2_TRON = "tron:";
|
|
33
|
+
var CAIP2_NEAR = "near:";
|
|
34
|
+
var CAIP2_APTOS = "aptos:";
|
|
35
|
+
var CAIP2_TEZOS = "tezos:";
|
|
36
|
+
var CAIP2_POLKADOT = "polkadot:";
|
|
37
|
+
var CAIP2_STACKS = "stacks:";
|
|
38
|
+
var CAIP2_COSMOS = "cosmos:";
|
|
39
|
+
function detectChainFamily(network) {
|
|
40
|
+
if (network.startsWith(CAIP2_EVM)) return "evm";
|
|
41
|
+
if (network.startsWith(CAIP2_TON)) return "ton";
|
|
42
|
+
if (network.startsWith(CAIP2_SOLANA)) return "solana";
|
|
43
|
+
if (network.startsWith(CAIP2_TRON)) return "tron";
|
|
44
|
+
if (network.startsWith(CAIP2_NEAR)) return "near";
|
|
45
|
+
if (network.startsWith(CAIP2_APTOS)) return "aptos";
|
|
46
|
+
if (network.startsWith(CAIP2_TEZOS)) return "tezos";
|
|
47
|
+
if (network.startsWith(CAIP2_POLKADOT)) return "polkadot";
|
|
48
|
+
if (network.startsWith(CAIP2_STACKS)) return "stacks";
|
|
49
|
+
if (network.startsWith(CAIP2_COSMOS)) return "cosmos";
|
|
50
|
+
throw new Error(`Unsupported network: ${network}. Cannot detect chain family from CAIP-2 prefix.`);
|
|
51
|
+
}
|
|
52
|
+
var EVM_CHAIN_MAP = {
|
|
53
|
+
ethereum: "eip155:1",
|
|
54
|
+
base: "eip155:8453",
|
|
55
|
+
arbitrum: "eip155:42161",
|
|
56
|
+
optimism: "eip155:10",
|
|
57
|
+
polygon: "eip155:137",
|
|
58
|
+
avalanche: "eip155:43114",
|
|
59
|
+
ink: "eip155:57073",
|
|
60
|
+
berachain: "eip155:80094",
|
|
61
|
+
unichain: "eip155:130"
|
|
62
|
+
};
|
|
63
|
+
function getEvmChainName(network) {
|
|
64
|
+
for (const [name, caip2] of Object.entries(EVM_CHAIN_MAP)) {
|
|
65
|
+
if (caip2 === network) return name;
|
|
66
|
+
}
|
|
67
|
+
return void 0;
|
|
68
|
+
}
|
|
69
|
+
function isEvmNetwork(network) {
|
|
70
|
+
return network.startsWith(CAIP2_EVM);
|
|
71
|
+
}
|
|
72
|
+
var CHAIN_NAME_TO_FAMILY = {
|
|
73
|
+
// EVM chains
|
|
74
|
+
ethereum: "evm",
|
|
75
|
+
arbitrum: "evm",
|
|
76
|
+
base: "evm",
|
|
77
|
+
polygon: "evm",
|
|
78
|
+
optimism: "evm",
|
|
79
|
+
avalanche: "evm",
|
|
80
|
+
ink: "evm",
|
|
81
|
+
berachain: "evm",
|
|
82
|
+
unichain: "evm",
|
|
83
|
+
// Non-EVM chains
|
|
84
|
+
ton: "ton",
|
|
85
|
+
solana: "solana",
|
|
86
|
+
tron: "tron",
|
|
87
|
+
near: "near",
|
|
88
|
+
aptos: "aptos",
|
|
89
|
+
tezos: "tezos",
|
|
90
|
+
polkadot: "polkadot",
|
|
91
|
+
stacks: "stacks",
|
|
92
|
+
cosmos: "cosmos"
|
|
93
|
+
};
|
|
94
|
+
function detectChainFamilyFromName(chainName) {
|
|
95
|
+
return CHAIN_NAME_TO_FAMILY[chainName.toLowerCase()];
|
|
96
|
+
}
|
|
97
|
+
|
|
28
98
|
// src/protocol.ts
|
|
29
99
|
var DEFAULT_FACILITATOR = "https://facilitator.t402.io";
|
|
30
100
|
var T402Protocol = class _T402Protocol {
|
|
@@ -33,6 +103,7 @@ var T402Protocol = class _T402Protocol {
|
|
|
33
103
|
__publicField(this, "wdk");
|
|
34
104
|
__publicField(this, "facilitator");
|
|
35
105
|
__publicField(this, "chains");
|
|
106
|
+
__publicField(this, "_registeredFamilies", /* @__PURE__ */ new Set());
|
|
36
107
|
this.wdk = wdk;
|
|
37
108
|
this.httpClient = httpClient;
|
|
38
109
|
this.facilitator = config.facilitator ?? DEFAULT_FACILITATOR;
|
|
@@ -42,18 +113,35 @@ var T402Protocol = class _T402Protocol {
|
|
|
42
113
|
* Create a new T402Protocol instance.
|
|
43
114
|
*
|
|
44
115
|
* This is async because it needs to initialize the WDK signer.
|
|
116
|
+
* Registers the primary EVM signer plus detects additional chain families
|
|
117
|
+
* from the configured chains list.
|
|
45
118
|
*
|
|
46
119
|
* @param wdk - An initialized T402WDK instance
|
|
47
120
|
* @param config - Protocol configuration
|
|
48
121
|
* @returns A configured T402Protocol instance
|
|
49
122
|
*/
|
|
50
123
|
static async create(wdk, config = {}) {
|
|
51
|
-
const chainName = config.chains?.[0] ?? "ethereum";
|
|
52
|
-
const signer = await wdk.getSigner(chainName);
|
|
53
124
|
const client = new t402Client();
|
|
54
|
-
|
|
125
|
+
const registeredFamilies = /* @__PURE__ */ new Set();
|
|
126
|
+
const chainName = config.chains?.[0] ?? "ethereum";
|
|
127
|
+
try {
|
|
128
|
+
const signer = await wdk.getSigner(chainName);
|
|
129
|
+
registerExactEvmScheme(client, { signer });
|
|
130
|
+
registeredFamilies.add("evm");
|
|
131
|
+
} catch {
|
|
132
|
+
}
|
|
133
|
+
if (config.chains) {
|
|
134
|
+
for (const chain of config.chains) {
|
|
135
|
+
const family = detectChainFamilyFromName(chain);
|
|
136
|
+
if (family) {
|
|
137
|
+
registeredFamilies.add(family);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
55
141
|
const httpClient = new t402HTTPClient(client);
|
|
56
|
-
|
|
142
|
+
const protocol = new _T402Protocol(wdk, httpClient, config);
|
|
143
|
+
protocol._registeredFamilies = registeredFamilies;
|
|
144
|
+
return protocol;
|
|
57
145
|
}
|
|
58
146
|
/**
|
|
59
147
|
* Fetch a URL with automatic 402 payment handling.
|
|
@@ -68,6 +156,7 @@ var T402Protocol = class _T402Protocol {
|
|
|
68
156
|
* @returns The final response and optional payment receipt
|
|
69
157
|
*/
|
|
70
158
|
async fetch(url, init) {
|
|
159
|
+
const urlStr = url.toString();
|
|
71
160
|
const response = await fetch(url, init);
|
|
72
161
|
if (response.status !== 402) {
|
|
73
162
|
return { response };
|
|
@@ -75,22 +164,75 @@ var T402Protocol = class _T402Protocol {
|
|
|
75
164
|
const paymentRequired = this.httpClient.getPaymentRequiredResponse(
|
|
76
165
|
(name) => response.headers.get(name)
|
|
77
166
|
);
|
|
78
|
-
const
|
|
167
|
+
const network = paymentRequired.accepts?.[0]?.network ?? "";
|
|
168
|
+
const amount = paymentRequired.accepts?.[0]?.amount ?? "";
|
|
169
|
+
this._emitOnWdk("payment:start", { url: urlStr, network, amount });
|
|
170
|
+
let paymentPayload;
|
|
171
|
+
try {
|
|
172
|
+
paymentPayload = await this.httpClient.createPaymentPayload(paymentRequired);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
175
|
+
this._emitOnWdk("payment:failed", { url: urlStr, error: errMsg });
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
178
|
+
this._emitOnWdk("payment:signed", {
|
|
179
|
+
url: urlStr,
|
|
180
|
+
scheme: paymentPayload.accepted.scheme,
|
|
181
|
+
network: paymentPayload.accepted.network
|
|
182
|
+
});
|
|
79
183
|
const paymentHeaders = this.httpClient.encodePaymentSignatureHeader(paymentPayload);
|
|
80
184
|
const headers = new Headers(init?.headers);
|
|
81
185
|
for (const [key, value] of Object.entries(paymentHeaders)) {
|
|
82
186
|
headers.set(key, value);
|
|
83
187
|
}
|
|
84
188
|
const retryResponse = await fetch(url, { ...init, headers });
|
|
189
|
+
this._emitOnWdk("payment:submitted", { url: urlStr, statusCode: retryResponse.status });
|
|
190
|
+
const success = retryResponse.status !== 402;
|
|
85
191
|
const receipt = {
|
|
86
|
-
success
|
|
192
|
+
success,
|
|
87
193
|
network: paymentPayload.accepted.network,
|
|
88
194
|
scheme: paymentPayload.accepted.scheme,
|
|
89
195
|
amount: paymentPayload.accepted.amount,
|
|
90
196
|
payTo: paymentPayload.accepted.payTo
|
|
91
197
|
};
|
|
198
|
+
let chainFamily = "evm";
|
|
199
|
+
try {
|
|
200
|
+
chainFamily = detectChainFamily(paymentPayload.accepted.network);
|
|
201
|
+
} catch {
|
|
202
|
+
}
|
|
203
|
+
const enrichedReceipt = {
|
|
204
|
+
id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
205
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
206
|
+
url: urlStr,
|
|
207
|
+
network: paymentPayload.accepted.network,
|
|
208
|
+
scheme: paymentPayload.accepted.scheme,
|
|
209
|
+
amount: paymentPayload.accepted.amount,
|
|
210
|
+
payTo: paymentPayload.accepted.payTo,
|
|
211
|
+
success,
|
|
212
|
+
chainFamily
|
|
213
|
+
};
|
|
214
|
+
try {
|
|
215
|
+
await this.wdk.getReceiptStore().save(enrichedReceipt);
|
|
216
|
+
} catch {
|
|
217
|
+
}
|
|
218
|
+
if (success) {
|
|
219
|
+
this._emitOnWdk("payment:complete", { url: urlStr, success: true, receipt });
|
|
220
|
+
} else {
|
|
221
|
+
this._emitOnWdk("payment:failed", { url: urlStr, error: "Payment rejected (still 402)" });
|
|
222
|
+
}
|
|
92
223
|
return { response: retryResponse, receipt };
|
|
93
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* Emit an event on the underlying WDK event system.
|
|
227
|
+
* Silently no-ops if the WDK doesn't support events.
|
|
228
|
+
*/
|
|
229
|
+
_emitOnWdk(event, data) {
|
|
230
|
+
try {
|
|
231
|
+
const wdk = this.wdk;
|
|
232
|
+
wdk.emit?.(event, data);
|
|
233
|
+
} catch {
|
|
234
|
+
}
|
|
235
|
+
}
|
|
94
236
|
/**
|
|
95
237
|
* Extract payment requirements from a URL
|
|
96
238
|
*
|
|
@@ -155,58 +297,32 @@ var T402Protocol = class _T402Protocol {
|
|
|
155
297
|
getChains() {
|
|
156
298
|
return [...this.chains];
|
|
157
299
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
var CAIP2_SOLANA = "solana:";
|
|
164
|
-
var CAIP2_TRON = "tron:";
|
|
165
|
-
var CAIP2_NEAR = "near:";
|
|
166
|
-
var CAIP2_APTOS = "aptos:";
|
|
167
|
-
var CAIP2_TEZOS = "tezos:";
|
|
168
|
-
var CAIP2_POLKADOT = "polkadot:";
|
|
169
|
-
var CAIP2_STACKS = "stacks:";
|
|
170
|
-
var CAIP2_COSMOS = "cosmos:";
|
|
171
|
-
function detectChainFamily(network) {
|
|
172
|
-
if (network.startsWith(CAIP2_EVM)) return "evm";
|
|
173
|
-
if (network.startsWith(CAIP2_TON)) return "ton";
|
|
174
|
-
if (network.startsWith(CAIP2_SOLANA)) return "solana";
|
|
175
|
-
if (network.startsWith(CAIP2_TRON)) return "tron";
|
|
176
|
-
if (network.startsWith(CAIP2_NEAR)) return "near";
|
|
177
|
-
if (network.startsWith(CAIP2_APTOS)) return "aptos";
|
|
178
|
-
if (network.startsWith(CAIP2_TEZOS)) return "tezos";
|
|
179
|
-
if (network.startsWith(CAIP2_POLKADOT)) return "polkadot";
|
|
180
|
-
if (network.startsWith(CAIP2_STACKS)) return "stacks";
|
|
181
|
-
if (network.startsWith(CAIP2_COSMOS)) return "cosmos";
|
|
182
|
-
throw new Error(
|
|
183
|
-
`Unsupported network: ${network}. Cannot detect chain family from CAIP-2 prefix.`
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
var EVM_CHAIN_MAP = {
|
|
187
|
-
ethereum: "eip155:1",
|
|
188
|
-
base: "eip155:8453",
|
|
189
|
-
arbitrum: "eip155:42161",
|
|
190
|
-
optimism: "eip155:10",
|
|
191
|
-
polygon: "eip155:137",
|
|
192
|
-
avalanche: "eip155:43114",
|
|
193
|
-
ink: "eip155:57073",
|
|
194
|
-
berachain: "eip155:80094",
|
|
195
|
-
unichain: "eip155:130"
|
|
196
|
-
};
|
|
197
|
-
function getEvmChainName(network) {
|
|
198
|
-
for (const [name, caip2] of Object.entries(EVM_CHAIN_MAP)) {
|
|
199
|
-
if (caip2 === network) return name;
|
|
300
|
+
/**
|
|
301
|
+
* Get the set of registered chain families (e.g., 'evm', 'ton', 'solana')
|
|
302
|
+
*/
|
|
303
|
+
getRegisteredFamilies() {
|
|
304
|
+
return new Set(this._registeredFamilies);
|
|
200
305
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
306
|
+
/**
|
|
307
|
+
* Check if this protocol instance can handle a given CAIP-2 network.
|
|
308
|
+
*
|
|
309
|
+
* @param network - CAIP-2 network identifier (e.g., "eip155:42161", "ton:mainnet")
|
|
310
|
+
* @returns True if the required chain family is registered
|
|
311
|
+
*/
|
|
312
|
+
canHandleNetwork(network) {
|
|
313
|
+
try {
|
|
314
|
+
const family = detectChainFamily(network);
|
|
315
|
+
return this._registeredFamilies.has(family);
|
|
316
|
+
} catch {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
};
|
|
206
321
|
export {
|
|
207
322
|
EVM_CHAIN_MAP,
|
|
208
323
|
T402Protocol,
|
|
209
324
|
detectChainFamily,
|
|
325
|
+
detectChainFamilyFromName,
|
|
210
326
|
extractPaymentRequired,
|
|
211
327
|
getEvmChainName,
|
|
212
328
|
isEvmNetwork
|
package/dist/esm/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/protocol.ts","../../src/http-client.ts","../../src/signer-factory.ts"],"sourcesContent":["/**\n * T402Protocol - Main class for WDK apps to add T402 payment capability\n *\n * Uses the real t402 client infrastructure (t402Client + mechanism-specific\n * scheme clients) for proper payment payload creation and signing.\n *\n * @example\n * ```typescript\n * import { T402Protocol } from '@t402/wdk-protocol';\n * import { T402WDK } from '@t402/wdk';\n *\n * const wdk = new T402WDK(seedPhrase, { arbitrum: rpcUrl });\n * const t402 = await T402Protocol.create(wdk, {\n * chains: ['ethereum', 'arbitrum'],\n * });\n *\n * // Auto-pay for HTTP 402 resources\n * const { response, receipt } = await t402.fetch('https://api.example.com/premium');\n * ```\n */\n\nimport { t402Client } from '@t402/core/client'\nimport { t402HTTPClient } from '@t402/core/http'\nimport type { PaymentRequired, PaymentPayload } from '@t402/core/types'\nimport { registerExactEvmScheme } from '@t402/evm/exact/client'\nimport type { T402WDK } from '@t402/wdk'\n\nimport { extractPaymentRequired } from './http-client.js'\nimport type { T402ProtocolConfig, T402FetchResult, PaymentReceipt } from './types.js'\n\nconst DEFAULT_FACILITATOR = 'https://facilitator.t402.io'\n\n/**\n * T402Protocol enables any WDK wallet app to handle HTTP 402 payments.\n *\n * Uses the real t402 protocol client infrastructure with EVM mechanism support.\n * Payment payloads are properly signed using EIP-3009 authorization.\n */\nexport class T402Protocol {\n private httpClient: t402HTTPClient\n private wdk: T402WDK\n private facilitator: string\n private chains: string[]\n\n private constructor(\n wdk: T402WDK,\n httpClient: t402HTTPClient,\n config: T402ProtocolConfig,\n ) {\n this.wdk = wdk\n this.httpClient = httpClient\n this.facilitator = config.facilitator ?? DEFAULT_FACILITATOR\n this.chains = config.chains ?? []\n }\n\n /**\n * Create a new T402Protocol instance.\n *\n * This is async because it needs to initialize the WDK signer.\n *\n * @param wdk - An initialized T402WDK instance\n * @param config - Protocol configuration\n * @returns A configured T402Protocol instance\n */\n static async create(wdk: T402WDK, config: T402ProtocolConfig = {}): Promise<T402Protocol> {\n // Get an EVM signer from WDK for the first available chain\n const chainName = config.chains?.[0] ?? 'ethereum'\n const signer = await wdk.getSigner(chainName)\n\n // Create t402 client with EVM exact scheme\n const client = new t402Client()\n registerExactEvmScheme(client, { signer })\n\n const httpClient = new t402HTTPClient(client)\n\n return new T402Protocol(wdk, httpClient, config)\n }\n\n /**\n * Fetch a URL with automatic 402 payment handling.\n *\n * 1. Makes the initial request\n * 2. If 402, extracts payment requirements\n * 3. Creates a properly signed payment payload (EIP-3009 for EVM)\n * 4. Retries the request with the signed payment header\n *\n * @param url - URL to fetch\n * @param init - Standard fetch RequestInit options\n * @returns The final response and optional payment receipt\n */\n async fetch(url: string | URL, init?: RequestInit): Promise<T402FetchResult> {\n // Make initial request\n const response = await fetch(url, init)\n\n // If not 402, return as-is\n if (response.status !== 402) {\n return { response }\n }\n\n // Extract payment requirements from 402 response\n const paymentRequired = this.httpClient.getPaymentRequiredResponse(\n (name: string) => response.headers.get(name),\n )\n\n // Create signed payment payload using mechanism-specific logic\n const paymentPayload = await this.httpClient.createPaymentPayload(paymentRequired)\n\n // Build retry headers\n const paymentHeaders = this.httpClient.encodePaymentSignatureHeader(paymentPayload)\n const headers = new Headers(init?.headers)\n for (const [key, value] of Object.entries(paymentHeaders)) {\n headers.set(key, value)\n }\n\n // Retry with payment\n const retryResponse = await fetch(url, { ...init, headers })\n\n const receipt: PaymentReceipt = {\n success: retryResponse.status !== 402,\n network: paymentPayload.accepted.network,\n scheme: paymentPayload.accepted.scheme,\n amount: paymentPayload.accepted.amount,\n payTo: paymentPayload.accepted.payTo,\n }\n\n return { response: retryResponse, receipt }\n }\n\n /**\n * Extract payment requirements from a URL\n *\n * @param url - URL to check for payment requirements\n * @param init - Standard fetch RequestInit options\n * @returns The PaymentRequired object from the 402 response\n * @throws Error if the response is not 402\n */\n async getRequirements(url: string | URL, init?: RequestInit): Promise<PaymentRequired> {\n const response = await fetch(url, init)\n if (response.status !== 402) {\n throw new Error(`Expected 402 response, got ${response.status}`)\n }\n return extractPaymentRequired(response)\n }\n\n /**\n * Sign a payment for specific requirements using the t402 client infrastructure\n *\n * @param paymentRequired - The full PaymentRequired context\n * @returns A properly signed PaymentPayload (e.g., EIP-3009 for EVM)\n */\n async signPayment(paymentRequired: PaymentRequired): Promise<PaymentPayload> {\n return this.httpClient.createPaymentPayload(paymentRequired)\n }\n\n /**\n * Submit a request with a pre-signed payment payload\n *\n * @param url - URL to request\n * @param paymentPayload - The signed payment payload\n * @param init - Standard fetch RequestInit options\n * @returns The HTTP response\n */\n async submitPayment(\n url: string | URL,\n paymentPayload: PaymentPayload,\n init?: RequestInit,\n ): Promise<Response> {\n const paymentHeaders = this.httpClient.encodePaymentSignatureHeader(paymentPayload)\n const headers = new Headers(init?.headers)\n for (const [key, value] of Object.entries(paymentHeaders)) {\n headers.set(key, value)\n }\n\n return fetch(url, { ...init, headers })\n }\n\n /**\n * Get the underlying t402 HTTP client for advanced usage\n */\n getHttpClient(): t402HTTPClient {\n return this.httpClient\n }\n\n /**\n * Get the underlying WDK instance\n */\n getWdk(): T402WDK {\n return this.wdk\n }\n\n /**\n * Get the facilitator URL\n */\n getFacilitator(): string {\n return this.facilitator\n }\n\n /**\n * Get the configured chains\n */\n getChains(): string[] {\n return [...this.chains]\n }\n}\n","/**\n * HTTP client utilities for 402 payment handling\n */\n\nimport { decodePaymentRequiredHeader } from '@t402/core/http'\nimport type { PaymentRequired } from '@t402/core/types'\n\n/** V2 header names */\nconst HEADER_PAYMENT_REQUIRED = 'payment-required'\n\n/** V1 header names (fallback) */\nconst HEADER_X_PAYMENT = 'x-payment'\n\n/**\n * Extract PaymentRequired from a 402 response.\n * Tries V2 header first, then falls back to V1.\n *\n * @param response - The HTTP response with status 402\n * @returns The parsed PaymentRequired object\n * @throws Error if no valid payment header is found\n */\nexport function extractPaymentRequired(response: Response): PaymentRequired {\n // Try V2 header\n const v2Header = response.headers.get(HEADER_PAYMENT_REQUIRED)\n if (v2Header) {\n return decodePaymentRequiredHeader(v2Header)\n }\n\n // Try V1 header\n const v1Header = response.headers.get(HEADER_X_PAYMENT)\n if (v1Header) {\n return decodePaymentRequiredHeader(v1Header)\n }\n\n throw new Error(\n 'No payment requirements found in 402 response. ' +\n `Expected \"${HEADER_PAYMENT_REQUIRED}\" or \"${HEADER_X_PAYMENT}\" header.`,\n )\n}\n","/**\n * Chain detection utilities for CAIP-2 network identifiers\n */\n\n/**\n * CAIP-2 namespace prefixes\n */\nconst CAIP2_EVM = 'eip155:'\nconst CAIP2_TON = 'ton:'\nconst CAIP2_SOLANA = 'solana:'\nconst CAIP2_TRON = 'tron:'\nconst CAIP2_NEAR = 'near:'\nconst CAIP2_APTOS = 'aptos:'\nconst CAIP2_TEZOS = 'tezos:'\nconst CAIP2_POLKADOT = 'polkadot:'\nconst CAIP2_STACKS = 'stacks:'\nconst CAIP2_COSMOS = 'cosmos:'\n\n/**\n * Chain family detected from CAIP-2 network identifier\n */\nexport type ChainFamily =\n | 'evm'\n | 'ton'\n | 'solana'\n | 'tron'\n | 'near'\n | 'aptos'\n | 'tezos'\n | 'polkadot'\n | 'stacks'\n | 'cosmos'\n\n/**\n * Detect chain family from a CAIP-2 network identifier\n *\n * @param network - CAIP-2 network identifier (e.g., \"eip155:1\", \"ton:mainnet\")\n * @returns The chain family\n * @throws Error if network prefix is not recognized\n */\nexport function detectChainFamily(network: string): ChainFamily {\n if (network.startsWith(CAIP2_EVM)) return 'evm'\n if (network.startsWith(CAIP2_TON)) return 'ton'\n if (network.startsWith(CAIP2_SOLANA)) return 'solana'\n if (network.startsWith(CAIP2_TRON)) return 'tron'\n if (network.startsWith(CAIP2_NEAR)) return 'near'\n if (network.startsWith(CAIP2_APTOS)) return 'aptos'\n if (network.startsWith(CAIP2_TEZOS)) return 'tezos'\n if (network.startsWith(CAIP2_POLKADOT)) return 'polkadot'\n if (network.startsWith(CAIP2_STACKS)) return 'stacks'\n if (network.startsWith(CAIP2_COSMOS)) return 'cosmos'\n\n throw new Error(\n `Unsupported network: ${network}. Cannot detect chain family from CAIP-2 prefix.`,\n )\n}\n\n/**\n * Map of EVM chain names to CAIP-2 identifiers\n */\nexport const EVM_CHAIN_MAP: Record<string, string> = {\n ethereum: 'eip155:1',\n base: 'eip155:8453',\n arbitrum: 'eip155:42161',\n optimism: 'eip155:10',\n polygon: 'eip155:137',\n avalanche: 'eip155:43114',\n ink: 'eip155:57073',\n berachain: 'eip155:80094',\n unichain: 'eip155:130',\n}\n\n/**\n * Get EVM chain name from CAIP-2 network identifier\n *\n * @param network - CAIP-2 network (e.g., \"eip155:42161\")\n * @returns Chain name (e.g., \"arbitrum\") or undefined\n */\nexport function getEvmChainName(network: string): string | undefined {\n for (const [name, caip2] of Object.entries(EVM_CHAIN_MAP)) {\n if (caip2 === network) return name\n }\n return undefined\n}\n\n/**\n * Check if a network is an EVM chain\n *\n * @param network - CAIP-2 network identifier\n * @returns True if the network is an EVM chain\n */\nexport function isEvmNetwork(network: string): boolean {\n return network.startsWith(CAIP2_EVM)\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/protocol.ts","../../src/http-client.ts","../../src/signer-factory.ts"],"sourcesContent":["/**\n * T402Protocol - Main class for WDK apps to add T402 payment capability\n *\n * Uses the real t402 client infrastructure (t402Client + mechanism-specific\n * scheme clients) for proper payment payload creation and signing.\n *\n * @example\n * ```typescript\n * import { T402Protocol } from '@t402/wdk-protocol';\n * import { T402WDK } from '@t402/wdk';\n *\n * const wdk = new T402WDK(seedPhrase, { arbitrum: rpcUrl });\n * const t402 = await T402Protocol.create(wdk, {\n * chains: ['ethereum', 'arbitrum'],\n * });\n *\n * // Auto-pay for HTTP 402 resources\n * const { response, receipt } = await t402.fetch('https://api.example.com/premium');\n * ```\n */\n\nimport { t402Client } from '@t402/core/client'\nimport { t402HTTPClient } from '@t402/core/http'\nimport type { PaymentRequired, PaymentPayload } from '@t402/core/types'\nimport { registerExactEvmScheme } from '@t402/evm/exact/client'\nimport type { T402WDK } from '@t402/wdk'\nimport type { EnrichedReceipt } from '@t402/wdk'\n\nimport { extractPaymentRequired } from './http-client.js'\nimport { detectChainFamily, detectChainFamilyFromName } from './signer-factory.js'\nimport type { T402ProtocolConfig, T402FetchResult, PaymentReceipt } from './types.js'\n\nconst DEFAULT_FACILITATOR = 'https://facilitator.t402.io'\n\n/**\n * T402Protocol enables any WDK wallet app to handle HTTP 402 payments.\n *\n * Uses the real t402 protocol client infrastructure with EVM mechanism support.\n * Payment payloads are properly signed using EIP-3009 authorization.\n * Supports multi-chain registration for EVM and non-EVM chain families.\n */\nexport class T402Protocol {\n private httpClient: t402HTTPClient\n private wdk: T402WDK\n private facilitator: string\n private chains: string[]\n private _registeredFamilies: Set<string> = new Set()\n\n private constructor(wdk: T402WDK, httpClient: t402HTTPClient, config: T402ProtocolConfig) {\n this.wdk = wdk\n this.httpClient = httpClient\n this.facilitator = config.facilitator ?? DEFAULT_FACILITATOR\n this.chains = config.chains ?? []\n }\n\n /**\n * Create a new T402Protocol instance.\n *\n * This is async because it needs to initialize the WDK signer.\n * Registers the primary EVM signer plus detects additional chain families\n * from the configured chains list.\n *\n * @param wdk - An initialized T402WDK instance\n * @param config - Protocol configuration\n * @returns A configured T402Protocol instance\n */\n static async create(wdk: T402WDK, config: T402ProtocolConfig = {}): Promise<T402Protocol> {\n const client = new t402Client()\n const registeredFamilies = new Set<string>()\n\n // Register EVM (primary chain)\n const chainName = config.chains?.[0] ?? 'ethereum'\n try {\n const signer = await wdk.getSigner(chainName)\n registerExactEvmScheme(client, { signer })\n registeredFamilies.add('evm')\n } catch {\n // EVM not available — non-EVM-only config\n }\n\n // Detect additional chain families from configured chains\n if (config.chains) {\n for (const chain of config.chains) {\n const family = detectChainFamilyFromName(chain)\n if (family) {\n registeredFamilies.add(family)\n }\n }\n }\n\n const httpClient = new t402HTTPClient(client)\n const protocol = new T402Protocol(wdk, httpClient, config)\n protocol._registeredFamilies = registeredFamilies\n\n return protocol\n }\n\n /**\n * Fetch a URL with automatic 402 payment handling.\n *\n * 1. Makes the initial request\n * 2. If 402, extracts payment requirements\n * 3. Creates a properly signed payment payload (EIP-3009 for EVM)\n * 4. Retries the request with the signed payment header\n *\n * @param url - URL to fetch\n * @param init - Standard fetch RequestInit options\n * @returns The final response and optional payment receipt\n */\n async fetch(url: string | URL, init?: RequestInit): Promise<T402FetchResult> {\n const urlStr = url.toString()\n\n // Make initial request\n const response = await fetch(url, init)\n\n // If not 402, return as-is\n if (response.status !== 402) {\n return { response }\n }\n\n // Extract payment requirements from 402 response\n const paymentRequired = this.httpClient.getPaymentRequiredResponse((name: string) =>\n response.headers.get(name),\n )\n\n const network = paymentRequired.accepts?.[0]?.network ?? ''\n const amount = paymentRequired.accepts?.[0]?.amount ?? ''\n\n // Emit payment:start\n this._emitOnWdk('payment:start', { url: urlStr, network, amount })\n\n // Create signed payment payload using mechanism-specific logic\n let paymentPayload: PaymentPayload\n try {\n paymentPayload = await this.httpClient.createPaymentPayload(paymentRequired)\n } catch (error) {\n const errMsg = error instanceof Error ? error.message : String(error)\n this._emitOnWdk('payment:failed', { url: urlStr, error: errMsg })\n throw error\n }\n\n this._emitOnWdk('payment:signed', {\n url: urlStr,\n scheme: paymentPayload.accepted.scheme,\n network: paymentPayload.accepted.network,\n })\n\n // Build retry headers\n const paymentHeaders = this.httpClient.encodePaymentSignatureHeader(paymentPayload)\n const headers = new Headers(init?.headers)\n for (const [key, value] of Object.entries(paymentHeaders)) {\n headers.set(key, value)\n }\n\n // Retry with payment\n const retryResponse = await fetch(url, { ...init, headers })\n\n this._emitOnWdk('payment:submitted', { url: urlStr, statusCode: retryResponse.status })\n\n const success = retryResponse.status !== 402\n const receipt: PaymentReceipt = {\n success,\n network: paymentPayload.accepted.network,\n scheme: paymentPayload.accepted.scheme,\n amount: paymentPayload.accepted.amount,\n payTo: paymentPayload.accepted.payTo,\n }\n\n // Determine chain family for the enriched receipt\n let chainFamily = 'evm'\n try {\n chainFamily = detectChainFamily(paymentPayload.accepted.network)\n } catch {\n // default to 'evm' if detection fails\n }\n\n // Save enriched receipt to the WDK receipt store\n const enrichedReceipt: EnrichedReceipt = {\n id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n timestamp: new Date().toISOString(),\n url: urlStr,\n network: paymentPayload.accepted.network,\n scheme: paymentPayload.accepted.scheme,\n amount: paymentPayload.accepted.amount,\n payTo: paymentPayload.accepted.payTo,\n success,\n chainFamily,\n }\n\n try {\n await this.wdk.getReceiptStore().save(enrichedReceipt)\n } catch {\n // Receipt save failure is non-fatal\n }\n\n if (success) {\n this._emitOnWdk('payment:complete', { url: urlStr, success: true, receipt })\n } else {\n this._emitOnWdk('payment:failed', { url: urlStr, error: 'Payment rejected (still 402)' })\n }\n\n return { response: retryResponse, receipt }\n }\n\n /**\n * Emit an event on the underlying WDK event system.\n * Silently no-ops if the WDK doesn't support events.\n */\n private _emitOnWdk(event: string, data: unknown): void {\n try {\n const wdk = this.wdk as unknown as {\n emit?(event: string, data: unknown): boolean\n }\n wdk.emit?.(event, data)\n } catch {\n // Non-fatal: WDK may not have events support\n }\n }\n\n /**\n * Extract payment requirements from a URL\n *\n * @param url - URL to check for payment requirements\n * @param init - Standard fetch RequestInit options\n * @returns The PaymentRequired object from the 402 response\n * @throws Error if the response is not 402\n */\n async getRequirements(url: string | URL, init?: RequestInit): Promise<PaymentRequired> {\n const response = await fetch(url, init)\n if (response.status !== 402) {\n throw new Error(`Expected 402 response, got ${response.status}`)\n }\n return extractPaymentRequired(response)\n }\n\n /**\n * Sign a payment for specific requirements using the t402 client infrastructure\n *\n * @param paymentRequired - The full PaymentRequired context\n * @returns A properly signed PaymentPayload (e.g., EIP-3009 for EVM)\n */\n async signPayment(paymentRequired: PaymentRequired): Promise<PaymentPayload> {\n return this.httpClient.createPaymentPayload(paymentRequired)\n }\n\n /**\n * Submit a request with a pre-signed payment payload\n *\n * @param url - URL to request\n * @param paymentPayload - The signed payment payload\n * @param init - Standard fetch RequestInit options\n * @returns The HTTP response\n */\n async submitPayment(\n url: string | URL,\n paymentPayload: PaymentPayload,\n init?: RequestInit,\n ): Promise<Response> {\n const paymentHeaders = this.httpClient.encodePaymentSignatureHeader(paymentPayload)\n const headers = new Headers(init?.headers)\n for (const [key, value] of Object.entries(paymentHeaders)) {\n headers.set(key, value)\n }\n\n return fetch(url, { ...init, headers })\n }\n\n /**\n * Get the underlying t402 HTTP client for advanced usage\n */\n getHttpClient(): t402HTTPClient {\n return this.httpClient\n }\n\n /**\n * Get the underlying WDK instance\n */\n getWdk(): T402WDK {\n return this.wdk\n }\n\n /**\n * Get the facilitator URL\n */\n getFacilitator(): string {\n return this.facilitator\n }\n\n /**\n * Get the configured chains\n */\n getChains(): string[] {\n return [...this.chains]\n }\n\n /**\n * Get the set of registered chain families (e.g., 'evm', 'ton', 'solana')\n */\n getRegisteredFamilies(): Set<string> {\n return new Set(this._registeredFamilies)\n }\n\n /**\n * Check if this protocol instance can handle a given CAIP-2 network.\n *\n * @param network - CAIP-2 network identifier (e.g., \"eip155:42161\", \"ton:mainnet\")\n * @returns True if the required chain family is registered\n */\n canHandleNetwork(network: string): boolean {\n try {\n const family = detectChainFamily(network)\n return this._registeredFamilies.has(family)\n } catch {\n return false\n }\n }\n}\n","/**\n * HTTP client utilities for 402 payment handling\n */\n\nimport { decodePaymentRequiredHeader } from '@t402/core/http'\nimport type { PaymentRequired } from '@t402/core/types'\n\n/** V2 header names */\nconst HEADER_PAYMENT_REQUIRED = 'payment-required'\n\n/** V1 header names (fallback) */\nconst HEADER_X_PAYMENT = 'x-payment'\n\n/**\n * Extract PaymentRequired from a 402 response.\n * Tries V2 header first, then falls back to V1.\n *\n * @param response - The HTTP response with status 402\n * @returns The parsed PaymentRequired object\n * @throws Error if no valid payment header is found\n */\nexport function extractPaymentRequired(response: Response): PaymentRequired {\n // Try V2 header\n const v2Header = response.headers.get(HEADER_PAYMENT_REQUIRED)\n if (v2Header) {\n return decodePaymentRequiredHeader(v2Header)\n }\n\n // Try V1 header\n const v1Header = response.headers.get(HEADER_X_PAYMENT)\n if (v1Header) {\n return decodePaymentRequiredHeader(v1Header)\n }\n\n throw new Error(\n 'No payment requirements found in 402 response. ' +\n `Expected \"${HEADER_PAYMENT_REQUIRED}\" or \"${HEADER_X_PAYMENT}\" header.`,\n )\n}\n","/**\n * Chain detection utilities for CAIP-2 network identifiers\n */\n\n/**\n * CAIP-2 namespace prefixes\n */\nconst CAIP2_EVM = 'eip155:'\nconst CAIP2_TON = 'ton:'\nconst CAIP2_SOLANA = 'solana:'\nconst CAIP2_TRON = 'tron:'\nconst CAIP2_NEAR = 'near:'\nconst CAIP2_APTOS = 'aptos:'\nconst CAIP2_TEZOS = 'tezos:'\nconst CAIP2_POLKADOT = 'polkadot:'\nconst CAIP2_STACKS = 'stacks:'\nconst CAIP2_COSMOS = 'cosmos:'\n\n/**\n * Chain family detected from CAIP-2 network identifier\n */\nexport type ChainFamily =\n | 'evm'\n | 'ton'\n | 'solana'\n | 'tron'\n | 'near'\n | 'aptos'\n | 'tezos'\n | 'polkadot'\n | 'stacks'\n | 'cosmos'\n\n/**\n * Detect chain family from a CAIP-2 network identifier\n *\n * @param network - CAIP-2 network identifier (e.g., \"eip155:1\", \"ton:mainnet\")\n * @returns The chain family\n * @throws Error if network prefix is not recognized\n */\nexport function detectChainFamily(network: string): ChainFamily {\n if (network.startsWith(CAIP2_EVM)) return 'evm'\n if (network.startsWith(CAIP2_TON)) return 'ton'\n if (network.startsWith(CAIP2_SOLANA)) return 'solana'\n if (network.startsWith(CAIP2_TRON)) return 'tron'\n if (network.startsWith(CAIP2_NEAR)) return 'near'\n if (network.startsWith(CAIP2_APTOS)) return 'aptos'\n if (network.startsWith(CAIP2_TEZOS)) return 'tezos'\n if (network.startsWith(CAIP2_POLKADOT)) return 'polkadot'\n if (network.startsWith(CAIP2_STACKS)) return 'stacks'\n if (network.startsWith(CAIP2_COSMOS)) return 'cosmos'\n\n throw new Error(`Unsupported network: ${network}. Cannot detect chain family from CAIP-2 prefix.`)\n}\n\n/**\n * Map of EVM chain names to CAIP-2 identifiers\n */\nexport const EVM_CHAIN_MAP: Record<string, string> = {\n ethereum: 'eip155:1',\n base: 'eip155:8453',\n arbitrum: 'eip155:42161',\n optimism: 'eip155:10',\n polygon: 'eip155:137',\n avalanche: 'eip155:43114',\n ink: 'eip155:57073',\n berachain: 'eip155:80094',\n unichain: 'eip155:130',\n}\n\n/**\n * Get EVM chain name from CAIP-2 network identifier\n *\n * @param network - CAIP-2 network (e.g., \"eip155:42161\")\n * @returns Chain name (e.g., \"arbitrum\") or undefined\n */\nexport function getEvmChainName(network: string): string | undefined {\n for (const [name, caip2] of Object.entries(EVM_CHAIN_MAP)) {\n if (caip2 === network) return name\n }\n return undefined\n}\n\n/**\n * Check if a network is an EVM chain\n *\n * @param network - CAIP-2 network identifier\n * @returns True if the network is an EVM chain\n */\nexport function isEvmNetwork(network: string): boolean {\n return network.startsWith(CAIP2_EVM)\n}\n\n/**\n * Map of human-readable chain names to their chain family\n */\nconst CHAIN_NAME_TO_FAMILY: Record<string, ChainFamily> = {\n // EVM chains\n ethereum: 'evm',\n arbitrum: 'evm',\n base: 'evm',\n polygon: 'evm',\n optimism: 'evm',\n avalanche: 'evm',\n ink: 'evm',\n berachain: 'evm',\n unichain: 'evm',\n // Non-EVM chains\n ton: 'ton',\n solana: 'solana',\n tron: 'tron',\n near: 'near',\n aptos: 'aptos',\n tezos: 'tezos',\n polkadot: 'polkadot',\n stacks: 'stacks',\n cosmos: 'cosmos',\n}\n\n/**\n * Detect chain family from a human-readable chain name.\n *\n * @param chainName - Chain name (e.g., \"ethereum\", \"ton\", \"solana\")\n * @returns The chain family, or undefined if not recognized\n */\nexport function detectChainFamilyFromName(chainName: string): ChainFamily | undefined {\n return CHAIN_NAME_TO_FAMILY[chainName.toLowerCase()]\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@t402/wdk-protocol",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "T402 payment protocol for Tether WDK wallet apps",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.mjs",
|
|
@@ -16,22 +16,26 @@
|
|
|
16
16
|
],
|
|
17
17
|
"license": "Apache-2.0",
|
|
18
18
|
"author": "T402 Team",
|
|
19
|
-
"repository":
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/t402-io/t402.git",
|
|
22
|
+
"directory": "sdks/typescript/packages/wdk-protocol"
|
|
23
|
+
},
|
|
20
24
|
"dependencies": {
|
|
21
|
-
"@t402/
|
|
22
|
-
"@t402/
|
|
23
|
-
"@t402/wdk": "2.
|
|
25
|
+
"@t402/evm": "2.6.0",
|
|
26
|
+
"@t402/core": "2.6.0",
|
|
27
|
+
"@t402/wdk": "2.6.0"
|
|
24
28
|
},
|
|
25
29
|
"peerDependencies": {
|
|
26
30
|
"@tetherto/wdk": ">=1.0.0-beta.0",
|
|
27
31
|
"viem": "^2.0.0"
|
|
28
32
|
},
|
|
29
33
|
"devDependencies": {
|
|
30
|
-
"@types/node": "^25.2.
|
|
34
|
+
"@types/node": "^25.2.3",
|
|
31
35
|
"prettier": "3.8.1",
|
|
32
36
|
"tsup": "^8.5.1",
|
|
33
37
|
"typescript": "^5.9.3",
|
|
34
|
-
"vite-tsconfig-paths": "^6.1.
|
|
38
|
+
"vite-tsconfig-paths": "^6.1.1",
|
|
35
39
|
"vitest": "^3.2.4"
|
|
36
40
|
},
|
|
37
41
|
"exports": {
|
|
@@ -49,6 +53,10 @@
|
|
|
49
53
|
"files": [
|
|
50
54
|
"dist"
|
|
51
55
|
],
|
|
56
|
+
"homepage": "https://t402.io",
|
|
57
|
+
"publishConfig": {
|
|
58
|
+
"access": "public"
|
|
59
|
+
},
|
|
52
60
|
"scripts": {
|
|
53
61
|
"build": "tsup",
|
|
54
62
|
"test": "vitest run",
|