@x402/extensions 2.2.0 → 2.3.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 +322 -93
- package/dist/cjs/bazaar/index.d.ts +3 -562
- package/dist/cjs/bazaar/index.js +12 -0
- package/dist/cjs/bazaar/index.js.map +1 -1
- package/dist/cjs/index-DvDlinmy.d.ts +575 -0
- package/dist/cjs/index.d.ts +4 -1
- package/dist/cjs/index.js +1008 -2
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/payment-identifier/index.d.ts +345 -0
- package/dist/cjs/payment-identifier/index.js +285 -0
- package/dist/cjs/payment-identifier/index.js.map +1 -0
- package/dist/cjs/sign-in-with-x/index.d.ts +1054 -1
- package/dist/cjs/sign-in-with-x/index.js +766 -0
- package/dist/cjs/sign-in-with-x/index.js.map +1 -1
- package/dist/esm/bazaar/index.d.mts +3 -562
- package/dist/esm/bazaar/index.mjs +1 -1
- package/dist/esm/chunk-73HCOE6N.mjs +233 -0
- package/dist/esm/chunk-73HCOE6N.mjs.map +1 -0
- package/dist/esm/{chunk-WB72GLC2.mjs → chunk-DFJ4ZQFO.mjs} +13 -1
- package/dist/esm/chunk-DFJ4ZQFO.mjs.map +1 -0
- package/dist/esm/chunk-E3F2XHTI.mjs +719 -0
- package/dist/esm/chunk-E3F2XHTI.mjs.map +1 -0
- package/dist/esm/index-DvDlinmy.d.mts +575 -0
- package/dist/esm/index.d.mts +4 -1
- package/dist/esm/index.mjs +102 -3
- package/dist/esm/payment-identifier/index.d.mts +345 -0
- package/dist/esm/payment-identifier/index.mjs +39 -0
- package/dist/esm/sign-in-with-x/index.d.mts +1054 -1
- package/dist/esm/sign-in-with-x/index.mjs +66 -1
- package/package.json +16 -2
- package/dist/esm/chunk-MKFJ5AA3.mjs +0 -1
- package/dist/esm/chunk-WB72GLC2.mjs.map +0 -1
- /package/dist/esm/{chunk-MKFJ5AA3.mjs.map → payment-identifier/index.mjs.map} +0 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import { ResourceServerExtension, PaymentPayload } from '@x402/core/types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Type definitions for the Payment-Identifier Extension
|
|
5
|
+
*
|
|
6
|
+
* Enables clients to provide an idempotency key that resource servers
|
|
7
|
+
* can use for deduplication of payment requests.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Extension identifier constant for the payment-identifier extension
|
|
11
|
+
*/
|
|
12
|
+
declare const PAYMENT_IDENTIFIER = "payment-identifier";
|
|
13
|
+
/**
|
|
14
|
+
* Minimum length for payment identifier
|
|
15
|
+
*/
|
|
16
|
+
declare const PAYMENT_ID_MIN_LENGTH = 16;
|
|
17
|
+
/**
|
|
18
|
+
* Maximum length for payment identifier
|
|
19
|
+
*/
|
|
20
|
+
declare const PAYMENT_ID_MAX_LENGTH = 128;
|
|
21
|
+
/**
|
|
22
|
+
* Pattern for valid payment identifier characters (alphanumeric, hyphens, underscores)
|
|
23
|
+
*/
|
|
24
|
+
declare const PAYMENT_ID_PATTERN: RegExp;
|
|
25
|
+
/**
|
|
26
|
+
* Payment identifier info containing the required flag and client-provided ID
|
|
27
|
+
*/
|
|
28
|
+
interface PaymentIdentifierInfo {
|
|
29
|
+
/**
|
|
30
|
+
* Whether the server requires clients to include a payment identifier.
|
|
31
|
+
* When true, clients must provide an `id` or receive a 400 Bad Request.
|
|
32
|
+
*/
|
|
33
|
+
required: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Client-provided unique identifier for idempotency.
|
|
36
|
+
* Must be 16-128 characters, alphanumeric with hyphens and underscores allowed.
|
|
37
|
+
*/
|
|
38
|
+
id?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Payment identifier extension with info and schema.
|
|
42
|
+
*
|
|
43
|
+
* Used both for server-side declarations (info without id) and
|
|
44
|
+
* client-side payloads (info with id).
|
|
45
|
+
*/
|
|
46
|
+
interface PaymentIdentifierExtension {
|
|
47
|
+
/**
|
|
48
|
+
* The payment identifier info.
|
|
49
|
+
* Server declarations have required only, clients add the id.
|
|
50
|
+
*/
|
|
51
|
+
info: PaymentIdentifierInfo;
|
|
52
|
+
/**
|
|
53
|
+
* JSON Schema validating the info structure
|
|
54
|
+
*/
|
|
55
|
+
schema: PaymentIdentifierSchema;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* JSON Schema type for the payment-identifier extension
|
|
59
|
+
*/
|
|
60
|
+
interface PaymentIdentifierSchema {
|
|
61
|
+
$schema: "https://json-schema.org/draft/2020-12/schema";
|
|
62
|
+
type: "object";
|
|
63
|
+
properties: {
|
|
64
|
+
required: {
|
|
65
|
+
type: "boolean";
|
|
66
|
+
};
|
|
67
|
+
id: {
|
|
68
|
+
type: "string";
|
|
69
|
+
minLength: number;
|
|
70
|
+
maxLength: number;
|
|
71
|
+
pattern: string;
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
required: ["required"];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* JSON Schema definitions for the Payment-Identifier Extension
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* JSON Schema for validating payment identifier info.
|
|
83
|
+
* Compliant with JSON Schema Draft 2020-12.
|
|
84
|
+
*/
|
|
85
|
+
declare const paymentIdentifierSchema: PaymentIdentifierSchema;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Utility functions for the Payment-Identifier Extension
|
|
89
|
+
*/
|
|
90
|
+
/**
|
|
91
|
+
* Generates a unique payment identifier.
|
|
92
|
+
*
|
|
93
|
+
* @param prefix - Optional prefix for the ID (e.g., "pay_"). Defaults to "pay_".
|
|
94
|
+
* @returns A unique payment identifier string
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* // With default prefix
|
|
99
|
+
* const id = generatePaymentId(); // "pay_7d5d747be160e280504c099d984bcfe0"
|
|
100
|
+
*
|
|
101
|
+
* // With custom prefix
|
|
102
|
+
* const id = generatePaymentId("txn_"); // "txn_7d5d747be160e280504c099d984bcfe0"
|
|
103
|
+
*
|
|
104
|
+
* // Without prefix
|
|
105
|
+
* const id = generatePaymentId(""); // "7d5d747be160e280504c099d984bcfe0"
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
declare function generatePaymentId(prefix?: string): string;
|
|
109
|
+
/**
|
|
110
|
+
* Validates that a payment ID meets the format requirements.
|
|
111
|
+
*
|
|
112
|
+
* @param id - The payment ID to validate
|
|
113
|
+
* @returns True if the ID is valid, false otherwise
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* isValidPaymentId("pay_7d5d747be160e280"); // true (exactly 16 chars after prefix removal check)
|
|
118
|
+
* isValidPaymentId("abc"); // false (too short)
|
|
119
|
+
* isValidPaymentId("pay_abc!@#"); // false (invalid characters)
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
declare function isValidPaymentId(id: string): boolean;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Client-side utilities for the Payment-Identifier Extension
|
|
126
|
+
*/
|
|
127
|
+
/**
|
|
128
|
+
* Appends a payment identifier to the extensions object if the server declared support.
|
|
129
|
+
*
|
|
130
|
+
* This function reads the server's `payment-identifier` declaration from the extensions,
|
|
131
|
+
* and appends the client's ID to it. If the extension is not present (server didn't declare it),
|
|
132
|
+
* the extensions are returned unchanged.
|
|
133
|
+
*
|
|
134
|
+
* @param extensions - The extensions object from PaymentRequired (will be modified in place)
|
|
135
|
+
* @param id - Optional custom payment ID. If not provided, a new ID will be generated.
|
|
136
|
+
* @returns The modified extensions object (same reference as input)
|
|
137
|
+
* @throws Error if the provided ID is invalid
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```typescript
|
|
141
|
+
* import { appendPaymentIdentifierToExtensions } from '@x402/extensions/payment-identifier';
|
|
142
|
+
*
|
|
143
|
+
* // Get extensions from server's PaymentRequired response
|
|
144
|
+
* const extensions = paymentRequired.extensions ?? {};
|
|
145
|
+
*
|
|
146
|
+
* // Append a generated ID (only if server declared payment-identifier)
|
|
147
|
+
* appendPaymentIdentifierToExtensions(extensions);
|
|
148
|
+
*
|
|
149
|
+
* // Or use a custom ID
|
|
150
|
+
* appendPaymentIdentifierToExtensions(extensions, "pay_my_custom_id_12345");
|
|
151
|
+
*
|
|
152
|
+
* // Include in PaymentPayload
|
|
153
|
+
* const paymentPayload = {
|
|
154
|
+
* x402Version: 2,
|
|
155
|
+
* resource: paymentRequired.resource,
|
|
156
|
+
* accepted: selectedPaymentOption,
|
|
157
|
+
* payload: { ... },
|
|
158
|
+
* extensions
|
|
159
|
+
* };
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
declare function appendPaymentIdentifierToExtensions(extensions: Record<string, unknown>, id?: string): Record<string, unknown>;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Resource Server utilities for the Payment-Identifier Extension
|
|
166
|
+
*/
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Declares the payment-identifier extension for inclusion in PaymentRequired.extensions.
|
|
170
|
+
*
|
|
171
|
+
* Resource servers call this function to advertise support for payment identifiers.
|
|
172
|
+
* The declaration indicates whether a payment identifier is required and includes
|
|
173
|
+
* the schema that clients must follow.
|
|
174
|
+
*
|
|
175
|
+
* @param required - Whether clients must provide a payment identifier. Defaults to false.
|
|
176
|
+
* @returns A PaymentIdentifierExtension object ready for PaymentRequired.extensions
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```typescript
|
|
180
|
+
* import { declarePaymentIdentifierExtension, PAYMENT_IDENTIFIER } from '@x402/extensions/payment-identifier';
|
|
181
|
+
*
|
|
182
|
+
* // Include in PaymentRequired response (optional identifier)
|
|
183
|
+
* const paymentRequired = {
|
|
184
|
+
* x402Version: 2,
|
|
185
|
+
* resource: { ... },
|
|
186
|
+
* accepts: [ ... ],
|
|
187
|
+
* extensions: {
|
|
188
|
+
* [PAYMENT_IDENTIFIER]: declarePaymentIdentifierExtension()
|
|
189
|
+
* }
|
|
190
|
+
* };
|
|
191
|
+
*
|
|
192
|
+
* // Require payment identifier
|
|
193
|
+
* const paymentRequiredStrict = {
|
|
194
|
+
* x402Version: 2,
|
|
195
|
+
* resource: { ... },
|
|
196
|
+
* accepts: [ ... ],
|
|
197
|
+
* extensions: {
|
|
198
|
+
* [PAYMENT_IDENTIFIER]: declarePaymentIdentifierExtension(true)
|
|
199
|
+
* }
|
|
200
|
+
* };
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
declare function declarePaymentIdentifierExtension(required?: boolean): PaymentIdentifierExtension;
|
|
204
|
+
/**
|
|
205
|
+
* ResourceServerExtension implementation for payment-identifier.
|
|
206
|
+
*
|
|
207
|
+
* This extension doesn't require any enrichment hooks since the declaration
|
|
208
|
+
* is static. It's provided for consistency with other extensions and for
|
|
209
|
+
* potential future use with the extension registration system.
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```typescript
|
|
213
|
+
* import { paymentIdentifierResourceServerExtension } from '@x402/extensions/payment-identifier';
|
|
214
|
+
*
|
|
215
|
+
* resourceServer.registerExtension(paymentIdentifierResourceServerExtension);
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
declare const paymentIdentifierResourceServerExtension: ResourceServerExtension;
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Validation and extraction utilities for the Payment-Identifier Extension
|
|
222
|
+
*/
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Type guard to check if an object is a valid payment-identifier extension structure.
|
|
226
|
+
*
|
|
227
|
+
* This checks for the basic structure (info object with required boolean),
|
|
228
|
+
* but does not validate the id format if present.
|
|
229
|
+
*
|
|
230
|
+
* @param extension - The object to check
|
|
231
|
+
* @returns True if the object has the expected payment-identifier extension structure
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```typescript
|
|
235
|
+
* if (isPaymentIdentifierExtension(extensions["payment-identifier"])) {
|
|
236
|
+
* // TypeScript knows this is PaymentIdentifierExtension
|
|
237
|
+
* console.log(extension.info.required);
|
|
238
|
+
* }
|
|
239
|
+
* ```
|
|
240
|
+
*/
|
|
241
|
+
declare function isPaymentIdentifierExtension(extension: unknown): extension is PaymentIdentifierExtension;
|
|
242
|
+
/**
|
|
243
|
+
* Result of payment identifier validation
|
|
244
|
+
*/
|
|
245
|
+
interface PaymentIdentifierValidationResult {
|
|
246
|
+
/**
|
|
247
|
+
* Whether the payment identifier is valid
|
|
248
|
+
*/
|
|
249
|
+
valid: boolean;
|
|
250
|
+
/**
|
|
251
|
+
* Error messages if validation failed
|
|
252
|
+
*/
|
|
253
|
+
errors?: string[];
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Validates a payment-identifier extension object.
|
|
257
|
+
*
|
|
258
|
+
* Checks both the structure (using JSON Schema) and the ID format.
|
|
259
|
+
*
|
|
260
|
+
* @param extension - The extension object to validate
|
|
261
|
+
* @returns Validation result with errors if invalid
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* ```typescript
|
|
265
|
+
* const result = validatePaymentIdentifier(paymentPayload.extensions?.["payment-identifier"]);
|
|
266
|
+
* if (!result.valid) {
|
|
267
|
+
* console.error("Invalid payment identifier:", result.errors);
|
|
268
|
+
* }
|
|
269
|
+
* ```
|
|
270
|
+
*/
|
|
271
|
+
declare function validatePaymentIdentifier(extension: unknown): PaymentIdentifierValidationResult;
|
|
272
|
+
/**
|
|
273
|
+
* Extracts the payment identifier from a PaymentPayload.
|
|
274
|
+
*
|
|
275
|
+
* @param paymentPayload - The payment payload to extract from
|
|
276
|
+
* @param validate - Whether to validate the ID before returning (default: true)
|
|
277
|
+
* @returns The payment ID string, or null if not present or invalid
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```typescript
|
|
281
|
+
* const id = extractPaymentIdentifier(paymentPayload);
|
|
282
|
+
* if (id) {
|
|
283
|
+
* // Use for idempotency lookup
|
|
284
|
+
* const cached = await idempotencyStore.get(id);
|
|
285
|
+
* }
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
288
|
+
declare function extractPaymentIdentifier(paymentPayload: PaymentPayload, validate?: boolean): string | null;
|
|
289
|
+
/**
|
|
290
|
+
* Extracts and validates the payment identifier from a PaymentPayload.
|
|
291
|
+
*
|
|
292
|
+
* @param paymentPayload - The payment payload to extract from
|
|
293
|
+
* @returns Object with the ID and validation result
|
|
294
|
+
*
|
|
295
|
+
* @example
|
|
296
|
+
* ```typescript
|
|
297
|
+
* const { id, validation } = extractAndValidatePaymentIdentifier(paymentPayload);
|
|
298
|
+
* if (!validation.valid) {
|
|
299
|
+
* return res.status(400).json({ error: validation.errors });
|
|
300
|
+
* }
|
|
301
|
+
* if (id) {
|
|
302
|
+
* // Use for idempotency
|
|
303
|
+
* }
|
|
304
|
+
* ```
|
|
305
|
+
*/
|
|
306
|
+
declare function extractAndValidatePaymentIdentifier(paymentPayload: PaymentPayload): {
|
|
307
|
+
id: string | null;
|
|
308
|
+
validation: PaymentIdentifierValidationResult;
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* Checks if a PaymentPayload contains a payment-identifier extension.
|
|
312
|
+
*
|
|
313
|
+
* @param paymentPayload - The payment payload to check
|
|
314
|
+
* @returns True if the extension is present
|
|
315
|
+
*/
|
|
316
|
+
declare function hasPaymentIdentifier(paymentPayload: PaymentPayload): boolean;
|
|
317
|
+
/**
|
|
318
|
+
* Checks if the server requires a payment identifier based on the extension info.
|
|
319
|
+
*
|
|
320
|
+
* @param extension - The payment-identifier extension from PaymentRequired or PaymentPayload
|
|
321
|
+
* @returns True if the server requires a payment identifier
|
|
322
|
+
*/
|
|
323
|
+
declare function isPaymentIdentifierRequired(extension: unknown): boolean;
|
|
324
|
+
/**
|
|
325
|
+
* Validates that a payment identifier is provided when required.
|
|
326
|
+
*
|
|
327
|
+
* Use this to check if a client's PaymentPayload satisfies the server's requirement.
|
|
328
|
+
*
|
|
329
|
+
* @param paymentPayload - The client's payment payload
|
|
330
|
+
* @param serverRequired - Whether the server requires a payment identifier (from PaymentRequired)
|
|
331
|
+
* @returns Validation result - invalid if required but not provided
|
|
332
|
+
*
|
|
333
|
+
* @example
|
|
334
|
+
* ```typescript
|
|
335
|
+
* const serverExtension = paymentRequired.extensions?.["payment-identifier"];
|
|
336
|
+
* const serverRequired = isPaymentIdentifierRequired(serverExtension);
|
|
337
|
+
* const result = validatePaymentIdentifierRequirement(paymentPayload, serverRequired);
|
|
338
|
+
* if (!result.valid) {
|
|
339
|
+
* return res.status(400).json({ error: result.errors });
|
|
340
|
+
* }
|
|
341
|
+
* ```
|
|
342
|
+
*/
|
|
343
|
+
declare function validatePaymentIdentifierRequirement(paymentPayload: PaymentPayload, serverRequired: boolean): PaymentIdentifierValidationResult;
|
|
344
|
+
|
|
345
|
+
export { PAYMENT_IDENTIFIER, PAYMENT_ID_MAX_LENGTH, PAYMENT_ID_MIN_LENGTH, PAYMENT_ID_PATTERN, type PaymentIdentifierExtension, type PaymentIdentifierInfo, type PaymentIdentifierSchema, type PaymentIdentifierValidationResult, appendPaymentIdentifierToExtensions, declarePaymentIdentifierExtension, extractAndValidatePaymentIdentifier, extractPaymentIdentifier, generatePaymentId, hasPaymentIdentifier, isPaymentIdentifierExtension, isPaymentIdentifierRequired, isValidPaymentId, paymentIdentifierResourceServerExtension, paymentIdentifierSchema, validatePaymentIdentifier, validatePaymentIdentifierRequirement };
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/payment-identifier/index.ts
|
|
31
|
+
var payment_identifier_exports = {};
|
|
32
|
+
__export(payment_identifier_exports, {
|
|
33
|
+
PAYMENT_IDENTIFIER: () => PAYMENT_IDENTIFIER,
|
|
34
|
+
PAYMENT_ID_MAX_LENGTH: () => PAYMENT_ID_MAX_LENGTH,
|
|
35
|
+
PAYMENT_ID_MIN_LENGTH: () => PAYMENT_ID_MIN_LENGTH,
|
|
36
|
+
PAYMENT_ID_PATTERN: () => PAYMENT_ID_PATTERN,
|
|
37
|
+
appendPaymentIdentifierToExtensions: () => appendPaymentIdentifierToExtensions,
|
|
38
|
+
declarePaymentIdentifierExtension: () => declarePaymentIdentifierExtension,
|
|
39
|
+
extractAndValidatePaymentIdentifier: () => extractAndValidatePaymentIdentifier,
|
|
40
|
+
extractPaymentIdentifier: () => extractPaymentIdentifier,
|
|
41
|
+
generatePaymentId: () => generatePaymentId,
|
|
42
|
+
hasPaymentIdentifier: () => hasPaymentIdentifier,
|
|
43
|
+
isPaymentIdentifierExtension: () => isPaymentIdentifierExtension,
|
|
44
|
+
isPaymentIdentifierRequired: () => isPaymentIdentifierRequired,
|
|
45
|
+
isValidPaymentId: () => isValidPaymentId,
|
|
46
|
+
paymentIdentifierResourceServerExtension: () => paymentIdentifierResourceServerExtension,
|
|
47
|
+
paymentIdentifierSchema: () => paymentIdentifierSchema,
|
|
48
|
+
validatePaymentIdentifier: () => validatePaymentIdentifier,
|
|
49
|
+
validatePaymentIdentifierRequirement: () => validatePaymentIdentifierRequirement
|
|
50
|
+
});
|
|
51
|
+
module.exports = __toCommonJS(payment_identifier_exports);
|
|
52
|
+
|
|
53
|
+
// src/payment-identifier/types.ts
|
|
54
|
+
var PAYMENT_IDENTIFIER = "payment-identifier";
|
|
55
|
+
var PAYMENT_ID_MIN_LENGTH = 16;
|
|
56
|
+
var PAYMENT_ID_MAX_LENGTH = 128;
|
|
57
|
+
var PAYMENT_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
58
|
+
|
|
59
|
+
// src/payment-identifier/schema.ts
|
|
60
|
+
var paymentIdentifierSchema = {
|
|
61
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: {
|
|
64
|
+
required: {
|
|
65
|
+
type: "boolean"
|
|
66
|
+
},
|
|
67
|
+
id: {
|
|
68
|
+
type: "string",
|
|
69
|
+
minLength: PAYMENT_ID_MIN_LENGTH,
|
|
70
|
+
maxLength: PAYMENT_ID_MAX_LENGTH,
|
|
71
|
+
pattern: "^[a-zA-Z0-9_-]+$"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
required: ["required"]
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// src/payment-identifier/utils.ts
|
|
78
|
+
function generatePaymentId(prefix = "pay_") {
|
|
79
|
+
const uuid = crypto.randomUUID().replace(/-/g, "");
|
|
80
|
+
return `${prefix}${uuid}`;
|
|
81
|
+
}
|
|
82
|
+
function isValidPaymentId(id) {
|
|
83
|
+
if (typeof id !== "string") {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
if (id.length < PAYMENT_ID_MIN_LENGTH || id.length > PAYMENT_ID_MAX_LENGTH) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
return PAYMENT_ID_PATTERN.test(id);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/payment-identifier/validation.ts
|
|
93
|
+
var import__ = __toESM(require("ajv/dist/2020.js"));
|
|
94
|
+
function isPaymentIdentifierExtension(extension) {
|
|
95
|
+
if (!extension || typeof extension !== "object") {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
const ext = extension;
|
|
99
|
+
if (!ext.info || typeof ext.info !== "object") {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
const info = ext.info;
|
|
103
|
+
if (typeof info.required !== "boolean") {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
function validatePaymentIdentifier(extension) {
|
|
109
|
+
if (!extension || typeof extension !== "object") {
|
|
110
|
+
return {
|
|
111
|
+
valid: false,
|
|
112
|
+
errors: ["Extension must be an object"]
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const ext = extension;
|
|
116
|
+
if (!ext.info || typeof ext.info !== "object") {
|
|
117
|
+
return {
|
|
118
|
+
valid: false,
|
|
119
|
+
errors: ["Extension must have an 'info' property"]
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const info = ext.info;
|
|
123
|
+
if (typeof info.required !== "boolean") {
|
|
124
|
+
return {
|
|
125
|
+
valid: false,
|
|
126
|
+
errors: ["Extension info must have a 'required' boolean property"]
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
if (info.id !== void 0 && typeof info.id !== "string") {
|
|
130
|
+
return {
|
|
131
|
+
valid: false,
|
|
132
|
+
errors: ["Extension info 'id' must be a string if provided"]
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
if (info.id !== void 0 && !isValidPaymentId(info.id)) {
|
|
136
|
+
return {
|
|
137
|
+
valid: false,
|
|
138
|
+
errors: [
|
|
139
|
+
`Invalid payment ID format. ID must be 16-128 characters and contain only alphanumeric characters, hyphens, and underscores.`
|
|
140
|
+
]
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
if (ext.schema) {
|
|
144
|
+
try {
|
|
145
|
+
const ajv = new import__.default({ strict: false, allErrors: true });
|
|
146
|
+
const validate = ajv.compile(ext.schema);
|
|
147
|
+
const valid = validate(ext.info);
|
|
148
|
+
if (!valid && validate.errors) {
|
|
149
|
+
const errors = validate.errors?.map((err) => {
|
|
150
|
+
const path = err.instancePath || "(root)";
|
|
151
|
+
return `${path}: ${err.message}`;
|
|
152
|
+
}) || ["Unknown validation error"];
|
|
153
|
+
return { valid: false, errors };
|
|
154
|
+
}
|
|
155
|
+
} catch (error) {
|
|
156
|
+
return {
|
|
157
|
+
valid: false,
|
|
158
|
+
errors: [
|
|
159
|
+
`Schema validation failed: ${error instanceof Error ? error.message : String(error)}`
|
|
160
|
+
]
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return { valid: true };
|
|
165
|
+
}
|
|
166
|
+
function extractPaymentIdentifier(paymentPayload, validate = true) {
|
|
167
|
+
if (!paymentPayload.extensions) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
const extension = paymentPayload.extensions[PAYMENT_IDENTIFIER];
|
|
171
|
+
if (!extension || typeof extension !== "object") {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
const ext = extension;
|
|
175
|
+
if (!ext.info || typeof ext.info !== "object") {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
const info = ext.info;
|
|
179
|
+
if (typeof info.id !== "string") {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
if (validate && !isValidPaymentId(info.id)) {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
return info.id;
|
|
186
|
+
}
|
|
187
|
+
function extractAndValidatePaymentIdentifier(paymentPayload) {
|
|
188
|
+
if (!paymentPayload.extensions) {
|
|
189
|
+
return { id: null, validation: { valid: true } };
|
|
190
|
+
}
|
|
191
|
+
const extension = paymentPayload.extensions[PAYMENT_IDENTIFIER];
|
|
192
|
+
if (!extension) {
|
|
193
|
+
return { id: null, validation: { valid: true } };
|
|
194
|
+
}
|
|
195
|
+
const validation = validatePaymentIdentifier(extension);
|
|
196
|
+
if (!validation.valid) {
|
|
197
|
+
return { id: null, validation };
|
|
198
|
+
}
|
|
199
|
+
const ext = extension;
|
|
200
|
+
return { id: ext.info.id ?? null, validation: { valid: true } };
|
|
201
|
+
}
|
|
202
|
+
function hasPaymentIdentifier(paymentPayload) {
|
|
203
|
+
return !!(paymentPayload.extensions && paymentPayload.extensions[PAYMENT_IDENTIFIER]);
|
|
204
|
+
}
|
|
205
|
+
function isPaymentIdentifierRequired(extension) {
|
|
206
|
+
if (!extension || typeof extension !== "object") {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
const ext = extension;
|
|
210
|
+
if (!ext.info || typeof ext.info !== "object") {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
return ext.info.required === true;
|
|
214
|
+
}
|
|
215
|
+
function validatePaymentIdentifierRequirement(paymentPayload, serverRequired) {
|
|
216
|
+
if (!serverRequired) {
|
|
217
|
+
return { valid: true };
|
|
218
|
+
}
|
|
219
|
+
const id = extractPaymentIdentifier(paymentPayload, false);
|
|
220
|
+
if (!id) {
|
|
221
|
+
return {
|
|
222
|
+
valid: false,
|
|
223
|
+
errors: ["Server requires a payment identifier but none was provided"]
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
if (!isValidPaymentId(id)) {
|
|
227
|
+
return {
|
|
228
|
+
valid: false,
|
|
229
|
+
errors: [
|
|
230
|
+
`Invalid payment ID format. ID must be 16-128 characters and contain only alphanumeric characters, hyphens, and underscores.`
|
|
231
|
+
]
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
return { valid: true };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// src/payment-identifier/client.ts
|
|
238
|
+
function appendPaymentIdentifierToExtensions(extensions, id) {
|
|
239
|
+
const extension = extensions[PAYMENT_IDENTIFIER];
|
|
240
|
+
if (!isPaymentIdentifierExtension(extension)) {
|
|
241
|
+
return extensions;
|
|
242
|
+
}
|
|
243
|
+
const paymentId = id ?? generatePaymentId();
|
|
244
|
+
if (!isValidPaymentId(paymentId)) {
|
|
245
|
+
throw new Error(
|
|
246
|
+
`Invalid payment ID: "${paymentId}". ID must be 16-128 characters and contain only alphanumeric characters, hyphens, and underscores.`
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
extension.info.id = paymentId;
|
|
250
|
+
return extensions;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// src/payment-identifier/resourceServer.ts
|
|
254
|
+
function declarePaymentIdentifierExtension(required = false) {
|
|
255
|
+
return {
|
|
256
|
+
info: { required },
|
|
257
|
+
schema: paymentIdentifierSchema
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
var paymentIdentifierResourceServerExtension = {
|
|
261
|
+
key: PAYMENT_IDENTIFIER
|
|
262
|
+
// No enrichment needed - the declaration is static
|
|
263
|
+
// Future hooks for idempotency could be added here if needed
|
|
264
|
+
};
|
|
265
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
266
|
+
0 && (module.exports = {
|
|
267
|
+
PAYMENT_IDENTIFIER,
|
|
268
|
+
PAYMENT_ID_MAX_LENGTH,
|
|
269
|
+
PAYMENT_ID_MIN_LENGTH,
|
|
270
|
+
PAYMENT_ID_PATTERN,
|
|
271
|
+
appendPaymentIdentifierToExtensions,
|
|
272
|
+
declarePaymentIdentifierExtension,
|
|
273
|
+
extractAndValidatePaymentIdentifier,
|
|
274
|
+
extractPaymentIdentifier,
|
|
275
|
+
generatePaymentId,
|
|
276
|
+
hasPaymentIdentifier,
|
|
277
|
+
isPaymentIdentifierExtension,
|
|
278
|
+
isPaymentIdentifierRequired,
|
|
279
|
+
isValidPaymentId,
|
|
280
|
+
paymentIdentifierResourceServerExtension,
|
|
281
|
+
paymentIdentifierSchema,
|
|
282
|
+
validatePaymentIdentifier,
|
|
283
|
+
validatePaymentIdentifierRequirement
|
|
284
|
+
});
|
|
285
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/payment-identifier/index.ts","../../../src/payment-identifier/types.ts","../../../src/payment-identifier/schema.ts","../../../src/payment-identifier/utils.ts","../../../src/payment-identifier/validation.ts","../../../src/payment-identifier/client.ts","../../../src/payment-identifier/resourceServer.ts"],"sourcesContent":["/**\n * Payment-Identifier Extension for x402 v2\n *\n * Enables clients to provide an idempotency key (`id`) that resource servers\n * can use for deduplication of payment requests.\n *\n * ## Usage\n *\n * ### For Resource Servers\n *\n * ```typescript\n * import {\n * declarePaymentIdentifierExtension,\n * PAYMENT_IDENTIFIER\n * } from '@x402/extensions/payment-identifier';\n *\n * // Advertise support in PaymentRequired response (optional identifier)\n * const paymentRequired = {\n * x402Version: 2,\n * resource: { ... },\n * accepts: [ ... ],\n * extensions: {\n * [PAYMENT_IDENTIFIER]: declarePaymentIdentifierExtension()\n * }\n * };\n *\n * // Require payment identifier\n * const paymentRequiredStrict = {\n * x402Version: 2,\n * resource: { ... },\n * accepts: [ ... ],\n * extensions: {\n * [PAYMENT_IDENTIFIER]: declarePaymentIdentifierExtension(true)\n * }\n * };\n * ```\n *\n * ### For Clients\n *\n * ```typescript\n * import { appendPaymentIdentifierToExtensions } from '@x402/extensions/payment-identifier';\n *\n * // Get extensions from server's PaymentRequired response\n * const extensions = { ...paymentRequired.extensions };\n *\n * // Append payment ID (only if server declared the extension)\n * appendPaymentIdentifierToExtensions(extensions);\n *\n * // Include in PaymentPayload\n * const paymentPayload = {\n * x402Version: 2,\n * resource: paymentRequired.resource,\n * accepted: selectedPaymentOption,\n * payload: { ... },\n * extensions\n * };\n * ```\n *\n * ### For Idempotency Implementation\n *\n * ```typescript\n * import { extractPaymentIdentifier } from '@x402/extensions/payment-identifier';\n *\n * // In your settle handler\n * const id = extractPaymentIdentifier(paymentPayload);\n * if (id) {\n * const cached = await idempotencyStore.get(id);\n * if (cached) {\n * return cached; // Return cached response\n * }\n * }\n * ```\n */\n\n// Export types\nexport type {\n PaymentIdentifierInfo,\n PaymentIdentifierExtension,\n PaymentIdentifierSchema,\n} from \"./types\";\n\nexport {\n PAYMENT_IDENTIFIER,\n PAYMENT_ID_MIN_LENGTH,\n PAYMENT_ID_MAX_LENGTH,\n PAYMENT_ID_PATTERN,\n} from \"./types\";\n\n// Export schema\nexport { paymentIdentifierSchema } from \"./schema\";\n\n// Export utilities\nexport { generatePaymentId, isValidPaymentId } from \"./utils\";\n\n// Export client functions\nexport { appendPaymentIdentifierToExtensions } from \"./client\";\n\n// Export resource server functions\nexport {\n declarePaymentIdentifierExtension,\n paymentIdentifierResourceServerExtension,\n} from \"./resourceServer\";\n\n// Export validation and extraction functions\nexport {\n isPaymentIdentifierExtension,\n validatePaymentIdentifier,\n extractPaymentIdentifier,\n extractAndValidatePaymentIdentifier,\n hasPaymentIdentifier,\n isPaymentIdentifierRequired,\n validatePaymentIdentifierRequirement,\n type PaymentIdentifierValidationResult,\n} from \"./validation\";\n","/**\n * Type definitions for the Payment-Identifier Extension\n *\n * Enables clients to provide an idempotency key that resource servers\n * can use for deduplication of payment requests.\n */\n\n/**\n * Extension identifier constant for the payment-identifier extension\n */\nexport const PAYMENT_IDENTIFIER = \"payment-identifier\";\n\n/**\n * Minimum length for payment identifier\n */\nexport const PAYMENT_ID_MIN_LENGTH = 16;\n\n/**\n * Maximum length for payment identifier\n */\nexport const PAYMENT_ID_MAX_LENGTH = 128;\n\n/**\n * Pattern for valid payment identifier characters (alphanumeric, hyphens, underscores)\n */\nexport const PAYMENT_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;\n\n/**\n * Payment identifier info containing the required flag and client-provided ID\n */\nexport interface PaymentIdentifierInfo {\n /**\n * Whether the server requires clients to include a payment identifier.\n * When true, clients must provide an `id` or receive a 400 Bad Request.\n */\n required: boolean;\n\n /**\n * Client-provided unique identifier for idempotency.\n * Must be 16-128 characters, alphanumeric with hyphens and underscores allowed.\n */\n id?: string;\n}\n\n/**\n * Payment identifier extension with info and schema.\n *\n * Used both for server-side declarations (info without id) and\n * client-side payloads (info with id).\n */\nexport interface PaymentIdentifierExtension {\n /**\n * The payment identifier info.\n * Server declarations have required only, clients add the id.\n */\n info: PaymentIdentifierInfo;\n\n /**\n * JSON Schema validating the info structure\n */\n schema: PaymentIdentifierSchema;\n}\n\n/**\n * JSON Schema type for the payment-identifier extension\n */\nexport interface PaymentIdentifierSchema {\n $schema: \"https://json-schema.org/draft/2020-12/schema\";\n type: \"object\";\n properties: {\n required: {\n type: \"boolean\";\n };\n id: {\n type: \"string\";\n minLength: number;\n maxLength: number;\n pattern: string;\n };\n };\n required: [\"required\"];\n}\n","/**\n * JSON Schema definitions for the Payment-Identifier Extension\n */\n\nimport type { PaymentIdentifierSchema } from \"./types\";\nimport { PAYMENT_ID_MIN_LENGTH, PAYMENT_ID_MAX_LENGTH } from \"./types\";\n\n/**\n * JSON Schema for validating payment identifier info.\n * Compliant with JSON Schema Draft 2020-12.\n */\nexport const paymentIdentifierSchema: PaymentIdentifierSchema = {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n type: \"object\",\n properties: {\n required: {\n type: \"boolean\",\n },\n id: {\n type: \"string\",\n minLength: PAYMENT_ID_MIN_LENGTH,\n maxLength: PAYMENT_ID_MAX_LENGTH,\n pattern: \"^[a-zA-Z0-9_-]+$\",\n },\n },\n required: [\"required\"],\n};\n","/**\n * Utility functions for the Payment-Identifier Extension\n */\n\nimport { PAYMENT_ID_MIN_LENGTH, PAYMENT_ID_MAX_LENGTH, PAYMENT_ID_PATTERN } from \"./types\";\n\n/**\n * Generates a unique payment identifier.\n *\n * @param prefix - Optional prefix for the ID (e.g., \"pay_\"). Defaults to \"pay_\".\n * @returns A unique payment identifier string\n *\n * @example\n * ```typescript\n * // With default prefix\n * const id = generatePaymentId(); // \"pay_7d5d747be160e280504c099d984bcfe0\"\n *\n * // With custom prefix\n * const id = generatePaymentId(\"txn_\"); // \"txn_7d5d747be160e280504c099d984bcfe0\"\n *\n * // Without prefix\n * const id = generatePaymentId(\"\"); // \"7d5d747be160e280504c099d984bcfe0\"\n * ```\n */\nexport function generatePaymentId(prefix: string = \"pay_\"): string {\n // Generate UUID v4 without hyphens (32 hex chars)\n const uuid = crypto.randomUUID().replace(/-/g, \"\");\n return `${prefix}${uuid}`;\n}\n\n/**\n * Validates that a payment ID meets the format requirements.\n *\n * @param id - The payment ID to validate\n * @returns True if the ID is valid, false otherwise\n *\n * @example\n * ```typescript\n * isValidPaymentId(\"pay_7d5d747be160e280\"); // true (exactly 16 chars after prefix removal check)\n * isValidPaymentId(\"abc\"); // false (too short)\n * isValidPaymentId(\"pay_abc!@#\"); // false (invalid characters)\n * ```\n */\nexport function isValidPaymentId(id: string): boolean {\n if (typeof id !== \"string\") {\n return false;\n }\n\n if (id.length < PAYMENT_ID_MIN_LENGTH || id.length > PAYMENT_ID_MAX_LENGTH) {\n return false;\n }\n\n return PAYMENT_ID_PATTERN.test(id);\n}\n","/**\n * Validation and extraction utilities for the Payment-Identifier Extension\n */\n\nimport Ajv from \"ajv/dist/2020.js\";\nimport type { PaymentPayload } from \"@x402/core/types\";\nimport type { PaymentIdentifierExtension, PaymentIdentifierInfo } from \"./types\";\nimport { PAYMENT_IDENTIFIER } from \"./types\";\nimport { paymentIdentifierSchema } from \"./schema\";\nimport { isValidPaymentId } from \"./utils\";\n\n/**\n * Type guard to check if an object is a valid payment-identifier extension structure.\n *\n * This checks for the basic structure (info object with required boolean),\n * but does not validate the id format if present.\n *\n * @param extension - The object to check\n * @returns True if the object has the expected payment-identifier extension structure\n *\n * @example\n * ```typescript\n * if (isPaymentIdentifierExtension(extensions[\"payment-identifier\"])) {\n * // TypeScript knows this is PaymentIdentifierExtension\n * console.log(extension.info.required);\n * }\n * ```\n */\nexport function isPaymentIdentifierExtension(\n extension: unknown,\n): extension is PaymentIdentifierExtension {\n if (!extension || typeof extension !== \"object\") {\n return false;\n }\n\n const ext = extension as Partial<PaymentIdentifierExtension>;\n\n if (!ext.info || typeof ext.info !== \"object\") {\n return false;\n }\n\n const info = ext.info as Partial<PaymentIdentifierInfo>;\n\n // Must have required boolean\n if (typeof info.required !== \"boolean\") {\n return false;\n }\n\n return true;\n}\n\n/**\n * Result of payment identifier validation\n */\nexport interface PaymentIdentifierValidationResult {\n /**\n * Whether the payment identifier is valid\n */\n valid: boolean;\n\n /**\n * Error messages if validation failed\n */\n errors?: string[];\n}\n\n/**\n * Validates a payment-identifier extension object.\n *\n * Checks both the structure (using JSON Schema) and the ID format.\n *\n * @param extension - The extension object to validate\n * @returns Validation result with errors if invalid\n *\n * @example\n * ```typescript\n * const result = validatePaymentIdentifier(paymentPayload.extensions?.[\"payment-identifier\"]);\n * if (!result.valid) {\n * console.error(\"Invalid payment identifier:\", result.errors);\n * }\n * ```\n */\nexport function validatePaymentIdentifier(extension: unknown): PaymentIdentifierValidationResult {\n if (!extension || typeof extension !== \"object\") {\n return {\n valid: false,\n errors: [\"Extension must be an object\"],\n };\n }\n\n const ext = extension as Partial<PaymentIdentifierExtension>;\n\n // Check info exists\n if (!ext.info || typeof ext.info !== \"object\") {\n return {\n valid: false,\n errors: [\"Extension must have an 'info' property\"],\n };\n }\n\n const info = ext.info as Partial<PaymentIdentifierInfo>;\n\n // Check required field exists and is a boolean\n if (typeof info.required !== \"boolean\") {\n return {\n valid: false,\n errors: [\"Extension info must have a 'required' boolean property\"],\n };\n }\n\n // Check id exists and is a string (if provided)\n if (info.id !== undefined && typeof info.id !== \"string\") {\n return {\n valid: false,\n errors: [\"Extension info 'id' must be a string if provided\"],\n };\n }\n\n // Validate ID format if provided\n if (info.id !== undefined && !isValidPaymentId(info.id)) {\n return {\n valid: false,\n errors: [\n `Invalid payment ID format. ID must be 16-128 characters and contain only alphanumeric characters, hyphens, and underscores.`,\n ],\n };\n }\n\n // If schema is provided, validate against it\n if (ext.schema) {\n try {\n const ajv = new Ajv({ strict: false, allErrors: true });\n const validate = ajv.compile(ext.schema);\n const valid = validate(ext.info);\n\n if (!valid && validate.errors) {\n const errors = validate.errors?.map(err => {\n const path = err.instancePath || \"(root)\";\n return `${path}: ${err.message}`;\n }) || [\"Unknown validation error\"];\n\n return { valid: false, errors };\n }\n } catch (error) {\n return {\n valid: false,\n errors: [\n `Schema validation failed: ${error instanceof Error ? error.message : String(error)}`,\n ],\n };\n }\n }\n\n return { valid: true };\n}\n\n/**\n * Extracts the payment identifier from a PaymentPayload.\n *\n * @param paymentPayload - The payment payload to extract from\n * @param validate - Whether to validate the ID before returning (default: true)\n * @returns The payment ID string, or null if not present or invalid\n *\n * @example\n * ```typescript\n * const id = extractPaymentIdentifier(paymentPayload);\n * if (id) {\n * // Use for idempotency lookup\n * const cached = await idempotencyStore.get(id);\n * }\n * ```\n */\nexport function extractPaymentIdentifier(\n paymentPayload: PaymentPayload,\n validate: boolean = true,\n): string | null {\n if (!paymentPayload.extensions) {\n return null;\n }\n\n const extension = paymentPayload.extensions[PAYMENT_IDENTIFIER];\n\n if (!extension || typeof extension !== \"object\") {\n return null;\n }\n\n const ext = extension as Partial<PaymentIdentifierExtension>;\n\n if (!ext.info || typeof ext.info !== \"object\") {\n return null;\n }\n\n const info = ext.info as Partial<PaymentIdentifierInfo>;\n\n if (typeof info.id !== \"string\") {\n return null;\n }\n\n if (validate && !isValidPaymentId(info.id)) {\n return null;\n }\n\n return info.id;\n}\n\n/**\n * Extracts and validates the payment identifier from a PaymentPayload.\n *\n * @param paymentPayload - The payment payload to extract from\n * @returns Object with the ID and validation result\n *\n * @example\n * ```typescript\n * const { id, validation } = extractAndValidatePaymentIdentifier(paymentPayload);\n * if (!validation.valid) {\n * return res.status(400).json({ error: validation.errors });\n * }\n * if (id) {\n * // Use for idempotency\n * }\n * ```\n */\nexport function extractAndValidatePaymentIdentifier(paymentPayload: PaymentPayload): {\n id: string | null;\n validation: PaymentIdentifierValidationResult;\n} {\n if (!paymentPayload.extensions) {\n return { id: null, validation: { valid: true } };\n }\n\n const extension = paymentPayload.extensions[PAYMENT_IDENTIFIER];\n\n if (!extension) {\n return { id: null, validation: { valid: true } };\n }\n\n const validation = validatePaymentIdentifier(extension);\n\n if (!validation.valid) {\n return { id: null, validation };\n }\n\n const ext = extension as PaymentIdentifierExtension;\n return { id: ext.info.id ?? null, validation: { valid: true } };\n}\n\n/**\n * Checks if a PaymentPayload contains a payment-identifier extension.\n *\n * @param paymentPayload - The payment payload to check\n * @returns True if the extension is present\n */\nexport function hasPaymentIdentifier(paymentPayload: PaymentPayload): boolean {\n return !!(paymentPayload.extensions && paymentPayload.extensions[PAYMENT_IDENTIFIER]);\n}\n\n/**\n * Checks if the server requires a payment identifier based on the extension info.\n *\n * @param extension - The payment-identifier extension from PaymentRequired or PaymentPayload\n * @returns True if the server requires a payment identifier\n */\nexport function isPaymentIdentifierRequired(extension: unknown): boolean {\n if (!extension || typeof extension !== \"object\") {\n return false;\n }\n\n const ext = extension as Partial<PaymentIdentifierExtension>;\n\n if (!ext.info || typeof ext.info !== \"object\") {\n return false;\n }\n\n return (ext.info as Partial<PaymentIdentifierInfo>).required === true;\n}\n\n/**\n * Validates that a payment identifier is provided when required.\n *\n * Use this to check if a client's PaymentPayload satisfies the server's requirement.\n *\n * @param paymentPayload - The client's payment payload\n * @param serverRequired - Whether the server requires a payment identifier (from PaymentRequired)\n * @returns Validation result - invalid if required but not provided\n *\n * @example\n * ```typescript\n * const serverExtension = paymentRequired.extensions?.[\"payment-identifier\"];\n * const serverRequired = isPaymentIdentifierRequired(serverExtension);\n * const result = validatePaymentIdentifierRequirement(paymentPayload, serverRequired);\n * if (!result.valid) {\n * return res.status(400).json({ error: result.errors });\n * }\n * ```\n */\nexport function validatePaymentIdentifierRequirement(\n paymentPayload: PaymentPayload,\n serverRequired: boolean,\n): PaymentIdentifierValidationResult {\n if (!serverRequired) {\n return { valid: true };\n }\n\n const id = extractPaymentIdentifier(paymentPayload, false);\n\n if (!id) {\n return {\n valid: false,\n errors: [\"Server requires a payment identifier but none was provided\"],\n };\n }\n\n // Validate the ID format\n if (!isValidPaymentId(id)) {\n return {\n valid: false,\n errors: [\n `Invalid payment ID format. ID must be 16-128 characters and contain only alphanumeric characters, hyphens, and underscores.`,\n ],\n };\n }\n\n return { valid: true };\n}\n\nexport { paymentIdentifierSchema };\n","/**\n * Client-side utilities for the Payment-Identifier Extension\n */\n\nimport { PAYMENT_IDENTIFIER } from \"./types\";\nimport { generatePaymentId, isValidPaymentId } from \"./utils\";\nimport { isPaymentIdentifierExtension } from \"./validation\";\n\n/**\n * Appends a payment identifier to the extensions object if the server declared support.\n *\n * This function reads the server's `payment-identifier` declaration from the extensions,\n * and appends the client's ID to it. If the extension is not present (server didn't declare it),\n * the extensions are returned unchanged.\n *\n * @param extensions - The extensions object from PaymentRequired (will be modified in place)\n * @param id - Optional custom payment ID. If not provided, a new ID will be generated.\n * @returns The modified extensions object (same reference as input)\n * @throws Error if the provided ID is invalid\n *\n * @example\n * ```typescript\n * import { appendPaymentIdentifierToExtensions } from '@x402/extensions/payment-identifier';\n *\n * // Get extensions from server's PaymentRequired response\n * const extensions = paymentRequired.extensions ?? {};\n *\n * // Append a generated ID (only if server declared payment-identifier)\n * appendPaymentIdentifierToExtensions(extensions);\n *\n * // Or use a custom ID\n * appendPaymentIdentifierToExtensions(extensions, \"pay_my_custom_id_12345\");\n *\n * // Include in PaymentPayload\n * const paymentPayload = {\n * x402Version: 2,\n * resource: paymentRequired.resource,\n * accepted: selectedPaymentOption,\n * payload: { ... },\n * extensions\n * };\n * ```\n */\nexport function appendPaymentIdentifierToExtensions(\n extensions: Record<string, unknown>,\n id?: string,\n): Record<string, unknown> {\n const extension = extensions[PAYMENT_IDENTIFIER];\n\n // Only append if the server declared this extension with valid structure\n if (!isPaymentIdentifierExtension(extension)) {\n return extensions;\n }\n\n const paymentId = id ?? generatePaymentId();\n\n if (!isValidPaymentId(paymentId)) {\n throw new Error(\n `Invalid payment ID: \"${paymentId}\". ` +\n `ID must be 16-128 characters and contain only alphanumeric characters, hyphens, and underscores.`,\n );\n }\n\n // Append the ID to the existing extension info\n extension.info.id = paymentId;\n\n return extensions;\n}\n","/**\n * Resource Server utilities for the Payment-Identifier Extension\n */\n\nimport type { ResourceServerExtension } from \"@x402/core/types\";\nimport type { PaymentIdentifierExtension } from \"./types\";\nimport { PAYMENT_IDENTIFIER } from \"./types\";\nimport { paymentIdentifierSchema } from \"./schema\";\n\n/**\n * Declares the payment-identifier extension for inclusion in PaymentRequired.extensions.\n *\n * Resource servers call this function to advertise support for payment identifiers.\n * The declaration indicates whether a payment identifier is required and includes\n * the schema that clients must follow.\n *\n * @param required - Whether clients must provide a payment identifier. Defaults to false.\n * @returns A PaymentIdentifierExtension object ready for PaymentRequired.extensions\n *\n * @example\n * ```typescript\n * import { declarePaymentIdentifierExtension, PAYMENT_IDENTIFIER } from '@x402/extensions/payment-identifier';\n *\n * // Include in PaymentRequired response (optional identifier)\n * const paymentRequired = {\n * x402Version: 2,\n * resource: { ... },\n * accepts: [ ... ],\n * extensions: {\n * [PAYMENT_IDENTIFIER]: declarePaymentIdentifierExtension()\n * }\n * };\n *\n * // Require payment identifier\n * const paymentRequiredStrict = {\n * x402Version: 2,\n * resource: { ... },\n * accepts: [ ... ],\n * extensions: {\n * [PAYMENT_IDENTIFIER]: declarePaymentIdentifierExtension(true)\n * }\n * };\n * ```\n */\nexport function declarePaymentIdentifierExtension(\n required: boolean = false,\n): PaymentIdentifierExtension {\n return {\n info: { required },\n schema: paymentIdentifierSchema,\n };\n}\n\n/**\n * ResourceServerExtension implementation for payment-identifier.\n *\n * This extension doesn't require any enrichment hooks since the declaration\n * is static. It's provided for consistency with other extensions and for\n * potential future use with the extension registration system.\n *\n * @example\n * ```typescript\n * import { paymentIdentifierResourceServerExtension } from '@x402/extensions/payment-identifier';\n *\n * resourceServer.registerExtension(paymentIdentifierResourceServerExtension);\n * ```\n */\nexport const paymentIdentifierResourceServerExtension: ResourceServerExtension = {\n key: PAYMENT_IDENTIFIER,\n\n // No enrichment needed - the declaration is static\n // Future hooks for idempotency could be added here if needed\n};\n"],"mappings":"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","names":["Ajv"]}
|