@rebuy/rebuy 3.51.1 → 3.53.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 (35) hide show
  1. package/dist/index.cjs +47 -31
  2. package/dist/index.mjs +47 -31
  3. package/dist/schema/index.d.ts +1 -1
  4. package/dist/schema/postPurchaseAdmission.d.ts +6 -6
  5. package/dist/schema/postPurchaseFollowups.d.ts +1 -1
  6. package/dist/schema/postPurchaseOfferEligibility.d.ts +24 -1
  7. package/dist/schema/postPurchaseProduct.d.ts +2 -0
  8. package/dist/schema/postPurchaseProductCollectionView.d.ts +1 -0
  9. package/dist/schema/postPurchaseProductDisplay.d.ts +1 -0
  10. package/dist/schema/postPurchaseProductGallery.d.ts +1 -0
  11. package/dist/schema/postPurchaseProductView.d.ts +1 -0
  12. package/dist/schema/postPurchaseRecovery.d.ts +1 -1
  13. package/dist/schema/{postPurchaseUpgrade.d.ts → postPurchaseSts.d.ts} +14 -14
  14. package/dist/schema/postPurchaseSubscriptionProduct.d.ts +2 -0
  15. package/dist/server/__fixtures__/postPurchaseSts.d.ts +98 -0
  16. package/dist/server/classifyPostPurchaseOffer.d.ts +4 -2
  17. package/dist/server/index.cjs +166 -78
  18. package/dist/server/index.mjs +166 -78
  19. package/dist/server/postPurchaseProductDisplay.d.ts +1 -0
  20. package/dist/server/postPurchaseProductGallery.d.ts +5 -1
  21. package/dist/server/postPurchaseSts.d.ts +1293 -0
  22. package/dist/server/preparePostPurchaseAdmissionView.d.ts +1 -0
  23. package/dist/server/preparePostPurchaseCollectionGroup.d.ts +1 -0
  24. package/dist/server/preparePostPurchaseCollectionView.d.ts +5 -1
  25. package/dist/server/preparePostPurchaseGroupAdmissionView.d.ts +8 -0
  26. package/dist/server/preparePostPurchaseGroupDefault.d.ts +8 -0
  27. package/dist/server/preparePostPurchaseGroupView.d.ts +8 -0
  28. package/dist/server/preparePostPurchaseMemberView.d.ts +818 -1
  29. package/dist/server/preparePostPurchaseQuantityAdmissionView.d.ts +12 -1
  30. package/dist/server/preparePostPurchaseQuantityView.d.ts +12 -1
  31. package/dist/server/preparePostPurchaseStsMember.d.ts +824 -0
  32. package/dist/server/preparePostPurchaseSubscription.d.ts +1 -0
  33. package/dist/server/projectPostPurchaseProduct.d.ts +1 -0
  34. package/dist/server/readPostPurchaseQuantity.d.ts +4 -1
  35. package/package.json +1 -1
@@ -0,0 +1,98 @@
1
+ /** The STS Flow: the subscription fixture with STS on and the refund notice asked for. */
2
+ export declare const stsSettings: {
3
+ upgrade_to_subscription: {
4
+ allow: boolean;
5
+ email_refund_notice: boolean;
6
+ };
7
+ discount: {
8
+ amount: number;
9
+ type: string;
10
+ };
11
+ product_type: string;
12
+ subscription: {
13
+ discount: {
14
+ amount: number;
15
+ type: string;
16
+ };
17
+ shipping: {
18
+ amount: number;
19
+ type: string;
20
+ };
21
+ };
22
+ blocks: {
23
+ type: string;
24
+ }[];
25
+ endpoint: string;
26
+ integrations: {};
27
+ key: string;
28
+ language: {};
29
+ product_limit: number;
30
+ product_options: {};
31
+ quantity_inputs: {
32
+ default_quantity: number;
33
+ enabled: boolean;
34
+ };
35
+ shipping: {
36
+ amount: string;
37
+ title: string;
38
+ type: string;
39
+ };
40
+ };
41
+ export declare const stsResponse: {
42
+ data: {
43
+ selling_plan_groups: {
44
+ id: string;
45
+ requires_selling_plan: boolean;
46
+ selling_plans: {
47
+ id: number;
48
+ name: string;
49
+ options: {
50
+ name: string;
51
+ position: number;
52
+ value: string;
53
+ }[];
54
+ price_adjustments: never[];
55
+ }[];
56
+ }[];
57
+ variants: {
58
+ selling_plan_allocations: {
59
+ selling_plan_group_id: string;
60
+ selling_plan_id: number;
61
+ }[];
62
+ compare_at_price: string;
63
+ id: number;
64
+ inventory_management: string;
65
+ inventory_policy: string;
66
+ inventory_quantity: number;
67
+ price: string;
68
+ product_id: number;
69
+ title: string;
70
+ }[];
71
+ description: string;
72
+ id: number;
73
+ image: {
74
+ src: string;
75
+ };
76
+ title: string;
77
+ }[];
78
+ metadata: {};
79
+ };
80
+ /** The buyer bought variant 411 of product 410 one-time, three of them. */
81
+ export declare const oneTimeLine: {
82
+ productId: number;
83
+ quantity: number;
84
+ variantId: number;
85
+ };
86
+ export declare const stsContext: {
87
+ originalLineItems: {
88
+ productId: number;
89
+ quantity: number;
90
+ variantId: number;
91
+ }[];
92
+ };
93
+ /**
94
+ * Wraps `call` so every existing case also runs with the STS argument at position `index` and proves the
95
+ * output byte-identical (or the same failure). Use it only where the Offer does not enable STS, or with
96
+ * an argument that leaves STS off.
97
+ */
98
+ export declare const provingStsInert: <A extends unknown[], R>(call: (...args: A) => R, index: number, sts: unknown) => (...args: A) => R;
@@ -1,3 +1,5 @@
1
1
  import { type z } from 'zod';
2
- import { type PostPurchaseOfferEligibility, PostPurchaseOfferEligibilityContext } from '../schema/postPurchaseOfferEligibility';
3
- export declare const classifyPostPurchaseOffer: (settings: unknown, response: unknown, context: z.input<typeof PostPurchaseOfferEligibilityContext>) => PostPurchaseOfferEligibility;
2
+ import { type PostPurchaseOfferEligibility, PostPurchaseOfferEligibilityContext, PostPurchaseStsOptions } from '../schema/postPurchaseOfferEligibility';
3
+ export declare const classifyPostPurchaseOffer: (settings: unknown, response: unknown, context: z.input<typeof PostPurchaseOfferEligibilityContext>,
4
+ /** STS opt-in; absent or `{ sts: false }` keeps every pre-STS outcome. */
5
+ options?: PostPurchaseStsOptions) => PostPurchaseOfferEligibility;
@@ -6368,6 +6368,12 @@ var import_zod54 = require("zod");
6368
6368
  // src/schema/postPurchaseProductGallery.ts
6369
6369
  var import_zod52 = require("zod");
6370
6370
  var PostPurchaseProductGallery = import_zod52.z.object({
6371
+ /**
6372
+ * Show the thumbnail row: the product had more than one image before `images` was capped at the
6373
+ * sub-image limit, and that limit allows at least one thumbnail. It stays true when the cap leaves one
6374
+ * image (legacy checks the count before slicing). Older replies omit it; fall back to `images.length > 1`.
6375
+ */
6376
+ hasMultiple: import_zod52.z.boolean().optional(),
6371
6377
  images: import_zod52.z.array(
6372
6378
  import_zod52.z.object({
6373
6379
  description: import_zod52.z.string(),
@@ -6533,9 +6539,12 @@ var subscriptionUnavailable = (normalized, plan, allowCollection, quantity3) =>
6533
6539
  const { data, effective, original } = normalized;
6534
6540
  const unavailable = "An eligible subscription plan with supported shipping and discount is required";
6535
6541
  if (data.length !== 1 || data[0].variants.length !== 1) return unavailable;
6536
- if (effective.productType === "one-time" || [original, effective].some(
6537
- (config) => !allowCollection && config.productLimit !== 1 || config.upgradeToSubscription.allow || !quantity3 && config.quantityInputs.enabled && (config.quantityInputs.minValue !== config.quantityInputs.maxValue || config.quantityInputs.defaultQuantity !== config.quantityInputs.minValue)
6538
- ))
6542
+ if (
6543
+ // Legacy STS ran whatever the product type: its trigger forced the subscription option on.
6544
+ effective.productType === "one-time" && !quantity3?.sts || [original, effective].some(
6545
+ (config) => !allowCollection && config.productLimit !== 1 || config.upgradeToSubscription.allow && !quantity3?.sts || !quantity3 && config.quantityInputs.enabled && (config.quantityInputs.minValue !== config.quantityInputs.maxValue || config.quantityInputs.defaultQuantity !== config.quantityInputs.minValue)
6546
+ )
6547
+ )
6539
6548
  return unavailable;
6540
6549
  const product = data[0];
6541
6550
  const variant2 = product.variants[0];
@@ -6560,15 +6569,19 @@ var postPurchasePrimaryImage = (product) => {
6560
6569
  };
6561
6570
 
6562
6571
  // src/server/postPurchaseProductGallery.ts
6563
- var postPurchaseProductGallery = (product, limit) => ({
6564
- images: (product.images ?? []).slice(0, limit ?? 0).map((image) => ({
6565
- description: image.alt ?? product.title,
6566
- id: image.id,
6567
- source: sizeImageSource(image.src, "800x800"),
6568
- thumbnail: sizeImageSource(image.src, "200x200")
6569
- })),
6570
- selectedImageId: product.images?.find((image) => image.id === product.variants[0].imageId)?.id
6571
- });
6572
+ var postPurchaseProductGallery = (product, limit) => {
6573
+ const cap = Math.max(Math.floor(limit ?? 0), 0);
6574
+ return {
6575
+ hasMultiple: (product.images?.length ?? 0) > 1 && cap >= 1,
6576
+ images: (product.images ?? []).slice(0, cap).map((image) => ({
6577
+ description: image.alt ?? product.title,
6578
+ id: image.id,
6579
+ source: sizeImageSource(image.src, "800x800"),
6580
+ thumbnail: sizeImageSource(image.src, "200x200")
6581
+ })),
6582
+ selectedImageId: product.images?.find((image) => image.id === product.variants[0].imageId)?.id
6583
+ };
6584
+ };
6572
6585
 
6573
6586
  // src/transforms/postPurchase/convertDescriptionRte.ts
6574
6587
  var import_zod58 = require("zod");
@@ -7261,7 +7274,7 @@ var PostPurchaseMemberIdentity = import_zod75.z.object({
7261
7274
  }).strict();
7262
7275
 
7263
7276
  // src/schema/postPurchaseAdmission.ts
7264
- var PurchaseAdmissionModeSchema = import_zod76.z.enum(["purchase", "upgrade"]);
7277
+ var PurchaseAdmissionModeSchema = import_zod76.z.enum(["purchase", "sts"]);
7265
7278
  var selection = PreparedPostPurchaseProduct.shape.selection;
7266
7279
  var EventCalculationSchema = PostPurchaseProductCosts.pick({ currencyCode: true, totalMinor: true }).strict();
7267
7280
  var PurchaseExpectedSchema = import_zod76.z.object({
@@ -7283,8 +7296,8 @@ var PurchaseExpectedSchema = import_zod76.z.object({
7283
7296
  ({ member, progressRevision }) => !member || progressRevision !== void 0,
7284
7297
  "Captured member requires progress"
7285
7298
  ).refine(
7286
- ({ mode, selection: { sellingPlanId } }) => mode !== "upgrade" || sellingPlanId !== void 0,
7287
- "An upgrade selects a subscription"
7299
+ ({ mode, selection: { sellingPlanId } }) => mode !== "sts" || sellingPlanId !== void 0,
7300
+ "An STS selects a subscription"
7288
7301
  ).refine(({ buyerConsentToSubscriptions: consent, changeset, selection: selection4 }) => {
7289
7302
  const [change, shipping] = changeset.changes;
7290
7303
  if (selection4.sellingPlanId === void 0)
@@ -7300,7 +7313,7 @@ var PurchaseReceiptSchema = import_zod76.z.object({
7300
7313
  changesetToken: import_zod76.z.string().min(1),
7301
7314
  mode: PurchaseAdmissionModeSchema.optional(),
7302
7315
  operationId: import_zod76.z.uuid(),
7303
- /** The server-bound one-time line an upgrade refunds; its quantity is the order's, not the selection's. */
7316
+ /** The server-bound one-time line an STS refunds; its quantity is the order's, not the selection's. */
7304
7317
  originalLine: import_zod76.z.strictObject({ quantity: selection.shape.quantity, variantId: selection.shape.variantId }).optional(),
7305
7318
  requiresSubscriptionConsent: import_zod76.z.boolean(),
7306
7319
  selection
@@ -7308,8 +7321,8 @@ var PurchaseReceiptSchema = import_zod76.z.object({
7308
7321
  ({ requiresSubscriptionConsent, selection: selection4 }) => requiresSubscriptionConsent === (selection4.sellingPlanId !== void 0),
7309
7322
  "Receipt consent must match its selected plan"
7310
7323
  ).refine(
7311
- ({ mode, originalLine, selection: { sellingPlanId, variantId } }) => mode === "upgrade" ? sellingPlanId !== void 0 && originalLine?.variantId === variantId : originalLine === void 0,
7312
- "An upgrade Receipt binds the original line of its subscribed variant, and only an upgrade does"
7324
+ ({ mode, originalLine, selection: { sellingPlanId, variantId } }) => mode === "sts" ? sellingPlanId !== void 0 && originalLine?.variantId === variantId : originalLine === void 0,
7325
+ "An STS Receipt binds the original line of its subscribed variant, and only an STS does"
7313
7326
  );
7314
7327
  var PurchaseResponseSchema = import_zod76.z.object({ data: PurchaseReceiptSchema, successful: import_zod76.z.literal(true) });
7315
7328
 
@@ -7433,14 +7446,41 @@ var projectPostPurchaseVariantCatalog = (product, settings) => {
7433
7446
  });
7434
7447
  };
7435
7448
 
7436
- // src/schema/postPurchaseQuantity.ts
7449
+ // src/schema/postPurchaseOfferEligibility.ts
7437
7450
  var import_zod82 = require("zod");
7451
+ var selection2 = PreparedPostPurchaseProduct.shape.selection;
7452
+ var PostPurchaseOfferSkipReason = import_zod82.z.enum(["empty", "no-eligible-subscription"]);
7453
+ var PostPurchaseOfferEligibilityContext = import_zod82.z.object({
7454
+ excludedProductIds: PostPurchaseExcludedProductIds,
7455
+ originalLineItems: import_zod82.z.array(selection2.pick({ productId: true, sellingPlanId: true, variantId: true }))
7456
+ });
7457
+ var PostPurchaseStsOptions = import_zod82.z.object({ sts: import_zod82.z.boolean().optional() }).strict();
7458
+ var PostPurchaseStsContext = import_zod82.z.object({
7459
+ originalLineItems: import_zod82.z.array(
7460
+ selection2.pick({ productId: true, quantity: true, sellingPlanId: true, variantId: true })
7461
+ )
7462
+ });
7463
+ var PostPurchaseOfferEligibility = import_zod82.z.discriminatedUnion("status", [
7464
+ import_zod82.z.object({
7465
+ members: import_zod82.z.array(
7466
+ import_zod82.z.object({ productId: selection2.shape.productId, productIndex: import_zod82.z.number().int().nonnegative() })
7467
+ ),
7468
+ /** Present only with STS on: each member switches one original one-time line to subscription. */
7469
+ mode: import_zod82.z.literal("sts").optional(),
7470
+ status: import_zod82.z.literal("retain")
7471
+ }),
7472
+ import_zod82.z.object({ reason: PostPurchaseOfferSkipReason, status: import_zod82.z.literal("skip") }),
7473
+ import_zod82.z.object({ reason: import_zod82.z.literal("eligible-sts").optional(), status: import_zod82.z.literal("unavailable") })
7474
+ ]);
7475
+
7476
+ // src/schema/postPurchaseQuantity.ts
7477
+ var import_zod83 = require("zod");
7438
7478
  var quantity2 = PreparedPostPurchaseProduct.shape.selection.shape.quantity;
7439
7479
  var PostPurchaseQuantityChoice = PostPurchaseCollectionChoice.extend({ quantity: quantity2.optional() });
7440
7480
  var PostPurchaseQuantityPolicy = PostPurchaseSettings.shape.quantityInputs.omit({ defaultQuantity: true }).extend({
7441
7481
  initialQuantity: quantity2,
7442
7482
  maxValue: quantity2,
7443
- minValue: import_zod82.z.literal(0).transform(() => 1).or(quantity2)
7483
+ minValue: import_zod83.z.literal(0).transform(() => 1).or(quantity2)
7444
7484
  }).refine(({ maxValue, minValue }) => minValue <= maxValue, "Quantity bounds are reversed");
7445
7485
 
7446
7486
  // src/server/readPostPurchaseQuantity.ts
@@ -7470,40 +7510,88 @@ var readPostPurchaseQuantity = ({
7470
7510
  return { policy, quantity: quantity3 };
7471
7511
  };
7472
7512
 
7513
+ // src/server/postPurchaseSts.ts
7514
+ var stsAllowed = ({ effective, original }) => [original, effective].some((config) => config.upgradeToSubscription.allow);
7515
+ var postPurchaseStsLine = (normalized, product, lines, variantId) => {
7516
+ if (!product.sellingPlanGroups?.length || product.productGroupVariants.length) return void 0;
7517
+ for (const variant2 of product.variants) {
7518
+ const matched = lines.filter((line) => line.sellingPlanId === void 0 && line.variantId === variant2.id);
7519
+ const data = [{ ...product, variants: [variant2] }];
7520
+ if ((variantId === void 0 || variant2.id === variantId) && matched.length === 1 && postPurchaseVariantAvailable(variant2) && projectPostPurchasePlanCatalog({ ...normalized, data })?.plans.length)
7521
+ return { data, line: matched[0] };
7522
+ }
7523
+ };
7524
+ var preparePostPurchaseStsView = (widgetId, normalized, product, context, requested, report) => {
7525
+ const { originalLineItems } = PostPurchaseStsContext.parse(context);
7526
+ const found = postPurchaseStsLine(normalized, product, originalLineItems, requested.variantId);
7527
+ if (!found) return null;
7528
+ const whole = found.line.quantity;
7529
+ if (requested.quantity !== void 0 && requested.quantity !== whole)
7530
+ throw new PostPurchaseQuantityUnavailable("An STS covers the whole original quantity");
7531
+ const bounds = { initialQuantity: whole, maxValue: whole, minValue: whole };
7532
+ const policy = PostPurchaseQuantityPolicy.parse({ enabled: false, ...bounds });
7533
+ const quantity3 = { policy, quantity: whole, sts: true };
7534
+ const input = { ...normalized, data: found.data };
7535
+ return {
7536
+ quantity: quantity3,
7537
+ sts: {
7538
+ emailRefundNotice: normalized.effective.upgradeToSubscription.emailRefundNotice,
7539
+ originalLine: { quantity: whole, variantId: found.line.variantId }
7540
+ },
7541
+ view: prepareNormalizedPostPurchaseView(widgetId, input, report, requested.choice, quantity3, true)
7542
+ };
7543
+ };
7544
+ var prepareStsCollectionMember = (widgetId, normalized, { product, productIndex }, context, choice, report) => {
7545
+ const stsResult = preparePostPurchaseStsView(widgetId, normalized, product, context, { choice }, report);
7546
+ return stsResult && { productId: product.id, productIndex, reportingProduct: void 0, view: stsResult.view };
7547
+ };
7548
+
7549
+ // src/server/preparePostPurchaseStsMember.ts
7550
+ var preparePostPurchaseStsMember = (widgetId, settings, response, selected, sts, requestedQuantity, report) => {
7551
+ const { members, normalized } = normalizePostPurchaseCollection(settings, response);
7552
+ if (!stsAllowed(normalized)) return void 0;
7553
+ const member = members.find(({ product }) => product.id === selected.productId);
7554
+ const quantity3 = requestedQuantity && ("quantity" in requestedQuantity ? requestedQuantity.quantity : requestedQuantity.expectedQuantity);
7555
+ const prepared = member && preparePostPurchaseStsView(widgetId, normalized, member.product, sts, { ...selected, quantity: quantity3 }, report);
7556
+ if (!member || !prepared) return null;
7557
+ const { view, ...facts } = prepared;
7558
+ return { ...facts, member: { productId: member.product.id, productIndex: member.productIndex, view }, normalized };
7559
+ };
7560
+
7473
7561
  // src/schema/postPurchaseVariantDefault.ts
7474
- var import_zod83 = require("zod");
7562
+ var import_zod84 = require("zod");
7475
7563
  var values = PostPurchaseVariantValues.partial().extend({
7476
7564
  option1: PostPurchaseVariantValues.shape.option1.nullish()
7477
7565
  });
7478
7566
  var variant = values.extend({
7479
7567
  id: PostPurchaseVariantId,
7480
- inventoryManagement: import_zod83.z.string().nullable(),
7481
- inventoryPolicy: import_zod83.z.string(),
7482
- inventoryQuantity: import_zod83.z.number()
7568
+ inventoryManagement: import_zod84.z.string().nullable(),
7569
+ inventoryPolicy: import_zod84.z.string(),
7570
+ inventoryQuantity: import_zod84.z.number()
7483
7571
  });
7484
- var options = import_zod83.z.array(PostPurchaseVariantOption.pick({ name: true, values: true }));
7485
- var PostPurchaseVariantDefaultProduct = import_zod83.z.object({
7572
+ var options = import_zod84.z.array(PostPurchaseVariantOption.pick({ name: true, values: true }));
7573
+ var PostPurchaseVariantDefaultProduct = import_zod84.z.object({
7486
7574
  id: PostPurchaseProductId,
7487
7575
  options,
7488
7576
  selectedVariant: variant.optional(),
7489
- variants: import_zod83.z.array(variant)
7577
+ variants: import_zod84.z.array(variant)
7490
7578
  });
7491
7579
  var PostPurchaseVariantDefaultSettings = PostPurchaseSettings.shape.productOptions.pick({
7492
7580
  hideOutOfStockVariants: true,
7493
7581
  matchVariant: true
7494
7582
  });
7495
- var PostPurchaseOrderAttributes = import_zod83.z.record(import_zod83.z.string(), import_zod83.z.array(import_zod83.z.string())).default({});
7496
- var PostPurchaseOriginalVariants = import_zod83.z.array(
7497
- import_zod83.z.object({ productId: PostPurchaseProductId, variantId: PostPurchaseVariantId })
7583
+ var PostPurchaseOrderAttributes = import_zod84.z.record(import_zod84.z.string(), import_zod84.z.array(import_zod84.z.string())).default({});
7584
+ var PostPurchaseOriginalVariants = import_zod84.z.array(
7585
+ import_zod84.z.object({ productId: PostPurchaseProductId, variantId: PostPurchaseVariantId })
7498
7586
  );
7499
- var PostPurchaseAttributeProducts = import_zod83.z.array(
7500
- import_zod83.z.object({ id: PostPurchaseProductId, options, variants: import_zod83.z.array(values.extend({ id: PostPurchaseVariantId })) })
7587
+ var PostPurchaseAttributeProducts = import_zod84.z.array(
7588
+ import_zod84.z.object({ id: PostPurchaseProductId, options, variants: import_zod84.z.array(values.extend({ id: PostPurchaseVariantId })) })
7501
7589
  );
7502
7590
 
7503
7591
  // src/schema/postPurchaseVariantDefaultContext.ts
7504
- var import_zod84 = require("zod");
7505
- var PostPurchaseVariantDefaultContext = import_zod84.z.object({
7506
- enrichedLineItems: import_zod84.z.unknown().optional(),
7592
+ var import_zod85 = require("zod");
7593
+ var PostPurchaseVariantDefaultContext = import_zod85.z.object({
7594
+ enrichedLineItems: import_zod85.z.unknown().optional(),
7507
7595
  originalVariants: PostPurchaseOriginalVariants
7508
7596
  });
7509
7597
 
@@ -7578,8 +7666,10 @@ var resolvePostPurchaseMemberDefault = (product, original, context) => {
7578
7666
  };
7579
7667
 
7580
7668
  // src/server/preparePostPurchaseMemberView.ts
7581
- var prepareMember = (widgetId, settings, response, requested, report, excludedProductIds, requestedQuantity, defaults) => {
7669
+ var prepareMember = (widgetId, settings, response, requested, report, excludedProductIds, requestedQuantity, defaults, sts) => {
7582
7670
  const selected = PostPurchaseCollectionChoice.parse(requested);
7671
+ const stsResult = sts && preparePostPurchaseStsMember(widgetId, settings, response, selected, sts, requestedQuantity, report);
7672
+ if (stsResult !== void 0) return stsResult;
7583
7673
  const { members, normalized } = normalizePostPurchaseCollection(settings, response, excludedProductIds);
7584
7674
  const found = members.find(({ product: product2 }) => product2.id === selected.productId);
7585
7675
  if (!found) return null;
@@ -7606,7 +7696,7 @@ var preparePostPurchaseMemberAdmissionView = (widgetId, settings, response, requ
7606
7696
  };
7607
7697
 
7608
7698
  // src/server/preparePostPurchaseQuantityView.ts
7609
- var preparePostPurchaseQuantityView = (widgetId, settings, response, requested, report, excludedProductIds, defaults) => {
7699
+ var preparePostPurchaseQuantityView = (widgetId, settings, response, requested, report, excludedProductIds, defaults, sts) => {
7610
7700
  const { quantity: quantity3, ...selection4 } = PostPurchaseQuantityChoice.parse(requested);
7611
7701
  const prepared = prepareMember(
7612
7702
  widgetId,
@@ -7616,15 +7706,21 @@ var preparePostPurchaseQuantityView = (widgetId, settings, response, requested,
7616
7706
  report,
7617
7707
  excludedProductIds,
7618
7708
  { quantity: quantity3 },
7619
- defaults
7709
+ defaults,
7710
+ sts
7620
7711
  );
7621
- return prepared ? { ...prepared.member, quantityPolicy: prepared.quantity.policy } : null;
7712
+ if (!prepared) return null;
7713
+ return {
7714
+ ...prepared.member,
7715
+ quantityPolicy: prepared.quantity.policy,
7716
+ ..."sts" in prepared && { sts: prepared.sts }
7717
+ };
7622
7718
  };
7623
7719
 
7624
7720
  // src/server/preparePostPurchaseQuantityAdmissionView.ts
7625
- var selection2 = PostPurchaseQuantityChoice.required({ quantity: true });
7626
- var preparePostPurchaseQuantityAdmissionView = (widgetId, settings, response, expected, report, excludedProductIds, defaults) => {
7627
- const { quantity: expectedQuantity, ...requested } = selection2.parse(expected);
7721
+ var selection3 = PostPurchaseQuantityChoice.required({ quantity: true });
7722
+ var preparePostPurchaseQuantityAdmissionView = (widgetId, settings, response, expected, report, excludedProductIds, defaults, sts) => {
7723
+ const { quantity: expectedQuantity, ...requested } = selection3.parse(expected);
7628
7724
  const prepared = prepareMember(
7629
7725
  widgetId,
7630
7726
  settings,
@@ -7633,11 +7729,17 @@ var preparePostPurchaseQuantityAdmissionView = (widgetId, settings, response, ex
7633
7729
  report,
7634
7730
  excludedProductIds,
7635
7731
  { expectedQuantity },
7636
- defaults
7732
+ defaults,
7733
+ sts
7637
7734
  );
7638
7735
  if (!prepared) return null;
7639
7736
  const { removePartialOrder } = PostPurchaseSettings.shape.advance.parse(prepared.normalized.effective.advance);
7640
- return { ...prepared.member, quantityPolicy: prepared.quantity.policy, removePartialOrder };
7737
+ return {
7738
+ ...prepared.member,
7739
+ quantityPolicy: prepared.quantity.policy,
7740
+ removePartialOrder,
7741
+ ..."sts" in prepared && { sts: prepared.sts }
7742
+ };
7641
7743
  };
7642
7744
 
7643
7745
  // src/schema/postPurchaseGroup.ts
@@ -7800,11 +7902,16 @@ var preparePostPurchaseCollectionGroup = (widgetId, settings, response, member,
7800
7902
 
7801
7903
  // src/server/preparePostPurchaseCollectionView.ts
7802
7904
  var CollectionChoice = PostPurchaseCollectionChoice.omit({ variantId: true });
7803
- var preparePostPurchaseCollectionView = (widgetId, settings, response, report, requested, excludedProductIds, defaults = { originalVariants: [] }) => {
7905
+ var preparePostPurchaseCollectionView = (widgetId, settings, response, report, requested, excludedProductIds, defaults, sts) => {
7804
7906
  const { members, normalized } = normalizePostPurchaseCollection(settings, response);
7805
7907
  const excluded = PostPurchaseExcludedProductIds.parse(excludedProductIds);
7806
7908
  const selected = CollectionChoice.optional().parse(requested);
7909
+ const stsMode = sts && stsAllowed(normalized) ? sts : void 0;
7807
7910
  const projected = members.map((member) => {
7911
+ if (stsMode) {
7912
+ const choice = member.product.id === selected?.productId ? selected.choice : void 0;
7913
+ return prepareStsCollectionMember(widgetId, normalized, member, stsMode, choice, report);
7914
+ }
7808
7915
  if (member.product.productGroupVariants.length) {
7809
7916
  if (selected?.productId === member.product.id && selected.choice)
7810
7917
  throw new Error("Grouped choices require selected merchandise");
@@ -7815,7 +7922,7 @@ var preparePostPurchaseCollectionView = (widgetId, settings, response, report, r
7815
7922
  member,
7816
7923
  normalized,
7817
7924
  excluded,
7818
- defaults,
7925
+ defaults ?? { originalVariants: [] },
7819
7926
  report
7820
7927
  );
7821
7928
  return group;
@@ -7846,25 +7953,6 @@ var preparePostPurchaseCollectionView = (widgetId, settings, response, report, r
7846
7953
  };
7847
7954
  };
7848
7955
 
7849
- // src/schema/postPurchaseOfferEligibility.ts
7850
- var import_zod85 = require("zod");
7851
- var selection3 = PreparedPostPurchaseProduct.shape.selection;
7852
- var PostPurchaseOfferSkipReason = import_zod85.z.enum(["empty", "no-eligible-subscription"]);
7853
- var PostPurchaseOfferEligibilityContext = import_zod85.z.object({
7854
- excludedProductIds: PostPurchaseExcludedProductIds,
7855
- originalLineItems: import_zod85.z.array(selection3.pick({ productId: true, sellingPlanId: true, variantId: true }))
7856
- });
7857
- var PostPurchaseOfferEligibility = import_zod85.z.discriminatedUnion("status", [
7858
- import_zod85.z.object({
7859
- members: import_zod85.z.array(
7860
- import_zod85.z.object({ productId: selection3.shape.productId, productIndex: import_zod85.z.number().int().nonnegative() })
7861
- ),
7862
- status: import_zod85.z.literal("retain")
7863
- }),
7864
- import_zod85.z.object({ reason: PostPurchaseOfferSkipReason, status: import_zod85.z.literal("skip") }),
7865
- import_zod85.z.object({ reason: import_zod85.z.literal("eligible-upgrade").optional(), status: import_zod85.z.literal("unavailable") })
7866
- ]);
7867
-
7868
7956
  // src/server/postPurchaseMemberEligibility.ts
7869
7957
  var PostPurchaseInventoryUnavailable = class extends Error {
7870
7958
  };
@@ -7893,22 +7981,28 @@ var postPurchaseMemberEligibility = (normalized, product, excluded) => {
7893
7981
  };
7894
7982
 
7895
7983
  // src/server/classifyPostPurchaseOffer.ts
7896
- var classifyPostPurchaseOffer = (settings, response, context) => {
7984
+ var identities = (members) => members.map(({ product, productIndex }) => ({ productId: product.id, productIndex }));
7985
+ var classifyPostPurchaseOffer = (settings, response, context, options2) => {
7897
7986
  try {
7898
7987
  const trusted = PostPurchaseOfferEligibilityContext.parse(context);
7988
+ const { sts: stsMode = false } = PostPurchaseStsOptions.parse(options2 ?? {});
7899
7989
  const { members, normalized } = normalizePostPurchaseCollection(settings, response);
7900
7990
  const configurations = [normalized.original, normalized.effective];
7901
- const upgrades = configurations.some((config) => config.upgradeToSubscription.allow);
7991
+ const stsEnabled = configurations.some((config) => config.upgradeToSubscription.allow);
7992
+ const sts = stsEnabled && stsMode;
7902
7993
  const oneTime = new Set(
7903
7994
  trusted.originalLineItems.filter((line) => line.sellingPlanId === void 0).map((line) => line.variantId)
7904
7995
  );
7905
- if (upgrades && members.some(
7996
+ if (stsEnabled && !stsMode && members.some(
7906
7997
  ({ product }) => product.sellingPlanGroups?.length && product.variants.some((variant2) => oneTime.has(variant2.id))
7907
7998
  ))
7908
- return { reason: "eligible-upgrade", status: "unavailable" };
7909
- if (normalized.effective.productType !== "one-time") {
7999
+ return { reason: "eligible-sts", status: "unavailable" };
8000
+ if (normalized.effective.productType !== "one-time" || sts) {
7910
8001
  configurations.forEach((config) => PostPurchaseSubscriptionSettings.parse(config.subscription));
7911
8002
  }
8003
+ const lines = trusted.originalLineItems;
8004
+ const stsMembers = sts ? members.filter(({ product }) => postPurchaseStsLine(normalized, product, lines)) : [];
8005
+ if (stsMembers.length) return { members: identities(stsMembers), mode: "sts", status: "retain" };
7912
8006
  const classified = members.map((member) => {
7913
8007
  try {
7914
8008
  return {
@@ -7922,19 +8016,13 @@ var classifyPostPurchaseOffer = (settings, response, context) => {
7922
8016
  }
7923
8017
  });
7924
8018
  if (!members.length) return { reason: "empty", status: "skip" };
7925
- if (upgrades) return { reason: "no-eligible-subscription", status: "skip" };
8019
+ if (stsEnabled) return { reason: "no-eligible-subscription", status: "skip" };
7926
8020
  const candidates = classified.filter(
7927
8021
  ({ product }) => product.productGroupVariants.length ? readPostPurchaseGroup(product, normalized.effective, trusted.excludedProductIds).entries.length > 0 : !trusted.excludedProductIds.includes(product.id)
7928
8022
  );
7929
8023
  if (!candidates.length) return { reason: "empty", status: "skip" };
7930
8024
  const retained = candidates.filter(({ eligible }) => eligible);
7931
- return retained.length ? {
7932
- members: retained.map(({ product, productIndex }) => ({
7933
- productId: product.id,
7934
- productIndex
7935
- })),
7936
- status: "retain"
7937
- } : { reason: "no-eligible-subscription", status: "skip" };
8025
+ return retained.length ? { members: identities(retained), status: "retain" } : { reason: "no-eligible-subscription", status: "skip" };
7938
8026
  } catch {
7939
8027
  return { status: "unavailable" };
7940
8028
  }