@escape-game-over/atlas 0.1.66 → 0.1.67

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/docs/checks.md CHANGED
@@ -89,6 +89,13 @@ augmentation is real. Both examples carry one:
89
89
  two files in it, and [`b2b`](../examples/b2b/type-tests/wiring.ts) against one
90
90
  with none, where the union is empty and *every* path is rejected.
91
91
 
92
+ Declared analytics events are the other augmentation, and the opposite case:
93
+ nothing is inferred, so a declaration means the same thing here as in a project.
94
+ `type-tests/declared-events.ts` writes one by the package's own name, as a
95
+ project does, and asserts that an undeclared name, missing required data and
96
+ data on an event declared without any all fail. The declaration holds for the
97
+ whole program, so the runtime tests call the names it declares.
98
+
92
99
  ## Runtime tests
93
100
 
94
101
  ```bash
@@ -117,7 +124,7 @@ dependencies at all. Vitest type-checks them itself when it runs them.
117
124
  | `breadcrumbs.test.ts` | the trail, a dropped ancestor, `orphanSegments`, and how a gap is reported |
118
125
  | `jsonld/*.test.ts` | that a `</script>` in any value cannot close the block, each node's shape and `@id`, and how a price table becomes offers |
119
126
  | `analytics.test.ts` | Umami's attributes, its three-state booleans, the `domains` list that would record nothing, and that `consentRequired` answers exactly when a tag was emitted |
120
- | `google-analytics.test.ts` | that consent is denied first and precedes every tag, one loader for many ids, dead `UA-` properties, and the preconnect — once, ahead of the block that writes the loader's URL, never `crossorigin` |
127
+ | `google-analytics.test.ts` | that consent is denied first and precedes every tag, one loader for many ids, dead `UA-` properties, the preconnect — once, ahead of the block that writes the loader's URL, never `crossorigin` — and where `googleEvent` sends, per setting |
121
128
  | `contact.test.ts` | the E.164 a `tel:` needs — trunk zero dropped, spacing stripped — and the displayed form kept |
122
129
  | `hours.test.ts` | collapsing a week into runs, week start changing the answer, and every impossible week that throws |
123
130
  | `money.test.ts` | a bare count widened to a band, the span of a table, and the gaps and overlaps that throw |
@@ -535,6 +535,88 @@ move before this pauses them. Left in, everything still works. `muted` is also
535
535
  set on attach, since no browser will start an unmuted video nobody pressed play
536
536
  on.
537
537
 
538
+ ## Events
539
+
540
+ One function per vendor, all dropped silently where the vendor is not
541
+ configured, not loaded or not permitted — an analytics call must never be the
542
+ reason a page misbehaves.
543
+
544
+ | Function | Names | Consent |
545
+ | -------------- | ------------------------------ | ------------------------------------------ |
546
+ | `googleEvent` | GA4's recommended, or declared | Consent Mode, which Google already applies |
547
+ | `metaEvent` | Meta's standard, or declared | the pixel loads only once granted |
548
+ | `tiktokEvent` | TikTok's standard, or declared | the pixel loads only once granted |
549
+ | `snapEvent` | Snap's standard only | checked on every call |
550
+ | `axonEvent` | Axon's standard only | checked on every call |
551
+ | `umamiEvent` | declared only | none needed: Umami sets no cookie |
552
+ | `dripEvent` | declared only | checked on every call |
553
+ | `clarityEvent` | declared only | none needed: cookieless until granted |
554
+
555
+ **A project declares its own events once**, for every site it builds, by
556
+ merging into the interface each function reads — the arrangement
557
+ `PublicFileRegistry` uses. Each name maps to the data it carries, `undefined` for
558
+ none:
559
+
560
+ ```ts
561
+ // src/events.ts — any file the project's tsconfig includes
562
+ export {};
563
+
564
+ declare module "@escape-game-over/atlas/client" {
565
+ interface GoogleCustomEvents {
566
+ form_submission_contact: undefined;
567
+ form_submission_quote: { readonly room: string };
568
+ }
569
+ interface UmamiEvents {
570
+ "franchise-enquiry": { readonly country: string };
571
+ }
572
+ }
573
+ ```
574
+
575
+ ```ts
576
+ googleEvent("form_submission_contact");
577
+ googleEvent("form_submission_quote", { room: "Tomb" });
578
+ googleEvent("form_submissions_contact"); // does not compile
579
+ ```
580
+
581
+ A name nobody declared does not compile, so a typo cannot quietly become a
582
+ second event in a report — which is why this is not a `string` with the standard
583
+ names offered for autocomplete. Data declared with a required field is required
584
+ at every call. The interfaces are `GoogleCustomEvents`, `MetaCustomEvents`,
585
+ `TikTokCustomEvents`, `UmamiEvents`, `DripEvents` and `ClarityEvents`; Clarity
586
+ carries a name only, so its entries are all `undefined`. Snap and Axon take no
587
+ declarations because they accept no names but their own.
588
+
589
+ **The file must be a module** — the `export {}` above. Without an import or an
590
+ export, `declare module` *replaces* the package's types instead of adding to
591
+ them, and every import from it breaks.
592
+
593
+ **Declared data is sent as written, so it names what the visitor chose, never
594
+ who they are.** Google's terms forbid sending it anything that identifies a
595
+ person — a name, an email, a phone number, a free-text message — and its
596
+ [guidance](https://support.google.com/analytics/answer/6366371) names event
597
+ parameters as the usual leak. The standard parameter types have no field for
598
+ any of those; a declaration is where one would have to be added, deliberately.
599
+
600
+ ### `googleEvent`: where it goes
601
+
602
+ The deployment's `google` settings decide, not the caller. The head script
603
+ defines a global — `GOOGLE_EVENT_GLOBAL`, beside `CONSENT_UPDATE_GLOBAL` and for
604
+ the same reason — that sends:
605
+
606
+ - with `tagIds`: `gtag("event", name, data)`, which `gtag.js` reads;
607
+ - with `containerIds`: `dataLayer.push({ event: name, ...data })`, which is what
608
+ a Tag Manager *Custom Event* trigger listens for — the `dataLayer.push` a
609
+ marketing agency's brief asks for;
610
+ - with both, both. A container that also runs a GA4 tag on the same event then
611
+ counts it twice; that is set up in Tag Manager, where lib cannot see it.
612
+
613
+ The ecommerce events — `purchase`, `add_to_cart`, `view_item` and the rest — go
614
+ to Tag Manager under an `ecommerce` key, after a `{ ecommerce: null }` that
615
+ clears the previous one, which is the shape its GA4 tags read items and revenue
616
+ from. `purchase` does not compile without `value`, `currency` and
617
+ `transaction_id`: without them GA records a sale of nothing, and a reload
618
+ records it again.
619
+
538
620
  ## Testing
539
621
 
540
622
  None of these tests has a document, and none needs one: every module under test
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@escape-game-over/atlas",
3
- "version": "0.1.66",
3
+ "version": "0.1.67",
4
4
  "type": "module",
5
5
  "description": "Typed, data-driven machinery for static multi-locale, multi-deployment Astro sites.",
6
6
  "private": false,