@jwiedeman/gtm-kit-astro 1.1.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/README.md +331 -0
- package/dist/components/index.cjs +31 -0
- package/dist/components/index.cjs.map +1 -0
- package/dist/components/index.d.cts +41 -0
- package/dist/components/index.d.ts +41 -0
- package/dist/components/index.js +8 -0
- package/dist/components/index.js.map +1 -0
- package/dist/index.cjs +39 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +182 -0
- package/dist/index.d.ts +182 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
- package/src/components/GtmHead.astro +117 -0
- package/src/components/GtmNoScript.astro +56 -0
- package/src/components/GtmScript.astro +70 -0
package/README.md
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
# @jwiedeman/gtm-kit-astro
|
|
2
|
+
|
|
3
|
+
[](https://github.com/jwiedeman/GTM-Kit/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@jwiedeman/gtm-kit-astro)
|
|
5
|
+
[](https://bundlephobia.com/package/@jwiedeman/gtm-kit-astro)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
[](https://astro.build/)
|
|
9
|
+
|
|
10
|
+
**Astro components and helpers for Google Tag Manager. Supports View Transitions API.**
|
|
11
|
+
|
|
12
|
+
The Astro integration for GTM Kit - includes ready-to-use components and client-side helpers for page tracking.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @jwiedeman/gtm-kit @jwiedeman/gtm-kit-astro
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
yarn add @jwiedeman/gtm-kit @jwiedeman/gtm-kit-astro
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pnpm add @jwiedeman/gtm-kit @jwiedeman/gtm-kit-astro
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
33
|
+
|
|
34
|
+
### Option 1: Use the GtmHead Component (Recommended)
|
|
35
|
+
|
|
36
|
+
The easiest way to add GTM to your Astro site:
|
|
37
|
+
|
|
38
|
+
```astro
|
|
39
|
+
---
|
|
40
|
+
// src/layouts/Layout.astro
|
|
41
|
+
import { GtmHead } from '@jwiedeman/gtm-kit-astro/components';
|
|
42
|
+
---
|
|
43
|
+
<html>
|
|
44
|
+
<head>
|
|
45
|
+
<GtmHead
|
|
46
|
+
containers="GTM-XXXXXX"
|
|
47
|
+
enablePageTracking
|
|
48
|
+
/>
|
|
49
|
+
</head>
|
|
50
|
+
<body>
|
|
51
|
+
<slot />
|
|
52
|
+
</body>
|
|
53
|
+
</html>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Option 2: Use Individual Components
|
|
57
|
+
|
|
58
|
+
For more control, use the script and noscript components separately:
|
|
59
|
+
|
|
60
|
+
```astro
|
|
61
|
+
---
|
|
62
|
+
// src/layouts/Layout.astro
|
|
63
|
+
import { GtmScript, GtmNoScript } from '@jwiedeman/gtm-kit-astro/components';
|
|
64
|
+
---
|
|
65
|
+
<html>
|
|
66
|
+
<head>
|
|
67
|
+
<GtmScript containers="GTM-XXXXXX" />
|
|
68
|
+
</head>
|
|
69
|
+
<body>
|
|
70
|
+
<GtmNoScript containers="GTM-XXXXXX" />
|
|
71
|
+
<slot />
|
|
72
|
+
</body>
|
|
73
|
+
</html>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Option 3: Client-Side API
|
|
77
|
+
|
|
78
|
+
For programmatic control:
|
|
79
|
+
|
|
80
|
+
```astro
|
|
81
|
+
---
|
|
82
|
+
// src/layouts/Layout.astro
|
|
83
|
+
---
|
|
84
|
+
<html>
|
|
85
|
+
<head>
|
|
86
|
+
<!-- Your head content -->
|
|
87
|
+
</head>
|
|
88
|
+
<body>
|
|
89
|
+
<slot />
|
|
90
|
+
<script>
|
|
91
|
+
import { initGtm, push, setupPageTracking } from '@jwiedeman/gtm-kit-astro';
|
|
92
|
+
|
|
93
|
+
initGtm({ containers: 'GTM-XXXXXX' });
|
|
94
|
+
setupPageTracking();
|
|
95
|
+
|
|
96
|
+
// Push custom events
|
|
97
|
+
push({ event: 'page_loaded', page_type: 'home' });
|
|
98
|
+
</script>
|
|
99
|
+
</body>
|
|
100
|
+
</html>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Features
|
|
106
|
+
|
|
107
|
+
| Feature | Description |
|
|
108
|
+
| -------------------- | --------------------------------------------------------- |
|
|
109
|
+
| **View Transitions** | Automatic page tracking with Astro's View Transitions API |
|
|
110
|
+
| **Zero Config** | Works out of the box with sensible defaults |
|
|
111
|
+
| **Astro 3, 4, 5** | Compatible with all modern Astro versions |
|
|
112
|
+
| **TypeScript** | Full type definitions included |
|
|
113
|
+
| **Consent Mode v2** | Built-in GDPR compliance support |
|
|
114
|
+
| **SSR Safe** | Works with static and SSR modes |
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Components
|
|
119
|
+
|
|
120
|
+
### `<GtmHead />`
|
|
121
|
+
|
|
122
|
+
All-in-one component for the `<head>` section. Includes script loading, consent setup, and optional page tracking.
|
|
123
|
+
|
|
124
|
+
```astro
|
|
125
|
+
<GtmHead
|
|
126
|
+
containers="GTM-XXXXXX"
|
|
127
|
+
enablePageTracking
|
|
128
|
+
defaultConsent={{
|
|
129
|
+
ad_storage: 'denied',
|
|
130
|
+
analytics_storage: 'denied'
|
|
131
|
+
}}
|
|
132
|
+
pageViewEventName="page_view"
|
|
133
|
+
/>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### Props
|
|
137
|
+
|
|
138
|
+
| Prop | Type | Default | Description |
|
|
139
|
+
| -------------------- | -------------------- | ---------------------------------- | ------------------------------- |
|
|
140
|
+
| `containers` | `string \| string[]` | Required | GTM container ID(s) |
|
|
141
|
+
| `host` | `string` | `https://www.googletagmanager.com` | Custom GTM host |
|
|
142
|
+
| `dataLayerName` | `string` | `dataLayer` | Custom dataLayer name |
|
|
143
|
+
| `defaultConsent` | `ConsentState` | - | Default consent state |
|
|
144
|
+
| `enablePageTracking` | `boolean` | `false` | Enable automatic page tracking |
|
|
145
|
+
| `pageViewEventName` | `string` | `page_view` | Custom page view event name |
|
|
146
|
+
| `scriptAttributes` | `object` | - | Script attributes (nonce, etc.) |
|
|
147
|
+
|
|
148
|
+
### `<GtmScript />`
|
|
149
|
+
|
|
150
|
+
Generates GTM script tags for the `<head>`.
|
|
151
|
+
|
|
152
|
+
```astro
|
|
153
|
+
<GtmScript
|
|
154
|
+
containers="GTM-XXXXXX"
|
|
155
|
+
scriptAttributes={{ nonce: 'abc123' }}
|
|
156
|
+
/>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### `<GtmNoScript />`
|
|
160
|
+
|
|
161
|
+
Generates noscript iframe fallback for the `<body>`.
|
|
162
|
+
|
|
163
|
+
```astro
|
|
164
|
+
<GtmNoScript containers="GTM-XXXXXX" />
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Client-Side API
|
|
170
|
+
|
|
171
|
+
### `initGtm(options)`
|
|
172
|
+
|
|
173
|
+
Initialize GTM on the client side.
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
import { initGtm } from '@jwiedeman/gtm-kit-astro';
|
|
177
|
+
|
|
178
|
+
initGtm({
|
|
179
|
+
containers: 'GTM-XXXXXX',
|
|
180
|
+
dataLayerName: 'dataLayer'
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### `push(data)`
|
|
185
|
+
|
|
186
|
+
Push data to the dataLayer.
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
import { push } from '@jwiedeman/gtm-kit-astro';
|
|
190
|
+
|
|
191
|
+
push({ event: 'button_click', button_id: 'cta-main' });
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### `setupPageTracking(options)`
|
|
195
|
+
|
|
196
|
+
Set up automatic page view tracking. Works with Astro's View Transitions.
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { setupPageTracking } from '@jwiedeman/gtm-kit-astro';
|
|
200
|
+
|
|
201
|
+
setupPageTracking({
|
|
202
|
+
eventName: 'page_view' // Optional, defaults to 'page_view'
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### `setupViewTransitions(options)`
|
|
207
|
+
|
|
208
|
+
Alias for `setupPageTracking`. Sets up tracking for View Transitions API.
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
import { setupViewTransitions } from '@jwiedeman/gtm-kit-astro';
|
|
212
|
+
|
|
213
|
+
setupViewTransitions({ eventName: 'virtual_page_view' });
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### `trackPageView(options)`
|
|
217
|
+
|
|
218
|
+
Manually track a page view.
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
import { trackPageView } from '@jwiedeman/gtm-kit-astro';
|
|
222
|
+
|
|
223
|
+
trackPageView({
|
|
224
|
+
eventName: 'page_view',
|
|
225
|
+
pagePath: '/custom-path',
|
|
226
|
+
pageTitle: 'Custom Title'
|
|
227
|
+
});
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Consent Mode v2 (GDPR)
|
|
233
|
+
|
|
234
|
+
### Setting Default Consent
|
|
235
|
+
|
|
236
|
+
```astro
|
|
237
|
+
<GtmHead
|
|
238
|
+
containers="GTM-XXXXXX"
|
|
239
|
+
defaultConsent={{
|
|
240
|
+
ad_storage: 'denied',
|
|
241
|
+
ad_user_data: 'denied',
|
|
242
|
+
ad_personalization: 'denied',
|
|
243
|
+
analytics_storage: 'denied'
|
|
244
|
+
}}
|
|
245
|
+
/>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Updating Consent After User Choice
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
import { updateConsent } from '@jwiedeman/gtm-kit-astro';
|
|
252
|
+
|
|
253
|
+
// User accepts analytics
|
|
254
|
+
updateConsent({
|
|
255
|
+
analytics_storage: 'granted'
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// User accepts all
|
|
259
|
+
updateConsent({
|
|
260
|
+
ad_storage: 'granted',
|
|
261
|
+
ad_user_data: 'granted',
|
|
262
|
+
ad_personalization: 'granted',
|
|
263
|
+
analytics_storage: 'granted'
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## View Transitions Integration
|
|
270
|
+
|
|
271
|
+
GTM Kit automatically tracks page views when using Astro's View Transitions. Just enable page tracking:
|
|
272
|
+
|
|
273
|
+
```astro
|
|
274
|
+
---
|
|
275
|
+
import { GtmHead } from '@jwiedeman/gtm-kit-astro/components';
|
|
276
|
+
import { ViewTransitions } from 'astro:transitions';
|
|
277
|
+
---
|
|
278
|
+
<html>
|
|
279
|
+
<head>
|
|
280
|
+
<ViewTransitions />
|
|
281
|
+
<GtmHead
|
|
282
|
+
containers="GTM-XXXXXX"
|
|
283
|
+
enablePageTracking
|
|
284
|
+
/>
|
|
285
|
+
</head>
|
|
286
|
+
<body>
|
|
287
|
+
<slot />
|
|
288
|
+
</body>
|
|
289
|
+
</html>
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Page views are automatically tracked on:
|
|
293
|
+
|
|
294
|
+
- Initial page load
|
|
295
|
+
- Client-side navigation via View Transitions
|
|
296
|
+
- Browser back/forward navigation
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Multiple Containers
|
|
301
|
+
|
|
302
|
+
```astro
|
|
303
|
+
<GtmHead
|
|
304
|
+
containers={['GTM-XXXXXX', 'GTM-YYYYYY']}
|
|
305
|
+
enablePageTracking
|
|
306
|
+
/>
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## CSP (Content Security Policy)
|
|
312
|
+
|
|
313
|
+
```astro
|
|
314
|
+
<GtmHead
|
|
315
|
+
containers="GTM-XXXXXX"
|
|
316
|
+
scriptAttributes={{ nonce: 'your-nonce-value' }}
|
|
317
|
+
/>
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## Requirements
|
|
323
|
+
|
|
324
|
+
- Astro 3.0+, 4.0+, or 5.0+
|
|
325
|
+
- `@jwiedeman/gtm-kit` (peer dependency)
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## License
|
|
330
|
+
|
|
331
|
+
MIT
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var gtmKit = require('@jwiedeman/gtm-kit');
|
|
4
|
+
|
|
5
|
+
var h=r=>{let{containers:s,host:c=gtmKit.DEFAULT_GTM_HOST,defaultQueryParams:g,scriptAttributes:e,dataLayerName:d=gtmKit.DEFAULT_DATA_LAYER_NAME}=r,i=gtmKit.normalizeContainers(s);if(!i.length)throw new Error("At least one GTM container is required.");return i.map(t=>{if(!t.id)throw new Error("Container id is required.");let p={...g,...t.queryParams},u=gtmKit.buildGtmScriptUrl(c,t.id,p,d),{async:n,defer:a,nonce:l,...o}=e!=null?e:{},T={};for(let[y,m]of Object.entries(o))m!=null&&(T[y]=m);return {id:t.id,src:u,async:n!=null?n:!0,defer:a,nonce:l,attributes:T}})},w={height:"0",width:"0",style:"display:none;visibility:hidden",title:"Google Tag Manager"},D=r=>{let{containers:s,host:c=gtmKit.DEFAULT_GTM_HOST,defaultQueryParams:g,iframeAttributes:e,dataLayerName:d=gtmKit.DEFAULT_DATA_LAYER_NAME}=r,i=gtmKit.normalizeContainers(s);if(!i.length)throw new Error("At least one GTM container is required.");return i.map(t=>{if(!t.id)throw new Error("Container id is required.");let p={...g,...t.queryParams},u=gtmKit.buildGtmNoscriptUrl(c,t.id,p,d),n={...w,...e},a={};for(let[l,o]of Object.entries(n))o!=null&&(a[l]=String(o));return {id:t.id,src:u,attributes:a}})},G=(r=gtmKit.DEFAULT_DATA_LAYER_NAME)=>`window.${r}=window.${r}||[];`;
|
|
6
|
+
|
|
7
|
+
Object.defineProperty(exports, 'DEFAULT_GTM_HOST', {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () { return gtmKit.DEFAULT_GTM_HOST; }
|
|
10
|
+
});
|
|
11
|
+
Object.defineProperty(exports, 'buildNoscriptUrl', {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () { return gtmKit.buildGtmNoscriptUrl; }
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(exports, 'buildScriptUrl', {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return gtmKit.buildGtmScriptUrl; }
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports, 'normalizeContainer', {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () { return gtmKit.normalizeContainer; }
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(exports, 'normalizeContainers', {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function () { return gtmKit.normalizeContainers; }
|
|
26
|
+
});
|
|
27
|
+
exports.generateDataLayerScript = G;
|
|
28
|
+
exports.generateNoscriptTags = D;
|
|
29
|
+
exports.generateScriptTags = h;
|
|
30
|
+
//# sourceMappingURL=out.js.map
|
|
31
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/helpers.ts","../../src/components/index.ts"],"names":["DEFAULT_DATA_LAYER_NAME","DEFAULT_GTM_HOST","normalizeContainer","normalizeContainers","buildGtmScriptUrl","buildGtmNoscriptUrl","generateScriptTags","config","containers","host","defaultQueryParams","scriptAttributes","dataLayerName","normalized","container","params","src","asyncAttr","defer","nonce","restAttributes","attributes","key","value","DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES","generateNoscriptTags","iframeAttributes","mergedAttributes","generateDataLayerScript"],"mappings":"AAAA,OACE,2BAAAA,EACA,oBAAAC,EACA,sBAAAC,EACA,uBAAAC,EACA,qBAAAC,EACA,uBAAAC,MACK,qBAiCA,IAAMC,EAAsBC,GAA6C,CAC9E,GAAM,CACJ,WAAAC,EACA,KAAAC,EAAOR,EACP,mBAAAS,EACA,iBAAAC,EACA,cAAAC,EAAgBZ,CAClB,EAAIO,EAEEM,EAAaV,EAAoBK,CAAU,EAEjD,GAAI,CAACK,EAAW,OACd,MAAM,IAAI,MAAM,yCAAyC,EAG3D,OAAOA,EAAW,IAAKC,GAAc,CACnC,GAAI,CAACA,EAAU,GACb,MAAM,IAAI,MAAM,2BAA2B,EAG7C,IAAMC,EAAS,CACb,GAAGL,EACH,GAAGI,EAAU,WACf,EAEME,EAAMZ,EAAkBK,EAAMK,EAAU,GAAIC,EAAQH,CAAa,EACjE,CAAE,MAAOK,EAAW,MAAAC,EAAO,MAAAC,EAAO,GAAGC,CAAe,EAAIT,GAAA,KAAAA,EAAoB,CAAC,EAE7EU,EAA+C,CAAC,EAEtD,OAAW,CAACC,EAAKC,CAAK,IAAK,OAAO,QAAQH,CAAc,EAC3BG,GAAU,OACnCF,EAAWC,CAAG,EAAIC,GAItB,MAAO,CACL,GAAIT,EAAU,GACd,IAAAE,EACA,MAAOC,GAAA,KAAAA,EAAa,GACpB,MAAAC,EACA,MAAAC,EACA,WAAAE,CACF,CACF,CAAC,CACH,EAQMG,EAA6D,CACjE,OAAQ,IACR,MAAO,IACP,MAAO,iCACP,MAAO,oBACT,EAMaC,EACXlB,GAGsB,CACtB,GAAM,CACJ,WAAAC,EACA,KAAAC,EAAOR,EACP,mBAAAS,EACA,iBAAAgB,EACA,cAAAd,EAAgBZ,CAClB,EAAIO,EAEEM,EAAaV,EAAoBK,CAAU,EAEjD,GAAI,CAACK,EAAW,OACd,MAAM,IAAI,MAAM,yCAAyC,EAG3D,OAAOA,EAAW,IAAKC,GAAc,CACnC,GAAI,CAACA,EAAU,GACb,MAAM,IAAI,MAAM,2BAA2B,EAG7C,IAAMC,EAAS,CACb,GAAGL,EACH,GAAGI,EAAU,WACf,EAEME,EAAMX,EAAoBI,EAAMK,EAAU,GAAIC,EAAQH,CAAa,EACnEe,EAAmB,CACvB,GAAGH,EACH,GAAGE,CACL,EAEML,EAAqC,CAAC,EAC5C,OAAW,CAACC,EAAKC,CAAK,IAAK,OAAO,QAAQI,CAAgB,EAC7BJ,GAAU,OACnCF,EAAWC,CAAG,EAAI,OAAOC,CAAK,GAIlC,MAAO,CACL,GAAIT,EAAU,GACd,IAAAE,EACA,WAAAK,CACF,CACF,CAAC,CACH,EAKaO,EAA0B,CAAChB,EAAwBZ,IACvD,UAAUY,CAAa,WAAWA,CAAa,QC3JxD,OACE,uBAAAT,EACA,sBAAAD,EACqB,qBAArBE,EACuB,uBAAvBC,MACK","sourcesContent":["import {\n DEFAULT_DATA_LAYER_NAME,\n DEFAULT_GTM_HOST,\n normalizeContainer,\n normalizeContainers,\n buildGtmScriptUrl,\n buildGtmNoscriptUrl\n} from '@jwiedeman/gtm-kit';\nimport type { ContainerConfigInput, ScriptAttributes } from '@jwiedeman/gtm-kit';\n\n// Re-export for convenience\nexport {\n DEFAULT_GTM_HOST,\n normalizeContainer,\n normalizeContainers,\n buildGtmScriptUrl as buildScriptUrl,\n buildGtmNoscriptUrl as buildNoscriptUrl\n};\n\nexport interface GtmScriptConfig {\n containers: ContainerConfigInput | ContainerConfigInput[];\n host?: string;\n defaultQueryParams?: Record<string, string | number | boolean>;\n scriptAttributes?: ScriptAttributes;\n dataLayerName?: string;\n}\n\nexport interface ScriptTagData {\n id: string;\n src: string;\n async: boolean;\n defer?: boolean;\n nonce?: string;\n attributes: Record<string, string | boolean>;\n}\n\n/**\n * Generate script tag data for GTM containers.\n * Used by Astro components to render script tags.\n */\nexport const generateScriptTags = (config: GtmScriptConfig): ScriptTagData[] => {\n const {\n containers,\n host = DEFAULT_GTM_HOST,\n defaultQueryParams,\n scriptAttributes,\n dataLayerName = DEFAULT_DATA_LAYER_NAME\n } = config;\n\n const normalized = normalizeContainers(containers);\n\n if (!normalized.length) {\n throw new Error('At least one GTM container is required.');\n }\n\n return normalized.map((container) => {\n if (!container.id) {\n throw new Error('Container id is required.');\n }\n\n const params = {\n ...defaultQueryParams,\n ...container.queryParams\n };\n\n const src = buildGtmScriptUrl(host, container.id, params, dataLayerName);\n const { async: asyncAttr, defer, nonce, ...restAttributes } = scriptAttributes ?? {};\n\n const attributes: Record<string, string | boolean> = {};\n\n for (const [key, value] of Object.entries(restAttributes)) {\n if (value !== undefined && value !== null) {\n attributes[key] = value;\n }\n }\n\n return {\n id: container.id,\n src,\n async: asyncAttr ?? true,\n defer,\n nonce,\n attributes\n };\n });\n};\n\nexport interface NoscriptTagData {\n id: string;\n src: string;\n attributes: Record<string, string>;\n}\n\nconst DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES: Record<string, string> = {\n height: '0',\n width: '0',\n style: 'display:none;visibility:hidden',\n title: 'Google Tag Manager'\n};\n\n/**\n * Generate noscript iframe data for GTM containers.\n * Used by Astro components to render noscript fallbacks.\n */\nexport const generateNoscriptTags = (\n config: Omit<GtmScriptConfig, 'scriptAttributes'> & {\n iframeAttributes?: Record<string, string | number | boolean>;\n }\n): NoscriptTagData[] => {\n const {\n containers,\n host = DEFAULT_GTM_HOST,\n defaultQueryParams,\n iframeAttributes,\n dataLayerName = DEFAULT_DATA_LAYER_NAME\n } = config;\n\n const normalized = normalizeContainers(containers);\n\n if (!normalized.length) {\n throw new Error('At least one GTM container is required.');\n }\n\n return normalized.map((container) => {\n if (!container.id) {\n throw new Error('Container id is required.');\n }\n\n const params = {\n ...defaultQueryParams,\n ...container.queryParams\n };\n\n const src = buildGtmNoscriptUrl(host, container.id, params, dataLayerName);\n const mergedAttributes = {\n ...DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,\n ...iframeAttributes\n };\n\n const attributes: Record<string, string> = {};\n for (const [key, value] of Object.entries(mergedAttributes)) {\n if (value !== undefined && value !== null) {\n attributes[key] = String(value);\n }\n }\n\n return {\n id: container.id,\n src,\n attributes\n };\n });\n};\n\n/**\n * Generate the dataLayer initialization script.\n */\nexport const generateDataLayerScript = (dataLayerName: string = DEFAULT_DATA_LAYER_NAME): string => {\n return `window.${dataLayerName}=window.${dataLayerName}||[];`;\n};\n","export { generateScriptTags, generateNoscriptTags, generateDataLayerScript, DEFAULT_GTM_HOST } from './helpers';\n\n// Re-export URL utilities from core for backwards compatibility\nexport {\n normalizeContainers,\n normalizeContainer,\n buildGtmScriptUrl as buildScriptUrl,\n buildGtmNoscriptUrl as buildNoscriptUrl\n} from '@jwiedeman/gtm-kit';\n\nexport type { GtmScriptConfig, ScriptTagData, NoscriptTagData } from './helpers';\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ContainerConfigInput, ScriptAttributes } from '@jwiedeman/gtm-kit';
|
|
2
|
+
export { DEFAULT_GTM_HOST, buildGtmNoscriptUrl as buildNoscriptUrl, buildGtmScriptUrl as buildScriptUrl, normalizeContainer, normalizeContainers } from '@jwiedeman/gtm-kit';
|
|
3
|
+
|
|
4
|
+
interface GtmScriptConfig {
|
|
5
|
+
containers: ContainerConfigInput | ContainerConfigInput[];
|
|
6
|
+
host?: string;
|
|
7
|
+
defaultQueryParams?: Record<string, string | number | boolean>;
|
|
8
|
+
scriptAttributes?: ScriptAttributes;
|
|
9
|
+
dataLayerName?: string;
|
|
10
|
+
}
|
|
11
|
+
interface ScriptTagData {
|
|
12
|
+
id: string;
|
|
13
|
+
src: string;
|
|
14
|
+
async: boolean;
|
|
15
|
+
defer?: boolean;
|
|
16
|
+
nonce?: string;
|
|
17
|
+
attributes: Record<string, string | boolean>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Generate script tag data for GTM containers.
|
|
21
|
+
* Used by Astro components to render script tags.
|
|
22
|
+
*/
|
|
23
|
+
declare const generateScriptTags: (config: GtmScriptConfig) => ScriptTagData[];
|
|
24
|
+
interface NoscriptTagData {
|
|
25
|
+
id: string;
|
|
26
|
+
src: string;
|
|
27
|
+
attributes: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Generate noscript iframe data for GTM containers.
|
|
31
|
+
* Used by Astro components to render noscript fallbacks.
|
|
32
|
+
*/
|
|
33
|
+
declare const generateNoscriptTags: (config: Omit<GtmScriptConfig, 'scriptAttributes'> & {
|
|
34
|
+
iframeAttributes?: Record<string, string | number | boolean>;
|
|
35
|
+
}) => NoscriptTagData[];
|
|
36
|
+
/**
|
|
37
|
+
* Generate the dataLayer initialization script.
|
|
38
|
+
*/
|
|
39
|
+
declare const generateDataLayerScript: (dataLayerName?: string) => string;
|
|
40
|
+
|
|
41
|
+
export { GtmScriptConfig, NoscriptTagData, ScriptTagData, generateDataLayerScript, generateNoscriptTags, generateScriptTags };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ContainerConfigInput, ScriptAttributes } from '@jwiedeman/gtm-kit';
|
|
2
|
+
export { DEFAULT_GTM_HOST, buildGtmNoscriptUrl as buildNoscriptUrl, buildGtmScriptUrl as buildScriptUrl, normalizeContainer, normalizeContainers } from '@jwiedeman/gtm-kit';
|
|
3
|
+
|
|
4
|
+
interface GtmScriptConfig {
|
|
5
|
+
containers: ContainerConfigInput | ContainerConfigInput[];
|
|
6
|
+
host?: string;
|
|
7
|
+
defaultQueryParams?: Record<string, string | number | boolean>;
|
|
8
|
+
scriptAttributes?: ScriptAttributes;
|
|
9
|
+
dataLayerName?: string;
|
|
10
|
+
}
|
|
11
|
+
interface ScriptTagData {
|
|
12
|
+
id: string;
|
|
13
|
+
src: string;
|
|
14
|
+
async: boolean;
|
|
15
|
+
defer?: boolean;
|
|
16
|
+
nonce?: string;
|
|
17
|
+
attributes: Record<string, string | boolean>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Generate script tag data for GTM containers.
|
|
21
|
+
* Used by Astro components to render script tags.
|
|
22
|
+
*/
|
|
23
|
+
declare const generateScriptTags: (config: GtmScriptConfig) => ScriptTagData[];
|
|
24
|
+
interface NoscriptTagData {
|
|
25
|
+
id: string;
|
|
26
|
+
src: string;
|
|
27
|
+
attributes: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Generate noscript iframe data for GTM containers.
|
|
31
|
+
* Used by Astro components to render noscript fallbacks.
|
|
32
|
+
*/
|
|
33
|
+
declare const generateNoscriptTags: (config: Omit<GtmScriptConfig, 'scriptAttributes'> & {
|
|
34
|
+
iframeAttributes?: Record<string, string | number | boolean>;
|
|
35
|
+
}) => NoscriptTagData[];
|
|
36
|
+
/**
|
|
37
|
+
* Generate the dataLayer initialization script.
|
|
38
|
+
*/
|
|
39
|
+
declare const generateDataLayerScript: (dataLayerName?: string) => string;
|
|
40
|
+
|
|
41
|
+
export { GtmScriptConfig, NoscriptTagData, ScriptTagData, generateDataLayerScript, generateNoscriptTags, generateScriptTags };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { normalizeContainers, buildGtmScriptUrl, buildGtmNoscriptUrl, DEFAULT_DATA_LAYER_NAME, DEFAULT_GTM_HOST } from '@jwiedeman/gtm-kit';
|
|
2
|
+
export { DEFAULT_GTM_HOST, buildGtmNoscriptUrl as buildNoscriptUrl, buildGtmScriptUrl as buildScriptUrl, normalizeContainer, normalizeContainers } from '@jwiedeman/gtm-kit';
|
|
3
|
+
|
|
4
|
+
var h=r=>{let{containers:s,host:c=DEFAULT_GTM_HOST,defaultQueryParams:g,scriptAttributes:e,dataLayerName:d=DEFAULT_DATA_LAYER_NAME}=r,i=normalizeContainers(s);if(!i.length)throw new Error("At least one GTM container is required.");return i.map(t=>{if(!t.id)throw new Error("Container id is required.");let p={...g,...t.queryParams},u=buildGtmScriptUrl(c,t.id,p,d),{async:n,defer:a,nonce:l,...o}=e!=null?e:{},T={};for(let[y,m]of Object.entries(o))m!=null&&(T[y]=m);return {id:t.id,src:u,async:n!=null?n:!0,defer:a,nonce:l,attributes:T}})},w={height:"0",width:"0",style:"display:none;visibility:hidden",title:"Google Tag Manager"},D=r=>{let{containers:s,host:c=DEFAULT_GTM_HOST,defaultQueryParams:g,iframeAttributes:e,dataLayerName:d=DEFAULT_DATA_LAYER_NAME}=r,i=normalizeContainers(s);if(!i.length)throw new Error("At least one GTM container is required.");return i.map(t=>{if(!t.id)throw new Error("Container id is required.");let p={...g,...t.queryParams},u=buildGtmNoscriptUrl(c,t.id,p,d),n={...w,...e},a={};for(let[l,o]of Object.entries(n))o!=null&&(a[l]=String(o));return {id:t.id,src:u,attributes:a}})},G=(r=DEFAULT_DATA_LAYER_NAME)=>`window.${r}=window.${r}||[];`;
|
|
5
|
+
|
|
6
|
+
export { G as generateDataLayerScript, D as generateNoscriptTags, h as generateScriptTags };
|
|
7
|
+
//# sourceMappingURL=out.js.map
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/helpers.ts","../../src/components/index.ts"],"names":["DEFAULT_DATA_LAYER_NAME","DEFAULT_GTM_HOST","normalizeContainer","normalizeContainers","buildGtmScriptUrl","buildGtmNoscriptUrl","generateScriptTags","config","containers","host","defaultQueryParams","scriptAttributes","dataLayerName","normalized","container","params","src","asyncAttr","defer","nonce","restAttributes","attributes","key","value","DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES","generateNoscriptTags","iframeAttributes","mergedAttributes","generateDataLayerScript"],"mappings":"AAAA,OACE,2BAAAA,EACA,oBAAAC,EACA,sBAAAC,EACA,uBAAAC,EACA,qBAAAC,EACA,uBAAAC,MACK,qBAiCA,IAAMC,EAAsBC,GAA6C,CAC9E,GAAM,CACJ,WAAAC,EACA,KAAAC,EAAOR,EACP,mBAAAS,EACA,iBAAAC,EACA,cAAAC,EAAgBZ,CAClB,EAAIO,EAEEM,EAAaV,EAAoBK,CAAU,EAEjD,GAAI,CAACK,EAAW,OACd,MAAM,IAAI,MAAM,yCAAyC,EAG3D,OAAOA,EAAW,IAAKC,GAAc,CACnC,GAAI,CAACA,EAAU,GACb,MAAM,IAAI,MAAM,2BAA2B,EAG7C,IAAMC,EAAS,CACb,GAAGL,EACH,GAAGI,EAAU,WACf,EAEME,EAAMZ,EAAkBK,EAAMK,EAAU,GAAIC,EAAQH,CAAa,EACjE,CAAE,MAAOK,EAAW,MAAAC,EAAO,MAAAC,EAAO,GAAGC,CAAe,EAAIT,GAAA,KAAAA,EAAoB,CAAC,EAE7EU,EAA+C,CAAC,EAEtD,OAAW,CAACC,EAAKC,CAAK,IAAK,OAAO,QAAQH,CAAc,EAC3BG,GAAU,OACnCF,EAAWC,CAAG,EAAIC,GAItB,MAAO,CACL,GAAIT,EAAU,GACd,IAAAE,EACA,MAAOC,GAAA,KAAAA,EAAa,GACpB,MAAAC,EACA,MAAAC,EACA,WAAAE,CACF,CACF,CAAC,CACH,EAQMG,EAA6D,CACjE,OAAQ,IACR,MAAO,IACP,MAAO,iCACP,MAAO,oBACT,EAMaC,EACXlB,GAGsB,CACtB,GAAM,CACJ,WAAAC,EACA,KAAAC,EAAOR,EACP,mBAAAS,EACA,iBAAAgB,EACA,cAAAd,EAAgBZ,CAClB,EAAIO,EAEEM,EAAaV,EAAoBK,CAAU,EAEjD,GAAI,CAACK,EAAW,OACd,MAAM,IAAI,MAAM,yCAAyC,EAG3D,OAAOA,EAAW,IAAKC,GAAc,CACnC,GAAI,CAACA,EAAU,GACb,MAAM,IAAI,MAAM,2BAA2B,EAG7C,IAAMC,EAAS,CACb,GAAGL,EACH,GAAGI,EAAU,WACf,EAEME,EAAMX,EAAoBI,EAAMK,EAAU,GAAIC,EAAQH,CAAa,EACnEe,EAAmB,CACvB,GAAGH,EACH,GAAGE,CACL,EAEML,EAAqC,CAAC,EAC5C,OAAW,CAACC,EAAKC,CAAK,IAAK,OAAO,QAAQI,CAAgB,EAC7BJ,GAAU,OACnCF,EAAWC,CAAG,EAAI,OAAOC,CAAK,GAIlC,MAAO,CACL,GAAIT,EAAU,GACd,IAAAE,EACA,WAAAK,CACF,CACF,CAAC,CACH,EAKaO,EAA0B,CAAChB,EAAwBZ,IACvD,UAAUY,CAAa,WAAWA,CAAa,QC3JxD,OACE,uBAAAT,EACA,sBAAAD,EACqB,qBAArBE,EACuB,uBAAvBC,MACK","sourcesContent":["import {\n DEFAULT_DATA_LAYER_NAME,\n DEFAULT_GTM_HOST,\n normalizeContainer,\n normalizeContainers,\n buildGtmScriptUrl,\n buildGtmNoscriptUrl\n} from '@jwiedeman/gtm-kit';\nimport type { ContainerConfigInput, ScriptAttributes } from '@jwiedeman/gtm-kit';\n\n// Re-export for convenience\nexport {\n DEFAULT_GTM_HOST,\n normalizeContainer,\n normalizeContainers,\n buildGtmScriptUrl as buildScriptUrl,\n buildGtmNoscriptUrl as buildNoscriptUrl\n};\n\nexport interface GtmScriptConfig {\n containers: ContainerConfigInput | ContainerConfigInput[];\n host?: string;\n defaultQueryParams?: Record<string, string | number | boolean>;\n scriptAttributes?: ScriptAttributes;\n dataLayerName?: string;\n}\n\nexport interface ScriptTagData {\n id: string;\n src: string;\n async: boolean;\n defer?: boolean;\n nonce?: string;\n attributes: Record<string, string | boolean>;\n}\n\n/**\n * Generate script tag data for GTM containers.\n * Used by Astro components to render script tags.\n */\nexport const generateScriptTags = (config: GtmScriptConfig): ScriptTagData[] => {\n const {\n containers,\n host = DEFAULT_GTM_HOST,\n defaultQueryParams,\n scriptAttributes,\n dataLayerName = DEFAULT_DATA_LAYER_NAME\n } = config;\n\n const normalized = normalizeContainers(containers);\n\n if (!normalized.length) {\n throw new Error('At least one GTM container is required.');\n }\n\n return normalized.map((container) => {\n if (!container.id) {\n throw new Error('Container id is required.');\n }\n\n const params = {\n ...defaultQueryParams,\n ...container.queryParams\n };\n\n const src = buildGtmScriptUrl(host, container.id, params, dataLayerName);\n const { async: asyncAttr, defer, nonce, ...restAttributes } = scriptAttributes ?? {};\n\n const attributes: Record<string, string | boolean> = {};\n\n for (const [key, value] of Object.entries(restAttributes)) {\n if (value !== undefined && value !== null) {\n attributes[key] = value;\n }\n }\n\n return {\n id: container.id,\n src,\n async: asyncAttr ?? true,\n defer,\n nonce,\n attributes\n };\n });\n};\n\nexport interface NoscriptTagData {\n id: string;\n src: string;\n attributes: Record<string, string>;\n}\n\nconst DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES: Record<string, string> = {\n height: '0',\n width: '0',\n style: 'display:none;visibility:hidden',\n title: 'Google Tag Manager'\n};\n\n/**\n * Generate noscript iframe data for GTM containers.\n * Used by Astro components to render noscript fallbacks.\n */\nexport const generateNoscriptTags = (\n config: Omit<GtmScriptConfig, 'scriptAttributes'> & {\n iframeAttributes?: Record<string, string | number | boolean>;\n }\n): NoscriptTagData[] => {\n const {\n containers,\n host = DEFAULT_GTM_HOST,\n defaultQueryParams,\n iframeAttributes,\n dataLayerName = DEFAULT_DATA_LAYER_NAME\n } = config;\n\n const normalized = normalizeContainers(containers);\n\n if (!normalized.length) {\n throw new Error('At least one GTM container is required.');\n }\n\n return normalized.map((container) => {\n if (!container.id) {\n throw new Error('Container id is required.');\n }\n\n const params = {\n ...defaultQueryParams,\n ...container.queryParams\n };\n\n const src = buildGtmNoscriptUrl(host, container.id, params, dataLayerName);\n const mergedAttributes = {\n ...DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,\n ...iframeAttributes\n };\n\n const attributes: Record<string, string> = {};\n for (const [key, value] of Object.entries(mergedAttributes)) {\n if (value !== undefined && value !== null) {\n attributes[key] = String(value);\n }\n }\n\n return {\n id: container.id,\n src,\n attributes\n };\n });\n};\n\n/**\n * Generate the dataLayer initialization script.\n */\nexport const generateDataLayerScript = (dataLayerName: string = DEFAULT_DATA_LAYER_NAME): string => {\n return `window.${dataLayerName}=window.${dataLayerName}||[];`;\n};\n","export { generateScriptTags, generateNoscriptTags, generateDataLayerScript, DEFAULT_GTM_HOST } from './helpers';\n\n// Re-export URL utilities from core for backwards compatibility\nexport {\n normalizeContainers,\n normalizeContainer,\n buildGtmScriptUrl as buildScriptUrl,\n buildGtmNoscriptUrl as buildNoscriptUrl\n} from '@jwiedeman/gtm-kit';\n\nexport type { GtmScriptConfig, ScriptTagData, NoscriptTagData } from './helpers';\n"]}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var gtmKit = require('@jwiedeman/gtm-kit');
|
|
4
|
+
|
|
5
|
+
var o=null,r=null,f=e=>o||(o=gtmKit.createGtmClient(e),r=e,o.init(),o),i=()=>o,m=()=>{if(!o)throw new Error("[gtm-kit/astro] GTM client not initialized. Call initGtm() first or ensure the GTM script has loaded.");return o},p=e=>{var t;let n=i();if(n)return n.push(e),!0;if(typeof window!="undefined"){let c=(t=r==null?void 0:r.dataLayerName)!=null?t:"dataLayer",l=window[c];return Array.isArray(l)?(l.push(e),!0):(console.warn("[gtm-kit/astro] GTM not initialized and dataLayer not found."),!1)}return !1},C=(e,n)=>{let t=i();return t?(t.setConsentDefaults(e,n),!0):(console.warn("[gtm-kit/astro] GTM not initialized. Consent defaults should be set before init."),!1)},y=(e,n)=>{let t=i();return t?(t.updateConsent(e,n),!0):(console.warn("[gtm-kit/astro] GTM not initialized. Cannot update consent."),!1)},h=()=>{let e=i();return e?e.whenReady():Promise.reject(new Error("[gtm-kit/astro] GTM not initialized."))},k=()=>{o&&(o.teardown(),o=null,r=null);};var d=()=>{},P=e=>typeof e=="function"?e():e!=null?e:{},s=(e={})=>{let{eventName:n="page_view",includeQueryParams:t=!0,additionalData:c}=e;if(typeof window=="undefined")return;let w=t?window.location.pathname+window.location.search:window.location.pathname,l={event:n,page_path:w,page_location:window.location.href,page_title:document.title,...P(c)};p(l);},u=!1,a="";var G=(e={})=>{if(typeof window=="undefined"||typeof document=="undefined"||u)return d;u=!0,a=window.location.pathname+window.location.search,s(e);let n=()=>{let t=window.location.pathname+window.location.search;t!==a&&(a=t,s(e));};return document.addEventListener("astro:page-load",n),()=>{document.removeEventListener("astro:page-load",n),u=!1,a="";}},x=(e={})=>{if(typeof window=="undefined")return d;a=window.location.pathname+window.location.search,s(e);let n=()=>{let t=window.location.pathname+window.location.search;t!==a&&(a=t,s(e));};return window.addEventListener("popstate",n),()=>{window.removeEventListener("popstate",n),a="";}};
|
|
6
|
+
|
|
7
|
+
Object.defineProperty(exports, 'allGranted', {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () { return gtmKit.allGranted; }
|
|
10
|
+
});
|
|
11
|
+
Object.defineProperty(exports, 'analyticsOnly', {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () { return gtmKit.analyticsOnly; }
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(exports, 'consentPresets', {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return gtmKit.consentPresets; }
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports, 'eeaDefault', {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () { return gtmKit.eeaDefault; }
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(exports, 'getConsentPreset', {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function () { return gtmKit.getConsentPreset; }
|
|
26
|
+
});
|
|
27
|
+
exports.getGtmClient = i;
|
|
28
|
+
exports.initGtm = f;
|
|
29
|
+
exports.push = p;
|
|
30
|
+
exports.requireGtmClient = m;
|
|
31
|
+
exports.setConsentDefaults = C;
|
|
32
|
+
exports.setupPageTracking = x;
|
|
33
|
+
exports.setupViewTransitions = G;
|
|
34
|
+
exports.teardown = k;
|
|
35
|
+
exports.trackPageView = s;
|
|
36
|
+
exports.updateConsent = y;
|
|
37
|
+
exports.whenReady = h;
|
|
38
|
+
//# sourceMappingURL=out.js.map
|
|
39
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/page-tracking.ts","../src/index.ts"],"names":["createGtmClient","clientInstance","clientConfig","initGtm","options","getGtmClient","requireGtmClient","push","value","_a","client","dataLayerName","dataLayer","setConsentDefaults","state","updateConsent","whenReady","teardown","noop","getAdditionalData","additionalData","trackPageView","eventName","includeQueryParams","pagePath","pageViewData","viewTransitionsSetup","lastTrackedPath","setupViewTransitions","handlePageLoad","currentPath","setupPageTracking","handlePopState","consentPresets","getConsentPreset","eeaDefault","allGranted","analyticsOnly"],"mappings":"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","sourcesContent":["import {\n createGtmClient,\n type ConsentRegionOptions,\n type ConsentState,\n type CreateGtmClientOptions,\n type DataLayerValue,\n type GtmClient,\n type ScriptLoadState\n} from '@jwiedeman/gtm-kit';\n\nlet clientInstance: GtmClient | null = null;\nlet clientConfig: CreateGtmClientOptions | null = null;\n\n/**\n * Initialize the GTM client for use in Astro.\n * Should be called once when the page loads.\n *\n * @example\n * ```ts\n * // In a client-side script\n * import { initGtm } from '@jwiedeman/gtm-kit-astro';\n *\n * initGtm({ containers: 'GTM-XXXXXX' });\n * ```\n */\nexport const initGtm = (options: CreateGtmClientOptions): GtmClient => {\n // If already initialized, return existing instance\n // (common in Astro with view transitions where initGtm may be called multiple times)\n if (clientInstance) {\n return clientInstance;\n }\n\n clientInstance = createGtmClient(options);\n clientConfig = options;\n clientInstance.init();\n\n return clientInstance;\n};\n\n/**\n * Get the current GTM client instance.\n * Returns null if not initialized.\n *\n * @example\n * ```ts\n * import { getGtmClient } from '@jwiedeman/gtm-kit-astro';\n *\n * const client = getGtmClient();\n * if (client) {\n * client.push({ event: 'page_view' });\n * }\n * ```\n */\nexport const getGtmClient = (): GtmClient | null => clientInstance;\n\n/**\n * Get the GTM client or throw if not initialized.\n * Use this when you expect the client to be available.\n *\n * @throws Error if GTM client is not initialized\n */\nexport const requireGtmClient = (): GtmClient => {\n if (!clientInstance) {\n throw new Error(\n '[gtm-kit/astro] GTM client not initialized. Call initGtm() first or ensure the GTM script has loaded.'\n );\n }\n return clientInstance;\n};\n\n/**\n * Push a value to the GTM dataLayer.\n * This is a convenience function that handles the case where GTM isn't initialized.\n *\n * @returns true if the value was pushed successfully, false otherwise\n *\n * @example\n * ```ts\n * import { push } from '@jwiedeman/gtm-kit-astro';\n *\n * const success = push({ event: 'button_click', button_name: 'hero_cta' });\n * if (!success) {\n * console.warn('GTM not ready');\n * }\n * ```\n */\nexport const push = (value: DataLayerValue): boolean => {\n const client = getGtmClient();\n if (client) {\n client.push(value);\n return true;\n } else if (typeof window !== 'undefined') {\n // Fallback: push directly to dataLayer if it exists\n const dataLayerName = clientConfig?.dataLayerName ?? 'dataLayer';\n const win = window as unknown as Record<string, unknown>;\n const dataLayer = win[dataLayerName] as DataLayerValue[] | undefined;\n if (Array.isArray(dataLayer)) {\n dataLayer.push(value);\n return true;\n } else {\n console.warn('[gtm-kit/astro] GTM not initialized and dataLayer not found.');\n return false;\n }\n }\n return false;\n};\n\n/**\n * Set consent defaults (must be called before GTM loads).\n *\n * @returns true if consent defaults were set, false if GTM not initialized\n *\n * @example\n * ```ts\n * import { setConsentDefaults } from '@jwiedeman/gtm-kit-astro';\n *\n * const success = setConsentDefaults({\n * ad_storage: 'denied',\n * analytics_storage: 'denied'\n * });\n * ```\n */\nexport const setConsentDefaults = (state: ConsentState, options?: ConsentRegionOptions): boolean => {\n const client = getGtmClient();\n if (client) {\n client.setConsentDefaults(state, options);\n return true;\n } else {\n console.warn('[gtm-kit/astro] GTM not initialized. Consent defaults should be set before init.');\n return false;\n }\n};\n\n/**\n * Update consent state after user interaction.\n *\n * @returns true if consent was updated, false if GTM not initialized\n *\n * @example\n * ```ts\n * import { updateConsent } from '@jwiedeman/gtm-kit-astro';\n *\n * // When user accepts cookies\n * const success = updateConsent({\n * ad_storage: 'granted',\n * analytics_storage: 'granted',\n * ad_user_data: 'granted',\n * ad_personalization: 'granted'\n * });\n * ```\n */\nexport const updateConsent = (state: ConsentState, options?: ConsentRegionOptions): boolean => {\n const client = getGtmClient();\n if (client) {\n client.updateConsent(state, options);\n return true;\n } else {\n console.warn('[gtm-kit/astro] GTM not initialized. Cannot update consent.');\n return false;\n }\n};\n\n/**\n * Wait for GTM scripts to be ready.\n *\n * @example\n * ```ts\n * import { whenReady } from '@jwiedeman/gtm-kit-astro';\n *\n * whenReady().then((states) => {\n * console.log('GTM loaded:', states);\n * });\n * ```\n */\nexport const whenReady = (): Promise<ScriptLoadState[]> => {\n const client = getGtmClient();\n if (client) {\n return client.whenReady();\n }\n return Promise.reject(new Error('[gtm-kit/astro] GTM not initialized.'));\n};\n\n/**\n * Clean up the GTM client.\n * Call this when navigating away or cleaning up.\n */\nexport const teardown = (): void => {\n if (clientInstance) {\n clientInstance.teardown();\n clientInstance = null;\n clientConfig = null;\n }\n};\n","import { push } from './client';\n\n// No-op function for SSR/cleanup returns\nconst noop = (): void => {\n /* no-op */\n};\n\nexport interface PageViewData {\n event?: string;\n page_path?: string;\n page_location?: string;\n page_title?: string;\n page_referrer?: string;\n [key: string]: unknown;\n}\n\nexport interface TrackPageViewOptions {\n /**\n * The event name to use for page views.\n * @default 'page_view'\n */\n eventName?: string;\n\n /**\n * Whether to include query parameters in the page path.\n * @default true\n */\n includeQueryParams?: boolean;\n\n /**\n * Additional data to include with each page view.\n */\n additionalData?: Record<string, unknown> | (() => Record<string, unknown>);\n}\n\nconst getAdditionalData = (additionalData: TrackPageViewOptions['additionalData']): Record<string, unknown> => {\n if (typeof additionalData === 'function') {\n return additionalData();\n }\n return additionalData ?? {};\n};\n\n/**\n * Track a page view event.\n *\n * @example\n * ```ts\n * import { trackPageView } from '@jwiedeman/gtm-kit-astro';\n *\n * // Track current page\n * trackPageView();\n *\n * // Track with custom data\n * trackPageView({\n * additionalData: { user_type: 'guest' }\n * });\n * ```\n */\nexport const trackPageView = (options: TrackPageViewOptions = {}): void => {\n const { eventName = 'page_view', includeQueryParams = true, additionalData } = options;\n\n if (typeof window === 'undefined') {\n return;\n }\n\n const pagePath = includeQueryParams ? window.location.pathname + window.location.search : window.location.pathname;\n\n const pageViewData: PageViewData = {\n event: eventName,\n page_path: pagePath,\n page_location: window.location.href,\n page_title: document.title,\n ...getAdditionalData(additionalData)\n };\n\n push(pageViewData);\n};\n\nlet viewTransitionsSetup = false;\nlet lastTrackedPath = '';\n\n/**\n * Reset page tracking state (for testing only).\n * @internal\n */\nexport const _resetPageTrackingState = (): void => {\n viewTransitionsSetup = false;\n lastTrackedPath = '';\n};\n\n/**\n * Set up automatic page view tracking with Astro View Transitions.\n * Call this once when the page loads.\n *\n * @example\n * ```astro\n * ---\n * // src/layouts/Layout.astro\n * ---\n * <script>\n * import { initGtm, setupViewTransitions } from '@jwiedeman/gtm-kit-astro';\n *\n * initGtm({ containers: 'GTM-XXXXXX' });\n * setupViewTransitions();\n * </script>\n * ```\n */\nexport const setupViewTransitions = (options: TrackPageViewOptions = {}): (() => void) => {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return noop;\n }\n\n // Prevent duplicate setup\n if (viewTransitionsSetup) {\n return noop;\n }\n\n viewTransitionsSetup = true;\n\n // Track initial page view\n lastTrackedPath = window.location.pathname + window.location.search;\n trackPageView(options);\n\n // Handle Astro View Transitions\n // The 'astro:page-load' event fires after every page load, including View Transitions\n const handlePageLoad = () => {\n const currentPath = window.location.pathname + window.location.search;\n\n // Avoid duplicate tracking for the same path\n if (currentPath === lastTrackedPath) {\n return;\n }\n\n lastTrackedPath = currentPath;\n trackPageView(options);\n };\n\n document.addEventListener('astro:page-load', handlePageLoad);\n\n // Cleanup function\n return () => {\n document.removeEventListener('astro:page-load', handlePageLoad);\n viewTransitionsSetup = false;\n lastTrackedPath = '';\n };\n};\n\n/**\n * Set up page view tracking for standard navigation (no View Transitions).\n * Tracks on popstate (back/forward) and initial load.\n *\n * @example\n * ```ts\n * import { setupPageTracking } from '@jwiedeman/gtm-kit-astro';\n *\n * setupPageTracking();\n * ```\n */\nexport const setupPageTracking = (options: TrackPageViewOptions = {}): (() => void) => {\n if (typeof window === 'undefined') {\n return noop;\n }\n\n // Track initial page view\n lastTrackedPath = window.location.pathname + window.location.search;\n trackPageView(options);\n\n // Handle browser back/forward navigation\n const handlePopState = () => {\n const currentPath = window.location.pathname + window.location.search;\n\n if (currentPath === lastTrackedPath) {\n return;\n }\n\n lastTrackedPath = currentPath;\n trackPageView(options);\n };\n\n window.addEventListener('popstate', handlePopState);\n\n return () => {\n window.removeEventListener('popstate', handlePopState);\n lastTrackedPath = '';\n };\n};\n","// Client-side GTM management\nexport {\n initGtm,\n getGtmClient,\n requireGtmClient,\n push,\n setConsentDefaults,\n updateConsent,\n whenReady,\n teardown\n} from './client';\n\n// Page tracking\nexport { trackPageView, setupViewTransitions, setupPageTracking } from './page-tracking';\nexport type { PageViewData, TrackPageViewOptions } from './page-tracking';\n\n// Re-export core types for convenience\nexport type {\n ConsentState,\n ConsentRegionOptions,\n CreateGtmClientOptions,\n DataLayerValue,\n GtmClient,\n ScriptLoadState,\n ContainerConfigInput,\n ContainerDescriptor,\n ScriptAttributes\n} from '@jwiedeman/gtm-kit';\n\n// Re-export consent helpers\nexport { consentPresets, getConsentPreset, eeaDefault, allGranted, analyticsOnly } from '@jwiedeman/gtm-kit';\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { CreateGtmClientOptions, GtmClient, DataLayerValue, ConsentState, ConsentRegionOptions, ScriptLoadState } from '@jwiedeman/gtm-kit';
|
|
2
|
+
export { ConsentRegionOptions, ConsentState, ContainerConfigInput, ContainerDescriptor, CreateGtmClientOptions, DataLayerValue, GtmClient, ScriptAttributes, ScriptLoadState, allGranted, analyticsOnly, consentPresets, eeaDefault, getConsentPreset } from '@jwiedeman/gtm-kit';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Initialize the GTM client for use in Astro.
|
|
6
|
+
* Should be called once when the page loads.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* // In a client-side script
|
|
11
|
+
* import { initGtm } from '@jwiedeman/gtm-kit-astro';
|
|
12
|
+
*
|
|
13
|
+
* initGtm({ containers: 'GTM-XXXXXX' });
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
declare const initGtm: (options: CreateGtmClientOptions) => GtmClient;
|
|
17
|
+
/**
|
|
18
|
+
* Get the current GTM client instance.
|
|
19
|
+
* Returns null if not initialized.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { getGtmClient } from '@jwiedeman/gtm-kit-astro';
|
|
24
|
+
*
|
|
25
|
+
* const client = getGtmClient();
|
|
26
|
+
* if (client) {
|
|
27
|
+
* client.push({ event: 'page_view' });
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
declare const getGtmClient: () => GtmClient | null;
|
|
32
|
+
/**
|
|
33
|
+
* Get the GTM client or throw if not initialized.
|
|
34
|
+
* Use this when you expect the client to be available.
|
|
35
|
+
*
|
|
36
|
+
* @throws Error if GTM client is not initialized
|
|
37
|
+
*/
|
|
38
|
+
declare const requireGtmClient: () => GtmClient;
|
|
39
|
+
/**
|
|
40
|
+
* Push a value to the GTM dataLayer.
|
|
41
|
+
* This is a convenience function that handles the case where GTM isn't initialized.
|
|
42
|
+
*
|
|
43
|
+
* @returns true if the value was pushed successfully, false otherwise
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* import { push } from '@jwiedeman/gtm-kit-astro';
|
|
48
|
+
*
|
|
49
|
+
* const success = push({ event: 'button_click', button_name: 'hero_cta' });
|
|
50
|
+
* if (!success) {
|
|
51
|
+
* console.warn('GTM not ready');
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
declare const push: (value: DataLayerValue) => boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Set consent defaults (must be called before GTM loads).
|
|
58
|
+
*
|
|
59
|
+
* @returns true if consent defaults were set, false if GTM not initialized
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* import { setConsentDefaults } from '@jwiedeman/gtm-kit-astro';
|
|
64
|
+
*
|
|
65
|
+
* const success = setConsentDefaults({
|
|
66
|
+
* ad_storage: 'denied',
|
|
67
|
+
* analytics_storage: 'denied'
|
|
68
|
+
* });
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
declare const setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Update consent state after user interaction.
|
|
74
|
+
*
|
|
75
|
+
* @returns true if consent was updated, false if GTM not initialized
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import { updateConsent } from '@jwiedeman/gtm-kit-astro';
|
|
80
|
+
*
|
|
81
|
+
* // When user accepts cookies
|
|
82
|
+
* const success = updateConsent({
|
|
83
|
+
* ad_storage: 'granted',
|
|
84
|
+
* analytics_storage: 'granted',
|
|
85
|
+
* ad_user_data: 'granted',
|
|
86
|
+
* ad_personalization: 'granted'
|
|
87
|
+
* });
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
declare const updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Wait for GTM scripts to be ready.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* import { whenReady } from '@jwiedeman/gtm-kit-astro';
|
|
97
|
+
*
|
|
98
|
+
* whenReady().then((states) => {
|
|
99
|
+
* console.log('GTM loaded:', states);
|
|
100
|
+
* });
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
declare const whenReady: () => Promise<ScriptLoadState[]>;
|
|
104
|
+
/**
|
|
105
|
+
* Clean up the GTM client.
|
|
106
|
+
* Call this when navigating away or cleaning up.
|
|
107
|
+
*/
|
|
108
|
+
declare const teardown: () => void;
|
|
109
|
+
|
|
110
|
+
interface PageViewData {
|
|
111
|
+
event?: string;
|
|
112
|
+
page_path?: string;
|
|
113
|
+
page_location?: string;
|
|
114
|
+
page_title?: string;
|
|
115
|
+
page_referrer?: string;
|
|
116
|
+
[key: string]: unknown;
|
|
117
|
+
}
|
|
118
|
+
interface TrackPageViewOptions {
|
|
119
|
+
/**
|
|
120
|
+
* The event name to use for page views.
|
|
121
|
+
* @default 'page_view'
|
|
122
|
+
*/
|
|
123
|
+
eventName?: string;
|
|
124
|
+
/**
|
|
125
|
+
* Whether to include query parameters in the page path.
|
|
126
|
+
* @default true
|
|
127
|
+
*/
|
|
128
|
+
includeQueryParams?: boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Additional data to include with each page view.
|
|
131
|
+
*/
|
|
132
|
+
additionalData?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Track a page view event.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```ts
|
|
139
|
+
* import { trackPageView } from '@jwiedeman/gtm-kit-astro';
|
|
140
|
+
*
|
|
141
|
+
* // Track current page
|
|
142
|
+
* trackPageView();
|
|
143
|
+
*
|
|
144
|
+
* // Track with custom data
|
|
145
|
+
* trackPageView({
|
|
146
|
+
* additionalData: { user_type: 'guest' }
|
|
147
|
+
* });
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
declare const trackPageView: (options?: TrackPageViewOptions) => void;
|
|
151
|
+
/**
|
|
152
|
+
* Set up automatic page view tracking with Astro View Transitions.
|
|
153
|
+
* Call this once when the page loads.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```astro
|
|
157
|
+
* ---
|
|
158
|
+
* // src/layouts/Layout.astro
|
|
159
|
+
* ---
|
|
160
|
+
* <script>
|
|
161
|
+
* import { initGtm, setupViewTransitions } from '@jwiedeman/gtm-kit-astro';
|
|
162
|
+
*
|
|
163
|
+
* initGtm({ containers: 'GTM-XXXXXX' });
|
|
164
|
+
* setupViewTransitions();
|
|
165
|
+
* </script>
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
declare const setupViewTransitions: (options?: TrackPageViewOptions) => (() => void);
|
|
169
|
+
/**
|
|
170
|
+
* Set up page view tracking for standard navigation (no View Transitions).
|
|
171
|
+
* Tracks on popstate (back/forward) and initial load.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```ts
|
|
175
|
+
* import { setupPageTracking } from '@jwiedeman/gtm-kit-astro';
|
|
176
|
+
*
|
|
177
|
+
* setupPageTracking();
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
declare const setupPageTracking: (options?: TrackPageViewOptions) => (() => void);
|
|
181
|
+
|
|
182
|
+
export { PageViewData, TrackPageViewOptions, getGtmClient, initGtm, push, requireGtmClient, setConsentDefaults, setupPageTracking, setupViewTransitions, teardown, trackPageView, updateConsent, whenReady };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { CreateGtmClientOptions, GtmClient, DataLayerValue, ConsentState, ConsentRegionOptions, ScriptLoadState } from '@jwiedeman/gtm-kit';
|
|
2
|
+
export { ConsentRegionOptions, ConsentState, ContainerConfigInput, ContainerDescriptor, CreateGtmClientOptions, DataLayerValue, GtmClient, ScriptAttributes, ScriptLoadState, allGranted, analyticsOnly, consentPresets, eeaDefault, getConsentPreset } from '@jwiedeman/gtm-kit';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Initialize the GTM client for use in Astro.
|
|
6
|
+
* Should be called once when the page loads.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* // In a client-side script
|
|
11
|
+
* import { initGtm } from '@jwiedeman/gtm-kit-astro';
|
|
12
|
+
*
|
|
13
|
+
* initGtm({ containers: 'GTM-XXXXXX' });
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
declare const initGtm: (options: CreateGtmClientOptions) => GtmClient;
|
|
17
|
+
/**
|
|
18
|
+
* Get the current GTM client instance.
|
|
19
|
+
* Returns null if not initialized.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { getGtmClient } from '@jwiedeman/gtm-kit-astro';
|
|
24
|
+
*
|
|
25
|
+
* const client = getGtmClient();
|
|
26
|
+
* if (client) {
|
|
27
|
+
* client.push({ event: 'page_view' });
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
declare const getGtmClient: () => GtmClient | null;
|
|
32
|
+
/**
|
|
33
|
+
* Get the GTM client or throw if not initialized.
|
|
34
|
+
* Use this when you expect the client to be available.
|
|
35
|
+
*
|
|
36
|
+
* @throws Error if GTM client is not initialized
|
|
37
|
+
*/
|
|
38
|
+
declare const requireGtmClient: () => GtmClient;
|
|
39
|
+
/**
|
|
40
|
+
* Push a value to the GTM dataLayer.
|
|
41
|
+
* This is a convenience function that handles the case where GTM isn't initialized.
|
|
42
|
+
*
|
|
43
|
+
* @returns true if the value was pushed successfully, false otherwise
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* import { push } from '@jwiedeman/gtm-kit-astro';
|
|
48
|
+
*
|
|
49
|
+
* const success = push({ event: 'button_click', button_name: 'hero_cta' });
|
|
50
|
+
* if (!success) {
|
|
51
|
+
* console.warn('GTM not ready');
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
declare const push: (value: DataLayerValue) => boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Set consent defaults (must be called before GTM loads).
|
|
58
|
+
*
|
|
59
|
+
* @returns true if consent defaults were set, false if GTM not initialized
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* import { setConsentDefaults } from '@jwiedeman/gtm-kit-astro';
|
|
64
|
+
*
|
|
65
|
+
* const success = setConsentDefaults({
|
|
66
|
+
* ad_storage: 'denied',
|
|
67
|
+
* analytics_storage: 'denied'
|
|
68
|
+
* });
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
declare const setConsentDefaults: (state: ConsentState, options?: ConsentRegionOptions) => boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Update consent state after user interaction.
|
|
74
|
+
*
|
|
75
|
+
* @returns true if consent was updated, false if GTM not initialized
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import { updateConsent } from '@jwiedeman/gtm-kit-astro';
|
|
80
|
+
*
|
|
81
|
+
* // When user accepts cookies
|
|
82
|
+
* const success = updateConsent({
|
|
83
|
+
* ad_storage: 'granted',
|
|
84
|
+
* analytics_storage: 'granted',
|
|
85
|
+
* ad_user_data: 'granted',
|
|
86
|
+
* ad_personalization: 'granted'
|
|
87
|
+
* });
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
declare const updateConsent: (state: ConsentState, options?: ConsentRegionOptions) => boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Wait for GTM scripts to be ready.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* import { whenReady } from '@jwiedeman/gtm-kit-astro';
|
|
97
|
+
*
|
|
98
|
+
* whenReady().then((states) => {
|
|
99
|
+
* console.log('GTM loaded:', states);
|
|
100
|
+
* });
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
declare const whenReady: () => Promise<ScriptLoadState[]>;
|
|
104
|
+
/**
|
|
105
|
+
* Clean up the GTM client.
|
|
106
|
+
* Call this when navigating away or cleaning up.
|
|
107
|
+
*/
|
|
108
|
+
declare const teardown: () => void;
|
|
109
|
+
|
|
110
|
+
interface PageViewData {
|
|
111
|
+
event?: string;
|
|
112
|
+
page_path?: string;
|
|
113
|
+
page_location?: string;
|
|
114
|
+
page_title?: string;
|
|
115
|
+
page_referrer?: string;
|
|
116
|
+
[key: string]: unknown;
|
|
117
|
+
}
|
|
118
|
+
interface TrackPageViewOptions {
|
|
119
|
+
/**
|
|
120
|
+
* The event name to use for page views.
|
|
121
|
+
* @default 'page_view'
|
|
122
|
+
*/
|
|
123
|
+
eventName?: string;
|
|
124
|
+
/**
|
|
125
|
+
* Whether to include query parameters in the page path.
|
|
126
|
+
* @default true
|
|
127
|
+
*/
|
|
128
|
+
includeQueryParams?: boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Additional data to include with each page view.
|
|
131
|
+
*/
|
|
132
|
+
additionalData?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Track a page view event.
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```ts
|
|
139
|
+
* import { trackPageView } from '@jwiedeman/gtm-kit-astro';
|
|
140
|
+
*
|
|
141
|
+
* // Track current page
|
|
142
|
+
* trackPageView();
|
|
143
|
+
*
|
|
144
|
+
* // Track with custom data
|
|
145
|
+
* trackPageView({
|
|
146
|
+
* additionalData: { user_type: 'guest' }
|
|
147
|
+
* });
|
|
148
|
+
* ```
|
|
149
|
+
*/
|
|
150
|
+
declare const trackPageView: (options?: TrackPageViewOptions) => void;
|
|
151
|
+
/**
|
|
152
|
+
* Set up automatic page view tracking with Astro View Transitions.
|
|
153
|
+
* Call this once when the page loads.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```astro
|
|
157
|
+
* ---
|
|
158
|
+
* // src/layouts/Layout.astro
|
|
159
|
+
* ---
|
|
160
|
+
* <script>
|
|
161
|
+
* import { initGtm, setupViewTransitions } from '@jwiedeman/gtm-kit-astro';
|
|
162
|
+
*
|
|
163
|
+
* initGtm({ containers: 'GTM-XXXXXX' });
|
|
164
|
+
* setupViewTransitions();
|
|
165
|
+
* </script>
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
declare const setupViewTransitions: (options?: TrackPageViewOptions) => (() => void);
|
|
169
|
+
/**
|
|
170
|
+
* Set up page view tracking for standard navigation (no View Transitions).
|
|
171
|
+
* Tracks on popstate (back/forward) and initial load.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```ts
|
|
175
|
+
* import { setupPageTracking } from '@jwiedeman/gtm-kit-astro';
|
|
176
|
+
*
|
|
177
|
+
* setupPageTracking();
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
declare const setupPageTracking: (options?: TrackPageViewOptions) => (() => void);
|
|
181
|
+
|
|
182
|
+
export { PageViewData, TrackPageViewOptions, getGtmClient, initGtm, push, requireGtmClient, setConsentDefaults, setupPageTracking, setupViewTransitions, teardown, trackPageView, updateConsent, whenReady };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createGtmClient } from '@jwiedeman/gtm-kit';
|
|
2
|
+
export { allGranted, analyticsOnly, consentPresets, eeaDefault, getConsentPreset } from '@jwiedeman/gtm-kit';
|
|
3
|
+
|
|
4
|
+
var o=null,r=null,f=e=>o||(o=createGtmClient(e),r=e,o.init(),o),i=()=>o,m=()=>{if(!o)throw new Error("[gtm-kit/astro] GTM client not initialized. Call initGtm() first or ensure the GTM script has loaded.");return o},p=e=>{var t;let n=i();if(n)return n.push(e),!0;if(typeof window!="undefined"){let c=(t=r==null?void 0:r.dataLayerName)!=null?t:"dataLayer",l=window[c];return Array.isArray(l)?(l.push(e),!0):(console.warn("[gtm-kit/astro] GTM not initialized and dataLayer not found."),!1)}return !1},C=(e,n)=>{let t=i();return t?(t.setConsentDefaults(e,n),!0):(console.warn("[gtm-kit/astro] GTM not initialized. Consent defaults should be set before init."),!1)},y=(e,n)=>{let t=i();return t?(t.updateConsent(e,n),!0):(console.warn("[gtm-kit/astro] GTM not initialized. Cannot update consent."),!1)},h=()=>{let e=i();return e?e.whenReady():Promise.reject(new Error("[gtm-kit/astro] GTM not initialized."))},k=()=>{o&&(o.teardown(),o=null,r=null);};var d=()=>{},P=e=>typeof e=="function"?e():e!=null?e:{},s=(e={})=>{let{eventName:n="page_view",includeQueryParams:t=!0,additionalData:c}=e;if(typeof window=="undefined")return;let w=t?window.location.pathname+window.location.search:window.location.pathname,l={event:n,page_path:w,page_location:window.location.href,page_title:document.title,...P(c)};p(l);},u=!1,a="";var G=(e={})=>{if(typeof window=="undefined"||typeof document=="undefined"||u)return d;u=!0,a=window.location.pathname+window.location.search,s(e);let n=()=>{let t=window.location.pathname+window.location.search;t!==a&&(a=t,s(e));};return document.addEventListener("astro:page-load",n),()=>{document.removeEventListener("astro:page-load",n),u=!1,a="";}},x=(e={})=>{if(typeof window=="undefined")return d;a=window.location.pathname+window.location.search,s(e);let n=()=>{let t=window.location.pathname+window.location.search;t!==a&&(a=t,s(e));};return window.addEventListener("popstate",n),()=>{window.removeEventListener("popstate",n),a="";}};
|
|
5
|
+
|
|
6
|
+
export { i as getGtmClient, f as initGtm, p as push, m as requireGtmClient, C as setConsentDefaults, x as setupPageTracking, G as setupViewTransitions, k as teardown, s as trackPageView, y as updateConsent, h as whenReady };
|
|
7
|
+
//# sourceMappingURL=out.js.map
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/page-tracking.ts","../src/index.ts"],"names":["createGtmClient","clientInstance","clientConfig","initGtm","options","getGtmClient","requireGtmClient","push","value","_a","client","dataLayerName","dataLayer","setConsentDefaults","state","updateConsent","whenReady","teardown","noop","getAdditionalData","additionalData","trackPageView","eventName","includeQueryParams","pagePath","pageViewData","viewTransitionsSetup","lastTrackedPath","setupViewTransitions","handlePageLoad","currentPath","setupPageTracking","handlePopState","consentPresets","getConsentPreset","eeaDefault","allGranted","analyticsOnly"],"mappings":"AAAA,OACE,mBAAAA,MAOK,qBAEP,IAAIC,EAAmC,KACnCC,EAA8C,KAcrCC,EAAWC,GAGlBH,IAIJA,EAAiBD,EAAgBI,CAAO,EACxCF,EAAeE,EACfH,EAAe,KAAK,EAEbA,GAiBII,EAAe,IAAwBJ,EAQvCK,EAAmB,IAAiB,CAC/C,GAAI,CAACL,EACH,MAAM,IAAI,MACR,uGACF,EAEF,OAAOA,CACT,EAkBaM,EAAQC,GAAmC,CAtFxD,IAAAC,EAuFE,IAAMC,EAASL,EAAa,EAC5B,GAAIK,EACF,OAAAA,EAAO,KAAKF,CAAK,EACV,GACF,GAAI,OAAO,QAAW,YAAa,CAExC,IAAMG,GAAgBF,EAAAP,GAAA,YAAAA,EAAc,gBAAd,KAAAO,EAA+B,YAE/CG,EADM,OACUD,CAAa,EACnC,OAAI,MAAM,QAAQC,CAAS,GACzBA,EAAU,KAAKJ,CAAK,EACb,KAEP,QAAQ,KAAK,8DAA8D,EACpE,GAEX,CACA,MAAO,EACT,EAiBaK,EAAqB,CAACC,EAAqBV,IAA4C,CAClG,IAAMM,EAASL,EAAa,EAC5B,OAAIK,GACFA,EAAO,mBAAmBI,EAAOV,CAAO,EACjC,KAEP,QAAQ,KAAK,kFAAkF,EACxF,GAEX,EAoBaW,EAAgB,CAACD,EAAqBV,IAA4C,CAC7F,IAAMM,EAASL,EAAa,EAC5B,OAAIK,GACFA,EAAO,cAAcI,EAAOV,CAAO,EAC5B,KAEP,QAAQ,KAAK,6DAA6D,EACnE,GAEX,EAcaY,EAAY,IAAkC,CACzD,IAAMN,EAASL,EAAa,EAC5B,OAAIK,EACKA,EAAO,UAAU,EAEnB,QAAQ,OAAO,IAAI,MAAM,sCAAsC,CAAC,CACzE,EAMaO,EAAW,IAAY,CAC9BhB,IACFA,EAAe,SAAS,EACxBA,EAAiB,KACjBC,EAAe,KAEnB,EC7LA,IAAMgB,EAAO,IAAY,CAEzB,EA8BMC,EAAqBC,GACrB,OAAOA,GAAmB,WACrBA,EAAe,EAEjBA,GAAA,KAAAA,EAAkB,CAAC,EAmBfC,EAAgB,CAACjB,EAAgC,CAAC,IAAY,CACzE,GAAM,CAAE,UAAAkB,EAAY,YAAa,mBAAAC,EAAqB,GAAM,eAAAH,CAAe,EAAIhB,EAE/E,GAAI,OAAO,QAAW,YACpB,OAGF,IAAMoB,EAAWD,EAAqB,OAAO,SAAS,SAAW,OAAO,SAAS,OAAS,OAAO,SAAS,SAEpGE,EAA6B,CACjC,MAAOH,EACP,UAAWE,EACX,cAAe,OAAO,SAAS,KAC/B,WAAY,SAAS,MACrB,GAAGL,EAAkBC,CAAc,CACrC,EAEAb,EAAKkB,CAAY,CACnB,EAEIC,EAAuB,GACvBC,EAAkB,GA4Bf,IAAMC,EAAuB,CAACxB,EAAgC,CAAC,IAAoB,CAMxF,GALI,OAAO,QAAW,aAAe,OAAO,UAAa,aAKrDsB,EACF,OAAOR,EAGTQ,EAAuB,GAGvBC,EAAkB,OAAO,SAAS,SAAW,OAAO,SAAS,OAC7DN,EAAcjB,CAAO,EAIrB,IAAMyB,EAAiB,IAAM,CAC3B,IAAMC,EAAc,OAAO,SAAS,SAAW,OAAO,SAAS,OAG3DA,IAAgBH,IAIpBA,EAAkBG,EAClBT,EAAcjB,CAAO,EACvB,EAEA,gBAAS,iBAAiB,kBAAmByB,CAAc,EAGpD,IAAM,CACX,SAAS,oBAAoB,kBAAmBA,CAAc,EAC9DH,EAAuB,GACvBC,EAAkB,EACpB,CACF,EAaaI,EAAoB,CAAC3B,EAAgC,CAAC,IAAoB,CACrF,GAAI,OAAO,QAAW,YACpB,OAAOc,EAITS,EAAkB,OAAO,SAAS,SAAW,OAAO,SAAS,OAC7DN,EAAcjB,CAAO,EAGrB,IAAM4B,EAAiB,IAAM,CAC3B,IAAMF,EAAc,OAAO,SAAS,SAAW,OAAO,SAAS,OAE3DA,IAAgBH,IAIpBA,EAAkBG,EAClBT,EAAcjB,CAAO,EACvB,EAEA,cAAO,iBAAiB,WAAY4B,CAAc,EAE3C,IAAM,CACX,OAAO,oBAAoB,WAAYA,CAAc,EACrDL,EAAkB,EACpB,CACF,EC3JA,OAAS,kBAAAM,EAAgB,oBAAAC,EAAkB,cAAAC,EAAY,cAAAC,EAAY,iBAAAC,MAAqB","sourcesContent":["import {\n createGtmClient,\n type ConsentRegionOptions,\n type ConsentState,\n type CreateGtmClientOptions,\n type DataLayerValue,\n type GtmClient,\n type ScriptLoadState\n} from '@jwiedeman/gtm-kit';\n\nlet clientInstance: GtmClient | null = null;\nlet clientConfig: CreateGtmClientOptions | null = null;\n\n/**\n * Initialize the GTM client for use in Astro.\n * Should be called once when the page loads.\n *\n * @example\n * ```ts\n * // In a client-side script\n * import { initGtm } from '@jwiedeman/gtm-kit-astro';\n *\n * initGtm({ containers: 'GTM-XXXXXX' });\n * ```\n */\nexport const initGtm = (options: CreateGtmClientOptions): GtmClient => {\n // If already initialized, return existing instance\n // (common in Astro with view transitions where initGtm may be called multiple times)\n if (clientInstance) {\n return clientInstance;\n }\n\n clientInstance = createGtmClient(options);\n clientConfig = options;\n clientInstance.init();\n\n return clientInstance;\n};\n\n/**\n * Get the current GTM client instance.\n * Returns null if not initialized.\n *\n * @example\n * ```ts\n * import { getGtmClient } from '@jwiedeman/gtm-kit-astro';\n *\n * const client = getGtmClient();\n * if (client) {\n * client.push({ event: 'page_view' });\n * }\n * ```\n */\nexport const getGtmClient = (): GtmClient | null => clientInstance;\n\n/**\n * Get the GTM client or throw if not initialized.\n * Use this when you expect the client to be available.\n *\n * @throws Error if GTM client is not initialized\n */\nexport const requireGtmClient = (): GtmClient => {\n if (!clientInstance) {\n throw new Error(\n '[gtm-kit/astro] GTM client not initialized. Call initGtm() first or ensure the GTM script has loaded.'\n );\n }\n return clientInstance;\n};\n\n/**\n * Push a value to the GTM dataLayer.\n * This is a convenience function that handles the case where GTM isn't initialized.\n *\n * @returns true if the value was pushed successfully, false otherwise\n *\n * @example\n * ```ts\n * import { push } from '@jwiedeman/gtm-kit-astro';\n *\n * const success = push({ event: 'button_click', button_name: 'hero_cta' });\n * if (!success) {\n * console.warn('GTM not ready');\n * }\n * ```\n */\nexport const push = (value: DataLayerValue): boolean => {\n const client = getGtmClient();\n if (client) {\n client.push(value);\n return true;\n } else if (typeof window !== 'undefined') {\n // Fallback: push directly to dataLayer if it exists\n const dataLayerName = clientConfig?.dataLayerName ?? 'dataLayer';\n const win = window as unknown as Record<string, unknown>;\n const dataLayer = win[dataLayerName] as DataLayerValue[] | undefined;\n if (Array.isArray(dataLayer)) {\n dataLayer.push(value);\n return true;\n } else {\n console.warn('[gtm-kit/astro] GTM not initialized and dataLayer not found.');\n return false;\n }\n }\n return false;\n};\n\n/**\n * Set consent defaults (must be called before GTM loads).\n *\n * @returns true if consent defaults were set, false if GTM not initialized\n *\n * @example\n * ```ts\n * import { setConsentDefaults } from '@jwiedeman/gtm-kit-astro';\n *\n * const success = setConsentDefaults({\n * ad_storage: 'denied',\n * analytics_storage: 'denied'\n * });\n * ```\n */\nexport const setConsentDefaults = (state: ConsentState, options?: ConsentRegionOptions): boolean => {\n const client = getGtmClient();\n if (client) {\n client.setConsentDefaults(state, options);\n return true;\n } else {\n console.warn('[gtm-kit/astro] GTM not initialized. Consent defaults should be set before init.');\n return false;\n }\n};\n\n/**\n * Update consent state after user interaction.\n *\n * @returns true if consent was updated, false if GTM not initialized\n *\n * @example\n * ```ts\n * import { updateConsent } from '@jwiedeman/gtm-kit-astro';\n *\n * // When user accepts cookies\n * const success = updateConsent({\n * ad_storage: 'granted',\n * analytics_storage: 'granted',\n * ad_user_data: 'granted',\n * ad_personalization: 'granted'\n * });\n * ```\n */\nexport const updateConsent = (state: ConsentState, options?: ConsentRegionOptions): boolean => {\n const client = getGtmClient();\n if (client) {\n client.updateConsent(state, options);\n return true;\n } else {\n console.warn('[gtm-kit/astro] GTM not initialized. Cannot update consent.');\n return false;\n }\n};\n\n/**\n * Wait for GTM scripts to be ready.\n *\n * @example\n * ```ts\n * import { whenReady } from '@jwiedeman/gtm-kit-astro';\n *\n * whenReady().then((states) => {\n * console.log('GTM loaded:', states);\n * });\n * ```\n */\nexport const whenReady = (): Promise<ScriptLoadState[]> => {\n const client = getGtmClient();\n if (client) {\n return client.whenReady();\n }\n return Promise.reject(new Error('[gtm-kit/astro] GTM not initialized.'));\n};\n\n/**\n * Clean up the GTM client.\n * Call this when navigating away or cleaning up.\n */\nexport const teardown = (): void => {\n if (clientInstance) {\n clientInstance.teardown();\n clientInstance = null;\n clientConfig = null;\n }\n};\n","import { push } from './client';\n\n// No-op function for SSR/cleanup returns\nconst noop = (): void => {\n /* no-op */\n};\n\nexport interface PageViewData {\n event?: string;\n page_path?: string;\n page_location?: string;\n page_title?: string;\n page_referrer?: string;\n [key: string]: unknown;\n}\n\nexport interface TrackPageViewOptions {\n /**\n * The event name to use for page views.\n * @default 'page_view'\n */\n eventName?: string;\n\n /**\n * Whether to include query parameters in the page path.\n * @default true\n */\n includeQueryParams?: boolean;\n\n /**\n * Additional data to include with each page view.\n */\n additionalData?: Record<string, unknown> | (() => Record<string, unknown>);\n}\n\nconst getAdditionalData = (additionalData: TrackPageViewOptions['additionalData']): Record<string, unknown> => {\n if (typeof additionalData === 'function') {\n return additionalData();\n }\n return additionalData ?? {};\n};\n\n/**\n * Track a page view event.\n *\n * @example\n * ```ts\n * import { trackPageView } from '@jwiedeman/gtm-kit-astro';\n *\n * // Track current page\n * trackPageView();\n *\n * // Track with custom data\n * trackPageView({\n * additionalData: { user_type: 'guest' }\n * });\n * ```\n */\nexport const trackPageView = (options: TrackPageViewOptions = {}): void => {\n const { eventName = 'page_view', includeQueryParams = true, additionalData } = options;\n\n if (typeof window === 'undefined') {\n return;\n }\n\n const pagePath = includeQueryParams ? window.location.pathname + window.location.search : window.location.pathname;\n\n const pageViewData: PageViewData = {\n event: eventName,\n page_path: pagePath,\n page_location: window.location.href,\n page_title: document.title,\n ...getAdditionalData(additionalData)\n };\n\n push(pageViewData);\n};\n\nlet viewTransitionsSetup = false;\nlet lastTrackedPath = '';\n\n/**\n * Reset page tracking state (for testing only).\n * @internal\n */\nexport const _resetPageTrackingState = (): void => {\n viewTransitionsSetup = false;\n lastTrackedPath = '';\n};\n\n/**\n * Set up automatic page view tracking with Astro View Transitions.\n * Call this once when the page loads.\n *\n * @example\n * ```astro\n * ---\n * // src/layouts/Layout.astro\n * ---\n * <script>\n * import { initGtm, setupViewTransitions } from '@jwiedeman/gtm-kit-astro';\n *\n * initGtm({ containers: 'GTM-XXXXXX' });\n * setupViewTransitions();\n * </script>\n * ```\n */\nexport const setupViewTransitions = (options: TrackPageViewOptions = {}): (() => void) => {\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return noop;\n }\n\n // Prevent duplicate setup\n if (viewTransitionsSetup) {\n return noop;\n }\n\n viewTransitionsSetup = true;\n\n // Track initial page view\n lastTrackedPath = window.location.pathname + window.location.search;\n trackPageView(options);\n\n // Handle Astro View Transitions\n // The 'astro:page-load' event fires after every page load, including View Transitions\n const handlePageLoad = () => {\n const currentPath = window.location.pathname + window.location.search;\n\n // Avoid duplicate tracking for the same path\n if (currentPath === lastTrackedPath) {\n return;\n }\n\n lastTrackedPath = currentPath;\n trackPageView(options);\n };\n\n document.addEventListener('astro:page-load', handlePageLoad);\n\n // Cleanup function\n return () => {\n document.removeEventListener('astro:page-load', handlePageLoad);\n viewTransitionsSetup = false;\n lastTrackedPath = '';\n };\n};\n\n/**\n * Set up page view tracking for standard navigation (no View Transitions).\n * Tracks on popstate (back/forward) and initial load.\n *\n * @example\n * ```ts\n * import { setupPageTracking } from '@jwiedeman/gtm-kit-astro';\n *\n * setupPageTracking();\n * ```\n */\nexport const setupPageTracking = (options: TrackPageViewOptions = {}): (() => void) => {\n if (typeof window === 'undefined') {\n return noop;\n }\n\n // Track initial page view\n lastTrackedPath = window.location.pathname + window.location.search;\n trackPageView(options);\n\n // Handle browser back/forward navigation\n const handlePopState = () => {\n const currentPath = window.location.pathname + window.location.search;\n\n if (currentPath === lastTrackedPath) {\n return;\n }\n\n lastTrackedPath = currentPath;\n trackPageView(options);\n };\n\n window.addEventListener('popstate', handlePopState);\n\n return () => {\n window.removeEventListener('popstate', handlePopState);\n lastTrackedPath = '';\n };\n};\n","// Client-side GTM management\nexport {\n initGtm,\n getGtmClient,\n requireGtmClient,\n push,\n setConsentDefaults,\n updateConsent,\n whenReady,\n teardown\n} from './client';\n\n// Page tracking\nexport { trackPageView, setupViewTransitions, setupPageTracking } from './page-tracking';\nexport type { PageViewData, TrackPageViewOptions } from './page-tracking';\n\n// Re-export core types for convenience\nexport type {\n ConsentState,\n ConsentRegionOptions,\n CreateGtmClientOptions,\n DataLayerValue,\n GtmClient,\n ScriptLoadState,\n ContainerConfigInput,\n ContainerDescriptor,\n ScriptAttributes\n} from '@jwiedeman/gtm-kit';\n\n// Re-export consent helpers\nexport { consentPresets, getConsentPreset, eeaDefault, allGranted, analyticsOnly } from '@jwiedeman/gtm-kit';\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jwiedeman/gtm-kit-astro",
|
|
3
|
+
"version": "1.1.3",
|
|
4
|
+
"description": "Astro components and helpers for GTM Kit - Google Tag Manager integration.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/jwiedeman/GTM-Kit.git",
|
|
8
|
+
"directory": "packages/astro"
|
|
9
|
+
},
|
|
10
|
+
"author": "jwiedeman",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"gtm",
|
|
13
|
+
"google-tag-manager",
|
|
14
|
+
"astro",
|
|
15
|
+
"astrojs",
|
|
16
|
+
"view-transitions"
|
|
17
|
+
],
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"type": "module",
|
|
23
|
+
"main": "dist/index.cjs",
|
|
24
|
+
"module": "dist/index.js",
|
|
25
|
+
"types": "dist/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.js",
|
|
30
|
+
"require": "./dist/index.cjs"
|
|
31
|
+
},
|
|
32
|
+
"./components": {
|
|
33
|
+
"types": "./dist/components/index.d.ts",
|
|
34
|
+
"import": "./dist/components/index.js",
|
|
35
|
+
"require": "./dist/components/index.cjs"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"src/components/*.astro"
|
|
41
|
+
],
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsup",
|
|
44
|
+
"clean": "rm -rf dist",
|
|
45
|
+
"lint": "eslint --max-warnings=0 \"src/**/*.ts\"",
|
|
46
|
+
"test": "jest --config ./jest.config.cjs --runInBand",
|
|
47
|
+
"typecheck": "tsc --noEmit"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@jwiedeman/gtm-kit": "workspace:*"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"astro": "^3.0.0 || ^4.0.0 || ^5.0.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"astro": "^4.16.0",
|
|
57
|
+
"tslib": "^2.6.2"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* GTM Head Component
|
|
4
|
+
*
|
|
5
|
+
* A convenience component that sets up GTM in the document head
|
|
6
|
+
* with optional consent mode and auto page tracking.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```astro
|
|
10
|
+
* ---
|
|
11
|
+
* import { GtmHead } from '@jwiedeman/gtm-kit-astro/components';
|
|
12
|
+
* ---
|
|
13
|
+
* <head>
|
|
14
|
+
* <GtmHead
|
|
15
|
+
* containers="GTM-XXXXXX"
|
|
16
|
+
* enablePageTracking
|
|
17
|
+
* defaultConsent={{
|
|
18
|
+
* ad_storage: 'denied',
|
|
19
|
+
* analytics_storage: 'denied'
|
|
20
|
+
* }}
|
|
21
|
+
* />
|
|
22
|
+
* </head>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
import type { ContainerConfigInput, ScriptAttributes, ConsentState } from '@jwiedeman/gtm-kit';
|
|
26
|
+
import {
|
|
27
|
+
generateScriptTags,
|
|
28
|
+
generateDataLayerScript,
|
|
29
|
+
DEFAULT_GTM_HOST
|
|
30
|
+
} from './helpers';
|
|
31
|
+
|
|
32
|
+
export interface Props {
|
|
33
|
+
/** GTM container ID(s) - single string or array */
|
|
34
|
+
containers: ContainerConfigInput | ContainerConfigInput[];
|
|
35
|
+
/** GTM host URL */
|
|
36
|
+
host?: string;
|
|
37
|
+
/** Query parameters to add to all containers */
|
|
38
|
+
defaultQueryParams?: Record<string, string | number | boolean>;
|
|
39
|
+
/** Script tag attributes (async, defer, nonce, etc.) */
|
|
40
|
+
scriptAttributes?: ScriptAttributes;
|
|
41
|
+
/** Custom dataLayer name */
|
|
42
|
+
dataLayerName?: string;
|
|
43
|
+
/** Default consent state (set before GTM loads) */
|
|
44
|
+
defaultConsent?: ConsentState;
|
|
45
|
+
/** Enable automatic page view tracking with View Transitions */
|
|
46
|
+
enablePageTracking?: boolean;
|
|
47
|
+
/** Custom page view event name */
|
|
48
|
+
pageViewEventName?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const {
|
|
52
|
+
containers,
|
|
53
|
+
host = DEFAULT_GTM_HOST,
|
|
54
|
+
defaultQueryParams,
|
|
55
|
+
scriptAttributes,
|
|
56
|
+
dataLayerName = 'dataLayer',
|
|
57
|
+
defaultConsent,
|
|
58
|
+
enablePageTracking = false,
|
|
59
|
+
pageViewEventName = 'page_view'
|
|
60
|
+
} = Astro.props;
|
|
61
|
+
|
|
62
|
+
const scripts = generateScriptTags({
|
|
63
|
+
containers,
|
|
64
|
+
host,
|
|
65
|
+
defaultQueryParams,
|
|
66
|
+
scriptAttributes,
|
|
67
|
+
dataLayerName
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Build initialization script
|
|
71
|
+
let initScript = generateDataLayerScript(dataLayerName);
|
|
72
|
+
|
|
73
|
+
// Add consent defaults if provided
|
|
74
|
+
if (defaultConsent) {
|
|
75
|
+
const consentEntries = Object.entries(defaultConsent)
|
|
76
|
+
.map(([key, value]) => `'${key}':'${value}'`)
|
|
77
|
+
.join(',');
|
|
78
|
+
initScript += `${dataLayerName}.push(['consent','default',{${consentEntries}}]);`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Generate the containers config for client-side initialization
|
|
82
|
+
const containersArray = Array.isArray(containers) ? containers : [containers];
|
|
83
|
+
const containersJson = JSON.stringify(containersArray);
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
<script is:inline set:html={initScript} />
|
|
87
|
+
{scripts.map((script) => (
|
|
88
|
+
<script
|
|
89
|
+
src={script.src}
|
|
90
|
+
async={script.async}
|
|
91
|
+
defer={script.defer}
|
|
92
|
+
nonce={script.nonce}
|
|
93
|
+
data-gtm-container-id={script.id}
|
|
94
|
+
{...script.attributes}
|
|
95
|
+
/>
|
|
96
|
+
))}
|
|
97
|
+
|
|
98
|
+
{enablePageTracking && (
|
|
99
|
+
<script
|
|
100
|
+
define:vars={{ containersJson, dataLayerName, pageViewEventName }}
|
|
101
|
+
>
|
|
102
|
+
// Initialize GTM client and set up page tracking
|
|
103
|
+
import('@jwiedeman/gtm-kit-astro')
|
|
104
|
+
.then(({ initGtm, setupViewTransitions }) => {
|
|
105
|
+
try {
|
|
106
|
+
const containers = JSON.parse(containersJson);
|
|
107
|
+
initGtm({ containers, dataLayerName });
|
|
108
|
+
setupViewTransitions({ eventName: pageViewEventName });
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error('[gtm-kit/astro] Failed to initialize GTM:', error);
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
.catch((error) => {
|
|
114
|
+
console.error('[gtm-kit/astro] Failed to load GTM module:', error);
|
|
115
|
+
});
|
|
116
|
+
</script>
|
|
117
|
+
)}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* GTM NoScript Component
|
|
4
|
+
*
|
|
5
|
+
* Renders the GTM noscript fallback iframe(s).
|
|
6
|
+
* Use this immediately after the opening <body> tag.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```astro
|
|
10
|
+
* ---
|
|
11
|
+
* import { GtmNoScript } from '@jwiedeman/gtm-kit-astro/components';
|
|
12
|
+
* ---
|
|
13
|
+
* <body>
|
|
14
|
+
* <GtmNoScript containers="GTM-XXXXXX" />
|
|
15
|
+
* <!-- rest of body -->
|
|
16
|
+
* </body>
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
import type { ContainerConfigInput } from '@jwiedeman/gtm-kit';
|
|
20
|
+
import { generateNoscriptTags, DEFAULT_GTM_HOST } from './helpers';
|
|
21
|
+
|
|
22
|
+
export interface Props {
|
|
23
|
+
/** GTM container ID(s) - single string or array */
|
|
24
|
+
containers: ContainerConfigInput | ContainerConfigInput[];
|
|
25
|
+
/** GTM host URL */
|
|
26
|
+
host?: string;
|
|
27
|
+
/** Query parameters to add to all containers */
|
|
28
|
+
defaultQueryParams?: Record<string, string | number | boolean>;
|
|
29
|
+
/** Custom iframe attributes */
|
|
30
|
+
iframeAttributes?: Record<string, string | number | boolean>;
|
|
31
|
+
/** Custom dataLayer name */
|
|
32
|
+
dataLayerName?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const {
|
|
36
|
+
containers,
|
|
37
|
+
host = DEFAULT_GTM_HOST,
|
|
38
|
+
defaultQueryParams,
|
|
39
|
+
iframeAttributes,
|
|
40
|
+
dataLayerName = 'dataLayer'
|
|
41
|
+
} = Astro.props;
|
|
42
|
+
|
|
43
|
+
const noscripts = generateNoscriptTags({
|
|
44
|
+
containers,
|
|
45
|
+
host,
|
|
46
|
+
defaultQueryParams,
|
|
47
|
+
iframeAttributes,
|
|
48
|
+
dataLayerName
|
|
49
|
+
});
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
{noscripts.map((ns) => (
|
|
53
|
+
<noscript>
|
|
54
|
+
<iframe src={ns.src} {...ns.attributes} />
|
|
55
|
+
</noscript>
|
|
56
|
+
))}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* GTM Script Component
|
|
4
|
+
*
|
|
5
|
+
* Renders the GTM script tag(s) in the document head.
|
|
6
|
+
* Use this in your <head> section.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```astro
|
|
10
|
+
* ---
|
|
11
|
+
* import { GtmScript } from '@jwiedeman/gtm-kit-astro/components';
|
|
12
|
+
* ---
|
|
13
|
+
* <head>
|
|
14
|
+
* <GtmScript containers="GTM-XXXXXX" />
|
|
15
|
+
* </head>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import type { ContainerConfigInput, ScriptAttributes } from '@jwiedeman/gtm-kit';
|
|
19
|
+
import {
|
|
20
|
+
generateScriptTags,
|
|
21
|
+
generateDataLayerScript,
|
|
22
|
+
DEFAULT_GTM_HOST
|
|
23
|
+
} from './helpers';
|
|
24
|
+
|
|
25
|
+
export interface Props {
|
|
26
|
+
/** GTM container ID(s) - single string or array */
|
|
27
|
+
containers: ContainerConfigInput | ContainerConfigInput[];
|
|
28
|
+
/** GTM host URL */
|
|
29
|
+
host?: string;
|
|
30
|
+
/** Query parameters to add to all containers */
|
|
31
|
+
defaultQueryParams?: Record<string, string | number | boolean>;
|
|
32
|
+
/** Script tag attributes (async, defer, nonce, etc.) */
|
|
33
|
+
scriptAttributes?: ScriptAttributes;
|
|
34
|
+
/** Custom dataLayer name */
|
|
35
|
+
dataLayerName?: string;
|
|
36
|
+
/** Whether to include dataLayer initialization script */
|
|
37
|
+
initDataLayer?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const {
|
|
41
|
+
containers,
|
|
42
|
+
host = DEFAULT_GTM_HOST,
|
|
43
|
+
defaultQueryParams,
|
|
44
|
+
scriptAttributes,
|
|
45
|
+
dataLayerName = 'dataLayer',
|
|
46
|
+
initDataLayer = true
|
|
47
|
+
} = Astro.props;
|
|
48
|
+
|
|
49
|
+
const scripts = generateScriptTags({
|
|
50
|
+
containers,
|
|
51
|
+
host,
|
|
52
|
+
defaultQueryParams,
|
|
53
|
+
scriptAttributes,
|
|
54
|
+
dataLayerName
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const dataLayerInit = initDataLayer ? generateDataLayerScript(dataLayerName) : null;
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
{dataLayerInit && <script is:inline set:html={dataLayerInit} />}
|
|
61
|
+
{scripts.map((script) => (
|
|
62
|
+
<script
|
|
63
|
+
src={script.src}
|
|
64
|
+
async={script.async}
|
|
65
|
+
defer={script.defer}
|
|
66
|
+
nonce={script.nonce}
|
|
67
|
+
data-gtm-container-id={script.id}
|
|
68
|
+
{...script.attributes}
|
|
69
|
+
/>
|
|
70
|
+
))}
|