@replohq/sdk 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -70,5 +70,9 @@ export declare const cartSchema: z.ZodObject<{
70
70
  code: z.ZodString;
71
71
  applicable: z.ZodBoolean;
72
72
  }, z.core.$strip>>>;
73
+ discountAllocations: z.ZodOptional<z.ZodArray<z.ZodObject<{
74
+ discountedAmount: z.ZodNumber;
75
+ title: z.ZodNullable<z.ZodString>;
76
+ }, z.core.$strip>>>;
73
77
  }, z.core.$strip>;
74
78
  export type Cart = z.infer<typeof cartSchema>;
@@ -56,12 +56,17 @@ const cartDiscountCodeSchema = z.object({
56
56
  code: z.string(),
57
57
  applicable: z.boolean()
58
58
  });
59
+ const cartDiscountAllocationSchema = z.object({
60
+ discountedAmount: amountSchema,
61
+ title: z.string().nullable()
62
+ });
59
63
  const cartSchema = z.object({
60
64
  id: z.string(),
61
65
  lines: z.array(cartLineSchema),
62
66
  cost: cartCostSchema,
63
67
  checkoutUrl: z.string().optional(),
64
- discountCodes: z.array(cartDiscountCodeSchema).optional()
68
+ discountCodes: z.array(cartDiscountCodeSchema).optional(),
69
+ discountAllocations: z.array(cartDiscountAllocationSchema).optional()
65
70
  });
66
71
  export {
67
72
  cartSchema
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../cart/cart-schema.ts"],
4
- "sourcesContent": ["import { z } from \"zod\";\n\n// NOTE (Ryan, 2026-07-23, REPL-27611): Self-contained copy of the cart wire\n// schema that the SDK gateway validates on published pages, so nothing\n// shipped to a generated site imports from `schemas`. The backend keeps the\n// canonical copy in `schemas/cart.ts` (its cart services can't depend on\n// the SDK without a cycle); `cart-schema.spec.ts` keeps the two in lockstep.\n// This module is internal wire validation; public types live in `cart/cart-types`.\n\n// ---------------------------------------------------------------------------\n// Cart line attribute\n// ---------------------------------------------------------------------------\n\nconst cartLineAttributeSchema = z.object({\n key: z.string(),\n value: z.union([z.string(), z.number(), z.boolean()]),\n});\n\n// ---------------------------------------------------------------------------\n// Image (cart-scoped; lightweight compared to objectType image)\n// ---------------------------------------------------------------------------\n\nconst cartImageSchema = z.object({\n url: z.string(),\n altText: z.string().nullable(),\n});\n\n// ---------------------------------------------------------------------------\n// Selling plan types\n// ---------------------------------------------------------------------------\n\n// Integer minor units (Stripe convention): 1999 = $19.99 USD. Mirrors\n// amountSchema in schemas/money.ts, which shipped code cannot import.\nconst amountSchema = z.number().int();\nconst amountWithCurrencyCodeSchema = z.object({\n amount: amountSchema,\n currencyCode: z.string(),\n});\n\nconst sellingPlanPriceAdjustmentSchema = z.object({\n compareAtPrice: amountWithCurrencyCodeSchema,\n perDeliveryPrice: amountWithCurrencyCodeSchema,\n price: amountWithCurrencyCodeSchema,\n unitPrice: amountWithCurrencyCodeSchema.nullable(),\n});\n\nconst sellingPlanAllocationSchema = z.object({\n sellingPlan: z.object({\n id: z.string(),\n name: z.string(),\n description: z.string().nullable(),\n }),\n priceAdjustments: z.array(sellingPlanPriceAdjustmentSchema),\n checkoutChargeAmount: amountWithCurrencyCodeSchema,\n remainingBalanceChargeAmount: amountWithCurrencyCodeSchema,\n});\n\n// ---------------------------------------------------------------------------\n// Cart line merchandise\n// ---------------------------------------------------------------------------\n\nconst cartLineMerchandiseSchema = z.object({\n id: z.string(),\n product: z.object({\n id: z.string(),\n title: z.string(),\n }),\n title: z.string(),\n price: amountSchema,\n compareAtPrice: amountSchema.nullish(),\n image: cartImageSchema.nullable(),\n selectedOptions: z.array(z.object({ name: z.string(), value: z.string() })),\n});\n\n// ---------------------------------------------------------------------------\n// Cart line\n// ---------------------------------------------------------------------------\n\nconst cartLineSchema = z.object({\n id: z.string(),\n quantity: z.number(),\n merchandise: cartLineMerchandiseSchema,\n attributes: z.array(cartLineAttributeSchema),\n sellingPlanAllocation: sellingPlanAllocationSchema.nullish(),\n});\n\n// ---------------------------------------------------------------------------\n// Cart cost\n// ---------------------------------------------------------------------------\n\nconst cartCostSchema = z.object({\n subtotalAmount: amountSchema,\n totalAmount: amountSchema,\n currencyCode: z.string(),\n});\n\n// ---------------------------------------------------------------------------\n// Cart discount code\n// ---------------------------------------------------------------------------\n\nconst cartDiscountCodeSchema = z.object({\n code: z.string(),\n applicable: z.boolean(),\n});\n\n// ---------------------------------------------------------------------------\n// Cart (top level)\n// ---------------------------------------------------------------------------\n\nexport const cartSchema = z.object({\n id: z.string(),\n lines: z.array(cartLineSchema),\n cost: cartCostSchema,\n checkoutUrl: z.string().optional(),\n discountCodes: z.array(cartDiscountCodeSchema).optional(),\n});\n\nexport type Cart = z.infer<typeof cartSchema>;\n"],
5
- "mappings": "AAAA,SAAS,SAAS;AAalB,MAAM,0BAA0B,EAAE,OAAO;AAAA,EACvC,KAAK,EAAE,OAAO;AAAA,EACd,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,CAAC;AACtD,CAAC;AAMD,MAAM,kBAAkB,EAAE,OAAO;AAAA,EAC/B,KAAK,EAAE,OAAO;AAAA,EACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAC/B,CAAC;AAQD,MAAM,eAAe,EAAE,OAAO,EAAE,IAAI;AACpC,MAAM,+BAA+B,EAAE,OAAO;AAAA,EAC5C,QAAQ;AAAA,EACR,cAAc,EAAE,OAAO;AACzB,CAAC;AAED,MAAM,mCAAmC,EAAE,OAAO;AAAA,EAChD,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,OAAO;AAAA,EACP,WAAW,6BAA6B,SAAS;AACnD,CAAC;AAED,MAAM,8BAA8B,EAAE,OAAO;AAAA,EAC3C,aAAa,EAAE,OAAO;AAAA,IACpB,IAAI,EAAE,OAAO;AAAA,IACb,MAAM,EAAE,OAAO;AAAA,IACf,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACnC,CAAC;AAAA,EACD,kBAAkB,EAAE,MAAM,gCAAgC;AAAA,EAC1D,sBAAsB;AAAA,EACtB,8BAA8B;AAChC,CAAC;AAMD,MAAM,4BAA4B,EAAE,OAAO;AAAA,EACzC,IAAI,EAAE,OAAO;AAAA,EACb,SAAS,EAAE,OAAO;AAAA,IAChB,IAAI,EAAE,OAAO;AAAA,IACb,OAAO,EAAE,OAAO;AAAA,EAClB,CAAC;AAAA,EACD,OAAO,EAAE,OAAO;AAAA,EAChB,OAAO;AAAA,EACP,gBAAgB,aAAa,QAAQ;AAAA,EACrC,OAAO,gBAAgB,SAAS;AAAA,EAChC,iBAAiB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;AAC5E,CAAC;AAMD,MAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,IAAI,EAAE,OAAO;AAAA,EACb,UAAU,EAAE,OAAO;AAAA,EACnB,aAAa;AAAA,EACb,YAAY,EAAE,MAAM,uBAAuB;AAAA,EAC3C,uBAAuB,4BAA4B,QAAQ;AAC7D,CAAC;AAMD,MAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,cAAc,EAAE,OAAO;AACzB,CAAC;AAMD,MAAM,yBAAyB,EAAE,OAAO;AAAA,EACtC,MAAM,EAAE,OAAO;AAAA,EACf,YAAY,EAAE,QAAQ;AACxB,CAAC;AAMM,MAAM,aAAa,EAAE,OAAO;AAAA,EACjC,IAAI,EAAE,OAAO;AAAA,EACb,OAAO,EAAE,MAAM,cAAc;AAAA,EAC7B,MAAM;AAAA,EACN,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,eAAe,EAAE,MAAM,sBAAsB,EAAE,SAAS;AAC1D,CAAC;",
4
+ "sourcesContent": ["import { z } from \"zod\";\n\n// NOTE (Ryan, 2026-07-23, REPL-27611): Self-contained copy of the cart wire\n// schema that the SDK gateway validates on published pages, so nothing\n// shipped to a generated site imports from `schemas`. The backend keeps the\n// canonical copy in `schemas/cart.ts` (its cart services can't depend on\n// the SDK without a cycle); `cart-schema.spec.ts` keeps the two in lockstep.\n// This module is internal wire validation; public types live in `cart/cart-types`.\n\n// ---------------------------------------------------------------------------\n// Cart line attribute\n// ---------------------------------------------------------------------------\n\nconst cartLineAttributeSchema = z.object({\n key: z.string(),\n value: z.union([z.string(), z.number(), z.boolean()]),\n});\n\n// ---------------------------------------------------------------------------\n// Image (cart-scoped; lightweight compared to objectType image)\n// ---------------------------------------------------------------------------\n\nconst cartImageSchema = z.object({\n url: z.string(),\n altText: z.string().nullable(),\n});\n\n// ---------------------------------------------------------------------------\n// Selling plan types\n// ---------------------------------------------------------------------------\n\n// Integer minor units (Stripe convention): 1999 = $19.99 USD. Mirrors\n// amountSchema in schemas/money.ts, which shipped code cannot import.\nconst amountSchema = z.number().int();\nconst amountWithCurrencyCodeSchema = z.object({\n amount: amountSchema,\n currencyCode: z.string(),\n});\n\nconst sellingPlanPriceAdjustmentSchema = z.object({\n compareAtPrice: amountWithCurrencyCodeSchema,\n perDeliveryPrice: amountWithCurrencyCodeSchema,\n price: amountWithCurrencyCodeSchema,\n unitPrice: amountWithCurrencyCodeSchema.nullable(),\n});\n\nconst sellingPlanAllocationSchema = z.object({\n sellingPlan: z.object({\n id: z.string(),\n name: z.string(),\n description: z.string().nullable(),\n }),\n priceAdjustments: z.array(sellingPlanPriceAdjustmentSchema),\n checkoutChargeAmount: amountWithCurrencyCodeSchema,\n remainingBalanceChargeAmount: amountWithCurrencyCodeSchema,\n});\n\n// ---------------------------------------------------------------------------\n// Cart line merchandise\n// ---------------------------------------------------------------------------\n\nconst cartLineMerchandiseSchema = z.object({\n id: z.string(),\n product: z.object({\n id: z.string(),\n title: z.string(),\n }),\n title: z.string(),\n price: amountSchema,\n compareAtPrice: amountSchema.nullish(),\n image: cartImageSchema.nullable(),\n selectedOptions: z.array(z.object({ name: z.string(), value: z.string() })),\n});\n\n// ---------------------------------------------------------------------------\n// Cart line\n// ---------------------------------------------------------------------------\n\nconst cartLineSchema = z.object({\n id: z.string(),\n quantity: z.number(),\n merchandise: cartLineMerchandiseSchema,\n attributes: z.array(cartLineAttributeSchema),\n sellingPlanAllocation: sellingPlanAllocationSchema.nullish(),\n});\n\n// ---------------------------------------------------------------------------\n// Cart cost\n// ---------------------------------------------------------------------------\n\nconst cartCostSchema = z.object({\n subtotalAmount: amountSchema,\n totalAmount: amountSchema,\n currencyCode: z.string(),\n});\n\n// ---------------------------------------------------------------------------\n// Cart discount code\n// ---------------------------------------------------------------------------\n\nconst cartDiscountCodeSchema = z.object({\n code: z.string(),\n applicable: z.boolean(),\n});\n\n// ---------------------------------------------------------------------------\n// Cart discount allocation\n// ---------------------------------------------------------------------------\n\nconst cartDiscountAllocationSchema = z.object({\n discountedAmount: amountSchema,\n title: z.string().nullable(),\n});\n\n// ---------------------------------------------------------------------------\n// Cart (top level)\n// ---------------------------------------------------------------------------\n\nexport const cartSchema = z.object({\n id: z.string(),\n lines: z.array(cartLineSchema),\n cost: cartCostSchema,\n checkoutUrl: z.string().optional(),\n discountCodes: z.array(cartDiscountCodeSchema).optional(),\n discountAllocations: z.array(cartDiscountAllocationSchema).optional(),\n});\n\nexport type Cart = z.infer<typeof cartSchema>;\n"],
5
+ "mappings": "AAAA,SAAS,SAAS;AAalB,MAAM,0BAA0B,EAAE,OAAO;AAAA,EACvC,KAAK,EAAE,OAAO;AAAA,EACd,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,CAAC;AACtD,CAAC;AAMD,MAAM,kBAAkB,EAAE,OAAO;AAAA,EAC/B,KAAK,EAAE,OAAO;AAAA,EACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAC/B,CAAC;AAQD,MAAM,eAAe,EAAE,OAAO,EAAE,IAAI;AACpC,MAAM,+BAA+B,EAAE,OAAO;AAAA,EAC5C,QAAQ;AAAA,EACR,cAAc,EAAE,OAAO;AACzB,CAAC;AAED,MAAM,mCAAmC,EAAE,OAAO;AAAA,EAChD,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,OAAO;AAAA,EACP,WAAW,6BAA6B,SAAS;AACnD,CAAC;AAED,MAAM,8BAA8B,EAAE,OAAO;AAAA,EAC3C,aAAa,EAAE,OAAO;AAAA,IACpB,IAAI,EAAE,OAAO;AAAA,IACb,MAAM,EAAE,OAAO;AAAA,IACf,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACnC,CAAC;AAAA,EACD,kBAAkB,EAAE,MAAM,gCAAgC;AAAA,EAC1D,sBAAsB;AAAA,EACtB,8BAA8B;AAChC,CAAC;AAMD,MAAM,4BAA4B,EAAE,OAAO;AAAA,EACzC,IAAI,EAAE,OAAO;AAAA,EACb,SAAS,EAAE,OAAO;AAAA,IAChB,IAAI,EAAE,OAAO;AAAA,IACb,OAAO,EAAE,OAAO;AAAA,EAClB,CAAC;AAAA,EACD,OAAO,EAAE,OAAO;AAAA,EAChB,OAAO;AAAA,EACP,gBAAgB,aAAa,QAAQ;AAAA,EACrC,OAAO,gBAAgB,SAAS;AAAA,EAChC,iBAAiB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;AAC5E,CAAC;AAMD,MAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,IAAI,EAAE,OAAO;AAAA,EACb,UAAU,EAAE,OAAO;AAAA,EACnB,aAAa;AAAA,EACb,YAAY,EAAE,MAAM,uBAAuB;AAAA,EAC3C,uBAAuB,4BAA4B,QAAQ;AAC7D,CAAC;AAMD,MAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,cAAc,EAAE,OAAO;AACzB,CAAC;AAMD,MAAM,yBAAyB,EAAE,OAAO;AAAA,EACtC,MAAM,EAAE,OAAO;AAAA,EACf,YAAY,EAAE,QAAQ;AACxB,CAAC;AAMD,MAAM,+BAA+B,EAAE,OAAO;AAAA,EAC5C,kBAAkB;AAAA,EAClB,OAAO,EAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAMM,MAAM,aAAa,EAAE,OAAO;AAAA,EACjC,IAAI,EAAE,OAAO;AAAA,EACb,OAAO,EAAE,MAAM,cAAc;AAAA,EAC7B,MAAM;AAAA,EACN,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,eAAe,EAAE,MAAM,sBAAsB,EAAE,SAAS;AAAA,EACxD,qBAAqB,EAAE,MAAM,4BAA4B,EAAE,SAAS;AACtE,CAAC;",
6
6
  "names": []
7
7
  }
@@ -100,12 +100,24 @@ export interface CartDiscountCode {
100
100
  */
101
101
  applicable: boolean;
102
102
  }
103
+ /**
104
+ * One discount Shopify applied to a cart line or to the whole cart. The amount
105
+ * is already subtracted from `cost.totalAmount` (and from `cost.subtotalAmount`
106
+ * for line-level discounts).
107
+ */
108
+ export interface CartDiscountAllocation {
109
+ /** Integer minor units (Stripe convention) in the cart's currencyCode */
110
+ discountedAmount: number;
111
+ /** Automatic discount title or discount code; null when Shopify has neither */
112
+ title: string | null;
113
+ }
103
114
  export interface Cart {
104
115
  id: string;
105
116
  lines: CartLine[];
106
117
  cost: CartCost;
107
118
  checkoutUrl?: string;
108
119
  discountCodes?: CartDiscountCode[];
120
+ discountAllocations?: CartDiscountAllocation[];
109
121
  }
110
122
  export interface CartLinePayload {
111
123
  id: string;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../cart/cart-types.ts"],
4
- "sourcesContent": ["/**\n * TypeScript types for cart data structures. Use these types when working with cart data, but don't import from this module directly in components - use the cart hooks instead.\n * @module\n */\n\nimport type { SellingPlanGroup } from \"../loaders/loader-schemas\";\n\nexport interface Image {\n url: string;\n altText: string | null;\n}\n\nexport interface CartLineMerchandise {\n id: string;\n product: {\n id: string;\n title: string;\n sellingPlanGroups?: SellingPlanGroup[];\n };\n title: string;\n /** Integer minor units (Stripe convention): 1999 = $19.99 USD */\n price: number;\n compareAtPrice?: number | null;\n image: Image | null;\n selectedOptions: {\n name: string;\n value: string;\n }[];\n}\n\nexport interface CartLineAttribute {\n key: string;\n value: string | number | boolean;\n}\n\n/** Replo attribution property added to cart/buy-now line items for order attribution in Shopify. */\nexport const REPLO_ATTRIBUTION_PROPERTY: CartLineAttribute = {\n key: \"_replo\",\n value: \"true\",\n};\n\nexport interface SellingPlanPriceAdjustment {\n compareAtPrice: {\n amount: number;\n currencyCode: string;\n };\n perDeliveryPrice: {\n amount: number;\n currencyCode: string;\n };\n price: {\n amount: number;\n currencyCode: string;\n };\n unitPrice: {\n amount: number;\n currencyCode: string;\n } | null;\n}\n\nexport interface SellingPlanAllocation {\n sellingPlan: {\n id: string;\n name: string;\n description: string | null;\n };\n priceAdjustments: SellingPlanPriceAdjustment[];\n checkoutChargeAmount: {\n amount: number;\n currencyCode: string;\n };\n remainingBalanceChargeAmount: {\n amount: number;\n currencyCode: string;\n };\n}\n\nexport interface CartLine {\n id: string;\n quantity: number;\n /**\n * Null when this is an optimistic line whose merchandise couldn't be\n * resolved from the query cache or passed explicitly. Consumers should\n * render a skeleton/loading state in that case; the line is replaced\n * with real merchandise once the server roundtrip lands.\n */\n merchandise: CartLineMerchandise | null;\n attributes: CartLineAttribute[];\n sellingPlanAllocation?: SellingPlanAllocation | null;\n}\n\nexport interface CartCost {\n /** Integer minor units (Stripe convention) in currencyCode */\n subtotalAmount: number;\n totalAmount: number;\n currencyCode: string;\n}\n\n/**\n * Represents a discount code applied to a cart.\n */\nexport interface CartDiscountCode {\n /** The discount code string */\n code: string;\n /**\n * Whether the discount code is applicable to the current cart.\n * A code may not be applicable due to:\n * - Cart contents not meeting product/collection eligibility\n * - Minimum purchase amount not met\n * - Code expired or usage limits reached\n * - Customer restrictions\n * - Conflicting discount rules\n */\n applicable: boolean;\n}\n\nexport interface Cart {\n id: string;\n lines: CartLine[];\n cost: CartCost;\n checkoutUrl?: string;\n discountCodes?: CartDiscountCode[];\n}\n\nexport interface CartLinePayload {\n id: string;\n quantity: number;\n merchandise?: CartLineMerchandise;\n properties?: CartLineAttribute[];\n sellingPlanId?: string | null;\n}\n\nexport interface AddToCartPayload {\n lines: CartLinePayload[];\n cartId: string;\n}\n\nexport interface UpdateCartLineItemPayload {\n line: CartLinePayload;\n cartId: string;\n}\n\nexport interface RemoveFromCartPayload {\n lineIds: string[];\n cartId: string;\n}\n\nexport interface UpdateCartDiscountCodesPayload {\n cartId: string;\n discountCodes: string[];\n}\n"],
4
+ "sourcesContent": ["/**\n * TypeScript types for cart data structures. Use these types when working with cart data, but don't import from this module directly in components - use the cart hooks instead.\n * @module\n */\n\nimport type { SellingPlanGroup } from \"../loaders/loader-schemas\";\n\nexport interface Image {\n url: string;\n altText: string | null;\n}\n\nexport interface CartLineMerchandise {\n id: string;\n product: {\n id: string;\n title: string;\n sellingPlanGroups?: SellingPlanGroup[];\n };\n title: string;\n /** Integer minor units (Stripe convention): 1999 = $19.99 USD */\n price: number;\n compareAtPrice?: number | null;\n image: Image | null;\n selectedOptions: {\n name: string;\n value: string;\n }[];\n}\n\nexport interface CartLineAttribute {\n key: string;\n value: string | number | boolean;\n}\n\n/** Replo attribution property added to cart/buy-now line items for order attribution in Shopify. */\nexport const REPLO_ATTRIBUTION_PROPERTY: CartLineAttribute = {\n key: \"_replo\",\n value: \"true\",\n};\n\nexport interface SellingPlanPriceAdjustment {\n compareAtPrice: {\n amount: number;\n currencyCode: string;\n };\n perDeliveryPrice: {\n amount: number;\n currencyCode: string;\n };\n price: {\n amount: number;\n currencyCode: string;\n };\n unitPrice: {\n amount: number;\n currencyCode: string;\n } | null;\n}\n\nexport interface SellingPlanAllocation {\n sellingPlan: {\n id: string;\n name: string;\n description: string | null;\n };\n priceAdjustments: SellingPlanPriceAdjustment[];\n checkoutChargeAmount: {\n amount: number;\n currencyCode: string;\n };\n remainingBalanceChargeAmount: {\n amount: number;\n currencyCode: string;\n };\n}\n\nexport interface CartLine {\n id: string;\n quantity: number;\n /**\n * Null when this is an optimistic line whose merchandise couldn't be\n * resolved from the query cache or passed explicitly. Consumers should\n * render a skeleton/loading state in that case; the line is replaced\n * with real merchandise once the server roundtrip lands.\n */\n merchandise: CartLineMerchandise | null;\n attributes: CartLineAttribute[];\n sellingPlanAllocation?: SellingPlanAllocation | null;\n}\n\nexport interface CartCost {\n /** Integer minor units (Stripe convention) in currencyCode */\n subtotalAmount: number;\n totalAmount: number;\n currencyCode: string;\n}\n\n/**\n * Represents a discount code applied to a cart.\n */\nexport interface CartDiscountCode {\n /** The discount code string */\n code: string;\n /**\n * Whether the discount code is applicable to the current cart.\n * A code may not be applicable due to:\n * - Cart contents not meeting product/collection eligibility\n * - Minimum purchase amount not met\n * - Code expired or usage limits reached\n * - Customer restrictions\n * - Conflicting discount rules\n */\n applicable: boolean;\n}\n\n/**\n * One discount Shopify applied to a cart line or to the whole cart. The amount\n * is already subtracted from `cost.totalAmount` (and from `cost.subtotalAmount`\n * for line-level discounts).\n */\nexport interface CartDiscountAllocation {\n /** Integer minor units (Stripe convention) in the cart's currencyCode */\n discountedAmount: number;\n /** Automatic discount title or discount code; null when Shopify has neither */\n title: string | null;\n}\n\nexport interface Cart {\n id: string;\n lines: CartLine[];\n cost: CartCost;\n checkoutUrl?: string;\n discountCodes?: CartDiscountCode[];\n discountAllocations?: CartDiscountAllocation[];\n}\n\nexport interface CartLinePayload {\n id: string;\n quantity: number;\n merchandise?: CartLineMerchandise;\n properties?: CartLineAttribute[];\n sellingPlanId?: string | null;\n}\n\nexport interface AddToCartPayload {\n lines: CartLinePayload[];\n cartId: string;\n}\n\nexport interface UpdateCartLineItemPayload {\n line: CartLinePayload;\n cartId: string;\n}\n\nexport interface RemoveFromCartPayload {\n lineIds: string[];\n cartId: string;\n}\n\nexport interface UpdateCartDiscountCodesPayload {\n cartId: string;\n discountCodes: string[];\n}\n"],
5
5
  "mappings": "AAoCO,MAAM,6BAAgD;AAAA,EAC3D,KAAK;AAAA,EACL,OAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -13,20 +13,21 @@ export interface CartTotals {
13
13
  export declare function calculateLineItemsSubtotal(lineItems: CartLine[]): number;
14
14
  /**
15
15
  * Recompute a cart's cost from its line items. Cookie carts are their own source
16
- * of truth (no server roundtrip) and apply no cart-level discounts, so subtotal
17
- * equals total. Without this the cost stays at the 0 it was created with, and
18
- * every consumer that trusts it (cart total, checkout analytics) reports $0 for
19
- * a priced cart.
16
+ * of truth (no server roundtrip) and apply no discounts, so subtotal equals
17
+ * total and there are no discount allocations. Without this the cost stays at
18
+ * the 0 it was created with, and every consumer that trusts it (cart total,
19
+ * checkout analytics) reports $0 for a priced cart.
20
20
  */
21
21
  export declare function recalculateCartCost(cart: Cart): Cart;
22
22
  /**
23
23
  * Calculate cart totals including subtotal, discounts, and final total.
24
24
  * When cart cost data is provided (from Shopify), uses the actual totalAmount
25
- * which includes cart-level discounts from discount codes.
25
+ * and sums the provider's discount allocations (automatic, code, and custom
26
+ * discounts, at both line and cart level) for the discount amount.
26
27
  *
27
28
  * @param options - Object containing lineItems and cart
28
29
  * @param options.lineItems - Array of cart line items
29
- * @param options.cart - Optional cart data from Shopify (includes discount codes)
30
+ * @param options.cart - Optional cart data from Shopify (includes discount allocations)
30
31
  */
31
32
  export declare function calculateCartTotals({ lineItems, cart, }: {
32
33
  lineItems: CartLine[];
@@ -14,7 +14,8 @@ function recalculateCartCost(cart) {
14
14
  ...cart.cost,
15
15
  subtotalAmount: subtotal,
16
16
  totalAmount: subtotal
17
- }
17
+ },
18
+ discountAllocations: []
18
19
  };
19
20
  }
20
21
  function calculateCartTotals({
@@ -26,8 +27,10 @@ function calculateCartTotals({
26
27
  return sum + getCartLinePricing(item).compareAtPrice * item.quantity;
27
28
  }, 0);
28
29
  const total = cart?.cost.totalAmount ?? lineItemSubtotal;
29
- const actualSubtotal = cart?.cost.subtotalAmount ?? lineItemSubtotal;
30
- const discountAmount = actualSubtotal - total;
30
+ const discountAmount = (cart?.discountAllocations ?? []).reduce(
31
+ (sum, allocation) => sum + allocation.discountedAmount,
32
+ 0
33
+ );
31
34
  const totalSavings = compareAtSubtotal - total;
32
35
  return {
33
36
  subtotal: lineItemSubtotal,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../cart/utils/cart-utils.ts"],
4
- "sourcesContent": ["import type { Cart, CartLine } from \"../cart-types\";\n\nimport { formatAmount } from \"schemas/money\";\n\nimport { getCartLinePricing } from \"./variant-to-cart-line\";\n\nexport interface CartTotals {\n subtotal: number;\n discountAmount: number;\n totalSavings: number;\n total: number;\n}\n\n/**\n * Sum the final (post selling-plan) price of every line item in the cart.\n * This is the authoritative subtotal for cookie-based carts, which have no\n * server-computed cost to rely on.\n */\nexport function calculateLineItemsSubtotal(lineItems: CartLine[]): number {\n return lineItems.reduce(\n (sum, item) => sum + getCartLinePricing(item).finalPrice * item.quantity,\n 0,\n );\n}\n\n/**\n * Recompute a cart's cost from its line items. Cookie carts are their own source\n * of truth (no server roundtrip) and apply no cart-level discounts, so subtotal\n * equals total. Without this the cost stays at the 0 it was created with, and\n * every consumer that trusts it (cart total, checkout analytics) reports $0 for\n * a priced cart.\n */\nexport function recalculateCartCost(cart: Cart): Cart {\n const subtotal = calculateLineItemsSubtotal(cart.lines);\n return {\n ...cart,\n cost: {\n ...cart.cost,\n subtotalAmount: subtotal,\n totalAmount: subtotal,\n },\n };\n}\n\n/**\n * Calculate cart totals including subtotal, discounts, and final total.\n * When cart cost data is provided (from Shopify), uses the actual totalAmount\n * which includes cart-level discounts from discount codes.\n *\n * @param options - Object containing lineItems and cart\n * @param options.lineItems - Array of cart line items\n * @param options.cart - Optional cart data from Shopify (includes discount codes)\n */\nexport function calculateCartTotals({\n lineItems,\n cart,\n}: {\n lineItems: CartLine[];\n cart: Cart | null;\n}): CartTotals {\n const lineItemSubtotal = calculateLineItemsSubtotal(lineItems);\n const compareAtSubtotal = lineItems.reduce((sum, item) => {\n return sum + getCartLinePricing(item).compareAtPrice * item.quantity;\n }, 0);\n\n // NOTE (Jasmine, 2026-07-22): Trust the provider's authoritative cost when\n // present. For Shopify this is the server-computed cart cost (including a\n // legitimate $0 when items aren't purchasable), which we must not\n // second-guess; cookie carts keep their cost truthful via\n // cookie-cart-persistence.ts.\n const total = cart?.cost.totalAmount ?? lineItemSubtotal;\n\n // If we have provider cost data, use subtotalAmount which doesn't include discounts\n const actualSubtotal = cart?.cost.subtotalAmount ?? lineItemSubtotal;\n const discountAmount = actualSubtotal - total;\n\n const totalSavings = compareAtSubtotal - total;\n\n return {\n subtotal: lineItemSubtotal,\n discountAmount,\n totalSavings,\n total,\n };\n}\n\n/**\n * @deprecated Back-compat shim kept for surface parity with canopy-sdk, so\n * sites migrating off `import { formatPrice } from\n * \"canopy-sdk/cart/utils/cart-utils\"` keep rendering with only the package\n * specifier renamed. It formats INTEGER MINOR UNITS \u2014 the units every cart\n * value uses (`calculateCartTotals`, `getCartLinePricing`, `CartCost`):\n * passing 1999 yields \"$19.99\", not \"$1,999.00\". New code should call\n * `formatAmount({ amount, currencyCode })` from `@replohq/sdk/money` directly.\n */\nexport function formatPrice(price: number, currency: string = \"USD\"): string {\n return formatAmount({ amount: price, currencyCode: currency });\n}\n\n/**\n * Validates and formats a Shopify selling plan ID to ensure it has the correct GID format.\n *\n * @param sellingPlanId - The selling plan ID to validate and format\n * @returns The formatted selling plan ID with GID prefix, or null if no ID provided\n */\nexport function formatSellingPlanId(\n sellingPlanId: string | null | undefined,\n): string | null {\n if (!sellingPlanId) {\n return null;\n }\n\n // Check if it already has the gid format\n if (sellingPlanId.startsWith(\"gid://shopify/SellingPlan/\")) {\n return sellingPlanId;\n }\n\n // If it doesn't have the gid format, prepend it\n return `gid://shopify/SellingPlan/${sellingPlanId}`;\n}\n"],
5
- "mappings": "AAEA,SAAS,oBAAoB;AAE7B,SAAS,0BAA0B;AAc5B,SAAS,2BAA2B,WAA+B;AACxE,SAAO,UAAU;AAAA,IACf,CAAC,KAAK,SAAS,MAAM,mBAAmB,IAAI,EAAE,aAAa,KAAK;AAAA,IAChE;AAAA,EACF;AACF;AASO,SAAS,oBAAoB,MAAkB;AACpD,QAAM,WAAW,2BAA2B,KAAK,KAAK;AACtD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM;AAAA,MACJ,GAAG,KAAK;AAAA,MACR,gBAAgB;AAAA,MAChB,aAAa;AAAA,IACf;AAAA,EACF;AACF;AAWO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AACF,GAGe;AACb,QAAM,mBAAmB,2BAA2B,SAAS;AAC7D,QAAM,oBAAoB,UAAU,OAAO,CAAC,KAAK,SAAS;AACxD,WAAO,MAAM,mBAAmB,IAAI,EAAE,iBAAiB,KAAK;AAAA,EAC9D,GAAG,CAAC;AAOJ,QAAM,QAAQ,MAAM,KAAK,eAAe;AAGxC,QAAM,iBAAiB,MAAM,KAAK,kBAAkB;AACpD,QAAM,iBAAiB,iBAAiB;AAExC,QAAM,eAAe,oBAAoB;AAEzC,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAWO,SAAS,YAAY,OAAe,WAAmB,OAAe;AAC3E,SAAO,aAAa,EAAE,QAAQ,OAAO,cAAc,SAAS,CAAC;AAC/D;AAQO,SAAS,oBACd,eACe;AACf,MAAI,CAAC,eAAe;AAClB,WAAO;AAAA,EACT;AAGA,MAAI,cAAc,WAAW,4BAA4B,GAAG;AAC1D,WAAO;AAAA,EACT;AAGA,SAAO,6BAA6B,aAAa;AACnD;",
4
+ "sourcesContent": ["import type { Cart, CartLine } from \"../cart-types\";\n\nimport { formatAmount } from \"schemas/money\";\n\nimport { getCartLinePricing } from \"./variant-to-cart-line\";\n\nexport interface CartTotals {\n subtotal: number;\n discountAmount: number;\n totalSavings: number;\n total: number;\n}\n\n/**\n * Sum the final (post selling-plan) price of every line item in the cart.\n * This is the authoritative subtotal for cookie-based carts, which have no\n * server-computed cost to rely on.\n */\nexport function calculateLineItemsSubtotal(lineItems: CartLine[]): number {\n return lineItems.reduce(\n (sum, item) => sum + getCartLinePricing(item).finalPrice * item.quantity,\n 0,\n );\n}\n\n/**\n * Recompute a cart's cost from its line items. Cookie carts are their own source\n * of truth (no server roundtrip) and apply no discounts, so subtotal equals\n * total and there are no discount allocations. Without this the cost stays at\n * the 0 it was created with, and every consumer that trusts it (cart total,\n * checkout analytics) reports $0 for a priced cart.\n */\nexport function recalculateCartCost(cart: Cart): Cart {\n const subtotal = calculateLineItemsSubtotal(cart.lines);\n return {\n ...cart,\n cost: {\n ...cart.cost,\n subtotalAmount: subtotal,\n totalAmount: subtotal,\n },\n discountAllocations: [],\n };\n}\n\n/**\n * Calculate cart totals including subtotal, discounts, and final total.\n * When cart cost data is provided (from Shopify), uses the actual totalAmount\n * and sums the provider's discount allocations (automatic, code, and custom\n * discounts, at both line and cart level) for the discount amount.\n *\n * @param options - Object containing lineItems and cart\n * @param options.lineItems - Array of cart line items\n * @param options.cart - Optional cart data from Shopify (includes discount allocations)\n */\nexport function calculateCartTotals({\n lineItems,\n cart,\n}: {\n lineItems: CartLine[];\n cart: Cart | null;\n}): CartTotals {\n const lineItemSubtotal = calculateLineItemsSubtotal(lineItems);\n const compareAtSubtotal = lineItems.reduce((sum, item) => {\n return sum + getCartLinePricing(item).compareAtPrice * item.quantity;\n }, 0);\n\n // NOTE (Jasmine, 2026-07-22): Trust the provider's authoritative cost when\n // present. For Shopify this is the server-computed cart cost (including a\n // legitimate $0 when items aren't purchasable), which we must not\n // second-guess; cookie carts keep their cost truthful via\n // cookie-cart-persistence.ts.\n const total = cart?.cost.totalAmount ?? lineItemSubtotal;\n\n // Shopify folds line-level discounts into cost.subtotalAmount too, so the\n // cost gap can't be used; the allocations carry every applied discount.\n const discountAmount = (cart?.discountAllocations ?? []).reduce(\n (sum, allocation) => sum + allocation.discountedAmount,\n 0,\n );\n\n const totalSavings = compareAtSubtotal - total;\n\n return {\n subtotal: lineItemSubtotal,\n discountAmount,\n totalSavings,\n total,\n };\n}\n\n/**\n * @deprecated Back-compat shim kept for surface parity with canopy-sdk, so\n * sites migrating off `import { formatPrice } from\n * \"canopy-sdk/cart/utils/cart-utils\"` keep rendering with only the package\n * specifier renamed. It formats INTEGER MINOR UNITS \u2014 the units every cart\n * value uses (`calculateCartTotals`, `getCartLinePricing`, `CartCost`):\n * passing 1999 yields \"$19.99\", not \"$1,999.00\". New code should call\n * `formatAmount({ amount, currencyCode })` from `@replohq/sdk/money` directly.\n */\nexport function formatPrice(price: number, currency: string = \"USD\"): string {\n return formatAmount({ amount: price, currencyCode: currency });\n}\n\n/**\n * Validates and formats a Shopify selling plan ID to ensure it has the correct GID format.\n *\n * @param sellingPlanId - The selling plan ID to validate and format\n * @returns The formatted selling plan ID with GID prefix, or null if no ID provided\n */\nexport function formatSellingPlanId(\n sellingPlanId: string | null | undefined,\n): string | null {\n if (!sellingPlanId) {\n return null;\n }\n\n // Check if it already has the gid format\n if (sellingPlanId.startsWith(\"gid://shopify/SellingPlan/\")) {\n return sellingPlanId;\n }\n\n // If it doesn't have the gid format, prepend it\n return `gid://shopify/SellingPlan/${sellingPlanId}`;\n}\n"],
5
+ "mappings": "AAEA,SAAS,oBAAoB;AAE7B,SAAS,0BAA0B;AAc5B,SAAS,2BAA2B,WAA+B;AACxE,SAAO,UAAU;AAAA,IACf,CAAC,KAAK,SAAS,MAAM,mBAAmB,IAAI,EAAE,aAAa,KAAK;AAAA,IAChE;AAAA,EACF;AACF;AASO,SAAS,oBAAoB,MAAkB;AACpD,QAAM,WAAW,2BAA2B,KAAK,KAAK;AACtD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM;AAAA,MACJ,GAAG,KAAK;AAAA,MACR,gBAAgB;AAAA,MAChB,aAAa;AAAA,IACf;AAAA,IACA,qBAAqB,CAAC;AAAA,EACxB;AACF;AAYO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AACF,GAGe;AACb,QAAM,mBAAmB,2BAA2B,SAAS;AAC7D,QAAM,oBAAoB,UAAU,OAAO,CAAC,KAAK,SAAS;AACxD,WAAO,MAAM,mBAAmB,IAAI,EAAE,iBAAiB,KAAK;AAAA,EAC9D,GAAG,CAAC;AAOJ,QAAM,QAAQ,MAAM,KAAK,eAAe;AAIxC,QAAM,kBAAkB,MAAM,uBAAuB,CAAC,GAAG;AAAA,IACvD,CAAC,KAAK,eAAe,MAAM,WAAW;AAAA,IACtC;AAAA,EACF;AAEA,QAAM,eAAe,oBAAoB;AAEzC,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAWO,SAAS,YAAY,OAAe,WAAmB,OAAe;AAC3E,SAAO,aAAa,EAAE,QAAQ,OAAO,cAAc,SAAS,CAAC;AAC/D;AAQO,SAAS,oBACd,eACe;AACf,MAAI,CAAC,eAAe;AAClB,WAAO;AAAA,EACT;AAGA,MAAI,cAAc,WAAW,4BAA4B,GAAG;AAC1D,WAAO;AAAA,EACT;AAGA,SAAO,6BAA6B,aAAa;AACnD;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  export const BUILD_METADATA = {
2
2
  "packageName": "@replohq/sdk",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "branch": "HEAD",
5
- "commit": "8534cbe94f47e7d47bbb1c214bf02f58289cc1a8",
6
- "builtAt": "2026-09-02T20:05:57.576Z"
5
+ "commit": "169d937b821d030ec7248cb90cc303bad98f79d4",
6
+ "builtAt": "2026-09-02T22:01:44.766Z"
7
7
  };
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@replohq/sdk",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "reploBuild": {
5
5
  "packageName": "@replohq/sdk",
6
- "version": "1.2.1",
6
+ "version": "1.2.2",
7
7
  "branch": "HEAD",
8
- "commit": "8534cbe94f47e7d47bbb1c214bf02f58289cc1a8",
9
- "builtAt": "2026-09-02T20:05:57.576Z"
8
+ "commit": "169d937b821d030ec7248cb90cc303bad98f79d4",
9
+ "builtAt": "2026-09-02T22:01:44.766Z"
10
10
  },
11
11
  "description": "Replo SDK — cart, analytics, and data loaders for agent-built Next.js sites.",
12
12
  "license": "SEE LICENSE IN LICENSE",