@moonbase.sh/storefront-api 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -71,6 +71,7 @@ __export(schemas_exports2, {
71
71
  offerConditionSchema: () => offerConditionSchema,
72
72
  storefrontBundleSchema: () => storefrontBundleSchema,
73
73
  storefrontOfferSchema: () => storefrontOfferSchema,
74
+ storefrontOfferTargetSchema: () => storefrontOfferTargetSchema,
74
75
  storefrontProductSchema: () => storefrontProductSchema,
75
76
  storefrontSchema: () => storefrontSchema,
76
77
  taxEstimateSchema: () => taxEstimateSchema
@@ -287,13 +288,36 @@ var cartContainsItemsConditionSchema = import_zod3.z.object({
287
288
  relevantItemVariations: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.string().array())
288
289
  });
289
290
  var offerConditionSchema = import_zod3.z.discriminatedUnion("type", [cartContainsItemsConditionSchema]);
291
+ var offerTargetItemSchema = import_zod3.z.union([storefrontProductSchema, storefrontBundleSchema]);
292
+ var storefrontOfferTargetSchema = import_zod3.z.object({
293
+ // The product or bundle the offer applies to.
294
+ item: offerTargetItemSchema,
295
+ // The pricing variation IDs the offer is restricted to; an empty list means all variations.
296
+ variations: import_zod3.z.string().array()
297
+ });
298
+ function legacyOfferTargets(target, targetVariations) {
299
+ if (!target)
300
+ return [];
301
+ const items = Array.isArray(target) ? target : [target];
302
+ return items.map((item) => ({ item, variations: items.length === 1 ? targetVariations != null ? targetVariations : [] : [] }));
303
+ }
290
304
  var storefrontOfferSchema = import_zod3.z.object({
291
305
  id: import_zod3.z.string(),
292
- target: singleOrMultiple(import_zod3.z.union([storefrontProductSchema, storefrontBundleSchema])),
293
- targetVariations: import_zod3.z.string().array(),
306
+ // Each target pairs a product/bundle with the pricing variations the offer applies to (an empty
307
+ // list means all variations). This is the model to consume.
308
+ targets: import_zod3.z.array(storefrontOfferTargetSchema).optional(),
309
+ // Legacy fields, kept optional only so old cached storefront responses still parse. The API now
310
+ // exposes the unified `targets` model; we derive `targets` from these when a response predates it.
311
+ // `.catch` guards against the deprecated shape drifting: a malformed legacy field is ignored
312
+ // rather than failing the whole response (newer responses carry `targets` anyway).
313
+ target: singleOrMultiple(offerTargetItemSchema).optional().catch(void 0),
314
+ targetVariations: import_zod3.z.string().array().optional().catch(void 0),
294
315
  condition: offerConditionSchema,
295
316
  discount: discountSchema
296
- });
317
+ }).transform(({ target, targetVariations, targets, ...rest }) => ({
318
+ ...rest,
319
+ targets: targets != null ? targets : legacyOfferTargets(target, targetVariations)
320
+ }));
297
321
  var taxEstimateSchema = import_zod3.z.object({
298
322
  rate: import_zod3.z.number(),
299
323
  mode: import_zod3.z.enum(["Exclusive", "Inclusive"]),
@@ -515,11 +539,11 @@ async function handleResponseProblem(response, logger) {
515
539
  throw new NotAuthorizedError();
516
540
  }
517
541
  let problemDetails;
542
+ const body = await response.text();
518
543
  try {
519
- const json = await response.json();
520
- problemDetails = problemDetailsSchema.parse(json);
544
+ problemDetails = problemDetailsSchema.parse(JSON.parse(body));
521
545
  } catch (err) {
522
- logger.warn("Could not handle response", { response, err, content: await response.text() });
546
+ logger.warn("Could not handle response", { response, err, content: body });
523
547
  throw new Error("An unknown problem occurred");
524
548
  }
525
549
  logger.debug("The response indicates a problem", problemDetails);
@@ -583,7 +607,8 @@ var connectionUrlSchema = import_zod8.z.object({
583
607
  var userSchema = import_zod8.z.object({
584
608
  id: import_zod8.z.string(),
585
609
  email: import_zod8.z.string(),
586
- name: import_zod8.z.string(),
610
+ // Nullable: customers created via import may have no name.
611
+ name: import_zod8.z.string().nullable(),
587
612
  tenantId: import_zod8.z.string(),
588
613
  address: addressSchema.optional(),
589
614
  phone: import_zod8.z.string().optional(),
@@ -912,6 +937,9 @@ var ProductEndpoints = class {
912
937
  }
913
938
  };
914
939
 
940
+ // src/inventory/subscriptions/endpoints.ts
941
+ var import_zod14 = require("zod");
942
+
915
943
  // src/utils/api.ts
916
944
  function objectToQuery(obj) {
917
945
  return Object.entries(obj != null ? obj : {}).filter(([_, value]) => value !== void 0).map(([key, value]) => `${key}=${encodeURIComponent(value instanceof Date ? value.toISOString() : value)}`).join("&");
@@ -1037,9 +1065,6 @@ var MoonbaseApi = class {
1037
1065
  }
1038
1066
  };
1039
1067
 
1040
- // src/inventory/subscriptions/endpoints.ts
1041
- var import_zod14 = require("zod");
1042
-
1043
1068
  // src/inventory/subscriptions/schemas.ts
1044
1069
  var schemas_exports8 = {};
1045
1070
  __export(schemas_exports8, {
@@ -1048,15 +1073,6 @@ __export(schemas_exports8, {
1048
1073
  });
1049
1074
  var import_zod13 = require("zod");
1050
1075
 
1051
- // src/inventory/subscriptions/models.ts
1052
- var SubscriptionStatus = /* @__PURE__ */ ((SubscriptionStatus2) => {
1053
- SubscriptionStatus2["Active"] = "Active";
1054
- SubscriptionStatus2["Expired"] = "Expired";
1055
- SubscriptionStatus2["Cancelled"] = "Cancelled";
1056
- SubscriptionStatus2["Completed"] = "Completed";
1057
- return SubscriptionStatus2;
1058
- })(SubscriptionStatus || {});
1059
-
1060
1076
  // src/orders/schemas.ts
1061
1077
  var schemas_exports7 = {};
1062
1078
  __export(schemas_exports7, {
@@ -1193,6 +1209,15 @@ var orderSchema = import_zod12.z.discriminatedUnion("status", [
1193
1209
  completedOrderSchema
1194
1210
  ]);
1195
1211
 
1212
+ // src/inventory/subscriptions/models.ts
1213
+ var SubscriptionStatus = /* @__PURE__ */ ((SubscriptionStatus2) => {
1214
+ SubscriptionStatus2["Active"] = "Active";
1215
+ SubscriptionStatus2["Expired"] = "Expired";
1216
+ SubscriptionStatus2["Cancelled"] = "Cancelled";
1217
+ SubscriptionStatus2["Completed"] = "Completed";
1218
+ return SubscriptionStatus2;
1219
+ })(SubscriptionStatus || {});
1220
+
1196
1221
  // src/inventory/subscriptions/schemas.ts
1197
1222
  var baseMilestoneProgressEventSchema = import_zod13.z.object({
1198
1223
  milestoneId: import_zod13.z.string(),
@@ -1368,6 +1393,36 @@ var StorefrontEndpoints = class {
1368
1393
  }
1369
1394
  };
1370
1395
 
1396
+ // src/utils/logger.ts
1397
+ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
1398
+ LogLevel2[LogLevel2["Debug"] = 0] = "Debug";
1399
+ LogLevel2[LogLevel2["Information"] = 1] = "Information";
1400
+ LogLevel2[LogLevel2["Warn"] = 2] = "Warn";
1401
+ LogLevel2[LogLevel2["Error"] = 3] = "Error";
1402
+ return LogLevel2;
1403
+ })(LogLevel || {});
1404
+ var ConsoleLogger = class {
1405
+ constructor(level = 2 /* Warn */) {
1406
+ this.level = level;
1407
+ }
1408
+ debug(message, ...optionalParams) {
1409
+ if (this.level <= 0 /* Debug */)
1410
+ console.debug(message, ...optionalParams);
1411
+ }
1412
+ log(message, ...optionalParams) {
1413
+ if (this.level <= 1 /* Information */)
1414
+ console.log(message, ...optionalParams);
1415
+ }
1416
+ warn(message, ...optionalParams) {
1417
+ if (this.level <= 2 /* Warn */)
1418
+ console.warn(message, ...optionalParams);
1419
+ }
1420
+ error(message, ...optionalParams) {
1421
+ if (this.level <= 3 /* Error */)
1422
+ console.error(message, ...optionalParams);
1423
+ }
1424
+ };
1425
+
1371
1426
  // src/utils/store.ts
1372
1427
  var LocalStorageStore = class {
1373
1428
  get(key) {
@@ -1415,7 +1470,8 @@ var InMemoryStore = class {
1415
1470
  }
1416
1471
  }
1417
1472
  listen(key, callback) {
1418
- if (!this.listeners[key]) this.listeners[key] = [];
1473
+ if (!this.listeners[key])
1474
+ this.listeners[key] = [];
1419
1475
  this.listeners[key].push(callback);
1420
1476
  }
1421
1477
  };
@@ -1459,7 +1515,8 @@ var _TokenStore = class _TokenStore {
1459
1515
  setUser(user) {
1460
1516
  const identity = user;
1461
1517
  if (!identity.accessToken || !identity.refreshToken) {
1462
- if (!this.tokens) return null;
1518
+ if (!this.tokens)
1519
+ return null;
1463
1520
  this.tokens = {
1464
1521
  ...user,
1465
1522
  accessToken: this.tokens.accessToken,
@@ -1589,32 +1646,6 @@ var VoucherEndpoints = class {
1589
1646
  }
1590
1647
  };
1591
1648
 
1592
- // src/utils/logger.ts
1593
- var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
1594
- LogLevel2[LogLevel2["Debug"] = 0] = "Debug";
1595
- LogLevel2[LogLevel2["Information"] = 1] = "Information";
1596
- LogLevel2[LogLevel2["Warn"] = 2] = "Warn";
1597
- LogLevel2[LogLevel2["Error"] = 3] = "Error";
1598
- return LogLevel2;
1599
- })(LogLevel || {});
1600
- var ConsoleLogger = class {
1601
- constructor(level = 2 /* Warn */) {
1602
- this.level = level;
1603
- }
1604
- debug(message, ...optionalParams) {
1605
- if (this.level <= 0 /* Debug */) console.debug(message, ...optionalParams);
1606
- }
1607
- log(message, ...optionalParams) {
1608
- if (this.level <= 1 /* Information */) console.log(message, ...optionalParams);
1609
- }
1610
- warn(message, ...optionalParams) {
1611
- if (this.level <= 2 /* Warn */) console.warn(message, ...optionalParams);
1612
- }
1613
- error(message, ...optionalParams) {
1614
- if (this.level <= 3 /* Error */) console.error(message, ...optionalParams);
1615
- }
1616
- };
1617
-
1618
1649
  // src/schemas.ts
1619
1650
  var schemas_exports12 = {};
1620
1651
  __export(schemas_exports12, {
@@ -1665,7 +1696,7 @@ var MoneyCollectionUtils = class {
1665
1696
  var OfferUtils = class _OfferUtils {
1666
1697
  static eligible(offer, order) {
1667
1698
  switch (offer.condition.type) {
1668
- case "CartContainsItems":
1699
+ case "CartContainsItems": {
1669
1700
  const relevantItems = order.items.filter(
1670
1701
  (i) => i.type === "Product" && offer.condition.relevantItemVariations[`Product/${i.productId}`] && offer.condition.relevantItemVariations[`Product/${i.productId}`].includes(i.variationId) || i.type === "Bundle" && offer.condition.relevantItemVariations[`Bundle/${i.bundleId}`] && offer.condition.relevantItemVariations[`Bundle/${i.bundleId}`].includes(i.variationId)
1671
1702
  );
@@ -1677,6 +1708,7 @@ var OfferUtils = class _OfferUtils {
1677
1708
  return offer.condition.relevantItemVariations[`Product/${productId}`] && offer.condition.relevantItemVariations[`Product/${productId}`].includes(variationId);
1678
1709
  });
1679
1710
  return relevantItems.length + relevantReplacedItems.length >= offer.condition.minimumItems;
1711
+ }
1680
1712
  }
1681
1713
  console.warn("Unsupported offer condition found:", offer.condition);
1682
1714
  return false;
@@ -1685,11 +1717,27 @@ var OfferUtils = class _OfferUtils {
1685
1717
  // a. Not be owned, or all targets need to be owned
1686
1718
  // b. Not already in the cart
1687
1719
  static relevantTargets(offer, cartItems) {
1688
- if (Array.isArray(offer.target)) {
1689
- const allOwned = offer.target.every((i) => i.owned);
1690
- return offer.target.filter((i) => (allOwned || !i.owned) && !cartItems.some((l) => l.type === i.type && i.id === (l.type === "Product" ? l.productId : l.bundleId)));
1720
+ if (offer.targets.length > 1) {
1721
+ const allOwned = offer.targets.every((t) => t.item.owned);
1722
+ return offer.targets.filter((t) => (allOwned || !t.item.owned) && !cartItems.some((l) => l.type === t.item.type && t.item.id === (l.type === "Product" ? l.productId : l.bundleId)));
1691
1723
  }
1692
- return [offer.target];
1724
+ return offer.targets;
1725
+ }
1726
+ // The pricing variations a target restricts the offer to. An empty (or missing) variation list
1727
+ // means the offer is not narrowed to specific variations, in which case we keep the established
1728
+ // single default-variation upsell.
1729
+ static targetedVariations(target) {
1730
+ var _a;
1731
+ const { item, variations } = target;
1732
+ if (variations.length === 0)
1733
+ return item.defaultVariation ? [item.defaultVariation] : [];
1734
+ const itemVariations = (_a = item.variations) != null ? _a : item.defaultVariation ? [item.defaultVariation] : [];
1735
+ return itemVariations.filter((v) => variations.includes(v.id));
1736
+ }
1737
+ // Expands the relevant targets into one `{ target, variation }` entry per targeted variation, so
1738
+ // an offer targeting several variations (or several products) surfaces each as its own upsell row.
1739
+ static relevantTargetVariations(offer, cartItems) {
1740
+ return _OfferUtils.relevantTargets(offer, cartItems).flatMap((target) => _OfferUtils.targetedVariations(target).map((variation) => ({ target: target.item, variation })));
1693
1741
  }
1694
1742
  static applyToVariation(offer, variation) {
1695
1743
  const discount = DiscountUtils.apply(offer.discount, variation.price);
@@ -1700,7 +1748,7 @@ var OfferUtils = class _OfferUtils {
1700
1748
  };
1701
1749
  }
1702
1750
  static targetContainsBundle(offer, bundleId) {
1703
- if (Array.isArray(offer.target)) return offer.target.some((i) => i.type === "Bundle" && i.id === bundleId);
1751
+ return offer.targets.some((t) => t.item.type === "Bundle" && t.item.id === bundleId);
1704
1752
  }
1705
1753
  };
1706
1754