@justai/cuts 0.3.0 → 0.3.2

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.
Files changed (2) hide show
  1. package/package.json +2 -2
  2. package/src/Base.astro +29 -12
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@justai/cuts",
3
- "version": "0.3.0",
4
- "description": "A persona's named parts \u2014 the page shell that holds them, and the cuts themselves.",
3
+ "version": "0.3.2",
4
+ "description": "A persona's named parts the page shell that holds them, and the cuts themselves.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
7
7
  "type": "git",
package/src/Base.astro CHANGED
@@ -61,19 +61,28 @@ const localePath = (l: string) => (l === defaultLocale ? "/" : `/${l}/`);
61
61
  <meta charset="utf-8" />
62
62
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
63
63
  <link rel="preconnect" href="https://api.justai.pro" crossorigin />
64
- <!-- detail: reveal only after we've positioned at the Kernel no scroll flash.
65
- Gated behind .js so it's always visible if JS is off. -->
66
- <!-- justai auth: capture the SSO token here, synchronously, BEFORE the scroll-spy rewrites the hash
67
- to #kernel — otherwise it clobbers #auth_token before the deferred sdk.js can read it. -->
64
+ {/* justai auth: capture the SSO token here, synchronously, BEFORE anything else can touch the
65
+ hash. Its position in the head is LOAD-BEARING, not stylistic, because two later scripts
66
+ would otherwise take the token: the scroll-spy rewrites the hash to #kernel and CLOBBERS
67
+ #auth_token before the deferred sdk.js can read it; and the language picker copies the
68
+ current hash onto the next locale's URL (LangPicker), which would PROPAGATE the raw token
69
+ into a new page and into history. Capturing first defeats both. Move this and sign-in breaks
70
+ silently — no error, the visitor simply lands back signed out. */}
68
71
  <script is:inline>(function(){try{var h=location.hash||"";var m=h.match(/(?:^#|&)auth_token=([^&]+)/);if(m){localStorage.setItem("justai_token",decodeURIComponent(m[1]))}else if(/(?:^#|&)auth_signout=1\b/.test(h)){localStorage.removeItem("justai_token")}else{return}history.replaceState(null,"",location.pathname+location.search)}catch(e){}})();</script>
69
72
  <script is:inline>document.documentElement.classList.add("js")</script>
73
+ {/* Reveal only after a page marks itself ready — gated behind .js so the page is always visible
74
+ if JS is off, and no scroll flash before we position at the Kernel. This style is a TRAP as
75
+ much as a feature, and the warning must stay beside it: ANY page using this layout without a
76
+ kernel script that sets body.ready stays invisible FOREVER. The 404 is the page that keeps
77
+ falling into this — it carries its own inline body.classList.add("ready") for exactly this
78
+ reason. Nothing errors; the page is simply never shown. */}
70
79
  <style is:inline>html.js body{opacity:0}html.js body.ready{opacity:1}</style>
71
- <!-- The locale list is INJECTED, never typed. It used to be a literal array here — a second
80
+ {/* The locale list is INJECTED, never typed. It used to be a literal array here — a second
72
81
  declaration beside src/i18n/index.ts, kept in agreement by hand, in the one place where
73
82
  being wrong is invisible: a locale missing from this list simply never auto-routes, and
74
83
  nothing anywhere goes red. The same shape in astro.config had already drifted (twelve
75
84
  listed while /it/ was live), which is why this one is wired to the real list instead of
76
- being checked against it. -->
85
+ being checked against it. */}
77
86
  <script is:inline define:vars={{ supported: locales, def: defaultLocale }}>
78
87
  // Auto-route to the visitor's language: a saved choice wins; otherwise the browser
79
88
  // language on first visit. Only on the default (en) root — explicit /xx/ links are
@@ -130,7 +139,7 @@ const localePath = (l: string) => (l === defaultLocale ? "/" : `/${l}/`);
130
139
  rel="icon"
131
140
  href={favicon}
132
141
  />
133
- <!-- PWA: Workbox service worker (precache + offline) + installable manifest -->
142
+ {/* PWA: Workbox service worker (precache + offline) + installable manifest */}
134
143
  <link rel="manifest" href="/manifest.webmanifest" />
135
144
  <link rel="apple-touch-icon" href="/icon-192.png" />
136
145
  {import.meta.env.DEV ? (
@@ -153,14 +162,14 @@ const localePath = (l: string) => (l === defaultLocale ? "/" : `/${l}/`);
153
162
  if ("serviceWorker" in navigator) addEventListener("load", () => navigator.serviceWorker.register("/sw.js"));
154
163
  </script>
155
164
  )}
156
- <!-- Google Analytics 4 — anonymous (ad signals + personalization OFF), lazy-loaded after idle.
165
+ {/* Google Analytics 4 — anonymous (ad signals + personalization OFF), lazy-loaded after idle.
157
166
  analytics_storage granted: direct user counting (cookieless modeling needs high traffic to
158
167
  surface, so it shows nothing at low/launch volume).
159
168
 
160
169
  gaId comes through define:vars because this script runs in the BROWSER. An is:inline block
161
170
  has no access to component scope, so a bare `gaId` here would be undefined at runtime and
162
171
  every persona would report to a property that does not exist — silently, with no failed
163
- request and no console error, which is the only kind of analytics bug nobody finds. -->
172
+ request and no console error, which is the only kind of analytics bug nobody finds. */}
164
173
  <script is:inline define:vars={{ gaId }}>
165
174
  window.dataLayer = window.dataLayer || [];
166
175
  function gtag() { dataLayer.push(arguments); }
@@ -169,7 +178,15 @@ const localePath = (l: string) => (l === defaultLocale ? "/" : `/${l}/`);
169
178
  // EEA + UK + CH: deny analytics until the visitor consents (the banner below grants it).
170
179
  gtag("consent", "default", { region: ["AT","BE","BG","HR","CY","CZ","DK","EE","FI","FR","DE","GR","HU","IE","IT","LV","LT","LU","MT","NL","PL","PT","RO","SK","SI","ES","SE","IS","LI","NO","GB","CH"], ad_storage: "denied", ad_user_data: "denied", ad_personalization: "denied", analytics_storage: "denied" });
171
180
  try { var cc0 = localStorage.getItem("consent"); if (cc0) gtag("consent", "update", { analytics_storage: cc0 }); } catch (e) {}
172
- gtag("config", gaId, { cookie_expires: 60 * 60 * 24 * 60, /* two months — matches the GA data retention; the cookie must not outlive the data it labels (foundations/15) */ allow_google_signals: false, allow_ad_personalization_signals: false });
181
+ // page_title is PINNED to the title as it is at load, before anything can touch it. Only one
182
+ // persona mutates document.title today — time shows a live clock in the tab — and without this
183
+ // its analytics reports "13:32 · Amsterdam" as the page name instead of the page. For every
184
+ // other persona it captures the same string the title already has, so it costs nothing and
185
+ // removes a trap the next persona that animates its tab would otherwise walk into.
186
+ //
187
+ // Found by migration: it existed only in time, and the extraction dropped it silently. Nothing
188
+ // errored — the analytics would simply have been wrong from that day on.
189
+ gtag("config", gaId, { cookie_expires: 60 * 60 * 24 * 60, page_title: document.title, /* two months — matches the GA data retention; the cookie must not outlive the data it labels (foundations/15) */ allow_google_signals: false, allow_ad_personalization_signals: false });
173
190
  addEventListener("load", function () {
174
191
  (window.requestIdleCallback || function (f) { setTimeout(f, 1200); })(function () {
175
192
  var s = document.createElement("script");
@@ -182,8 +199,8 @@ const localePath = (l: string) => (l === defaultLocale ? "/" : `/${l}/`);
182
199
  </head>
183
200
  <body>
184
201
  <slot />
185
- <!-- Consent banner — shown only to European-timezone visitors with no stored choice. The
186
- Consent Mode region default already denies analytics for the EEA/UK until "Allow". -->
202
+ {/* Consent banner — shown only to European-timezone visitors with no stored choice. The
203
+ Consent Mode region default already denies analytics for the EEA/UK until "Allow". */}
187
204
  <div id="cc" class="cc" role="dialog" aria-label={t.chromePrivacy}>
188
205
  <div class="cc-card">
189
206
  <p class="cc-text">{t.consentText}</p>