@rebuy/rebuy 2.34.0 → 2.35.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.
Files changed (43) hide show
  1. package/dist/index.js +204 -23
  2. package/dist/index.js.map +4 -4
  3. package/dist/index.mjs +204 -23
  4. package/dist/index.mjs.map +4 -4
  5. package/dist/schema/checkout-and-beyond/constants.js +2 -0
  6. package/dist/schema/checkout-and-beyond/constants.js.map +2 -2
  7. package/dist/schema/checkout-and-beyond/constants.mjs +2 -0
  8. package/dist/schema/checkout-and-beyond/constants.mjs.map +2 -2
  9. package/dist/schema/checkout-and-beyond/index.js +183 -6
  10. package/dist/schema/checkout-and-beyond/index.js.map +3 -3
  11. package/dist/schema/checkout-and-beyond/index.mjs +183 -6
  12. package/dist/schema/checkout-and-beyond/index.mjs.map +3 -3
  13. package/dist/schema/widget-data.js +197 -23
  14. package/dist/schema/widget-data.js.map +4 -4
  15. package/dist/schema/widget-data.mjs +197 -23
  16. package/dist/schema/widget-data.mjs.map +3 -3
  17. package/dist/schema/widgets/checkout-and-beyond/banner.d.ts +27 -25
  18. package/dist/schema/widgets/checkout-and-beyond/banner.d.ts.map +1 -1
  19. package/dist/schema/widgets/checkout-and-beyond/button.d.ts +5 -0
  20. package/dist/schema/widgets/checkout-and-beyond/button.d.ts.map +1 -1
  21. package/dist/schema/widgets/checkout-and-beyond/carousel.d.ts +25 -25
  22. package/dist/schema/widgets/checkout-and-beyond/cartLine.d.ts +25 -25
  23. package/dist/schema/widgets/checkout-and-beyond/common.d.ts +3 -1
  24. package/dist/schema/widgets/checkout-and-beyond/common.d.ts.map +1 -1
  25. package/dist/schema/widgets/checkout-and-beyond/icons.d.ts +124 -0
  26. package/dist/schema/widgets/checkout-and-beyond/icons.d.ts.map +1 -0
  27. package/dist/schema/widgets/checkout-and-beyond/image.d.ts +319 -2
  28. package/dist/schema/widgets/checkout-and-beyond/image.d.ts.map +1 -1
  29. package/dist/schema/widgets/checkout-and-beyond/index.d.ts +1 -0
  30. package/dist/schema/widgets/checkout-and-beyond/index.d.ts.map +1 -1
  31. package/dist/schema/widgets/checkout-and-beyond/offers.d.ts +25 -25
  32. package/dist/schema/widgets/checkout-and-beyond/progressBar.d.ts +25 -25
  33. package/dist/schema/widgets/checkout-and-beyond/progressBar.d.ts.map +1 -1
  34. package/dist/server/index.js +193 -25
  35. package/dist/server/index.js.map +4 -4
  36. package/dist/server/index.mjs +193 -25
  37. package/dist/server/index.mjs.map +4 -4
  38. package/dist/transforms/index.js +193 -25
  39. package/dist/transforms/index.js.map +3 -3
  40. package/dist/transforms/index.mjs +193 -25
  41. package/dist/transforms/index.mjs.map +3 -3
  42. package/dist/transforms/smartCart/convertSmartCartProgressBarToV2.d.ts.map +1 -1
  43. package/package.json +1 -1
@@ -71,6 +71,7 @@ var borderWidths = ["base", "medium", "thick"];
71
71
  var BorderWidth = freezeEnum(borderWidths);
72
72
  var buttonActions = [
73
73
  "acceptOffer",
74
+ "addGift",
74
75
  "addToOrder",
75
76
  "declineAllOffers",
76
77
  "declineOffer",
@@ -80,6 +81,7 @@ var buttonActions = [
80
81
  "goToPrevPage",
81
82
  "goToURL",
82
83
  "removeFromOrder",
84
+ "removeGift",
83
85
  "selectVariant",
84
86
  "showPagination",
85
87
  "switchToSubscription",
@@ -209,6 +211,90 @@ var VariantSelector = freezeEnum(variantSelectors);
209
211
  var verticalAlignments = ["top", "middle", "bottom"];
210
212
  var VerticalAlignment = freezeEnum(verticalAlignments);
211
213
 
214
+ // src/schema/widgets/checkout-and-beyond/icons.ts
215
+ var iconNames = [
216
+ "alert-circle",
217
+ "alert-triangle",
218
+ "alert-triangle-filled",
219
+ "arrow-down",
220
+ "arrow-left",
221
+ "arrow-right",
222
+ "arrow-up",
223
+ "arrow-up-right",
224
+ "bag",
225
+ "bullet",
226
+ "calendar",
227
+ "camera",
228
+ "caret-down",
229
+ "cart",
230
+ "cash-dollar",
231
+ "categories",
232
+ "check",
233
+ "check-circle",
234
+ "check-circle-filled",
235
+ "chevron-down",
236
+ "chevron-left",
237
+ "chevron-right",
238
+ "chevron-up",
239
+ "circle",
240
+ "clipboard",
241
+ "clock",
242
+ "credit-card",
243
+ "delete",
244
+ "delivered",
245
+ "delivery",
246
+ "disabled",
247
+ "discount",
248
+ "edit",
249
+ "email",
250
+ "empty",
251
+ "external",
252
+ "filter",
253
+ "geolocation",
254
+ "gift-card",
255
+ "globe",
256
+ "grid",
257
+ "image",
258
+ "info",
259
+ "info-filled",
260
+ "list-bulleted",
261
+ "location",
262
+ "lock",
263
+ "map",
264
+ "menu",
265
+ "menu-horizontal",
266
+ "menu-vertical",
267
+ "minus",
268
+ "mobile",
269
+ "note",
270
+ "order",
271
+ "organization",
272
+ "plus",
273
+ "profile",
274
+ "question-circle",
275
+ "question-circle-filled",
276
+ "reorder",
277
+ "reset",
278
+ "return",
279
+ "savings",
280
+ "search",
281
+ "settings",
282
+ "star",
283
+ "star-filled",
284
+ "star-half",
285
+ "store",
286
+ "truck",
287
+ "upload",
288
+ "x",
289
+ "x-circle",
290
+ "x-circle-filled"
291
+ ];
292
+ var IconName = freezeEnum(iconNames);
293
+ var iconSizes = ["base", "large", "large-100", "small", "small-100", "small-200"];
294
+ var IconSize = freezeEnum(iconSizes);
295
+ var iconTones = ["auto", "critical", "custom", "info", "neutral", "success", "warning"];
296
+ var IconTone = freezeEnum(iconTones);
297
+
212
298
  // src/schema/widgets/checkout-and-beyond/regex.ts
213
299
  var DYNAMIC_TOKEN_REGEX = /^\{\{\s*[A-Za-z]+\s*\}\}$/;
214
300
  var HEX_COLOR_REGEX = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
@@ -319,12 +405,44 @@ var CABLayoutSection = import_zod2.z.object({
319
405
  width: import_zod2.z.number().default(100)
320
406
  });
321
407
 
408
+ // src/schema/widgets/checkout-and-beyond/utils.ts
409
+ var import_es_toolkit = require("es-toolkit");
410
+ var import_compat = require("es-toolkit/compat");
411
+ var isHTML = (html = "") => {
412
+ if (typeof window !== "undefined") {
413
+ const parser = new DOMParser();
414
+ const doc = parser.parseFromString(html, "text/html");
415
+ const hasHTML = (nodeList) => Array.from(nodeList).some((node) => node.nodeType === 1);
416
+ return hasHTML(doc.body.childNodes) || hasHTML(doc.head.childNodes);
417
+ }
418
+ return html.search(HTML_TAGS_REGEX) !== -1;
419
+ };
420
+ var hasHTMLInDoc = (doc) => doc.content.some(({ content = [] }) => content.some(({ text }) => isHTML(text)));
421
+ var checkForHTML = (input) => !((0, import_compat.isString)(input) && isHTML(input) || (0, import_es_toolkit.isPlainObject)(input) && hasHTMLInDoc(input));
422
+ var NO_HTML = { message: "HTML is not supported" };
423
+
322
424
  // src/schema/widgets/checkout-and-beyond/banner.ts
323
425
  var CABBannerSection = import_zod3.z.lazy(
324
426
  () => CABLayoutSection.omit({ sectionType: true }).extend({
325
427
  buttonField: import_zod3.z.enum(buttonFields).optional(),
326
428
  color: import_zod3.z.enum(bannerColors).default("info"),
327
429
  dismissible: import_zod3.z.boolean().default(true),
430
+ /**
431
+ * The `s-banner` heading — localized content (a buyer can see a merchant-composed banner). Absent OR
432
+ * blank ⇒ no heading; the renderer emits no heading slot for `''` rather than an empty one.
433
+ *
434
+ * Merchant-composed buyer-facing plain text, so it rejects HTML at the boundary the same way
435
+ * `CABImageSection.altText` and `CABTextSection.content` do (the unchecked localized records elsewhere —
436
+ * `progressBar`'s gift labels, `reviews`' plurals — are converter/constant-sourced, not merchant input).
437
+ *
438
+ * The refinement is a last-resort ASSERTION, not the normalization boundary: `normalizeTextContent` only
439
+ * rewrites `sectionType: 'text'` nodes' `content`, so nothing strips markup or canonicalizes `{token}`
440
+ * here. A producer must strip upstream the way `composeOffer` does for `altText`. Get it wrong and
441
+ * `salvageSections` stubs the whole banner (children included) with a drift report — degraded, reported,
442
+ * not a 500. Nothing emits `heading` yet; the first converter that maps merchant banner copy into it
443
+ * either strips first or teaches `normalizeTextContent` to strip this field.
444
+ */
445
+ heading: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.string().refine(checkForHTML, NO_HTML)).optional(),
328
446
  sectionType: import_zod3.z.literal(SectionType.banner).default(SectionType.banner)
329
447
  })
330
448
  );
@@ -337,24 +455,6 @@ var import_zod5 = require("zod");
337
455
  var import_compat2 = require("es-toolkit/compat");
338
456
  var import_uuid2 = require("uuid");
339
457
  var import_zod4 = require("zod");
340
-
341
- // src/schema/widgets/checkout-and-beyond/utils.ts
342
- var import_es_toolkit = require("es-toolkit");
343
- var import_compat = require("es-toolkit/compat");
344
- var isHTML = (html = "") => {
345
- if (typeof window !== "undefined") {
346
- const parser = new DOMParser();
347
- const doc = parser.parseFromString(html, "text/html");
348
- const hasHTML = (nodeList) => Array.from(nodeList).some((node) => node.nodeType === 1);
349
- return hasHTML(doc.body.childNodes) || hasHTML(doc.head.childNodes);
350
- }
351
- return html.search(HTML_TAGS_REGEX) !== -1;
352
- };
353
- var hasHTMLInDoc = (doc) => doc.content.some(({ content = [] }) => content.some(({ text }) => isHTML(text)));
354
- var checkForHTML = (input) => !((0, import_compat.isString)(input) && isHTML(input) || (0, import_es_toolkit.isPlainObject)(input) && hasHTMLInDoc(input));
355
- var NO_HTML = { message: "HTML is not supported" };
356
-
357
- // src/schema/widgets/checkout-and-beyond/text.ts
358
458
  var enumOrOmit = (...vals) => import_zod4.z.string().transform((val) => vals.includes(val) ? val : void 0).optional();
359
459
  var TiptapText = import_zod4.z.object({
360
460
  marks: import_zod4.z.union([
@@ -469,6 +569,21 @@ var CABButtonSection = import_zod5.z.object({
469
569
  sectionId: import_zod5.z.uuid().default(() => (0, import_uuid3.v7)()),
470
570
  sections: import_zod5.z.union([import_zod5.z.array(CABButtonContent), import_zod5.z.strictObject({}).transform(() => [])]).default(() => []),
471
571
  sectionType: import_zod5.z.literal(SectionType.button).default(SectionType.button),
572
+ /**
573
+ * The smart-cart tier this button acts on (`addGift`/`removeGift`): scopes the click to one tier's gift. The
574
+ * client resolves the tier's gift (productId) from the progress-bar context by this `tierId` — the button node
575
+ * stays data, no bespoke per-tier wiring. Absent on non-gift buttons (offer add/remove, navigation, links).
576
+ *
577
+ * Deliberately NOT `CABTextTier` (the shape `CABTextSection.tier` uses): a gift button acts on a tier the bar
578
+ * already resolved, so it needs the id and nothing else. Reusing the text tier would make `threshold`
579
+ * required, leave `tierId` optional, and DEFAULT `tierType` to `'shipping'` — a schema-supplied wrong answer
580
+ * on a gift button. Unknown keys are stripped, so a client spreading a whole tier in still parses.
581
+ *
582
+ * `.min(1)` because an empty id IS the silently-id-less state this shape exists to prevent: the client's
583
+ * lookup finds no tier and the click resolves to nothing. Safe to bound — the field is new, so there are no
584
+ * stored payloads to grandfather, and the producer is client code, not a merchant form.
585
+ */
586
+ tier: import_zod5.z.object({ tierId: import_zod5.z.string().min(1) }).optional(),
472
587
  /** Fire-and-forget pixel POSTed when the button is clicked (e.g. a Monetize decline). */
473
588
  trackingUrl: import_zod5.z.string().optional()
474
589
  });
@@ -842,8 +957,12 @@ var CABProgressTier = import_zod14.z.object({
842
957
  }).optional(),
843
958
  /**
844
959
  * The step-row label at this tier's slot (onsite `getTierLabel`): the merchant custom label, else the
845
- * type default ('Free Shipping' / product title / '{n}% Discount'). Localized content; blank ⇒ no
846
- * label under the tier's icon. Plain text — the step row is a compact icon+label, not rich copy.
960
+ * type default — 'Free Shipping' or '{n}% Discount'. A PRODUCT tier gets NO converter label: its name is
961
+ * the gift PRODUCT title, which the converter can't supply (config carries only product IDs), so the
962
+ * client resolves it (authoritative Shopify title, React parity) with its own localized generic fallback.
963
+ * Localized content; absent OR blank ⇒ no label under the tier's icon (the converter's `toTierMeta` already
964
+ * turns a blank label into an absent key, and a client-authored blank means the same thing — the renderer
965
+ * emits no caption slot rather than an empty one). Plain text — a compact icon+label.
847
966
  */
848
967
  label: import_zod14.z.record(import_zod14.z.string(), import_zod14.z.string()).optional(),
849
968
  /**
@@ -1104,12 +1223,39 @@ var CABSection = import_zod18.z.lazy(
1104
1223
  );
1105
1224
 
1106
1225
  // src/schema/widgets/checkout-and-beyond/image.ts
1107
- var CABImageSection = import_zod19.z.object({
1226
+ var CABImageSectionFields = import_zod19.z.object({
1108
1227
  altText: import_zod19.z.string().refine(checkForHTML, NO_HTML).default(""),
1109
- aspectRatio: import_zod19.z.literal(1).nullable().default(null),
1228
+ /**
1229
+ * Image width÷height (e.g. `46` for the progress-bar fill); `null` renders at natural size. Any POSITIVE
1230
+ * ratio — never limited to 1, but never `0`/negative either: a renderer dividing by it would get `Infinity`,
1231
+ * and CSS `aspect-ratio` drops a negative value and silently reverts to natural size.
1232
+ */
1233
+ aspectRatio: import_zod19.z.number().positive().nullable().default(null),
1110
1234
  border: import_zod19.z.lazy(() => CABBorder),
1111
1235
  buttonField: import_zod19.z.enum(buttonFields).optional(),
1112
- category: import_zod19.z.enum(["gallery", "icons", "payment-methods", "secure-checkout"]).nullable().default(null),
1236
+ /**
1237
+ * `icon` renders `source` as a single `s-icon` by name (the uber-image path covers icons too), reading
1238
+ * `iconSize`/`iconTone`. The other values are a harmless informational holdover from the previous
1239
+ * implementation — they were never significant to rendering (`icons`, plural, is NOT deprecated, just one of
1240
+ * those inert legacy tags); `icon` is the first value that means anything.
1241
+ *
1242
+ * INVARIANT, encoded by the `.superRefine` below (a refined object IS a valid `z.discriminatedUnion` member
1243
+ * in zod 4 — see `CABTextSection`): `category: 'icon'` ⇒ `source` is an icon name or `''` (icon not yet
1244
+ * chosen); any other category ⇒ `source` is NOT a bare icon name, so it stays a URL/token/`''`.
1245
+ *
1246
+ * Encoded rather than left to the renderer because `source` is ONE union with no category gate, so widening
1247
+ * it with `iconNames` also widened what a STORED payload may contain: 14 of the names are plain English
1248
+ * words (`image`, `x`, `search`, `note`, `order`, `globe`, …), and a legacy `source: 'image'` used to fail
1249
+ * parse — which `salvageSections` turns into a null-rendering stub PLUS a drift report. Ungated it would
1250
+ * instead parse and reach the renderer as `<img src="image">`: a broken image, silently, where the old
1251
+ * behavior degraded gracefully and told us about it. The client-assembled half of the invariant was never
1252
+ * the risky half.
1253
+ */
1254
+ category: import_zod19.z.enum(["gallery", "icon", "icons", "payment-methods", "secure-checkout"]).nullable().default(null),
1255
+ /** `icon`-mode only: the `s-icon` `size`; `null` ⇒ the component default (`base`). Ignored by image treatments. */
1256
+ iconSize: import_zod19.z.enum(iconSizes).nullable().default(null),
1257
+ /** `icon`-mode only: the `s-icon` `tone`; `null` ⇒ the component default (`auto`). Ignored by image treatments. */
1258
+ iconTone: import_zod19.z.enum(iconTones).nullable().default(null),
1113
1259
  name: import_zod19.z.string().optional(),
1114
1260
  naturalHeight: import_zod19.z.number().default(0),
1115
1261
  naturalWidth: import_zod19.z.number().default(0),
@@ -1121,9 +1267,31 @@ var CABImageSection = import_zod19.z.object({
1121
1267
  rule: CABRule.optional(),
1122
1268
  sectionId: import_zod19.z.uuid().default(() => (0, import_uuid12.v7)()),
1123
1269
  sectionType: import_zod19.z.literal(SectionType.image).default(SectionType.image),
1124
- source: import_zod19.z.union([import_zod19.z.url(), import_zod19.z.literal(""), import_zod19.z.string().regex(DYNAMIC_TOKEN_REGEX)]).default(""),
1270
+ /**
1271
+ * An image URL or dynamic token, an empty default, or — when `category: 'icon'` — an icon NAME. Icon mode
1272
+ * takes a name or `''` only, NOT a token: no renderer resolves a token to an icon today, so accepting one
1273
+ * would promise a capability that doesn't exist. Widen the refine's carve-out to `DYNAMIC_TOKEN_REGEX` when a
1274
+ * server-chosen tier icon actually needs it.
1275
+ */
1276
+ source: import_zod19.z.union([import_zod19.z.url(), import_zod19.z.literal(""), import_zod19.z.string().regex(DYNAMIC_TOKEN_REGEX), import_zod19.z.enum(iconNames)]).default(""),
1125
1277
  width: import_zod19.z.number().default(100)
1126
1278
  });
1279
+ var iconNameSet = new Set(iconNames);
1280
+ var isIconName = (source) => iconNameSet.has(source);
1281
+ var CABImageSection = CABImageSectionFields.superRefine(({ category, source }, ctx) => {
1282
+ if (category === "icon" && source !== "" && !isIconName(source))
1283
+ ctx.addIssue({
1284
+ code: "custom",
1285
+ message: "icon-mode source must be an icon name",
1286
+ path: ["source"]
1287
+ });
1288
+ if (category !== "icon" && isIconName(source))
1289
+ ctx.addIssue({
1290
+ code: "custom",
1291
+ message: "source must be a URL or dynamic token unless category is `icon`",
1292
+ path: ["source"]
1293
+ });
1294
+ });
1127
1295
 
1128
1296
  // src/transforms/contentBlockV1/stripContentBlockHtml.ts
1129
1297
  var HTML_COMMENT_RE = /<!--[\s\S]*?-->/g;
@@ -3036,7 +3204,7 @@ var tierLabel = (tier) => {
3036
3204
  if (type === "shipping") return "Free Shipping";
3037
3205
  if (type === "discount")
3038
3206
  return tier.discountType === "fixedAmount" ? "{{discountAmount}} Off" : `${tier.discountAmountFromTotal ?? 0}% Discount`;
3039
- return tier.products?.[0]?.title ?? tier.allProducts?.[0]?.title ?? "Free Product";
3207
+ return void 0;
3040
3208
  };
3041
3209
  var discountOf = (tier) => {
3042
3210
  if (tier.type !== "discount") return void 0;