@rebuy/rebuy 3.16.3 → 3.17.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/gwp/index.cjs +4 -0
- package/dist/gwp/index.mjs +4 -0
- package/dist/gwp/types.d.ts +27 -5
- package/dist/server/giftValidation.d.ts +17 -19
- package/dist/server/giftWidgets.d.ts +37 -0
- package/dist/server/index.cjs +215 -100
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.mjs +215 -100
- package/dist/server/requestSchemas.d.ts +34 -1
- package/dist/server/sgwpCapacity.d.ts +25 -0
- package/dist/server/sgwpValidation.d.ts +19 -0
- package/dist/server/shared.d.ts +5 -4
- package/dist/server/shopSubtotal.d.ts +25 -0
- package/package.json +1 -1
package/dist/server/index.d.ts
CHANGED
|
@@ -14,5 +14,5 @@ export { fetchUserConfig } from '../server/userConfig';
|
|
|
14
14
|
export { validateGifts } from '../server/giftValidation';
|
|
15
15
|
export { fetchMonetizeOffers, type MonetizeOffers } from '../server/monetizeOffers';
|
|
16
16
|
export { postAnalyticsEvents, translateAnalyticsEvent, type CabAnalyticsEventName } from '../server/analytics';
|
|
17
|
-
export { AnalyticsEventInputSchema, AnalyticsInputSchema, CartInputSchema, CartLineInputSchema, DataSourceInputSchema, GiftInputSchema, GiftValidationInputSchema, MonetizeInputSchema, MonetizeTransactionItemSchema, REQUEST_BOUNDS, UserConfigInputSchema, WidgetSettingsInputSchema, } from '../server/requestSchemas';
|
|
18
|
-
export { NotFoundError, REBUY_ENGINE_HOST, UpstreamError, type AnalyticsEventInput, type AnalyticsInput, type CartInput, type CartLineInput, type DataSourceInput, type GiftInput, type GiftValidationInput, type MonetizeInput, type MonetizeTransactionItem, type ServerContext, type ServerDrift, type UpstreamFetch, type UserConfigInput, type WidgetSettingsInput, } from '../server/shared';
|
|
17
|
+
export { AnalyticsEventInputSchema, AnalyticsInputSchema, CartInputSchema, CartLineInputSchema, DataSourceInputSchema, GiftAdjustmentSchema, GiftInputSchema, GiftValidationInputSchema, GiftValidationResponseSchema, MonetizeInputSchema, MonetizeTransactionItemSchema, REQUEST_BOUNDS, UserConfigInputSchema, WidgetSettingsInputSchema, } from '../server/requestSchemas';
|
|
18
|
+
export { NotFoundError, REBUY_ENGINE_HOST, UpstreamError, type AnalyticsEventInput, type AnalyticsInput, type CartInput, type CartLineInput, type DataSourceInput, type GiftAdjustment, type GiftInput, type GiftValidationInput, type GiftValidationResponse, type MonetizeInput, type MonetizeTransactionItem, type ServerContext, type ServerDrift, type UpstreamFetch, type UserConfigInput, type WidgetSettingsInput, } from '../server/shared';
|
package/dist/server/index.mjs
CHANGED
|
@@ -23,6 +23,9 @@ var isDefinitiveRuleAnswer = (metadata) => metadata != null && (metadata.matched
|
|
|
23
23
|
var hasLostDiscount = (gift) => !gift.discounted && gift.cost > 0;
|
|
24
24
|
var shouldRemoveGift = (gift, validIds) => !validIds.has(gift.productId) || hasLostDiscount(gift);
|
|
25
25
|
|
|
26
|
+
// src/gwp/types.ts
|
|
27
|
+
var GIFT_KINDS = ["gwp", "sgwp"];
|
|
28
|
+
|
|
26
29
|
// src/schema/metadata.ts
|
|
27
30
|
import { z as z2 } from "zod";
|
|
28
31
|
|
|
@@ -382,6 +385,14 @@ var NotFoundError = class extends Error {
|
|
|
382
385
|
}
|
|
383
386
|
};
|
|
384
387
|
|
|
388
|
+
// src/server/shopSubtotal.ts
|
|
389
|
+
var shopCurrencyRate = (cart) => {
|
|
390
|
+
const rate = cart.currencyRate ?? 1;
|
|
391
|
+
return Number.isFinite(rate) && rate > 0 ? rate : 1;
|
|
392
|
+
};
|
|
393
|
+
var shopSubtotalCents = (cart) => Math.round((cart.subtotal - (cart.discountTotal ?? 0)) / shopCurrencyRate(cart));
|
|
394
|
+
var toShopCents = (majorPresentment, rate) => Math.round(majorPresentment * 100 / rate);
|
|
395
|
+
|
|
385
396
|
// src/schema/cabShopConfig.ts
|
|
386
397
|
import { z as z6 } from "zod";
|
|
387
398
|
|
|
@@ -3875,9 +3886,7 @@ var buildEngineParams = (input, key) => {
|
|
|
3875
3886
|
variant_id: variantId
|
|
3876
3887
|
}));
|
|
3877
3888
|
const itemCount = cart.items.reduce((total, { quantity }) => total + quantity, 0);
|
|
3878
|
-
const
|
|
3879
|
-
const rate = Number.isFinite(currencyRate) && currencyRate > 0 ? currencyRate : 1;
|
|
3880
|
-
const subtotal = Math.round((cart.subtotal - (cart.discountTotal ?? 0)) / rate);
|
|
3889
|
+
const subtotal = shopSubtotalCents(cart);
|
|
3881
3890
|
return {
|
|
3882
3891
|
cart: {
|
|
3883
3892
|
attributes: encodeAttributes(cart.attributes),
|
|
@@ -4350,26 +4359,92 @@ var convertWidgetSettings = async (input, ctx) => {
|
|
|
4350
4359
|
return experiment && isCABTree(result) ? { ...result, experiment } : result;
|
|
4351
4360
|
};
|
|
4352
4361
|
|
|
4353
|
-
// src/server/
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4362
|
+
// src/server/giftWidgets.ts
|
|
4363
|
+
import { z as z29 } from "zod";
|
|
4364
|
+
var SettingsNumber = z29.union([
|
|
4365
|
+
z29.number(),
|
|
4366
|
+
z29.string().trim().regex(/^-?\d+(\.\d+)?$/)
|
|
4367
|
+
]).pipe(z29.coerce.number());
|
|
4368
|
+
var SgwpMilestoneSchema = z29.object({
|
|
4369
|
+
selectable_product_quantity: SettingsNumber.pipe(z29.number().int().nonnegative()),
|
|
4370
|
+
unlock_price: SettingsNumber
|
|
4371
|
+
});
|
|
4372
|
+
var fetchGiftWidgetSettings = async (widgetId, shop, ctx) => unwrapData(await ctx.fetchUpstream("/api/v1/widgets/settings", { id: String(widgetId), shop }, { host: ctx.host }));
|
|
4373
|
+
var readDataSourcePath = (settings) => {
|
|
4374
|
+
const endpoint = deepCamelCase(settings)?.endpoint;
|
|
4358
4375
|
return typeof endpoint === "string" && endpoint ? endpoint : void 0;
|
|
4359
4376
|
};
|
|
4360
|
-
var
|
|
4377
|
+
var readMilestones = (settings, report) => {
|
|
4378
|
+
const raw = settings && typeof settings === "object" ? settings.milestones : void 0;
|
|
4379
|
+
if (raw == null) return [];
|
|
4380
|
+
const parsed = z29.array(SgwpMilestoneSchema).safeParse(raw);
|
|
4381
|
+
if (parsed.success) return parsed.data;
|
|
4382
|
+
report?.({
|
|
4383
|
+
detail: [
|
|
4384
|
+
"selectable-gift milestones unreadable",
|
|
4385
|
+
...parsed.error.issues.slice(0, 1).map((issue) => [issue.path.join("."), issue.message].filter(Boolean).join(": "))
|
|
4386
|
+
].join(": "),
|
|
4387
|
+
kind: "giftMilestones"
|
|
4388
|
+
});
|
|
4389
|
+
return [];
|
|
4390
|
+
};
|
|
4391
|
+
var groupGiftsByWidget = (gifts, kind) => {
|
|
4361
4392
|
const byWidget = /* @__PURE__ */ new Map();
|
|
4362
4393
|
for (const gift of gifts) {
|
|
4394
|
+
if (gift.kind !== kind) continue;
|
|
4363
4395
|
byWidget.set(gift.widgetId, [...byWidget.get(gift.widgetId) ?? [], gift]);
|
|
4364
4396
|
}
|
|
4365
4397
|
return byWidget;
|
|
4366
4398
|
};
|
|
4367
|
-
|
|
4399
|
+
|
|
4400
|
+
// src/server/sgwpCapacity.ts
|
|
4401
|
+
var sgwpQualifyingSubtotalCents = (cart, gifts) => {
|
|
4402
|
+
const giftMajor = gifts.filter((gift) => gift.kind === "sgwp").reduce((total, gift) => total + gift.cost, 0);
|
|
4403
|
+
return shopSubtotalCents(cart) - toShopCents(giftMajor, shopCurrencyRate(cart));
|
|
4404
|
+
};
|
|
4405
|
+
var unlockedCapacity = (milestones, subtotalCents) => milestones.reduce(
|
|
4406
|
+
(capacity, milestone) => Math.round(milestone.unlock_price * 100) <= subtotalCents ? capacity + milestone.selectable_product_quantity : capacity,
|
|
4407
|
+
0
|
|
4408
|
+
);
|
|
4409
|
+
|
|
4410
|
+
// src/server/sgwpValidation.ts
|
|
4411
|
+
var computeSgwpAdjustments = (gifts, capacity) => {
|
|
4412
|
+
let surplus = gifts.reduce((units, gift) => units + gift.quantity, 0) - capacity;
|
|
4413
|
+
const adjust = [];
|
|
4414
|
+
for (const gift of gifts) {
|
|
4415
|
+
if (surplus <= 0) break;
|
|
4416
|
+
const trimmed = Math.min(gift.quantity, surplus);
|
|
4417
|
+
adjust.push({ lineId: gift.lineId, quantity: gift.quantity - trimmed });
|
|
4418
|
+
surplus -= trimmed;
|
|
4419
|
+
}
|
|
4420
|
+
return adjust;
|
|
4421
|
+
};
|
|
4422
|
+
var validateSelectableGifts = async (input, ctx) => {
|
|
4423
|
+
const byWidget = groupGiftsByWidget(input.gifts, "sgwp");
|
|
4424
|
+
if (byWidget.size === 0) return [];
|
|
4425
|
+
const subtotalCents = sgwpQualifyingSubtotalCents(input.cart, input.gifts);
|
|
4368
4426
|
const perWidget = await Promise.all(
|
|
4369
|
-
[...
|
|
4427
|
+
[...byWidget].map(async ([widgetId, gifts]) => {
|
|
4428
|
+
try {
|
|
4429
|
+
const settings = await fetchGiftWidgetSettings(widgetId, input.shop, ctx);
|
|
4430
|
+
const milestones = readMilestones(settings, ctx.reportDrift);
|
|
4431
|
+
if (milestones.length === 0) return [];
|
|
4432
|
+
return computeSgwpAdjustments(gifts, unlockedCapacity(milestones, subtotalCents));
|
|
4433
|
+
} catch {
|
|
4434
|
+
return [];
|
|
4435
|
+
}
|
|
4436
|
+
})
|
|
4437
|
+
);
|
|
4438
|
+
return perWidget.flat();
|
|
4439
|
+
};
|
|
4440
|
+
|
|
4441
|
+
// src/server/giftValidation.ts
|
|
4442
|
+
var validateGwpGifts = async (input, ctx) => {
|
|
4443
|
+
const perWidget = await Promise.all(
|
|
4444
|
+
[...groupGiftsByWidget(input.gifts, "gwp")].map(async ([widgetId, gifts]) => {
|
|
4370
4445
|
const discountLost = gifts.filter(hasLostDiscount).map((gift) => gift.lineId);
|
|
4371
4446
|
try {
|
|
4372
|
-
const dataSourcePath = await
|
|
4447
|
+
const dataSourcePath = readDataSourcePath(await fetchGiftWidgetSettings(widgetId, input.shop, ctx));
|
|
4373
4448
|
if (!dataSourcePath) return discountLost;
|
|
4374
4449
|
const { metadata } = await fetchDataSourceResults(
|
|
4375
4450
|
{
|
|
@@ -4402,7 +4477,17 @@ var validateGifts = async (input, ctx) => {
|
|
|
4402
4477
|
}
|
|
4403
4478
|
})
|
|
4404
4479
|
);
|
|
4405
|
-
return
|
|
4480
|
+
return perWidget.flat();
|
|
4481
|
+
};
|
|
4482
|
+
var validateGifts = async (input, ctx) => {
|
|
4483
|
+
const [remove, adjust] = await Promise.all([validateGwpGifts(input, ctx), validateSelectableGifts(input, ctx)]);
|
|
4484
|
+
const removed = new Set(remove);
|
|
4485
|
+
const targets = /* @__PURE__ */ new Map();
|
|
4486
|
+
for (const { lineId, quantity } of adjust) {
|
|
4487
|
+
if (removed.has(lineId)) continue;
|
|
4488
|
+
targets.set(lineId, Math.min(quantity, targets.get(lineId) ?? quantity));
|
|
4489
|
+
}
|
|
4490
|
+
return { adjust: [...targets].map(([lineId, quantity]) => ({ lineId, quantity })), remove: [...removed] };
|
|
4406
4491
|
};
|
|
4407
4492
|
|
|
4408
4493
|
// src/server/analytics.ts
|
|
@@ -4524,7 +4609,7 @@ var postAnalyticsEvents = async (input, ctx) => {
|
|
|
4524
4609
|
};
|
|
4525
4610
|
|
|
4526
4611
|
// src/server/requestSchemas.ts
|
|
4527
|
-
import { z as
|
|
4612
|
+
import { z as z30 } from "zod";
|
|
4528
4613
|
var REQUEST_BOUNDS = {
|
|
4529
4614
|
/** Cart-level attributes per cart. */
|
|
4530
4615
|
CART_ATTRIBUTES_MAX: 100,
|
|
@@ -4555,42 +4640,42 @@ var REQUEST_BOUNDS = {
|
|
|
4555
4640
|
/** Rich ads transaction lines — the engine's ads contract. */
|
|
4556
4641
|
TRANSACTION_ITEMS_MAX: 50
|
|
4557
4642
|
};
|
|
4558
|
-
var KeyValue =
|
|
4559
|
-
key:
|
|
4560
|
-
value:
|
|
4643
|
+
var KeyValue = z30.object({
|
|
4644
|
+
key: z30.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
|
|
4645
|
+
value: z30.string().max(REQUEST_BOUNDS.STRING_VALUE_MAX).optional()
|
|
4561
4646
|
});
|
|
4562
|
-
var CartLineInputSchema =
|
|
4563
|
-
productId:
|
|
4564
|
-
properties:
|
|
4565
|
-
quantity:
|
|
4566
|
-
subscriptionId:
|
|
4567
|
-
variantId:
|
|
4647
|
+
var CartLineInputSchema = z30.object({
|
|
4648
|
+
productId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
|
|
4649
|
+
properties: z30.array(KeyValue).max(REQUEST_BOUNDS.LINE_PROPERTIES_MAX).optional(),
|
|
4650
|
+
quantity: z30.number(),
|
|
4651
|
+
subscriptionId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4652
|
+
variantId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX)
|
|
4568
4653
|
});
|
|
4569
|
-
var CartInputSchema =
|
|
4570
|
-
attributes:
|
|
4654
|
+
var CartInputSchema = z30.object({
|
|
4655
|
+
attributes: z30.array(KeyValue).max(REQUEST_BOUNDS.CART_ATTRIBUTES_MAX).optional(),
|
|
4571
4656
|
/**
|
|
4572
4657
|
* Presentment-per-shop-currency FX rate (buyer price ÷ shop price, e.g. `1.35` for a USD shop
|
|
4573
4658
|
* selling in CAD). Money rule thresholds are authored in SHOP currency, so the engine subtotal is
|
|
4574
4659
|
* divided by this before evaluation. Omit (or send 1) when the cart is already in the shop's currency.
|
|
4575
4660
|
*/
|
|
4576
|
-
currencyRate:
|
|
4661
|
+
currencyRate: z30.number().optional(),
|
|
4577
4662
|
/** Applied discount codes; the engine evaluates `discount_code` rules against them (sent as `[{code}]`). */
|
|
4578
|
-
discountCodes:
|
|
4663
|
+
discountCodes: z30.array(z30.string().max(REQUEST_BOUNDS.STRING_KEY_MAX)).max(REQUEST_BOUNDS.DISCOUNT_CODES_MAX).optional(),
|
|
4579
4664
|
/** Presentment cents of cart-level discount allocations, subtracted from `subtotal` for the engine. */
|
|
4580
|
-
discountTotal:
|
|
4581
|
-
items:
|
|
4665
|
+
discountTotal: z30.number().optional(),
|
|
4666
|
+
items: z30.array(CartLineInputSchema).max(REQUEST_BOUNDS.CART_ITEMS_MAX),
|
|
4582
4667
|
/** Presentment subtotal in cents. */
|
|
4583
|
-
subtotal:
|
|
4668
|
+
subtotal: z30.number()
|
|
4584
4669
|
});
|
|
4585
|
-
var UserConfigInputSchema =
|
|
4586
|
-
var DataSourceInputSchema =
|
|
4670
|
+
var UserConfigInputSchema = z30.object({ shop: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX) });
|
|
4671
|
+
var DataSourceInputSchema = z30.object({
|
|
4587
4672
|
cart: CartInputSchema,
|
|
4588
4673
|
/**
|
|
4589
4674
|
* Numeric Shopify company-location id when the buyer is a B2B session (`buyerIdentity.purchasingCompany`).
|
|
4590
4675
|
* Present ⇒ the orchestrator filters results by the location's catalog via admin-api (REB-23713); the
|
|
4591
4676
|
* client's country-context market check is bypassed for B2B (it false-negatives B2B-catalog products).
|
|
4592
4677
|
*/
|
|
4593
|
-
companyLocationId:
|
|
4678
|
+
companyLocationId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4594
4679
|
/**
|
|
4595
4680
|
* Buyer's market country (ISO 3166-1 alpha-2) — forwarded to the engine as the `country_code` PARAM
|
|
4596
4681
|
* when the shop's markets toggle is on (REB-21688; the sink was the `X-Country-Code` header under
|
|
@@ -4599,16 +4684,16 @@ var DataSourceInputSchema = z29.object({
|
|
|
4599
4684
|
* uppercase (the wire value is forwarded verbatim as the param) so a case-sensitive engine lookup
|
|
4600
4685
|
* can't silently miss a lowercase code — `adsEngine.ts` uppercases for the same reason.
|
|
4601
4686
|
*/
|
|
4602
|
-
country:
|
|
4603
|
-
customerId:
|
|
4604
|
-
dataSourcePath:
|
|
4687
|
+
country: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).regex(/^[A-Za-z]{2}$/, "must be an ISO 3166-1 alpha-2 country code (e.g. CA)").transform((value) => value.toUpperCase()).optional(),
|
|
4688
|
+
customerId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4689
|
+
dataSourcePath: z30.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
|
|
4605
4690
|
/**
|
|
4606
4691
|
* Engine `filter_inputs` override: `'no'` keeps in-cart (input) products in the results/rule
|
|
4607
4692
|
* outputs — gift validation sends it so a gift's own product can appear in its answer. Omitted = the
|
|
4608
4693
|
* engine's default filtering.
|
|
4609
4694
|
*/
|
|
4610
|
-
filterInputs:
|
|
4611
|
-
integrations:
|
|
4695
|
+
filterInputs: z30.enum(["no", "yes"]).optional(),
|
|
4696
|
+
integrations: z30.record(z30.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), z30.boolean()).refine((record) => Object.keys(record).length <= REQUEST_BOUNDS.INTEGRATION_KEYS_MAX, {
|
|
4612
4697
|
message: `Too many integration keys (max ${REQUEST_BOUNDS.INTEGRATION_KEYS_MAX})`
|
|
4613
4698
|
}).optional(),
|
|
4614
4699
|
/**
|
|
@@ -4621,20 +4706,31 @@ var DataSourceInputSchema = z29.object({
|
|
|
4621
4706
|
* request header) fails the regex. Callers should send the buyer's resolved locale (e.g. Shopify
|
|
4622
4707
|
* checkout's `localization.language.isoCode`), not the request header verbatim.
|
|
4623
4708
|
*/
|
|
4624
|
-
language:
|
|
4625
|
-
limit:
|
|
4626
|
-
productType:
|
|
4627
|
-
shop:
|
|
4628
|
-
visitorId:
|
|
4709
|
+
language: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).regex(/^[A-Za-z0-9-]+$/, "must be a single BCP-47 tag (e.g. fr-CA), not a q-value list").optional(),
|
|
4710
|
+
limit: z30.number().max(REQUEST_BOUNDS.LIMIT_MAX),
|
|
4711
|
+
productType: z30.enum(["both", "one-time", "subscription"]).optional(),
|
|
4712
|
+
shop: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
|
|
4713
|
+
visitorId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
|
|
4629
4714
|
});
|
|
4630
|
-
var GiftInputSchema =
|
|
4631
|
-
cost:
|
|
4632
|
-
discounted:
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4715
|
+
var GiftInputSchema = z30.object({
|
|
4716
|
+
cost: z30.number(),
|
|
4717
|
+
discounted: z30.boolean(),
|
|
4718
|
+
/**
|
|
4719
|
+
* Which gift attribution the line carries (REB-24363). Defaults to `gwp` because a client that predates
|
|
4720
|
+
* the field only ever sent GWP lines — without the default an older extension's request would 422.
|
|
4721
|
+
*/
|
|
4722
|
+
kind: z30.enum(GIFT_KINDS).default("gwp"),
|
|
4723
|
+
lineId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
|
|
4724
|
+
productId: z30.number(),
|
|
4725
|
+
/**
|
|
4726
|
+
* The line's unit count (REB-24363) — the selectable-GWP verdict trims surplus units against milestone
|
|
4727
|
+
* capacity. The second deliberate default: a client predating the field sent only GWP lines, whose
|
|
4728
|
+
* verdict is whole-line, so a missing quantity reads as one unit rather than 422ing the older request.
|
|
4729
|
+
*/
|
|
4730
|
+
quantity: z30.number().int().min(1).default(1),
|
|
4731
|
+
widgetId: z30.number()
|
|
4636
4732
|
});
|
|
4637
|
-
var GiftValidationInputSchema =
|
|
4733
|
+
var GiftValidationInputSchema = z30.object({
|
|
4638
4734
|
cart: CartInputSchema,
|
|
4639
4735
|
/**
|
|
4640
4736
|
* Buyer's market country — threaded into the per-widget data-source evaluations, which forward it to
|
|
@@ -4643,59 +4739,76 @@ var GiftValidationInputSchema = z29.object({
|
|
|
4643
4739
|
* turns markets off); regex-bound and uppercase-normalized for the same reasons as
|
|
4644
4740
|
* `DataSourceInputSchema`'s `country`.
|
|
4645
4741
|
*/
|
|
4646
|
-
country:
|
|
4647
|
-
customerId:
|
|
4648
|
-
gifts:
|
|
4742
|
+
country: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).regex(/^[A-Za-z]{2}$/, "must be an ISO 3166-1 alpha-2 country code (e.g. CA)").transform((value) => value.toUpperCase()).optional(),
|
|
4743
|
+
customerId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4744
|
+
gifts: z30.array(GiftInputSchema).max(REQUEST_BOUNDS.GIFTS_MAX),
|
|
4649
4745
|
/**
|
|
4650
4746
|
* Buyer's checkout language — threaded into the per-widget data-source evaluations, which normalize
|
|
4651
4747
|
* and forward it as the engine `locale` param under the same markets-toggle gate (REB-21688). MUST be
|
|
4652
4748
|
* a single BCP-47 tag, for the same reason as `DataSourceInputSchema`'s `language` above.
|
|
4653
4749
|
*/
|
|
4654
|
-
language:
|
|
4655
|
-
shop:
|
|
4656
|
-
visitorId:
|
|
4750
|
+
language: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).regex(/^[A-Za-z0-9-]+$/, "must be a single BCP-47 tag (e.g. fr-CA), not a q-value list").optional(),
|
|
4751
|
+
shop: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
|
|
4752
|
+
visitorId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
|
|
4753
|
+
});
|
|
4754
|
+
var GiftAdjustmentSchema = z30.object({
|
|
4755
|
+
lineId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
|
|
4756
|
+
quantity: z30.number().int().nonnegative()
|
|
4657
4757
|
});
|
|
4658
|
-
var
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4758
|
+
var GiftValidationResponseSchema = z30.object({
|
|
4759
|
+
adjust: z30.array(GiftAdjustmentSchema).max(REQUEST_BOUNDS.GIFTS_MAX).default([]),
|
|
4760
|
+
remove: z30.array(z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX)).max(REQUEST_BOUNDS.GIFTS_MAX).refine(
|
|
4761
|
+
(remove) => new Set(remove).size === remove.length,
|
|
4762
|
+
"a line id may appear at most once in `remove`"
|
|
4763
|
+
)
|
|
4764
|
+
}).refine(
|
|
4765
|
+
({ adjust, remove }) => !adjust.some(({ lineId }) => remove.includes(lineId)),
|
|
4766
|
+
"a line id may not appear in both `remove` and `adjust`"
|
|
4767
|
+
).refine(
|
|
4768
|
+
({ adjust }) => new Set(adjust.map(({ lineId }) => lineId)).size === adjust.length,
|
|
4769
|
+
"a line id may appear at most once in `adjust`"
|
|
4770
|
+
);
|
|
4771
|
+
var MonetizeTransactionItemSchema = z30.object({
|
|
4772
|
+
id: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
|
|
4773
|
+
priceCents: z30.number(),
|
|
4774
|
+
quantity: z30.number(),
|
|
4775
|
+
title: z30.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX),
|
|
4776
|
+
type: z30.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX)
|
|
4664
4777
|
});
|
|
4665
|
-
var MonetizeInputSchema =
|
|
4778
|
+
var MonetizeInputSchema = z30.object({
|
|
4666
4779
|
cart: CartInputSchema,
|
|
4667
4780
|
/** Client-minted render-beacon correlation id; forwarded to the ads engine as `client_request_id`. */
|
|
4668
|
-
clientRequestId:
|
|
4669
|
-
country:
|
|
4670
|
-
currency:
|
|
4781
|
+
clientRequestId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4782
|
+
country: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4783
|
+
currency: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4671
4784
|
/** Ads-targeting identity/geo/locale fields (React parity); folded into the engine query verbatim. */
|
|
4672
|
-
customerEmail:
|
|
4673
|
-
customerFirstName:
|
|
4674
|
-
customerId:
|
|
4675
|
-
customerLastName:
|
|
4676
|
-
language:
|
|
4785
|
+
customerEmail: z30.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
|
|
4786
|
+
customerFirstName: z30.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
|
|
4787
|
+
customerId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4788
|
+
customerLastName: z30.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
|
|
4789
|
+
language: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4677
4790
|
/** Buyer-facing order name (e.g. `#1001`) for the server-composed "Order … Confirmed" chrome line. */
|
|
4678
|
-
orderName:
|
|
4791
|
+
orderName: z30.string().max(REQUEST_BOUNDS.STRING_TEXT_MAX).optional(),
|
|
4679
4792
|
/** Ads surface label, forwarded verbatim; `customer_account` is measured/floored as its own surface (the account-area order list). */
|
|
4680
|
-
placement:
|
|
4793
|
+
placement: z30.enum(["customer_account", "order_status", "thank_you_page"]),
|
|
4681
4794
|
/** Privacy Policy footer href — the Monetize widget's `privacy_policy_url` setting (React parity). */
|
|
4682
|
-
privacyPolicyUrl:
|
|
4795
|
+
privacyPolicyUrl: z30.string().max(REQUEST_BOUNDS.STRING_URL_MAX).optional(),
|
|
4683
4796
|
/** 30-min rolling session id (React parity); used for the ads `session_id`, else the visitor id. */
|
|
4684
|
-
sessionId:
|
|
4685
|
-
shop:
|
|
4797
|
+
sessionId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4798
|
+
shop: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
|
|
4686
4799
|
/** Editor/QA indicator; OR-ed into the ads-engine `testing` flag so it stays out of billing/reporting. */
|
|
4687
|
-
testing:
|
|
4688
|
-
timezone:
|
|
4800
|
+
testing: z30.boolean().optional(),
|
|
4801
|
+
timezone: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4689
4802
|
/** Decorated (numeric) order id → the ads `transaction_id`. */
|
|
4690
|
-
transactionId:
|
|
4803
|
+
transactionId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4691
4804
|
/** Rich per-line ads items; capped at the engine's ads contract. Preferred over `cart.items`. */
|
|
4692
|
-
transactionItems:
|
|
4805
|
+
transactionItems: z30.array(MonetizeTransactionItemSchema).max(REQUEST_BOUNDS.TRANSACTION_ITEMS_MAX).optional(),
|
|
4693
4806
|
/** Order total in presentment cents (React prefers total over subtotal); else `cart.subtotal`. */
|
|
4694
|
-
transactionTotal:
|
|
4695
|
-
visitorId:
|
|
4696
|
-
zipCode:
|
|
4807
|
+
transactionTotal: z30.number().optional(),
|
|
4808
|
+
visitorId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4809
|
+
zipCode: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
|
|
4697
4810
|
});
|
|
4698
|
-
var WidgetSettingsInputSchema =
|
|
4811
|
+
var WidgetSettingsInputSchema = z30.object({
|
|
4699
4812
|
/**
|
|
4700
4813
|
* Same domain as `CabShopConfig.cacheKey`, for the same reason: this side WINS the orchestrator's
|
|
4701
4814
|
* `input.cacheKey ?? config.shop.cacheKey` (and an explicit value skips the config read entirely), so
|
|
@@ -4703,9 +4816,9 @@ var WidgetSettingsInputSchema = z29.object({
|
|
|
4703
4816
|
* and pin the edge copy permanently stale. `.catch(undefined)` because a bogus buster should degrade
|
|
4704
4817
|
* the read to un-busted, never 400 a widget render.
|
|
4705
4818
|
*/
|
|
4706
|
-
cacheKey:
|
|
4707
|
-
id:
|
|
4708
|
-
key:
|
|
4819
|
+
cacheKey: z30.number().int().positive().optional().catch(void 0),
|
|
4820
|
+
id: z30.number(),
|
|
4821
|
+
key: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4709
4822
|
/**
|
|
4710
4823
|
* Monetize context for inline hydration: when present AND the widget converts to a Monetize marker,
|
|
4711
4824
|
* the server fetches/composes the offer cards inside this same request (no second `/cab/monetize`
|
|
@@ -4714,25 +4827,25 @@ var WidgetSettingsInputSchema = z29.object({
|
|
|
4714
4827
|
* `privacyPolicyUrl` comes from the widget settings server-side (more authoritative than a relay).
|
|
4715
4828
|
*/
|
|
4716
4829
|
monetize: MonetizeInputSchema.omit({ privacyPolicyUrl: true, shop: true }).optional(),
|
|
4717
|
-
shop:
|
|
4830
|
+
shop: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
|
|
4718
4831
|
/** Stable per-buyer id; when present, enables sticky server-side A/B variant selection. */
|
|
4719
|
-
visitorId:
|
|
4832
|
+
visitorId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
|
|
4720
4833
|
});
|
|
4721
|
-
var AnalyticsEventInputSchema =
|
|
4722
|
-
name:
|
|
4723
|
-
properties:
|
|
4724
|
-
sentAt:
|
|
4834
|
+
var AnalyticsEventInputSchema = z30.object({
|
|
4835
|
+
name: z30.string().max(REQUEST_BOUNDS.STRING_KEY_MAX),
|
|
4836
|
+
properties: z30.record(z30.string().max(REQUEST_BOUNDS.STRING_KEY_MAX), z30.unknown()).optional(),
|
|
4837
|
+
sentAt: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
|
|
4725
4838
|
});
|
|
4726
|
-
var AnalyticsInputSchema =
|
|
4839
|
+
var AnalyticsInputSchema = z30.object({
|
|
4727
4840
|
/** Rebuy cart token (the `r_cart_token` cart attribute), when available — primary aggregation key. */
|
|
4728
|
-
cartToken:
|
|
4841
|
+
cartToken: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4729
4842
|
/** Shopify checkout token, when available — drives cart/checkout aggregation downstream. */
|
|
4730
|
-
checkoutToken:
|
|
4731
|
-
events:
|
|
4732
|
-
shop:
|
|
4733
|
-
visitorId:
|
|
4843
|
+
checkoutToken: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional(),
|
|
4844
|
+
events: z30.array(AnalyticsEventInputSchema).max(REQUEST_BOUNDS.EVENTS_MAX),
|
|
4845
|
+
shop: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
|
|
4846
|
+
visitorId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX),
|
|
4734
4847
|
/** The widget id (smartBlockId) the events belong to. */
|
|
4735
|
-
widgetId:
|
|
4848
|
+
widgetId: z30.string().max(REQUEST_BOUNDS.STRING_ID_MAX).optional()
|
|
4736
4849
|
});
|
|
4737
4850
|
export {
|
|
4738
4851
|
AnalyticsEventInputSchema,
|
|
@@ -4740,8 +4853,10 @@ export {
|
|
|
4740
4853
|
CartInputSchema,
|
|
4741
4854
|
CartLineInputSchema,
|
|
4742
4855
|
DataSourceInputSchema,
|
|
4856
|
+
GiftAdjustmentSchema,
|
|
4743
4857
|
GiftInputSchema,
|
|
4744
4858
|
GiftValidationInputSchema,
|
|
4859
|
+
GiftValidationResponseSchema,
|
|
4745
4860
|
MonetizeInputSchema,
|
|
4746
4861
|
MonetizeTransactionItemSchema,
|
|
4747
4862
|
NotFoundError,
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* `*Input` twins in `./shared` are now `z.infer` of these schemas (single source of truth, no drift).
|
|
5
5
|
*
|
|
6
6
|
* These model the wire shape only: no `.default()`s (a request field is either sent or omitted — defaulting
|
|
7
|
-
* would diverge `z.infer` from the twin it replaces and hide a missing field)
|
|
7
|
+
* would diverge `z.infer` from the twin it replaces and hide a missing field) — the two exceptions are
|
|
8
|
+
* `GiftInputSchema.kind` and `.quantity`, additive fields whose defaults ARE the cross-version contract — and unknown keys are stripped
|
|
8
9
|
* by the plain `z.object`, which is the intended lenient request-parse behavior. Upper bounds
|
|
9
10
|
* (`REQUEST_BOUNDS`) ARE part of the wire contract: the `/cab/*` routes are public and unauthenticated, so
|
|
10
11
|
* the schema is the only edge guard against unbounded payloads.
|
|
@@ -128,8 +129,13 @@ export declare const DataSourceInputSchema: z.ZodObject<{
|
|
|
128
129
|
export declare const GiftInputSchema: z.ZodObject<{
|
|
129
130
|
cost: z.ZodNumber;
|
|
130
131
|
discounted: z.ZodBoolean;
|
|
132
|
+
kind: z.ZodDefault<z.ZodEnum<{
|
|
133
|
+
gwp: "gwp";
|
|
134
|
+
sgwp: "sgwp";
|
|
135
|
+
}>>;
|
|
131
136
|
lineId: z.ZodString;
|
|
132
137
|
productId: z.ZodNumber;
|
|
138
|
+
quantity: z.ZodDefault<z.ZodNumber>;
|
|
133
139
|
widgetId: z.ZodNumber;
|
|
134
140
|
}, z.core.$strip>;
|
|
135
141
|
/** Input for `validateGifts`. */
|
|
@@ -159,14 +165,39 @@ export declare const GiftValidationInputSchema: z.ZodObject<{
|
|
|
159
165
|
gifts: z.ZodArray<z.ZodObject<{
|
|
160
166
|
cost: z.ZodNumber;
|
|
161
167
|
discounted: z.ZodBoolean;
|
|
168
|
+
kind: z.ZodDefault<z.ZodEnum<{
|
|
169
|
+
gwp: "gwp";
|
|
170
|
+
sgwp: "sgwp";
|
|
171
|
+
}>>;
|
|
162
172
|
lineId: z.ZodString;
|
|
163
173
|
productId: z.ZodNumber;
|
|
174
|
+
quantity: z.ZodDefault<z.ZodNumber>;
|
|
164
175
|
widgetId: z.ZodNumber;
|
|
165
176
|
}, z.core.$strip>>;
|
|
166
177
|
language: z.ZodOptional<z.ZodString>;
|
|
167
178
|
shop: z.ZodString;
|
|
168
179
|
visitorId: z.ZodOptional<z.ZodString>;
|
|
169
180
|
}, z.core.$strip>;
|
|
181
|
+
/** One per-line quantity target in the gift-validation receipt; `0` means remove the line. */
|
|
182
|
+
export declare const GiftAdjustmentSchema: z.ZodObject<{
|
|
183
|
+
lineId: z.ZodString;
|
|
184
|
+
quantity: z.ZodNumber;
|
|
185
|
+
}, z.core.$strip>;
|
|
186
|
+
/**
|
|
187
|
+
* The gift-validation RECEIPT: whole-line removals beside per-line quantity targets. `validateGifts`
|
|
188
|
+
* derives its return type from this, so the two lists stay one contract. `adjust` defaults so a proxy that
|
|
189
|
+
* predates the field still answers a valid `{ remove }` receipt. One verdict per line: a line id in both
|
|
190
|
+
* lists, or twice in either, is a server bug — the client would have to pick a winner (or mutate a line
|
|
191
|
+
* twice), so the contract forbids all three here and `validateGifts` upholds them (strictest verdict wins,
|
|
192
|
+
* named once) even when a request names one `lineId` more than once.
|
|
193
|
+
*/
|
|
194
|
+
export declare const GiftValidationResponseSchema: z.ZodObject<{
|
|
195
|
+
adjust: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
196
|
+
lineId: z.ZodString;
|
|
197
|
+
quantity: z.ZodNumber;
|
|
198
|
+
}, z.core.$strip>>>;
|
|
199
|
+
remove: z.ZodArray<z.ZodString>;
|
|
200
|
+
}, z.core.$strip>;
|
|
170
201
|
/**
|
|
171
202
|
* A rich transaction line the ads engine prices/targets on — the full per-line detail React sends. Distinct
|
|
172
203
|
* from a cart line: it carries the merchandise title/type/unit-price the rule-evaluation cart context omits.
|
|
@@ -318,8 +349,10 @@ export type AnalyticsInput = z.infer<typeof AnalyticsInputSchema>;
|
|
|
318
349
|
export type CartInput = z.infer<typeof CartInputSchema>;
|
|
319
350
|
export type CartLineInput = z.infer<typeof CartLineInputSchema>;
|
|
320
351
|
export type DataSourceInput = z.infer<typeof DataSourceInputSchema>;
|
|
352
|
+
export type GiftAdjustment = z.infer<typeof GiftAdjustmentSchema>;
|
|
321
353
|
export type GiftInput = z.infer<typeof GiftInputSchema>;
|
|
322
354
|
export type GiftValidationInput = z.infer<typeof GiftValidationInputSchema>;
|
|
355
|
+
export type GiftValidationResponse = z.infer<typeof GiftValidationResponseSchema>;
|
|
323
356
|
export type MonetizeInput = z.infer<typeof MonetizeInputSchema>;
|
|
324
357
|
export type MonetizeTransactionItem = z.infer<typeof MonetizeTransactionItemSchema>;
|
|
325
358
|
export type UserConfigInput = z.infer<typeof UserConfigInputSchema>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type SgwpMilestone } from '../server/giftWidgets';
|
|
2
|
+
import { type CartInput, type GiftInput } from '../server/shared';
|
|
3
|
+
/**
|
|
4
|
+
* The subtotal a selectable-GWP milestone is judged against: the rule subtotal in shop cents
|
|
5
|
+
* ({@link shopSubtotalCents} — the same figure the GWP rules see) minus the cost of EVERY selectable gift
|
|
6
|
+
* line in the cart, from every widget and regardless of price. A gift may legitimately carry a price (a $3
|
|
7
|
+
* gift covering shipping), and counting it would let the gift hold its own threshold met after the
|
|
8
|
+
* qualifying items are gone (React `getSgwpUnlockSubtotalCents`). `cost` is a presentment MAJOR-unit
|
|
9
|
+
* line total, so the gift costs are summed in presentment first and converted through the rate ONCE —
|
|
10
|
+
* rounding each line separately can drift a cent from the summed figure at a threshold boundary.
|
|
11
|
+
*
|
|
12
|
+
* `gwp` lines are NOT subtracted, on purpose (React excluded selectable lines only). A discounted GWP gift
|
|
13
|
+
* is free, so it adds nothing to spend; one that lost its discount is in the same receipt's `remove`, and
|
|
14
|
+
* once the client applies that the next validation judges the milestones against the reduced subtotal —
|
|
15
|
+
* self-healing within a round trip, with any residue on the merchant's side, never the buyer's.
|
|
16
|
+
*/
|
|
17
|
+
export declare const sgwpQualifyingSubtotalCents: (cart: CartInput, gifts: GiftInput[]) => number;
|
|
18
|
+
/**
|
|
19
|
+
* Gift units the cart has unlocked: Σ `selectable_product_quantity` over the milestones whose unlock price is
|
|
20
|
+
* at or below the subtotal, both in shop cents. `unlock_price` is authored in shop MAJOR units, so it is
|
|
21
|
+
* ×100 and rounded exactly as React's `getMilestoneUnlockPriceCents` did (a float residue like 150.5 × 100
|
|
22
|
+
* = 15050.000000000002 must not push a threshold a cent past a subtotal that meets it). Cumulative, not
|
|
23
|
+
* stepped: every met milestone contributes — the retired React validator's semantics, reproduced.
|
|
24
|
+
*/
|
|
25
|
+
export declare const unlockedCapacity: (milestones: SgwpMilestone[], subtotalCents: number) => number;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type GiftAdjustment, type GiftInput, type GiftValidationInput, type ServerContext } from '../server/shared';
|
|
2
|
+
/**
|
|
3
|
+
* Per-line quantity targets that bring one widget's selectable gifts back within `capacity` units. Surplus
|
|
4
|
+
* units come off the FIRST lines in request order: the request mirrors `shopify.lines`, whose index 0 is
|
|
5
|
+
* the most recently added line (Shopify's cart convention), so this is LIFO by add time — the earliest-
|
|
6
|
+
* claimed gifts survive, exactly as the retired React `computeSgwpLineAdjustments` walked them. A line the
|
|
7
|
+
* surplus consumes whole targets `0` (remove); a line it only dents targets its reduced quantity; a line it
|
|
8
|
+
* never reaches gets no entry.
|
|
9
|
+
*/
|
|
10
|
+
export declare const computeSgwpAdjustments: (gifts: GiftInput[], capacity: number) => GiftAdjustment[];
|
|
11
|
+
/**
|
|
12
|
+
* The selectable-GWP half of the gift-validation receipt: for each `sgwp` widget in the request, read its
|
|
13
|
+
* `milestones` from its widget settings and trim the widget's lines to the capacity the cart has unlocked.
|
|
14
|
+
* Entirely fail-safe, like the GWP qualification path: an upstream failure, a deleted widget, or absent,
|
|
15
|
+
* empty, or malformed milestones all keep the widget's gifts (no entries). The GWP charged-gift rule never
|
|
16
|
+
* applies here — a selectable gift may be legitimately priced. Widgets are independent: one failing
|
|
17
|
+
* fetch never disturbs another's verdict.
|
|
18
|
+
*/
|
|
19
|
+
export declare const validateSelectableGifts: (input: GiftValidationInput, ctx: ServerContext) => Promise<GiftAdjustment[]>;
|
package/dist/server/shared.d.ts
CHANGED
|
@@ -27,14 +27,15 @@ export type UpstreamFetch = (path: string, params: Record<string, string>, optio
|
|
|
27
27
|
}) => Promise<unknown>;
|
|
28
28
|
/**
|
|
29
29
|
* A drift signal the orchestrators emit when a per-item payload salvage drops something: a malformed
|
|
30
|
-
* offer product, an invalid/unknown section stubbed out, an unreadable rule verdict,
|
|
31
|
-
* entry the shared schema inerted (`shopConfig`)
|
|
30
|
+
* offer product, an invalid/unknown section stubbed out, an unreadable rule verdict, a shop-config
|
|
31
|
+
* entry the shared schema inerted (`shopConfig`), or unreadable selectable-gift milestones
|
|
32
|
+
* (`giftMilestones` — the widget's gifts are then kept). Distinct from a hard {@link UpstreamError} — the
|
|
32
33
|
* request still succeeds (degraded), so this is the only trace that an upstream contract moved. Optional
|
|
33
34
|
* on {@link ServerContext}; the host (rebuy-api) wires it to its logger.
|
|
34
35
|
*/
|
|
35
36
|
export type ServerDrift = {
|
|
36
37
|
detail: string;
|
|
37
|
-
kind: 'b2bAvailability' | 'dataSource' | 'monetizeOffer' | 'product' | 'ruleVerdict' | 'section' | 'shopConfig';
|
|
38
|
+
kind: 'b2bAvailability' | 'dataSource' | 'giftMilestones' | 'monetizeOffer' | 'product' | 'ruleVerdict' | 'section' | 'shopConfig';
|
|
38
39
|
};
|
|
39
40
|
/** A {@link ServerDrift} sink, as the orchestrators pass it around internally. */
|
|
40
41
|
export type Reporter = (event: ServerDrift) => void;
|
|
@@ -69,4 +70,4 @@ export declare class NotFoundError extends Error {
|
|
|
69
70
|
* requests against the exact contract the orchestrators are typed on. Kept re-exported here so the
|
|
70
71
|
* `@rebuy/rebuy/server` type surface is unchanged.
|
|
71
72
|
*/
|
|
72
|
-
export type { AnalyticsEventInput, AnalyticsInput, CartInput, CartLineInput, DataSourceInput, GiftInput, GiftValidationInput, MonetizeInput, MonetizeTransactionItem, UserConfigInput, WidgetSettingsInput, } from '../server/requestSchemas';
|
|
73
|
+
export type { AnalyticsEventInput, AnalyticsInput, CartInput, CartLineInput, DataSourceInput, GiftAdjustment, GiftInput, GiftValidationInput, GiftValidationResponse, MonetizeInput, MonetizeTransactionItem, UserConfigInput, WidgetSettingsInput, } from '../server/requestSchemas';
|