@jwiedeman/gtm-kit-astro 1.1.3 → 1.1.5

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 CHANGED
@@ -326,6 +326,20 @@ Page views are automatically tracked on:
326
326
 
327
327
  ---
328
328
 
329
+ ## Related Packages
330
+
331
+ - **Core**: [@jwiedeman/gtm-kit](https://www.npmjs.com/package/@jwiedeman/gtm-kit) (required)
332
+
333
+ ---
334
+
335
+ ## Support
336
+
337
+ **Have a question, found a bug, or need help?**
338
+
339
+ [Open an issue on GitHub](https://github.com/jwiedeman/GTM-Kit/issues) — we're actively maintaining this project and respond quickly.
340
+
341
+ ---
342
+
329
343
  ## License
330
344
 
331
345
  MIT
@@ -2,7 +2,7 @@
2
2
 
3
3
  var gtmKit = require('@jwiedeman/gtm-kit');
4
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}||[];`;
5
+ var w=r=>/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(r);var C=r=>Object.fromEntries(Object.entries(r).filter(([,e])=>e!=null)),x=r=>{let{containers:e,host:o=gtmKit.DEFAULT_GTM_HOST,defaultQueryParams:c,scriptAttributes:i,dataLayerName:g=gtmKit.DEFAULT_DATA_LAYER_NAME}=r,n=gtmKit.normalizeContainers(e);if(!n.length)throw new Error("At least one GTM container is required.");return n.map(t=>{if(!t.id)throw new Error("Container id is required.");let p={...c,...t.queryParams},l=gtmKit.buildGtmScriptUrl(o,t.id,p,g),{async:a,defer:u,nonce:s,...d}=i!=null?i:{};return {id:t.id,src:l,async:a!=null?a:!0,defer:u,nonce:s,attributes:C(d)}})},E=r=>{let{containers:e,host:o=gtmKit.DEFAULT_GTM_HOST,defaultQueryParams:c,iframeAttributes:i,dataLayerName:g=gtmKit.DEFAULT_DATA_LAYER_NAME}=r,n=gtmKit.normalizeContainers(e);if(!n.length)throw new Error("At least one GTM container is required.");return n.map(t=>{if(!t.id)throw new Error("Container id is required.");let p={...c,...t.queryParams},l=gtmKit.buildGtmNoscriptUrl(o,t.id,p,g),a={...gtmKit.DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,...i},u=Object.fromEntries(Object.entries(a).filter(([,s])=>s!=null).map(([s,d])=>[s,String(d)]));return {id:t.id,src:l,attributes:u}})},h=(r=gtmKit.DEFAULT_DATA_LAYER_NAME)=>{if(!w(r))throw new Error(`Invalid dataLayerName: "${r}". Must be a valid JavaScript identifier (letters, digits, $, _ only, cannot start with a digit).`);return `window.${r}=window.${r}||[];`};
6
6
 
7
7
  Object.defineProperty(exports, 'DEFAULT_GTM_HOST', {
8
8
  enumerable: true,
@@ -24,8 +24,8 @@ Object.defineProperty(exports, 'normalizeContainers', {
24
24
  enumerable: true,
25
25
  get: function () { return gtmKit.normalizeContainers; }
26
26
  });
27
- exports.generateDataLayerScript = G;
28
- exports.generateNoscriptTags = D;
29
- exports.generateScriptTags = h;
27
+ exports.generateDataLayerScript = h;
28
+ exports.generateNoscriptTags = E;
29
+ exports.generateScriptTags = x;
30
30
  //# sourceMappingURL=out.js.map
31
31
  //# sourceMappingURL=index.cjs.map
@@ -1 +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"]}
1
+ {"version":3,"sources":["../../src/components/helpers.ts","../../src/components/index.ts"],"names":["DEFAULT_DATA_LAYER_NAME","DEFAULT_GTM_HOST","DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES","normalizeContainer","normalizeContainers","buildGtmScriptUrl","buildGtmNoscriptUrl","isValidJsIdentifier","value","filterNullish","obj","v","generateScriptTags","config","containers","host","defaultQueryParams","scriptAttributes","dataLayerName","normalized","container","params","src","asyncAttr","defer","nonce","restAttributes","generateNoscriptTags","iframeAttributes","mergedAttributes","attributes","k","generateDataLayerScript"],"mappings":"AAAA,OACE,2BAAAA,EACA,oBAAAC,EACA,sCAAAC,EACA,sBAAAC,EACA,uBAAAC,EACA,qBAAAC,EACA,uBAAAC,MACK,qBAiBA,IAAMC,EAAuBC,GAE3B,6BAA6B,KAAKA,CAAK,EAqBhD,IAAMC,EAAoDC,GACxD,OAAO,YAAY,OAAO,QAAQA,CAAG,EAAE,OAAO,CAAC,CAAC,CAAEC,CAAC,IAAMA,GAAK,IAAI,CAAC,EAuBxDC,EAAsBC,GAA6C,CAC9E,GAAM,CACJ,WAAAC,EACA,KAAAC,EAAOd,EACP,mBAAAe,EACA,iBAAAC,EACA,cAAAC,EAAgBlB,CAClB,EAAIa,EAEEM,EAAaf,EAAoBU,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,EAAMjB,EAAkBU,EAAMK,EAAU,GAAIC,EAAQH,CAAa,EACjE,CAAE,MAAOK,EAAW,MAAAC,EAAO,MAAAC,EAAO,GAAGC,CAAe,EAAIT,GAAA,KAAAA,EAAoB,CAAC,EAEnF,MAAO,CACL,GAAIG,EAAU,GACd,IAAAE,EACA,MAAOC,GAAA,KAAAA,EAAa,GACpB,MAAAC,EACA,MAAAC,EACA,WAAYhB,EAAciB,CAAc,CAC1C,CACF,CAAC,CACH,EAYaC,EACXd,GAGsB,CACtB,GAAM,CACJ,WAAAC,EACA,KAAAC,EAAOd,EACP,mBAAAe,EACA,iBAAAY,EACA,cAAAV,EAAgBlB,CAClB,EAAIa,EAEEM,EAAaf,EAAoBU,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,EAAMhB,EAAoBS,EAAMK,EAAU,GAAIC,EAAQH,CAAa,EACnEW,EAAmB,CACvB,GAAG3B,EACH,GAAG0B,CACL,EAGME,EAAa,OAAO,YACxB,OAAO,QAAQD,CAAgB,EAC5B,OAAO,CAAC,CAAC,CAAElB,CAAC,IAAMA,GAAK,IAAI,EAC3B,IAAI,CAAC,CAACoB,EAAGpB,CAAC,IAAM,CAACoB,EAAG,OAAOpB,CAAC,CAAC,CAAC,CACnC,EAEA,MAAO,CACL,GAAIS,EAAU,GACd,IAAAE,EACA,WAAAQ,CACF,CACF,CAAC,CACH,EAMaE,EAA0B,CAACd,EAAwBlB,IAAoC,CAClG,GAAI,CAACO,EAAoBW,CAAa,EACpC,MAAM,IAAI,MACR,2BAA2BA,CAAa,mGAC1C,EAEF,MAAO,UAAUA,CAAa,WAAWA,CAAa,OACxD,ECnLA,OACE,uBAAAd,EACA,sBAAAD,EACqB,qBAArBE,EACuB,uBAAvBC,MACK","sourcesContent":["import {\n DEFAULT_DATA_LAYER_NAME,\n DEFAULT_GTM_HOST,\n DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,\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 DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,\n normalizeContainer,\n normalizeContainers,\n buildGtmScriptUrl as buildScriptUrl,\n buildGtmNoscriptUrl as buildNoscriptUrl\n};\n\n/**\n * Validate that a string is a valid JavaScript identifier.\n * This prevents XSS attacks through dataLayerName injection.\n */\nexport const isValidJsIdentifier = (value: string): boolean => {\n // Must be a valid JS identifier: starts with letter/$/_, followed by letters/digits/$/_\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(value);\n};\n\n/**\n * Escape a string for safe use in JavaScript string literals.\n * Prevents XSS when interpolating user-provided values into inline scripts.\n */\nexport const escapeJsString = (value: string): string => {\n return value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/'/g, \"\\\\'\")\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n .replace(/</g, '\\\\x3c')\n .replace(/>/g, '\\\\x3e')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n};\n\n/** Filter out null/undefined values from an object */\nconst filterNullish = <T extends Record<string, unknown>>(obj: T): T =>\n Object.fromEntries(Object.entries(obj).filter(([, v]) => v != null)) as T;\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 return {\n id: container.id,\n src,\n async: asyncAttr ?? true,\n defer,\n nonce,\n attributes: filterNullish(restAttributes) as Record<string, string | boolean>\n };\n });\n};\n\nexport interface NoscriptTagData {\n id: string;\n src: string;\n attributes: Record<string, string>;\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 // Filter nullish values and convert to strings\n const attributes = Object.fromEntries(\n Object.entries(mergedAttributes)\n .filter(([, v]) => v != null)\n .map(([k, v]) => [k, String(v)])\n ) as Record<string, string>;\n\n return {\n id: container.id,\n src,\n attributes\n };\n });\n};\n\n/**\n * Generate the dataLayer initialization script.\n * @throws {Error} If dataLayerName is not a valid JavaScript identifier\n */\nexport const generateDataLayerScript = (dataLayerName: string = DEFAULT_DATA_LAYER_NAME): string => {\n if (!isValidJsIdentifier(dataLayerName)) {\n throw new Error(\n `Invalid dataLayerName: \"${dataLayerName}\". Must be a valid JavaScript identifier (letters, digits, $, _ only, cannot start with a digit).`\n );\n }\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"]}
@@ -35,6 +35,7 @@ declare const generateNoscriptTags: (config: Omit<GtmScriptConfig, 'scriptAttrib
35
35
  }) => NoscriptTagData[];
36
36
  /**
37
37
  * Generate the dataLayer initialization script.
38
+ * @throws {Error} If dataLayerName is not a valid JavaScript identifier
38
39
  */
39
40
  declare const generateDataLayerScript: (dataLayerName?: string) => string;
40
41
 
@@ -35,6 +35,7 @@ declare const generateNoscriptTags: (config: Omit<GtmScriptConfig, 'scriptAttrib
35
35
  }) => NoscriptTagData[];
36
36
  /**
37
37
  * Generate the dataLayer initialization script.
38
+ * @throws {Error} If dataLayerName is not a valid JavaScript identifier
38
39
  */
39
40
  declare const generateDataLayerScript: (dataLayerName?: string) => string;
40
41
 
@@ -1,8 +1,8 @@
1
- import { normalizeContainers, buildGtmScriptUrl, buildGtmNoscriptUrl, DEFAULT_DATA_LAYER_NAME, DEFAULT_GTM_HOST } from '@jwiedeman/gtm-kit';
1
+ import { normalizeContainers, buildGtmScriptUrl, buildGtmNoscriptUrl, DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES, DEFAULT_DATA_LAYER_NAME, DEFAULT_GTM_HOST } from '@jwiedeman/gtm-kit';
2
2
  export { DEFAULT_GTM_HOST, buildGtmNoscriptUrl as buildNoscriptUrl, buildGtmScriptUrl as buildScriptUrl, normalizeContainer, normalizeContainers } from '@jwiedeman/gtm-kit';
3
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}||[];`;
4
+ var w=r=>/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(r);var C=r=>Object.fromEntries(Object.entries(r).filter(([,e])=>e!=null)),x=r=>{let{containers:e,host:o=DEFAULT_GTM_HOST,defaultQueryParams:c,scriptAttributes:i,dataLayerName:g=DEFAULT_DATA_LAYER_NAME}=r,n=normalizeContainers(e);if(!n.length)throw new Error("At least one GTM container is required.");return n.map(t=>{if(!t.id)throw new Error("Container id is required.");let p={...c,...t.queryParams},l=buildGtmScriptUrl(o,t.id,p,g),{async:a,defer:u,nonce:s,...d}=i!=null?i:{};return {id:t.id,src:l,async:a!=null?a:!0,defer:u,nonce:s,attributes:C(d)}})},E=r=>{let{containers:e,host:o=DEFAULT_GTM_HOST,defaultQueryParams:c,iframeAttributes:i,dataLayerName:g=DEFAULT_DATA_LAYER_NAME}=r,n=normalizeContainers(e);if(!n.length)throw new Error("At least one GTM container is required.");return n.map(t=>{if(!t.id)throw new Error("Container id is required.");let p={...c,...t.queryParams},l=buildGtmNoscriptUrl(o,t.id,p,g),a={...DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,...i},u=Object.fromEntries(Object.entries(a).filter(([,s])=>s!=null).map(([s,d])=>[s,String(d)]));return {id:t.id,src:l,attributes:u}})},h=(r=DEFAULT_DATA_LAYER_NAME)=>{if(!w(r))throw new Error(`Invalid dataLayerName: "${r}". Must be a valid JavaScript identifier (letters, digits, $, _ only, cannot start with a digit).`);return `window.${r}=window.${r}||[];`};
5
5
 
6
- export { G as generateDataLayerScript, D as generateNoscriptTags, h as generateScriptTags };
6
+ export { h as generateDataLayerScript, E as generateNoscriptTags, x as generateScriptTags };
7
7
  //# sourceMappingURL=out.js.map
8
8
  //# sourceMappingURL=index.js.map
@@ -1 +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"]}
1
+ {"version":3,"sources":["../../src/components/helpers.ts","../../src/components/index.ts"],"names":["DEFAULT_DATA_LAYER_NAME","DEFAULT_GTM_HOST","DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES","normalizeContainer","normalizeContainers","buildGtmScriptUrl","buildGtmNoscriptUrl","isValidJsIdentifier","value","filterNullish","obj","v","generateScriptTags","config","containers","host","defaultQueryParams","scriptAttributes","dataLayerName","normalized","container","params","src","asyncAttr","defer","nonce","restAttributes","generateNoscriptTags","iframeAttributes","mergedAttributes","attributes","k","generateDataLayerScript"],"mappings":"AAAA,OACE,2BAAAA,EACA,oBAAAC,EACA,sCAAAC,EACA,sBAAAC,EACA,uBAAAC,EACA,qBAAAC,EACA,uBAAAC,MACK,qBAiBA,IAAMC,EAAuBC,GAE3B,6BAA6B,KAAKA,CAAK,EAqBhD,IAAMC,EAAoDC,GACxD,OAAO,YAAY,OAAO,QAAQA,CAAG,EAAE,OAAO,CAAC,CAAC,CAAEC,CAAC,IAAMA,GAAK,IAAI,CAAC,EAuBxDC,EAAsBC,GAA6C,CAC9E,GAAM,CACJ,WAAAC,EACA,KAAAC,EAAOd,EACP,mBAAAe,EACA,iBAAAC,EACA,cAAAC,EAAgBlB,CAClB,EAAIa,EAEEM,EAAaf,EAAoBU,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,EAAMjB,EAAkBU,EAAMK,EAAU,GAAIC,EAAQH,CAAa,EACjE,CAAE,MAAOK,EAAW,MAAAC,EAAO,MAAAC,EAAO,GAAGC,CAAe,EAAIT,GAAA,KAAAA,EAAoB,CAAC,EAEnF,MAAO,CACL,GAAIG,EAAU,GACd,IAAAE,EACA,MAAOC,GAAA,KAAAA,EAAa,GACpB,MAAAC,EACA,MAAAC,EACA,WAAYhB,EAAciB,CAAc,CAC1C,CACF,CAAC,CACH,EAYaC,EACXd,GAGsB,CACtB,GAAM,CACJ,WAAAC,EACA,KAAAC,EAAOd,EACP,mBAAAe,EACA,iBAAAY,EACA,cAAAV,EAAgBlB,CAClB,EAAIa,EAEEM,EAAaf,EAAoBU,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,EAAMhB,EAAoBS,EAAMK,EAAU,GAAIC,EAAQH,CAAa,EACnEW,EAAmB,CACvB,GAAG3B,EACH,GAAG0B,CACL,EAGME,EAAa,OAAO,YACxB,OAAO,QAAQD,CAAgB,EAC5B,OAAO,CAAC,CAAC,CAAElB,CAAC,IAAMA,GAAK,IAAI,EAC3B,IAAI,CAAC,CAACoB,EAAGpB,CAAC,IAAM,CAACoB,EAAG,OAAOpB,CAAC,CAAC,CAAC,CACnC,EAEA,MAAO,CACL,GAAIS,EAAU,GACd,IAAAE,EACA,WAAAQ,CACF,CACF,CAAC,CACH,EAMaE,EAA0B,CAACd,EAAwBlB,IAAoC,CAClG,GAAI,CAACO,EAAoBW,CAAa,EACpC,MAAM,IAAI,MACR,2BAA2BA,CAAa,mGAC1C,EAEF,MAAO,UAAUA,CAAa,WAAWA,CAAa,OACxD,ECnLA,OACE,uBAAAd,EACA,sBAAAD,EACqB,qBAArBE,EACuB,uBAAvBC,MACK","sourcesContent":["import {\n DEFAULT_DATA_LAYER_NAME,\n DEFAULT_GTM_HOST,\n DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,\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 DEFAULT_NOSCRIPT_IFRAME_ATTRIBUTES,\n normalizeContainer,\n normalizeContainers,\n buildGtmScriptUrl as buildScriptUrl,\n buildGtmNoscriptUrl as buildNoscriptUrl\n};\n\n/**\n * Validate that a string is a valid JavaScript identifier.\n * This prevents XSS attacks through dataLayerName injection.\n */\nexport const isValidJsIdentifier = (value: string): boolean => {\n // Must be a valid JS identifier: starts with letter/$/_, followed by letters/digits/$/_\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(value);\n};\n\n/**\n * Escape a string for safe use in JavaScript string literals.\n * Prevents XSS when interpolating user-provided values into inline scripts.\n */\nexport const escapeJsString = (value: string): string => {\n return value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/'/g, \"\\\\'\")\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n .replace(/</g, '\\\\x3c')\n .replace(/>/g, '\\\\x3e')\n .replace(/\\u2028/g, '\\\\u2028')\n .replace(/\\u2029/g, '\\\\u2029');\n};\n\n/** Filter out null/undefined values from an object */\nconst filterNullish = <T extends Record<string, unknown>>(obj: T): T =>\n Object.fromEntries(Object.entries(obj).filter(([, v]) => v != null)) as T;\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 return {\n id: container.id,\n src,\n async: asyncAttr ?? true,\n defer,\n nonce,\n attributes: filterNullish(restAttributes) as Record<string, string | boolean>\n };\n });\n};\n\nexport interface NoscriptTagData {\n id: string;\n src: string;\n attributes: Record<string, string>;\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 // Filter nullish values and convert to strings\n const attributes = Object.fromEntries(\n Object.entries(mergedAttributes)\n .filter(([, v]) => v != null)\n .map(([k, v]) => [k, String(v)])\n ) as Record<string, string>;\n\n return {\n id: container.id,\n src,\n attributes\n };\n });\n};\n\n/**\n * Generate the dataLayer initialization script.\n * @throws {Error} If dataLayerName is not a valid JavaScript identifier\n */\nexport const generateDataLayerScript = (dataLayerName: string = DEFAULT_DATA_LAYER_NAME): string => {\n if (!isValidJsIdentifier(dataLayerName)) {\n throw new Error(\n `Invalid dataLayerName: \"${dataLayerName}\". Must be a valid JavaScript identifier (letters, digits, $, _ only, cannot start with a digit).`\n );\n }\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/package.json CHANGED
@@ -1,21 +1,29 @@
1
1
  {
2
2
  "name": "@jwiedeman/gtm-kit-astro",
3
- "version": "1.1.3",
4
- "description": "Astro components and helpers for GTM Kit - Google Tag Manager integration.",
3
+ "version": "1.1.5",
4
+ "description": "Astro components and helpers for GTM Kit - Google Tag Manager integration with View Transitions support.",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/jwiedeman/GTM-Kit.git",
8
8
  "directory": "packages/astro"
9
9
  },
10
+ "homepage": "https://github.com/jwiedeman/GTM-Kit/tree/main/packages/astro#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/jwiedeman/GTM-Kit/issues"
13
+ },
10
14
  "author": "jwiedeman",
11
15
  "keywords": [
12
16
  "gtm",
13
17
  "google-tag-manager",
14
18
  "astro",
15
19
  "astrojs",
16
- "view-transitions"
20
+ "view-transitions",
21
+ "static-site",
22
+ "analytics",
23
+ "tracking"
17
24
  ],
18
25
  "license": "MIT",
26
+ "sideEffects": false,
19
27
  "publishConfig": {
20
28
  "access": "public"
21
29
  },
@@ -26,6 +26,8 @@ import type { ContainerConfigInput, ScriptAttributes, ConsentState } from '@jwie
26
26
  import {
27
27
  generateScriptTags,
28
28
  generateDataLayerScript,
29
+ escapeJsString,
30
+ isValidJsIdentifier,
29
31
  DEFAULT_GTM_HOST
30
32
  } from './helpers';
31
33
 
@@ -72,8 +74,17 @@ let initScript = generateDataLayerScript(dataLayerName);
72
74
 
73
75
  // Add consent defaults if provided
74
76
  if (defaultConsent) {
77
+ // Validate consent keys are valid identifiers and escape values to prevent XSS
75
78
  const consentEntries = Object.entries(defaultConsent)
76
- .map(([key, value]) => `'${key}':'${value}'`)
79
+ .map(([key, value]) => {
80
+ // Consent keys should be valid identifiers (e.g., 'ad_storage', 'analytics_storage')
81
+ if (!isValidJsIdentifier(key)) {
82
+ throw new Error(`Invalid consent key: "${key}". Must be a valid JavaScript identifier.`);
83
+ }
84
+ // Escape the value to prevent XSS
85
+ const escapedValue = escapeJsString(String(value));
86
+ return `'${key}':'${escapedValue}'`;
87
+ })
77
88
  .join(',');
78
89
  initScript += `${dataLayerName}.push(['consent','default',{${consentEntries}}]);`;
79
90
  }