{"_id":"@bussolabs/closeyourit-js","_rev":"15-5583e6dd68e8b51b1ff6fd62c898f924","name":"@bussolabs/closeyourit-js","dist-tags":{"latest":"0.11.4"},"versions":{"0.1.0":{"name":"@bussolabs/closeyourit-js","version":"0.1.0","license":"MIT","_id":"@bussolabs/closeyourit-js@0.1.0","maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"homepage":"https://github.com/bussolabs/closeyourit-js#readme","bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"dist":{"shasum":"cd6cf89650eabb460fe65785c4c03e5d97a32a2e","tarball":"https://registry.npmjs.org/@bussolabs/closeyourit-js/-/closeyourit-js-0.1.0.tgz","fileCount":11,"integrity":"sha512-0TSYZBoGFG97O5Xp8WRBS3t8bwiBHo4Yf0Wd0a8vkPk5uCC8MXz2jFS7SEPR7kVRU0OH63vN49tdtrfQzzbHWQ==","signatures":[{"sig":"MEUCIQDsxPDRdStrL03cIN6K4zS3EnYZN7LkDaioQDwxLzjZeAIgX4IlgAIY5xLUXpzui9XwdL0SEqTJaawqlZEdx6oeP10=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":618638},"main":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/closeyourit.min.js","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./min":"./dist/closeyourit.min.js"},"gitHead":"7204895b90d728a8c2c92b29a511ae3e783514e0","scripts":{"lint":"tsc --noEmit","test":"vitest run --coverage","build":"tsup","format":"prettier --write .","prepack":"pnpm build","test:watch":"vitest","format:check":"prettier --check ."},"_npmUser":{"name":"alessiobussolari","email":"hello@bussolarialessio.me"},"jsdelivr":"./dist/closeyourit.min.js","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"_npmVersion":"11.17.0","description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8","jsdom":"^25","vitest":"^2","prettier":"^3.9.4","typescript":"^5","@types/node":"^22","@vitest/coverage-v8":"^2.1.9"},"_npmOperationalInternal":{"tmp":"tmp/closeyourit-js_0.1.0_1782977717478_0.4669435650690752","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@bussolabs/closeyourit-js","version":"0.2.0","license":"MIT","_id":"@bussolabs/closeyourit-js@0.2.0","maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"homepage":"https://github.com/bussolabs/closeyourit-js#readme","bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"dist":{"shasum":"a4e9530d9cf3633087f45d370334d7bf22adc8e6","tarball":"https://registry.npmjs.org/@bussolabs/closeyourit-js/-/closeyourit-js-0.2.0.tgz","fileCount":11,"integrity":"sha512-eJBQMvaGH1KIv3sIsWjBsESjlr4gfVZjiFHmamiLNidn5GIeh5dowdVjo8IdLqJwx8wgdKUulhokD0jVoVxNvA==","signatures":[{"sig":"MEQCIFdsKUPAD7nDhHg/wXcssEJY2240S9zaDJV8h31fizJnAiAgEYxJyNm0jhpHv5+S2wSRCF1yGMRs97/5rkujm5iZSw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":654693},"main":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/closeyourit.min.js","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./min":"./dist/closeyourit.min.js"},"gitHead":"c3e25783d62b5bdc7f421d15d5e7045e8cd7fe79","scripts":{"lint":"tsc --noEmit","test":"vitest run --coverage","build":"tsup","format":"prettier --write .","prepack":"pnpm build","test:watch":"vitest","format:check":"prettier --check ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1eb6577f-8abe-498c-ad38-95e67c004878"}},"jsdelivr":"./dist/closeyourit.min.js","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"_npmVersion":"11.6.1","description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8","jsdom":"^25","vitest":"^2","prettier":"^3.9.4","typescript":"^5","@types/node":"^22","@vitest/coverage-v8":"^2.1.9"},"_npmOperationalInternal":{"tmp":"tmp/closeyourit-js_0.2.0_1783013398740_0.992927829517795","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@bussolabs/closeyourit-js","version":"0.3.0","license":"MIT","_id":"@bussolabs/closeyourit-js@0.3.0","maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"homepage":"https://github.com/bussolabs/closeyourit-js#readme","bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"dist":{"shasum":"719366fc35d8ae0415fc7cae7f8f91a413caac05","tarball":"https://registry.npmjs.org/@bussolabs/closeyourit-js/-/closeyourit-js-0.3.0.tgz","fileCount":11,"integrity":"sha512-tR7Sui1GzZnDbhrjQkRpAjjiFCiOZrArcv5PnszBZMJiM7ZJlLgFjxiYNYCU1u9fptfFEMUe6eNhgeyGRNnktQ==","signatures":[{"sig":"MEUCIE0MWsnIs8reIwyw+VJAVY+38p3w4ogwuv5sYZGE1Ou5AiEA5gPW0W24wNhhdOAtNyeQviSeDk+6Y8jlcoacrndA3tg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":662428},"main":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/closeyourit.min.js","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./min":"./dist/closeyourit.min.js"},"gitHead":"59ee59f3fd8a80c781f3b9052af4d1e0654fafe4","scripts":{"lint":"tsc --noEmit","test":"vitest run --coverage","build":"tsup","format":"prettier --write .","prepack":"pnpm build","test:watch":"vitest","format:check":"prettier --check ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1eb6577f-8abe-498c-ad38-95e67c004878"}},"jsdelivr":"./dist/closeyourit.min.js","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"_npmVersion":"11.6.1","description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8","jsdom":"^25","vitest":"^2","prettier":"^3.9.4","typescript":"^5","@types/node":"^22","@vitest/coverage-v8":"^2.1.9"},"_npmOperationalInternal":{"tmp":"tmp/closeyourit-js_0.3.0_1783092024132_0.9144896993287595","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@bussolabs/closeyourit-js","version":"0.5.0","license":"MIT","_id":"@bussolabs/closeyourit-js@0.5.0","maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"homepage":"https://github.com/bussolabs/closeyourit-js#readme","bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"dist":{"shasum":"0aa64a3fe03e5187a30a5d025de70398047ae8e0","tarball":"https://registry.npmjs.org/@bussolabs/closeyourit-js/-/closeyourit-js-0.5.0.tgz","fileCount":11,"integrity":"sha512-YE0egH9rfCtMjEx0mE2AlIUX4Ll8gBby++jIYlQ4yKr064kcYvp9bxTV0e+IQ582eirgR2uKaudc18U9RCavPA==","signatures":[{"sig":"MEUCIHsHUCvFkPgs/sUdoK/E9BAOD9mWuq+qO6Evc1VkUMLbAiEA7L2TpU2AaFf7MPjo+KWIadq+2S0BLlMdsJX0bxzUBXU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":737538},"main":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/closeyourit.min.js","module":"./dist/index.mjs","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./min":"./dist/closeyourit.min.js"},"gitHead":"3529ec76a6f3feb01f88a08aa2508d17ca0a5ab1","scripts":{"lint":"tsc --noEmit","test":"vitest run --coverage","build":"tsup","format":"prettier --write .","prepack":"pnpm build","test:watch":"vitest","format:check":"prettier --check ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1eb6577f-8abe-498c-ad38-95e67c004878"}},"jsdelivr":"./dist/closeyourit.min.js","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"_npmVersion":"11.6.1","description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8","jsdom":"^25","vitest":"^2","prettier":"^3.9.4","typescript":"^5","@types/node":"^22","@vitest/coverage-v8":"^2.1.9"},"_npmOperationalInternal":{"tmp":"tmp/closeyourit-js_0.5.0_1783525076919_0.02470878511260377","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@bussolabs/closeyourit-js","version":"0.6.0","license":"MIT","_id":"@bussolabs/closeyourit-js@0.6.0","maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"homepage":"https://github.com/bussolabs/closeyourit-js#readme","bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"dist":{"shasum":"f906725649b41192cda579be5bb8e8e6927f7f52","tarball":"https://registry.npmjs.org/@bussolabs/closeyourit-js/-/closeyourit-js-0.6.0.tgz","fileCount":11,"integrity":"sha512-z0aLzM+jro7a1VcYRAo9A8MU+qN/uwEcwFilL3MmP1I6A1V+rXZ2EWXEytn+VtQSbTbt4TlAljiTmI72rVEXJQ==","signatures":[{"sig":"MEUCIQDDRCcMQnUhrcMU5T8WhcMq5apiwSdiYVvP31mwCJNxjwIgFLTtm8n8FsIM0Sd05TfC2SXuyKjsWnBVrZ+t2UnXutU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":785681},"main":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/closeyourit.min.js","module":"./dist/index.mjs","engines":{"node":">=20.16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./min":"./dist/closeyourit.min.js"},"gitHead":"bcbcb0329c8c6124164f62f14bc087009e2d360c","scripts":{"lint":"tsc --noEmit","test":"vitest run --coverage","build":"tsup","format":"prettier --write .","prepack":"pnpm build","test:watch":"vitest","format:check":"prettier --check ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1eb6577f-8abe-498c-ad38-95e67c004878"}},"jsdelivr":"./dist/closeyourit.min.js","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"_npmVersion":"11.6.1","description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8","jsdom":"^25","vitest":"^2","prettier":"^3.9.4","typescript":"^5","@types/node":"^22","@vitest/coverage-v8":"^2.1.9"},"_npmOperationalInternal":{"tmp":"tmp/closeyourit-js_0.6.0_1783667681797_0.15410845708209653","host":"s3://npm-registry-packages-npm-production"}},"0.6.1":{"name":"@bussolabs/closeyourit-js","version":"0.6.1","license":"MIT","_id":"@bussolabs/closeyourit-js@0.6.1","maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"homepage":"https://github.com/bussolabs/closeyourit-js#readme","bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"dist":{"shasum":"06b425452d7b1c6a2aa21de27aa74d241d4cbb8e","tarball":"https://registry.npmjs.org/@bussolabs/closeyourit-js/-/closeyourit-js-0.6.1.tgz","fileCount":11,"integrity":"sha512-hhg9KvNf1l3BZvWX9Rl7uNTE1xFoYncU0FN0Y0uwS9VBiF39wcv0qSJadqVJgKiznwPgKwsRvKYV2oPpgicBNQ==","signatures":[{"sig":"MEUCIAWkxr5A/jbkYsux8Qa8oUN9VHPhwNtr3dUn9JGvWxF8AiEA76FXfmpE4HbsW7/T6MipEBGMjzuRzQrbt5Sb4F8qO60=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":796086},"main":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/closeyourit.min.js","module":"./dist/index.mjs","engines":{"node":">=20.16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./min":"./dist/closeyourit.min.js"},"gitHead":"e4b60308657e4075e0a54d9e32688f44fc87f540","scripts":{"lint":"tsc --noEmit","test":"vitest run --coverage","build":"tsup","format":"prettier --write .","prepack":"pnpm build","test:watch":"vitest","format:check":"prettier --check ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1eb6577f-8abe-498c-ad38-95e67c004878"}},"jsdelivr":"./dist/closeyourit.min.js","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"_npmVersion":"11.6.1","description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8","jsdom":"^25","vitest":"^2","prettier":"^3.9.4","typescript":"^5","@types/node":"^22","@vitest/coverage-v8":"^2.1.9"},"_npmOperationalInternal":{"tmp":"tmp/closeyourit-js_0.6.1_1783785572690_0.10231631404584252","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"@bussolabs/closeyourit-js","version":"0.7.0","license":"MIT","_id":"@bussolabs/closeyourit-js@0.7.0","maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"homepage":"https://github.com/bussolabs/closeyourit-js#readme","bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"dist":{"shasum":"23c8976f7b8619345529c3ee7307a9766390d9c7","tarball":"https://registry.npmjs.org/@bussolabs/closeyourit-js/-/closeyourit-js-0.7.0.tgz","fileCount":11,"integrity":"sha512-Ve+EMdnEabBLpE5L+8U85eWzLgDr2UHSv9WN3dTaiUzMicuVY6TezZQ0mcK57FD/Hmlu/RFXvzI8L7qxoCOV4Q==","signatures":[{"sig":"MEUCIQClCkB9e2kku3jKn26ZjzDQ2SreweTCR3AWK/JrCARC2gIgMROCJXvG1sS1C5e7fXureFbEh1ZcTlP9o1S4sx5XgNE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":951899},"main":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/closeyourit.min.js","module":"./dist/index.mjs","engines":{"node":">=20.16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./min":"./dist/closeyourit.min.js"},"gitHead":"b1fec7fd3d8a5a614a57359f09e7526509b0fcdf","scripts":{"lint":"tsc --noEmit","test":"vitest run --coverage","build":"tsup","smoke":"node scripts/smoke-package.mjs","format":"prettier --write .","prepack":"pnpm build","test:watch":"vitest","format:check":"prettier --check ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1eb6577f-8abe-498c-ad38-95e67c004878"}},"jsdelivr":"./dist/closeyourit.min.js","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"_npmVersion":"11.6.1","description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"8.20.0","tsup":"^8","jsdom":"^25","vitest":"^2","prettier":"^3.9.4","typescript":"^5","@types/node":"^22","ajv-formats":"3.0.1","@vitest/coverage-v8":"^2.1.9"},"_npmOperationalInternal":{"tmp":"tmp/closeyourit-js_0.7.0_1785538410352_0.4329228919960022","host":"s3://npm-registry-packages-npm-production"}},"0.7.1":{"name":"@bussolabs/closeyourit-js","version":"0.7.1","license":"MIT","_id":"@bussolabs/closeyourit-js@0.7.1","maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"homepage":"https://github.com/bussolabs/closeyourit-js#readme","bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"dist":{"shasum":"b12cc160a1c27b1cd928f0a17bfd68c9f2b952fa","tarball":"https://registry.npmjs.org/@bussolabs/closeyourit-js/-/closeyourit-js-0.7.1.tgz","fileCount":11,"integrity":"sha512-xN8b2pGtCi+a9IBQEpCswa72Z5QI0QunB2si0fqpcnRIhfxZO6UK6fuNgoKksQNvAvLRFkybhQ3QpfJb+dWF7Q==","signatures":[{"sig":"MEQCIBHiZLvFEZzqOt1u4ysgZRbo3bmRTsJn6SmlHiIiYOkBAiAZ0XjP1KSjPHcycliEMQrqHCtya0Mrc9V0TcUFuGQ0+A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":971758},"main":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/closeyourit.min.js","module":"./dist/index.mjs","engines":{"node":">=20.16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./min":"./dist/closeyourit.min.js"},"gitHead":"2bc2256ff49987cae5038bc43a319e5fcf7155bb","scripts":{"lint":"tsc --noEmit","test":"vitest run --coverage","build":"tsup","smoke":"node scripts/smoke-package.mjs","format":"prettier --write .","prepack":"pnpm build","test:watch":"vitest","format:check":"prettier --check ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1eb6577f-8abe-498c-ad38-95e67c004878"}},"jsdelivr":"./dist/closeyourit.min.js","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"_npmVersion":"11.6.1","description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"8.20.0","tsup":"^8","jsdom":"^25","vitest":"^2","prettier":"^3.9.4","typescript":"^5","@types/node":"^22","ajv-formats":"3.0.1","@vitest/coverage-v8":"^2.1.9"},"_npmOperationalInternal":{"tmp":"tmp/closeyourit-js_0.7.1_1786005372165_0.2234109417342185","host":"s3://npm-registry-packages-npm-production"}},"0.8.0":{"name":"@bussolabs/closeyourit-js","version":"0.8.0","license":"MIT","_id":"@bussolabs/closeyourit-js@0.8.0","maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"homepage":"https://github.com/bussolabs/closeyourit-js#readme","bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"dist":{"shasum":"dc14708cd8161f165c6a7cc9e0b2df9ebbb03cea","tarball":"https://registry.npmjs.org/@bussolabs/closeyourit-js/-/closeyourit-js-0.8.0.tgz","fileCount":11,"integrity":"sha512-NT0X6uYheX+hoy8PMDzq6v18sYjXWJCFM01JuTafNeUvGEy+DsCpiVT3bzpwJwHR3/jmUjQzxsqaNtoJ79Ha7A==","signatures":[{"sig":"MEUCIQDXM3cfVBA/JD7SsTEUnt241hoFg8oD0pKl+9zzyY9b8AIgH2uTzihV4nsPO5iXeLJ/+OhpFK3sYoo0Ilav8HTmSSc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1120216},"main":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/closeyourit.min.js","module":"./dist/index.mjs","engines":{"node":">=20.16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./min":"./dist/closeyourit.min.js"},"gitHead":"5cd21a0764e564f243e933c4cbda1b7134a396ec","scripts":{"lint":"tsc --noEmit","test":"vitest run --coverage","build":"tsup","smoke":"node scripts/smoke-package.mjs","format":"prettier --write .","prepack":"pnpm build","test:watch":"vitest","format:check":"prettier --check ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1eb6577f-8abe-498c-ad38-95e67c004878"}},"jsdelivr":"./dist/closeyourit.min.js","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"_npmVersion":"11.6.1","description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"8.20.0","tsup":"^8","jsdom":"^25","vitest":"^2","prettier":"^3.9.4","typescript":"^5","@types/node":"^22","ajv-formats":"3.0.1","@vitest/coverage-v8":"^2.1.9"},"_npmOperationalInternal":{"tmp":"tmp/closeyourit-js_0.8.0_1786010824567_0.7826159704794091","host":"s3://npm-registry-packages-npm-production"}},"0.9.0":{"name":"@bussolabs/closeyourit-js","version":"0.9.0","license":"MIT","_id":"@bussolabs/closeyourit-js@0.9.0","maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"homepage":"https://github.com/bussolabs/closeyourit-js#readme","bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"dist":{"shasum":"29ecd2a3cd4ef291cc209366e20ad8891a820b6f","tarball":"https://registry.npmjs.org/@bussolabs/closeyourit-js/-/closeyourit-js-0.9.0.tgz","fileCount":11,"integrity":"sha512-bpVzGhOMFFnRMpJkXIuy/TFC5dcoNREUqTkWRUMW7/o7T3lw1WVc0YHAf198k2IV+wxkSb+rexI2shY8u9l2dQ==","signatures":[{"sig":"MEYCIQD8BLnYasOSFowMu2M42g9F6llHppGRoRg7iZ3LEboAIQIhANXYANm7RRx91uRyVdjmLISQoe6NrosyY779LbisaSQe","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1162967},"main":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/closeyourit.min.js","module":"./dist/index.mjs","engines":{"node":">=20.16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./min":"./dist/closeyourit.min.js"},"gitHead":"19cb0559c42fbe3066c083ec04fdf752368b132b","scripts":{"lint":"tsc --noEmit","test":"vitest run --coverage","build":"tsup","smoke":"node scripts/smoke-package.mjs","format":"prettier --write .","prepack":"pnpm build","audit:prod":"pnpm audit --prod --audit-level=moderate","test:watch":"vitest","format:check":"prettier --check ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1eb6577f-8abe-498c-ad38-95e67c004878"}},"jsdelivr":"./dist/closeyourit.min.js","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"_npmVersion":"11.6.1","description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"8.20.0","tsup":"^8.5.1","jsdom":"^29.1.1","vitest":"^4.1.10","prettier":"^3.9.6","typescript":"^5.9.3","@types/node":"^24.13.3","ajv-formats":"3.0.1","@vitest/coverage-v8":"^4.1.10"},"_npmOperationalInternal":{"tmp":"tmp/closeyourit-js_0.9.0_1786824453510_0.9988389298187552","host":"s3://npm-registry-packages-npm-production"}},"0.10.0":{"name":"@bussolabs/closeyourit-js","version":"0.10.0","license":"MIT","_id":"@bussolabs/closeyourit-js@0.10.0","maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"homepage":"https://github.com/bussolabs/closeyourit-js#readme","bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"dist":{"shasum":"6c895e7adeb4fabb3368a31ce15702a3fab21948","tarball":"https://registry.npmjs.org/@bussolabs/closeyourit-js/-/closeyourit-js-0.10.0.tgz","fileCount":11,"integrity":"sha512-H4fYGQUj7St81wFSg4MuRC7iQjaEeSYPE52DfSPi/8sWVZURS+geStJQHHXh7YlY+BGz255aVPCeIC9I2gsztQ==","signatures":[{"sig":"MEUCIGt72m2rP2OdjBAspaCyFW+FKktZ4hXD/2LBTVcFZ6LeAiEAizVUSmtc9jvNtE0AM4nOz7l7e784WtDANxekf922Jc4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1655962},"main":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/closeyourit.min.js","module":"./dist/index.mjs","engines":{"node":">=20.16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./min":"./dist/closeyourit.min.js"},"gitHead":"65e99e3abe7d77265cc91410f9f41184391bda78","scripts":{"lint":"tsc --noEmit","size":"node scripts/bundle-size.mjs","test":"vitest run --coverage","build":"tsup","smoke":"node scripts/smoke-package.mjs","format":"prettier --write .","prepack":"pnpm build","audit:prod":"pnpm audit --prod --audit-level=moderate","test:watch":"vitest","format:check":"prettier --check ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1eb6577f-8abe-498c-ad38-95e67c004878"}},"jsdelivr":"./dist/closeyourit.min.js","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"_npmVersion":"11.6.1","description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","dependencies":{"web-vitals":"6.1.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"8.20.0","tsup":"^8.5.1","jsdom":"^29.1.1","vitest":"^4.1.10","prettier":"^3.9.6","typescript":"^5.9.3","@types/node":"^24.13.3","ajv-formats":"3.0.1","@vitest/coverage-v8":"^4.1.10"},"_npmOperationalInternal":{"tmp":"tmp/closeyourit-js_0.10.0_1786899543497_0.482630064079399","host":"s3://npm-registry-packages-npm-production"}},"0.11.0":{"name":"@bussolabs/closeyourit-js","version":"0.11.0","license":"MIT","_id":"@bussolabs/closeyourit-js@0.11.0","maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"homepage":"https://github.com/bussolabs/closeyourit-js#readme","bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"dist":{"shasum":"a949e48d63b4a66e6c39bfab5503c7fae2327028","tarball":"https://registry.npmjs.org/@bussolabs/closeyourit-js/-/closeyourit-js-0.11.0.tgz","fileCount":11,"integrity":"sha512-VOvYx0yWbtTPfZO7ngzUBGVEMOWaXxaCeo9aqpMjsnDsGp6PaX4b7l3oQRf1gX8GBLWYPPYYiIOWMstBwtbOwQ==","signatures":[{"sig":"MEYCIQD8To/nY1RbupR4QyCJnyn3TAMmW4Bwca6CbfMpiQl7rQIhAKLdvlA2bKNNZUuI3FEPrSY0wDa2w8E61tLYjy1vJCUu","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1746879},"main":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/closeyourit.min.js","module":"./dist/index.mjs","engines":{"node":">=20.16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./min":"./dist/closeyourit.min.js"},"gitHead":"004e3388d156ac87d1171bd1b34690ba74ebc534","scripts":{"lint":"tsc --noEmit","size":"node scripts/bundle-size.mjs","test":"vitest run --coverage","build":"tsup","smoke":"node scripts/smoke-package.mjs","format":"prettier --write .","prepack":"pnpm build","audit:prod":"pnpm audit --prod --audit-level=moderate","test:watch":"vitest","format:check":"prettier --check ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1eb6577f-8abe-498c-ad38-95e67c004878"}},"jsdelivr":"./dist/closeyourit.min.js","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"_npmVersion":"11.6.1","description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","dependencies":{"web-vitals":"6.1.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"8.20.0","tsup":"^8.5.1","jsdom":"^29.1.1","vitest":"^4.1.10","prettier":"^3.9.6","typescript":"^5.9.3","@types/node":"^24.13.3","ajv-formats":"3.0.1","@vitest/coverage-v8":"^4.1.10"},"_npmOperationalInternal":{"tmp":"tmp/closeyourit-js_0.11.0_1788429434891_0.5626706897212725","host":"s3://npm-registry-packages-npm-production"}},"0.11.1":{"name":"@bussolabs/closeyourit-js","version":"0.11.1","license":"MIT","_id":"@bussolabs/closeyourit-js@0.11.1","maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"homepage":"https://github.com/bussolabs/closeyourit-js#readme","bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"dist":{"shasum":"287a2963b2e37b36ade713e2a75eec0acdb53d79","tarball":"https://registry.npmjs.org/@bussolabs/closeyourit-js/-/closeyourit-js-0.11.1.tgz","fileCount":11,"integrity":"sha512-eLjJ34m8wQdi+e2qHW1tnAg88IBOuQ2A8eADOwaJfqIp4Uz7PzCfPg+mT+CHq3sbY1lTBcyl1AOG/3kW68a3Yg==","signatures":[{"sig":"MEYCIQCtzrHxoTodi5nFG2aUQZzsEPD3fYmuXU3im612ApyfpwIhAL2qNDX3YycNdKo0IKDSDVwHfwWU9VzwzV2ogju+eInY","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1746879},"main":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/closeyourit.min.js","module":"./dist/index.mjs","engines":{"node":">=20.16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./min":"./dist/closeyourit.min.js"},"gitHead":"4678edbf6d797aabad96b4d69249f1a0cabea7d0","scripts":{"lint":"tsc --noEmit","size":"node scripts/bundle-size.mjs","test":"vitest run --coverage","build":"tsup","smoke":"node scripts/smoke-package.mjs","format":"prettier --write .","prepack":"pnpm build","audit:prod":"pnpm audit --prod --audit-level=moderate","test:watch":"vitest","format:check":"prettier --check ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1eb6577f-8abe-498c-ad38-95e67c004878"}},"jsdelivr":"./dist/closeyourit.min.js","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"_npmVersion":"11.6.1","description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","dependencies":{"web-vitals":"6.1.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"8.20.0","tsup":"^8.5.1","jsdom":"^29.1.1","vitest":"^4.1.10","prettier":"^3.9.6","typescript":"^5.9.3","@types/node":"^24.13.3","ajv-formats":"3.0.1","@vitest/coverage-v8":"^4.1.10"},"_npmOperationalInternal":{"tmp":"tmp/closeyourit-js_0.11.1_1788458665937_0.6942916808184789","host":"s3://npm-registry-packages-npm-production"}},"0.11.2":{"name":"@bussolabs/closeyourit-js","version":"0.11.2","license":"MIT","_id":"@bussolabs/closeyourit-js@0.11.2","maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"homepage":"https://github.com/bussolabs/closeyourit-js#readme","bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"dist":{"shasum":"9ce85e313c86a10374743104c3c50225fd94175a","tarball":"https://registry.npmjs.org/@bussolabs/closeyourit-js/-/closeyourit-js-0.11.2.tgz","fileCount":11,"integrity":"sha512-jiVMQHWtfWfcCod1B2SGoyTJnuf18QgLDQGXreFMos6DqgvMaooZl14kRDYo4SmVMkJN+mC/Zcm+pgbpO7g/hQ==","signatures":[{"sig":"MEYCIQCxdPcBz0qc1Js3ejyXE77I9aLznnvv3uOpiyWhshQVewIhAOBjQDsTWr4f6Eoo8LCy5GBah+5yoOHuFJeHq1htuiXM","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1768388},"main":"./dist/index.js","types":"./dist/index.d.ts","unpkg":"./dist/closeyourit.min.js","module":"./dist/index.mjs","engines":{"node":">=20.16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./min":"./dist/closeyourit.min.js"},"gitHead":"aa608df4f467ba4dd44a45a12b54fddf939f3e18","scripts":{"lint":"tsc --noEmit","size":"node scripts/bundle-size.mjs","test":"vitest run --coverage","build":"tsup","smoke":"node scripts/smoke-package.mjs","format":"prettier --write .","prepack":"pnpm build","audit:prod":"pnpm audit --prod --audit-level=moderate","test:watch":"vitest","format:check":"prettier --check ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:1eb6577f-8abe-498c-ad38-95e67c004878"}},"jsdelivr":"./dist/closeyourit.min.js","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"_npmVersion":"11.6.1","description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","dependencies":{"web-vitals":"6.2.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"8.20.0","tsup":"^8.5.1","jsdom":"^29.1.1","vitest":"^4.1.10","prettier":"^3.9.6","typescript":"^5.9.3","@types/node":"^26.4.1","ajv-formats":"3.0.1","@vitest/coverage-v8":"^4.1.10"},"_npmOperationalInternal":{"tmp":"tmp/closeyourit-js_0.11.2_1788743562986_0.8599818060434639","host":"s3://npm-registry-packages-npm-production"}},"0.11.4":{"_id":"@bussolabs/closeyourit-js@0.11.4","bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"dist":{"shasum":"eb810b637f0bb1b8abfb613d02bd229bfe70e039","tarball":"https://registry.npmjs.org/@bussolabs/closeyourit-js/-/closeyourit-js-0.11.4.tgz","fileCount":11,"integrity":"sha512-6ldCo859eP+kZfDxEWpDTGMTz5sC8bc6F/VCB07uQjcbmqlLzXemlLnK1d3pfayNIzHw76FyEGDXbb9DSGEsRw==","signatures":[{"sig":"MEUCIGYJgVbHCRcuqsfFLK26UpH7AXebfUHFE79aTMFxAIUvAiEAsZjpQVn/oOIS07S2uVa5xXtdPCaNuGoU8gH65ea28t8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIEl6Wih0THRT3KLj0GHn505sCyaDxnqrpib3tkBJ8T0pAiEAm1k5DEvGabzjy4NQE7uGeOlLDqOg/pHM4Lwc7UwqE0w="}],"unpackedSize":1768388},"main":"./dist/index.js","name":"@bussolabs/closeyourit-js","types":"./dist/index.d.ts","unpkg":"./dist/closeyourit.min.js","module":"./dist/index.mjs","engines":{"node":">=20.16"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./min":"./dist/closeyourit.min.js"},"gitHead":"fb64c26cf941d4b1065f3816859c91b387771744","license":"MIT","scripts":{"lint":"tsc --noEmit","size":"node scripts/bundle-size.mjs","test":"vitest run --coverage","build":"tsup","smoke":"node scripts/smoke-package.mjs","format":"prettier --write .","prepack":"pnpm build","audit:prod":"pnpm audit --prod --audit-level=moderate","test:watch":"vitest","format:check":"prettier --check ."},"version":"0.11.4","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"1eb6577f-8abe-498c-ad38-95e67c004878"}},"homepage":"https://github.com/bussolabs/closeyourit-js#readme","jsdelivr":"./dist/closeyourit.min.js","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"_npmVersion":"11.19.0","description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","directories":{},"maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"sideEffects":false,"_nodeVersion":"24.21.0","dependencies":{"web-vitals":"6.2.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"ajv":"8.20.0","tsup":"^8.5.1","jsdom":"^30.1.0","vitest":"^4.1.10","prettier":"^3.9.8","typescript":"^5.9.3","@types/node":"^26.6.2","ajv-formats":"3.0.1","@vitest/coverage-v8":"^4.1.10"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/closeyourit-js_0.11.4_1790807783935_0.49359594914529303"}}},"time":{"created":"2026-07-02T07:35:17.336Z","modified":"2026-09-30T22:36:24.228Z","0.1.0":"2026-07-02T07:35:17.654Z","0.2.0":"2026-07-02T17:29:58.898Z","0.3.0":"2026-07-03T15:20:24.282Z","0.5.0":"2026-07-08T15:37:57.114Z","0.6.0":"2026-07-10T07:14:41.983Z","0.6.1":"2026-07-11T15:59:32.869Z","0.7.0":"2026-07-31T22:53:30.552Z","0.7.1":"2026-08-06T08:36:12.341Z","0.8.0":"2026-08-06T10:07:04.716Z","0.9.0":"2026-08-15T20:07:33.668Z","0.10.0":"2026-08-16T16:59:03.654Z","0.11.0":"2026-09-03T09:57:15.057Z","0.11.1":"2026-09-03T18:04:26.078Z","0.11.2":"2026-09-07T01:12:43.129Z","0.11.4":"2026-09-30T22:36:24.042Z"},"bugs":{"url":"https://github.com/bussolabs/closeyourit-js/issues"},"license":"MIT","homepage":"https://github.com/bussolabs/closeyourit-js#readme","repository":{"url":"git+https://github.com/bussolabs/closeyourit-js.git","type":"git"},"description":"Browser SDK for CloseYourIt — error and log monitoring for the web (self-hosted, Sentry-compatible wire format)","maintainers":[{"name":"alessiobussolari","email":"hello@bussolarialessio.me"}],"readme":"# closeyourit-js\n\nSDK JavaScript di [CloseYourIt](https://www.closeyour.it) per il monitoring di errori, log e\nperformance — **isomorfo: browser + Node 20.16+**. TypeScript, **una sola dipendenza runtime**\n([`web-vitals`](https://github.com/GoogleChrome/web-vitals), che a sua volta non ne ha), formato\nwire Sentry-compatibile: lo stesso contratto di ingestione degli altri SDK CloseYourIt —\n[`closeyourit-ruby`](https://github.com/bussolabs/closeyourit-ruby),\n[`closeyourit-dart`](https://github.com/bussolabs/closeyourit-dart) e\n[`closeyourit-python`](https://github.com/bussolabs/closeyourit-python).\n\nNel browser cattura automaticamente le eccezioni non gestite, i rifiuti di Promise, i log\nstrutturati e i breadcrumb (click, navigazione, console, richieste HTTP); su Node aggancia\n`uncaughtException`/`unhandledRejection` e flusha su `beforeExit`/`SIGTERM`. In più: metriche\n`slow_method` via `measure()` e — opt-in — verdetti performance (`slow_external_http`,\n`repeated_http`, `jank`). Scrubbing PII lato client, invio fire-and-forget: non fa mai crashare\nl'host.\n\n> **Stesso wire, funzioni diverse.** Il contratto di ingestione è condiviso; le funzioni no. Ogni\n> SDK copre ciò che ha senso sulla sua piattaforma: qui ci sono `pageview`, session replay e jank,\n> mentre `slow_query` e `job_metric` vivono altrove. Cosa esiste dove, e da quale versione, sta in\n> una tabella unica: `compatibility/sdk-feature-parity.md`, nel repository di documentazione\n> `closeyourit-docs`. Questo README descrive **solo** l'SDK JavaScript: le funzioni\n> non coincidono fra SDK, e nessuna riga qui va letta come una promessa su Ruby, Dart o Python.\n\n> **Credenziali — server vs browser.** Il progetto ha **due** credenziali per lo **stesso**\n> token:\n>\n> - **`token`** — il bearer **segreto** `cyi_…`. È a piena potenza (ingest **e** read): è una\n>   credenziale **SERVER-ONLY**. Usalo su Node/SSR (`Authorization: Bearer`). **Non deve MAI finire\n>   in un bundle browser**: chiunque lo estrarrebbe dal tab Network in pochi secondi.\n> - **`publicKey`** — la **DSN public key** (esadecimale, come lo `sentry_key` di Sentry). Per design\n>   **non è segreta**: è la credenziale **browser-safe**. Nel browser l'SDK la usa via `?sentry_key=`\n>   sul path drop-in Sentry, **mai il bearer**.\n>\n> Nel browser configura `publicKey`; se passi solo il bearer segreto, l'SDK **resta no-op** (avvisa in\n> console) invece di esporlo. Prendi entrambe le credenziali dalla pagina del progetto su CloseYourIt.\n\n## Installazione\n\n### npm (bundler: Vite, webpack, Rollup, …)\n\n```bash\npnpm add @bussolabs/closeyourit-js\n# oppure: npm install @bussolabs/closeyourit-js\n```\n\n```ts\nimport * as CloseYourIt from '@bussolabs/closeyourit-js'\n\nCloseYourIt.init({\n  endpointUrl: 'https://www.closeyour.it',\n  publicKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', // DSN public key (browser-safe)\n  projectId: '00000000-0000-0000-0000-000000000000',\n  environment: 'production',\n  release: 'web@1.4.2',\n})\n```\n\n### `<script>` (IIFE, senza build step)\n\nIl bundle IIFE espone il globale `window.CloseYourIt` (~20 KB gzip, ~18 KB brotli: il tetto è\ncommittato in `bundle-budget.json` e la CI lo verifica a ogni run). In produzione **pinna la\nversione** e aggiungi la [Subresource Integrity](https://developer.mozilla.org/docs/Web/Security/Subresource_Integrity)\n(`integrity` + `crossorigin`) per proteggerti da una compromissione della CDN:\n\n```html\n<script\n  src=\"https://cdn.jsdelivr.net/npm/@bussolabs/closeyourit-js@0.2.0/dist/closeyourit.min.js\"\n  integrity=\"sha384-…\"\n  crossorigin=\"anonymous\"\n></script>\n<script>\n  CloseYourIt.init({\n    endpointUrl: 'https://www.closeyour.it',\n    publicKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', // DSN public key (browser-safe)\n    projectId: '00000000-0000-0000-0000-000000000000',\n    environment: 'production',\n  })\n</script>\n```\n\nL'hash `integrity` reale della versione pubblicata si ottiene da jsDelivr (pulsante \"SRI\" sulla\npagina del file) o localmente con\n`curl -s https://cdn.jsdelivr.net/npm/@bussolabs/closeyourit-js@0.2.0/dist/closeyourit.min.js | openssl dgst -sha384 -binary | openssl base64 -A`.\n\nMetti lo `<script>` il più in alto possibile nel `<head>`: dopo `init`, i gestori globali\ncatturano ogni errore successivo, anche quelli sollevati durante il resto del caricamento.\n\n### Node 20.16+\n\nStesso package, stessa `init`. Su Node l'SDK installa i gestori di processo\n(`uncaughtException`/`unhandledRejection`: cattura → flush → se non hai handler tuoi, esce con\ncodice 1 preservando la semantica crash di default) e flusha i buffer su `beforeExit`/`SIGTERM`.\nGli eventi Node portano anche `server_name` (hostname, come nella gem Ruby): richiede\n`process.getBuiltinModule` (Node ≥20.16) — da cui il minimo dichiarato in `engines`.\n\n```ts\nimport * as CloseYourIt from '@bussolabs/closeyourit-js'\n\nCloseYourIt.init({\n  endpointUrl: 'https://www.closeyour.it',\n  token: process.env.CLOSEYOURIT_TOKEN!, // bearer segreto: lecito lato server\n  projectId: process.env.CLOSEYOURIT_PROJECT_ID!,\n  environment: process.env.NODE_ENV ?? 'production',\n})\n\n// Cattura manuale + flush esplicito (es. script batch/CLI)\ntry {\n  await job()\n} catch (e) {\n  CloseYourIt.captureException(e, { handled: true })\n  await CloseYourIt.flush()\n  throw e\n}\n```\n\nSu Node più richieste sono elaborate insieme: per tenere user/tag/request/breadcrumb **isolati\nper richiesta** (e mai attraverso il confine tra flussi concorrenti) avvolgi l'handler in\n`CloseYourIt.runWithScope(...)` — in Express/Connect basta un middleware:\n`app.use((req, res, next) => CloseYourIt.runWithScope(() => next()))`. Dentro il blocco imposta il\ncontesto con `CloseYourIt.setUser(...)` / `client.scope.setRequest({ url, method })` o passa\n`contexts` all'hint. Dove non puoi avvolgere l'intera richiesta (es. un hook `error` globale) usa\n`CloseYourIt.withScope(...)` per una cattura con contesto temporaneo, senza toccare lo scope\ncondiviso. Il wrapper automatico di `fetch` è solo browser: per l'HTTP server-side usa\nbreadcrumb/`measure` manuali.\n\n## Uso\n\nDopo `init` gli errori non gestiti e i rifiuti di Promise vengono catturati automaticamente. Le\nAPI aggiuntive:\n\n```ts\n// Cattura manuale di un'eccezione gestita\ntry {\n  rischioso()\n} catch (e) {\n  CloseYourIt.captureException(e, { handled: true })\n}\n\n// Messaggio diagnostico\nCloseYourIt.captureMessage('cache miss sul carrello', 'warning')\n\n// Log strutturato (bufferizzato e inviato in batch)\nCloseYourIt.log('info', 'ordine creato', { order_id: 42, total_cents: 1990 })\n\n// Logger nominato con metodi per livello (warn → warning sul wire)\nCloseYourIt.logger.warn('risposta lenta dal gateway')\nCloseYourIt.logger.named('payments').info('rimborso emesso', { order_id: 42 })\n\n// Metrica slow_method: misura un blocco (sync o async) e invia oltre soglia\nconst totale = CloseYourIt.measure('checkout.total', () => calcolaTotale(cart))\nconst dati = await CloseYourIt.measure('api.orders', () => fetchOrders())\n\n// Contesto allegato a errori e messaggi successivi\nCloseYourIt.setUser({ id: 'acc_123' }) // senza sendPii viaggia solo l'id\nCloseYourIt.setTag('area', 'checkout')\nCloseYourIt.setTags({ tenant: 'acme', tier: 'gold' })\nCloseYourIt.setExtra('plan', 'pro')\nCloseYourIt.setContext('billing', { seats: 3 })\n\n// Breadcrumb manuale (oltre a quelli automatici)\nCloseYourIt.addBreadcrumb({ category: 'ui.action', message: 'apre modale pagamento' })\n\n// Correlazione: il trace_id di pagina è generato all'init; sovrascrivibile\nCloseYourIt.setTraceId(myRequestId)\nCloseYourIt.getTraceId()\n\n// Svuota i log bufferizzati e attende gli invii in volo (idempotente)\nawait CloseYourIt.flush()\n\n// Spegne l'SDK e ripristina i patch globali\nawait CloseYourIt.close()\n```\n\n## Performance issues (opt-in)\n\nCon `detectPerformanceIssues: true` l'SDK emette verdetti `performance_issue` su `/metrics`:\n\n- **`slow_external_http`** — un `fetch`/XHR verso un host esterno oltre\n  `slowExternalThresholdMs` (default 1s). Il path è templatizzato (`/v1/charges/<n>`,\n  `/users/<uuid>`), mai la query string.\n- **`repeated_http`** — la stessa richiesta (host + path templatizzato) ripetuta\n  `repeatedHttpThreshold` volte (default 5) in `repeatedHttpWindowMs` (default 5s): l'\"N+1 del\n  client\". Emesso una volta per finestra.\n- **`jank`** — long task del main thread oltre `jankThresholdMs` (default 100ms) via\n  `PerformanceObserver(longtask)`; di fatto Chromium-only, altrove è un no-op silenzioso. Route\n  = `location.pathname` templatizzato.\n\n```ts\nCloseYourIt.init({\n  /* … */\n  detectPerformanceIssues: true,\n})\n```\n\nIndipendentemente dall'opt-in, il breadcrumb `http` marca `slow_external_http: true`\n(`level: warning`) sulle chiamate esterne oltre soglia — utile come contesto negli errori.\n\n## Web Vitals (opt-in)\n\nCon `trackWebVitals: true` l'SDK misura sul browser dei visitatori veri le metriche con cui Google\ngiudica la velocità di un sito, e le invia a `POST /api/v1/projects/{projectId}/web_vitals`:\n\n| Metrica | Cosa misura                                                | Ruolo                      |\n| ------- | ---------------------------------------------------------- | -------------------------- |\n| `lcp`   | Quanto ci mette a comparire il contenuto principale (ms)   | Core Web Vital             |\n| `cls`   | Quanto la pagina si sposta sotto gli occhi (adimensionale) | Core Web Vital             |\n| `inp`   | Quanto tarda la pagina a rispondere a un'interazione (ms)  | Core Web Vital             |\n| `ttfb`  | Quanto tarda il server a mandare il primo byte (ms)        | Diagnostica di un LCP alto |\n| `fcp`   | Quando appare il primo contenuto, qualunque esso sia (ms)  | Diagnostica di un LCP alto |\n\n```ts\nCloseYourIt.init({\n  /* … */\n  trackWebVitals: true,\n  webVitalsSampleRate: 0.2, // opzionale: una pagina su cinque\n})\n```\n\n**Chi misura.** [`web-vitals`](https://github.com/GoogleChrome/web-vitals) 6.x, la libreria di\nriferimento di Google, ed è l'**unica dipendenza** del pacchetto. LCP e CLS a mano sono fattibili,\nl'INP no — dipende dal percentile sulle interazioni e da eccezioni che cambiano tra versioni di\nChrome — e una versione sbagliata produce numeri plausibili che nessuno smaschera per mesi. È anche\nl'unico modo di essere confrontabili con i dati di CrUX, che è il punto di affiancare le due colonne\nnella stessa pagina. Viene importata **per metrica** (`web-vitals/onLCP.js`) e nella sola build\nstandard, **mai** `web-vitals/attribution`: quella pesa molto di più e il suo dato oggi non avrebbe\ndove andare. Il bundle browser ha un tetto committato (`bundle-budget.json`) che la CI verifica a\nogni run: la URL su jsDelivr non è pinnata, quindi ogni versione arriva da sola su tutti i siti\ninstallati e un byte in più lo scaricano tutti i loro visitatori.\n\n**Quando partono.** Tutte insieme, in **un solo invio**, quando la pagina esce di scena\n(`pagehide`/`visibilitychange(hidden)`): prima di allora i valori sono provvisori — l'LCP può ancora\nessere superato, il CLS può ancora crescere. TTFB e FCP sono definitivi molto prima, ma aspettano in\nmemoria insieme agli altri: mandarli subito significherebbe due richieste per caricamento invece di\nuna. Il comportamento è quello di **default** della libreria, non `reportAllChanges`: ogni metrica\narriva una volta sola, col valore definitivo.\n\n**Una misura per metrica, per caricamento**, ed è la prima a valere: quello che la libreria riporta\ndopo che il batch è partito viene scartato. Il rovescio da conoscere: se l'utente passa a un'altra\nscheda e poi torna, il report è già partito e quello che accade dopo non viene misurato. È una scelta\ndeliberata — due valori della stessa pagina dentro un percentile lo falsano più di una misura\ntroncata. Una metrica che invece arriva **in ritardo per la prima volta** (dopo il primo invio non\nc'è un secondo `pagehide` su cui contare) parte da sola entro cinque secondi, così non resta in\nostaggio del buffer.\n\n**Cosa viaggia.** `hostname`, `path` (**mai** la query né il frammento), il tipo di navigazione,\n`environment` e `release` se configurata. Nessun identificatore del visitatore: come per le\npageview, il resto lo ricava il server dalla richiesta. L'**esito** (buono/da migliorare/scarso) non\nviene inviato: lo calcola il backend dalle soglie ufficiali, così un SDK vecchio non può dipingere di\nverde ciò che oggi è rosso. Il tipo di navigazione che l'ingest non conosce (`back-forward-cache`,\n`soft-navigation`) viene semplicemente omesso: la misura parte lo stesso, perderla per un campo\naccessorio sarebbe uno scambio pessimo.\n\n**Sampling.** `webVitalsSampleRate` (default `1.0`) decide sul **caricamento intero**: le misure di\nuna pagina partono tutte o nessuna, anche quando arrivano in due invii. Campionarle una per una\ncostruirebbe i percentili di metriche diverse su insiemi di pagine diversi, che non sono più\nconfrontabili. Sotto `1.0` il percentile diventa inaffidabile sui siti a basso traffico, che sono la\nmaggioranza: abbassarlo conviene solo con volumi alti.\n\n**Browser non supportati.** Ogni metrica è indipendente: quella che il browser non sa misurare non\nviene raccolta e le altre partono lo stesso, e l'`init` non cambia comportamento. Oggi LCP e INP sono\ndi fatto Chromium-only; TTFB e FCP arrivano quasi ovunque. L'INP di una pagina che nessuno ha toccato\nnon viene inventato: senza interazioni non c'è misura.\n\nIn una SPA le misure sono attribuite al **percorso al momento del caricamento**, non all'ultima route\nvisitata: LCP, CLS e INP descrivono quel caricamento, e assegnarli alla pagina dove l'utente è\narrivato darebbe la colpa a quella sbagliata.\n\n## Errori delle risorse e violazioni CSP (opt-in)\n\nCon `captureResourceErrors: true` l'SDK segnala i guasti che nessuno stack trace racconta: uno\nscript o un foglio di stile che non arriva, un'immagine che non carica, una regola di Content\nSecurity Policy che blocca qualcosa che alla pagina serviva.\n\n```ts\nCloseYourIt.init({\n  /* … */\n  captureResourceErrors: true,\n})\n```\n\nArrivano sul canale eventi, come gli errori JS, con `level: warning` — una risorsa bloccata è quasi\nsempre ambiente o terze parti (un blocco pubblicità, una CDN irraggiungibile), non un difetto\ndell'applicazione: alzarla a `error` riempirebbe l'alerting di rumore che nessuno può correggere.\n\n| Tipo evento     | Messaggio (chiave di raggruppamento)                          | Contesto allegato                                                       |\n| --------------- | ------------------------------------------------------------- | ----------------------------------------------------------------------- |\n| `ResourceError` | `script non caricato: https://cdn.example.com/app.js`         | `contexts.resource` = `{ url, element }`                                |\n| `CSPViolation`  | `script-src ha bloccato https://tracker.example.com/pixel.js` | `contexts.csp` = `{ blocked_uri, effective_directive, disposition, … }` |\n\n**Gli URL viaggiano sempre senza query string** (può portare token di firma delle CDN, e per sapere\nquale risorsa manca non serve), indipendentemente da `sendPii`.\n\n**Throttle.** Massimo **10 segnalazioni per caricamento pagina e per famiglia** (risorse e CSP hanno\ntetti distinti: una CDN giù non deve nascondere una policy che blocca, sono due problemi diversi), e\nla stessa risorsa che continua a fallire vale una segnalazione sola. Vale il campionamento\n`sampleRate` degli altri eventi; `excludedExceptions: ['ResourceError']` (o `'CSPViolation'`) spegne\nuna sola famiglia.\n\nDelle immagini responsive viene segnalato il file che il browser ha davvero scelto (`currentSrc`):\ncon `srcset` l'attributo `src` può essere assente o indicare un'altra variante.\n\n## Pageview tracking (web analytics, opt-in)\n\nCon `trackPageviews: true` l'SDK invia un pageview a `POST /api/v1/projects/{projectId}/pageviews`\nal caricamento e a ogni navigazione SPA (`pushState`/`replaceState`/`popstate`, **dedup sul\npathname**: hash change e `replaceState` sullo stesso path non contano). Sostituisce Plausible:\ncookieless, il visitatore è un hash giornaliero calcolato **server-side** — nel body viaggiano solo\n`hostname`, `pathname` (mai la query), `referrer` e le 3 chiavi UTM estratte client-side.\n\n```ts\nCloseYourIt.init({\n  endpointUrl: 'https://www.closeyour.it',\n  publicKey: '…', // DSN public key (browser-safe)\n  projectId: '…',\n  environment: 'production',\n  trackPageviews: true,\n})\n\n// Pageview manuale (es. virtual pageview di un wizard)\nCloseYourIt.capturePageview({ path: '/wizard/step-2' })\n```\n\nDa `<script>` CDN (siti senza bundler — versione pinnata + SRI come in [Installazione](#script-iife-senza-build-step)):\n\n```html\n<script\n  src=\"https://cdn.jsdelivr.net/npm/@bussolabs/closeyourit-js@0.2.0/dist/closeyourit.min.js\"\n  integrity=\"sha384-…\"\n  crossorigin=\"anonymous\"\n></script>\n<script>\n  CloseYourIt.init({\n    endpointUrl: '…',\n    publicKey: '…', // DSN public key (browser-safe)\n    projectId: '…',\n    trackPageviews: true,\n  })\n</script>\n```\n\nI pageview non sono campionati (`sampleRate` non si applica) e non passano da `beforeSend`.\n\n## Telemetria d'uso (server-only, opt-in)\n\nCon `usageEnabled: true` l'SDK tiene il registro di **quali** route, job e chiavi custom vengono\ndavvero eseguiti e lo spedisce a finestre su `POST /api/v1/projects/{projectId}/usages`: una\nrichiesta ogni 5 minuti per processo, più quella finale su `close()`. Da lì la pagina d'uso del\nprogetto e la riga di comando (`cyi`) sanno cosa è vivo e cosa non viene mai chiamato — la stessa\nfunzione della gem Ruby (`CloseYourIt.used`).\n\n> **Solo lato server, e solo col `token`.** Il canale è autenticato col **bearer segreto**: nel\n> browser non è mai eleggibile, e anche su Node non lo è se si è configurata la sola `publicKey`. In\n> entrambi i casi il registro resta spento e `init` lo dice con un `console.warn`, invece di lasciare\n> la pagina d'uso vuota senza spiegazione. Va acceso nel processo Node — SSR, API, worker — passando\n> `token`.\n\n```ts\nCloseYourIt.init({\n  endpointUrl: 'https://www.closeyour.it',\n  token: process.env.CLOSEYOURIT_TOKEN, // bearer segreto, server-only\n  projectId: '…',\n  environment: 'production',\n  usageEnabled: true,\n})\n\n// Una chiave custom: «questo ramo viene mai preso?»\nCloseYourIt.used('checkout.fallback-manuale')\n\n// Route e job, tipizzati (aggancio per middleware e runner di code)\napp.use((req, _res, next) => {\n  CloseYourIt.recordUsage('route', `${req.method}:${req.route?.path ?? 'unknown'}`)\n  next()\n})\nCloseYourIt.recordUsage('job', 'CleanupJob')\n```\n\nLe regole del canale, condivise con la gem Ruby:\n\n- **Il simbolo è letterale, mai interpolato con dati.** Il contratto ammette solo\n  `[A-Za-z0-9_:#./-]{1,200}`: niente spazi e niente query string, quindi URL con parametri, id\n  utente e IP non possono nemmeno essere espressi. Ciò che non rispetta il formato viene scartato in\n  silenzio, senza far cadere la finestra. Per le route usa il nome dell'handler (`users#index`,\n  `GET:/users/:id`), **mai l'URL chiamato**.\n- **I conteggi sono indicativi, `last_seen_at` è portante.** Una finestra persa costa una finestra su\n  un simbolo che si rivede subito dopo; nessuna analisi confronta un conteggio col precedente.\n- **Nessun campionamento, mai.** Campionare una rotta chiamata tre volte al mese fabbricherebbe\n  proprio il falso «mai vista» che il canale esiste per evitare.\n- **Il registro si svuota a ogni finestra.** `usageMaxSymbols` (default 2000, massimo 5000) limita i\n  simboli _distinti_ di UNA finestra: oltre il tetto la finestra dichiara `truncated: true` — i\n  simboli già visti continuano a contare, i nuovi aspettano la finestra dopo — e quel flag squalifica\n  il kind lato analisi, che così non deduce «mai visto» da dati incompleti.\n- **Non passa da `beforeSend`**: non è un evento e non contiene dati utente per costruzione.\n\n## Tracing distribuito (W3C Trace Context)\n\nLo SDK legge e propaga gli header standard\n[W3C Trace Context](https://www.w3.org/TR/trace-context/) (`traceparent`/`tracestate`), così errori e\nlog CloseYourIt si correlano con un trace distribuito già esistente — senza adottare un protocollo\nproprietario. Il `trace-id` W3C (32 esadecimali) coincide con il `trace_id` interno: adottarlo è un\nmapping 1:1.\n\n**Adottare un trace in ingresso** — `continueTrace(carrier)` legge il `traceparent` dalla richiesta\nentrante (header server/SSR, un `Headers` o un getter `(name) => value`): il suo trace-id diventa il\n`trace_id` di correlazione, così ogni errore/log successivo si aggancia al trace distribuito. Header\nassente o malformato: no-op (si tiene il trace corrente).\n\n**Propagare verso valle** — `getTraceHeaders(target?)` restituisce gli header da iniettare in una\nrichiesta in uscita, **solo verso destinazioni fidate**: quelle in `tracePropagationTargets` (allowlist\ndi stringhe — match substring, stile Sentry — o RegExp) più il same-origin nel browser. Verso ogni\naltra destinazione ritorna `{}`: il trace interno e il `baggage` (potenziale PII) **non raggiungono\nhost non fidati**. Ogni chiamata genera un nuovo span-id (l'hop corrente).\n\n```ts\nimport * as CloseYourIt from '@bussolabs/closeyourit-js'\n\nCloseYourIt.init({\n  endpointUrl: 'https://www.closeyour.it',\n  publicKey: '…', // browser-safe\n  projectId: '…',\n  tracePropagationTargets: ['https://api.example.com', /\\.internal\\./],\n})\n\n// SSR/server: adotta il trace della richiesta entrante.\nCloseYourIt.continueTrace(req.headers)\n\n// Propaga verso un servizio consentito (verso altri host → {}, nessun header).\nawait fetch('https://api.example.com/orders', {\n  headers: { ...CloseYourIt.getTraceHeaders('https://api.example.com/orders') },\n})\n```\n\nNessuna iniezione automatica nelle richieste: la propagazione è **opt-in** e passa sempre\ndall'allowlist, così l'SDK non altera le richieste verso terze parti né provoca preflight CORS\nindesiderati.\n\n## Configurazione\n\n`init(options)` accetta:\n\n| Opzione                   | Tipo                              | Default          | Descrizione                                                                                                                                                                                              |\n| ------------------------- | --------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `endpointUrl`             | `string`                          | — (obbligatorio) | Base URL del backend, es. `https://www.closeyour.it` (senza path).                                                                                                                                       |\n| `token`                   | `string`                          | —                | Bearer **segreto** (`cyi_…`), `Authorization: Bearer`. **SERVER-ONLY**: Node/SSR, mai nel bundle browser.                                                                                                |\n| `publicKey`               | `string`                          | —                | **DSN public key** (hex, non segreta): credenziale **browser-safe** via `?sentry_key=`.                                                                                                                  |\n| `projectId`               | `string`                          | — (obbligatorio) | UUID del progetto su CloseYourIt.                                                                                                                                                                        |\n| `environment`             | `string`                          | `'production'`   | Nome ambiente.                                                                                                                                                                                           |\n| `release`                 | `string`                          | auto (Node)      | Versione/release applicativa. **Auto-rilevata su Node** dal deploy (`APP_GIT_TAG`/`GIT_TAG` semver, poi `KAMAL_VERSION`/`GIT_SHA`) se non passata; nel browser va passata esplicita (build-time inject). |\n| `sampleRate`              | `number`                          | `1.0`            | Probabilità di invio di errori/messaggi. Le metriche non sono mai campionate.                                                                                                                            |\n| `sendPii`                 | `boolean`                         | `false`          | Con `false`: `user` ridotto a `{id}`, URL senza query, referrer strippato.                                                                                                                               |\n| `beforeSend`              | `(payload) => payload \\| null`    | —                | Hook di redazione/scarto applicato a ogni payload (errori, log, metriche).                                                                                                                               |\n| `onDiagnostic`            | `(event, details) => void`        | —                | Hook diagnostico locale (`enqueue`/`send`/`drop`/`timeout`/`shutdown`): rende visibili gli eventi scartati con il motivo. Non ricorsivo, non genera telemetria (vedi sotto).                             |\n| `excludedExceptions`      | `string[]`                        | `[]`             | Nomi di errore (`error.name`) da non inviare mai (es. `\"AbortError\"`).                                                                                                                                   |\n| `breadcrumbs`             | `boolean`                         | `true`           | Master switch dei breadcrumb automatici.                                                                                                                                                                 |\n| `autoBreadcrumbs`         | `{click,navigation,console,http}` | tutti `true`     | Interruttori granulari dei breadcrumb.                                                                                                                                                                   |\n| `maxBreadcrumbs`          | `number`                          | `50`             | Capienza del ring buffer dei breadcrumb.                                                                                                                                                                 |\n| `captureRequest`          | `boolean`                         | `true`           | Allega il contesto `request` (URL pagina, User-Agent, referrer) agli eventi (browser).                                                                                                                   |\n| `logsEnabled`             | `boolean`                         | `true`           | Invio dei log strutturati.                                                                                                                                                                               |\n| `logsSampleRate`          | `number`                          | `1.0`            | Sampling dei log, indipendente da `sampleRate`.                                                                                                                                                          |\n| `logsBatchSize`           | `number`                          | `50`             | Log accumulati che forzano il flush del batch.                                                                                                                                                           |\n| `logsFlushIntervalMs`     | `number`                          | `5000`           | Flush periodico dei log.                                                                                                                                                                                 |\n| `logsMinLevel`            | `LogLevel`                        | `'info'`         | Livello minimo inviato (sotto soglia scartati client-side).                                                                                                                                              |\n| `slowMethodThresholdMs`   | `number`                          | `200`            | Soglia oltre cui `measure()` invia la metrica `slow_method`.                                                                                                                                             |\n| `captureMethodArguments`  | `boolean`                         | `false`          | Invia gli argomenti passati a `measure(..., { args })` (scrubati, troncati).                                                                                                                             |\n| `detectPerformanceIssues` | `boolean`                         | `false`          | Master switch dei verdetti performance.                                                                                                                                                                  |\n| `captureExternalHttp`     | `boolean`                         | `true`           | Rileva le HTTP esterne (effettivo solo col detect attivo).                                                                                                                                               |\n| `slowExternalThresholdMs` | `number`                          | `1000`           | Soglia HTTP esterna lenta: marca il breadcrumb e (col detect) emette il verdetto. `0` disattiva.                                                                                                         |\n| `repeatedHttpThreshold`   | `number`                          | `5`              | Richieste identiche nella finestra che emettono `repeated_http`.                                                                                                                                         |\n| `repeatedHttpWindowMs`    | `number`                          | `5000`           | Ampiezza della finestra `repeated_http`.                                                                                                                                                                 |\n| `detectJank`              | `boolean`                         | `true`           | Long task del main thread (effettivo solo col detect attivo).                                                                                                                                            |\n| `jankThresholdMs`         | `number`                          | `100`            | Durata di un long task oltre cui emettere `jank`.                                                                                                                                                        |\n| `trackWebVitals`          | `boolean`                         | `false`          | Raccoglie LCP/CLS/INP/TTFB/FCP dal browser dei visitatori e li invia a `…/web_vitals` all'uscita di pagina. Vedi «Web Vitals».                                                                           |\n| `webVitalsSampleRate`     | `number`                          | `1.0`            | Sampling delle misure Web Vitals, indipendente da `sampleRate`. Decide sul caricamento intero.                                                                                                           |\n| `captureResourceErrors`   | `boolean`                         | `false`          | Segnala risorse che non caricano e violazioni CSP come eventi `warning`. URL sempre senza query, max 10 per pagina.                                                                                      |\n| `usageEnabled`            | `boolean`                         | `false`          | Telemetria d'uso: registra quali route/job/chiavi girano davvero e le invia a `…/usages`. **Server-only** (canale a bearer): nel browser resta spenta con `console.warn`. Vedi «Telemetria d'uso».       |\n| `usageFlushIntervalMs`    | `number`                          | `300000`         | Intervallo tra due finestre di telemetria d'uso (5 minuti). Una finestra parte solo se ha visto qualcosa.                                                                                                |\n| `usageMaxSymbols`         | `number`                          | `2000`           | Simboli **distinti** per finestra (massimo 5000, il limite del backend). Oltre il tetto la finestra dichiara `truncated`.                                                                                |\n| `tracePropagationTargets` | `(string \\| RegExp)[]`            | `[]`             | Allowlist delle destinazioni verso cui `getTraceHeaders(target)` propaga il trace W3C. Nel browser il same-origin è sempre fidato. Vedi «Tracing distribuito».                                           |\n| `maxQueue`                | `number`                          | `30`             | Invii HTTP in volo prima di scartare (fire-and-forget, mai backpressure).                                                                                                                                |\n| `autoInstall`             | `boolean`                         | `true`           | Installa le integrazioni della piattaforma. Disattivabile per test/setup custom.                                                                                                                         |\n| `debug`                   | `boolean`                         | `false`          | Log diagnostici interni su console.                                                                                                                                                                      |\n| `enabled`                 | `boolean`                         | `true`           | Master switch: con `false` l'SDK è interamente no-op.                                                                                                                                                    |\n\nServono sempre `endpointUrl` e `projectId`, più **una credenziale valida per l'ambiente**: `token`\n(bearer segreto) lato server, `publicKey` (DSN public key) nel browser. Se manca (o `enabled: false`),\nl'SDK **resta no-op senza sollevare**: tutte le chiamate sono innocue. Nel browser, passare **solo** il\nbearer segreto lascia l'SDK no-op (con `console.warn`) — non lo espone mai. Una `init` valida\nsuccessiva subentra a una configurazione incompleta. Ripetere `init` con **opzioni diverse\nriconfigura l'SDK a caldo**: il client precedente viene chiuso e svuotato in sicurezza (gli eventi\ngià in coda partono verso la vecchia configurazione) e la nuova entra subito in uso — con opzioni\nequivalenti resta un no-op idempotente e non serve più un `close()` manuale.\n\n> **Usa l'endpoint canonico `www`.** `https://www.closeyour.it` risponde direttamente all'ingest;\n> l'apex (`https://closeyour.it`) fa `301 → www` e, per un `POST`, il browser può degradare la\n> richiesta a `GET` perdendo il body. Su Node l'SDK segue da solo fino a 2 redirect preservando il\n> POST (solo verso lo stesso host o la variante `www`); nel browser punta sempre al `www`.\n\n## Ricette framework\n\n### Nuxt 3 (client + server)\n\n```ts\n// plugins/closeyourit.client.ts — errori del browser\nimport * as CloseYourIt from '@bussolabs/closeyourit-js'\n\nexport default defineNuxtPlugin(() => {\n  const config = useRuntimeConfig()\n  CloseYourIt.init({\n    endpointUrl: 'https://www.closeyour.it',\n    publicKey: config.public.closeyouritPublicKey, // public config: browser-safe\n    projectId: config.public.closeyouritProjectId,\n    environment: config.public.appEnv,\n    release: config.public.appVersion,\n  })\n})\n```\n\n```ts\n// server/plugins/closeyourit.ts — errori SSR/Nitro\nimport * as CloseYourIt from '@bussolabs/closeyourit-js'\n\nexport default defineNitroPlugin((nitroApp) => {\n  const client = CloseYourIt.init({\n    endpointUrl: 'https://www.closeyour.it',\n    token: process.env.CLOSEYOURIT_TOKEN!,\n    projectId: process.env.CLOSEYOURIT_PROJECT_ID!,\n    environment: process.env.NODE_ENV ?? 'production',\n  })\n\n  // withScope isola il request context sul flusso corrente: con richieste\n  // concorrenti i dati di una non finiscono nell'errore di un'altra.\n  nitroApp.hooks.hook('error', (error, { event }) => {\n    client.withScope((scope) => {\n      if (event) scope.setRequest({ url: event.path, method: event.method })\n      CloseYourIt.captureException(error, { handled: true })\n    })\n  })\n})\n```\n\nNel browser (`closeyourit.client.ts`) usa la **`publicKey`** (DSN public key, non segreta): è\n**browser-safe**, quindi va nella `runtimeConfig.public` (esposta al client). Il **bearer segreto\n`token`** vive **solo** nel plugin server (`server/plugins/closeyourit.ts`, `process.env` mai\n`public`): è SERVER-ONLY e non deve mai finire nel bundle browser né raggiungere il client.\n\nNel plugin **server** la `release` può essere omessa: su Node l'SDK la **auto-rileva** dal deploy\n(tag semver `APP_GIT_TAG`/`GIT_TAG`, poi `KAMAL_VERSION`/`GIT_SHA` come fallback — la stessa catena\ntag-first della gem Ruby). Nel **browser** non c'è auto-detect: passa `release` esplicita (build-time inject,\nes. `config.public.appVersion`). Passarla comunque su Node ha sempre la precedenza sull'auto-detect.\n\n### Angular (ErrorHandler)\n\n```ts\n// closeyourit.error-handler.ts\nimport { ErrorHandler, Injectable } from '@angular/core'\nimport * as CloseYourIt from '@bussolabs/closeyourit-js'\n\n@Injectable()\nexport class CloseYourItErrorHandler implements ErrorHandler {\n  handleError(error: unknown): void {\n    CloseYourIt.captureException(error, { handled: false })\n    console.error(error)\n  }\n}\n\n// app.config.ts\nimport { ApplicationConfig } from '@angular/core'\nimport * as CloseYourIt from '@bussolabs/closeyourit-js'\n\nCloseYourIt.init({\n  endpointUrl: 'https://www.closeyour.it',\n  publicKey: environment.closeyouritPublicKey, // DSN public key (browser-safe)\n  projectId: environment.closeyouritProjectId,\n  environment: environment.production ? 'production' : 'development',\n})\n\nexport const appConfig: ApplicationConfig = {\n  providers: [{ provide: ErrorHandler, useClass: CloseYourItErrorHandler }],\n}\n```\n\nAngular inghiotte gli errori di zona prima che arrivino a `window.onerror`: l'`ErrorHandler` è il\npunto giusto. I gestori globali dell'SDK restano utili per gli errori fuori da Angular.\n\n## Privacy e PII\n\nTre livelli di difesa prima dell'invio:\n\n- **Policy `sendPii` (default off)**: `user` viaggia ridotto a `{id}` (email & co. non partono\n  proprio), gli URL sono privati di query string, il referrer è strippato. Con `sendPii: true`\n  dichiari esplicitamente l'intento di inviare l'utente intero e gli URL completi.\n- **Scrubbing automatico**: i valori le cui chiavi combaciano con la denylist sensibile\n  (`pass`, `secret`, `token`, `api_key`, `authorization`, `cookie`, `csrf`, `credit`, `card`,\n  `cvv`, `ssn`, `iban`, `email`) vengono sostituiti con `[FILTERED]` in modo ricorsivo, in tutto\n  ciò che viene serializzato (tag, extra, context, attributi dei log, `data` dei breadcrumb,\n  argomenti di `measure`). Le assegnazioni `chiave_sensibile=valore` dentro ai messaggi di errore\n  sono redatte anch'esse, e un header di accesso scritto per esteso (`Authorization: Bearer …`,\n  `Cookie: …`, `X-Api-Key: …`) perde l'intero valore fino a fine riga tenendo il proprio nome —\n  `Authorization: [FILTERED]`, la stessa forma del backend, che è l'autorità PII. La denylist è un\n  superset di quella del backend (aggiunge `email`); il backend ri-scruba comunque.\n- **`beforeSend`**: hook finale sotto il tuo controllo — muta il payload o ritorna `null` per\n  scartarlo del tutto. Vale per errori, messaggi, log e metriche.\n\n### Session replay: cosa viene mascherato\n\nIl replay parte già mascherato, e copre sia quello che l'utente digita sia quello che la pagina\ngli mostra — in un gestionale i dati sensibili sono soprattutto i secondi (nomi di clienti,\npratiche, importi):\n\n| Opzione                  | Default | Effetto                                                                                         |\n| ------------------------ | ------- | ----------------------------------------------------------------------------------------------- |\n| `replayMaskAllInputs`    | `true`  | Maschera il contenuto di tutti i campi da compilare.                                            |\n| `replayMaskTextSelector` | `'*'`   | Maschera il testo di **tutti** gli elementi: `*` è il selettore rrweb che li fa matchare tutti. |\n| `replayBlockSelector`    | —       | Esclude dalla registrazione gli elementi che combaciano: non vengono proprio catturati.         |\n\n**Mostrare qualcosa in chiaro è un opt-out esplicito**: si passa un selettore più stretto, che\nrestringe il masking a quei soli elementi. Chi imposta `replayMaskTextSelector: '.riservato'`\nmaschera solo quella parte e lascia in chiaro tutto il resto — è una scelta da fare in modo\nconsapevole, non un default che si subisce.\n\nLe registrazioni non sono correggibili a posteriori: un dato registrato in chiaro si toglie solo\ncancellando la registrazione. Per questo il default è il più stretto.\n\nLo `User-Agent` custom viaggia solo su Node (nel browser è un forbidden header e allargherebbe la\npreflight CORS).\n\n## Contratto wire\n\n`POST` con `Content-Type: application/json`. L'**autenticazione dipende dall'ambiente**:\n\n- **Server (Node/SSR)** — `Authorization: Bearer <token>` (bearer segreto) sui path `/api/v1/projects/*`.\n- **Browser** — DSN public key via `?sentry_key=<publicKey>` (nessun header di auth). Gli\n  **errori/messaggi** vanno al drop-in Sentry `POST {endpointUrl}/api/{projectId}/store` (stesso\n  payload evento); gli altri canali usano gli stessi path `/api/v1/projects/*` con `?sentry_key=`.\n\n| Cosa              | Endpoint (server, bearer)                                   | Payload                                     |\n| ----------------- | ----------------------------------------------------------- | ------------------------------------------- |\n| Errori / messaggi | `POST {endpointUrl}/api/v1/projects/{projectId}/events`     | oggetto evento (formato Sentry)             |\n| Metriche          | `POST {endpointUrl}/api/v1/projects/{projectId}/metrics`    | `kind: slow_method \\| performance_issue`    |\n| Log               | `POST {endpointUrl}/api/v1/projects/{projectId}/logs`       | array di voci (chunk ≤ 1000 per richiesta)  |\n| Web Vitals        | `POST {endpointUrl}/api/v1/projects/{projectId}/web_vitals` | array di misure (`metric`, `value`, pagina) |\n| Telemetria d'uso  | `POST {endpointUrl}/api/v1/projects/{projectId}/usages`     | finestra di simboli visti (**solo bearer**) |\n\nNel browser gli errori/messaggi passano invece dal drop-in Sentry\n`POST {endpointUrl}/api/{projectId}/store`. Campi `snake_case`, formato Sentry (`event_id`,\n`exception.values[]`, `contexts`, `sdk`, `trace_id`). Il backend risponde `2xx`. Nel browser gli invii\nusano `fetch(keepalive: true)` (sotto la quota di 64 KB); il transport non solleva mai e non fa retry\nloop. Per la visibilità degli eventi scartati (`getStats()` e `onDiagnostic`) vedi **Diagnostica\nlocale**.\n\n**Scheda che si chiude.** Da `pagehide`/`visibilitychange(hidden)` in poi l'invio browser passa da\n`navigator.sendBeacon`: `fetch(keepalive)` non sopravvive alla chiusura della scheda su Safari iOS e\nl'ultima misura resterebbe a terra. Il beacon vale solo in modalità **DSN public key** (non potendo\nimpostare header, con il bearer partirebbe senza credenziale) e manda il body come\n`Content-Type: text/plain` — con `application/json` non sarebbe una richiesta CORS-simple e\nscatenerebbe una preflight a cui un invio in chiusura pagina non sopravvive; il body resta il\nmedesimo JSON, che il backend parsa dalla richiesta grezza. Dove il beacon manca, o rifiuta il\npayload perché la quota per-origin è esaurita, l'invio ripiega su `fetch(keepalive)`. Il beacon non\nrestituisce una risposta: quegli invii contano come `sent` (presi in carico dal browser) e il loro\nevento diagnostico `send` non porta uno `status`, che arriva comunque **dopo** l'`enqueue` come nel\nramo `fetch`. Al ritorno in primo piano (`pageshow` da bfcache) si torna al `fetch`, la cui risposta\nè ciò su cui si regge la diagnostica.\n\nLe richieste **già partite** col `fetch` quando la pagina si chiude non vengono rispedite col beacon:\nle duplicherebbe ogni volta che il `fetch` arriva comunque, e un dato contato due volte è un danno\ncerto contro una perdita solo possibile. Su quelle vale `keepalive`, per quel che può.\n\n> **CORS**: l'ingest di CloseYourIt espone CORS sugli endpoint `/api/v1/projects/*` e sul drop-in\n> Sentry `/api/:id/{store,envelope}` (`Authorization` + `Content-Type`, `POST`/`OPTIONS`). Nessun\n> cookie/credenziale di sessione è coinvolto: l'auth è il **Bearer** (server) o la **DSN public key**\n> in query `?sentry_key=` (browser). La public key **non è segreta** — la query non allarga la\n> preflight (solo `Content-Type`); l'abuso dal browser è mitigato lato backend da rate limit e\n> allowlist di Origin, non dalla segretezza della chiave. Gli stessi endpoint accettano anche un body\n> `text/plain` con dentro il medesimo JSON: è la forma che usa il beacon di chiusura pagina, l'unica\n> che non scatena una preflight.\n\n## Diagnostica locale\n\nIl transport è fire-and-forget: un evento può non partire senza che l'applicazione se ne accorga (coda\npiena, `beforeSend` che lo scarta, timeout, `4xx`/`5xx`, rete assente). Due strumenti **process-local**\nlo rendono visibile senza generare nuova telemetria.\n\n`getStats()` ritorna lo snapshot dei contatori: gli aggregati più la ripartizione `reasons` per motivo.\n\n```ts\nCloseYourIt.getStats()\n// {\n//   enqueued: 12, sent: 10, dropped: 2, failed: 2, timeout: 1,\n//   reasons: { sample_rate: 0, before_send: 1, error: 0, queue_full: 1, response: 1, network: 0 }\n// }\n```\n\n`dropped` è la somma dei motivi di scarto client-side (`sample_rate`, `before_send`, `error`,\n`queue_full`); `failed` la somma dei fallimenti d'invio (`response`, `network`) **più** i `timeout`\n(contati anche nell'aggregato `timeout`). `enqueued` conta gli invii accettati in coda — che poi\ndiventano `sent` o `failed`. Nell'esempio: 12 accodati → 10 spediti, 1 rifiutato (`response`) e 1 in\n`timeout`; a parte, 1 scartato da `before_send` e 1 da coda piena.\n\n`onDiagnostic(event, details)` (opzione di `init`) riceve ogni tappa del ciclo di vita di un evento in\ntempo reale:\n\n```ts\nCloseYourIt.init({\n  // …\n  onDiagnostic: (event, details) => {\n    // event: 'enqueue' | 'send' | 'drop' | 'timeout' | 'shutdown'\n    // details: { reason?, status?, error?, path?, batch?, stats? }\n    if (event === 'drop') console.warn('[telemetria] evento scartato:', details.reason)\n  },\n})\n```\n\n| `event`    | quando                                   | `details`                                                   |\n| ---------- | ---------------------------------------- | ----------------------------------------------------------- |\n| `enqueue`  | evento accodato al transport             | `path`, `batch` (per i log)                                 |\n| `send`     | risposta `2xx`                           | `status`                                                    |\n| `drop`     | evento scartato o rifiutato              | `reason` (+ `status` per `response`, `error` per `network`) |\n| `timeout`  | timeout di rete (sotto-conteggio failed) | `error` (nome classe)                                       |\n| `shutdown` | `close()` del client                     | `stats` (snapshot finale)                                   |\n\nI `reason` di `drop`: `sample_rate` (campionamento), `before_send` (hook che ritorna `null`), `error`\n(hook che solleva), `queue_full` (coda piena), `response` (`4xx`/`429`/`5xx`, vedi `status`), `network`\n(errore di rete o `fetch` assente).\n\nL'hook è **non ricorsivo**: mentre è in esecuzione le API di cattura sono no-op e un ulteriore evento\ndiagnostico è soppresso, così consultare la diagnostica non genera mai nuovi eventi CloseYourIt. I\n`details` contengono solo metadati (mai payload, header o segreti): `error` è il **nome** della classe\nd'errore, mai il messaggio. Un'eccezione sollevata dall'hook viene assorbita.\n\n## Budget e truncation\n\nIl servizio rifiuta con `413` i payload troppo grandi (contratto condiviso: envelope decompresso ≤ 5\nMB, compresso ≤ 1 MB; batch log ≤ 1000, replay ≤ 50 chunk). Senza un budget lato client un evento con\nbreadcrumb/contesti enormi, un batch di log o un chunk di replay verrebbe **perso interamente**. Prima\ndi ogni invio l'SDK misura i **byte UTF-8** del payload serializzato (non i caratteri: un emoji è 1\ncarattere ma 4 byte) e, se supera il budget conservativo per canale (`512 KiB` per richiesta,\nampiamente sotto i limiti del servizio e di un gateway trusted), lo **riduce** invece di perderlo. Il\npayload ridotto porta `truncated: true`.\n\nLa riduzione toglie **prima i contenuti meno importanti**, preservando identità ed errore principale:\n\n| Canale            | Strategia di truncation                                                                                                                                                                                                                                                         |\n| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Errori / messaggi | Droppa in ordine: breadcrumb (i più vecchi) → `request` → contexts custom (tiene `runtime`/`os`/`app`/`device`/`replay`) → `extra` → `tags` → frame dello stacktrace → infine tronca il `value` dell'errore. `event_id`, `level`, `timestamp`, `exception.type` restano sempre. |\n| Log               | Ogni log troppo grande perde prima gli `attributes`, poi il `message` è troncato; il batch è spezzato in più richieste sotto budget e sotto il cap di conteggio, **senza perdere nessuna voce**.                                                                                |\n| Replay            | Droppa gli eventi rrweb dalla coda tenendo il prefisso in ordine (timeline continua dall'inizio); `replay_session_id`/`seq`/`started_at` restano.                                                                                                                               |\n| Metriche/pageview | Campi già piccoli a monte; una rete generica tronca comunque `label`/`url`/`route`/`path`/`referrer`/`utm` e rimuove i valori custom (anche quelli iniettati da `beforeSend`) se il payload sfora il budget.                                                                    |\n\n## Dimensione bundle\n\n| Output          | File                      | Dimensione                                         |\n| --------------- | ------------------------- | -------------------------------------------------- |\n| IIFE minificato | `dist/closeyourit.min.js` | **~20 KB gzip, ~18 KB brotli** (tetto in CI)       |\n| ESM             | `dist/index.mjs`          | per bundler (tree-shakeable, `sideEffects: false`) |\n| CJS             | `dist/index.js`           | per ambienti CommonJS                              |\n| Tipi            | `dist/index.d.ts`         | TypeScript                                         |\n\n## Sviluppo\n\nToolchain pinnata con [mise](https://mise.jdx.dev) (`mise.toml`): Node 24 + pnpm 11.\n\n```bash\nmise install\nmise exec -- pnpm install\nmise exec -- pnpm format:check # prettier (gate anche in CI)\nmise exec -- pnpm lint         # tsc --noEmit (strict)\nmise exec -- pnpm build        # tsup -> dist/ (ESM + CJS + IIFE + tipi)\nmise exec -- pnpm size         # peso del bundle browser contro bundle-budget.json (dopo build)\nmise exec -- pnpm test         # vitest (jsdom + node), con gate coverage\nmise exec -- pnpm smoke        # npm pack + smoke del pacchetto (ESM/CJS/browser/tipi)\n```\n\nI test girano in jsdom (browser) e in ambiente node (`*.node.test.ts`) con `fetch` mockato; la\ncoverage v8 su `src/**` ha un gate (linee/statement/funzioni ≥ 90 %, branch ≥ 85 %) — le soglie\nsono un ratchet, si alzano soltanto.\n\n### Verifica del pacchetto pubblicato\n\nLa suite esercita `src/**`; non basta a garantire che l'**archivio npm** sia consumabile. Lo smoke\n(`scripts/smoke-package.mjs`, script `pnpm smoke`) prova il pacchetto come un consumatore reale:\n`npm pack`, install in un progetto **pulito** (nessuna dependency oltre al tarball), poi `require`\n**CommonJS**, `import` **ESM**, load del bundle **browser** (IIFE, globale `CloseYourIt`) e\nrisoluzione dei **tipi** (`tsc --moduleResolution nodenext`); verifica inoltre che il tarball non\ncontenga sorgenti o test e che nessun target dichiarato (`main`/`module`/`types`/`exports`/CDN)\npunti a un file mancante. In CI il **consumo** (require/import/browser) viene eseguito sul Node\n**20.16** (minimo di `engines`) e su quello corrente — mentre build, pack e type-check restano sulla\ntoolchain pinnata (pnpm richiede Node ≥22.13); il binario del Node target si passa via\n`SMOKE_CONSUMER_NODE`. Se il pacchetto costruito non è consumabile, la **release è bloccata**\n(`publish` dipende da questo gate). Il contratto statico del manifest è blindato anche dalla suite\n(`test/packageManifest.node.test.ts`).\n\n## Licenza\n\n[MIT](./LICENSE) © 2026 Alessio Bussolari\n","readmeFilename":"README.md"}