@omnixhq/ucp-client 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,1053 @@
1
+ "use strict";
2
+ //#region rolldown:runtime
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+
24
+ //#endregion
25
+ const zod = __toESM(require("zod"));
26
+ const node_crypto = __toESM(require("node:crypto"));
27
+ const __ucp_js_sdk = __toESM(require("@ucp-js/sdk"));
28
+
29
+ //#region src/errors.ts
30
+ /** Thrown when the gateway returns an error response with `messages[]`. */
31
+ var UCPError = class extends Error {
32
+ code;
33
+ type;
34
+ statusCode;
35
+ /** JSONPath to the field that caused the error, from the first message. */
36
+ path;
37
+ contentType;
38
+ /** All messages from the gateway response. */
39
+ messages;
40
+ constructor(code, message, type = "error", statusCode = 400, options = {}) {
41
+ super(message);
42
+ this.name = "UCPError";
43
+ this.code = code;
44
+ this.type = type;
45
+ this.statusCode = statusCode;
46
+ this.path = options.path;
47
+ this.contentType = options.contentType;
48
+ this.messages = options.messages ?? [];
49
+ }
50
+ };
51
+ /** Thrown on HTTP 409 when no `messages[]` body is present (idempotency key collision). */
52
+ var UCPIdempotencyConflictError = class extends UCPError {
53
+ constructor(message = "Idempotency key reused with different request body") {
54
+ super("IDEMPOTENCY_CONFLICT", message, "error", 409);
55
+ this.name = "UCPIdempotencyConflictError";
56
+ }
57
+ };
58
+ /** Thrown when a checkout response has `status: 'requires_escalation'` with a `continue_url`. */
59
+ var UCPEscalationError = class extends Error {
60
+ /** The URL to redirect the buyer to for merchant-hosted checkout UI. */
61
+ continue_url;
62
+ constructor(continue_url, message = "Payment requires escalation") {
63
+ super(message);
64
+ this.name = "UCPEscalationError";
65
+ this.continue_url = continue_url;
66
+ }
67
+ };
68
+ /** Thrown when an OAuth token exchange, refresh, or revocation fails. */
69
+ var UCPOAuthError = class extends Error {
70
+ statusCode;
71
+ constructor(message, statusCode) {
72
+ super(message);
73
+ this.name = "UCPOAuthError";
74
+ this.statusCode = statusCode;
75
+ }
76
+ };
77
+
78
+ //#endregion
79
+ //#region src/http.ts
80
+ var HttpClient = class HttpClient {
81
+ gatewayUrl;
82
+ agentProfileUrl;
83
+ ucpVersion;
84
+ requestSignature;
85
+ accessToken;
86
+ onValidationWarning;
87
+ constructor(config) {
88
+ this.gatewayUrl = config.gatewayUrl;
89
+ this.agentProfileUrl = config.agentProfileUrl;
90
+ this.ucpVersion = config.ucpVersion;
91
+ this.requestSignature = config.requestSignature;
92
+ this.accessToken = config.accessToken;
93
+ this.onValidationWarning = config.onValidationWarning ?? ((msg, detail) => console.warn(msg, detail));
94
+ }
95
+ withAccessToken(token) {
96
+ return new HttpClient({
97
+ gatewayUrl: this.gatewayUrl,
98
+ agentProfileUrl: this.agentProfileUrl,
99
+ ucpVersion: this.ucpVersion,
100
+ ...this.requestSignature !== void 0 ? { requestSignature: this.requestSignature } : {},
101
+ accessToken: token,
102
+ onValidationWarning: this.onValidationWarning
103
+ });
104
+ }
105
+ async request(method, path, body) {
106
+ const url = `${this.gatewayUrl}${path}`;
107
+ const requestId = (0, node_crypto.randomUUID)();
108
+ const headers = {
109
+ "UCP-Agent": `profile="${this.agentProfileUrl}", version="${this.ucpVersion}"`,
110
+ "request-id": requestId
111
+ };
112
+ if (body !== void 0) headers["Content-Type"] = "application/json";
113
+ if (this.requestSignature !== void 0) headers["request-signature"] = this.requestSignature;
114
+ if (this.accessToken !== void 0) headers["Authorization"] = `Bearer ${this.accessToken}`;
115
+ if (method === "POST" || method === "PUT") headers["idempotency-key"] = (0, node_crypto.randomUUID)();
116
+ const res = await fetch(url, {
117
+ method,
118
+ headers,
119
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {}
120
+ });
121
+ const data = await res.json().catch(() => ({}));
122
+ if (!res.ok) this.throwFromResponse(data, res.status);
123
+ return data;
124
+ }
125
+ validate(data, schema) {
126
+ const result = schema.safeParse(data);
127
+ if (!result.success) {
128
+ this.onValidationWarning("[UCPClient] Response validation failed:", result.error.message);
129
+ return data;
130
+ }
131
+ return result.data;
132
+ }
133
+ throwFromResponse(data, statusCode) {
134
+ if (typeof data !== "object" || data === null) {
135
+ if (statusCode === 409) throw new UCPIdempotencyConflictError();
136
+ throw new UCPError("HTTP_ERROR", `Gateway returned ${statusCode}`, "error", statusCode);
137
+ }
138
+ const body = data;
139
+ const rawMessages = body["messages"];
140
+ if (Array.isArray(rawMessages) && rawMessages.length > 0) {
141
+ const allMessages = parseMessages(rawMessages);
142
+ const first = allMessages[0];
143
+ const code = first.code ?? "UNKNOWN";
144
+ throw new UCPError(code, first.content, first.type, statusCode, {
145
+ ...first.path !== void 0 ? { path: first.path } : {},
146
+ ...first.content_type !== void 0 ? { contentType: first.content_type } : {},
147
+ messages: allMessages
148
+ });
149
+ }
150
+ if (statusCode === 409) throw new UCPIdempotencyConflictError();
151
+ throw new UCPError("HTTP_ERROR", `Gateway returned ${statusCode}`, "error", statusCode);
152
+ }
153
+ };
154
+ function parseMessages(rawMessages) {
155
+ return rawMessages.map((m) => {
156
+ const record = m;
157
+ const rawType = String(record["type"] ?? "error");
158
+ const validTypes = [
159
+ "error",
160
+ "warning",
161
+ "info"
162
+ ];
163
+ const type = validTypes.includes(rawType) ? rawType : "error";
164
+ return {
165
+ type,
166
+ content: String(record["content"] ?? "Unknown error"),
167
+ ...record["code"] !== void 0 ? { code: String(record["code"]) } : {},
168
+ ...record["severity"] !== void 0 ? { severity: String(record["severity"]) } : {},
169
+ ...record["path"] !== void 0 ? { path: String(record["path"]) } : {},
170
+ ...record["content_type"] !== void 0 ? { content_type: String(record["content_type"]) } : {}
171
+ };
172
+ });
173
+ }
174
+
175
+ //#endregion
176
+ //#region src/schemas.ts
177
+ const CheckoutSessionSchema = __ucp_js_sdk.ExtendedCheckoutResponseSchema.passthrough();
178
+ const UCPProfileSchema = __ucp_js_sdk.UcpDiscoveryProfileSchema.passthrough();
179
+ const UCPProductSchema = zod.z.object({
180
+ id: zod.z.string(),
181
+ title: zod.z.string(),
182
+ description: zod.z.string().nullable(),
183
+ price_cents: zod.z.number().int(),
184
+ currency: zod.z.string().min(3).max(3),
185
+ in_stock: zod.z.boolean(),
186
+ stock_quantity: zod.z.number().int().min(0),
187
+ images: zod.z.array(zod.z.string().url()),
188
+ variants: zod.z.array(zod.z.object({
189
+ id: zod.z.string(),
190
+ title: zod.z.string(),
191
+ price_cents: zod.z.number().int(),
192
+ in_stock: zod.z.boolean(),
193
+ attributes: zod.z.record(zod.z.string())
194
+ }).passthrough())
195
+ }).passthrough();
196
+ const UCPOrderSchema = zod.z.object({
197
+ id: zod.z.string(),
198
+ status: zod.z.enum([
199
+ "pending",
200
+ "processing",
201
+ "shipped",
202
+ "delivered",
203
+ "canceled"
204
+ ]),
205
+ total_cents: zod.z.number().int(),
206
+ currency: zod.z.string().min(3).max(3),
207
+ created_at_iso: zod.z.string().datetime({ offset: true })
208
+ }).passthrough();
209
+ const CreateCheckoutRequestSchema = __ucp_js_sdk.ExtendedCheckoutCreateRequestSchema.passthrough();
210
+ const UpdateCheckoutRequestSchema = __ucp_js_sdk.ExtendedCheckoutUpdateRequestSchema.passthrough();
211
+ const CompleteCheckoutRequestSchema = zod.z.object({ payment: zod.z.object({ instruments: zod.z.array(zod.z.object({
212
+ id: zod.z.string(),
213
+ handler_id: zod.z.string(),
214
+ type: zod.z.string(),
215
+ selected: zod.z.boolean().optional(),
216
+ credential: zod.z.object({
217
+ type: zod.z.string(),
218
+ token: zod.z.string().optional()
219
+ }).optional(),
220
+ billing_address: zod.z.unknown().optional()
221
+ }).passthrough()) }) });
222
+
223
+ //#endregion
224
+ //#region src/capabilities/checkout.ts
225
+ const DEFAULT_METHOD_ID = "default";
226
+ const DEFAULT_GROUP_ID = "default";
227
+ /**
228
+ * Checkout session operations. Available when the server declares `dev.ucp.shopping.checkout`.
229
+ * Check `extensions` to see which optional features (fulfillment, discount, etc.) are supported.
230
+ */
231
+ var CheckoutCapability = class {
232
+ /** Which checkout extensions the server supports. */
233
+ extensions;
234
+ constructor(http, extensions) {
235
+ this.http = http;
236
+ this.extensions = extensions;
237
+ }
238
+ async create(payload) {
239
+ const data = await this.http.request("POST", "/checkout-sessions", payload);
240
+ return this.validateSession(data);
241
+ }
242
+ async get(id) {
243
+ const data = await this.http.request("GET", `/checkout-sessions/${encodeURIComponent(id)}`);
244
+ return this.validateSession(data);
245
+ }
246
+ async update(id, patch) {
247
+ const data = await this.http.request("PUT", `/checkout-sessions/${encodeURIComponent(id)}`, patch);
248
+ return this.validateSession(data);
249
+ }
250
+ async complete(id, payload) {
251
+ const data = await this.http.request("POST", `/checkout-sessions/${encodeURIComponent(id)}/complete`, payload);
252
+ return this.validateSession(data);
253
+ }
254
+ async cancel(id) {
255
+ const data = await this.http.request("POST", `/checkout-sessions/${encodeURIComponent(id)}/cancel`);
256
+ return this.validateSession(data);
257
+ }
258
+ async setFulfillment(id, type, patch) {
259
+ return this.update(id, {
260
+ ...patch,
261
+ fulfillment: { methods: [{
262
+ id: DEFAULT_METHOD_ID,
263
+ type
264
+ }] }
265
+ });
266
+ }
267
+ async selectDestination(id, destinationId, fulfillmentType = "shipping", patch) {
268
+ return this.update(id, {
269
+ ...patch,
270
+ fulfillment: { methods: [{
271
+ id: DEFAULT_METHOD_ID,
272
+ type: fulfillmentType,
273
+ selected_destination_id: destinationId
274
+ }] }
275
+ });
276
+ }
277
+ async selectFulfillmentOption(id, optionId, destinationId, fulfillmentType = "shipping", patch) {
278
+ return this.update(id, {
279
+ ...patch,
280
+ fulfillment: { methods: [{
281
+ id: DEFAULT_METHOD_ID,
282
+ type: fulfillmentType,
283
+ ...destinationId !== void 0 ? { selected_destination_id: destinationId } : {},
284
+ groups: [{
285
+ id: DEFAULT_GROUP_ID,
286
+ selected_option_id: optionId
287
+ }]
288
+ }] }
289
+ });
290
+ }
291
+ async applyDiscountCodes(id, codes, patch) {
292
+ return this.update(id, {
293
+ ...patch,
294
+ discounts: { codes: [...codes] }
295
+ });
296
+ }
297
+ validateSession(data) {
298
+ const session = this.http.validate(data, CheckoutSessionSchema);
299
+ if (session.status === "requires_escalation" && session.continue_url) throw new UCPEscalationError(session.continue_url);
300
+ return session;
301
+ }
302
+ };
303
+
304
+ //#endregion
305
+ //#region src/capabilities/order.ts
306
+ /** Order operations. Available when the server declares `dev.ucp.shopping.order`. */
307
+ var OrderCapability = class {
308
+ constructor(http) {
309
+ this.http = http;
310
+ }
311
+ /** Retrieve an order by ID. Returns the UCP spec-compliant Order object. */
312
+ async get(id) {
313
+ const data = await this.http.request("GET", `/orders/${encodeURIComponent(id)}`);
314
+ return this.http.validate(data, __ucp_js_sdk.OrderSchema);
315
+ }
316
+ };
317
+
318
+ //#endregion
319
+ //#region src/capabilities/identity-linking.ts
320
+ const TokenResponseSchema = zod.z.object({
321
+ access_token: zod.z.string(),
322
+ token_type: zod.z.string(),
323
+ expires_in: zod.z.number().optional(),
324
+ refresh_token: zod.z.string().optional(),
325
+ scope: zod.z.string().optional()
326
+ }).passthrough();
327
+ /**
328
+ * OAuth 2.0 identity linking for account linking between platforms and merchants.
329
+ * Available when the server declares `dev.ucp.common.identity_linking`.
330
+ */
331
+ var IdentityLinkingCapability = class {
332
+ constructor(metadata) {
333
+ this.metadata = metadata;
334
+ }
335
+ /** Build the OAuth authorization URL to redirect the buyer to. */
336
+ getAuthorizationUrl(params) {
337
+ const url = new URL(this.metadata.authorization_endpoint);
338
+ url.searchParams.set("response_type", "code");
339
+ url.searchParams.set("client_id", params.client_id);
340
+ url.searchParams.set("redirect_uri", params.redirect_uri);
341
+ url.searchParams.set("scope", params.scope ?? "ucp:scopes:checkout_session");
342
+ if (params.state !== void 0) url.searchParams.set("state", params.state);
343
+ return url.toString();
344
+ }
345
+ async exchangeCode(params) {
346
+ const body = new URLSearchParams({
347
+ grant_type: "authorization_code",
348
+ code: params.code,
349
+ redirect_uri: params.redirect_uri
350
+ });
351
+ return this.tokenRequest(params.client_id, params.client_secret, body);
352
+ }
353
+ async refreshToken(params) {
354
+ const body = new URLSearchParams({
355
+ grant_type: "refresh_token",
356
+ refresh_token: params.refresh_token
357
+ });
358
+ return this.tokenRequest(params.client_id, params.client_secret, body);
359
+ }
360
+ async revokeToken(params) {
361
+ const body = new URLSearchParams({ token: params.token });
362
+ if (params.token_type_hint !== void 0) body.set("token_type_hint", params.token_type_hint);
363
+ const res = await fetch(this.metadata.revocation_endpoint, {
364
+ method: "POST",
365
+ headers: {
366
+ "Content-Type": "application/x-www-form-urlencoded",
367
+ Authorization: encodeBasicAuth(params.client_id, params.client_secret)
368
+ },
369
+ body: body.toString()
370
+ });
371
+ if (!res.ok) throw new UCPOAuthError(`Token revocation failed: ${res.status}`, res.status);
372
+ }
373
+ getMetadata() {
374
+ return this.metadata;
375
+ }
376
+ async tokenRequest(clientId, clientSecret, body) {
377
+ const res = await fetch(this.metadata.token_endpoint, {
378
+ method: "POST",
379
+ headers: {
380
+ "Content-Type": "application/x-www-form-urlencoded",
381
+ Authorization: encodeBasicAuth(clientId, clientSecret)
382
+ },
383
+ body: body.toString()
384
+ });
385
+ if (!res.ok) throw new UCPOAuthError(`Token exchange failed with status ${res.status}`, res.status);
386
+ const raw = await res.json();
387
+ const parsed = TokenResponseSchema.safeParse(raw);
388
+ if (!parsed.success) throw new UCPOAuthError(`Invalid token response: ${parsed.error.message}`, res.status);
389
+ return parsed.data;
390
+ }
391
+ };
392
+ function encodeBasicAuth(username, password) {
393
+ return `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
394
+ }
395
+
396
+ //#endregion
397
+ //#region src/capabilities/products.ts
398
+ /** Product catalog search and retrieval. Always available (gateway-specific, not part of UCP spec). */
399
+ var ProductsCapability = class {
400
+ constructor(http) {
401
+ this.http = http;
402
+ }
403
+ /** Search products by query string with optional filters. */
404
+ async search(query, filters = {}) {
405
+ const params = new URLSearchParams({ q: query });
406
+ const filterEntries = [
407
+ ["max_price_cents", filters.max_price_cents],
408
+ ["min_price_cents", filters.min_price_cents],
409
+ ["in_stock", filters.in_stock],
410
+ ["category", filters.category],
411
+ ["limit", filters.limit],
412
+ ["page", filters.page]
413
+ ];
414
+ for (const [key, value] of filterEntries) if (value != null) params.set(key, String(value));
415
+ const res = await this.http.request("GET", `/ucp/products?${params.toString()}`);
416
+ const data = res;
417
+ const products = Array.isArray(data) ? data : data.products ?? [];
418
+ return products.map((p) => this.http.validate(p, UCPProductSchema));
419
+ }
420
+ async get(id) {
421
+ const data = await this.http.request("GET", `/ucp/products/${encodeURIComponent(id)}`);
422
+ return this.http.validate(data, UCPProductSchema);
423
+ }
424
+ };
425
+
426
+ //#endregion
427
+ //#region src/types/config.ts
428
+ const DEFAULT_UCP_VERSION = "2026-01-23";
429
+ const UCP_CAPABILITIES = {
430
+ CHECKOUT: "dev.ucp.shopping.checkout",
431
+ FULFILLMENT: "dev.ucp.shopping.fulfillment",
432
+ DISCOUNT: "dev.ucp.shopping.discount",
433
+ BUYER_CONSENT: "dev.ucp.shopping.buyer_consent",
434
+ ORDER: "dev.ucp.shopping.order",
435
+ IDENTITY_LINKING: "dev.ucp.common.identity_linking",
436
+ AP2_MANDATE: "dev.ucp.shopping.ap2_mandate"
437
+ };
438
+
439
+ //#endregion
440
+ //#region src/agent-tools.ts
441
+ /**
442
+ * Returns ready-to-use tool definitions for agent registration.
443
+ * Only tools supported by the connected server are included.
444
+ *
445
+ * Each tool has:
446
+ * - `name` — unique tool identifier
447
+ * - `description` — what the tool does (for the LLM)
448
+ * - `parameters` — JSON Schema describing the expected input
449
+ * - `execute(params)` — function that calls the right capability method
450
+ *
451
+ * @example
452
+ * ```typescript
453
+ * const client = await UCPClient.connect(config);
454
+ * const tools = getAgentTools(client);
455
+ *
456
+ * // Register with Anthropic Claude API
457
+ * const response = await anthropic.messages.create({
458
+ * tools: tools.map(t => ({
459
+ * name: t.name,
460
+ * description: t.description,
461
+ * input_schema: t.parameters,
462
+ * })),
463
+ * // ...
464
+ * });
465
+ *
466
+ * // Execute tool calls
467
+ * for (const block of response.content) {
468
+ * if (block.type === 'tool_use') {
469
+ * const tool = tools.find(t => t.name === block.name);
470
+ * const result = await tool.execute(block.input);
471
+ * }
472
+ * }
473
+ * ```
474
+ */
475
+ function getAgentTools(client) {
476
+ const tools = [...productTools(client)];
477
+ if (client.checkout) {
478
+ tools.push(...checkoutTools(client));
479
+ if (client.checkout.extensions.fulfillment) tools.push(...fulfillmentTools(client));
480
+ if (client.checkout.extensions.discount) tools.push(...discountTools(client));
481
+ }
482
+ if (client.order) tools.push(...orderTools(client));
483
+ return tools;
484
+ }
485
+ function productTools(client) {
486
+ return [{
487
+ name: "search_products",
488
+ description: "Search the product catalog by query string. Returns matching products with prices, availability, and images.",
489
+ parameters: {
490
+ type: "object",
491
+ properties: {
492
+ query: {
493
+ type: "string",
494
+ description: "Search query (e.g., \"running shoes\")"
495
+ },
496
+ max_price_cents: {
497
+ type: "number",
498
+ description: "Maximum price in cents"
499
+ },
500
+ min_price_cents: {
501
+ type: "number",
502
+ description: "Minimum price in cents"
503
+ },
504
+ in_stock: {
505
+ type: "boolean",
506
+ description: "Filter to in-stock items only"
507
+ },
508
+ category: {
509
+ type: "string",
510
+ description: "Product category"
511
+ },
512
+ limit: {
513
+ type: "number",
514
+ description: "Max results to return"
515
+ }
516
+ },
517
+ required: ["query"]
518
+ },
519
+ execute: async (params) => {
520
+ const { query,...filters } = params;
521
+ return client.products.search(query, filters);
522
+ }
523
+ }, {
524
+ name: "get_product",
525
+ description: "Get detailed product information by ID, including variants, images, and stock.",
526
+ parameters: {
527
+ type: "object",
528
+ properties: { id: {
529
+ type: "string",
530
+ description: "Product ID"
531
+ } },
532
+ required: ["id"]
533
+ },
534
+ execute: async (params) => client.products.get(params["id"])
535
+ }];
536
+ }
537
+ function checkoutTools(client) {
538
+ return [
539
+ {
540
+ name: "create_checkout",
541
+ description: "Create a new checkout session with line items. Returns a session with an ID to use in subsequent calls.",
542
+ parameters: {
543
+ type: "object",
544
+ properties: {
545
+ line_items: {
546
+ type: "array",
547
+ description: "Products to purchase",
548
+ items: {
549
+ type: "object",
550
+ properties: {
551
+ item: {
552
+ type: "object",
553
+ properties: { id: {
554
+ type: "string",
555
+ description: "Product ID"
556
+ } },
557
+ required: ["id"]
558
+ },
559
+ quantity: {
560
+ type: "number",
561
+ description: "Quantity to purchase"
562
+ }
563
+ },
564
+ required: ["item", "quantity"]
565
+ }
566
+ },
567
+ currency: {
568
+ type: "string",
569
+ description: "ISO 4217 currency code (e.g., \"USD\")"
570
+ }
571
+ },
572
+ required: ["line_items"]
573
+ },
574
+ execute: async (params) => client.checkout.create(params)
575
+ },
576
+ {
577
+ name: "get_checkout",
578
+ description: "Get the current state of a checkout session, including status, totals, and available options.",
579
+ parameters: {
580
+ type: "object",
581
+ properties: { id: {
582
+ type: "string",
583
+ description: "Checkout session ID"
584
+ } },
585
+ required: ["id"]
586
+ },
587
+ execute: async (params) => client.checkout.get(params["id"])
588
+ },
589
+ {
590
+ name: "update_checkout",
591
+ description: "Update a checkout session with buyer information, shipping address, or payment details.",
592
+ parameters: {
593
+ type: "object",
594
+ properties: {
595
+ id: {
596
+ type: "string",
597
+ description: "Checkout session ID"
598
+ },
599
+ buyer: {
600
+ type: "object",
601
+ description: "Buyer contact information",
602
+ properties: {
603
+ first_name: { type: "string" },
604
+ last_name: { type: "string" },
605
+ email: { type: "string" },
606
+ phone_number: { type: "string" }
607
+ }
608
+ },
609
+ context: {
610
+ type: "object",
611
+ description: "Localization context for pricing and availability",
612
+ properties: {
613
+ address_country: {
614
+ type: "string",
615
+ description: "ISO 3166-1 alpha-2 country code"
616
+ },
617
+ address_region: {
618
+ type: "string",
619
+ description: "State or province"
620
+ },
621
+ postal_code: { type: "string" }
622
+ }
623
+ }
624
+ },
625
+ required: ["id"]
626
+ },
627
+ execute: async (params) => {
628
+ const { id,...patch } = params;
629
+ return client.checkout.update(id, patch);
630
+ }
631
+ },
632
+ {
633
+ name: "complete_checkout",
634
+ description: "Complete a checkout session with payment. Places the order. Returns the completed session with order ID.",
635
+ parameters: {
636
+ type: "object",
637
+ properties: {
638
+ id: {
639
+ type: "string",
640
+ description: "Checkout session ID"
641
+ },
642
+ payment: {
643
+ type: "object",
644
+ description: "Payment information",
645
+ properties: { instruments: {
646
+ type: "array",
647
+ items: {
648
+ type: "object",
649
+ properties: {
650
+ id: {
651
+ type: "string",
652
+ description: "Instrument ID"
653
+ },
654
+ handler_id: {
655
+ type: "string",
656
+ description: "Payment handler ID from the server profile"
657
+ },
658
+ type: {
659
+ type: "string",
660
+ description: "Payment type (e.g., \"card\", \"offline\")"
661
+ },
662
+ credential: {
663
+ type: "object",
664
+ properties: {
665
+ type: {
666
+ type: "string",
667
+ description: "Credential type (e.g., \"token\")"
668
+ },
669
+ token: {
670
+ type: "string",
671
+ description: "Payment token"
672
+ }
673
+ },
674
+ required: ["type"]
675
+ }
676
+ },
677
+ required: [
678
+ "id",
679
+ "handler_id",
680
+ "type"
681
+ ]
682
+ }
683
+ } },
684
+ required: ["instruments"]
685
+ }
686
+ },
687
+ required: ["id", "payment"]
688
+ },
689
+ execute: async (params) => {
690
+ const { id,...payload } = params;
691
+ return client.checkout.complete(String(id), payload);
692
+ }
693
+ },
694
+ {
695
+ name: "cancel_checkout",
696
+ description: "Cancel a checkout session. The session cannot be used after cancellation.",
697
+ parameters: {
698
+ type: "object",
699
+ properties: { id: {
700
+ type: "string",
701
+ description: "Checkout session ID"
702
+ } },
703
+ required: ["id"]
704
+ },
705
+ execute: async (params) => client.checkout.cancel(params["id"])
706
+ }
707
+ ];
708
+ }
709
+ function fulfillmentTools(client) {
710
+ return [
711
+ {
712
+ name: "set_fulfillment",
713
+ description: "Set the fulfillment method for a checkout (e.g., \"shipping\" or \"pickup\").",
714
+ parameters: {
715
+ type: "object",
716
+ properties: {
717
+ id: {
718
+ type: "string",
719
+ description: "Checkout session ID"
720
+ },
721
+ type: {
722
+ type: "string",
723
+ enum: ["shipping", "pickup"],
724
+ description: "Fulfillment method"
725
+ }
726
+ },
727
+ required: ["id", "type"]
728
+ },
729
+ execute: async (params) => client.checkout.setFulfillment(params["id"], params["type"])
730
+ },
731
+ {
732
+ name: "select_destination",
733
+ description: "Select a shipping destination for a checkout session.",
734
+ parameters: {
735
+ type: "object",
736
+ properties: {
737
+ id: {
738
+ type: "string",
739
+ description: "Checkout session ID"
740
+ },
741
+ destination_id: {
742
+ type: "string",
743
+ description: "Destination ID to select"
744
+ },
745
+ fulfillment_type: {
746
+ type: "string",
747
+ default: "shipping",
748
+ description: "Fulfillment type"
749
+ }
750
+ },
751
+ required: ["id", "destination_id"]
752
+ },
753
+ execute: async (params) => client.checkout.selectDestination(params["id"], params["destination_id"], params["fulfillment_type"] ?? "shipping")
754
+ },
755
+ {
756
+ name: "select_fulfillment_option",
757
+ description: "Select a fulfillment option (e.g., standard shipping, express shipping) for a checkout session.",
758
+ parameters: {
759
+ type: "object",
760
+ properties: {
761
+ id: {
762
+ type: "string",
763
+ description: "Checkout session ID"
764
+ },
765
+ option_id: {
766
+ type: "string",
767
+ description: "Fulfillment option ID to select"
768
+ },
769
+ destination_id: {
770
+ type: "string",
771
+ description: "Destination ID (if applicable)"
772
+ },
773
+ fulfillment_type: {
774
+ type: "string",
775
+ default: "shipping",
776
+ description: "Fulfillment type"
777
+ }
778
+ },
779
+ required: ["id", "option_id"]
780
+ },
781
+ execute: async (params) => client.checkout.selectFulfillmentOption(params["id"], params["option_id"], params["destination_id"], params["fulfillment_type"] ?? "shipping")
782
+ }
783
+ ];
784
+ }
785
+ function discountTools(client) {
786
+ return [{
787
+ name: "apply_discount_codes",
788
+ description: "Apply one or more discount codes to a checkout session.",
789
+ parameters: {
790
+ type: "object",
791
+ properties: {
792
+ id: {
793
+ type: "string",
794
+ description: "Checkout session ID"
795
+ },
796
+ codes: {
797
+ type: "array",
798
+ items: { type: "string" },
799
+ description: "Discount codes to apply"
800
+ }
801
+ },
802
+ required: ["id", "codes"]
803
+ },
804
+ execute: async (params) => client.checkout.applyDiscountCodes(params["id"], params["codes"])
805
+ }];
806
+ }
807
+ function orderTools(client) {
808
+ return [{
809
+ name: "get_order",
810
+ description: "Get order details by ID, including line items, fulfillment status, and tracking information.",
811
+ parameters: {
812
+ type: "object",
813
+ properties: { id: {
814
+ type: "string",
815
+ description: "Order ID"
816
+ } },
817
+ required: ["id"]
818
+ },
819
+ execute: async (params) => client.order.get(params["id"])
820
+ }];
821
+ }
822
+
823
+ //#endregion
824
+ //#region src/UCPClient.ts
825
+ /**
826
+ * Connect to a UCP server, discover its capabilities, and return a {@link ConnectedClient}.
827
+ *
828
+ * @example
829
+ * ```typescript
830
+ * const client = await connect({
831
+ * gatewayUrl: 'https://store.example.com/ucp',
832
+ * agentProfileUrl: 'https://platform.example.com/.well-known/ucp',
833
+ * });
834
+ *
835
+ * if (client.checkout) {
836
+ * const session = await client.checkout.create({ line_items: [...] });
837
+ * }
838
+ * ```
839
+ */
840
+ async function connect(config, options) {
841
+ validateConfig(config);
842
+ const http = new HttpClient({
843
+ gatewayUrl: config.gatewayUrl.replace(/\/+$/, ""),
844
+ agentProfileUrl: config.agentProfileUrl,
845
+ ucpVersion: config.ucpVersion ?? DEFAULT_UCP_VERSION,
846
+ ...config.requestSignature !== void 0 ? { requestSignature: config.requestSignature } : {},
847
+ ...options?.onValidationWarning !== void 0 ? { onValidationWarning: options.onValidationWarning } : {}
848
+ });
849
+ const rawProfile = await http.request("GET", "/.well-known/ucp");
850
+ const profile = http.validate(rawProfile, UCPProfileSchema);
851
+ const capabilityNames = extractCapabilityNames(profile);
852
+ const checkout = buildCheckoutCapability(http, capabilityNames);
853
+ const order = capabilityNames.has(UCP_CAPABILITIES.ORDER) ? new OrderCapability(http) : null;
854
+ const identityLinking = await buildIdentityLinking(config, capabilityNames);
855
+ const products = new ProductsCapability(http);
856
+ const paymentHandlers = extractPaymentHandlers(profile);
857
+ const client = {
858
+ profile,
859
+ checkout,
860
+ order,
861
+ identityLinking,
862
+ products,
863
+ paymentHandlers,
864
+ describeTools: () => buildToolDescriptors(checkout, order, identityLinking),
865
+ getAgentTools: () => getAgentTools(client)
866
+ };
867
+ return Object.freeze(client);
868
+ }
869
+ /**
870
+ * UCP client entry point. Use `UCPClient.connect()` to discover server capabilities
871
+ * and get a {@link ConnectedClient}.
872
+ *
873
+ * @example
874
+ * ```typescript
875
+ * const client = await UCPClient.connect({
876
+ * gatewayUrl: 'https://store.example.com/ucp',
877
+ * agentProfileUrl: 'https://platform.example.com/.well-known/ucp',
878
+ * });
879
+ * ```
880
+ */
881
+ var UCPClient = class {
882
+ constructor() {}
883
+ static connect = connect;
884
+ };
885
+ function validateConfig(config) {
886
+ new URL(config.gatewayUrl);
887
+ if (config.agentProfileUrl.includes("\"") || config.agentProfileUrl.includes("\n")) throw new Error("agentProfileUrl must not contain double quotes or newlines");
888
+ new URL(config.agentProfileUrl);
889
+ }
890
+ function extractCapabilityNames(profile) {
891
+ const capabilities = profile.ucp?.capabilities;
892
+ if (!Array.isArray(capabilities)) return new Set();
893
+ return new Set(capabilities.map((c) => c.name).filter((n) => n !== void 0));
894
+ }
895
+ const PaymentHandlerInstanceSchema = zod.z.object({
896
+ id: zod.z.string(),
897
+ version: zod.z.string(),
898
+ spec: zod.z.string(),
899
+ schema: zod.z.string(),
900
+ config: zod.z.record(zod.z.unknown()).optional()
901
+ }).passthrough();
902
+ const PaymentHandlerMapSchema = zod.z.record(zod.z.array(PaymentHandlerInstanceSchema));
903
+ function extractPaymentHandlers(profile) {
904
+ const raw = profile["payment_handlers"];
905
+ if (typeof raw !== "object" || raw === null) return {};
906
+ const result = PaymentHandlerMapSchema.safeParse(raw);
907
+ if (!result.success) return {};
908
+ return result.data;
909
+ }
910
+ function buildCheckoutCapability(http, capabilityNames) {
911
+ if (!capabilityNames.has(UCP_CAPABILITIES.CHECKOUT)) return null;
912
+ const extensions = {
913
+ fulfillment: capabilityNames.has(UCP_CAPABILITIES.FULFILLMENT),
914
+ discount: capabilityNames.has(UCP_CAPABILITIES.DISCOUNT),
915
+ buyerConsent: capabilityNames.has(UCP_CAPABILITIES.BUYER_CONSENT),
916
+ ap2Mandate: capabilityNames.has(UCP_CAPABILITIES.AP2_MANDATE)
917
+ };
918
+ return new CheckoutCapability(http, extensions);
919
+ }
920
+ const OAuthServerMetadataSchema = zod.z.object({
921
+ issuer: zod.z.string(),
922
+ authorization_endpoint: zod.z.string().url(),
923
+ token_endpoint: zod.z.string().url(),
924
+ revocation_endpoint: zod.z.string().url(),
925
+ scopes_supported: zod.z.array(zod.z.string()),
926
+ response_types_supported: zod.z.array(zod.z.string()),
927
+ grant_types_supported: zod.z.array(zod.z.string()),
928
+ token_endpoint_auth_methods_supported: zod.z.array(zod.z.string()),
929
+ service_documentation: zod.z.string().url().optional()
930
+ }).passthrough();
931
+ async function buildIdentityLinking(config, capabilityNames) {
932
+ if (!capabilityNames.has(UCP_CAPABILITIES.IDENTITY_LINKING)) return null;
933
+ const gatewayUrl = config.gatewayUrl.replace(/\/+$/, "");
934
+ const metadataUrl = `${gatewayUrl}/.well-known/oauth-authorization-server`;
935
+ const res = await fetch(metadataUrl);
936
+ if (!res.ok) throw new Error(`Identity linking capability declared but OAuth metadata fetch failed: ${res.status} from ${metadataUrl}`);
937
+ const raw = await res.json();
938
+ const parsed = OAuthServerMetadataSchema.safeParse(raw);
939
+ if (!parsed.success) throw new Error(`Identity linking OAuth metadata validation failed: ${parsed.error.message}`);
940
+ return new IdentityLinkingCapability(parsed.data);
941
+ }
942
+ function buildToolDescriptors(checkout, order, identityLinking) {
943
+ const tools = [{
944
+ name: "search_products",
945
+ capability: "products",
946
+ description: "Search product catalog"
947
+ }, {
948
+ name: "get_product",
949
+ capability: "products",
950
+ description: "Get product by ID"
951
+ }];
952
+ if (checkout) {
953
+ tools.push({
954
+ name: "create_checkout",
955
+ capability: "checkout",
956
+ description: "Create a checkout session"
957
+ }, {
958
+ name: "get_checkout",
959
+ capability: "checkout",
960
+ description: "Get checkout session by ID"
961
+ }, {
962
+ name: "update_checkout",
963
+ capability: "checkout",
964
+ description: "Update a checkout session"
965
+ }, {
966
+ name: "complete_checkout",
967
+ capability: "checkout",
968
+ description: "Complete checkout with payment"
969
+ }, {
970
+ name: "cancel_checkout",
971
+ capability: "checkout",
972
+ description: "Cancel a checkout session"
973
+ });
974
+ if (checkout.extensions.fulfillment) tools.push({
975
+ name: "set_fulfillment",
976
+ capability: "checkout.fulfillment",
977
+ description: "Set fulfillment method (shipping/pickup)"
978
+ }, {
979
+ name: "select_destination",
980
+ capability: "checkout.fulfillment",
981
+ description: "Select shipping destination"
982
+ }, {
983
+ name: "select_fulfillment_option",
984
+ capability: "checkout.fulfillment",
985
+ description: "Select fulfillment option (e.g., express shipping)"
986
+ });
987
+ if (checkout.extensions.discount) tools.push({
988
+ name: "apply_discount_codes",
989
+ capability: "checkout.discount",
990
+ description: "Apply discount codes to checkout"
991
+ });
992
+ }
993
+ if (order) tools.push({
994
+ name: "get_order",
995
+ capability: "order",
996
+ description: "Get order by ID"
997
+ });
998
+ if (identityLinking) tools.push({
999
+ name: "get_authorization_url",
1000
+ capability: "identity_linking",
1001
+ description: "Get OAuth authorization URL for account linking"
1002
+ }, {
1003
+ name: "exchange_auth_code",
1004
+ capability: "identity_linking",
1005
+ description: "Exchange authorization code for access token"
1006
+ }, {
1007
+ name: "refresh_access_token",
1008
+ capability: "identity_linking",
1009
+ description: "Refresh an expired access token"
1010
+ }, {
1011
+ name: "revoke_token",
1012
+ capability: "identity_linking",
1013
+ description: "Revoke an access or refresh token"
1014
+ });
1015
+ return tools;
1016
+ }
1017
+
1018
+ //#endregion
1019
+ exports.BuyerSchema = __ucp_js_sdk.BuyerSchema
1020
+ exports.CheckoutCapability = CheckoutCapability
1021
+ exports.CheckoutResponseStatusSchema = __ucp_js_sdk.CheckoutResponseStatusSchema
1022
+ exports.CheckoutSessionSchema = CheckoutSessionSchema
1023
+ exports.CompleteCheckoutRequestSchema = CompleteCheckoutRequestSchema
1024
+ exports.CreateCheckoutRequestSchema = CreateCheckoutRequestSchema
1025
+ exports.DEFAULT_UCP_VERSION = DEFAULT_UCP_VERSION
1026
+ exports.FulfillmentMethodResponseSchema = __ucp_js_sdk.FulfillmentMethodResponseSchema
1027
+ exports.FulfillmentResponseSchema = __ucp_js_sdk.FulfillmentResponseSchema
1028
+ exports.IdentityLinkingCapability = IdentityLinkingCapability
1029
+ exports.ItemResponseSchema = __ucp_js_sdk.ItemResponseSchema
1030
+ exports.LineItemResponseSchema = __ucp_js_sdk.LineItemResponseSchema
1031
+ exports.MessageErrorSchema = __ucp_js_sdk.MessageErrorSchema
1032
+ exports.MessageSchema = __ucp_js_sdk.MessageSchema
1033
+ exports.OrderCapability = OrderCapability
1034
+ exports.PaymentHandlerResponseSchema = __ucp_js_sdk.PaymentHandlerResponseSchema
1035
+ exports.PaymentInstrumentSchema = __ucp_js_sdk.PaymentInstrumentSchema
1036
+ exports.PaymentResponseSchema = __ucp_js_sdk.PaymentResponseSchema
1037
+ exports.PostalAddressSchema = __ucp_js_sdk.PostalAddressSchema
1038
+ exports.ProductsCapability = ProductsCapability
1039
+ exports.TotalResponseSchema = __ucp_js_sdk.TotalResponseSchema
1040
+ exports.UCPClient = UCPClient
1041
+ exports.UCPError = UCPError
1042
+ exports.UCPEscalationError = UCPEscalationError
1043
+ exports.UCPIdempotencyConflictError = UCPIdempotencyConflictError
1044
+ exports.UCPOAuthError = UCPOAuthError
1045
+ exports.UCPOrderSchema = UCPOrderSchema
1046
+ exports.UCPProductSchema = UCPProductSchema
1047
+ exports.UCPProfileSchema = UCPProfileSchema
1048
+ exports.UCPSpecOrderSchema = __ucp_js_sdk.OrderSchema
1049
+ exports.UCP_CAPABILITIES = UCP_CAPABILITIES
1050
+ exports.UpdateCheckoutRequestSchema = UpdateCheckoutRequestSchema
1051
+ exports.connect = connect
1052
+ exports.getAgentTools = getAgentTools
1053
+ //# sourceMappingURL=index.cjs.map