fg-tracker-browser 0.2.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/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ # Changelog — fg-tracker-browser
2
+
3
+ ## 0.2.0 (fg-tracker-browser) — 2026-09-15
4
+
5
+ - **Renomeado de `stread-track-browser` — nomes antigos continuam funcionando e serão removidos na 1.0.** Veja "Migração de stread-track-browser" no README.
6
+ - Header da chave passa a ser `x-fg-tracker-key` (a API aceita também o legado `x-stread-track-key`, inclusive no CORS). Requer a API do FG Tracker com suporte ao header novo.
7
+ - Novo export `API_KEY_HEADER`. Prefixo dos logs de debug: `[fg-tracker-browser]`.
8
+ - `package.json`: repositório `FORTGROUND/fg-tracker`, `publishConfig.access: public`, `prepack` limpa e recompila `dist/`.
9
+
10
+ ## 0.2.0 (stread-track-browser) — 2026-09-14
11
+
12
+ - **Tráfego (CONTRATO.md §25)**: opções `analytics` (default `false`) e `trackPageviews` (default = `analytics`). Quem já usa o SDK só para erros não muda de comportamento.
13
+ - Pageview automático na carga inicial e em navegações SPA (`history.pushState`/`replaceState`/`popstate`, compatível com o App Router do Next.js), com dedupe pela URL e checagem periódica como rede de segurança.
14
+ - Visitante anônimo (`fgt_vid`, 1 ano, `SameSite=Lax`) e sessão (`fgt_sid`, 30 min de inatividade) com fallback em `localStorage`.
15
+ - `tracker.page(path?)`, `tracker.identify(userId)`, `tracker.setConsent('granted' | 'denied' | 'pending')`; opções `consent`, `cookieDomain`, `sanitizePath`.
16
+ - Respeita `navigator.doNotTrack === '1'`.
17
+ - `sendBeacon` no `pagehide` passa a enviar `text/plain` (sem preflight de CORS); a API aceita o JSON nesse content-type e a chave em `?key=`.
18
+
19
+ ## 0.1.0
20
+
21
+ - Primeira versão: erros não tratados, breadcrumbs, usuário/release, fetch com `traceparent`, source maps (§24).
package/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # fg-tracker-browser
2
+
3
+ SDK de navegador do FG Tracker (CONTRATO.md §24). Sem dependências, ESM, ~6 KB. Captura erros não tratados com os últimos **breadcrumbs** (cliques, navegação, console, fetch), o usuário logado, a página e a release; opcionalmente liga o `fetch` do front ao trace da API (`traceparent`).
4
+
5
+ ```ts
6
+ import { init } from 'fg-tracker-browser';
7
+
8
+ const tracker = init({
9
+ apiKey: 'stk_...', // chave do projeto (só ingere; pode ser pública)
10
+ endpoint: 'https://<api-do-fg-tracker>', // URL da API mostrada em Conectar
11
+ serviceName: 'phase-web',
12
+ release: import.meta.env.VITE_RELEASE, // o mesmo valor enviado com os source maps
13
+ environment: 'production',
14
+ tracesSampleRate: 0.2, // 20% dos fetches viram traces
15
+ propagateTraceTo: ['api.phasia.studio'], // quem recebe traceparent (default: mesma origem)
16
+ ignoreErrors: [/ResizeObserver loop/],
17
+ });
18
+
19
+ tracker.setUser({ id: user.id, email: user.email });
20
+ tracker.captureException(err, { stage: 'checkout' });
21
+ tracker.captureMessage('cupom aplicado', 'info');
22
+ tracker.addBreadcrumb({ type: 'custom', message: 'modal aberto' });
23
+ ```
24
+
25
+ | opção | default | descrição |
26
+ |---|---|---|
27
+ | `apiKey`, `endpoint` | — | sem `apiKey` o SDK vira no-op (com aviso) |
28
+ | `serviceName`, `release`, `environment`, `user`, `attributes` | — | vão em todo evento |
29
+ | `sampleRate` | `1` | fração de erros enviados |
30
+ | `tracesSampleRate` | `0` | fração de fetches que geram um trace (`browser` → `http.client`) |
31
+ | `propagateTraceTo` | mesma origem | hosts/prefixos/RegExp que recebem `traceparent` |
32
+ | `ignoreErrors` | `[]` | `name: message` (string/RegExp) ignorados |
33
+ | `beforeSend` | — | `(event) => event \| null` |
34
+ | `breadcrumbs` | tudo ligado | `{ click, navigation, console, fetch }` |
35
+ | `maxBreadcrumbs` | `30` | anel de breadcrumbs |
36
+ | `captureGlobalErrors` | `true` | `window.onerror` + `unhandledrejection` |
37
+ | `flushIntervalMs` | `1500` | envio em lote (`keepalive`; `sendBeacon` ao sair da página) |
38
+ | `analytics` | `false` | liga visitantes anônimos + pageviews (§25). Quem não passa a opção não muda nada |
39
+ | `trackPageviews` | `= analytics` | pageviews automáticos (carga inicial, `pushState`/`replaceState`/`popstate`) |
40
+ | `consent` | `'granted'` | `'pending'` guarda em memória sem cookies até `setConsent('granted')`; `'denied'` descarta |
41
+ | `cookieDomain` | — | ex.: `.fortground.com.br` para o mesmo visitante entre subdomínios |
42
+ | `sanitizePath` | `normalizePath` | `(path) => string \| null` antes do envio (`null` não registra) |
43
+
44
+ Cada erro vira um span `kind: 'browser'`, `name: page:/rota/:id`, com `attributes.breadcrumbs` — o painel mostra "O que o usuário fez antes" no trace e a issue nasce agrupada por assinatura, com usuário afetado e release.
45
+
46
+ ## Tráfego (pageviews)
47
+
48
+ ```ts
49
+ const tracker = init({ apiKey: 'stk_...', endpoint: 'https://<api-do-fg-tracker>', // URL da API mostrada em Conectar serviceName: 'meu-site', analytics: true });
50
+ tracker.identify(user.id); // liga o visitante ao usuário (a API guarda só sha256 com sal do projeto)
51
+ tracker.page('/checkout/sucesso'); // pageview manual (dedupe com o automático pela URL)
52
+ tracker.setConsent('granted'); // quando o banner de cookies for aceito (se iniciou com consent: 'pending')
53
+ ```
54
+
55
+ - Visitante: 128 bits aleatórios no cookie first-party `fgt_vid` (1 ano, `SameSite=Lax`, `Secure` em https), com fallback em `localStorage`. Sessão: `fgt_sid`, renovada a cada evento e trocada após 30 min sem atividade.
56
+ - Payload (`analytics[]` no `POST /v1/ingest`): `{ type: 'pageview', url (caminho normalizado + só utm_*), title?, referrer (só a origem externa), utm_source/medium/campaign/term/content, screen (mobile/tablet/desktop), locale, visitor_id, session_id, ts, user_id? }` e `{ type: 'identify', user_id, visitor_id, session_id, ts }`.
57
+ - `navigator.doNotTrack === '1'` desliga a analytics (erros continuam). Nenhuma PII: query string, hash, e-mail e títulos não são guardados pela API.
58
+ - Instalação em Next.js App Router: `docs/instalar-pageviews.md`.
59
+
60
+ ## Source maps
61
+
62
+ Suba os `.map` da release no deploy (e apague-os do bundle público):
63
+
64
+ ```sh
65
+ FG_TRACKER_KEY=stk_... FG_TRACKER_URL=https://<api-do-fg-tracker> \
66
+ npx -p fg-tracker-sdk fg-tracker-sourcemaps --dir dist --release "phase-web@$GITHUB_SHA" --url-prefix "~/assets"
67
+ find dist -name '*.map' -delete
68
+ ```
69
+
70
+ A ingestão traduz `app-3f2a1c.js:1:48213` para `src/checkout/Cart.tsx:42:11`: o culpado da issue e os commits suspeitos passam a apontar para o código-fonte.
71
+
72
+ O `endpoint` é obrigatório: use a URL da API mostrada no painel em **Conectar**. O domínio `https://tracker-api.fortground.com.br` será o endereço definitivo; até ele entrar no ar, use a URL atual do painel. O SDK envia a chave no header `x-fg-tracker-key` (e em `?key=` no `sendBeacon`).
73
+
74
+ ## Migração de stread-track-browser
75
+
76
+ O pacote foi renomeado de `stread-track-browser` (nunca publicado no npm; usado via workspace/tarball) para `fg-tracker-browser` (mesma versão, 0.2.0, primeira publicação). Nomes antigos continuam funcionando e serão removidos na 1.0.
77
+
78
+ | antigo | novo | compatibilidade |
79
+ |---|---|---|
80
+ | pacote `stread-track-browser` | `fg-tracker-browser` | mesma API (`init`, `createBrowserTracker`); troque só o import |
81
+ | header `x-stread-track-key` | `x-fg-tracker-key` | a API aceita os dois (e `?key=`); o CORS libera os dois |
82
+ | CLI `stread-track-sourcemaps` (do SDK Node) | `fg-tracker-sourcemaps` (`fg-tracker-sdk`) | alias obsoleto mantido |
83
+ | `STREAD_TRACK_KEY`/`STREAD_TRACK_URL`/`STREAD_TRACK_RELEASE` no CI | `FG_TRACKER_KEY`/`FG_TRACKER_URL`/`FG_TRACKER_RELEASE` | o nome antigo é fallback |
84
+ | prefixo de log `[stread-track-browser]` | `[fg-tracker-browser]` | — |
85
+
86
+ Cookies (`fgt_vid`, `fgt_sid`) e o formato do payload não mudaram: visitantes e sessões continuam os mesmos após a troca.
87
+
88
+ ## Build e testes
89
+
90
+ ```sh
91
+ pnpm --filter fg-tracker-browser build # dist/
92
+ pnpm --filter fg-tracker-browser test # node:test com window/document falsos
93
+ ```
@@ -0,0 +1,40 @@
1
+ import type { AnalyticsEvent, BrowserEnv, Consent, PageviewEvent } from './types.js';
2
+ /**
3
+ * Pageviews e visitantes anônimos (CONTRATO.md §25): ids aleatórios em cookies
4
+ * first-party (`fgt_vid` 1 ano, `fgt_sid` 30 min de inatividade), sem PII.
5
+ * Só é criado quando `analytics`/`trackPageviews` estão ligados.
6
+ */
7
+ export declare const VISITOR_COOKIE = "fgt_vid";
8
+ export declare const SESSION_COOKIE = "fgt_sid";
9
+ export declare const VISITOR_TTL_SECONDS: number;
10
+ export declare const SESSION_IDLE_MS: number;
11
+ declare const UTM_KEYS: readonly ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content"];
12
+ type UtmKey = (typeof UTM_KEYS)[number];
13
+ export declare function randomId(env: BrowserEnv): string;
14
+ /** `Do Not Track` ligado no navegador (`navigator.doNotTrack === '1'`, com as variantes antigas). */
15
+ export declare function doNotTrackEnabled(env: BrowserEnv): boolean;
16
+ /** Bucket de tela: `mobile` (< 768 px), `tablet` (< 1024 px) ou `desktop`. */
17
+ export declare function screenBucket(width: number | undefined | null): PageviewEvent['screen'];
18
+ /** Só a origem do referrer externo; o da própria origem vira `null` (navegação interna). */
19
+ export declare function referrerOrigin(referrer: string | undefined | null, currentOrigin: string | undefined): string | null;
20
+ /** Parâmetros `utm_*` da URL (os únicos que sobrevivem da query string). */
21
+ export declare function utmParams(search: string | undefined | null): Partial<Record<UtmKey, string>>;
22
+ /** Caminho + só os `utm_*` da query (hash e demais parâmetros descartados). */
23
+ export declare function pageUrl(path: string, utm: Partial<Record<UtmKey, string>>): string;
24
+ export interface AnalyticsOptions {
25
+ consent: Consent;
26
+ cookieDomain?: string;
27
+ sanitizePath: (path: string) => string | null;
28
+ onEvent: (event: AnalyticsEvent) => void;
29
+ }
30
+ export interface Analytics {
31
+ /** Registra um pageview (dedupe: mesma URL da última vez é ignorada, exceto `force`). */
32
+ page(path?: string, force?: boolean): void;
33
+ identify(userId: string | number | null): void;
34
+ setConsent(consent: Consent): void;
35
+ /** Eventos retidos enquanto `consent === 'pending'`. */
36
+ readonly pending: readonly AnalyticsEvent[];
37
+ readonly consent: Consent;
38
+ }
39
+ export declare function createAnalytics(env: BrowserEnv, options: AnalyticsOptions): Analytics;
40
+ export {};
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Pageviews e visitantes anônimos (CONTRATO.md §25): ids aleatórios em cookies
3
+ * first-party (`fgt_vid` 1 ano, `fgt_sid` 30 min de inatividade), sem PII.
4
+ * Só é criado quando `analytics`/`trackPageviews` estão ligados.
5
+ */
6
+ export const VISITOR_COOKIE = 'fgt_vid';
7
+ export const SESSION_COOKIE = 'fgt_sid';
8
+ export const VISITOR_TTL_SECONDS = 365 * 24 * 60 * 60;
9
+ export const SESSION_IDLE_MS = 30 * 60 * 1000;
10
+ const MAX_ANALYTICS_QUEUE = 200;
11
+ const UTM_KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content'];
12
+ export function randomId(env) {
13
+ const cryptoImpl = (env.window?.crypto ?? globalThis.crypto);
14
+ const out = new Uint8Array(16);
15
+ if (cryptoImpl?.getRandomValues)
16
+ cryptoImpl.getRandomValues(out);
17
+ else
18
+ for (let i = 0; i < out.length; i += 1)
19
+ out[i] = Math.floor(Math.random() * 256);
20
+ return Array.from(out, (b) => b.toString(16).padStart(2, '0')).join('');
21
+ }
22
+ /** `Do Not Track` ligado no navegador (`navigator.doNotTrack === '1'`, com as variantes antigas). */
23
+ export function doNotTrackEnabled(env) {
24
+ const nav = (env.navigator ?? env.window?.navigator);
25
+ const win = env.window;
26
+ return nav?.doNotTrack === '1' || win?.doNotTrack === '1' || nav?.msDoNotTrack === '1';
27
+ }
28
+ /** Bucket de tela: `mobile` (< 768 px), `tablet` (< 1024 px) ou `desktop`. */
29
+ export function screenBucket(width) {
30
+ if (!width || !Number.isFinite(width))
31
+ return null;
32
+ if (width < 768)
33
+ return 'mobile';
34
+ if (width < 1024)
35
+ return 'tablet';
36
+ return 'desktop';
37
+ }
38
+ /** Só a origem do referrer externo; o da própria origem vira `null` (navegação interna). */
39
+ export function referrerOrigin(referrer, currentOrigin) {
40
+ if (!referrer)
41
+ return null;
42
+ try {
43
+ const url = new URL(referrer);
44
+ if (url.protocol !== 'http:' && url.protocol !== 'https:')
45
+ return null;
46
+ return url.origin === currentOrigin ? null : url.origin;
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ }
52
+ /** Parâmetros `utm_*` da URL (os únicos que sobrevivem da query string). */
53
+ export function utmParams(search) {
54
+ const out = {};
55
+ if (!search)
56
+ return out;
57
+ const params = new URLSearchParams(search.startsWith('?') ? search.slice(1) : search);
58
+ for (const key of UTM_KEYS) {
59
+ const value = params.get(key);
60
+ if (value && value.trim())
61
+ out[key] = value.trim().slice(0, 200);
62
+ }
63
+ return out;
64
+ }
65
+ /** Caminho + só os `utm_*` da query (hash e demais parâmetros descartados). */
66
+ export function pageUrl(path, utm) {
67
+ const query = new URLSearchParams();
68
+ for (const key of UTM_KEYS)
69
+ if (utm[key])
70
+ query.set(key, utm[key]);
71
+ const qs = query.toString();
72
+ return qs ? `${path}?${qs}` : path;
73
+ }
74
+ /** Cookie first-party (SameSite=Lax) com fallback em `localStorage` quando cookies estão bloqueados. */
75
+ function createStorage(env, cookieDomain) {
76
+ const doc = env.document ?? env.window?.document;
77
+ const secure = (env.location ?? env.window?.location)?.protocol === 'https:';
78
+ const local = () => {
79
+ try {
80
+ return env.window?.localStorage ?? null;
81
+ }
82
+ catch {
83
+ return null;
84
+ }
85
+ };
86
+ const readCookie = (name) => {
87
+ try {
88
+ const raw = doc?.cookie ?? '';
89
+ for (const part of raw.split(';')) {
90
+ const [key, ...rest] = part.trim().split('=');
91
+ if (key === name)
92
+ return decodeURIComponent(rest.join('='));
93
+ }
94
+ }
95
+ catch {
96
+ /* cookies bloqueados */
97
+ }
98
+ return null;
99
+ };
100
+ return {
101
+ get(name) {
102
+ const cookie = readCookie(name);
103
+ if (cookie)
104
+ return cookie;
105
+ try {
106
+ const raw = local()?.getItem(name);
107
+ if (!raw)
108
+ return null;
109
+ const [value, expires] = raw.split('|');
110
+ if (!value || Number(expires) < Date.now())
111
+ return null;
112
+ return value;
113
+ }
114
+ catch {
115
+ return null;
116
+ }
117
+ },
118
+ set(name, value, maxAgeSeconds) {
119
+ try {
120
+ if (doc) {
121
+ doc.cookie = `${name}=${encodeURIComponent(value)}; Max-Age=${maxAgeSeconds}; Path=/; SameSite=Lax${secure ? '; Secure' : ''}${cookieDomain ? `; Domain=${cookieDomain}` : ''}`;
122
+ }
123
+ }
124
+ catch {
125
+ /* cookies bloqueados */
126
+ }
127
+ if (readCookie(name) === value)
128
+ return;
129
+ try {
130
+ local()?.setItem(name, `${value}|${Date.now() + maxAgeSeconds * 1000}`);
131
+ }
132
+ catch {
133
+ /* sem armazenamento: ids ficam só em memória */
134
+ }
135
+ },
136
+ };
137
+ }
138
+ export function createAnalytics(env, options) {
139
+ const storage = createStorage(env, options.cookieDomain);
140
+ let consent = options.consent;
141
+ const pending = [];
142
+ let memoryVisitor = null;
143
+ let memorySession = null;
144
+ let userId = null;
145
+ let lastUrl = null;
146
+ let firstPage = true;
147
+ const visitorId = () => {
148
+ if (consent === 'granted') {
149
+ const stored = storage.get(VISITOR_COOKIE);
150
+ if (stored && /^[0-9a-f]{32}$/.test(stored)) {
151
+ memoryVisitor = stored;
152
+ return stored;
153
+ }
154
+ }
155
+ memoryVisitor ?? (memoryVisitor = randomId(env));
156
+ if (consent === 'granted')
157
+ storage.set(VISITOR_COOKIE, memoryVisitor, VISITOR_TTL_SECONDS);
158
+ return memoryVisitor;
159
+ };
160
+ /** Sessão: `<id>.<último uso em ms>`; renova a cada evento e expira após 30 min parada. */
161
+ const sessionId = (at) => {
162
+ if (consent === 'granted' && !memorySession) {
163
+ const [id, last] = (storage.get(SESSION_COOKIE) ?? '').split('.');
164
+ if (id && /^[0-9a-f]{32}$/.test(id) && Number(last) > 0)
165
+ memorySession = { id, last: Number(last) };
166
+ }
167
+ if (!memorySession || at - memorySession.last > SESSION_IDLE_MS)
168
+ memorySession = { id: randomId(env), last: at };
169
+ memorySession.last = Math.max(memorySession.last, at);
170
+ if (consent === 'granted')
171
+ storage.set(SESSION_COOKIE, `${memorySession.id}.${memorySession.last}`, SESSION_IDLE_MS / 1000);
172
+ return memorySession.id;
173
+ };
174
+ const emit = (event) => {
175
+ if (consent === 'denied')
176
+ return;
177
+ if (consent === 'pending') {
178
+ pending.push(event);
179
+ if (pending.length > MAX_ANALYTICS_QUEUE)
180
+ pending.splice(0, pending.length - MAX_ANALYTICS_QUEUE);
181
+ return;
182
+ }
183
+ options.onEvent(event);
184
+ };
185
+ return {
186
+ page(path, force = false) {
187
+ if (consent === 'denied')
188
+ return;
189
+ const loc = env.location ?? env.window?.location;
190
+ const rawPath = (path ?? loc?.pathname ?? '/').split('#')[0];
191
+ const [pathOnly, query] = rawPath.split('?');
192
+ const sanitized = options.sanitizePath(pathOnly || '/');
193
+ if (sanitized === null)
194
+ return;
195
+ const utm = utmParams(path !== undefined ? query : loc?.search);
196
+ const url = pageUrl(sanitized, utm);
197
+ if (!force && url === lastUrl)
198
+ return;
199
+ lastUrl = url;
200
+ const doc = env.document ?? env.window?.document;
201
+ const nav = env.navigator ?? env.window?.navigator;
202
+ const at = Date.now();
203
+ const event = {
204
+ type: 'pageview',
205
+ url,
206
+ referrer: firstPage ? referrerOrigin(doc?.referrer, loc?.origin) : null,
207
+ ...utm,
208
+ screen: screenBucket(env.window?.screen?.width ?? env.window?.innerWidth),
209
+ locale: nav?.language ?? null,
210
+ visitor_id: visitorId(),
211
+ session_id: sessionId(at),
212
+ ts: new Date(at).toISOString(),
213
+ };
214
+ if (doc?.title)
215
+ event.title = doc.title.slice(0, 200);
216
+ if (userId)
217
+ event.user_id = userId;
218
+ firstPage = false;
219
+ emit(event);
220
+ },
221
+ identify(next) {
222
+ userId = next === null || next === undefined || next === '' ? null : String(next).slice(0, 200);
223
+ if (!userId || consent === 'denied')
224
+ return;
225
+ const at = Date.now();
226
+ emit({ type: 'identify', user_id: userId, visitor_id: visitorId(), session_id: sessionId(at), ts: new Date(at).toISOString() });
227
+ },
228
+ setConsent(next) {
229
+ consent = next;
230
+ if (next === 'denied') {
231
+ pending.splice(0);
232
+ return;
233
+ }
234
+ if (next === 'granted') {
235
+ // Persiste os ids gerados em memória durante o `pending` e libera a fila.
236
+ if (memoryVisitor)
237
+ storage.set(VISITOR_COOKIE, memoryVisitor, VISITOR_TTL_SECONDS);
238
+ if (memorySession)
239
+ storage.set(SESSION_COOKIE, `${memorySession.id}.${memorySession.last}`, SESSION_IDLE_MS / 1000);
240
+ for (const event of pending.splice(0))
241
+ options.onEvent(event);
242
+ }
243
+ },
244
+ get pending() {
245
+ return pending;
246
+ },
247
+ get consent() {
248
+ return consent;
249
+ },
250
+ };
251
+ }
252
+ //# sourceMappingURL=analytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { BrowserEnv, BrowserOptions, BrowserTracker } from './types.js';
2
+ export type { AnalyticsEvent, Breadcrumb, BreadcrumbType, BrowserEnv, BrowserEvent, BrowserOptions, BrowserTracker, BrowserUser, Consent, IdentifyEvent, PageviewEvent, } from './types.js';
3
+ /** Header da chave do projeto enviado pelo SDK (a API aceita também o legado `x-stread-track-key`). */
4
+ export declare const API_KEY_HEADER = "x-fg-tracker-key";
5
+ export { doNotTrackEnabled, pageUrl, referrerOrigin, screenBucket, utmParams, SESSION_COOKIE, VISITOR_COOKIE } from './analytics.js';
6
+ /** `/orders/42/items/9f…` → `/orders/:id/items/:id` (mesma regra do SDK Node). */
7
+ export declare function normalizePath(input: string | undefined | null): string;
8
+ export declare function toError(input: unknown): {
9
+ name: string;
10
+ message: string;
11
+ stack?: string;
12
+ };
13
+ /** Seletor curto de um elemento clicado: `button#buy.primary` ou texto. */
14
+ export declare function describeTarget(target: EventTarget | null): string;
15
+ export declare function createBrowserTracker(options: BrowserOptions, env?: BrowserEnv): BrowserTracker;
16
+ /** Inicializa uma vez por página; devolve o tracker (também disponível em `getTracker()`). */
17
+ export declare function init(options: BrowserOptions): BrowserTracker;
18
+ export declare function getTracker(): BrowserTracker | null;
package/dist/index.js ADDED
@@ -0,0 +1,450 @@
1
+ import { createAnalytics, doNotTrackEnabled } from './analytics.js';
2
+ /** Header da chave do projeto enviado pelo SDK (a API aceita também o legado `x-stread-track-key`). */
3
+ export const API_KEY_HEADER = 'x-fg-tracker-key';
4
+ export { doNotTrackEnabled, pageUrl, referrerOrigin, screenBucket, utmParams, SESSION_COOKIE, VISITOR_COOKIE } from './analytics.js';
5
+ /**
6
+ * fg-tracker-browser (CONTRATO.md §24): captura erros não tratados, guarda os
7
+ * últimos breadcrumbs (cliques, navegação, console, fetch) e envia cada erro como
8
+ * um span `browser` para `POST /v1/ingest` — com release, usuário e página, para a
9
+ * issue nascer agrupada, simbolizada (source maps) e ligada ao trace da API.
10
+ */
11
+ const DEFAULT_FLUSH_MS = 1500;
12
+ const DEFAULT_MAX_BREADCRUMBS = 30;
13
+ const MAX_QUEUE = 200;
14
+ const MAX_STACK_LINES = 30;
15
+ const DEDUPE_WINDOW_MS = 1000;
16
+ function randomHex(bytes, env) {
17
+ const cryptoImpl = (env.window?.crypto ?? globalThis.crypto);
18
+ const out = new Uint8Array(bytes);
19
+ if (cryptoImpl?.getRandomValues)
20
+ cryptoImpl.getRandomValues(out);
21
+ else
22
+ for (let i = 0; i < bytes; i += 1)
23
+ out[i] = Math.floor(Math.random() * 256);
24
+ return Array.from(out, (b) => b.toString(16).padStart(2, '0')).join('');
25
+ }
26
+ const UUID_RE = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi;
27
+ /** `/orders/42/items/9f…` → `/orders/:id/items/:id` (mesma regra do SDK Node). */
28
+ export function normalizePath(input) {
29
+ if (!input)
30
+ return '/';
31
+ const path = input.split('?')[0].split('#')[0].replace(UUID_RE, ':id');
32
+ const out = path
33
+ .split('/')
34
+ .map((seg) => (seg && (/^\d+$/.test(seg) || /^[0-9a-f]{16,}$/i.test(seg)) ? ':id' : seg))
35
+ .join('/') || '/';
36
+ return out.length > 1 && out.endsWith('/') ? out.slice(0, -1) : out;
37
+ }
38
+ export function toError(input) {
39
+ if (input instanceof Error) {
40
+ const out = { name: input.name || 'Error', message: input.message };
41
+ if (input.stack)
42
+ out.stack = input.stack.split('\n').slice(0, MAX_STACK_LINES).join('\n');
43
+ return out;
44
+ }
45
+ if (input && typeof input === 'object' && 'message' in input) {
46
+ const obj = input;
47
+ return { name: String(obj.name ?? 'Error'), message: String(obj.message ?? ''), ...(typeof obj.stack === 'string' ? { stack: obj.stack } : {}) };
48
+ }
49
+ return { name: 'Error', message: typeof input === 'string' ? input : JSON.stringify(input) ?? String(input) };
50
+ }
51
+ function matches(value, patterns) {
52
+ return !!patterns?.some((pattern) => (pattern instanceof RegExp ? pattern.test(value) : value.includes(pattern)));
53
+ }
54
+ /** Seletor curto de um elemento clicado: `button#buy.primary` ou texto. */
55
+ export function describeTarget(target) {
56
+ const el = target;
57
+ if (!el || typeof el.tagName !== 'string')
58
+ return 'unknown';
59
+ let out = el.tagName.toLowerCase();
60
+ if (el.id)
61
+ out += `#${el.id}`;
62
+ const classes = typeof el.className === 'string' ? el.className.trim().split(/\s+/).filter(Boolean).slice(0, 2) : [];
63
+ if (classes.length)
64
+ out += `.${classes.join('.')}`;
65
+ const text = (el.textContent ?? '').trim().replace(/\s+/g, ' ').slice(0, 40);
66
+ const label = el.getAttribute?.('aria-label') ?? el.getAttribute?.('data-testid');
67
+ if (label)
68
+ out += `[${label}]`;
69
+ else if (text)
70
+ out += ` "${text}"`;
71
+ return out;
72
+ }
73
+ function shouldPropagate(url, targets, origin) {
74
+ if (!targets)
75
+ return !!origin && url.origin === origin;
76
+ return targets.some((t) => (t instanceof RegExp ? t.test(url.href) : t.startsWith('http') ? url.href.startsWith(t) : url.host === t || url.hostname === t || url.hostname.endsWith(`.${t}`)));
77
+ }
78
+ export function createBrowserTracker(options, env = globalThis) {
79
+ const endpoint = options.endpoint.replace(/\/+$/, '');
80
+ const enabled = Boolean(options.apiKey);
81
+ const maxBreadcrumbs = Math.max(5, options.maxBreadcrumbs ?? DEFAULT_MAX_BREADCRUMBS);
82
+ const crumbs = [];
83
+ const queue = [];
84
+ const analyticsQueue = [];
85
+ const baseFetch = env.fetch ?? env.window?.fetch?.bind(env.window);
86
+ let user = options.user ?? null;
87
+ let extra = { ...(options.attributes ?? {}) };
88
+ let lastSignature = '';
89
+ let lastAt = 0;
90
+ let timer = null;
91
+ const cleanups = [];
92
+ const crumbOn = (type) => options.breadcrumbs?.[type] !== false;
93
+ const log = (...args) => {
94
+ if (options.debug)
95
+ (env.console ?? console).info('[fg-tracker-browser]', ...args);
96
+ };
97
+ const now = () => new Date().toISOString();
98
+ const addBreadcrumb = (crumb) => {
99
+ crumbs.push({ ...crumb, ts: crumb.ts ?? now() });
100
+ if (crumbs.length > maxBreadcrumbs)
101
+ crumbs.splice(0, crumbs.length - maxBreadcrumbs);
102
+ };
103
+ const baseAttributes = () => {
104
+ const loc = env.location ?? env.window?.location;
105
+ const nav = env.navigator ?? env.window?.navigator;
106
+ const attrs = {
107
+ ...extra,
108
+ url: loc?.href ?? null,
109
+ page: loc ? normalizePath(loc.pathname) : null,
110
+ userAgent: nav?.userAgent ?? null,
111
+ language: nav?.language ?? null,
112
+ viewport: env.window ? `${env.window.innerWidth}x${env.window.innerHeight}` : null,
113
+ client: 'browser',
114
+ };
115
+ if (options.serviceName)
116
+ attrs.serviceName = options.serviceName;
117
+ if (options.release)
118
+ attrs.release = options.release;
119
+ if (options.environment)
120
+ attrs.environment = options.environment;
121
+ if (user) {
122
+ attrs['user.id'] = String(user.id);
123
+ if (user.email)
124
+ attrs['user.email'] = user.email;
125
+ if (user.name)
126
+ attrs['user.name'] = user.name;
127
+ }
128
+ return attrs;
129
+ };
130
+ const enqueue = (event) => {
131
+ if (!enabled)
132
+ return;
133
+ let out = event;
134
+ if (options.beforeSend) {
135
+ try {
136
+ out = options.beforeSend(event);
137
+ }
138
+ catch {
139
+ out = event;
140
+ }
141
+ }
142
+ if (!out)
143
+ return;
144
+ queue.push(out);
145
+ if (queue.length > MAX_QUEUE)
146
+ queue.splice(0, queue.length - MAX_QUEUE);
147
+ };
148
+ const send = async (events, analyticsEvents = [], useBeacon = false) => {
149
+ if (events.length === 0 && analyticsEvents.length === 0)
150
+ return true;
151
+ const byTrace = new Map();
152
+ for (const event of events) {
153
+ const { traceId, ...rest } = event;
154
+ byTrace.set(traceId, [...(byTrace.get(traceId) ?? []), rest]);
155
+ }
156
+ const payload = { traces: [...byTrace].map(([traceId, spans]) => ({ traceId, spans })) };
157
+ if (analyticsEvents.length > 0)
158
+ payload.analytics = analyticsEvents;
159
+ const body = JSON.stringify(payload);
160
+ const url = `${endpoint}/v1/ingest?key=${encodeURIComponent(options.apiKey)}`;
161
+ const nav = env.navigator ?? env.window?.navigator;
162
+ if (useBeacon && nav?.sendBeacon) {
163
+ try {
164
+ // text/plain é "simples" para CORS: o beacon sai sem preflight; a API aceita JSON nesse content-type.
165
+ if (nav.sendBeacon(url, new Blob([body], { type: 'text/plain;charset=UTF-8' })))
166
+ return true;
167
+ }
168
+ catch {
169
+ /* cai no fetch */
170
+ }
171
+ }
172
+ if (!baseFetch)
173
+ return false;
174
+ try {
175
+ const res = await baseFetch(`${endpoint}/v1/ingest`, {
176
+ method: 'POST',
177
+ headers: { 'content-type': 'application/json', [API_KEY_HEADER]: options.apiKey },
178
+ body,
179
+ keepalive: true,
180
+ });
181
+ log('enviados', events.length, 'eventos e', analyticsEvents.length, 'de analytics →', res.status);
182
+ return res.ok || res.status < 500;
183
+ }
184
+ catch (err) {
185
+ log('falha no envio', err);
186
+ return false;
187
+ }
188
+ };
189
+ let flushing = null;
190
+ const flush = async () => {
191
+ if (flushing)
192
+ await flushing;
193
+ if (queue.length === 0 && analyticsQueue.length === 0)
194
+ return;
195
+ const batch = queue.splice(0, queue.length);
196
+ const analyticsBatch = analyticsQueue.splice(0, analyticsQueue.length);
197
+ flushing = send(batch, analyticsBatch)
198
+ .then((ok) => {
199
+ if (!ok) {
200
+ queue.unshift(...batch.slice(-50));
201
+ analyticsQueue.unshift(...analyticsBatch.slice(-100));
202
+ }
203
+ })
204
+ .finally(() => {
205
+ flushing = null;
206
+ });
207
+ return flushing;
208
+ };
209
+ const capture = (error, attributes = {}, level = 'error') => {
210
+ if (!enabled)
211
+ return;
212
+ const err = toError(error);
213
+ const signature = `${err.name}|${err.message}`;
214
+ const at = Date.now();
215
+ if (matches(signature, options.ignoreErrors))
216
+ return;
217
+ if (signature === lastSignature && at - lastAt < DEDUPE_WINDOW_MS)
218
+ return;
219
+ lastSignature = signature;
220
+ lastAt = at;
221
+ if ((options.sampleRate ?? 1) < 1 && Math.random() >= (options.sampleRate ?? 1))
222
+ return;
223
+ const loc = env.location ?? env.window?.location;
224
+ const startedAt = now();
225
+ enqueue({
226
+ traceId: randomHex(16, env),
227
+ spanId: randomHex(8, env),
228
+ parentSpanId: null,
229
+ kind: 'browser',
230
+ name: `page:${loc ? normalizePath(loc.pathname) : '/'}`,
231
+ method: null,
232
+ route: loc ? normalizePath(loc.pathname) : null,
233
+ statusCode: null,
234
+ startedAt,
235
+ endedAt: startedAt,
236
+ durationMs: 0,
237
+ attributes: { ...baseAttributes(), ...attributes, level, breadcrumbs: crumbs.slice(-maxBreadcrumbs) },
238
+ error: level === 'error' || level === 'warning' ? err : null,
239
+ });
240
+ addBreadcrumb({ type: 'error', level: level === 'info' ? 'info' : 'error', message: `${err.name}: ${err.message}`.slice(0, 200) });
241
+ void flush();
242
+ };
243
+ /* --------------------------------------------------------------- fetch */
244
+ const trackedFetch = async (input, init) => {
245
+ if (!baseFetch)
246
+ throw new Error('fetch indisponível');
247
+ const raw = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;
248
+ let url = null;
249
+ try {
250
+ url = new URL(raw, (env.location ?? env.window?.location)?.href);
251
+ }
252
+ catch {
253
+ url = null;
254
+ }
255
+ if (!url || raw.startsWith(endpoint))
256
+ return baseFetch(input, init);
257
+ const method = (init?.method ?? (input instanceof Request ? input.method : 'GET')).toUpperCase();
258
+ const sampled = enabled && (options.tracesSampleRate ?? 0) > 0 && Math.random() < (options.tracesSampleRate ?? 0);
259
+ const origin = (env.location ?? env.window?.location)?.origin;
260
+ const traceId = randomHex(16, env);
261
+ const rootId = randomHex(8, env);
262
+ const spanId = randomHex(8, env);
263
+ let request = { input, init };
264
+ if (sampled && shouldPropagate(url, options.propagateTraceTo, origin)) {
265
+ const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : undefined));
266
+ headers.set('traceparent', `00-${traceId}-${spanId}-01`);
267
+ request = { input, init: { ...init, headers } };
268
+ }
269
+ const started = Date.now();
270
+ const startedAt = new Date(started).toISOString();
271
+ let status = null;
272
+ let failure = null;
273
+ try {
274
+ const res = await baseFetch(request.input, request.init);
275
+ status = res.status;
276
+ return res;
277
+ }
278
+ catch (err) {
279
+ failure = toError(err);
280
+ throw err;
281
+ }
282
+ finally {
283
+ const durationMs = Date.now() - started;
284
+ if (crumbOn('fetch'))
285
+ addBreadcrumb({ type: 'fetch', category: 'http', level: status && status >= 500 ? 'error' : failure ? 'error' : 'info', message: `${method} ${url.origin}${normalizePath(url.pathname)} → ${status ?? failure?.name ?? '?'}`, data: { method, url: url.href, status, durationMs } });
286
+ if (sampled) {
287
+ const loc = env.location ?? env.window?.location;
288
+ const endedAt = new Date(started + durationMs).toISOString();
289
+ enqueue({ traceId, spanId: rootId, parentSpanId: null, kind: 'browser', name: `page:${loc ? normalizePath(loc.pathname) : '/'}`, method: null, route: loc ? normalizePath(loc.pathname) : null, statusCode: null, startedAt, endedAt, durationMs, attributes: { ...baseAttributes(), sampled: true }, error: null });
290
+ enqueue({ traceId, spanId, parentSpanId: rootId, kind: 'http.client', name: `${method} ${url.origin}${normalizePath(url.pathname)}`, method, route: normalizePath(url.pathname), statusCode: status, startedAt, endedAt, durationMs, attributes: { url: url.href, host: url.host, propagated: shouldPropagate(url, options.propagateTraceTo, origin), ...(options.serviceName ? { serviceName: options.serviceName } : {}), ...(options.release ? { release: options.release } : {}) }, error: status && status >= 500 ? { name: 'HttpError', message: `HTTP ${status}` } : failure });
291
+ }
292
+ }
293
+ };
294
+ /* ------------------------------------------------------------ analytics */
295
+ const analyticsRequested = options.analytics === true || options.trackPageviews === true;
296
+ const analytics = enabled && analyticsRequested && !doNotTrackEnabled(env)
297
+ ? createAnalytics(env, {
298
+ consent: options.consent ?? 'granted',
299
+ cookieDomain: options.cookieDomain,
300
+ sanitizePath: options.sanitizePath ?? normalizePath,
301
+ onEvent: (event) => {
302
+ analyticsQueue.push(event);
303
+ if (analyticsQueue.length > MAX_QUEUE)
304
+ analyticsQueue.splice(0, analyticsQueue.length - MAX_QUEUE);
305
+ },
306
+ })
307
+ : null;
308
+ if (enabled && analyticsRequested && !analytics)
309
+ log('Do Not Track ligado: analytics desativada');
310
+ const autoPageviews = !!analytics && (options.trackPageviews ?? options.analytics) !== false;
311
+ /* ------------------------------------------------------------ listeners */
312
+ const win = env.window;
313
+ if (win && enabled) {
314
+ if (options.captureGlobalErrors !== false) {
315
+ const onError = (event) => {
316
+ if (!event.error && !event.message)
317
+ return;
318
+ capture(event.error ?? new Error(event.message), { source: event.filename ?? null, line: event.lineno ?? null, column: event.colno ?? null, mechanism: 'onerror' });
319
+ };
320
+ const onRejection = (event) => capture(event.reason ?? new Error('Unhandled rejection'), { mechanism: 'unhandledrejection' });
321
+ win.addEventListener('error', onError);
322
+ win.addEventListener('unhandledrejection', onRejection);
323
+ cleanups.push(() => win.removeEventListener('error', onError), () => win.removeEventListener('unhandledrejection', onRejection));
324
+ }
325
+ const doc = env.document ?? win.document;
326
+ if (doc && crumbOn('click')) {
327
+ const onClick = (event) => addBreadcrumb({ type: 'click', category: 'ui', message: describeTarget(event.target) });
328
+ doc.addEventListener('click', onClick, true);
329
+ cleanups.push(() => doc.removeEventListener('click', onClick, true));
330
+ }
331
+ if (crumbOn('navigation') || autoPageviews) {
332
+ const hist = env.history ?? win.history;
333
+ const loc = env.location ?? win.location;
334
+ const record = (from, to) => {
335
+ if (crumbOn('navigation'))
336
+ addBreadcrumb({ type: 'navigation', category: 'navigation', message: `${from} → ${to}`, data: { from, to } });
337
+ };
338
+ // Pageview depois da troca de URL (pushState/replaceState/popstate); o dedupe ignora a mesma URL.
339
+ const pageview = () => {
340
+ if (autoPageviews)
341
+ analytics?.page();
342
+ };
343
+ const onPop = () => {
344
+ record('(back/forward)', loc.pathname);
345
+ pageview();
346
+ };
347
+ win.addEventListener('popstate', onPop);
348
+ cleanups.push(() => win.removeEventListener('popstate', onPop));
349
+ if (hist && typeof hist.pushState === 'function') {
350
+ const originalPush = hist.pushState;
351
+ const originalReplace = hist.replaceState;
352
+ hist.pushState = (data, unused, url) => {
353
+ const from = loc.pathname;
354
+ originalPush.call(hist, data, unused, url);
355
+ record(from, url ? String(url) : loc.pathname);
356
+ pageview();
357
+ };
358
+ hist.replaceState = (data, unused, url) => {
359
+ originalReplace.call(hist, data, unused, url);
360
+ pageview();
361
+ };
362
+ cleanups.push(() => {
363
+ hist.pushState = originalPush;
364
+ hist.replaceState = originalReplace;
365
+ });
366
+ }
367
+ }
368
+ if (crumbOn('console')) {
369
+ const con = env.console ?? win.console;
370
+ for (const level of ['error', 'warn']) {
371
+ const original = con[level].bind(con);
372
+ con[level] = (...args) => {
373
+ addBreadcrumb({ type: 'console', category: 'console', level: level === 'error' ? 'error' : 'warning', message: args.map((a) => (typeof a === 'string' ? a : toError(a).message)).join(' ').slice(0, 300) });
374
+ original(...args);
375
+ };
376
+ cleanups.push(() => {
377
+ con[level] = original;
378
+ });
379
+ }
380
+ }
381
+ if (crumbOn('fetch') && typeof win.fetch === 'function') {
382
+ const original = win.fetch;
383
+ win.fetch = trackedFetch;
384
+ cleanups.push(() => {
385
+ win.fetch = original;
386
+ });
387
+ }
388
+ const onHide = () => {
389
+ if (queue.length > 0 || analyticsQueue.length > 0)
390
+ void send(queue.splice(0, queue.length), analyticsQueue.splice(0, analyticsQueue.length), true);
391
+ };
392
+ win.addEventListener('pagehide', onHide);
393
+ cleanups.push(() => win.removeEventListener('pagehide', onHide));
394
+ // Pageview da carga inicial.
395
+ if (autoPageviews)
396
+ analytics?.page();
397
+ timer = setInterval(() => {
398
+ // Rede de segurança para roteadores que trocam a URL sem passar pelo history patchado.
399
+ if (autoPageviews)
400
+ analytics?.page();
401
+ void flush();
402
+ }, Math.max(500, options.flushIntervalMs ?? DEFAULT_FLUSH_MS));
403
+ timer.unref?.(); // em Node (testes/SSR) não segura o processo
404
+ }
405
+ if (!enabled)
406
+ (env.console ?? console).warn('[fg-tracker-browser] apiKey ausente: SDK desabilitado.');
407
+ return {
408
+ captureException: (error, attributes) => capture(error, attributes, 'error'),
409
+ captureMessage: (message, level = 'info', attributes) => capture(new Error(message), { ...attributes, isMessage: true }, level),
410
+ addBreadcrumb,
411
+ setUser: (next) => {
412
+ user = next;
413
+ },
414
+ setAttribute: (key, value) => {
415
+ extra = { ...extra, [key]: value };
416
+ },
417
+ fetch: trackedFetch,
418
+ flush,
419
+ page: (path) => {
420
+ analytics?.page(path);
421
+ },
422
+ identify: (userId) => {
423
+ analytics?.identify(userId);
424
+ },
425
+ setConsent: (consent) => {
426
+ analytics?.setConsent(consent);
427
+ },
428
+ close: () => {
429
+ for (const cleanup of cleanups.splice(0))
430
+ cleanup();
431
+ if (timer)
432
+ clearInterval(timer);
433
+ timer = null;
434
+ },
435
+ get breadcrumbs() {
436
+ return crumbs;
437
+ },
438
+ };
439
+ }
440
+ let current = null;
441
+ /** Inicializa uma vez por página; devolve o tracker (também disponível em `getTracker()`). */
442
+ export function init(options) {
443
+ current?.close();
444
+ current = createBrowserTracker(options);
445
+ return current;
446
+ }
447
+ export function getTracker() {
448
+ return current;
449
+ }
450
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,151 @@
1
+ /** Tipos públicos do fg-tracker-browser (CONTRATO.md §24). */
2
+ export interface BrowserUser {
3
+ id: string | number;
4
+ email?: string;
5
+ name?: string;
6
+ }
7
+ export type BreadcrumbType = 'click' | 'navigation' | 'console' | 'fetch' | 'xhr' | 'error' | 'custom';
8
+ export interface Breadcrumb {
9
+ type: BreadcrumbType;
10
+ /** Momento (ISO). */
11
+ ts: string;
12
+ message?: string;
13
+ category?: string;
14
+ level?: 'info' | 'warning' | 'error';
15
+ data?: Record<string, unknown>;
16
+ }
17
+ export interface BrowserOptions {
18
+ /** Chave do projeto (`stk_...`). */
19
+ apiKey: string;
20
+ /** URL base da API do FG Tracker. */
21
+ endpoint: string;
22
+ /** Nome da aplicação (`attributes.serviceName`), ex.: `phase-web`. */
23
+ serviceName?: string;
24
+ /** Versão publicada — o mesmo valor usado no upload dos source maps (`web@<sha>`). */
25
+ release?: string;
26
+ environment?: string;
27
+ /** Usuário inicial (pode ser mudado com `setUser`). */
28
+ user?: BrowserUser | null;
29
+ /** Fração de erros enviados (0..1). Default 1. */
30
+ sampleRate?: number;
31
+ /** Fração de chamadas `fetch` que viram traces (com `traceparent` para a API). Default 0. */
32
+ tracesSampleRate?: number;
33
+ /** Origens que recebem `traceparent` (host, prefixo ou RegExp). Default: mesma origem da página. */
34
+ propagateTraceTo?: (string | RegExp)[];
35
+ /** Erros (nome ou mensagem) ignorados. */
36
+ ignoreErrors?: (string | RegExp)[];
37
+ /** Último filtro: altere o evento ou devolva `null` para descartar. */
38
+ beforeSend?: (event: BrowserEvent) => BrowserEvent | null;
39
+ /** Quais breadcrumbs coletar. Default: todos. */
40
+ breadcrumbs?: Partial<Record<Exclude<BreadcrumbType, 'error' | 'custom'>, boolean>>;
41
+ /** Tamanho do buffer de breadcrumbs. Default 30. */
42
+ maxBreadcrumbs?: number;
43
+ /** Atributos fixos em todo evento (ex.: `{ 'phase.client': 'pwa' }`). */
44
+ attributes?: Record<string, unknown>;
45
+ /** Envia erros automaticamente (`window.onerror`, `unhandledrejection`). Default true. */
46
+ captureGlobalErrors?: boolean;
47
+ /** Intervalo de envio em ms. Default 1500. */
48
+ flushIntervalMs?: number;
49
+ debug?: boolean;
50
+ /**
51
+ * Liga a analytics de tráfego (§25): visitantes anônimos (`fgt_vid`/`fgt_sid`) e pageviews.
52
+ * Default `false` — quem já usa o SDK só para erros não muda de comportamento.
53
+ */
54
+ analytics?: boolean;
55
+ /** Pageviews automáticos (carga inicial + navegação SPA). Default = `analytics`. */
56
+ trackPageviews?: boolean;
57
+ /**
58
+ * Consentimento para analytics (não afeta a captura de erros). `pending` guarda os eventos
59
+ * em memória, sem gravar cookies, até `setConsent('granted')`; `denied` descarta. Default `granted`.
60
+ */
61
+ consent?: Consent;
62
+ /** Domínio dos cookies (ex.: `.fortground.com.br` para compartilhar o visitante entre subdomínios). */
63
+ cookieDomain?: string;
64
+ /**
65
+ * Transforma o caminho antes do envio; devolva `null` para não registrar a página.
66
+ * Default: `normalizePath` (números, uuids e hashes viram `:id`, sem query/hash).
67
+ */
68
+ sanitizePath?: (path: string) => string | null;
69
+ }
70
+ export type Consent = 'granted' | 'denied' | 'pending';
71
+ /** Pageview no formato do `POST /v1/ingest` (`analytics[]`). Sem PII: caminho sem query (exceto `utm_*`), referrer só com a origem. */
72
+ export interface PageviewEvent {
73
+ type: 'pageview';
74
+ /** Caminho + `utm_*` (ex.: `/precos?utm_source=instagram`). */
75
+ url: string;
76
+ title?: string;
77
+ /** Origem do referrer externo (`https://www.google.com`) ou `null`. */
78
+ referrer: string | null;
79
+ utm_source?: string;
80
+ utm_medium?: string;
81
+ utm_campaign?: string;
82
+ utm_term?: string;
83
+ utm_content?: string;
84
+ screen: 'mobile' | 'tablet' | 'desktop' | null;
85
+ locale: string | null;
86
+ visitor_id: string;
87
+ session_id: string;
88
+ /** Id do usuário após `identify` (a API guarda só o hash). */
89
+ user_id?: string;
90
+ ts: string;
91
+ }
92
+ /** Liga o visitante anônimo a um usuário (a API guarda só o hash do id). */
93
+ export interface IdentifyEvent {
94
+ type: 'identify';
95
+ user_id: string;
96
+ visitor_id: string;
97
+ session_id: string;
98
+ ts: string;
99
+ }
100
+ export type AnalyticsEvent = PageviewEvent | IdentifyEvent;
101
+ /** Evento (span `browser`) no formato do `POST /v1/ingest`. */
102
+ export interface BrowserEvent {
103
+ traceId: string;
104
+ spanId: string;
105
+ parentSpanId: string | null;
106
+ kind: 'browser' | 'http.client';
107
+ name: string;
108
+ method: string | null;
109
+ route: string | null;
110
+ statusCode: number | null;
111
+ startedAt: string;
112
+ endedAt: string;
113
+ durationMs: number;
114
+ attributes: Record<string, unknown>;
115
+ error: {
116
+ name: string;
117
+ message: string;
118
+ stack?: string;
119
+ } | null;
120
+ }
121
+ export interface BrowserTracker {
122
+ captureException(error: unknown, attributes?: Record<string, unknown>): void;
123
+ captureMessage(message: string, level?: 'info' | 'warning' | 'error', attributes?: Record<string, unknown>): void;
124
+ addBreadcrumb(crumb: Omit<Breadcrumb, 'ts'> & {
125
+ ts?: string;
126
+ }): void;
127
+ setUser(user: BrowserUser | null): void;
128
+ setAttribute(key: string, value: unknown): void;
129
+ /** `fetch` instrumentado (breadcrumb + trace amostrado com `traceparent`). */
130
+ fetch: typeof globalThis.fetch;
131
+ flush(): Promise<void>;
132
+ /** Pageview manual (default: a URL atual). Ignorado sem `analytics`/`trackPageviews`, com Do Not Track ou `consent: denied`. */
133
+ page(path?: string): void;
134
+ /** Liga o visitante anônimo ao usuário logado (`null` desliga). O id é guardado só como hash na API. */
135
+ identify(userId: string | number | null): void;
136
+ /** Atualiza o consentimento de analytics; `granted` libera a fila retida em `pending`. */
137
+ setConsent(consent: Consent): void;
138
+ /** Remove os listeners globais e o patch do fetch. */
139
+ close(): void;
140
+ readonly breadcrumbs: readonly Breadcrumb[];
141
+ }
142
+ /** Superfície mínima do ambiente (injetável em testes). */
143
+ export interface BrowserEnv {
144
+ window?: Window & typeof globalThis;
145
+ document?: Document;
146
+ navigator?: Navigator;
147
+ location?: Location;
148
+ fetch?: typeof globalThis.fetch;
149
+ console?: Console;
150
+ history?: History;
151
+ }
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ /** Tipos públicos do fg-tracker-browser (CONTRATO.md §24). */
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,8DAA8D"}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "fg-tracker-browser",
3
+ "version": "0.2.0",
4
+ "description": "SDK de navegador do FG Tracker: erros não tratados, breadcrumbs (cliques, navegação, console, fetch), usuário, release e propagação de trace para a API",
5
+ "license": "UNLICENSED",
6
+ "homepage": "https://github.com/FORTGROUND/fg-tracker/tree/main/packages/browser#readme",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/FORTGROUND/fg-tracker.git",
10
+ "directory": "packages/browser"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/FORTGROUND/fg-tracker/issues"
14
+ },
15
+ "keywords": [
16
+ "fg-tracker",
17
+ "browser",
18
+ "error-tracking",
19
+ "breadcrumbs",
20
+ "sourcemaps",
21
+ "tracing",
22
+ "analytics",
23
+ "pageviews"
24
+ ],
25
+ "type": "module",
26
+ "main": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "browser": "./dist/index.js",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "import": "./dist/index.js",
33
+ "default": "./dist/index.js"
34
+ }
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "README.md",
39
+ "CHANGELOG.md"
40
+ ],
41
+ "sideEffects": false,
42
+ "scripts": {
43
+ "build": "tsc -p tsconfig.json",
44
+ "typecheck": "tsc -p tsconfig.json --noEmit",
45
+ "clean": "rm -rf dist",
46
+ "test": "node --test test/*.test.mjs",
47
+ "prepack": "npm run clean && npm run build"
48
+ },
49
+ "devDependencies": {
50
+ "typescript": "^5.9.2"
51
+ },
52
+ "publishConfig": {
53
+ "access": "public"
54
+ }
55
+ }