poulet 0.0.6 → 0.1.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.
Files changed (44) hide show
  1. package/README.md +268 -4
  2. package/dist/index.cjs +2 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.cts +117 -0
  5. package/dist/index.d.ts +117 -0
  6. package/dist/index.global.js +2 -0
  7. package/dist/index.global.js.map +1 -0
  8. package/dist/index.js +2 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/react.cjs +2 -0
  11. package/dist/react.cjs.map +1 -0
  12. package/dist/react.d.cts +16 -0
  13. package/dist/react.d.ts +16 -0
  14. package/dist/react.global.js +25 -0
  15. package/dist/react.global.js.map +1 -0
  16. package/dist/react.js +2 -0
  17. package/dist/react.js.map +1 -0
  18. package/package.json +70 -52
  19. package/LICENSE +0 -22
  20. package/dist/.gitkeep +0 -0
  21. package/dist/poulet.common.js +0 -959
  22. package/dist/poulet.js +0 -962
  23. package/dist/poulet.min.js +0 -7
  24. package/dist/poulet.mjs +0 -957
  25. package/lib/Core/Component/_copyAccessor.js +0 -3
  26. package/lib/Core/Component/_defineReactive.js +0 -46
  27. package/lib/Core/Component/_mergeMixins.js +0 -53
  28. package/lib/Core/Component/index.js +0 -139
  29. package/lib/Core/Directive/_stringParser.js +0 -61
  30. package/lib/Core/Directive/index.js +0 -93
  31. package/lib/Core/Observer.js +0 -32
  32. package/lib/Core/index.js +0 -140
  33. package/lib/Directives/Class.js +0 -26
  34. package/lib/Directives/Html.js +0 -7
  35. package/lib/Directives/Model.js +0 -57
  36. package/lib/Directives/On.js +0 -13
  37. package/lib/Directives/Show.js +0 -9
  38. package/lib/Directives/Style.js +0 -7
  39. package/lib/Directives/Text.js +0 -7
  40. package/lib/Directives/index.js +0 -6
  41. package/lib/Mixins/index.js +0 -0
  42. package/lib/get.js +0 -10
  43. package/lib/index.js +0 -6
  44. package/lib/set.js +0 -10
package/README.md CHANGED
@@ -1,9 +1,273 @@
1
- # poulet
1
+ # @poulet/metrics
2
2
 
3
+ 📊 **SDK JavaScript léger** pour mesurer le **temps réellement actif** sur une application web, collecter des **événements métier**, permettre aux testeurs de **soumettre des bugs**, et alimenter un serveur pour **rémunérer automatiquement** le temps/bounties.
4
+
5
+ * ✅ **Web SDK** (Vanilla JS, ESM, CJS, IIFE pour CDN)
6
+ * ✅ **Adapter React** (`<MetricsProvider>` + `useMetrics`)
7
+ * ✅ Respect **RGPD** & **Do Not Track**
8
+ * ✅ Anti-fraude : inactivité, onglets multiples, jitter, rythme plausible
9
+ * ✅ Transport fiable (`sendBeacon` → `fetch` + queue offline)
10
+ * ✅ Poids < 12 kB gzip (core sans bug reporter UI)
11
+
12
+ ---
13
+
14
+ ## ✨ Fonctionnalités
15
+
16
+ * **Sessions** : ouverture/fermeture automatique, `session.start` & `session.end`.
17
+ * **Heartbeats** : signaux réguliers envoyés **seulement si actif** (onglet visible + interaction récente).
18
+ * **Événements** : `trackEvent(name, props)` pour instrumenter vos étapes métier.
19
+ * **Bugs** : `reportBug({title, description, severity})` pour collecter les remontées des testeurs.
20
+ * **Consentement RGPD** : démarre en *pending*, active la mesure après `setConsent`.
21
+ * **Anti-fraude** :
22
+
23
+ * pause si onglet caché,
24
+ * pause si inactif > X secondes,
25
+ * un seul onglet “leader” envoie les heartbeats,
26
+ * jitter sur l’intervalle pour éviter les patterns parfaits.
27
+ * **Transport** : batching, retries, offline queue, `sendBeacon` en priorité.
28
+ * **Interopérabilité** : IIFE (CDN global `window.PouletMetrics`), ESM/CJS (`import { init } from '@poulet/metrics'`), React (`@poulet/metrics/react`).
29
+
30
+ ---
31
+
32
+ ## 📦 Installation
33
+
34
+ ### NPM
35
+
36
+ ```bash
37
+ npm install poulet
3
38
  ```
4
- yarn add poulet
39
+
40
+ ### CDN
41
+
42
+ ```html
43
+ <script src="https://cdn.jsdelivr.net/npm/poulet/dist/index.global.js" defer></script>
44
+ <script>
45
+ window.PouletMetrics.init({
46
+ projectKey: 'PUB_DEMO',
47
+ endpoint: 'https://collector.example.com',
48
+ consent: { default: 'pending' },
49
+ privacy: { dntRespect: true },
50
+ debug: true
51
+ });
52
+ </script>
53
+ ```
54
+
55
+ ---
56
+
57
+ ## 🚀 Usage
58
+
59
+ ### Vanilla (site classique)
60
+
61
+ ```html
62
+ <script src="https://cdn.jsdelivr.net/npm/poulet/dist/index.global.js" defer></script>
63
+ <script>
64
+ window.PouletMetrics.init({
65
+ projectKey: 'PUB_123',
66
+ endpoint: 'https://collector.example.com',
67
+ consent: { default: 'pending' },
68
+ privacy: { dntRespect: true }
69
+ });
70
+
71
+ // Consentement obtenu via CMP
72
+ window.PouletMetrics.setConsent({ analytics: true });
73
+
74
+ // Envoi d’un événement
75
+ window.PouletMetrics.trackEvent('cta_click', { variant: 'A' });
76
+
77
+ // Signalement d’un bug
78
+ window.PouletMetrics.reportBug({
79
+ title: 'Texte coupé',
80
+ severity: 'minor',
81
+ description: 'Le bouton est tronqué en responsive'
82
+ });
83
+ </script>
84
+ ```
85
+
86
+ ---
87
+
88
+ ### React
89
+
90
+ ```tsx
91
+ import React from 'react';
92
+ import { createRoot } from 'react-dom/client';
93
+ import { MetricsProvider, useMetrics } from 'poulet/react';
94
+
95
+ function Demo() {
96
+ const { trackEvent, reportBug, setConsent } = useMetrics();
97
+ return (
98
+ <div>
99
+ <button onClick={() => setConsent({ analytics: true })}>Autoriser tracking</button>
100
+ <button onClick={() => trackEvent('clicked_button', { place: 'hero' })}>Event</button>
101
+ <button onClick={() => reportBug({ title: 'Bug React', severity: 'ux' })}>Bug</button>
102
+ </div>
103
+ );
104
+ }
105
+
106
+ createRoot(document.getElementById('root')!)
107
+ .render(<MetricsProvider config={{
108
+ projectKey: 'PUB_123',
109
+ endpoint: 'https://collector.example.com',
110
+ consent: { default: 'pending' },
111
+ privacy: { dntRespect: true }
112
+ }}>
113
+ <Demo/>
114
+ </MetricsProvider>);
115
+ ```
116
+
117
+ ---
118
+
119
+ ## 🛠 API
120
+
121
+ ### `init(config: Config)`
122
+
123
+ Initialise le SDK.
124
+ Principaux champs :
125
+
126
+ ```ts
127
+ {
128
+ projectKey: string, // Identifiant projet
129
+ endpoint: string, // URL collector
130
+ consent?: { default:'pending'|'granted'|'denied' },
131
+ user?: { testerPseudoId?: string }, // pas de PII
132
+ billing?: { heartbeatSec?:number; idleSec?:number; maxHoursPerDay?:number },
133
+ privacy?: { piiFilter?:boolean; dntRespect?:boolean; countryHint?:string },
134
+ security?: { hmacPublicKey?:string },
135
+ features?: { bugReporter?:boolean; replay?:boolean; sentryBridge?:boolean },
136
+ debug?: boolean
137
+ }
138
+ ```
139
+
140
+ ### `setConsent({ analytics?: boolean; replay?: boolean })`
141
+
142
+ Active ou désactive la collecte selon le consentement.
143
+
144
+ ### `trackEvent(name: string, props?: object)`
145
+
146
+ Déclare un événement métier.
147
+
148
+ ### `reportBug({ title, description?, severity?, attachments? })`
149
+
150
+ Envoie un bug (texte + option capture/pièce jointe).
151
+
152
+ ### `shutdown()`
153
+
154
+ Ferme la session et flush la queue.
155
+
156
+ ### `getSessionId()`
157
+
158
+ Retourne l’ID de la session courante.
159
+
160
+ ### `forgetMe()`
161
+
162
+ Stoppe la collecte et purge localement (utile pour RGPD).
163
+
164
+ ---
165
+
166
+ ## 📤 Événements envoyés
167
+
168
+ * `session.start` → ouverture d’une session (id, ua, tz, consentFlags).
169
+ * `heartbeat` → ping régulier **si actif**.
170
+ * `event` → événement métier.
171
+ * `bug` → bug report.
172
+ * `session.end` → fermeture volontaire ou `pagehide`.
173
+
174
+ ---
175
+
176
+ ## 🔒 Anti-fraude
177
+
178
+ * **Actif uniquement si** : onglet visible + interaction récente (< idleSec).
179
+ * **Un seul onglet leader** émet.
180
+ * **Jitter** ±10% sur l’intervalle heartbeat.
181
+ * **Contrôles côté serveur** :
182
+
183
+ * rythme plausible (7s–45s),
184
+ * plafonds d’heures/jour/testeur,
185
+ * rejet des heartbeats inactifs.
186
+
187
+ ---
188
+
189
+ ## 🛡 Confidentialité & RGPD
190
+
191
+ * **Consentement** requis (`setConsent`).
192
+ * **Respect DNT** (`navigator.doNotTrack === "1"`).
193
+ * **Minimisation** : pas de PII, identifiants pseudonymisés.
194
+ * **Droits utilisateurs** : `forgetMe()` côté SDK, endpoint côté serveur pour effacement complet.
195
+ * **DPA** requis si usage de SaaS tiers (Sentry, PostHog).
196
+
197
+ ---
198
+
199
+ ## ⚡ Transport & Offline
200
+
201
+ * Envoi via `sendBeacon` si possible, sinon `fetch`.
202
+ * Batching (par 10–20 événements).
203
+ * Queue offline (IndexedDB en option).
204
+ * Retry exponentiel.
205
+
206
+ ---
207
+
208
+ ## 🔧 Exemple collector minimal (Express)
209
+
210
+ ```js
211
+ app.post('/ingest', (req,res) => {
212
+ const { projectKey, items } = req.body || {};
213
+ items.forEach(it => console.log(it));
214
+ res.json({ ok: true, received: items.length });
215
+ });
5
216
  ```
6
- or
217
+
218
+ ---
219
+
220
+ ## 📊 Calcul minutes facturables (côté serveur)
221
+
222
+ ```js
223
+ minutes = (#heartbeats_valides × heartbeatSec) / 60
7
224
  ```
8
- npm i --save poulet
225
+
226
+ Valide → `active:true, vis:true, idle:false` + intervalle plausible.
227
+
228
+ ---
229
+
230
+ ## 📡 CDN
231
+
232
+ Disponible via :
233
+
234
+ * **jsDelivr** :
235
+ `https://cdn.jsdelivr.net/npm/@poulet/metrics/dist/index.global.js`
236
+ * **unpkg** :
237
+ `https://unpkg.com/@poulet/metrics/dist/index.global.js`
238
+
239
+ Ajoute un **SRI hash** en prod pour renforcer la sécurité.
240
+
241
+ ---
242
+
243
+ ## 📦 Publication
244
+
245
+ ```bash
246
+ npm run build
247
+ npm publish --access public
9
248
  ```
249
+
250
+ * **Exports** :
251
+
252
+ * `@poulet/metrics` → core ESM/CJS
253
+ * `@poulet/metrics/react` → adapter React
254
+ * `@poulet/metrics/iife` → **[bundle]()** global pour `<script>`
255
+
256
+ ---
257
+
258
+ ## ✅ Roadmap
259
+
260
+ * [x] Sessions, heartbeats, events, bugs
261
+ * [x] Consentement RGPD + DNT
262
+ * [x] Anti-fraude (idle, onglets multiples)
263
+ * [x] Transport fiable (beacon/fetch/queue)
264
+
265
+ ---
266
+
267
+ ## 📝 Licence
268
+
269
+ MIT © Poulet du bug
270
+
271
+ ---
272
+
273
+ Veux-tu que je t’ajoute un **schéma architecture (mermaid)** dans le README pour illustrer le flux **Testeur → SDK → Collector → Paiement** ?
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ 'use strict';var s=()=>Date.now();var A=(e,t,n)=>(e.addEventListener(t,n,{passive:true}),()=>e.removeEventListener(t,n)),f=(e,t)=>(document.addEventListener(e,t,{passive:true}),()=>document.removeEventListener(e,t));var C=(e,t=.1)=>{let n=e*t;return e+(Math.random()*2-1)*n},E=e=>{if(!e||typeof e!="object")return e;let t=["email","phone","password","ssn"],n=Array.isArray(e)?[]:{};for(let o of Object.keys(e)){if(t.includes(o.toLowerCase()))continue;let i=e[o];n[o]=typeof i=="object"?E(i):i;}return n},y=(...e)=>{window.__POULET_DEBUG__&&console.log("[poulet]",...e);},_=e=>Uint8Array.from(atob(e),t=>t.charCodeAt(0));var B=Date.now(),L=[],M=()=>B,O=()=>{T();let e=()=>{B=Date.now();},t=f("mousemove",e),n=f("keydown",e),o=f("scroll",e),i=f("touchstart",e),c=A(window,"focus",e),g=A(window,"blur",e),U=f("visibilitychange",e);L=[t,n,o,i,c,g,U];},T=()=>{L.forEach(e=>e()),L=[];};var u="poulet_leader_session",d=false,F=e=>{let t=localStorage.getItem(u);return t?(d=t===e,d):(localStorage.setItem(u,e),d=true,true)},R=e=>{localStorage.getItem(u)===e&&localStorage.removeItem(u),d=false;};var q=(e,t)=>{let n=o=>{if(o.key!==u)return;let i=localStorage.getItem(u);i?(d=i===e,t(d)):(localStorage.setItem(u,e),t(true),d=true);};return window.addEventListener("storage",n),()=>window.removeEventListener("storage",n)},K=()=>{var e;return {ua:navigator.userAgent,tz:(e=Intl.DateTimeFormat().resolvedOptions().timeZone)!=null?e:"UTC",dpr:window.devicePixelRatio||1}};var m=false,k=false,S="pending",H=true,z=e=>{H=e;},N=e=>{S=e,H&&typeof navigator!="undefined"&&navigator.doNotTrack==="1"&&(m=false,k=false,S="denied");},V=e=>{typeof e.analytics=="boolean"&&(m=e.analytics,S=m?"granted":"denied"),typeof e.replay=="boolean"&&(k=e.replay);},W=()=>({analytics:m,replay:k,state:S}),D=()=>m===true;var p,x=[],j=false;async function X(e){if(!(!p.hmacPublicKey||!("crypto"in window)))try{let t=_(p.hmacPublicKey),n=await crypto.subtle.importKey("raw",t,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),o=await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(e));return btoa(String.fromCharCode(...new Uint8Array(o)))}catch(t){return}}async function $(e){let t=e.map(c=>E(c)),n=JSON.stringify({projectKey:p.projectKey,items:t}),o=await X(n);if(navigator.sendBeacon&&!p.debug){let c={type:"application/json"},g=new Blob([n],c);if(navigator.sendBeacon(p.endpoint+"/ingest",g))return true}return (await fetch(p.endpoint+"/ingest",{method:"POST",headers:{"Content-Type":"application/json",...o?{"x-signature":o}:{}},body:n})).ok}function G(e){p=e,window.addEventListener("online",b),setInterval(b,5e3);}function l(e){x.push(e),x.length>=10&&b();}async function b(){if(!(j||x.length===0)){j=true;try{let e=x.splice(0,20);await $(e)||(x.unshift(...e),y("flush failed, will retry"));}catch(e){y("flush error",e);}finally{j=false;}}}var a,r=null,v=null,h,J={projectKey:"",endpoint:"",consent:{default:"pending"},user:{},billing:{heartbeatSec:15,idleSec:60,maxHoursPerDay:6},privacy:{piiFilter:true,dntRespect:true,countryHint:"FR"},security:{hmacPublicKey:void 0},features:{bugReporter:true,replay:false,sentryBridge:false},sampling:{heartbeats:1,events:1,bugs:1},debug:false};function Y(e){a={...J,...e,consent:{...J.consent,...e.consent}},window.__POULET_DEBUG__=!!a.debug,G({endpoint:a.endpoint,projectKey:a.projectKey,hmacPublicKey:a.security.hmacPublicKey,debug:a.debug});}function I(){if(r)return;let e=crypto.randomUUID(),t=K();r={sessionId:e,startedAt:s(),lastActivityAt:s(),active:true,leader:F(e)},h&&h(),h=q(e,o=>{r&&(r.leader=o);}),O();let n={type:"session.start",sessionId:e,ts:s(),projectKey:a.projectKey,ua:t.ua,tz:t.tz,dpr:t.dpr,consentFlags:{analytics:D(),replay:false}};l(n),ee(),y("session opened",e);}function P(e){if(!r)return;Z(),T(),R(r.sessionId);let t={type:"session.end",sessionId:r.sessionId,ts:s(),reason:e};l(t),b(),h&&h(),r=null,y("session closed",e);}function ee(){Z();let e=()=>{if(!r||!D())return;let t=s()-M()>=a.billing.idleSec*1e3,n=document.visibilityState==="visible",o=n&&!t&&r.leader,i=K();if(Math.random()<=a.sampling.heartbeats&&o){let g={type:"heartbeat",sessionId:r.sessionId,ts:s(),active:true,vis:n,idle:false,jitter:Math.random(),ua:i.ua,tz:i.tz,dpr:i.dpr,purpose:"billing"};l(g);}let c=C(a.billing.heartbeatSec*1e3,.1);v=window.setTimeout(e,c);};v=window.setTimeout(e,C(a.billing.heartbeatSec*1e3,.1));}function Z(){v&&(clearTimeout(v),v=null);}var w=()=>{var e;return (e=r==null?void 0:r.sessionId)!=null?e:null};function te(e){let t=w();if(!t)return;let n={type:"bug",sessionId:t,ts:s(),title:e.title,description:e.description,severity:e.severity,hasCapture:!!(e.attachments&&e.attachments.length>0),purpose:"diagnostics"};l(n);}var Q=false;function Ee(e){var t,n,o,i;Q||(z((n=(t=e.privacy)==null?void 0:t.dntRespect)!=null?n:true),N((i=(o=e.consent)==null?void 0:o.default)!=null?i:"pending"),Y(e),document.visibilityState==="visible"&&I(),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&I();}),addEventListener("pagehide",()=>P("pagehide")),Q=true);}function Le(e){V(e),document.visibilityState==="visible"&&I();}function Te(e,t){let n=w();if(!n)return;let o={type:"event",sessionId:n,ts:s(),name:e,props:t,purpose:"diagnostics"};l(o);}function Ke(){P("shutdown");}function ke(){return w()}function De(){P("shutdown");}var je=W;exports._consentFlags=je;exports.forgetMe=De;exports.getSessionId=ke;exports.init=Ee;exports.reportBug=te;exports.setConsent=Le;exports.shutdown=Ke;exports.trackEvent=Te;//# sourceMappingURL=index.cjs.map
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils.ts","../src/activity.ts","../src/antifraud.ts","../src/consent.ts","../src/transport.ts","../src/core.ts","../src/bug.ts","../src/index.ts"],"names":["now","on","t","type","fn","onDoc","jitterMs","baseMs","pct","delta","filterPII","o","SUSPICIOUS","out","k","v","log","args","base64ToArrayBuffer","b64","c","lastActivity","unsub","getLastActivity","startActivityTracking","stopActivityTracking","touch","un1","un2","un3","un4","un5","un6","un7","f","LS_KEY","leader","becomeLeaderIfFree","sessionId","current","relinquishLeadership","handleStorageLeadership","onChange","listener","e","fingerprintLite","_a","analyticsAllowed","replayAllowed","state","dntRespected","setDNTPolicy","respect","initConsent","defaultState","setConsent","flags","consentFlags","analyticsOn","cfg","queue","flushing","sign","body","keyData","key","sig","postBatch","items","sanitized","i","headers","blob","initTransport","config","flush","enqueue","payload","batch","session","hbTimer","unStorage","DEFAULTS","configure","openSession","id","fp","lead","startPayload","scheduleHeartbeats","closeSession","reason","stopHeartbeats","endPayload","loop","idle","vis","active","hb","next","getSessionIdSafe","reportBug","p","initialized","init","_b","_c","_d","trackEvent","name","props","ev","shutdown","getSessionId","forgetMe","_consentFlags"],"mappings":"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","file":"index.cjs","sourcesContent":["// src/utils.ts\nexport const now = () => Date.now();\n\nexport const uuid = (): string =>\n (crypto?.randomUUID?.() ?? 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (crypto.getRandomValues(new Uint8Array(1))[0] & 0xf) >> 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n }));\n\nexport const isVisible = () => typeof document !== 'undefined' && document.visibilityState === 'visible';\n\nexport const on = <K extends keyof WindowEventMap>(t: Window, type: K, fn: (e: WindowEventMap[K]) => void) => {\n t.addEventListener(type, fn as any, { passive: true });\n return () => t.removeEventListener(type, fn as any);\n};\n\nexport const onDoc = <K extends keyof DocumentEventMap>(type: K, fn: (e: DocumentEventMap[K]) => void) => {\n document.addEventListener(type, fn as any, { passive: true });\n return () => document.removeEventListener(type, fn as any);\n};\n\nexport const clamp = (n: number, min: number, max: number) => Math.max(min, Math.min(max, n));\n\nexport const jitterMs = (baseMs: number, pct = 0.1) => {\n const delta = baseMs * pct;\n return baseMs + (Math.random() * 2 - 1) * delta;\n};\n\nexport const filterPII = (o: any): any => {\n if (!o || typeof o !== 'object') return o;\n const SUSPICIOUS = ['email', 'phone', 'password', 'ssn'];\n const out: any = Array.isArray(o) ? [] : {};\n for (const k of Object.keys(o)) {\n if (SUSPICIOUS.includes(k.toLowerCase())) continue;\n const v = (o as any)[k];\n out[k] = typeof v === 'object' ? filterPII(v) : v;\n }\n return out;\n};\n\nexport const log = (...args: any[]) => {\n if ((window as any).__POULET_DEBUG__) console.log('[poulet]', ...args);\n};\n\nexport const base64ToArrayBuffer = (b64: string) => Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));\n","// src/activity.ts\nimport { isVisible, onDoc, on } from './utils';\n\nlet lastActivity = Date.now();\nlet unsub: Array<() => void> = [];\n\nexport const getLastActivity = () => lastActivity;\n\nexport const startActivityTracking = () => {\n stopActivityTracking();\n const touch = () => { lastActivity = Date.now(); };\n const un1 = onDoc('mousemove', touch);\n const un2 = onDoc('keydown', touch);\n const un3 = onDoc('scroll', touch);\n const un4 = onDoc('touchstart', touch);\n const un5 = on(window, 'focus', touch);\n const un6 = on(window, 'blur', touch);\n const un7 = onDoc('visibilitychange' as any, touch);\n unsub = [un1, un2, un3, un4, un5, un6, un7];\n};\n\nexport const stopActivityTracking = () => {\n unsub.forEach((f) => f());\n unsub = [];\n};\n\nexport const isActive = (idleSec: number) => {\n const idleMs = idleSec * 1000;\n return isVisible() && (Date.now() - lastActivity) < idleMs;\n};\n","// src/antifraud.ts\nconst LS_KEY = 'poulet_leader_session';\nlet leader = false;\n\nexport const becomeLeaderIfFree = (sessionId: string): boolean => {\n const current = localStorage.getItem(LS_KEY);\n if (!current) {\n localStorage.setItem(LS_KEY, sessionId);\n leader = true;\n return true;\n }\n leader = current === sessionId;\n return leader;\n};\n\nexport const relinquishLeadership = (sessionId: string) => {\n const current = localStorage.getItem(LS_KEY);\n if (current === sessionId) {\n localStorage.removeItem(LS_KEY);\n }\n leader = false;\n};\n\nexport const isLeader = () => leader;\n\nexport const handleStorageLeadership = (sessionId: string, onChange: (isLeader: boolean)=>void) => {\n const listener = (e: StorageEvent) => {\n if (e.key !== LS_KEY) return;\n const now = localStorage.getItem(LS_KEY);\n const newLeader = now === sessionId || !now;\n if (!now) { // try claim\n localStorage.setItem(LS_KEY, sessionId);\n onChange(true);\n leader = true;\n } else {\n leader = now === sessionId;\n onChange(leader);\n }\n };\n window.addEventListener('storage', listener);\n return () => window.removeEventListener('storage', listener);\n};\n\nexport const fingerprintLite = () => ({\n ua: navigator.userAgent,\n tz: Intl.DateTimeFormat().resolvedOptions().timeZone ?? 'UTC',\n dpr: window.devicePixelRatio || 1,\n});\n","// src/consent.ts\nimport type { ConsentState } from './types';\n\nlet analyticsAllowed = false;\nlet replayAllowed = false;\nlet state: ConsentState = 'pending';\nlet dntRespected = true;\n\nexport const setDNTPolicy = (respect: boolean) => { dntRespected = respect; };\n\nexport const initConsent = (defaultState: ConsentState) => {\n state = defaultState;\n if (dntRespected && typeof navigator !== 'undefined' && (navigator as any).doNotTrack === '1') {\n analyticsAllowed = false;\n replayAllowed = false;\n state = 'denied';\n }\n};\n\nexport const setConsent = (flags: { analytics?: boolean; replay?: boolean }) => {\n if (typeof flags.analytics === 'boolean') {\n analyticsAllowed = flags.analytics;\n state = analyticsAllowed ? 'granted' : 'denied';\n }\n if (typeof flags.replay === 'boolean') replayAllowed = flags.replay;\n};\n\nexport const consentFlags = () => ({ analytics: analyticsAllowed, replay: replayAllowed, state });\nexport const analyticsOn = () => analyticsAllowed === true;\nexport const replayOn = () => replayAllowed === true;\n","// src/transport.ts\nimport { base64ToArrayBuffer, filterPII, log } from './utils';\nimport type { OutgoingPayload } from './types';\n\ntype TransportConfig = {\n endpoint: string;\n projectKey: string;\n hmacPublicKey?: string; // base64; optional\n debug?: boolean;\n};\n\nlet cfg: TransportConfig;\nlet queue: OutgoingPayload[] = [];\nlet flushing = false;\n\nasync function sign(body: string): Promise<string | undefined> {\n if (!cfg.hmacPublicKey || !('crypto' in window)) return undefined;\n try {\n const keyData = base64ToArrayBuffer(cfg.hmacPublicKey);\n const key = await crypto.subtle.importKey('raw', keyData, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);\n const sig = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(body));\n return btoa(String.fromCharCode(...new Uint8Array(sig)));\n } catch {\n return undefined;\n }\n}\n\nasync function postBatch(items: OutgoingPayload[]) {\n const sanitized = items.map((i) => filterPII(i));\n const body = JSON.stringify({ projectKey: cfg.projectKey, items: sanitized });\n const sig = await sign(body);\n\n // Try Beacon first\n if (navigator.sendBeacon && !cfg.debug) {\n const headers = { type: 'application/json' };\n const blob = new Blob([body], headers);\n const ok = navigator.sendBeacon(cfg.endpoint + '/ingest', blob);\n if (ok) return true;\n }\n\n // Fallback fetch\n const res = await fetch(cfg.endpoint + '/ingest', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...(sig ? { 'x-signature': sig } : {}) },\n body\n });\n return res.ok;\n}\n\nexport function initTransport(config: TransportConfig) {\n cfg = config;\n window.addEventListener('online', flush);\n setInterval(flush, 5000);\n}\n\nexport function enqueue(payload: OutgoingPayload) {\n queue.push(payload);\n if (queue.length >= 10) void flush();\n}\n\nexport async function flush() {\n if (flushing || queue.length === 0) return;\n flushing = true;\n try {\n const batch = queue.splice(0, 20);\n const ok = await postBatch(batch);\n if (!ok) {\n // put back\n queue.unshift(...batch);\n log('flush failed, will retry');\n }\n } catch (e) {\n log('flush error', e);\n } finally {\n flushing = false;\n }\n}\n","// src/core.ts\nimport { jitterMs, log, now } from './utils';\nimport { startActivityTracking, stopActivityTracking, isActive, getLastActivity } from './activity';\nimport { becomeLeaderIfFree, handleStorageLeadership, relinquishLeadership, isLeader, fingerprintLite } from './antifraud';\nimport { analyticsOn, consentFlags } from './consent';\nimport { initTransport, enqueue, flush } from './transport';\nimport type { Config, SessionState, HeartbeatPayload, SessionStart, SessionEnd } from './types';\n\nlet config: Required<Config>;\nlet session: SessionState | null = null;\nlet hbTimer: number | null = null;\nlet unStorage: (() => void) | undefined;\n\nconst DEFAULTS: Required<Config> = {\n projectKey: '',\n endpoint: '',\n consent: { default: 'pending' },\n user: {},\n billing: { heartbeatSec: 15, idleSec: 60, maxHoursPerDay: 6 },\n privacy: { piiFilter: true, dntRespect: true, countryHint: 'FR' },\n security: { hmacPublicKey: undefined as any },\n features: { bugReporter: true, replay: false, sentryBridge: false },\n sampling: { heartbeats: 1, events: 1, bugs: 1 },\n debug: false,\n};\n\nexport function configure(cfg: Config) {\n config = { ...DEFAULTS, ...cfg, consent: { ...DEFAULTS.consent, ...cfg.consent } } as Required<Config>;\n (window as any).__POULET_DEBUG__ = !!config.debug;\n initTransport({\n endpoint: config.endpoint,\n projectKey: config.projectKey,\n hmacPublicKey: config.security.hmacPublicKey,\n debug: config.debug,\n });\n}\n\nexport function openSession() {\n if (session) return;\n const id = crypto.randomUUID();\n const fp = fingerprintLite();\n session = {\n sessionId: id,\n startedAt: now(),\n lastActivityAt: now(),\n active: true,\n leader: becomeLeaderIfFree(id),\n };\n if (unStorage) unStorage();\n unStorage = handleStorageLeadership(id, (lead) => {\n if (session) session.leader = lead;\n });\n\n startActivityTracking();\n\n const startPayload: SessionStart = {\n type: 'session.start',\n sessionId: id,\n ts: now(),\n projectKey: config.projectKey,\n ua: fp.ua,\n tz: fp.tz,\n dpr: fp.dpr,\n consentFlags: { analytics: analyticsOn(), replay: false },\n };\n enqueue(startPayload);\n scheduleHeartbeats();\n log('session opened', id);\n}\n\nexport function closeSession(reason: SessionEnd['reason']) {\n if (!session) return;\n stopHeartbeats();\n stopActivityTracking();\n relinquishLeadership(session.sessionId);\n const endPayload: SessionEnd = { type: 'session.end', sessionId: session.sessionId, ts: now(), reason };\n enqueue(endPayload);\n void flush();\n if (unStorage) unStorage();\n session = null;\n log('session closed', reason);\n}\n\nfunction scheduleHeartbeats() {\n stopHeartbeats();\n const loop = () => {\n if (!session) return;\n if (!analyticsOn()) return; // consent required\n // @ts-ignore\n const idle = (now() - getLastActivity()) >= config.billing.idleSec * 1000;\n const vis = document.visibilityState === 'visible';\n const active = vis && !idle && session.leader;\n const fp = fingerprintLite();\n\n // @ts-ignore\n if (Math.random() <= config.sampling.heartbeats && active) {\n const hb: HeartbeatPayload = {\n type: 'heartbeat',\n sessionId: session.sessionId,\n ts: now(),\n active: true,\n vis,\n idle: false,\n jitter: Math.random(),\n ua: fp.ua,\n tz: fp.tz,\n dpr: fp.dpr,\n purpose: 'billing',\n };\n enqueue(hb);\n }\n\n // @ts-ignore\n const next = jitterMs(config.billing.heartbeatSec * 1000, 0.1);\n hbTimer = window.setTimeout(loop, next);\n };\n // @ts-ignore\n hbTimer = window.setTimeout(loop, jitterMs(config.billing.heartbeatSec * 1000, 0.1));\n}\n\nfunction stopHeartbeats() {\n if (hbTimer) {\n clearTimeout(hbTimer);\n hbTimer = null;\n }\n}\n\nexport const getSessionIdSafe = () => session?.sessionId ?? null;\n","// src/bug.ts\nimport { enqueue } from './transport';\nimport type { BugPayload } from './types';\nimport { now } from './utils';\nimport { getSessionIdSafe } from './core';\n\nexport function reportBug(payload: {\n title: string; description?: string;\n severity?: 'blocker'|'major'|'minor'|'ux';\n attachments?: Blob[];\n}) {\n const sessionId = getSessionIdSafe();\n if (!sessionId) return;\n const p: BugPayload = {\n type: 'bug',\n sessionId,\n ts: now(),\n title: payload.title,\n description: payload.description,\n severity: payload.severity,\n hasCapture: !!(payload.attachments && payload.attachments.length > 0),\n purpose: 'diagnostics'\n };\n enqueue(p);\n // NOTE: upload des pièces jointes = hors scope core (peut passer par un autre endpoint)\n}\n","// src/index.ts\nimport { configure, openSession, closeSession, getSessionIdSafe } from './core';\nimport { setConsent as _setConsent, initConsent, setDNTPolicy, consentFlags } from './consent';\nimport { enqueue } from './transport';\nimport type { Config, EventPayload } from './types';\nimport { now } from './utils';\nexport * from './types';\nexport { reportBug } from './bug';\n\nlet initialized = false;\n\nexport function init(cfg: Config) {\n if (initialized) return;\n setDNTPolicy(cfg.privacy?.dntRespect ?? true);\n initConsent(cfg.consent?.default ?? 'pending');\n configure(cfg);\n // ouverture paresseuse : dès qu’il y a visibilité/activité\n if (document.visibilityState === 'visible') openSession();\n document.addEventListener('visibilitychange', () => {\n if (document.visibilityState === 'visible') openSession();\n });\n // Flush/close sur pagehide\n addEventListener('pagehide', () => closeSession('pagehide'));\n initialized = true;\n}\n\nexport function setConsent(flags: { analytics?: boolean; replay?: boolean }) {\n _setConsent(flags);\n if (document.visibilityState === 'visible') openSession();\n}\n\nexport function trackEvent(name: string, props?: Record<string, unknown>) {\n const sessionId = getSessionIdSafe();\n if (!sessionId) return;\n const ev: EventPayload = {\n type: 'event',\n sessionId,\n ts: now(),\n name,\n props,\n purpose: 'diagnostics',\n };\n enqueue(ev);\n}\n\nexport function shutdown() {\n closeSession('shutdown');\n}\n\nexport function getSessionId() {\n return getSessionIdSafe();\n}\n\nexport function forgetMe() {\n // côté core : rien de persistant par défaut (queue en mémoire).\n // si tu ajoutes IndexedDB/localStorage pour queue offline, purge ici.\n // Pour l’exemple, on ne stocke pas persistantement.\n closeSession('shutdown');\n}\n\nexport const _consentFlags = consentFlags;\n"]}
@@ -0,0 +1,117 @@
1
+ type ConsentState = 'pending' | 'granted' | 'denied';
2
+ type Config = {
3
+ projectKey: string;
4
+ endpoint: string;
5
+ consent?: {
6
+ default: ConsentState;
7
+ };
8
+ user?: {
9
+ testerPseudoId?: string;
10
+ };
11
+ billing?: {
12
+ heartbeatSec?: number;
13
+ idleSec?: number;
14
+ maxHoursPerDay?: number;
15
+ };
16
+ privacy?: {
17
+ piiFilter?: boolean;
18
+ dntRespect?: boolean;
19
+ countryHint?: string;
20
+ };
21
+ security?: {
22
+ hmacPublicKey?: string;
23
+ };
24
+ features?: {
25
+ bugReporter?: boolean;
26
+ replay?: boolean;
27
+ sentryBridge?: boolean;
28
+ };
29
+ sampling?: {
30
+ heartbeats?: number;
31
+ events?: number;
32
+ bugs?: number;
33
+ };
34
+ debug?: boolean;
35
+ };
36
+ type SessionState = {
37
+ sessionId: string;
38
+ startedAt: number;
39
+ lastActivityAt: number;
40
+ active: boolean;
41
+ leader: boolean;
42
+ };
43
+ type HeartbeatPayload = {
44
+ type: 'heartbeat';
45
+ sessionId: string;
46
+ ts: number;
47
+ active: boolean;
48
+ vis: boolean;
49
+ idle: boolean;
50
+ jitter: number;
51
+ ua: string;
52
+ tz: string;
53
+ dpr: number;
54
+ purpose: 'billing';
55
+ };
56
+ type EventPayload = {
57
+ type: 'event';
58
+ sessionId: string;
59
+ ts: number;
60
+ name: string;
61
+ props?: Record<string, unknown>;
62
+ purpose: 'diagnostics';
63
+ };
64
+ type BugPayload = {
65
+ type: 'bug';
66
+ sessionId: string;
67
+ ts: number;
68
+ title: string;
69
+ description?: string;
70
+ severity?: 'blocker' | 'major' | 'minor' | 'ux';
71
+ hasCapture?: boolean;
72
+ purpose: 'diagnostics';
73
+ };
74
+ type OutgoingPayload = HeartbeatPayload | EventPayload | BugPayload | SessionStart | SessionEnd;
75
+ type SessionStart = {
76
+ type: 'session.start';
77
+ sessionId: string;
78
+ ts: number;
79
+ projectKey: string;
80
+ ua: string;
81
+ tz: string;
82
+ dpr: number;
83
+ consentFlags: {
84
+ analytics: boolean;
85
+ replay: boolean;
86
+ };
87
+ };
88
+ type SessionEnd = {
89
+ type: 'session.end';
90
+ sessionId: string;
91
+ ts: number;
92
+ reason: 'pagehide' | 'timeout' | 'shutdown';
93
+ };
94
+
95
+ declare function reportBug(payload: {
96
+ title: string;
97
+ description?: string;
98
+ severity?: 'blocker' | 'major' | 'minor' | 'ux';
99
+ attachments?: Blob[];
100
+ }): void;
101
+
102
+ declare function init(cfg: Config): void;
103
+ declare function setConsent(flags: {
104
+ analytics?: boolean;
105
+ replay?: boolean;
106
+ }): void;
107
+ declare function trackEvent(name: string, props?: Record<string, unknown>): void;
108
+ declare function shutdown(): void;
109
+ declare function getSessionId(): string | null;
110
+ declare function forgetMe(): void;
111
+ declare const _consentFlags: () => {
112
+ analytics: boolean;
113
+ replay: boolean;
114
+ state: ConsentState;
115
+ };
116
+
117
+ export { type BugPayload, type Config, type ConsentState, type EventPayload, type HeartbeatPayload, type OutgoingPayload, type SessionEnd, type SessionStart, type SessionState, _consentFlags, forgetMe, getSessionId, init, reportBug, setConsent, shutdown, trackEvent };
@@ -0,0 +1,117 @@
1
+ type ConsentState = 'pending' | 'granted' | 'denied';
2
+ type Config = {
3
+ projectKey: string;
4
+ endpoint: string;
5
+ consent?: {
6
+ default: ConsentState;
7
+ };
8
+ user?: {
9
+ testerPseudoId?: string;
10
+ };
11
+ billing?: {
12
+ heartbeatSec?: number;
13
+ idleSec?: number;
14
+ maxHoursPerDay?: number;
15
+ };
16
+ privacy?: {
17
+ piiFilter?: boolean;
18
+ dntRespect?: boolean;
19
+ countryHint?: string;
20
+ };
21
+ security?: {
22
+ hmacPublicKey?: string;
23
+ };
24
+ features?: {
25
+ bugReporter?: boolean;
26
+ replay?: boolean;
27
+ sentryBridge?: boolean;
28
+ };
29
+ sampling?: {
30
+ heartbeats?: number;
31
+ events?: number;
32
+ bugs?: number;
33
+ };
34
+ debug?: boolean;
35
+ };
36
+ type SessionState = {
37
+ sessionId: string;
38
+ startedAt: number;
39
+ lastActivityAt: number;
40
+ active: boolean;
41
+ leader: boolean;
42
+ };
43
+ type HeartbeatPayload = {
44
+ type: 'heartbeat';
45
+ sessionId: string;
46
+ ts: number;
47
+ active: boolean;
48
+ vis: boolean;
49
+ idle: boolean;
50
+ jitter: number;
51
+ ua: string;
52
+ tz: string;
53
+ dpr: number;
54
+ purpose: 'billing';
55
+ };
56
+ type EventPayload = {
57
+ type: 'event';
58
+ sessionId: string;
59
+ ts: number;
60
+ name: string;
61
+ props?: Record<string, unknown>;
62
+ purpose: 'diagnostics';
63
+ };
64
+ type BugPayload = {
65
+ type: 'bug';
66
+ sessionId: string;
67
+ ts: number;
68
+ title: string;
69
+ description?: string;
70
+ severity?: 'blocker' | 'major' | 'minor' | 'ux';
71
+ hasCapture?: boolean;
72
+ purpose: 'diagnostics';
73
+ };
74
+ type OutgoingPayload = HeartbeatPayload | EventPayload | BugPayload | SessionStart | SessionEnd;
75
+ type SessionStart = {
76
+ type: 'session.start';
77
+ sessionId: string;
78
+ ts: number;
79
+ projectKey: string;
80
+ ua: string;
81
+ tz: string;
82
+ dpr: number;
83
+ consentFlags: {
84
+ analytics: boolean;
85
+ replay: boolean;
86
+ };
87
+ };
88
+ type SessionEnd = {
89
+ type: 'session.end';
90
+ sessionId: string;
91
+ ts: number;
92
+ reason: 'pagehide' | 'timeout' | 'shutdown';
93
+ };
94
+
95
+ declare function reportBug(payload: {
96
+ title: string;
97
+ description?: string;
98
+ severity?: 'blocker' | 'major' | 'minor' | 'ux';
99
+ attachments?: Blob[];
100
+ }): void;
101
+
102
+ declare function init(cfg: Config): void;
103
+ declare function setConsent(flags: {
104
+ analytics?: boolean;
105
+ replay?: boolean;
106
+ }): void;
107
+ declare function trackEvent(name: string, props?: Record<string, unknown>): void;
108
+ declare function shutdown(): void;
109
+ declare function getSessionId(): string | null;
110
+ declare function forgetMe(): void;
111
+ declare const _consentFlags: () => {
112
+ analytics: boolean;
113
+ replay: boolean;
114
+ state: ConsentState;
115
+ };
116
+
117
+ export { type BugPayload, type Config, type ConsentState, type EventPayload, type HeartbeatPayload, type OutgoingPayload, type SessionEnd, type SessionStart, type SessionState, _consentFlags, forgetMe, getSessionId, init, reportBug, setConsent, shutdown, trackEvent };
@@ -0,0 +1,2 @@
1
+ var Poulet=(function(exports){'use strict';var s=()=>Date.now();var A=(e,t,n)=>(e.addEventListener(t,n,{passive:true}),()=>e.removeEventListener(t,n)),f=(e,t)=>(document.addEventListener(e,t,{passive:true}),()=>document.removeEventListener(e,t));var C=(e,t=.1)=>{let n=e*t;return e+(Math.random()*2-1)*n},E=e=>{if(!e||typeof e!="object")return e;let t=["email","phone","password","ssn"],n=Array.isArray(e)?[]:{};for(let o of Object.keys(e)){if(t.includes(o.toLowerCase()))continue;let i=e[o];n[o]=typeof i=="object"?E(i):i;}return n},y=(...e)=>{window.__POULET_DEBUG__&&console.log("[poulet]",...e);},_=e=>Uint8Array.from(atob(e),t=>t.charCodeAt(0));var B=Date.now(),L=[],M=()=>B,O=()=>{T();let e=()=>{B=Date.now();},t=f("mousemove",e),n=f("keydown",e),o=f("scroll",e),i=f("touchstart",e),c=A(window,"focus",e),g=A(window,"blur",e),U=f("visibilitychange",e);L=[t,n,o,i,c,g,U];},T=()=>{L.forEach(e=>e()),L=[];};var u="poulet_leader_session",d=false,F=e=>{let t=localStorage.getItem(u);return t?(d=t===e,d):(localStorage.setItem(u,e),d=true,true)},R=e=>{localStorage.getItem(u)===e&&localStorage.removeItem(u),d=false;};var q=(e,t)=>{let n=o=>{if(o.key!==u)return;let i=localStorage.getItem(u);i?(d=i===e,t(d)):(localStorage.setItem(u,e),t(true),d=true);};return window.addEventListener("storage",n),()=>window.removeEventListener("storage",n)},K=()=>{var e;return {ua:navigator.userAgent,tz:(e=Intl.DateTimeFormat().resolvedOptions().timeZone)!=null?e:"UTC",dpr:window.devicePixelRatio||1}};var m=false,k=false,S="pending",H=true,z=e=>{H=e;},N=e=>{S=e,H&&typeof navigator!="undefined"&&navigator.doNotTrack==="1"&&(m=false,k=false,S="denied");},V=e=>{typeof e.analytics=="boolean"&&(m=e.analytics,S=m?"granted":"denied"),typeof e.replay=="boolean"&&(k=e.replay);},W=()=>({analytics:m,replay:k,state:S}),D=()=>m===true;var p,x=[],j=false;async function X(e){if(!(!p.hmacPublicKey||!("crypto"in window)))try{let t=_(p.hmacPublicKey),n=await crypto.subtle.importKey("raw",t,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),o=await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(e));return btoa(String.fromCharCode(...new Uint8Array(o)))}catch(t){return}}async function $(e){let t=e.map(c=>E(c)),n=JSON.stringify({projectKey:p.projectKey,items:t}),o=await X(n);if(navigator.sendBeacon&&!p.debug){let c={type:"application/json"},g=new Blob([n],c);if(navigator.sendBeacon(p.endpoint+"/ingest",g))return true}return (await fetch(p.endpoint+"/ingest",{method:"POST",headers:{"Content-Type":"application/json",...o?{"x-signature":o}:{}},body:n})).ok}function G(e){p=e,window.addEventListener("online",b),setInterval(b,5e3);}function l(e){x.push(e),x.length>=10&&b();}async function b(){if(!(j||x.length===0)){j=true;try{let e=x.splice(0,20);await $(e)||(x.unshift(...e),y("flush failed, will retry"));}catch(e){y("flush error",e);}finally{j=false;}}}var a,r=null,v=null,h,J={projectKey:"",endpoint:"",consent:{default:"pending"},user:{},billing:{heartbeatSec:15,idleSec:60,maxHoursPerDay:6},privacy:{piiFilter:true,dntRespect:true,countryHint:"FR"},security:{hmacPublicKey:void 0},features:{bugReporter:true,replay:false,sentryBridge:false},sampling:{heartbeats:1,events:1,bugs:1},debug:false};function Y(e){a={...J,...e,consent:{...J.consent,...e.consent}},window.__POULET_DEBUG__=!!a.debug,G({endpoint:a.endpoint,projectKey:a.projectKey,hmacPublicKey:a.security.hmacPublicKey,debug:a.debug});}function I(){if(r)return;let e=crypto.randomUUID(),t=K();r={sessionId:e,startedAt:s(),lastActivityAt:s(),active:true,leader:F(e)},h&&h(),h=q(e,o=>{r&&(r.leader=o);}),O();let n={type:"session.start",sessionId:e,ts:s(),projectKey:a.projectKey,ua:t.ua,tz:t.tz,dpr:t.dpr,consentFlags:{analytics:D(),replay:false}};l(n),ee(),y("session opened",e);}function P(e){if(!r)return;Z(),T(),R(r.sessionId);let t={type:"session.end",sessionId:r.sessionId,ts:s(),reason:e};l(t),b(),h&&h(),r=null,y("session closed",e);}function ee(){Z();let e=()=>{if(!r||!D())return;let t=s()-M()>=a.billing.idleSec*1e3,n=document.visibilityState==="visible",o=n&&!t&&r.leader,i=K();if(Math.random()<=a.sampling.heartbeats&&o){let g={type:"heartbeat",sessionId:r.sessionId,ts:s(),active:true,vis:n,idle:false,jitter:Math.random(),ua:i.ua,tz:i.tz,dpr:i.dpr,purpose:"billing"};l(g);}let c=C(a.billing.heartbeatSec*1e3,.1);v=window.setTimeout(e,c);};v=window.setTimeout(e,C(a.billing.heartbeatSec*1e3,.1));}function Z(){v&&(clearTimeout(v),v=null);}var w=()=>{var e;return (e=r==null?void 0:r.sessionId)!=null?e:null};function te(e){let t=w();if(!t)return;let n={type:"bug",sessionId:t,ts:s(),title:e.title,description:e.description,severity:e.severity,hasCapture:!!(e.attachments&&e.attachments.length>0),purpose:"diagnostics"};l(n);}var Q=false;function Ee(e){var t,n,o,i;Q||(z((n=(t=e.privacy)==null?void 0:t.dntRespect)!=null?n:true),N((i=(o=e.consent)==null?void 0:o.default)!=null?i:"pending"),Y(e),document.visibilityState==="visible"&&I(),document.addEventListener("visibilitychange",()=>{document.visibilityState==="visible"&&I();}),addEventListener("pagehide",()=>P("pagehide")),Q=true);}function Le(e){V(e),document.visibilityState==="visible"&&I();}function Te(e,t){let n=w();if(!n)return;let o={type:"event",sessionId:n,ts:s(),name:e,props:t,purpose:"diagnostics"};l(o);}function Ke(){P("shutdown");}function ke(){return w()}function De(){P("shutdown");}var je=W;exports._consentFlags=je;exports.forgetMe=De;exports.getSessionId=ke;exports.init=Ee;exports.reportBug=te;exports.setConsent=Le;exports.shutdown=Ke;exports.trackEvent=Te;return exports;})({});//# sourceMappingURL=index.global.js.map
2
+ //# sourceMappingURL=index.global.js.map