@shoppexio/storefront 1.0.100 → 1.0.102

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/index.d.cts CHANGED
@@ -271,13 +271,7 @@ interface Product {
271
271
  price_display?: string;
272
272
  price_discount?: number;
273
273
  currency: string;
274
- /**
275
- * RAW local stock only. `-1` (or any negative value) means unlimited, `0` means
276
- * no local units. This is NEVER on its own a purchasable cap: a supplier-backed
277
- * product reports `stock: 0` by design and is still buyable. Gate buying on
278
- * {@link Product.orderable}, and use `resolveDisplayStock` / `isProductInStock`
279
- * rather than reading this field directly.
280
- */
274
+ /** Local stock; a negative value means unlimited. */
281
275
  stock?: number;
282
276
  /**
283
277
  * Per-product override for the shop's stock-counter setting; `null` inherits.
@@ -294,27 +288,8 @@ interface Product {
294
288
  */
295
289
  hideStockCounter?: boolean | null;
296
290
  hide_stock_counter?: boolean | null;
297
- /**
298
- * Authoritative buyability predicate, mirrored from the backend's order-time
299
- * gate: `local stock covers one unit OR an eligible supplier source can fulfil
300
- * the line`. This — not `stock` — is what a storefront must gate the buy button,
301
- * the quantity cap and the sold-out badge on.
302
- *
303
- * Absent on payloads that predate Dynamic Delivery. When absent, treat
304
- * availability exactly as `stock` alone dictates; a missing field must never
305
- * turn a genuinely sold-out product into a buyable one.
306
- */
291
+ /** Whether local stock and visibility allow this selection to be bought. */
307
292
  orderable?: boolean;
308
- /**
309
- * True when an enabled supplier source fulfils this product instead of local
310
- * stock. `orderable` remains the buy/sold-out gate; this field decides the
311
- * QUANTITY CAP: the supplier purchase — not the local counter — fulfils the line
312
- * and the completion excludes it from the local decrement, so residual local
313
- * units bound nothing and the cap is unlimited even at `stock: 1`. Absent on
314
- * payloads that predate Dynamic Delivery; when absent, the cap stays exactly
315
- * what `stock` alone dictates.
316
- */
317
- supplier_backed?: boolean;
318
293
  quantity_min?: number;
319
294
  quantity_max?: number;
320
295
  min_quantity?: number;
@@ -411,32 +386,10 @@ interface ProductVariant {
411
386
  price?: number;
412
387
  /** The merchant's SKU for this option; null when they set none. */
413
388
  sku?: string | null;
414
- /**
415
- * RAW local stock for this option only. `-1` (or any negative value) means
416
- * unlimited, `0` means no local units — which a supplier-backed option reports
417
- * by design. Never render this as a purchasable cap on its own; gate on
418
- * {@link ProductVariant.orderable}.
419
- */
389
+ /** Local stock; a negative value means unlimited. */
420
390
  stock?: number;
421
- /**
422
- * Authoritative buyability predicate for this option: `local stock covers one
423
- * unit OR an eligible supplier source can fulfil the line`. The backend resolves
424
- * a product-wide supplier mapping onto every variant's own flag, so this alone
425
- * is authoritative for a selected variant.
426
- *
427
- * Absent on payloads that predate Dynamic Delivery; when absent, availability
428
- * follows `stock` alone, exactly as before.
429
- */
391
+ /** Whether local stock and visibility allow this selection to be bought. */
430
392
  orderable?: boolean;
431
- /**
432
- * True when an enabled supplier source fulfils this option instead of local
433
- * stock. `orderable` remains the buy/sold-out gate; this field decides the
434
- * QUANTITY CAP — a supplier-backed row is unbounded even when it still holds a
435
- * few local units, because the supplier purchase fulfils the line and the
436
- * completion excludes it from the local decrement. Absent on payloads that
437
- * predate Dynamic Delivery.
438
- */
439
- supplier_backed?: boolean;
440
393
  quantity_min?: number;
441
394
  quantity_max?: number;
442
395
  quantityMin?: number;
@@ -479,32 +432,10 @@ interface PriceVariant {
479
432
  price: number;
480
433
  /** The merchant's SKU for this option; null when they set none. */
481
434
  sku?: string | null;
482
- /**
483
- * RAW local stock for this price variant only. `-1` (or any negative value)
484
- * means unlimited, `0` means no local units — which a supplier-backed variant
485
- * reports by design. Never render this as a purchasable cap on its own; gate on
486
- * {@link PriceVariant.orderable}.
487
- */
435
+ /** Local stock; a negative value means unlimited. */
488
436
  stock?: number;
489
- /**
490
- * Authoritative buyability predicate for this price variant: `local stock covers
491
- * one unit OR an eligible supplier source can fulfil the line`. The backend
492
- * resolves a product-wide supplier mapping onto every variant's own flag, so
493
- * this alone is authoritative for a selected variant.
494
- *
495
- * Absent on payloads that predate Dynamic Delivery; when absent, availability
496
- * follows `stock` alone, exactly as before.
497
- */
437
+ /** Whether local stock and visibility allow this selection to be bought. */
498
438
  orderable?: boolean;
499
- /**
500
- * True when an enabled supplier source fulfils this price variant instead of
501
- * local stock. `orderable` remains the buy/sold-out gate; this field decides the
502
- * QUANTITY CAP — a supplier-backed row is unbounded even when it still holds a
503
- * few local units, because the supplier purchase fulfils the line and the
504
- * completion excludes it from the local decrement. Absent on payloads that
505
- * predate Dynamic Delivery.
506
- */
507
- supplier_backed?: boolean;
508
439
  quantity_min?: number;
509
440
  quantity_max?: number;
510
441
  quantityMin?: number;
@@ -1698,8 +1629,8 @@ declare function isStorefrontCheckboxCustomFieldValueChecked(value: string | und
1698
1629
  declare function validateStorefrontCustomFieldValue(field: StorefrontCustomField, value: string): string | null;
1699
1630
  declare function buildStorefrontCustomFieldPayload(fields: StorefrontCustomField[], values: Record<string, string>): Record<string, string>;
1700
1631
 
1701
- type VariantLike = Pick<ProductVariant, 'stock' | 'orderable' | 'supplier_backed'> | Pick<PriceVariant, 'stock' | 'orderable' | 'supplier_backed'>;
1702
- type ProductLike = Pick<Product, 'type' | 'stock' | 'orderable' | 'supplier_backed' | 'on_hold' | 'price_variants' | 'variants'> & {
1632
+ type VariantLike = Pick<ProductVariant, 'stock' | 'orderable'> | Pick<PriceVariant, 'stock' | 'orderable'>;
1633
+ type ProductLike = Pick<Product, 'type' | 'stock' | 'orderable' | 'on_hold' | 'price_variants' | 'variants'> & {
1703
1634
  onHold?: boolean | number | string | null;
1704
1635
  is_on_hold?: boolean | number | string | null;
1705
1636
  isOnHold?: boolean | number | string | null;
package/dist/index.d.ts CHANGED
@@ -271,13 +271,7 @@ interface Product {
271
271
  price_display?: string;
272
272
  price_discount?: number;
273
273
  currency: string;
274
- /**
275
- * RAW local stock only. `-1` (or any negative value) means unlimited, `0` means
276
- * no local units. This is NEVER on its own a purchasable cap: a supplier-backed
277
- * product reports `stock: 0` by design and is still buyable. Gate buying on
278
- * {@link Product.orderable}, and use `resolveDisplayStock` / `isProductInStock`
279
- * rather than reading this field directly.
280
- */
274
+ /** Local stock; a negative value means unlimited. */
281
275
  stock?: number;
282
276
  /**
283
277
  * Per-product override for the shop's stock-counter setting; `null` inherits.
@@ -294,27 +288,8 @@ interface Product {
294
288
  */
295
289
  hideStockCounter?: boolean | null;
296
290
  hide_stock_counter?: boolean | null;
297
- /**
298
- * Authoritative buyability predicate, mirrored from the backend's order-time
299
- * gate: `local stock covers one unit OR an eligible supplier source can fulfil
300
- * the line`. This — not `stock` — is what a storefront must gate the buy button,
301
- * the quantity cap and the sold-out badge on.
302
- *
303
- * Absent on payloads that predate Dynamic Delivery. When absent, treat
304
- * availability exactly as `stock` alone dictates; a missing field must never
305
- * turn a genuinely sold-out product into a buyable one.
306
- */
291
+ /** Whether local stock and visibility allow this selection to be bought. */
307
292
  orderable?: boolean;
308
- /**
309
- * True when an enabled supplier source fulfils this product instead of local
310
- * stock. `orderable` remains the buy/sold-out gate; this field decides the
311
- * QUANTITY CAP: the supplier purchase — not the local counter — fulfils the line
312
- * and the completion excludes it from the local decrement, so residual local
313
- * units bound nothing and the cap is unlimited even at `stock: 1`. Absent on
314
- * payloads that predate Dynamic Delivery; when absent, the cap stays exactly
315
- * what `stock` alone dictates.
316
- */
317
- supplier_backed?: boolean;
318
293
  quantity_min?: number;
319
294
  quantity_max?: number;
320
295
  min_quantity?: number;
@@ -411,32 +386,10 @@ interface ProductVariant {
411
386
  price?: number;
412
387
  /** The merchant's SKU for this option; null when they set none. */
413
388
  sku?: string | null;
414
- /**
415
- * RAW local stock for this option only. `-1` (or any negative value) means
416
- * unlimited, `0` means no local units — which a supplier-backed option reports
417
- * by design. Never render this as a purchasable cap on its own; gate on
418
- * {@link ProductVariant.orderable}.
419
- */
389
+ /** Local stock; a negative value means unlimited. */
420
390
  stock?: number;
421
- /**
422
- * Authoritative buyability predicate for this option: `local stock covers one
423
- * unit OR an eligible supplier source can fulfil the line`. The backend resolves
424
- * a product-wide supplier mapping onto every variant's own flag, so this alone
425
- * is authoritative for a selected variant.
426
- *
427
- * Absent on payloads that predate Dynamic Delivery; when absent, availability
428
- * follows `stock` alone, exactly as before.
429
- */
391
+ /** Whether local stock and visibility allow this selection to be bought. */
430
392
  orderable?: boolean;
431
- /**
432
- * True when an enabled supplier source fulfils this option instead of local
433
- * stock. `orderable` remains the buy/sold-out gate; this field decides the
434
- * QUANTITY CAP — a supplier-backed row is unbounded even when it still holds a
435
- * few local units, because the supplier purchase fulfils the line and the
436
- * completion excludes it from the local decrement. Absent on payloads that
437
- * predate Dynamic Delivery.
438
- */
439
- supplier_backed?: boolean;
440
393
  quantity_min?: number;
441
394
  quantity_max?: number;
442
395
  quantityMin?: number;
@@ -479,32 +432,10 @@ interface PriceVariant {
479
432
  price: number;
480
433
  /** The merchant's SKU for this option; null when they set none. */
481
434
  sku?: string | null;
482
- /**
483
- * RAW local stock for this price variant only. `-1` (or any negative value)
484
- * means unlimited, `0` means no local units — which a supplier-backed variant
485
- * reports by design. Never render this as a purchasable cap on its own; gate on
486
- * {@link PriceVariant.orderable}.
487
- */
435
+ /** Local stock; a negative value means unlimited. */
488
436
  stock?: number;
489
- /**
490
- * Authoritative buyability predicate for this price variant: `local stock covers
491
- * one unit OR an eligible supplier source can fulfil the line`. The backend
492
- * resolves a product-wide supplier mapping onto every variant's own flag, so
493
- * this alone is authoritative for a selected variant.
494
- *
495
- * Absent on payloads that predate Dynamic Delivery; when absent, availability
496
- * follows `stock` alone, exactly as before.
497
- */
437
+ /** Whether local stock and visibility allow this selection to be bought. */
498
438
  orderable?: boolean;
499
- /**
500
- * True when an enabled supplier source fulfils this price variant instead of
501
- * local stock. `orderable` remains the buy/sold-out gate; this field decides the
502
- * QUANTITY CAP — a supplier-backed row is unbounded even when it still holds a
503
- * few local units, because the supplier purchase fulfils the line and the
504
- * completion excludes it from the local decrement. Absent on payloads that
505
- * predate Dynamic Delivery.
506
- */
507
- supplier_backed?: boolean;
508
439
  quantity_min?: number;
509
440
  quantity_max?: number;
510
441
  quantityMin?: number;
@@ -1698,8 +1629,8 @@ declare function isStorefrontCheckboxCustomFieldValueChecked(value: string | und
1698
1629
  declare function validateStorefrontCustomFieldValue(field: StorefrontCustomField, value: string): string | null;
1699
1630
  declare function buildStorefrontCustomFieldPayload(fields: StorefrontCustomField[], values: Record<string, string>): Record<string, string>;
1700
1631
 
1701
- type VariantLike = Pick<ProductVariant, 'stock' | 'orderable' | 'supplier_backed'> | Pick<PriceVariant, 'stock' | 'orderable' | 'supplier_backed'>;
1702
- type ProductLike = Pick<Product, 'type' | 'stock' | 'orderable' | 'supplier_backed' | 'on_hold' | 'price_variants' | 'variants'> & {
1632
+ type VariantLike = Pick<ProductVariant, 'stock' | 'orderable'> | Pick<PriceVariant, 'stock' | 'orderable'>;
1633
+ type ProductLike = Pick<Product, 'type' | 'stock' | 'orderable' | 'on_hold' | 'price_variants' | 'variants'> & {
1703
1634
  onHold?: boolean | number | string | null;
1704
1635
  is_on_hold?: boolean | number | string | null;
1705
1636
  isOnHold?: boolean | number | string | null;
package/dist/index.js CHANGED
@@ -2472,12 +2472,7 @@ function priceVariantToProductVariant(variant) {
2472
2472
  price: typeof variant.price === "number" ? variant.price : Number(variant.price) || 0,
2473
2473
  sku: variant.sku,
2474
2474
  stock: typeof variant.stock === "number" ? variant.stock : void 0,
2475
- // Dynamic Delivery (S8): carry the availability pair through. A supplier-backed
2476
- // variant reports `stock: 0`, so dropping `orderable` here would make the mapped
2477
- // variant look sold out. Left `undefined` when the source omits it, which keeps
2478
- // the historical stock-only behaviour for payloads that predate the field.
2479
2475
  orderable: typeof variant.orderable === "boolean" ? variant.orderable : void 0,
2480
- supplier_backed: typeof variant.supplier_backed === "boolean" ? variant.supplier_backed : void 0,
2481
2476
  quantity_min: variant.quantity_min,
2482
2477
  quantity_max: variant.quantity_max,
2483
2478
  quantityMin: variant.quantityMin,
@@ -2668,6 +2663,16 @@ function isSafeHttpsRedirectTemplateUrl(url) {
2668
2663
  }
2669
2664
  }
2670
2665
 
2666
+ // ../contracts/src/storefront-consent-choice.ts
2667
+ var COOKIE_CONSENT_VERSION = 1;
2668
+ var COOKIE_CONSENT_COOKIE = "shoppex_consent";
2669
+ var COOKIE_CONSENT_CHECKOUT_HASH_KEY = "shoppex_consent";
2670
+ var COOKIE_CONSENT_VALUE = new RegExp(`^v${COOKIE_CONSENT_VERSION}\\.f([01])\\.a([01])\\.m([01])$`);
2671
+ function parseCookieConsentValue(value) {
2672
+ const match = value ? COOKIE_CONSENT_VALUE.exec(value) : null;
2673
+ return match ? { functional: match[1] === "1", analytics: match[2] === "1", marketing: match[3] === "1" } : null;
2674
+ }
2675
+
2671
2676
  // ../sdk/src/modules/checkout.ts
2672
2677
  var CheckoutCreateError = class _CheckoutCreateError extends Error {
2673
2678
  constructor(message, options = {}) {
@@ -2832,10 +2837,16 @@ function buildCheckoutUrlFromInvoiceId(checkoutBaseUrl, invoiceId) {
2832
2837
  return null;
2833
2838
  }
2834
2839
  }
2840
+ function readStorefrontConsentValue() {
2841
+ if (typeof document === "undefined" || typeof document.cookie !== "string") return null;
2842
+ const value = document.cookie.split(";").map((part) => part.trim()).find((part) => part.startsWith(`${COOKIE_CONSENT_COOKIE}=`))?.slice(COOKIE_CONSENT_COOKIE.length + 1);
2843
+ return parseCookieConsentValue(value) ? value : null;
2844
+ }
2835
2845
  function appendCheckoutUrlOptions(checkoutUrl, options) {
2836
2846
  const normalizedEmail = normalizeEmail(options.email);
2837
2847
  const normalizedLocale = typeof options.locale === "string" ? options.locale.trim() : "";
2838
- if (!normalizedEmail && !normalizedLocale) {
2848
+ const consent = readStorefrontConsentValue();
2849
+ if (!normalizedEmail && !normalizedLocale && !consent) {
2839
2850
  return checkoutUrl;
2840
2851
  }
2841
2852
  try {
@@ -2843,9 +2854,10 @@ function appendCheckoutUrlOptions(checkoutUrl, options) {
2843
2854
  if (normalizedLocale) {
2844
2855
  parsedCheckoutUrl.searchParams.set("locale", normalizedLocale);
2845
2856
  }
2846
- if (normalizedEmail) {
2857
+ if (normalizedEmail || consent) {
2847
2858
  const hashParams = new URLSearchParams(parsedCheckoutUrl.hash.startsWith("#") ? parsedCheckoutUrl.hash.slice(1) : parsedCheckoutUrl.hash);
2848
- hashParams.set(CHECKOUT_PREFILL_EMAIL_HASH_KEY, normalizedEmail);
2859
+ if (normalizedEmail) hashParams.set(CHECKOUT_PREFILL_EMAIL_HASH_KEY, normalizedEmail);
2860
+ if (consent) hashParams.set(COOKIE_CONSENT_CHECKOUT_HASH_KEY, consent);
2849
2861
  parsedCheckoutUrl.hash = hashParams.toString();
2850
2862
  }
2851
2863
  return parsedCheckoutUrl.toString();
@@ -3303,18 +3315,6 @@ async function getShopReviews() {
3303
3315
 
3304
3316
  // ../sdk/src/utils/storefront-stock.ts
3305
3317
  var UNLIMITED_STOCK = -1;
3306
- function applyOrderable(stock, orderable, supplierBacked) {
3307
- if (orderable !== true) {
3308
- return stock;
3309
- }
3310
- if (supplierBacked === true) {
3311
- return UNLIMITED_STOCK;
3312
- }
3313
- if (stock !== 0) {
3314
- return stock;
3315
- }
3316
- return UNLIMITED_STOCK;
3317
- }
3318
3318
  function normalizeStockValue(value) {
3319
3319
  if (typeof value !== "number" || !Number.isFinite(value)) {
3320
3320
  return null;
@@ -3344,18 +3344,14 @@ function collectVariantStocks(product) {
3344
3344
  }
3345
3345
  function resolveVariantStockValue(variant) {
3346
3346
  const normalized = normalizeStockValue(variant?.stock);
3347
- return applyOrderable(normalized ?? UNLIMITED_STOCK, variant?.orderable, variant?.supplier_backed);
3347
+ return normalized ?? UNLIMITED_STOCK;
3348
3348
  }
3349
3349
  function resolveDisplayStock(product) {
3350
3350
  if (!product) {
3351
3351
  return UNLIMITED_STOCK;
3352
3352
  }
3353
3353
  if (typeof product.type === "string" && product.type.toUpperCase() === "SERIALS") {
3354
- return applyOrderable(
3355
- normalizeStockValue(product.stock) ?? UNLIMITED_STOCK,
3356
- product.orderable,
3357
- product.supplier_backed
3358
- );
3354
+ return normalizeStockValue(product.stock) ?? UNLIMITED_STOCK;
3359
3355
  }
3360
3356
  const variantStocks = collectVariantStocks(product);
3361
3357
  if (variantStocks.length > 0) {
@@ -3363,13 +3359,9 @@ function resolveDisplayStock(product) {
3363
3359
  return UNLIMITED_STOCK;
3364
3360
  }
3365
3361
  const total = variantStocks.reduce((sum, stock) => sum + Math.max(stock, 0), 0);
3366
- return applyOrderable(total, product.orderable, product.supplier_backed);
3362
+ return total;
3367
3363
  }
3368
- return applyOrderable(
3369
- normalizeStockValue(product.stock) ?? UNLIMITED_STOCK,
3370
- product.orderable,
3371
- product.supplier_backed
3372
- );
3364
+ return normalizeStockValue(product.stock) ?? UNLIMITED_STOCK;
3373
3365
  }
3374
3366
  function isProductOutOfStock(product) {
3375
3367
  if (isProductOnHold(product)) return true;