@vskstudio/takt-astro 0.2.0 → 0.3.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/Badge.astro ADDED
@@ -0,0 +1,14 @@
1
+ ---
2
+ import { badgeUrl, type BadgeVariant, type BadgeGlyph, type WidgetLang } from '@vskstudio/takt-core'
3
+
4
+ type Props = {
5
+ domain: string
6
+ variant?: BadgeVariant
7
+ glyph?: BadgeGlyph
8
+ lang?: WidgetLang
9
+ host?: string
10
+ }
11
+
12
+ const { domain, variant, glyph, lang, host, ...rest } = Astro.props
13
+ ---
14
+ <img src={badgeUrl(domain, { variant, glyph, lang, host })} alt="takt" loading="lazy" decoding="async" {...rest} />
package/Embed.astro ADDED
@@ -0,0 +1,16 @@
1
+ ---
2
+ import { embedUrl, type EmbedTheme, type WidgetLang } from '@vskstudio/takt-core'
3
+
4
+ type Props = {
5
+ domain: string
6
+ theme?: EmbedTheme
7
+ lang?: WidgetLang
8
+ host?: string
9
+ width?: number | string
10
+ height?: number | string
11
+ title?: string
12
+ }
13
+
14
+ const { domain, theme, lang, host, width = 404, height = 264, title = 'takt', ...rest } = Astro.props
15
+ ---
16
+ <iframe src={embedUrl(domain, { theme, lang, host })} title={title} width={width} height={height} loading="lazy" style="border:0" {...rest}></iframe>
package/README.md CHANGED
@@ -53,7 +53,7 @@ Both the integration and the component accept the same options:
53
53
 
54
54
  ## View Transitions
55
55
 
56
- Astro's client router navigates via `history.pushState`. Core's SPA tracking patches `pushState`, so a single pageview fires per client navigation — including View Transitions DOM swaps — while `init()` fires the one initial pageview. That single source means navigations are never double-counted. The runtime is SSR/prerender safe — it only runs in the browser.
56
+ 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.
57
57
 
58
58
  ## Custom events
59
59
 
@@ -65,6 +65,32 @@ import { track } from '@vskstudio/takt-astro'
65
65
  track('Signup', { revenue: { amount: '9.00', currency: 'USD' } })
66
66
  ```
67
67
 
68
+ ## Widgets
69
+
70
+ Thin wrappers around Takt's server-rendered badge SVG and embed iframe.
71
+
72
+ ```astro
73
+ ---
74
+ import Badge from '@vskstudio/takt-astro/Badge.astro'
75
+ import Embed from '@vskstudio/takt-astro/Embed.astro'
76
+ ---
77
+ <Badge domain="example.com" variant="d" />
78
+ <Embed domain="example.com" theme="dark" />
79
+ ```
80
+
81
+ `Badge` renders an `<img>` (props: `domain`, `variant`, `glyph`, `lang`, `host`); `Embed` renders an `<iframe>` (props: `domain`, `theme`, `lang`, `host`, `width`, `height`, `title`). Extra attributes pass through to the underlying element.
82
+
83
+ ## Public stats
84
+
85
+ `createStats` (re-exported from core) reads public analytics:
86
+
87
+ ```js
88
+ import { createStats } from '@vskstudio/takt-astro'
89
+
90
+ const stats = createStats({ domain: 'example.com' })
91
+ const summary = await stats.summary({ period: '7d' })
92
+ ```
93
+
68
94
  ## License
69
95
 
70
96
  MIT
package/Takt.astro CHANGED
@@ -1,10 +1,33 @@
1
1
  ---
2
- import { resolveOptions, type TaktOptions } from './src/options'
3
- import { buildRuntime } from './src/runtime'
2
+ // Import from the built output: the published package ships dist/ + this file,
3
+ // not src/, so a src import would break on install.
4
+ import { resolveOptions, type TaktOptions } from './dist/index.js'
4
5
 
5
6
  type Props = TaktOptions
6
7
 
7
- const runtime = buildRuntime(resolveOptions(Astro.props))
8
+ // Options travel as a JSON data island, NOT interpolated into JS, so a domain or
9
+ // endpoint containing `</script>`/quotes can't break out. `<` is escaped so the
10
+ // value can't terminate the island's <script> tag either.
11
+ const config = JSON.stringify(resolveOptions(Astro.props))
12
+ .replace(/</g, '\\u003c')
13
+ .replace(/>/g, '\\u003e')
14
+ .replace(/&/g, '\\u0026')
8
15
  ---
9
16
  <!-- Pick ONE install path — this component OR the integration — not both. -->
10
- <script is:inline type="module" set:html={runtime}></script>
17
+ <script type="application/json" data-takt-config set:html={config}></script>
18
+ <!-- A bundled (non-inline) module so Astro resolves the bare core import; an
19
+ is:inline module would leave it unresolved in the browser. -->
20
+ <script>
21
+ import { init, pageview } from '@vskstudio/takt-core'
22
+ const el = document.querySelector('script[data-takt-config]')
23
+ const w = window as unknown as { __takt?: boolean }
24
+ if (el && !w.__takt) {
25
+ const o = JSON.parse(el.textContent || '{}')
26
+ w.__takt = true
27
+ // auto forced off: Astro's ClientRouter runs several history ops per nav, so
28
+ // core's history patch would over-count. Drive pageviews from after-swap.
29
+ init({ ...o, auto: false })
30
+ pageview()
31
+ if (o.auto !== false) document.addEventListener('astro:after-swap', () => pageview())
32
+ }
33
+ </script>
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AstroIntegration } from 'astro';
2
2
  import { InitOptions } from '@vskstudio/takt-core';
3
- export { InitOptions, TrackOptions, optIn, optOut, pageview, track } from '@vskstudio/takt-core';
3
+ export { BadgeGlyph, BadgeOptions, BadgeVariant, EmbedOptions, EmbedTheme, InitOptions, PublicApiError, StatsBreakdown, StatsBreakdownRow, StatsClient, StatsClientOptions, StatsDimension, StatsMetrics, StatsParams, StatsPeriod, StatsPoint, StatsRealtime, StatsSummary, StatsTimeseries, TrackOptions, WidgetLang, badgeUrl, createStats, embedUrl, optIn, optOut, pageview, track } from '@vskstudio/takt-core';
4
4
 
5
5
  /**
6
6
  * Options for the Takt integration and `<Takt />` component. Mirrors core's
package/dist/index.js CHANGED
@@ -13,23 +13,24 @@ function resolveOptions(options = {}) {
13
13
 
14
14
  // src/runtime.ts
15
15
  function buildRuntime(options) {
16
- const json = JSON.stringify(options).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026");
16
+ const spa = options.auto !== false;
17
+ const json = JSON.stringify({ ...options, auto: false }).replace(/</g, "\\u003c").replace(/>/g, "\\u003e").replace(/&/g, "\\u0026");
17
18
  return [
18
- `import { init } from '@vskstudio/takt-core';`,
19
+ `import { init, pageview } from '@vskstudio/takt-core';`,
19
20
  // SSR/prerender guard: this module is evaluated under Node when Astro
20
21
  // prerenders, where window/init's browser APIs are absent.
21
22
  `if (typeof window !== 'undefined' && !window.__takt) {`,
22
23
  ` const o = ${json};`,
23
24
  // Idempotent across both entry paths (integration + <Takt/>): the flag stops
24
- // a second boot from disposing the first instance's listeners.
25
+ // a second boot from re-registering listeners or re-firing the initial view.
25
26
  ` window.__takt = true;`,
26
- // Single source of pageviews. init() enables core's SPA tracking, which
27
- // patches history.pushState/replaceState. Astro's ClientRouter navigates via
28
- // pushState and does NOT replace the history object on DOM swap, so the patch
29
- // persists and fires one pageview per View Transitions navigation. init()
30
- // also fires the initial pageview. We therefore do NOT listen to
31
- // astro:page-load — doing so would double-count every in-app navigation.
32
27
  ` init(o);`,
28
+ // One initial pageview (also covers full-page MPA loads, where the script
29
+ // re-runs per navigation and astro:after-swap never fires).
30
+ ` pageview();`,
31
+ // astro:after-swap fires exactly once per ClientRouter navigation (incl.
32
+ // back/forward), giving one pageview per nav with no double-count.
33
+ ...spa ? [` document.addEventListener('astro:after-swap', () => pageview());`] : [],
33
34
  `}`
34
35
  ].join("\n");
35
36
  }
@@ -49,9 +50,14 @@ function takt(options = {}) {
49
50
 
50
51
  // src/index.ts
51
52
  import { track, pageview, optOut, optIn } from "@vskstudio/takt-core";
53
+ import { createStats, PublicApiError, badgeUrl, embedUrl } from "@vskstudio/takt-core";
52
54
  export {
55
+ PublicApiError,
56
+ badgeUrl,
53
57
  buildRuntime,
58
+ createStats,
54
59
  takt as default,
60
+ embedUrl,
55
61
  optIn,
56
62
  optOut,
57
63
  pageview,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vskstudio/takt-astro",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Astro integration for Takt privacy-friendly analytics",
5
5
  "license": "MIT",
6
6
  "author": "VSK Studio",
@@ -32,23 +32,28 @@
32
32
  "default": "./dist/index.js"
33
33
  },
34
34
  "./Takt.astro": "./Takt.astro",
35
+ "./Badge.astro": "./Badge.astro",
36
+ "./Embed.astro": "./Embed.astro",
35
37
  "./package.json": "./package.json"
36
38
  },
37
39
  "files": [
38
40
  "dist",
39
- "Takt.astro"
41
+ "Takt.astro",
42
+ "Badge.astro",
43
+ "Embed.astro"
40
44
  ],
41
45
  "engines": {
42
46
  "node": ">=18"
43
47
  },
44
48
  "peerDependencies": {
45
- "@vskstudio/takt-core": ">=0.2.0",
49
+ "@vskstudio/takt-core": ">=0.3.0",
46
50
  "astro": ">=4"
47
51
  },
48
52
  "devDependencies": {
49
53
  "@changesets/cli": "^2.31.0",
54
+ "@playwright/test": "^1.50.0",
50
55
  "@size-limit/preset-small-lib": "^11.1.6",
51
- "@vskstudio/takt-core": "^0.2.0",
56
+ "@vskstudio/takt-core": "^0.3.0",
52
57
  "astro": "^5.0.0",
53
58
  "eslint": "^9.0.0",
54
59
  "size-limit": "^11.1.6",
@@ -62,6 +67,7 @@
62
67
  "typecheck": "tsc --noEmit",
63
68
  "lint": "eslint .",
64
69
  "test": "vitest run",
70
+ "e2e": "playwright test",
65
71
  "size": "size-limit",
66
72
  "release": "pnpm build && changeset publish"
67
73
  }