@iann29/rastro 0.1.0-alpha.7 → 0.1.0-alpha.9

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 (73) hide show
  1. package/README.md +60 -32
  2. package/agent/integration.md +14 -6
  3. package/agent/manifest.json +9 -7
  4. package/agent/manifest.schema.json +8 -5
  5. package/dist/client/federation.d.ts +13 -8
  6. package/dist/client/federation.d.ts.map +1 -1
  7. package/dist/client/federation.js +4 -1
  8. package/dist/client/federation.js.map +1 -1
  9. package/dist/client/index.d.ts +419 -17
  10. package/dist/client/index.d.ts.map +1 -1
  11. package/dist/client/index.js +55 -2
  12. package/dist/client/index.js.map +1 -1
  13. package/dist/component/_generated/component.d.ts +71 -7
  14. package/dist/component/_generated/component.d.ts.map +1 -1
  15. package/dist/component/constants.d.ts +6 -1
  16. package/dist/component/constants.d.ts.map +1 -1
  17. package/dist/component/constants.js +13 -1
  18. package/dist/component/constants.js.map +1 -1
  19. package/dist/component/coverage.d.ts +1 -0
  20. package/dist/component/coverage.d.ts.map +1 -1
  21. package/dist/component/coverage.js +13 -2
  22. package/dist/component/coverage.js.map +1 -1
  23. package/dist/component/eventStore.d.ts +1 -1
  24. package/dist/component/http.d.ts.map +1 -1
  25. package/dist/component/http.js +2 -0
  26. package/dist/component/http.js.map +1 -1
  27. package/dist/component/ingest.d.ts +1 -1
  28. package/dist/component/ingest.d.ts.map +1 -1
  29. package/dist/component/ingest.js +173 -3
  30. package/dist/component/ingest.js.map +1 -1
  31. package/dist/component/reports.d.ts +77 -3
  32. package/dist/component/reports.d.ts.map +1 -1
  33. package/dist/component/reports.js +275 -3
  34. package/dist/component/reports.js.map +1 -1
  35. package/dist/component/retention.d.ts +4 -4
  36. package/dist/component/retention.d.ts.map +1 -1
  37. package/dist/component/retention.js +12 -2
  38. package/dist/component/retention.js.map +1 -1
  39. package/dist/component/sanitize.d.ts +9 -0
  40. package/dist/component/sanitize.d.ts.map +1 -1
  41. package/dist/component/sanitize.js +25 -0
  42. package/dist/component/sanitize.js.map +1 -1
  43. package/dist/component/schema.d.ts +69 -7
  44. package/dist/component/schema.js +25 -0
  45. package/dist/component/schema.js.map +1 -1
  46. package/dist/component/validators.d.ts +7 -7
  47. package/dist/component/validators.d.ts.map +1 -1
  48. package/dist/component/validators.js +1 -1
  49. package/dist/component/validators.js.map +1 -1
  50. package/dist/tracker/generated.d.ts +4 -4
  51. package/dist/tracker/generated.d.ts.map +1 -1
  52. package/dist/tracker/generated.js +4 -4
  53. package/dist/tracker/generated.js.map +1 -1
  54. package/dist/tracker/tracker.d.ts +1 -1
  55. package/dist/tracker/tracker.d.ts.map +1 -1
  56. package/dist/tracker/tracker.js +24 -2
  57. package/dist/tracker/tracker.js.map +1 -1
  58. package/dist/tracker.min.js +1 -1
  59. package/docs/federation-setup.md +2 -0
  60. package/docs/federation.md +4 -0
  61. package/docs/upgrading.md +91 -10
  62. package/llms.txt +3 -1
  63. package/package.json +1 -1
  64. package/src/component/_generated/component.ts +58 -1
  65. package/src/component/constants.ts +13 -1
  66. package/src/component/coverage.ts +12 -1
  67. package/src/component/http.ts +2 -0
  68. package/src/component/ingest.ts +278 -1
  69. package/src/component/reports.ts +364 -2
  70. package/src/component/retention.ts +16 -1
  71. package/src/component/sanitize.ts +31 -0
  72. package/src/component/schema.ts +26 -0
  73. package/src/component/validators.ts +1 -0
@@ -1,8 +1,8 @@
1
1
  // Generated by scripts/build-tracker.mjs. Do not edit.
2
- export const TRACKER_SOURCE = "(()=>{const e=document.currentScript,t=e?.dataset.site,s=e?.dataset.endpoint||e?.src&&new URL(\"events\",e.src).href;if(!t||!s)return;const o=()=>crypto.randomUUID?.()||Math.random()+\"\",n=new URLSearchParams(location.search),r=n.get(\"ref\")?.slice(0,64);let a,i,c;for(const e of[\"source\",\"medium\",\"campaign\",\"term\",\"content\"]){const t=n.get(\"utm_\"+e)?.slice(0,64);t&&((a??={})[\"utm_\"+e]=t)}try{i=sessionStorage._r||o(),sessionStorage._r=i,c=r||sessionStorage._a,c&&(sessionStorage._a=c),a||=sessionStorage._u&&JSON.parse(sessionStorage._u),a&&(sessionStorage._u=JSON.stringify(a))}catch{i=o(),c=r}const d=e.dataset.visitor||i;let l,p=0;const g=[],u=document.referrer?new URL(document.referrer).origin:void 0,h=e=>{const o=g.splice(0,50);if(!o.length)return;const n=()=>new Blob([JSON.stringify({siteId:t,events:o,sentAt:Date.now()})]);let r=n();for(;r.size>64e3&&o.length>1;)g.unshift(o.pop()),r=n();e&&navigator.sendBeacon(s,r)||fetch(s,{method:\"POST\",body:r,keepalive:1}).catch(()=>{}),g.length&&h(e)},m=(e,t,s)=>{const o=Date.now();g.push({eventId:`${i}.${o.toString(36)}.${p}`,sessionId:i,visitorId:d,type:e,name:t,path:location.pathname.slice(0,256),referrer:u,timestamp:o,sequence:p++,affiliateSlug:c,...s}),clearTimeout(l),l=setTimeout(h,1200)};let f;const v=()=>{const e=location.pathname;e!==f&&(f=e,m(\"pageview\",void 0,a&&{properties:a}))};window.rastro=(e,t,s)=>{if(\"context\"===e)return{sessionId:i,visitorId:d};\"event\"===e&&m(\"custom\",`${t||\"event\"}`.slice(0,80),s&&JSON.stringify(s).length>2e4?void 0:{properties:s})},document.addEventListener(\"click\",e=>{const t=e.target?.closest(\"a,button,[data-rastro-event]\");if(!t)return;const s=t.dataset.rastroEvent,o=t.href,n=o&&new URL(o),r=/^https?:$/.test(n?.protocol),a=r&&n.origin!==location.origin;m(s?\"custom\":a?\"outbound\":\"click\",s,{target:(t.dataset.rastroLabel||t.innerText||t.tagName).slice(0,64),href:r?((a?n.origin:\"\")+n.pathname).slice(0,256):void 0})},1);const S=e=>{const t=history[e];history[e]=(...e)=>{t.apply(history,e),v()}};S(\"pushState\"),S(\"replaceState\"),addEventListener(\"popstate\",v),addEventListener(\"pagehide\",()=>h(1)),setInterval(()=>{m(\"heartbeat\"),h()},2e4),v()})();";
3
- export const TRACKER_GZIP_BASE64 = "H4sIAAAAAAACA3VVUW/cNgz+K4kQGBLCqpc0DQYb6mHF9pCha4td+xRkjSLTtlBb8iT60uzs/z7Y58slue7NImWR/Ph9JOdCvdsY7yIdocq96Rp0JE0XAjpamWBbAlK4lLkmHZFktIQQn1rQ5a23jvoelzIGkyQO74++/vWBM1yjo8gAR7uQVcAiswU/pr4/jiIgdcFl2+hejamY8NCSl0G73Ddfv179tpRc9P2fmqrZyMUpY+DUHGOFOpjqsw66ibz2RpP1TsbJKiAoJ0skzgIWTCxlrK1BvoDLC5HVSEcaLJis8IHPEBz54ppF3wWDDFiDue0aBszoptW2dAwYYZgs3hE6YjdiRo92oTpqvrFTfBGNkoRzvVyqzSCud3duFImBwsPGqogxWu9W5IMuUX4Lfe+5gAOzsmBU6PuXDg0mSfiBVRkBuu8Pnu+S5I/Vp4+y1SHiwW+dAP2T1zo1/RMpWFfa4oFrIQajyVQbq8ZsjQrDFo1c4SM/1jZa8qHv7YR5Da1azE0v1fUNdHveBSwwBAzLHYMOPEL6YEvr0rW3+dECKoWPBPaqlLGdQX+7EBPVvKzRlVQ9Z5ub2DZGeV/7O379orDNyPKrPCXYMjj1ENHRr5T+pgml8/dcDOJmS6KgHBcTibIgo/0X311e4Jsk2UV+d5aJUnYuVrYg7mXrWy4mbnKRYZI4vbalJh9kRJe/R2284xGC6PsCyVQ8wqZBqnyess+fVl8Y3Pn8IQ3wHbHVtV1jejYIOTWCT3oeBJRz8CSpOIoBGsURCKJ4gta+lqyUbRcrvpnKvcrT25ONHeTJxkvyqwkW/uZSjJZ2uN2x8ipPLczdvcrTHOihxRTB6QZTglZTlT5KcjyNjkdVnL+9FLBra9oB2QYj6aadwP6nQ2cwbU9PQReFra0mXNVdmRqQUsZBgKlRhy+2Qd8RrwXUKiLtzhWcnS8WYpgaVMxNX6tn0+4gtQyPlSqShBcKoeGs1SWuLd4zmMmmk2TTBt9iIIsx1YMQQ3ZvXe7vZdCRgn+Csi34dkr8IKaUwpmAm/8Bb8i203K6myQNZ6aL5BsGtycb6vvZO9w+AvjLQkCcdbynbhQ72p3jxXKbePo06ziIAR51pfP89/HhDzYSOgycmdqa7wz2siKFknQokZbS1D5iJM403HVE3sH1KPNX2+pfTTnesK3y6LnkoqLHkbC9PgUGr2haDOCU368OPwrk9d8VURuX6clrSWNYt5Rt8OSNrwVoFZLEzfPgWO37ubVkDY/LHYipXjLf0Z3vXM7SXY0RNtvCUv4ytw/6Duu+J2mdw/AFf9B4IF1+1A2Kp6MdxuTTsBzH+y52ypg43RNLPCP9PLrGNpyJGZyVeop3ZSP58HCNN9n+U3EpJY7MIqnbtn7gsw9QwJqLYchWnI0yXpEmZAJW495ra21wZznsduvbODlh/VO3LrGyOTIYpVPxMzHuJLpyhGGt6+24aTirUAe6Q01MQMXFAOd4sc1KcJH9B5nHiolmCAAA";
4
- export const TRACKER_RAW_BYTES = 2150;
5
- export const TRACKER_GZIP_BYTES = 1134;
2
+ export const TRACKER_SOURCE = "(()=>{const e=document.currentScript,t=e?.dataset.site,s=e?.dataset.endpoint||e?.src&&new URL(\"events\",e.src).href;if(!t||!s)return;const o=()=>crypto.randomUUID?.()||Math.random()+\"\",n=new URLSearchParams(location.search),r=n.get(\"ref\")?.slice(0,64);let a,i,c;for(const e of[\"source\",\"medium\",\"campaign\",\"term\",\"content\"]){const t=n.get(\"utm_\"+e)?.slice(0,64);t&&((a??={})[\"utm_\"+e]=t)}try{i=sessionStorage._r||o(),sessionStorage._r=i,c=r||sessionStorage._a,c&&(sessionStorage._a=c),a||=sessionStorage._u&&JSON.parse(sessionStorage._u),a&&(sessionStorage._u=JSON.stringify(a))}catch{i=o(),c=r}let d=e.dataset.visitor;try{d||=localStorage._rv||=o()}catch{}d||=i;let l,p=0;const g=[],h=document.referrer?new URL(document.referrer).origin:void 0,u=e=>{const o=g.splice(0,50);if(!o.length)return;const n=()=>new Blob([JSON.stringify({siteId:t,events:o,sentAt:Date.now()})]);let r=n();for(;r.size>64e3&&o.length>1;)g.unshift(o.pop()),r=n();e&&navigator.sendBeacon(s,r)||fetch(s,{method:\"POST\",body:r,keepalive:1}).catch(()=>{}),g.length&&u(e)},m=(e,t,s)=>{const o=Date.now();g.push({eventId:`${i}.${o.toString(36)}.${p}`,sessionId:i,visitorId:d,type:e,name:t,path:location.pathname.slice(0,256),referrer:h,timestamp:o,sequence:p++,affiliateSlug:c,...s}),clearTimeout(l),l=setTimeout(u,1200)};let v;const f=()=>{const e=location.pathname;e!==v&&(v=e,m(\"pageview\",void 0,a&&{properties:a}))};window.rastro=(e,t,s)=>{if(\"context\"===e)return{sessionId:i,visitorId:d};\"event\"===e&&m(\"custom\",`${t||\"event\"}`.slice(0,80),s&&JSON.stringify(s).length>2e4?void 0:{properties:s})},document.addEventListener(\"click\",e=>{const t=e.target?.closest(\"a,button,[data-rastro-event]\");if(!t)return;const s=t.dataset.rastroEvent,o=t.href,n=o&&new URL(o),r=/^https?:$/.test(n?.protocol),a=r&&n.origin!==location.origin;m(s?\"custom\":a?\"outbound\":\"click\",s,{target:(t.dataset.rastroLabel||t.innerText||t.tagName).slice(0,64),href:r?((a?n.origin:\"\")+n.pathname).slice(0,256):void 0})},1);const S=e=>{const t=history[e];history[e]=(...e)=>{t.apply(history,e),f()}};S(\"pushState\"),S(\"replaceState\"),addEventListener(\"popstate\",f),addEventListener(\"pagehide\",()=>{m(\"leave\"),u(1)}),addEventListener(\"pageshow\",e=>{e.persisted&&(m(\"heartbeat\"),u(1))}),setInterval(()=>{m(\"heartbeat\"),u()},2e4),f()})();";
3
+ export const TRACKER_GZIP_BASE64 = "H4sIAAAAAAACA3VV227cNhD9FZswBBKeMLbjGIUEZtEgfXDhJkE3eTLcmKZGEhGJVMnROtuV/r2QVuv1JXmTZsi5nDlnyLlQ7zbGu0gHqHJvugYdSdOFgI6WJtiWgBQuZK5JRyQZLSHExxZ0eeuto77HhYzBJInD+4Ovf19xhit0FBngaBeyClhktuCH1PeHUQSkLrhsm92rsRQT1i15GbTLffP16+WHheSi7//SVM1GLo4ZA6fmHEvUwVSfddBN5LU3mqx3Mk5WAUE5WSJxFrBgYiFjbQ3yE7g4F1mNdKDBgskKH/gMwYEvrln0XTDIgDWY265hwIxuWm1Lx4ARhsniHaEjdiNm9GiXqqPmGzvGZ9koSTjXi4XaDOJ6d+ZGkRgorDdWRYzRerckH3SJ8lvoe88FvDArC0aFvn/u0GCShL+wKiNA9/2L8F2S/Ln89FG2OkR8ca0ToH8SrVPTnUjButIWa66FGIwmU22sGqs1KgwjrLnCB3asbLTkQza2mfe9GmdU7/tZ9f14dQ4zjCfsNJoaWnUyc6NU1zdQ7ekZsMAQMCx2RHvhEdIHW1qXrrzND06gU/jAc69KGdt5Nm9PxMRIL2t0JVVPSekmUo5Z3tf+jl8/638ziuEyTwm2RE89RHT0O6UfNKF0/p6LQdxsuRaU42LiWhZktP/hu4tzfJMku8zvTjNRys7FyhbEvWx9y8VEYS4yTBKnV7bU5IOM6PL3qI13PEIQfV8gmYpH2DRIlc9T9vnT8guDO5+v0wDfEVtd2xWmp4OQE9B8kv0goJyTJ0nHUQzQKI5AEMUjtPa9ZKVsu1jxzdTuZZ7eHm3sII82XpJfTrDwNxditLTD7Y68l3lqYabBZZ7mQOsWUwSnG0wJWk1V+qDc8W90PIjn7O2FgN1Y0wrINhhJN+0E9r8dOoNpe3wMuihsbTXhsu7K1ICUMg4CTI06fLEN+o54LaBWEWn338Hp2cmJGKYBreahF+rJUnxRWoaHSq2ShK8UQsNZq0tcWbxnMJNNJ8mmDb7FQBZjqgchhuzeutzfy6AjBf8IZVvw7TL5QUwphTMBN78Ab8i2S3U6myQNZ6aL5BsGt0cb6vvZO9w+APjbiYA4y31P3Sh2tDvD88W28PRx1XEQAzzoSuf5H2PgKxsJHQbOTG3NdwZ7WZFCSTqUSAtpah8xEmca7joi7+B63Aevtt2/mmq8YVvl0VPJRUUPu2N7fEoMXtH0foBTfv/C+FEgr/+piNq4SI9eSxrTuoVsgydvfC1Aq5Akbt4Hh2o/z60la3hc7EBM9YL5ju5853KW7nqMsNk2lvLntV3pO6z7nqR1DsMX/EHjD+nyo25QPH4BYCw+DYvxFdjlThkTx3tiiSekn1fXOIZTMYOzVI/xrmwkH9bXeJPtPxWXUuLILJK6bes1n32AAgouhiFbcjbKeEmakAlYjs9jW2uDO8vLabe+jZMTip+6dYmVzZHBJJ2Gsxr1agzV8VMx/OpKrPz9lkIoWwxxdOZJwhvOKtSB7lDTHGMMEpEuHWFY6Zrv8jw9JwY4w/Ntn4KL7H/zTKaM3wgAAA==";
4
+ export const TRACKER_RAW_BYTES = 2271;
5
+ export const TRACKER_GZIP_BYTES = 1177;
6
6
  export const VITALS_SOURCE = "(()=>{const t=document.currentScript,e=t?.dataset.site,n=t?.dataset.endpoint||t?.src&&new URL(\"events\",t.src).href;if(!e||!n)return;const r=()=>crypto.randomUUID?.()||Math.random()+\"\";let a;try{a=sessionStorage._r||r(),sessionStorage._r=a}catch{a=r()}const s=t.dataset.visitor||a,o=location.pathname.slice(0,256),i={},c=[],d=(t,e,n)=>{try{const r=new PerformanceObserver(t=>e(t.getEntries()));r.observe({type:t,buffered:1,...n}),c.push({observer:r,handler:e})}catch{}},h=performance.getEntriesByType?.(\"navigation\")[0];h&&h.responseStart>0&&(i.TTFB=h.responseStart),d(\"paint\",t=>{for(const e of t)\"first-contentful-paint\"===e.name&&(i.FCP=e.startTime)}),d(\"largest-contentful-paint\",t=>{const e=t[t.length-1];e&&(i.LCP=e.startTime)});let l=0,f=0,m=0;d(\"layout-shift\",t=>{for(const e of t)e.hadRecentInput||(l&&e.startTime-m<1e3&&e.startTime-f<5e3?l+=e.value:(l=e.value,f=e.startTime),m=e.startTime,i.CLS=Math.max(i.CLS||0,1e3*l))});const u=[],p=new Set,v=t=>{for(const e of t)e.interactionId&&(p.add(e.interactionId),u.push(e.duration));if(!u.length)return;u.sort((t,e)=>e-t),u.length=Math.min(u.length,10);const e=performance.interactionCount||p.size;i.INP=u[Math.min(u.length-1,Math.floor(e/50))]};d(\"event\",v,{durationThreshold:40}),d(\"first-input\",v);let g=0;const y=()=>{if(g)return;for(const{observer:t,handler:e}of c)e(t.takeRecords()),t.disconnect();const t=Date.now(),r=Object.keys(i).map((e,n)=>({eventId:`${a}.${t.toString(36)}.v${n}`,sessionId:a,visitorId:s,type:\"vital\",name:e,value:Math.round(i[e]),path:o,timestamp:t,sequence:n}));if(!r.length)return;g=1;const d=new Blob([JSON.stringify({siteId:e,events:r,sentAt:t})]),h=navigator.sendBeacon?.bind(navigator);h&&h(n,d)||fetch(n,{method:\"POST\",body:d,keepalive:1}).catch(()=>{})};document.addEventListener(\"visibilitychange\",()=>{\"hidden\"===document.visibilityState&&y()}),addEventListener(\"pagehide\",y)})();";
7
7
  export const VITALS_GZIP_BASE64 = "H4sIAAAAAAACA3VV72/bNhD9V1IhMMiV5uxl6Qe5TLCkLeAha4I4+RQEK02eLC4SqZEnd5qk/32gZOfn+k06kXfv3b17IoSKk1Y5G/AAhXaqLsEiV7X3YHGlvKmQgcBTriXKAMiDQWD2eQSsrpyx2HV4yoNXk4mF7we31xckgS1YDAnDGKc895AtTEbeQde9s9QD1t4uxupeRCjKNxU67qXVrry9XX465YR23R8S812Q0PdJsigAD+QCfdNKESAE4+wKnZcb4H/6rvOEsjdhIXslUeWtFJ7QfiwbBD4S2Zpg0Pmuk8yJwimJxlleScytLIGHwiggM/bL8QfKjGh7psTdPdOCIANmYyMjoD2d2IQr8JnzpbQKLtcB/BY8QXECBPkG8LNFbyAQSunCczceIC02FaTI1nWWgQedzhnn3PaUKV7VISft7qRPPcul1QX4FHq6I9f3LBfVU91nhc6am6aCU04SK7dmM9BL6N3sfpFPJjn3ECpnA6xQejyZTSbE8JubL2fi1SfKNEkqaSwmDMVJmzlPRtJw4LIDpElmfMCpchbBYlYX0/G0EAJ4bOWQ+sv5lQAeYsYbUwLth7yF9Bv4v8tDqV0ZgXfIC7AbzKfz+8WY7+JNvkElhZixTMxYKWaLIX/japyG3GQ/gg88l/oaFFhc2qrGriPFZPIs9bT8OIejl6Hs4zEcnRbvBfCtLGpISbF/ZNkLXKx8/soMP79YiUHgpfyHDK9dN2NzOPqpoJHFCK6OWqsGVa0A2Vb8ALuxCF6qONulnkxIxaXW5FWcsnrUEnBd+0EIlA6bWe/6ul/OmgfnkUSJU3ECU4xXxyM70MaSfYTNZ3u48EKDz4qfuzpaRcWD+RcWhi+/Xon67k2q6ZwNsaxwzhP4+XhG6X0fJzh4SsK2rN1Dv8k9hNwVOv11NqpoFKCJ00vYdhTCRsx22JrBalqTkc2e5mMjn5YLny2Xyw4UjVuL8gGuQTmv49oy5NoE5awFhWRPHcUnicCt+04o8+Jy/Rco5A/QBGIoL2VFyGgXpB24LHX67bCVPT9skaNboTd2Q44+0J5vD1vbf9tb2VKnku1MaqnTwAanSLYGZZGwuFgpsFF9o2G62mpi7uCesuhiqWNoSggoyypFFuDvGqyC1Pa74ftXw9+I+Y6THoR3Vrg1uft9dfmVhwGlyRrSxj/CUqfARrdPPQtg8TdMsaf3lOVi5zbO8wBWn4FUzp7ytbGaPH6igwcRyzTtugxQxee2BMydTpOry9VNwtZON6lmDwCVLMwW0nlP+eB6ZBhoT/vF4y9Mav054rkwAcGCJ0ns3NoUBhuVS7uBhA23ktxoDTa60+Plp6MrlAiTSUOiP73NWckN5EZDwhraU0IX/wGQzzziUQcAAA==";
8
8
  export const VITALS_RAW_BYTES = 1873;
@@ -1 +1 @@
1
- {"version":3,"file":"generated.js","sourceRoot":"","sources":["../../src/tracker/generated.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,MAAM,CAAC,MAAM,cAAc,GAAG,8pEAA8pE,CAAC;AAC7rE,MAAM,CAAC,MAAM,mBAAmB,GAAG,0+CAA0+C,CAAC;AAC9gD,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC;AACtC,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AACvC,MAAM,CAAC,MAAM,aAAa,GAAG,+2DAA+2D,CAAC;AAC74D,MAAM,CAAC,MAAM,kBAAkB,GAAG,k3CAAk3C,CAAC;AACr5C,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC;AACrC,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC"}
1
+ {"version":3,"file":"generated.js","sourceRoot":"","sources":["../../src/tracker/generated.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,MAAM,CAAC,MAAM,cAAc,GAAG,6xEAA6xE,CAAC;AAC5zE,MAAM,CAAC,MAAM,mBAAmB,GAAG,siDAAsiD,CAAC;AAC1kD,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC;AACtC,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AACvC,MAAM,CAAC,MAAM,aAAa,GAAG,+2DAA+2D,CAAC;AAC74D,MAAM,CAAC,MAAM,kBAAkB,GAAG,k3CAAk3C,CAAC;AACr5C,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC;AACrC,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC"}
@@ -1,6 +1,6 @@
1
1
  type RastroProperty = string | number | boolean | null;
2
2
  type RastroProperties = Record<string, RastroProperty>;
3
- type RastroEventType = "pageview" | "click" | "custom" | "conversion" | "heartbeat" | "outbound";
3
+ type RastroEventType = "pageview" | "click" | "custom" | "conversion" | "heartbeat" | "outbound" | "leave";
4
4
  interface RastroEvent {
5
5
  eventId: string;
6
6
  sessionId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/tracker/tracker.ts"],"names":[],"mappings":"AAAA,KAAK,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AACvD,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AACvD,KAAK,eAAe,GAClB,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,YAAY,GAAG,WAAW,GAAG,UAAU,CAAC;AAE5E,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED,UAAU,aAAa;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,KAAK,aAAa,GAAG,CACnB,OAAO,EAAE,OAAO,GAAG,SAAS,EAC5B,KAAK,CAAC,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,gBAAgB,KAC1B,aAAa,GAAG,IAAI,CAAC;AAE1B,UAAU,YAAa,SAAQ,MAAM;IACnC,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB"}
1
+ {"version":3,"file":"tracker.d.ts","sourceRoot":"","sources":["../../src/tracker/tracker.ts"],"names":[],"mappings":"AAAA,KAAK,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AACvD,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AACvD,KAAK,eAAe,GAChB,UAAU,GACV,OAAO,GACP,QAAQ,GACR,YAAY,GACZ,WAAW,GACX,UAAU,GACV,OAAO,CAAC;AAEZ,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAED,UAAU,aAAa;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,KAAK,aAAa,GAAG,CACnB,OAAO,EAAE,OAAO,GAAG,SAAS,EAC5B,KAAK,CAAC,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,gBAAgB,KAC1B,aAAa,GAAG,IAAI,CAAC;AAE1B,UAAU,YAAa,SAAQ,MAAM;IACnC,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB"}
@@ -32,7 +32,18 @@
32
32
  sessionId = createId();
33
33
  affiliate = referral;
34
34
  }
35
- const visitorId = script.dataset.visitor || sessionId;
35
+ // The identity, in order: the host's signed-in id, the persistent
36
+ // pseudonymous id (one random id per browser and site origin, kept in
37
+ // localStorage), and, when storage is blocked, the per-tab session id —
38
+ // which the server then counts through its salted daily hash.
39
+ let visitorId = script.dataset.visitor;
40
+ try {
41
+ visitorId ||= localStorage._rv ||= createId();
42
+ }
43
+ catch {
44
+ // Blocked storage never breaks the page; the session still counts.
45
+ }
46
+ visitorId ||= sessionId;
36
47
  let sequence = 0;
37
48
  let flushTimer;
38
49
  const queue = [];
@@ -124,7 +135,18 @@
124
135
  wrapHistory("pushState");
125
136
  wrapHistory("replaceState");
126
137
  addEventListener("popstate", pageview);
127
- addEventListener("pagehide", () => flush(true));
138
+ addEventListener("pagehide", () => {
139
+ emit("leave");
140
+ flush(true);
141
+ });
142
+ addEventListener("pageshow", (event) => {
143
+ // Back from the bfcache: the leave above already shortened this session's
144
+ // live presence, so revive it immediately instead of waiting a beat.
145
+ if (event.persisted) {
146
+ emit("heartbeat");
147
+ flush(true);
148
+ }
149
+ });
128
150
  setInterval(() => {
129
151
  emit("heartbeat");
130
152
  flush();
@@ -1 +1 @@
1
- {"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/tracker/tracker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../src/tracker/tracker.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- (()=>{const e=document.currentScript,t=e?.dataset.site,s=e?.dataset.endpoint||e?.src&&new URL("events",e.src).href;if(!t||!s)return;const o=()=>crypto.randomUUID?.()||Math.random()+"",n=new URLSearchParams(location.search),r=n.get("ref")?.slice(0,64);let a,i,c;for(const e of["source","medium","campaign","term","content"]){const t=n.get("utm_"+e)?.slice(0,64);t&&((a??={})["utm_"+e]=t)}try{i=sessionStorage._r||o(),sessionStorage._r=i,c=r||sessionStorage._a,c&&(sessionStorage._a=c),a||=sessionStorage._u&&JSON.parse(sessionStorage._u),a&&(sessionStorage._u=JSON.stringify(a))}catch{i=o(),c=r}const d=e.dataset.visitor||i;let l,p=0;const g=[],u=document.referrer?new URL(document.referrer).origin:void 0,h=e=>{const o=g.splice(0,50);if(!o.length)return;const n=()=>new Blob([JSON.stringify({siteId:t,events:o,sentAt:Date.now()})]);let r=n();for(;r.size>64e3&&o.length>1;)g.unshift(o.pop()),r=n();e&&navigator.sendBeacon(s,r)||fetch(s,{method:"POST",body:r,keepalive:1}).catch(()=>{}),g.length&&h(e)},m=(e,t,s)=>{const o=Date.now();g.push({eventId:`${i}.${o.toString(36)}.${p}`,sessionId:i,visitorId:d,type:e,name:t,path:location.pathname.slice(0,256),referrer:u,timestamp:o,sequence:p++,affiliateSlug:c,...s}),clearTimeout(l),l=setTimeout(h,1200)};let f;const v=()=>{const e=location.pathname;e!==f&&(f=e,m("pageview",void 0,a&&{properties:a}))};window.rastro=(e,t,s)=>{if("context"===e)return{sessionId:i,visitorId:d};"event"===e&&m("custom",`${t||"event"}`.slice(0,80),s&&JSON.stringify(s).length>2e4?void 0:{properties:s})},document.addEventListener("click",e=>{const t=e.target?.closest("a,button,[data-rastro-event]");if(!t)return;const s=t.dataset.rastroEvent,o=t.href,n=o&&new URL(o),r=/^https?:$/.test(n?.protocol),a=r&&n.origin!==location.origin;m(s?"custom":a?"outbound":"click",s,{target:(t.dataset.rastroLabel||t.innerText||t.tagName).slice(0,64),href:r?((a?n.origin:"")+n.pathname).slice(0,256):void 0})},1);const S=e=>{const t=history[e];history[e]=(...e)=>{t.apply(history,e),v()}};S("pushState"),S("replaceState"),addEventListener("popstate",v),addEventListener("pagehide",()=>h(1)),setInterval(()=>{m("heartbeat"),h()},2e4),v()})();
1
+ (()=>{const e=document.currentScript,t=e?.dataset.site,s=e?.dataset.endpoint||e?.src&&new URL("events",e.src).href;if(!t||!s)return;const o=()=>crypto.randomUUID?.()||Math.random()+"",n=new URLSearchParams(location.search),r=n.get("ref")?.slice(0,64);let a,i,c;for(const e of["source","medium","campaign","term","content"]){const t=n.get("utm_"+e)?.slice(0,64);t&&((a??={})["utm_"+e]=t)}try{i=sessionStorage._r||o(),sessionStorage._r=i,c=r||sessionStorage._a,c&&(sessionStorage._a=c),a||=sessionStorage._u&&JSON.parse(sessionStorage._u),a&&(sessionStorage._u=JSON.stringify(a))}catch{i=o(),c=r}let d=e.dataset.visitor;try{d||=localStorage._rv||=o()}catch{}d||=i;let l,p=0;const g=[],h=document.referrer?new URL(document.referrer).origin:void 0,u=e=>{const o=g.splice(0,50);if(!o.length)return;const n=()=>new Blob([JSON.stringify({siteId:t,events:o,sentAt:Date.now()})]);let r=n();for(;r.size>64e3&&o.length>1;)g.unshift(o.pop()),r=n();e&&navigator.sendBeacon(s,r)||fetch(s,{method:"POST",body:r,keepalive:1}).catch(()=>{}),g.length&&u(e)},m=(e,t,s)=>{const o=Date.now();g.push({eventId:`${i}.${o.toString(36)}.${p}`,sessionId:i,visitorId:d,type:e,name:t,path:location.pathname.slice(0,256),referrer:h,timestamp:o,sequence:p++,affiliateSlug:c,...s}),clearTimeout(l),l=setTimeout(u,1200)};let v;const f=()=>{const e=location.pathname;e!==v&&(v=e,m("pageview",void 0,a&&{properties:a}))};window.rastro=(e,t,s)=>{if("context"===e)return{sessionId:i,visitorId:d};"event"===e&&m("custom",`${t||"event"}`.slice(0,80),s&&JSON.stringify(s).length>2e4?void 0:{properties:s})},document.addEventListener("click",e=>{const t=e.target?.closest("a,button,[data-rastro-event]");if(!t)return;const s=t.dataset.rastroEvent,o=t.href,n=o&&new URL(o),r=/^https?:$/.test(n?.protocol),a=r&&n.origin!==location.origin;m(s?"custom":a?"outbound":"click",s,{target:(t.dataset.rastroLabel||t.innerText||t.tagName).slice(0,64),href:r?((a?n.origin:"")+n.pathname).slice(0,256):void 0})},1);const S=e=>{const t=history[e];history[e]=(...e)=>{t.apply(history,e),f()}};S("pushState"),S("replaceState"),addEventListener("popstate",f),addEventListener("pagehide",()=>{m("leave"),u(1)}),addEventListener("pageshow",e=>{e.persisted&&(m("heartbeat"),u(1))}),setInterval(()=>{m("heartbeat"),u()},2e4),f()})();
@@ -304,6 +304,8 @@ export const {
304
304
  goalsReport,
305
305
  funnelsReport,
306
306
  affiliatesReport,
307
+ vitalsReport,
308
+ siteMap,
307
309
  dataCoverage,
308
310
  } = federated;
309
311
  ```
@@ -48,6 +48,8 @@ The exact generated surface is:
48
48
  - `funnelsReport`
49
49
  - `affiliatesReport`
50
50
  - `dataCoverage`
51
+ - `vitalsReport` (optional capability `vitals`, hosts from `alpha.6`)
52
+ - `siteMap` (optional capability `siteMap`, hosts from `alpha.8`)
51
53
 
52
54
  There are no ingestion, configuration-write, retention-write, raw-site, or site
53
55
  mutation functions in this surface. The read-only goal, funnel, and affiliate
@@ -185,6 +187,8 @@ export const {
185
187
  goalsReport,
186
188
  funnelsReport,
187
189
  affiliatesReport,
190
+ vitalsReport,
191
+ siteMap,
188
192
  dataCoverage,
189
193
  } = federated;
190
194
  ```
package/docs/upgrading.md CHANGED
@@ -6,16 +6,18 @@ deployment.
6
6
 
7
7
  ## Release matrix
8
8
 
9
- | Current state | Required path | Success condition |
10
- | ----------------------------------------------------- | ------------------------------------------------------------------------- | ---------------------------------------------------------------- |
11
- | Fresh deployment | Install the intended release directly | Component deploys and `/rastro/health` succeeds |
12
- | `0.1.0-alpha.0` with maintained data | Install `0.1.0-alpha.1` first and wait for staged visitor-index backfills | Every staged index reports complete before installing `alpha.2` |
13
- | `0.1.0-alpha.1` | Wait for staged visitor-index backfills, then install `alpha.2` | Backfills complete before active readers deploy |
14
- | `0.1.0-alpha.2` with legacy `events` rows | Stay on `alpha.2` and run/resume migration | Durable success plus empty source |
15
- | `0.1.0-alpha.3` fresh/canonical deployment | Rehearse the next alpha normally | Schema, reports, tracker, and retention checks pass |
16
- | `0.1.0-alpha.3` through `alpha.5` with canonical data | Install `0.1.0-alpha.6` directly; Web Vitals tables are additive | Schema deploys and `/rastro/health` reports `webVitals: "optIn"` |
17
- | `0.1.0-alpha.6` | Install `0.1.0-alpha.7` directly; no schema change | `GET /rastro/tracker.js` contains `sentAt` |
18
- | Any release whose packed declarations lack federation | Stop and request an eligible exact registry release | Packed declarations contain the federation exports |
9
+ | Current state | Required path | Success condition |
10
+ | ----------------------------------------------------- | ----------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
11
+ | Fresh deployment | Install the intended release directly | Component deploys and `/rastro/health` succeeds |
12
+ | `0.1.0-alpha.0` with maintained data | Install `0.1.0-alpha.1` first and wait for staged visitor-index backfills | Every staged index reports complete before installing `alpha.2` |
13
+ | `0.1.0-alpha.1` | Wait for staged visitor-index backfills, then install `alpha.2` | Backfills complete before active readers deploy |
14
+ | `0.1.0-alpha.2` with legacy `events` rows | Stay on `alpha.2` and run/resume migration | Durable success plus empty source |
15
+ | `0.1.0-alpha.3` fresh/canonical deployment | Rehearse the next alpha normally | Schema, reports, tracker, and retention checks pass |
16
+ | `0.1.0-alpha.3` through `alpha.5` with canonical data | Install `0.1.0-alpha.6` directly; Web Vitals tables are additive | Schema deploys and `/rastro/health` reports `webVitals: "optIn"` |
17
+ | `0.1.0-alpha.6` | Install `0.1.0-alpha.7` directly; no schema change | `GET /rastro/tracker.js` contains `sentAt` |
18
+ | `0.1.0-alpha.7` | Install `0.1.0-alpha.8` directly; site map tables are additive; re-export `siteMap` | `/rastro/health` reports `siteMap: "dailyRollup"` |
19
+ | `0.1.0-alpha.8` | Install `0.1.0-alpha.9` directly; no schema change; the tracker changes | `/rastro/health` reports `liveDepartures: "leaveBeacon"` |
20
+ | Any release whose packed declarations lack federation | Stop and request an eligible exact registry release | Packed declarations contain the federation exports |
19
21
 
20
22
  Do not upgrade a populated legacy deployment directly to a release that removes
21
23
  the `events` table. Schema acceptance alone does not prove that telemetry was
@@ -129,6 +131,81 @@ Acceptance for this upgrade: `/rastro/health` succeeds, `GET /rastro/tracker.js`
129
131
  contains `sentAt`, and a visitor whose device clock is minutes off appears in
130
132
  **Ao vivo** within seconds of loading a page.
131
133
 
134
+ ## Site map (alpha.8)
135
+
136
+ `0.1.0-alpha.8` adds the route map as a purely additive upgrade: a new
137
+ `routeDailyRollups` component table fed at ingestion, optional fields on
138
+ existing tables (`liveSessions.previousPath`/`movedAt`,
139
+ `sessions.lastPageviewAt`, `analyticsCoverage.siteMapSince`), the `siteMap`
140
+ query, and the retention kind `siteMapRollups` (governed by `reportsDays`). No
141
+ data migration and no staged indexes are involved — install and deploy through
142
+ the host's normal workflow. Ingestion writes one extra rollup document per
143
+ distinct route in a batch.
144
+
145
+ One federation edit is required. The connector manifest is static package
146
+ metadata: after this upgrade it advertises the optional `siteMap` capability
147
+ whether or not the host module exports the function, and connection verification
148
+ checks the manifest's shape, not each function's existence. A host that upgrades
149
+ the package without re-exporting the query leaves the dashboard's **Mapa** view
150
+ failing with a missing-function error. Add `siteMap` to the destructured export
151
+ in `convex/rastroFederation.ts` before deploying:
152
+
153
+ ```ts
154
+ export const {
155
+ manifest,
156
+ // ...the existing exports...
157
+ vitalsReport,
158
+ siteMap,
159
+ dataCoverage,
160
+ } = federated;
161
+ ```
162
+
163
+ The map has no history to backfill: coverage starts at `siteMapSince`, stamped
164
+ by the first ingest after the upgrade, and the dashboard names the date its map
165
+ data begins. In the central dashboard, open **Conexões** and click **Verificar
166
+ novamente** on the active connection so the stored capability list picks up
167
+ `siteMap` and the **Mapa** view replaces its upgrade notice.
168
+
169
+ Acceptance for this upgrade: `/rastro/health` reports
170
+ `features.siteMap: "dailyRollup"`, and after one real visit that navigates
171
+ between two pages, `siteMap` returns both routes and the transition between
172
+ them.
173
+
174
+ ## Realtime presence and persistent identity (alpha.9)
175
+
176
+ `0.1.0-alpha.9` changes no schema, but it changes the served tracker twice over,
177
+ so the cache window is the whole upgrade story.
178
+
179
+ Live presence becomes realtime: the tracker announces a `leave` on `pagehide`
180
+ and the live session retires about ten seconds later, a back/forward-cache
181
+ return revives it immediately, and the safety net for a browser that never says
182
+ goodbye is 90 seconds (down from five minutes). A leave stores no telemetry and
183
+ never extends presence, so replays are inert.
184
+
185
+ Anonymous identity becomes persistent: the tracker keeps one pseudonymous id per
186
+ browser and site origin in `localStorage` and sends it as `visitorId`, so one
187
+ person in several tabs counts once, returning visitors count once across days,
188
+ and journeys join across sessions. A host-supplied `data-visitor` id still wins
189
+ and never touches the stored id; blocked storage falls back to the per-tab id
190
+ and the salted daily hash exactly as before.
191
+
192
+ **Review the host's privacy disclosures before deploying.** The persistent
193
+ visitor ID is an identifier under most privacy laws; the README's privacy
194
+ contract describes what is stored (origin-scoped, never a cookie, gone when the
195
+ visitor clears site data) and the consent note to reconcile with local
196
+ requirements.
197
+
198
+ **The tracker is cached** (`max-age=300, stale-while-revalidate=86400`): for up
199
+ to a day after the deploy, returning visitors and already-open tabs run the old
200
+ tracker — per-tab identity, no leave beacon. They degrade cleanly to the
201
+ 90-second safety net and to per-tab counting until the cache turns over.
202
+ Validate in a private window, not in a tab that was open during the deploy.
203
+
204
+ Acceptance for this upgrade: `/rastro/health` reports
205
+ `features.liveDepartures: "leaveBeacon"`, `GET /rastro/tracker.js` contains
206
+ `leave` and `_rv`, two tabs on the site appear as one active visitor, and
207
+ closing both removes the visitor from **Ao vivo** within seconds.
208
+
132
209
  ## Federation releases
133
210
 
134
211
  Federation is additive to component telemetry but requires host tables,
@@ -158,6 +235,10 @@ control-plane issuer.
158
235
  - A real tracker request is accepted from an allowed origin.
159
236
  - When the host opts into Web Vitals: `/rastro/vitals.js` serves and
160
237
  `vitalsReport` reflects a real page load.
238
+ - On `alpha.8` or later: the federation module re-exports `siteMap` and, after a
239
+ real two-page visit, `siteMap` returns both routes and their transition.
240
+ - On `alpha.9` or later: closing the site's last tab removes the visitor from
241
+ the live view within seconds, and two tabs count as one visitor.
161
242
  - Protected overview, journey, goal, funnel, and affiliate reports used by the
162
243
  host still run.
163
244
  - Trusted conversion idempotency and currency checks still pass.
package/llms.txt CHANGED
@@ -53,8 +53,9 @@ Do not infer federation availability from this website, a dist-tag, or a source
53
53
  - Funnel report maximum: 90 complete UTC days.
54
54
  - Affiliate reports require complete UTC-day boundaries.
55
55
  - Vitals report maximum: 90 complete UTC days; `vitals` is an optional capability that hosts before `alpha.6` do not advertise.
56
+ - Site map maximum: 90 complete UTC days, read newest day first within 8,000 route rows; older days it could not read are declared as partial coverage. `siteMap` is an optional capability that hosts before `alpha.8` do not advertise, and its data starts at the first ingest after that upgrade.
56
57
  - Maximum live visitors: 500.
57
- - Live window: five minutes since the visitor's last event or heartbeat. `POST /rastro/events` re-anchors a batch whose `sentAt` is more than 30 seconds from server time, so a wrong device clock decides neither liveness nor hour buckets.
58
+ - Live window: a `leave` beacon on pagehide retires a visitor about ten seconds after they leave, and a bfcache return revives them; the safety net without a goodbye is 90 seconds since the last event or heartbeat. `POST /rastro/events` re-anchors a batch whose `sentAt` is more than 30 seconds from server time, so a wrong device clock decides neither liveness nor hour buckets.
58
59
  - Maximum journey events: 500.
59
60
  - Token lifetime: 10 minutes, RS256, permission `analytics:read`.
60
61
 
@@ -67,3 +68,4 @@ Do not infer federation availability from this website, a dist-tag, or a source
67
68
  - Overview ranges require complete UTC hour or day buckets. Manual pagination honors `numItems` and `cursor` only.
68
69
  - `dataCoverage` echoes the authorized site ID but returns no event, visitor, or session IDs.
69
70
  - `vitalsReport` returns p75, averages, and exact good/needs-improvement/poor counts per metric, page, and device — never individual measurements.
71
+ - `siteMap` returns per-route totals (pageviews, estimated visitors, entries, derived exits and bounces, time on page) and route-to-route transition counts, with numeric, UUID, and long hexadecimal segments collapsed to `:id` — never sessions, visitor IDs, or query strings. `liveVisitors` adds `previousPath` and `movedAt` when a visitor moves between routes.
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "bugs": {
7
7
  "url": "https://github.com/amageweb/amage-rastro/issues"
8
8
  },
9
- "version": "0.1.0-alpha.7",
9
+ "version": "0.1.0-alpha.9",
10
10
  "license": "Apache-2.0",
11
11
  "publishConfig": {
12
12
  "access": "public"
@@ -207,6 +207,7 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
207
207
  | "custom"
208
208
  | "conversion"
209
209
  | "heartbeat"
210
+ | "leave"
210
211
  | "outbound"
211
212
  | "vital";
212
213
  value?: number;
@@ -306,7 +307,8 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
306
307
  | "goals"
307
308
  | "funnels"
308
309
  | "affiliates"
309
- | "vitals";
310
+ | "vitals"
311
+ | "siteMap";
310
312
  }>;
311
313
  from: number;
312
314
  siteId: string;
@@ -515,9 +517,11 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
515
517
  lastSeenAt: number;
516
518
  latitude?: number;
517
519
  longitude?: number;
520
+ movedAt?: number;
518
521
  os: string;
519
522
  pageviewCount: number;
520
523
  path: string;
524
+ previousPath?: string;
521
525
  sessionId: string;
522
526
  siteId: string;
523
527
  source: string;
@@ -694,6 +698,7 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
694
698
  | "custom"
695
699
  | "conversion"
696
700
  | "heartbeat"
701
+ | "leave"
697
702
  | "outbound"
698
703
  | "vital";
699
704
  visitorId: string;
@@ -703,6 +708,54 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
703
708
  },
704
709
  Name
705
710
  >;
711
+ siteMap: FunctionReference<
712
+ "query",
713
+ "internal",
714
+ { from: number; siteIds: Array<string>; to: number },
715
+ {
716
+ from: number;
717
+ metadata: {
718
+ basis: "dailyRollup" | "boundedLegacy";
719
+ coverage: {
720
+ availableFrom: number | null;
721
+ availableThrough: number | null;
722
+ generation: number | null;
723
+ retainedBefore: number | null;
724
+ state: "complete" | "partial" | "retained" | "unavailable";
725
+ };
726
+ limits: {
727
+ routesPerDay: number;
728
+ rows: number;
729
+ transitionSlots: number;
730
+ };
731
+ range: {
732
+ boundary: "inclusive";
733
+ from: number;
734
+ timezone: "UTC";
735
+ to: number;
736
+ };
737
+ visitors: { basis: "estimatedUnique"; exact: boolean };
738
+ };
739
+ routes: Array<{
740
+ bounces: number;
741
+ daily: Array<{ bucketStart: number; pageviews: number }>;
742
+ dwellMs: number;
743
+ dwellSamples: number;
744
+ entries: number;
745
+ exits: number;
746
+ pageviews: number;
747
+ route: string;
748
+ transitionsIn: number;
749
+ transitionsOut: number;
750
+ visitors: number;
751
+ }>;
752
+ to: number;
753
+ transitions: Array<{ count: number; from: string; to: string }>;
754
+ truncated: { routes: boolean; transitions: boolean };
755
+ window: { from: number; to: number } | null;
756
+ },
757
+ Name
758
+ >;
706
759
  visitorJourney: FunctionReference<
707
760
  "query",
708
761
  "internal",
@@ -743,6 +796,7 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
743
796
  | "custom"
744
797
  | "conversion"
745
798
  | "heartbeat"
799
+ | "leave"
746
800
  | "outbound"
747
801
  | "vital";
748
802
  visitorId: string;
@@ -828,6 +882,7 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
828
882
  | "funnelRollups"
829
883
  | "affiliateRollups"
830
884
  | "vitalRollups"
885
+ | "siteMapRollups"
831
886
  | "attributions"
832
887
  | "liveSessions"
833
888
  | "ingestWindows"
@@ -863,6 +918,7 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
863
918
  | "funnelRollups"
864
919
  | "affiliateRollups"
865
920
  | "vitalRollups"
921
+ | "siteMapRollups"
866
922
  | "attributions"
867
923
  | "liveSessions"
868
924
  | "ingestWindows"
@@ -909,6 +965,7 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
909
965
  | "funnelRollups"
910
966
  | "affiliateRollups"
911
967
  | "vitalRollups"
968
+ | "siteMapRollups"
912
969
  | "attributions"
913
970
  | "liveSessions"
914
971
  | "ingestWindows"
@@ -7,7 +7,8 @@ export const MAX_BYTES_PER_SESSION_WINDOW = 256 * 1024;
7
7
  export const SITE_INGEST_SHARDS = 4_096;
8
8
  export const MAX_SITE_EVENTS_PER_SHARD_WINDOW = 300;
9
9
  export const MAX_SITE_BYTES_PER_SHARD_WINDOW = 512 * 1024;
10
- export const LIVE_SESSION_TTL_MS = 5 * 60_000;
10
+ export const LIVE_SESSION_TTL_MS = 90_000;
11
+ export const LIVE_LEAVE_GRACE_MS = 10_000;
11
12
  export const LIVE_SWEEP_INTERVAL_MS = 5_000;
12
13
  export const CLOCK_SKEW_TOLERANCE_MS = 30_000;
13
14
  export const AGGREGATE_SHARDS = 128;
@@ -54,3 +55,14 @@ export const HOUR_MS = 3_600_000;
54
55
  export const MINUTE_MS = 60_000;
55
56
  export const RETENTION_POLICY_INTERVAL_MS = DAY_MS;
56
57
  export const MAX_VISITOR_ALIASES = 10;
58
+ // Site map rollups: one row per (site, route, UTC day, shard). A day keeps at
59
+ // most this many route rows per shard before new routes fold into "(other)";
60
+ // each row keeps this many outgoing targets before they fold the same way. A
61
+ // report reads at most MAX_SITE_MAP_ROWS rows, newest day first — about
62
+ // 5 MiB of rows, under the 8 MiB a function may read once the feature-report
63
+ // byte reserve is kept — and declares the older days it could not read as
64
+ // partial coverage: 20 days at the daily cap, 40 for a 100-route site.
65
+ export const MAX_SITE_MAP_ROUTES_PER_DAY = 200;
66
+ export const ROUTE_TRANSITION_SLOTS = 24;
67
+ export const MAX_SITE_MAP_ROWS = 8_000;
68
+ export const SITE_MAP_OTHER_ROUTE = "(other)";
@@ -12,11 +12,22 @@ export async function ensureAnalyticsControl(
12
12
  .query("analyticsCoverage")
13
13
  .withIndex("by_siteId", (range) => range.eq("siteId", siteId))
14
14
  .unique();
15
- if (existing) return existing;
15
+ if (existing) {
16
+ if (existing.siteMapSince !== undefined) return existing;
17
+ // A site that predates the site map starts its map coverage at the first
18
+ // ingest after the upgrade; the same safety delay applies as for rollups.
19
+ const siteMapSince = now + ROLLUP_SAFETY_DELAY_MS;
20
+ await ctx.db.patch("analyticsCoverage", existing._id, {
21
+ siteMapSince,
22
+ updatedAt: now,
23
+ });
24
+ return { ...existing, siteMapSince, updatedAt: now };
25
+ }
16
26
  const fields = {
17
27
  siteId,
18
28
  generation: 1 as const,
19
29
  rollupCompleteFrom: now + ROLLUP_SAFETY_DELAY_MS,
30
+ siteMapSince: now + ROLLUP_SAFETY_DELAY_MS,
20
31
  retained,
21
32
  updatedAt: now,
22
33
  };
@@ -298,6 +298,8 @@ http.route({
298
298
  ? "dailyHash"
299
299
  : "session",
300
300
  webVitals: "optIn",
301
+ siteMap: "dailyRollup",
302
+ liveDepartures: "leaveBeacon",
301
303
  },
302
304
  },
303
305
  200,