diff --git a/CLAUDE.md b/CLAUDE.md index 9d09ddf3..45865911 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -85,6 +85,7 @@ Each export is built from the source file below (`dist/.js`, see abov |---|---| | `@decocms/blocks` | `src/index.ts` — the v8 runtime API only (`createCMS`, `currentClient`, `matchRoute`, `remoteLoader`, `parseDraftPointer`, `Blocks`, `Lazy`, …; a client is `cms.client({ version, visitor, date, experiments, campaigns })`, with `forRelease()`/`forDraft(p)` as shortcuts; the preview helpers are `cms.readVersion` (→ `{ version, date?, experiments?, campaigns? }`, spread into `cms.client`; `cms.draftPointer` is its `version` alone)/`cms.draftCookie`, since they check the preview hosts (the current release's `previewHosts`, which Studio writes into the release metadata, plus `createCMS({ preview: { hosts } })`; every host while a site has published no list, or with no `site` and no `preview.hosts`); `parseVersion` is the same reading without the host check, for the bindings), re-exported from `src/v8/index.ts` as one explicit `export { … } from "./v8/index.ts"` block (a conformance test parses that form) | | `@decocms/blocks/analytics` | `src/v8/analytics.ts` — `AnalyticsScript`, `track` | +| `@decocms/blocks/analytics/client` | `src/v8/analytics/client.ts` — `startAnalytics(options)`: the Deco Analytics client for a v8 site, without the external tag. Importing it touches nothing; in the browser it fills `window.__dq` with the fields the collector writes ahead of `/_dq/a.js`, imports core and then each module named in `options.modules` (one chunk each, so a site downloads only what it starts), and replays what the page queued once every module registered. Resolves to the client's API, or null on the server, when collection is off for the visitor, when anything failed (it never rejects), or the tag's API when the tag booted first. Events go to `/_dq/e` on the page's own host by default, so the collector resolves the site from `Host`. `client.test.ts` holds that its events equal the standalone tag's | | `@decocms/blocks/experiments` | `src/v8/experiments.ts` — who is in which A/B test, pure and isomorphic (no React, no `node:`, no CMS runtime, no module state, no environment reads): `assign(experiments, visitor)` → `{ [name]: boolean }`, `newVisitor`, `parseVisitor`, `serializeVisitor`, `readVisitor(request)` → `{ visitor, cookie }` (the web helper; `cookie` only when the visitor had no id), and the types `Visitor`, `Experiments`, `Assignments` (`experiments.test.ts` pins the runtime names). Nothing calls them for you: the app reads the visitor and passes it to `cms.client({ visitor })`, and the built-in `split-traffic` calls `assign`. A decision is arithmetic (`roll = murmur3_32("name:id") % 10000 / 100`, in when it is under the rounded percentage), so one visitor id serves every test and raising a percentage only adds people. The hash, the roll and the id live in the internal `src/v8/bucketing.ts` (not exported; the tests import it by path). `Visitor` is v7's `deco_segment` (same fields and encoding) plus an `id`, written once when it has none; v7's stored assignments are honoured while their `pct` holds (a missing or `-1` `pct` included), never rewritten. Changing the hash or the pinned vectors in `experiments.test.ts` moves every visitor already allocated: never a test to update | | `@decocms/blocks/fetch` | `src/v8/fetch.ts` — `createInstrumentedFetch` | | `@decocms/blocks/image` | `src/v8/image.ts` — the Deco image CDN's URLs (`decoCdn`), `createImageUrl`, `srcSet`, `parseSrcSet`, `preloadLink` and the generic `ImageProvider` type. Platform-neutral only: no commerce platform's URLs, hosts or detection here (a platform's provider lives in its client package, e.g. `@decocms/apps-vtex/image`). Pure functions, no React, no module state: a site builds one `ImageUrl`; the bindings render it | @@ -144,6 +145,8 @@ v7's pure helpers, for sites moved from v7: each one gives v7's output (latest 7 ### Key boundaries +- **The Deco Analytics client's source lives in `src/v8/analytics/` (`runtime/`, `shared/`), one implementation for two consumers.** decocms/analytics bundles each entry with esbuild into a standalone script that its collector Worker serves at `/_dq/a.js` to every site (v7, checkout and sites outside deco included), and `AnalyticsScript` renders that `