@replohq/sdk 2.19.0 → 2.20.1
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/hooks/use-add-to-cart.d.ts +17 -4
- package/cart/hooks/use-add-to-cart.js +6 -2
- package/cart/hooks/use-buy-now.d.ts +17 -5
- package/cart/hooks/use-buy-now.js +6 -2
- package/cart/hooks/use-checkout-availability.d.ts +21 -0
- package/cart/hooks/use-checkout-availability.js +71 -0
- package/consent/replo-scripts.d.ts +2 -6
- package/consent/replo-scripts.js +26 -33
- package/lib/buildMetadata.js +3 -3
- package/loaders/integration-loader-schemas.d.ts +1 -0
- package/loaders/loader-schemas.d.ts +3 -0
- package/loaders/loader-schemas.js +4 -2
- package/package.json +4 -4
- package/providers/canopy-client-config.d.ts +2 -0
- package/providers/replo-provider.js +2 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { QueryClient } from "@tanstack/react-query";
|
|
2
2
|
import type { CartError } from "../cart-provider";
|
|
3
3
|
import type { CartLineAdjustment, CartLineAttribute, CartLineMerchandise } from "../cart-types";
|
|
4
|
+
import type { CheckoutCatalog } from "./use-checkout-availability";
|
|
4
5
|
/**
|
|
5
6
|
* Describes a single item to add to the cart. Uses the merchandiseId
|
|
6
7
|
* (e.g. a variant GID) directly from data loader output. Product
|
|
@@ -56,27 +57,39 @@ export declare function findMerchandiseInQueryCache({ queryClient, merchandiseId
|
|
|
56
57
|
* and opens the cart UI, which renders it, so a click handler needs no
|
|
57
58
|
* handling of its own.
|
|
58
59
|
*
|
|
60
|
+
* `checkoutAvailability` is `"unavailable"` while the store can't take
|
|
61
|
+
* payments yet, or when the `catalog` passed is one this site's checkout
|
|
62
|
+
* can't sell. Show the button disabled with "Coming soon" then: a shopper
|
|
63
|
+
* could fill a cart but never check out.
|
|
64
|
+
*
|
|
59
65
|
* @example
|
|
60
66
|
* ```tsx
|
|
61
67
|
* import { useAddToCart } from "@replohq/sdk/cart/hooks/use-add-to-cart";
|
|
62
68
|
*
|
|
63
69
|
* function AddToCartButton({ variant }) {
|
|
64
|
-
* const { addToCart, isAdding } = useAddToCart(
|
|
70
|
+
* const { addToCart, isAdding, checkoutAvailability } = useAddToCart({
|
|
71
|
+
* catalog: "shopify",
|
|
72
|
+
* });
|
|
73
|
+
* const isComingSoon = checkoutAvailability === "unavailable";
|
|
65
74
|
*
|
|
66
75
|
* return (
|
|
67
76
|
* <button
|
|
68
|
-
* disabled={!variant.availableForSale || isAdding}
|
|
77
|
+
* disabled={!variant.availableForSale || isAdding || isComingSoon}
|
|
69
78
|
* onClick={() => {
|
|
70
79
|
* void addToCart([{ merchandiseId: variant.id, quantity: 1 }]);
|
|
71
80
|
* }}
|
|
72
81
|
* >
|
|
73
|
-
* {isAdding ? "Adding..." : "Add to Cart"}
|
|
82
|
+
* {isComingSoon ? "Coming soon" : isAdding ? "Adding..." : "Add to Cart"}
|
|
74
83
|
* </button>
|
|
75
84
|
* );
|
|
76
85
|
* }
|
|
77
86
|
* ```
|
|
78
87
|
*/
|
|
79
|
-
export declare function useAddToCart(
|
|
88
|
+
export declare function useAddToCart({ catalog, }?: {
|
|
89
|
+
/** The catalog this control sells from, so `checkoutAvailability` can say whether this site's checkout sells it. */
|
|
90
|
+
catalog?: CheckoutCatalog | null;
|
|
91
|
+
}): {
|
|
80
92
|
addToCart: (items: AddToCartItem[], openCartAfterAdd?: boolean) => Promise<AddToCartResult>;
|
|
81
93
|
isAdding: boolean;
|
|
94
|
+
checkoutAvailability: import("./use-checkout-availability").CheckoutAvailability;
|
|
82
95
|
};
|
|
@@ -6,6 +6,7 @@ import { DATA_LOADER_KEYS } from "../../loaders/loader-keys";
|
|
|
6
6
|
import { isPlaceholderMerchandiseId } from "../../loaders/placeholder-product";
|
|
7
7
|
import { useCartInternal } from "../cart-provider";
|
|
8
8
|
import { toCartError } from "../utils/cart-error";
|
|
9
|
+
import { useCheckoutAvailability } from "./use-checkout-availability";
|
|
9
10
|
const PRODUCT_LOADER_KEYS = [
|
|
10
11
|
DATA_LOADER_KEYS.SHOPIFY_PRODUCT,
|
|
11
12
|
DATA_LOADER_KEYS.REPLO_PRODUCT
|
|
@@ -81,10 +82,13 @@ function findMerchandiseInQueryCache({
|
|
|
81
82
|
}
|
|
82
83
|
return void 0;
|
|
83
84
|
}
|
|
84
|
-
function useAddToCart(
|
|
85
|
+
function useAddToCart({
|
|
86
|
+
catalog = null
|
|
87
|
+
} = {}) {
|
|
85
88
|
const cart = useCartInternal();
|
|
86
89
|
const queryClient = useQueryClient();
|
|
87
90
|
const [isAdding, setIsAdding] = React.useState(false);
|
|
91
|
+
const checkoutAvailability = useCheckoutAvailability({ catalog });
|
|
88
92
|
const addToCart = React.useCallback(
|
|
89
93
|
async (items, openCartAfterAdd = true) => {
|
|
90
94
|
const buyableItems = items.filter((item) => {
|
|
@@ -121,7 +125,7 @@ function useAddToCart() {
|
|
|
121
125
|
},
|
|
122
126
|
[cart, queryClient]
|
|
123
127
|
);
|
|
124
|
-
return { addToCart, isAdding };
|
|
128
|
+
return { addToCart, isAdding, checkoutAvailability };
|
|
125
129
|
}
|
|
126
130
|
export {
|
|
127
131
|
findMerchandiseInQueryCache,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CartLineAttribute } from "../cart-types";
|
|
2
|
+
import type { CheckoutCatalog } from "./use-checkout-availability";
|
|
2
3
|
/**
|
|
3
4
|
* What a `buyNow` call did. Out of stock is an expected storefront outcome
|
|
4
5
|
* (a buyer can race the last unit), so it rides the return value rather than
|
|
@@ -34,18 +35,25 @@ export interface VariantBuyNowInfo {
|
|
|
34
35
|
* the browser to checkout. Stripe checkout ignores selling plans and discount
|
|
35
36
|
* codes, logging a server-side warning when either is supplied.
|
|
36
37
|
*
|
|
38
|
+
* `checkoutAvailability` is `"unavailable"` while the store can't take
|
|
39
|
+
* payments yet (Replo checkout not set up, or checkout turned off), or when
|
|
40
|
+
* the `catalog` passed is one this site's checkout can't sell. Show the button
|
|
41
|
+
* disabled with "Coming soon" then, instead of letting the shopper hit a
|
|
42
|
+
* failed checkout.
|
|
43
|
+
*
|
|
37
44
|
* @example
|
|
38
45
|
*
|
|
39
46
|
* ```tsx
|
|
40
47
|
* import { useBuyNow } from "@replohq/sdk/cart/hooks/use-buy-now";
|
|
41
48
|
*
|
|
42
49
|
* function MyComponent({ selectedVariant, selectedSellingPlan, quantity }) {
|
|
43
|
-
* const { buyNow } = useBuyNow();
|
|
50
|
+
* const { buyNow, checkoutAvailability } = useBuyNow();
|
|
44
51
|
* const [isSoldOut, setIsSoldOut] = React.useState(false);
|
|
52
|
+
* const isComingSoon = checkoutAvailability === "unavailable";
|
|
45
53
|
*
|
|
46
54
|
* return (
|
|
47
55
|
* <Button
|
|
48
|
-
* disabled={!selectedVariant?.availableForSale || isSoldOut}
|
|
56
|
+
* disabled={!selectedVariant?.availableForSale || isSoldOut || isComingSoon}
|
|
49
57
|
* onClick={async () => {
|
|
50
58
|
* if (selectedVariant) {
|
|
51
59
|
* const outcome = await buyNow(
|
|
@@ -70,15 +78,18 @@ export interface VariantBuyNowInfo {
|
|
|
70
78
|
* }
|
|
71
79
|
* }}
|
|
72
80
|
* >
|
|
73
|
-
* {isSoldOut ? "Sold out" : "Shop Now"}
|
|
81
|
+
* {isComingSoon ? "Coming soon" : isSoldOut ? "Sold out" : "Shop Now"}
|
|
74
82
|
* </Button>
|
|
75
83
|
* );
|
|
76
84
|
* }
|
|
77
85
|
* ```
|
|
78
86
|
*
|
|
79
|
-
* @returns Object containing the buyNow function
|
|
87
|
+
* @returns Object containing the buyNow function and whether checkout can take payments
|
|
80
88
|
*/
|
|
81
|
-
export declare function useBuyNow(
|
|
89
|
+
export declare function useBuyNow({ catalog, }?: {
|
|
90
|
+
/** The catalog this control sells from, so `checkoutAvailability` can say whether this site's checkout sells it. */
|
|
91
|
+
catalog?: CheckoutCatalog | null;
|
|
92
|
+
}): {
|
|
82
93
|
buyNow: (variants: VariantBuyNowInfo[], options?: {
|
|
83
94
|
discountCodes?: string[];
|
|
84
95
|
/** Order-level Shopify cart attributes, including experiment attribution. */
|
|
@@ -87,4 +98,5 @@ export declare function useBuyNow(): {
|
|
|
87
98
|
value: string;
|
|
88
99
|
}[];
|
|
89
100
|
}) => Promise<BuyNowOutcome>;
|
|
101
|
+
checkoutAvailability: import("./use-checkout-availability").CheckoutAvailability;
|
|
90
102
|
};
|
|
@@ -5,6 +5,7 @@ import { CanopyError } from "../../lib/canopy-error";
|
|
|
5
5
|
import { navigateExternal } from "../../lib/external-navigation";
|
|
6
6
|
import { buyNowWithRecoveryAction } from "../buy-now-action";
|
|
7
7
|
import { CartCountryContext } from "../cart-country-context";
|
|
8
|
+
import { useCheckoutAvailability } from "./use-checkout-availability";
|
|
8
9
|
const REPLO_LOCAL_STORAGE_SESSION_KEY = "_replo_sid";
|
|
9
10
|
const REPLO_SESSION_ID_KEY = "rsid";
|
|
10
11
|
const REPLO_CLIENT_ID_KEY = "rclid";
|
|
@@ -13,8 +14,11 @@ class ProductHasNoVariantsError extends CanopyError {
|
|
|
13
14
|
class CheckoutAttemptError extends CanopyError {
|
|
14
15
|
}
|
|
15
16
|
const checkoutAttempts = /* @__PURE__ */ new Map();
|
|
16
|
-
function useBuyNow(
|
|
17
|
+
function useBuyNow({
|
|
18
|
+
catalog = null
|
|
19
|
+
} = {}) {
|
|
17
20
|
const country = React.useContext(CartCountryContext);
|
|
21
|
+
const checkoutAvailability = useCheckoutAvailability({ catalog });
|
|
18
22
|
const reploSessionString = useClientValue(
|
|
19
23
|
() => localStorage.getItem(REPLO_LOCAL_STORAGE_SESSION_KEY),
|
|
20
24
|
null
|
|
@@ -88,7 +92,7 @@ function useBuyNow() {
|
|
|
88
92
|
},
|
|
89
93
|
[reploSessionString, country]
|
|
90
94
|
);
|
|
91
|
-
return { buyNow };
|
|
95
|
+
return { buyNow, checkoutAvailability };
|
|
92
96
|
}
|
|
93
97
|
export {
|
|
94
98
|
useBuyNow
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether shoppers can check out on this site right now. `"checking"` while
|
|
3
|
+
* the store's payments are being confirmed; buy controls stay usable then, so
|
|
4
|
+
* a store that can sell never flashes an unavailable state.
|
|
5
|
+
*/
|
|
6
|
+
export type CheckoutAvailability = "checking" | "available" | "unavailable";
|
|
7
|
+
/**
|
|
8
|
+
* Which catalog a buy control sells from: `"shopify"` for Shopify loader
|
|
9
|
+
* output, `"replo"` for Replo products. Shopify checkout can't sell Replo
|
|
10
|
+
* products and Replo checkout can't sell Shopify ones.
|
|
11
|
+
*/
|
|
12
|
+
export type CheckoutCatalog = "shopify" | "replo";
|
|
13
|
+
/**
|
|
14
|
+
* Replo checkout can only sell once the store's payments are set up, which
|
|
15
|
+
* can finish or lapse long after a publish, so it is read live. Shopify
|
|
16
|
+
* checkout is the store's own and is treated as available. Without a
|
|
17
|
+
* `catalog` only the site's checkout is judged, as before the option existed.
|
|
18
|
+
*/
|
|
19
|
+
export declare function useCheckoutAvailability({ catalog, }: {
|
|
20
|
+
catalog: CheckoutCatalog | null;
|
|
21
|
+
}): CheckoutAvailability;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useQuery } from "@tanstack/react-query";
|
|
3
|
+
import { CanopyError } from "../../lib/canopy-error";
|
|
4
|
+
import { useCanopyClientConfig } from "../../providers/canopy-client-config";
|
|
5
|
+
class CheckoutAvailabilityError extends CanopyError {
|
|
6
|
+
}
|
|
7
|
+
const CHECKOUT_AVAILABILITY_STALE_MS = 6e4;
|
|
8
|
+
async function fetchCanAcceptPayments(config) {
|
|
9
|
+
const response = await fetch(
|
|
10
|
+
`${config.canopyApiBaseUrl}/api/v1/stripe-checkout/availability`,
|
|
11
|
+
{
|
|
12
|
+
method: "POST",
|
|
13
|
+
headers: { "Content-Type": "application/json" },
|
|
14
|
+
body: JSON.stringify({ projectId: config.projectId })
|
|
15
|
+
}
|
|
16
|
+
);
|
|
17
|
+
if (!response.ok) {
|
|
18
|
+
throw new CheckoutAvailabilityError({
|
|
19
|
+
message: `Checkout availability check failed with status ${response.status}`
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
const body = await response.json();
|
|
23
|
+
if (typeof body !== "object" || body === null || !("canAcceptPayments" in body) || typeof body.canAcceptPayments !== "boolean") {
|
|
24
|
+
throw new CheckoutAvailabilityError({
|
|
25
|
+
message: "Checkout availability check returned an unexpected response"
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return body.canAcceptPayments;
|
|
29
|
+
}
|
|
30
|
+
function useCheckoutAvailability({
|
|
31
|
+
catalog
|
|
32
|
+
}) {
|
|
33
|
+
const config = useCanopyClientConfig();
|
|
34
|
+
const checkoutProvider = config?.checkoutProvider ?? null;
|
|
35
|
+
const query = useQuery({
|
|
36
|
+
queryKey: ["replo", "checkout-availability", config?.projectId ?? null],
|
|
37
|
+
queryFn: () => {
|
|
38
|
+
if (!config) {
|
|
39
|
+
throw new CheckoutAvailabilityError({
|
|
40
|
+
message: "This site has no canopy-api config"
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return fetchCanAcceptPayments(config);
|
|
44
|
+
},
|
|
45
|
+
enabled: checkoutProvider === "stripe" && catalog !== "shopify",
|
|
46
|
+
staleTime: CHECKOUT_AVAILABILITY_STALE_MS,
|
|
47
|
+
retry: 1
|
|
48
|
+
});
|
|
49
|
+
if (checkoutProvider === null) {
|
|
50
|
+
return "available";
|
|
51
|
+
}
|
|
52
|
+
if (checkoutProvider === "none") {
|
|
53
|
+
return "unavailable";
|
|
54
|
+
}
|
|
55
|
+
if (checkoutProvider === "shopify") {
|
|
56
|
+
return catalog === "replo" ? "unavailable" : "available";
|
|
57
|
+
}
|
|
58
|
+
if (catalog === "shopify") {
|
|
59
|
+
return "unavailable";
|
|
60
|
+
}
|
|
61
|
+
if (query.isPending) {
|
|
62
|
+
return "checking";
|
|
63
|
+
}
|
|
64
|
+
if (query.isError) {
|
|
65
|
+
return "available";
|
|
66
|
+
}
|
|
67
|
+
return query.data ? "available" : "unavailable";
|
|
68
|
+
}
|
|
69
|
+
export {
|
|
70
|
+
useCheckoutAvailability
|
|
71
|
+
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ScriptTagDescriptor } from "../_vendor/schemas/generated/consent";
|
|
2
2
|
import type { ConsentCategory, ReploScriptEntry } from "./types";
|
|
3
|
-
import { Component } from "react";
|
|
4
3
|
/**
|
|
5
4
|
* Injects the resolved tags into `document.head` once a caller has decided
|
|
6
5
|
* consent allows it. Reused both for author-managed `ReploScripts` entries and
|
|
@@ -16,12 +15,9 @@ type InjectedScriptProps = {
|
|
|
16
15
|
descriptors: ScriptTagDescriptor[];
|
|
17
16
|
/** Used under a delegated platform to derive the attributes that gate the tag. */
|
|
18
17
|
requiredConsent?: ConsentCategory[];
|
|
19
|
-
usercentricsService?: string;
|
|
18
|
+
usercentricsService?: string | null;
|
|
20
19
|
};
|
|
21
|
-
export declare
|
|
22
|
-
componentDidMount(): void;
|
|
23
|
-
render(): null;
|
|
24
|
-
}
|
|
20
|
+
export declare function InjectedScript({ baseId, descriptors, requiredConsent, usercentricsService, }: InjectedScriptProps): null;
|
|
25
21
|
/**
|
|
26
22
|
* The single registry component for all managed tracking scripts on the site.
|
|
27
23
|
* Authored once in `app/layout.tsx`; the agent/miniapp only edit the `scripts`
|
package/consent/replo-scripts.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import {
|
|
3
|
+
import { useEffect } from "react";
|
|
4
4
|
import {
|
|
5
5
|
buildGrantMarker,
|
|
6
6
|
enableConsentDelegation,
|
|
@@ -59,30 +59,30 @@ function descriptorsFor(entry) {
|
|
|
59
59
|
}
|
|
60
60
|
return buildScriptTags(entry);
|
|
61
61
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
function InjectedScript({
|
|
63
|
+
baseId,
|
|
64
|
+
descriptors,
|
|
65
|
+
requiredConsent = [],
|
|
66
|
+
usercentricsService = null
|
|
67
|
+
}) {
|
|
68
|
+
useEffect(() => {
|
|
65
69
|
injectGatedScript({
|
|
66
|
-
baseId
|
|
67
|
-
descriptors
|
|
70
|
+
baseId,
|
|
71
|
+
descriptors,
|
|
68
72
|
requiredConsent,
|
|
69
73
|
usercentricsService
|
|
70
74
|
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
+
}, []);
|
|
76
|
+
return null;
|
|
75
77
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
registerScript(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
78
|
+
function ScriptRegistration({ script }) {
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
registerScript(script);
|
|
81
|
+
return () => {
|
|
82
|
+
unregisterScript(script.id);
|
|
83
|
+
};
|
|
84
|
+
}, []);
|
|
85
|
+
return null;
|
|
86
86
|
}
|
|
87
87
|
function registrationFor(entry, loaderContainerId) {
|
|
88
88
|
const id = scriptId(entry);
|
|
@@ -121,23 +121,16 @@ function ManagedScript({
|
|
|
121
121
|
baseId: id,
|
|
122
122
|
descriptors: descriptorsFor(entry),
|
|
123
123
|
requiredConsent,
|
|
124
|
-
usercentricsService
|
|
124
|
+
usercentricsService
|
|
125
125
|
}
|
|
126
126
|
)
|
|
127
127
|
] });
|
|
128
128
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
componentWillUnmount() {
|
|
136
|
-
this.uninstall();
|
|
137
|
-
}
|
|
138
|
-
render() {
|
|
139
|
-
return null;
|
|
140
|
-
}
|
|
129
|
+
function ConsentWindowApi() {
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
return installConsentWindowApi();
|
|
132
|
+
}, []);
|
|
133
|
+
return null;
|
|
141
134
|
}
|
|
142
135
|
function ReploScripts({ scripts }) {
|
|
143
136
|
const platform = findConsentPlatform(scripts);
|
package/lib/buildMetadata.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const BUILD_METADATA = {
|
|
2
2
|
"packageName": "@replohq/sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.20.1",
|
|
4
4
|
"branch": "HEAD",
|
|
5
|
-
"commit": "
|
|
6
|
-
"builtAt": "2026-11-
|
|
5
|
+
"commit": "1d896e2349feb742232139686002f2e2741f01ea",
|
|
6
|
+
"builtAt": "2026-11-06T21:19:31.851Z"
|
|
7
7
|
};
|
|
@@ -210,6 +210,7 @@ export declare const rebuyRecommendationsOutputSchema: z.ZodObject<{
|
|
|
210
210
|
previewUrl: z.ZodNullable<z.ZodString>;
|
|
211
211
|
}, z.core.$strip>], "kind">>>;
|
|
212
212
|
}, z.core.$strip>>>;
|
|
213
|
+
externalCheckoutUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
213
214
|
}, z.core.$strip>>;
|
|
214
215
|
}, z.core.$strip>;
|
|
215
216
|
export declare const smileEarningRuleSchema: z.ZodObject<{
|
|
@@ -389,6 +389,7 @@ export declare const productSchema: z.ZodObject<{
|
|
|
389
389
|
previewUrl: z.ZodNullable<z.ZodString>;
|
|
390
390
|
}, z.core.$strip>], "kind">>>;
|
|
391
391
|
}, z.core.$strip>>>;
|
|
392
|
+
externalCheckoutUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
392
393
|
}, z.core.$strip>;
|
|
393
394
|
export type Product = z.infer<typeof productSchema>;
|
|
394
395
|
export declare const okendoReviewMediaSchema: z.ZodObject<{
|
|
@@ -640,6 +641,7 @@ export declare const fullProductSchema: z.ZodObject<{
|
|
|
640
641
|
previewUrl: z.ZodNullable<z.ZodString>;
|
|
641
642
|
}, z.core.$strip>], "kind">>>;
|
|
642
643
|
}, z.core.$strip>>;
|
|
644
|
+
externalCheckoutUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
643
645
|
}, z.core.$strip>;
|
|
644
646
|
export declare const fullCollectionSchema: z.ZodObject<{
|
|
645
647
|
id: z.ZodString;
|
|
@@ -834,6 +836,7 @@ export declare const paginatedProductsSchema: z.ZodObject<{
|
|
|
834
836
|
previewUrl: z.ZodNullable<z.ZodString>;
|
|
835
837
|
}, z.core.$strip>], "kind">>>;
|
|
836
838
|
}, z.core.$strip>>>;
|
|
839
|
+
externalCheckoutUrl: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
837
840
|
}, z.core.$strip>>;
|
|
838
841
|
pageInfo: z.ZodObject<{
|
|
839
842
|
hasNextPage: z.ZodBoolean;
|
|
@@ -145,7 +145,8 @@ const productSchema = z.object({
|
|
|
145
145
|
tags: z.array(z.string()).optional(),
|
|
146
146
|
sellingPlanGroups: z.array(sellingPlanGroupSchema).optional(),
|
|
147
147
|
requiresSellingPlan: z.boolean().optional(),
|
|
148
|
-
metafields: z.array(metafieldSchema).optional()
|
|
148
|
+
metafields: z.array(metafieldSchema).optional(),
|
|
149
|
+
externalCheckoutUrl: z.string().nullish()
|
|
149
150
|
});
|
|
150
151
|
const okendoReviewMediaSchema = z.object({
|
|
151
152
|
type: z.string().describe('Okendo media type, e.g. "image" or "video"'),
|
|
@@ -216,7 +217,8 @@ const fullProductSchema = z.object({
|
|
|
216
217
|
tags: z.array(z.string()),
|
|
217
218
|
sellingPlanGroups: z.array(sellingPlanGroupSchema),
|
|
218
219
|
requiresSellingPlan: productSchema.shape.requiresSellingPlan,
|
|
219
|
-
metafields: z.array(metafieldSchema)
|
|
220
|
+
metafields: z.array(metafieldSchema),
|
|
221
|
+
externalCheckoutUrl: productSchema.shape.externalCheckoutUrl
|
|
220
222
|
});
|
|
221
223
|
const fullCollectionSchema = z.object({
|
|
222
224
|
id: z.string(),
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@replohq/sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.20.1",
|
|
4
4
|
"reploBuild": {
|
|
5
5
|
"packageName": "@replohq/sdk",
|
|
6
|
-
"version": "2.
|
|
6
|
+
"version": "2.20.1",
|
|
7
7
|
"branch": "HEAD",
|
|
8
|
-
"commit": "
|
|
9
|
-
"builtAt": "2026-11-
|
|
8
|
+
"commit": "1d896e2349feb742232139686002f2e2741f01ea",
|
|
9
|
+
"builtAt": "2026-11-06T21:19:31.851Z"
|
|
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",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CheckoutProvider } from "../lib/integration-utils";
|
|
1
2
|
import React from "react";
|
|
2
3
|
/**
|
|
3
4
|
* What browser code needs to call canopy-api directly. Resolved from the worker
|
|
@@ -7,6 +8,7 @@ import React from "react";
|
|
|
7
8
|
export type CanopyClientConfig = {
|
|
8
9
|
canopyApiBaseUrl: string;
|
|
9
10
|
projectId: string;
|
|
11
|
+
checkoutProvider: CheckoutProvider;
|
|
10
12
|
};
|
|
11
13
|
export declare function CanopyClientConfigProvider({ config, children, }: React.PropsWithChildren<{
|
|
12
14
|
config: CanopyClientConfig | null;
|
|
@@ -19,7 +19,8 @@ async function ReploProvider({
|
|
|
19
19
|
checkoutProvider = env.CHECKOUT_PROVIDER ?? "none";
|
|
20
20
|
canopyClientConfig = {
|
|
21
21
|
canopyApiBaseUrl: buildBaseUrl(env.CANOPY_API_HOST),
|
|
22
|
-
projectId: env.PROJECT_ID
|
|
22
|
+
projectId: env.PROJECT_ID,
|
|
23
|
+
checkoutProvider
|
|
23
24
|
};
|
|
24
25
|
} catch {
|
|
25
26
|
checkoutProvider = "none";
|