JavaScript SDKVersions
Documentation / Getting started / Versions
JavaScript SDK
Every stable version of JavaScript SDK, newest first.
Release notes are written in Italian.
0.14.2 · 2026-10-07
Corretto
- La 0.14.1 non è stata pubblicata. Le destinazioni con schema (
http://host,location.origin) tornano a essere riconosciute: confronto su schema, host e porta quando indicata.
0.14.1 · 2026-10-07
Corretto
- La 0.14.0 non è stata pubblicata. Questa versione la sostituisce con lo stesso contenuto; il tetto del bundle è stato alzato di 0,5 KB per il nuovo mascheramento.
0.14.0 · 2026-10-07
Modificato
- Host fidati del trace confrontati per nome host. Una stringa in
tracePropagationTargetsvale solo per quell'host o i suoi sottodomini (example.comcopreapi.example.com): prima bastava che l'indirizzo la contenesse. Le espressioni regolari non cambiano. (CYJS-63)
Corretto
- Token fuori da widget di aiuto e breadcrumb. Il pulsante «Serve aiuto?» invia solo origine e percorso della pagina, il testo dei breadcrumb è mascherato come i messaggi d'errore e il cookie del replay è marcato
Secure. (CYJS-63)
0.13.0 · 2026-10-05
Added
- Query lente e ripetute su Node. Puoi osservare PostgreSQL e MySQL, anche tramite Drizzle e l'adapter PostgreSQL di Prisma. La raccolta è facoltativa, oscura i dati delle query e si disattiva senza chiudere le connessioni dell'applicazione.
0.12.0 · 2026-10-04
Aggiunto
- Integrazioni per i framework web. Adapter opzionali per React, Next.js, Vue, Nuxt, Angular, Svelte e SvelteKit collegano errori e richieste al contesto applicativo. Le guide indicano versioni collaudate e limiti.
- Pulsante «Serve aiuto?» — una riga di
<script>aggiunge al sito un pulsante con il modulo per scrivere al team. È un file a parte: chi non lo usa non scarica niente in più. (CYRA-942)
Corretto
- Cause degli errori conservate. Gli eventi includono fino a dieci eccezioni concatenate, con dati sensibili oscurati e protezioni contro cicli e proprietà illeggibili.
0.11.4 · 2026-10-01
Corretto
- Pubblicazione riparata. La 0.11.3 non è arrivata su npm: questa versione contiene le stesse modifiche.
0.11.3 · 2026-10-01
Modificato
- Manutenzione interna. La pubblicazione su npm non usa più un token salvato e le dipendenze di sviluppo sono aggiornate. Per chi usa la libreria non cambia niente. (CYJS-39)
0.11.2 · 2026-09-07
Sicurezza
- Una chiave d'accesso finita dentro a un messaggio ora sparisce per intero — se un errore riportava la riga di accesso, la libreria ne nascondeva solo l'inizio e lasciava visibile la parte che conta. Ora di quella riga resta il solo nome, e il resto del messaggio si legge come prima (CYJS-38).
- Un rimbalzo del server non può più far viaggiare in chiaro la chiave d'accesso — se l'indirizzo di raccolta rispondeva «vai qui», la libreria lo seguiva anche verso una connessione non protetta. Ora rimbalzi e catene di rimbalzi si accettano solo entro l'indirizzo di partenza (CYJS-37).
0.11.1 · 2026-09-03
Sicurezza
- Chiusa una falla in una libreria usata solo per le prove — il componente che controlla i formati durante lo sviluppo si appoggiava a una versione che poteva essere ingannata su quale indirizzo stesse leggendo. Non finiva nel pacchetto che si installa, ma ora è aggiornato lo stesso.
0.11.0 · 2026-09-03
Aggiunto
- Le applicazioni JavaScript dicono quali funzioni vengono davvero usate — con
usageEnabledla libreria manda ogni 5 minuti l'elenco di route, job e chiavi eseguite, e il progetto compare nella pagina d'uso e nella riga di comando. Solo lato server: nel browser resta spenta e lo dice.
Modificato
- La presentazione della libreria non promette più di fare le stesse cose delle altre — si diceva identica alle librerie Ruby e Dart, ma alcune funzioni esistono solo in una o due. Ora rimanda alla tabella unica che dice quale libreria sa fare cosa, e da quale versione.
Sicurezza
- Solo versioni definitive arrivano a chi installa la libreria — chi la installa senza chiedere
un numero preciso riceve quella che il magazzino pubblico segna come «l'ultima buona». Finora
bastava un'etichetta di prova per far partire la pubblicazione vera: il commento sopra al lavoro
diceva «solo versioni definitive», la regola scritta accettava qualunque etichetta che cominciasse
per
v. Roba non ancora verificata sarebbe finita in casa di chi usa la libreria, marcata come l'ultima buona — non è mai successo solo perché i rilasci li ha sempre fatti una persona a mano. Adesso la pubblicazione si ferma prima di partire quando l'etichetta non è definitiva.
Corretto
- Il numero del rilascio e quello dentro il pacchetto non possono più divergere — erano tre numeri diversi che nessuno metteva a confronto: quello dell'etichetta, quello scritto nel pacchetto, e quello che la libreria dichiara di essere quando ci manda un errore. Un rilascio poteva chiamarsi 0.12.0 e pubblicare 0.11.0 senza che nulla diventasse rosso; e se 0.11.0 era già uscita, il magazzino rifiutava il rilascio buono lasciando il lavoro a metà. Il terzo numero, se restava indietro, faceva comparire nel pannello gli errori dei siti sotto una versione che non era quella vera. Adesso il rilascio si ferma prima di pubblicare quando i tre numeri non coincidono, e dice quale non torna.
0.10.0 · 2026-08-16
Aggiunto
- Velocità percepita dai visitatori veri (CYJS-12, CYJS-28) — con
trackWebVitals: truel'SDK misura sul browser di chi visita il sito le tre cose con cui Google giudica la velocità: quanto ci mette a comparire il contenuto principale (LCP), quanto la pagina si sposta sotto gli occhi mentre carica (CLS) e quanto tarda a rispondere quando la si tocca (INP). Insieme arrivano le due misure che spiegano un caricamento lento: quanto ci mette il server a rispondere (TTFB) e quando compare il primo pezzo di pagina (FCP). Finora quei numeri si potevano solo stimare in laboratorio: adesso arrivano dalle visite vere, pagina per pagina.
A misurarli è la libreria di Google, la stessa che sta dietro ai dati che Google pubblica sui siti: così i numeri di CloseYourIt e quelli che si leggono altrove parlano della stessa cosa e si possono mettere una accanto all'altra. È l'unica libreria esterna che l'SDK si porta dietro, ed è dentro il pacchetto: chi lo installa non deve aggiungere nulla.
Le misure partono tutte insieme, in un invio solo, quando la pagina esce di scena: prima di allora sono provvisorie — il contenuto principale può ancora essere superato da uno più grande, gli spostamenti possono ancora aumentare. Un valore per metrica a caricamento: una seconda uscita non produce un doppione. Quello che arriva in ritardo, dopo che l'invio è già partito, viene mandato entro cinque secondi invece di restare fermo in attesa di un'uscita di pagina che potrebbe non arrivare mai. Nel corpo viaggiano il nome del sito, il percorso della pagina (mai la query, che può contenere dati riservati), il tipo di navigazione, l'ambiente e la versione: nessun dato che identifichi il visitatore. Il giudizio buono/da migliorare/scarso non viene mandato — lo calcola CloseYourIt, così un SDK vecchio non può dipingere di verde ciò che oggi è rosso.webVitalsSampleRate(default1.0, indipendente dal campionamento degli errori) permette di raccoglierne solo una parte, e decide sul caricamento intero: le misure di una pagina partono tutte o nessuna, altrimenti i percentili di metriche diverse verrebbero da insiemi di pagine diversi e non sarebbero più confrontabili tra loro.
Dove il browser non sa misurare, non succede nulla: la metrica che manca semplicemente non arriva, le altre partono lo stesso e il resto dell'SDK non cambia comportamento.
Nota per chi pubblica questa versione. Lo snippet che i siti caricano da CDN non è fissato a una versione: appena questa esce, entro pochi giorni arriva da sola su tutti i siti che hanno installato CloseYourIt. Le misure hanno quindi bisogno che la parte che le riceve sia già attiva in produzione (CYRA-538), altrimenti i browser dei visitatori manderebbero dati verso una porta chiusa. Prima quello, poi la pubblicazione. - Risorse che non caricano e policy del browser che bloccano (CYJS-12) — con
captureResourceErrors: truel'SDK segnala i guasti che nessun errore JavaScript racconta: uno script o un foglio di stile che non arriva, un'immagine che non carica, una regola di sicurezza della pagina (CSP) che blocca qualcosa che serviva. Prima quei fallimenti erano invisibili: il browser li segnalava e basta, e la pagina restava rotta senza che nessuno lo sapesse.
Arrivano insieme agli altri errori, ma come avvisi e non come errori dell'applicazione: una risorsa bloccata è quasi sempre ambiente o terze parti — un blocco pubblicità, una CDN irraggiungibile — e trattarla da guasto riempirebbe gli avvisi di rumore che nessuno può correggere. Gli indirizzi viaggiano sempre senza query string, che nelle CDN porta le firme di accesso. Il tetto è di dieci segnalazioni per pagina e la stessa risorsa che continua a fallire ne vale una sola: una CDN giù fa fallire ogni immagine del catalogo, e le prime dicono già tutto.
Cambiato
- Il peso dello snippet ha un tetto, e la CI lo fa rispettare (CYJS-28) — lo
<script>che i siti caricano da CDN lo scarica ogni visitatore di ogni sito che ha installato CloseYourIt, anche chi delle novità non usa niente. Da ora la sua dimensione massima è scritta nel progetto e viene verificata a ogni modifica: se una nuova funzione lo fa crescere oltre il tetto, il controllo si ferma e la crescita va discussa invece di passare inosservata. Con le misure di velocità dentro, lo snippet pesa circa 18 KB compressi.
0.9.0 · 2026-08-15
Cambiato
- L'ultima misura parte anche quando la scheda si chiude (CYJS-29) — chiudendo la pagina l'invio in
corso poteva non arrivare mai, soprattutto su iPhone: la richiesta veniva abbandonata a metà e quel
dato spariva senza lasciare traccia. Da
pagehide/visibilitychange(hidden)in poi gli invii del browser passano dal canale che i browser tengono in vita apposta per questo momento (navigator.sendBeacon), quindi l'ultima misura, l'ultimo log e l'ultimo errore arrivano lo stesso.
Vale solo per il browser autenticato con la DSN public key: quel canale non può portare header, e con il bearer l'invio partirebbe senza credenziale — lì resta ilfetchdi prima. Il body viaggia cometext/plain(lo stesso JSON di sempre): conapplication/jsonil browser anteporrebbe una richiesta di permesso che, a pagina in chiusura, non fa in tempo a completarsi. Dove il canale non c'è o rifiuta il payload perché la sua quota è esaurita, si ripiega sulfetchdi prima: un invio senza garanzie è meglio di un invio perso.
Nota per chi legge i contatori: il browser non restituisce una risposta per questi invii. Contano comesentnel senso di "presi in carico dal browser" e il loro evento diagnosticosendnon porta unostatus. Al ritorno in primo piano (ripristino da bfcache) si torna alfetch, che la risposta la dà. - Le registrazioni delle sessioni mascherano anche il testo mostrato dalla pagina (CYJS-15) — prima
il masking di default copriva solo quello che l'utente digitava nei campi. In un gestionale i dati
sensibili sono soprattutto testo che la pagina mostra — nomi di clienti, pratiche, importi — e finiva
registrato in chiaro. Ora
replayMaskTextSelectorvale'*'per default, il selettore che in rrweb fa matchare ogni elemento: tutto il testo risulta coperto.
Cambio di comportamento. Chi vuole vedere in chiaro una parte della pagina deve dichiararlo, passando un selettore più stretto (replayMaskTextSelector: '.riservato'maschera solo quella parte). Chi già passava un selettore proprio non è toccato: il valore esplicito vince sul default.
Il motivo per cui il default va dalla parte stretta: una registrazione non si corregge a posteriori, un dato finito in chiaro si toglie solo cancellando l'intera registrazione.
Infrastruttura
- Toolchain aggiornata e catena di build irrobustita (CYJS-14) — le action della CI non girano più su
un tag mobile (
@v6) ma sullo SHA del commit, con la versione nel commento: un tag può essere spostato su codice mai revisionato, e qui accanto gira il job che pubblica su npm. IlGITHUB_TOKENparte in sola lettura per tutti i job e solo la pubblicazione alza i permessi, per il solo OIDC. A ogni run un audit verifica le dipendenze che finiscono davvero nel pacchetto pubblicato (pnpm run audit:prod). - Aggiornamenti separati e verificabili (CYJS-14) — Dependabot sorveglia sia le action della CI sia i pacchetti npm: minor e patch arrivano raggruppate, ogni salto maggiore resta una richiesta a sé, da valutare con i suoi gate verdi. Un contratto in test blinda la regola, così un bump collettivo non può rientrare di nascosto.
- Strumenti di sviluppo aggiornati un salto per volta (CYJS-14) —
@types/nodealla 24 (la major del Node in uso, non l'ultima pubblicata: i tipi devono descrivere il runtime che gira davvero),jsdomalla 29 evitestcon@vitest/coverage-v8alla 4. Nessun effetto sul pacchetto pubblicato: sono gli strumenti con cui viene costruito e verificato.typescriptresta sulla 5 perché la 7 rompe la generazione dei tipi dentrotsup; il motivo è annotato dove serve, così chi ci riprova non riparte da zero. Un test in più rifiuta gli aggiornamenti che chiedono un Node più nuovo di quello della toolchain: prima quel disallineamento si scopriva solo a CI rotta.
0.8.0 · 2026-08-06
Aggiunto
- Visibilità degli eventi scartati dallo SDK (CYJS-9) — quando un evento non parte (coda piena,
beforeSendche lo scarta o solleva, campionamento, timeout,4xx/429/5xx, rete assente) l'applicazione può ora diagnosticarlo senza generare nuova telemetria.getStats()espone, oltre agli aggregati (enqueued/sent/dropped/failed/timeout), la ripartizionereasonsper motivo; la nuova opzioneonDiagnostic(event, details)notifica in tempo reale ogni tappa (enqueue/send/drop/timeout/shutdown) con il motivo. L'hook è process-local e non ricorsivo (mentre gira, le API di cattura sono no-op e i diagnostici annidati soppressi), idetailsnon contengono mai payload né segreti (errorè il solo nome della classe). Inoltre unbeforeSendche solleva non propaga più: l'errore è assorbito e contabilizzato come scarto (motivoerror). - Propagazione del contesto di tracing W3C (CYJS-13) — lo SDK legge e propaga gli header standard
traceparent/tracestate(W3C Trace Context), così servizi e browser che usano il tracing distribuito mantengono la correlazione senza un protocollo proprietario.continueTrace(carrier)adotta un trace context in ingresso (header di richiesta server/SSR, unHeaderso un getter): il suo trace-id diventa iltrace_iddi correlazione — errori, log e metriche si agganciano al trace distribuito — e parent/sampling/tracestate/baggage sono conservati per la ri-propagazione.getTraceHeaders(target?)restituisce gli header da iniettare in una richiesta in uscita, ma solo verso destinazioni fidate: la nuova opzionetracePropagationTargets(allowlist di stringhe o RegExp) più il same-origin nel browser. Verso ogni altra destinazione ritorna{}— nessun header — così il trace interno e il baggage (potenziale PII) non raggiungono host non fidati. Header assente o malformato: no-op, si mantiene il trace corrente. Isomorfo browser/Node, zero dipendenze.
0.7.1 · 2026-08-06
Corretto
- Riconfigurazione dell'SDK a caldo senza riavviare Node (CYJS-8) — richiamare
initcon opzioni diverse (endpoint, token, release, …) veniva ignorato finché l'SDK era attivo: la nuova configurazione non entrava mai in uso. Orainitriconfigura a caldo: smonta gli handler del client precedente e ne avvia flush+close in background (gli eventi già in coda partono verso la vecchia configurazione;flush()/close()attendono anche quella chiusura, così non si perde nulla all'uscita del processo), trasferisce lo scope corrente (trace_id, utente, tag, breadcrumb) al nuovo client e mette in uso la nuova config — senzaclose()manuale e senza lasciare handler duplicati. Con opzioni equivalenti resta un no-op idempotente, anche a client disabilitato (confronto sulle opzioni risolte,beforeSendper reference).
0.7.0 · 2026-08-01
Aggiunto
- Budget in byte e troncamento per canale prima dell'invio (CYJS-10) — ogni canale ha ora un tetto di
byte e una strategia di troncamento propria, applicata prima della spedizione. Il budget di
messageevalueconta i byte dopo l'escaping JSON ("→\", newline→\n, control→\u00XX), non quelli della stringa grezza: prima log ed eventi pieni di virgolette potevano restare sopra soglia. Una rete di sicurezza comune a tutti i canali tronca le stringhe non identitarie e rimuove i valori custom residui — anche quelli iniettati dabeforeSend— garantendo che il payload rientri sempre nel budget.
Corretto
- Il contesto non si mescola più fra richieste concorrenti su Node (CYJS-7) — su Node più richieste
condividevano un solo holder di scope: utente, tag, request,
trace_ide breadcrumb di una richiesta finivano negli eventi di un'altra. Ora c'è unAsyncLocalStoragelato server (import browser-safe) con le APIrunWithScope/withScope. La guida Node e l'esempio Nitro non mostrano più l'anti-pattern sullo scope condiviso: si avvolge l'handler conrunWithScopee si cattura negli hook globali conwithScope. - Versione dell'SDK allineata al pacchetto — la costante interna era rimasta a
0.6.0mentre il pacchetto era alla0.6.1.
Infrastruttura
- Smoke test del pacchetto npm come consumatore reale (CYJS-11) — la CI ora costruisce, impacchetta e
consuma davvero il pacchetto (require CJS, import ESM, load del bundle IIFE) con il Node della matrice,
tenendo separata la toolchain dal consumatore:
pnpmgira sul Node pinnato, il consumo sul Node minimo supportato. Senza questa separazione il job sarebbe fallito sempre, bloccando ogni release. - E2E non mockato di tutti i canali browser (CYJS-6) — con la DSN public key vengono inviati per davvero errori, messaggi, log, metriche, pageview e replay verso un backend di prova, i cui status attesi sono derivati dalle fixture del contratto invece che ricopiati a mano: se il contratto documentato cambia, il test diventa rosso.
0.6.1 · 2026-07-11
Aggiunto
- Auto-detect della release Node-side (CYJS-5) — su runtime Node reale (SSR/backend) l'SDK
rileva ora da solo la
releasedal deploy, in parità tag-first con la gem Ruby: prima il tag semver (APP_GIT_TAGpoiGIT_TAG, accettati solo se semver validi), poi lo SHA del deploy (KAMAL_VERSIONpoiGIT_SHA) come fallback. Unareleasepassata nelle options ha sempre la precedenza. Il rilevamento è gated su Node reale (process.versions.node, esclude window/jsdom): nel browser non c'è alcun accesso alle variabili di processo — lareleaseva passata esplicita (build-time inject). SDK isomorfo: solo lettura di ENV, mai un subprocess git.
0.6.0 · 2026-07-10
Sicurezza
- Il bearer segreto
cyi_non finisce mai più nel browser (CYJS-1) —tokenè ora una credenziale SERVER-ONLY (piena potenza ingest + read). Nel browser l'SDK autentica con la nuova opzionepublicKey(DSN public key, non segreta) via?sentry_key=sul drop-in SentryPOST /api/{projectId}/storeper gli errori/messaggi; il bearer non viene mai inviato dal browser. Passando nel browser solo il bearer segreto, l'SDK resta no-op (conconsole.warn) invece di esporlo nel bundle/tab Network. README riconciliati (rimossa l'indicazione "può stare nel bundle").
Aggiunto
- Opzione
publicKey(DSN public key) — credenziale browser-safe. Node/SSR continua a usaretoken(bearer) sui path/api/v1/projects/*; il browser usapublicKey(eventi al drop-in/store, gli altri canali sui path v1 con?sentry_key=).
Modifiche che rompono la compatibilità
- Browser: la sola
token(bearercyi_) non abilita più l'SDK nel browser — servepublicKey. Aggiornare i progetti browser per fornire la DSN public key. Node/SSR invariato.
Corretto
repeated_http: conteggio visibile in UI (CYJS-2) — il verdettorepeated_httpemette ora il campo wirequery_countinvece dicount_in_request. Prima il conteggio delle richieste ripetute dal browser era invisibile nel Monitor (colonna—), perché il reader Rails (occurrence_query_count) e l'SDK dart leggonoquery_count: un solo nome di campo wire cross-SDK.- DX misconfig:
init()con una config incompleta (token/projectId mancante) ora emette unconsole.warnesplicito ("SDK disabilitato: … — nessun evento verrà inviato") invece di restare un no-op totalmente silenzioso. Non avvisa quando la disabilitazione è voluta (enabled: false). - DX diagnostica: su risposta non-2xx il log di debug include ora il codice d'errore
R…e il messaggio dall'envelope del backend (es.R422-INGEST-001: Evento malformato), non solo lo status.
0.5.0 · 2026-07-08
Aggiunto
- Metadata comportamentale nel session replay — ogni chunk porta ora
path(pathname corrente al flush, senza query string) euser(id dasetUser, opzionale). Alimentano la galleria "come si comportano gli utenti" nel Monitor (pagine visitate, sessioni per utente). Additivo e retro-compatibile: i chunk senzapath/userrestano validi. Nuovo getterScope#userId.
0.4.0 · 2026-07-07
Aggiunto
- Session replay (opt-in
replay, defaultfalse) — registra la sessione con rrweb e invia i chunk aPOST /api/v1/projects/{projectId}/replays. Recorder inintegrations/browser/replay.ts(twin diinstallPageviews): buffer degli eventi rrweb, flush periodico (replayFlushIntervalMs, default 5000) + supagehide/visibilitychange(hidden)+ a soglia di buffer. Passa daenqueue→ soggetto abeforeSende ai contatori come gli altri invii. - Sessione di replay longeva (
session.ts) — id opaco (no PII) stabile per l'intera sessione-browser viasessionStorage(cyi_replay), più longevo deltrace_idper-pagina; fallback in-memory se lo storage non è disponibile. - Correlazione errore ↔ replay — gli errori/messaggi JS portano l'id in
contexts.replay.replay_id(nuovoScope.replaySessionId); per gli errori server il recorder scrive un cookie di sessionecyi_replay(SameSite=Lax) che le richieste same-origin trasportano al backend. FacadegetReplaySessionId(). - Privacy — masking di default:
replayMaskAllInputs(defaulttrue), piùreplayBlockSelectorereplayMaskTextSelector(rrweb) per bloccare/mascherare elementi sensibili. rrweb NON è una dipendenza: il recorder usa il globalewindow.rrweb(build UMD caricata dalla pagina), il core resta zero-dep.
Modificato
- Allineata
SDK_VERSION(version.ts) apackage.json(era ferma a0.2.0).
0.3.0 · 2026-07-03
Aggiunto
captureEvent(name, overrides?)— invia un custom event (goal/conversione analytics) con il camponamevalorizzato; no-op fuori dal browser, pre-init o senza nome.- Payload pageview esteso —
buildPageviewestrae le 5 chiavi UTM (aggiunteutm_term/utm_content) e includescreen_widthdalla viewport (il server la classifica inscreen_class, mai il valore raw). Additivo: gli SDK a 3 chiavi restano compatibili.
0.2.0 · 2026-07-02
Aggiunto
- Pageview tracking (web analytics) — opzione
trackPageviews(defaultfalse, opt-in): pageview all'init()e a ogni navigazione SPA (patchhistory.pushState/replaceState+popstate) con dedup sul pathname (hash change ereplaceStateripetuti sullo stesso path non emettono, semantica Plausible). EndpointPOST /api/v1/projects/{projectId}/pageviews. capturePageview(overrides?)sulla facade (anchewindow.CloseYourIt.capturePageviewvia IIFE) per pageview manuali; i pageview non sono soggetti asampleRate(sono il dato, non un campione).- Payload privacy-first:
hostname+pathname(mai la query string),document.referrer(omesso se vuoto), UTM estratti client-side (soloutm_source/utm_medium/utm_campaign),event_idUUID per idempotenza,occurred_atISO. Nessun dato identificante nel body: IP e User-Agent li consuma il server dalla richiesta (visitor hash cookieless a salt giornaliero).
Modificato
- Refactor interno
subscribeNavigation(integrations/browser/navigation.ts): un solo monkey-patch dihistorycondiviso tra breadcrumb di navigazione e pageview (patch installato al primo subscriber, ripristinato all'ultimo unsubscribe).
0.1.0 · 2026-07-02
Aggiunto
- SDK
@bussolabs/closeyourit-jsisomorfo browser + Node 20+ (TypeScript, zero dipendenze runtime). Contratto wire identico acloseyourit-rubyecloseyourit-dart(formato Sentry, campisnake_case,POST /api/v1/projects/{projectId}/{events,metrics,logs}conAuthorization: Bearer cyi_…). - Cattura errori:
captureExceptionecaptureMessage; nel browser gestori globalierror+unhandledrejection(viaaddEventListener, non clobberano handler esistenti); su NodeuncaughtException/unhandledRejectioncon flush (timeout 2s) e uscita col codice 1 se non ci sono handler utente (semantica crash di default preservata).excludedExceptionsper nome; dedup a identità d'oggetto (WeakSet, mark-before-sampling) + finestra temporale. - Log strutturati:
log(level, message, attributes, logger)eloggernominato (debug/info/warn/error/fatal,warn→warning), buffer batch (50/5s, chunk ≤ 1000) con flush automatico su timer,pagehide/visibilitychange(hidden)(browser,fetch(keepalive)sotto la quota 64 KB) ebeforeExit/SIGTERM(Node). GatinglogsEnabled/logsMinLevel/logsSampleRate. - Metriche:
measure(label, body)(sync/async, ritorna il valore, metrica anche su throw) →slow_methodoltreslowMethodThresholdMs;argumentsopt-in concaptureMethodArguments(scrubati, troncati). Mai campionate. - Performance issues (opt-in
detectPerformanceIssues):slow_external_http(fetch/XHR esterna oltre soglia, path templatizzato<uuid>/<n>),repeated_http(stessa richiesta ≥ N volte in finestra — l'N+1 del client),jank(long task viaPerformanceObserver, di fatto Chromium-only). - Scope:
setUser/setTag/setTags/setExtra/setContext/setTraceId/setRequest+clearScope;trace_iddi pagina generato all'init per correlare errori, log e metriche; request context automatico nel browser (URL senza query, User-Agent, referrer). - Breadcrumb automatici con interruttori granulari (
autoBreadcrumbs): click, navigazione (pushState/replaceState/popstate),console.warn/console.error,fetch/XHR (marcaturaslow_external_httpsulle esterne lente). URL privati di query e hash. - Privacy: policy
sendPii(default off:user→{id}, URL senza query, referrer strippato), scrubber PII ricorsivo (denylist superset del backend, includeemail), hookbeforeSendsu ogni payload. - Affidabilità: transport fire-and-forget che non solleva mai, coda bounded (
maxQueue) con drop e contatorigetStats(); su Node redirect POST seguiti a mano (max 2, solo same-host o www-swap: il Bearer non esce mai verso host terzi) eUser-Agent: closeyourit-js/{versione}. - Distribuzione: build ESM + CJS + tipi per bundler/npm, e IIFE minificato
(
window.CloseYourIt) per<script>— ~7 KB gzip.