Skip to content

feat(types-google-analytics): unified GA4 + GTM dataLayer types#298

Open
stephansama wants to merge 3 commits into
mainfrom
stephansama/ste-56-create-a-google-analytics-types-package
Open

feat(types-google-analytics): unified GA4 + GTM dataLayer types#298
stephansama wants to merge 3 commits into
mainfrom
stephansama/ste-56-create-a-google-analytics-types-package

Conversation

@stephansama

Copy link
Copy Markdown
Owner

Closes STE-56

New @stephansama/google-analytics-types package. Types-only, covers both surfaces (GTM dataLayer.push + GA4 gtag('event', ...)) sharing one event taxonomy.

Exports

  • Gtag — function signature with typed overloads on event name.
  • DataLayerEvent — discriminated union on event covering all 18 recommended events; custom events fall through to { event: string } & Record<string, unknown>.
  • GA4EventParamsMap + per-event interfaces (extend via module augmentation for custom events).
  • GA4Item — shared ecommerce item shape.

Window augmentation

Augments Window with typed dataLayer + gtag properties — no extra imports at call sites.

Tests

4 type-level assertions via expectTypeOf covering gtag overload shape, custom-event acceptance, DataLayerEvent union, and the EventName↔Map identity.

Acceptance criteria

  • dataLayer push payload types (GTM)
  • gtag('event', ...) signature types (GA4)
  • 17 recommended-event params (add_payment_info → view_promotion)
  • Window augmentation
  • Extension via module augmentation
  • README example
  • Type tests
  • Zero runtime, sideEffects:false

@vercel

vercel Bot commented May 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
packages Ready Ready Preview, Comment May 18, 2026 4:47am

@changeset-bot

changeset-bot Bot commented May 18, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 4e92a5b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@stephansama/types-google-analytics Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Rate limit exceeded

@stephansama has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 56 minutes and 41 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 24a5b31e-4e3b-4810-ad5b-73aca1d148ad

📥 Commits

Reviewing files that changed from the base of the PR and between f264d7d and 4e92a5b.

📒 Files selected for processing (1)
  • .changeset/types-google-analytics-initial.md
📝 Walkthrough

Walkthrough

This PR introduces a new TypeScript types-only package @stephansama/types-google-analytics providing type-safe definitions for GA4 gtag event calls and GTM dataLayer payloads, with comprehensive event parameter interfaces, Window augmentation, build configuration, and validation tests.

Changes

New types-google-analytics Package

Layer / File(s) Summary
TypeScript Build Configuration
core/types-google-analytics/tsconfig.json, core/types-google-analytics/tsconfig.build.json
Establishes TypeScript compilation with src source scope, dist output, declaration emission, composite builds, and build-time exclusion of test files.
GA4 and GTM Type Contracts
core/types-google-analytics/src/index.ts
Defines DataLayerEvent discriminated union for GTM payloads, canonical GA4EventParamsMap with typed parameter interfaces for add-to-cart, checkout, purchase, search, authentication, and promotional events, overloaded Gtag interface supporting both GA4 recommended and custom events, and Window augmentation for dataLayer and gtag.
Type Validation Tests and Documentation
core/types-google-analytics/src/index.test.ts, core/types-google-analytics/README.md
Vitest type assertions verify Gtag overloads, DataLayerEvent shape, and GA4EventName alignment with EventParamsMap. Package README documents exports, usage examples, covered GA4 event names, and Window augmentation behavior.
Package Configuration and Workspace Registration
core/types-google-analytics/package.json, README.md
Configures ES module package with type declaration exports, build/lint scripts, Node engine >=24, and publish settings. Updates root workspace table with package entry, npm badges, and README link.

🎯 2 (Simple) | ⏱️ ~10 minutes

🐰 A types package hops into the warren,
With GA4 events all properly declared,
Each gtag call now blessed with safety,
Window knows its dataLayer, rare and stately—
Type-checked analytics, precision squared! 📊✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: introducing unified TypeScript types for both GA4 and GTM dataLayer, which is the primary purpose of this new types-only package.
Description check ✅ Passed The description is comprehensive with clear sections (Exports, Window augmentation, Tests, Acceptance criteria) that explain the package purpose, API surface, and implementation details, though it deviates from the repository's template by adding custom sections instead of using the provided checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch stephansama/ste-56-create-a-google-analytics-types-package

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented May 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@pkg-pr-new

pkg-pr-new Bot commented May 18, 2026

Copy link
Copy Markdown

Open in StackBlitz

@stephansama/ai-commit-msg

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/ai-commit-msg@298

@stephansama/alfred-kaomoji

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/alfred-kaomoji@298

@stephansama/astro-iconify-svgmap

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/astro-iconify-svgmap@298

@stephansama/auto-readme

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/auto-readme@298

@stephansama/catppuccin-jsonresume-theme

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/catppuccin-jsonresume-theme@298

@stephansama/catppuccin-opml

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/catppuccin-opml@298

@stephansama/catppuccin-rss

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/catppuccin-rss@298

@stephansama/catppuccin-typedoc

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/catppuccin-typedoc@298

@stephansama/catppuccin-xsl

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/catppuccin-xsl@298

@stephansama/eslint-config

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/eslint-config@298

create-stephansama-example

pnpm add https://pkg.pr.new/stephansama/packages/create-stephansama-example@298

@stephansama/find-makefile-targets

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/find-makefile-targets@298

@stephansama/github-env

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/github-env@298

@stephansama/multipublish

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/multipublish@298

@stephansama/pnpm-hooks

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/pnpm-hooks@298

@stephansama/prettier-plugin-handlebars

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/prettier-plugin-handlebars@298

@stephansama/remark-asciinema

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/remark-asciinema@298

@stephansama/single-file

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/single-file@298

@stephansama/svelte-social-share-links

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/svelte-social-share-links@298

@stephansama/typed-env

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/typed-env@298

@stephansama/typed-events

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/typed-events@298

@stephansama/typed-nocodb-api

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/typed-nocodb-api@298

@stephansama/typed-templates

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/typed-templates@298

@stephansama/types-github-action-env

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/types-github-action-env@298

@stephansama/types-google-analytics

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/types-google-analytics@298

@stephansama/types-lhci

pnpm add https://pkg.pr.new/stephansama/packages/@stephansama/types-lhci@298

commit: 4e92a5b

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces @stephansama/google-analytics-types, a new types-only package providing TypeScript definitions for Google Tag Manager's dataLayer and GA4's gtag events. The package includes interfaces for recommended GA4 events, ecommerce items, and global window augmentation. Feedback from the review highlights that the DataLayerEvent union is currently too broad, which bypasses strict validation for specific events. Additionally, the Node.js engine requirement needs to be adjusted to a supported version, and the items field in the purchase event should be marked as required to align with GA4 documentation.

Comment on lines +21 to +25
export type DataLayerEvent =
| (Record<string, unknown> & { event: string })
| {
[K in GA4EventName]: GA4EventParamsMap[K] & { event: K };
}[GA4EventName];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current definition of DataLayerEvent includes a catch-all (Record<string, unknown> & { event: string }). Because this is a union, TypeScript will match any object with an event property against this broad type, effectively disabling validation for the recommended GA4 events (e.g., a purchase event missing required fields will not trigger an error).

To ensure strict typing and validation, the catch-all should be removed. Users can still support custom events by extending the GA4EventParamsMap interface via module augmentation, as noted in your documentation.

export type DataLayerEvent = {
	[K in GA4EventName]: GA4EventParamsMap[K] & { event: K };
}[GA4EventName];

"tsdown": "catalog:"
},
"engines": {
"node": ">=24"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Node.js engine requirement is set to >=24, but Node.js 24 has not been released yet (Node 22 is the current LTS and Node 23 is the current stable). This will prevent the package from being installed on most current environments. You likely intended to target >=20 or >=22.

Suggested change
"node": ">=24"
"node": ">=22"

export interface GA4PurchaseEventParams {
coupon?: string;
currency: string;
items?: GA4Item[];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to the GA4 recommended events reference, the items parameter is required for the purchase event.

Suggested change
items?: GA4Item[];
items: GA4Item[];

@stephansama stephansama changed the title feat(google-analytics-types): unified GA4 + GTM dataLayer types feat(types-google-analytics): unified GA4 + GTM dataLayer types May 18, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/types-google-analytics/package.json`:
- Around line 47-49: The package.json currently pins the "engines" field to
"node": ">=24", which is unnecessarily restrictive for a types-only package (see
"sideEffects": false); update the package.json by either removing the "engines"
entry entirely or relaxing it to a broader LTS range such as "node": ">=18" so
consumers on Node 18/20/22 can install the package; locate and edit the
"engines" object/string in the package.json to apply this change.

In `@core/types-google-analytics/README.md`:
- Line 1: Update the README title in README.md to use the correct package name:
replace the current "`@stephansama/google-analytics-types`" heading with
"`@stephansama/types-google-analytics`" so it matches the package and directory
naming (verify the top-line H1 string and any other occurrences in the file).

In `@core/types-google-analytics/src/index.test.ts`:
- Line 14: The test suite description string in the unit test (the describe(...)
call in index.test.ts) uses the wrong package name; change the describe label
from "`@stephansama/google-analytics-types`" to the correct package name
"`@stephansama/types-google-analytics`" so it matches the directory and PR
metadata (update the string inside the describe call).
- Around line 25-29: Replace the loose structural check on
GA4PurchaseEventParameters with an assertion that the actual gtag invocation was
type-checked: assert that the third parameter type of the gtag call (e.g.
Parameters<typeof gtag>[2]) matches the expected shape (properties currency:
string, transaction_id: string, value: number). Update the test to use
expectTypeOf on Parameters<typeof gtag>[2] (or the appropriate call signature
type) against the GA4PurchaseEventParameters shape so the overload resolution
for the gtag call is validated directly.
- Around line 6-7: Remove the unnecessary type aliases in the import: stop
importing GA4EventParametersMap and GA4PurchaseEventParameters as aliases and
import the actual exported names GA4EventParamsMap and GA4PurchaseEventParams
directly; then replace any uses of the alias identifiers (GA4EventParametersMap,
GA4PurchaseEventParameters) in the test file with the real names
GA4EventParamsMap and GA4PurchaseEventParams (these occur where the aliases were
referenced later in the file).

In `@core/types-google-analytics/src/index.ts`:
- Around line 167-171: The loose custom-event overload for the Gtag type
currently allows any string (including known GA4EventName) and should be
narrowed so known event names are forced to use the strongly-typed overload;
update the second overload signature for Gtag (the one with command: "event") to
use name: Exclude<string, GA4EventName> so that known GA4EventName values bind
to the strict first overload that uses GA4EventParamsMap, preventing accidental
bypass of the typed params checks.
- Around line 21-25: DataLayerEvent's first union branch (Record<string,
unknown> & { event: string }) is too permissive and lets known GA4 event names
(e.g. "purchase") match that branch and bypass the stricter
GA4PurchaseEventParams; change that branch so its event property excludes
GA4EventName (e.g. { event: Exclude<string, GA4EventName> } or Record<string,
unknown> & { event: Exclude<string, GA4EventName> }) so that known GA4EventName
values are forced to match the GA4EventParamsMap lookup branch (refer to
DataLayerEvent, GA4EventName, GA4EventParamsMap).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: dc1dfb74-7d4b-4e42-a3cd-f4468c4cc140

📥 Commits

Reviewing files that changed from the base of the PR and between 9a84b42 and f264d7d.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • README.md
  • core/types-google-analytics/README.md
  • core/types-google-analytics/package.json
  • core/types-google-analytics/src/index.test.ts
  • core/types-google-analytics/src/index.ts
  • core/types-google-analytics/tsconfig.build.json
  • core/types-google-analytics/tsconfig.json

Comment on lines +47 to +49
"engines": {
"node": ">=24"
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Unnecessarily restrictive Node engine requirement for a types-only package.

Requiring Node >=24 will block adoption by projects using Node 18 LTS, Node 20 LTS, or Node 22 LTS. Since this is a types-only package with no runtime dependencies and sideEffects: false, there is no technical reason to require such a recent Node version. TypeScript type definitions are consumed at compile time and do not depend on Node runtime features.

📦 Recommended fix to support LTS Node versions
   "engines": {
-    "node": ">=24"
+    "node": ">=18"
   },

Alternatively, if you have a specific reason for requiring Node 24+, consider omitting the engines field entirely for maximum compatibility.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"engines": {
"node": ">=24"
},
"engines": {
"node": ">=18"
},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/types-google-analytics/package.json` around lines 47 - 49, The
package.json currently pins the "engines" field to "node": ">=24", which is
unnecessarily restrictive for a types-only package (see "sideEffects": false);
update the package.json by either removing the "engines" entry entirely or
relaxing it to a broader LTS range such as "node": ">=18" so consumers on Node
18/20/22 can install the package; locate and edit the "engines" object/string in
the package.json to apply this change.

@@ -0,0 +1,36 @@
# @stephansama/google-analytics-types

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix package name to match directory structure.

The README title shows @stephansama/google-analytics-types, but the PR summary and directory path (core/types-google-analytics/) indicate the correct package name is @stephansama/types-google-analytics. The word order is reversed.

🐛 Correct the package name
-# `@stephansama/google-analytics-types`
+# `@stephansama/types-google-analytics`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# @stephansama/google-analytics-types
# `@stephansama/types-google-analytics`
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/types-google-analytics/README.md` at line 1, Update the README title in
README.md to use the correct package name: replace the current
"`@stephansama/google-analytics-types`" heading with
"`@stephansama/types-google-analytics`" so it matches the package and directory
naming (verify the top-line H1 string and any other occurrences in the file).

Comment on lines +6 to +7
GA4EventParamsMap as GA4EventParametersMap,
GA4PurchaseEventParams as GA4PurchaseEventParameters,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Remove unnecessary type aliases.

The aliases GA4EventParametersMap and GA4PurchaseEventParameters are inconsistent with the actual exported type names (GA4EventParamsMap and GA4PurchaseEventParams). This renaming from "Params" to "Parameters" creates confusion without adding value.

♻️ Simplify imports by removing aliases
 import type {
 	DataLayerEvent,
 	GA4EventName,
-	GA4EventParamsMap as GA4EventParametersMap,
-	GA4PurchaseEventParams as GA4PurchaseEventParameters,
+	GA4EventParamsMap,
+	GA4PurchaseEventParams,
 	Gtag,
 } from "./index";

Then update line 25 and line 48:

-		expectTypeOf<GA4PurchaseEventParameters>().toMatchTypeOf<{
+		expectTypeOf<GA4PurchaseEventParams>().toMatchTypeOf<{
-		expectTypeOf<GA4EventName>().toEqualTypeOf<
-			keyof GA4EventParametersMap
-		>();
+		expectTypeOf<GA4EventName>().toEqualTypeOf<keyof GA4EventParamsMap>();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/types-google-analytics/src/index.test.ts` around lines 6 - 7, Remove the
unnecessary type aliases in the import: stop importing GA4EventParametersMap and
GA4PurchaseEventParameters as aliases and import the actual exported names
GA4EventParamsMap and GA4PurchaseEventParams directly; then replace any uses of
the alias identifiers (GA4EventParametersMap, GA4PurchaseEventParameters) in the
test file with the real names GA4EventParamsMap and GA4PurchaseEventParams
(these occur where the aliases were referenced later in the file).

// These are type-level assertions — the runtime body of each `it` is empty
// because the value of the test is in `expectTypeOf` at compile time.

describe("@stephansama/google-analytics-types", () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix package name to match directory structure.

The test suite describes @stephansama/google-analytics-types, but the PR summary and directory path (core/types-google-analytics/) indicate the package name should be @stephansama/types-google-analytics. The word order is reversed.

🐛 Correct the package name
-describe("`@stephansama/google-analytics-types`", () => {
+describe("`@stephansama/types-google-analytics`", () => {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
describe("@stephansama/google-analytics-types", () => {
describe("`@stephansama/types-google-analytics`", () => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/types-google-analytics/src/index.test.ts` at line 14, The test suite
description string in the unit test (the describe(...) call in index.test.ts)
uses the wrong package name; change the describe label from
"`@stephansama/google-analytics-types`" to the correct package name
"`@stephansama/types-google-analytics`" so it matches the directory and PR
metadata (update the string inside the describe call).

Comment on lines +25 to +29
expectTypeOf<GA4PurchaseEventParameters>().toMatchTypeOf<{
currency: string;
transaction_id: string;
value: number;
}>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Strengthen type assertion to verify gtag call enforcement.

The current assertion only verifies that the GA4PurchaseEventParams type definition includes certain properties, but doesn't confirm that the gtag call on lines 19-24 was actually type-checked against those requirements. Consider asserting on the call's parameter types directly.

💡 Example of a stronger assertion
-		expectTypeOf<GA4PurchaseEventParams>().toMatchTypeOf<{
-			currency: string;
-			transaction_id: string;
-			value: number;
-		}>();
+		expectTypeOf(gtag).parameter(2).toMatchTypeOf<GA4PurchaseEventParams>();

This approach verifies that the third parameter of the gtag call matches the expected type, confirming the overload resolution works correctly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/types-google-analytics/src/index.test.ts` around lines 25 - 29, Replace
the loose structural check on GA4PurchaseEventParameters with an assertion that
the actual gtag invocation was type-checked: assert that the third parameter
type of the gtag call (e.g. Parameters<typeof gtag>[2]) matches the expected
shape (properties currency: string, transaction_id: string, value: number).
Update the test to use expectTypeOf on Parameters<typeof gtag>[2] (or the
appropriate call signature type) against the GA4PurchaseEventParameters shape so
the overload resolution for the gtag call is validated directly.

Comment on lines +21 to +25
export type DataLayerEvent =
| (Record<string, unknown> & { event: string })
| {
[K in GA4EventName]: GA4EventParamsMap[K] & { event: K };
}[GA4EventName];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify broad branch currently allows known event names.
rg -n -C2 'export type DataLayerEvent|event:\s*string|Exclude<string,\s*GA4EventName>' core/types-google-analytics/src/index.ts

Repository: stephansama/packages

Length of output: 307


🏁 Script executed:

#!/bin/bash
# Find GA4EventName and GA4EventParamsMap definitions
rg -n 'GA4EventName|GA4EventParamsMap' core/types-google-analytics/src/index.ts | head -30

Repository: stephansama/packages

Length of output: 323


🏁 Script executed:

#!/bin/bash
# Get a broader view of the file to understand the type structure
wc -l core/types-google-analytics/src/index.ts

Repository: stephansama/packages

Length of output: 109


🏁 Script executed:

#!/bin/bash
# Read the GA4EventParamsMap definition and context around DataLayerEvent
sed -n '45,160p' core/types-google-analytics/src/index.ts

Repository: stephansama/packages

Length of output: 3542


🏁 Script executed:

#!/bin/bash
# Check for test files or examples using DataLayerEvent
find core/types-google-analytics -name "*.test.*" -o -name "*.spec.*" -o -name "*.example.*" 2>/dev/null | head -10

Repository: stephansama/packages

Length of output: 110


🏁 Script executed:

#!/bin/bash
# Search for any usage or imports of DataLayerEvent
rg -n 'DataLayerEvent' --type ts

Repository: stephansama/packages

Length of output: 375


🏁 Script executed:

#!/bin/bash
# Read the test file to understand type validation
cat -n core/types-google-analytics/src/index.test.ts

Repository: stephansama/packages

Length of output: 1804


DataLayerEvent currently accepts invalid payloads for known GA4 events.

Line 22 makes the union too broad with event: string, allowing { event: "purchase" } to match the first branch and bypass the typed GA4PurchaseEventParams requirements (currency, transaction_id, value are all required).

Proposed fix
 export type DataLayerEvent =
-	| (Record<string, unknown> & { event: string })
+	| (Record<string, unknown> & { event: Exclude<string, GA4EventName> })
 	| {
 			[K in GA4EventName]: GA4EventParamsMap[K] & { event: K };
 	  }[GA4EventName];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/types-google-analytics/src/index.ts` around lines 21 - 25,
DataLayerEvent's first union branch (Record<string, unknown> & { event: string
}) is too permissive and lets known GA4 event names (e.g. "purchase") match that
branch and bypass the stricter GA4PurchaseEventParams; change that branch so its
event property excludes GA4EventName (e.g. { event: Exclude<string,
GA4EventName> } or Record<string, unknown> & { event: Exclude<string,
GA4EventName> }) so that known GA4EventName values are forced to match the
GA4EventParamsMap lookup branch (refer to DataLayerEvent, GA4EventName,
GA4EventParamsMap).

Comment on lines +167 to +171
(
command: "event",
name: string,
parameters?: Record<string, unknown>,
): void;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the custom overload is currently unconstrained.
rg -n -C2 'command:\s*"event"|name:\s*string|Exclude<string,\s*GA4EventName>' core/types-google-analytics/src/index.ts

Repository: stephansama/packages

Length of output: 398


🏁 Script executed:

# First, let's look at the complete Gtag type definition and understand the context
cat -n core/types-google-analytics/src/index.ts | head -200

Repository: stephansama/packages

Length of output: 7631


🏁 Script executed:

# Find where GA4EventName is defined
rg -n 'GA4EventName' core/types-google-analytics/src/index.ts | head -20

Repository: stephansama/packages

Length of output: 240


🏁 Script executed:

# Check imports and type definitions at the top of the file
head -50 core/types-google-analytics/src/index.ts

Repository: stephansama/packages

Length of output: 2067


🏁 Script executed:

# Check if there are any tests or usage examples that might show the impact
rg -n 'gtag' core/types-google-analytics/src/index.ts

Repository: stephansama/packages

Length of output: 206


🏁 Script executed:

# Look for any test files or examples to understand usage patterns
fd -e test -e spec -e example core/types-google-analytics

Repository: stephansama/packages

Length of output: 478


🏁 Script executed:

# Search for test files in the core/types-google-analytics directory
fd -e test -e spec -e example . core/types-google-analytics

Repository: stephansama/packages

Length of output: 46


🏁 Script executed:

# Check the package structure and see if there are any test files
ls -la core/types-google-analytics/

Repository: stephansama/packages

Length of output: 489


Strengthen custom-event overload to exclude known GA4 event names from loose typing.

The second Gtag overload accepts name: string which includes known event names from GA4EventName. This allows calls like gtag('event', 'purchase', { invalid: true }) to match the unconstrained overload instead of the strict typed overload that enforces GA4EventParamsMap['purchase'].

Use Exclude<string, GA4EventName> on the second overload to force all known event names to the strict first overload:

Proposed fix
 	/** GA4 custom event with arbitrary params */
 	(
 		command: "event",
-		name: string,
+		name: Exclude<string, GA4EventName>,
 		parameters?: Record<string, unknown>,
 	): void;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
(
command: "event",
name: string,
parameters?: Record<string, unknown>,
): void;
(
command: "event",
name: Exclude<string, GA4EventName>,
parameters?: Record<string, unknown>,
): void;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/types-google-analytics/src/index.ts` around lines 167 - 171, The loose
custom-event overload for the Gtag type currently allows any string (including
known GA4EventName) and should be narrowed so known event names are forced to
use the strongly-typed overload; update the second overload signature for Gtag
(the one with command: "event") to use name: Exclude<string, GA4EventName> so
that known GA4EventName values bind to the strict first overload that uses
GA4EventParamsMap, preventing accidental bypass of the typed params checks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant