@reactionary/ucp 0.10.34 → 0.10.36
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/index.js +11 -0
- package/lib/reactionary-ucp-checkout-session.js +603 -0
- package/lib/reactionary-ucp-discounts.js +88 -0
- package/lib/reactionary-ucp-http.js +7 -0
- package/lib/reactionary-ucp-identity.js +2 -7
- package/lib/reactionary-ucp-localization.js +92 -0
- package/lib/reactionary-ucp-mapping.js +182 -0
- package/lib/reactionary-ucp-order.js +152 -0
- package/lib/reactionary-ucp-profile.js +11 -4
- package/lib/reactionary-ucp-rest.js +135 -225
- package/lib/reactionary-ucp-server.js +139 -6
- package/lib/reactionary-ucp-session-store.js +145 -1
- package/lib/reactionary-ucp-signing.js +72 -0
- package/lib/reactionary-ucp-webhooks.js +113 -0
- package/package.json +2 -2
- package/src/index.d.ts +4 -0
- package/src/lib/reactionary-ucp-checkout-session.d.ts +91 -0
- package/src/lib/reactionary-ucp-common.d.ts +93 -1
- package/src/lib/reactionary-ucp-discounts.d.ts +24 -0
- package/src/lib/reactionary-ucp-http.d.ts +2 -0
- package/src/lib/reactionary-ucp-localization.d.ts +35 -0
- package/src/lib/reactionary-ucp-mapping.d.ts +41 -0
- package/src/lib/reactionary-ucp-order.d.ts +77 -0
- package/src/lib/reactionary-ucp-rest.d.ts +27 -1
- package/src/lib/reactionary-ucp-server.d.ts +14 -0
- package/src/lib/reactionary-ucp-session-store.d.ts +191 -0
- package/src/lib/reactionary-ucp-signing.d.ts +27 -0
- package/src/lib/reactionary-ucp-webhooks.d.ts +48 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Address, Cart, Checkout, CostBreakDown, MonetaryAmount, Order } from '@reactionary/core';
|
|
2
|
+
import type { components } from './ucp-shopping.openapi.js';
|
|
3
|
+
import type { UCPPaymentHandlers } from './reactionary-ucp-common.js';
|
|
4
|
+
export declare const UCP_VERSION = "2026-08-25";
|
|
5
|
+
export type UCPCheckout = components['schemas']['checkout'];
|
|
6
|
+
export type UCPLineItem = components['schemas']['line_item'];
|
|
7
|
+
export type UCPMessage = components['schemas']['message'];
|
|
8
|
+
export type UCPTotal = components['schemas']['total'];
|
|
9
|
+
export type UCPPostalAddress = components['schemas']['postal_address'];
|
|
10
|
+
export type UCPSelectedPaymentInstrument = NonNullable<NonNullable<UCPCheckout['payment']>['instruments']>[number];
|
|
11
|
+
export declare function getSelectedPaymentInstrument(checkout: Pick<UCPCheckout, 'payment'>): UCPSelectedPaymentInstrument | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* The buyer-facing order page under the merchant's site. The spec requires a
|
|
14
|
+
* valid URL; without a configured merchant URL there is nothing to link to,
|
|
15
|
+
* and the empty string is left for the caller's schema to flag.
|
|
16
|
+
*/
|
|
17
|
+
export declare function toOrderPermalinkUrl(merchantUrl: string | undefined, orderId: string): string;
|
|
18
|
+
export declare function toReactionaryAddress(address: UCPPostalAddress): Omit<Address, 'identifier'>;
|
|
19
|
+
export type UCPPricedItem = Pick<Cart['items'][number] | Checkout['items'][number] | Order['items'][number], 'identifier' | 'variant' | 'quantity' | 'price'>;
|
|
20
|
+
/** A line's undiscounted amount (unit price × quantity), in minor units. */
|
|
21
|
+
export declare function getLineSubtotal(lineItem: UCPPricedItem): number;
|
|
22
|
+
/** The discount allocated to a line, in minor units. */
|
|
23
|
+
export declare function getLineDiscount(lineItem: UCPPricedItem): number;
|
|
24
|
+
export declare function toUcpCartLineItem(lineItem: UCPPricedItem): UCPLineItem;
|
|
25
|
+
/**
|
|
26
|
+
* Order-level totals. With line items, the subtotal is their undiscounted
|
|
27
|
+
* sum, discounts allocated to lines are reported as `items_discount` and the
|
|
28
|
+
* remainder of the total discount as order-level `discount` (discount
|
|
29
|
+
* extension, "Impact on Line Items and Totals").
|
|
30
|
+
*/
|
|
31
|
+
export declare function toUcpCostTotals(price: CostBreakDown, items?: UCPPricedItem[]): UCPTotal[];
|
|
32
|
+
export declare function toUcpTotals(amount: MonetaryAmount): UCPTotal[];
|
|
33
|
+
export declare function getMoneyValue(amount: MonetaryAmount): number;
|
|
34
|
+
export declare function getMoneyCurrency(amount: MonetaryAmount): string;
|
|
35
|
+
export declare function createUcpSuccessMetadata(): components['schemas']['ucp_$defs-base'] & {
|
|
36
|
+
status: 'success';
|
|
37
|
+
};
|
|
38
|
+
export declare function createUcpCheckoutSuccessMetadata(paymentHandlers: UCPPaymentHandlers): components['schemas']['response_checkout_schema'];
|
|
39
|
+
export declare function createUcpErrorMessage(code: string, message: string, path?: string): UCPMessage;
|
|
40
|
+
export declare function createUCPError<TResponse>(code: string, message: string, path?: string): TResponse;
|
|
41
|
+
export declare function createUcpWarning(code: string, content: string, path: string): UCPMessage;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as z from 'zod';
|
|
2
|
+
import type { ReactionaryUCPClient } from './reactionary-ucp-common.js';
|
|
3
|
+
import { type ReactionaryUCPSessionStore } from './reactionary-ucp-session-store.js';
|
|
4
|
+
import type { ReactionaryUCPWebhooks } from './reactionary-ucp-webhooks.js';
|
|
5
|
+
import type { components } from './ucp-shopping.openapi.js';
|
|
6
|
+
type UCPErrorResponse = components['schemas']['error_response'];
|
|
7
|
+
type UCPOrder = Omit<components['schemas']['order'], '$defs'>;
|
|
8
|
+
export type UCPOrderResponse = UCPOrder | UCPErrorResponse;
|
|
9
|
+
/**
|
|
10
|
+
* The parts of a PUT /orders/{id} body applied by testOrderUpdates: the
|
|
11
|
+
* fulfillment event log and the adjustments, each replaced as a whole.
|
|
12
|
+
*/
|
|
13
|
+
export declare const UCPOrderUpdateSchema: z.ZodObject<{
|
|
14
|
+
fulfillment: z.ZodOptional<z.ZodObject<{
|
|
15
|
+
events: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
16
|
+
id: z.ZodString;
|
|
17
|
+
occurred_at: z.ZodISODateTime;
|
|
18
|
+
type: z.ZodString;
|
|
19
|
+
line_items: z.ZodArray<z.ZodObject<{
|
|
20
|
+
id: z.ZodString;
|
|
21
|
+
quantity: z.ZodInt;
|
|
22
|
+
}, z.core.$strip>>;
|
|
23
|
+
tracking_number: z.ZodOptional<z.ZodString>;
|
|
24
|
+
tracking_url: z.ZodOptional<z.ZodURL>;
|
|
25
|
+
carrier: z.ZodOptional<z.ZodString>;
|
|
26
|
+
description: z.ZodOptional<z.ZodString>;
|
|
27
|
+
}, z.core.$loose>>>;
|
|
28
|
+
}, z.core.$loose>>;
|
|
29
|
+
adjustments: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
30
|
+
id: z.ZodString;
|
|
31
|
+
type: z.ZodString;
|
|
32
|
+
occurred_at: z.ZodISODateTime;
|
|
33
|
+
status: z.ZodEnum<{
|
|
34
|
+
pending: "pending";
|
|
35
|
+
completed: "completed";
|
|
36
|
+
failed: "failed";
|
|
37
|
+
}>;
|
|
38
|
+
line_items: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
39
|
+
id: z.ZodString;
|
|
40
|
+
quantity: z.ZodInt;
|
|
41
|
+
}, z.core.$strip>>>;
|
|
42
|
+
totals: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
43
|
+
type: z.ZodString;
|
|
44
|
+
amount: z.ZodInt;
|
|
45
|
+
}, z.core.$loose>>>;
|
|
46
|
+
description: z.ZodOptional<z.ZodString>;
|
|
47
|
+
}, z.core.$loose>>>;
|
|
48
|
+
}, z.core.$loose>;
|
|
49
|
+
export type UCPOrderUpdate = z.infer<typeof UCPOrderUpdateSchema>;
|
|
50
|
+
export interface UCPOrderContext {
|
|
51
|
+
client: ReactionaryUCPClient;
|
|
52
|
+
store: ReactionaryUCPSessionStore;
|
|
53
|
+
merchantUrl?: string;
|
|
54
|
+
webhooks?: ReactionaryUCPWebhooks;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* The backend scopes orders to the session's identity (the session that
|
|
58
|
+
* placed the order, or a linked identity), so an order this session may not
|
|
59
|
+
* see is not found rather than forbidden.
|
|
60
|
+
*/
|
|
61
|
+
export declare function getOrder(context: UCPOrderContext, orderId: string): Promise<UCPOrderResponse>;
|
|
62
|
+
/**
|
|
63
|
+
* Test-only: records fulfillment events and adjustments on an order placed
|
|
64
|
+
* through a UCP checkout session, as a business would post them.
|
|
65
|
+
*/
|
|
66
|
+
export declare function updateOrder(context: UCPOrderContext, orderId: string, update: UCPOrderUpdate): Promise<UCPOrderResponse>;
|
|
67
|
+
/**
|
|
68
|
+
* Test-only: records a shipment of every line item, as a business would
|
|
69
|
+
* when the order ships, and notifies the platform.
|
|
70
|
+
*/
|
|
71
|
+
export declare function simulateShipping(context: UCPOrderContext, orderId: string): Promise<UCPOrderResponse>;
|
|
72
|
+
/**
|
|
73
|
+
* Sends the "Order created" event for a newly placed order, resolving the
|
|
74
|
+
* platform's webhook URL from its profile.
|
|
75
|
+
*/
|
|
76
|
+
export declare function notifyOrderPlaced(context: UCPOrderContext, orderId: string): Promise<void>;
|
|
77
|
+
export {};
|
|
@@ -1,6 +1,32 @@
|
|
|
1
|
+
import type { Identity } from '@reactionary/core';
|
|
1
2
|
import type { ReactionaryUCPClient, UCPPaymentHandlers } from './reactionary-ucp-common.js';
|
|
3
|
+
import type { ReactionaryUCPWebhooks } from './reactionary-ucp-webhooks.js';
|
|
2
4
|
import type { ReactionaryUCPSessionStore } from './reactionary-ucp-session-store.js';
|
|
3
|
-
|
|
5
|
+
import { type UCPInventoryOptions, type UCPPaymentAuthorizationWait, type UCPTestPaymentHandler } from './reactionary-ucp-checkout-session.js';
|
|
6
|
+
export declare function handleRestRequest(request: Request, client: ReactionaryUCPClient, path: string, sessionId: string, sessionStore: ReactionaryUCPSessionStore, options: UCPRestOptions): Promise<Response | undefined>;
|
|
7
|
+
export interface UCPRestOptions {
|
|
8
|
+
paymentHandlers: UCPPaymentHandlers;
|
|
9
|
+
placeholderEmail: string;
|
|
10
|
+
paymentAuthorizationWait: UCPPaymentAuthorizationWait;
|
|
11
|
+
identity: Identity;
|
|
12
|
+
/** The merchant's site URL, used to build order permalinks. */
|
|
13
|
+
merchantUrl?: string;
|
|
14
|
+
/** See ReactionaryUCPServerOptions.anonymousOrderEmail. */
|
|
15
|
+
anonymousOrderEmail?: string;
|
|
16
|
+
/** See ReactionaryUCPServerOptions.testPaymentHandlers. */
|
|
17
|
+
testPaymentHandlers?: UCPTestPaymentHandler[];
|
|
18
|
+
/** See ReactionaryUCPServerOptions.acceptRawCardCredentials. */
|
|
19
|
+
acceptRawCardCredentials?: boolean;
|
|
20
|
+
/** See ReactionaryUCPServerOptions.inventory. */
|
|
21
|
+
inventory?: UCPInventoryOptions;
|
|
22
|
+
/** See ReactionaryUCPServerOptions.testOrderUpdates. */
|
|
23
|
+
testOrderUpdates?: boolean;
|
|
24
|
+
/** See ReactionaryUCPServerOptions.testSimulationSecret. */
|
|
25
|
+
testSimulationSecret?: string;
|
|
26
|
+
webhooks?: ReactionaryUCPWebhooks;
|
|
27
|
+
/** The requesting platform's UCP-Agent profile URL. */
|
|
28
|
+
agentProfile?: string;
|
|
29
|
+
}
|
|
4
30
|
export declare class UCPHttpError extends Error {
|
|
5
31
|
readonly status: number;
|
|
6
32
|
readonly body: unknown;
|
|
@@ -5,6 +5,7 @@ export declare class ReactionaryUCPServer<TClient extends ReactionaryUCPClient =
|
|
|
5
5
|
private readonly clientFactory;
|
|
6
6
|
private readonly options;
|
|
7
7
|
private readonly sessionStore;
|
|
8
|
+
private readonly webhooks?;
|
|
8
9
|
readonly identity?: ReactionaryUCPIdentity;
|
|
9
10
|
constructor(clientFactory: ReactionaryUCPClientFactory<TClient>, options?: ReactionaryUCPServerOptions);
|
|
10
11
|
fetch(request: Request): Promise<Response>;
|
|
@@ -12,6 +13,19 @@ export declare class ReactionaryUCPServer<TClient extends ReactionaryUCPClient =
|
|
|
12
13
|
getHandler(): ReactionaryUCPHttpHandler;
|
|
13
14
|
toNodeHandler(): ReactionaryUCPNodeRequestHandler;
|
|
14
15
|
close(): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Requests addressing a cart or checkout session resume the session that
|
|
18
|
+
* created it: agents rarely echo the UCP session header, but backends scope
|
|
19
|
+
* carts to that session's (anonymous) identity.
|
|
20
|
+
*/
|
|
21
|
+
private resolveSessionId;
|
|
22
|
+
/**
|
|
23
|
+
* Orders resume the session that placed them only for the platform that
|
|
24
|
+
* completed the checkout (order capability: the business verifies the
|
|
25
|
+
* requesting platform created the checkout). Any other request runs in its
|
|
26
|
+
* own session, where the backend does not find the order.
|
|
27
|
+
*/
|
|
28
|
+
private resolveOrderSessionId;
|
|
15
29
|
private createRequestContext;
|
|
16
30
|
private handleRequest;
|
|
17
31
|
}
|
|
@@ -1,5 +1,184 @@
|
|
|
1
1
|
import { type Cache, type Session } from '@reactionary/core';
|
|
2
2
|
import * as z from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* Buyer consent per purpose (buyer consent extension): the spec's purpose
|
|
5
|
+
* map ({ granted, source, segments }), or the flat booleans of earlier
|
|
6
|
+
* versions still used by the conformance SDK (e.g. { marketing: true }).
|
|
7
|
+
*/
|
|
8
|
+
export declare const UCPBuyerConsentSchema: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
9
|
+
granted: z.ZodBoolean;
|
|
10
|
+
source: z.ZodEnum<{
|
|
11
|
+
business: "business";
|
|
12
|
+
platform: "platform";
|
|
13
|
+
}>;
|
|
14
|
+
segments: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
15
|
+
granted: z.ZodBoolean;
|
|
16
|
+
source: z.ZodEnum<{
|
|
17
|
+
business: "business";
|
|
18
|
+
platform: "platform";
|
|
19
|
+
}>;
|
|
20
|
+
}, z.core.$loose>>>;
|
|
21
|
+
}, z.core.$loose>]>>;
|
|
22
|
+
export declare const UCPCheckoutSessionStateSchema: z.ZodObject<{
|
|
23
|
+
id: z.ZodString;
|
|
24
|
+
cartId: z.ZodString;
|
|
25
|
+
status: z.ZodEnum<{
|
|
26
|
+
canceled: "canceled";
|
|
27
|
+
complete_in_progress: "complete_in_progress";
|
|
28
|
+
completed: "completed";
|
|
29
|
+
open: "open";
|
|
30
|
+
}>;
|
|
31
|
+
buyer: z.ZodOptional<z.ZodObject<{
|
|
32
|
+
first_name: z.ZodOptional<z.ZodString>;
|
|
33
|
+
last_name: z.ZodOptional<z.ZodString>;
|
|
34
|
+
email: z.ZodOptional<z.ZodString>;
|
|
35
|
+
phone_number: z.ZodOptional<z.ZodString>;
|
|
36
|
+
/** Round-tripped only; not persisted beyond the session yet. */
|
|
37
|
+
consent: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
38
|
+
granted: z.ZodBoolean;
|
|
39
|
+
source: z.ZodEnum<{
|
|
40
|
+
business: "business";
|
|
41
|
+
platform: "platform";
|
|
42
|
+
}>;
|
|
43
|
+
segments: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
44
|
+
granted: z.ZodBoolean;
|
|
45
|
+
source: z.ZodEnum<{
|
|
46
|
+
business: "business";
|
|
47
|
+
platform: "platform";
|
|
48
|
+
}>;
|
|
49
|
+
}, z.core.$loose>>>;
|
|
50
|
+
}, z.core.$loose>]>>>;
|
|
51
|
+
}, z.core.$loose>>;
|
|
52
|
+
billingAddress: z.ZodOptional<z.ZodObject<{
|
|
53
|
+
id: z.ZodOptional<z.ZodString>;
|
|
54
|
+
first_name: z.ZodOptional<z.ZodString>;
|
|
55
|
+
last_name: z.ZodOptional<z.ZodString>;
|
|
56
|
+
street_address: z.ZodOptional<z.ZodString>;
|
|
57
|
+
extended_address: z.ZodOptional<z.ZodString>;
|
|
58
|
+
address_locality: z.ZodOptional<z.ZodString>;
|
|
59
|
+
address_region: z.ZodOptional<z.ZodString>;
|
|
60
|
+
address_country: z.ZodOptional<z.ZodString>;
|
|
61
|
+
postal_code: z.ZodOptional<z.ZodString>;
|
|
62
|
+
phone_number: z.ZodOptional<z.ZodString>;
|
|
63
|
+
}, z.core.$loose>>;
|
|
64
|
+
destination: z.ZodOptional<z.ZodObject<{
|
|
65
|
+
id: z.ZodOptional<z.ZodString>;
|
|
66
|
+
first_name: z.ZodOptional<z.ZodString>;
|
|
67
|
+
last_name: z.ZodOptional<z.ZodString>;
|
|
68
|
+
street_address: z.ZodOptional<z.ZodString>;
|
|
69
|
+
extended_address: z.ZodOptional<z.ZodString>;
|
|
70
|
+
address_locality: z.ZodOptional<z.ZodString>;
|
|
71
|
+
address_region: z.ZodOptional<z.ZodString>;
|
|
72
|
+
address_country: z.ZodOptional<z.ZodString>;
|
|
73
|
+
postal_code: z.ZodOptional<z.ZodString>;
|
|
74
|
+
phone_number: z.ZodOptional<z.ZodString>;
|
|
75
|
+
}, z.core.$loose>>;
|
|
76
|
+
selectedOptionId: z.ZodOptional<z.ZodString>;
|
|
77
|
+
/** The selected fulfillment option's title, as last shown to the agent. */
|
|
78
|
+
selectedOptionTitle: z.ZodOptional<z.ZodString>;
|
|
79
|
+
instrument: z.ZodOptional<z.ZodObject<{
|
|
80
|
+
id: z.ZodString;
|
|
81
|
+
handler_id: z.ZodString;
|
|
82
|
+
type: z.ZodString;
|
|
83
|
+
}, z.core.$loose>>;
|
|
84
|
+
lastTotal: z.ZodOptional<z.ZodNumber>;
|
|
85
|
+
finalCheckoutId: z.ZodOptional<z.ZodString>;
|
|
86
|
+
orderId: z.ZodOptional<z.ZodString>;
|
|
87
|
+
}, z.core.$loose>;
|
|
88
|
+
export type UCPCheckoutSessionState = z.infer<typeof UCPCheckoutSessionStateSchema>;
|
|
89
|
+
export declare const UCPFulfillmentEventSchema: z.ZodObject<{
|
|
90
|
+
id: z.ZodString;
|
|
91
|
+
occurred_at: z.ZodISODateTime;
|
|
92
|
+
type: z.ZodString;
|
|
93
|
+
line_items: z.ZodArray<z.ZodObject<{
|
|
94
|
+
id: z.ZodString;
|
|
95
|
+
quantity: z.ZodInt;
|
|
96
|
+
}, z.core.$strip>>;
|
|
97
|
+
tracking_number: z.ZodOptional<z.ZodString>;
|
|
98
|
+
tracking_url: z.ZodOptional<z.ZodURL>;
|
|
99
|
+
carrier: z.ZodOptional<z.ZodString>;
|
|
100
|
+
description: z.ZodOptional<z.ZodString>;
|
|
101
|
+
}, z.core.$loose>;
|
|
102
|
+
export declare const UCPAdjustmentSchema: z.ZodObject<{
|
|
103
|
+
id: z.ZodString;
|
|
104
|
+
type: z.ZodString;
|
|
105
|
+
occurred_at: z.ZodISODateTime;
|
|
106
|
+
status: z.ZodEnum<{
|
|
107
|
+
pending: "pending";
|
|
108
|
+
completed: "completed";
|
|
109
|
+
failed: "failed";
|
|
110
|
+
}>;
|
|
111
|
+
line_items: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
112
|
+
id: z.ZodString;
|
|
113
|
+
quantity: z.ZodInt;
|
|
114
|
+
}, z.core.$strip>>>;
|
|
115
|
+
totals: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
116
|
+
type: z.ZodString;
|
|
117
|
+
amount: z.ZodInt;
|
|
118
|
+
}, z.core.$loose>>>;
|
|
119
|
+
description: z.ZodOptional<z.ZodString>;
|
|
120
|
+
}, z.core.$loose>;
|
|
121
|
+
/**
|
|
122
|
+
* What UCP knows about an order placed through a checkout session: its
|
|
123
|
+
* origin, the fulfillment the agent selected, and (with testOrderUpdates)
|
|
124
|
+
* the events and adjustments posted to it.
|
|
125
|
+
*/
|
|
126
|
+
export declare const UCPOrderStateSchema: z.ZodObject<{
|
|
127
|
+
id: z.ZodString;
|
|
128
|
+
checkoutSessionId: z.ZodString;
|
|
129
|
+
/** The UCP session that completed the checkout and owns the order. */
|
|
130
|
+
sessionId: z.ZodString;
|
|
131
|
+
/** The UCP-Agent profile of the platform that completed the checkout. */
|
|
132
|
+
agentProfile: z.ZodOptional<z.ZodString>;
|
|
133
|
+
/** The order webhook URL from the platform's profile, resolved at placement. */
|
|
134
|
+
webhookUrl: z.ZodOptional<z.ZodString>;
|
|
135
|
+
destination: z.ZodOptional<z.ZodObject<{
|
|
136
|
+
id: z.ZodOptional<z.ZodString>;
|
|
137
|
+
first_name: z.ZodOptional<z.ZodString>;
|
|
138
|
+
last_name: z.ZodOptional<z.ZodString>;
|
|
139
|
+
street_address: z.ZodOptional<z.ZodString>;
|
|
140
|
+
extended_address: z.ZodOptional<z.ZodString>;
|
|
141
|
+
address_locality: z.ZodOptional<z.ZodString>;
|
|
142
|
+
address_region: z.ZodOptional<z.ZodString>;
|
|
143
|
+
address_country: z.ZodOptional<z.ZodString>;
|
|
144
|
+
postal_code: z.ZodOptional<z.ZodString>;
|
|
145
|
+
phone_number: z.ZodOptional<z.ZodString>;
|
|
146
|
+
}, z.core.$loose>>;
|
|
147
|
+
fulfillmentTitle: z.ZodOptional<z.ZodString>;
|
|
148
|
+
events: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
149
|
+
id: z.ZodString;
|
|
150
|
+
occurred_at: z.ZodISODateTime;
|
|
151
|
+
type: z.ZodString;
|
|
152
|
+
line_items: z.ZodArray<z.ZodObject<{
|
|
153
|
+
id: z.ZodString;
|
|
154
|
+
quantity: z.ZodInt;
|
|
155
|
+
}, z.core.$strip>>;
|
|
156
|
+
tracking_number: z.ZodOptional<z.ZodString>;
|
|
157
|
+
tracking_url: z.ZodOptional<z.ZodURL>;
|
|
158
|
+
carrier: z.ZodOptional<z.ZodString>;
|
|
159
|
+
description: z.ZodOptional<z.ZodString>;
|
|
160
|
+
}, z.core.$loose>>>;
|
|
161
|
+
adjustments: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
162
|
+
id: z.ZodString;
|
|
163
|
+
type: z.ZodString;
|
|
164
|
+
occurred_at: z.ZodISODateTime;
|
|
165
|
+
status: z.ZodEnum<{
|
|
166
|
+
pending: "pending";
|
|
167
|
+
completed: "completed";
|
|
168
|
+
failed: "failed";
|
|
169
|
+
}>;
|
|
170
|
+
line_items: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
171
|
+
id: z.ZodString;
|
|
172
|
+
quantity: z.ZodInt;
|
|
173
|
+
}, z.core.$strip>>>;
|
|
174
|
+
totals: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
175
|
+
type: z.ZodString;
|
|
176
|
+
amount: z.ZodInt;
|
|
177
|
+
}, z.core.$loose>>>;
|
|
178
|
+
description: z.ZodOptional<z.ZodString>;
|
|
179
|
+
}, z.core.$loose>>>;
|
|
180
|
+
}, z.core.$loose>;
|
|
181
|
+
export type UCPOrderState = z.output<typeof UCPOrderStateSchema>;
|
|
3
182
|
declare const UCPIdempotencyRecordSchema: z.ZodObject<{
|
|
4
183
|
action: z.ZodString;
|
|
5
184
|
fingerprint: z.ZodOptional<z.ZodString>;
|
|
@@ -15,6 +194,18 @@ export declare class ReactionaryUCPSessionStore {
|
|
|
15
194
|
put(sessionId: string, session: Session): Promise<void>;
|
|
16
195
|
getIdempotencyRecord(sessionId: string, idempotencyKey: string): Promise<UCPIdempotencyRecord | undefined>;
|
|
17
196
|
putIdempotencyRecord(sessionId: string, idempotencyKey: string, record: UCPIdempotencyRecord): Promise<void>;
|
|
197
|
+
getCheckoutSession(checkoutSessionId: string): Promise<UCPCheckoutSessionState | undefined>;
|
|
198
|
+
putCheckoutSession(state: UCPCheckoutSessionState): Promise<void>;
|
|
199
|
+
getOrder(orderId: string): Promise<UCPOrderState | undefined>;
|
|
200
|
+
putOrder(state: UCPOrderState): Promise<void>;
|
|
201
|
+
/**
|
|
202
|
+
* Binds a created resource (cart or checkout session) to the UCP session
|
|
203
|
+
* that owns its backend state. Agents address resources by id and rarely
|
|
204
|
+
* echo the UCP session header, yet backends scope carts to the session's
|
|
205
|
+
* (anonymous) identity, so later requests must resume the owning session.
|
|
206
|
+
*/
|
|
207
|
+
bindResource(resourceId: string, sessionId: string): Promise<void>;
|
|
208
|
+
getResourceSession(resourceId: string): Promise<string | undefined>;
|
|
18
209
|
private getCacheKey;
|
|
19
210
|
private getDependencyId;
|
|
20
211
|
private getIdempotencyCacheKey;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type JsonWebKey } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* A business signing key for UCP message signatures (RFC 9421). Its public
|
|
4
|
+
* part must be published under `keys` in the business profile; see
|
|
5
|
+
* toPublicSigningJwk.
|
|
6
|
+
*/
|
|
7
|
+
export interface UCPSigningKey {
|
|
8
|
+
/** The key id, referenced as `keyid` in signatures and `kid` in the profile. */
|
|
9
|
+
kid: string;
|
|
10
|
+
/** The private key as a JWK: EC P-256 (ES256), EC P-384 (ES384) or OKP Ed25519. */
|
|
11
|
+
privateKeyJwk: JsonWebKey;
|
|
12
|
+
}
|
|
13
|
+
export interface UCPSignableRequest {
|
|
14
|
+
method: string;
|
|
15
|
+
url: string;
|
|
16
|
+
/** Request headers by lower-case name; signed when listed as components. */
|
|
17
|
+
headers: Record<string, string>;
|
|
18
|
+
body: string;
|
|
19
|
+
}
|
|
20
|
+
/** The public JWK to publish in the business profile's `keys` for a signing key. */
|
|
21
|
+
export declare function toPublicSigningJwk(key: UCPSigningKey): Record<string, string>;
|
|
22
|
+
/**
|
|
23
|
+
* Signs a REST request per the UCP REST binding of RFC 9421: computes the
|
|
24
|
+
* Content-Digest (RFC 9530) of the raw body and signs the required
|
|
25
|
+
* components, returning the headers to add.
|
|
26
|
+
*/
|
|
27
|
+
export declare function signRestRequest(request: UCPSignableRequest, key: UCPSigningKey, created?: number): Record<string, string>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type UCPSigningKey } from './reactionary-ucp-signing.js';
|
|
2
|
+
export interface ReactionaryUCPWebhookOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Signs deliveries; the order capability requires signed webhook payloads.
|
|
5
|
+
* Without it deliveries are sent unsigned, and a warning is logged.
|
|
6
|
+
*/
|
|
7
|
+
signingKey?: UCPSigningKey;
|
|
8
|
+
/**
|
|
9
|
+
* Delays before each retry of a failed delivery. Retries are held in
|
|
10
|
+
* memory, so they do not survive a restart. Defaults to 0.5s, 2s, 10s, 1m
|
|
11
|
+
* and 5m.
|
|
12
|
+
*/
|
|
13
|
+
retryDelaysMs?: number[];
|
|
14
|
+
/**
|
|
15
|
+
* Accepts `http:` agent profile and webhook URLs. Only https URLs are
|
|
16
|
+
* fetched otherwise. Intended for conformance and test environments.
|
|
17
|
+
*/
|
|
18
|
+
allowInsecureUrls?: boolean;
|
|
19
|
+
/** Fetch implementation; defaults to the global fetch. */
|
|
20
|
+
fetch?: typeof fetch;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Delivers order events to the webhook URL a platform declares in its
|
|
24
|
+
* profile (order capability `config.webhook_url`), following Standard
|
|
25
|
+
* Webhooks headers and the UCP REST signing binding.
|
|
26
|
+
*/
|
|
27
|
+
export declare class ReactionaryUCPWebhooks {
|
|
28
|
+
private readonly options;
|
|
29
|
+
/** The business profile URL, sent as the deliveries' UCP-Agent. */
|
|
30
|
+
private readonly businessProfileUrl;
|
|
31
|
+
private readonly profileCache;
|
|
32
|
+
private readonly retryDelaysMs;
|
|
33
|
+
private readonly fetchImpl;
|
|
34
|
+
private warnedUnsigned;
|
|
35
|
+
constructor(options: ReactionaryUCPWebhookOptions,
|
|
36
|
+
/** The business profile URL, sent as the deliveries' UCP-Agent. */
|
|
37
|
+
businessProfileUrl: string);
|
|
38
|
+
/** The order webhook URL declared in a platform's profile, if any. */
|
|
39
|
+
resolveOrderWebhookUrl(agentProfileUrl: string): Promise<string | undefined>;
|
|
40
|
+
/**
|
|
41
|
+
* Sends an order event without waiting for it. Failed attempts are retried
|
|
42
|
+
* as the same event: same Webhook-Id, Webhook-Timestamp and body.
|
|
43
|
+
*/
|
|
44
|
+
deliver(webhookUrl: string, order: object): void;
|
|
45
|
+
private attempt;
|
|
46
|
+
private fetchOrderWebhookUrl;
|
|
47
|
+
private isAllowedUrl;
|
|
48
|
+
}
|