@escape-game-over/atlas 0.1.58 → 0.1.60
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/package.json +1 -1
- package/src/analytics/axon-pixel.ts +6 -1
- package/src/analytics/clarity.ts +29 -0
- package/src/analytics/drip.ts +20 -0
- package/src/analytics/index.ts +15 -0
- package/src/analytics/meta-pixel.ts +7 -1
- package/src/analytics/snap-pixel.ts +6 -1
- package/src/analytics/tiktok-pixel.ts +7 -1
- package/src/astro/Clarity.astro +18 -0
- package/src/astro/ConsentBanner.astro +5 -1
- package/src/astro/Drip.astro +18 -0
- package/src/astro/GoogleMap.astro +5 -0
- package/src/astro/clarity-event.ts +15 -0
- package/src/astro/clarity.ts +60 -0
- package/src/astro/client.ts +2 -0
- package/src/astro/consent-gate.ts +21 -0
- package/src/astro/drip-event.ts +24 -0
- package/src/astro/drip.ts +37 -0
- package/src/index.ts +2 -0
package/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { warn } from "../warn.ts";
|
|
2
2
|
import { UUID } from "./snap-pixel.ts";
|
|
3
3
|
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* AppLovin's Axon pixel. Marketing: it loads only once a visitor grants that.
|
|
6
|
+
*
|
|
7
|
+
* @see https://support.applovin.com/en/growth/promoting-your-websites/axon-pixel-integration/axon-pixel-native-js
|
|
8
|
+
* @see https://support.applovin.com/en/growth/promoting-your-websites/axon-pixel-integration/events-and-objects
|
|
9
|
+
*/
|
|
5
10
|
export interface AxonPixelSettings {
|
|
6
11
|
/** From the Axon dashboard: a UUID. */
|
|
7
12
|
readonly eventKey: string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { warn } from "../warn.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Microsoft Clarity. It has a cookieless mode, so like Google it loads for
|
|
5
|
+
* every visitor: without consent it records each page view on its own and sets
|
|
6
|
+
* no cookie, and the visitor's answer switches its cookies on or off.
|
|
7
|
+
*
|
|
8
|
+
* @see https://learn.microsoft.com/en-us/clarity/setup-and-installation/clarity-setup
|
|
9
|
+
* @see https://learn.microsoft.com/en-us/clarity/setup-and-installation/consent-mode
|
|
10
|
+
* @see https://learn.microsoft.com/en-us/clarity/setup-and-installation/clarity-consent-api-v2
|
|
11
|
+
*/
|
|
12
|
+
export interface ClaritySettings {
|
|
13
|
+
/** From the Clarity project's settings: 10 lowercase letters and digits. */
|
|
14
|
+
readonly projectId: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Warns about an id that is not a project id: it would report nowhere. */
|
|
18
|
+
export function checkClarity(
|
|
19
|
+
clarity: ClaritySettings | undefined,
|
|
20
|
+
at: string
|
|
21
|
+
): void {
|
|
22
|
+
if (clarity === undefined || /^[a-z0-9]{10}$/.test(clarity.projectId)) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
warn(
|
|
26
|
+
at,
|
|
27
|
+
`Clarity project id "${clarity.projectId}" is not 10 lowercase letters and digits, so it reports nowhere. Copy it from the Clarity project's settings.`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { warn } from "../warn.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Drip's site tracking. Marketing: it loads only once a visitor grants that.
|
|
5
|
+
*
|
|
6
|
+
* @see https://help.drip.com/hc/en-us/articles/4424702539789-Install-Your-JavaScript-Snippet
|
|
7
|
+
*/
|
|
8
|
+
export interface DripSettings {
|
|
9
|
+
/** From Drip's Site Setup: digits, the `_dcs.account` of its snippet. */
|
|
10
|
+
readonly accountId: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Warns about an id that is not an account id: it would report nowhere. */
|
|
14
|
+
export function checkDrip(drip: DripSettings | undefined, at: string): void {
|
|
15
|
+
if (drip === undefined || /^\d+$/.test(drip.accountId)) return;
|
|
16
|
+
warn(
|
|
17
|
+
at,
|
|
18
|
+
`Drip account id "${drip.accountId}" is not all digits, so it reports nowhere. Copy it from Drip's Site Setup.`
|
|
19
|
+
);
|
|
20
|
+
}
|
package/src/analytics/index.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { MetaTag } from "../meta/tag.ts";
|
|
2
2
|
import type { HttpsUrl } from "../url.ts";
|
|
3
3
|
import { type AxonPixelSettings, checkAxonPixel } from "./axon-pixel.ts";
|
|
4
|
+
import { type ClaritySettings, checkClarity } from "./clarity.ts";
|
|
5
|
+
import { checkDrip, type DripSettings } from "./drip.ts";
|
|
4
6
|
import { type GoogleSettings, googleEmits, googleScripts } from "./google.ts";
|
|
5
7
|
import { checkMetaPixel, type MetaPixelSettings } from "./meta-pixel.ts";
|
|
6
8
|
import { checkSnapPixel, type SnapPixelSettings } from "./snap-pixel.ts";
|
|
@@ -28,6 +30,8 @@ import {
|
|
|
28
30
|
*/
|
|
29
31
|
|
|
30
32
|
export type { AxonPixelSettings } from "./axon-pixel.ts";
|
|
33
|
+
export type { ClaritySettings } from "./clarity.ts";
|
|
34
|
+
export type { DripSettings } from "./drip.ts";
|
|
31
35
|
export {
|
|
32
36
|
CONSENT_UPDATE_GLOBAL,
|
|
33
37
|
type ConsentDefaults,
|
|
@@ -56,6 +60,10 @@ export interface AnalyticsSettings {
|
|
|
56
60
|
readonly snapchat?: SnapPixelSettings;
|
|
57
61
|
/** Loaded by `ConsentBanner`, after marketing is granted. */
|
|
58
62
|
readonly axon?: AxonPixelSettings;
|
|
63
|
+
/** Loaded by `ConsentBanner`, after marketing is granted. */
|
|
64
|
+
readonly drip?: DripSettings;
|
|
65
|
+
/** Loaded by `ConsentBanner` for every visitor, cookieless until analytics is granted. */
|
|
66
|
+
readonly clarity?: ClaritySettings;
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
/**
|
|
@@ -80,6 +88,8 @@ export function analyticsScripts(
|
|
|
80
88
|
checkTikTokPixel(analytics.tiktok, origin);
|
|
81
89
|
checkSnapPixel(analytics.snapchat, origin);
|
|
82
90
|
checkAxonPixel(analytics.axon, origin);
|
|
91
|
+
checkDrip(analytics.drip, origin);
|
|
92
|
+
checkClarity(analytics.clarity, origin);
|
|
83
93
|
const google = googleScripts(analytics.google, origin);
|
|
84
94
|
return {
|
|
85
95
|
head: [...google.head, ...umamiScripts(analytics.umami)],
|
|
@@ -126,6 +136,11 @@ export function consentVendors(
|
|
|
126
136
|
snapchat: analytics.snapchat !== undefined,
|
|
127
137
|
// No consent mode at all.
|
|
128
138
|
axon: analytics.axon !== undefined,
|
|
139
|
+
// No consent mode at all.
|
|
140
|
+
drip: analytics.drip !== undefined,
|
|
141
|
+
// Cookieless without consent, but the answer is what switches its
|
|
142
|
+
// cookies on, so it needs the banner.
|
|
143
|
+
clarity: analytics.clarity !== undefined,
|
|
129
144
|
};
|
|
130
145
|
|
|
131
146
|
return (Object.keys(VENDORS) as (keyof AnalyticsSettings)[]).filter(
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type { NonEmpty } from "../types.ts";
|
|
2
2
|
import { warn } from "../warn.ts";
|
|
3
3
|
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Meta's pixel. Marketing: it loads only once a visitor grants that.
|
|
6
|
+
*
|
|
7
|
+
* @see https://developers.facebook.com/docs/meta-pixel/get-started
|
|
8
|
+
* @see https://developers.facebook.com/docs/meta-pixel/reference
|
|
9
|
+
* @see https://developers.facebook.com/docs/meta-pixel/implementation/gdpr
|
|
10
|
+
*/
|
|
5
11
|
export interface MetaPixelSettings {
|
|
6
12
|
/** From Events Manager: 15 or 16 digits. Several share one script. */
|
|
7
13
|
readonly pixelIds: NonEmpty<string>;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import type { NonEmpty } from "../types.ts";
|
|
2
2
|
import { warn } from "../warn.ts";
|
|
3
3
|
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* Snapchat's pixel. Marketing: it loads only once a visitor grants that.
|
|
6
|
+
*
|
|
7
|
+
* @see https://businesshelp.snapchat.com/s/article/pixel-direct-implementation
|
|
8
|
+
* @see https://forbusiness.snapchat.com/en-US/blog/the-snap-pixel-how-it-works-and-how-to-install-it
|
|
9
|
+
*/
|
|
5
10
|
export interface SnapPixelSettings {
|
|
6
11
|
/** From Snap's Events Manager: a UUID. */
|
|
7
12
|
readonly pixelIds: NonEmpty<string>;
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type { NonEmpty } from "../types.ts";
|
|
2
2
|
import { warn } from "../warn.ts";
|
|
3
3
|
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* TikTok's pixel. Marketing: it loads only once a visitor grants that.
|
|
6
|
+
*
|
|
7
|
+
* @see https://ads.tiktok.com/help/article/get-started-pixel
|
|
8
|
+
* @see https://ads.tiktok.com/help/article/standard-events-parameters
|
|
9
|
+
* @see https://ads.tiktok.com/help/article/how-to-use-cookies-with-tiktok-pixel
|
|
10
|
+
*/
|
|
5
11
|
export interface TikTokPixelSettings {
|
|
6
12
|
/** From TikTok Events Manager: 20 capital letters and digits. */
|
|
7
13
|
readonly pixelIds: NonEmpty<string>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
/** Internal to `ConsentBanner.astro`, so Clarity's script ships only where it is configured. */
|
|
3
|
+
import type { ClaritySettings } from "../analytics/clarity.ts";
|
|
4
|
+
import AtlasElement from "./AtlasElement.astro";
|
|
5
|
+
import { clarityElement } from "./clarity.ts";
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
readonly settings: ClaritySettings;
|
|
9
|
+
}
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<script src="./clarity.ts" />
|
|
13
|
+
|
|
14
|
+
<AtlasElement
|
|
15
|
+
of={clarityElement}
|
|
16
|
+
data-project-id={Astro.props.settings.projectId}
|
|
17
|
+
hidden
|
|
18
|
+
/>
|
|
@@ -5,13 +5,15 @@
|
|
|
5
5
|
* buttons.
|
|
6
6
|
*
|
|
7
7
|
* Renders nothing — and ships no script — when this site's analytics need no
|
|
8
|
-
* permission. Also loads the vendors that wait for consent, such as the Meta, TikTok, Snap and Axon pixels. Otherwise the banner starts hidden and shows only to a visitor
|
|
8
|
+
* permission. Also loads the vendors that wait for consent, such as the Meta, TikTok, Snap and Axon pixels, Drip and Clarity. Otherwise the banner starts hidden and shows only to a visitor
|
|
9
9
|
* with no answer on record, or when a `data-consent-reopen` control is pressed.
|
|
10
10
|
*/
|
|
11
11
|
import type { HTMLAttributes } from "astro/types";
|
|
12
12
|
import { type AnalyticsSettings, consentRequired } from "../analytics/index.ts";
|
|
13
13
|
import AxonPixel from "./AxonPixel.astro";
|
|
14
|
+
import Clarity from "./Clarity.astro";
|
|
14
15
|
import ConsentElement from "./ConsentElement.astro";
|
|
16
|
+
import Drip from "./Drip.astro";
|
|
15
17
|
import MetaPixel from "./MetaPixel.astro";
|
|
16
18
|
import SnapPixel from "./SnapPixel.astro";
|
|
17
19
|
import TikTokPixel from "./TikTokPixel.astro";
|
|
@@ -32,5 +34,7 @@ const { analytics, ...attrs } = Astro.props;
|
|
|
32
34
|
{analytics?.tiktok && <TikTokPixel settings={analytics.tiktok} />}
|
|
33
35
|
{analytics?.snapchat && <SnapPixel settings={analytics.snapchat} />}
|
|
34
36
|
{analytics?.axon && <AxonPixel settings={analytics.axon} />}
|
|
37
|
+
{analytics?.drip && <Drip settings={analytics.drip} />}
|
|
38
|
+
{analytics?.clarity && <Clarity settings={analytics.clarity} />}
|
|
35
39
|
</>
|
|
36
40
|
)}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
/** Internal to `ConsentBanner.astro`, so Drip's script ships only where it is configured. */
|
|
3
|
+
import type { DripSettings } from "../analytics/drip.ts";
|
|
4
|
+
import AtlasElement from "./AtlasElement.astro";
|
|
5
|
+
import { dripElement } from "./drip.ts";
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
readonly settings: DripSettings;
|
|
9
|
+
}
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<script src="./drip.ts" />
|
|
13
|
+
|
|
14
|
+
<AtlasElement
|
|
15
|
+
of={dripElement}
|
|
16
|
+
data-account-id={Astro.props.settings.accountId}
|
|
17
|
+
hidden
|
|
18
|
+
/>
|
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Give the element its size; the map fills it.
|
|
13
13
|
*
|
|
14
|
+
* @see https://developers.google.com/maps/documentation/javascript/load-maps-js-api
|
|
15
|
+
* @see https://developers.google.com/maps/documentation/javascript/advanced-markers/overview
|
|
16
|
+
* @see https://developers.google.com/maps/documentation/get-map-id
|
|
17
|
+
* @see https://developers.google.com/maps/billing-and-pricing/pricing
|
|
18
|
+
*
|
|
14
19
|
* ```astro
|
|
15
20
|
* <GoogleMap apiKey={key} mapId={id} colorScheme="DARK" places={[{ at, label, href }]} class="block h-96">
|
|
16
21
|
* <button type="button">Show map</button>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** What `clarity.ts` defines once the page has loaded. */
|
|
2
|
+
interface ClarityWindow {
|
|
3
|
+
clarity?: (...args: unknown[]) => void;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Marks the current Clarity recording with a named event — a form sent, a
|
|
8
|
+
* booking opened — so recordings can be filtered by it.
|
|
9
|
+
*
|
|
10
|
+
* Sent with or without consent: Clarity records either way, and without it
|
|
11
|
+
* sets no cookie. Dropped before Clarity loads, or where it is not configured.
|
|
12
|
+
*/
|
|
13
|
+
export function clarityEvent(name: string): void {
|
|
14
|
+
(window as unknown as ClarityWindow).clarity?.("event", name);
|
|
15
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { appendScript } from "./append-script.ts";
|
|
2
|
+
import type { ConsentChoices } from "./consent.ts";
|
|
3
|
+
import { withConsent } from "./consent-gate.ts";
|
|
4
|
+
import { element } from "./element.ts";
|
|
5
|
+
import { data } from "./ref.ts";
|
|
6
|
+
|
|
7
|
+
/** Clarity's `clarity`: a queue until its script arrives and replays it. */
|
|
8
|
+
interface Clarity {
|
|
9
|
+
(...args: unknown[]): void;
|
|
10
|
+
q?: unknown[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface ClarityWindow {
|
|
14
|
+
clarity?: Clarity;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Clarity's own base code, as it defines `clarity` before the script loads. */
|
|
18
|
+
function defineClarity(): Clarity {
|
|
19
|
+
const global = window as unknown as ClarityWindow;
|
|
20
|
+
if (global.clarity !== undefined) return global.clarity;
|
|
21
|
+
// `arguments` is the list of whatever a call passed, which every regular
|
|
22
|
+
// `function` gets without declaring it (an arrow function does not). The
|
|
23
|
+
// queue stores that object rather than an array because Clarity's official
|
|
24
|
+
// snippet does: it is the shape Clarity promises its script will replay.
|
|
25
|
+
const clarity = function () {
|
|
26
|
+
// biome-ignore lint/complexity/noArguments: see above.
|
|
27
|
+
const args = arguments;
|
|
28
|
+
clarity.q ??= [];
|
|
29
|
+
clarity.q.push(args);
|
|
30
|
+
} as Clarity;
|
|
31
|
+
global.clarity = clarity;
|
|
32
|
+
return clarity;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Clarity's consent call, in its own spelling. */
|
|
36
|
+
const consentv2 = (choices: ConsentChoices) => ({
|
|
37
|
+
ad_Storage: choices.marketing,
|
|
38
|
+
analytics_Storage: choices.analytics,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Loads Clarity with the answer so far, then passes on every answer. Stated
|
|
43
|
+
* even when denied: a Clarity project set to use cookies by default would
|
|
44
|
+
* otherwise set them before anyone was asked.
|
|
45
|
+
*/
|
|
46
|
+
export function clarity(projectId: string, signal?: AbortSignal): void {
|
|
47
|
+
let loaded = false;
|
|
48
|
+
withConsent((choices) => {
|
|
49
|
+
const queue = defineClarity();
|
|
50
|
+
queue("consentv2", consentv2(choices));
|
|
51
|
+
if (loaded) return;
|
|
52
|
+
loaded = true;
|
|
53
|
+
appendScript(`https://www.clarity.ms/tag/${projectId}`);
|
|
54
|
+
}, signal);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Internal to `Clarity.astro`. */
|
|
58
|
+
export const clarityElement = element("atlas-clarity", ({ root, signal }) => {
|
|
59
|
+
clarity(data(root, "project-id"), signal);
|
|
60
|
+
});
|
package/src/astro/client.ts
CHANGED
|
@@ -13,9 +13,11 @@ export * from "./attribution.ts";
|
|
|
13
13
|
export * from "./axon-event.ts";
|
|
14
14
|
export * from "./background-video.ts";
|
|
15
15
|
export * from "./carousel.ts";
|
|
16
|
+
export * from "./clarity-event.ts";
|
|
16
17
|
// Reading only: a form that reports what the visitor agreed to. Recording an
|
|
17
18
|
// answer stays with the banner.
|
|
18
19
|
export { type ConsentRecord, readConsent } from "./consent.ts";
|
|
20
|
+
export * from "./drip-event.ts";
|
|
19
21
|
export {
|
|
20
22
|
type Connect,
|
|
21
23
|
type ElementContext,
|
|
@@ -46,3 +46,24 @@ export function whenGranted(
|
|
|
46
46
|
{ signal }
|
|
47
47
|
);
|
|
48
48
|
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* For a vendor with a cookieless mode, which loads whatever the answer: after
|
|
52
|
+
* `load`, `apply` gets the answer so far (everything denied until one is
|
|
53
|
+
* given), then every answer given on this page.
|
|
54
|
+
*/
|
|
55
|
+
export function withConsent(
|
|
56
|
+
apply: (choices: ConsentChoices) => void,
|
|
57
|
+
signal?: AbortSignal
|
|
58
|
+
): void {
|
|
59
|
+
const start = () => {
|
|
60
|
+
apply(readConsent() ?? { analytics: "denied", marketing: "denied" });
|
|
61
|
+
addEventListener(
|
|
62
|
+
CONSENT_EVENT,
|
|
63
|
+
(event) => apply((event as CustomEvent<ConsentChoices>).detail),
|
|
64
|
+
{ signal }
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
if (document.readyState === "complete") start();
|
|
68
|
+
else addEventListener("load", start, { once: true, signal });
|
|
69
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { readConsent } from "./consent.ts";
|
|
2
|
+
|
|
3
|
+
/** What `drip.ts` defines once marketing is granted. */
|
|
4
|
+
interface DripWindow {
|
|
5
|
+
_dcq?: unknown[][];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Records an event with Drip, to start a workflow — a lead sent, a voucher
|
|
10
|
+
* bought. Drip's events are named by the site, so any name goes.
|
|
11
|
+
*
|
|
12
|
+
* Dropped unless Drip loaded and marketing is still granted: Drip has no
|
|
13
|
+
* consent call of its own, so the check is here. An analytics call must never
|
|
14
|
+
* be the reason a page misbehaves, so a dropped event is silent.
|
|
15
|
+
*/
|
|
16
|
+
export function dripEvent(
|
|
17
|
+
action: string,
|
|
18
|
+
properties?: Readonly<Record<string, string | number | boolean>>
|
|
19
|
+
): void {
|
|
20
|
+
if (readConsent()?.marketing !== "granted") return;
|
|
21
|
+
const queue = (window as unknown as DripWindow)._dcq;
|
|
22
|
+
if (properties === undefined) queue?.push(["track", action]);
|
|
23
|
+
else queue?.push(["track", action, properties]);
|
|
24
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { appendScript } from "./append-script.ts";
|
|
2
|
+
import type { ConsentGated } from "./consent-gate.ts";
|
|
3
|
+
import { whenGranted } from "./consent-gate.ts";
|
|
4
|
+
import { element } from "./element.ts";
|
|
5
|
+
import { data } from "./ref.ts";
|
|
6
|
+
|
|
7
|
+
/** Drip's globals: a queue of calls, and the account its script reports to. */
|
|
8
|
+
interface DripWindow {
|
|
9
|
+
_dcq?: unknown[][];
|
|
10
|
+
_dcs?: { account?: string };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Drip, loaded on the first grant. Its script records visits by itself, so
|
|
15
|
+
* nothing is queued here. Drip has no consent call, so a withdrawal cannot
|
|
16
|
+
* pause what already loaded: `dripEvent` stops sending, and the next page does
|
|
17
|
+
* not load it.
|
|
18
|
+
*/
|
|
19
|
+
export function drip(accountId: string): ConsentGated {
|
|
20
|
+
let loaded = false;
|
|
21
|
+
return {
|
|
22
|
+
grant: () => {
|
|
23
|
+
if (loaded) return;
|
|
24
|
+
loaded = true;
|
|
25
|
+
const global = window as unknown as DripWindow;
|
|
26
|
+
global._dcq ??= [];
|
|
27
|
+
global._dcs ??= {};
|
|
28
|
+
global._dcs.account = accountId;
|
|
29
|
+
appendScript(`https://tag.getdrip.com/${accountId}.js`);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Internal to `Drip.astro`. */
|
|
35
|
+
export const dripElement = element("atlas-drip", ({ root, signal }) => {
|
|
36
|
+
whenGranted("marketing", drip(data(root, "account-id")), signal);
|
|
37
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -23,11 +23,13 @@ export {
|
|
|
23
23
|
type AnalyticsSettings,
|
|
24
24
|
type AnalyticsTags,
|
|
25
25
|
type AxonPixelSettings,
|
|
26
|
+
type ClaritySettings,
|
|
26
27
|
CONSENT_UPDATE_GLOBAL,
|
|
27
28
|
type ConsentDefaults,
|
|
28
29
|
type ConsentState,
|
|
29
30
|
consentRequired,
|
|
30
31
|
consentVendors,
|
|
32
|
+
type DripSettings,
|
|
31
33
|
type GoogleSettings,
|
|
32
34
|
type MetaPixelSettings,
|
|
33
35
|
type SnapPixelSettings,
|