@replohq/sdk 2.18.2 → 2.18.3
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/cart/cart-actions.js +42 -13
- package/cart/checkout-actions.js +1 -1
- package/cart/checkout-session-actions.js +2 -2
- package/cart/gateways/cart-gateway.d.ts +29 -8
- package/cart/gateways/cookie-cart-gateway.d.ts +4 -2
- package/cart/gateways/cookie-cart-gateway.js +4 -4
- package/cart/gateways/resolver-cart-gateway.js +28 -16
- package/cart/gateways/stripe-cart-gateway.js +1 -1
- package/cart/start-stripe-checkout.js +1 -1
- package/gateways/canopy-api.d.ts +21 -15
- package/gateways/canopy-api.js +105 -54
- package/lib/buildMetadata.js +3 -3
- package/lib/buyer-ip.d.ts +6 -0
- package/lib/buyer-ip.js +7 -0
- package/loaders/invoke-loader-action.js +6 -1
- package/loaders/invoke-loader-server.js +5 -1
- package/loaders/invoke-loader.js +5 -1
- package/loaders/loader-output.d.ts +2 -1
- package/loaders/loader-output.js +7 -3
- package/package.json +4 -4
package/cart/cart-actions.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use server";
|
|
2
2
|
import { cookies } from "next/headers";
|
|
3
|
+
import { readBuyerIp } from "../lib/buyer-ip";
|
|
3
4
|
import { getCheckoutProvider } from "../lib/integration-utils";
|
|
4
5
|
import { REPLO_ATTRIBUTION_PROPERTY } from "./cart-types";
|
|
5
6
|
import {
|
|
@@ -23,7 +24,8 @@ async function reconcileExistingCart(cart, country) {
|
|
|
23
24
|
if (country && reconciledCart.buyerIdentity?.country !== country) {
|
|
24
25
|
return await cartGateway.updateCartBuyerIdentity({
|
|
25
26
|
cartId: reconciledCart.id,
|
|
26
|
-
buyerIdentity: { country }
|
|
27
|
+
buyerIdentity: { country },
|
|
28
|
+
buyerIp: await readBuyerIp()
|
|
27
29
|
});
|
|
28
30
|
}
|
|
29
31
|
return reconciledCart;
|
|
@@ -51,9 +53,10 @@ async function getCartAction() {
|
|
|
51
53
|
const cartGateway = await getCartGateway();
|
|
52
54
|
const sharedToken = checkoutProvider === "shopify" ? cookieStore.get(SHARED_SHOPIFY_CART_COOKIE_NAME)?.value : void 0;
|
|
53
55
|
if (sharedToken) {
|
|
54
|
-
const sharedCart = await cartGateway.getCart(
|
|
55
|
-
`${SHOPIFY_CART_ID_PREFIX}${sharedToken}
|
|
56
|
-
|
|
56
|
+
const sharedCart = await cartGateway.getCart({
|
|
57
|
+
cartId: `${SHOPIFY_CART_ID_PREFIX}${sharedToken}`,
|
|
58
|
+
buyerIp: await readBuyerIp()
|
|
59
|
+
});
|
|
57
60
|
if (sharedCart) {
|
|
58
61
|
return sharedCart;
|
|
59
62
|
}
|
|
@@ -62,7 +65,10 @@ async function getCartAction() {
|
|
|
62
65
|
if (!existingCartId) {
|
|
63
66
|
return null;
|
|
64
67
|
}
|
|
65
|
-
const cart = await cartGateway.getCart(
|
|
68
|
+
const cart = await cartGateway.getCart({
|
|
69
|
+
cartId: existingCartId,
|
|
70
|
+
buyerIp: await readBuyerIp()
|
|
71
|
+
});
|
|
66
72
|
if (!cart) {
|
|
67
73
|
try {
|
|
68
74
|
cookieStore.set(SHOPIFY_CART_COOKIE_NAME, "", {
|
|
@@ -92,7 +98,8 @@ async function createCartAction(options) {
|
|
|
92
98
|
lines,
|
|
93
99
|
discountCodes,
|
|
94
100
|
attributes,
|
|
95
|
-
buyerIdentity: country ? { country } : void 0
|
|
101
|
+
buyerIdentity: country ? { country } : void 0,
|
|
102
|
+
buyerIp: await readBuyerIp()
|
|
96
103
|
});
|
|
97
104
|
if (cart && !skipStoringCart) {
|
|
98
105
|
try {
|
|
@@ -117,7 +124,8 @@ async function createCartAction(options) {
|
|
|
117
124
|
}
|
|
118
125
|
async function addToCartAction(lines, cartId) {
|
|
119
126
|
const cartGateway = await getCartGateway();
|
|
120
|
-
const
|
|
127
|
+
const buyerIp = await readBuyerIp();
|
|
128
|
+
const cart = await cartGateway.addToCart({ lines, cartId, buyerIp });
|
|
121
129
|
if (!cart || await getCheckoutProvider() !== "shopify" || cart.attributes?.some(
|
|
122
130
|
(attribute) => attribute.key === REPLO_ATTRIBUTION_PROPERTY.key
|
|
123
131
|
)) {
|
|
@@ -125,29 +133,50 @@ async function addToCartAction(lines, cartId) {
|
|
|
125
133
|
}
|
|
126
134
|
const attributedCart = await cartGateway.replaceCartAttributes({
|
|
127
135
|
cartId: cart.id,
|
|
128
|
-
attributes: [...cart.attributes ?? [], REPLO_ATTRIBUTION_PROPERTY]
|
|
136
|
+
attributes: [...cart.attributes ?? [], REPLO_ATTRIBUTION_PROPERTY],
|
|
137
|
+
buyerIp
|
|
129
138
|
});
|
|
130
139
|
return attributedCart ?? cart;
|
|
131
140
|
}
|
|
132
141
|
async function updateCartLineItemAction(line, cartId) {
|
|
133
142
|
const cartGateway = await getCartGateway();
|
|
134
|
-
return await cartGateway.updateCartLineItem({
|
|
143
|
+
return await cartGateway.updateCartLineItem({
|
|
144
|
+
line,
|
|
145
|
+
cartId,
|
|
146
|
+
buyerIp: await readBuyerIp()
|
|
147
|
+
});
|
|
135
148
|
}
|
|
136
149
|
async function removeCartLineItemsAction(lineIds, cartId) {
|
|
137
150
|
const cartGateway = await getCartGateway();
|
|
138
|
-
return await cartGateway.removeCartLineItems({
|
|
151
|
+
return await cartGateway.removeCartLineItems({
|
|
152
|
+
lineIds,
|
|
153
|
+
cartId,
|
|
154
|
+
buyerIp: await readBuyerIp()
|
|
155
|
+
});
|
|
139
156
|
}
|
|
140
157
|
async function updateCartDiscountCodesAction(discountCodes, cartId) {
|
|
141
158
|
const cartGateway = await getCartGateway();
|
|
142
|
-
return await cartGateway.updateCartDiscountCodes({
|
|
159
|
+
return await cartGateway.updateCartDiscountCodes({
|
|
160
|
+
discountCodes,
|
|
161
|
+
cartId,
|
|
162
|
+
buyerIp: await readBuyerIp()
|
|
163
|
+
});
|
|
143
164
|
}
|
|
144
165
|
async function updateCartNoteAction(note, cartId) {
|
|
145
166
|
const cartGateway = await getCartGateway();
|
|
146
|
-
return await cartGateway.updateCartNote({
|
|
167
|
+
return await cartGateway.updateCartNote({
|
|
168
|
+
note,
|
|
169
|
+
cartId,
|
|
170
|
+
buyerIp: await readBuyerIp()
|
|
171
|
+
});
|
|
147
172
|
}
|
|
148
173
|
async function replaceCartAttributesAction(attributes, cartId) {
|
|
149
174
|
const cartGateway = await getCartGateway();
|
|
150
|
-
return await cartGateway.replaceCartAttributes({
|
|
175
|
+
return await cartGateway.replaceCartAttributes({
|
|
176
|
+
attributes,
|
|
177
|
+
cartId,
|
|
178
|
+
buyerIp: await readBuyerIp()
|
|
179
|
+
});
|
|
151
180
|
}
|
|
152
181
|
export {
|
|
153
182
|
addToCartAction,
|
package/cart/checkout-actions.js
CHANGED
|
@@ -19,7 +19,7 @@ async function getCrossSellsAction(input) {
|
|
|
19
19
|
if (await getCheckoutProvider() !== "stripe") {
|
|
20
20
|
return [];
|
|
21
21
|
}
|
|
22
|
-
return await
|
|
22
|
+
return await getCanopyApiGateway().findCrossSells(input);
|
|
23
23
|
}
|
|
24
24
|
export {
|
|
25
25
|
createCheckoutSessionAction,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use server";
|
|
2
2
|
import { getCanopyApiGateway } from "../gateways/canopy-api";
|
|
3
3
|
async function updateCheckoutShippingAction(input) {
|
|
4
|
-
return await
|
|
4
|
+
return await getCanopyApiGateway().updateCheckoutShipping(input);
|
|
5
5
|
}
|
|
6
6
|
async function addCrossSellAction(input) {
|
|
7
|
-
return await
|
|
7
|
+
return await getCanopyApiGateway().addCrossSell(input);
|
|
8
8
|
}
|
|
9
9
|
export {
|
|
10
10
|
addCrossSellAction,
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { AddToCartPayload, Cart, CartBuyerIdentity, CartLinePayload, RemoveFromCartPayload, ReplaceCartAttributesPayload, UpdateCartDiscountCodesPayload, UpdateCartLineItemPayload, UpdateCartNotePayload } from "../cart-types";
|
|
2
|
+
/** `buyerIp` is the shopper's IP; Shopify carts forward it, others ignore it. */
|
|
2
3
|
export interface CartGateway {
|
|
3
|
-
getCart(
|
|
4
|
+
getCart(request: {
|
|
5
|
+
cartId: string;
|
|
6
|
+
} & {
|
|
7
|
+
buyerIp: string | null;
|
|
8
|
+
}): Promise<Cart | null>;
|
|
4
9
|
/**
|
|
5
10
|
* Bring a stored cart back in line with its source of truth. Cookie carts
|
|
6
11
|
* reprice against the catalog and drop unavailable lines (persisting the
|
|
@@ -8,7 +13,7 @@ export interface CartGateway {
|
|
|
8
13
|
* cart unchanged.
|
|
9
14
|
*/
|
|
10
15
|
reconcileStoredCart(cart: Cart): Promise<Cart>;
|
|
11
|
-
createCart(options
|
|
16
|
+
createCart(options: {
|
|
12
17
|
lines?: CartLinePayload[];
|
|
13
18
|
discountCodes?: string[];
|
|
14
19
|
attributes?: {
|
|
@@ -16,16 +21,32 @@ export interface CartGateway {
|
|
|
16
21
|
value: string;
|
|
17
22
|
}[];
|
|
18
23
|
buyerIdentity?: CartBuyerIdentity;
|
|
24
|
+
} & {
|
|
25
|
+
buyerIp: string | null;
|
|
26
|
+
}): Promise<Cart | null>;
|
|
27
|
+
addToCart(cartPayload: AddToCartPayload & {
|
|
28
|
+
buyerIp: string | null;
|
|
19
29
|
}): Promise<Cart | null>;
|
|
20
|
-
addToCart(cartPayload: AddToCartPayload): Promise<Cart | null>;
|
|
21
30
|
updateCartBuyerIdentity(payload: {
|
|
22
31
|
cartId: string;
|
|
23
32
|
buyerIdentity: CartBuyerIdentity;
|
|
33
|
+
} & {
|
|
34
|
+
buyerIp: string | null;
|
|
35
|
+
}): Promise<Cart | null>;
|
|
36
|
+
updateCartLineItem(cartPayload: UpdateCartLineItemPayload & {
|
|
37
|
+
buyerIp: string | null;
|
|
38
|
+
}): Promise<Cart | null>;
|
|
39
|
+
removeCartLineItems(cartPayload: RemoveFromCartPayload & {
|
|
40
|
+
buyerIp: string | null;
|
|
41
|
+
}): Promise<Cart | null>;
|
|
42
|
+
updateCartDiscountCodes(cartPayload: UpdateCartDiscountCodesPayload & {
|
|
43
|
+
buyerIp: string | null;
|
|
44
|
+
}): Promise<Cart | null>;
|
|
45
|
+
updateCartNote(cartPayload: UpdateCartNotePayload & {
|
|
46
|
+
buyerIp: string | null;
|
|
47
|
+
}): Promise<Cart | null>;
|
|
48
|
+
replaceCartAttributes(cartPayload: ReplaceCartAttributesPayload & {
|
|
49
|
+
buyerIp: string | null;
|
|
24
50
|
}): Promise<Cart | null>;
|
|
25
|
-
updateCartLineItem(cartPayload: UpdateCartLineItemPayload): Promise<Cart | null>;
|
|
26
|
-
removeCartLineItems(cartPayload: RemoveFromCartPayload): Promise<Cart | null>;
|
|
27
|
-
updateCartDiscountCodes(cartPayload: UpdateCartDiscountCodesPayload): Promise<Cart | null>;
|
|
28
|
-
updateCartNote(cartPayload: UpdateCartNotePayload): Promise<Cart | null>;
|
|
29
|
-
replaceCartAttributes(cartPayload: ReplaceCartAttributesPayload): Promise<Cart | null>;
|
|
30
51
|
}
|
|
31
52
|
export declare function getCartGateway(): Promise<CartGateway>;
|
|
@@ -27,8 +27,10 @@ export declare abstract class CookieBasedCartGateway implements CartGateway {
|
|
|
27
27
|
private reconcile;
|
|
28
28
|
private reconcileForWrite;
|
|
29
29
|
reconcileStoredCart(cart: Cart): Promise<Cart>;
|
|
30
|
-
getCart(cartId
|
|
31
|
-
|
|
30
|
+
getCart({ cartId }: {
|
|
31
|
+
cartId: string;
|
|
32
|
+
}): Promise<Cart | null>;
|
|
33
|
+
createCart({ lines, }: {
|
|
32
34
|
lines?: CartLinePayload[];
|
|
33
35
|
discountCodes?: string[];
|
|
34
36
|
buyerIdentity?: CartBuyerIdentity;
|
|
@@ -51,7 +51,7 @@ class CookieBasedCartGateway {
|
|
|
51
51
|
}
|
|
52
52
|
return reconciledCart;
|
|
53
53
|
}
|
|
54
|
-
async getCart(cartId) {
|
|
54
|
+
async getCart({ cartId }) {
|
|
55
55
|
try {
|
|
56
56
|
const cart = await loadCartFromCookie(this.config.cookieName);
|
|
57
57
|
return cart?.id === cartId ? cart : null;
|
|
@@ -65,7 +65,7 @@ class CookieBasedCartGateway {
|
|
|
65
65
|
}
|
|
66
66
|
async createCart({
|
|
67
67
|
lines
|
|
68
|
-
}
|
|
68
|
+
}) {
|
|
69
69
|
try {
|
|
70
70
|
const cart = await createCartWithPersistence({
|
|
71
71
|
cookieName: this.config.cookieName,
|
|
@@ -146,7 +146,7 @@ class CookieBasedCartGateway {
|
|
|
146
146
|
`${this.config.gatewayName} cart gateway does not yet support discount codes`
|
|
147
147
|
);
|
|
148
148
|
try {
|
|
149
|
-
return await this.getCart(cartPayload.cartId);
|
|
149
|
+
return await this.getCart({ cartId: cartPayload.cartId });
|
|
150
150
|
} catch (error) {
|
|
151
151
|
console.warn("Failed to fetch cart for discount code update:", error);
|
|
152
152
|
return null;
|
|
@@ -155,7 +155,7 @@ class CookieBasedCartGateway {
|
|
|
155
155
|
async updateCartBuyerIdentity({
|
|
156
156
|
cartId
|
|
157
157
|
}) {
|
|
158
|
-
return this.getCart(cartId);
|
|
158
|
+
return this.getCart({ cartId });
|
|
159
159
|
}
|
|
160
160
|
async updateCartNote({
|
|
161
161
|
cartId,
|
|
@@ -4,18 +4,21 @@ class ResolverCartGateway {
|
|
|
4
4
|
async reconcileStoredCart(cart) {
|
|
5
5
|
return cart;
|
|
6
6
|
}
|
|
7
|
-
async getCart(
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
async getCart({
|
|
8
|
+
cartId,
|
|
9
|
+
buyerIp
|
|
10
|
+
}) {
|
|
11
|
+
return await getCanopyApiGateway().cartGet({ cartId, buyerIp });
|
|
10
12
|
}
|
|
11
13
|
async createCart({
|
|
12
14
|
lines,
|
|
13
15
|
discountCodes,
|
|
14
16
|
attributes,
|
|
15
|
-
buyerIdentity
|
|
16
|
-
|
|
17
|
+
buyerIdentity,
|
|
18
|
+
buyerIp
|
|
19
|
+
}) {
|
|
17
20
|
try {
|
|
18
|
-
const gateway =
|
|
21
|
+
const gateway = getCanopyApiGateway();
|
|
19
22
|
return await gateway.cartCreate({
|
|
20
23
|
lines: lines?.map((line) => ({
|
|
21
24
|
merchandiseId: line.id,
|
|
@@ -28,7 +31,8 @@ class ResolverCartGateway {
|
|
|
28
31
|
})),
|
|
29
32
|
discountCodes,
|
|
30
33
|
attributes,
|
|
31
|
-
country: buyerIdentity?.country
|
|
34
|
+
country: buyerIdentity?.country,
|
|
35
|
+
buyerIp
|
|
32
36
|
});
|
|
33
37
|
} catch (error) {
|
|
34
38
|
console.warn("Failed to create cart via canopy-api:", error);
|
|
@@ -37,9 +41,10 @@ class ResolverCartGateway {
|
|
|
37
41
|
}
|
|
38
42
|
async addToCart(cartPayload) {
|
|
39
43
|
try {
|
|
40
|
-
const gateway =
|
|
44
|
+
const gateway = getCanopyApiGateway();
|
|
41
45
|
return await gateway.cartAddLines({
|
|
42
46
|
cartId: cartPayload.cartId,
|
|
47
|
+
buyerIp: cartPayload.buyerIp,
|
|
43
48
|
lines: cartPayload.lines.map((line) => ({
|
|
44
49
|
merchandiseId: line.id,
|
|
45
50
|
quantity: line.quantity,
|
|
@@ -57,9 +62,10 @@ class ResolverCartGateway {
|
|
|
57
62
|
}
|
|
58
63
|
async updateCartLineItem(cartPayload) {
|
|
59
64
|
try {
|
|
60
|
-
const gateway =
|
|
65
|
+
const gateway = getCanopyApiGateway();
|
|
61
66
|
return await gateway.cartUpdateLines({
|
|
62
67
|
cartId: cartPayload.cartId,
|
|
68
|
+
buyerIp: cartPayload.buyerIp,
|
|
63
69
|
lines: [
|
|
64
70
|
{
|
|
65
71
|
lineId: cartPayload.line.id,
|
|
@@ -79,9 +85,10 @@ class ResolverCartGateway {
|
|
|
79
85
|
}
|
|
80
86
|
async removeCartLineItems(cartPayload) {
|
|
81
87
|
try {
|
|
82
|
-
const gateway =
|
|
88
|
+
const gateway = getCanopyApiGateway();
|
|
83
89
|
return await gateway.cartRemoveLines({
|
|
84
90
|
cartId: cartPayload.cartId,
|
|
91
|
+
buyerIp: cartPayload.buyerIp,
|
|
85
92
|
lineIds: cartPayload.lineIds
|
|
86
93
|
});
|
|
87
94
|
} catch (error) {
|
|
@@ -91,9 +98,10 @@ class ResolverCartGateway {
|
|
|
91
98
|
}
|
|
92
99
|
async updateCartDiscountCodes(cartPayload) {
|
|
93
100
|
try {
|
|
94
|
-
const gateway =
|
|
101
|
+
const gateway = getCanopyApiGateway();
|
|
95
102
|
return await gateway.cartUpdateDiscountCodes({
|
|
96
103
|
cartId: cartPayload.cartId,
|
|
104
|
+
buyerIp: cartPayload.buyerIp,
|
|
97
105
|
discountCodes: cartPayload.discountCodes
|
|
98
106
|
});
|
|
99
107
|
} catch (error) {
|
|
@@ -103,13 +111,15 @@ class ResolverCartGateway {
|
|
|
103
111
|
}
|
|
104
112
|
async updateCartBuyerIdentity({
|
|
105
113
|
cartId,
|
|
106
|
-
buyerIdentity
|
|
114
|
+
buyerIdentity,
|
|
115
|
+
buyerIp
|
|
107
116
|
}) {
|
|
108
117
|
try {
|
|
109
|
-
const gateway =
|
|
118
|
+
const gateway = getCanopyApiGateway();
|
|
110
119
|
return await gateway.cartUpdateBuyerIdentity({
|
|
111
120
|
cartId,
|
|
112
|
-
country: buyerIdentity.country
|
|
121
|
+
country: buyerIdentity.country,
|
|
122
|
+
buyerIp
|
|
113
123
|
});
|
|
114
124
|
} catch (error) {
|
|
115
125
|
console.warn(
|
|
@@ -121,9 +131,10 @@ class ResolverCartGateway {
|
|
|
121
131
|
}
|
|
122
132
|
async updateCartNote(cartPayload) {
|
|
123
133
|
try {
|
|
124
|
-
const gateway =
|
|
134
|
+
const gateway = getCanopyApiGateway();
|
|
125
135
|
return await gateway.cartUpdateNote({
|
|
126
136
|
cartId: cartPayload.cartId,
|
|
137
|
+
buyerIp: cartPayload.buyerIp,
|
|
127
138
|
note: cartPayload.note
|
|
128
139
|
});
|
|
129
140
|
} catch (error) {
|
|
@@ -133,9 +144,10 @@ class ResolverCartGateway {
|
|
|
133
144
|
}
|
|
134
145
|
async replaceCartAttributes(cartPayload) {
|
|
135
146
|
try {
|
|
136
|
-
const gateway =
|
|
147
|
+
const gateway = getCanopyApiGateway();
|
|
137
148
|
return await gateway.cartReplaceAttributes({
|
|
138
149
|
cartId: cartPayload.cartId,
|
|
150
|
+
buyerIp: cartPayload.buyerIp,
|
|
139
151
|
attributes: cartPayload.attributes.map((attribute) => ({
|
|
140
152
|
key: attribute.key,
|
|
141
153
|
value: String(attribute.value)
|
|
@@ -19,7 +19,7 @@ class StripeCartGateway extends CookieBasedCartGateway {
|
|
|
19
19
|
cartIdGenerator: stripeCartIdGenerator,
|
|
20
20
|
gatewayName: "Stripe",
|
|
21
21
|
reconcileLines: async (lines) => {
|
|
22
|
-
const gateway =
|
|
22
|
+
const gateway = getCanopyApiGateway();
|
|
23
23
|
return await gateway.reconcileCartLines({ lines });
|
|
24
24
|
}
|
|
25
25
|
};
|
|
@@ -37,7 +37,7 @@ async function startStripeCheckout({
|
|
|
37
37
|
"[Replo] Stripe buy now does not support selling plans or discount codes; those options were ignored."
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
|
-
const outcome = await
|
|
40
|
+
const outcome = await getCanopyApiGateway().createStripeCheckoutSession({
|
|
41
41
|
checkoutAttemptId: checkoutAttemptId ?? uuidv4(),
|
|
42
42
|
lines: lineItems.map((item) => ({
|
|
43
43
|
variantId: item.variantId,
|
package/gateways/canopy-api.d.ts
CHANGED
|
@@ -89,16 +89,13 @@ export type CheckoutAddress = {
|
|
|
89
89
|
};
|
|
90
90
|
export declare function shouldIncludeInactiveProducts(): boolean;
|
|
91
91
|
declare class CanopyApiGateway {
|
|
92
|
-
private apiHost;
|
|
93
|
-
private baseUrl;
|
|
94
|
-
constructor(apiHost: string);
|
|
95
92
|
private static readonly REQUEST_TIMEOUT_MILLISECONDS;
|
|
96
|
-
static setup(): Promise<CanopyApiGateway>;
|
|
97
93
|
private _post;
|
|
98
94
|
private _get;
|
|
99
|
-
invokeLoader({ loaderKey, args, }: {
|
|
95
|
+
invokeLoader({ loaderKey, args, buyerIp, }: {
|
|
100
96
|
loaderKey: string;
|
|
101
97
|
args: Record<string, unknown>;
|
|
98
|
+
buyerIp: string | null;
|
|
102
99
|
}): Promise<{
|
|
103
100
|
data: unknown;
|
|
104
101
|
meta?: {
|
|
@@ -121,10 +118,12 @@ declare class CanopyApiGateway {
|
|
|
121
118
|
}[];
|
|
122
119
|
}): Promise<ReconciledCartLine[]>;
|
|
123
120
|
private _cartPost;
|
|
124
|
-
cartGet({ cartId }: {
|
|
121
|
+
cartGet({ cartId, buyerIp, }: {
|
|
125
122
|
cartId: string;
|
|
123
|
+
buyerIp: string | null;
|
|
126
124
|
}): Promise<Cart | null>;
|
|
127
|
-
cartCreate(options
|
|
125
|
+
cartCreate({ buyerIp, ...options }: {
|
|
126
|
+
buyerIp: string | null;
|
|
128
127
|
lines?: {
|
|
129
128
|
merchandiseId: string;
|
|
130
129
|
quantity: number;
|
|
@@ -141,8 +140,9 @@ declare class CanopyApiGateway {
|
|
|
141
140
|
}[];
|
|
142
141
|
country?: StorefrontCountryCode;
|
|
143
142
|
}): Promise<Cart>;
|
|
144
|
-
cartAddLines({ cartId, lines, }: {
|
|
143
|
+
cartAddLines({ cartId, lines, buyerIp, }: {
|
|
145
144
|
cartId: string;
|
|
145
|
+
buyerIp: string | null;
|
|
146
146
|
lines: {
|
|
147
147
|
merchandiseId: string;
|
|
148
148
|
quantity: number;
|
|
@@ -153,8 +153,9 @@ declare class CanopyApiGateway {
|
|
|
153
153
|
sellingPlanId?: string | null;
|
|
154
154
|
}[];
|
|
155
155
|
}): Promise<Cart>;
|
|
156
|
-
cartUpdateLines({ cartId, lines, }: {
|
|
156
|
+
cartUpdateLines({ cartId, lines, buyerIp, }: {
|
|
157
157
|
cartId: string;
|
|
158
|
+
buyerIp: string | null;
|
|
158
159
|
lines: {
|
|
159
160
|
lineId: string;
|
|
160
161
|
quantity: number;
|
|
@@ -165,24 +166,29 @@ declare class CanopyApiGateway {
|
|
|
165
166
|
sellingPlanId?: string | null;
|
|
166
167
|
}[];
|
|
167
168
|
}): Promise<Cart>;
|
|
168
|
-
cartRemoveLines({ cartId, lineIds, }: {
|
|
169
|
+
cartRemoveLines({ cartId, lineIds, buyerIp, }: {
|
|
169
170
|
cartId: string;
|
|
171
|
+
buyerIp: string | null;
|
|
170
172
|
lineIds: string[];
|
|
171
173
|
}): Promise<Cart>;
|
|
172
|
-
cartUpdateDiscountCodes({ cartId, discountCodes, }: {
|
|
174
|
+
cartUpdateDiscountCodes({ cartId, discountCodes, buyerIp, }: {
|
|
173
175
|
cartId: string;
|
|
176
|
+
buyerIp: string | null;
|
|
174
177
|
discountCodes: string[];
|
|
175
178
|
}): Promise<Cart>;
|
|
176
|
-
cartUpdateBuyerIdentity({ cartId, country, }: {
|
|
179
|
+
cartUpdateBuyerIdentity({ cartId, country, buyerIp, }: {
|
|
177
180
|
cartId: string;
|
|
181
|
+
buyerIp: string | null;
|
|
178
182
|
country: StorefrontCountryCode;
|
|
179
183
|
}): Promise<Cart>;
|
|
180
|
-
cartUpdateNote({ cartId, note, }: {
|
|
184
|
+
cartUpdateNote({ cartId, note, buyerIp, }: {
|
|
181
185
|
cartId: string;
|
|
186
|
+
buyerIp: string | null;
|
|
182
187
|
note: string;
|
|
183
188
|
}): Promise<Cart>;
|
|
184
|
-
cartReplaceAttributes({ cartId, attributes, }: {
|
|
189
|
+
cartReplaceAttributes({ cartId, attributes, buyerIp, }: {
|
|
185
190
|
cartId: string;
|
|
191
|
+
buyerIp: string | null;
|
|
186
192
|
attributes: {
|
|
187
193
|
key: string;
|
|
188
194
|
value: string;
|
|
@@ -223,5 +229,5 @@ declare class CanopyApiGateway {
|
|
|
223
229
|
variantId: string;
|
|
224
230
|
}): Promise<AddCrossSellOutcome>;
|
|
225
231
|
}
|
|
226
|
-
export declare function getCanopyApiGateway():
|
|
232
|
+
export declare function getCanopyApiGateway(): CanopyApiGateway;
|
|
227
233
|
export {};
|
package/gateways/canopy-api.js
CHANGED
|
@@ -92,19 +92,12 @@ const addCrossSellOutcomeSchema = z.discriminatedUnion("type", [
|
|
|
92
92
|
function shouldIncludeInactiveProducts() {
|
|
93
93
|
return Boolean(process.env.IS_REPLO_SANDBOX);
|
|
94
94
|
}
|
|
95
|
+
function buyerIpHeaders(buyerIp) {
|
|
96
|
+
return buyerIp ? { "x-replo-buyer-ip": buyerIp } : {};
|
|
97
|
+
}
|
|
95
98
|
class CanopyApiGateway {
|
|
96
|
-
apiHost;
|
|
97
|
-
baseUrl;
|
|
98
|
-
constructor(apiHost) {
|
|
99
|
-
this.apiHost = apiHost;
|
|
100
|
-
this.baseUrl = buildBaseUrl(apiHost);
|
|
101
|
-
}
|
|
102
99
|
static REQUEST_TIMEOUT_MILLISECONDS = 1e4;
|
|
103
|
-
|
|
104
|
-
const env = await getEnv();
|
|
105
|
-
return new CanopyApiGateway(env.CANOPY_API_HOST);
|
|
106
|
-
}
|
|
107
|
-
async _post(url, body) {
|
|
100
|
+
async _post(url, body, headers) {
|
|
108
101
|
const abortController = new AbortController();
|
|
109
102
|
const timeoutId = setTimeout(() => {
|
|
110
103
|
abortController.abort();
|
|
@@ -112,7 +105,7 @@ class CanopyApiGateway {
|
|
|
112
105
|
try {
|
|
113
106
|
return await fetch(url, {
|
|
114
107
|
method: "POST",
|
|
115
|
-
headers: { "Content-Type": "application/json" },
|
|
108
|
+
headers: { "Content-Type": "application/json", ...headers },
|
|
116
109
|
body: JSON.stringify(body),
|
|
117
110
|
signal: abortController.signal
|
|
118
111
|
});
|
|
@@ -121,7 +114,7 @@ class CanopyApiGateway {
|
|
|
121
114
|
if (process.env.NODE_ENV !== "production") {
|
|
122
115
|
message += `
|
|
123
116
|
|
|
124
|
-
apiHost: ${
|
|
117
|
+
apiHost: ${(await getEnv()).CANOPY_API_HOST}
|
|
125
118
|
If you're running locally, make sure the canopy-api cloudflare worker is running. You may need to restart the dev server.`;
|
|
126
119
|
}
|
|
127
120
|
throw new UnknownCanopyApiError({ message, cause: error });
|
|
@@ -141,7 +134,7 @@ If you're running locally, make sure the canopy-api cloudflare worker is running
|
|
|
141
134
|
if (process.env.NODE_ENV !== "production") {
|
|
142
135
|
message += `
|
|
143
136
|
|
|
144
|
-
apiHost: ${
|
|
137
|
+
apiHost: ${(await getEnv()).CANOPY_API_HOST}
|
|
145
138
|
If you're running locally, make sure the canopy-api cloudflare worker is running. You may need to restart the dev server.`;
|
|
146
139
|
}
|
|
147
140
|
throw new UnknownCanopyApiError({ message, cause: error });
|
|
@@ -151,15 +144,20 @@ If you're running locally, make sure the canopy-api cloudflare worker is running
|
|
|
151
144
|
}
|
|
152
145
|
async invokeLoader({
|
|
153
146
|
loaderKey,
|
|
154
|
-
args
|
|
147
|
+
args,
|
|
148
|
+
buyerIp
|
|
155
149
|
}) {
|
|
156
150
|
const env = await getEnv();
|
|
157
|
-
const response = await this._post(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
151
|
+
const response = await this._post(
|
|
152
|
+
`${buildBaseUrl(env.CANOPY_API_HOST)}/api/v1/loaders/invoke`,
|
|
153
|
+
{
|
|
154
|
+
projectId: env.PROJECT_ID,
|
|
155
|
+
loaderKey,
|
|
156
|
+
args,
|
|
157
|
+
includeInactiveProducts: shouldIncludeInactiveProducts()
|
|
158
|
+
},
|
|
159
|
+
buyerIpHeaders(buyerIp)
|
|
160
|
+
);
|
|
163
161
|
if (!response.ok) {
|
|
164
162
|
const errorBody = await response.text().catch(() => "");
|
|
165
163
|
throw new CanopyApiGatewayError({
|
|
@@ -174,8 +172,9 @@ If you're running locally, make sure the canopy-api cloudflare worker is running
|
|
|
174
172
|
}) {
|
|
175
173
|
const env = await getEnv();
|
|
176
174
|
const response = await this._post(
|
|
177
|
-
`${
|
|
178
|
-
{ projectId: env.PROJECT_ID, lines }
|
|
175
|
+
`${buildBaseUrl(env.CANOPY_API_HOST)}/api/v1/product-catalog/reconcile-cart-lines`,
|
|
176
|
+
{ projectId: env.PROJECT_ID, lines },
|
|
177
|
+
{}
|
|
179
178
|
);
|
|
180
179
|
if (!response.ok) {
|
|
181
180
|
const errorBody = await response.text().catch(() => "");
|
|
@@ -186,9 +185,13 @@ If you're running locally, make sure the canopy-api cloudflare worker is running
|
|
|
186
185
|
}
|
|
187
186
|
return reconcileCartLinesResponseSchema.parse(await response.json()).lines;
|
|
188
187
|
}
|
|
189
|
-
async _cartPost(
|
|
188
|
+
async _cartPost({
|
|
189
|
+
path,
|
|
190
|
+
body,
|
|
191
|
+
buyerIp
|
|
192
|
+
}) {
|
|
190
193
|
const env = await getEnv();
|
|
191
|
-
const url = `${
|
|
194
|
+
const url = `${buildBaseUrl(env.CANOPY_API_HOST)}/api/v1/cart${path}`;
|
|
192
195
|
const abortController = new AbortController();
|
|
193
196
|
const timeoutId = setTimeout(() => {
|
|
194
197
|
abortController.abort();
|
|
@@ -198,7 +201,8 @@ If you're running locally, make sure the canopy-api cloudflare worker is running
|
|
|
198
201
|
response = await fetch(url, {
|
|
199
202
|
method: "POST",
|
|
200
203
|
headers: {
|
|
201
|
-
"Content-Type": "application/json"
|
|
204
|
+
"Content-Type": "application/json",
|
|
205
|
+
...buyerIpHeaders(buyerIp)
|
|
202
206
|
},
|
|
203
207
|
body: JSON.stringify({ ...body, projectId: env.PROJECT_ID }),
|
|
204
208
|
signal: abortController.signal
|
|
@@ -221,9 +225,12 @@ If you're running locally, make sure the canopy-api cloudflare worker is running
|
|
|
221
225
|
const json = await response.json();
|
|
222
226
|
return cartSchema.parse(json.data);
|
|
223
227
|
}
|
|
224
|
-
async cartGet({
|
|
228
|
+
async cartGet({
|
|
229
|
+
cartId,
|
|
230
|
+
buyerIp
|
|
231
|
+
}) {
|
|
225
232
|
try {
|
|
226
|
-
return await this._cartPost("/get", { cartId });
|
|
233
|
+
return await this._cartPost({ path: "/get", body: { cartId }, buyerIp });
|
|
227
234
|
} catch (error) {
|
|
228
235
|
if (error instanceof CanopyApiGatewayError && error.statusCode === 404) {
|
|
229
236
|
return null;
|
|
@@ -231,55 +238,97 @@ If you're running locally, make sure the canopy-api cloudflare worker is running
|
|
|
231
238
|
throw error;
|
|
232
239
|
}
|
|
233
240
|
}
|
|
234
|
-
async cartCreate(
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
241
|
+
async cartCreate({
|
|
242
|
+
buyerIp,
|
|
243
|
+
...options
|
|
244
|
+
}) {
|
|
245
|
+
return this._cartPost({
|
|
246
|
+
path: "/create",
|
|
247
|
+
body: {
|
|
248
|
+
lines: options.lines,
|
|
249
|
+
discountCodes: options.discountCodes,
|
|
250
|
+
attributes: options.attributes,
|
|
251
|
+
country: options.country
|
|
252
|
+
},
|
|
253
|
+
buyerIp
|
|
240
254
|
});
|
|
241
255
|
}
|
|
242
256
|
async cartAddLines({
|
|
243
257
|
cartId,
|
|
244
|
-
lines
|
|
258
|
+
lines,
|
|
259
|
+
buyerIp
|
|
245
260
|
}) {
|
|
246
|
-
return this._cartPost(
|
|
261
|
+
return this._cartPost({
|
|
262
|
+
path: "/add-lines",
|
|
263
|
+
body: { cartId, lines },
|
|
264
|
+
buyerIp
|
|
265
|
+
});
|
|
247
266
|
}
|
|
248
267
|
async cartUpdateLines({
|
|
249
268
|
cartId,
|
|
250
|
-
lines
|
|
269
|
+
lines,
|
|
270
|
+
buyerIp
|
|
251
271
|
}) {
|
|
252
|
-
return this._cartPost(
|
|
272
|
+
return this._cartPost({
|
|
273
|
+
path: "/update-lines",
|
|
274
|
+
body: { cartId, lines },
|
|
275
|
+
buyerIp
|
|
276
|
+
});
|
|
253
277
|
}
|
|
254
278
|
async cartRemoveLines({
|
|
255
279
|
cartId,
|
|
256
|
-
lineIds
|
|
280
|
+
lineIds,
|
|
281
|
+
buyerIp
|
|
257
282
|
}) {
|
|
258
|
-
return this._cartPost(
|
|
283
|
+
return this._cartPost({
|
|
284
|
+
path: "/remove-lines",
|
|
285
|
+
body: { cartId, lineIds },
|
|
286
|
+
buyerIp
|
|
287
|
+
});
|
|
259
288
|
}
|
|
260
289
|
async cartUpdateDiscountCodes({
|
|
261
290
|
cartId,
|
|
262
|
-
discountCodes
|
|
291
|
+
discountCodes,
|
|
292
|
+
buyerIp
|
|
263
293
|
}) {
|
|
264
|
-
return this._cartPost(
|
|
294
|
+
return this._cartPost({
|
|
295
|
+
path: "/update-discount-codes",
|
|
296
|
+
body: { cartId, discountCodes },
|
|
297
|
+
buyerIp
|
|
298
|
+
});
|
|
265
299
|
}
|
|
266
300
|
async cartUpdateBuyerIdentity({
|
|
267
301
|
cartId,
|
|
268
|
-
country
|
|
302
|
+
country,
|
|
303
|
+
buyerIp
|
|
269
304
|
}) {
|
|
270
|
-
return this._cartPost(
|
|
305
|
+
return this._cartPost({
|
|
306
|
+
path: "/update-buyer-identity",
|
|
307
|
+
body: { cartId, country },
|
|
308
|
+
buyerIp
|
|
309
|
+
});
|
|
271
310
|
}
|
|
272
311
|
async cartUpdateNote({
|
|
273
312
|
cartId,
|
|
274
|
-
note
|
|
313
|
+
note,
|
|
314
|
+
buyerIp
|
|
275
315
|
}) {
|
|
276
|
-
return this._cartPost(
|
|
316
|
+
return this._cartPost({
|
|
317
|
+
path: "/update-note",
|
|
318
|
+
body: { cartId, note },
|
|
319
|
+
buyerIp
|
|
320
|
+
});
|
|
277
321
|
}
|
|
278
322
|
async cartReplaceAttributes({
|
|
279
323
|
cartId,
|
|
280
|
-
attributes
|
|
324
|
+
attributes,
|
|
325
|
+
buyerIp
|
|
281
326
|
}) {
|
|
282
|
-
return this._cartPost(
|
|
327
|
+
return this._cartPost({
|
|
328
|
+
path: "/replace-attributes",
|
|
329
|
+
body: { cartId, attributes },
|
|
330
|
+
buyerIp
|
|
331
|
+
});
|
|
283
332
|
}
|
|
284
333
|
async _stripeCheckoutPost({
|
|
285
334
|
path,
|
|
@@ -288,8 +337,9 @@ If you're running locally, make sure the canopy-api cloudflare worker is running
|
|
|
288
337
|
}) {
|
|
289
338
|
const env = await getEnv();
|
|
290
339
|
const response = await this._post(
|
|
291
|
-
`${
|
|
292
|
-
{ projectId: env.PROJECT_ID, ...body }
|
|
340
|
+
`${buildBaseUrl(env.CANOPY_API_HOST)}/api/v1/stripe-checkout/${path}`,
|
|
341
|
+
{ projectId: env.PROJECT_ID, ...body },
|
|
342
|
+
{}
|
|
293
343
|
);
|
|
294
344
|
if (!response.ok) {
|
|
295
345
|
throw new CanopyApiGatewayError({
|
|
@@ -308,7 +358,7 @@ If you're running locally, make sure the canopy-api cloudflare worker is running
|
|
|
308
358
|
}) {
|
|
309
359
|
const env = await getEnv();
|
|
310
360
|
const response = await this._post(
|
|
311
|
-
`${
|
|
361
|
+
`${buildBaseUrl(env.CANOPY_API_HOST)}/api/v1/stripe-checkout/create-session`,
|
|
312
362
|
{
|
|
313
363
|
cartId: checkoutAttemptId,
|
|
314
364
|
checkoutAttemptId,
|
|
@@ -317,7 +367,8 @@ If you're running locally, make sure the canopy-api cloudflare worker is running
|
|
|
317
367
|
successUrl,
|
|
318
368
|
cancelUrl,
|
|
319
369
|
...uiMode === "form" ? { uiMode } : {}
|
|
320
|
-
}
|
|
370
|
+
},
|
|
371
|
+
{}
|
|
321
372
|
);
|
|
322
373
|
if (!response.ok) {
|
|
323
374
|
const restart = response.status === 409 ? restartCheckoutSchema.safeParse(await response.json()) : null;
|
|
@@ -362,8 +413,8 @@ If you're running locally, make sure the canopy-api cloudflare worker is running
|
|
|
362
413
|
});
|
|
363
414
|
}
|
|
364
415
|
}
|
|
365
|
-
|
|
366
|
-
return CanopyApiGateway
|
|
416
|
+
function getCanopyApiGateway() {
|
|
417
|
+
return new CanopyApiGateway();
|
|
367
418
|
}
|
|
368
419
|
export {
|
|
369
420
|
CanopyApiGatewayError,
|
package/lib/buildMetadata.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const BUILD_METADATA = {
|
|
2
2
|
"packageName": "@replohq/sdk",
|
|
3
|
-
"version": "2.18.
|
|
3
|
+
"version": "2.18.3",
|
|
4
4
|
"branch": "HEAD",
|
|
5
|
-
"commit": "
|
|
6
|
-
"builtAt": "2026-11-
|
|
5
|
+
"commit": "00c3d9662c0d5daa0cfd0ef03bb3b182e0cc0652",
|
|
6
|
+
"builtAt": "2026-11-03T23:49:23.685Z"
|
|
7
7
|
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shopper's IP, for canopy to pass to Shopify so it throttles and
|
|
3
|
+
* bot-checks each shopper separately; canopy only sees this site's server.
|
|
4
|
+
* Server actions only: it reads the incoming request.
|
|
5
|
+
*/
|
|
6
|
+
export declare function readBuyerIp(): Promise<string | null>;
|
package/lib/buyer-ip.js
ADDED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
"use server";
|
|
2
|
+
import { readBuyerIp } from "../lib/buyer-ip";
|
|
2
3
|
import { fetchValidatedLoaderOutput } from "./loader-output";
|
|
3
4
|
async function invokeLoaderAction({
|
|
4
5
|
loaderKey,
|
|
5
6
|
args
|
|
6
7
|
}) {
|
|
7
|
-
return fetchValidatedLoaderOutput({
|
|
8
|
+
return fetchValidatedLoaderOutput({
|
|
9
|
+
loaderKey,
|
|
10
|
+
args,
|
|
11
|
+
buyerIp: await readBuyerIp()
|
|
12
|
+
});
|
|
8
13
|
}
|
|
9
14
|
export {
|
|
10
15
|
invokeLoaderAction
|
|
@@ -49,7 +49,11 @@ async function invokeLoaderServer({
|
|
|
49
49
|
try {
|
|
50
50
|
return {
|
|
51
51
|
kind: "data",
|
|
52
|
-
data: await fetchValidatedLoaderOutput({
|
|
52
|
+
data: await fetchValidatedLoaderOutput({
|
|
53
|
+
loaderKey,
|
|
54
|
+
args,
|
|
55
|
+
buyerIp: null
|
|
56
|
+
})
|
|
53
57
|
};
|
|
54
58
|
} catch (error) {
|
|
55
59
|
if (error instanceof LoaderOutputError) {
|
package/loaders/invoke-loader.js
CHANGED
|
@@ -13,7 +13,11 @@ async function invokeUntypedLoader({
|
|
|
13
13
|
try {
|
|
14
14
|
if (process.env.NEXT_RUNTIME) {
|
|
15
15
|
const { fetchValidatedLoaderOutput } = await import("./loader-output");
|
|
16
|
-
return await fetchValidatedLoaderOutput({
|
|
16
|
+
return await fetchValidatedLoaderOutput({
|
|
17
|
+
loaderKey,
|
|
18
|
+
args,
|
|
19
|
+
buyerIp: null
|
|
20
|
+
});
|
|
17
21
|
}
|
|
18
22
|
const { invokeLoaderAction } = await import("./invoke-loader-action");
|
|
19
23
|
return await invokeLoaderAction({ loaderKey, args });
|
|
@@ -25,7 +25,8 @@ export declare class LoaderOutputError extends CanopyError {
|
|
|
25
25
|
* before any request, since JSON would drop them and canopy-api would reject
|
|
26
26
|
* the rest. The log matters because `PrefetchedLoaders` swallows rejections.
|
|
27
27
|
*/
|
|
28
|
-
export declare function fetchValidatedLoaderOutput({ loaderKey, args, }: {
|
|
28
|
+
export declare function fetchValidatedLoaderOutput({ loaderKey, args, buyerIp, }: {
|
|
29
29
|
loaderKey: string;
|
|
30
30
|
args: Record<string, unknown>;
|
|
31
|
+
buyerIp: string | null;
|
|
31
32
|
}): Promise<unknown>;
|
package/loaders/loader-output.js
CHANGED
|
@@ -92,15 +92,19 @@ class LoaderOutputError extends CanopyError {
|
|
|
92
92
|
}
|
|
93
93
|
async function fetchValidatedLoaderOutput({
|
|
94
94
|
loaderKey,
|
|
95
|
-
args
|
|
95
|
+
args,
|
|
96
|
+
buyerIp
|
|
96
97
|
}) {
|
|
97
98
|
const argsError = getLoaderArgsError({ loaderKey, args });
|
|
98
99
|
if (argsError !== null) {
|
|
99
100
|
console.error(argsError.message);
|
|
100
101
|
throw argsError;
|
|
101
102
|
}
|
|
102
|
-
const
|
|
103
|
-
|
|
103
|
+
const { data } = await getCanopyApiGateway().invokeLoader({
|
|
104
|
+
loaderKey,
|
|
105
|
+
args,
|
|
106
|
+
buyerIp
|
|
107
|
+
});
|
|
104
108
|
const knownKey = dataLoaderKeySchema.safeParse(loaderKey);
|
|
105
109
|
if (!knownKey.success) {
|
|
106
110
|
return data;
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@replohq/sdk",
|
|
3
|
-
"version": "2.18.
|
|
3
|
+
"version": "2.18.3",
|
|
4
4
|
"reploBuild": {
|
|
5
5
|
"packageName": "@replohq/sdk",
|
|
6
|
-
"version": "2.18.
|
|
6
|
+
"version": "2.18.3",
|
|
7
7
|
"branch": "HEAD",
|
|
8
|
-
"commit": "
|
|
9
|
-
"builtAt": "2026-11-
|
|
8
|
+
"commit": "00c3d9662c0d5daa0cfd0ef03bb3b182e0cc0652",
|
|
9
|
+
"builtAt": "2026-11-03T23:49:23.685Z"
|
|
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",
|