@replohq/sdk 1.14.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_vendor/schemas/generated/consent.d.ts +13 -1
- package/analytics/get-analytics-sinks.js +9 -0
- package/analytics/sinks/x-sink.d.ts +32 -0
- package/analytics/sinks/x-sink.js +126 -0
- package/cart/buy-now-action.js +6 -3
- package/consent/replo-scripts.js +19 -5
- package/consent/script-registration-store.d.ts +9 -4
- package/consent/script-snippets.d.ts +9 -9
- package/consent/script-snippets.js +31 -5
- package/consent/types.d.ts +13 -1
- package/lib/buildMetadata.js +3 -3
- package/package.json +4 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ReploScriptType = "GA4" | "GoogleTagManager" | "Meta" | "TikTok" | "Pinterest" | "Reddit" | "Snapchat" | "Hotjar" | "MicrosoftClarity" | "Contentsquare" | "Segment" | "Northbeam" | "Gorgias" | "Converge" | "Cookiebot" | "snippet" | "custom" | "consentPlatform";
|
|
1
|
+
export type ReploScriptType = "GA4" | "GoogleTagManager" | "Meta" | "TikTok" | "Pinterest" | "Reddit" | "Snapchat" | "X" | "Hotjar" | "MicrosoftClarity" | "Contentsquare" | "Segment" | "Northbeam" | "Gorgias" | "Converge" | "Cookiebot" | "snippet" | "custom" | "consentPlatform";
|
|
2
2
|
export type ConsentCategory = "necessary" | "analytics" | "marketing" | "preferences" | "sale_of_data";
|
|
3
3
|
export type ConsentMode = "off" | "simple" | "per-category";
|
|
4
4
|
export type ScriptTagDescriptor = {
|
|
@@ -12,10 +12,22 @@ export type ScriptTagDescriptor = {
|
|
|
12
12
|
body: string;
|
|
13
13
|
module?: boolean;
|
|
14
14
|
};
|
|
15
|
+
export type XPixelEvents = {
|
|
16
|
+
pageView?: string;
|
|
17
|
+
productViewed?: string;
|
|
18
|
+
addToCart?: string;
|
|
19
|
+
startCheckout?: string;
|
|
20
|
+
purchase?: string;
|
|
21
|
+
};
|
|
15
22
|
export type ReploScriptEntry = {
|
|
16
23
|
type: "GA4" | "GoogleTagManager" | "Meta" | "TikTok" | "Pinterest" | "Reddit" | "Snapchat" | "Hotjar" | "MicrosoftClarity" | "Contentsquare" | "Segment" | "Northbeam" | "Gorgias" | "Converge";
|
|
17
24
|
identifier: string;
|
|
18
25
|
requiredConsent?: ConsentCategory[];
|
|
26
|
+
} | {
|
|
27
|
+
type: "X";
|
|
28
|
+
identifier: string;
|
|
29
|
+
events?: Partial<XPixelEvents>;
|
|
30
|
+
requiredConsent?: ConsentCategory[];
|
|
19
31
|
} | {
|
|
20
32
|
type: "Cookiebot";
|
|
21
33
|
identifier: string;
|
|
@@ -11,6 +11,7 @@ import { ReploSink } from "./sinks/replo-sink";
|
|
|
11
11
|
import { SnapchatSink } from "./sinks/snapchat-sink";
|
|
12
12
|
import { TikTokSink } from "./sinks/tiktok-sink";
|
|
13
13
|
import { WindowSink } from "./sinks/window-sink";
|
|
14
|
+
import { XSink } from "./sinks/x-sink";
|
|
14
15
|
import { gateShopifyOwnedFunnelEvents } from "./utils/shopify-funnel-gate";
|
|
15
16
|
const PROVIDER_SINK_FACTORIES = {
|
|
16
17
|
GA4: () => new GA4Sink(),
|
|
@@ -26,6 +27,14 @@ const SNIPPET_PROVIDER_SINK_FACTORIES = {
|
|
|
26
27
|
[snippetScriptId("Elevar")]: () => new ElevarSink()
|
|
27
28
|
};
|
|
28
29
|
function findSinkFactory(script) {
|
|
30
|
+
if (script.type === "X") {
|
|
31
|
+
return () => {
|
|
32
|
+
return new XSink({
|
|
33
|
+
pixelId: script.pixelId,
|
|
34
|
+
events: script.events
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
}
|
|
29
38
|
if (script.type === "snippet") {
|
|
30
39
|
return SNIPPET_PROVIDER_SINK_FACTORIES[script.id] ?? null;
|
|
31
40
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { XPixelEvents } from "../../_vendor/schemas/generated/consent";
|
|
2
|
+
import type { AnalyticsSink, DataPayload, PurchasePayload } from "../analytics-sink";
|
|
3
|
+
import type { PageMetadata } from "../utils/navigation-tracker";
|
|
4
|
+
declare global {
|
|
5
|
+
interface Window {
|
|
6
|
+
twq?: (command: "config" | "event", ...args: unknown[]) => void;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Sends storefront events to X as the conversion events the merchant created
|
|
11
|
+
* in X Ads Events Manager. X has no named events in code, so an event without
|
|
12
|
+
* a mapped ID sends nothing. The consent-gated base code's `twq('config')`
|
|
13
|
+
* already records the site visit and landing page view on load.
|
|
14
|
+
*/
|
|
15
|
+
export declare class XSink implements AnalyticsSink {
|
|
16
|
+
private readonly events;
|
|
17
|
+
private send;
|
|
18
|
+
constructor({ pixelId, events }: {
|
|
19
|
+
pixelId: string;
|
|
20
|
+
events: XPixelEvents;
|
|
21
|
+
});
|
|
22
|
+
private track;
|
|
23
|
+
pageView(metadata: PageMetadata | undefined): Promise<void>;
|
|
24
|
+
purchase({ amount, currency, data }: PurchasePayload): Promise<void>;
|
|
25
|
+
click(): Promise<void>;
|
|
26
|
+
productViewed({ data }: DataPayload): Promise<void>;
|
|
27
|
+
addToCart({ data }: DataPayload): Promise<void>;
|
|
28
|
+
removeFromCart(): Promise<void>;
|
|
29
|
+
viewCart(): Promise<void>;
|
|
30
|
+
startCheckout({ data }: DataPayload): Promise<void>;
|
|
31
|
+
viewCollection(): Promise<void>;
|
|
32
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { filterUndefined } from "../../_vendor/replo-utils/lib/object.mjs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { isXEventIdForPixel } from "../../consent/script-snippets";
|
|
4
|
+
import { legacyResourceId } from "../utils/analytics-products";
|
|
5
|
+
import { createEventQueue } from "../utils/analytics-utils";
|
|
6
|
+
const analyticsRecordSchema = z.record(z.string(), z.unknown());
|
|
7
|
+
const nonEmptyStringSchema = z.union([
|
|
8
|
+
z.string().min(1),
|
|
9
|
+
z.number().finite().transform(String)
|
|
10
|
+
]);
|
|
11
|
+
const finiteNumberSchema = z.union([
|
|
12
|
+
z.number().finite(),
|
|
13
|
+
z.string().trim().min(1).transform(Number).pipe(z.number().finite())
|
|
14
|
+
]);
|
|
15
|
+
function parseRecord(value) {
|
|
16
|
+
const result = analyticsRecordSchema.safeParse(value);
|
|
17
|
+
return result.success ? result.data : {};
|
|
18
|
+
}
|
|
19
|
+
function parseString(value) {
|
|
20
|
+
const result = nonEmptyStringSchema.safeParse(value);
|
|
21
|
+
return result.success ? result.data : void 0;
|
|
22
|
+
}
|
|
23
|
+
function parseNumber(value) {
|
|
24
|
+
const result = finiteNumberSchema.safeParse(value);
|
|
25
|
+
return result.success ? result.data : void 0;
|
|
26
|
+
}
|
|
27
|
+
function mapContent(value, defaultQuantity) {
|
|
28
|
+
const line = parseRecord(value);
|
|
29
|
+
const variant = parseRecord(line.variant);
|
|
30
|
+
const product = parseRecord(variant.product);
|
|
31
|
+
const productId = parseString(line.productId) ?? parseString(product.id);
|
|
32
|
+
if (!productId) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
return filterUndefined({
|
|
36
|
+
content_id: legacyResourceId(productId),
|
|
37
|
+
content_name: parseString(line.productTitle) ?? parseString(product.title) ?? parseString(line.title),
|
|
38
|
+
content_price: parseNumber(line.price) ?? parseNumber(parseRecord(variant.price).amount),
|
|
39
|
+
num_items: parseNumber(line.quantity) ?? defaultQuantity
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function mapContents(lines) {
|
|
43
|
+
const result = z.array(z.unknown()).safeParse(lines);
|
|
44
|
+
if (!result.success) {
|
|
45
|
+
return void 0;
|
|
46
|
+
}
|
|
47
|
+
const contents = result.data.map((line) => mapContent(line, void 0)).filter((content) => content !== null);
|
|
48
|
+
return contents.length > 0 ? contents : void 0;
|
|
49
|
+
}
|
|
50
|
+
function lineValue(content) {
|
|
51
|
+
if (content?.content_price === void 0) {
|
|
52
|
+
return void 0;
|
|
53
|
+
}
|
|
54
|
+
return content.content_price * (content.num_items ?? 1);
|
|
55
|
+
}
|
|
56
|
+
class XSink {
|
|
57
|
+
events;
|
|
58
|
+
send = createEventQueue(
|
|
59
|
+
() => typeof window !== "undefined" && Boolean(window.twq),
|
|
60
|
+
(eventId, parameters) => window.twq?.("event", eventId, parameters),
|
|
61
|
+
"X"
|
|
62
|
+
);
|
|
63
|
+
constructor({ pixelId, events }) {
|
|
64
|
+
this.events = Object.fromEntries(
|
|
65
|
+
Object.entries(events).flatMap(([event, eventId]) => {
|
|
66
|
+
const trimmed = eventId?.trim();
|
|
67
|
+
return trimmed && isXEventIdForPixel({ eventId: trimmed, pixelId }) ? [[event, trimmed]] : [];
|
|
68
|
+
})
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
track(event, parameters) {
|
|
72
|
+
const eventId = this.events[event];
|
|
73
|
+
if (eventId) {
|
|
74
|
+
this.send(eventId, filterUndefined(parameters));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async pageView(metadata) {
|
|
78
|
+
if (metadata?.navigationType === "initial") {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
this.track("pageView", {});
|
|
82
|
+
}
|
|
83
|
+
async purchase({ amount, currency, data }) {
|
|
84
|
+
this.track("purchase", {
|
|
85
|
+
value: amount,
|
|
86
|
+
currency,
|
|
87
|
+
conversion_id: parseString(data.order_id) ?? parseString(data.orderId) ?? parseString(data.id),
|
|
88
|
+
contents: mapContents(data.lineItems)
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
async click() {
|
|
92
|
+
}
|
|
93
|
+
async productViewed({ data }) {
|
|
94
|
+
const content = mapContent(data, 1);
|
|
95
|
+
this.track("productViewed", {
|
|
96
|
+
value: lineValue(content),
|
|
97
|
+
currency: parseString(data.currency),
|
|
98
|
+
contents: content ? [content] : void 0
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
async addToCart({ data }) {
|
|
102
|
+
const content = mapContent(data, 1);
|
|
103
|
+
this.track("addToCart", {
|
|
104
|
+
value: lineValue(content),
|
|
105
|
+
currency: parseString(data.currency),
|
|
106
|
+
contents: content ? [content] : void 0
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
async removeFromCart() {
|
|
110
|
+
}
|
|
111
|
+
async viewCart() {
|
|
112
|
+
}
|
|
113
|
+
async startCheckout({ data }) {
|
|
114
|
+
const totalPrice = parseRecord(data.totalPrice);
|
|
115
|
+
this.track("startCheckout", {
|
|
116
|
+
value: parseNumber(totalPrice.amount),
|
|
117
|
+
currency: parseString(data.currencyCode) ?? parseString(totalPrice.currencyCode),
|
|
118
|
+
contents: mapContents(data.lineItems)
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
async viewCollection() {
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export {
|
|
125
|
+
XSink
|
|
126
|
+
};
|
package/cart/buy-now-action.js
CHANGED
|
@@ -9,6 +9,7 @@ import { buildBaseUrl } from "../lib/url-utils";
|
|
|
9
9
|
import { createCartAction } from "./cart-actions";
|
|
10
10
|
import { REPLO_ATTRIBUTION_PROPERTY } from "./cart-types";
|
|
11
11
|
import { getReturnUrls } from "./return-urls";
|
|
12
|
+
const REPLO_PROJECT_ID_KEY = "rpid";
|
|
12
13
|
class BuyNowError extends CanopyError {
|
|
13
14
|
}
|
|
14
15
|
class BuyNowCartCreationError extends CanopyError {
|
|
@@ -53,7 +54,7 @@ async function buyNowWithRecoveryAction(input) {
|
|
|
53
54
|
"[Replo] Stripe buy now does not support selling plans or discount codes; those options were ignored."
|
|
54
55
|
);
|
|
55
56
|
}
|
|
56
|
-
const
|
|
57
|
+
const env2 = await getEnv();
|
|
57
58
|
const temporaryCartId = input.checkoutAttemptId ?? uuidv4();
|
|
58
59
|
const body = {
|
|
59
60
|
cartId: temporaryCartId,
|
|
@@ -63,11 +64,11 @@ async function buyNowWithRecoveryAction(input) {
|
|
|
63
64
|
quantity: line.quantity,
|
|
64
65
|
properties: line.properties
|
|
65
66
|
})),
|
|
66
|
-
projectId:
|
|
67
|
+
projectId: env2.PROJECT_ID,
|
|
67
68
|
successUrl: `${origin}/checkout/success`,
|
|
68
69
|
cancelUrl
|
|
69
70
|
};
|
|
70
|
-
const canopyApiUrl = `${buildBaseUrl(
|
|
71
|
+
const canopyApiUrl = `${buildBaseUrl(env2.CANOPY_API_HOST)}/api/v1/stripe-checkout/create-session`;
|
|
71
72
|
const response = await fetch(canopyApiUrl, {
|
|
72
73
|
method: "POST",
|
|
73
74
|
headers: { "Content-Type": "application/json" },
|
|
@@ -130,6 +131,8 @@ async function buyNowWithRecoveryAction(input) {
|
|
|
130
131
|
});
|
|
131
132
|
}
|
|
132
133
|
const checkoutUrl = new URL(cart.checkoutUrl, origin);
|
|
134
|
+
const env = await getEnv();
|
|
135
|
+
checkoutUrl.searchParams.set(REPLO_PROJECT_ID_KEY, env.PROJECT_ID);
|
|
133
136
|
return { result: "created", redirectUrl: checkoutUrl.toString() };
|
|
134
137
|
}
|
|
135
138
|
export {
|
package/consent/replo-scripts.js
CHANGED
|
@@ -57,7 +57,7 @@ function descriptorsFor(entry) {
|
|
|
57
57
|
if (entry.type === "consentPlatform" || entry.type === "Cookiebot") {
|
|
58
58
|
return [];
|
|
59
59
|
}
|
|
60
|
-
return buildScriptTags(
|
|
60
|
+
return buildScriptTags(entry);
|
|
61
61
|
}
|
|
62
62
|
class InjectedScript extends Component {
|
|
63
63
|
componentDidMount() {
|
|
@@ -89,17 +89,31 @@ class ScriptRegistration extends Component {
|
|
|
89
89
|
return null;
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
function
|
|
93
|
-
const requiredConsent = requiredConsentFor(entry);
|
|
92
|
+
function registrationFor(entry) {
|
|
94
93
|
const id = scriptId(entry);
|
|
94
|
+
const requiredConsent = requiredConsentFor(entry);
|
|
95
|
+
if (entry.type === "X") {
|
|
96
|
+
return {
|
|
97
|
+
id,
|
|
98
|
+
type: "X",
|
|
99
|
+
requiredConsent,
|
|
100
|
+
pixelId: entry.identifier,
|
|
101
|
+
events: entry.events ?? {}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return { id, type: entry.type, requiredConsent };
|
|
105
|
+
}
|
|
106
|
+
function ManagedScript({ entry }) {
|
|
107
|
+
const registration = registrationFor(entry);
|
|
108
|
+
const { id, requiredConsent } = registration;
|
|
95
109
|
const isBlockedByNativeConsent = useIsBlockedByNativeConsent(requiredConsent);
|
|
96
110
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
97
111
|
/* @__PURE__ */ jsx(
|
|
98
112
|
ScriptRegistration,
|
|
99
113
|
{
|
|
100
|
-
script:
|
|
114
|
+
script: registration
|
|
101
115
|
},
|
|
102
|
-
|
|
116
|
+
JSON.stringify(registration)
|
|
103
117
|
),
|
|
104
118
|
!isBlockedByNativeConsent && /* @__PURE__ */ jsx(
|
|
105
119
|
InjectedScript,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ConsentCategory, ReploScriptType } from "../_vendor/schemas/generated/consent";
|
|
1
|
+
import type { ConsentCategory, ReploScriptType, XPixelEvents } from "../_vendor/schemas/generated/consent";
|
|
2
2
|
/**
|
|
3
3
|
* Tracks which managed scripts are currently mounted on the page. Each
|
|
4
4
|
* `ReploScripts` entry registers itself here on mount, so the analytics provider
|
|
@@ -6,11 +6,16 @@ import type { ConsentCategory, ReploScriptType } from "../_vendor/schemas/genera
|
|
|
6
6
|
* without importing a static list. Like the consent store, this is a singleton
|
|
7
7
|
* rather than React context so it works regardless of tree position.
|
|
8
8
|
*/
|
|
9
|
-
export
|
|
9
|
+
export type RegisteredScript = {
|
|
10
10
|
id: string;
|
|
11
|
-
type: ReploScriptType;
|
|
12
11
|
requiredConsent: ConsentCategory[];
|
|
13
|
-
}
|
|
12
|
+
} & ({
|
|
13
|
+
type: Exclude<ReploScriptType, "X">;
|
|
14
|
+
} | {
|
|
15
|
+
type: "X";
|
|
16
|
+
pixelId: string;
|
|
17
|
+
events: XPixelEvents;
|
|
18
|
+
});
|
|
14
19
|
/**
|
|
15
20
|
* Registration id of a `snippet` entry. Snippet providers have no distinct
|
|
16
21
|
* `type`, so both `ReploScripts` (registering) and the analytics sink factory
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import type { ConsentCategory, ReploScriptType, ScriptTagDescriptor } from "../_vendor/schemas/generated/consent";
|
|
1
|
+
import type { ConsentCategory, ReploScriptEntry, ReploScriptType, ScriptTagDescriptor } from "../_vendor/schemas/generated/consent";
|
|
2
2
|
type ProviderType = Exclude<ReploScriptType, "custom" | "snippet" | "consentPlatform" | "Cookiebot">;
|
|
3
3
|
/**
|
|
4
4
|
* Snippet providers don't synthesize tags (the user pastes the provider-issued
|
|
5
5
|
* snippet as the entry's `body`), but they still get a first-class default
|
|
6
6
|
* consent categorization like identifier providers.
|
|
7
7
|
*/
|
|
8
|
-
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
/** IDs for another pixel would credit a different advertiser. */
|
|
9
|
+
export declare function isXEventIdForPixel({ eventId, pixelId, }: {
|
|
10
|
+
eventId: string;
|
|
11
|
+
pixelId: string;
|
|
12
|
+
}): boolean;
|
|
13
|
+
/** The runtime injects these tags in order after consent allows tracking. */
|
|
14
|
+
export declare function buildScriptTags(entry: Extract<ReploScriptEntry, {
|
|
14
15
|
type: ProviderType;
|
|
15
|
-
|
|
16
|
-
}): ScriptTagDescriptor[];
|
|
16
|
+
}>): ScriptTagDescriptor[];
|
|
17
17
|
/**
|
|
18
18
|
* The default consent categories that gate an identifier-provider script when an
|
|
19
19
|
* entry does not specify `requiredConsent`. `snippet` and `custom` entries carry
|
|
@@ -69,6 +69,15 @@ gtag('config', '${id}');`
|
|
|
69
69
|
}
|
|
70
70
|
]
|
|
71
71
|
},
|
|
72
|
+
X: {
|
|
73
|
+
defaultConsent: ["marketing"],
|
|
74
|
+
buildTags: (id) => [
|
|
75
|
+
{
|
|
76
|
+
kind: "inline",
|
|
77
|
+
body: `!function(e,t,n,s,u,a){e.twq||(s=e.twq=function(){s.exe?s.exe.apply(s,arguments):s.queue.push(arguments);},s.version='1.1',s.queue=[],u=t.createElement(n),u.async=!0,u.src='https://static.ads-twitter.com/uwt.js',a=t.getElementsByTagName(n)[0],a.parentNode.insertBefore(u,a))}(window,document,'script');twq('config','${id}');`
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
},
|
|
72
81
|
Hotjar: {
|
|
73
82
|
defaultConsent: ["analytics"],
|
|
74
83
|
buildTags: (id) => [
|
|
@@ -140,16 +149,33 @@ gtag('config', '${id}');`
|
|
|
140
149
|
]
|
|
141
150
|
}
|
|
142
151
|
};
|
|
143
|
-
function
|
|
144
|
-
|
|
145
|
-
|
|
152
|
+
function isXEventIdForPixel({
|
|
153
|
+
eventId,
|
|
154
|
+
pixelId
|
|
146
155
|
}) {
|
|
147
|
-
|
|
156
|
+
const match = /^tw-([a-z0-9]+)-[a-z0-9]+$/i.exec(eventId);
|
|
157
|
+
return match?.[1]?.toLowerCase() === pixelId.toLowerCase();
|
|
158
|
+
}
|
|
159
|
+
function buildScriptTags(entry) {
|
|
160
|
+
const tags = PROVIDER_SNIPPETS[entry.type].buildTags(entry.identifier);
|
|
161
|
+
if (entry.type === "X") {
|
|
162
|
+
const pageViewId = entry.events?.pageView?.trim();
|
|
163
|
+
if (pageViewId && isXEventIdForPixel({ eventId: pageViewId, pixelId: entry.identifier })) {
|
|
164
|
+
return tags.map((tag) => {
|
|
165
|
+
return tag.kind === "inline" ? {
|
|
166
|
+
...tag,
|
|
167
|
+
body: `${tag.body}twq('event',${JSON.stringify(pageViewId)},{});`
|
|
168
|
+
} : tag;
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return tags;
|
|
148
173
|
}
|
|
149
174
|
function defaultConsentFor(type) {
|
|
150
175
|
return PROVIDER_SNIPPETS[type].defaultConsent;
|
|
151
176
|
}
|
|
152
177
|
export {
|
|
153
178
|
buildScriptTags,
|
|
154
|
-
defaultConsentFor
|
|
179
|
+
defaultConsentFor,
|
|
180
|
+
isXEventIdForPixel
|
|
155
181
|
};
|
package/consent/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ReploScriptType = "GA4" | "GoogleTagManager" | "Meta" | "TikTok" | "Pinterest" | "Reddit" | "Snapchat" | "Hotjar" | "MicrosoftClarity" | "Contentsquare" | "Segment" | "Northbeam" | "Gorgias" | "Converge" | "Cookiebot" | "snippet" | "custom" | "consentPlatform";
|
|
1
|
+
export type ReploScriptType = "GA4" | "GoogleTagManager" | "Meta" | "TikTok" | "Pinterest" | "Reddit" | "Snapchat" | "X" | "Hotjar" | "MicrosoftClarity" | "Contentsquare" | "Segment" | "Northbeam" | "Gorgias" | "Converge" | "Cookiebot" | "snippet" | "custom" | "consentPlatform";
|
|
2
2
|
export type ConsentCategory = "necessary" | "analytics" | "marketing" | "preferences" | "sale_of_data";
|
|
3
3
|
export type ConsentMode = "off" | "simple" | "per-category";
|
|
4
4
|
declare module "react" {
|
|
@@ -16,10 +16,22 @@ export type ScriptTagDescriptor = {
|
|
|
16
16
|
kind: "inline";
|
|
17
17
|
body: string;
|
|
18
18
|
};
|
|
19
|
+
export type XPixelEvents = {
|
|
20
|
+
pageView?: string;
|
|
21
|
+
productViewed?: string;
|
|
22
|
+
addToCart?: string;
|
|
23
|
+
startCheckout?: string;
|
|
24
|
+
purchase?: string;
|
|
25
|
+
};
|
|
19
26
|
export type ReploScriptEntry = {
|
|
20
27
|
type: "GA4" | "GoogleTagManager" | "Meta" | "TikTok" | "Pinterest" | "Reddit" | "Snapchat" | "Hotjar" | "MicrosoftClarity" | "Contentsquare" | "Segment" | "Northbeam" | "Gorgias" | "Converge" | "Cookiebot";
|
|
21
28
|
identifier: string;
|
|
22
29
|
requiredConsent?: ConsentCategory[];
|
|
30
|
+
} | {
|
|
31
|
+
type: "X";
|
|
32
|
+
identifier: string;
|
|
33
|
+
events?: XPixelEvents;
|
|
34
|
+
requiredConsent?: ConsentCategory[];
|
|
23
35
|
} | {
|
|
24
36
|
type: "snippet";
|
|
25
37
|
id: string;
|
package/lib/buildMetadata.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const BUILD_METADATA = {
|
|
2
2
|
"packageName": "@replohq/sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"branch": "HEAD",
|
|
5
|
-
"commit": "
|
|
6
|
-
"builtAt": "2026-10-
|
|
5
|
+
"commit": "3759f7d83c0c4991b7ccbafed0d1b55da1ed48b4",
|
|
6
|
+
"builtAt": "2026-10-09T21:52:34.432Z"
|
|
7
7
|
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@replohq/sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"reploBuild": {
|
|
5
5
|
"packageName": "@replohq/sdk",
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.15.0",
|
|
7
7
|
"branch": "HEAD",
|
|
8
|
-
"commit": "
|
|
9
|
-
"builtAt": "2026-10-
|
|
8
|
+
"commit": "3759f7d83c0c4991b7ccbafed0d1b55da1ed48b4",
|
|
9
|
+
"builtAt": "2026-10-09T21:52:34.432Z"
|
|
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",
|