@moonbase.sh/storefront-api 3.10.0 → 3.12.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/README.md CHANGED
@@ -24,7 +24,8 @@ Configuration notes:
24
24
 
25
25
  - `endpoint`: your Moonbase storefront URL.
26
26
  - `includeManifests`: include downloadable file manifests when available.
27
- - `persistUtm`: store detected UTM values and ad click IDs in localStorage instead of sessionStorage.
27
+ - `persistUtm`: in `@moonbase.sh/vue`, keep the attribution a visitor arrived with in localStorage, across visits, instead of sessionStorage for the tab. Only with the visitor's consent (see `attributionConsent`); a refusal removes it.
28
+ - `attributionConsent`: in `@moonbase.sh/vue`, whether the visitor has agreed to marketing cookies. `false` keeps the UTM tags, referrer and the ad platforms a click came from (`adClicks`) but not the ad click IDs themselves, and records a tagged arrival on the order only with the first thing put in the cart; `true` keeps the click IDs too. Left out, it follows the store's own setting in Moonbase, which the catalog reports for this visitor as `cookieConsentRequired`. Change it later with `setAttributionConsent()`.
28
29
 
29
30
  ## Common usage
30
31
 
@@ -211,6 +212,11 @@ from TikTok) go to the API under those names, and the rest as `utm_*`.
211
212
  in from the tags and click IDs it has already picked up, unless you pass your own
212
213
  `utm`.
213
214
 
215
+ A click ID identifies the visitor's click, so only send one once the visitor has
216
+ agreed to marketing cookies, where the law asks for that. `withoutClickIds(utm)`
217
+ drops their values and keeps the platforms they came from in `adClicks` (sent as
218
+ `utm_ad_click`), which still counts the visit as an ad click.
219
+
214
220
  ## Inventory flow
215
221
 
216
222
  Most inventory endpoints require an authenticated user:
package/dist/index.cjs CHANGED
@@ -54,6 +54,7 @@ __export(index_exports, {
54
54
  SubscriptionStatus: () => SubscriptionStatus,
55
55
  TokenStore: () => TokenStore,
56
56
  accessTokenLifetime: () => accessTokenLifetime,
57
+ adClicksOf: () => adClicksOf,
57
58
  imageWidths: () => imageWidths,
58
59
  isLocalStorageAvailable: () => isLocalStorageAvailable,
59
60
  isPromotionDisplay: () => isPromotionDisplay,
@@ -66,7 +67,8 @@ __export(index_exports, {
66
67
  promotionDisplays: () => promotionDisplays,
67
68
  resolveUtm: () => resolveUtm,
68
69
  schemas: () => schemas_exports12,
69
- utmToObject: () => utmToObject
70
+ utmToObject: () => utmToObject,
71
+ withoutClickIds: () => withoutClickIds
70
72
  });
71
73
  module.exports = __toCommonJS(index_exports);
72
74
 
@@ -117,6 +119,7 @@ var MarketingConsentType = /* @__PURE__ */ ((MarketingConsentType2) => {
117
119
  return MarketingConsentType2;
118
120
  })(MarketingConsentType || {});
119
121
  function utmToObject(utm) {
122
+ var _a;
120
123
  return Object.entries({
121
124
  utm_source: utm == null ? void 0 : utm.source,
122
125
  utm_medium: utm == null ? void 0 : utm.medium,
@@ -129,7 +132,8 @@ function utmToObject(utm) {
129
132
  wbraid: utm == null ? void 0 : utm.wbraid,
130
133
  fbclid: utm == null ? void 0 : utm.fbclid,
131
134
  msclkid: utm == null ? void 0 : utm.msclkid,
132
- ttclid: utm == null ? void 0 : utm.ttclid
135
+ ttclid: utm == null ? void 0 : utm.ttclid,
136
+ utm_ad_click: ((_a = utm == null ? void 0 : utm.adClicks) == null ? void 0 : _a.length) ? utm.adClicks.join(",") : void 0
133
137
  }).filter(([_, value]) => value !== void 0).reduce((obj, [key, value]) => ({
134
138
  ...obj,
135
139
  [key]: value
@@ -500,7 +504,11 @@ var storefrontSchema = import_zod3.z.object({
500
504
  // Promotions need to be optional since we may still have old, cached representations in browsers
501
505
  promotions: storefrontPromotionsSchema.optional(),
502
506
  // Depending on circumstances, we may have a tax estimate available
503
- estimatedTax: taxEstimateSchema.optional()
507
+ estimatedTax: taxEstimateSchema.optional(),
508
+ // Whether the storefront has to wait for this visitor's cookie consent before it keeps ad click
509
+ // IDs or remembers their visit: the store's setting, for the country the visit comes from.
510
+ // Optional for older backends and cached catalogs, which count as asking.
511
+ cookieConsentRequired: import_zod3.z.boolean().optional()
504
512
  });
505
513
 
506
514
  // src/activationRequests/models.ts
@@ -1295,7 +1303,7 @@ var ProductEndpoints = class {
1295
1303
  var import_zod15 = require("zod");
1296
1304
 
1297
1305
  // package.json
1298
- var version = "3.10.0";
1306
+ var version = "3.12.0";
1299
1307
 
1300
1308
  // src/utils/client.ts
1301
1309
  function buildClientHeader(sdk) {
@@ -1451,6 +1459,10 @@ var MoonbaseApi = class {
1451
1459
  var schemas_exports8 = {};
1452
1460
  __export(schemas_exports8, {
1453
1461
  milestoneProgressSchema: () => milestoneProgressSchema,
1462
+ pendingPlanChangeSchema: () => pendingPlanChangeSchema,
1463
+ pricingOptionSchema: () => pricingOptionSchema,
1464
+ subscriptionPlanOptionSchema: () => subscriptionPlanOptionSchema,
1465
+ subscriptionPlanOptionsSchema: () => subscriptionPlanOptionsSchema,
1454
1466
  subscriptionSchema: () => subscriptionSchema
1455
1467
  });
1456
1468
  var import_zod14 = require("zod");
@@ -1660,6 +1672,33 @@ var milestoneProgressSchema = import_zod14.z.object({
1660
1672
  toNormalizedCycleNumber: import_zod14.z.number(),
1661
1673
  events: import_zod14.z.record(import_zod14.z.coerce.number(), milestoneProgressEventSchema.array())
1662
1674
  });
1675
+ var pricingOptionSchema = import_zod14.z.object({
1676
+ id: import_zod14.z.string(),
1677
+ name: import_zod14.z.string(),
1678
+ cycleLength: import_zod14.z.nativeEnum(CycleLength)
1679
+ });
1680
+ var pendingPlanChangeSchema = import_zod14.z.object({
1681
+ option: pricingOptionSchema,
1682
+ // The renewal that starts the new plan and charges `nextTotal`.
1683
+ takesEffectAt: import_zod14.z.coerce.date(),
1684
+ nextTotal: orderTotalSchema,
1685
+ // Whether everything the subscription gets off now (discount, offer, coupons) still applies on the new plan.
1686
+ keepsDiscount: import_zod14.z.boolean(),
1687
+ scheduledAt: import_zod14.z.coerce.date()
1688
+ });
1689
+ var subscriptionPlanOptionSchema = import_zod14.z.object({
1690
+ option: pricingOptionSchema,
1691
+ // What the next renewal charges on this plan. For the plan it is on, its normal renewal.
1692
+ nextTotal: orderTotalSchema,
1693
+ takesEffectAt: import_zod14.z.coerce.date(),
1694
+ keepsDiscount: import_zod14.z.boolean(),
1695
+ current: import_zod14.z.boolean(),
1696
+ scheduled: import_zod14.z.boolean()
1697
+ });
1698
+ var subscriptionPlanOptionsSchema = import_zod14.z.object({
1699
+ unavailable: import_zod14.z.string().nullish(),
1700
+ plans: subscriptionPlanOptionSchema.array()
1701
+ });
1663
1702
  var subscriptionSchema = import_zod14.z.object({
1664
1703
  id: import_zod14.z.string(),
1665
1704
  status: import_zod14.z.nativeEnum(SubscriptionStatus),
@@ -1674,6 +1713,10 @@ var subscriptionSchema = import_zod14.z.object({
1674
1713
  paymentMethod: import_zod14.z.string().optional(),
1675
1714
  milestoneProgress: milestoneProgressSchema.nullish(),
1676
1715
  embeddedUpdatePaymentUrl: import_zod14.z.string().optional(),
1716
+ // Older backends send neither, and one this version can't read is dropped rather than failing
1717
+ // the whole subscription.
1718
+ pricingOption: pricingOptionSchema.nullish().catch(void 0),
1719
+ pendingChange: pendingPlanChangeSchema.nullish().catch(void 0),
1677
1720
  content: import_zod14.z.discriminatedUnion("type", [
1678
1721
  import_zod14.z.object({
1679
1722
  type: import_zod14.z.literal("Product"),
@@ -1717,6 +1760,38 @@ var SubscriptionEndpoints = class {
1717
1760
  });
1718
1761
  return response.data;
1719
1762
  }
1763
+ /**
1764
+ * The plans the subscription can switch to when its current period ends, each with what the
1765
+ * next renewal would charge on it. The plan it is on comes first. When it can't switch,
1766
+ * `unavailable` says why, ready to show to the customer.
1767
+ */
1768
+ async getPlanOptions(subscriptionId) {
1769
+ const response = await this.api.authenticatedFetch(`/api/customer/inventory/subscriptions/${subscriptionId}/plan-options`, subscriptionPlanOptionsSchema);
1770
+ return response.data;
1771
+ }
1772
+ /**
1773
+ * Switches the subscription to another plan when its current period ends. Nothing is charged
1774
+ * now: the next renewal charges the new plan and starts its cycle. Until then the customer can
1775
+ * switch again, and passing the plan it is on keeps that plan. Returns the updated subscription,
1776
+ * with the switch in `pendingChange`.
1777
+ */
1778
+ async changePlan(subscriptionId, variationId) {
1779
+ const response = await this.api.authenticatedFetch(`/api/customer/inventory/subscriptions/${subscriptionId}/plan-change`, subscriptionSchema, {
1780
+ method: "POST",
1781
+ body: { variationId }
1782
+ });
1783
+ return response.data;
1784
+ }
1785
+ /**
1786
+ * Keeps the subscription on its current plan, dropping a switch scheduled with `changePlan`.
1787
+ * Returns the updated subscription.
1788
+ */
1789
+ async cancelPlanChange(subscriptionId) {
1790
+ const response = await this.api.authenticatedFetch(`/api/customer/inventory/subscriptions/${subscriptionId}/plan-change`, subscriptionSchema, {
1791
+ method: "DELETE"
1792
+ });
1793
+ return response.data;
1794
+ }
1720
1795
  async renew(subscriptionId, returnUrl, embedded) {
1721
1796
  const response = await this.api.authenticatedFetch(`/api/customer/inventory/subscriptions/${subscriptionId}/renew?redirect=false&return=${returnUrl}&embedded=${embedded ? "true" : "false"}`, import_zod15.z.object({
1722
1797
  location: import_zod15.z.string()
@@ -2989,6 +3064,31 @@ var ImageUtils = class _ImageUtils {
2989
3064
  };
2990
3065
 
2991
3066
  // src/utils/utm.ts
3067
+ var clickIdPlatforms = [
3068
+ ["gclid", "google"],
3069
+ ["gbraid", "google"],
3070
+ ["wbraid", "google"],
3071
+ ["msclkid", "microsoft"],
3072
+ ["fbclid", "meta"],
3073
+ ["ttclid", "tiktok"]
3074
+ ];
3075
+ var adPlatformOrder = ["google", "microsoft", "meta", "tiktok"];
3076
+ function adClicksOf(utm) {
3077
+ var _a;
3078
+ if (!utm)
3079
+ return void 0;
3080
+ const platforms = new Set((_a = utm.adClicks) != null ? _a : []);
3081
+ for (const [key, platform] of clickIdPlatforms) {
3082
+ if (utm[key])
3083
+ platforms.add(platform);
3084
+ }
3085
+ const ordered = adPlatformOrder.filter((platform) => platforms.has(platform));
3086
+ return ordered.length > 0 ? ordered : void 0;
3087
+ }
3088
+ function withoutClickIds(utm) {
3089
+ const { gclid: _gclid, gbraid: _gbraid, wbraid: _wbraid, msclkid: _msclkid, fbclid: _fbclid, ttclid: _ttclid, ...rest } = utm;
3090
+ return { ...rest, adClicks: adClicksOf(utm) };
3091
+ }
2992
3092
  function parseOffSiteReferrer(rawReferrer, currentOrigin) {
2993
3093
  if (!rawReferrer)
2994
3094
  return void 0;
@@ -3003,7 +3103,7 @@ function parseOffSiteReferrer(rawReferrer, currentOrigin) {
3003
3103
  }
3004
3104
  function resolveUtm(cached, fresh) {
3005
3105
  const freshHasUtm = !!(fresh.source || fresh.medium || fresh.campaign || fresh.term || fresh.content);
3006
- const freshHasClickId = !!(fresh.gclid || fresh.gbraid || fresh.wbraid || fresh.fbclid || fresh.msclkid || fresh.ttclid);
3106
+ const freshHasClickId = !!adClicksOf(fresh);
3007
3107
  const freshIsExternalArrival = freshHasUtm || freshHasClickId || !!fresh.referrer;
3008
3108
  if (freshIsExternalArrival)
3009
3109
  return fresh;
@@ -3066,6 +3166,7 @@ var MoonbaseClient = class {
3066
3166
  SubscriptionStatus,
3067
3167
  TokenStore,
3068
3168
  accessTokenLifetime,
3169
+ adClicksOf,
3069
3170
  imageWidths,
3070
3171
  isLocalStorageAvailable,
3071
3172
  isPromotionDisplay,
@@ -3078,5 +3179,6 @@ var MoonbaseClient = class {
3078
3179
  promotionDisplays,
3079
3180
  resolveUtm,
3080
3181
  schemas,
3081
- utmToObject
3182
+ utmToObject,
3183
+ withoutClickIds
3082
3184
  });