@rebuy/rebuy 3.16.1 → 3.16.2

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
@@ -1205,7 +1205,15 @@ var CabShopConfig = import_zod2.z.object({
1205
1205
  */
1206
1206
  markets: import_zod2.z.object({ enabled: import_zod2.z.boolean() }).nullish().catch(DRIFTED_MARKETS).default(() => ({ enabled: false })).transform((markets) => markets ?? { enabled: false }),
1207
1207
  monetize: import_zod2.z.object({ publisherKey: import_zod2.z.string().nullable() }).nullish().catch(void 0),
1208
- shopId: import_zod2.z.number().optional().catch(void 0)
1208
+ shopId: import_zod2.z.number().optional().catch(void 0),
1209
+ /**
1210
+ * The merchant's display name ("Gift Basket Store") — the Monetize header copy reads it.
1211
+ * `.catch()` like its siblings: a missing/drifted name degrades the header to the
1212
+ * myshopify-domain slug (the pre-CAB React fallback), never a parse fail. An empty string is a
1213
+ * VALID parse — the slug fallback for `''` (and whitespace/tag-only names) lives in
1214
+ * composeOffer's `||` chain, not here.
1215
+ */
1216
+ shopName: import_zod2.z.string().nullish().catch(void 0)
1209
1217
  });
1210
1218
  var CabUserConfig = import_zod2.z.object({
1211
1219
  shop: CabShopConfig,
package/dist/index.mjs CHANGED
@@ -919,7 +919,15 @@ var CabShopConfig = z2.object({
919
919
  */
920
920
  markets: z2.object({ enabled: z2.boolean() }).nullish().catch(DRIFTED_MARKETS).default(() => ({ enabled: false })).transform((markets) => markets ?? { enabled: false }),
921
921
  monetize: z2.object({ publisherKey: z2.string().nullable() }).nullish().catch(void 0),
922
- shopId: z2.number().optional().catch(void 0)
922
+ shopId: z2.number().optional().catch(void 0),
923
+ /**
924
+ * The merchant's display name ("Gift Basket Store") — the Monetize header copy reads it.
925
+ * `.catch()` like its siblings: a missing/drifted name degrades the header to the
926
+ * myshopify-domain slug (the pre-CAB React fallback), never a parse fail. An empty string is a
927
+ * VALID parse — the slug fallback for `''` (and whitespace/tag-only names) lives in
928
+ * composeOffer's `||` chain, not here.
929
+ */
930
+ shopName: z2.string().nullish().catch(void 0)
923
931
  });
924
932
  var CabUserConfig = z2.object({
925
933
  shop: CabShopConfig,
@@ -52,6 +52,7 @@ export declare const CabShopConfig: z.ZodObject<{
52
52
  publisherKey: z.ZodNullable<z.ZodString>;
53
53
  }, z.core.$strip>>>>;
54
54
  shopId: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
55
+ shopName: z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
55
56
  }, z.core.$strip>;
56
57
  export type CabShopConfig = z.infer<typeof CabShopConfig>;
57
58
  /**
@@ -90,6 +91,7 @@ export declare const CabUserConfig: z.ZodObject<{
90
91
  publisherKey: z.ZodNullable<z.ZodString>;
91
92
  }, z.core.$strip>>>>;
92
93
  shopId: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
94
+ shopName: z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
93
95
  }, z.core.$strip>;
94
96
  smartCart: z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodObject<{
95
97
  components: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -31,11 +31,20 @@ export declare const isTestingRequest: (input: MonetizeInput, isProduction: bool
31
31
  * (total preferred over subtotal). Empty values are omitted.
32
32
  */
33
33
  export declare const buildAdsParams: (input: MonetizeInput, publisherKey: string, supplyKey: string, testing: boolean, userAgent?: string, ipAddress?: string) => Record<string, string>;
34
+ /** The engine offers plus the shop's display name (for the header copy), resolved on the same config read. */
35
+ export type AdsEngineResult = {
36
+ offers: AdsEngineOffer[];
37
+ storeName?: string;
38
+ };
34
39
  /**
35
40
  * Fetch live ad offers from the Rebuy ads engine. Resolves the shop's publisher key server-side (and
36
- * returns `[]` when the shop isn't enrolled — no ads, not an error). A non-prod upstream sends the
41
+ * returns no offers when the shop isn't enrolled — no ads, not an error). A non-prod upstream sends the
37
42
  * staging supply key; a non-prod/editor/QA-email request is flagged `testing` (excluded from billing).
38
43
  * `prefetched` is a caller's already-resolved shop config (inline hydration threads it) — consulted only
39
- * AFTER the gates below, so a gated-out request still costs zero upstream calls either way.
44
+ * AFTER the gates below, so a gated-out request still costs zero upstream calls either way. `storeName`
45
+ * rides along from the same config read so the card composer never needs its own resolution: absent
46
+ * only before the config read (the country/session gates), present once it happens — including the
47
+ * enrolled-but-keyless return, deliberately, so the shape is uniform after the read (with no offers
48
+ * the name simply goes nowhere).
40
49
  */
41
- export declare const fetchAdsEngineOffers: (input: MonetizeInput, ctx: ServerContext, prefetched?: CabUserConfig) => Promise<AdsEngineOffer[]>;
50
+ export declare const fetchAdsEngineOffers: (input: MonetizeInput, ctx: ServerContext, prefetched?: CabUserConfig) => Promise<AdsEngineResult>;
@@ -10,4 +10,4 @@ import { type MonetizeInput } from '../server/shared';
10
10
  * decline pixel (`trackingUrl`) and advances. Parsing through the schema fills defaults and validates
11
11
  * the shape.
12
12
  */
13
- export declare const composeOfferCard: (offer: AdsEngineOffer, input: MonetizeInput) => CABSection | undefined;
13
+ export declare const composeOfferCard: (offer: AdsEngineOffer, input: MonetizeInput, storeName?: string) => CABSection | undefined;
@@ -625,7 +625,15 @@ var CabShopConfig = import_zod6.z.object({
625
625
  */
626
626
  markets: import_zod6.z.object({ enabled: import_zod6.z.boolean() }).nullish().catch(DRIFTED_MARKETS).default(() => ({ enabled: false })).transform((markets) => markets ?? { enabled: false }),
627
627
  monetize: import_zod6.z.object({ publisherKey: import_zod6.z.string().nullable() }).nullish().catch(void 0),
628
- shopId: import_zod6.z.number().optional().catch(void 0)
628
+ shopId: import_zod6.z.number().optional().catch(void 0),
629
+ /**
630
+ * The merchant's display name ("Gift Basket Store") — the Monetize header copy reads it.
631
+ * `.catch()` like its siblings: a missing/drifted name degrades the header to the
632
+ * myshopify-domain slug (the pre-CAB React fallback), never a parse fail. An empty string is a
633
+ * VALID parse — the slug fallback for `''` (and whitespace/tag-only names) lives in
634
+ * composeOffer's `||` chain, not here.
635
+ */
636
+ shopName: import_zod6.z.string().nullish().catch(void 0)
629
637
  });
630
638
  var CabUserConfig = import_zod6.z.object({
631
639
  shop: CabShopConfig,
@@ -4060,11 +4068,12 @@ var buildAdsParams = (input, publisherKey, supplyKey, testing, userAgent, ipAddr
4060
4068
  };
4061
4069
  };
4062
4070
  var fetchAdsEngineOffers = async (input, ctx, prefetched) => {
4063
- if (!input.country || !SUPPORTED_COUNTRIES.has(input.country.toUpperCase())) return [];
4064
- if (!(input.sessionId || input.visitorId)) return [];
4071
+ if (!input.country || !SUPPORTED_COUNTRIES.has(input.country.toUpperCase())) return { offers: [] };
4072
+ if (!(input.sessionId || input.visitorId)) return { offers: [] };
4065
4073
  const { shop } = prefetched ?? await fetchUserConfig({ shop: input.shop }, ctx);
4066
4074
  const publisherKey = shop.monetize?.publisherKey;
4067
- if (!publisherKey) return [];
4075
+ const storeName = shop.shopName ?? void 0;
4076
+ if (!publisherKey) return { offers: [], storeName };
4068
4077
  const isProduction = ctx.host === REBUY_ENGINE_HOST;
4069
4078
  const supplyKey = isProduction ? SUPPLY_KEY.production : SUPPLY_KEY.staging;
4070
4079
  const upstream = await ctx.fetchUpstream(
@@ -4079,7 +4088,7 @@ var fetchAdsEngineOffers = async (input, ctx, prefetched) => {
4079
4088
  ),
4080
4089
  { host: adsHost(ctx.host) }
4081
4090
  );
4082
- return AdsEngineResponse.parse(upstream).offers;
4091
+ return { offers: AdsEngineResponse.parse(upstream).offers, storeName };
4083
4092
  };
4084
4093
 
4085
4094
  // src/server/composeOffer.ts
@@ -4120,19 +4129,22 @@ var styled = (value, { align, bold, color, fontSize, href }) => ({
4120
4129
  },
4121
4130
  sectionType: SectionType.text
4122
4131
  });
4123
- var shopName = (shop) => shop.replace(/\.myshopify\.com$/, "") || "store";
4124
- var headerSections = (input) => [
4132
+ var shopName = (shop, storeName) => storeName?.replace(/<[^>]*>/g, "").trim() || shop.replace(/\.myshopify\.com$/, "") || "store";
4133
+ var headerSections = (input, storeName) => [
4125
4134
  {
4126
4135
  sections: [
4127
4136
  styled("Congratulations!", { bold: true, fontSize: "heading" }),
4128
- styled(`Your ${shopName(input.shop)} purchase unlocked a bonus:`, { bold: true, fontSize: "heading" })
4137
+ styled(`Your ${shopName(input.shop, storeName)} purchase unlocked a bonus:`, {
4138
+ bold: true,
4139
+ fontSize: "heading"
4140
+ })
4129
4141
  ],
4130
4142
  sectionType: SectionType.layout,
4131
4143
  spacing: Spacing.none
4132
4144
  },
4133
4145
  text(input.orderName ? `Order ${input.orderName} Confirmed` : "Order Confirmed")
4134
4146
  ];
4135
- var composeOfferCard = (offer, input) => {
4147
+ var composeOfferCard = (offer, input, storeName) => {
4136
4148
  const copy = {
4137
4149
  sections: [text(offer.headline), smallText(offer.description)],
4138
4150
  sectionType: SectionType.layout,
@@ -4143,7 +4155,7 @@ var composeOfferCard = (offer, input) => {
4143
4155
  border: { style: BorderStyle.base },
4144
4156
  padding: Spacing.tight,
4145
4157
  sections: [
4146
- ...headerSections(input),
4158
+ ...headerSections(input, storeName),
4147
4159
  offer.image_url ? {
4148
4160
  alignment: { horizontal: HorizontalAlignment.start, vertical: VerticalAlignment.middle },
4149
4161
  direction: Direction.grid,
@@ -4221,9 +4233,8 @@ var composeOfferCard = (offer, input) => {
4221
4233
 
4222
4234
  // src/server/monetizeOffers.ts
4223
4235
  var fetchMonetizeOffers = async (input, ctx, prefetched) => {
4224
- const composed = (await fetchAdsEngineOffers(input, ctx, prefetched)).map(
4225
- (offer) => composeOfferCard(offer, input)
4226
- );
4236
+ const { offers: engineOffers, storeName } = await fetchAdsEngineOffers(input, ctx, prefetched);
4237
+ const composed = engineOffers.map((offer) => composeOfferCard(offer, input, storeName));
4227
4238
  const offers = composed.filter((card) => card !== void 0);
4228
4239
  if (offers.length < composed.length)
4229
4240
  ctx.reportDrift?.({
@@ -577,7 +577,15 @@ var CabShopConfig = z6.object({
577
577
  */
578
578
  markets: z6.object({ enabled: z6.boolean() }).nullish().catch(DRIFTED_MARKETS).default(() => ({ enabled: false })).transform((markets) => markets ?? { enabled: false }),
579
579
  monetize: z6.object({ publisherKey: z6.string().nullable() }).nullish().catch(void 0),
580
- shopId: z6.number().optional().catch(void 0)
580
+ shopId: z6.number().optional().catch(void 0),
581
+ /**
582
+ * The merchant's display name ("Gift Basket Store") — the Monetize header copy reads it.
583
+ * `.catch()` like its siblings: a missing/drifted name degrades the header to the
584
+ * myshopify-domain slug (the pre-CAB React fallback), never a parse fail. An empty string is a
585
+ * VALID parse — the slug fallback for `''` (and whitespace/tag-only names) lives in
586
+ * composeOffer's `||` chain, not here.
587
+ */
588
+ shopName: z6.string().nullish().catch(void 0)
581
589
  });
582
590
  var CabUserConfig = z6.object({
583
591
  shop: CabShopConfig,
@@ -4012,11 +4020,12 @@ var buildAdsParams = (input, publisherKey, supplyKey, testing, userAgent, ipAddr
4012
4020
  };
4013
4021
  };
4014
4022
  var fetchAdsEngineOffers = async (input, ctx, prefetched) => {
4015
- if (!input.country || !SUPPORTED_COUNTRIES.has(input.country.toUpperCase())) return [];
4016
- if (!(input.sessionId || input.visitorId)) return [];
4023
+ if (!input.country || !SUPPORTED_COUNTRIES.has(input.country.toUpperCase())) return { offers: [] };
4024
+ if (!(input.sessionId || input.visitorId)) return { offers: [] };
4017
4025
  const { shop } = prefetched ?? await fetchUserConfig({ shop: input.shop }, ctx);
4018
4026
  const publisherKey = shop.monetize?.publisherKey;
4019
- if (!publisherKey) return [];
4027
+ const storeName = shop.shopName ?? void 0;
4028
+ if (!publisherKey) return { offers: [], storeName };
4020
4029
  const isProduction = ctx.host === REBUY_ENGINE_HOST;
4021
4030
  const supplyKey = isProduction ? SUPPLY_KEY.production : SUPPLY_KEY.staging;
4022
4031
  const upstream = await ctx.fetchUpstream(
@@ -4031,7 +4040,7 @@ var fetchAdsEngineOffers = async (input, ctx, prefetched) => {
4031
4040
  ),
4032
4041
  { host: adsHost(ctx.host) }
4033
4042
  );
4034
- return AdsEngineResponse.parse(upstream).offers;
4043
+ return { offers: AdsEngineResponse.parse(upstream).offers, storeName };
4035
4044
  };
4036
4045
 
4037
4046
  // src/server/composeOffer.ts
@@ -4072,19 +4081,22 @@ var styled = (value, { align, bold, color, fontSize, href }) => ({
4072
4081
  },
4073
4082
  sectionType: SectionType.text
4074
4083
  });
4075
- var shopName = (shop) => shop.replace(/\.myshopify\.com$/, "") || "store";
4076
- var headerSections = (input) => [
4084
+ var shopName = (shop, storeName) => storeName?.replace(/<[^>]*>/g, "").trim() || shop.replace(/\.myshopify\.com$/, "") || "store";
4085
+ var headerSections = (input, storeName) => [
4077
4086
  {
4078
4087
  sections: [
4079
4088
  styled("Congratulations!", { bold: true, fontSize: "heading" }),
4080
- styled(`Your ${shopName(input.shop)} purchase unlocked a bonus:`, { bold: true, fontSize: "heading" })
4089
+ styled(`Your ${shopName(input.shop, storeName)} purchase unlocked a bonus:`, {
4090
+ bold: true,
4091
+ fontSize: "heading"
4092
+ })
4081
4093
  ],
4082
4094
  sectionType: SectionType.layout,
4083
4095
  spacing: Spacing.none
4084
4096
  },
4085
4097
  text(input.orderName ? `Order ${input.orderName} Confirmed` : "Order Confirmed")
4086
4098
  ];
4087
- var composeOfferCard = (offer, input) => {
4099
+ var composeOfferCard = (offer, input, storeName) => {
4088
4100
  const copy = {
4089
4101
  sections: [text(offer.headline), smallText(offer.description)],
4090
4102
  sectionType: SectionType.layout,
@@ -4095,7 +4107,7 @@ var composeOfferCard = (offer, input) => {
4095
4107
  border: { style: BorderStyle.base },
4096
4108
  padding: Spacing.tight,
4097
4109
  sections: [
4098
- ...headerSections(input),
4110
+ ...headerSections(input, storeName),
4099
4111
  offer.image_url ? {
4100
4112
  alignment: { horizontal: HorizontalAlignment.start, vertical: VerticalAlignment.middle },
4101
4113
  direction: Direction.grid,
@@ -4173,9 +4185,8 @@ var composeOfferCard = (offer, input) => {
4173
4185
 
4174
4186
  // src/server/monetizeOffers.ts
4175
4187
  var fetchMonetizeOffers = async (input, ctx, prefetched) => {
4176
- const composed = (await fetchAdsEngineOffers(input, ctx, prefetched)).map(
4177
- (offer) => composeOfferCard(offer, input)
4178
- );
4188
+ const { offers: engineOffers, storeName } = await fetchAdsEngineOffers(input, ctx, prefetched);
4189
+ const composed = engineOffers.map((offer) => composeOfferCard(offer, input, storeName));
4179
4190
  const offers = composed.filter((card) => card !== void 0);
4180
4191
  if (offers.length < composed.length)
4181
4192
  ctx.reportDrift?.({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rebuy/rebuy",
3
- "version": "3.16.1",
3
+ "version": "3.16.2",
4
4
  "description": "Shared zod schemas, legacy-to-CAB widget transforms, and server orchestrators for Rebuy's Shopify consumers (rebuy-api, admin-nextjs, rebuy-shopify-extensions)",
5
5
  "license": "MIT",
6
6
  "author": "Rebuy, Inc.",