@xedo/sdk 0.1.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.
@@ -0,0 +1,362 @@
1
+ /**
2
+ * Public, hand-written type surface for the Xedo SDK.
3
+ *
4
+ * The Xedo Developer API returns its resource payloads inside a generic
5
+ * envelope (`{ success, data }`). The entity payloads themselves are described
6
+ * loosely in `openapi.json` (`type: object`), so we expose them as open
7
+ * JSON objects here and keep the precise, validated shapes for the checkout
8
+ * inputs — which the API does constrain. The generated mirror of the spec
9
+ * lives in `./generated.ts` (do not edit by hand).
10
+ */
11
+ /** A free-form JSON object returned by the API. */
12
+ type JsonObject = {
13
+ [key: string]: unknown;
14
+ };
15
+ /** Sort direction shared by every paginated list endpoint. */
16
+ type SortOrder = 'asc' | 'desc';
17
+ /** Result of `GET /v1/ping` — use it to validate an API key end to end. */
18
+ interface PingResult {
19
+ marketplaceId: number;
20
+ timestamp: string;
21
+ }
22
+ /** A product from the merchant catalogue (`GET /v1/products`). */
23
+ type Product = JsonObject;
24
+ /** A collection / category of products (`GET /v1/collections`). */
25
+ type Collection = JsonObject;
26
+ /** A paid order (`GET /v1/orders`). */
27
+ type Order = JsonObject;
28
+ /** A cart (`GET /v1/carts`). `DRAFT` carts are never exposed by the API. */
29
+ type Cart = JsonObject;
30
+ /** Computed totals returned by `POST /v1/carts/preview` (nothing persisted). */
31
+ type CheckoutPreview = JsonObject;
32
+ /**
33
+ * Returned by `POST /v1/carts` and `POST /v1/carts/{publicId}/pay`. Always
34
+ * carries the hosted `checkoutUrl` to redirect the customer to.
35
+ */
36
+ interface CheckoutResult extends JsonObject {
37
+ checkoutUrl: string;
38
+ }
39
+ /** Shared cursor parameters for every paginated list endpoint. */
40
+ interface ListParams {
41
+ /** Page number (1-based). */
42
+ page?: number;
43
+ /** Page size (capped by the platform, ~100 max). */
44
+ perPage?: number;
45
+ /** Sort direction. */
46
+ order?: SortOrder;
47
+ /** Full-text search (3 characters minimum). */
48
+ search?: string;
49
+ /** Abort signal for this request. */
50
+ signal?: AbortSignal;
51
+ }
52
+ interface ProductListParams extends ListParams {
53
+ sort?: 'id' | 'name' | 'price' | 'createdAt';
54
+ /** Filter by collection slug. */
55
+ collection?: string;
56
+ /** Include variations and combinations (SKUs) in the response. */
57
+ includeVariations?: boolean;
58
+ /** Include disabled products (drafts). */
59
+ includeDisabled?: boolean;
60
+ }
61
+ interface CollectionListParams extends ListParams {
62
+ sort?: 'id' | 'name' | 'createdAt';
63
+ }
64
+ interface OrderListParams extends ListParams {
65
+ sort?: 'id' | 'createdAt' | 'amount';
66
+ }
67
+ interface CartListParams extends ListParams {
68
+ sort?: 'id' | 'createdAt';
69
+ }
70
+ /** Options for single-resource retrieval that supports draft resolution. */
71
+ interface RetrieveOptions {
72
+ /** Resolve a disabled product (draft) as well. */
73
+ includeDisabled?: boolean;
74
+ signal?: AbortSignal;
75
+ }
76
+ /** Options for a plain single-resource retrieval. */
77
+ interface RequestOptions {
78
+ signal?: AbortSignal;
79
+ }
80
+ /**
81
+ * One page of a paginated list. The SDK unwraps the API envelope but keeps the
82
+ * pagination metadata so callers can build their own UIs.
83
+ */
84
+ interface PaginatedResult<T> {
85
+ data: T[];
86
+ /** Total number of rows matching the query, across all pages. */
87
+ total: number;
88
+ /** 1-based index of the first row returned. */
89
+ start: number;
90
+ /** 1-based index of the last row returned. */
91
+ end: number;
92
+ }
93
+ /** Rate-limit headers captured from the most recent response. */
94
+ interface RateLimitInfo {
95
+ limit: number | null;
96
+ remaining: number | null;
97
+ reset: number | null;
98
+ }
99
+ interface CheckoutItem {
100
+ /** e.g. "PRD-XPK39ZQA01". */
101
+ publicProductId: string;
102
+ /** Quantity, >= 1. */
103
+ quantity: number;
104
+ /** SKU public id, when the product has variations. */
105
+ combinationPublicId?: string;
106
+ }
107
+ interface CheckoutDelivery {
108
+ deliveryType: 'DELIVERY' | 'PICKUP';
109
+ /** Required when `deliveryType === 'DELIVERY'`. */
110
+ deliveryAreaId?: number;
111
+ }
112
+ interface CheckoutCustomer {
113
+ firstName: string;
114
+ lastName: string;
115
+ email: string;
116
+ phone: string;
117
+ }
118
+ type PaymentMethod = 'external_wallet' | 'split_payment';
119
+ interface CheckoutPreviewInput {
120
+ items: CheckoutItem[];
121
+ delivery: CheckoutDelivery;
122
+ paymentMethod: PaymentMethod;
123
+ }
124
+ interface CheckoutCreateInput extends CheckoutPreviewInput {
125
+ customer: CheckoutCustomer;
126
+ /** HTTPS is mandatory. */
127
+ returnUrl: string;
128
+ additionalDetails?: string;
129
+ /**
130
+ * Free JSON payload echoed back, unchanged, in every cart/order response.
131
+ * Use it to correlate a Xedo order with your own state (`internalOrderId`,
132
+ * `source`, `templateId`, …).
133
+ */
134
+ meta?: Record<string, unknown>;
135
+ }
136
+ interface CheckoutRetryPayInput {
137
+ returnUrl: string;
138
+ }
139
+
140
+ type FetchLike = (input: string | URL, init?: RequestInit) => Promise<Response>;
141
+ interface TransportOptions {
142
+ apiKey: string;
143
+ baseUrl: string;
144
+ maxRetries: number;
145
+ timeoutMs: number;
146
+ fetchImpl: FetchLike;
147
+ }
148
+ interface RequestConfig {
149
+ query?: Record<string, unknown>;
150
+ body?: unknown;
151
+ signal?: AbortSignal;
152
+ /** Accept header; defaults to `application/json`. */
153
+ accept?: string;
154
+ }
155
+ type HttpMethod = 'GET' | 'POST';
156
+ /**
157
+ * Owns the HTTP concern: auth header, query/body serialization, per-request
158
+ * timeout + abort, automatic 429 retries, envelope parsing and error mapping.
159
+ * Resources sit on top and never touch `fetch` directly.
160
+ */
161
+ declare class Transport {
162
+ private readonly opts;
163
+ lastRateLimit: RateLimitInfo | null;
164
+ constructor(opts: TransportOptions);
165
+ /** Run a request and return the unwrapped `data` payload, typed as `T`. */
166
+ getData<T>(method: HttpMethod, path: string, config?: RequestConfig): Promise<T>;
167
+ /** Run a GET list request and return `{ data, total, start, end }`. */
168
+ getPage<T>(path: string, config?: RequestConfig): Promise<PaginatedResult<T>>;
169
+ /** Run a request that returns a binary body (e.g. the invoice PDF). */
170
+ getBinary(method: HttpMethod, path: string, config?: RequestConfig): Promise<ArrayBuffer>;
171
+ private requestJson;
172
+ private tryParseJson;
173
+ private toError;
174
+ /** Fetch with retry on 429; returns the final {@link Response}. */
175
+ private execute;
176
+ private fetchOnce;
177
+ private buildUrl;
178
+ private captureRateLimit;
179
+ private retryDelayMs;
180
+ }
181
+
182
+ declare abstract class Resource {
183
+ protected readonly transport: Transport;
184
+ constructor(transport: Transport);
185
+ }
186
+
187
+ declare class Carts extends Resource {
188
+ /**
189
+ * `GET /v1/carts` — one page of carts. `DRAFT` carts are never exposed by
190
+ * the API.
191
+ */
192
+ list(params?: CartListParams): Promise<PaginatedResult<Cart>>;
193
+ /** Async iterator over every cart across all pages. */
194
+ listAll(params?: CartListParams): AsyncGenerator<Cart>;
195
+ /** `GET /v1/carts/{publicId}`. */
196
+ retrieve(publicId: string, opts?: RequestOptions): Promise<Cart>;
197
+ /** `POST /v1/carts/preview` — compute totals without persisting anything. */
198
+ preview(input: CheckoutPreviewInput, opts?: RequestOptions): Promise<CheckoutPreview>;
199
+ /**
200
+ * `POST /v1/carts` — create the cart (`PENDING_PAYMENT`) and return
201
+ * `data.checkoutUrl`. On a `502 PAYMENT_INIT_FAILED` the cart is kept; retry
202
+ * the payment with {@link Carts.pay} (or use {@link Carts.createAndPay}).
203
+ */
204
+ create(input: CheckoutCreateInput, opts?: RequestOptions): Promise<CheckoutResult>;
205
+ /**
206
+ * `POST /v1/carts/{publicId}/pay` — relaunch payment initialization after a
207
+ * `502 PAYMENT_INIT_FAILED`.
208
+ */
209
+ pay(publicId: string, input: CheckoutRetryPayInput, opts?: RequestOptions): Promise<CheckoutResult>;
210
+ /**
211
+ * Convenience wrapper around the 502 checkout flow: create the cart, and if
212
+ * the payment provider could not be reached (`PAYMENT_INIT_FAILED`), retry
213
+ * `pay()` once with the same `returnUrl`. Stays transparent — it logs the
214
+ * code and never swallows a definitive failure.
215
+ */
216
+ createAndPay(input: CheckoutCreateInput, opts?: RequestOptions): Promise<CheckoutResult>;
217
+ }
218
+
219
+ declare class Collections extends Resource {
220
+ /** `GET /v1/collections` — one page of collections. */
221
+ list(params?: CollectionListParams): Promise<PaginatedResult<Collection>>;
222
+ /** Async iterator over every collection across all pages. */
223
+ listAll(params?: CollectionListParams): AsyncGenerator<Collection>;
224
+ /** `GET /v1/collections/{publicId}`. */
225
+ retrieve(publicId: string, opts?: RequestOptions): Promise<Collection>;
226
+ /** `GET /v1/collections/by-slug/{slug}`. */
227
+ retrieveBySlug(slug: string, opts?: RequestOptions): Promise<Collection>;
228
+ }
229
+
230
+ declare class Orders extends Resource {
231
+ /** `GET /v1/orders` — one page of paid orders. */
232
+ list(params?: OrderListParams): Promise<PaginatedResult<Order>>;
233
+ /** Async iterator over every order across all pages. */
234
+ listAll(params?: OrderListParams): AsyncGenerator<Order>;
235
+ /** `GET /v1/orders/{publicId}`. */
236
+ retrieve(publicId: string, opts?: RequestOptions): Promise<Order>;
237
+ /**
238
+ * `GET /v1/orders/{publicId}/invoice` — the invoice PDF as a binary
239
+ * `ArrayBuffer` (not JSON). Throws {@link XedoNotFoundError} if the invoice
240
+ * has not been generated yet.
241
+ */
242
+ invoice(publicId: string, opts?: RequestOptions): Promise<ArrayBuffer>;
243
+ }
244
+
245
+ declare class Products extends Resource {
246
+ /** `GET /v1/products` — one page of products. */
247
+ list(params?: ProductListParams): Promise<PaginatedResult<Product>>;
248
+ /** Async iterator over every product across all pages. */
249
+ listAll(params?: ProductListParams): AsyncGenerator<Product>;
250
+ /** `GET /v1/products/{publicId}`. */
251
+ retrieve(publicId: string, opts?: RetrieveOptions): Promise<Product>;
252
+ /** `GET /v1/products/by-slug/{slug}`. */
253
+ retrieveBySlug(slug: string, opts?: RetrieveOptions): Promise<Product>;
254
+ }
255
+
256
+ interface XedoOptions {
257
+ /** Developer API key: `xdk_live_…` or `xdk_test_…`. */
258
+ apiKey: string;
259
+ /** Override the API base URL. Defaults to the production marketplace URL. */
260
+ baseUrl?: string;
261
+ /** Max automatic retries on `429`. Defaults to 4. */
262
+ maxRetries?: number;
263
+ /** Per-request timeout in milliseconds. Defaults to 30000. */
264
+ timeoutMs?: number;
265
+ /** Inject a custom fetch (tests, edge runtimes). Defaults to global fetch. */
266
+ fetch?: FetchLike;
267
+ /**
268
+ * Escape hatch to run in a browser. Strongly discouraged: your
269
+ * `xdk_live_…` key would be exposed in the client bundle.
270
+ */
271
+ dangerouslyAllowBrowser?: boolean;
272
+ }
273
+ /**
274
+ * The Xedo Developer API client. Server-side only — see
275
+ * `dangerouslyAllowBrowser`.
276
+ *
277
+ * ```ts
278
+ * const xedo = new Xedo({ apiKey: process.env.XEDO_API_KEY! });
279
+ * const { data } = await xedo.products.list({ perPage: 20 });
280
+ * ```
281
+ */
282
+ declare class Xedo {
283
+ readonly products: Products;
284
+ readonly collections: Collections;
285
+ readonly orders: Orders;
286
+ readonly carts: Carts;
287
+ private readonly apiKey;
288
+ private readonly transport;
289
+ constructor(options: XedoOptions);
290
+ /**
291
+ * The environment inferred from the key prefix. The rest of the key is
292
+ * treated as opaque.
293
+ */
294
+ get environment(): 'test' | 'live' | 'unknown';
295
+ /** Rate-limit headers from the most recent response, for monitoring. */
296
+ get lastRateLimit(): RateLimitInfo | null;
297
+ /** `GET /v1/ping` — validate the API key end to end. */
298
+ ping(opts?: RequestOptions): Promise<PingResult>;
299
+ }
300
+
301
+ /**
302
+ * Typed error hierarchy. Every `success: false` response (and every transport
303
+ * failure) is thrown as a {@link XedoError} or one of its subclasses. Route on
304
+ * `error.code` (stable, machine-readable), never on `error.message` (French,
305
+ * subject to change).
306
+ */
307
+ interface XedoErrorParams {
308
+ message: string;
309
+ /** Machine-readable code, e.g. "PRODUCT_NOT_FOUND". */
310
+ code: string;
311
+ /** HTTP status (0 for transport/connection errors). */
312
+ status: number;
313
+ /** Per-field validation details. */
314
+ errors?: Record<string, string[]>;
315
+ /** Extra context (e.g. `cartPublicId` on PAYMENT_INIT_FAILED). */
316
+ data?: unknown;
317
+ /** Request id, when the API returns one. */
318
+ requestId?: string;
319
+ /** `Retry-After` value in seconds, when present. */
320
+ retryAfter?: number;
321
+ }
322
+ declare class XedoError extends Error {
323
+ readonly code: string;
324
+ readonly status: number;
325
+ readonly errors?: Record<string, string[]>;
326
+ readonly data?: unknown;
327
+ readonly requestId?: string;
328
+ constructor(params: XedoErrorParams);
329
+ }
330
+ /** 401 — `MISSING_DEVELOPER_API_KEY`, `INVALID_DEVELOPER_API_KEY`. */
331
+ declare class XedoAuthError extends XedoError {
332
+ }
333
+ /** 400 — bad request / invalid payment configuration. */
334
+ declare class XedoValidationError extends XedoError {
335
+ }
336
+ /** 404 — product, combination, delivery area, cart or generic not found. */
337
+ declare class XedoNotFoundError extends XedoError {
338
+ }
339
+ /** 422 — `INSUFFICIENT_STOCK` (per-product detail in `errors`). */
340
+ declare class XedoStockError extends XedoError {
341
+ }
342
+ /** 409 — `CART_NOT_RETRYABLE`. */
343
+ declare class XedoConflictError extends XedoError {
344
+ }
345
+ /** 429 — `RATE_LIMITED`. Exposes `retryAfter` (seconds). */
346
+ declare class XedoRateLimitError extends XedoError {
347
+ readonly retryAfter?: number;
348
+ constructor(params: XedoErrorParams);
349
+ }
350
+ /**
351
+ * 502 — `PAYMENT_INIT_FAILED`. The cart was kept; relaunch the payment via
352
+ * `xedo.carts.pay(cartPublicId, …)`. Exposes `cartPublicId`.
353
+ */
354
+ declare class XedoPaymentInitError extends XedoError {
355
+ readonly cartPublicId?: string;
356
+ constructor(params: XedoErrorParams);
357
+ }
358
+ /** Transport-level failure (timeout, network, malformed response). */
359
+ declare class XedoConnectionError extends XedoError {
360
+ }
361
+
362
+ export { type Cart, type CartListParams, type CheckoutCreateInput, type CheckoutCustomer, type CheckoutDelivery, type CheckoutItem, type CheckoutPreview, type CheckoutPreviewInput, type CheckoutResult, type CheckoutRetryPayInput, type Collection, type CollectionListParams, type FetchLike, type JsonObject, type ListParams, type Order, type OrderListParams, type PaginatedResult, type PaymentMethod, type PingResult, type Product, type ProductListParams, type RateLimitInfo, type RequestOptions, type RetrieveOptions, type SortOrder, Xedo, XedoAuthError, XedoConflictError, XedoConnectionError, XedoError, type XedoErrorParams, XedoNotFoundError, type XedoOptions, XedoPaymentInitError, XedoRateLimitError, XedoStockError, XedoValidationError };