@weftlabs/sdk 0.25.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/README.md +499 -0
- package/dist/client-C9_zh3Qg.d.mts +11 -0
- package/dist/client-C9_zh3Qg.d.ts +11 -0
- package/dist/facilitator/index.d.mts +18 -0
- package/dist/facilitator/index.d.ts +18 -0
- package/dist/facilitator/index.js +180 -0
- package/dist/facilitator/index.js.map +1 -0
- package/dist/facilitator/index.mjs +149 -0
- package/dist/facilitator/index.mjs.map +1 -0
- package/dist/facilitator/middleware/index.d.mts +539 -0
- package/dist/facilitator/middleware/index.d.ts +539 -0
- package/dist/facilitator/middleware/index.js +1522 -0
- package/dist/facilitator/middleware/index.js.map +1 -0
- package/dist/facilitator/middleware/index.mjs +1493 -0
- package/dist/facilitator/middleware/index.mjs.map +1 -0
- package/dist/index.d.mts +5667 -0
- package/dist/index.d.ts +5667 -0
- package/dist/index.js +5555 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +5553 -0
- package/dist/index.mjs.map +1 -0
- package/dist/server.d.mts +8 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.js +1587 -0
- package/dist/server.js.map +1 -0
- package/dist/server.mjs +1574 -0
- package/dist/server.mjs.map +1 -0
- package/docs/APIKeysApi.md +219 -0
- package/docs/AccountApi.md +72 -0
- package/docs/AccountBootstrapApproval.md +36 -0
- package/docs/AccountBootstrapCreated.md +44 -0
- package/docs/AccountBootstrapCreatedApproval.md +38 -0
- package/docs/AccountBootstrapCreatedResponse.md +32 -0
- package/docs/AccountBootstrapRequest.md +42 -0
- package/docs/AccountBootstrapStatus.md +40 -0
- package/docs/AccountBootstrapStatusResponse.md +32 -0
- package/docs/AccountDetails.md +43 -0
- package/docs/AgentBootstrapApi.md +223 -0
- package/docs/ApiKey.md +42 -0
- package/docs/ApiKeyCreated.md +40 -0
- package/docs/ApiKeyCreatedResponse.md +32 -0
- package/docs/ApiKeyListResponse.md +34 -0
- package/docs/AuthApi.md +408 -0
- package/docs/AuthResponse.md +32 -0
- package/docs/AuthResponseData.md +36 -0
- package/docs/BalanceApi.md +73 -0
- package/docs/BalanceResponse.md +45 -0
- package/docs/ConfirmRequest.md +32 -0
- package/docs/CreateApiKeyRequest.md +32 -0
- package/docs/DocumentationApi.md +65 -0
- package/docs/EnrolledResource.md +59 -0
- package/docs/ErrorResponse.md +33 -0
- package/docs/Fetch403Response.md +44 -0
- package/docs/FetchApi.md +91 -0
- package/docs/FetchBalanceSnapshot.md +41 -0
- package/docs/FetchErrorResponse.md +41 -0
- package/docs/FetchRequest.md +46 -0
- package/docs/FetchRequestBody.md +31 -0
- package/docs/FetchResponse.md +49 -0
- package/docs/InsufficientScopeResponse.md +37 -0
- package/docs/MeApiKey.md +40 -0
- package/docs/MeApiKeyCreator.md +37 -0
- package/docs/MeResponse.md +32 -0
- package/docs/MeResponseData.md +56 -0
- package/docs/MessageResponse.md +32 -0
- package/docs/MessageResponseData.md +32 -0
- package/docs/ModelError.md +39 -0
- package/docs/Pagination.md +38 -0
- package/docs/PasswordResetRequest.md +32 -0
- package/docs/PasswordUpdateRequest.md +36 -0
- package/docs/Payment.md +56 -0
- package/docs/PaymentListResponse.md +34 -0
- package/docs/PaymentResponse.md +32 -0
- package/docs/PaymentsApi.md +154 -0
- package/docs/PrincipalWallet.md +34 -0
- package/docs/PromoBalance.md +37 -0
- package/docs/Purchase.md +58 -0
- package/docs/PurchaseArtifact.md +38 -0
- package/docs/PurchaseListResponse.md +34 -0
- package/docs/PurchaseResponse.md +32 -0
- package/docs/PurchasesApi.md +157 -0
- package/docs/RateLimitResponse.md +34 -0
- package/docs/ResendConfirmationRequest.md +32 -0
- package/docs/ResourceEnrollmentRequest.md +39 -0
- package/docs/ResourceEnrollmentResponse.md +32 -0
- package/docs/ResourceStats.md +45 -0
- package/docs/ResourcesApi.md +77 -0
- package/docs/SearchAccessMethod.md +52 -0
- package/docs/SearchApi.md +86 -0
- package/docs/SearchCapabilityRef.md +34 -0
- package/docs/SearchCuratedCallability.md +34 -0
- package/docs/SearchCuratedExecution.md +32 -0
- package/docs/SearchCuratedOperation.md +36 -0
- package/docs/SearchCuratedService.md +34 -0
- package/docs/SearchCuratedSource.md +36 -0
- package/docs/SearchEndpointCall.md +39 -0
- package/docs/SearchEndpointHit.md +74 -0
- package/docs/SearchEndpointPrice.md +41 -0
- package/docs/SearchErrorResponse.md +35 -0
- package/docs/SearchExecutionModeFilter.md +34 -0
- package/docs/SearchFilterSpec.md +49 -0
- package/docs/SearchMethodFilter.md +34 -0
- package/docs/SearchPaymentOffer.md +47 -0
- package/docs/SearchPriceAtomicFilter.md +41 -0
- package/docs/SearchPriceUsdFilter.md +41 -0
- package/docs/SearchProtocolFilter.md +35 -0
- package/docs/SearchProviderRef.md +36 -0
- package/docs/SearchRequest.md +36 -0
- package/docs/SearchResourceTypeFilter.md +35 -0
- package/docs/SearchResponse.md +67 -0
- package/docs/SearchResponseWarningsInner.md +38 -0
- package/docs/SearchResult.md +38 -0
- package/docs/SearchStringSetFilter.md +34 -0
- package/docs/SearchWeftFetchCompatibility.md +36 -0
- package/docs/SignInRequest.md +34 -0
- package/docs/SignUpRequest.md +36 -0
- package/docs/SpendingPolicy.md +36 -0
- package/docs/User.md +36 -0
- package/docs/UserPrincipal.md +49 -0
- package/docs/Wallet.md +42 -0
- package/examples/charge-api-hono.mjs +40 -0
- package/examples/charge-api.mjs +43 -0
- package/examples/quickstart.mjs +16 -0
- package/package.json +105 -0
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
import { OutgoingHttpHeaders } from 'node:http';
|
|
2
|
+
import { RouteConfig, RoutesConfig, HTTPRequestContext, CompletedSettlement, PaymentCancellationDispatcher, PaywallConfig, PaywallProvider, x402ResourceServer } from '@x402/core/server';
|
|
3
|
+
export { PaywallConfig, PaywallProvider, RouteConfig, RoutesConfig } from '@x402/core/server';
|
|
4
|
+
import { PaymentPayload, PaymentRequirements, Network, SchemeNetworkServer } from '@x402/core/types';
|
|
5
|
+
export { Network, SchemeNetworkServer } from '@x402/core/types';
|
|
6
|
+
import { W as WeftFacilitatorConfig } from '../../client-C9_zh3Qg.mjs';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* What kind of thing the seller is selling.
|
|
10
|
+
*
|
|
11
|
+
* Deliberately small. If you need a kind that is not here, use `tags`.
|
|
12
|
+
*/
|
|
13
|
+
type WeftProductType = "api" | "agent" | "mcp";
|
|
14
|
+
/**
|
|
15
|
+
* Reserved tag prefix that carries {@link WeftProductIdentity.type} on the wire.
|
|
16
|
+
*
|
|
17
|
+
* `ResourceInfo` in the x402 protocol has no field for a product kind, and the
|
|
18
|
+
* facilitator only relays `serviceName`, `tags` and `iconUrl` to the settlement
|
|
19
|
+
* event. `tags` is therefore the only channel a product type can travel in, so
|
|
20
|
+
* the SDK encodes it as one reserved tag — `weft:type:api`, `weft:type:agent`,
|
|
21
|
+
* `weft:type:mcp`.
|
|
22
|
+
*
|
|
23
|
+
* The prefix is namespaced so it cannot collide with a seller's own free-text
|
|
24
|
+
* tags, stays readable in a raw settlement row, and is matched downstream with
|
|
25
|
+
* a plain `startsWith`. The SDK guarantees at most one such tag per route: any
|
|
26
|
+
* `weft:type:*` value a caller puts in `tags` is dropped with a warning, in
|
|
27
|
+
* favour of the `type` field on the product or on the route.
|
|
28
|
+
*/
|
|
29
|
+
declare const WEFT_TYPE_TAG_PREFIX = "weft:type:";
|
|
30
|
+
/**
|
|
31
|
+
* Product-level identity, declared once and applied to every protected route.
|
|
32
|
+
*
|
|
33
|
+
* This is what turns a settlement into a named product in the Weft dashboard.
|
|
34
|
+
* Every field is optional; a middleware configured without any of them behaves
|
|
35
|
+
* exactly as it did before this identity existed.
|
|
36
|
+
*
|
|
37
|
+
* Every field is also validated at construction time, because these values
|
|
38
|
+
* routinely come from JSON or env and TypeScript is not present at runtime.
|
|
39
|
+
* Anything the x402 protocol cannot carry is clamped or dropped, with one
|
|
40
|
+
* `[weft]` line explaining what shipped — never a thrown error in a payment
|
|
41
|
+
* server's boot path, and never a malformed challenge on the wire.
|
|
42
|
+
*/
|
|
43
|
+
interface WeftProductIdentity {
|
|
44
|
+
/**
|
|
45
|
+
* Display name of the product, e.g. `"Acme Pricing API"`.
|
|
46
|
+
*
|
|
47
|
+
* Travels as `ResourceInfo.serviceName` on the 402 challenge. The protocol
|
|
48
|
+
* carries 32 printable-ASCII characters; a longer name is truncated to fit,
|
|
49
|
+
* with a warning naming both values.
|
|
50
|
+
*/
|
|
51
|
+
name?: string;
|
|
52
|
+
/**
|
|
53
|
+
* What kind of product this is.
|
|
54
|
+
*
|
|
55
|
+
* Travels as a reserved `weft:type:<type>` tag — see {@link WEFT_TYPE_TAG_PREFIX}.
|
|
56
|
+
* A route may declare its own `type`, which wins for that route.
|
|
57
|
+
*/
|
|
58
|
+
type?: WeftProductType;
|
|
59
|
+
/**
|
|
60
|
+
* Free-text tags describing the product, e.g. `["finance", "pricing"]`.
|
|
61
|
+
*
|
|
62
|
+
* Travels as `ResourceInfo.tags`. Tags starting with `weft:type:` are
|
|
63
|
+
* reserved and are dropped in favour of {@link WeftProductIdentity.type}.
|
|
64
|
+
*
|
|
65
|
+
* The x402 protocol allows five tags of at most 32 printable-ASCII
|
|
66
|
+
* characters. A declared `type` uses one slot, so four remain. Anything
|
|
67
|
+
* beyond that is dropped with a warning rather than being put on the wire,
|
|
68
|
+
* because an out-of-bounds array costs the seller every tag they declared.
|
|
69
|
+
*/
|
|
70
|
+
tags?: string[];
|
|
71
|
+
/**
|
|
72
|
+
* Absolute `http:` or `https:` URL of an icon for the product.
|
|
73
|
+
*
|
|
74
|
+
* Travels as `ResourceInfo.iconUrl`. A dashboard renders this URL, so any
|
|
75
|
+
* other scheme is dropped with a warning.
|
|
76
|
+
*/
|
|
77
|
+
iconUrl?: string;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Extension key under which the product declaration travels on the wire.
|
|
81
|
+
*
|
|
82
|
+
* Unlike the identity fields, which ride `ResourceInfo`, the product
|
|
83
|
+
* declaration rides x402 v2 `extensions`: declared by the server on the 402
|
|
84
|
+
* challenge, echoed by the buyer's client onto `PaymentPayload`, validated
|
|
85
|
+
* against the advertisement at verify time, and relayed by the facilitator on
|
|
86
|
+
* the settlement event.
|
|
87
|
+
*/
|
|
88
|
+
declare const WEFT_PRODUCT_EXTENSION_KEY = "weft.product";
|
|
89
|
+
/**
|
|
90
|
+
* JSON Schema (Draft 2020-12) for the `weft.product` extension's `info`.
|
|
91
|
+
*
|
|
92
|
+
* Ships verbatim as the extension's `schema` member, per the x402 v2
|
|
93
|
+
* extensions shape `{info, schema}`. Every field is optional because absent
|
|
94
|
+
* declarations are omitted from `info` rather than sent empty.
|
|
95
|
+
*
|
|
96
|
+
* `additionalProperties: false` is a **published contract statement, not an
|
|
97
|
+
* enforcement**. Upstream's echo check is a subset match — advertised `info`
|
|
98
|
+
* fields must be preserved, but a buyer may *add* fields to the echoed
|
|
99
|
+
* `info` and pass, and when a route advertises no extensions the check never
|
|
100
|
+
* runs. So an echoed `weft.product` proves nothing about fields the seller
|
|
101
|
+
* did not advertise: by the time it reaches a consumer it is unauthenticated
|
|
102
|
+
* buyer input. A buyer has no legitimate reason to add fields to a seller
|
|
103
|
+
* claim, and this flag is the declared basis for consumers to strip
|
|
104
|
+
* anything unadvertised — but the stripping, and the deeper rule, are the
|
|
105
|
+
* consumer's job. Attribution must never key on echoed extension contents;
|
|
106
|
+
* it keys on seller-authenticated joins — the API key that settled the
|
|
107
|
+
* payment (weft-app #635 freezes `payments.product_id` from exactly that at
|
|
108
|
+
* settlement time) or the S1 handshake's authenticated declaration.
|
|
109
|
+
*/
|
|
110
|
+
declare const WEFT_PRODUCT_INFO_SCHEMA: {
|
|
111
|
+
readonly $schema: "https://json-schema.org/draft/2020-12/schema";
|
|
112
|
+
readonly type: "object";
|
|
113
|
+
readonly properties: {
|
|
114
|
+
readonly kind: {
|
|
115
|
+
readonly type: "string";
|
|
116
|
+
readonly enum: readonly string[];
|
|
117
|
+
};
|
|
118
|
+
readonly product_id: {
|
|
119
|
+
readonly type: "string";
|
|
120
|
+
readonly minLength: 1;
|
|
121
|
+
};
|
|
122
|
+
readonly manifest_hash: {
|
|
123
|
+
readonly type: "string";
|
|
124
|
+
readonly minLength: 1;
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
readonly additionalProperties: false;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Product-level declaration: the identity plus the product reference fields.
|
|
131
|
+
*
|
|
132
|
+
* `productId` and `manifestHash` are not cosmetic identity — they are the
|
|
133
|
+
* seller's claim about *which* dashboard product this deployment is and what
|
|
134
|
+
* manifest it was built from. They travel in the `weft.product` extension,
|
|
135
|
+
* never in `ResourceInfo`, so they extend the identity type rather than
|
|
136
|
+
* joining it.
|
|
137
|
+
*/
|
|
138
|
+
interface WeftProductDeclaration extends WeftProductIdentity {
|
|
139
|
+
/**
|
|
140
|
+
* Identifier of the dashboard product this deployment claims to be.
|
|
141
|
+
*
|
|
142
|
+
* Travels as `extensions["weft.product"].info.product_id` on the 402
|
|
143
|
+
* challenge and, echoed by the buyer, on the payment payload the
|
|
144
|
+
* facilitator settles.
|
|
145
|
+
*/
|
|
146
|
+
productId?: string;
|
|
147
|
+
/**
|
|
148
|
+
* Hash of the product manifest this deployment was built from.
|
|
149
|
+
*
|
|
150
|
+
* Travels as `extensions["weft.product"].info.manifest_hash`, next to
|
|
151
|
+
* {@link WeftProductDeclaration.productId}. Opaque to the SDK: no format is
|
|
152
|
+
* enforced beyond being a non-empty string.
|
|
153
|
+
*/
|
|
154
|
+
manifestHash?: string;
|
|
155
|
+
/**
|
|
156
|
+
* Field names inside `weft.request` that revenue may be broken down by,
|
|
157
|
+
* e.g. `["model", "tier"]`.
|
|
158
|
+
*
|
|
159
|
+
* Travels only on the authenticated boot handshake — never on the 402
|
|
160
|
+
* challenge, never in `weft.product`. That is the point of it: the values
|
|
161
|
+
* on a payment are buyer-echoed, so an aggregate summing an *undeclared*
|
|
162
|
+
* key would be summing buyer-controlled input. A field declared here is
|
|
163
|
+
* one the seller vouched for under their own API key, which is what makes
|
|
164
|
+
* "revenue for model=gpt-5.6 this month" an answer rather than a guess.
|
|
165
|
+
*
|
|
166
|
+
* Declare dimensions, not payloads. Low cardinality, enumerable: `model`,
|
|
167
|
+
* `tier`, `size`, `region`. Never prompt text, a user id or a document
|
|
168
|
+
* body — those blow up the index, leak content, and are useless as a
|
|
169
|
+
* breakdown anyway.
|
|
170
|
+
*/
|
|
171
|
+
dimensions?: string[];
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* A route config that may also declare the product kind for that route alone.
|
|
175
|
+
*
|
|
176
|
+
* `RouteConfig` comes from `@x402/core` and has no field for a product kind.
|
|
177
|
+
* A seller whose surface is part API and part MCP needs to say so per route,
|
|
178
|
+
* so the SDK accepts `type` here, consumes it into the reserved tag, and never
|
|
179
|
+
* passes the field itself down to the resource server.
|
|
180
|
+
*
|
|
181
|
+
* The inherited `extensions` map gains one capability here: any value may be a
|
|
182
|
+
* `WeftDynamicExtension` callback instead of a static object, resolved per
|
|
183
|
+
* request at the same point as `price`. The field is already typed
|
|
184
|
+
* `Record<string, unknown>` upstream, so this needs no wider type — only the
|
|
185
|
+
* middleware registering the resolver for those keys.
|
|
186
|
+
*/
|
|
187
|
+
interface WeftRouteConfig extends RouteConfig {
|
|
188
|
+
/** Product kind for this route; overrides {@link WeftProductIdentity.type}. */
|
|
189
|
+
type?: WeftProductType;
|
|
190
|
+
}
|
|
191
|
+
/** {@link RoutesConfig}, with per-route {@link WeftRouteConfig.type} allowed. */
|
|
192
|
+
type WeftRoutesConfig = Record<string, WeftRouteConfig> | WeftRouteConfig;
|
|
193
|
+
/**
|
|
194
|
+
* Build the reserved tag for a product type.
|
|
195
|
+
*
|
|
196
|
+
* @param type - The product type to encode
|
|
197
|
+
* @returns The reserved tag, e.g. `weft:type:api`
|
|
198
|
+
*/
|
|
199
|
+
declare function productTypeTag(type: WeftProductType): string;
|
|
200
|
+
/**
|
|
201
|
+
* Merge product-level identity into every protected route.
|
|
202
|
+
*
|
|
203
|
+
* A per-route value always wins over the product-level default, so a seller
|
|
204
|
+
* who names one route individually keeps that name. Fields nobody declared
|
|
205
|
+
* stay absent from the 402 challenge rather than being sent empty.
|
|
206
|
+
*
|
|
207
|
+
* Every value this produces is inside the bounds `ResourceInfoSchema` declares,
|
|
208
|
+
* so the challenge the middleware emits parses for any buyer that validates.
|
|
209
|
+
* Values that cannot be made to fit are clamped or dropped, each with one
|
|
210
|
+
* `[weft]` line at construction time.
|
|
211
|
+
*
|
|
212
|
+
* A config that declares no Weft identity at all — neither on the middleware
|
|
213
|
+
* nor on a route — is returned by reference, exactly as the caller wrote it.
|
|
214
|
+
* That is the pre-identity behaviour, kept deliberately: with nothing of ours
|
|
215
|
+
* on the routes, what the seller puts in a `RouteConfig` is between them and
|
|
216
|
+
* `@x402/core`.
|
|
217
|
+
*
|
|
218
|
+
* @param routes - Route configuration passed by the caller
|
|
219
|
+
* @param identity - Product-level declaration from the middleware config
|
|
220
|
+
* @returns Route configuration with identity applied; the input is never mutated
|
|
221
|
+
*/
|
|
222
|
+
declare function applyProductIdentity(routes: WeftRoutesConfig, identity: WeftProductDeclaration): RoutesConfig;
|
|
223
|
+
|
|
224
|
+
/** A structurally valid, but not cryptographically verified, v2 payment. */
|
|
225
|
+
interface PaymentResumeCandidate {
|
|
226
|
+
paymentPayload: PaymentPayload;
|
|
227
|
+
paymentRequirements: PaymentRequirements;
|
|
228
|
+
}
|
|
229
|
+
/** Verified payment inputs restored from durable application storage. */
|
|
230
|
+
interface VerifiedPaymentResume {
|
|
231
|
+
paymentPayload: PaymentPayload;
|
|
232
|
+
paymentRequirements: PaymentRequirements;
|
|
233
|
+
declaredExtensions?: Record<string, unknown>;
|
|
234
|
+
/** Restore this receipt when Core settled before the original handler. */
|
|
235
|
+
beforeHandlerSettlement?: CompletedSettlement;
|
|
236
|
+
/** Restore Core's cancellation state for a before-handler settlement. */
|
|
237
|
+
cancellationDispatcher?: PaymentCancellationDispatcher;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Restore a previously verified payment for settlement replay.
|
|
241
|
+
*
|
|
242
|
+
* This callback is a trust boundary. The caller must durably bind its result to
|
|
243
|
+
* the exact signed payment payload and request fingerprint. The SDK does not
|
|
244
|
+
* authenticate or validate callback output before settlement.
|
|
245
|
+
*/
|
|
246
|
+
type ResumeVerifiedPayment = (context: HTTPRequestContext, candidate: PaymentResumeCandidate) => VerifiedPaymentResume | undefined | Promise<VerifiedPaymentResume | undefined>;
|
|
247
|
+
|
|
248
|
+
interface ExpressRequest {
|
|
249
|
+
method: string;
|
|
250
|
+
path: string;
|
|
251
|
+
protocol: string;
|
|
252
|
+
headers: Record<string, string | string[] | undefined>;
|
|
253
|
+
query: Record<string, string | string[] | undefined>;
|
|
254
|
+
body?: unknown;
|
|
255
|
+
header(name: string): string | string[] | undefined;
|
|
256
|
+
}
|
|
257
|
+
interface ExpressResponse {
|
|
258
|
+
status(code: number): ExpressResponse;
|
|
259
|
+
setHeader(name: string, value: string | number | readonly string[]): ExpressResponse;
|
|
260
|
+
/**
|
|
261
|
+
* Headers the route handler has set. Read at settlement time so a
|
|
262
|
+
* `Settlement-Overrides` header reaches the facilitator.
|
|
263
|
+
*/
|
|
264
|
+
getHeaders(): OutgoingHttpHeaders;
|
|
265
|
+
removeHeader(name: string): void;
|
|
266
|
+
send(body: unknown): ExpressResponse;
|
|
267
|
+
json(body: unknown): ExpressResponse;
|
|
268
|
+
statusCode: number;
|
|
269
|
+
writeHead: (...args: unknown[]) => ExpressResponse;
|
|
270
|
+
write: (...args: unknown[]) => boolean;
|
|
271
|
+
end: (...args: unknown[]) => ExpressResponse;
|
|
272
|
+
flushHeaders: () => void;
|
|
273
|
+
}
|
|
274
|
+
type ExpressNextFunction = (err?: unknown) => void;
|
|
275
|
+
type ExpressMiddleware = (req: ExpressRequest, res: ExpressResponse, next: ExpressNextFunction) => Promise<void> | void;
|
|
276
|
+
interface SchemeRegistration$1 {
|
|
277
|
+
network: Network;
|
|
278
|
+
server: SchemeNetworkServer;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Configuration for the Express payment middleware.
|
|
282
|
+
*
|
|
283
|
+
* Extends {@link WeftProductDeclaration}, so `name`, `type`, `tags`,
|
|
284
|
+
* `iconUrl`, `productId` and `manifestHash` are declared once here and
|
|
285
|
+
* applied to every protected route.
|
|
286
|
+
*/
|
|
287
|
+
interface WeftExpressMiddlewareConfig extends WeftProductDeclaration {
|
|
288
|
+
/**
|
|
289
|
+
* The seller's Weft API key.
|
|
290
|
+
*
|
|
291
|
+
* Authenticates the facilitator calls that need it: `X-API-Key` on
|
|
292
|
+
* `/settle` — which the facilitator requires, or every settlement 401s —
|
|
293
|
+
* and `Authorization: Bearer <key>` on the construction-time `/supported`
|
|
294
|
+
* handshake, which is how the dashboard learns an SDK is deployed before
|
|
295
|
+
* any payment. Optional, but a seller who omits it must supply their own
|
|
296
|
+
* `facilitator.createAuthHeaders` or settlement fails.
|
|
297
|
+
*/
|
|
298
|
+
apiKey?: string;
|
|
299
|
+
facilitator?: WeftFacilitatorConfig;
|
|
300
|
+
schemes?: SchemeRegistration$1[];
|
|
301
|
+
paywallConfig?: PaywallConfig;
|
|
302
|
+
paywall?: PaywallProvider;
|
|
303
|
+
syncFacilitatorOnStart?: boolean;
|
|
304
|
+
/** Restore durably bound verified inputs for settlement replay. */
|
|
305
|
+
resumeVerifiedPayment?: ResumeVerifiedPayment;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Create an Express middleware that requires x402 payment for the given routes.
|
|
309
|
+
*
|
|
310
|
+
* Product identity declared on `config` (`name`, `type`, `tags`, `iconUrl`) is
|
|
311
|
+
* merged into every route, so it travels on the 402 challenge's `resource` and
|
|
312
|
+
* from there onto the buyer's payment payload and the settlement event.
|
|
313
|
+
*
|
|
314
|
+
* @param routes - Route configuration, either a path map or a single route;
|
|
315
|
+
* each route may declare its own `type` to override the product's
|
|
316
|
+
* @param config - Facilitator, scheme, paywall and product identity settings
|
|
317
|
+
* @returns An Express middleware function
|
|
318
|
+
*/
|
|
319
|
+
declare function weftPaymentMiddleware(routes: WeftRoutesConfig, config?: WeftExpressMiddlewareConfig): ExpressMiddleware;
|
|
320
|
+
|
|
321
|
+
interface HonoRequest {
|
|
322
|
+
method: string;
|
|
323
|
+
path: string;
|
|
324
|
+
url: string;
|
|
325
|
+
header(name: string): string | undefined;
|
|
326
|
+
query(): Record<string, string>;
|
|
327
|
+
query(name: string): string | undefined;
|
|
328
|
+
json(): Promise<unknown>;
|
|
329
|
+
}
|
|
330
|
+
interface HonoContext {
|
|
331
|
+
req: HonoRequest;
|
|
332
|
+
res: Response | undefined;
|
|
333
|
+
error?: Error;
|
|
334
|
+
header(name: string, value: string | undefined, options?: {
|
|
335
|
+
append?: boolean;
|
|
336
|
+
}): void;
|
|
337
|
+
html(body: string, status?: number): Response;
|
|
338
|
+
json(body: unknown, status?: number): Response;
|
|
339
|
+
}
|
|
340
|
+
type HonoMiddleware = (c: HonoContext, next: () => Promise<void>) => Promise<Response | void>;
|
|
341
|
+
interface SchemeRegistration {
|
|
342
|
+
network: Network;
|
|
343
|
+
server: SchemeNetworkServer;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Configuration for the Hono payment middleware.
|
|
347
|
+
*
|
|
348
|
+
* Extends {@link WeftProductDeclaration}, so `name`, `type`, `tags`,
|
|
349
|
+
* `iconUrl`, `productId` and `manifestHash` are declared once here and
|
|
350
|
+
* applied to every protected route.
|
|
351
|
+
*/
|
|
352
|
+
interface WeftHonoMiddlewareConfig extends WeftProductDeclaration {
|
|
353
|
+
/**
|
|
354
|
+
* The seller's Weft API key.
|
|
355
|
+
*
|
|
356
|
+
* Authenticates the facilitator calls that need it: `X-API-Key` on
|
|
357
|
+
* `/settle` — which the facilitator requires, or every settlement 401s —
|
|
358
|
+
* and `Authorization: Bearer <key>` on the construction-time `/supported`
|
|
359
|
+
* handshake, which is how the dashboard learns an SDK is deployed before
|
|
360
|
+
* any payment. Optional, but a seller who omits it must supply their own
|
|
361
|
+
* `facilitator.createAuthHeaders` or settlement fails.
|
|
362
|
+
*/
|
|
363
|
+
apiKey?: string;
|
|
364
|
+
facilitator?: WeftFacilitatorConfig;
|
|
365
|
+
schemes?: SchemeRegistration[];
|
|
366
|
+
paywallConfig?: PaywallConfig;
|
|
367
|
+
paywall?: PaywallProvider;
|
|
368
|
+
syncFacilitatorOnStart?: boolean;
|
|
369
|
+
/** Restore durably bound verified inputs for settlement replay. */
|
|
370
|
+
resumeVerifiedPayment?: ResumeVerifiedPayment;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Create a Hono middleware that requires x402 payment for the given routes.
|
|
374
|
+
*
|
|
375
|
+
* Product identity declared on `config` (`name`, `type`, `tags`, `iconUrl`) is
|
|
376
|
+
* merged into every route, so it travels on the 402 challenge's `resource` and
|
|
377
|
+
* from there onto the buyer's payment payload and the settlement event.
|
|
378
|
+
*
|
|
379
|
+
* @param routes - Route configuration, either a path map or a single route;
|
|
380
|
+
* each route may declare its own `type` to override the product's
|
|
381
|
+
* @param config - Facilitator, scheme, paywall and product identity settings
|
|
382
|
+
* @returns A Hono middleware function
|
|
383
|
+
*/
|
|
384
|
+
declare function weftPaymentMiddlewareHono(routes: WeftRoutesConfig, config?: WeftHonoMiddlewareConfig): HonoMiddleware;
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* A route extension whose value is computed per request.
|
|
388
|
+
*
|
|
389
|
+
* Declared in place of a static value under a key of a route's `extensions`,
|
|
390
|
+
* and evaluated at the same point as the `price` callback — while the 402
|
|
391
|
+
* challenge is being built, with the same {@link HTTPRequestContext}. The
|
|
392
|
+
* resolved value ships on the challenge, the buyer's client echoes it onto the
|
|
393
|
+
* payment payload, and the facilitator relays it onto the settlement event, so
|
|
394
|
+
* a seller who prices from the request body can also say what that body asked
|
|
395
|
+
* for:
|
|
396
|
+
*
|
|
397
|
+
* ```ts
|
|
398
|
+
* {
|
|
399
|
+
* accepts: [{ scheme, network, payTo, price: quote }],
|
|
400
|
+
* extensions: {
|
|
401
|
+
* [WEFT_REQUEST_EXTENSION_KEY]: async (context) => {
|
|
402
|
+
* const { model, max_tokens } = (await context.adapter.getBody()) as Body;
|
|
403
|
+
* return { model, max_tokens };
|
|
404
|
+
* },
|
|
405
|
+
* },
|
|
406
|
+
* }
|
|
407
|
+
* ```
|
|
408
|
+
*
|
|
409
|
+
* {@link WEFT_REQUEST_EXTENSION_KEY} is the key to reach for. Under it the SDK
|
|
410
|
+
* owns the envelope: the callback returns the `info` payload alone and the
|
|
411
|
+
* published {@link WEFT_REQUEST_INFO_SCHEMA} is stamped beside it, exactly as
|
|
412
|
+
* `weft.product` is assembled from declared fields. Under any other key the
|
|
413
|
+
* resolved value ships verbatim, envelope and all — the escape hatch for a
|
|
414
|
+
* seller who needs their own namespace on the wire.
|
|
415
|
+
*
|
|
416
|
+
* Two rules the callback has to hold to.
|
|
417
|
+
*
|
|
418
|
+
* **It must be deterministic for one request.** The challenge is built twice —
|
|
419
|
+
* once for the unpaid request, once for the buyer's paid retry — and upstream
|
|
420
|
+
* rejects the payment with `extension_echo_mismatch` when what the buyer
|
|
421
|
+
* echoes no longer matches what the retry advertises. Derive the value from
|
|
422
|
+
* the request; never from a clock, a counter or a random source.
|
|
423
|
+
*
|
|
424
|
+
* **It is display-only.** By the time the value reaches a consumer it is
|
|
425
|
+
* unauthenticated buyer input, exactly like every other echoed extension.
|
|
426
|
+
* Attribution stays keyed on the authenticated API key that settled the
|
|
427
|
+
* payment, never on anything in here.
|
|
428
|
+
*
|
|
429
|
+
* The value travels as JSON and is advertised as JSON round-trips it, so a
|
|
430
|
+
* `NaN` arrives as `null` and a function-valued field does not arrive at all.
|
|
431
|
+
* Return plain JSON data and the question never comes up.
|
|
432
|
+
*/
|
|
433
|
+
type WeftDynamicExtension = (context: HTTPRequestContext) => unknown | Promise<unknown>;
|
|
434
|
+
/**
|
|
435
|
+
* Extension key for the seller's per-request context.
|
|
436
|
+
*
|
|
437
|
+
* The one *named* key this mechanism ships, and the one to use unless a
|
|
438
|
+
* seller needs their own namespace on the wire. x402 extensions are named
|
|
439
|
+
* capabilities with published contracts — discovery, receipts, gas sponsoring
|
|
440
|
+
* — registered and reviewed rather than invented per seller. A key that any
|
|
441
|
+
* seller may invent is a metadata channel wearing an extension's clothes, so
|
|
442
|
+
* the SDK publishes one key with one contract and leaves the free-form form
|
|
443
|
+
* as the deliberate exception.
|
|
444
|
+
*
|
|
445
|
+
* Sits beside {@link WEFT_PRODUCT_EXTENSION_KEY}, and divides cleanly from it:
|
|
446
|
+
* `weft.product` says what is being sold and is fixed at boot; `weft.request`
|
|
447
|
+
* says what this one call asked for and is resolved per request.
|
|
448
|
+
*/
|
|
449
|
+
declare const WEFT_REQUEST_EXTENSION_KEY = "weft.request";
|
|
450
|
+
/**
|
|
451
|
+
* JSON Schema (Draft 2020-12) for the `weft.request` extension's `info`.
|
|
452
|
+
*
|
|
453
|
+
* Ships verbatim as the extension's `schema` member. Deliberately open where
|
|
454
|
+
* `WEFT_PRODUCT_INFO_SCHEMA` is closed: what a request asked for is the
|
|
455
|
+
* seller's vocabulary — `{model, max_tokens}` for one rail, `{pages}` for
|
|
456
|
+
* another — and no schema Weft could author would fit them all.
|
|
457
|
+
*
|
|
458
|
+
* The contract it publishes is therefore not a field list but a posture: this
|
|
459
|
+
* key holds seller-authored, display-only context for one request, and a
|
|
460
|
+
* consumer must key nothing on it. `additionalProperties: true` states that
|
|
461
|
+
* openness rather than leaving it to be inferred from an absent constraint.
|
|
462
|
+
*/
|
|
463
|
+
declare const WEFT_REQUEST_INFO_SCHEMA: {
|
|
464
|
+
readonly $schema: "https://json-schema.org/draft/2020-12/schema";
|
|
465
|
+
readonly title: "Weft per-request context";
|
|
466
|
+
readonly description: string;
|
|
467
|
+
readonly type: "object";
|
|
468
|
+
readonly additionalProperties: true;
|
|
469
|
+
};
|
|
470
|
+
/**
|
|
471
|
+
* Largest serialized extensions object, in bytes, the SDK will put on a
|
|
472
|
+
* challenge.
|
|
473
|
+
*
|
|
474
|
+
* Mirrors the facilitator's own `MAX_EXTENSIONS_BYTES` relay cap, and is
|
|
475
|
+
* measured the same way: on the whole object, key names included. The
|
|
476
|
+
* facilitator omits *every* extension when the object is over — `weft.product`
|
|
477
|
+
* with it — so a resolved value that would take the object past the cap is
|
|
478
|
+
* dropped here, on its own key, where the rest of the declaration survives.
|
|
479
|
+
*
|
|
480
|
+
* Keep these blobs small. They describe a request; they are not a place to
|
|
481
|
+
* store one.
|
|
482
|
+
*/
|
|
483
|
+
declare const MAX_EXTENSION_BYTES: number;
|
|
484
|
+
/**
|
|
485
|
+
* Teach a resource server to resolve the routes' {@link WeftDynamicExtension}
|
|
486
|
+
* callbacks.
|
|
487
|
+
*
|
|
488
|
+
* Upstream reads `routeConfig.extensions` straight off the shared, long-lived
|
|
489
|
+
* route config, so a per-request value cannot be written there without racing
|
|
490
|
+
* every concurrent request. `registerExtension` is the path that *is* request
|
|
491
|
+
* scoped: the enrichment hook runs while the challenge for one request is
|
|
492
|
+
* being built, and its return value replaces that request's copy of the key —
|
|
493
|
+
* which is the same object the verify and settle steps go on to see.
|
|
494
|
+
*
|
|
495
|
+
* A config with no callbacks registers nothing at all.
|
|
496
|
+
*
|
|
497
|
+
* @param server - The resource server the middleware is building on
|
|
498
|
+
* @param routes - Route configuration passed by the caller
|
|
499
|
+
*/
|
|
500
|
+
declare function registerDynamicExtensions(server: x402ResourceServer, routes: WeftRoutesConfig): void;
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Header that carries the seller's declared product identity on the
|
|
504
|
+
* construction-time `/supported` call.
|
|
505
|
+
*
|
|
506
|
+
* The value is base64url-encoded JSON of
|
|
507
|
+
* `{name, type, tags, icon_url, dimensions}`. The first four are exactly the
|
|
508
|
+
* identity the 402 challenge will carry, so a dashboard fed from the
|
|
509
|
+
* handshake and one fed from settlements agree.
|
|
510
|
+
*
|
|
511
|
+
* `dimensions` is the exception, and travels here *only*. It never touches
|
|
512
|
+
* the challenge, because its whole job is to be the one statement about a
|
|
513
|
+
* payment's metadata that a buyer never had a chance to author: this call is
|
|
514
|
+
* authenticated by the seller's API key, so a field named here is a field the
|
|
515
|
+
* seller vouched for. That is what lets revenue be summed by it.
|
|
516
|
+
*
|
|
517
|
+
* Fields nobody declared are absent from the JSON, and the header itself is
|
|
518
|
+
* absent when nothing was declared at all.
|
|
519
|
+
*/
|
|
520
|
+
declare const WEFT_DECLARED_HEADER = "X-Weft-Declared";
|
|
521
|
+
/** The middleware adapters a handshake can identify itself as. */
|
|
522
|
+
type WeftAdapterName = "express" | "hono";
|
|
523
|
+
/**
|
|
524
|
+
* Header the Weft facilitator reads the seller's API key from on `/settle`
|
|
525
|
+
* and `/verify`.
|
|
526
|
+
*
|
|
527
|
+
* The facilitator's `/settle` handler validates this header and returns 401
|
|
528
|
+
* without it, so a seller who sets `apiKey` and nothing else must have it
|
|
529
|
+
* here or every settlement — the step that credits their wallet — fails.
|
|
530
|
+
* `/verify` does not require the key, but the facilitator reads it when
|
|
531
|
+
* present and stamps the verification event with the key's digest; the SDK
|
|
532
|
+
* sends it there too so the seller's funnel attributes verification attempts
|
|
533
|
+
* instead of counting settlements against zero. `/supported` carries the same
|
|
534
|
+
* key as a bearer for the handshake, so one key travels under two header names
|
|
535
|
+
* by the facilitator's own design, not the SDK's whim.
|
|
536
|
+
*/
|
|
537
|
+
declare const WEFT_API_KEY_HEADER = "X-API-Key";
|
|
538
|
+
|
|
539
|
+
export { type ExpressMiddleware, type HonoMiddleware, MAX_EXTENSION_BYTES, type PaymentResumeCandidate, type ResumeVerifiedPayment, type SchemeRegistration$1 as SchemeRegistration, type VerifiedPaymentResume, WEFT_API_KEY_HEADER, WEFT_DECLARED_HEADER, WEFT_PRODUCT_EXTENSION_KEY, WEFT_PRODUCT_INFO_SCHEMA, WEFT_REQUEST_EXTENSION_KEY, WEFT_REQUEST_INFO_SCHEMA, WEFT_TYPE_TAG_PREFIX, type WeftAdapterName, type WeftDynamicExtension, type WeftExpressMiddlewareConfig, type WeftHonoMiddlewareConfig, type WeftProductDeclaration, type WeftProductIdentity, type WeftProductType, type WeftRouteConfig, type WeftRoutesConfig, applyProductIdentity, productTypeTag, registerDynamicExtensions, weftPaymentMiddleware, weftPaymentMiddlewareHono };
|