brainerce 1.47.1 → 1.47.3

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.js CHANGED
@@ -664,6 +664,7 @@ var BrainerceClient = class {
664
664
  this.proxyMode = options.proxyMode || false;
665
665
  this.analyticsBaseUrl = this.resolveAnalyticsBaseUrl(options.analyticsBaseUrl, resolvedBase);
666
666
  this.onAuthError = options.onAuthError;
667
+ this.onCartReset = options.onCartReset;
667
668
  this.hydrateSessionCart();
668
669
  this.detectRecoverCartFromUrl();
669
670
  }
@@ -4262,14 +4263,17 @@ var BrainerceClient = class {
4262
4263
  const migrated = await this.migrateLocalCartToSession();
4263
4264
  if (migrated) return migrated;
4264
4265
  if (this.sessionCartId && this.sessionToken) {
4266
+ const previousCartId = this.sessionCartId;
4265
4267
  try {
4266
4268
  const cart2 = await this.getCart(this.sessionCartId);
4267
4269
  if (cart2.status === "ACTIVE") {
4268
4270
  return cart2;
4269
4271
  }
4270
4272
  this.clearSessionCart();
4273
+ this.onCartReset?.({ previousCartId, reason: "not_active" });
4271
4274
  } catch {
4272
4275
  this.clearSessionCart();
4276
+ this.onCartReset?.({ previousCartId, reason: "not_found" });
4273
4277
  }
4274
4278
  }
4275
4279
  if (this.sessionToken) {
@@ -6498,9 +6502,9 @@ var BrainerceClient = class {
6498
6502
  );
6499
6503
  }
6500
6504
  // -------------------- Loyalty --------------------
6501
- // Storefront-mode only (storeId + customerToken). The backend exposes loyalty
6502
- // solely under /api/stores/:storeId/loyalty there is no vibe-coded route, so
6503
- // these do NOT branch on isVibeCodedMode() (that would 404 silently).
6505
+ // Available in both storefront mode (storeId + customerToken) and
6506
+ // vibe-coded mode (salesChannelId + customerToken) Phase 5 added the
6507
+ // /api/vc/:connectionId/loyalty/* routes mirroring /api/stores/:storeId/loyalty.
6504
6508
  /**
6505
6509
  * Get the logged-in customer's loyalty status: enrollment, points balance,
6506
6510
  * lifetime earned, the program's display config, earned milestone `badges`,
@@ -6524,10 +6528,16 @@ var BrainerceClient = class {
6524
6528
  401
6525
6529
  );
6526
6530
  }
6531
+ if (this.isVibeCodedMode()) {
6532
+ return this.vibeCodedRequest("GET", "/loyalty/me");
6533
+ }
6527
6534
  if (this.storeId && !this.apiKey) {
6528
6535
  return this.storefrontRequest("GET", "/loyalty/me");
6529
6536
  }
6530
- throw new BrainerceError("getLoyaltyStatus is only available in storefront mode", 400);
6537
+ throw new BrainerceError(
6538
+ "getLoyaltyStatus is only available in vibe-coded or storefront mode",
6539
+ 400
6540
+ );
6531
6541
  }
6532
6542
  /**
6533
6543
  * Enroll the logged-in customer in the store's loyalty program (requires
@@ -6546,10 +6556,16 @@ var BrainerceClient = class {
6546
6556
  401
6547
6557
  );
6548
6558
  }
6559
+ if (this.isVibeCodedMode()) {
6560
+ return this.vibeCodedRequest("POST", "/loyalty/enroll");
6561
+ }
6549
6562
  if (this.storeId && !this.apiKey) {
6550
6563
  return this.storefrontRequest("POST", "/loyalty/enroll");
6551
6564
  }
6552
- throw new BrainerceError("enrollInLoyalty is only available in storefront mode", 400);
6565
+ throw new BrainerceError(
6566
+ "enrollInLoyalty is only available in vibe-coded or storefront mode",
6567
+ 400
6568
+ );
6553
6569
  }
6554
6570
  /**
6555
6571
  * List the rewards the customer can redeem points for (active rewards, cheapest
@@ -6568,10 +6584,16 @@ var BrainerceClient = class {
6568
6584
  401
6569
6585
  );
6570
6586
  }
6587
+ if (this.isVibeCodedMode()) {
6588
+ return this.vibeCodedRequest("GET", "/loyalty/rewards/available");
6589
+ }
6571
6590
  if (this.storeId && !this.apiKey) {
6572
6591
  return this.storefrontRequest("GET", "/loyalty/rewards/available");
6573
6592
  }
6574
- throw new BrainerceError("getAvailableRewards is only available in storefront mode", 400);
6593
+ throw new BrainerceError(
6594
+ "getAvailableRewards is only available in vibe-coded or storefront mode",
6595
+ 400
6596
+ );
6575
6597
  }
6576
6598
  /**
6577
6599
  * Redeem a reward: spends the customer's points and mints a one-time coupon
@@ -6591,10 +6613,16 @@ var BrainerceClient = class {
6591
6613
  401
6592
6614
  );
6593
6615
  }
6616
+ if (this.isVibeCodedMode()) {
6617
+ return this.vibeCodedRequest("POST", "/loyalty/redeem", { rewardId });
6618
+ }
6594
6619
  if (this.storeId && !this.apiKey) {
6595
6620
  return this.storefrontRequest("POST", "/loyalty/redeem", { rewardId });
6596
6621
  }
6597
- throw new BrainerceError("redeemLoyaltyReward is only available in storefront mode", 400);
6622
+ throw new BrainerceError(
6623
+ "redeemLoyaltyReward is only available in vibe-coded or storefront mode",
6624
+ 400
6625
+ );
6598
6626
  }
6599
6627
  /**
6600
6628
  * Report a social share, granting the SOCIAL_SHARE earning-rule bonus if the
@@ -6614,6 +6642,13 @@ var BrainerceClient = class {
6614
6642
  401
6615
6643
  );
6616
6644
  }
6645
+ if (this.isVibeCodedMode()) {
6646
+ return this.vibeCodedRequest(
6647
+ "POST",
6648
+ "/loyalty/social-share",
6649
+ platform ? { platform } : {}
6650
+ );
6651
+ }
6617
6652
  if (this.storeId && !this.apiKey) {
6618
6653
  return this.storefrontRequest(
6619
6654
  "POST",
@@ -6621,7 +6656,10 @@ var BrainerceClient = class {
6621
6656
  platform ? { platform } : {}
6622
6657
  );
6623
6658
  }
6624
- throw new BrainerceError("reportSocialShare is only available in storefront mode", 400);
6659
+ throw new BrainerceError(
6660
+ "reportSocialShare is only available in vibe-coded or storefront mode",
6661
+ 400
6662
+ );
6625
6663
  }
6626
6664
  /**
6627
6665
  * Public referral-link lookup: who referred the visitor and what welcome
@@ -6640,12 +6678,20 @@ var BrainerceClient = class {
6640
6678
  * ```
6641
6679
  */
6642
6680
  async getReferralInfo(code) {
6681
+ if (this.isVibeCodedMode()) {
6682
+ return this.vibeCodedRequest("GET", "/loyalty/referral-info", void 0, {
6683
+ code
6684
+ });
6685
+ }
6643
6686
  if (this.storeId && !this.apiKey) {
6644
6687
  return this.storefrontRequest("GET", "/loyalty/referral-info", void 0, {
6645
6688
  code
6646
6689
  });
6647
6690
  }
6648
- throw new BrainerceError("getReferralInfo is only available in storefront mode", 400);
6691
+ throw new BrainerceError(
6692
+ "getReferralInfo is only available in vibe-coded or storefront mode",
6693
+ 400
6694
+ );
6649
6695
  }
6650
6696
  /**
6651
6697
  * AI-recommended reward for the logged-in customer — "recommended for you"
@@ -6669,13 +6715,22 @@ var BrainerceClient = class {
6669
6715
  401
6670
6716
  );
6671
6717
  }
6718
+ if (this.isVibeCodedMode()) {
6719
+ return this.vibeCodedRequest(
6720
+ "GET",
6721
+ "/loyalty/rewards/recommended"
6722
+ );
6723
+ }
6672
6724
  if (this.storeId && !this.apiKey) {
6673
6725
  return this.storefrontRequest(
6674
6726
  "GET",
6675
6727
  "/loyalty/rewards/recommended"
6676
6728
  );
6677
6729
  }
6678
- throw new BrainerceError("getRecommendedReward is only available in storefront mode", 400);
6730
+ throw new BrainerceError(
6731
+ "getRecommendedReward is only available in vibe-coded or storefront mode",
6732
+ 400
6733
+ );
6679
6734
  }
6680
6735
  /**
6681
6736
  * List the paid membership plans the customer can subscribe to (requires
@@ -6694,10 +6749,16 @@ var BrainerceClient = class {
6694
6749
  401
6695
6750
  );
6696
6751
  }
6752
+ if (this.isVibeCodedMode()) {
6753
+ return this.vibeCodedRequest("GET", "/loyalty/membership/plans");
6754
+ }
6697
6755
  if (this.storeId && !this.apiKey) {
6698
6756
  return this.storefrontRequest("GET", "/loyalty/membership/plans");
6699
6757
  }
6700
- throw new BrainerceError("getMembershipPlans is only available in storefront mode", 400);
6758
+ throw new BrainerceError(
6759
+ "getMembershipPlans is only available in vibe-coded or storefront mode",
6760
+ 400
6761
+ );
6701
6762
  }
6702
6763
  /**
6703
6764
  * List the customer's saved payment methods (display fields only — brand /
@@ -6717,6 +6778,12 @@ var BrainerceClient = class {
6717
6778
  401
6718
6779
  );
6719
6780
  }
6781
+ if (this.isVibeCodedMode()) {
6782
+ return this.vibeCodedRequest(
6783
+ "GET",
6784
+ "/loyalty/membership/payment-methods"
6785
+ );
6786
+ }
6720
6787
  if (this.storeId && !this.apiKey) {
6721
6788
  return this.storefrontRequest(
6722
6789
  "GET",
@@ -6724,7 +6791,7 @@ var BrainerceClient = class {
6724
6791
  );
6725
6792
  }
6726
6793
  throw new BrainerceError(
6727
- "getMySavedPaymentMethods is only available in storefront mode",
6794
+ "getMySavedPaymentMethods is only available in vibe-coded or storefront mode",
6728
6795
  400
6729
6796
  );
6730
6797
  }
@@ -6751,6 +6818,13 @@ var BrainerceClient = class {
6751
6818
  401
6752
6819
  );
6753
6820
  }
6821
+ if (this.isVibeCodedMode()) {
6822
+ return this.vibeCodedRequest(
6823
+ "POST",
6824
+ "/loyalty/membership/subscribe",
6825
+ params
6826
+ );
6827
+ }
6754
6828
  if (this.storeId && !this.apiKey) {
6755
6829
  return this.storefrontRequest(
6756
6830
  "POST",
@@ -6758,7 +6832,10 @@ var BrainerceClient = class {
6758
6832
  params
6759
6833
  );
6760
6834
  }
6761
- throw new BrainerceError("subscribeToMembership is only available in storefront mode", 400);
6835
+ throw new BrainerceError(
6836
+ "subscribeToMembership is only available in vibe-coded or storefront mode",
6837
+ 400
6838
+ );
6762
6839
  }
6763
6840
  /**
6764
6841
  * Cancel the customer's paid membership (requires customerToken).
@@ -6780,10 +6857,52 @@ var BrainerceClient = class {
6780
6857
  401
6781
6858
  );
6782
6859
  }
6860
+ if (this.isVibeCodedMode()) {
6861
+ return this.vibeCodedRequest("POST", "/loyalty/membership/cancel");
6862
+ }
6783
6863
  if (this.storeId && !this.apiKey) {
6784
6864
  return this.storefrontRequest("POST", "/loyalty/membership/cancel");
6785
6865
  }
6786
- throw new BrainerceError("cancelMembership is only available in storefront mode", 400);
6866
+ throw new BrainerceError(
6867
+ "cancelMembership is only available in vibe-coded or storefront mode",
6868
+ 400
6869
+ );
6870
+ }
6871
+ /**
6872
+ * Mint a short-lived session for the embeddable loyalty widget (Phase 5) and
6873
+ * return the ready-to-use iframe URL. Requires customerToken. The returned
6874
+ * `embedUrl` is safe to drop straight into an `<iframe src>` — it carries a
6875
+ * scoped ~15-minute session token, never the real customerToken. Re-call this
6876
+ * before the iframe reloads (e.g. on page navigation) to refresh it.
6877
+ *
6878
+ * @example
6879
+ * ```typescript
6880
+ * const { embedUrl } = await client.getLoyaltyWidgetSession();
6881
+ * // <iframe src={embedUrl} width="360" height="420" />
6882
+ * ```
6883
+ */
6884
+ async getLoyaltyWidgetSession() {
6885
+ if (!this.customerToken && !this.proxyMode) {
6886
+ throw new BrainerceError(
6887
+ "Customer token required. Call setCustomerToken() after login.",
6888
+ 401
6889
+ );
6890
+ }
6891
+ let result;
6892
+ if (this.isVibeCodedMode()) {
6893
+ result = await this.vibeCodedRequest("POST", "/loyalty/widget-session");
6894
+ } else if (this.storeId && !this.apiKey) {
6895
+ result = await this.storefrontRequest("POST", "/loyalty/widget-session");
6896
+ } else {
6897
+ throw new BrainerceError(
6898
+ "getLoyaltyWidgetSession is only available in vibe-coded or storefront mode",
6899
+ 400
6900
+ );
6901
+ }
6902
+ return {
6903
+ ...result,
6904
+ embedUrl: `${this.baseUrl}/api/loyalty/embed/${encodePathSegment(result.storeId)}/${encodePathSegment(result.sessionId)}`
6905
+ };
6787
6906
  }
6788
6907
  /**
6789
6908
  * Get the current customer's orders (requires customerToken)
@@ -9098,25 +9217,60 @@ function buildArticleJsonLd(post, opts) {
9098
9217
  return result;
9099
9218
  }
9100
9219
  function buildProductJsonLd(product, opts) {
9101
- const url = absoluteUrl(opts.siteUrl, opts.path ?? (product.slug ? `/products/${product.slug}` : void 0));
9220
+ const url = absoluteUrl(
9221
+ opts.siteUrl,
9222
+ opts.path ?? (product.slug ? `/products/${product.slug}` : void 0)
9223
+ );
9102
9224
  const images = (product.images ?? []).map((img) => img.url).filter(Boolean);
9103
9225
  const brand = opts.brandName ?? product.brands?.[0]?.name;
9104
9226
  const description = stripHtml(product.description).slice(0, 5e3);
9105
9227
  const effectivePrice = product.salePrice ?? product.basePrice;
9106
9228
  const inStock = product.inventory ? (product.inventory.available ?? 0) > 0 : true;
9107
9229
  const isVariable = product.type === "VARIABLE" && product.priceMin && product.priceMax;
9230
+ const itemCondition = "https://schema.org/NewCondition";
9231
+ const shippingDetails = (opts.shipping ?? []).filter((z) => z.amount !== null).map((z) => ({
9232
+ "@type": "OfferShippingDetails",
9233
+ shippingRate: { "@type": "MonetaryAmount", value: z.amount, currency: opts.currency },
9234
+ shippingDestination: { "@type": "DefinedRegion", addressCountry: z.countries },
9235
+ ...z.handlingTime != null || z.minDeliveryDays != null || z.maxDeliveryDays != null ? {
9236
+ deliveryTime: {
9237
+ "@type": "ShippingDeliveryTime",
9238
+ ...z.handlingTime != null ? {
9239
+ handlingTime: {
9240
+ "@type": "QuantitativeValue",
9241
+ minValue: 0,
9242
+ maxValue: z.handlingTime
9243
+ }
9244
+ } : {},
9245
+ ...z.minDeliveryDays != null || z.maxDeliveryDays != null ? {
9246
+ transitTime: {
9247
+ "@type": "QuantitativeValue",
9248
+ minValue: z.minDeliveryDays ?? z.maxDeliveryDays,
9249
+ maxValue: z.maxDeliveryDays ?? z.minDeliveryDays
9250
+ }
9251
+ } : {}
9252
+ }
9253
+ } : {}
9254
+ }));
9108
9255
  const offer = isVariable ? {
9109
9256
  "@type": "AggregateOffer",
9110
9257
  lowPrice: product.priceMin,
9111
9258
  highPrice: product.priceMax,
9112
9259
  priceCurrency: opts.currency,
9113
9260
  availability: inStock ? "https://schema.org/InStock" : "https://schema.org/OutOfStock",
9261
+ itemCondition,
9262
+ ...shippingDetails.length > 0 ? { shippingDetails } : {},
9114
9263
  ...url ? { url } : {}
9115
9264
  } : {
9116
9265
  "@type": "Offer",
9117
9266
  price: effectivePrice,
9118
9267
  priceCurrency: opts.currency,
9119
9268
  availability: inStock ? "https://schema.org/InStock" : "https://schema.org/OutOfStock",
9269
+ itemCondition,
9270
+ // Only meaningful for an active sale price with a known end date —
9271
+ // a regular (non-sale) price has no expiry to declare.
9272
+ ...product.salePrice && product.salePriceEndsAt ? { priceValidUntil: product.salePriceEndsAt } : {},
9273
+ ...shippingDetails.length > 0 ? { shippingDetails } : {},
9120
9274
  ...url ? { url } : {}
9121
9275
  };
9122
9276
  return {