platform-types 1.10.688 → 1.10.690
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/cjs/index.js +2 -0
- package/dist/cjs/order.js +27 -4
- package/dist/cjs/storefrontDesign.js +20 -10
- package/dist/cjs/storefrontSeo.js +64 -0
- package/dist/cjs/storefrontTheme.js +32 -8
- package/dist/cjs/storefrontWebLiteralKeys.js +1115 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/order.d.ts +28 -5
- package/dist/order.js +27 -4
- package/dist/store.d.ts +10 -2
- package/dist/storefrontDesign.d.ts +73 -10
- package/dist/storefrontDesign.js +18 -9
- package/dist/storefrontSeo.d.ts +77 -0
- package/dist/storefrontSeo.js +58 -0
- package/dist/storefrontTheme.d.ts +23 -7
- package/dist/storefrontTheme.js +30 -8
- package/dist/storefrontWebLiteralKeys.d.ts +23 -0
- package/dist/storefrontWebLiteralKeys.js +1111 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -79,6 +79,8 @@ export * from './storefrontTheme.ts';
|
|
|
79
79
|
export * from './storeNetwork.ts';
|
|
80
80
|
export * from './storefrontAssets.ts';
|
|
81
81
|
export * from './storefrontEvent.ts';
|
|
82
|
+
export * from './storefrontSeo.ts';
|
|
83
|
+
export * from './storefrontWebLiteralKeys.ts';
|
|
82
84
|
export * from './subscription.ts';
|
|
83
85
|
export * from './support.ts';
|
|
84
86
|
export * from './terminal.ts';
|
package/dist/index.js
CHANGED
|
@@ -87,6 +87,8 @@ export * from "./storefrontTheme.js";
|
|
|
87
87
|
export * from "./storeNetwork.js";
|
|
88
88
|
export * from "./storefrontAssets.js";
|
|
89
89
|
export * from "./storefrontEvent.js";
|
|
90
|
+
export * from "./storefrontSeo.js";
|
|
91
|
+
export * from "./storefrontWebLiteralKeys.js";
|
|
90
92
|
export * from "./subscription.js";
|
|
91
93
|
export * from "./support.js";
|
|
92
94
|
export * from "./terminal.js";
|
package/dist/order.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { MoneyOutAttribution } from './terminal.ts';
|
|
2
2
|
declare global {
|
|
3
|
+
interface OrderBelowMinimumPurchaseData {
|
|
4
|
+
minBuy: number;
|
|
5
|
+
grandTotal: number;
|
|
6
|
+
currency: string;
|
|
7
|
+
}
|
|
3
8
|
/**
|
|
4
9
|
* A coupon as it was redeemed onto an order — the grant frozen at
|
|
5
10
|
* consumption, plus the money it actually took.
|
|
@@ -2576,10 +2581,28 @@ export declare const orderFulfilmentProgress: (order: OrderFulfilmentProgressInp
|
|
|
2576
2581
|
* `data.shiftId`. Logged; reconcile the queued sale by hand.
|
|
2577
2582
|
* - `ORDER_CURRENCY_NOT_SUBSCRIBED` · 400 — the sale's currency has no
|
|
2578
2583
|
* subscription in the store's `currencies`. Logged.
|
|
2579
|
-
* - `PAYMENT_METHODS_NOT_CONFIGURED` · 409 — `tenders` sent
|
|
2580
|
-
* has no payment methods at
|
|
2581
|
-
*
|
|
2582
|
-
*
|
|
2584
|
+
* - `PAYMENT_METHODS_NOT_CONFIGURED` · 409 — `tenders` sent, or storefront/
|
|
2585
|
+
* WhatsApp checkout attempted, while the store has no payment methods at
|
|
2586
|
+
* all. Storefront checkout carries `data: {}` and refuses before the cart read.
|
|
2587
|
+
* - `PAYMENT_METHOD_NOT_FOUND` · 400 — a tender leg's `method`, or storefront
|
|
2588
|
+
* checkout's `paymentMethod`, names none of the store's payment methods.
|
|
2589
|
+
* Storefront checkout carries `data: {}` and refuses before the cart read.
|
|
2590
|
+
*
|
|
2591
|
+
* Storefront and WhatsApp checkout business refusals. None allocates an order
|
|
2592
|
+
* id, redeems a coupon or writes an order; none is logged as an error:
|
|
2593
|
+
* - `DELIVERY_METHOD_NOT_FOUND` · 400 — `deliveryMethod` is not in the store's
|
|
2594
|
+
* delivery catalogue, including an absent/empty catalogue. `data: {}`;
|
|
2595
|
+
* refused before reading the cart.
|
|
2596
|
+
* - `ORDER_INVALID_CART` · 400 — the normalized cart has no finite numeric
|
|
2597
|
+
* `totals.grandTotal`. `data: {}`; refused before repricing/allocation.
|
|
2598
|
+
* - `ORDER_BELOW_MINIMUM_PURCHASE` · 400 — after repricing has confirmed the
|
|
2599
|
+
* cart, its grand total is below a finite positive `Number(customer.minBuy)`.
|
|
2600
|
+
* Equality passes. `data: OrderBelowMinimumPurchaseData` carries minBuy,
|
|
2601
|
+
* grandTotal and the cart display currency, with no currency conversion.
|
|
2602
|
+
* - `EMAIL_VERIFICATION_REQUIRED` · 403 — the store requires email verification
|
|
2603
|
+
* and the live customer has not verified. No data payload; before cart read.
|
|
2604
|
+
* - `ACCOUNT_DISABLED` · 403 — the live customer is disabled. No data payload;
|
|
2605
|
+
* before cart read. This is distinct from the staff `CUSTOMER_DISABLED` code.
|
|
2583
2606
|
*
|
|
2584
2607
|
* Commit-time drawer refusals, on a create whose cash tender books into a
|
|
2585
2608
|
* drawer shift. No order committed, but a coupon redeemed before the commit
|
|
@@ -2677,6 +2700,6 @@ export declare const orderFulfilmentProgress: (order: OrderFulfilmentProgressInp
|
|
|
2677
2700
|
* `SUBSCRIPTION_READONLY`) sit on the order CREATE leg only: an edit is not a new
|
|
2678
2701
|
* order, so `bareOrderPostHandler` routes past `requireMetered` entirely.
|
|
2679
2702
|
*/
|
|
2680
|
-
export declare const ORDER_ERROR_CODES: readonly ["ORDER_COST_DENOMINATION_UNKNOWN", "SERVICE_ORDER_DELIVERY_MANAGED", "ORDER_NOT_FOUND", "ORDER_LOCKED", "ORDER_NOT_READY", "ORDER_DELIVERED_ANOTHER_DAY", "ORDER_DELIVERY_STATE_UNCHANGED", "ORDER_ILLEGAL_TRANSITION", "ORDER_VERSION_CONFLICT", "CUSTOMER_NOT_FOUND", "CUSTOMER_MERGED", "ORDER_HAS_NO_CUSTOMER", "CUSTOMER_ANONYMIZED", "FX_CONVERSION_UNAVAILABLE", "ROLE_FORBIDDEN", "ORDER_CANCELLED", "PAYMENT_SETTLED_ON_ANOTHER_ORDER", "ORDER_HAS_SHIPMENTS", "ORDER_HAS_RETURNS", "SHIPMENT_QUANTITY_EXCEEDED", "SHIPMENT_LINE_MISMATCH", "SHIPMENT_NOT_FOUND", "SHIPMENT_LIMIT_REACHED", "SHIPMENT_TOO_LARGE", "ORDER_FULFILMENT_EXTERNAL", "SHIPMENT_FAILED", "ADMIN_REQUIRED", "IDEMPOTENCY_KEY_REQUIRED", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSE", "IDEMPOTENCY_IN_PROGRESS", "IDEMPOTENCY_LOCK_CONTENTION", "IDEMPOTENCY_KEY_FAILED", "IDEMPOTENT_RESPONSE_NOT_CACHED", "ORDER_CANCELLATION_NOT_PROTECTED", "ORDER_CANCELLATION_COMMITTED", "ORDER_CANCELLATION_LOCKED", "ORDER_CANCELLATION_TOO_LARGE", "ORDER_CANCELLATION_FAILED", "SALE_LEDGER_RETRACTION_REFUSED", "SALE_LEDGER_ROW_NOT_OWNED", "PRODUCT_NOT_FOUND", "PRODUCT_SALE_LIMIT_EXCEEDED", "PRODUCT_SALE_LIMIT_INVALID", "DEPOSIT_SOURCE_NOT_ALLOWED", "DEPOSIT_CURRENCY_MISMATCH", "DEPOSIT_EXCEEDS_TOTAL", "DEPOSIT_FREEZE_REQUIRES_INVOICE", "DEPOSIT_FREEZE_INVOICE_PENDING", "DEPOSIT_CHARACTERIZATION_CONFLICT", "DEPOSIT_FREEZE_INVOICE_NOT_QUALIFYING", "DEPOSIT_INVOICED_ORDER_MUST_FREEZE", "DEPOSIT_REFERENCE_IS_LINKED_PAYMENT", "DEPOSIT_DUPLICATE_REFERENCE", "PAYMENT_REFERENCED_BY_DEPOSIT", "ORDER_HAS_UNREFUNDED_DEPOSIT", "DEPOSIT_NOT_FOUND", "DEPOSIT_ALREADY_REFUNDED", "UNIT_QUANTITY_NOT_WHOLE", "UNIT_REVISION_STALE", "UNIT_QUANTITY_UNREPRESENTABLE", "KIT_RECIPE_CHANGED", "CART_PROMOTION_UNAVAILABLE", "ORDER_HAS_KIT_LINES", "ORDER_TARGET_REQUIRED", "ORDER_SOURCE_CONFLICT", "ORDER_CUSTOMER_REQUIRED", "BASKET_EMPTY", "BASKET_CHANGED_DURING_CHECKOUT", "CART_VERSION_CREATE_ONLY", "CART_VERSION_REQUIRES_CART_ID", "CART_REVISION_STALE", "CART_CUSTOMER_MISMATCH", "COUNTER_SALE_CREATE_ONLY", "SOLD_AT_CREATE_ONLY", "SOLD_AT_IN_FUTURE", "ORDER_TENDER_CREATE_ONLY", "CREDIT_OVERRIDE_CREATE_ONLY", "ON_ACCOUNT_CREATE_ONLY", "ON_ACCOUNT_WITH_TENDERS", "TENDERS_REQUIRE_COUNTER_SALE", "LINES_REQUIRE_COUNTER_SALE", "PRODUCT_COST_UNKNOWN", "PRICE_CHANGE_DISABLED", "LINE_DISCOUNT_EXCEEDS_MAX", "CUSTOMER_DISABLED", "SHIFT_NOT_AVAILABLE", "SOLD_AT_OUTSIDE_SHIFT", "ORDER_CURRENCY_NOT_SUBSCRIBED", "PAYMENT_METHODS_NOT_CONFIGURED", "PAYMENT_METHOD_NOT_FOUND", "CURRENCY_MISMATCH", "SHIFT_NOT_OPEN", "ORDER_DISCOUNT_AFTER_INVOICE", "ORDER_DISCOUNT_ON_SERVICE_ORDER", "ORDER_DISCOUNT_ON_MARKETPLACE_ORDER", "ORDER_INVOICE_METHOD_OUTSTANDING_FACTURA", "ORDER_SERVICE_PERIOD_AFTER_INVOICE", "ORDER_ATTEMPT_COMMITTED", "ORDER_ATTEMPT_ABANDONED", "ORDER_ATTEMPT_KEY_EXPIRED", "ORDER_ATTEMPT_KEY_SCOPE_MISMATCH"];
|
|
2703
|
+
export declare const ORDER_ERROR_CODES: readonly ["ORDER_COST_DENOMINATION_UNKNOWN", "SERVICE_ORDER_DELIVERY_MANAGED", "ORDER_NOT_FOUND", "ORDER_LOCKED", "ORDER_NOT_READY", "ORDER_DELIVERED_ANOTHER_DAY", "ORDER_DELIVERY_STATE_UNCHANGED", "ORDER_ILLEGAL_TRANSITION", "ORDER_VERSION_CONFLICT", "CUSTOMER_NOT_FOUND", "CUSTOMER_MERGED", "ORDER_HAS_NO_CUSTOMER", "CUSTOMER_ANONYMIZED", "FX_CONVERSION_UNAVAILABLE", "ROLE_FORBIDDEN", "ORDER_CANCELLED", "PAYMENT_SETTLED_ON_ANOTHER_ORDER", "ORDER_HAS_SHIPMENTS", "ORDER_HAS_RETURNS", "SHIPMENT_QUANTITY_EXCEEDED", "SHIPMENT_LINE_MISMATCH", "SHIPMENT_NOT_FOUND", "SHIPMENT_LIMIT_REACHED", "SHIPMENT_TOO_LARGE", "ORDER_FULFILMENT_EXTERNAL", "SHIPMENT_FAILED", "ADMIN_REQUIRED", "IDEMPOTENCY_KEY_REQUIRED", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSE", "IDEMPOTENCY_IN_PROGRESS", "IDEMPOTENCY_LOCK_CONTENTION", "IDEMPOTENCY_KEY_FAILED", "IDEMPOTENT_RESPONSE_NOT_CACHED", "ORDER_CANCELLATION_NOT_PROTECTED", "ORDER_CANCELLATION_COMMITTED", "ORDER_CANCELLATION_LOCKED", "ORDER_CANCELLATION_TOO_LARGE", "ORDER_CANCELLATION_FAILED", "SALE_LEDGER_RETRACTION_REFUSED", "SALE_LEDGER_ROW_NOT_OWNED", "PRODUCT_NOT_FOUND", "PRODUCT_SALE_LIMIT_EXCEEDED", "PRODUCT_SALE_LIMIT_INVALID", "DEPOSIT_SOURCE_NOT_ALLOWED", "DEPOSIT_CURRENCY_MISMATCH", "DEPOSIT_EXCEEDS_TOTAL", "DEPOSIT_FREEZE_REQUIRES_INVOICE", "DEPOSIT_FREEZE_INVOICE_PENDING", "DEPOSIT_CHARACTERIZATION_CONFLICT", "DEPOSIT_FREEZE_INVOICE_NOT_QUALIFYING", "DEPOSIT_INVOICED_ORDER_MUST_FREEZE", "DEPOSIT_REFERENCE_IS_LINKED_PAYMENT", "DEPOSIT_DUPLICATE_REFERENCE", "PAYMENT_REFERENCED_BY_DEPOSIT", "ORDER_HAS_UNREFUNDED_DEPOSIT", "DEPOSIT_NOT_FOUND", "DEPOSIT_ALREADY_REFUNDED", "UNIT_QUANTITY_NOT_WHOLE", "UNIT_REVISION_STALE", "UNIT_QUANTITY_UNREPRESENTABLE", "KIT_RECIPE_CHANGED", "CART_PROMOTION_UNAVAILABLE", "ORDER_HAS_KIT_LINES", "ORDER_TARGET_REQUIRED", "ORDER_SOURCE_CONFLICT", "ORDER_CUSTOMER_REQUIRED", "BASKET_EMPTY", "BASKET_CHANGED_DURING_CHECKOUT", "CART_VERSION_CREATE_ONLY", "CART_VERSION_REQUIRES_CART_ID", "CART_REVISION_STALE", "CART_CUSTOMER_MISMATCH", "COUNTER_SALE_CREATE_ONLY", "SOLD_AT_CREATE_ONLY", "SOLD_AT_IN_FUTURE", "ORDER_TENDER_CREATE_ONLY", "CREDIT_OVERRIDE_CREATE_ONLY", "ON_ACCOUNT_CREATE_ONLY", "ON_ACCOUNT_WITH_TENDERS", "TENDERS_REQUIRE_COUNTER_SALE", "LINES_REQUIRE_COUNTER_SALE", "PRODUCT_COST_UNKNOWN", "PRICE_CHANGE_DISABLED", "LINE_DISCOUNT_EXCEEDS_MAX", "CUSTOMER_DISABLED", "SHIFT_NOT_AVAILABLE", "SOLD_AT_OUTSIDE_SHIFT", "ORDER_CURRENCY_NOT_SUBSCRIBED", "PAYMENT_METHODS_NOT_CONFIGURED", "PAYMENT_METHOD_NOT_FOUND", "DELIVERY_METHOD_NOT_FOUND", "ORDER_BELOW_MINIMUM_PURCHASE", "ORDER_INVALID_CART", "EMAIL_VERIFICATION_REQUIRED", "ACCOUNT_DISABLED", "CURRENCY_MISMATCH", "SHIFT_NOT_OPEN", "ORDER_DISCOUNT_AFTER_INVOICE", "ORDER_DISCOUNT_ON_SERVICE_ORDER", "ORDER_DISCOUNT_ON_MARKETPLACE_ORDER", "ORDER_INVOICE_METHOD_OUTSTANDING_FACTURA", "ORDER_SERVICE_PERIOD_AFTER_INVOICE", "ORDER_ATTEMPT_COMMITTED", "ORDER_ATTEMPT_ABANDONED", "ORDER_ATTEMPT_KEY_EXPIRED", "ORDER_ATTEMPT_KEY_SCOPE_MISMATCH"];
|
|
2681
2704
|
export type OrderErrorCode = (typeof ORDER_ERROR_CODES)[number];
|
|
2682
2705
|
export {};
|
package/dist/order.js
CHANGED
|
@@ -337,10 +337,28 @@ export const orderFulfilmentProgress = (order) => {
|
|
|
337
337
|
* `data.shiftId`. Logged; reconcile the queued sale by hand.
|
|
338
338
|
* - `ORDER_CURRENCY_NOT_SUBSCRIBED` · 400 — the sale's currency has no
|
|
339
339
|
* subscription in the store's `currencies`. Logged.
|
|
340
|
-
* - `PAYMENT_METHODS_NOT_CONFIGURED` · 409 — `tenders` sent
|
|
341
|
-
* has no payment methods at
|
|
342
|
-
*
|
|
343
|
-
*
|
|
340
|
+
* - `PAYMENT_METHODS_NOT_CONFIGURED` · 409 — `tenders` sent, or storefront/
|
|
341
|
+
* WhatsApp checkout attempted, while the store has no payment methods at
|
|
342
|
+
* all. Storefront checkout carries `data: {}` and refuses before the cart read.
|
|
343
|
+
* - `PAYMENT_METHOD_NOT_FOUND` · 400 — a tender leg's `method`, or storefront
|
|
344
|
+
* checkout's `paymentMethod`, names none of the store's payment methods.
|
|
345
|
+
* Storefront checkout carries `data: {}` and refuses before the cart read.
|
|
346
|
+
*
|
|
347
|
+
* Storefront and WhatsApp checkout business refusals. None allocates an order
|
|
348
|
+
* id, redeems a coupon or writes an order; none is logged as an error:
|
|
349
|
+
* - `DELIVERY_METHOD_NOT_FOUND` · 400 — `deliveryMethod` is not in the store's
|
|
350
|
+
* delivery catalogue, including an absent/empty catalogue. `data: {}`;
|
|
351
|
+
* refused before reading the cart.
|
|
352
|
+
* - `ORDER_INVALID_CART` · 400 — the normalized cart has no finite numeric
|
|
353
|
+
* `totals.grandTotal`. `data: {}`; refused before repricing/allocation.
|
|
354
|
+
* - `ORDER_BELOW_MINIMUM_PURCHASE` · 400 — after repricing has confirmed the
|
|
355
|
+
* cart, its grand total is below a finite positive `Number(customer.minBuy)`.
|
|
356
|
+
* Equality passes. `data: OrderBelowMinimumPurchaseData` carries minBuy,
|
|
357
|
+
* grandTotal and the cart display currency, with no currency conversion.
|
|
358
|
+
* - `EMAIL_VERIFICATION_REQUIRED` · 403 — the store requires email verification
|
|
359
|
+
* and the live customer has not verified. No data payload; before cart read.
|
|
360
|
+
* - `ACCOUNT_DISABLED` · 403 — the live customer is disabled. No data payload;
|
|
361
|
+
* before cart read. This is distinct from the staff `CUSTOMER_DISABLED` code.
|
|
344
362
|
*
|
|
345
363
|
* Commit-time drawer refusals, on a create whose cash tender books into a
|
|
346
364
|
* drawer shift. No order committed, but a coupon redeemed before the commit
|
|
@@ -545,6 +563,11 @@ export const ORDER_ERROR_CODES = [
|
|
|
545
563
|
'ORDER_CURRENCY_NOT_SUBSCRIBED',
|
|
546
564
|
'PAYMENT_METHODS_NOT_CONFIGURED',
|
|
547
565
|
'PAYMENT_METHOD_NOT_FOUND',
|
|
566
|
+
'DELIVERY_METHOD_NOT_FOUND',
|
|
567
|
+
'ORDER_BELOW_MINIMUM_PURCHASE',
|
|
568
|
+
'ORDER_INVALID_CART',
|
|
569
|
+
'EMAIL_VERIFICATION_REQUIRED',
|
|
570
|
+
'ACCOUNT_DISABLED',
|
|
548
571
|
// Commit-time drawer refusals; `CURRENCY_MISMATCH` carries its fields at the body's top level.
|
|
549
572
|
'CURRENCY_MISMATCH',
|
|
550
573
|
'SHIFT_NOT_OPEN',
|
package/dist/store.d.ts
CHANGED
|
@@ -115,6 +115,11 @@ declare global {
|
|
|
115
115
|
deactivatesAt?: number | null;
|
|
116
116
|
config?: Partial<StorefrontLiveSettings> & {
|
|
117
117
|
showDefaultPriceList?: number;
|
|
118
|
+
/** New self-registrants use this list; absent means PUBLICO (1).
|
|
119
|
+
* Zero is refused and writes validate membership in store.priceLists.
|
|
120
|
+
* Never sent to shoppers.
|
|
121
|
+
*/
|
|
122
|
+
newCustomerPriceList?: number;
|
|
118
123
|
showStocks?: boolean;
|
|
119
124
|
};
|
|
120
125
|
sidebar?: {
|
|
@@ -152,9 +157,12 @@ declare global {
|
|
|
152
157
|
appVersion?: number;
|
|
153
158
|
stats?: Record<string, string>;
|
|
154
159
|
}
|
|
155
|
-
/** Sparse tenant PATCH shape; live null values reset to registry defaults and are never stored.
|
|
160
|
+
/** Sparse tenant PATCH shape; live null values reset to registry defaults and are never stored.
|
|
161
|
+
* An unknown newCustomerPriceList refuses 400 PRICE_LIST_NOT_FOUND with
|
|
162
|
+
* data: { field: 'ecommerce.config.newCustomerPriceList', value: number }; nothing written.
|
|
163
|
+
*/
|
|
156
164
|
interface EcommercePatchInput {
|
|
157
|
-
config?: Pick<NonNullable<Ecommerce['config']>, 'showDefaultPriceList'> & StorefrontLiveSettingsPatch;
|
|
165
|
+
config?: Pick<NonNullable<Ecommerce['config']>, 'showDefaultPriceList' | 'newCustomerPriceList'> & StorefrontLiveSettingsPatch;
|
|
158
166
|
sidebar?: Ecommerce['sidebar'];
|
|
159
167
|
home?: Omit<NonNullable<Ecommerce['home']>, 'displayOrders' | 'displayProfile'>;
|
|
160
168
|
themeColors?: Ecommerce['themeColors'];
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { StorefrontThemeWarning } from './storefrontTheme.ts';
|
|
2
|
+
/** The social kinds a contact may link, each to its own hosts; a contact links at most one per kind. */
|
|
3
|
+
export declare const STOREFRONT_SOCIAL_HOSTS: {
|
|
4
|
+
readonly instagram: readonly ["instagram.com", "www.instagram.com"];
|
|
5
|
+
readonly facebook: readonly ["facebook.com", "www.facebook.com"];
|
|
6
|
+
readonly youtube: readonly ["youtube.com", "www.youtube.com", "youtu.be", "www.youtu.be"];
|
|
7
|
+
readonly tiktok: readonly ["tiktok.com", "www.tiktok.com"];
|
|
8
|
+
readonly linkedin: readonly ["linkedin.com", "www.linkedin.com"];
|
|
9
|
+
readonly x: readonly ["x.com", "www.x.com"];
|
|
10
|
+
};
|
|
2
11
|
export declare const STOREFRONT_DESIGN_LIMITS: {
|
|
3
12
|
readonly customPages: 20;
|
|
4
13
|
readonly pageAliases: 20;
|
|
@@ -37,9 +46,17 @@ export declare const STOREFRONT_DESIGN_LIMITS: {
|
|
|
37
46
|
readonly contactAddress: 500;
|
|
38
47
|
readonly contactNote: 200;
|
|
39
48
|
readonly contactHours: 14;
|
|
40
|
-
|
|
49
|
+
/** One link per social kind, so the cap is the number of kinds. */
|
|
50
|
+
readonly contactSocials: number;
|
|
41
51
|
readonly contactEmail: 254;
|
|
42
52
|
};
|
|
53
|
+
/**
|
|
54
|
+
* A custom page's slug: lowercase ASCII letters, digits and inner hyphens, 1 to
|
|
55
|
+
* `STOREFRONT_DESIGN_LIMITS.slug` characters, starting and ending alphanumeric. The one
|
|
56
|
+
* definition: the api's validators, its page renderer and the edge viewer request read it.
|
|
57
|
+
*/
|
|
58
|
+
export declare const STOREFRONT_PAGE_SLUG_RE: RegExp;
|
|
59
|
+
export declare const isStorefrontPageSlug: (value: unknown) => value is string;
|
|
43
60
|
export declare const STOREFRONT_SECTION_TYPES: readonly ["banner", "imageText", "products", "categories", "brands", "text", "faq", "benefits", "contact", "paymentDelivery"];
|
|
44
61
|
export declare const STOREFRONT_BUILTIN_DESTINATIONS: readonly ["home", "catalogue", "offers", "new", "search", "cart", "account", "privacy"];
|
|
45
62
|
/**
|
|
@@ -55,14 +72,6 @@ export declare const STOREFRONT_PROTECTED_BUILTIN_DESTINATIONS: readonly ["searc
|
|
|
55
72
|
export declare const STOREFRONT_CONTACT_FIELDS: readonly ["email", "phone", "whatsapp", "address", "hours", "socials"];
|
|
56
73
|
export declare const STOREFRONT_RESERVED_SLUGS: readonly ["home", "index", "api", "auth", "login", "logout", "account", "cart", "checkout", "orders", "search", "products", "product", "producto", "coleccion", "categories", "brands", "sale", "new", "privacy", "terms", "sitemap", "robots", "manifest", "assets", "preview", "admin", "storefront", "pagina", "basket", "profile", "favorites", "invoices", "payments", "payment-methods", "user", "mantenimiento"];
|
|
57
74
|
export declare const STOREFRONT_BENEFIT_ICONS: readonly ["truck", "shield", "credit-card", "store", "heart", "check"];
|
|
58
|
-
export declare const STOREFRONT_SOCIAL_HOSTS: {
|
|
59
|
-
readonly instagram: readonly ["instagram.com", "www.instagram.com"];
|
|
60
|
-
readonly facebook: readonly ["facebook.com", "www.facebook.com"];
|
|
61
|
-
readonly youtube: readonly ["youtube.com", "www.youtube.com", "youtu.be", "www.youtu.be"];
|
|
62
|
-
readonly tiktok: readonly ["tiktok.com", "www.tiktok.com"];
|
|
63
|
-
readonly linkedin: readonly ["linkedin.com", "www.linkedin.com"];
|
|
64
|
-
readonly x: readonly ["x.com", "www.x.com"];
|
|
65
|
-
};
|
|
66
75
|
export declare function createStorefrontDesignV1(): StorefrontDesignV1;
|
|
67
76
|
declare global {
|
|
68
77
|
type StorefrontDesignSectionType = (typeof STOREFRONT_SECTION_TYPES)[number];
|
|
@@ -272,7 +281,7 @@ declare global {
|
|
|
272
281
|
};
|
|
273
282
|
/**
|
|
274
283
|
* Image placements gain `url`/`mobileUrl`: the variant-LESS base
|
|
275
|
-
* `/
|
|
284
|
+
* `/media/{stage}/{storeId}/{publicationId}/{assetId}`, a path on the images host. Append
|
|
276
285
|
* `/${StorefrontAssetVariant}` (one of `STOREFRONT_ASSET_VARIANTS`) to request it; the base
|
|
277
286
|
* alone is not servable. Never route it through `/fit-in/`: the media path is refused there.
|
|
278
287
|
* Private preview envelopes instead supply `/preview/read?operation=asset&assetId=...`; the
|
|
@@ -400,6 +409,17 @@ declare global {
|
|
|
400
409
|
items: StorefrontDesignHistoryEntry[];
|
|
401
410
|
cursor?: string;
|
|
402
411
|
}
|
|
412
|
+
/** A page of the live publication: the slug it answers at and the former slugs that 301 to it. */
|
|
413
|
+
interface StorefrontDesignPublishedPage {
|
|
414
|
+
slug: string;
|
|
415
|
+
aliases: string[];
|
|
416
|
+
}
|
|
417
|
+
/** Where a resolved setting's value came from: the registry default, a platform layer, or the document. */
|
|
418
|
+
type StorefrontDesignSettingProvenance = 'default' | 'platform' | 'design';
|
|
419
|
+
/**
|
|
420
|
+
* GET draft and every mutation that answers the draft (init, save, discard, restore) carry the
|
|
421
|
+
* same result; an idempotent replay rebuilds the four derived fields from current reads.
|
|
422
|
+
*/
|
|
403
423
|
interface StorefrontDesignDraftResult {
|
|
404
424
|
draftRevision: string;
|
|
405
425
|
publishedRevision: string | null;
|
|
@@ -407,6 +427,28 @@ declare global {
|
|
|
407
427
|
dirty: boolean;
|
|
408
428
|
mappingConflicts: StorefrontDesignMappingConflict[];
|
|
409
429
|
legacySourceRevision: string;
|
|
430
|
+
/**
|
|
431
|
+
* The live publication's page addresses, keyed by page id: every page that has ever been
|
|
432
|
+
* published and still owns its slug, a since-removed or disabled page's included. Renaming
|
|
433
|
+
* an ENABLED page listed here makes its current slug a 301 alias on the next publish; a
|
|
434
|
+
* page absent here has no live address, so renaming it creates no alias. Absent when the
|
|
435
|
+
* shop has never published.
|
|
436
|
+
*/
|
|
437
|
+
publishedPages?: Record<string, StorefrontDesignPublishedPage>;
|
|
438
|
+
/**
|
|
439
|
+
* What publishing this saved document would refuse today, as field errors: missing required
|
|
440
|
+
* content, a link to a disabled or missing page (`DANGLING_REFERENCE`), a slug a published
|
|
441
|
+
* page still owns (`ALIAS_CONFLICT`), a page out of aliases (`ALIAS_LIMIT`), and one
|
|
442
|
+
* `MAPPING_CONFLICT` per unresolved `mappingConflicts` entry, at that entry's path (the
|
|
443
|
+
* publish refusal itself names the single path `mappingConflicts`). Empty when publishable.
|
|
444
|
+
* Never blocks a save, and never covers asset readiness, which publish probes on its own
|
|
445
|
+
* (`STOREFRONT_ASSET_NOT_READY`).
|
|
446
|
+
*/
|
|
447
|
+
publishIssues?: StorefrontDesignFieldError[];
|
|
448
|
+
/** The document's settings over the live platform layer: what the published shop would render. */
|
|
449
|
+
effectiveSettings?: StorefrontDesignSettings;
|
|
450
|
+
/** Per setting, which layer `effectiveSettings` took it from. */
|
|
451
|
+
settingsProvenance?: Record<keyof StorefrontDesignSettings, StorefrontDesignSettingProvenance>;
|
|
410
452
|
}
|
|
411
453
|
interface StorefrontDesignDeliveryTarget {
|
|
412
454
|
/**
|
|
@@ -516,6 +558,27 @@ declare global {
|
|
|
516
558
|
assetId: string;
|
|
517
559
|
variant?: StorefrontAssetVariant;
|
|
518
560
|
};
|
|
561
|
+
/**
|
|
562
|
+
* The codes `GET /preview/read` answers itself, on the common `{ message, error }` body:
|
|
563
|
+
* 400 `STOREFRONT_PREVIEW_INVALID` (a query the read schema refuses, a repeated parameter or a
|
|
564
|
+
* body), 401 `STOREFRONT_PREVIEW_INVALID` (no or a malformed bearer grant), 401 `…_EXPIRED`,
|
|
565
|
+
* 403 `…_REVOKED` / `…_FORBIDDEN` / `PLAN_UPGRADE_REQUIRED` (bare, without the editor
|
|
566
|
+
* routes' plan fields), 404 `ASSET_NOT_FOUND` (an asset the pinned draft does not reference or
|
|
567
|
+
* that is not ready), 405 `METHOD_NOT_ALLOWED` (anything but GET and OPTIONS), 413
|
|
568
|
+
* `STOREFRONT_PREVIEW_IMAGE_TOO_LARGE` (asset bytes over 4 MiB) and 503 `…_UNAVAILABLE`.
|
|
569
|
+
*/
|
|
570
|
+
type StorefrontPreviewReadErrorCode = 'STOREFRONT_PREVIEW_INVALID' | 'STOREFRONT_PREVIEW_EXPIRED' | 'STOREFRONT_PREVIEW_REVOKED' | 'STOREFRONT_PREVIEW_FORBIDDEN' | 'STOREFRONT_PREVIEW_UNAVAILABLE' | 'STOREFRONT_PREVIEW_IMAGE_TOO_LARGE' | 'PLAN_UPGRADE_REQUIRED' | 'ASSET_NOT_FOUND' | 'METHOD_NOT_ALLOWED';
|
|
571
|
+
/**
|
|
572
|
+
* The codes a catalogue operation answers through its public web route's own core, as that
|
|
573
|
+
* route does: 404 `PRODUCT_NOT_FOUND` / `PRODUCT_GROUP_NOT_FOUND` / `COLLECTION_NOT_FOUND`,
|
|
574
|
+
* 400 `INVALID_CURSOR` / `INVALID_DISCOVERY_QUERY`, 409 `CURSOR_STALE` (a collection that
|
|
575
|
+
* changed between the reads bracketing a page) and 503 `PRODUCT_LOOKUP_INCOMPLETE`.
|
|
576
|
+
*/
|
|
577
|
+
type StorefrontPreviewCatalogueErrorCode = 'PRODUCT_NOT_FOUND' | 'PRODUCT_GROUP_NOT_FOUND' | 'COLLECTION_NOT_FOUND' | 'INVALID_CURSOR' | 'INVALID_DISCOVERY_QUERY' | 'CURSOR_STALE' | 'PRODUCT_LOOKUP_INCOMPLETE';
|
|
578
|
+
interface StorefrontPreviewReadFailure {
|
|
579
|
+
message: string;
|
|
580
|
+
error: StorefrontPreviewReadErrorCode | StorefrontPreviewCatalogueErrorCode;
|
|
581
|
+
}
|
|
519
582
|
interface StorefrontPreviewDesignResult {
|
|
520
583
|
mode: 'preview';
|
|
521
584
|
draftRevision: string;
|
package/dist/storefrontDesign.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/** The social kinds a contact may link, each to its own hosts; a contact links at most one per kind. */
|
|
2
|
+
export const STOREFRONT_SOCIAL_HOSTS = {
|
|
3
|
+
instagram: ['instagram.com', 'www.instagram.com'],
|
|
4
|
+
facebook: ['facebook.com', 'www.facebook.com'],
|
|
5
|
+
youtube: ['youtube.com', 'www.youtube.com', 'youtu.be', 'www.youtu.be'],
|
|
6
|
+
tiktok: ['tiktok.com', 'www.tiktok.com'],
|
|
7
|
+
linkedin: ['linkedin.com', 'www.linkedin.com'],
|
|
8
|
+
x: ['x.com', 'www.x.com'],
|
|
9
|
+
};
|
|
1
10
|
export const STOREFRONT_DESIGN_LIMITS = {
|
|
2
11
|
customPages: 20,
|
|
3
12
|
pageAliases: 20,
|
|
@@ -36,9 +45,17 @@ export const STOREFRONT_DESIGN_LIMITS = {
|
|
|
36
45
|
contactAddress: 500,
|
|
37
46
|
contactNote: 200,
|
|
38
47
|
contactHours: 14,
|
|
39
|
-
|
|
48
|
+
/** One link per social kind, so the cap is the number of kinds. */
|
|
49
|
+
contactSocials: Object.keys(STOREFRONT_SOCIAL_HOSTS).length,
|
|
40
50
|
contactEmail: 254,
|
|
41
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* A custom page's slug: lowercase ASCII letters, digits and inner hyphens, 1 to
|
|
54
|
+
* `STOREFRONT_DESIGN_LIMITS.slug` characters, starting and ending alphanumeric. The one
|
|
55
|
+
* definition: the api's validators, its page renderer and the edge viewer request read it.
|
|
56
|
+
*/
|
|
57
|
+
export const STOREFRONT_PAGE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,78}[a-z0-9])?$/;
|
|
58
|
+
export const isStorefrontPageSlug = (value) => typeof value === 'string' && STOREFRONT_PAGE_SLUG_RE.test(value);
|
|
42
59
|
export const STOREFRONT_SECTION_TYPES = [
|
|
43
60
|
'banner',
|
|
44
61
|
'imageText',
|
|
@@ -117,14 +134,6 @@ export const STOREFRONT_RESERVED_SLUGS = [
|
|
|
117
134
|
'mantenimiento',
|
|
118
135
|
];
|
|
119
136
|
export const STOREFRONT_BENEFIT_ICONS = ['truck', 'shield', 'credit-card', 'store', 'heart', 'check'];
|
|
120
|
-
export const STOREFRONT_SOCIAL_HOSTS = {
|
|
121
|
-
instagram: ['instagram.com', 'www.instagram.com'],
|
|
122
|
-
facebook: ['facebook.com', 'www.facebook.com'],
|
|
123
|
-
youtube: ['youtube.com', 'www.youtube.com', 'youtu.be', 'www.youtu.be'],
|
|
124
|
-
tiktok: ['tiktok.com', 'www.tiktok.com'],
|
|
125
|
-
linkedin: ['linkedin.com', 'www.linkedin.com'],
|
|
126
|
-
x: ['x.com', 'www.x.com'],
|
|
127
|
-
};
|
|
128
137
|
export function createStorefrontDesignV1() {
|
|
129
138
|
return {
|
|
130
139
|
schemaVersion: 1,
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Information-page paths and the storefront's SEO inheritance chain — one
|
|
3
|
+
* definition for the server that renders a shared link's head and the editor
|
|
4
|
+
* that previews it.
|
|
5
|
+
*/
|
|
6
|
+
/** Path prefix of a published information page: `/pagina/<slug>`. */
|
|
7
|
+
export declare const STOREFRONT_PAGE_PATH_PREFIX = "/pagina/";
|
|
8
|
+
/** The path an information page with `slug` is served at. The slug is neither validated nor encoded here. */
|
|
9
|
+
export declare const storefrontPagePath: (slug: string) => string;
|
|
10
|
+
/** The description a shop is shared with when neither the page nor the shop sets one. */
|
|
11
|
+
export declare const storefrontDefaultSeoDescription: (storeName: string) => string;
|
|
12
|
+
/**
|
|
13
|
+
* Where a resolved SEO field came from: the page itself, the shop-wide `seo`
|
|
14
|
+
* block, the shop logo (image only), or the platform default.
|
|
15
|
+
*/
|
|
16
|
+
export type StorefrontSeoSource = 'page' | 'shop' | 'logo' | 'default';
|
|
17
|
+
/** The SEO fields a page and the shop each carry; `Placement` is the image shape of the document passed in. */
|
|
18
|
+
export interface StorefrontSeoFields<Placement = StorefrontDesignImagePlacement> {
|
|
19
|
+
title?: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
image?: Placement;
|
|
22
|
+
noindex?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* What {@link resolveStorefrontSeo} reads from a design document. A draft
|
|
26
|
+
* (`StorefrontDesignV1`), the published projection and `PublicStorefrontDesign`
|
|
27
|
+
* all satisfy it; with the last, a resolved image keeps its `url`.
|
|
28
|
+
*/
|
|
29
|
+
export interface StorefrontSeoDocument<Placement = StorefrontDesignImagePlacement> {
|
|
30
|
+
seo: StorefrontSeoFields<Placement>;
|
|
31
|
+
branding: {
|
|
32
|
+
logo?: Placement;
|
|
33
|
+
};
|
|
34
|
+
pages: readonly {
|
|
35
|
+
id: string;
|
|
36
|
+
title: string;
|
|
37
|
+
seo?: StorefrontSeoFields<Placement>;
|
|
38
|
+
}[];
|
|
39
|
+
}
|
|
40
|
+
/** The SEO a page is shared with, each field with where it came from. */
|
|
41
|
+
export interface ResolvedStorefrontSeo<Placement = StorefrontDesignImagePlacement> {
|
|
42
|
+
title: string;
|
|
43
|
+
description: string;
|
|
44
|
+
/**
|
|
45
|
+
* The placement shared as `og:image` (cropped to 1200x630), or `null` for
|
|
46
|
+
* the platform's own share image (`source.image === 'default'`).
|
|
47
|
+
*/
|
|
48
|
+
image: Placement | null;
|
|
49
|
+
noindex: boolean;
|
|
50
|
+
source: {
|
|
51
|
+
title: Exclude<StorefrontSeoSource, 'logo'>;
|
|
52
|
+
description: Exclude<StorefrontSeoSource, 'logo'>;
|
|
53
|
+
image: StorefrontSeoSource;
|
|
54
|
+
noindex: Exclude<StorefrontSeoSource, 'logo'>;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The SEO the storefront shares a page with: `'home'`, or an information page
|
|
59
|
+
* by `id`.
|
|
60
|
+
*
|
|
61
|
+
* - title: the page's `seo.title`, else its `title`, else the shop's
|
|
62
|
+
* `seo.title`, else `storeName`. Home skips the page steps — its own `title`
|
|
63
|
+
* is never used.
|
|
64
|
+
* - description: the page's `seo.description`, else the shop's, else
|
|
65
|
+
* {@link storefrontDefaultSeoDescription}.
|
|
66
|
+
* - image: the page's `seo.image`, else the shop's, else the logo, else `null`
|
|
67
|
+
* (the platform share image).
|
|
68
|
+
* - noindex: the page's `seo.noindex` when set — an explicit `false` beats a
|
|
69
|
+
* shop-wide `true` — else the shop's, else `false`.
|
|
70
|
+
*
|
|
71
|
+
* An empty title or description counts as unset and falls through. Returns
|
|
72
|
+
* `undefined` for a page id the document does not carry; `'home'` always
|
|
73
|
+
* resolves. A shop with no published design is out of scope: its head uses
|
|
74
|
+
* the store's own name, photo and the default description.
|
|
75
|
+
*/
|
|
76
|
+
export declare function resolveStorefrontSeo<Placement>(document: StorefrontSeoDocument<Placement>, target: 'home', storeName: string): ResolvedStorefrontSeo<Placement>;
|
|
77
|
+
export declare function resolveStorefrontSeo<Placement>(document: StorefrontSeoDocument<Placement>, target: string, storeName: string): ResolvedStorefrontSeo<Placement> | undefined;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Information-page paths and the storefront's SEO inheritance chain — one
|
|
3
|
+
* definition for the server that renders a shared link's head and the editor
|
|
4
|
+
* that previews it.
|
|
5
|
+
*/
|
|
6
|
+
/** Path prefix of a published information page: `/pagina/<slug>`. */
|
|
7
|
+
export const STOREFRONT_PAGE_PATH_PREFIX = '/pagina/';
|
|
8
|
+
/** The path an information page with `slug` is served at. The slug is neither validated nor encoded here. */
|
|
9
|
+
export const storefrontPagePath = (slug) => `${STOREFRONT_PAGE_PATH_PREFIX}${slug}`;
|
|
10
|
+
/** The description a shop is shared with when neither the page nor the shop sets one. */
|
|
11
|
+
export const storefrontDefaultSeoDescription = (storeName) => `Comprá online en ${storeName}: catálogo, precios y stock actualizados.`;
|
|
12
|
+
const shopImage = (document) => {
|
|
13
|
+
if (document.seo.image)
|
|
14
|
+
return { image: document.seo.image, source: 'shop' };
|
|
15
|
+
if (document.branding.logo)
|
|
16
|
+
return { image: document.branding.logo, source: 'logo' };
|
|
17
|
+
return { image: null, source: 'default' };
|
|
18
|
+
};
|
|
19
|
+
/** Home's SEO — and the default every information page inherits field by field. */
|
|
20
|
+
const shopSeo = (document, storeName) => {
|
|
21
|
+
const { seo } = document;
|
|
22
|
+
const image = shopImage(document);
|
|
23
|
+
return {
|
|
24
|
+
title: seo.title || storeName,
|
|
25
|
+
description: seo.description || storefrontDefaultSeoDescription(storeName),
|
|
26
|
+
image: image.image,
|
|
27
|
+
noindex: seo.noindex === true,
|
|
28
|
+
source: {
|
|
29
|
+
title: seo.title ? 'shop' : 'default',
|
|
30
|
+
description: seo.description ? 'shop' : 'default',
|
|
31
|
+
image: image.source,
|
|
32
|
+
noindex: typeof seo.noindex === 'boolean' ? 'shop' : 'default',
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export function resolveStorefrontSeo(document, target, storeName) {
|
|
37
|
+
const shop = shopSeo(document, storeName);
|
|
38
|
+
if (target === 'home')
|
|
39
|
+
return shop;
|
|
40
|
+
const page = document.pages.find(({ id }) => id === target);
|
|
41
|
+
if (!page)
|
|
42
|
+
return undefined;
|
|
43
|
+
const own = page.seo;
|
|
44
|
+
const pageTitle = own?.title || page.title;
|
|
45
|
+
const pageNoindex = own?.noindex;
|
|
46
|
+
return {
|
|
47
|
+
title: pageTitle || shop.title,
|
|
48
|
+
description: own?.description || shop.description,
|
|
49
|
+
image: own?.image || shop.image,
|
|
50
|
+
noindex: typeof pageNoindex === 'boolean' ? pageNoindex : shop.noindex,
|
|
51
|
+
source: {
|
|
52
|
+
title: pageTitle ? 'page' : shop.source.title,
|
|
53
|
+
description: own?.description ? 'page' : shop.source.description,
|
|
54
|
+
image: own?.image ? 'page' : shop.source.image,
|
|
55
|
+
noindex: typeof pageNoindex === 'boolean' ? 'page' : shop.source.noindex,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type StorefrontDesignSettings } from './storefrontDesignRegistry.ts';
|
|
1
|
+
import { type StorefrontDesignSettings, type StorefrontDesignSettingsLayer } from './storefrontDesignRegistry.ts';
|
|
2
2
|
type StorefrontThemeMode = 'light' | 'dark';
|
|
3
3
|
type StorefrontThemeSurfaceId = 'page' | 'header' | 'footer';
|
|
4
4
|
export interface StorefrontThemeSurface {
|
|
@@ -51,11 +51,27 @@ export interface StorefrontResolvedTheme {
|
|
|
51
51
|
}
|
|
52
52
|
export declare const storefrontContrastRatio: (foreground: string, background: string) => number;
|
|
53
53
|
/**
|
|
54
|
-
* The
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* overrides ONLY — no GLOBAL or WEB layer takes part — so a consumer uses this
|
|
58
|
-
* as shipped rather than merging layers of its own first.
|
|
54
|
+
* The GLOBAL design-settings layer of the platform globals row as `getPlatformGlobalsRow`
|
|
55
|
+
* returns it (`{ [key]: { value, ... } }`): each entry's `value`, kept only when it is a
|
|
56
|
+
* valid design setting, so a non-design global or a malformed value never reaches a theme.
|
|
59
57
|
*/
|
|
60
|
-
export declare const
|
|
58
|
+
export declare const storefrontGlobalSettingsLayer: (globalsRow?: Record<string, unknown>) => StorefrontDesignSettingsLayer;
|
|
59
|
+
/**
|
|
60
|
+
* The settings a storefront is served with: registry defaults, then the platform GLOBAL
|
|
61
|
+
* layer, then the design's own overrides. The one resolver behind the public envelope's
|
|
62
|
+
* `effectiveSettings`, the draft's `effectiveSettings` and the publish contrast report —
|
|
63
|
+
* a caller passes the globals row it read, never a layer stack of its own. The edge
|
|
64
|
+
* renderer's `theme-color` is design-only: its role reads no GLOBALS row.
|
|
65
|
+
*/
|
|
66
|
+
export declare const resolveStorefrontEffectiveSettings: (overrides?: Partial<StorefrontDesignSettings>, globalsRow?: Record<string, unknown>) => StorefrontDesignSettings;
|
|
67
|
+
/**
|
|
68
|
+
* The storefront theme for a design's settings overrides, resolved through
|
|
69
|
+
* `resolveStorefrontEffectiveSettings`: the GLOBAL layer of `globalsRow` sits under the
|
|
70
|
+
* design, exactly as in the public envelope's `effectiveSettings`. Omitting `globalsRow`
|
|
71
|
+
* resolves defaults plus the design only — correct solely while no GLOBAL design setting
|
|
72
|
+
* is set, so a caller serving or reporting on a storefront passes the row (the edge
|
|
73
|
+
* renderer's `theme-color` is the one exception, design-only by its read grant). Passing
|
|
74
|
+
* already-effective settings as `overrides` rebuilds the same theme.
|
|
75
|
+
*/
|
|
76
|
+
export declare const resolveStorefrontTheme: (overrides?: Partial<StorefrontDesignSettings>, globalsRow?: Record<string, unknown>) => StorefrontResolvedTheme;
|
|
61
77
|
export {};
|
package/dist/storefrontTheme.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolveStorefrontDesignSettings } from "./storefrontDesignRegistry.js";
|
|
1
|
+
import { resolveStorefrontDesignSettings, validateStorefrontDesignSetting, } from "./storefrontDesignRegistry.js";
|
|
2
2
|
const channels = (color) => [
|
|
3
3
|
Number.parseInt(color.slice(1, 3), 16),
|
|
4
4
|
Number.parseInt(color.slice(3, 5), 16),
|
|
@@ -62,14 +62,36 @@ const surfaceTokens = (background, settings, mode, surface, warnings) => {
|
|
|
62
62
|
};
|
|
63
63
|
};
|
|
64
64
|
/**
|
|
65
|
-
* The
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* overrides ONLY — no GLOBAL or WEB layer takes part — so a consumer uses this
|
|
69
|
-
* as shipped rather than merging layers of its own first.
|
|
65
|
+
* The GLOBAL design-settings layer of the platform globals row as `getPlatformGlobalsRow`
|
|
66
|
+
* returns it (`{ [key]: { value, ... } }`): each entry's `value`, kept only when it is a
|
|
67
|
+
* valid design setting, so a non-design global or a malformed value never reaches a theme.
|
|
70
68
|
*/
|
|
71
|
-
export const
|
|
72
|
-
|
|
69
|
+
export const storefrontGlobalSettingsLayer = (globalsRow) => ({
|
|
70
|
+
layer: 'GLOBAL',
|
|
71
|
+
values: Object.fromEntries(Object.entries(globalsRow ?? {}).flatMap(([key, entry]) => {
|
|
72
|
+
const value = entry !== null && typeof entry === 'object' ? entry.value : undefined;
|
|
73
|
+
return validateStorefrontDesignSetting(key, value) ? [[key, value]] : [];
|
|
74
|
+
})),
|
|
75
|
+
});
|
|
76
|
+
/**
|
|
77
|
+
* The settings a storefront is served with: registry defaults, then the platform GLOBAL
|
|
78
|
+
* layer, then the design's own overrides. The one resolver behind the public envelope's
|
|
79
|
+
* `effectiveSettings`, the draft's `effectiveSettings` and the publish contrast report —
|
|
80
|
+
* a caller passes the globals row it read, never a layer stack of its own. The edge
|
|
81
|
+
* renderer's `theme-color` is design-only: its role reads no GLOBALS row.
|
|
82
|
+
*/
|
|
83
|
+
export const resolveStorefrontEffectiveSettings = (overrides = {}, globalsRow) => resolveStorefrontDesignSettings(overrides, [storefrontGlobalSettingsLayer(globalsRow)]);
|
|
84
|
+
/**
|
|
85
|
+
* The storefront theme for a design's settings overrides, resolved through
|
|
86
|
+
* `resolveStorefrontEffectiveSettings`: the GLOBAL layer of `globalsRow` sits under the
|
|
87
|
+
* design, exactly as in the public envelope's `effectiveSettings`. Omitting `globalsRow`
|
|
88
|
+
* resolves defaults plus the design only — correct solely while no GLOBAL design setting
|
|
89
|
+
* is set, so a caller serving or reporting on a storefront passes the row (the edge
|
|
90
|
+
* renderer's `theme-color` is the one exception, design-only by its read grant). Passing
|
|
91
|
+
* already-effective settings as `overrides` rebuilds the same theme.
|
|
92
|
+
*/
|
|
93
|
+
export const resolveStorefrontTheme = (overrides = {}, globalsRow) => {
|
|
94
|
+
const settings = resolveStorefrontEffectiveSettings(overrides, globalsRow);
|
|
73
95
|
const warnings = [];
|
|
74
96
|
const makeMode = (mode) => {
|
|
75
97
|
const background = (requested) => mode === 'light' ? requested.toUpperCase() : mix(requested, '#000000', 0.9);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every storefront `WEB` literal key a shop may override, in code-unit order.
|
|
3
|
+
*
|
|
4
|
+
* This list is what the api's override validator accepts — one definition, so
|
|
5
|
+
* an editor offers exactly the keys a save will keep. A key outside it is
|
|
6
|
+
* refused as `UNKNOWN_KEY` on save and dropped on read.
|
|
7
|
+
*
|
|
8
|
+
* ⚠️ It is NOT every key the storefront renders. Withheld on purpose:
|
|
9
|
+
* - every key starting with `PRIVACY_` — privacy and terms are platform text,
|
|
10
|
+
* the same on every shop, and the storefront ignores a shop value for them;
|
|
11
|
+
* - the keys only the not-found and unavailable screens render, which read no
|
|
12
|
+
* shop layer;
|
|
13
|
+
* - keys whose storefront value is not a plain `{name}`-token sentence (it
|
|
14
|
+
* branches, computes, or is not a string), which a shop string cannot
|
|
15
|
+
* express.
|
|
16
|
+
* An editor that lists any of those offers an edit the server refuses.
|
|
17
|
+
*
|
|
18
|
+
* Interpolated values use `{name}` tokens named after the storefront's own
|
|
19
|
+
* parameters.
|
|
20
|
+
*/
|
|
21
|
+
export declare const STOREFRONT_WEB_LITERAL_KEYS: readonly string[];
|
|
22
|
+
/** Whether a shop may override `key` — membership in {@link STOREFRONT_WEB_LITERAL_KEYS}. */
|
|
23
|
+
export declare const isStorefrontLiteralKey: (key: string) => boolean;
|