@bosonprotocol/x402-server 0.1.0-alpha-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/LICENSE +201 -0
- package/README.md +65 -0
- package/dist/cjs/challenge/index.d.ts +64 -0
- package/dist/cjs/challenge/index.js +96 -0
- package/dist/cjs/challenge/index.js.map +1 -0
- package/dist/cjs/client-tnrpqVMW.d.ts +36 -0
- package/dist/cjs/config-CBr9qMps.d.ts +419 -0
- package/dist/cjs/facilitator/index.d.ts +26 -0
- package/dist/cjs/facilitator/index.js +136 -0
- package/dist/cjs/facilitator/index.js.map +1 -0
- package/dist/cjs/handlers/index.d.ts +267 -0
- package/dist/cjs/handlers/index.js +1182 -0
- package/dist/cjs/handlers/index.js.map +1 -0
- package/dist/cjs/index.d.ts +72 -0
- package/dist/cjs/index.js +1643 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/onchain/index.d.ts +73 -0
- package/dist/cjs/onchain/index.js +87 -0
- package/dist/cjs/onchain/index.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/validate/index.d.ts +67 -0
- package/dist/cjs/validate/index.js +429 -0
- package/dist/cjs/validate/index.js.map +1 -0
- package/dist/esm/challenge/index.js +3 -0
- package/dist/esm/challenge/index.js.map +1 -0
- package/dist/esm/chunk-4NQ3VKC3.js +84 -0
- package/dist/esm/chunk-4NQ3VKC3.js.map +1 -0
- package/dist/esm/chunk-CGVXQX5V.js +426 -0
- package/dist/esm/chunk-CGVXQX5V.js.map +1 -0
- package/dist/esm/chunk-DJMCSCBE.js +3 -0
- package/dist/esm/chunk-DJMCSCBE.js.map +1 -0
- package/dist/esm/chunk-EAKQ4EFZ.js +124 -0
- package/dist/esm/chunk-EAKQ4EFZ.js.map +1 -0
- package/dist/esm/chunk-GBPU373M.js +93 -0
- package/dist/esm/chunk-GBPU373M.js.map +1 -0
- package/dist/esm/chunk-PU5Y7FZG.js +14 -0
- package/dist/esm/chunk-PU5Y7FZG.js.map +1 -0
- package/dist/esm/chunk-WU7QJ7YP.js +3 -0
- package/dist/esm/chunk-WU7QJ7YP.js.map +1 -0
- package/dist/esm/chunk-Y5HFLCAT.js +657 -0
- package/dist/esm/chunk-Y5HFLCAT.js.map +1 -0
- package/dist/esm/facilitator/index.js +4 -0
- package/dist/esm/facilitator/index.js.map +1 -0
- package/dist/esm/handlers/index.js +6 -0
- package/dist/esm/handlers/index.js.map +1 -0
- package/dist/esm/index.js +261 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/onchain/index.js +4 -0
- package/dist/esm/onchain/index.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/validate/index.js +4 -0
- package/dist/esm/validate/index.js.map +1 -0
- package/package.json +88 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
import * as _bosonprotocol_x402_facilitator from '@bosonprotocol/x402-facilitator';
|
|
2
|
+
import * as _bosonprotocol_x402_actions from '@bosonprotocol/x402-actions';
|
|
3
|
+
import { ChannelRegistry } from '@bosonprotocol/x402-actions';
|
|
4
|
+
import { EvmNetwork, Address } from '@bosonprotocol/x402-core/schemes/escrow';
|
|
5
|
+
import { Hex } from 'viem';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { CoreSDK } from '@bosonprotocol/core-sdk';
|
|
8
|
+
import { ExchangeReader } from './onchain/index.js';
|
|
9
|
+
|
|
10
|
+
/** Funds entity returned by `coreSdk.getFunds` — narrowed to the fields the handler reshapes. */
|
|
11
|
+
interface CoreSdkFundsEntity {
|
|
12
|
+
id?: string;
|
|
13
|
+
accountId: string;
|
|
14
|
+
availableAmount: string;
|
|
15
|
+
token: {
|
|
16
|
+
address: string;
|
|
17
|
+
decimals: string;
|
|
18
|
+
symbol: string;
|
|
19
|
+
name: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/** Seller entity returned by `coreSdk.getSellersByAddress` — only the id is consumed. */
|
|
23
|
+
interface CoreSdkSellerEntity {
|
|
24
|
+
id: string;
|
|
25
|
+
}
|
|
26
|
+
/** Buyer entity returned by `coreSdk.getBuyers` — only the id is consumed. */
|
|
27
|
+
interface CoreSdkBuyerEntity {
|
|
28
|
+
id: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The subset of `CoreSDK` the read-only handlers actually use. Both the
|
|
32
|
+
* real `CoreSDK` and a hand-rolled stub for tests satisfy this shape.
|
|
33
|
+
*/
|
|
34
|
+
interface CoreSdkReadAdapter {
|
|
35
|
+
getFunds(queryVars: {
|
|
36
|
+
fundsFilter: {
|
|
37
|
+
accountId: string;
|
|
38
|
+
};
|
|
39
|
+
}): Promise<CoreSdkFundsEntity[]>;
|
|
40
|
+
getSellersByAddress(address: string): Promise<CoreSdkSellerEntity[]>;
|
|
41
|
+
getBuyers(queryVars: {
|
|
42
|
+
buyersFilter: {
|
|
43
|
+
wallet: string;
|
|
44
|
+
};
|
|
45
|
+
}): Promise<CoreSdkBuyerEntity[]>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Cast a full `CoreSDK` to the narrowed adapter shape. Structural-only;
|
|
49
|
+
* does not capture or wrap anything.
|
|
50
|
+
*/
|
|
51
|
+
declare function asCoreSdkReadAdapter(coreSdk: CoreSDK): CoreSdkReadAdapter;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Minimal signing surface needed by `signFullOffer`. Structurally
|
|
55
|
+
* compatible with viem's `Account` (in particular `LocalAccount` from
|
|
56
|
+
* `privateKeyToAccount`), but kept narrow so consumers can plug in
|
|
57
|
+
* HSM- / KMS- / ERC-1271-backed signers without depending on viem's
|
|
58
|
+
* internal account types.
|
|
59
|
+
*/
|
|
60
|
+
interface SellerSigner {
|
|
61
|
+
/** Address that the EIP-712 signature must recover to (`creator` in `BosonOfferRef`). */
|
|
62
|
+
readonly address: Address;
|
|
63
|
+
/** EIP-712 typed-data signer. Accepts the same shape viem's `signTypedData` does. */
|
|
64
|
+
signTypedData: (params: {
|
|
65
|
+
domain: Record<string, unknown>;
|
|
66
|
+
types: Record<string, readonly {
|
|
67
|
+
name: string;
|
|
68
|
+
type: string;
|
|
69
|
+
}[]>;
|
|
70
|
+
primaryType: string;
|
|
71
|
+
message: Record<string, unknown>;
|
|
72
|
+
}) => Promise<Hex>;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Per-server configuration. Validated by `x402bServerConfigSchema` at
|
|
76
|
+
* `createX402bServer` time so bad config fails fast at boot rather than
|
|
77
|
+
* later inside a 402 response.
|
|
78
|
+
*/
|
|
79
|
+
interface X402bServerConfig {
|
|
80
|
+
/** CAIP-2 EVM network the server advertises (e.g. `eip155:8453`). */
|
|
81
|
+
network: EvmNetwork;
|
|
82
|
+
/** EVM chain id matching `network` — passed straight to the EIP-712 builder's salt. */
|
|
83
|
+
chainId: number;
|
|
84
|
+
/** Address of the Boson Diamond — the EIP-712 `verifyingContract` and the wire-level `escrowAddress`. */
|
|
85
|
+
escrow: Address;
|
|
86
|
+
/** Seller signer (signs the FullOffer EIP-712 typed-data). */
|
|
87
|
+
signer: SellerSigner;
|
|
88
|
+
/** Facilitator service the server forwards meta-tx envelopes to. The URL is also advertised in `nextActions[].endpoints.facilitator`. */
|
|
89
|
+
facilitator: {
|
|
90
|
+
url: string;
|
|
91
|
+
};
|
|
92
|
+
/** Per-seller channel + endpoint registry consumed by `deriveNextActions`. */
|
|
93
|
+
channelRegistry: ChannelRegistry;
|
|
94
|
+
/**
|
|
95
|
+
* Reader the convenience handlers use to verify the post-settle /
|
|
96
|
+
* post-perform-action exchange state. Required at runtime when any
|
|
97
|
+
* write handler is invoked; the `signOffer` / `buildPaymentRequirements`
|
|
98
|
+
* read-only paths don't touch it. See `./onchain/verify-exchange.ts`
|
|
99
|
+
* for the interface.
|
|
100
|
+
*/
|
|
101
|
+
exchangeReader?: ExchangeReader;
|
|
102
|
+
/**
|
|
103
|
+
* URL of the Boson Protocol subgraph for this network. Used by the
|
|
104
|
+
* read-only `available-funds` handler and the address→entityId
|
|
105
|
+
* resolver shared with `withdraw-funds`. Optional at config time
|
|
106
|
+
* (legacy commit/redeem handlers don't need it); required at runtime
|
|
107
|
+
* by `handlers.withdrawFunds` / `handlers.getAvailableFunds`.
|
|
108
|
+
*/
|
|
109
|
+
subgraphUrl?: string;
|
|
110
|
+
/**
|
|
111
|
+
* Pre-built read-only core-sdk client. If omitted, the server
|
|
112
|
+
* constructs one internally from `subgraphUrl` + `escrow` + `chainId`
|
|
113
|
+
* with a throwing `Web3LibAdapter` stub. Provide your own for tests
|
|
114
|
+
* or when you want to share a single core-sdk instance with the
|
|
115
|
+
* rest of your service.
|
|
116
|
+
*/
|
|
117
|
+
coreSdkRead?: CoreSdkReadAdapter;
|
|
118
|
+
/**
|
|
119
|
+
* Server-side store of the fulfillment option ids advertised for
|
|
120
|
+
* each Flow A exchange (keyed by `exchangeId`). Populated from the
|
|
121
|
+
* original `PaymentRequirements` after commit verification and read
|
|
122
|
+
* at redeem time so the buyer's redeem-time fulfillment choice
|
|
123
|
+
* cannot switch to a channel the offer never advertised.
|
|
124
|
+
*
|
|
125
|
+
* Optional in the config: when omitted, `createX402bServer` wires up
|
|
126
|
+
* an in-memory `Map`. Hosts running multiple instances should plug
|
|
127
|
+
* in their own cross-process `Map`-shaped backing store.
|
|
128
|
+
*/
|
|
129
|
+
exchangeFulfillmentOptionStore?: Map<string, readonly string[]>;
|
|
130
|
+
/**
|
|
131
|
+
* Pending fulfillment updates that reached REDEEMED on-chain but
|
|
132
|
+
* failed the server-side `channel.onCommit(...)` upsert. The commit
|
|
133
|
+
* handler records Flow B updates here before attempting the channel
|
|
134
|
+
* write; the redeem handler does the same for Flow A. Both delete the
|
|
135
|
+
* record on success and leave it behind with the error message on
|
|
136
|
+
* failure so the host can replay/reconcile out of band.
|
|
137
|
+
*/
|
|
138
|
+
fulfillmentRecoveryStore?: Map<string, FulfillmentRecoveryEntry>;
|
|
139
|
+
/**
|
|
140
|
+
* Fulfillment channels the server accepts at redeem time when the
|
|
141
|
+
* client re-submits delivery data. Structurally a subset of
|
|
142
|
+
* `@bosonprotocol/x402-fulfillment`'s `FulfillmentChannel` — only
|
|
143
|
+
* `id`, `validate`, and `onCommit` are read here, so existing
|
|
144
|
+
* channel instances pass through directly. Required iff a host
|
|
145
|
+
* wants to accept redeem-time fulfillment updates; absent means
|
|
146
|
+
* redeem requests carrying `fulfillment` are rejected with
|
|
147
|
+
* `FULFILLMENT_CHANNELS_NOT_CONFIGURED`.
|
|
148
|
+
*/
|
|
149
|
+
fulfillmentChannels?: readonly RedeemFulfillmentChannel[];
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Minimal structural slice of `FulfillmentChannel` the redeem
|
|
153
|
+
* handler needs. Kept inline so `@bosonprotocol/x402-server` does
|
|
154
|
+
* not depend on `@bosonprotocol/x402-fulfillment` (avoids a hard
|
|
155
|
+
* coupling between the resource-server SDK and a specific channel
|
|
156
|
+
* package); any real channel implementation is type-compatible.
|
|
157
|
+
*/
|
|
158
|
+
interface RedeemFulfillmentChannel {
|
|
159
|
+
readonly id: string;
|
|
160
|
+
validate(data: Record<string, unknown> | null): {
|
|
161
|
+
ok: true;
|
|
162
|
+
} | {
|
|
163
|
+
ok: false;
|
|
164
|
+
reason: string;
|
|
165
|
+
};
|
|
166
|
+
onCommit(exchangeId: string, data: Record<string, unknown> | null): Promise<void>;
|
|
167
|
+
}
|
|
168
|
+
interface FulfillmentRecoveryEntry {
|
|
169
|
+
exchangeId: string;
|
|
170
|
+
option: string;
|
|
171
|
+
data: Record<string, unknown> | null;
|
|
172
|
+
redeemer: Address;
|
|
173
|
+
recordedAt: number;
|
|
174
|
+
error?: string;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* zod validator for `X402bServerConfig`. Shallow on the signer +
|
|
178
|
+
* exchange reader (viem account types bring their own structural
|
|
179
|
+
* validators; the user-supplied reader impl is structurally typed);
|
|
180
|
+
* strict on the scalar fields we own here, and on the channel
|
|
181
|
+
* registry via `@bosonprotocol/x402-actions`.
|
|
182
|
+
*/
|
|
183
|
+
declare const x402bServerConfigSchema: z.ZodEffects<z.ZodObject<{
|
|
184
|
+
network: z.ZodString;
|
|
185
|
+
chainId: z.ZodNumber;
|
|
186
|
+
escrow: z.ZodString;
|
|
187
|
+
signer: z.ZodObject<{
|
|
188
|
+
address: z.ZodString;
|
|
189
|
+
signTypedData: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodPromise<z.ZodString>>;
|
|
190
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
191
|
+
address: z.ZodString;
|
|
192
|
+
signTypedData: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodPromise<z.ZodString>>;
|
|
193
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
194
|
+
address: z.ZodString;
|
|
195
|
+
signTypedData: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodPromise<z.ZodString>>;
|
|
196
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
197
|
+
facilitator: z.ZodObject<{
|
|
198
|
+
url: z.ZodEffects<z.ZodString, string, string>;
|
|
199
|
+
}, "strict", z.ZodTypeAny, {
|
|
200
|
+
url: string;
|
|
201
|
+
}, {
|
|
202
|
+
url: string;
|
|
203
|
+
}>;
|
|
204
|
+
channelRegistry: z.ZodObject<{
|
|
205
|
+
channels: z.ZodEffects<z.ZodArray<z.ZodEnum<[_bosonprotocol_x402_actions.ActionChannel, ..._bosonprotocol_x402_actions.ActionChannel[]]>, "many">, _bosonprotocol_x402_actions.ActionChannel[], _bosonprotocol_x402_actions.ActionChannel[]>;
|
|
206
|
+
endpoints: z.ZodOptional<z.ZodRecord<z.ZodEnum<[_bosonprotocol_x402_facilitator.ActionId, ..._bosonprotocol_x402_facilitator.ActionId[]]>, z.ZodEffects<z.ZodString, string, string>>>;
|
|
207
|
+
xmtp: z.ZodOptional<z.ZodString>;
|
|
208
|
+
mcp: z.ZodOptional<z.ZodString>;
|
|
209
|
+
escrow: z.ZodString;
|
|
210
|
+
}, "strict", z.ZodTypeAny, {
|
|
211
|
+
channels: _bosonprotocol_x402_actions.ActionChannel[];
|
|
212
|
+
escrow: string;
|
|
213
|
+
mcp?: string | undefined;
|
|
214
|
+
xmtp?: string | undefined;
|
|
215
|
+
endpoints?: Partial<Record<_bosonprotocol_x402_facilitator.ActionId, string>> | undefined;
|
|
216
|
+
}, {
|
|
217
|
+
channels: _bosonprotocol_x402_actions.ActionChannel[];
|
|
218
|
+
escrow: string;
|
|
219
|
+
mcp?: string | undefined;
|
|
220
|
+
xmtp?: string | undefined;
|
|
221
|
+
endpoints?: Partial<Record<_bosonprotocol_x402_facilitator.ActionId, string>> | undefined;
|
|
222
|
+
}>;
|
|
223
|
+
exchangeReader: z.ZodOptional<z.ZodObject<{
|
|
224
|
+
read: z.ZodFunction<z.ZodTuple<[z.ZodString], z.ZodUnknown>, z.ZodUnknown>;
|
|
225
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
226
|
+
read: z.ZodFunction<z.ZodTuple<[z.ZodString], z.ZodUnknown>, z.ZodUnknown>;
|
|
227
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
228
|
+
read: z.ZodFunction<z.ZodTuple<[z.ZodString], z.ZodUnknown>, z.ZodUnknown>;
|
|
229
|
+
}, z.ZodTypeAny, "passthrough">>>;
|
|
230
|
+
subgraphUrl: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
231
|
+
coreSdkRead: z.ZodOptional<z.ZodObject<{
|
|
232
|
+
getFunds: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
233
|
+
getSellersByAddress: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
234
|
+
getBuyers: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
235
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
236
|
+
getFunds: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
237
|
+
getSellersByAddress: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
238
|
+
getBuyers: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
239
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
240
|
+
getFunds: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
241
|
+
getSellersByAddress: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
242
|
+
getBuyers: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
243
|
+
}, z.ZodTypeAny, "passthrough">>>;
|
|
244
|
+
exchangeFulfillmentOptionStore: z.ZodOptional<z.ZodType<Map<unknown, unknown>, z.ZodTypeDef, Map<unknown, unknown>>>;
|
|
245
|
+
fulfillmentRecoveryStore: z.ZodOptional<z.ZodType<Map<unknown, unknown>, z.ZodTypeDef, Map<unknown, unknown>>>;
|
|
246
|
+
fulfillmentChannels: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodObject<{
|
|
247
|
+
id: z.ZodString;
|
|
248
|
+
validate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
249
|
+
onCommit: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
250
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
251
|
+
id: z.ZodString;
|
|
252
|
+
validate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
253
|
+
onCommit: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
254
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
255
|
+
id: z.ZodString;
|
|
256
|
+
validate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
257
|
+
onCommit: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
258
|
+
}, z.ZodTypeAny, "passthrough">>, "many">, z.objectOutputType<{
|
|
259
|
+
id: z.ZodString;
|
|
260
|
+
validate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
261
|
+
onCommit: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
262
|
+
}, z.ZodTypeAny, "passthrough">[], z.objectInputType<{
|
|
263
|
+
id: z.ZodString;
|
|
264
|
+
validate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
265
|
+
onCommit: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
266
|
+
}, z.ZodTypeAny, "passthrough">[]>>;
|
|
267
|
+
}, "strict", z.ZodTypeAny, {
|
|
268
|
+
chainId: number;
|
|
269
|
+
network: string;
|
|
270
|
+
escrow: string;
|
|
271
|
+
channelRegistry: {
|
|
272
|
+
channels: _bosonprotocol_x402_actions.ActionChannel[];
|
|
273
|
+
escrow: string;
|
|
274
|
+
mcp?: string | undefined;
|
|
275
|
+
xmtp?: string | undefined;
|
|
276
|
+
endpoints?: Partial<Record<_bosonprotocol_x402_facilitator.ActionId, string>> | undefined;
|
|
277
|
+
};
|
|
278
|
+
facilitator: {
|
|
279
|
+
url: string;
|
|
280
|
+
};
|
|
281
|
+
signer: {
|
|
282
|
+
address: string;
|
|
283
|
+
signTypedData: (args_0: unknown, ...args: unknown[]) => Promise<string>;
|
|
284
|
+
} & {
|
|
285
|
+
[k: string]: unknown;
|
|
286
|
+
};
|
|
287
|
+
subgraphUrl?: string | undefined;
|
|
288
|
+
exchangeReader?: z.objectOutputType<{
|
|
289
|
+
read: z.ZodFunction<z.ZodTuple<[z.ZodString], z.ZodUnknown>, z.ZodUnknown>;
|
|
290
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
291
|
+
coreSdkRead?: z.objectOutputType<{
|
|
292
|
+
getFunds: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
293
|
+
getSellersByAddress: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
294
|
+
getBuyers: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
295
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
296
|
+
exchangeFulfillmentOptionStore?: Map<unknown, unknown> | undefined;
|
|
297
|
+
fulfillmentRecoveryStore?: Map<unknown, unknown> | undefined;
|
|
298
|
+
fulfillmentChannels?: z.objectOutputType<{
|
|
299
|
+
id: z.ZodString;
|
|
300
|
+
validate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
301
|
+
onCommit: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
302
|
+
}, z.ZodTypeAny, "passthrough">[] | undefined;
|
|
303
|
+
}, {
|
|
304
|
+
chainId: number;
|
|
305
|
+
network: string;
|
|
306
|
+
escrow: string;
|
|
307
|
+
channelRegistry: {
|
|
308
|
+
channels: _bosonprotocol_x402_actions.ActionChannel[];
|
|
309
|
+
escrow: string;
|
|
310
|
+
mcp?: string | undefined;
|
|
311
|
+
xmtp?: string | undefined;
|
|
312
|
+
endpoints?: Partial<Record<_bosonprotocol_x402_facilitator.ActionId, string>> | undefined;
|
|
313
|
+
};
|
|
314
|
+
facilitator: {
|
|
315
|
+
url: string;
|
|
316
|
+
};
|
|
317
|
+
signer: {
|
|
318
|
+
address: string;
|
|
319
|
+
signTypedData: (args_0: unknown, ...args: unknown[]) => Promise<string>;
|
|
320
|
+
} & {
|
|
321
|
+
[k: string]: unknown;
|
|
322
|
+
};
|
|
323
|
+
subgraphUrl?: string | undefined;
|
|
324
|
+
exchangeReader?: z.objectInputType<{
|
|
325
|
+
read: z.ZodFunction<z.ZodTuple<[z.ZodString], z.ZodUnknown>, z.ZodUnknown>;
|
|
326
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
327
|
+
coreSdkRead?: z.objectInputType<{
|
|
328
|
+
getFunds: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
329
|
+
getSellersByAddress: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
330
|
+
getBuyers: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
331
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
332
|
+
exchangeFulfillmentOptionStore?: Map<unknown, unknown> | undefined;
|
|
333
|
+
fulfillmentRecoveryStore?: Map<unknown, unknown> | undefined;
|
|
334
|
+
fulfillmentChannels?: z.objectInputType<{
|
|
335
|
+
id: z.ZodString;
|
|
336
|
+
validate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
337
|
+
onCommit: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
338
|
+
}, z.ZodTypeAny, "passthrough">[] | undefined;
|
|
339
|
+
}>, {
|
|
340
|
+
chainId: number;
|
|
341
|
+
network: string;
|
|
342
|
+
escrow: string;
|
|
343
|
+
channelRegistry: {
|
|
344
|
+
channels: _bosonprotocol_x402_actions.ActionChannel[];
|
|
345
|
+
escrow: string;
|
|
346
|
+
mcp?: string | undefined;
|
|
347
|
+
xmtp?: string | undefined;
|
|
348
|
+
endpoints?: Partial<Record<_bosonprotocol_x402_facilitator.ActionId, string>> | undefined;
|
|
349
|
+
};
|
|
350
|
+
facilitator: {
|
|
351
|
+
url: string;
|
|
352
|
+
};
|
|
353
|
+
signer: {
|
|
354
|
+
address: string;
|
|
355
|
+
signTypedData: (args_0: unknown, ...args: unknown[]) => Promise<string>;
|
|
356
|
+
} & {
|
|
357
|
+
[k: string]: unknown;
|
|
358
|
+
};
|
|
359
|
+
subgraphUrl?: string | undefined;
|
|
360
|
+
exchangeReader?: z.objectOutputType<{
|
|
361
|
+
read: z.ZodFunction<z.ZodTuple<[z.ZodString], z.ZodUnknown>, z.ZodUnknown>;
|
|
362
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
363
|
+
coreSdkRead?: z.objectOutputType<{
|
|
364
|
+
getFunds: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
365
|
+
getSellersByAddress: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
366
|
+
getBuyers: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
367
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
368
|
+
exchangeFulfillmentOptionStore?: Map<unknown, unknown> | undefined;
|
|
369
|
+
fulfillmentRecoveryStore?: Map<unknown, unknown> | undefined;
|
|
370
|
+
fulfillmentChannels?: z.objectOutputType<{
|
|
371
|
+
id: z.ZodString;
|
|
372
|
+
validate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
373
|
+
onCommit: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
374
|
+
}, z.ZodTypeAny, "passthrough">[] | undefined;
|
|
375
|
+
}, {
|
|
376
|
+
chainId: number;
|
|
377
|
+
network: string;
|
|
378
|
+
escrow: string;
|
|
379
|
+
channelRegistry: {
|
|
380
|
+
channels: _bosonprotocol_x402_actions.ActionChannel[];
|
|
381
|
+
escrow: string;
|
|
382
|
+
mcp?: string | undefined;
|
|
383
|
+
xmtp?: string | undefined;
|
|
384
|
+
endpoints?: Partial<Record<_bosonprotocol_x402_facilitator.ActionId, string>> | undefined;
|
|
385
|
+
};
|
|
386
|
+
facilitator: {
|
|
387
|
+
url: string;
|
|
388
|
+
};
|
|
389
|
+
signer: {
|
|
390
|
+
address: string;
|
|
391
|
+
signTypedData: (args_0: unknown, ...args: unknown[]) => Promise<string>;
|
|
392
|
+
} & {
|
|
393
|
+
[k: string]: unknown;
|
|
394
|
+
};
|
|
395
|
+
subgraphUrl?: string | undefined;
|
|
396
|
+
exchangeReader?: z.objectInputType<{
|
|
397
|
+
read: z.ZodFunction<z.ZodTuple<[z.ZodString], z.ZodUnknown>, z.ZodUnknown>;
|
|
398
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
399
|
+
coreSdkRead?: z.objectInputType<{
|
|
400
|
+
getFunds: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
401
|
+
getSellersByAddress: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
402
|
+
getBuyers: z.ZodFunction<z.ZodTuple<[z.ZodUnknown], z.ZodUnknown>, z.ZodUnknown>;
|
|
403
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
404
|
+
exchangeFulfillmentOptionStore?: Map<unknown, unknown> | undefined;
|
|
405
|
+
fulfillmentRecoveryStore?: Map<unknown, unknown> | undefined;
|
|
406
|
+
fulfillmentChannels?: z.objectInputType<{
|
|
407
|
+
id: z.ZodString;
|
|
408
|
+
validate: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
409
|
+
onCommit: z.ZodFunction<z.ZodTuple<[], z.ZodUnknown>, z.ZodUnknown>;
|
|
410
|
+
}, z.ZodTypeAny, "passthrough">[] | undefined;
|
|
411
|
+
}>;
|
|
412
|
+
/**
|
|
413
|
+
* Cross-field invariant: `config.escrow` and
|
|
414
|
+
* `config.channelRegistry.escrow` must agree — the Diamond address is
|
|
415
|
+
* the same on both sides. Run this after `x402bServerConfigSchema.parse`.
|
|
416
|
+
*/
|
|
417
|
+
declare function assertChannelRegistryEscrowMatch(config: X402bServerConfig): void;
|
|
418
|
+
|
|
419
|
+
export { type CoreSdkBuyerEntity as C, type FulfillmentRecoveryEntry as F, type RedeemFulfillmentChannel as R, type SellerSigner as S, type X402bServerConfig as X, type CoreSdkFundsEntity as a, type CoreSdkReadAdapter as b, type CoreSdkSellerEntity as c, asCoreSdkReadAdapter as d, assertChannelRegistryEscrowMatch as e, x402bServerConfigSchema as x };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export { C as CreateFacilitatorClientOptions, F as FacilitatorClient, a as FetchLike, c as createFacilitatorClient } from '../client-tnrpqVMW.js';
|
|
2
|
+
import { FacilitatorErrorCode } from '@bosonprotocol/x402-facilitator';
|
|
3
|
+
export { FacilitatorErrorCode, FacilitatorPerformActionInput, FacilitatorPerformActionResult, FacilitatorSettleInput, FacilitatorSettleResult, FacilitatorVerifyInput, FacilitatorVerifyResult } from '@bosonprotocol/x402-facilitator';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Stable, x402-server-side codes for HTTP-transport failures.
|
|
7
|
+
* Distinct from the facilitator-side `FacilitatorErrorCode` enum so
|
|
8
|
+
* callers can branch on "the facilitator answered with X" vs "we
|
|
9
|
+
* never reached the facilitator".
|
|
10
|
+
*/
|
|
11
|
+
type FacilitatorHttpErrorCode = "NETWORK_ERROR" | "BAD_HTTP_STATUS" | "BAD_RESPONSE_BODY" | "TIMEOUT";
|
|
12
|
+
/** Network- or transport-layer failure when calling the facilitator. */
|
|
13
|
+
declare class FacilitatorHttpError extends Error {
|
|
14
|
+
readonly code: FacilitatorHttpErrorCode;
|
|
15
|
+
readonly status?: number;
|
|
16
|
+
/** Original facilitator-side error code, if the body parsed cleanly. */
|
|
17
|
+
readonly facilitatorCode?: FacilitatorErrorCode;
|
|
18
|
+
constructor(message: string, init: {
|
|
19
|
+
code: FacilitatorHttpErrorCode;
|
|
20
|
+
status?: number;
|
|
21
|
+
facilitatorCode?: FacilitatorErrorCode;
|
|
22
|
+
cause?: unknown;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { FacilitatorHttpError, type FacilitatorHttpErrorCode };
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/facilitator/errors.ts
|
|
4
|
+
var FacilitatorHttpError = class extends Error {
|
|
5
|
+
constructor(message, init) {
|
|
6
|
+
super(message, init.cause !== void 0 ? { cause: init.cause } : void 0);
|
|
7
|
+
this.name = "FacilitatorHttpError";
|
|
8
|
+
this.code = init.code;
|
|
9
|
+
if (init.status !== void 0) this.status = init.status;
|
|
10
|
+
if (init.facilitatorCode !== void 0) this.facilitatorCode = init.facilitatorCode;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// src/facilitator/client.ts
|
|
15
|
+
function createFacilitatorClient(opts) {
|
|
16
|
+
const fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
17
|
+
if (fetchImpl === void 0) {
|
|
18
|
+
throw new Error(
|
|
19
|
+
"createFacilitatorClient: no `fetch` implementation available. Pass `opts.fetch` explicitly."
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
const baseUrl = opts.url.replace(/\/+$/, "");
|
|
23
|
+
const baseHeaders = { "content-type": "application/json", ...opts.headers ?? {} };
|
|
24
|
+
const post = async (path, body, validate) => {
|
|
25
|
+
let res;
|
|
26
|
+
try {
|
|
27
|
+
res = await fetchImpl(`${baseUrl}${path}`, {
|
|
28
|
+
method: "POST",
|
|
29
|
+
headers: baseHeaders,
|
|
30
|
+
body: JSON.stringify(body)
|
|
31
|
+
});
|
|
32
|
+
} catch (cause) {
|
|
33
|
+
throw new FacilitatorHttpError(`facilitator network error (${path})`, {
|
|
34
|
+
code: "NETWORK_ERROR",
|
|
35
|
+
cause
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
let text;
|
|
39
|
+
try {
|
|
40
|
+
text = await res.text();
|
|
41
|
+
} catch (cause) {
|
|
42
|
+
throw new FacilitatorHttpError(`facilitator response body could not be read (${path})`, {
|
|
43
|
+
code: "BAD_RESPONSE_BODY",
|
|
44
|
+
status: res.status,
|
|
45
|
+
cause
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
let parsed;
|
|
49
|
+
try {
|
|
50
|
+
parsed = text.length === 0 ? null : JSON.parse(text);
|
|
51
|
+
} catch (cause) {
|
|
52
|
+
throw new FacilitatorHttpError(`facilitator returned non-JSON body (${path})`, {
|
|
53
|
+
code: "BAD_RESPONSE_BODY",
|
|
54
|
+
status: res.status,
|
|
55
|
+
cause
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (!res.ok) {
|
|
59
|
+
if (res.status === 400 && isFailureBranch(parsed) && validate(parsed)) {
|
|
60
|
+
return parsed;
|
|
61
|
+
}
|
|
62
|
+
const facilitatorCode = extractFacilitatorCode(parsed);
|
|
63
|
+
throw new FacilitatorHttpError(
|
|
64
|
+
`facilitator HTTP ${res.status} (${path}): ${reasonString(parsed) ?? text}`,
|
|
65
|
+
{
|
|
66
|
+
code: "BAD_HTTP_STATUS",
|
|
67
|
+
status: res.status,
|
|
68
|
+
...facilitatorCode !== void 0 ? { facilitatorCode } : {}
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
if (!validate(parsed)) {
|
|
73
|
+
throw new FacilitatorHttpError(`facilitator returned unexpected body shape (${path})`, {
|
|
74
|
+
code: "BAD_RESPONSE_BODY",
|
|
75
|
+
status: res.status
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return parsed;
|
|
79
|
+
};
|
|
80
|
+
return {
|
|
81
|
+
verify: (input) => post("/verify", input, isVerifyResult),
|
|
82
|
+
settle: (input) => post("/settle", input, isSettleResult),
|
|
83
|
+
performAction: (input) => post(
|
|
84
|
+
`/perform-action?action=${encodeURIComponent(input.action)}`,
|
|
85
|
+
input,
|
|
86
|
+
isPerformActionResult
|
|
87
|
+
)
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function isObject(v) {
|
|
91
|
+
return v !== null && typeof v === "object";
|
|
92
|
+
}
|
|
93
|
+
function isFailureBranch(v) {
|
|
94
|
+
return isObject(v) && v.ok === false && typeof v.code === "string" && typeof v.reason === "string";
|
|
95
|
+
}
|
|
96
|
+
function isVerifyResult(parsed) {
|
|
97
|
+
if (!isObject(parsed)) return false;
|
|
98
|
+
if (parsed.ok === true) return true;
|
|
99
|
+
return isFailureBranch(parsed);
|
|
100
|
+
}
|
|
101
|
+
function isSettleResult(parsed) {
|
|
102
|
+
if (!isObject(parsed)) return false;
|
|
103
|
+
if (parsed.ok === true) {
|
|
104
|
+
return typeof parsed.exchangeId === "string" && typeof parsed.txHash === "string";
|
|
105
|
+
}
|
|
106
|
+
return isFailureBranch(parsed);
|
|
107
|
+
}
|
|
108
|
+
function isPerformActionResult(parsed) {
|
|
109
|
+
if (!isObject(parsed)) return false;
|
|
110
|
+
if (parsed.ok === true) {
|
|
111
|
+
if (typeof parsed.txHash !== "string") return false;
|
|
112
|
+
if (parsed.newExchangeState !== void 0 && typeof parsed.newExchangeState !== "string") {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
if (parsed.newDisputeState !== void 0 && typeof parsed.newDisputeState !== "string") {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
return isFailureBranch(parsed);
|
|
121
|
+
}
|
|
122
|
+
function extractFacilitatorCode(body) {
|
|
123
|
+
if (body === null || typeof body !== "object") return void 0;
|
|
124
|
+
const code = body.code;
|
|
125
|
+
return typeof code === "string" ? code : void 0;
|
|
126
|
+
}
|
|
127
|
+
function reasonString(body) {
|
|
128
|
+
if (body === null || typeof body !== "object") return void 0;
|
|
129
|
+
const reason = body.reason;
|
|
130
|
+
return typeof reason === "string" ? reason : void 0;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
exports.FacilitatorHttpError = FacilitatorHttpError;
|
|
134
|
+
exports.createFacilitatorClient = createFacilitatorClient;
|
|
135
|
+
//# sourceMappingURL=index.js.map
|
|
136
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/facilitator/errors.ts","../../../src/facilitator/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Typed error class for HTTP-level facilitator failures. Distinct from\n// the `{ ok: false, code }` shape the facilitator itself returns —\n// those are domain errors and surface in the typed result. This class\n// is thrown only when the HTTP transport fails (network error,\n// non-2xx response with an unparseable body, etc.).\n\nimport type { FacilitatorErrorCode } from \"@bosonprotocol/x402-facilitator\";\n\n/**\n * Stable, x402-server-side codes for HTTP-transport failures.\n * Distinct from the facilitator-side `FacilitatorErrorCode` enum so\n * callers can branch on \"the facilitator answered with X\" vs \"we\n * never reached the facilitator\".\n */\nexport type FacilitatorHttpErrorCode =\n | \"NETWORK_ERROR\"\n | \"BAD_HTTP_STATUS\"\n | \"BAD_RESPONSE_BODY\"\n | \"TIMEOUT\";\n\n/** Network- or transport-layer failure when calling the facilitator. */\nexport class FacilitatorHttpError extends Error {\n readonly code: FacilitatorHttpErrorCode;\n readonly status?: number;\n /** Original facilitator-side error code, if the body parsed cleanly. */\n readonly facilitatorCode?: FacilitatorErrorCode;\n\n constructor(\n message: string,\n init: {\n code: FacilitatorHttpErrorCode;\n status?: number;\n facilitatorCode?: FacilitatorErrorCode;\n cause?: unknown;\n },\n ) {\n super(message, init.cause !== undefined ? { cause: init.cause } : undefined);\n this.name = \"FacilitatorHttpError\";\n this.code = init.code;\n if (init.status !== undefined) this.status = init.status;\n if (init.facilitatorCode !== undefined) this.facilitatorCode = init.facilitatorCode;\n }\n}\n","// HTTP client for the Boson facilitator service. The facilitator runs\n// as a remote process implementing the three endpoints in\n// docs/boson-impl-07-facilitator.md (`/verify`, `/settle`,\n// `/perform-action?action=<action>`); this module wraps `fetch` with the typed\n// request/response shapes exported by `@bosonprotocol/x402-facilitator`.\n//\n// Domain results (`{ ok: true, ... }` or `{ ok: false, code, reason }`)\n// are returned verbatim — both shapes are answers the caller branches\n// on. The facilitator-express adapter emits domain failures over HTTP\n// 400 (so curl users still see a 4xx), but the wire body is still a\n// well-formed result; we recognise that shape on HTTP 400 responses and\n// hand it back rather than throwing. HTTP-transport failures (network\n// down, non-JSON body, schema-mismatched body) throw\n// `FacilitatorHttpError` so the composition layer can distinguish\n// \"facilitator said no\" from \"we couldn't reach the facilitator\".\n\nimport type {\n FacilitatorErrorCode,\n FacilitatorPerformActionInput,\n FacilitatorPerformActionResult,\n FacilitatorSettleInput,\n FacilitatorSettleResult,\n FacilitatorVerifyInput,\n FacilitatorVerifyResult,\n} from \"@bosonprotocol/x402-facilitator\";\n\nimport { FacilitatorHttpError } from \"./errors.js\";\n\nexport type FetchLike = (\n input: string,\n init?: { method?: string; headers?: Record<string, string>; body?: string },\n) => Promise<{\n ok: boolean;\n status: number;\n text: () => Promise<string>;\n json?: () => Promise<unknown>;\n}>;\n\nexport interface CreateFacilitatorClientOptions {\n /** Base URL of the facilitator service (no trailing slash needed). */\n url: string;\n /** Optional `fetch` override — defaults to the global `fetch`. Useful for tests + non-`fetch` runtimes. */\n fetch?: FetchLike;\n /** Optional headers attached to every request — e.g. an `Authorization` for hosted facilitators. */\n headers?: Record<string, string>;\n}\n\nexport interface FacilitatorClient {\n verify(input: FacilitatorVerifyInput): Promise<FacilitatorVerifyResult>;\n settle(input: FacilitatorSettleInput): Promise<FacilitatorSettleResult>;\n performAction(input: FacilitatorPerformActionInput): Promise<FacilitatorPerformActionResult>;\n}\n\n/**\n * Construct a typed HTTP client for the facilitator. The returned\n * methods stringify the input as JSON and POST to the matching path\n * on the configured URL. Bodies matching the well-formed result shape\n * (whether HTTP 2xx success or HTTP 400 domain rejection) are returned\n * verbatim; transport failures (network, non-JSON body,\n * schema-mismatched body) raise `FacilitatorHttpError`.\n */\nexport function createFacilitatorClient(opts: CreateFacilitatorClientOptions): FacilitatorClient {\n const fetchImpl = opts.fetch ?? (globalThis.fetch as FetchLike | undefined);\n if (fetchImpl === undefined) {\n throw new Error(\n \"createFacilitatorClient: no `fetch` implementation available. Pass `opts.fetch` explicitly.\",\n );\n }\n const baseUrl = opts.url.replace(/\\/+$/, \"\");\n const baseHeaders = { \"content-type\": \"application/json\", ...(opts.headers ?? {}) };\n\n const post = async <Req, Res>(\n path: string,\n body: Req,\n validate: (parsed: unknown) => parsed is Res,\n ): Promise<Res> => {\n let res: Awaited<ReturnType<FetchLike>>;\n try {\n res = await fetchImpl(`${baseUrl}${path}`, {\n method: \"POST\",\n headers: baseHeaders,\n body: JSON.stringify(body),\n });\n } catch (cause) {\n throw new FacilitatorHttpError(`facilitator network error (${path})`, {\n code: \"NETWORK_ERROR\",\n cause,\n });\n }\n\n let text: string;\n try {\n text = await res.text();\n } catch (cause) {\n throw new FacilitatorHttpError(`facilitator response body could not be read (${path})`, {\n code: \"BAD_RESPONSE_BODY\",\n status: res.status,\n cause,\n });\n }\n\n let parsed: unknown;\n try {\n parsed = text.length === 0 ? null : JSON.parse(text);\n } catch (cause) {\n throw new FacilitatorHttpError(`facilitator returned non-JSON body (${path})`, {\n code: \"BAD_RESPONSE_BODY\",\n status: res.status,\n cause,\n });\n }\n\n if (!res.ok) {\n // The facilitator-express adapter returns domain failures as\n // HTTP 400 with the `{ok:false, code, reason}` body. Detect that\n // shape and surface it as the typed result — every endpoint's\n // `Res` union includes the same `{ok:false, code, reason}`\n // variant, so the cast through `validate` (which also accepts\n // that shape) preserves type-safety. Any other non-2xx status is\n // a genuine transport failure even if its body happens to look\n // like a facilitator result.\n if (res.status === 400 && isFailureBranch(parsed) && validate(parsed)) {\n return parsed;\n }\n const facilitatorCode = extractFacilitatorCode(parsed);\n throw new FacilitatorHttpError(\n `facilitator HTTP ${res.status} (${path}): ${reasonString(parsed) ?? text}`,\n {\n code: \"BAD_HTTP_STATUS\",\n status: res.status,\n ...(facilitatorCode !== undefined ? { facilitatorCode } : {}),\n },\n );\n }\n\n if (!validate(parsed)) {\n throw new FacilitatorHttpError(`facilitator returned unexpected body shape (${path})`, {\n code: \"BAD_RESPONSE_BODY\",\n status: res.status,\n });\n }\n return parsed;\n };\n\n return {\n verify: (input) =>\n post<FacilitatorVerifyInput, FacilitatorVerifyResult>(\"/verify\", input, isVerifyResult),\n settle: (input) =>\n post<FacilitatorSettleInput, FacilitatorSettleResult>(\"/settle\", input, isSettleResult),\n performAction: (input) =>\n post<FacilitatorPerformActionInput, FacilitatorPerformActionResult>(\n `/perform-action?action=${encodeURIComponent(input.action)}`,\n input,\n isPerformActionResult,\n ),\n };\n}\n\n// --- Response-shape type guards ----------------------------------------\n//\n// A buggy or malicious facilitator could return any 2xx JSON; without a\n// runtime check, `parsed as Res` would silently slip an unexpected shape\n// past the type system and the convenience handlers (PR 4) would\n// dereference fields that aren't there. These guards mirror the\n// discriminated unions in `@bosonprotocol/x402-facilitator`'s types and\n// fail any response that doesn't fit — surfaced as\n// `BAD_RESPONSE_BODY` so the caller treats it as a transport-layer\n// failure rather than a domain answer.\n\nfunction isObject(v: unknown): v is Record<string, unknown> {\n return v !== null && typeof v === \"object\";\n}\n\n/**\n * Failure branch is identical across all three endpoints. Accepts\n * `unknown` so the non-2xx path can pre-check the parsed body without\n * narrowing first.\n */\nfunction isFailureBranch(v: unknown): v is { ok: false; code: string; reason: string } {\n return (\n isObject(v) && v.ok === false && typeof v.code === \"string\" && typeof v.reason === \"string\"\n );\n}\n\nfunction isVerifyResult(parsed: unknown): parsed is FacilitatorVerifyResult {\n if (!isObject(parsed)) return false;\n if (parsed.ok === true) return true; // `{ ok: true }` carries no further fields\n return isFailureBranch(parsed);\n}\n\nfunction isSettleResult(parsed: unknown): parsed is FacilitatorSettleResult {\n if (!isObject(parsed)) return false;\n if (parsed.ok === true) {\n return typeof parsed.exchangeId === \"string\" && typeof parsed.txHash === \"string\";\n }\n return isFailureBranch(parsed);\n}\n\nfunction isPerformActionResult(parsed: unknown): parsed is FacilitatorPerformActionResult {\n if (!isObject(parsed)) return false;\n if (parsed.ok === true) {\n if (typeof parsed.txHash !== \"string\") return false;\n // Entity-keyed actions (e.g. `boson-withdrawFunds`) return just\n // `{ ok: true, txHash }` — no exchange state transition. Accept\n // that shape; only require `newExchangeState` when present.\n if (parsed.newExchangeState !== undefined && typeof parsed.newExchangeState !== \"string\") {\n return false;\n }\n if (parsed.newDisputeState !== undefined && typeof parsed.newDisputeState !== \"string\") {\n return false;\n }\n return true;\n }\n return isFailureBranch(parsed);\n}\n\nfunction extractFacilitatorCode(body: unknown): FacilitatorErrorCode | undefined {\n if (body === null || typeof body !== \"object\") return undefined;\n const code = (body as { code?: unknown }).code;\n return typeof code === \"string\" ? (code as FacilitatorErrorCode) : undefined;\n}\n\nfunction reasonString(body: unknown): string | undefined {\n if (body === null || typeof body !== \"object\") return undefined;\n const reason = (body as { reason?: unknown }).reason;\n return typeof reason === \"string\" ? reason : undefined;\n}\n"]}
|