fg-tracker-browser 0.4.0 → 0.5.1
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 +19 -0
- package/README.md +54 -16
- package/dist/index.d.ts +10 -3
- package/dist/index.js +422 -76
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +67 -6
- package/dist/vitals.d.ts +57 -0
- package/dist/vitals.js +537 -0
- package/dist/vitals.js.map +1 -0
- package/package.json +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog — fg-tracker-browser
|
|
2
2
|
|
|
3
|
+
## 0.5.1
|
|
4
|
+
|
|
5
|
+
- **`toError` e `captureException` nunca lançam**: com `BigInt`, objeto cíclico, getter ou `toString` que lança, Proxy ou Symbol, a mensagem vira a descrição do valor. Antes, `captureException(10n)` lançava, e o fetch instrumentado trocava o motivo de abort que a aplicação recebia (`ac.abort(10n)`, motivo cíclico) por um `TypeError`; agora ela recebe o mesmo motivo.
|
|
6
|
+
- Documentado (CONTRATO.md §16.1): o motivo de abort fica ligado ao único fetch instrumentado que o rejeitou, mesmo quando também chega ao erro por um caminho que o SDK não vê; a cadeia `cause` é seguida até 5 níveis, sem percorrer `AggregateError.errors`, `.response` nem `res.clone()`.
|
|
7
|
+
- Vem depois da 0.5.0 (RUM, #56): o `toError` tolerante também protege o caminho do XHR e o cancelamento que a 0.5.0 trata.
|
|
8
|
+
|
|
9
|
+
## 0.5.0
|
|
10
|
+
|
|
11
|
+
RUM do navegador (CONTRATO.md §24, §24.1).
|
|
12
|
+
|
|
13
|
+
- **Web Vitals por view** (opt-in, `webVitals: true` ou `{ sampleRate, softNavigations }`): LCP, FCP e TTFB da carga do documento; CLS e INP de cada view (carga, navegação SPA ou volta do bfcache). Enviados em `analytics[]` como `type: 'web_vitals'`, com `view_id` e `seq` (a API guarda o maior). Navegação SPA nunca gera LCP; aba aberta oculta não tem LCP/FCP; prerender medido desde a ativação (também com o SDK iniciado durante o prerender); métrica sem observer no navegador fica ausente (nunca 0). Sem cookie, sem dado pessoal, rota por `sanitizePath`. Novo getter `tracker.viewId` e `attributes['view.id']` nos erros e chamadas HTTP (a view de quando a chamada começou).
|
|
14
|
+
- **XHR instrumentado**: breadcrumb `xhr`, trace amostrado com `traceparent` por chamada (o da aplicação é respeitado), vínculo causal por `captureException(err, attrs, { cause: xhr })` (`error.cause: 'xhr'`), URL sem query. `breadcrumbs: { xhr: false }` desliga.
|
|
15
|
+
- **Mudança de comportamento: cancelamento não é erro.** Fetch com `AbortError` e `xhr.abort()` geram `http.client` com `attributes.aborted = true` e `error: null` (antes, cada cancelamento virava issue `AbortError`). Timeout, rede e 5xx continuam erro.
|
|
16
|
+
- **Página oculta envia a fila** (`visibilitychange` → `hidden`), além do `pagehide`: no celular a saída pode não ter `pagehide`. O que não cabe no orçamento do beacon volta para a fila (antes, no `pagehide`, se perdia): uma troca de aba nunca descarta eventos.
|
|
17
|
+
- **Corte de evento grande guarda o vínculo**: `fitEvent` preserva `remoteParentSpanId`, `error.cause`, `serviceName`, `environment`, `release`, `level`, `user.id`, `view.id` e afins antes dos outros atributos (antes, um erro com muitos atributos ou rota enorme perdia o vínculo com o fetch e os filtros de ambiente/serviço).
|
|
18
|
+
- Novos exports: `WEB_VITALS_THRESHOLDS`, `MAX_VIEWS_PER_DOCUMENT`, `MAX_REPORTS_PER_VIEW`, `SOFT_VIEW_GRACE_MS`; tipos `WebVitalsEvent`, `WebVitalsNavigationType`, `WebVitalsOptions`.
|
|
19
|
+
- Bundle (esbuild, minificado + gzip, `init` importado): 6,8 KB → 10,7 KB; Web Vitals ≈ 2,7 KB, XHR/abort/corte ≈ 1,2 KB.
|
|
20
|
+
- Requer a API com `track_web_vitals` (mesma versão do painel com a página Web Vitals); uma API anterior descarta os retratos sem afetar o resto do lote.
|
|
21
|
+
|
|
3
22
|
## 0.4.0
|
|
4
23
|
|
|
5
24
|
- **Erro ligado ao fetch que o causou** (CONTRATO.md §16.1). Com tracing (`tracesSampleRate`) e propagação (`propagateTraceTo`), um erro entra no trace do fetch quando há vínculo causal: o erro que o fetch lançou (inclusive via `unhandledrejection`), um erro cuja cadeia `cause` chega a ele ou à `Response`, ou `captureException(err, attrs, { cause: response })`. O erro fica no mesmo trace da API que atendeu o fetch, pendurado sob o span do fetch (`remoteParentSpanId`), e continua raiz: o agrupamento da issue não muda. Erro sem vínculo continua num trace próprio; nunca "o último trace ativo".
|
package/README.md
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
# fg-tracker-browser
|
|
2
2
|
|
|
3
|
-
SDK de navegador do FG Tracker (CONTRATO.md §24). Sem dependências, ESM, ~
|
|
3
|
+
SDK de navegador do FG Tracker (CONTRATO.md §24). Sem dependências, só ESM, ~11 KB com gzip (~27 KB minificado). Guia público: <https://tracker-site.fortground.com.br/docs/browser/>. Captura erros não tratados com os últimos **breadcrumbs** (cliques, navegação, console, fetch, XHR), o usuário logado, a página e a release; opcionalmente liga o `fetch` e o `XMLHttpRequest` do front ao trace da API (`traceparent`) e mede os **Web Vitals** (LCP, INP, CLS, FCP, TTFB) por view.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
import { init } from 'fg-tracker-browser';
|
|
7
7
|
|
|
8
8
|
const tracker = init({
|
|
9
|
-
apiKey: 'stk_...', // chave do projeto
|
|
10
|
-
endpoint: 'https
|
|
11
|
-
serviceName: '
|
|
9
|
+
apiKey: 'stk_...', // chave PÚBLICA do projeto; nunca a de servidor fgsk_
|
|
10
|
+
endpoint: 'https://tracker-api.fortground.com.br',
|
|
11
|
+
serviceName: 'checkout-web',
|
|
12
12
|
release: import.meta.env.VITE_RELEASE, // o mesmo valor enviado com os source maps
|
|
13
13
|
environment: 'production',
|
|
14
14
|
tracesSampleRate: 0.2, // 20% dos fetches viram traces
|
|
15
|
-
propagateTraceTo: ['api.
|
|
15
|
+
propagateTraceTo: ['api.suaempresa.com.br'], // quem recebe traceparent (default: mesma origem); o CORS dessa API precisa aceitar o header traceparent
|
|
16
16
|
ignoreErrors: [/ResizeObserver loop/],
|
|
17
17
|
});
|
|
18
18
|
|
|
@@ -30,11 +30,11 @@ tracker.addBreadcrumb({ type: 'custom', message: 'modal aberto' });
|
|
|
30
30
|
| `apiKey`, `endpoint` | — | sem `apiKey` o SDK vira no-op (com aviso) |
|
|
31
31
|
| `serviceName`, `release`, `environment`, `user`, `attributes` | — | vão em todo evento |
|
|
32
32
|
| `sampleRate` | `1` | fração de erros enviados |
|
|
33
|
-
| `tracesSampleRate` | `0` | fração de
|
|
33
|
+
| `tracesSampleRate` | `0` | fração de chamadas `fetch`/XHR que geram um trace (`browser` → `http.client`) |
|
|
34
34
|
| `propagateTraceTo` | mesma origem | hosts/prefixos/RegExp que recebem `traceparent` |
|
|
35
35
|
| `ignoreErrors` | `[]` | `name: message` (string/RegExp) ignorados |
|
|
36
36
|
| `beforeSend` | — | `(event) => event \| null` |
|
|
37
|
-
| `breadcrumbs` | tudo ligado | `{ click, navigation, console, fetch }` |
|
|
37
|
+
| `breadcrumbs` | tudo ligado | `{ click, navigation, console, fetch, xhr }`; `fetch: false`/`xhr: false` também tiram a instrumentação daquele cliente HTTP |
|
|
38
38
|
| `maxBreadcrumbs` | `30` | anel de breadcrumbs |
|
|
39
39
|
| `captureGlobalErrors` | `true` | `window.onerror` + `unhandledrejection` |
|
|
40
40
|
| `flushIntervalMs` | `1500` | envio em lote (`keepalive` dentro do orçamento de 64 KiB; `sendBeacon` ao sair da página) |
|
|
@@ -42,23 +42,32 @@ tracker.addBreadcrumb({ type: 'custom', message: 'modal aberto' });
|
|
|
42
42
|
| `trackPageviews` | `= analytics` | pageviews automáticos (carga inicial, `pushState`/`replaceState`/`popstate`) |
|
|
43
43
|
| `consent` | `'granted'` | `'pending'` guarda em memória sem cookies até `setConsent('granted')`; `'denied'` descarta |
|
|
44
44
|
| `cookieDomain` | — | ex.: `.fortground.com.br` para o mesmo visitante entre subdomínios |
|
|
45
|
-
| `sanitizePath` | `normalizePath` | `(path) => string \| null` antes do envio (`null` não registra) |
|
|
45
|
+
| `sanitizePath` | `normalizePath` | `(path) => string \| null` antes do envio (`null` não registra); vale para pageviews e Web Vitals |
|
|
46
|
+
| `webVitals` | `false` | `true` ou `{ sampleRate, softNavigations }`: Web Vitals por view (abaixo). Quem não passa a opção não muda nada |
|
|
47
|
+
|
|
48
|
+
> **Só a chave pública `stk_…` vai no navegador.** Tudo no bundle é público. O pacote não confere o prefixo: com a chave de servidor `fgsk_…` o segredo vaza e o envio falha (CORS recusa a origem e o `sendBeacon` recebe `401 SERVER_KEY_IN_URL`). Se isso acontecer, rotacione a `fgsk_` em Configurações → Chaves de ingestão.
|
|
49
|
+
>
|
|
50
|
+
> Não capturado: `XMLHttpRequest` (axios), Web Vitals e tempos de carregamento.
|
|
46
51
|
|
|
47
52
|
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.
|
|
48
53
|
|
|
49
54
|
Com `tracesSampleRate` e `propagateTraceTo`, um erro **causado** por um fetch entra no trace dele, junto da API que o atendeu: o erro que o fetch lançou (também quando chega como rejeição não tratada), um erro com `cause` apontando para esse erro ou para a `Response`, ou `captureException(err, attrs, { cause: response })`. Sem vínculo causal (erro de UI, outro fetch), o erro fica num trace próprio: o SDK nunca usa "o último trace ativo", que daria o trace errado com fetches em paralelo.
|
|
50
55
|
|
|
56
|
+
**XHR** (`XMLHttpRequest`, desde a 0.5): mesmo breadcrumb (`type: 'xhr'`) e mesmo trace amostrado do fetch, com `traceparent` próprio por chamada (se a aplicação já mandou um, o dela fica e o SDK não injeta outro). O vínculo causal é o próprio objeto: `captureException(err, attrs, { cause: xhr })` (`attributes['error.cause'] = 'xhr'`). A chamada fecha antes do `onload`/`onloadend` da aplicação, então um erro capturado ali já vê o breadcrumb dela. Chamadas encadeadas no mesmo objeto (`open()`/`send()` de novo no `onreadystatechange` de DONE, no `onload`, no `onerror` ou no `onloadend`) saem cada uma com o próprio span, resultado e duração; reabrir uma chamada ainda pendente a registra como cancelada. No XHR a URL sai sem query (`attributes.url` e `breadcrumbs[].data.url` = origem + caminho).
|
|
57
|
+
|
|
58
|
+
**Cancelamento não é erro** (desde a 0.5): fetch com `AbortError` (AbortController) e `xhr.abort()` geram o span `http.client` com `attributes.aborted = true` e `error: null`, e o breadcrumb com nível `warning`; antes, cada cancelamento (React Query, troca de rota) virava uma issue `AbortError`. Timeout (`TimeoutError`), falha de rede e 5xx continuam erro.
|
|
59
|
+
|
|
51
60
|
### Envio (CONTRATO.md §4.3)
|
|
52
61
|
|
|
53
62
|
- Rede, timeout (10 s), 408, 429 e 5xx: o lote volta para a fila (até 200 eventos de cada tipo) e o próximo envio espera um backoff com jitter (1 s → 60 s) ou o `Retry-After` da resposta. 413 divide o lote; outro 4xx descarta. O reenvio não duplica: spans e pageviews têm identidade e a API deduplica.
|
|
54
63
|
- O navegador aceita no máximo ~64 KiB em voo somando `fetch` com `keepalive` e `sendBeacon`; acima disso a requisição falha antes de chegar à API. O SDK só usa `keepalive` enquanto o lote cabe no que sobra de 60 KiB; lotes maiores vão sem `keepalive`.
|
|
55
|
-
- No `pagehide`, a fila (e um lote em voo sem `keepalive`, que o navegador cancelaria) sai em pedaços de até 60 KiB por `sendBeacon`, erros primeiro, depois pageviews, depois o resto, até o orçamento. O que não couber
|
|
56
|
-
- Um evento acima de 48 KiB é cortado (5 últimos breadcrumbs, stack e mensagem encurtados) e leva `attributes['fg.truncated'] = true`.
|
|
64
|
+
- No `pagehide` e quando a página fica oculta (`visibilitychange`, desde a 0.5: no celular o `pagehide` pode nunca chegar), a fila (e um lote em voo sem `keepalive`, que o navegador cancelaria) sai em pedaços de até 60 KiB por `sendBeacon`, erros primeiro, depois pageviews e Web Vitals, depois o resto, até o orçamento. O que não couber volta para a fila: numa troca de aba (a página continua viva) sai no flush normal; numa saída de verdade, a memória vai junto. Ao só ocultar, o lote em voo sem `keepalive` segue em voo e não é reenviado.
|
|
65
|
+
- Um evento acima de 48 KiB é cortado (5 últimos breadcrumbs, stack e mensagem encurtados) e leva `attributes['fg.truncated'] = true`. O corte guarda antes de tudo as chaves de identidade e vínculo (`remoteParentSpanId`, `error.cause`, `serviceName`, `environment`, `release`, `level`, `user.id`, `view.id`…): o erro cortado continua pendurado no fetch e nos filtros de ambiente/serviço.
|
|
57
66
|
|
|
58
67
|
## Tráfego (pageviews)
|
|
59
68
|
|
|
60
69
|
```ts
|
|
61
|
-
const tracker = init({ apiKey: 'stk_...', endpoint: 'https
|
|
70
|
+
const tracker = init({ apiKey: 'stk_...', endpoint: 'https://tracker-api.fortground.com.br', serviceName: 'meu-site', analytics: true });
|
|
62
71
|
tracker.identify(user.id); // liga o visitante ao usuário (a API guarda só sha256 com sal do projeto)
|
|
63
72
|
tracker.page('/checkout/sucesso'); // pageview manual (dedupe com o automático pela URL)
|
|
64
73
|
tracker.setConsent('granted'); // quando o banner de cookies for aceito (se iniciou com consent: 'pending')
|
|
@@ -66,16 +75,39 @@ tracker.setConsent('granted'); // quando o banner de cookies for aceito (se
|
|
|
66
75
|
|
|
67
76
|
- 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.
|
|
68
77
|
- Payload (`analytics[]` no `POST /v1/ingest`): `{ type: 'pageview', event_id, 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', event_id, user_id, visitor_id, session_id, ts }`. O `event_id` (32 hex) é gerado no navegador: reenviar o lote não conta o pageview duas vezes.
|
|
69
|
-
- `navigator.doNotTrack === '1'` desliga a analytics (erros continuam).
|
|
70
|
-
- Instalação em Next.js App Router:
|
|
78
|
+
- `navigator.doNotTrack === '1'` desliga a analytics (erros continuam). Nos pageviews, query string, hash, e-mail e títulos não são guardados pela API. `consent` vale só para pageviews: erros continuam sendo enviados com a URL completa e o usuário de `setUser`.
|
|
79
|
+
- Instalação em Next.js App Router: <https://tracker-site.fortground.com.br/docs/browser/#nextjs>.
|
|
80
|
+
|
|
81
|
+
## Web Vitals
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
init({ apiKey: 'stk_...', endpoint: 'https://<api-do-fg-tracker>', serviceName: 'meu-site', environment: 'production', webVitals: true });
|
|
85
|
+
// ou: webVitals: { sampleRate: 0.25, softNavigations: true }
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Painel: **Web Vitals** (p75, faixas bom/a melhorar/ruim, série, tabela por rota). Contrato: CONTRATO.md §24.1.
|
|
89
|
+
|
|
90
|
+
- **View** = carga do documento (`navigate`, `reload`, `back_forward`, `prerender`), navegação SPA (`soft`: `pushState`/`replaceState`/`popstate` com caminho novo) ou volta do bfcache (`restore`). Cada view tem um id aleatório (`view_id`), que também vai em `attributes['view.id']` dos erros e das chamadas HTTP da mesma view.
|
|
91
|
+
- **LCP, FCP e TTFB** só na carga do documento, contados até a página ficar oculta pela primeira vez (aba aberta em segundo plano não tem LCP nem FCP: `started_hidden`). O LCP fecha no primeiro input (tecla, ponteiro) ou ao ocultar. Uma navegação SPA **nunca** gera LCP: o conteúdo da rota nova não é a carga do documento. No prerender, os tempos contam a partir da ativação (lida no relatório, também com o SDK iniciado durante o prerender); a ocultação antes da ativação não conta, e um prerender nunca ativado não gera retrato.
|
|
92
|
+
- Uma chamada `fetch`/XHR fica com a view e a rota de quando começou, mesmo que termine depois de uma navegação SPA.
|
|
93
|
+
- **CLS** de cada view: a maior janela de sessão (shifts a menos de 1 s um do outro, janela de até 5 s), sem os shifts logo depois de input. Navegador sem `layout-shift`: CLS ausente, nunca 0.
|
|
94
|
+
- **INP** de cada view: a interação mais lenta (p98 aproximado: a cada 50 interações descarta a pior), só em views com interação. Interações contadas pelo `interactionId` das entradas de Event Timing de ≥ 16 ms (mais a primeira, de qualquer duração).
|
|
95
|
+
- As entradas de performance pertencem à view pelo instante em que aconteceram, não pela hora em que chegam: o clique que dispara a navegação SPA conta na view anterior. Uma interação inteira (keydown e keyup da mesma tecla, por exemplo) fica na view onde começou, mesmo que o keyup venha depois da navegação; se ele só chegar depois de essa view fechar, é descartado (nunca conta na view nova).
|
|
96
|
+
- **Quando sai**: ao ocultar a página (troca de aba, app em segundo plano, saída) e 1 s depois de uma navegação SPA (a view anterior). Cada relatório é um retrato completo da view com `seq` crescente; se a pessoa volta e interage, sai outro retrato da mesma view (a API guarda o de maior `seq`, então reenvio e ordem trocada são seguros). Sem mudança, nada sai.
|
|
97
|
+
- **Payload** (`analytics[]` no `POST /v1/ingest`): `{ type: 'web_vitals', view_id, seq, navigation_type, route, started_at, ts, started_hidden?, lcp?, fcp?, ttfb?, cls?, inp?, lcp_element?, inp_event?, inp_target?, interactions, screen, connection?, sample_rate, service?, environment?, release? }`. Tempos em ms, CLS sem unidade.
|
|
98
|
+
- **Privacidade**: sem cookie, sem visitante/sessão e sem dado pessoal. A rota passa por `sanitizePath` (sem query, ids viram `:id`; `null` não mede a rota); do elemento do LCP e do alvo do INP vai só a tag (`img`, `button`), nunca texto, id ou URL. Independe de `analytics`, `consent` e Do Not Track (é medida de desempenho, como os erros); a opção é opt-in.
|
|
99
|
+
- **Amostragem e limites**: `sampleRate` sorteia por carga do documento (as navegações SPA seguem a carga) e vai em cada retrato, para o painel ponderar percentis e estimar o volume. No máximo 100 views por documento e 20 retratos por view; fora da amostra ou sem `PerformanceObserver`, nada é medido (`viewId` = `null`).
|
|
100
|
+
- **Compatibilidade**: navegadores Chromium (Chrome, Edge) medem as cinco métricas. Outros podem não expor alguns tipos de entrada (`largest-contentful-paint`, `layout-shift`, `event`): o SDK confere `PerformanceObserver.supportedEntryTypes`, mede o que existe e manda só o que mediu (a cobertura do painel mostra em quantas views cada métrica veio). Uma API sem suporte a Web Vitals descarta o retrato (conta em `analytics.rejected`) sem afetar erros e pageviews do mesmo lote.
|
|
101
|
+
- **Custo**: +2,7 KB com gzip (6,3 KB minificado) no bundle, mesmo com a opção desligada; com ela, um observer por tipo de entrada e nenhum timer contínuo.
|
|
71
102
|
|
|
72
103
|
## Source maps
|
|
73
104
|
|
|
74
105
|
Suba os `.map` da release no deploy (e apague-os do bundle público):
|
|
75
106
|
|
|
76
107
|
```sh
|
|
77
|
-
|
|
78
|
-
|
|
108
|
+
# chave de servidor (no modo restrito a pública recebe 403); rode no CI, nunca no navegador
|
|
109
|
+
FG_TRACKER_KEY=fgsk_... FG_TRACKER_URL=https://tracker-api.fortground.com.br \
|
|
110
|
+
npx -p fg-tracker-sdk fg-tracker-sourcemaps --dir dist --release "checkout-web@$GITHUB_SHA" --url-prefix "~/assets"
|
|
79
111
|
find dist -name '*.map' -delete
|
|
80
112
|
```
|
|
81
113
|
|
|
@@ -83,7 +115,13 @@ A ingestão traduz `app-3f2a1c.js:1:48213` para `src/checkout/Cart.tsx:42:11`: o
|
|
|
83
115
|
|
|
84
116
|
O `endpoint` é obrigatório: use a URL da API mostrada no painel em **Conectar**. O endereço de produção da API é `https://tracker-api.fortground.com.br` (o antigo `track-api.fortground.com.br` continua respondendo). O SDK envia a chave no header `x-fg-tracker-key` (e em `?key=` no `sendBeacon`).
|
|
85
117
|
|
|
86
|
-
Cadastre a origem do site em **Configurações → Geral → Domínios permitidos** do projeto (ex.: `https://www.seusite.com.br`, `https://*.seusite.com.br`, `http://localhost:3000`); sem isso o navegador bloqueia o envio por CORS.
|
|
118
|
+
Cadastre a origem do site em **Configurações → Geral → Domínios permitidos** do projeto (ex.: `https://www.seusite.com.br`, `https://*.seusite.com.br`, `http://localhost:3000`); sem isso o navegador bloqueia o envio por CORS.
|
|
119
|
+
|
|
120
|
+
## Limites do vínculo com o fetch
|
|
121
|
+
|
|
122
|
+
- Um motivo de abort que um único fetch instrumentado rejeitou fica ligado a esse fetch, mesmo quando o mesmo objeto chega ao erro por um caminho que o SDK não vê (`signal.throwIfAborted()`, um fetch capturado antes do `init()`). Um motivo que saiu de mais de um fetch é ambíguo e não liga.
|
|
123
|
+
- A cadeia `cause` é seguida até 5 níveis. `AggregateError.errors`, `.response` (ky, ofetch) e `res.clone()` não são percorridos: use `captureException(err, attrs, { cause: response })`.
|
|
124
|
+
- `captureException` aceita qualquer valor (BigInt, objeto cíclico, getter que lança) sem lançar, e o fetch instrumentado devolve à aplicação o mesmo motivo de abort que recebeu.
|
|
87
125
|
|
|
88
126
|
## Migração de stread-track-browser
|
|
89
127
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { BrowserEnv, BrowserEvent, BrowserOptions, BrowserTracker } from './types.js';
|
|
2
|
-
export type { AnalyticsEvent, Breadcrumb, CaptureOptions, BreadcrumbType, BrowserEnv, BrowserEvent, BrowserOptions, BrowserTracker, BrowserUser, Consent, IdentifyEvent, PageviewEvent, } from './types.js';
|
|
2
|
+
export type { AnalyticsEvent, Breadcrumb, CaptureOptions, BreadcrumbType, BrowserEnv, BrowserEvent, BrowserOptions, BrowserTracker, BrowserUser, Consent, IdentifyEvent, PageviewEvent, WebVitalsEvent, WebVitalsNavigationType, WebVitalsOptions, } from './types.js';
|
|
3
3
|
/** Header da chave do projeto enviado pelo SDK (a API aceita também o legado `x-stread-track-key`). */
|
|
4
4
|
export declare const API_KEY_HEADER = "x-fg-tracker-key";
|
|
5
5
|
export { doNotTrackEnabled, pageUrl, referrerOrigin, screenBucket, utmParams, SESSION_COOKIE, VISITOR_COOKIE } from './analytics.js';
|
|
6
|
+
export { MAX_REPORTS_PER_VIEW, MAX_VIEWS_PER_DOCUMENT, SOFT_VIEW_GRACE_MS, WEB_VITALS_THRESHOLDS } from './vitals.js';
|
|
6
7
|
/**
|
|
7
8
|
* `fetch` com `keepalive` e `sendBeacon` têm ~64 KiB em voo, somados: acima disso o navegador
|
|
8
9
|
* recusa antes de chegar à API (sem 413). Lotes e o flush do `pagehide` cabem neste orçamento.
|
|
@@ -20,12 +21,18 @@ export declare function parseRetryAfter(value: string | null | undefined, now?:
|
|
|
20
21
|
export declare function toJsonSafe(value: unknown, seen?: WeakSet<object>): unknown;
|
|
21
22
|
/**
|
|
22
23
|
* Cabe um evento em `MAX_EVENT_BYTES` (bytes UTF-8 do JSON): primeiro só os 5 últimos
|
|
23
|
-
* breadcrumbs, depois stack e mensagem cortados, depois
|
|
24
|
-
* acumulado, e por fim só
|
|
24
|
+
* breadcrumbs, depois stack e mensagem cortados, depois as chaves de identidade e vínculo
|
|
25
|
+
* (`KEY_ATTRIBUTES`) e os atributos curtos dentro de um orçamento acumulado, e por fim só as
|
|
26
|
+
* chaves de identidade. Marca `attributes['fg.truncated']`. Nunca lança.
|
|
25
27
|
*/
|
|
26
28
|
export declare function fitEvent(event: BrowserEvent, maxBytes?: number): BrowserEvent;
|
|
27
29
|
/** `/orders/42/items/9f…` → `/orders/:id/items/:id` (mesma regra do SDK Node). */
|
|
28
30
|
export declare function normalizePath(input: string | undefined | null): string;
|
|
31
|
+
/**
|
|
32
|
+
* Nome, mensagem e stack de qualquer valor lançado ou capturado. Nunca lança (BigInt, objeto
|
|
33
|
+
* cíclico, getter ou `toString` que lança, Proxy): roda no `catch` do fetch instrumentado, que
|
|
34
|
+
* relança o motivo original para a aplicação, e no `captureException`.
|
|
35
|
+
*/
|
|
29
36
|
export declare function toError(input: unknown): {
|
|
30
37
|
name: string;
|
|
31
38
|
message: string;
|