@replohq/sdk 2.18.3 → 2.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/_vendor/replo-utils/lib/crypto.d.ts +5 -0
  2. package/_vendor/schemas/generated/consent.d.ts +13 -1
  3. package/analytics/analytics-provider.js +3 -1
  4. package/analytics/get-analytics-sinks.js +7 -4
  5. package/analytics/replo-pixel-script.d.ts +5 -5
  6. package/analytics/replo-pixel-script.js +23 -22
  7. package/cart/hooks/use-add-to-cart.d.ts +17 -4
  8. package/cart/hooks/use-add-to-cart.js +6 -2
  9. package/cart/hooks/use-buy-now.d.ts +17 -5
  10. package/cart/hooks/use-buy-now.js +6 -2
  11. package/cart/hooks/use-checkout-availability.d.ts +21 -0
  12. package/cart/hooks/use-checkout-availability.js +71 -0
  13. package/consent/consent-platform.d.ts +20 -5
  14. package/consent/consent-platform.js +94 -11
  15. package/consent/consent-store.d.ts +7 -2
  16. package/consent/consent-store.js +16 -4
  17. package/consent/inject-script-descriptors.d.ts +8 -1
  18. package/consent/inject-script-descriptors.js +23 -0
  19. package/consent/replo-scripts.d.ts +6 -2
  20. package/consent/replo-scripts.js +35 -27
  21. package/consent/script-registration-store.d.ts +2 -0
  22. package/consent/script-snippets.d.ts +1 -1
  23. package/consent/types.d.ts +18 -4
  24. package/consent/usercentrics-consent.d.ts +15 -0
  25. package/consent/usercentrics-consent.js +96 -0
  26. package/consent/window-api.js +1 -1
  27. package/lib/buildMetadata.js +3 -3
  28. package/loaders/integration-loader-schemas.d.ts +1 -0
  29. package/loaders/loader-schemas.d.ts +3 -0
  30. package/loaders/loader-schemas.js +4 -2
  31. package/package.json +4 -4
  32. package/providers/canopy-client-config.d.ts +2 -0
  33. package/providers/replo-provider.js +2 -1
@@ -0,0 +1,96 @@
1
+ import * as v from "valibot";
2
+ const usercentricsDetailsSchema = v.object({
3
+ consent: v.optional(v.object({ type: v.optional(v.string()) })),
4
+ services: v.record(
5
+ v.string(),
6
+ v.object({
7
+ name: v.string(),
8
+ essential: v.optional(v.boolean()),
9
+ consent: v.object({ given: v.boolean() })
10
+ })
11
+ )
12
+ });
13
+ const usercentricsBaseInfoSchema = v.array(
14
+ v.object({
15
+ name: v.string(),
16
+ isEssential: v.optional(v.boolean()),
17
+ consent: v.object({
18
+ status: v.boolean(),
19
+ history: v.optional(v.array(v.object({ type: v.optional(v.string()) })))
20
+ })
21
+ })
22
+ );
23
+ function usercentricsCategories(services) {
24
+ const optionalServices = services.filter((service) => !service.essential);
25
+ const acceptedAll = optionalServices.length > 0 && optionalServices.every((service) => service.given);
26
+ return {
27
+ necessary: true,
28
+ analytics: acceptedAll,
29
+ marketing: acceptedAll,
30
+ preferences: acceptedAll,
31
+ sale_of_data: acceptedAll
32
+ };
33
+ }
34
+ async function readUsercentricsServices() {
35
+ if (window.__ucCmp?.getConsentDetails) {
36
+ const details = v.safeParse(
37
+ usercentricsDetailsSchema,
38
+ await window.__ucCmp.getConsentDetails()
39
+ );
40
+ if (!details.success) {
41
+ console.warn("[Replo] Unreadable Usercentrics consent details");
42
+ return null;
43
+ }
44
+ return {
45
+ services: Object.values(details.output.services).map((service) => ({
46
+ name: service.name,
47
+ given: service.consent.given,
48
+ essential: service.essential === true
49
+ })),
50
+ isExplicit: details.output.consent?.type === "EXPLICIT"
51
+ };
52
+ }
53
+ const rawBaseInfo = window.UC_UI?.getServicesBaseInfo?.();
54
+ if (rawBaseInfo === void 0) {
55
+ return null;
56
+ }
57
+ const baseInfo = v.safeParse(usercentricsBaseInfoSchema, rawBaseInfo);
58
+ if (!baseInfo.success) {
59
+ console.warn("[Replo] Unreadable Usercentrics service info");
60
+ return null;
61
+ }
62
+ return {
63
+ services: baseInfo.output.map((service) => ({
64
+ name: service.name,
65
+ given: service.consent.status,
66
+ essential: service.isEssential === true
67
+ })),
68
+ isExplicit: baseInfo.output.some((service) => {
69
+ return service.consent.history?.at(-1)?.type === "explicit";
70
+ })
71
+ };
72
+ }
73
+ async function readUsercentricsChange(previous) {
74
+ const answer = await readUsercentricsServices();
75
+ if (!answer) {
76
+ return null;
77
+ }
78
+ const categories = usercentricsCategories(answer.services);
79
+ const grantedUsercentricsServices = answer.services.filter((service) => service.given).map((service) => service.name).sort();
80
+ const isUnchanged = categories.analytics === previous.categories.analytics && grantedUsercentricsServices.join() === previous.grantedUsercentricsServices.join();
81
+ const isDecided = answer.isExplicit || answer.services.some((service) => service.given && !service.essential);
82
+ if (isUnchanged && (previous.decidedAt !== null || !isDecided)) {
83
+ return null;
84
+ }
85
+ return {
86
+ categories,
87
+ decidedAt: isDecided ? Date.now() : null,
88
+ grantedUsercentricsServices,
89
+ hasDowngrade: previous.grantedUsercentricsServices.some((name) => {
90
+ return !grantedUsercentricsServices.includes(name);
91
+ })
92
+ };
93
+ }
94
+ export {
95
+ readUsercentricsChange
96
+ };
@@ -30,7 +30,7 @@ const api = {
30
30
  saleOfDataAllowed: () => isAllowed("sale_of_data"),
31
31
  shouldShowBanner: () => {
32
32
  const state = consentStore.getSnapshot();
33
- if (state.cmp === "cookiebot" || state.cmp === "external") {
33
+ if (state.cmp && state.cmp !== "replo") {
34
34
  return false;
35
35
  }
36
36
  return state.mode !== "off" && state.decidedAt === null;
@@ -1,7 +1,7 @@
1
1
  export const BUILD_METADATA = {
2
2
  "packageName": "@replohq/sdk",
3
- "version": "2.18.3",
3
+ "version": "2.20.0",
4
4
  "branch": "HEAD",
5
- "commit": "00c3d9662c0d5daa0cfd0ef03bb3b182e0cc0652",
6
- "builtAt": "2026-11-03T23:49:23.685Z"
5
+ "commit": "20365c00f7144702c4a7438ac5d907dc97b5b62a",
6
+ "builtAt": "2026-11-06T20:15:11.914Z"
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.18.3",
3
+ "version": "2.20.0",
4
4
  "reploBuild": {
5
5
  "packageName": "@replohq/sdk",
6
- "version": "2.18.3",
6
+ "version": "2.20.0",
7
7
  "branch": "HEAD",
8
- "commit": "00c3d9662c0d5daa0cfd0ef03bb3b182e0cc0652",
9
- "builtAt": "2026-11-03T23:49:23.685Z"
8
+ "commit": "20365c00f7144702c4a7438ac5d907dc97b5b62a",
9
+ "builtAt": "2026-11-06T20:15:11.914Z"
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";