@godaddy/gd-commerce-server 0.2.0 → 0.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 +28 -1
- package/dist/index.d.ts +104 -7
- package/dist/index.js +660 -494
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ Configure `checkoutReturnUrls` on the router using trusted deployment settings.
|
|
|
56
56
|
|
|
57
57
|
Without this policy, HTTP checkout returns 503 before creating a session. Invalid request destinations return 400. This applies to both router presets that expose checkout. Trusted in-process callers of `createCheckoutSession()` own their return URLs and must construct or validate them server-side.
|
|
58
58
|
|
|
59
|
-
A return from hosted checkout is not proof of payment. The order-status route uses the authorized Orders REST API, which supports completed orders, and returns its payment status (for example `PAID` or `PENDING`; `unknown
|
|
59
|
+
A return from hosted checkout is not proof of payment. The order-status route uses the authorized Orders REST API, which supports completed orders, and returns its payment status (for example `PAID` or `PENDING`; the exported `ORDER_STATUS_UNKNOWN`, `'unknown'`, if absent). Show it only as display enrichment and never present an unconfirmed payment as paid. The server OAuth client must be granted `commerce.order:read`. The helper verifies the returned order ID, store, and channel and returns a limited summary without customer contact data. The route returns 400 for a missing, blank, padded, `.`, or `..` order ID (padded IDs are rejected, not trimmed) or one the Orders API rejects as malformed (422 `VALIDATION_FAILED`), and 404 when the Orders API reports the order missing (404 `NOT_FOUND`) or the order belongs to another store or channel. A 404 without that code, such as from a misconfigured API base URL, is an upstream failure. Token and other Commerce failures, including a response for a different order ID, return 502 and unreadable configuration returns 503 (see [Errors](#errors)). Hosts must authenticate callers and authorize access to each requested order before exposing this route.
|
|
60
60
|
|
|
61
61
|
### Connection state
|
|
62
62
|
|
|
@@ -78,3 +78,30 @@ complete. Lost configuration is an error, never evidence of `unbound`. After a s
|
|
|
78
78
|
report `unbound` again only after it is deliberately disconnected. The storefront package owns
|
|
79
79
|
the generic sample products and local sample cart; this server never creates sample Commerce
|
|
80
80
|
records or simulates checkout.
|
|
81
|
+
|
|
82
|
+
## Errors
|
|
83
|
+
|
|
84
|
+
Every route reports failures the same way. The body is `{ "error": "<customer-facing message>", "code": "<code>", "requestId": "<id>" }` (order-status also includes `success: false`). The same id is passed to the logger. Bodies never contain upstream messages, configuration details, or credentials.
|
|
85
|
+
|
|
86
|
+
| Status | `code` | Meaning |
|
|
87
|
+
| --- | --- | --- |
|
|
88
|
+
| 400 | `invalid_request` | Missing or invalid input. |
|
|
89
|
+
| 404 | `not_found` | Missing order or product, or a write to an existing cart (`/cart/:id/...`) that is missing, expired, or completed. Cart reads keep returning `200 { "cart": null }`. Checkout with a stale or completed `draftOrderId` is not yet distinguished and returns 502. |
|
|
90
|
+
| 409 | `scope_mismatch` | `X-Commerce-Scope` no longer matches the configured store binding. |
|
|
91
|
+
| 502 | `upstream_unauthorized` | Commerce rejected this server's OAuth client or requested scope (HTTP 401/403, or an OAuth 400 with `invalid_client`, `invalid_grant`, `unauthorized_client`, or `invalid_scope`). It concerns server credentials, not the caller, so it is never reported as 401/403. |
|
|
92
|
+
| 502 | `upstream_error` | Commerce failed, returned an unexpected response, or could not be reached. |
|
|
93
|
+
| 503 | `not_configured` | Configuration is missing or unreadable, the host reports a connection state other than `ready`, or checkout return URLs are not configured. |
|
|
94
|
+
| 500 | `internal_error` | An unexpected error in this package. |
|
|
95
|
+
|
|
96
|
+
Upstream errors without a specific mapping stay 502; business errors such as invalid discount codes are not yet distinguished. 5xx detail, including upstream status and GraphQL error codes, goes to the logger:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
createCommerceRouter({
|
|
100
|
+
configuration,
|
|
101
|
+
logger: { error: (message, context) => log.error(context, message) },
|
|
102
|
+
// Use the host's request id when its edge sets one; unsafe or missing ids fall back to a UUID.
|
|
103
|
+
getRequestId: (req) => req.get('x-request-id'),
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`createCommerceCatalogRouter` and `createGoDaddyPaymentsRouter` accept the same `{ logger, getRequestId }` as their last argument. The logger defaults to `console.error`. In-process helpers throw the exported `CommerceError` subclasses (`InvalidRequestError`, `NotFoundError`, `CommerceNotConfiguredError`, `UpstreamError`), including when a host configuration throws while being read. Check `error.code` (for example `'not_found'`) rather than `instanceof`, which fails when a host has more than one copy of this package.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Router } from "express";
|
|
1
|
+
import { Request, Router } from "express";
|
|
2
2
|
|
|
3
3
|
//#region src/lib/commerce/checkout-config.d.ts
|
|
4
4
|
/** Shipping options accepted by the hosted checkout API. Omit to use the store's configuration. */
|
|
@@ -21,6 +21,86 @@ interface CheckoutReturnUrls {
|
|
|
21
21
|
successUrls: readonly string[];
|
|
22
22
|
}
|
|
23
23
|
//#endregion
|
|
24
|
+
//#region src/lib/commerce/errors.d.ts
|
|
25
|
+
/**
|
|
26
|
+
* Typed failures for the Commerce routes and helpers.
|
|
27
|
+
*
|
|
28
|
+
* Domain code throws these; `commerceRoute` is the only place that turns them into HTTP
|
|
29
|
+
* responses. `message` is internal and only logged. `publicMessage` is safe to show a shopper;
|
|
30
|
+
* when it is absent the route's failure label is used instead.
|
|
31
|
+
*/
|
|
32
|
+
type CommerceErrorCode = 'invalid_request' | 'scope_mismatch' | 'not_found' | 'not_configured' | 'upstream_unauthorized' | 'upstream_error' | 'internal_error';
|
|
33
|
+
interface CommerceErrorOptions {
|
|
34
|
+
cause?: unknown;
|
|
35
|
+
publicMessage?: string;
|
|
36
|
+
/** Internal diagnostics for the server log. Never sent to the browser. */
|
|
37
|
+
details?: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
declare class CommerceError extends Error {
|
|
40
|
+
readonly httpStatus: number;
|
|
41
|
+
readonly code: CommerceErrorCode;
|
|
42
|
+
readonly publicMessage?: string;
|
|
43
|
+
readonly details?: Record<string, unknown>;
|
|
44
|
+
constructor(httpStatus: number, code: CommerceErrorCode, message: string, options?: CommerceErrorOptions);
|
|
45
|
+
}
|
|
46
|
+
interface ClientErrorOptions extends Omit<CommerceErrorOptions, 'publicMessage'> {
|
|
47
|
+
/** Internal message for in-process callers; defaults to the public message. */
|
|
48
|
+
message?: string;
|
|
49
|
+
}
|
|
50
|
+
declare class InvalidRequestError extends CommerceError {
|
|
51
|
+
constructor(publicMessage: string, {
|
|
52
|
+
message,
|
|
53
|
+
...options
|
|
54
|
+
}?: ClientErrorOptions);
|
|
55
|
+
}
|
|
56
|
+
declare class ScopeMismatchError extends CommerceError {
|
|
57
|
+
constructor();
|
|
58
|
+
}
|
|
59
|
+
declare class NotFoundError extends CommerceError {
|
|
60
|
+
constructor(publicMessage: string, {
|
|
61
|
+
message,
|
|
62
|
+
...options
|
|
63
|
+
}?: ClientErrorOptions);
|
|
64
|
+
}
|
|
65
|
+
declare class CommerceNotConfiguredError extends CommerceError {
|
|
66
|
+
constructor(message: string, {
|
|
67
|
+
publicMessage,
|
|
68
|
+
...options
|
|
69
|
+
}?: CommerceErrorOptions);
|
|
70
|
+
}
|
|
71
|
+
interface UpstreamErrorOptions extends Omit<CommerceErrorOptions, 'publicMessage'> {
|
|
72
|
+
/** The upstream rejected this server's own credentials (OAuth client or scope). */
|
|
73
|
+
unauthorized?: boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Commerce returned a failure, an unexpected response, or could not be reached. Always 502:
|
|
77
|
+
* even an upstream 401/403 concerns this server's client credentials, not the caller, and
|
|
78
|
+
* answering 401 would collide with the host's own authentication handling.
|
|
79
|
+
*/
|
|
80
|
+
declare class UpstreamError extends CommerceError {
|
|
81
|
+
constructor(message: string, {
|
|
82
|
+
unauthorized,
|
|
83
|
+
...options
|
|
84
|
+
}?: UpstreamErrorOptions);
|
|
85
|
+
}
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region src/lib/commerce/commerce-route.d.ts
|
|
88
|
+
interface CommerceErrorLogContext {
|
|
89
|
+
requestId: string;
|
|
90
|
+
method: string;
|
|
91
|
+
path: string;
|
|
92
|
+
httpStatus: number;
|
|
93
|
+
code: CommerceErrorCode;
|
|
94
|
+
details?: Record<string, unknown>;
|
|
95
|
+
error: unknown;
|
|
96
|
+
}
|
|
97
|
+
/** Receives server-side failure detail that is never sent to the browser. */
|
|
98
|
+
interface CommerceLogger {
|
|
99
|
+
error(message: string, context: CommerceErrorLogContext): void;
|
|
100
|
+
}
|
|
101
|
+
/** Returns the host's id for this request (for example one set by its load balancer), if any. */
|
|
102
|
+
type CommerceRequestIdResolver = (req: Request) => string | undefined;
|
|
103
|
+
//#endregion
|
|
24
104
|
//#region src/lib/commerce/config.d.ts
|
|
25
105
|
interface CommerceConfig {
|
|
26
106
|
/** Public OAuth client id. */
|
|
@@ -59,7 +139,6 @@ declare function readCommerceConfig(options?: RuntimeCommerceConfigurationOption
|
|
|
59
139
|
declare function createRuntimeCommerceConfiguration(options?: RuntimeCommerceConfigurationOptions): CommerceConfiguration;
|
|
60
140
|
//#endregion
|
|
61
141
|
//#region src/lib/commerce/checkout-subgraph.d.ts
|
|
62
|
-
|
|
63
142
|
interface CheckoutSessionLineItemPriceDataInput {
|
|
64
143
|
/** Price per unit in the currency's smallest unit (e.g. cents for USD). */
|
|
65
144
|
unitAmount: number;
|
|
@@ -113,10 +192,12 @@ interface CheckoutSession {
|
|
|
113
192
|
declare function createCheckoutSession(params: CreateCheckoutSessionParams, configuration?: CommerceConfiguration): Promise<CheckoutSession>;
|
|
114
193
|
//#endregion
|
|
115
194
|
//#region src/lib/commerce/get-order-status.d.ts
|
|
195
|
+
/** `CommerceOrderStatus.status` when the Orders API reports no payment status. */
|
|
196
|
+
declare const ORDER_STATUS_UNKNOWN = "unknown";
|
|
116
197
|
interface CommerceOrderStatus {
|
|
117
198
|
/** GoDaddy order id. */
|
|
118
199
|
id: string;
|
|
119
|
-
/** Payment status reported by Commerce
|
|
200
|
+
/** Payment status reported by Commerce (e.g. `PAID`, `PENDING`), or `ORDER_STATUS_UNKNOWN`. */
|
|
120
201
|
status: string;
|
|
121
202
|
/** Total amount in the currency's smallest unit (cents for USD). */
|
|
122
203
|
amount: number;
|
|
@@ -129,6 +210,12 @@ interface CommerceOrderStatus {
|
|
|
129
210
|
/** Line item summaries, excluding private order metadata. */
|
|
130
211
|
lineItems?: unknown[];
|
|
131
212
|
}
|
|
213
|
+
declare class InvalidOrderIdError extends InvalidRequestError {
|
|
214
|
+
constructor();
|
|
215
|
+
}
|
|
216
|
+
declare class OrderNotFoundError extends NotFoundError {
|
|
217
|
+
constructor();
|
|
218
|
+
}
|
|
132
219
|
declare function getOrderStatus(orderId: string, configuration?: CommerceConfiguration): Promise<CommerceOrderStatus>;
|
|
133
220
|
//#endregion
|
|
134
221
|
//#region src/router.d.ts
|
|
@@ -136,14 +223,24 @@ interface CommerceRouterFeatures {
|
|
|
136
223
|
catalog?: boolean;
|
|
137
224
|
payments?: boolean;
|
|
138
225
|
}
|
|
139
|
-
|
|
226
|
+
/** Where failure detail is logged and how each request's id is chosen. */
|
|
227
|
+
interface CommerceRouterObservabilityOptions {
|
|
228
|
+
/** Receives 5xx failure detail. Defaults to `console.error`. */
|
|
229
|
+
logger?: CommerceLogger;
|
|
230
|
+
/**
|
|
231
|
+
* Returns the host's id for the request, for example `(req) => req.get('x-request-id')` when
|
|
232
|
+
* the host's edge sets that header. Invalid or missing ids fall back to a random UUID.
|
|
233
|
+
*/
|
|
234
|
+
getRequestId?: CommerceRequestIdResolver;
|
|
235
|
+
}
|
|
236
|
+
interface CreateCommerceRouterOptions extends CommerceRouterObservabilityOptions {
|
|
140
237
|
configuration?: CommerceConfiguration;
|
|
141
238
|
features?: CommerceRouterFeatures;
|
|
142
239
|
/** Required to enable browser checkout; never derived from request headers. */
|
|
143
240
|
checkoutReturnUrls?: CheckoutReturnUrls;
|
|
144
241
|
}
|
|
145
242
|
declare function createCommerceRouter(options?: CreateCommerceRouterOptions): Router;
|
|
146
|
-
declare function createCommerceCatalogRouter(configuration?: CommerceConfiguration): Router;
|
|
147
|
-
declare function createGoDaddyPaymentsRouter(configuration?: CommerceConfiguration, checkoutReturnUrls?: CheckoutReturnUrls): Router;
|
|
243
|
+
declare function createCommerceCatalogRouter(configuration?: CommerceConfiguration, observability?: CommerceRouterObservabilityOptions): Router;
|
|
244
|
+
declare function createGoDaddyPaymentsRouter(configuration?: CommerceConfiguration, checkoutReturnUrls?: CheckoutReturnUrls, observability?: CommerceRouterObservabilityOptions): Router;
|
|
148
245
|
//#endregion
|
|
149
|
-
export { type CheckoutReturnUrls, type CheckoutSession, type CommerceCheckoutConfiguration, type CommerceCheckoutShippingConfiguration, type CommerceConfig, type CommerceConfiguration, type CommerceConnectionState, type CommerceOrderStatus, type CommerceRouterFeatures, type CreateCheckoutSessionParams, type CreateCommerceRouterOptions, type RuntimeCommerceConfigurationOptions, createCheckoutSession, createCommerceCatalogRouter, createCommerceRouter, createGoDaddyPaymentsRouter, createRuntimeCommerceConfiguration, getOrderStatus, parseCommerceCheckoutConfiguration, readCommerceConfig };
|
|
246
|
+
export { type CheckoutReturnUrls, type CheckoutSession, type CommerceCheckoutConfiguration, type CommerceCheckoutShippingConfiguration, type CommerceConfig, type CommerceConfiguration, type CommerceConnectionState, CommerceError, type CommerceErrorCode, type CommerceErrorLogContext, type CommerceLogger, CommerceNotConfiguredError, type CommerceOrderStatus, type CommerceRequestIdResolver, type CommerceRouterFeatures, type CommerceRouterObservabilityOptions, type CreateCheckoutSessionParams, type CreateCommerceRouterOptions, InvalidOrderIdError, InvalidRequestError, NotFoundError, ORDER_STATUS_UNKNOWN, OrderNotFoundError, type RuntimeCommerceConfigurationOptions, ScopeMismatchError, UpstreamError, createCheckoutSession, createCommerceCatalogRouter, createCommerceRouter, createGoDaddyPaymentsRouter, createRuntimeCommerceConfiguration, getOrderStatus, parseCommerceCheckoutConfiguration, readCommerceConfig };
|