@escape-game-over/atlas 0.1.7 → 0.1.9

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
@@ -359,7 +359,8 @@ src/ the package — see the export map above for what is reachable
359
359
  jsonld/ the @graph — one file per node, each linked to Google's docs
360
360
  i18n/ defineMessages(), t(), placeholder extraction
361
361
  routes/ defineRoutes(), routeFamily(), merging and collisions
362
- analytics/ Umami and Google, and the Consent Mode defaults
362
+ analytics/ Umami and Google, the Consent Mode defaults, and whether a
363
+ visitor has to be asked anything at all
363
364
  astro/ the only framework-aware code, plus the one component
364
365
  bin/ the `atlas` CLI
365
366
  tests/ runtime behaviour — what a merge resolves to, what a builder rejects
package/docs/NOT-BUILT.md CHANGED
@@ -312,6 +312,13 @@ visitor changes their mind. Those are product and legal decisions that differ
312
312
  per deployment, and a template that guessed at them would be guessing at
313
313
  somebody's compliance.
314
314
 
315
+ **One part of it is lib's, and is built as of August 2026: whether there should
316
+ be a banner at all.** `consentRequired(analytics)`, with the reasoning in
317
+ `src/analytics/index.ts`. It sits here rather than in each project because it is
318
+ a question about *tags* — which lib owns — wearing the costume of a question
319
+ about banners, and because the obvious check is wrong in both directions.
320
+ Everything above about the banner itself still stands.
321
+
315
322
  The seam between the halves is a global — `CONSENT_UPDATE_GLOBAL` — because
316
323
  that is the only place they *can* meet: the head script runs before any module
317
324
  exists. lib emits an updater covering exactly the signals it defaulted, so a
@@ -326,6 +333,28 @@ Note the shape sibling projects use, and do not copy it: they group
326
333
  key. Verification is a `<meta>` proving ownership; analytics is a script. One
327
334
  config block, two different kinds of thing.
328
335
 
336
+ ### Should lib preload the analytics scripts, not just open the connection?
337
+
338
+ **No — and the connection is already opened, which is the part worth having.**
339
+ `preconnect`, built as of August 2026; see `AnalyticsTag` in
340
+ `src/analytics/tags.ts` for how and why.
341
+
342
+ The reason to stop there is priority. A preload does not merely start a fetch
343
+ earlier, it raises what that fetch competes with — and what would be raised here
344
+ is a third-party analytics script, against the image the page is judged on. The
345
+ tag would arrive sooner by making the LCP arrive later, which is a worse trade
346
+ than the one being fixed. A handshake has no such cost: it is latency with
347
+ nothing else contending for it, so moving it earlier takes nothing from
348
+ anything.
349
+
350
+ Two traps live with this, both spelled out where the code is. A preconnect is
351
+ reused only by a request whose CORS mode matches it, so one marked
352
+ `crossorigin` for a classic `<script src>` warms nothing while looking entirely
353
+ correct — fonts are the opposite case, and the two must not be copied between.
354
+ And Tag Manager's loader URL is written *by* the inline block, so nothing in the
355
+ markup names that origin until the script has run, which is what makes the
356
+ connection worth stating rather than leaving to the preload scanner.
357
+
329
358
  ### Should a room be an `Event`?
330
359
 
331
360
  **No.**
package/docs/checks.md CHANGED
@@ -105,27 +105,27 @@ They are **excluded from the type check**, because they import `vitest` and that
105
105
  command's promise is that the package type-checks with no ambient types and no
106
106
  dependencies at all. Vitest type-checks them itself when it runs them.
107
107
 
108
- | File | What it pins |
109
- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
110
- | `meta.test.ts` | the `robots` tag a policy builds, the pinned `twitter:card`, share-image warnings, length warnings, `fileUrl` |
111
- | `not-found.test.ts` | that a 404 carries the site's icon and theme colour, still names no canonical, and is held to the same icon rules |
112
- | `redirects.test.ts` | rule resolution for all three target kinds, the five rejections, the Cloudflare 2000-rule cap |
113
- | `sitemap.test.ts` | splitting into an index plus numbered parts, and that the entry keeps its name either way |
114
- | `merge.test.ts` | catalog and route overlay precedence — per locale, never per key |
115
- | `llms.test.ts` | section grouping, owners, heading and link precedence, and the undescribed fallback |
116
- | `public-files.test.ts` | walking `public/`, what is skipped, and why the declaration must be a module |
117
- | `breadcrumbs.test.ts` | the trail, a dropped ancestor, `orphanSegments`, and how a gap is reported |
118
- | `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
- | `analytics.test.ts` | Umami's attributes, its three-state booleans, and the `domains` list that would record nothing |
120
- | `google-analytics.test.ts` | that consent is denied first and precedes every tag, one loader for many ids, and dead `UA-` properties |
121
- | `contact.test.ts` | the E.164 a `tel:` needs — trunk zero dropped, spacing stripped — and the displayed form kept |
122
- | `hours.test.ts` | collapsing a week into runs, week start changing the answer, and every impossible week that throws |
123
- | `money.test.ts` | a bare count widened to a band, the span of a table, and the gaps and overlaps that throw |
124
- | `url.test.ts` | joining an origin to a path exactly once, and normalising the origin an `@id` is built from |
125
- | `warn.test.ts` | the shared prefix, and reducing a URL to its path |
126
- | `filters.test.ts` | folding both sides of a query, how each kind narrows, the four URL decisions, and attach/detach |
127
- | `filters-view.test.ts` | the write-back into the input and that it is skipped when unchanged, clear taking focus, and the nesting order |
128
- | `build-cache.test.ts` | that an unset `CI_ASTRO_CACHE` yields nothing, so Astro's own `cacheDir` default survives |
108
+ | File | What it pins |
109
+ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
110
+ | `meta.test.ts` | the `robots` tag a policy builds, the pinned `twitter:card`, share-image warnings, length warnings, `fileUrl` |
111
+ | `not-found.test.ts` | that a 404 carries the site's icon and theme colour, still names no canonical, and is held to the same icon rules |
112
+ | `redirects.test.ts` | rule resolution for all three target kinds, the five rejections, the Cloudflare 2000-rule cap |
113
+ | `sitemap.test.ts` | splitting into an index plus numbered parts, and that the entry keeps its name either way |
114
+ | `merge.test.ts` | catalog and route overlay precedence — per locale, never per key |
115
+ | `llms.test.ts` | section grouping, owners, heading and link precedence, and the undescribed fallback |
116
+ | `public-files.test.ts` | walking `public/`, what is skipped, and why the declaration must be a module |
117
+ | `breadcrumbs.test.ts` | the trail, a dropped ancestor, `orphanSegments`, and how a gap is reported |
118
+ | `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
+ | `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` |
121
+ | `contact.test.ts` | the E.164 a `tel:` needs — trunk zero dropped, spacing stripped — and the displayed form kept |
122
+ | `hours.test.ts` | collapsing a week into runs, week start changing the answer, and every impossible week that throws |
123
+ | `money.test.ts` | a bare count widened to a band, the span of a table, and the gaps and overlaps that throw |
124
+ | `url.test.ts` | joining an origin to a path exactly once, and normalising the origin an `@id` is built from |
125
+ | `warn.test.ts` | the shared prefix, and reducing a URL to its path |
126
+ | `filters.test.ts` | folding both sides of a query, how each kind narrows, the four URL decisions, and attach/detach |
127
+ | `filters-view.test.ts` | the write-back into the input and that it is skipped when unchanged, clear taking focus, and the nesting order |
128
+ | `build-cache.test.ts` | that an unset `CI_ASTRO_CACHE` yields nothing, so Astro's own `cacheDir` default survives |
129
129
 
130
130
  The fixture carries two nested families for `breadcrumbs.test.ts`, differing in
131
131
  the only way that changes behaviour: `guides` has a route owning its bare slug
@@ -35,6 +35,15 @@ attribute name in this package has to be matched by any consumer.
35
35
  | `./astro/dom` | scoped `one`/`all` lookups, typed | the selectors |
36
36
  | `./astro/dev-log` | a panel a failed wiring can announce itself in, in dev only | calling it behind `import.meta.env.DEV` |
37
37
 
38
+ `./astro/consent` is the only one of these with a build-time half. Its
39
+ `consentApplies()` reports whether there is a Google tag to consent to, which a
40
+ banner has to know — but it can only answer once it has been downloaded, so a
41
+ project that asks it alone ships the banner's script to every page to be told,
42
+ three requests later, that there was nothing to ask about. `consentRequired()`
43
+ from the package root is the same question at build time: false, and the banner
44
+ never reaches the HTML. Gate the render on that and keep the runtime check for
45
+ the banner that is rendered. See NOT-BUILT.md on where the halves divide.
46
+
38
47
  ## Lifetimes are the recurring bug
39
48
 
40
49
  Every module here that binds a listener hands back the undo, and the undo is
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@escape-game-over/atlas",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "type": "module",
5
5
  "description": "Typed, data-driven machinery for static multi-locale, multi-deployment Astro sites.",
6
6
  "private": false,
@@ -53,10 +53,10 @@
53
53
  "typescript": ">=5"
54
54
  },
55
55
  "devDependencies": {
56
- "@biomejs/biome": "2.5.10",
57
- "@types/node": "26.3.0",
56
+ "@biomejs/biome": "2.5.12",
57
+ "@types/node": "26.4.1",
58
58
  "@vitest/coverage-istanbul": "4.1.11",
59
- "astro": "7.2.7",
59
+ "astro": "7.2.10",
60
60
  "typescript": "6.0.3",
61
61
  "vitest": "4.1.11"
62
62
  }