@vskstudio/takt-astro 0.7.0 → 0.9.0

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
@@ -3,7 +3,7 @@
3
3
 
4
4
  > 📚 **Documentation** — [taktlytics.com/docs/wrappers/astro](https://taktlytics.com/docs/wrappers/astro)
5
5
 
6
- Astro integration for [Takt](https://github.com/vskstudio/takt-core), privacy-friendly analytics. It injects a tiny browser runtime that boots Takt, fires the initial pageview, and tracks client-side navigations — including [Astro View Transitions](https://docs.astro.build/en/guides/view-transitions/).
6
+ Astro integration for [Takt](https://github.com/taktlytics/takt-core), privacy-friendly analytics. It injects a tiny browser runtime that boots Takt, fires the initial pageview, and tracks client-side navigations — including [Astro View Transitions](https://docs.astro.build/en/guides/view-transitions/).
7
7
 
8
8
  ## Install
9
9
 
@@ -11,7 +11,7 @@ Astro integration for [Takt](https://github.com/vskstudio/takt-core), privacy-fr
11
11
  pnpm add @vskstudio/takt-astro @vskstudio/takt-core
12
12
  ```
13
13
 
14
- Both are peer dependencies: `astro` (`>=4`) and `@vskstudio/takt-core` (`>=0.9.0`).
14
+ Both are peer dependencies: `astro` (`>=4`) and `@vskstudio/takt-core` (`>=0.10.0`).
15
15
 
16
16
  ## Usage
17
17
 
@@ -62,6 +62,8 @@ Both the integration and the component accept the same options, with one excepti
62
62
  | `trackQuery` | `boolean` | `false` | Keep the full query string and hash instead of stripping them. Wins over `queryParams`. |
63
63
  | `queryParams` | `string[]` | – | Allowlist of query params to keep, applied only when `trackQuery` is off. |
64
64
  | `exclude` | `string[]` | – | Path prefixes never tracked, e.g. `['/app', '/account']` (segment-bounded, checked at send time). |
65
+ | `redactRoutes` | `string[]` | none | Route patterns sent in place of the real path, e.g. `['/verify/[token]']` sends `/verify/[token]` instead of `/verify/abc123`. See [Route redaction](#route-redaction). |
66
+ | `routeTemplates` | `boolean` | `false` | Send every page as its Astro route template (`/blog/[slug]`), read from `Astro.routePattern`. Needs Astro 5 and the route meta, see [Route redaction](#route-redaction). |
65
67
  | `scrubUrl` | `(url: string) => string` | – | **Integration only.** Rewrite each URL before it is sent (page, referrer, and the `url` prop of outbound-link and file-download events), e.g. to strip a fragment or PII. See the note below. |
66
68
  | `tagged` | `boolean` | `false` | Auto-track clicks on `[data-takt-event]` elements; `data-takt-prop-*` attributes become event props. |
67
69
  | `debug` | `boolean` | `false` | Log each payload to the browser console before sending. |
@@ -81,6 +83,42 @@ Both the integration and the component accept the same options, with one excepti
81
83
 
82
84
  Astro's client router runs several history operations per navigation (scroll-restoration `replaceState` plus `pushState`), so Takt does **not** rely on core's history patch here — it would over-count. Instead the runtime fires one explicit initial pageview and then one per Astro `astro:after-swap` event (including View Transitions DOM swaps and back/forward), so each navigation is counted exactly once. On a plain MPA (no client router) the script re-runs per page load, which fires the initial pageview each time. The runtime is SSR/prerender safe — it only runs in the browser.
83
85
 
86
+ ## Route redaction
87
+
88
+ Query strings are stripped by default, but path segments are sent as they are, so `/verify/abc123` leaks the token. List the sensitive routes in `redactRoutes` and every matching path is sent as its pattern, while the other pages keep their real path:
89
+
90
+ ```js
91
+ takt({ redactRoutes: ['/verify/[token]', '/invoices/[id].pdf'] })
92
+ ```
93
+
94
+ The rule covers the page URL, same-origin referrers, outbound and download link destinations, and 404 paths. Patterns use Astro's syntax (`[param]`, `[...rest]`) and also accept `:param` and `*`.
95
+
96
+ To send every page as its route template instead (`/blog/hello` becomes `/blog/[slug]`), turn on `routeTemplates`. Astro knows the template on the server (`Astro.routePattern`), so it travels in a `<meta name="takt:route">` tag that the runtime reads at each pageview, including after a ClientRouter navigation. With the integration, render that tag with `<TaktRoute />` in the `<head>` of your layout:
97
+
98
+ ```js
99
+ // astro.config.mjs
100
+ export default defineConfig({
101
+ integrations: [takt({ routeTemplates: true })],
102
+ })
103
+ ```
104
+
105
+ ```astro
106
+ ---
107
+ import TaktRoute from '@vskstudio/takt-astro/TaktRoute.astro'
108
+ ---
109
+ <head>
110
+ <TaktRoute />
111
+ </head>
112
+ ```
113
+
114
+ The `<Takt />` component renders the tag itself when `routeTemplates` is set:
115
+
116
+ ```astro
117
+ <Takt domain="example.com" routeTemplates />
118
+ ```
119
+
120
+ `Astro.routePattern` exists from Astro 5. On Astro 4 no tag is rendered, so `redactRoutes` still applies and the real path is sent otherwise. This mode merges every article of a public blog into one row, so it suits private areas better; `redactRoutes` is usually the right tool for a public site.
121
+
84
122
  ## Custom events
85
123
 
86
124
  `track`, `pageview`, `optOut`, `optIn` and `isOptedOut` are re-exported from core for convenience. `track` and `pageview` act on core's default instance, which only exists in the browser once the injected runtime has booted, so call them from a client-side `<script>`, not from `.astro` frontmatter (where they are silent no-ops):
@@ -161,7 +199,7 @@ From `@vskstudio/takt-astro`:
161
199
  - Re-exported from core: `track`, `pageview`, `optOut`, `optIn`, `isOptedOut`, `createStats`, `PublicApiError`, `badgeUrl`, `embedUrl`
162
200
  - Types: `TaktOptions`, plus `InitOptions`, `TrackOptions`, `BadgeOptions`, `EmbedOptions`, `BadgeVariant`, `BadgeGlyph`, `EmbedTheme`, `WidgetLang`, `StatsClient`, `StatsClientOptions`, `StatsParams`, `StatsPeriod`, `StatsDimension`, `StatsMetrics`, `StatsSummary`, `StatsPoint`, `StatsTimeseries`, `StatsBreakdownRow`, `StatsBreakdown`, `StatsRealtime` re-exported from core
163
201
 
164
- Component subpaths: `@vskstudio/takt-astro/Takt.astro`, `/Badge.astro`, `/Embed.astro`.
202
+ Component subpaths: `@vskstudio/takt-astro/Takt.astro`, `/TaktRoute.astro`, `/Badge.astro`, `/Embed.astro`.
165
203
 
166
204
  ## License
167
205
 
package/Takt.astro CHANGED
@@ -17,7 +17,10 @@ const config = JSON.stringify(resolveOptions(Astro.props))
17
17
  .replace(/</g, '\\u003c')
18
18
  .replace(/>/g, '\\u003e')
19
19
  .replace(/&/g, '\\u0026')
20
+
21
+ const route = Astro.props.routeTemplates ? Astro.routePattern : undefined
20
22
  ---
23
+ {route && <meta name="takt:route" content={route} />}
21
24
  <!-- Pick ONE install path — this component OR the integration — not both. -->
22
25
  <script type="application/json" data-takt-config set:html={config}></script>
23
26
  <!-- A bundled (non-inline) module so Astro resolves the bare core import; an
@@ -29,9 +32,12 @@ const config = JSON.stringify(resolveOptions(Astro.props))
29
32
  if (el && !w.__takt) {
30
33
  const o = JSON.parse(el.textContent || '{}')
31
34
  w.__takt = true
35
+ const routeTemplate = o.routeTemplates
36
+ ? () => document.querySelector('meta[name="takt:route"]')?.getAttribute('content') ?? null
37
+ : undefined
32
38
  // auto forced off: Astro's ClientRouter runs several history ops per nav, so
33
39
  // core's history patch would over-count. Drive pageviews from after-swap.
34
- init({ ...o, auto: false })
40
+ init({ ...o, auto: false, routeTemplate })
35
41
  pageview()
36
42
  if (o.auto !== false) document.addEventListener('astro:after-swap', () => pageview())
37
43
  }
@@ -0,0 +1,4 @@
1
+ ---
2
+ const route = Astro.routePattern
3
+ ---
4
+ {route && <meta name="takt:route" content={route} />}
package/dist/index.d.ts CHANGED
@@ -41,6 +41,8 @@ interface TaktOptions {
41
41
  queryParams?: string[];
42
42
  /** Path prefixes never tracked, e.g. `['/app','/account']`. Segment-bounded: `'/app'` matches `'/app'` and `'/app/…'` but not `'/application'`. */
43
43
  exclude?: string[];
44
+ redactRoutes?: string[];
45
+ routeTemplates?: boolean;
44
46
  /**
45
47
  * Rewrite each URL before it is sent (e.g. strip a fragment or PII).
46
48
  * MUST be a self-contained function: it is stringified at build time and
package/dist/index.js CHANGED
@@ -22,16 +22,23 @@ function resolveOptions(options = {}) {
22
22
  trackQuery: options.trackQuery,
23
23
  queryParams: options.queryParams,
24
24
  exclude: options.exclude,
25
+ redactRoutes: options.redactRoutes,
26
+ routeTemplates: options.routeTemplates,
25
27
  tagged: options.tagged,
26
28
  debug: options.debug
27
29
  };
28
30
  }
29
31
 
30
32
  // src/runtime.ts
33
+ var ROUTE_TEMPLATE_RESOLVER = `() => document.querySelector('meta[name="takt:route"]')?.getAttribute('content') ?? null`;
31
34
  function buildRuntime(options, scrubUrl) {
32
35
  const spa = options.auto !== false;
33
36
  const json = JSON.stringify({ ...options, auto: false }).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026");
34
- const config = scrubUrl ? `Object.assign(${json}, { scrubUrl: ${scrubUrl.toString()} })` : json;
37
+ const functions = [
38
+ ...scrubUrl ? [`scrubUrl: ${scrubUrl.toString()}`] : [],
39
+ ...options.routeTemplates ? [`routeTemplate: ${ROUTE_TEMPLATE_RESOLVER}`] : []
40
+ ];
41
+ const config = functions.length ? `Object.assign(${json}, { ${functions.join(", ")} })` : json;
35
42
  return [
36
43
  `import { init, pageview } from '@vskstudio/takt-core';`,
37
44
  // SSR/prerender guard: this module is evaluated under Node when Astro
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vskstudio/takt-astro",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Astro integration for Takt privacy-friendly analytics",
5
5
  "license": "MIT",
6
6
  "author": "VSK Studio",
@@ -14,13 +14,13 @@
14
14
  "withastro",
15
15
  "takt"
16
16
  ],
17
- "homepage": "https://github.com/vskstudio/takt-astro#readme",
17
+ "homepage": "https://github.com/taktlytics/takt-astro#readme",
18
18
  "repository": {
19
19
  "type": "git",
20
- "url": "git+https://github.com/vskstudio/takt-astro.git"
20
+ "url": "git+https://github.com/taktlytics/takt-astro.git"
21
21
  },
22
22
  "bugs": {
23
- "url": "https://github.com/vskstudio/takt-astro/issues"
23
+ "url": "https://github.com/taktlytics/takt-astro/issues"
24
24
  },
25
25
  "publishConfig": {
26
26
  "access": "public"
@@ -32,6 +32,7 @@
32
32
  "default": "./dist/index.js"
33
33
  },
34
34
  "./Takt.astro": "./Takt.astro",
35
+ "./TaktRoute.astro": "./TaktRoute.astro",
35
36
  "./Badge.astro": "./Badge.astro",
36
37
  "./Embed.astro": "./Embed.astro",
37
38
  "./package.json": "./package.json"
@@ -39,31 +40,22 @@
39
40
  "files": [
40
41
  "dist",
41
42
  "Takt.astro",
43
+ "TaktRoute.astro",
42
44
  "Badge.astro",
43
45
  "Embed.astro"
44
46
  ],
45
47
  "engines": {
46
48
  "node": ">=18"
47
49
  },
48
- "scripts": {
49
- "build": "tsup",
50
- "typecheck": "tsc --noEmit",
51
- "lint": "eslint .",
52
- "test": "vitest run",
53
- "e2e": "playwright test",
54
- "size": "size-limit",
55
- "prepublishOnly": "pnpm build",
56
- "release": "pnpm build && changeset publish"
57
- },
58
50
  "peerDependencies": {
59
- "@vskstudio/takt-core": ">=0.9.0",
51
+ "@vskstudio/takt-core": ">=0.11.0",
60
52
  "astro": ">=4"
61
53
  },
62
54
  "devDependencies": {
63
55
  "@changesets/cli": "^2.31.0",
64
56
  "@playwright/test": "^1.50.0",
65
57
  "@size-limit/preset-small-lib": "^11.1.6",
66
- "@vskstudio/takt-core": "^0.9.0",
58
+ "@vskstudio/takt-core": "^0.11.0",
67
59
  "astro": "^5.0.0",
68
60
  "eslint": "^9.0.0",
69
61
  "size-limit": "^11.1.6",
@@ -72,5 +64,13 @@
72
64
  "typescript-eslint": "^8.0.0",
73
65
  "vitest": "^2.1.0"
74
66
  },
75
- "packageManager": "pnpm@9.0.0"
76
- }
67
+ "scripts": {
68
+ "build": "tsup",
69
+ "typecheck": "tsc --noEmit",
70
+ "lint": "eslint .",
71
+ "test": "vitest run",
72
+ "e2e": "playwright test",
73
+ "size": "size-limit",
74
+ "release": "pnpm build && changeset publish"
75
+ }
76
+ }