@vskstudio/takt-astro 0.4.2 → 0.5.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 +18 -1
- package/Takt.astro +6 -1
- package/dist/index.d.ts +39 -2
- package/dist/index.js +18 -4
- package/package.json +13 -15
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ import Takt from '@vskstudio/takt-astro/Takt.astro'
|
|
|
39
39
|
|
|
40
40
|
## Options
|
|
41
41
|
|
|
42
|
-
Both the integration and the component accept the same options:
|
|
42
|
+
Both the integration and the component accept the same options, with one exception: `scrubUrl` is a function and works **only via the integration** (see the note below).
|
|
43
43
|
|
|
44
44
|
| Option | Type | Default | Description |
|
|
45
45
|
| --- | --- | --- | --- |
|
|
@@ -52,6 +52,23 @@ Both the integration and the component accept the same options:
|
|
|
52
52
|
| `spa` | `boolean` | `true` | Track client-side navigations. |
|
|
53
53
|
| `respectDnt` | `boolean` | `true` | Suppress events when Do Not Track is on. |
|
|
54
54
|
| `excludeLocalhost` | `boolean` | `true` | Suppress events on localhost / private IPs. |
|
|
55
|
+
| `enabled` | `boolean` | `true` | Master kill switch — set `false` to suppress every event. |
|
|
56
|
+
| `sampleRate` | `number` | `1` | Fraction of visitors to track, `0`–`1`. |
|
|
57
|
+
| `trackQuery` | `boolean` | `false` | Send the full query string with pageviews instead of stripping it. |
|
|
58
|
+
| `queryParams` | `string[]` | – | Whitelist of query params to keep when `trackQuery` is off. |
|
|
59
|
+
| `scrubUrl` | `(url: string) => string` | – | **Integration only.** Rewrite each URL before it is sent (e.g. strip a fragment or PII). See the note below. |
|
|
60
|
+
| `tagged` | `boolean` | `false` | Auto-track elements marked with `data-takt-event`. |
|
|
61
|
+
|
|
62
|
+
> **`scrubUrl` note.** Unlike the other options, `scrubUrl` is a **function**, so it
|
|
63
|
+
> is supported **only via the integration**, not the `<Takt />` component. The
|
|
64
|
+
> integration serializes config into a build-time runtime string, so `scrubUrl` is
|
|
65
|
+
> stringified with `.toString()` and re-evaluated in the browser. It MUST be a
|
|
66
|
+
> **self-contained** function — no closure variables or outer-scope references — and
|
|
67
|
+
> must be **developer-controlled**: never build it from user input.
|
|
68
|
+
>
|
|
69
|
+
> The `<Takt />` component serializes its config as a JSON data island, which cannot
|
|
70
|
+
> carry a function — so passing `scrubUrl` to `<Takt />` **throws at build time**
|
|
71
|
+
> rather than silently doing nothing. Use the integration if you need it.
|
|
55
72
|
|
|
56
73
|
## View Transitions
|
|
57
74
|
|
package/Takt.astro
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
// Import from the built output: the published package ships dist/ + this file,
|
|
3
3
|
// not src/, so a src import would break on install.
|
|
4
|
-
import { resolveOptions, type TaktOptions } from './dist/index.js'
|
|
4
|
+
import { resolveOptions, assertNoScrubUrl, type TaktOptions } from './dist/index.js'
|
|
5
5
|
|
|
6
6
|
type Props = TaktOptions
|
|
7
7
|
|
|
8
|
+
// Fail fast: scrubUrl is a function and cannot survive the JSON data island
|
|
9
|
+
// below, so accepting it here would be a silent no-op. The integration path
|
|
10
|
+
// supports it (embeds it as build-time JS); the component cannot.
|
|
11
|
+
assertNoScrubUrl(Astro.props)
|
|
12
|
+
|
|
8
13
|
// Options travel as a JSON data island, NOT interpolated into JS, so a domain or
|
|
9
14
|
// endpoint containing `</script>`/quotes can't break out. `<` is escaped so the
|
|
10
15
|
// value can't terminate the island's <script> tag either.
|
package/dist/index.d.ts
CHANGED
|
@@ -31,7 +31,41 @@ interface TaktOptions {
|
|
|
31
31
|
respectDnt?: boolean;
|
|
32
32
|
/** Suppress events on localhost and private IP ranges. Default `true`. */
|
|
33
33
|
excludeLocalhost?: boolean;
|
|
34
|
+
/** Master kill switch — when `false`, every event is suppressed. */
|
|
35
|
+
enabled?: boolean;
|
|
36
|
+
/** Fraction of visitors to track, `0`–`1`. Defaults to tracking everyone. */
|
|
37
|
+
sampleRate?: number;
|
|
38
|
+
/** Send the full query string with pageviews instead of stripping it. */
|
|
39
|
+
trackQuery?: boolean;
|
|
40
|
+
/** Whitelist of query params to keep when `trackQuery` is off. */
|
|
41
|
+
queryParams?: string[];
|
|
42
|
+
/**
|
|
43
|
+
* Rewrite each URL before it is sent (e.g. strip a fragment or PII).
|
|
44
|
+
* MUST be a self-contained function: it is stringified at build time and
|
|
45
|
+
* re-evaluated in the browser, so it cannot reference closure/outer-scope
|
|
46
|
+
* variables. Never build it from user input.
|
|
47
|
+
*
|
|
48
|
+
* Integration-only: a function cannot survive the `<Takt />` component's
|
|
49
|
+
* JSON data island, so it is supported solely via the `takt()` integration in
|
|
50
|
+
* `astro.config`. Passing it to `<Takt />` throws — see {@link assertNoScrubUrl}.
|
|
51
|
+
*/
|
|
52
|
+
scrubUrl?: (url: string) => string;
|
|
53
|
+
/** Auto-track elements marked with `data-takt-event`. */
|
|
54
|
+
tagged?: boolean;
|
|
34
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Guard the `<Takt />` component path against `scrubUrl`. The component
|
|
58
|
+
* serializes its config as a JSON data island (`JSON.stringify` → `JSON.parse`),
|
|
59
|
+
* which silently drops functions — so accepting `scrubUrl` there would be a
|
|
60
|
+
* silent no-op. Fail fast at build time and point to the integration, which
|
|
61
|
+
* embeds `scrubUrl` as build-time JS instead.
|
|
62
|
+
*/
|
|
63
|
+
declare function assertNoScrubUrl(options?: TaktOptions): void;
|
|
64
|
+
/**
|
|
65
|
+
* Map user options to core's {@link InitOptions} for JSON serialization.
|
|
66
|
+
* `scrubUrl` is intentionally absent here — it is a function and cannot survive
|
|
67
|
+
* `JSON.stringify`, so it is threaded separately to {@link buildRuntime}.
|
|
68
|
+
*/
|
|
35
69
|
declare function resolveOptions(options?: TaktOptions): InitOptions;
|
|
36
70
|
|
|
37
71
|
/** Pick ONE install path — this integration OR the `<Takt />` component — not both. */
|
|
@@ -42,7 +76,10 @@ declare function takt(options?: TaktOptions): AstroIntegration;
|
|
|
42
76
|
*
|
|
43
77
|
* Returned as a source string because Astro's `injectScript` and the `<Takt />`
|
|
44
78
|
* component both take a raw module body.
|
|
79
|
+
*
|
|
80
|
+
* `scrubUrl` is threaded separately because it is a function: `JSON.stringify`
|
|
81
|
+
* would silently drop it, so it is embedded as raw JS via `.toString()` instead.
|
|
45
82
|
*/
|
|
46
|
-
declare function buildRuntime(options: InitOptions): string;
|
|
83
|
+
declare function buildRuntime(options: InitOptions, scrubUrl?: (url: string) => string): string;
|
|
47
84
|
|
|
48
|
-
export { type TaktOptions, buildRuntime, takt as default, resolveOptions, takt };
|
|
85
|
+
export { type TaktOptions, assertNoScrubUrl, buildRuntime, takt as default, resolveOptions, takt };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
// src/options.ts
|
|
2
|
+
function assertNoScrubUrl(options = {}) {
|
|
3
|
+
if (options.scrubUrl !== void 0) {
|
|
4
|
+
throw new Error(
|
|
5
|
+
"Takt: scrubUrl is a function and cannot be serialized into the <Takt /> component's config. Use the Takt integration in astro.config instead (it embeds scrubUrl as build-time JS)."
|
|
6
|
+
);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
2
9
|
function resolveOptions(options = {}) {
|
|
3
10
|
return {
|
|
4
11
|
domain: options.domain,
|
|
@@ -9,20 +16,26 @@ function resolveOptions(options = {}) {
|
|
|
9
16
|
notFound: options.track404 ?? false,
|
|
10
17
|
respectDnt: options.respectDnt ?? true,
|
|
11
18
|
excludeLocalhost: options.excludeLocalhost ?? true,
|
|
12
|
-
auto: options.spa ?? true
|
|
19
|
+
auto: options.spa ?? true,
|
|
20
|
+
enabled: options.enabled,
|
|
21
|
+
sampleRate: options.sampleRate,
|
|
22
|
+
trackQuery: options.trackQuery,
|
|
23
|
+
queryParams: options.queryParams,
|
|
24
|
+
tagged: options.tagged
|
|
13
25
|
};
|
|
14
26
|
}
|
|
15
27
|
|
|
16
28
|
// src/runtime.ts
|
|
17
|
-
function buildRuntime(options) {
|
|
29
|
+
function buildRuntime(options, scrubUrl) {
|
|
18
30
|
const spa = options.auto !== false;
|
|
19
31
|
const json = JSON.stringify({ ...options, auto: false }).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026");
|
|
32
|
+
const config = scrubUrl ? `Object.assign(${json}, { scrubUrl: ${scrubUrl.toString()} })` : json;
|
|
20
33
|
return [
|
|
21
34
|
`import { init, pageview } from '@vskstudio/takt-core';`,
|
|
22
35
|
// SSR/prerender guard: this module is evaluated under Node when Astro
|
|
23
36
|
// prerenders, where window/init's browser APIs are absent.
|
|
24
37
|
`if (typeof window !== 'undefined' && !window.__takt) {`,
|
|
25
|
-
` const o = ${
|
|
38
|
+
` const o = ${config};`,
|
|
26
39
|
// Idempotent across both entry paths (integration + <Takt/>): the flag stops
|
|
27
40
|
// a second boot from re-registering listeners or re-firing the initial view.
|
|
28
41
|
` window.__takt = true;`,
|
|
@@ -39,7 +52,7 @@ function buildRuntime(options) {
|
|
|
39
52
|
|
|
40
53
|
// src/integration.ts
|
|
41
54
|
function takt(options = {}) {
|
|
42
|
-
const runtime = buildRuntime(resolveOptions(options));
|
|
55
|
+
const runtime = buildRuntime(resolveOptions(options), options.scrubUrl);
|
|
43
56
|
return {
|
|
44
57
|
name: "@vskstudio/takt-astro",
|
|
45
58
|
hooks: {
|
|
@@ -55,6 +68,7 @@ import { track, pageview, optOut, optIn } from "@vskstudio/takt-core";
|
|
|
55
68
|
import { createStats, PublicApiError, badgeUrl, embedUrl } from "@vskstudio/takt-core";
|
|
56
69
|
export {
|
|
57
70
|
PublicApiError,
|
|
71
|
+
assertNoScrubUrl,
|
|
58
72
|
badgeUrl,
|
|
59
73
|
buildRuntime,
|
|
60
74
|
createStats,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vskstudio/takt-astro",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Astro integration for Takt privacy-friendly analytics",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "VSK Studio",
|
|
@@ -45,25 +45,15 @@
|
|
|
45
45
|
"engines": {
|
|
46
46
|
"node": ">=18"
|
|
47
47
|
},
|
|
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
48
|
"peerDependencies": {
|
|
59
|
-
"@vskstudio/takt-core": ">=0.
|
|
49
|
+
"@vskstudio/takt-core": ">=0.5.0",
|
|
60
50
|
"astro": ">=4"
|
|
61
51
|
},
|
|
62
52
|
"devDependencies": {
|
|
63
53
|
"@changesets/cli": "^2.31.0",
|
|
64
54
|
"@playwright/test": "^1.50.0",
|
|
65
55
|
"@size-limit/preset-small-lib": "^11.1.6",
|
|
66
|
-
"@vskstudio/takt-core": "^0.
|
|
56
|
+
"@vskstudio/takt-core": "^0.5.0",
|
|
67
57
|
"astro": "^5.0.0",
|
|
68
58
|
"eslint": "^9.0.0",
|
|
69
59
|
"size-limit": "^11.1.6",
|
|
@@ -72,5 +62,13 @@
|
|
|
72
62
|
"typescript-eslint": "^8.0.0",
|
|
73
63
|
"vitest": "^2.1.0"
|
|
74
64
|
},
|
|
75
|
-
"
|
|
76
|
-
|
|
65
|
+
"scripts": {
|
|
66
|
+
"build": "tsup",
|
|
67
|
+
"typecheck": "tsc --noEmit",
|
|
68
|
+
"lint": "eslint .",
|
|
69
|
+
"test": "vitest run",
|
|
70
|
+
"e2e": "playwright test",
|
|
71
|
+
"size": "size-limit",
|
|
72
|
+
"release": "pnpm build && changeset publish"
|
|
73
|
+
}
|
|
74
|
+
}
|