@rebuy/rebuy 3.57.0 → 3.59.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 +2 -2
- package/dist/gwp/index.mjs +2 -2
- package/dist/index.cjs +30 -13
- package/dist/index.mjs +30 -13
- package/dist/schema/offerProduct.d.ts +3 -3
- package/dist/schema/postPurchaseFollowups.d.ts +4 -0
- package/dist/schema/postPurchaseRecovery.d.ts +4 -0
- package/dist/schema/postPurchaseSts.d.ts +25 -1
- package/dist/server/index.cjs +25 -19
- package/dist/server/index.mjs +25 -19
- package/dist/server/postPurchasePlanCatalog.d.ts +4 -0
- package/dist/server/postPurchaseSellingPlanRequirement.d.ts +14 -0
- package/dist/server/postPurchaseSts.d.ts +3 -1
- package/dist/server/shared.d.ts +16 -7
- package/package.json +1 -1
package/dist/gwp/index.cjs
CHANGED
|
@@ -37,8 +37,8 @@ var getValidGwpProductIds = (matchedRules = []) => new Set(
|
|
|
37
37
|
|
|
38
38
|
// src/gwp/hasUnsupportedRuleTypes.ts
|
|
39
39
|
var UNSUPPORTED_RULE_TYPES = ["url", "order_tag"];
|
|
40
|
-
var
|
|
41
|
-
var isUnsupportedType = (type = "") => UNSUPPORTED_RULE_TYPES.includes(type) || type.
|
|
40
|
+
var UNSUPPORTED_RULE_TYPE_FRAGMENT = "geolocation";
|
|
41
|
+
var isUnsupportedType = (type = "") => UNSUPPORTED_RULE_TYPES.includes(type) || type.includes(UNSUPPORTED_RULE_TYPE_FRAGMENT);
|
|
42
42
|
var ruleHasUnsupportedType = (rule) => (rule.logic ?? []).some((group) => (group.rules ?? []).some((item) => isUnsupportedType(item.type)));
|
|
43
43
|
var hasUnsupportedRuleTypes = (metadata) => [...metadata?.matchedRules ?? [], ...metadata?.unmatchedRules ?? []].some(ruleHasUnsupportedType);
|
|
44
44
|
|
package/dist/gwp/index.mjs
CHANGED
|
@@ -5,8 +5,8 @@ var getValidGwpProductIds = (matchedRules = []) => new Set(
|
|
|
5
5
|
|
|
6
6
|
// src/gwp/hasUnsupportedRuleTypes.ts
|
|
7
7
|
var UNSUPPORTED_RULE_TYPES = ["url", "order_tag"];
|
|
8
|
-
var
|
|
9
|
-
var isUnsupportedType = (type = "") => UNSUPPORTED_RULE_TYPES.includes(type) || type.
|
|
8
|
+
var UNSUPPORTED_RULE_TYPE_FRAGMENT = "geolocation";
|
|
9
|
+
var isUnsupportedType = (type = "") => UNSUPPORTED_RULE_TYPES.includes(type) || type.includes(UNSUPPORTED_RULE_TYPE_FRAGMENT);
|
|
10
10
|
var ruleHasUnsupportedType = (rule) => (rule.logic ?? []).some((group) => (group.rules ?? []).some((item) => isUnsupportedType(item.type)));
|
|
11
11
|
var hasUnsupportedRuleTypes = (metadata) => [...metadata?.matchedRules ?? [], ...metadata?.unmatchedRules ?? []].some(ruleHasUnsupportedType);
|
|
12
12
|
|
package/dist/index.cjs
CHANGED
|
@@ -1698,7 +1698,7 @@ var OfferProductDiscount = import_zod5.z.object({
|
|
|
1698
1698
|
type: import_zod5.z.string()
|
|
1699
1699
|
});
|
|
1700
1700
|
var OfferProductOption = import_zod5.z.object({
|
|
1701
|
-
id: import_zod5.z.number(),
|
|
1701
|
+
id: import_zod5.z.number().optional(),
|
|
1702
1702
|
name: import_zod5.z.string(),
|
|
1703
1703
|
position: import_zod5.z.number(),
|
|
1704
1704
|
values: import_zod5.z.array(import_zod5.z.string())
|
|
@@ -1710,7 +1710,7 @@ var OfferProductVariant = import_zod5.z.object({
|
|
|
1710
1710
|
inventoryManagement: import_zod5.z.string().nullable(),
|
|
1711
1711
|
inventoryPolicy: import_zod5.z.string(),
|
|
1712
1712
|
inventoryQuantity: import_zod5.z.number(),
|
|
1713
|
-
link: import_zod5.z.string(),
|
|
1713
|
+
link: import_zod5.z.string().optional(),
|
|
1714
1714
|
option1: import_zod5.z.string(),
|
|
1715
1715
|
option2: import_zod5.z.string().nullable(),
|
|
1716
1716
|
option3: import_zod5.z.string().nullable(),
|
|
@@ -1723,12 +1723,12 @@ var OfferProduct = import_zod5.z.object({
|
|
|
1723
1723
|
id: import_zod5.z.number(),
|
|
1724
1724
|
image: import_zod5.z.object({ src: import_zod5.z.string() }).nullish(),
|
|
1725
1725
|
/**
|
|
1726
|
-
* `variantIds` is
|
|
1726
|
+
* `variantIds` is nullish: the engine omits `variant_ids` (rather than sending `[]`) on an image tied to no
|
|
1727
1727
|
* variant — seen live on the `recommended` data source while `top_sellers` sends `[]` for the same image
|
|
1728
|
-
* (REB-24958). A missing list means "not variant-specific", exactly like `[]`, so the image
|
|
1729
|
-
* and the product is never dropped over it.
|
|
1728
|
+
* (REB-24958). A missing (or `null`) list means "not variant-specific", exactly like `[]`, so the image
|
|
1729
|
+
* keeps its `src` and the product is never dropped over it.
|
|
1730
1730
|
*/
|
|
1731
|
-
images: import_zod5.z.array(import_zod5.z.object({ src: import_zod5.z.string(), variantIds: import_zod5.z.array(import_zod5.z.number()).
|
|
1731
|
+
images: import_zod5.z.array(import_zod5.z.object({ src: import_zod5.z.string(), variantIds: import_zod5.z.array(import_zod5.z.number()).nullish() })).nullish(),
|
|
1732
1732
|
link: import_zod5.z.string().optional(),
|
|
1733
1733
|
metafields: import_zod5.z.array(import_zod5.z.object({ key: import_zod5.z.string(), namespace: import_zod5.z.string(), value: import_zod5.z.string() })).optional(),
|
|
1734
1734
|
options: import_zod5.z.array(OfferProductOption),
|
|
@@ -3313,7 +3313,15 @@ var StsCompensationProgressSchema = import_zod42.z.union([
|
|
|
3313
3313
|
AttemptSchema2,
|
|
3314
3314
|
FinishedSchema.extend({ status: import_zod42.z.enum(["removed", "failed", "unknown"]) })
|
|
3315
3315
|
]);
|
|
3316
|
-
var StsReviewReasonSchema = import_zod42.z.enum([
|
|
3316
|
+
var StsReviewReasonSchema = import_zod42.z.enum([
|
|
3317
|
+
"refund-unknown",
|
|
3318
|
+
"compensation-failed",
|
|
3319
|
+
"compensation-unknown",
|
|
3320
|
+
"charge-unconfirmed",
|
|
3321
|
+
"refund-lost",
|
|
3322
|
+
"compensation-lost",
|
|
3323
|
+
"refund-owed"
|
|
3324
|
+
]);
|
|
3317
3325
|
var StsReviewProgressSchema = import_zod42.z.strictObject({
|
|
3318
3326
|
markedAt: PostPurchaseTimestampSchema,
|
|
3319
3327
|
marker: AcceptedMetafieldResultSchema.shape.status,
|
|
@@ -3325,6 +3333,12 @@ var reviewReason = (refund, compensation) => {
|
|
|
3325
3333
|
return `compensation-${compensation.status}`;
|
|
3326
3334
|
return null;
|
|
3327
3335
|
};
|
|
3336
|
+
var judgedReason = (refund, compensation) => {
|
|
3337
|
+
if (refund === null) return "charge-unconfirmed";
|
|
3338
|
+
if (refund.status === "attempted") return "refund-lost";
|
|
3339
|
+
if (compensation?.status === "attempted") return "compensation-lost";
|
|
3340
|
+
return compensation?.status === "removed" ? "refund-owed" : null;
|
|
3341
|
+
};
|
|
3328
3342
|
var StsProgressSchema = import_zod42.z.strictObject({
|
|
3329
3343
|
compensation: StsCompensationProgressSchema.nullable(),
|
|
3330
3344
|
operationId: PurchaseReceiptSchema.shape.operationId,
|
|
@@ -3333,10 +3347,11 @@ var StsProgressSchema = import_zod42.z.strictObject({
|
|
|
3333
3347
|
}).refine(
|
|
3334
3348
|
({ compensation, refund }) => compensation === null || refund?.status === "failed",
|
|
3335
3349
|
"Compensation follows a known refund failure only"
|
|
3336
|
-
).refine(
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
);
|
|
3350
|
+
).refine(({ compensation, refund, review }) => {
|
|
3351
|
+
const resolved = reviewReason(refund, compensation);
|
|
3352
|
+
const reason = review?.reason ?? null;
|
|
3353
|
+
return reason === resolved || resolved === null && reason === judgedReason(refund, compensation);
|
|
3354
|
+
}, "Review must match the unresolved outcome");
|
|
3340
3355
|
|
|
3341
3356
|
// src/schema/postPurchaseFollowups.ts
|
|
3342
3357
|
var RequiredHealthSchema = import_zod43.z.union([
|
|
@@ -4918,8 +4933,10 @@ var PurchaseRecoveryRequestSchema = DecideRequestSchema.strict();
|
|
|
4918
4933
|
var PurchaseRecoveryResponseSchema = import_zod84.z.object({
|
|
4919
4934
|
data: import_zod84.z.object({
|
|
4920
4935
|
/**
|
|
4921
|
-
* Strict, so
|
|
4922
|
-
*
|
|
4936
|
+
* Strict, so rebuy-api (which validates its own reply against this schema) can never emit a field the
|
|
4937
|
+
* contract does not name. cab-post-purchase reads recovery with hand guards that ignore extra keys, so
|
|
4938
|
+
* the strictness never reaches it: release rebuy-api (the pin bump) first, then the client that reads a
|
|
4939
|
+
* field added here.
|
|
4923
4940
|
*/
|
|
4924
4941
|
operation: import_zod84.z.object({
|
|
4925
4942
|
/** Absent from a rebuy-api that predates it. */
|
package/dist/index.mjs
CHANGED
|
@@ -1218,7 +1218,7 @@ var OfferProductDiscount = z5.object({
|
|
|
1218
1218
|
type: z5.string()
|
|
1219
1219
|
});
|
|
1220
1220
|
var OfferProductOption = z5.object({
|
|
1221
|
-
id: z5.number(),
|
|
1221
|
+
id: z5.number().optional(),
|
|
1222
1222
|
name: z5.string(),
|
|
1223
1223
|
position: z5.number(),
|
|
1224
1224
|
values: z5.array(z5.string())
|
|
@@ -1230,7 +1230,7 @@ var OfferProductVariant = z5.object({
|
|
|
1230
1230
|
inventoryManagement: z5.string().nullable(),
|
|
1231
1231
|
inventoryPolicy: z5.string(),
|
|
1232
1232
|
inventoryQuantity: z5.number(),
|
|
1233
|
-
link: z5.string(),
|
|
1233
|
+
link: z5.string().optional(),
|
|
1234
1234
|
option1: z5.string(),
|
|
1235
1235
|
option2: z5.string().nullable(),
|
|
1236
1236
|
option3: z5.string().nullable(),
|
|
@@ -1243,12 +1243,12 @@ var OfferProduct = z5.object({
|
|
|
1243
1243
|
id: z5.number(),
|
|
1244
1244
|
image: z5.object({ src: z5.string() }).nullish(),
|
|
1245
1245
|
/**
|
|
1246
|
-
* `variantIds` is
|
|
1246
|
+
* `variantIds` is nullish: the engine omits `variant_ids` (rather than sending `[]`) on an image tied to no
|
|
1247
1247
|
* variant — seen live on the `recommended` data source while `top_sellers` sends `[]` for the same image
|
|
1248
|
-
* (REB-24958). A missing list means "not variant-specific", exactly like `[]`, so the image
|
|
1249
|
-
* and the product is never dropped over it.
|
|
1248
|
+
* (REB-24958). A missing (or `null`) list means "not variant-specific", exactly like `[]`, so the image
|
|
1249
|
+
* keeps its `src` and the product is never dropped over it.
|
|
1250
1250
|
*/
|
|
1251
|
-
images: z5.array(z5.object({ src: z5.string(), variantIds: z5.array(z5.number()).
|
|
1251
|
+
images: z5.array(z5.object({ src: z5.string(), variantIds: z5.array(z5.number()).nullish() })).nullish(),
|
|
1252
1252
|
link: z5.string().optional(),
|
|
1253
1253
|
metafields: z5.array(z5.object({ key: z5.string(), namespace: z5.string(), value: z5.string() })).optional(),
|
|
1254
1254
|
options: z5.array(OfferProductOption),
|
|
@@ -2833,7 +2833,15 @@ var StsCompensationProgressSchema = z42.union([
|
|
|
2833
2833
|
AttemptSchema2,
|
|
2834
2834
|
FinishedSchema.extend({ status: z42.enum(["removed", "failed", "unknown"]) })
|
|
2835
2835
|
]);
|
|
2836
|
-
var StsReviewReasonSchema = z42.enum([
|
|
2836
|
+
var StsReviewReasonSchema = z42.enum([
|
|
2837
|
+
"refund-unknown",
|
|
2838
|
+
"compensation-failed",
|
|
2839
|
+
"compensation-unknown",
|
|
2840
|
+
"charge-unconfirmed",
|
|
2841
|
+
"refund-lost",
|
|
2842
|
+
"compensation-lost",
|
|
2843
|
+
"refund-owed"
|
|
2844
|
+
]);
|
|
2837
2845
|
var StsReviewProgressSchema = z42.strictObject({
|
|
2838
2846
|
markedAt: PostPurchaseTimestampSchema,
|
|
2839
2847
|
marker: AcceptedMetafieldResultSchema.shape.status,
|
|
@@ -2845,6 +2853,12 @@ var reviewReason = (refund, compensation) => {
|
|
|
2845
2853
|
return `compensation-${compensation.status}`;
|
|
2846
2854
|
return null;
|
|
2847
2855
|
};
|
|
2856
|
+
var judgedReason = (refund, compensation) => {
|
|
2857
|
+
if (refund === null) return "charge-unconfirmed";
|
|
2858
|
+
if (refund.status === "attempted") return "refund-lost";
|
|
2859
|
+
if (compensation?.status === "attempted") return "compensation-lost";
|
|
2860
|
+
return compensation?.status === "removed" ? "refund-owed" : null;
|
|
2861
|
+
};
|
|
2848
2862
|
var StsProgressSchema = z42.strictObject({
|
|
2849
2863
|
compensation: StsCompensationProgressSchema.nullable(),
|
|
2850
2864
|
operationId: PurchaseReceiptSchema.shape.operationId,
|
|
@@ -2853,10 +2867,11 @@ var StsProgressSchema = z42.strictObject({
|
|
|
2853
2867
|
}).refine(
|
|
2854
2868
|
({ compensation, refund }) => compensation === null || refund?.status === "failed",
|
|
2855
2869
|
"Compensation follows a known refund failure only"
|
|
2856
|
-
).refine(
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
);
|
|
2870
|
+
).refine(({ compensation, refund, review }) => {
|
|
2871
|
+
const resolved = reviewReason(refund, compensation);
|
|
2872
|
+
const reason = review?.reason ?? null;
|
|
2873
|
+
return reason === resolved || resolved === null && reason === judgedReason(refund, compensation);
|
|
2874
|
+
}, "Review must match the unresolved outcome");
|
|
2860
2875
|
|
|
2861
2876
|
// src/schema/postPurchaseFollowups.ts
|
|
2862
2877
|
var RequiredHealthSchema = z43.union([
|
|
@@ -4438,8 +4453,10 @@ var PurchaseRecoveryRequestSchema = DecideRequestSchema.strict();
|
|
|
4438
4453
|
var PurchaseRecoveryResponseSchema = z84.object({
|
|
4439
4454
|
data: z84.object({
|
|
4440
4455
|
/**
|
|
4441
|
-
* Strict, so
|
|
4442
|
-
*
|
|
4456
|
+
* Strict, so rebuy-api (which validates its own reply against this schema) can never emit a field the
|
|
4457
|
+
* contract does not name. cab-post-purchase reads recovery with hand guards that ignore extra keys, so
|
|
4458
|
+
* the strictness never reaches it: release rebuy-api (the pin bump) first, then the client that reads a
|
|
4459
|
+
* field added here.
|
|
4443
4460
|
*/
|
|
4444
4461
|
operation: z84.object({
|
|
4445
4462
|
/** Absent from a rebuy-api that predates it. */
|
|
@@ -21,7 +21,7 @@ export declare const OfferProduct: z.ZodObject<{
|
|
|
21
21
|
}, z.core.$strip>>>;
|
|
22
22
|
images: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
|
|
23
23
|
src: z.ZodString;
|
|
24
|
-
variantIds: z.ZodOptional<z.ZodArray<z.ZodNumber
|
|
24
|
+
variantIds: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber>>>;
|
|
25
25
|
}, z.core.$strip>>>>;
|
|
26
26
|
link: z.ZodOptional<z.ZodString>;
|
|
27
27
|
metafields: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -30,7 +30,7 @@ export declare const OfferProduct: z.ZodObject<{
|
|
|
30
30
|
value: z.ZodString;
|
|
31
31
|
}, z.core.$strip>>>;
|
|
32
32
|
options: z.ZodArray<z.ZodObject<{
|
|
33
|
-
id: z.ZodNumber
|
|
33
|
+
id: z.ZodOptional<z.ZodNumber>;
|
|
34
34
|
name: z.ZodString;
|
|
35
35
|
position: z.ZodNumber;
|
|
36
36
|
values: z.ZodArray<z.ZodString>;
|
|
@@ -46,7 +46,7 @@ export declare const OfferProduct: z.ZodObject<{
|
|
|
46
46
|
inventoryManagement: z.ZodNullable<z.ZodString>;
|
|
47
47
|
inventoryPolicy: z.ZodString;
|
|
48
48
|
inventoryQuantity: z.ZodNumber;
|
|
49
|
-
link: z.ZodString
|
|
49
|
+
link: z.ZodOptional<z.ZodString>;
|
|
50
50
|
option1: z.ZodString;
|
|
51
51
|
option2: z.ZodNullable<z.ZodString>;
|
|
52
52
|
option3: z.ZodNullable<z.ZodString>;
|
|
@@ -169,6 +169,10 @@ export declare const AcceptedFollowupsResponseSchema: z.ZodObject<{
|
|
|
169
169
|
"refund-unknown": "refund-unknown";
|
|
170
170
|
"compensation-failed": "compensation-failed";
|
|
171
171
|
"compensation-unknown": "compensation-unknown";
|
|
172
|
+
"charge-unconfirmed": "charge-unconfirmed";
|
|
173
|
+
"refund-lost": "refund-lost";
|
|
174
|
+
"compensation-lost": "compensation-lost";
|
|
175
|
+
"refund-owed": "refund-owed";
|
|
172
176
|
}>;
|
|
173
177
|
}, z.core.$strict>>;
|
|
174
178
|
}, z.core.$strict>>;
|
|
@@ -152,6 +152,10 @@ export declare const PurchaseRecoveryResponseSchema: z.ZodObject<{
|
|
|
152
152
|
"refund-unknown": "refund-unknown";
|
|
153
153
|
"compensation-failed": "compensation-failed";
|
|
154
154
|
"compensation-unknown": "compensation-unknown";
|
|
155
|
+
"charge-unconfirmed": "charge-unconfirmed";
|
|
156
|
+
"refund-lost": "refund-lost";
|
|
157
|
+
"compensation-lost": "compensation-lost";
|
|
158
|
+
"refund-owed": "refund-owed";
|
|
155
159
|
}>;
|
|
156
160
|
}, z.core.$strict>>;
|
|
157
161
|
}, z.core.$strict>>;
|
|
@@ -36,11 +36,25 @@ export declare const StsCompensationProgressSchema: z.ZodUnion<readonly [z.ZodOb
|
|
|
36
36
|
* Why the STS is left for a person; `marker` is the `subscription_rollback_failed` metafield write. A
|
|
37
37
|
* `marker` of `unavailable` means the marker could not be written, NOT that no review is needed: the review
|
|
38
38
|
* stands whatever the marker status.
|
|
39
|
+
*
|
|
40
|
+
* The first three follow from a finished step. The rest are a server's judgement the steps cannot show, so
|
|
41
|
+
* each is allowed (never required) beside one state only:
|
|
42
|
+
* - `charge-unconfirmed`: the server sweep could not confirm the charge (no result reported in time, or an
|
|
43
|
+
* Unknown one), so no step will ever start. Without it a late `/purchases/accepted` reads as not started,
|
|
44
|
+
* which looks pending forever.
|
|
45
|
+
* - `refund-lost` / `compensation-lost`: that step was sent but its outcome was never saved, so it stays
|
|
46
|
+
* `attempted` and may have moved money.
|
|
47
|
+
* - `refund-owed`: the rollback removed the subscription line, but apiv2's removal never refunds, so the
|
|
48
|
+
* buyer may still have been charged for it.
|
|
39
49
|
*/
|
|
40
50
|
export declare const StsReviewReasonSchema: z.ZodEnum<{
|
|
41
51
|
"refund-unknown": "refund-unknown";
|
|
42
52
|
"compensation-failed": "compensation-failed";
|
|
43
53
|
"compensation-unknown": "compensation-unknown";
|
|
54
|
+
"charge-unconfirmed": "charge-unconfirmed";
|
|
55
|
+
"refund-lost": "refund-lost";
|
|
56
|
+
"compensation-lost": "compensation-lost";
|
|
57
|
+
"refund-owed": "refund-owed";
|
|
44
58
|
}>;
|
|
45
59
|
export declare const StsReviewProgressSchema: z.ZodObject<{
|
|
46
60
|
markedAt: z.ZodNumber;
|
|
@@ -56,12 +70,18 @@ export declare const StsReviewProgressSchema: z.ZodObject<{
|
|
|
56
70
|
"refund-unknown": "refund-unknown";
|
|
57
71
|
"compensation-failed": "compensation-failed";
|
|
58
72
|
"compensation-unknown": "compensation-unknown";
|
|
73
|
+
"charge-unconfirmed": "charge-unconfirmed";
|
|
74
|
+
"refund-lost": "refund-lost";
|
|
75
|
+
"compensation-lost": "compensation-lost";
|
|
76
|
+
"refund-owed": "refund-owed";
|
|
59
77
|
}>;
|
|
60
78
|
}, z.core.$strict>;
|
|
61
79
|
/**
|
|
62
80
|
* The refund-compensation saga of one admitted STS, `null` steps not yet started. Compensation follows a
|
|
63
81
|
* known refund failure only, and a review is recorded exactly when the outcome is unresolved (an unknown
|
|
64
|
-
* refund, or a failed or unknown rollback), so a compensated or unresolved STS never reads as switched.
|
|
82
|
+
* refund, or a failed or unknown rollback), so a compensated or unresolved STS never reads as switched. A
|
|
83
|
+
* server may also record a review the steps cannot show (an unconfirmed charge, a lost step, a refund owed
|
|
84
|
+
* after the rollback), only beside the one state it applies to.
|
|
65
85
|
*/
|
|
66
86
|
export declare const StsProgressSchema: z.ZodObject<{
|
|
67
87
|
compensation: z.ZodNullable<z.ZodUnion<readonly [z.ZodObject<{
|
|
@@ -107,6 +127,10 @@ export declare const StsProgressSchema: z.ZodObject<{
|
|
|
107
127
|
"refund-unknown": "refund-unknown";
|
|
108
128
|
"compensation-failed": "compensation-failed";
|
|
109
129
|
"compensation-unknown": "compensation-unknown";
|
|
130
|
+
"charge-unconfirmed": "charge-unconfirmed";
|
|
131
|
+
"refund-lost": "refund-lost";
|
|
132
|
+
"compensation-lost": "compensation-lost";
|
|
133
|
+
"refund-owed": "refund-owed";
|
|
110
134
|
}>;
|
|
111
135
|
}, z.core.$strict>>;
|
|
112
136
|
}, z.core.$strict>;
|
package/dist/server/index.cjs
CHANGED
|
@@ -81,8 +81,8 @@ var getValidGwpProductIds = (matchedRules = []) => new Set(
|
|
|
81
81
|
|
|
82
82
|
// src/gwp/hasUnsupportedRuleTypes.ts
|
|
83
83
|
var UNSUPPORTED_RULE_TYPES = ["url", "order_tag"];
|
|
84
|
-
var
|
|
85
|
-
var isUnsupportedType = (type = "") => UNSUPPORTED_RULE_TYPES.includes(type) || type.
|
|
84
|
+
var UNSUPPORTED_RULE_TYPE_FRAGMENT = "geolocation";
|
|
85
|
+
var isUnsupportedType = (type = "") => UNSUPPORTED_RULE_TYPES.includes(type) || type.includes(UNSUPPORTED_RULE_TYPE_FRAGMENT);
|
|
86
86
|
var ruleHasUnsupportedType = (rule) => (rule.logic ?? []).some((group) => (group.rules ?? []).some((item) => isUnsupportedType(item.type)));
|
|
87
87
|
var hasUnsupportedRuleTypes = (metadata) => [...metadata?.matchedRules ?? [], ...metadata?.unmatchedRules ?? []].some(ruleHasUnsupportedType);
|
|
88
88
|
|
|
@@ -364,7 +364,7 @@ var OfferProductDiscount = import_zod3.z.object({
|
|
|
364
364
|
type: import_zod3.z.string()
|
|
365
365
|
});
|
|
366
366
|
var OfferProductOption = import_zod3.z.object({
|
|
367
|
-
id: import_zod3.z.number(),
|
|
367
|
+
id: import_zod3.z.number().optional(),
|
|
368
368
|
name: import_zod3.z.string(),
|
|
369
369
|
position: import_zod3.z.number(),
|
|
370
370
|
values: import_zod3.z.array(import_zod3.z.string())
|
|
@@ -376,7 +376,7 @@ var OfferProductVariant = import_zod3.z.object({
|
|
|
376
376
|
inventoryManagement: import_zod3.z.string().nullable(),
|
|
377
377
|
inventoryPolicy: import_zod3.z.string(),
|
|
378
378
|
inventoryQuantity: import_zod3.z.number(),
|
|
379
|
-
link: import_zod3.z.string(),
|
|
379
|
+
link: import_zod3.z.string().optional(),
|
|
380
380
|
option1: import_zod3.z.string(),
|
|
381
381
|
option2: import_zod3.z.string().nullable(),
|
|
382
382
|
option3: import_zod3.z.string().nullable(),
|
|
@@ -389,12 +389,12 @@ var OfferProduct = import_zod3.z.object({
|
|
|
389
389
|
id: import_zod3.z.number(),
|
|
390
390
|
image: import_zod3.z.object({ src: import_zod3.z.string() }).nullish(),
|
|
391
391
|
/**
|
|
392
|
-
* `variantIds` is
|
|
392
|
+
* `variantIds` is nullish: the engine omits `variant_ids` (rather than sending `[]`) on an image tied to no
|
|
393
393
|
* variant — seen live on the `recommended` data source while `top_sellers` sends `[]` for the same image
|
|
394
|
-
* (REB-24958). A missing list means "not variant-specific", exactly like `[]`, so the image
|
|
395
|
-
* and the product is never dropped over it.
|
|
394
|
+
* (REB-24958). A missing (or `null`) list means "not variant-specific", exactly like `[]`, so the image
|
|
395
|
+
* keeps its `src` and the product is never dropped over it.
|
|
396
396
|
*/
|
|
397
|
-
images: import_zod3.z.array(import_zod3.z.object({ src: import_zod3.z.string(), variantIds: import_zod3.z.array(import_zod3.z.number()).
|
|
397
|
+
images: import_zod3.z.array(import_zod3.z.object({ src: import_zod3.z.string(), variantIds: import_zod3.z.array(import_zod3.z.number()).nullish() })).nullish(),
|
|
398
398
|
link: import_zod3.z.string().optional(),
|
|
399
399
|
metafields: import_zod3.z.array(import_zod3.z.object({ key: import_zod3.z.string(), namespace: import_zod3.z.string(), value: import_zod3.z.string() })).optional(),
|
|
400
400
|
options: import_zod3.z.array(OfferProductOption),
|
|
@@ -426,6 +426,8 @@ var filterByB2bAvailability = async (products, input, ctx) => {
|
|
|
426
426
|
productIds: products.map(productGid),
|
|
427
427
|
shopifyShopDomain: input.shop
|
|
428
428
|
},
|
|
429
|
+
/** admin-api verifies it (REB-25081); absent, the call is unauthenticated (log-only there until enforced). */
|
|
430
|
+
...ctx.sessionToken && { headers: { Authorization: `Bearer ${ctx.sessionToken}` } },
|
|
429
431
|
host: ctx.host,
|
|
430
432
|
method: "POST"
|
|
431
433
|
}
|
|
@@ -6192,6 +6194,10 @@ var reportOncePerResponse = (response, report, events) => {
|
|
|
6192
6194
|
}
|
|
6193
6195
|
};
|
|
6194
6196
|
|
|
6197
|
+
// src/server/postPurchaseSellingPlanRequirement.ts
|
|
6198
|
+
var requiresOwnSellingPlan = (product) => product.requiresSellingPlan === true;
|
|
6199
|
+
var requiresUnsuppliedSellingPlan = (product) => requiresOwnSellingPlan(product) && !product.sellingPlanGroups?.length;
|
|
6200
|
+
|
|
6195
6201
|
// src/server/readPostPurchaseProductSource.ts
|
|
6196
6202
|
var Envelope = PostPurchaseProductSource.extend({ data: import_zod45.z.array(import_zod45.z.unknown()) });
|
|
6197
6203
|
var Product3 = PostPurchaseProductSource.shape.data.element;
|
|
@@ -6204,9 +6210,9 @@ var readPostPurchaseProductSource = (response, report) => {
|
|
|
6204
6210
|
const parsed = Product3.safeParse(raw);
|
|
6205
6211
|
if (parsed.success) {
|
|
6206
6212
|
rememberPostPurchaseProductSource(parsed.data, response, productIndex);
|
|
6207
|
-
if (parsed.data
|
|
6213
|
+
if (requiresUnsuppliedSellingPlan(parsed.data))
|
|
6208
6214
|
drift.push({
|
|
6209
|
-
detail: `
|
|
6215
|
+
detail: `Ineligible post-purchase product ${parsed.data.id}: data.${productIndex}.requiresSellingPlan`,
|
|
6210
6216
|
kind: "product"
|
|
6211
6217
|
});
|
|
6212
6218
|
return [{ product: parsed.data, productIndex }];
|
|
@@ -6397,19 +6403,20 @@ var readPostPurchaseModernPlans = (raw, allocations) => {
|
|
|
6397
6403
|
};
|
|
6398
6404
|
|
|
6399
6405
|
// src/server/postPurchasePlanCatalog.ts
|
|
6406
|
+
var hasLegacyPlanGroups = ({ sellingPlanGroups }) => typeof sellingPlanGroups[0]?.id === "number";
|
|
6400
6407
|
var projectPostPurchasePlanCatalog = (normalized, report) => {
|
|
6401
6408
|
const { data } = normalized;
|
|
6402
|
-
if (data.length === 1 && data[0].variants.length > 1) return null;
|
|
6403
6409
|
if (normalized.emptiedByDrop && !data.length) return null;
|
|
6410
|
+
if (data.length === 1 && data[0].variants.length > 1) return null;
|
|
6404
6411
|
try {
|
|
6405
|
-
if (data.length !== 1 || data[0].variants.length !== 1) throw new Error("
|
|
6412
|
+
if (data.length !== 1 || data[0].variants.length !== 1) throw new Error("No single product and variant");
|
|
6406
6413
|
const product = data[0];
|
|
6407
6414
|
const variant2 = product.variants[0];
|
|
6408
6415
|
if (variant2.productId !== product.id) throw new Error("Foreign variant");
|
|
6409
6416
|
const groups = product.sellingPlanGroups;
|
|
6410
6417
|
const required = groups.map((group) => group.requiresSellingPlan);
|
|
6411
6418
|
if (required.some((flag) => flag !== required[0])) throw new Error("Conflicting requirement");
|
|
6412
|
-
const plans =
|
|
6419
|
+
const plans = hasLegacyPlanGroups(product) ? readPostPurchaseLegacyPlans(groups[0], variant2.id) : readPostPurchaseModernPlans(groups, variant2.sellingPlanAllocations);
|
|
6413
6420
|
const unique = /* @__PURE__ */ new Map();
|
|
6414
6421
|
for (const plan of plans) {
|
|
6415
6422
|
const previous = unique.get(plan.id);
|
|
@@ -6422,8 +6429,7 @@ var projectPostPurchasePlanCatalog = (normalized, report) => {
|
|
|
6422
6429
|
discountPercentage: postPurchasePlanDiscountPercentage(variant2.price, plan.adjustment)
|
|
6423
6430
|
})),
|
|
6424
6431
|
productId: product.id,
|
|
6425
|
-
|
|
6426
|
-
requiresSellingPlan: (required[0] ?? false) || product.requiresSellingPlan === true,
|
|
6432
|
+
requiresSellingPlan: (required[0] ?? false) || requiresOwnSellingPlan(product),
|
|
6427
6433
|
variantId: variant2.id
|
|
6428
6434
|
});
|
|
6429
6435
|
} catch {
|
|
@@ -6976,7 +6982,7 @@ var oneTimeUnavailable = (normalized, allowCollection, quantity3) => {
|
|
|
6976
6982
|
return "Only fixed one-time configuration is supported";
|
|
6977
6983
|
const product = data[0];
|
|
6978
6984
|
const variant2 = product.variants[0];
|
|
6979
|
-
if (product.productGroupVariants.length || product
|
|
6985
|
+
if (product.productGroupVariants.length || requiresOwnSellingPlan(product) || product.sellingPlanGroups?.some((group) => group.requiresSellingPlan))
|
|
6980
6986
|
return "A one-time variant without product groups or a required selling plan is required";
|
|
6981
6987
|
if (!postPurchaseVariantAvailable(variant2)) return VARIANT_UNAVAILABLE;
|
|
6982
6988
|
if (variant2.productId !== product.id) throw new Error("Product variant identity mismatch");
|
|
@@ -7647,7 +7653,7 @@ var reportUnreadableStsLine = (product, field, report) => {
|
|
|
7647
7653
|
};
|
|
7648
7654
|
var postPurchaseStsLine = (normalized, product, lines, variantId, report) => {
|
|
7649
7655
|
if (!product.sellingPlanGroups?.length || product.productGroupVariants.length) return void 0;
|
|
7650
|
-
const modern =
|
|
7656
|
+
const modern = !hasLegacyPlanGroups(product);
|
|
7651
7657
|
for (const [index, variant2] of product.variants.entries()) {
|
|
7652
7658
|
const matched = lines.filter((line) => line.sellingPlanId === void 0 && line.variantId === variant2.id);
|
|
7653
7659
|
const data = [{ ...product, variants: [variant2] }];
|
|
@@ -7655,7 +7661,7 @@ var postPurchaseStsLine = (normalized, product, lines, variantId, report) => {
|
|
|
7655
7661
|
const unread = [];
|
|
7656
7662
|
if (projectPostPurchasePlanCatalog({ ...normalized, data }, (event) => unread.push(event))?.plans.length)
|
|
7657
7663
|
return { data, line: matched[0] };
|
|
7658
|
-
const field = modern && !PostPurchasePlanAllocations.safeParse(variant2.sellingPlanAllocations).success ? `variants.${index}.sellingPlanAllocations` : unread.length ? "sellingPlanGroups" :
|
|
7664
|
+
const field = modern && !PostPurchasePlanAllocations.safeParse(variant2.sellingPlanAllocations).success ? `variants.${index}.sellingPlanAllocations` : !unread.length ? void 0 : variant2.productId === product.id ? "sellingPlanGroups" : `variants.${index}.productId`;
|
|
7659
7665
|
if (report && field) reportUnreadableStsLine(product, field, report);
|
|
7660
7666
|
}
|
|
7661
7667
|
}
|
|
@@ -8097,7 +8103,7 @@ var eligibility = (normalized, product, excluded) => {
|
|
|
8097
8103
|
if (product.productGroupVariants.length) {
|
|
8098
8104
|
const group = readPostPurchaseGroup(product, normalized.effective, excluded);
|
|
8099
8105
|
if (!group.entries.length) return void 0;
|
|
8100
|
-
return group.entries.map(({ product: option }) =>
|
|
8106
|
+
return group.entries.map(({ product: option }) => eligibility(normalized, option)).some(Boolean);
|
|
8101
8107
|
}
|
|
8102
8108
|
if (!product.variants.length) return false;
|
|
8103
8109
|
const variants = projectPostPurchaseVariantCatalog(product, normalized.effective).variants;
|
package/dist/server/index.mjs
CHANGED
|
@@ -8,8 +8,8 @@ var getValidGwpProductIds = (matchedRules = []) => new Set(
|
|
|
8
8
|
|
|
9
9
|
// src/gwp/hasUnsupportedRuleTypes.ts
|
|
10
10
|
var UNSUPPORTED_RULE_TYPES = ["url", "order_tag"];
|
|
11
|
-
var
|
|
12
|
-
var isUnsupportedType = (type = "") => UNSUPPORTED_RULE_TYPES.includes(type) || type.
|
|
11
|
+
var UNSUPPORTED_RULE_TYPE_FRAGMENT = "geolocation";
|
|
12
|
+
var isUnsupportedType = (type = "") => UNSUPPORTED_RULE_TYPES.includes(type) || type.includes(UNSUPPORTED_RULE_TYPE_FRAGMENT);
|
|
13
13
|
var ruleHasUnsupportedType = (rule) => (rule.logic ?? []).some((group) => (group.rules ?? []).some((item) => isUnsupportedType(item.type)));
|
|
14
14
|
var hasUnsupportedRuleTypes = (metadata) => [...metadata?.matchedRules ?? [], ...metadata?.unmatchedRules ?? []].some(ruleHasUnsupportedType);
|
|
15
15
|
|
|
@@ -291,7 +291,7 @@ var OfferProductDiscount = z3.object({
|
|
|
291
291
|
type: z3.string()
|
|
292
292
|
});
|
|
293
293
|
var OfferProductOption = z3.object({
|
|
294
|
-
id: z3.number(),
|
|
294
|
+
id: z3.number().optional(),
|
|
295
295
|
name: z3.string(),
|
|
296
296
|
position: z3.number(),
|
|
297
297
|
values: z3.array(z3.string())
|
|
@@ -303,7 +303,7 @@ var OfferProductVariant = z3.object({
|
|
|
303
303
|
inventoryManagement: z3.string().nullable(),
|
|
304
304
|
inventoryPolicy: z3.string(),
|
|
305
305
|
inventoryQuantity: z3.number(),
|
|
306
|
-
link: z3.string(),
|
|
306
|
+
link: z3.string().optional(),
|
|
307
307
|
option1: z3.string(),
|
|
308
308
|
option2: z3.string().nullable(),
|
|
309
309
|
option3: z3.string().nullable(),
|
|
@@ -316,12 +316,12 @@ var OfferProduct = z3.object({
|
|
|
316
316
|
id: z3.number(),
|
|
317
317
|
image: z3.object({ src: z3.string() }).nullish(),
|
|
318
318
|
/**
|
|
319
|
-
* `variantIds` is
|
|
319
|
+
* `variantIds` is nullish: the engine omits `variant_ids` (rather than sending `[]`) on an image tied to no
|
|
320
320
|
* variant — seen live on the `recommended` data source while `top_sellers` sends `[]` for the same image
|
|
321
|
-
* (REB-24958). A missing list means "not variant-specific", exactly like `[]`, so the image
|
|
322
|
-
* and the product is never dropped over it.
|
|
321
|
+
* (REB-24958). A missing (or `null`) list means "not variant-specific", exactly like `[]`, so the image
|
|
322
|
+
* keeps its `src` and the product is never dropped over it.
|
|
323
323
|
*/
|
|
324
|
-
images: z3.array(z3.object({ src: z3.string(), variantIds: z3.array(z3.number()).
|
|
324
|
+
images: z3.array(z3.object({ src: z3.string(), variantIds: z3.array(z3.number()).nullish() })).nullish(),
|
|
325
325
|
link: z3.string().optional(),
|
|
326
326
|
metafields: z3.array(z3.object({ key: z3.string(), namespace: z3.string(), value: z3.string() })).optional(),
|
|
327
327
|
options: z3.array(OfferProductOption),
|
|
@@ -353,6 +353,8 @@ var filterByB2bAvailability = async (products, input, ctx) => {
|
|
|
353
353
|
productIds: products.map(productGid),
|
|
354
354
|
shopifyShopDomain: input.shop
|
|
355
355
|
},
|
|
356
|
+
/** admin-api verifies it (REB-25081); absent, the call is unauthenticated (log-only there until enforced). */
|
|
357
|
+
...ctx.sessionToken && { headers: { Authorization: `Bearer ${ctx.sessionToken}` } },
|
|
356
358
|
host: ctx.host,
|
|
357
359
|
method: "POST"
|
|
358
360
|
}
|
|
@@ -6119,6 +6121,10 @@ var reportOncePerResponse = (response, report, events) => {
|
|
|
6119
6121
|
}
|
|
6120
6122
|
};
|
|
6121
6123
|
|
|
6124
|
+
// src/server/postPurchaseSellingPlanRequirement.ts
|
|
6125
|
+
var requiresOwnSellingPlan = (product) => product.requiresSellingPlan === true;
|
|
6126
|
+
var requiresUnsuppliedSellingPlan = (product) => requiresOwnSellingPlan(product) && !product.sellingPlanGroups?.length;
|
|
6127
|
+
|
|
6122
6128
|
// src/server/readPostPurchaseProductSource.ts
|
|
6123
6129
|
var Envelope = PostPurchaseProductSource.extend({ data: z45.array(z45.unknown()) });
|
|
6124
6130
|
var Product3 = PostPurchaseProductSource.shape.data.element;
|
|
@@ -6131,9 +6137,9 @@ var readPostPurchaseProductSource = (response, report) => {
|
|
|
6131
6137
|
const parsed = Product3.safeParse(raw);
|
|
6132
6138
|
if (parsed.success) {
|
|
6133
6139
|
rememberPostPurchaseProductSource(parsed.data, response, productIndex);
|
|
6134
|
-
if (parsed.data
|
|
6140
|
+
if (requiresUnsuppliedSellingPlan(parsed.data))
|
|
6135
6141
|
drift.push({
|
|
6136
|
-
detail: `
|
|
6142
|
+
detail: `Ineligible post-purchase product ${parsed.data.id}: data.${productIndex}.requiresSellingPlan`,
|
|
6137
6143
|
kind: "product"
|
|
6138
6144
|
});
|
|
6139
6145
|
return [{ product: parsed.data, productIndex }];
|
|
@@ -6324,19 +6330,20 @@ var readPostPurchaseModernPlans = (raw, allocations) => {
|
|
|
6324
6330
|
};
|
|
6325
6331
|
|
|
6326
6332
|
// src/server/postPurchasePlanCatalog.ts
|
|
6333
|
+
var hasLegacyPlanGroups = ({ sellingPlanGroups }) => typeof sellingPlanGroups[0]?.id === "number";
|
|
6327
6334
|
var projectPostPurchasePlanCatalog = (normalized, report) => {
|
|
6328
6335
|
const { data } = normalized;
|
|
6329
|
-
if (data.length === 1 && data[0].variants.length > 1) return null;
|
|
6330
6336
|
if (normalized.emptiedByDrop && !data.length) return null;
|
|
6337
|
+
if (data.length === 1 && data[0].variants.length > 1) return null;
|
|
6331
6338
|
try {
|
|
6332
|
-
if (data.length !== 1 || data[0].variants.length !== 1) throw new Error("
|
|
6339
|
+
if (data.length !== 1 || data[0].variants.length !== 1) throw new Error("No single product and variant");
|
|
6333
6340
|
const product = data[0];
|
|
6334
6341
|
const variant2 = product.variants[0];
|
|
6335
6342
|
if (variant2.productId !== product.id) throw new Error("Foreign variant");
|
|
6336
6343
|
const groups = product.sellingPlanGroups;
|
|
6337
6344
|
const required = groups.map((group) => group.requiresSellingPlan);
|
|
6338
6345
|
if (required.some((flag) => flag !== required[0])) throw new Error("Conflicting requirement");
|
|
6339
|
-
const plans =
|
|
6346
|
+
const plans = hasLegacyPlanGroups(product) ? readPostPurchaseLegacyPlans(groups[0], variant2.id) : readPostPurchaseModernPlans(groups, variant2.sellingPlanAllocations);
|
|
6340
6347
|
const unique = /* @__PURE__ */ new Map();
|
|
6341
6348
|
for (const plan of plans) {
|
|
6342
6349
|
const previous = unique.get(plan.id);
|
|
@@ -6349,8 +6356,7 @@ var projectPostPurchasePlanCatalog = (normalized, report) => {
|
|
|
6349
6356
|
discountPercentage: postPurchasePlanDiscountPercentage(variant2.price, plan.adjustment)
|
|
6350
6357
|
})),
|
|
6351
6358
|
productId: product.id,
|
|
6352
|
-
|
|
6353
|
-
requiresSellingPlan: (required[0] ?? false) || product.requiresSellingPlan === true,
|
|
6359
|
+
requiresSellingPlan: (required[0] ?? false) || requiresOwnSellingPlan(product),
|
|
6354
6360
|
variantId: variant2.id
|
|
6355
6361
|
});
|
|
6356
6362
|
} catch {
|
|
@@ -6903,7 +6909,7 @@ var oneTimeUnavailable = (normalized, allowCollection, quantity3) => {
|
|
|
6903
6909
|
return "Only fixed one-time configuration is supported";
|
|
6904
6910
|
const product = data[0];
|
|
6905
6911
|
const variant2 = product.variants[0];
|
|
6906
|
-
if (product.productGroupVariants.length || product
|
|
6912
|
+
if (product.productGroupVariants.length || requiresOwnSellingPlan(product) || product.sellingPlanGroups?.some((group) => group.requiresSellingPlan))
|
|
6907
6913
|
return "A one-time variant without product groups or a required selling plan is required";
|
|
6908
6914
|
if (!postPurchaseVariantAvailable(variant2)) return VARIANT_UNAVAILABLE;
|
|
6909
6915
|
if (variant2.productId !== product.id) throw new Error("Product variant identity mismatch");
|
|
@@ -7574,7 +7580,7 @@ var reportUnreadableStsLine = (product, field, report) => {
|
|
|
7574
7580
|
};
|
|
7575
7581
|
var postPurchaseStsLine = (normalized, product, lines, variantId, report) => {
|
|
7576
7582
|
if (!product.sellingPlanGroups?.length || product.productGroupVariants.length) return void 0;
|
|
7577
|
-
const modern =
|
|
7583
|
+
const modern = !hasLegacyPlanGroups(product);
|
|
7578
7584
|
for (const [index, variant2] of product.variants.entries()) {
|
|
7579
7585
|
const matched = lines.filter((line) => line.sellingPlanId === void 0 && line.variantId === variant2.id);
|
|
7580
7586
|
const data = [{ ...product, variants: [variant2] }];
|
|
@@ -7582,7 +7588,7 @@ var postPurchaseStsLine = (normalized, product, lines, variantId, report) => {
|
|
|
7582
7588
|
const unread = [];
|
|
7583
7589
|
if (projectPostPurchasePlanCatalog({ ...normalized, data }, (event) => unread.push(event))?.plans.length)
|
|
7584
7590
|
return { data, line: matched[0] };
|
|
7585
|
-
const field = modern && !PostPurchasePlanAllocations.safeParse(variant2.sellingPlanAllocations).success ? `variants.${index}.sellingPlanAllocations` : unread.length ? "sellingPlanGroups" :
|
|
7591
|
+
const field = modern && !PostPurchasePlanAllocations.safeParse(variant2.sellingPlanAllocations).success ? `variants.${index}.sellingPlanAllocations` : !unread.length ? void 0 : variant2.productId === product.id ? "sellingPlanGroups" : `variants.${index}.productId`;
|
|
7586
7592
|
if (report && field) reportUnreadableStsLine(product, field, report);
|
|
7587
7593
|
}
|
|
7588
7594
|
}
|
|
@@ -8024,7 +8030,7 @@ var eligibility = (normalized, product, excluded) => {
|
|
|
8024
8030
|
if (product.productGroupVariants.length) {
|
|
8025
8031
|
const group = readPostPurchaseGroup(product, normalized.effective, excluded);
|
|
8026
8032
|
if (!group.entries.length) return void 0;
|
|
8027
|
-
return group.entries.map(({ product: option }) =>
|
|
8033
|
+
return group.entries.map(({ product: option }) => eligibility(normalized, option)).some(Boolean);
|
|
8028
8034
|
}
|
|
8029
8035
|
if (!product.variants.length) return false;
|
|
8030
8036
|
const variants = projectPostPurchaseVariantCatalog(product, normalized.effective).variants;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { PostPurchasePlanCatalog } from '../schema/postPurchasePlanCatalog';
|
|
2
2
|
import type { normalizePostPurchaseProduct } from '../server/normalizePostPurchaseProduct';
|
|
3
3
|
import type { Reporter } from '../server/shared';
|
|
4
|
+
type Product = ReturnType<typeof normalizePostPurchaseProduct>['data'][number];
|
|
5
|
+
/** v1 selling-plan groups carry numeric ids and their plans on the group; modern ones key plans per variant. */
|
|
6
|
+
export declare const hasLegacyPlanGroups: ({ sellingPlanGroups }: Pick<Product, "sellingPlanGroups">) => boolean;
|
|
4
7
|
/**
|
|
5
8
|
* Optional inspection data survives unsupported preparation without changing its purchase authority. Each plan
|
|
6
9
|
* carries its own display saving on this variant's price, so the switch label needs no client maths.
|
|
@@ -12,3 +15,4 @@ import type { Reporter } from '../server/shared';
|
|
|
12
15
|
* not a second fault: each drop was already reported, so it answers null without another report.
|
|
13
16
|
*/
|
|
14
17
|
export declare const projectPostPurchasePlanCatalog: (normalized: ReturnType<typeof normalizePostPurchaseProduct>, report?: Reporter) => PostPurchasePlanCatalog | null;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type Requiring = {
|
|
2
|
+
requiresSellingPlan?: boolean | null;
|
|
3
|
+
sellingPlanGroups?: unknown[];
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* REB-25048: a v2 product flags `requires_selling_plan` on itself rather than on its selling plan groups. It is
|
|
7
|
+
* never sold one-time, and a product that also has groups is offered subscription-only. Legacy read only the first
|
|
8
|
+
* group's flag, so under Product Type `both` it dropped such a product where the rebuild offers it subscription-only
|
|
9
|
+
* (accepted deviation, connscoding on npm-rebuy #117: neither sells it one-time).
|
|
10
|
+
*/
|
|
11
|
+
export declare const requiresOwnSellingPlan: (product: Requiring) => boolean;
|
|
12
|
+
/** Requires a selling plan with no group to supply one: no purchasable mode is left, so eligibility drops it. */
|
|
13
|
+
export declare const requiresUnsuppliedSellingPlan: (product: Requiring) => boolean;
|
|
14
|
+
export {};
|
|
@@ -17,7 +17,9 @@ export declare const stsAllowed: ({ effective, original }: Pick<Normalized, "eff
|
|
|
17
17
|
* plan; (2) it sits on exactly one one-time line, since two make the refunded quantity ambiguous; (3) a grouped
|
|
18
18
|
* product is never an STS member; (4) the bound variant is the purchased line's, not the product's selected
|
|
19
19
|
* variant, and subscription is the only mode. The first such variant in catalog order wins, unless `variantId`
|
|
20
|
-
* names one.
|
|
20
|
+
* names one. Two more differences from legacy are accepted (connscoding, npm-rebuy #109): a subscription line
|
|
21
|
+
* beside a one-time line of the same variant still gets STS, where legacy's first match on the variant offered
|
|
22
|
+
* none; and the quantity is fixed at the whole one-time line, where legacy let the buyer change it.
|
|
21
23
|
*
|
|
22
24
|
* `report` hears a candidate (a purchased, in-stock variant on exactly one one-time line) whose plan data cannot be
|
|
23
25
|
* read, since it then silently switches nothing: a modern selling-plan variant whose `sellingPlanAllocations` is
|
package/dist/server/shared.d.ts
CHANGED
|
@@ -28,12 +28,12 @@ export type UpstreamFetch = (path: string, params: Record<string, string>, optio
|
|
|
28
28
|
/**
|
|
29
29
|
* A drift signal the orchestrators emit when a per-item payload salvage drops something: a malformed
|
|
30
30
|
* offer product (or a post-purchase data-source product, `product`, named by id and dotted path), an
|
|
31
|
-
* invalid/unknown section stubbed out, an unreadable rule verdict, a shop-config
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* request still succeeds (degraded), so this is the only trace that an upstream
|
|
36
|
-
* on {@link ServerContext}; the host (rebuy-api) wires it to its logger.
|
|
31
|
+
* invalid/unknown section stubbed out, an unreadable rule verdict, a shop-config entry the shared schema
|
|
32
|
+
* inerted (`shopConfig`), unreadable selectable-gift milestones (`giftMilestones` — the widget's gifts are
|
|
33
|
+
* then kept), or a post-purchase product's malformed selected review metafield (`reviews` — the reviews are
|
|
34
|
+
* then omitted; it names the product and the field, never the value). Distinct from a hard
|
|
35
|
+
* {@link UpstreamError} — the request still succeeds (degraded), so this is the only trace that an upstream
|
|
36
|
+
* contract moved. Optional on {@link ServerContext}; the host (rebuy-api) wires it to its logger.
|
|
37
37
|
*/
|
|
38
38
|
export type ServerDrift = {
|
|
39
39
|
detail: string;
|
|
@@ -55,10 +55,19 @@ export declare const isEmptyObject: (x: unknown) => boolean;
|
|
|
55
55
|
export type ServerContext = {
|
|
56
56
|
fetchUpstream: UpstreamFetch;
|
|
57
57
|
host: string;
|
|
58
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* Buyer request IP forwarded to the ads engine (the checkout worker can't read it; rebuy-api extracts it).
|
|
60
|
+
* Without it DSPs see one datacenter IP for all traffic — geo/IVT-flagging risk. Monetize only.
|
|
61
|
+
*/
|
|
59
62
|
ipAddress?: string;
|
|
60
63
|
/** Optional sink for {@link ServerDrift} — a degraded-but-successful payload salvage. */
|
|
61
64
|
reportDrift?: (event: ServerDrift) => void;
|
|
65
|
+
/**
|
|
66
|
+
* The checkout extension's Shopify session token (the bare JWT, no `Bearer ` prefix), as the host received
|
|
67
|
+
* it. Forwarded unread to admin-api's B2B availability check, which verifies it and binds the shop and the
|
|
68
|
+
* company location to the buyer it names (REB-25081). Never logged. B2B data-source filtering only.
|
|
69
|
+
*/
|
|
70
|
+
sessionToken?: string;
|
|
62
71
|
/** Browser user-agent forwarded to the ads engine (the checkout worker can't read it). Monetize only. */
|
|
63
72
|
userAgent?: string;
|
|
64
73
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebuy/rebuy",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.59.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.",
|