@rebuy/rebuy 3.12.1 → 3.13.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 +14 -0
- package/dist/index.mjs +14 -0
- package/dist/schema/cabShopConfig.d.ts +2 -0
- package/dist/server/adsEngine.d.ts +4 -1
- package/dist/server/index.cjs +47 -25
- package/dist/server/index.mjs +47 -25
- package/dist/server/monetizeOffers.d.ts +4 -2
- package/dist/server/requestSchemas.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1162,6 +1162,20 @@ var CabShopConfig = import_zod2.z.object({
|
|
|
1162
1162
|
apiKey: import_zod2.z.string(),
|
|
1163
1163
|
/** The shop's billing generation; the smart-cart entitlement gate only fires for `'v6'`. Missing/drift ⇒ `null` (fail open, ungated). */
|
|
1164
1164
|
billingVersion: import_zod2.z.string().nullable().catch(null).default(null),
|
|
1165
|
+
/**
|
|
1166
|
+
* The shop's rotating cache-buster: `onsite_cache_key` internally — a unix timestamp the engine bumps,
|
|
1167
|
+
* and the edge copy of this config purges, on every widget/settings/theme edit — but serialized on the
|
|
1168
|
+
* wire as `cache_key`, which `deepCamelCase` maps to this field (renaming it `onsiteCacheKey` would
|
|
1169
|
+
* sever the mapping silently; the wire-level assertion in `userConfig.test.ts` is what fails loudly).
|
|
1170
|
+
* Threaded onto the widgets/settings read as `cache_key` so the engine marks the response
|
|
1171
|
+
* immutable-cacheable and the `cached.*` edge serves it fresh-by-URL. The engine sends a numeric
|
|
1172
|
+
* string — coerce — but admit only number/string inputs and constrain to a positive integer: a bare
|
|
1173
|
+
* coercion folds `null`/`''`/`false` to `0` and `true` to `1` — "valid" numbers that would go upstream
|
|
1174
|
+
* as a constant never-rotating buster and pin the edge copy permanently stale. A real key is always a
|
|
1175
|
+
* positive int sent as number or string, so everything else lands on `.catch()` and degrades that read
|
|
1176
|
+
* to un-busted (origin-served — slower, never stale), never a parse fail.
|
|
1177
|
+
*/
|
|
1178
|
+
cacheKey: import_zod2.z.union([import_zod2.z.number(), import_zod2.z.string()]).transform((value) => Number(value)).pipe(import_zod2.z.number().int().positive()).optional().catch(void 0),
|
|
1165
1179
|
/**
|
|
1166
1180
|
* The shop's base-currency ISO code (e.g. `'USD'`). CAB derives the shop minor-unit exponent from it
|
|
1167
1181
|
* (`currencyDecimals`) so a Functions-applied fixed discount — whose amount is in shop minor units —
|
package/dist/index.mjs
CHANGED
|
@@ -876,6 +876,20 @@ var CabShopConfig = z2.object({
|
|
|
876
876
|
apiKey: z2.string(),
|
|
877
877
|
/** The shop's billing generation; the smart-cart entitlement gate only fires for `'v6'`. Missing/drift ⇒ `null` (fail open, ungated). */
|
|
878
878
|
billingVersion: z2.string().nullable().catch(null).default(null),
|
|
879
|
+
/**
|
|
880
|
+
* The shop's rotating cache-buster: `onsite_cache_key` internally — a unix timestamp the engine bumps,
|
|
881
|
+
* and the edge copy of this config purges, on every widget/settings/theme edit — but serialized on the
|
|
882
|
+
* wire as `cache_key`, which `deepCamelCase` maps to this field (renaming it `onsiteCacheKey` would
|
|
883
|
+
* sever the mapping silently; the wire-level assertion in `userConfig.test.ts` is what fails loudly).
|
|
884
|
+
* Threaded onto the widgets/settings read as `cache_key` so the engine marks the response
|
|
885
|
+
* immutable-cacheable and the `cached.*` edge serves it fresh-by-URL. The engine sends a numeric
|
|
886
|
+
* string — coerce — but admit only number/string inputs and constrain to a positive integer: a bare
|
|
887
|
+
* coercion folds `null`/`''`/`false` to `0` and `true` to `1` — "valid" numbers that would go upstream
|
|
888
|
+
* as a constant never-rotating buster and pin the edge copy permanently stale. A real key is always a
|
|
889
|
+
* positive int sent as number or string, so everything else lands on `.catch()` and degrades that read
|
|
890
|
+
* to un-busted (origin-served — slower, never stale), never a parse fail.
|
|
891
|
+
*/
|
|
892
|
+
cacheKey: z2.union([z2.number(), z2.string()]).transform((value) => Number(value)).pipe(z2.number().int().positive()).optional().catch(void 0),
|
|
879
893
|
/**
|
|
880
894
|
* The shop's base-currency ISO code (e.g. `'USD'`). CAB derives the shop minor-unit exponent from it
|
|
881
895
|
* (`currencyDecimals`) so a Functions-applied fixed discount — whose amount is in shop minor units —
|
|
@@ -39,6 +39,7 @@ export declare const CabShopConfig: z.ZodObject<{
|
|
|
39
39
|
}, z.core.$strip>>>>>;
|
|
40
40
|
apiKey: z.ZodString;
|
|
41
41
|
billingVersion: z.ZodDefault<z.ZodCatch<z.ZodNullable<z.ZodString>>>;
|
|
42
|
+
cacheKey: z.ZodCatch<z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>, z.ZodNumber>>>;
|
|
42
43
|
currency: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
43
44
|
markets: z.ZodPipe<z.ZodDefault<z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
44
45
|
enabled: z.ZodBoolean;
|
|
@@ -76,6 +77,7 @@ export declare const CabUserConfig: z.ZodObject<{
|
|
|
76
77
|
}, z.core.$strip>>>>>;
|
|
77
78
|
apiKey: z.ZodString;
|
|
78
79
|
billingVersion: z.ZodDefault<z.ZodCatch<z.ZodNullable<z.ZodString>>>;
|
|
80
|
+
cacheKey: z.ZodCatch<z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>, z.ZodNumber>>>;
|
|
79
81
|
currency: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
80
82
|
markets: z.ZodPipe<z.ZodDefault<z.ZodCatch<z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
81
83
|
enabled: z.ZodBoolean;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { type CabUserConfig } from '../schema/cabShopConfig';
|
|
2
3
|
import { type MonetizeInput, type ServerContext } from '../server/shared';
|
|
3
4
|
/**
|
|
4
5
|
* A single ads-engine offer. The `*_url` fields are tracking endpoints the engine returns fully
|
|
@@ -34,5 +35,7 @@ export declare const buildAdsParams: (input: MonetizeInput, publisherKey: string
|
|
|
34
35
|
* Fetch live ad offers from the Rebuy ads engine. Resolves the shop's publisher key server-side (and
|
|
35
36
|
* returns `[]` when the shop isn't enrolled — no ads, not an error). A non-prod upstream sends the
|
|
36
37
|
* staging supply key; a non-prod/editor/QA-email request is flagged `testing` (excluded from billing).
|
|
38
|
+
* `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.
|
|
37
40
|
*/
|
|
38
|
-
export declare const fetchAdsEngineOffers: (input: MonetizeInput, ctx: ServerContext) => Promise<AdsEngineOffer[]>;
|
|
41
|
+
export declare const fetchAdsEngineOffers: (input: MonetizeInput, ctx: ServerContext, prefetched?: CabUserConfig) => Promise<AdsEngineOffer[]>;
|
package/dist/server/index.cjs
CHANGED
|
@@ -582,6 +582,20 @@ var CabShopConfig = import_zod6.z.object({
|
|
|
582
582
|
apiKey: import_zod6.z.string(),
|
|
583
583
|
/** The shop's billing generation; the smart-cart entitlement gate only fires for `'v6'`. Missing/drift ⇒ `null` (fail open, ungated). */
|
|
584
584
|
billingVersion: import_zod6.z.string().nullable().catch(null).default(null),
|
|
585
|
+
/**
|
|
586
|
+
* The shop's rotating cache-buster: `onsite_cache_key` internally — a unix timestamp the engine bumps,
|
|
587
|
+
* and the edge copy of this config purges, on every widget/settings/theme edit — but serialized on the
|
|
588
|
+
* wire as `cache_key`, which `deepCamelCase` maps to this field (renaming it `onsiteCacheKey` would
|
|
589
|
+
* sever the mapping silently; the wire-level assertion in `userConfig.test.ts` is what fails loudly).
|
|
590
|
+
* Threaded onto the widgets/settings read as `cache_key` so the engine marks the response
|
|
591
|
+
* immutable-cacheable and the `cached.*` edge serves it fresh-by-URL. The engine sends a numeric
|
|
592
|
+
* string — coerce — but admit only number/string inputs and constrain to a positive integer: a bare
|
|
593
|
+
* coercion folds `null`/`''`/`false` to `0` and `true` to `1` — "valid" numbers that would go upstream
|
|
594
|
+
* as a constant never-rotating buster and pin the edge copy permanently stale. A real key is always a
|
|
595
|
+
* positive int sent as number or string, so everything else lands on `.catch()` and degrades that read
|
|
596
|
+
* to un-busted (origin-served — slower, never stale), never a parse fail.
|
|
597
|
+
*/
|
|
598
|
+
cacheKey: import_zod6.z.union([import_zod6.z.number(), import_zod6.z.string()]).transform((value) => Number(value)).pipe(import_zod6.z.number().int().positive()).optional().catch(void 0),
|
|
585
599
|
/**
|
|
586
600
|
* The shop's base-currency ISO code (e.g. `'USD'`). CAB derives the shop minor-unit exponent from it
|
|
587
601
|
* (`currencyDecimals`) so a Functions-applied fixed discount — whose amount is in shop minor units —
|
|
@@ -4008,10 +4022,10 @@ var buildAdsParams = (input, publisherKey, supplyKey, testing, userAgent, ipAddr
|
|
|
4008
4022
|
...userAgent && { user_agent: userAgent }
|
|
4009
4023
|
};
|
|
4010
4024
|
};
|
|
4011
|
-
var fetchAdsEngineOffers = async (input, ctx) => {
|
|
4025
|
+
var fetchAdsEngineOffers = async (input, ctx, prefetched) => {
|
|
4012
4026
|
if (!input.country || !SUPPORTED_COUNTRIES.has(input.country.toUpperCase())) return [];
|
|
4013
4027
|
if (!(input.sessionId || input.visitorId)) return [];
|
|
4014
|
-
const { shop } = await fetchUserConfig({ shop: input.shop }, ctx);
|
|
4028
|
+
const { shop } = prefetched ?? await fetchUserConfig({ shop: input.shop }, ctx);
|
|
4015
4029
|
const publisherKey = shop.monetize?.publisherKey;
|
|
4016
4030
|
if (!publisherKey) return [];
|
|
4017
4031
|
const isProduction = ctx.host === REBUY_ENGINE_HOST;
|
|
@@ -4169,8 +4183,10 @@ var composeOfferCard = (offer, input) => {
|
|
|
4169
4183
|
};
|
|
4170
4184
|
|
|
4171
4185
|
// src/server/monetizeOffers.ts
|
|
4172
|
-
var fetchMonetizeOffers = async (input, ctx) => {
|
|
4173
|
-
const composed = (await fetchAdsEngineOffers(input, ctx)).map(
|
|
4186
|
+
var fetchMonetizeOffers = async (input, ctx, prefetched) => {
|
|
4187
|
+
const composed = (await fetchAdsEngineOffers(input, ctx, prefetched)).map(
|
|
4188
|
+
(offer) => composeOfferCard(offer, input)
|
|
4189
|
+
);
|
|
4174
4190
|
const offers = composed.filter((card) => card !== void 0);
|
|
4175
4191
|
if (offers.length < composed.length)
|
|
4176
4192
|
ctx.reportDrift?.({
|
|
@@ -4225,8 +4241,8 @@ var dispatchWidgetTransform = (id, normalized, report) => {
|
|
|
4225
4241
|
if (isOfferV1(normalized)) return convertOfferToV2({ id, name: normalized.name, settings: normalized });
|
|
4226
4242
|
return normalized;
|
|
4227
4243
|
};
|
|
4228
|
-
var fetchProgressBarContext = async (shop, ctx) => {
|
|
4229
|
-
const config = await fetchUserConfig({ shop }, ctx).catch(() => void 0);
|
|
4244
|
+
var fetchProgressBarContext = async (shop, ctx, prefetched) => {
|
|
4245
|
+
const config = prefetched === void 0 ? await fetchUserConfig({ shop }, ctx).catch(() => void 0) : prefetched;
|
|
4230
4246
|
if (!config) return {};
|
|
4231
4247
|
if (config.shop.billingVersion === "v6" && config.shop.activePackages.some((pkg) => pkg.shortName === "")) {
|
|
4232
4248
|
ctx.reportDrift?.({
|
|
@@ -4265,7 +4281,7 @@ var findMonetizeMarker = (section) => {
|
|
|
4265
4281
|
}
|
|
4266
4282
|
return void 0;
|
|
4267
4283
|
};
|
|
4268
|
-
var hydrateMonetizeMarkers = async (converted, input, ctx) => {
|
|
4284
|
+
var hydrateMonetizeMarkers = async (converted, input, ctx, config) => {
|
|
4269
4285
|
if (!input.monetize || !isCABTree(converted)) return;
|
|
4270
4286
|
const first = findMonetizeMarker(converted);
|
|
4271
4287
|
if (!first) return;
|
|
@@ -4277,7 +4293,8 @@ var hydrateMonetizeMarkers = async (converted, input, ctx) => {
|
|
|
4277
4293
|
shop: input.shop,
|
|
4278
4294
|
visitorId: input.monetize.visitorId || input.visitorId
|
|
4279
4295
|
},
|
|
4280
|
-
ctx
|
|
4296
|
+
ctx,
|
|
4297
|
+
config ?? void 0
|
|
4281
4298
|
);
|
|
4282
4299
|
first.offers = offers;
|
|
4283
4300
|
} catch (err) {
|
|
@@ -4287,7 +4304,7 @@ var hydrateMonetizeMarkers = async (converted, input, ctx) => {
|
|
|
4287
4304
|
});
|
|
4288
4305
|
}
|
|
4289
4306
|
};
|
|
4290
|
-
var fetchAndConvert = async (id, input, ctx) => {
|
|
4307
|
+
var fetchAndConvert = async (id, input, ctx, config) => {
|
|
4291
4308
|
const params = { id: String(id), shop: input.shop };
|
|
4292
4309
|
if (input.cacheKey != null) params.cache_key = String(input.cacheKey);
|
|
4293
4310
|
if (input.key) params.key = input.key;
|
|
@@ -4304,34 +4321,32 @@ var fetchAndConvert = async (id, input, ctx) => {
|
|
|
4304
4321
|
if (isMissingUpstreamPayload(data)) throw new NotFoundError(`Widget not found: ${id}`);
|
|
4305
4322
|
const normalized = convertNumericObjects(deepCamelCase(data));
|
|
4306
4323
|
if (isProgressBarV1(normalized) && normalized.barSettings.barType === "smart-cart") {
|
|
4307
|
-
const { bars, progressColor } = await fetchProgressBarContext(input.shop, ctx);
|
|
4324
|
+
const { bars, progressColor } = await fetchProgressBarContext(input.shop, ctx, config);
|
|
4308
4325
|
return convertSmartCartProgressBarToV2({ bars: bars ?? [], id, progressColor, settings: normalized });
|
|
4309
4326
|
}
|
|
4310
4327
|
if (isConvertibleProgressBarV1(normalized)) {
|
|
4311
|
-
const { progressColor } = await fetchProgressBarContext(input.shop, ctx);
|
|
4328
|
+
const { progressColor } = await fetchProgressBarContext(input.shop, ctx, config);
|
|
4312
4329
|
return convertProgressBarToV2({ id, progressColor, settings: normalized });
|
|
4313
4330
|
}
|
|
4314
4331
|
const converted = dispatchWidgetTransform(id, normalized, ctx.reportDrift);
|
|
4315
4332
|
const colorless = isCABRootSection(normalized) ? colorlessProgressBars(converted) : [];
|
|
4316
4333
|
if (colorless.length > 0) {
|
|
4317
|
-
const { progressColor: color } = await fetchProgressBarContext(input.shop, ctx);
|
|
4334
|
+
const { progressColor: color } = await fetchProgressBarContext(input.shop, ctx, config);
|
|
4318
4335
|
if (color) for (const bar of colorless) bar.progressColor = color;
|
|
4319
4336
|
}
|
|
4320
4337
|
return converted;
|
|
4321
4338
|
};
|
|
4322
|
-
var resolveWidgetExperiment =
|
|
4323
|
-
if (!input.visitorId) return void 0;
|
|
4324
|
-
try {
|
|
4325
|
-
const { shop } = await fetchUserConfig({ shop: input.shop }, ctx);
|
|
4326
|
-
return resolveExperiment(shop.activeExperiments, input.id, input.visitorId);
|
|
4327
|
-
} catch {
|
|
4328
|
-
return void 0;
|
|
4329
|
-
}
|
|
4330
|
-
};
|
|
4339
|
+
var resolveWidgetExperiment = (input, config) => input.visitorId && config ? resolveExperiment(config.shop.activeExperiments, input.id, input.visitorId) : void 0;
|
|
4331
4340
|
var convertWidgetSettings = async (input, ctx) => {
|
|
4332
|
-
const
|
|
4333
|
-
const
|
|
4334
|
-
|
|
4341
|
+
const config = input.cacheKey != null && !input.visitorId ? void 0 : await fetchUserConfig({ shop: input.shop }, ctx).catch(() => null);
|
|
4342
|
+
const experiment = resolveWidgetExperiment(input, config);
|
|
4343
|
+
const result = await fetchAndConvert(
|
|
4344
|
+
experiment?.elementId ?? input.id,
|
|
4345
|
+
{ ...input, cacheKey: input.cacheKey ?? config?.shop.cacheKey },
|
|
4346
|
+
ctx,
|
|
4347
|
+
config
|
|
4348
|
+
);
|
|
4349
|
+
await hydrateMonetizeMarkers(result, input, ctx, config);
|
|
4335
4350
|
return experiment && isCABTree(result) ? { ...result, experiment } : result;
|
|
4336
4351
|
};
|
|
4337
4352
|
|
|
@@ -4675,7 +4690,14 @@ var MonetizeInputSchema = import_zod29.z.object({
|
|
|
4675
4690
|
zipCode: import_zod29.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
|
|
4676
4691
|
});
|
|
4677
4692
|
var WidgetSettingsInputSchema = import_zod29.z.object({
|
|
4678
|
-
|
|
4693
|
+
/**
|
|
4694
|
+
* Same domain as `CabShopConfig.cacheKey`, for the same reason: this side WINS the orchestrator's
|
|
4695
|
+
* `input.cacheKey ?? config.shop.cacheKey` (and an explicit value skips the config read entirely), so
|
|
4696
|
+
* an unconstrained `0`/negative/float here would go upstream as a constant never-rotating `cache_key`
|
|
4697
|
+
* and pin the edge copy permanently stale. `.catch(undefined)` because a bogus buster should degrade
|
|
4698
|
+
* the read to un-busted, never 400 a widget render.
|
|
4699
|
+
*/
|
|
4700
|
+
cacheKey: import_zod29.z.number().int().positive().optional().catch(void 0),
|
|
4679
4701
|
id: import_zod29.z.number(),
|
|
4680
4702
|
key: import_zod29.z.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4681
4703
|
/**
|
package/dist/server/index.mjs
CHANGED
|
@@ -534,6 +534,20 @@ var CabShopConfig = z6.object({
|
|
|
534
534
|
apiKey: z6.string(),
|
|
535
535
|
/** The shop's billing generation; the smart-cart entitlement gate only fires for `'v6'`. Missing/drift ⇒ `null` (fail open, ungated). */
|
|
536
536
|
billingVersion: z6.string().nullable().catch(null).default(null),
|
|
537
|
+
/**
|
|
538
|
+
* The shop's rotating cache-buster: `onsite_cache_key` internally — a unix timestamp the engine bumps,
|
|
539
|
+
* and the edge copy of this config purges, on every widget/settings/theme edit — but serialized on the
|
|
540
|
+
* wire as `cache_key`, which `deepCamelCase` maps to this field (renaming it `onsiteCacheKey` would
|
|
541
|
+
* sever the mapping silently; the wire-level assertion in `userConfig.test.ts` is what fails loudly).
|
|
542
|
+
* Threaded onto the widgets/settings read as `cache_key` so the engine marks the response
|
|
543
|
+
* immutable-cacheable and the `cached.*` edge serves it fresh-by-URL. The engine sends a numeric
|
|
544
|
+
* string — coerce — but admit only number/string inputs and constrain to a positive integer: a bare
|
|
545
|
+
* coercion folds `null`/`''`/`false` to `0` and `true` to `1` — "valid" numbers that would go upstream
|
|
546
|
+
* as a constant never-rotating buster and pin the edge copy permanently stale. A real key is always a
|
|
547
|
+
* positive int sent as number or string, so everything else lands on `.catch()` and degrades that read
|
|
548
|
+
* to un-busted (origin-served — slower, never stale), never a parse fail.
|
|
549
|
+
*/
|
|
550
|
+
cacheKey: z6.union([z6.number(), z6.string()]).transform((value) => Number(value)).pipe(z6.number().int().positive()).optional().catch(void 0),
|
|
537
551
|
/**
|
|
538
552
|
* The shop's base-currency ISO code (e.g. `'USD'`). CAB derives the shop minor-unit exponent from it
|
|
539
553
|
* (`currencyDecimals`) so a Functions-applied fixed discount — whose amount is in shop minor units —
|
|
@@ -3960,10 +3974,10 @@ var buildAdsParams = (input, publisherKey, supplyKey, testing, userAgent, ipAddr
|
|
|
3960
3974
|
...userAgent && { user_agent: userAgent }
|
|
3961
3975
|
};
|
|
3962
3976
|
};
|
|
3963
|
-
var fetchAdsEngineOffers = async (input, ctx) => {
|
|
3977
|
+
var fetchAdsEngineOffers = async (input, ctx, prefetched) => {
|
|
3964
3978
|
if (!input.country || !SUPPORTED_COUNTRIES.has(input.country.toUpperCase())) return [];
|
|
3965
3979
|
if (!(input.sessionId || input.visitorId)) return [];
|
|
3966
|
-
const { shop } = await fetchUserConfig({ shop: input.shop }, ctx);
|
|
3980
|
+
const { shop } = prefetched ?? await fetchUserConfig({ shop: input.shop }, ctx);
|
|
3967
3981
|
const publisherKey = shop.monetize?.publisherKey;
|
|
3968
3982
|
if (!publisherKey) return [];
|
|
3969
3983
|
const isProduction = ctx.host === REBUY_ENGINE_HOST;
|
|
@@ -4121,8 +4135,10 @@ var composeOfferCard = (offer, input) => {
|
|
|
4121
4135
|
};
|
|
4122
4136
|
|
|
4123
4137
|
// src/server/monetizeOffers.ts
|
|
4124
|
-
var fetchMonetizeOffers = async (input, ctx) => {
|
|
4125
|
-
const composed = (await fetchAdsEngineOffers(input, ctx)).map(
|
|
4138
|
+
var fetchMonetizeOffers = async (input, ctx, prefetched) => {
|
|
4139
|
+
const composed = (await fetchAdsEngineOffers(input, ctx, prefetched)).map(
|
|
4140
|
+
(offer) => composeOfferCard(offer, input)
|
|
4141
|
+
);
|
|
4126
4142
|
const offers = composed.filter((card) => card !== void 0);
|
|
4127
4143
|
if (offers.length < composed.length)
|
|
4128
4144
|
ctx.reportDrift?.({
|
|
@@ -4177,8 +4193,8 @@ var dispatchWidgetTransform = (id, normalized, report) => {
|
|
|
4177
4193
|
if (isOfferV1(normalized)) return convertOfferToV2({ id, name: normalized.name, settings: normalized });
|
|
4178
4194
|
return normalized;
|
|
4179
4195
|
};
|
|
4180
|
-
var fetchProgressBarContext = async (shop, ctx) => {
|
|
4181
|
-
const config = await fetchUserConfig({ shop }, ctx).catch(() => void 0);
|
|
4196
|
+
var fetchProgressBarContext = async (shop, ctx, prefetched) => {
|
|
4197
|
+
const config = prefetched === void 0 ? await fetchUserConfig({ shop }, ctx).catch(() => void 0) : prefetched;
|
|
4182
4198
|
if (!config) return {};
|
|
4183
4199
|
if (config.shop.billingVersion === "v6" && config.shop.activePackages.some((pkg) => pkg.shortName === "")) {
|
|
4184
4200
|
ctx.reportDrift?.({
|
|
@@ -4217,7 +4233,7 @@ var findMonetizeMarker = (section) => {
|
|
|
4217
4233
|
}
|
|
4218
4234
|
return void 0;
|
|
4219
4235
|
};
|
|
4220
|
-
var hydrateMonetizeMarkers = async (converted, input, ctx) => {
|
|
4236
|
+
var hydrateMonetizeMarkers = async (converted, input, ctx, config) => {
|
|
4221
4237
|
if (!input.monetize || !isCABTree(converted)) return;
|
|
4222
4238
|
const first = findMonetizeMarker(converted);
|
|
4223
4239
|
if (!first) return;
|
|
@@ -4229,7 +4245,8 @@ var hydrateMonetizeMarkers = async (converted, input, ctx) => {
|
|
|
4229
4245
|
shop: input.shop,
|
|
4230
4246
|
visitorId: input.monetize.visitorId || input.visitorId
|
|
4231
4247
|
},
|
|
4232
|
-
ctx
|
|
4248
|
+
ctx,
|
|
4249
|
+
config ?? void 0
|
|
4233
4250
|
);
|
|
4234
4251
|
first.offers = offers;
|
|
4235
4252
|
} catch (err) {
|
|
@@ -4239,7 +4256,7 @@ var hydrateMonetizeMarkers = async (converted, input, ctx) => {
|
|
|
4239
4256
|
});
|
|
4240
4257
|
}
|
|
4241
4258
|
};
|
|
4242
|
-
var fetchAndConvert = async (id, input, ctx) => {
|
|
4259
|
+
var fetchAndConvert = async (id, input, ctx, config) => {
|
|
4243
4260
|
const params = { id: String(id), shop: input.shop };
|
|
4244
4261
|
if (input.cacheKey != null) params.cache_key = String(input.cacheKey);
|
|
4245
4262
|
if (input.key) params.key = input.key;
|
|
@@ -4256,34 +4273,32 @@ var fetchAndConvert = async (id, input, ctx) => {
|
|
|
4256
4273
|
if (isMissingUpstreamPayload(data)) throw new NotFoundError(`Widget not found: ${id}`);
|
|
4257
4274
|
const normalized = convertNumericObjects(deepCamelCase(data));
|
|
4258
4275
|
if (isProgressBarV1(normalized) && normalized.barSettings.barType === "smart-cart") {
|
|
4259
|
-
const { bars, progressColor } = await fetchProgressBarContext(input.shop, ctx);
|
|
4276
|
+
const { bars, progressColor } = await fetchProgressBarContext(input.shop, ctx, config);
|
|
4260
4277
|
return convertSmartCartProgressBarToV2({ bars: bars ?? [], id, progressColor, settings: normalized });
|
|
4261
4278
|
}
|
|
4262
4279
|
if (isConvertibleProgressBarV1(normalized)) {
|
|
4263
|
-
const { progressColor } = await fetchProgressBarContext(input.shop, ctx);
|
|
4280
|
+
const { progressColor } = await fetchProgressBarContext(input.shop, ctx, config);
|
|
4264
4281
|
return convertProgressBarToV2({ id, progressColor, settings: normalized });
|
|
4265
4282
|
}
|
|
4266
4283
|
const converted = dispatchWidgetTransform(id, normalized, ctx.reportDrift);
|
|
4267
4284
|
const colorless = isCABRootSection(normalized) ? colorlessProgressBars(converted) : [];
|
|
4268
4285
|
if (colorless.length > 0) {
|
|
4269
|
-
const { progressColor: color } = await fetchProgressBarContext(input.shop, ctx);
|
|
4286
|
+
const { progressColor: color } = await fetchProgressBarContext(input.shop, ctx, config);
|
|
4270
4287
|
if (color) for (const bar of colorless) bar.progressColor = color;
|
|
4271
4288
|
}
|
|
4272
4289
|
return converted;
|
|
4273
4290
|
};
|
|
4274
|
-
var resolveWidgetExperiment =
|
|
4275
|
-
if (!input.visitorId) return void 0;
|
|
4276
|
-
try {
|
|
4277
|
-
const { shop } = await fetchUserConfig({ shop: input.shop }, ctx);
|
|
4278
|
-
return resolveExperiment(shop.activeExperiments, input.id, input.visitorId);
|
|
4279
|
-
} catch {
|
|
4280
|
-
return void 0;
|
|
4281
|
-
}
|
|
4282
|
-
};
|
|
4291
|
+
var resolveWidgetExperiment = (input, config) => input.visitorId && config ? resolveExperiment(config.shop.activeExperiments, input.id, input.visitorId) : void 0;
|
|
4283
4292
|
var convertWidgetSettings = async (input, ctx) => {
|
|
4284
|
-
const
|
|
4285
|
-
const
|
|
4286
|
-
|
|
4293
|
+
const config = input.cacheKey != null && !input.visitorId ? void 0 : await fetchUserConfig({ shop: input.shop }, ctx).catch(() => null);
|
|
4294
|
+
const experiment = resolveWidgetExperiment(input, config);
|
|
4295
|
+
const result = await fetchAndConvert(
|
|
4296
|
+
experiment?.elementId ?? input.id,
|
|
4297
|
+
{ ...input, cacheKey: input.cacheKey ?? config?.shop.cacheKey },
|
|
4298
|
+
ctx,
|
|
4299
|
+
config
|
|
4300
|
+
);
|
|
4301
|
+
await hydrateMonetizeMarkers(result, input, ctx, config);
|
|
4287
4302
|
return experiment && isCABTree(result) ? { ...result, experiment } : result;
|
|
4288
4303
|
};
|
|
4289
4304
|
|
|
@@ -4627,7 +4642,14 @@ var MonetizeInputSchema = z29.object({
|
|
|
4627
4642
|
zipCode: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
|
|
4628
4643
|
});
|
|
4629
4644
|
var WidgetSettingsInputSchema = z29.object({
|
|
4630
|
-
|
|
4645
|
+
/**
|
|
4646
|
+
* Same domain as `CabShopConfig.cacheKey`, for the same reason: this side WINS the orchestrator's
|
|
4647
|
+
* `input.cacheKey ?? config.shop.cacheKey` (and an explicit value skips the config read entirely), so
|
|
4648
|
+
* an unconstrained `0`/negative/float here would go upstream as a constant never-rotating `cache_key`
|
|
4649
|
+
* and pin the edge copy permanently stale. `.catch(undefined)` because a bogus buster should degrade
|
|
4650
|
+
* the read to un-busted, never 400 a widget render.
|
|
4651
|
+
*/
|
|
4652
|
+
cacheKey: z29.number().int().positive().optional().catch(void 0),
|
|
4631
4653
|
id: z29.number(),
|
|
4632
4654
|
key: z29.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4633
4655
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type CabUserConfig } from '../schema/cabShopConfig';
|
|
1
2
|
import { type CABSection } from '../schema/widgets/checkout-and-beyond';
|
|
2
3
|
import { type MonetizeInput, type ServerContext } from '../server/shared';
|
|
3
4
|
export type MonetizeOffers = {
|
|
@@ -8,6 +9,7 @@ export type MonetizeOffers = {
|
|
|
8
9
|
* offer card the extension renders directly. The header chrome (experiment copy + order-confirmed
|
|
9
10
|
* line) is baked inside every card — inside its border, as React draws it — so the response no longer
|
|
10
11
|
* carries a separate `header` (older extension builds read it as optional and render nothing). Empty
|
|
11
|
-
* when the shop isn't ad-enrolled.
|
|
12
|
+
* when the shop isn't ad-enrolled. `prefetched` is a caller's already-resolved shop config, passed
|
|
13
|
+
* through to the ads layer's publisher-key lookup so inline hydration doesn't refetch it.
|
|
12
14
|
*/
|
|
13
|
-
export declare const fetchMonetizeOffers: (input: MonetizeInput, ctx: ServerContext) => Promise<MonetizeOffers>;
|
|
15
|
+
export declare const fetchMonetizeOffers: (input: MonetizeInput, ctx: ServerContext, prefetched?: CabUserConfig) => Promise<MonetizeOffers>;
|
|
@@ -233,7 +233,7 @@ export declare const MonetizeInputSchema: z.ZodObject<{
|
|
|
233
233
|
}, z.core.$strip>;
|
|
234
234
|
/** Input for `convertWidgetSettings`. */
|
|
235
235
|
export declare const WidgetSettingsInputSchema: z.ZodObject<{
|
|
236
|
-
cacheKey: z.ZodOptional<z.ZodNumber
|
|
236
|
+
cacheKey: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
|
|
237
237
|
id: z.ZodNumber;
|
|
238
238
|
key: z.ZodOptional<z.ZodString>;
|
|
239
239
|
monetize: z.ZodOptional<z.ZodObject<{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebuy/rebuy",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.13.0",
|
|
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.",
|