@skuio/storefront 0.7.0 → 0.7.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/api.d.ts +32 -2
- package/dist/api.js +18 -6
- package/dist/api.js.map +1 -1
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -170,8 +170,29 @@ declare function serializeFulfillment(f: Fulfillment): ApiFulfillment;
|
|
|
170
170
|
declare function serializeOrder(o: Order, numberPrefix?: string): ApiOrder;
|
|
171
171
|
/** The Store API's view of a quote. `access_key` never leaves the store. */
|
|
172
172
|
declare function serializeQuote(q: StoreQuote, numberPrefix?: string): ApiQuote;
|
|
173
|
+
/**
|
|
174
|
+
* Maps a stored image src to the public URL a consumer can load. Return null
|
|
175
|
+
* (or undefined) to fall back to the default: an absolute URL as-is, anything
|
|
176
|
+
* else resolved against the request origin.
|
|
177
|
+
*/
|
|
178
|
+
type ImageUrlResolver = (src: string) => string | null | undefined;
|
|
179
|
+
interface SerializeProductOptions {
|
|
180
|
+
/** The store's own image resolver; see StoreApiOptions.imageUrl. */
|
|
181
|
+
imageUrl?: ImageUrlResolver;
|
|
182
|
+
/** The origin relative srcs resolve against when the resolver has no answer ("https://store.example"). */
|
|
183
|
+
origin?: string;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* The absolute URL the Store API reports for an image. The store's resolver
|
|
187
|
+
* wins; without one (or when it returns null) an absolute URL passes through
|
|
188
|
+
* unchanged and a relative path or bare filename is resolved against the
|
|
189
|
+
* request origin. Resolving a bare filename only produces a loadable URL when
|
|
190
|
+
* the store serves the file at that path — stores that fingerprint their
|
|
191
|
+
* assets must pass a resolver.
|
|
192
|
+
*/
|
|
193
|
+
declare function absoluteImageUrl(src: string, options?: SerializeProductOptions): string;
|
|
173
194
|
/** The Store API's view of a catalog product — the stored row, not the shopper projection. */
|
|
174
|
-
declare function serializeProduct(p: ProductRecord): ApiProduct;
|
|
195
|
+
declare function serializeProduct(p: ProductRecord, options?: SerializeProductOptions): ApiProduct;
|
|
175
196
|
declare function serializeCategory(c: CategoryRecord): ApiCategory;
|
|
176
197
|
|
|
177
198
|
declare class ValidationError extends Error {
|
|
@@ -189,6 +210,15 @@ interface StoreApiOptions {
|
|
|
189
210
|
apiKey: string | undefined;
|
|
190
211
|
/** Where the API is mounted in the request URL. */
|
|
191
212
|
basePath?: string;
|
|
213
|
+
/**
|
|
214
|
+
* Maps a stored product image src (a bare filename, a path, or an absolute
|
|
215
|
+
* URL) to the absolute URL the store actually serves it at — e.g. the
|
|
216
|
+
* fingerprinted `/_astro/<name>.<hash>.jpg` a template's `resolveImage()`
|
|
217
|
+
* finds, made absolute against the site URL. Return null to fall back to the
|
|
218
|
+
* default: an absolute src as-is, a relative one resolved against the
|
|
219
|
+
* request origin. `images[].url` in every response is always absolute.
|
|
220
|
+
*/
|
|
221
|
+
imageUrl?: ImageUrlResolver;
|
|
192
222
|
}
|
|
193
223
|
/** Who a request authenticated as: the environment key, or an approved connection. */
|
|
194
224
|
type ApiCaller = {
|
|
@@ -223,4 +253,4 @@ declare function serializeConnection(c: Connection): {
|
|
|
223
253
|
revoked_at: string | null;
|
|
224
254
|
};
|
|
225
255
|
|
|
226
|
-
export { type ApiCaller, type ApiCategory, type ApiFulfillment, type ApiOrder, type ApiProduct, type ApiQuote, STORE_API_BASE, STORE_API_BASES, type StoreApiOptions, ValidationError, handleStoreApi, serializeCategory, serializeConnection, serializeFulfillment, serializeOrder, serializeProduct, serializeQuote };
|
|
256
|
+
export { type ApiCaller, type ApiCategory, type ApiFulfillment, type ApiOrder, type ApiProduct, type ApiQuote, type ImageUrlResolver, STORE_API_BASE, STORE_API_BASES, type SerializeProductOptions, type StoreApiOptions, ValidationError, absoluteImageUrl, handleStoreApi, serializeCategory, serializeConnection, serializeFulfillment, serializeOrder, serializeProduct, serializeQuote };
|
package/dist/api.js
CHANGED
|
@@ -102,7 +102,17 @@ function serializeQuote(q, numberPrefix = "") {
|
|
|
102
102
|
cancelled_at: q.cancelledAt
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
-
|
|
105
|
+
var ABSOLUTE = /^[a-z][a-z0-9+.-]*:/i;
|
|
106
|
+
function absoluteImageUrl(src, options = {}) {
|
|
107
|
+
const url = options.imageUrl?.(src) || src;
|
|
108
|
+
if (ABSOLUTE.test(url) || !options.origin) return url;
|
|
109
|
+
try {
|
|
110
|
+
return new URL(url, `${options.origin.replace(/\/+$/, "")}/`).href;
|
|
111
|
+
} catch {
|
|
112
|
+
return url;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function serializeProduct(p, options = {}) {
|
|
106
116
|
return {
|
|
107
117
|
sku: p.sku,
|
|
108
118
|
name: p.name,
|
|
@@ -116,7 +126,7 @@ function serializeProduct(p) {
|
|
|
116
126
|
position: p.position,
|
|
117
127
|
legacy_path: p.legacyPath,
|
|
118
128
|
categories: p.categories.map((c) => ({ id: c.id, slug: c.slug, name: c.name })),
|
|
119
|
-
images: p.images.map((i) => ({ url: i.url, alt: i.alt, position: i.position })),
|
|
129
|
+
images: p.images.map((i) => ({ url: absoluteImageUrl(i.url, options), alt: i.alt, position: i.position })),
|
|
120
130
|
inventory: p.inventory ? { available: p.inventory.available, allow_backorder: p.inventory.allowBackorder, updated_at: p.inventory.updatedAt } : null,
|
|
121
131
|
created_at: p.createdAt,
|
|
122
132
|
updated_at: p.updatedAt
|
|
@@ -482,7 +492,8 @@ async function handleStoreApi(request, options) {
|
|
|
482
492
|
if (scope && caller.kind === "connection" && !caller.connection.scopes.includes(scope)) {
|
|
483
493
|
return error(403, "forbidden", `This connection was not approved for "${scope}"; reconnect and approve it at /admin/connect`);
|
|
484
494
|
}
|
|
485
|
-
|
|
495
|
+
const images = { imageUrl: options.imageUrl, origin: url.origin };
|
|
496
|
+
return await route(method, path, url, request, options.store, caller, images);
|
|
486
497
|
} catch (e) {
|
|
487
498
|
if (e instanceof ValidationError) return error(422, "validation_failed", e.message, e.details);
|
|
488
499
|
if (e instanceof StoreError) return error(e.status, e.code, e.message, e.details);
|
|
@@ -538,7 +549,7 @@ function scopeFor(path) {
|
|
|
538
549
|
if (first === "quotes") return "quotes";
|
|
539
550
|
return null;
|
|
540
551
|
}
|
|
541
|
-
async function route(method, path, url, request, store, caller) {
|
|
552
|
+
async function route(method, path, url, request, store, caller, images) {
|
|
542
553
|
const segments = path.split("/").filter(Boolean);
|
|
543
554
|
if (path === "/health" && method === "GET") {
|
|
544
555
|
const health = await store.health();
|
|
@@ -618,11 +629,11 @@ async function route(method, path, url, request, store, caller) {
|
|
|
618
629
|
if (path === "/products" && method === "GET") {
|
|
619
630
|
const query = validateListQuery(url.searchParams, { defaultLimit: 50, maxLimit: 200, allowUpdatedSince: true, allowActive: true });
|
|
620
631
|
const page = await store.catalog.listProducts(query);
|
|
621
|
-
return json({ data: page.products.map(serializeProduct), next_cursor: page.nextCursor });
|
|
632
|
+
return json({ data: page.products.map((p) => serializeProduct(p, images)), next_cursor: page.nextCursor });
|
|
622
633
|
}
|
|
623
634
|
if (segments[0] === "products" && segments.length === 2) {
|
|
624
635
|
const sku = decodeURIComponent(segments[1]);
|
|
625
|
-
if (method === "GET") return json({ data: serializeProduct(await store.catalog.requireProduct(sku)) });
|
|
636
|
+
if (method === "GET") return json({ data: serializeProduct(await store.catalog.requireProduct(sku), images) });
|
|
626
637
|
if (method === "DELETE") {
|
|
627
638
|
const done = await store.catalog.deactivateProduct(sku);
|
|
628
639
|
if (!done) return error(404, "not_found", `Product ${sku} not found`);
|
|
@@ -644,6 +655,7 @@ export {
|
|
|
644
655
|
STORE_API_BASE,
|
|
645
656
|
STORE_API_BASES,
|
|
646
657
|
ValidationError,
|
|
658
|
+
absoluteImageUrl,
|
|
647
659
|
handleStoreApi,
|
|
648
660
|
serializeCategory,
|
|
649
661
|
serializeConnection,
|
package/dist/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api/serialize.ts","../src/api/validate.ts","../src/api/index.ts"],"sourcesContent":["import type { CategoryRecord, ProductRecord } from '../store/catalog'\nimport type { Address, Fulfillment, Money, Order, QuoteStatus, StoreQuote } from '../types'\n\nexport interface ApiMoney {\n amount: number\n currency: string\n}\n\nexport interface ApiAddress {\n name: string | null\n line1: string | null\n line2: string | null\n city: string | null\n state: string | null\n postal_code: string | null\n country: string | null\n}\n\nexport interface ApiFulfillment {\n id: string\n external_id: string\n carrier: string | null\n service: string | null\n tracking_number: string | null\n tracking_url: string | null\n shipped_at: string | null\n lines: { sku: string; quantity: number }[]\n created_at: string\n}\n\nexport interface ApiOrder {\n id: string\n number: string\n status: Order['status']\n payment: { status: Order['payment']['status']; provider: string | null; reference: string | null; method_label: string | null; paid_at: string | null }\n currency: string\n subtotal: ApiMoney\n shipping: ApiMoney\n tax: ApiMoney\n discount: ApiMoney\n /** The store discount code the buyer used, upper case. Partner and commission stay in the store. */\n discount_code: string | null\n total: ApiMoney\n customer: { id: string; email: string; name: string | null; phone: string | null }\n shipping_address: ApiAddress\n billing_address: ApiAddress | null\n shipping_method: { code: string; name: string } | null\n lines: { id: string; sku: string; name: string; quantity: number; unit_amount: ApiMoney; total_amount: ApiMoney; fulfilled_quantity: number }[]\n fulfillments: ApiFulfillment[]\n external_reference: string | null\n notes: string | null\n metadata: Record<string, string>\n created_at: string\n updated_at: string\n paid_at: string | null\n cancelled_at: string | null\n}\n\nexport interface ApiQuote {\n id: string\n /** With the store's quote prefix: \"Q1001\". */\n number: string\n status: QuoteStatus\n currency: string\n customer: { id: string; email: string; name: string | null; phone: string | null }\n company: string | null\n message: string | null\n shipping_address: ApiAddress | null\n lines: { id: string; sku: string; name: string; quantity: number; list_amount: ApiMoney | null; unit_amount: ApiMoney | null; total_amount: ApiMoney | null }[]\n subtotal: ApiMoney | null\n shipping: ApiMoney | null\n tax: ApiMoney | null\n total: ApiMoney | null\n note: string | null\n expires_at: string | null\n external_reference: string | null\n /** The order the buyer's acceptance placed; it also arrives through GET /orders with `metadata.quote_id`. */\n order_id: string | null\n decline_reason: string | null\n metadata: Record<string, string>\n created_at: string\n updated_at: string\n quoted_at: string | null\n accepted_at: string | null\n declined_at: string | null\n cancelled_at: string | null\n}\n\nexport interface ApiProduct {\n sku: string\n name: string\n slug: string\n description_html: string | null\n short_description_html: string | null\n price: ApiMoney\n compare_at: ApiMoney | null\n attributes: Record<string, string>\n active: boolean\n position: number\n legacy_path: string | null\n categories: { id: string; slug: string | null; name: string | null }[]\n images: { url: string; alt: string | null; position: number }[]\n inventory: { available: number; allow_backorder: boolean; updated_at: string } | null\n created_at: string\n updated_at: string\n}\n\nexport interface ApiCategory {\n id: string\n parent_id: string | null\n slug: string\n name: string\n description_html: string | null\n position: number\n product_count: number\n created_at: string\n updated_at: string\n}\n\nconst money = (m: Money): ApiMoney => ({ amount: m.amount, currency: m.currency.toUpperCase() })\n\nconst address = (a: Address | null): ApiAddress | null =>\n a\n ? {\n name: a.name ?? null,\n line1: a.line1 ?? null,\n line2: a.line2 ?? null,\n city: a.city ?? null,\n state: a.state ?? null,\n postal_code: a.postalCode ?? null,\n country: a.country ?? null,\n }\n : null\n\nexport function serializeFulfillment(f: Fulfillment): ApiFulfillment {\n return {\n id: f.id,\n external_id: f.externalId,\n carrier: f.carrier,\n service: f.service,\n tracking_number: f.trackingNumber,\n tracking_url: f.trackingUrl,\n shipped_at: f.shippedAt,\n lines: f.lines.map((l) => ({ sku: l.sku, quantity: l.quantity })),\n created_at: f.createdAt,\n }\n}\n\n/**\n * The Store API's view of an order. `access_key` never leaves the store. `number` is the human number the buyer\n * sees, with the store's prefix (VLD4200), so the consumer shows the same number.\n */\nexport function serializeOrder(o: Order, numberPrefix = ''): ApiOrder {\n return {\n id: o.id,\n number: `${numberPrefix}${o.number}`,\n status: o.status,\n payment: { status: o.payment.status, provider: o.payment.provider, reference: o.payment.reference, method_label: o.payment.methodLabel, paid_at: o.payment.paidAt },\n currency: o.currency.toUpperCase(),\n subtotal: money(o.subtotal),\n shipping: money(o.shipping),\n tax: money(o.tax),\n discount: money(o.discount),\n discount_code: o.discountCode,\n total: money(o.total),\n customer: { id: o.customer.id, email: o.customer.email, name: o.customer.name, phone: o.customer.phone },\n shipping_address: address(o.shippingAddress) ?? { name: null, line1: null, line2: null, city: null, state: null, postal_code: null, country: null },\n billing_address: address(o.billingAddress),\n shipping_method: o.shippingMethod,\n lines: o.lines.map((l) => ({\n id: l.id,\n sku: l.sku,\n name: l.name,\n quantity: l.quantity,\n unit_amount: money(l.unitAmount),\n total_amount: money(l.totalAmount),\n fulfilled_quantity: l.fulfilledQuantity,\n })),\n fulfillments: o.fulfillments.map(serializeFulfillment),\n external_reference: o.externalReference,\n notes: o.notes,\n metadata: o.metadata,\n created_at: o.createdAt,\n updated_at: o.updatedAt,\n paid_at: o.paidAt,\n cancelled_at: o.cancelledAt,\n }\n}\n\nconst maybeMoney = (m: Money | null): ApiMoney | null => (m ? money(m) : null)\n\n/** The Store API's view of a quote. `access_key` never leaves the store. */\nexport function serializeQuote(q: StoreQuote, numberPrefix = ''): ApiQuote {\n return {\n id: q.id,\n number: `${numberPrefix}${q.number}`,\n status: q.status,\n currency: q.currency.toUpperCase(),\n customer: { id: q.customer.id, email: q.customer.email, name: q.customer.name, phone: q.customer.phone },\n company: q.company,\n message: q.message,\n shipping_address: address(q.shippingAddress),\n lines: q.lines.map((l) => ({\n id: l.id,\n sku: l.sku,\n name: l.name,\n quantity: l.quantity,\n list_amount: maybeMoney(l.listAmount),\n unit_amount: maybeMoney(l.unitAmount),\n total_amount: maybeMoney(l.totalAmount),\n })),\n subtotal: maybeMoney(q.subtotal),\n shipping: maybeMoney(q.shipping),\n tax: maybeMoney(q.tax),\n total: maybeMoney(q.total),\n note: q.offerNote,\n expires_at: q.expiresAt,\n external_reference: q.externalReference,\n order_id: q.orderId,\n decline_reason: q.declineReason,\n metadata: q.metadata,\n created_at: q.createdAt,\n updated_at: q.updatedAt,\n quoted_at: q.quotedAt,\n accepted_at: q.acceptedAt,\n declined_at: q.declinedAt,\n cancelled_at: q.cancelledAt,\n }\n}\n\n/** The Store API's view of a catalog product — the stored row, not the shopper projection. */\nexport function serializeProduct(p: ProductRecord): ApiProduct {\n return {\n sku: p.sku,\n name: p.name,\n slug: p.slug,\n description_html: p.descriptionHtml,\n short_description_html: p.shortDescriptionHtml,\n price: money(p.price),\n compare_at: p.compareAtPrice ? money(p.compareAtPrice) : null,\n attributes: p.attributes,\n active: p.active,\n position: p.position,\n legacy_path: p.legacyPath,\n categories: p.categories.map((c) => ({ id: c.id, slug: c.slug, name: c.name })),\n images: p.images.map((i) => ({ url: i.url, alt: i.alt, position: i.position })),\n inventory: p.inventory ? { available: p.inventory.available, allow_backorder: p.inventory.allowBackorder, updated_at: p.inventory.updatedAt } : null,\n created_at: p.createdAt,\n updated_at: p.updatedAt,\n }\n}\n\nexport function serializeCategory(c: CategoryRecord): ApiCategory {\n return {\n id: c.id,\n parent_id: c.parentId,\n slug: c.slug,\n name: c.name,\n description_html: c.descriptionHtml,\n position: c.position,\n product_count: c.productCount,\n created_at: c.createdAt,\n updated_at: c.updatedAt,\n }\n}\n","import type { CategoryInput, ProductInput } from '../store/catalog'\nimport type { InventoryItemInput } from '../store/inventory'\nimport type { FulfillmentInput } from '../store/orders'\nimport type { QuoteOfferInput } from '../store/quotes'\nimport type { Money } from '../types'\n\nexport class ValidationError extends Error {\n readonly details: Record<string, string>\n constructor(message: string, details: Record<string, string>) {\n super(message)\n this.name = 'ValidationError'\n this.details = details\n }\n}\n\ntype Details = Record<string, string>\n\nconst isObject = (v: unknown): v is Record<string, unknown> => !!v && typeof v === 'object' && !Array.isArray(v)\nconst isString = (v: unknown): v is string => typeof v === 'string'\nconst isInt = (v: unknown): v is number => typeof v === 'number' && Number.isInteger(v)\n\nfunction str(details: Details, obj: Record<string, unknown>, key: string, path: string, opts: { required?: boolean; max?: number; nullable?: boolean } = {}): string | null | undefined {\n const v = obj[key]\n if (v === undefined) {\n if (opts.required) details[path] = 'is required'\n return undefined\n }\n if (v === null) {\n if (opts.required && !opts.nullable) details[path] = 'is required'\n return opts.nullable || !opts.required ? null : undefined\n }\n if (!isString(v)) {\n details[path] = 'must be a string'\n return undefined\n }\n if (opts.required && !v.trim()) details[path] = 'is required'\n if (opts.max && v.length > opts.max) details[path] = `must be at most ${opts.max} characters`\n return v\n}\n\nfunction moneyField(details: Details, v: unknown, path: string, opts: { required?: boolean; nullable?: boolean } = {}): Money | null | undefined {\n if (v === undefined) {\n if (opts.required) details[path] = 'is required'\n return undefined\n }\n if (v === null) {\n if (!opts.nullable) details[path] = 'is required'\n return null\n }\n if (!isObject(v) || !isInt(v.amount) || !isString(v.currency) || v.currency.length !== 3) {\n details[path] = 'must be { amount: integer minor units, currency: ISO 4217 }'\n return undefined\n }\n if (v.amount < 0) details[path] = 'must not be negative'\n return { amount: v.amount, currency: v.currency }\n}\n\nfunction isoDate(details: Details, v: unknown, path: string): string | null | undefined {\n if (v === undefined) return undefined\n if (v === null) return null\n if (!isString(v) || Number.isNaN(Date.parse(v))) {\n details[path] = 'must be an ISO-8601 timestamp'\n return undefined\n }\n return new Date(v).toISOString()\n}\n\nfunction finish(details: Details, message: string): void {\n if (Object.keys(details).length) throw new ValidationError(message, details)\n}\n\nexport interface ListQuery {\n updatedSince: string | null\n cursor: string | null\n limit: number\n active: boolean | null\n}\n\n/**\n * Query string for the catalog list endpoints. Out-of-range values are a 422\n * rather than a silent clamp, so a caller paging with a bad limit is told.\n */\nexport function validateListQuery(\n params: URLSearchParams,\n opts: { defaultLimit: number; maxLimit: number; allowUpdatedSince?: boolean; allowActive?: boolean }\n): ListQuery {\n const details: Details = {}\n const limitRaw = params.get('limit')\n const limit = limitRaw ? Number(limitRaw) : opts.defaultLimit\n if (limitRaw && (!Number.isInteger(limit) || limit < 1 || limit > opts.maxLimit)) {\n details.limit = `must be an integer from 1 to ${opts.maxLimit}`\n }\n\n const updatedSinceRaw = opts.allowUpdatedSince ? params.get('updated_since') : null\n if (updatedSinceRaw && Number.isNaN(Date.parse(updatedSinceRaw))) details.updated_since = 'must be an ISO-8601 timestamp'\n\n const activeRaw = opts.allowActive ? params.get('active') : null\n let active: boolean | null = null\n if (activeRaw !== null) {\n if (activeRaw === 'true') active = true\n else if (activeRaw === 'false') active = false\n else details.active = 'must be true or false'\n }\n\n finish(details, 'Invalid query')\n return {\n updatedSince: updatedSinceRaw ? new Date(updatedSinceRaw).toISOString() : null,\n cursor: params.get('cursor'),\n limit: Number.isInteger(limit) ? limit : opts.defaultLimit,\n active,\n }\n}\n\nexport function validateProducts(body: Record<string, unknown>): ProductInput[] {\n const details: Details = {}\n const list = body.products\n if (!Array.isArray(list)) {\n details.products = 'must be an array'\n finish(details, 'Invalid products payload')\n }\n const items = list as unknown[]\n if (items.length > 200) details.products = 'must have at most 200 items'\n const out: ProductInput[] = []\n const seen = new Set<string>()\n items.forEach((raw, i) => {\n const p = `products.${i}`\n if (!isObject(raw)) {\n details[p] = 'must be an object'\n return\n }\n const sku = str(details, raw, 'sku', `${p}.sku`, { required: true, max: 64 })\n const name = str(details, raw, 'name', `${p}.name`, { required: true, max: 255 })\n const slug = str(details, raw, 'slug', `${p}.slug`, { max: 255, nullable: true })\n const description = str(details, raw, 'description_html', `${p}.description_html`, { nullable: true })\n const short = str(details, raw, 'short_description_html', `${p}.short_description_html`, { nullable: true })\n const price = moneyField(details, raw.price, `${p}.price`, { required: true })\n const compare = moneyField(details, raw.compare_at_price, `${p}.compare_at_price`, { nullable: true })\n if (sku && seen.has(sku)) details[`${p}.sku`] = 'appears more than once'\n if (sku) seen.add(sku)\n if (slug && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug)) details[`${p}.slug`] = 'must be lower-case letters, digits and hyphens'\n\n const images: { url: string; alt?: string | null }[] = []\n if (raw.images !== undefined) {\n if (!Array.isArray(raw.images)) details[`${p}.images`] = 'must be an array'\n else\n raw.images.forEach((img, j) => {\n if (!isObject(img) || !isString(img.url) || !img.url.trim()) details[`${p}.images.${j}.url`] = 'is required'\n else images.push({ url: img.url, alt: isString(img.alt) ? img.alt : null })\n })\n }\n const categoryIds: string[] = []\n if (raw.category_ids !== undefined) {\n if (!Array.isArray(raw.category_ids) || !raw.category_ids.every(isString)) details[`${p}.category_ids`] = 'must be an array of strings'\n else categoryIds.push(...(raw.category_ids as string[]))\n }\n let attributes: Record<string, string> = {}\n if (raw.attributes !== undefined) {\n if (!isObject(raw.attributes) || !Object.values(raw.attributes).every(isString)) details[`${p}.attributes`] = 'must be an object of strings'\n else attributes = raw.attributes as Record<string, string>\n }\n if (raw.active !== undefined && typeof raw.active !== 'boolean') details[`${p}.active`] = 'must be a boolean'\n if (raw.position !== undefined && !isInt(raw.position)) details[`${p}.position`] = 'must be an integer'\n\n if (sku && name && price) {\n out.push({\n sku: sku.trim(),\n name: name.trim(),\n slug: slug ?? null,\n description_html: description ?? null,\n short_description_html: short ?? null,\n price,\n compare_at_price: compare ?? null,\n images,\n category_ids: categoryIds,\n attributes,\n active: raw.active === undefined ? true : (raw.active as boolean),\n ...(isInt(raw.position) ? { position: raw.position } : {}),\n })\n }\n })\n finish(details, 'Invalid products payload')\n return out\n}\n\nexport function validateCategories(body: Record<string, unknown>): CategoryInput[] {\n const details: Details = {}\n const list = body.categories\n if (!Array.isArray(list)) {\n details.categories = 'must be an array'\n finish(details, 'Invalid categories payload')\n }\n const items = list as unknown[]\n if (items.length > 500) details.categories = 'must have at most 500 items'\n const out: CategoryInput[] = []\n const seen = new Set<string>()\n items.forEach((raw, i) => {\n const p = `categories.${i}`\n if (!isObject(raw)) {\n details[p] = 'must be an object'\n return\n }\n const id = str(details, raw, 'id', `${p}.id`, { required: true, max: 64 })\n const name = str(details, raw, 'name', `${p}.name`, { required: true, max: 255 })\n const slug = str(details, raw, 'slug', `${p}.slug`, { max: 255, nullable: true })\n const parent = str(details, raw, 'parent_id', `${p}.parent_id`, { max: 64, nullable: true })\n const description = str(details, raw, 'description_html', `${p}.description_html`, { nullable: true })\n if (id && seen.has(id)) details[`${p}.id`] = 'appears more than once'\n if (id) seen.add(id)\n if (id && parent && parent === id) details[`${p}.parent_id`] = 'cannot be the category itself'\n if (slug && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug)) details[`${p}.slug`] = 'must be lower-case letters, digits and hyphens'\n let image: { url: string; alt?: string | null } | null = null\n if (raw.image !== undefined && raw.image !== null) {\n if (!isObject(raw.image) || !isString(raw.image.url)) details[`${p}.image`] = 'must be { url, alt? } or null'\n else image = { url: raw.image.url, alt: isString(raw.image.alt) ? raw.image.alt : null }\n }\n if (raw.position !== undefined && !isInt(raw.position)) details[`${p}.position`] = 'must be an integer'\n if (id && name) {\n out.push({ id: id.trim(), name: name.trim(), slug: slug ?? null, parent_id: parent ?? null, description_html: description ?? null, image, ...(isInt(raw.position) ? { position: raw.position } : {}) })\n }\n })\n finish(details, 'Invalid categories payload')\n return out\n}\n\nexport function validateInventory(body: Record<string, unknown>): InventoryItemInput[] {\n const details: Details = {}\n const list = body.items\n if (!Array.isArray(list)) {\n details.items = 'must be an array'\n finish(details, 'Invalid inventory payload')\n }\n const items = list as unknown[]\n if (items.length > 500) details.items = 'must have at most 500 items'\n const out: InventoryItemInput[] = []\n items.forEach((raw, i) => {\n const p = `items.${i}`\n if (!isObject(raw)) {\n details[p] = 'must be an object'\n return\n }\n const sku = str(details, raw, 'sku', `${p}.sku`, { required: true, max: 64 })\n if (!isInt(raw.available)) details[`${p}.available`] = 'must be an integer'\n else if (raw.available < 0) details[`${p}.available`] = 'must be a non-negative integer'\n if (raw.allow_backorder !== undefined && typeof raw.allow_backorder !== 'boolean') details[`${p}.allow_backorder`] = 'must be a boolean'\n if (sku && isInt(raw.available) && raw.available >= 0) out.push({ sku: sku.trim(), available: raw.available, allow_backorder: raw.allow_backorder === true })\n })\n finish(details, 'Invalid inventory payload')\n return out\n}\n\nexport function validateFulfillment(body: Record<string, unknown>): FulfillmentInput {\n const details: Details = {}\n const externalId = str(details, body, 'external_id', 'external_id', { required: true, max: 64 })\n const carrier = str(details, body, 'carrier', 'carrier', { nullable: true, max: 100 })\n const service = str(details, body, 'service', 'service', { nullable: true, max: 100 })\n const trackingNumber = str(details, body, 'tracking_number', 'tracking_number', { nullable: true, max: 100 })\n const trackingUrl = str(details, body, 'tracking_url', 'tracking_url', { nullable: true, max: 2000 })\n if (trackingUrl && !/^https?:\\/\\//.test(trackingUrl)) details.tracking_url = 'must be an absolute http(s) URL'\n const shippedAt = isoDate(details, body.shipped_at, 'shipped_at')\n if (body.notify_customer !== undefined && typeof body.notify_customer !== 'boolean') details.notify_customer = 'must be a boolean'\n const lines: { sku: string; quantity: number }[] = []\n if (!Array.isArray(body.lines) || body.lines.length === 0) details.lines = 'must be a non-empty array'\n else\n body.lines.forEach((raw, i) => {\n if (!isObject(raw) || !isString(raw.sku) || !raw.sku.trim()) details[`lines.${i}.sku`] = 'is required'\n if (!isObject(raw) || !isInt(raw.quantity) || raw.quantity < 1) details[`lines.${i}.quantity`] = 'must be an integer of at least 1'\n if (isObject(raw) && isString(raw.sku) && isInt(raw.quantity) && raw.quantity >= 1) lines.push({ sku: raw.sku.trim(), quantity: raw.quantity })\n })\n finish(details, 'Invalid fulfillment payload')\n return {\n external_id: externalId!.trim(),\n carrier: carrier ?? null,\n service: service ?? null,\n tracking_number: trackingNumber ?? null,\n tracking_url: trackingUrl ?? null,\n shipped_at: shippedAt ?? null,\n lines,\n notify_customer: body.notify_customer === undefined ? true : (body.notify_customer as boolean),\n }\n}\n\nexport interface OrderPatch {\n external_reference?: string | null\n status?: 'cancelled'\n payment?: { status: 'paid' | 'refunded' | 'failed'; provider?: string | null; reference?: string | null; paid_at?: string | null }\n}\n\nexport function validateOrderPatch(body: Record<string, unknown>): OrderPatch {\n const details: Details = {}\n const out: OrderPatch = {}\n if ('external_reference' in body) {\n const ref = str(details, body, 'external_reference', 'external_reference', { nullable: true, max: 64 })\n if (ref !== undefined) out.external_reference = ref\n }\n if (body.status !== undefined) {\n if (body.status !== 'cancelled') details.status = 'can only be set to \"cancelled\"'\n else out.status = 'cancelled'\n }\n if (body.payment !== undefined) {\n if (!isObject(body.payment)) details.payment = 'must be an object'\n else {\n const p = body.payment\n if (p.status !== 'paid' && p.status !== 'refunded' && p.status !== 'failed') details['payment.status'] = 'must be paid, refunded or failed'\n const provider = str(details, p, 'provider', 'payment.provider', { nullable: true, max: 64 })\n const reference = str(details, p, 'reference', 'payment.reference', { nullable: true, max: 255 })\n const paidAt = isoDate(details, p.paid_at, 'payment.paid_at')\n if (p.status === 'paid' || p.status === 'refunded' || p.status === 'failed') {\n out.payment = { status: p.status, provider: provider ?? null, reference: reference ?? null, paid_at: paidAt ?? null }\n }\n }\n }\n if (!('external_reference' in body) && body.status === undefined && body.payment === undefined) details.body = 'must include external_reference, status or payment'\n finish(details, 'Invalid order patch')\n return out\n}\n\nexport interface QuotePatch {\n external_reference?: string | null\n status?: 'cancelled'\n offer?: QuoteOfferInput\n}\n\n/** `PATCH /quotes/{id}`: stamp a reference, withdraw the quote, or price it (`offer`). */\nexport function validateQuotePatch(body: Record<string, unknown>): QuotePatch {\n const details: Details = {}\n const out: QuotePatch = {}\n if ('external_reference' in body) {\n const ref = str(details, body, 'external_reference', 'external_reference', { nullable: true, max: 64 })\n if (ref !== undefined) out.external_reference = ref\n }\n if (body.status !== undefined) {\n if (body.status !== 'cancelled') details.status = 'can only be set to \"cancelled\"'\n else out.status = 'cancelled'\n }\n if (body.offer !== undefined) {\n if (!isObject(body.offer)) details.offer = 'must be an object'\n else {\n const o = body.offer\n const lines: QuoteOfferInput['lines'] = []\n if (!Array.isArray(o.lines) || o.lines.length === 0) details['offer.lines'] = 'must be a non-empty array'\n else\n o.lines.forEach((raw, i) => {\n if (!isObject(raw)) {\n details[`offer.lines.${i}`] = 'must be an object'\n return\n }\n const sku = str(details, raw, 'sku', `offer.lines.${i}.sku`, { required: true, max: 100 })\n const name = str(details, raw, 'name', `offer.lines.${i}.name`, { nullable: true, max: 300 })\n if (!isInt(raw.quantity) || raw.quantity < 1) details[`offer.lines.${i}.quantity`] = 'must be an integer of at least 1'\n const unit = moneyField(details, raw.unit_amount, `offer.lines.${i}.unit_amount`, { required: true })\n if (sku && isInt(raw.quantity) && raw.quantity >= 1 && unit) lines.push({ sku: sku.trim(), name: name ?? null, quantity: raw.quantity, unit_amount: unit })\n })\n const shipping = moneyField(details, o.shipping, 'offer.shipping', { nullable: true })\n const tax = moneyField(details, o.tax, 'offer.tax', { nullable: true })\n const expiresAt = isoDate(details, o.expires_at, 'offer.expires_at')\n const note = str(details, o, 'note', 'offer.note', { nullable: true, max: 4000 })\n if (o.notify_customer !== undefined && typeof o.notify_customer !== 'boolean') details['offer.notify_customer'] = 'must be a boolean'\n out.offer = {\n lines,\n shipping: shipping ?? null,\n tax: tax ?? null,\n expires_at: expiresAt ?? null,\n note: note ?? null,\n notify_customer: o.notify_customer === undefined ? true : (o.notify_customer as boolean),\n }\n }\n }\n if (out.status && out.offer) details.status = 'cannot be combined with an offer'\n if (!('external_reference' in body) && body.status === undefined && body.offer === undefined) details.body = 'must include external_reference, status or offer'\n finish(details, 'Invalid quote patch')\n return out\n}\n","import type { Connection, Store } from '../store'\nimport { API_KEY_PREFIX, type ConnectScope } from '../store/connections'\nimport { secretsEqual } from '../store/crypto'\nimport { StoreError } from '../store/errors'\nimport { serializeCategory, serializeFulfillment, serializeOrder, serializeProduct, serializeQuote } from './serialize'\nimport {\n validateCategories, validateFulfillment, validateInventory, validateListQuery, validateOrderPatch, validateProducts, validateQuotePatch, ValidationError,\n} from './validate'\n\nexport interface StoreApiOptions {\n store: Store\n /**\n * The STORE_API_KEY secret — the break-glass key that works without an owner\n * or a connection. Optional: a store whose consumers all connect through the\n * owner-approved flow can leave it unset.\n */\n apiKey: string | undefined\n /** Where the API is mounted in the request URL. */\n basePath?: string\n}\n\n/** Who a request authenticated as: the environment key, or an approved connection. */\nexport type ApiCaller = { kind: 'env' } | { kind: 'connection'; connection: Connection }\n\n/**\n * Where the Store API is served. `/api/store/v1` is the neutral path for any\n * operations system; `/api/skuio/v1` is the original path SKU.io's Storefront\n * integration calls, kept for good. Same handler, same keys, same responses.\n */\nexport const STORE_API_BASES = ['/api/store/v1', '/api/skuio/v1'] as const\n/** @deprecated The SKU.io path; use STORE_API_BASES. */\nexport const STORE_API_BASE = '/api/skuio/v1'\n\nconst json = (body: unknown, status = 200, headers: Record<string, string> = {}) =>\n new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store', ...headers } })\n\nconst error = (status: number, code: string, message: string, details: Record<string, string> | null = null) =>\n json({ error: { code, message, details } }, status)\n\n/**\n * The Store API (`docs/store-api.md`) as one fetch-style handler. Mount it on\n * a catch-all route under `/api/store/v1` (and `/api/skuio/v1`, the path SKU.io\n * calls) and hand it every method.\n */\nexport async function handleStoreApi(request: Request, options: StoreApiOptions): Promise<Response> {\n const url = new URL(request.url)\n const bases = options.basePath ? [options.basePath] : [...STORE_API_BASES]\n const base = bases.map((b) => b.replace(/\\/+$/, '')).find((b) => url.pathname.includes(b))\n if (!base) return error(404, 'not_found', 'No such endpoint')\n const at = url.pathname.indexOf(base)\n const path = url.pathname.slice(at + base.length).replace(/\\/+$/, '') || '/'\n const method = request.method.toUpperCase()\n\n try {\n // The token exchange is the one unauthenticated endpoint: the code is the credential.\n if (path === '/connect/token' && method === 'POST') {\n const issued = await options.store.connections.exchange(await readJson(request), clientAddress(request))\n return json({ data: { api_key: issued.apiKey, connection: serializeConnection(issued.connection) } }, 201)\n }\n\n const caller = await authorized(request, options.apiKey, options.store)\n if (!caller) return error(401, 'unauthorized', 'A valid bearer key is required: a connection key issued through /admin/connect, or the STORE_API_KEY secret')\n\n // A connection may use only what the owner approved; the STORE_API_KEY secret may use everything.\n const scope = scopeFor(path)\n if (scope && caller.kind === 'connection' && !caller.connection.scopes.includes(scope)) {\n return error(403, 'forbidden', `This connection was not approved for \"${scope}\"; reconnect and approve it at /admin/connect`)\n }\n\n return await route(method, path, url, request, options.store, caller)\n } catch (e) {\n if (e instanceof ValidationError) return error(422, 'validation_failed', e.message, e.details)\n if (e instanceof StoreError) return error(e.status, e.code, e.message, e.details)\n console.error('store api: unhandled error', e)\n return error(500, 'internal_error', 'The store could not complete the request')\n }\n}\n\nasync function authorized(request: Request, apiKey: string | undefined, store: Store): Promise<ApiCaller | null> {\n const header = request.headers.get('authorization') ?? ''\n const match = /^Bearer\\s+(.+)$/i.exec(header.trim())\n if (!match) return null\n const bearer = match[1]!.trim()\n if (bearer.startsWith(API_KEY_PREFIX)) {\n const connection = await store.connections.resolveKey(bearer)\n return connection ? { kind: 'connection', connection } : null\n }\n if (apiKey && (await secretsEqual(bearer, apiKey))) return { kind: 'env' }\n return null\n}\n\n/** The caller's address for failure counting; Cloudflare sets the first header, proxies the second. */\nfunction clientAddress(request: Request): string {\n return request.headers.get('cf-connecting-ip') ?? request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? 'unknown'\n}\n\nexport function serializeConnection(c: Connection) {\n return {\n id: c.id,\n name: c.name,\n tenant: c.tenant,\n scopes: c.scopes,\n key_prefix: c.keyPrefix,\n created_at: c.createdAt,\n issued_at: c.issuedAt,\n last_used_at: c.lastUsedAt,\n revoked_at: c.revokedAt,\n }\n}\n\nasync function readJson(request: Request): Promise<Record<string, unknown>> {\n const text = await request.text()\n if (!text.trim()) throw new ValidationError('Request body must be JSON', { body: 'is empty' })\n let parsed: unknown\n try {\n parsed = JSON.parse(text)\n } catch {\n throw new ValidationError('Request body must be JSON', { body: 'is not valid JSON' })\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new ValidationError('Request body must be a JSON object', { body: 'is not an object' })\n return parsed as Record<string, unknown>\n}\n\n/**\n * The scope an endpoint needs. There is deliberately no endpoint that creates\n * an order: orders come only from the store's own checkout, priced from its\n * database, or from a buyer accepting a quote, so a leaked key cannot invent\n * sales. A key with `quotes` can price a quote; only the buyer turns it into\n * an order.\n */\nfunction scopeFor(path: string): ConnectScope | null {\n const first = path.split('/').filter(Boolean)[0]\n if (first === 'orders') return /^\\/orders\\/[^/]+\\/fulfillments$/.test(path) ? 'fulfillments' : 'orders'\n if (first === 'inventory') return 'inventory'\n if (first === 'products' || first === 'categories') return 'catalog'\n if (first === 'quotes') return 'quotes'\n return null // /health, /connect\n}\n\nasync function route(method: string, path: string, url: URL, request: Request, store: Store, caller: ApiCaller): Promise<Response> {\n const segments = path.split('/').filter(Boolean)\n\n if (path === '/health' && method === 'GET') {\n const health = await store.health()\n const connection = caller.kind === 'connection' ? { id: caller.connection.id, name: caller.connection.name, tenant: caller.connection.tenant } : null\n return json({ data: { ...health, connection } })\n }\n\n if (path === '/connect') {\n if (method === 'GET') return json({ data: caller.kind === 'connection' ? serializeConnection(caller.connection) : null })\n if (method === 'DELETE') {\n if (caller.kind !== 'connection') return error(409, 'conflict', 'The STORE_API_KEY secret is not a connection; rotate it on the Worker instead')\n await store.connections.revoke(caller.connection.id)\n return new Response(null, { status: 204 })\n }\n }\n\n if (segments[0] === 'orders') {\n if (segments.length === 1 && method === 'GET') {\n const updatedSince = url.searchParams.get('updated_since')\n const cursor = url.searchParams.get('cursor')\n const limitRaw = url.searchParams.get('limit')\n const limit = limitRaw ? Number(limitRaw) : 50\n if (limitRaw && (!Number.isInteger(limit) || limit < 1 || limit > 200)) throw new ValidationError('Invalid query', { limit: 'must be an integer from 1 to 200' })\n if (updatedSince && Number.isNaN(Date.parse(updatedSince))) throw new ValidationError('Invalid query', { updated_since: 'must be an ISO-8601 timestamp' })\n // Lazy housekeeping: abandoned processor checkouts become cancelled before the consumer sees the list.\n await store.orders.expireAbandoned()\n const page = await store.orders.changedSince(updatedSince ? new Date(updatedSince).toISOString() : null, cursor, limit)\n return json({ data: page.orders.map((o) => serializeOrder(o, store.config.orders.numberPrefix)), next_cursor: page.nextCursor })\n }\n const id = segments[1] ? decodeURIComponent(segments[1]) : ''\n if (segments.length === 2 && id) {\n if (method === 'GET') return json({ data: serializeOrder(await store.orders.require(id), store.config.orders.numberPrefix) })\n if (method === 'PATCH') {\n const patch = validateOrderPatch(await readJson(request))\n // Recording a payment is its own scope: a key that may read and stamp orders cannot\n // turn an unpaid order into a paid one unless the owner approved that too.\n if (patch.payment && caller.kind === 'connection' && !caller.connection.scopes.includes('payments')) {\n return error(403, 'forbidden', 'This connection was not approved for \"payments\"; reconnect and approve it at /admin/connect')\n }\n let order = await store.orders.require(id)\n if (patch.external_reference !== undefined) order = await store.orders.setExternalReference(id, patch.external_reference)\n if (patch.payment) order = await store.orders.setPaymentStatus(id, patch.payment)\n if (patch.status === 'cancelled') order = await store.orders.cancel(id, 'Cancelled by the operations system')\n return json({ data: serializeOrder(order, store.config.orders.numberPrefix) })\n }\n }\n if (segments.length === 3 && id && segments[2] === 'fulfillments' && method === 'POST') {\n const input = validateFulfillment(await readJson(request))\n const result = await store.orders.addFulfillment(id, input)\n return json({ data: serializeFulfillment(result.fulfillment) }, result.created ? 201 : 200)\n }\n }\n\n if (segments[0] === 'quotes') {\n const prefix = store.config.quotes.numberPrefix\n if (segments.length === 1 && method === 'GET') {\n const query = validateListQuery(url.searchParams, { defaultLimit: 50, maxLimit: 200, allowUpdatedSince: true })\n // Lazy housekeeping: offers past their expiry become `expired` before the consumer sees the list.\n await store.quotes.expireStale()\n const page = await store.quotes.changedSince(query.updatedSince, query.cursor, query.limit)\n return json({ data: page.quotes.map((q) => serializeQuote(q, prefix)), next_cursor: page.nextCursor })\n }\n const id = segments[1] ? decodeURIComponent(segments[1]) : ''\n if (segments.length === 2 && id) {\n if (method === 'GET') return json({ data: serializeQuote(await store.quotes.require(id), prefix) })\n if (method === 'PATCH') {\n const patch = validateQuotePatch(await readJson(request))\n let quote = await store.quotes.require(id)\n if (patch.external_reference !== undefined) quote = await store.quotes.setExternalReference(id, patch.external_reference)\n if (patch.offer) quote = await store.quotes.offer(id, patch.offer)\n if (patch.status === 'cancelled') quote = await store.quotes.cancel(id, 'Cancelled by the operations system')\n return json({ data: serializeQuote(quote, prefix) })\n }\n }\n }\n\n if (path === '/inventory' && method === 'PUT') {\n const items = validateInventory(await readJson(request))\n return json({ data: await store.inventory.set(items) })\n }\n\n if (path === '/products' && method === 'PUT') {\n const products = validateProducts(await readJson(request))\n return json({ data: { upserted: await store.catalog.upsertProducts(products) } })\n }\n\n if (path === '/products' && method === 'GET') {\n const query = validateListQuery(url.searchParams, { defaultLimit: 50, maxLimit: 200, allowUpdatedSince: true, allowActive: true })\n const page = await store.catalog.listProducts(query)\n return json({ data: page.products.map(serializeProduct), next_cursor: page.nextCursor })\n }\n\n if (segments[0] === 'products' && segments.length === 2) {\n const sku = decodeURIComponent(segments[1]!)\n if (method === 'GET') return json({ data: serializeProduct(await store.catalog.requireProduct(sku)) })\n if (method === 'DELETE') {\n const done = await store.catalog.deactivateProduct(sku)\n if (!done) return error(404, 'not_found', `Product ${sku} not found`)\n return new Response(null, { status: 204 })\n }\n }\n\n if (path === '/categories' && method === 'PUT') {\n const categories = validateCategories(await readJson(request))\n return json({ data: { upserted: await store.catalog.upsertCategories(categories) } })\n }\n\n if (path === '/categories' && method === 'GET') {\n const query = validateListQuery(url.searchParams, { defaultLimit: 500, maxLimit: 1000 })\n const page = await store.catalog.listCategories(query)\n return json({ data: page.categories.map(serializeCategory), next_cursor: page.nextCursor })\n }\n\n return error(404, 'not_found', `No such endpoint: ${method} ${path}`)\n}\n\nexport {\n serializeOrder, serializeFulfillment, serializeProduct, serializeCategory, serializeQuote,\n type ApiOrder, type ApiFulfillment, type ApiProduct, type ApiCategory, type ApiQuote,\n} from './serialize'\nexport { ValidationError } from './validate'\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/api/serialize.ts","../src/api/validate.ts","../src/api/index.ts"],"sourcesContent":["import type { CategoryRecord, ProductRecord } from '../store/catalog'\nimport type { Address, Fulfillment, Money, Order, QuoteStatus, StoreQuote } from '../types'\n\nexport interface ApiMoney {\n amount: number\n currency: string\n}\n\nexport interface ApiAddress {\n name: string | null\n line1: string | null\n line2: string | null\n city: string | null\n state: string | null\n postal_code: string | null\n country: string | null\n}\n\nexport interface ApiFulfillment {\n id: string\n external_id: string\n carrier: string | null\n service: string | null\n tracking_number: string | null\n tracking_url: string | null\n shipped_at: string | null\n lines: { sku: string; quantity: number }[]\n created_at: string\n}\n\nexport interface ApiOrder {\n id: string\n number: string\n status: Order['status']\n payment: { status: Order['payment']['status']; provider: string | null; reference: string | null; method_label: string | null; paid_at: string | null }\n currency: string\n subtotal: ApiMoney\n shipping: ApiMoney\n tax: ApiMoney\n discount: ApiMoney\n /** The store discount code the buyer used, upper case. Partner and commission stay in the store. */\n discount_code: string | null\n total: ApiMoney\n customer: { id: string; email: string; name: string | null; phone: string | null }\n shipping_address: ApiAddress\n billing_address: ApiAddress | null\n shipping_method: { code: string; name: string } | null\n lines: { id: string; sku: string; name: string; quantity: number; unit_amount: ApiMoney; total_amount: ApiMoney; fulfilled_quantity: number }[]\n fulfillments: ApiFulfillment[]\n external_reference: string | null\n notes: string | null\n metadata: Record<string, string>\n created_at: string\n updated_at: string\n paid_at: string | null\n cancelled_at: string | null\n}\n\nexport interface ApiQuote {\n id: string\n /** With the store's quote prefix: \"Q1001\". */\n number: string\n status: QuoteStatus\n currency: string\n customer: { id: string; email: string; name: string | null; phone: string | null }\n company: string | null\n message: string | null\n shipping_address: ApiAddress | null\n lines: { id: string; sku: string; name: string; quantity: number; list_amount: ApiMoney | null; unit_amount: ApiMoney | null; total_amount: ApiMoney | null }[]\n subtotal: ApiMoney | null\n shipping: ApiMoney | null\n tax: ApiMoney | null\n total: ApiMoney | null\n note: string | null\n expires_at: string | null\n external_reference: string | null\n /** The order the buyer's acceptance placed; it also arrives through GET /orders with `metadata.quote_id`. */\n order_id: string | null\n decline_reason: string | null\n metadata: Record<string, string>\n created_at: string\n updated_at: string\n quoted_at: string | null\n accepted_at: string | null\n declined_at: string | null\n cancelled_at: string | null\n}\n\nexport interface ApiProduct {\n sku: string\n name: string\n slug: string\n description_html: string | null\n short_description_html: string | null\n price: ApiMoney\n compare_at: ApiMoney | null\n attributes: Record<string, string>\n active: boolean\n position: number\n legacy_path: string | null\n categories: { id: string; slug: string | null; name: string | null }[]\n images: { url: string; alt: string | null; position: number }[]\n inventory: { available: number; allow_backorder: boolean; updated_at: string } | null\n created_at: string\n updated_at: string\n}\n\nexport interface ApiCategory {\n id: string\n parent_id: string | null\n slug: string\n name: string\n description_html: string | null\n position: number\n product_count: number\n created_at: string\n updated_at: string\n}\n\nconst money = (m: Money): ApiMoney => ({ amount: m.amount, currency: m.currency.toUpperCase() })\n\nconst address = (a: Address | null): ApiAddress | null =>\n a\n ? {\n name: a.name ?? null,\n line1: a.line1 ?? null,\n line2: a.line2 ?? null,\n city: a.city ?? null,\n state: a.state ?? null,\n postal_code: a.postalCode ?? null,\n country: a.country ?? null,\n }\n : null\n\nexport function serializeFulfillment(f: Fulfillment): ApiFulfillment {\n return {\n id: f.id,\n external_id: f.externalId,\n carrier: f.carrier,\n service: f.service,\n tracking_number: f.trackingNumber,\n tracking_url: f.trackingUrl,\n shipped_at: f.shippedAt,\n lines: f.lines.map((l) => ({ sku: l.sku, quantity: l.quantity })),\n created_at: f.createdAt,\n }\n}\n\n/**\n * The Store API's view of an order. `access_key` never leaves the store. `number` is the human number the buyer\n * sees, with the store's prefix (VLD4200), so the consumer shows the same number.\n */\nexport function serializeOrder(o: Order, numberPrefix = ''): ApiOrder {\n return {\n id: o.id,\n number: `${numberPrefix}${o.number}`,\n status: o.status,\n payment: { status: o.payment.status, provider: o.payment.provider, reference: o.payment.reference, method_label: o.payment.methodLabel, paid_at: o.payment.paidAt },\n currency: o.currency.toUpperCase(),\n subtotal: money(o.subtotal),\n shipping: money(o.shipping),\n tax: money(o.tax),\n discount: money(o.discount),\n discount_code: o.discountCode,\n total: money(o.total),\n customer: { id: o.customer.id, email: o.customer.email, name: o.customer.name, phone: o.customer.phone },\n shipping_address: address(o.shippingAddress) ?? { name: null, line1: null, line2: null, city: null, state: null, postal_code: null, country: null },\n billing_address: address(o.billingAddress),\n shipping_method: o.shippingMethod,\n lines: o.lines.map((l) => ({\n id: l.id,\n sku: l.sku,\n name: l.name,\n quantity: l.quantity,\n unit_amount: money(l.unitAmount),\n total_amount: money(l.totalAmount),\n fulfilled_quantity: l.fulfilledQuantity,\n })),\n fulfillments: o.fulfillments.map(serializeFulfillment),\n external_reference: o.externalReference,\n notes: o.notes,\n metadata: o.metadata,\n created_at: o.createdAt,\n updated_at: o.updatedAt,\n paid_at: o.paidAt,\n cancelled_at: o.cancelledAt,\n }\n}\n\nconst maybeMoney = (m: Money | null): ApiMoney | null => (m ? money(m) : null)\n\n/** The Store API's view of a quote. `access_key` never leaves the store. */\nexport function serializeQuote(q: StoreQuote, numberPrefix = ''): ApiQuote {\n return {\n id: q.id,\n number: `${numberPrefix}${q.number}`,\n status: q.status,\n currency: q.currency.toUpperCase(),\n customer: { id: q.customer.id, email: q.customer.email, name: q.customer.name, phone: q.customer.phone },\n company: q.company,\n message: q.message,\n shipping_address: address(q.shippingAddress),\n lines: q.lines.map((l) => ({\n id: l.id,\n sku: l.sku,\n name: l.name,\n quantity: l.quantity,\n list_amount: maybeMoney(l.listAmount),\n unit_amount: maybeMoney(l.unitAmount),\n total_amount: maybeMoney(l.totalAmount),\n })),\n subtotal: maybeMoney(q.subtotal),\n shipping: maybeMoney(q.shipping),\n tax: maybeMoney(q.tax),\n total: maybeMoney(q.total),\n note: q.offerNote,\n expires_at: q.expiresAt,\n external_reference: q.externalReference,\n order_id: q.orderId,\n decline_reason: q.declineReason,\n metadata: q.metadata,\n created_at: q.createdAt,\n updated_at: q.updatedAt,\n quoted_at: q.quotedAt,\n accepted_at: q.acceptedAt,\n declined_at: q.declinedAt,\n cancelled_at: q.cancelledAt,\n }\n}\n\n/**\n * Maps a stored image src to the public URL a consumer can load. Return null\n * (or undefined) to fall back to the default: an absolute URL as-is, anything\n * else resolved against the request origin.\n */\nexport type ImageUrlResolver = (src: string) => string | null | undefined\n\nexport interface SerializeProductOptions {\n /** The store's own image resolver; see StoreApiOptions.imageUrl. */\n imageUrl?: ImageUrlResolver\n /** The origin relative srcs resolve against when the resolver has no answer (\"https://store.example\"). */\n origin?: string\n}\n\nconst ABSOLUTE = /^[a-z][a-z0-9+.-]*:/i\n\n/**\n * The absolute URL the Store API reports for an image. The store's resolver\n * wins; without one (or when it returns null) an absolute URL passes through\n * unchanged and a relative path or bare filename is resolved against the\n * request origin. Resolving a bare filename only produces a loadable URL when\n * the store serves the file at that path — stores that fingerprint their\n * assets must pass a resolver.\n */\nexport function absoluteImageUrl(src: string, options: SerializeProductOptions = {}): string {\n const url = options.imageUrl?.(src) || src\n if (ABSOLUTE.test(url) || !options.origin) return url\n try {\n return new URL(url, `${options.origin.replace(/\\/+$/, '')}/`).href\n } catch {\n return url\n }\n}\n\n/** The Store API's view of a catalog product — the stored row, not the shopper projection. */\nexport function serializeProduct(p: ProductRecord, options: SerializeProductOptions = {}): ApiProduct {\n return {\n sku: p.sku,\n name: p.name,\n slug: p.slug,\n description_html: p.descriptionHtml,\n short_description_html: p.shortDescriptionHtml,\n price: money(p.price),\n compare_at: p.compareAtPrice ? money(p.compareAtPrice) : null,\n attributes: p.attributes,\n active: p.active,\n position: p.position,\n legacy_path: p.legacyPath,\n categories: p.categories.map((c) => ({ id: c.id, slug: c.slug, name: c.name })),\n images: p.images.map((i) => ({ url: absoluteImageUrl(i.url, options), alt: i.alt, position: i.position })),\n inventory: p.inventory ? { available: p.inventory.available, allow_backorder: p.inventory.allowBackorder, updated_at: p.inventory.updatedAt } : null,\n created_at: p.createdAt,\n updated_at: p.updatedAt,\n }\n}\n\nexport function serializeCategory(c: CategoryRecord): ApiCategory {\n return {\n id: c.id,\n parent_id: c.parentId,\n slug: c.slug,\n name: c.name,\n description_html: c.descriptionHtml,\n position: c.position,\n product_count: c.productCount,\n created_at: c.createdAt,\n updated_at: c.updatedAt,\n }\n}\n","import type { CategoryInput, ProductInput } from '../store/catalog'\nimport type { InventoryItemInput } from '../store/inventory'\nimport type { FulfillmentInput } from '../store/orders'\nimport type { QuoteOfferInput } from '../store/quotes'\nimport type { Money } from '../types'\n\nexport class ValidationError extends Error {\n readonly details: Record<string, string>\n constructor(message: string, details: Record<string, string>) {\n super(message)\n this.name = 'ValidationError'\n this.details = details\n }\n}\n\ntype Details = Record<string, string>\n\nconst isObject = (v: unknown): v is Record<string, unknown> => !!v && typeof v === 'object' && !Array.isArray(v)\nconst isString = (v: unknown): v is string => typeof v === 'string'\nconst isInt = (v: unknown): v is number => typeof v === 'number' && Number.isInteger(v)\n\nfunction str(details: Details, obj: Record<string, unknown>, key: string, path: string, opts: { required?: boolean; max?: number; nullable?: boolean } = {}): string | null | undefined {\n const v = obj[key]\n if (v === undefined) {\n if (opts.required) details[path] = 'is required'\n return undefined\n }\n if (v === null) {\n if (opts.required && !opts.nullable) details[path] = 'is required'\n return opts.nullable || !opts.required ? null : undefined\n }\n if (!isString(v)) {\n details[path] = 'must be a string'\n return undefined\n }\n if (opts.required && !v.trim()) details[path] = 'is required'\n if (opts.max && v.length > opts.max) details[path] = `must be at most ${opts.max} characters`\n return v\n}\n\nfunction moneyField(details: Details, v: unknown, path: string, opts: { required?: boolean; nullable?: boolean } = {}): Money | null | undefined {\n if (v === undefined) {\n if (opts.required) details[path] = 'is required'\n return undefined\n }\n if (v === null) {\n if (!opts.nullable) details[path] = 'is required'\n return null\n }\n if (!isObject(v) || !isInt(v.amount) || !isString(v.currency) || v.currency.length !== 3) {\n details[path] = 'must be { amount: integer minor units, currency: ISO 4217 }'\n return undefined\n }\n if (v.amount < 0) details[path] = 'must not be negative'\n return { amount: v.amount, currency: v.currency }\n}\n\nfunction isoDate(details: Details, v: unknown, path: string): string | null | undefined {\n if (v === undefined) return undefined\n if (v === null) return null\n if (!isString(v) || Number.isNaN(Date.parse(v))) {\n details[path] = 'must be an ISO-8601 timestamp'\n return undefined\n }\n return new Date(v).toISOString()\n}\n\nfunction finish(details: Details, message: string): void {\n if (Object.keys(details).length) throw new ValidationError(message, details)\n}\n\nexport interface ListQuery {\n updatedSince: string | null\n cursor: string | null\n limit: number\n active: boolean | null\n}\n\n/**\n * Query string for the catalog list endpoints. Out-of-range values are a 422\n * rather than a silent clamp, so a caller paging with a bad limit is told.\n */\nexport function validateListQuery(\n params: URLSearchParams,\n opts: { defaultLimit: number; maxLimit: number; allowUpdatedSince?: boolean; allowActive?: boolean }\n): ListQuery {\n const details: Details = {}\n const limitRaw = params.get('limit')\n const limit = limitRaw ? Number(limitRaw) : opts.defaultLimit\n if (limitRaw && (!Number.isInteger(limit) || limit < 1 || limit > opts.maxLimit)) {\n details.limit = `must be an integer from 1 to ${opts.maxLimit}`\n }\n\n const updatedSinceRaw = opts.allowUpdatedSince ? params.get('updated_since') : null\n if (updatedSinceRaw && Number.isNaN(Date.parse(updatedSinceRaw))) details.updated_since = 'must be an ISO-8601 timestamp'\n\n const activeRaw = opts.allowActive ? params.get('active') : null\n let active: boolean | null = null\n if (activeRaw !== null) {\n if (activeRaw === 'true') active = true\n else if (activeRaw === 'false') active = false\n else details.active = 'must be true or false'\n }\n\n finish(details, 'Invalid query')\n return {\n updatedSince: updatedSinceRaw ? new Date(updatedSinceRaw).toISOString() : null,\n cursor: params.get('cursor'),\n limit: Number.isInteger(limit) ? limit : opts.defaultLimit,\n active,\n }\n}\n\nexport function validateProducts(body: Record<string, unknown>): ProductInput[] {\n const details: Details = {}\n const list = body.products\n if (!Array.isArray(list)) {\n details.products = 'must be an array'\n finish(details, 'Invalid products payload')\n }\n const items = list as unknown[]\n if (items.length > 200) details.products = 'must have at most 200 items'\n const out: ProductInput[] = []\n const seen = new Set<string>()\n items.forEach((raw, i) => {\n const p = `products.${i}`\n if (!isObject(raw)) {\n details[p] = 'must be an object'\n return\n }\n const sku = str(details, raw, 'sku', `${p}.sku`, { required: true, max: 64 })\n const name = str(details, raw, 'name', `${p}.name`, { required: true, max: 255 })\n const slug = str(details, raw, 'slug', `${p}.slug`, { max: 255, nullable: true })\n const description = str(details, raw, 'description_html', `${p}.description_html`, { nullable: true })\n const short = str(details, raw, 'short_description_html', `${p}.short_description_html`, { nullable: true })\n const price = moneyField(details, raw.price, `${p}.price`, { required: true })\n const compare = moneyField(details, raw.compare_at_price, `${p}.compare_at_price`, { nullable: true })\n if (sku && seen.has(sku)) details[`${p}.sku`] = 'appears more than once'\n if (sku) seen.add(sku)\n if (slug && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug)) details[`${p}.slug`] = 'must be lower-case letters, digits and hyphens'\n\n const images: { url: string; alt?: string | null }[] = []\n if (raw.images !== undefined) {\n if (!Array.isArray(raw.images)) details[`${p}.images`] = 'must be an array'\n else\n raw.images.forEach((img, j) => {\n if (!isObject(img) || !isString(img.url) || !img.url.trim()) details[`${p}.images.${j}.url`] = 'is required'\n else images.push({ url: img.url, alt: isString(img.alt) ? img.alt : null })\n })\n }\n const categoryIds: string[] = []\n if (raw.category_ids !== undefined) {\n if (!Array.isArray(raw.category_ids) || !raw.category_ids.every(isString)) details[`${p}.category_ids`] = 'must be an array of strings'\n else categoryIds.push(...(raw.category_ids as string[]))\n }\n let attributes: Record<string, string> = {}\n if (raw.attributes !== undefined) {\n if (!isObject(raw.attributes) || !Object.values(raw.attributes).every(isString)) details[`${p}.attributes`] = 'must be an object of strings'\n else attributes = raw.attributes as Record<string, string>\n }\n if (raw.active !== undefined && typeof raw.active !== 'boolean') details[`${p}.active`] = 'must be a boolean'\n if (raw.position !== undefined && !isInt(raw.position)) details[`${p}.position`] = 'must be an integer'\n\n if (sku && name && price) {\n out.push({\n sku: sku.trim(),\n name: name.trim(),\n slug: slug ?? null,\n description_html: description ?? null,\n short_description_html: short ?? null,\n price,\n compare_at_price: compare ?? null,\n images,\n category_ids: categoryIds,\n attributes,\n active: raw.active === undefined ? true : (raw.active as boolean),\n ...(isInt(raw.position) ? { position: raw.position } : {}),\n })\n }\n })\n finish(details, 'Invalid products payload')\n return out\n}\n\nexport function validateCategories(body: Record<string, unknown>): CategoryInput[] {\n const details: Details = {}\n const list = body.categories\n if (!Array.isArray(list)) {\n details.categories = 'must be an array'\n finish(details, 'Invalid categories payload')\n }\n const items = list as unknown[]\n if (items.length > 500) details.categories = 'must have at most 500 items'\n const out: CategoryInput[] = []\n const seen = new Set<string>()\n items.forEach((raw, i) => {\n const p = `categories.${i}`\n if (!isObject(raw)) {\n details[p] = 'must be an object'\n return\n }\n const id = str(details, raw, 'id', `${p}.id`, { required: true, max: 64 })\n const name = str(details, raw, 'name', `${p}.name`, { required: true, max: 255 })\n const slug = str(details, raw, 'slug', `${p}.slug`, { max: 255, nullable: true })\n const parent = str(details, raw, 'parent_id', `${p}.parent_id`, { max: 64, nullable: true })\n const description = str(details, raw, 'description_html', `${p}.description_html`, { nullable: true })\n if (id && seen.has(id)) details[`${p}.id`] = 'appears more than once'\n if (id) seen.add(id)\n if (id && parent && parent === id) details[`${p}.parent_id`] = 'cannot be the category itself'\n if (slug && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug)) details[`${p}.slug`] = 'must be lower-case letters, digits and hyphens'\n let image: { url: string; alt?: string | null } | null = null\n if (raw.image !== undefined && raw.image !== null) {\n if (!isObject(raw.image) || !isString(raw.image.url)) details[`${p}.image`] = 'must be { url, alt? } or null'\n else image = { url: raw.image.url, alt: isString(raw.image.alt) ? raw.image.alt : null }\n }\n if (raw.position !== undefined && !isInt(raw.position)) details[`${p}.position`] = 'must be an integer'\n if (id && name) {\n out.push({ id: id.trim(), name: name.trim(), slug: slug ?? null, parent_id: parent ?? null, description_html: description ?? null, image, ...(isInt(raw.position) ? { position: raw.position } : {}) })\n }\n })\n finish(details, 'Invalid categories payload')\n return out\n}\n\nexport function validateInventory(body: Record<string, unknown>): InventoryItemInput[] {\n const details: Details = {}\n const list = body.items\n if (!Array.isArray(list)) {\n details.items = 'must be an array'\n finish(details, 'Invalid inventory payload')\n }\n const items = list as unknown[]\n if (items.length > 500) details.items = 'must have at most 500 items'\n const out: InventoryItemInput[] = []\n items.forEach((raw, i) => {\n const p = `items.${i}`\n if (!isObject(raw)) {\n details[p] = 'must be an object'\n return\n }\n const sku = str(details, raw, 'sku', `${p}.sku`, { required: true, max: 64 })\n if (!isInt(raw.available)) details[`${p}.available`] = 'must be an integer'\n else if (raw.available < 0) details[`${p}.available`] = 'must be a non-negative integer'\n if (raw.allow_backorder !== undefined && typeof raw.allow_backorder !== 'boolean') details[`${p}.allow_backorder`] = 'must be a boolean'\n if (sku && isInt(raw.available) && raw.available >= 0) out.push({ sku: sku.trim(), available: raw.available, allow_backorder: raw.allow_backorder === true })\n })\n finish(details, 'Invalid inventory payload')\n return out\n}\n\nexport function validateFulfillment(body: Record<string, unknown>): FulfillmentInput {\n const details: Details = {}\n const externalId = str(details, body, 'external_id', 'external_id', { required: true, max: 64 })\n const carrier = str(details, body, 'carrier', 'carrier', { nullable: true, max: 100 })\n const service = str(details, body, 'service', 'service', { nullable: true, max: 100 })\n const trackingNumber = str(details, body, 'tracking_number', 'tracking_number', { nullable: true, max: 100 })\n const trackingUrl = str(details, body, 'tracking_url', 'tracking_url', { nullable: true, max: 2000 })\n if (trackingUrl && !/^https?:\\/\\//.test(trackingUrl)) details.tracking_url = 'must be an absolute http(s) URL'\n const shippedAt = isoDate(details, body.shipped_at, 'shipped_at')\n if (body.notify_customer !== undefined && typeof body.notify_customer !== 'boolean') details.notify_customer = 'must be a boolean'\n const lines: { sku: string; quantity: number }[] = []\n if (!Array.isArray(body.lines) || body.lines.length === 0) details.lines = 'must be a non-empty array'\n else\n body.lines.forEach((raw, i) => {\n if (!isObject(raw) || !isString(raw.sku) || !raw.sku.trim()) details[`lines.${i}.sku`] = 'is required'\n if (!isObject(raw) || !isInt(raw.quantity) || raw.quantity < 1) details[`lines.${i}.quantity`] = 'must be an integer of at least 1'\n if (isObject(raw) && isString(raw.sku) && isInt(raw.quantity) && raw.quantity >= 1) lines.push({ sku: raw.sku.trim(), quantity: raw.quantity })\n })\n finish(details, 'Invalid fulfillment payload')\n return {\n external_id: externalId!.trim(),\n carrier: carrier ?? null,\n service: service ?? null,\n tracking_number: trackingNumber ?? null,\n tracking_url: trackingUrl ?? null,\n shipped_at: shippedAt ?? null,\n lines,\n notify_customer: body.notify_customer === undefined ? true : (body.notify_customer as boolean),\n }\n}\n\nexport interface OrderPatch {\n external_reference?: string | null\n status?: 'cancelled'\n payment?: { status: 'paid' | 'refunded' | 'failed'; provider?: string | null; reference?: string | null; paid_at?: string | null }\n}\n\nexport function validateOrderPatch(body: Record<string, unknown>): OrderPatch {\n const details: Details = {}\n const out: OrderPatch = {}\n if ('external_reference' in body) {\n const ref = str(details, body, 'external_reference', 'external_reference', { nullable: true, max: 64 })\n if (ref !== undefined) out.external_reference = ref\n }\n if (body.status !== undefined) {\n if (body.status !== 'cancelled') details.status = 'can only be set to \"cancelled\"'\n else out.status = 'cancelled'\n }\n if (body.payment !== undefined) {\n if (!isObject(body.payment)) details.payment = 'must be an object'\n else {\n const p = body.payment\n if (p.status !== 'paid' && p.status !== 'refunded' && p.status !== 'failed') details['payment.status'] = 'must be paid, refunded or failed'\n const provider = str(details, p, 'provider', 'payment.provider', { nullable: true, max: 64 })\n const reference = str(details, p, 'reference', 'payment.reference', { nullable: true, max: 255 })\n const paidAt = isoDate(details, p.paid_at, 'payment.paid_at')\n if (p.status === 'paid' || p.status === 'refunded' || p.status === 'failed') {\n out.payment = { status: p.status, provider: provider ?? null, reference: reference ?? null, paid_at: paidAt ?? null }\n }\n }\n }\n if (!('external_reference' in body) && body.status === undefined && body.payment === undefined) details.body = 'must include external_reference, status or payment'\n finish(details, 'Invalid order patch')\n return out\n}\n\nexport interface QuotePatch {\n external_reference?: string | null\n status?: 'cancelled'\n offer?: QuoteOfferInput\n}\n\n/** `PATCH /quotes/{id}`: stamp a reference, withdraw the quote, or price it (`offer`). */\nexport function validateQuotePatch(body: Record<string, unknown>): QuotePatch {\n const details: Details = {}\n const out: QuotePatch = {}\n if ('external_reference' in body) {\n const ref = str(details, body, 'external_reference', 'external_reference', { nullable: true, max: 64 })\n if (ref !== undefined) out.external_reference = ref\n }\n if (body.status !== undefined) {\n if (body.status !== 'cancelled') details.status = 'can only be set to \"cancelled\"'\n else out.status = 'cancelled'\n }\n if (body.offer !== undefined) {\n if (!isObject(body.offer)) details.offer = 'must be an object'\n else {\n const o = body.offer\n const lines: QuoteOfferInput['lines'] = []\n if (!Array.isArray(o.lines) || o.lines.length === 0) details['offer.lines'] = 'must be a non-empty array'\n else\n o.lines.forEach((raw, i) => {\n if (!isObject(raw)) {\n details[`offer.lines.${i}`] = 'must be an object'\n return\n }\n const sku = str(details, raw, 'sku', `offer.lines.${i}.sku`, { required: true, max: 100 })\n const name = str(details, raw, 'name', `offer.lines.${i}.name`, { nullable: true, max: 300 })\n if (!isInt(raw.quantity) || raw.quantity < 1) details[`offer.lines.${i}.quantity`] = 'must be an integer of at least 1'\n const unit = moneyField(details, raw.unit_amount, `offer.lines.${i}.unit_amount`, { required: true })\n if (sku && isInt(raw.quantity) && raw.quantity >= 1 && unit) lines.push({ sku: sku.trim(), name: name ?? null, quantity: raw.quantity, unit_amount: unit })\n })\n const shipping = moneyField(details, o.shipping, 'offer.shipping', { nullable: true })\n const tax = moneyField(details, o.tax, 'offer.tax', { nullable: true })\n const expiresAt = isoDate(details, o.expires_at, 'offer.expires_at')\n const note = str(details, o, 'note', 'offer.note', { nullable: true, max: 4000 })\n if (o.notify_customer !== undefined && typeof o.notify_customer !== 'boolean') details['offer.notify_customer'] = 'must be a boolean'\n out.offer = {\n lines,\n shipping: shipping ?? null,\n tax: tax ?? null,\n expires_at: expiresAt ?? null,\n note: note ?? null,\n notify_customer: o.notify_customer === undefined ? true : (o.notify_customer as boolean),\n }\n }\n }\n if (out.status && out.offer) details.status = 'cannot be combined with an offer'\n if (!('external_reference' in body) && body.status === undefined && body.offer === undefined) details.body = 'must include external_reference, status or offer'\n finish(details, 'Invalid quote patch')\n return out\n}\n","import type { Connection, Store } from '../store'\nimport { API_KEY_PREFIX, type ConnectScope } from '../store/connections'\nimport { secretsEqual } from '../store/crypto'\nimport { StoreError } from '../store/errors'\nimport { serializeCategory, serializeFulfillment, serializeOrder, serializeProduct, serializeQuote, type ImageUrlResolver, type SerializeProductOptions } from './serialize'\nimport {\n validateCategories, validateFulfillment, validateInventory, validateListQuery, validateOrderPatch, validateProducts, validateQuotePatch, ValidationError,\n} from './validate'\n\nexport interface StoreApiOptions {\n store: Store\n /**\n * The STORE_API_KEY secret — the break-glass key that works without an owner\n * or a connection. Optional: a store whose consumers all connect through the\n * owner-approved flow can leave it unset.\n */\n apiKey: string | undefined\n /** Where the API is mounted in the request URL. */\n basePath?: string\n /**\n * Maps a stored product image src (a bare filename, a path, or an absolute\n * URL) to the absolute URL the store actually serves it at — e.g. the\n * fingerprinted `/_astro/<name>.<hash>.jpg` a template's `resolveImage()`\n * finds, made absolute against the site URL. Return null to fall back to the\n * default: an absolute src as-is, a relative one resolved against the\n * request origin. `images[].url` in every response is always absolute.\n */\n imageUrl?: ImageUrlResolver\n}\n\n/** Who a request authenticated as: the environment key, or an approved connection. */\nexport type ApiCaller = { kind: 'env' } | { kind: 'connection'; connection: Connection }\n\n/**\n * Where the Store API is served. `/api/store/v1` is the neutral path for any\n * operations system; `/api/skuio/v1` is the original path SKU.io's Storefront\n * integration calls, kept for good. Same handler, same keys, same responses.\n */\nexport const STORE_API_BASES = ['/api/store/v1', '/api/skuio/v1'] as const\n/** @deprecated The SKU.io path; use STORE_API_BASES. */\nexport const STORE_API_BASE = '/api/skuio/v1'\n\nconst json = (body: unknown, status = 200, headers: Record<string, string> = {}) =>\n new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store', ...headers } })\n\nconst error = (status: number, code: string, message: string, details: Record<string, string> | null = null) =>\n json({ error: { code, message, details } }, status)\n\n/**\n * The Store API (`docs/store-api.md`) as one fetch-style handler. Mount it on\n * a catch-all route under `/api/store/v1` (and `/api/skuio/v1`, the path SKU.io\n * calls) and hand it every method.\n */\nexport async function handleStoreApi(request: Request, options: StoreApiOptions): Promise<Response> {\n const url = new URL(request.url)\n const bases = options.basePath ? [options.basePath] : [...STORE_API_BASES]\n const base = bases.map((b) => b.replace(/\\/+$/, '')).find((b) => url.pathname.includes(b))\n if (!base) return error(404, 'not_found', 'No such endpoint')\n const at = url.pathname.indexOf(base)\n const path = url.pathname.slice(at + base.length).replace(/\\/+$/, '') || '/'\n const method = request.method.toUpperCase()\n\n try {\n // The token exchange is the one unauthenticated endpoint: the code is the credential.\n if (path === '/connect/token' && method === 'POST') {\n const issued = await options.store.connections.exchange(await readJson(request), clientAddress(request))\n return json({ data: { api_key: issued.apiKey, connection: serializeConnection(issued.connection) } }, 201)\n }\n\n const caller = await authorized(request, options.apiKey, options.store)\n if (!caller) return error(401, 'unauthorized', 'A valid bearer key is required: a connection key issued through /admin/connect, or the STORE_API_KEY secret')\n\n // A connection may use only what the owner approved; the STORE_API_KEY secret may use everything.\n const scope = scopeFor(path)\n if (scope && caller.kind === 'connection' && !caller.connection.scopes.includes(scope)) {\n return error(403, 'forbidden', `This connection was not approved for \"${scope}\"; reconnect and approve it at /admin/connect`)\n }\n\n const images: SerializeProductOptions = { imageUrl: options.imageUrl, origin: url.origin }\n return await route(method, path, url, request, options.store, caller, images)\n } catch (e) {\n if (e instanceof ValidationError) return error(422, 'validation_failed', e.message, e.details)\n if (e instanceof StoreError) return error(e.status, e.code, e.message, e.details)\n console.error('store api: unhandled error', e)\n return error(500, 'internal_error', 'The store could not complete the request')\n }\n}\n\nasync function authorized(request: Request, apiKey: string | undefined, store: Store): Promise<ApiCaller | null> {\n const header = request.headers.get('authorization') ?? ''\n const match = /^Bearer\\s+(.+)$/i.exec(header.trim())\n if (!match) return null\n const bearer = match[1]!.trim()\n if (bearer.startsWith(API_KEY_PREFIX)) {\n const connection = await store.connections.resolveKey(bearer)\n return connection ? { kind: 'connection', connection } : null\n }\n if (apiKey && (await secretsEqual(bearer, apiKey))) return { kind: 'env' }\n return null\n}\n\n/** The caller's address for failure counting; Cloudflare sets the first header, proxies the second. */\nfunction clientAddress(request: Request): string {\n return request.headers.get('cf-connecting-ip') ?? request.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? 'unknown'\n}\n\nexport function serializeConnection(c: Connection) {\n return {\n id: c.id,\n name: c.name,\n tenant: c.tenant,\n scopes: c.scopes,\n key_prefix: c.keyPrefix,\n created_at: c.createdAt,\n issued_at: c.issuedAt,\n last_used_at: c.lastUsedAt,\n revoked_at: c.revokedAt,\n }\n}\n\nasync function readJson(request: Request): Promise<Record<string, unknown>> {\n const text = await request.text()\n if (!text.trim()) throw new ValidationError('Request body must be JSON', { body: 'is empty' })\n let parsed: unknown\n try {\n parsed = JSON.parse(text)\n } catch {\n throw new ValidationError('Request body must be JSON', { body: 'is not valid JSON' })\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new ValidationError('Request body must be a JSON object', { body: 'is not an object' })\n return parsed as Record<string, unknown>\n}\n\n/**\n * The scope an endpoint needs. There is deliberately no endpoint that creates\n * an order: orders come only from the store's own checkout, priced from its\n * database, or from a buyer accepting a quote, so a leaked key cannot invent\n * sales. A key with `quotes` can price a quote; only the buyer turns it into\n * an order.\n */\nfunction scopeFor(path: string): ConnectScope | null {\n const first = path.split('/').filter(Boolean)[0]\n if (first === 'orders') return /^\\/orders\\/[^/]+\\/fulfillments$/.test(path) ? 'fulfillments' : 'orders'\n if (first === 'inventory') return 'inventory'\n if (first === 'products' || first === 'categories') return 'catalog'\n if (first === 'quotes') return 'quotes'\n return null // /health, /connect\n}\n\nasync function route(method: string, path: string, url: URL, request: Request, store: Store, caller: ApiCaller, images: SerializeProductOptions): Promise<Response> {\n const segments = path.split('/').filter(Boolean)\n\n if (path === '/health' && method === 'GET') {\n const health = await store.health()\n const connection = caller.kind === 'connection' ? { id: caller.connection.id, name: caller.connection.name, tenant: caller.connection.tenant } : null\n return json({ data: { ...health, connection } })\n }\n\n if (path === '/connect') {\n if (method === 'GET') return json({ data: caller.kind === 'connection' ? serializeConnection(caller.connection) : null })\n if (method === 'DELETE') {\n if (caller.kind !== 'connection') return error(409, 'conflict', 'The STORE_API_KEY secret is not a connection; rotate it on the Worker instead')\n await store.connections.revoke(caller.connection.id)\n return new Response(null, { status: 204 })\n }\n }\n\n if (segments[0] === 'orders') {\n if (segments.length === 1 && method === 'GET') {\n const updatedSince = url.searchParams.get('updated_since')\n const cursor = url.searchParams.get('cursor')\n const limitRaw = url.searchParams.get('limit')\n const limit = limitRaw ? Number(limitRaw) : 50\n if (limitRaw && (!Number.isInteger(limit) || limit < 1 || limit > 200)) throw new ValidationError('Invalid query', { limit: 'must be an integer from 1 to 200' })\n if (updatedSince && Number.isNaN(Date.parse(updatedSince))) throw new ValidationError('Invalid query', { updated_since: 'must be an ISO-8601 timestamp' })\n // Lazy housekeeping: abandoned processor checkouts become cancelled before the consumer sees the list.\n await store.orders.expireAbandoned()\n const page = await store.orders.changedSince(updatedSince ? new Date(updatedSince).toISOString() : null, cursor, limit)\n return json({ data: page.orders.map((o) => serializeOrder(o, store.config.orders.numberPrefix)), next_cursor: page.nextCursor })\n }\n const id = segments[1] ? decodeURIComponent(segments[1]) : ''\n if (segments.length === 2 && id) {\n if (method === 'GET') return json({ data: serializeOrder(await store.orders.require(id), store.config.orders.numberPrefix) })\n if (method === 'PATCH') {\n const patch = validateOrderPatch(await readJson(request))\n // Recording a payment is its own scope: a key that may read and stamp orders cannot\n // turn an unpaid order into a paid one unless the owner approved that too.\n if (patch.payment && caller.kind === 'connection' && !caller.connection.scopes.includes('payments')) {\n return error(403, 'forbidden', 'This connection was not approved for \"payments\"; reconnect and approve it at /admin/connect')\n }\n let order = await store.orders.require(id)\n if (patch.external_reference !== undefined) order = await store.orders.setExternalReference(id, patch.external_reference)\n if (patch.payment) order = await store.orders.setPaymentStatus(id, patch.payment)\n if (patch.status === 'cancelled') order = await store.orders.cancel(id, 'Cancelled by the operations system')\n return json({ data: serializeOrder(order, store.config.orders.numberPrefix) })\n }\n }\n if (segments.length === 3 && id && segments[2] === 'fulfillments' && method === 'POST') {\n const input = validateFulfillment(await readJson(request))\n const result = await store.orders.addFulfillment(id, input)\n return json({ data: serializeFulfillment(result.fulfillment) }, result.created ? 201 : 200)\n }\n }\n\n if (segments[0] === 'quotes') {\n const prefix = store.config.quotes.numberPrefix\n if (segments.length === 1 && method === 'GET') {\n const query = validateListQuery(url.searchParams, { defaultLimit: 50, maxLimit: 200, allowUpdatedSince: true })\n // Lazy housekeeping: offers past their expiry become `expired` before the consumer sees the list.\n await store.quotes.expireStale()\n const page = await store.quotes.changedSince(query.updatedSince, query.cursor, query.limit)\n return json({ data: page.quotes.map((q) => serializeQuote(q, prefix)), next_cursor: page.nextCursor })\n }\n const id = segments[1] ? decodeURIComponent(segments[1]) : ''\n if (segments.length === 2 && id) {\n if (method === 'GET') return json({ data: serializeQuote(await store.quotes.require(id), prefix) })\n if (method === 'PATCH') {\n const patch = validateQuotePatch(await readJson(request))\n let quote = await store.quotes.require(id)\n if (patch.external_reference !== undefined) quote = await store.quotes.setExternalReference(id, patch.external_reference)\n if (patch.offer) quote = await store.quotes.offer(id, patch.offer)\n if (patch.status === 'cancelled') quote = await store.quotes.cancel(id, 'Cancelled by the operations system')\n return json({ data: serializeQuote(quote, prefix) })\n }\n }\n }\n\n if (path === '/inventory' && method === 'PUT') {\n const items = validateInventory(await readJson(request))\n return json({ data: await store.inventory.set(items) })\n }\n\n if (path === '/products' && method === 'PUT') {\n const products = validateProducts(await readJson(request))\n return json({ data: { upserted: await store.catalog.upsertProducts(products) } })\n }\n\n if (path === '/products' && method === 'GET') {\n const query = validateListQuery(url.searchParams, { defaultLimit: 50, maxLimit: 200, allowUpdatedSince: true, allowActive: true })\n const page = await store.catalog.listProducts(query)\n return json({ data: page.products.map((p) => serializeProduct(p, images)), next_cursor: page.nextCursor })\n }\n\n if (segments[0] === 'products' && segments.length === 2) {\n const sku = decodeURIComponent(segments[1]!)\n if (method === 'GET') return json({ data: serializeProduct(await store.catalog.requireProduct(sku), images) })\n if (method === 'DELETE') {\n const done = await store.catalog.deactivateProduct(sku)\n if (!done) return error(404, 'not_found', `Product ${sku} not found`)\n return new Response(null, { status: 204 })\n }\n }\n\n if (path === '/categories' && method === 'PUT') {\n const categories = validateCategories(await readJson(request))\n return json({ data: { upserted: await store.catalog.upsertCategories(categories) } })\n }\n\n if (path === '/categories' && method === 'GET') {\n const query = validateListQuery(url.searchParams, { defaultLimit: 500, maxLimit: 1000 })\n const page = await store.catalog.listCategories(query)\n return json({ data: page.categories.map(serializeCategory), next_cursor: page.nextCursor })\n }\n\n return error(404, 'not_found', `No such endpoint: ${method} ${path}`)\n}\n\nexport {\n serializeOrder, serializeFulfillment, serializeProduct, serializeCategory, serializeQuote, absoluteImageUrl,\n type ImageUrlResolver, type SerializeProductOptions,\n type ApiOrder, type ApiFulfillment, type ApiProduct, type ApiCategory, type ApiQuote,\n} from './serialize'\nexport { ValidationError } from './validate'\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skuio/storefront",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "The store platform behind SKU.io storefronts: catalog, checkout, orders, buyer portal and the Store API over one SQL driver — Cloudflare D1 or SQLite on any Node host. Framework-agnostic; pairs with the Astro reference template.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|