{"_id":"ssignal","_rev":"36-c08c4dd4c9da240fbe6074399021f110","name":"ssignal","dist-tags":{"latest":"1.9.1"},"versions":{"1.0.0":{"name":"ssignal","version":"1.0.0","keywords":["signal","ssignal","keyword"],"author":{"name":"Ivan","email":"pilmee@gmail.com"},"license":"MIT","_id":"ssignal@1.0.0","maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"homepage":"https://github.com/ElJijuna/ssignal","bugs":{"url":"https://github.com/ElJijuna/ssignal/issues"},"dist":{"shasum":"f67016744f06452beb9486ab71c6d853b49184af","tarball":"https://registry.npmjs.org/ssignal/-/ssignal-1.0.0.tgz","fileCount":10,"integrity":"sha512-c616Ab+qDIcrKfKU7YiWGDTJ4Y63DREG0y/igVeAkd+uT9OgSsApAcluvsjl4nGbxE3C3xOUTBnnCalyCmvAng==","signatures":[{"sig":"MEUCIQC15RSCHIcNwwUa/5UnXp+qj661mT0x0HehCjsAC/AmFQIgGD/2ONpxM5zOIoDnRqg5PFsDLfYDR8Uoq7v3g5+3RYs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":6717},"main":"lib/index.js","type":"module","types":"lib/index.d.ts","engines":{"node":">=12.20"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/index.js","require":"./lib/index.js"},"./ssingal":{"types":"./lib/ssignal.d.ts","import":"./lib/ssignal.js","require":"./lib/ssignal.js"}},"gitHead":"9f55ead281f8632c4e3f77f06396de518d99b0e6","scripts":{"test":"jest","build":"tsc","test:coverage":"jest --coverage"},"_npmUser":{"name":"pilmee","email":"pilmee@gmail.com"},"repository":{"url":"git+https://github.com/ElJijuna/ssignal.git","type":"git"},"_npmVersion":"10.9.3","description":"Signal Pattern","directories":{},"_nodeVersion":"22.18.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","ts-jest":"^29.4.4","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.5.2"},"_npmOperationalInternal":{"tmp":"tmp/ssignal_1.0.0_1759273857767_0.24369203580056098","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"ssignal","version":"1.0.1","keywords":["signal","ssignal","keyword"],"author":{"name":"Ivan","email":"pilmee@gmail.com"},"license":"MIT","_id":"ssignal@1.0.1","maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"homepage":"https://github.com/ElJijuna/ssignal","bugs":{"url":"https://github.com/ElJijuna/ssignal/issues"},"dist":{"shasum":"6933e456ddc99b49a1c4db3e2caeaca27c78f049","tarball":"https://registry.npmjs.org/ssignal/-/ssignal-1.0.1.tgz","fileCount":10,"integrity":"sha512-GrQke/aiXKQNvfh51fLC02CCRldauS+mibSCy6RfhI5XQF9Dmj/3S6Qlm8tq9IKsRhQVu4NFvLLoIg1D58f8JQ==","signatures":[{"sig":"MEUCIQDcyihKv2noOYy9OKU7tV/lC19Y6QlcQYYlEN4rgRO50QIgAr+7VPiU60GrkqR7wAQYqcHnbncwimVF2DKyPpLMeR0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":6868},"main":"lib/index.js","type":"module","types":"lib/index.d.ts","engines":{"node":">=12.20"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/index.js","require":"./lib/index.js"},"./ssingal":{"types":"./lib/ssignal.d.ts","import":"./lib/ssignal.js","require":"./lib/ssignal.js"}},"gitHead":"1770fbb2acd33080a1e57a31528ce3a40865dde0","scripts":{"test":"jest","build":"tsc","test:coverage":"jest --coverage"},"_npmUser":{"name":"pilmee","email":"pilmee@gmail.com"},"repository":{"url":"git+https://github.com/ElJijuna/ssignal.git","type":"git"},"_npmVersion":"10.9.3","description":"Signal Pattern","directories":{},"_nodeVersion":"22.18.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","ts-jest":"^29.4.4","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.5.2"},"_npmOperationalInternal":{"tmp":"tmp/ssignal_1.0.1_1759274591625_0.4847887924162524","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"ssignal","version":"1.0.2","keywords":["signal","ssignal","keyword"],"author":{"name":"Ivan","email":"pilmee@gmail.com"},"license":"MIT","_id":"ssignal@1.0.2","maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"homepage":"https://github.com/ElJijuna/ssignal","bugs":{"url":"https://github.com/ElJijuna/ssignal/issues"},"dist":{"shasum":"2341ceff5b37237b6c47e874be12a07d486f4b0d","tarball":"https://registry.npmjs.org/ssignal/-/ssignal-1.0.2.tgz","fileCount":10,"integrity":"sha512-fqggGHjrmmJ6DDeAgO0iC7RwvIMUwYZfnu1POcJNk6Eyl4E1hloLmofXMyqzfePiMDCQRVeVOHv0UuZZniNO5A==","signatures":[{"sig":"MEUCICxla1Pf3xO+La30QwpKoQAS7J3HQORLRRgLkRL2sMq2AiEAjsApcn8n7bkofjMNFDEUWV0HtVvZM2jq/hphsezVboU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":7307},"main":"lib/index.js","type":"module","types":"lib/index.d.ts","engines":{"node":">=12.20"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/index.js","require":"./lib/index.js"},"./ssingal":{"types":"./lib/ssignal.d.ts","import":"./lib/ssignal.js","require":"./lib/ssignal.js"}},"gitHead":"d1ecb2d4d31dddac00fab8a5b5188c4753a8dd0a","scripts":{"test":"jest","build":"tsc","test:coverage":"jest --coverage"},"_npmUser":{"name":"pilmee","email":"pilmee@gmail.com"},"repository":{"url":"git+https://github.com/ElJijuna/ssignal.git","type":"git"},"_npmVersion":"10.9.3","description":"Signal Pattern","directories":{},"_nodeVersion":"22.18.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","ts-jest":"^29.4.4","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.5.2","jest-html-reporter":"^4.3.0","jest-test-performance":"^1.0.1","jest-slow-test-reporter":"^1.0.0","@jest-performance-reporter/core":"^2.1.3"},"_npmOperationalInternal":{"tmp":"tmp/ssignal_1.0.2_1759324951886_0.4123429742650311","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"ssignal","version":"1.1.0","keywords":["signal","ssignal","keyword"],"author":{"name":"Ivan","email":"pilmee@gmail.com"},"license":"MIT","_id":"ssignal@1.1.0","maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"homepage":"https://github.com/ElJijuna/ssignal","bugs":{"url":"https://github.com/ElJijuna/ssignal/issues"},"dist":{"shasum":"2198d34a313a4b7e80d2e06e0e31bbc6ad143953","tarball":"https://registry.npmjs.org/ssignal/-/ssignal-1.1.0.tgz","fileCount":10,"integrity":"sha512-RXJIjiNjy7EV+t2ITQUY3W1/ksw1vhIjkz12FYMcIiwvo6sbGFLsuXJcO9INsqzjiysIH4o5tu4G9M02D3nEiA==","signatures":[{"sig":"MEQCIAMrTY8NAS2eAYnZmECgOVthsKNqR86edj5UGUIHur79AiALWRgzfYPgxFyJKPqQJ2+qbt0aKMbNCVUT/BC4izq61Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":12363},"main":"lib/index.js","type":"module","types":"lib/index.d.ts","engines":{"node":">=12.20"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/index.js","require":"./lib/index.js"},"./ssingal":{"types":"./lib/ssignal.d.ts","import":"./lib/ssignal.js","require":"./lib/ssignal.js"}},"gitHead":"522d9cbaffe5e38e15623b2ef76c0b757ffe322e","scripts":{"test":"jest","build":"tsc","test:coverage":"jest --coverage"},"_npmUser":{"name":"pilmee","email":"pilmee@gmail.com"},"repository":{"url":"git+https://github.com/ElJijuna/ssignal.git","type":"git"},"_npmVersion":"10.9.3","description":"Signal Pattern","directories":{},"_nodeVersion":"22.18.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","ts-jest":"^29.4.4","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.5.2","jest-html-reporter":"^4.3.0","jest-test-performance":"^1.0.1","jest-slow-test-reporter":"^1.0.0","@jest-performance-reporter/core":"^2.1.3"},"_npmOperationalInternal":{"tmp":"tmp/ssignal_1.1.0_1759330793868_0.4324631136163095","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"ssignal","version":"1.2.0","keywords":["signal","ssignal","keyword"],"author":{"name":"Ivan","email":"pilmee@gmail.com"},"license":"MIT","_id":"ssignal@1.2.0","maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"homepage":"https://github.com/ElJijuna/ssignal","bugs":{"url":"https://github.com/ElJijuna/ssignal/issues"},"dist":{"shasum":"7a9c6d756615b4c886a4d310aa403d00c3c1c622","tarball":"https://registry.npmjs.org/ssignal/-/ssignal-1.2.0.tgz","fileCount":11,"integrity":"sha512-jKix5LUfnFRQRrLs4gPCmqopANMWnEv1cYxJIHtxgNWXVZyn8jyUF6skCgrgUmVrj4hsy8+ylL5Bs4qc9BEeEQ==","signatures":[{"sig":"MEUCIAUy7Lpbaljn0nFesp8ldHT4O3RvRo1he/RN+JUo1E2fAiEAmoUDD3Qddt843OFfQ5QlzGwpMzx7TEYSq0FqZMSYmoo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":13394},"main":"./lib/ssignal.cjs.js","type":"module","types":"./lib/ssignal.d.ts","unpkg":"./lib/ssignal.umd.js","module":"./lib/ssignal.es.js","engines":{"node":">=12.20"},"exports":{".":{"import":"./lib/ssignal.es.js","require":"./lib/ssignal.cjs.js"}},"gitHead":"25f106d1ff405916d6cd72ec89113fedb487ce80","scripts":{"test":"jest","build":"vite build","test:coverage":"jest --coverage"},"_npmUser":{"name":"pilmee","email":"pilmee@gmail.com"},"repository":{"url":"git+https://github.com/ElJijuna/ssignal.git","type":"git"},"_npmVersion":"10.9.3","description":"Signal Pattern","directories":{},"_nodeVersion":"22.18.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","vite":"^7.1.7","ts-jest":"^29.4.4","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.5.2","vite-plugin-dts":"^4.5.4","jest-html-reporter":"^4.3.0","jest-test-performance":"^1.0.1","jest-slow-test-reporter":"^1.0.0","@jest-performance-reporter/core":"^2.1.3"},"_npmOperationalInternal":{"tmp":"tmp/ssignal_1.2.0_1759344342850_0.26387180558564616","host":"s3://npm-registry-packages-npm-production"}},"1.2.1":{"name":"ssignal","version":"1.2.1","keywords":["signal","ssignal","keyword"],"author":{"name":"Ivan","email":"pilmee@gmail.com"},"license":"MIT","_id":"ssignal@1.2.1","maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"homepage":"https://github.com/ElJijuna/ssignal","bugs":{"url":"https://github.com/ElJijuna/ssignal/issues"},"dist":{"shasum":"8a80a9cc324671367470da1f9f50777ea35380de","tarball":"https://registry.npmjs.org/ssignal/-/ssignal-1.2.1.tgz","fileCount":11,"integrity":"sha512-hGrmSERJnNkKEDaXG+2+198lBA9umbkhBeIWlyu6+iQ/Az/nhwlu7ih53Q9k4T8NM84VovRXF5WAdriAjRwS2w==","signatures":[{"sig":"MEYCIQD7Uz4IR6aQgCP27iUdMuTmjqrE0XMwWZuJ8KMuxftT4AIhAOIc1NxQHzC4AKfdyrWrFm6t8hLM0P3IjlodAzzkRLBG","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":13729},"main":"./lib/ssignal.cjs.js","type":"module","types":"./lib/ssignal.d.ts","unpkg":"./lib/ssignal.umd.js","module":"./lib/ssignal.es.js","engines":{"node":">=12.20"},"exports":{".":{"import":"./lib/ssignal.es.js","require":"./lib/ssignal.cjs.js"}},"gitHead":"b6f831f82cfbf92562f9527be79380c392276383","scripts":{"test":"jest","build":"vite build","test:coverage":"jest --coverage"},"_npmUser":{"name":"pilmee","email":"pilmee@gmail.com"},"repository":{"url":"git+https://github.com/ElJijuna/ssignal.git","type":"git"},"_npmVersion":"10.9.3","description":"Signal Pattern","directories":{},"_nodeVersion":"22.18.0","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","vite":"^7.1.7","ts-jest":"^29.4.4","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.5.2","vite-plugin-dts":"^4.5.4","jest-html-reporter":"^4.3.0","jest-test-performance":"^1.0.1","jest-slow-test-reporter":"^1.0.0","@jest-performance-reporter/core":"^2.1.3"},"_npmOperationalInternal":{"tmp":"tmp/ssignal_1.2.1_1759344959313_0.930431868968832","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"ssignal","version":"1.4.0","keywords":["signal","ssignal","reactive","state-management","observable","eventtarget"],"author":{"name":"Ivan","email":"pilmee@gmail.com"},"license":"MIT","_id":"ssignal@1.4.0","maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"homepage":"https://github.com/ElJijuna/ssignal","bugs":{"url":"https://github.com/ElJijuna/ssignal/issues"},"dist":{"shasum":"28c523307c18c530d1b7bf510e3ecd62cc18b6d9","tarball":"https://registry.npmjs.org/ssignal/-/ssignal-1.4.0.tgz","fileCount":11,"integrity":"sha512-QEDwhvWYPuLxYG2rTWQG2g9AA1nUvkSSwiS1QNvS8RGfmgWicUJf/flIBQk+E1++bnjXxwEObtyPfT1MB0r6Ew==","signatures":[{"sig":"MEUCIG6DGeggKS/dw+YZXMV5Qffjcz68zcGELLhRU5yhPi+wAiEA+gLZLxmJiFPzuKfvponyg93jPAJuiDOALNbkr8tKAEA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":29256},"main":"./lib/ssignal.cjs.js","type":"module","types":"./lib/index.d.ts","unpkg":"./lib/ssignal.umd.js","module":"./lib/ssignal.es.js","engines":{"node":">=18.7.0"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/ssignal.es.js","require":"./lib/ssignal.cjs.js"}},"gitHead":"c65c9034952af7d76c96a7a238afa08300b8303d","scripts":{"test":"jest","build":"vite build","test:coverage":"jest --coverage"},"_npmUser":{"name":"pilmee","email":"pilmee@gmail.com"},"repository":{"url":"git+https://github.com/ElJijuna/ssignal.git","type":"git"},"_npmVersion":"10.9.8","description":"Lightweight zero-dependency reactive signal built on the native EventTarget API. Supports any value type, reactive Map mutations, updater functions, and AbortSignal integration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","vite":"^7.1.7","ts-jest":"^29.4.4","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.5.2","vite-plugin-dts":"^4.5.4","semantic-release":"^24.2.3","jest-html-reporter":"^4.3.0","jest-test-performance":"^1.0.1","jest-slow-test-reporter":"^1.0.0","@semantic-release/changelog":"^6.0.3","@jest-performance-reporter/core":"^2.1.3"},"_npmOperationalInternal":{"tmp":"tmp/ssignal_1.4.0_1777778227950_0.2357749621519294","host":"s3://npm-registry-packages-npm-production"}},"1.5.0":{"name":"ssignal","version":"1.5.0","keywords":["signal","ssignal","reactive","state-management","observable","eventtarget"],"author":{"name":"Ivan","email":"pilmee@gmail.com"},"license":"MIT","_id":"ssignal@1.5.0","maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"homepage":"https://github.com/ElJijuna/ssignal","bugs":{"url":"https://github.com/ElJijuna/ssignal/issues"},"dist":{"shasum":"d5050d74b0ce4c77f4566faa67d6270c84987daf","tarball":"https://registry.npmjs.org/ssignal/-/ssignal-1.5.0.tgz","fileCount":11,"integrity":"sha512-NQV89bGzmEM6CHQP/C3S38W3BqNnVCAxEVZ6IBImsif/eBIjtKoA/bMPjZrZMFlxW8EEQ8UUGJrd7+/GcARjUg==","signatures":[{"sig":"MEQCID0tW7xRdoA+gp8thiKf3hQtnCw+b9ni0KHa09fcmkp6AiBV2MzEfzgS1Z+IsbFtHnF/DlEu3UUHLSY6Pp6mDCoqkA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33419},"main":"./lib/ssignal.cjs.js","type":"module","types":"./lib/index.d.ts","unpkg":"./lib/ssignal.umd.js","module":"./lib/ssignal.es.js","engines":{"node":">=18.7.0"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/ssignal.es.js","require":"./lib/ssignal.cjs.js"}},"gitHead":"3bb8b299c796454252df549d9f705c5c2da147c6","scripts":{"test":"jest","build":"vite build","test:coverage":"jest --coverage"},"_npmUser":{"name":"pilmee","email":"pilmee@gmail.com"},"repository":{"url":"git+https://github.com/ElJijuna/ssignal.git","type":"git"},"_npmVersion":"10.9.8","description":"Lightweight zero-dependency reactive signal built on the native EventTarget API. Supports any value type, reactive Map mutations, updater functions, and AbortSignal integration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","vite":"^7.1.7","ts-jest":"^29.4.4","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.5.2","vite-plugin-dts":"^4.5.4","semantic-release":"^24.2.3","jest-html-reporter":"^4.3.0","jest-test-performance":"^1.0.1","jest-slow-test-reporter":"^1.0.0","@semantic-release/changelog":"^6.0.3","@jest-performance-reporter/core":"^2.1.3"},"_npmOperationalInternal":{"tmp":"tmp/ssignal_1.5.0_1777846422529_0.98150942518479","host":"s3://npm-registry-packages-npm-production"}},"1.6.0":{"name":"ssignal","version":"1.6.0","keywords":["signal","ssignal","reactive","state-management","observable","eventtarget"],"author":{"name":"Ivan","email":"pilmee@gmail.com"},"license":"MIT","_id":"ssignal@1.6.0","maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"homepage":"https://github.com/ElJijuna/ssignal","bugs":{"url":"https://github.com/ElJijuna/ssignal/issues"},"dist":{"shasum":"ee0e0a1434e0e20c63627a84aaabe43913c822cd","tarball":"https://registry.npmjs.org/ssignal/-/ssignal-1.6.0.tgz","fileCount":11,"integrity":"sha512-BQ2AtBiGbUCNujNB2nQVbjC9ewk47OSDbq7X5wj1/EEfJBH3vqwh4rqiIBA4lF1jlZkYW+45RySJ4DB1qmwSsw==","signatures":[{"sig":"MEQCIH/GBU+fdpw8jaljMLBCUOuKyMI48qa+o2LTeb51NOwUAiBBG/5LosvZ0QoJdbvXmIj0fAjZ7EvbtISb3UqEsqAfYg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33655},"main":"./lib/ssignal.cjs.js","type":"module","types":"./lib/index.d.ts","unpkg":"./lib/ssignal.umd.js","module":"./lib/ssignal.es.js","engines":{"node":">=18.7.0"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/ssignal.es.js","require":"./lib/ssignal.cjs.js"}},"gitHead":"9d8183a3a21ed7e7003b0f7afca5724c25602ed0","scripts":{"test":"jest","build":"vite build","test:coverage":"jest --coverage"},"_npmUser":{"name":"pilmee","email":"pilmee@gmail.com"},"repository":{"url":"git+https://github.com/ElJijuna/ssignal.git","type":"git"},"_npmVersion":"10.9.8","description":"Lightweight zero-dependency reactive signal built on the native EventTarget API. Supports any value type, reactive Map mutations, updater functions, and AbortSignal integration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","vite":"^7.1.7","ts-jest":"^29.4.4","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.5.2","vite-plugin-dts":"^4.5.4","semantic-release":"^24.2.3","jest-html-reporter":"^4.3.0","jest-test-performance":"^1.0.1","jest-slow-test-reporter":"^1.0.0","@semantic-release/changelog":"^6.0.3","@jest-performance-reporter/core":"^2.1.3"},"_npmOperationalInternal":{"tmp":"tmp/ssignal_1.6.0_1777906442089_0.9969231432568264","host":"s3://npm-registry-packages-npm-production"}},"1.7.0":{"name":"ssignal","version":"1.7.0","keywords":["signal","ssignal","reactive","state-management","observable","eventtarget"],"author":{"name":"Ivan","email":"pilmee@gmail.com"},"license":"MIT","_id":"ssignal@1.7.0","maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"homepage":"https://github.com/ElJijuna/ssignal","bugs":{"url":"https://github.com/ElJijuna/ssignal/issues"},"dist":{"shasum":"68985c61c90aec0960e86caedb173c05146f781a","tarball":"https://registry.npmjs.org/ssignal/-/ssignal-1.7.0.tgz","fileCount":14,"integrity":"sha512-h+avX2dS8HcKGIRluMPe5NzFMgGvXUVsNKGXI26oHI6LD6lSl34h5A9Yj+IeuBoC0T/eWsI3900Mf6QbwWcO+g==","signatures":[{"sig":"MEUCIQCmvHt8UNohVqQv6VJmuipMgNzeQdvjKrul2sjNdr8H7QIgPnFSHQe/6wkfWu0CNQBJuztR6g5p7659vQi5aLKEqfc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":35802},"main":"./lib/ssignal.cjs.js","type":"module","types":"./lib/index.d.ts","unpkg":"./lib/ssignal.umd.js","module":"./lib/ssignal.es.js","engines":{"node":">=18.7.0"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/ssignal.es.js","require":"./lib/ssignal.cjs.js"}},"gitHead":"a5e72b5be967174ce9be99dde6fb51b23002099a","scripts":{"lint":"eslint .","test":"jest --config jest.config.cjs","build":"vite build","check":"npm run lint && npm run format:check && npm run typecheck && npm test","format":"biome check --write .","lint:fix":"eslint . --fix","typecheck":"tsc --noEmit","format:check":"biome check .","test:coverage":"jest --config jest.config.cjs --coverage","test:performance":"jest --config jest.performance.config.cjs"},"_npmUser":{"name":"pilmee","email":"pilmee@gmail.com"},"repository":{"url":"git+https://github.com/ElJijuna/ssignal.git","type":"git"},"_npmVersion":"11.15.0","description":"Lightweight zero-dependency reactive signal built on the native EventTarget API. Supports any value type, reactive Map mutations, updater functions, and AbortSignal integration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","vite":"^8.0.14","eslint":"^9.39.4","ts-jest":"^29.4.4","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.5.2","super-configs":"^1.13.0","@biomejs/biome":"^2.4.16","vite-plugin-dts":"^5.0.1","semantic-release":"^25.0.3","jest-html-reporter":"^4.3.0","jest-test-performance":"^1.0.1","jest-slow-test-reporter":"^1.0.0","@semantic-release/changelog":"^6.0.3","@jest-performance-reporter/core":"^2.1.3"},"_npmOperationalInternal":{"tmp":"tmp/ssignal_1.7.0_1781194458365_0.5995879415129526","host":"s3://npm-registry-packages-npm-production"}},"1.7.1":{"name":"ssignal","version":"1.7.1","keywords":["signal","ssignal","reactive","state-management","observable","eventtarget"],"author":{"name":"Ivan","email":"pilmee@gmail.com"},"license":"MIT","_id":"ssignal@1.7.1","maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"homepage":"https://github.com/ElJijuna/ssignal","bugs":{"url":"https://github.com/ElJijuna/ssignal/issues"},"dist":{"shasum":"80f88d7f59347a0dbe753ce0d74455c1d80bcfa4","tarball":"https://registry.npmjs.org/ssignal/-/ssignal-1.7.1.tgz","fileCount":14,"integrity":"sha512-oB5NFDk/W46MK9BUsWCBIn+fCl0NRqqtW61Po3G43uOTehRYa4ELgbf/MCQRx8CWp4E7iuXdw5Md/xRzGUdULQ==","signatures":[{"sig":"MEUCIQDVuWtHVTU/fUzM09hYnOMCcN6pD2j+BBZJ3g8AWZd//QIgeEU8AlO9VifpMiZwtOsiSRUO5sf06XtqW5xPvX/a/RY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIB/PaKU7b4pDZt+UdN734YLTDFxoVliVYcRoLZ7Lb+cxAiBnfbnRTAXdkeSG1uTuNA28VHRAur8ZEuCKad+ZlsxMpA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":36360},"main":"./lib/ssignal.cjs","type":"module","types":"./lib/index.d.ts","unpkg":"./lib/ssignal.umd.js","module":"./lib/ssignal.es.js","engines":{"node":">=18.7.0"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/ssignal.es.js","require":"./lib/ssignal.cjs"}},"gitHead":"d5af401a0ae9c45ea1eaf20fd9e17e0c140b9775","scripts":{"lint":"eslint .","test":"jest --config jest.config.cjs","build":"vite build","check":"npm run lint && npm run format:check && npm run typecheck && npm test","format":"biome check --write .","lint:fix":"eslint . --fix","typecheck":"tsc --noEmit","format:check":"biome check .","test:coverage":"jest --config jest.config.cjs --coverage","test:performance":"jest --config jest.performance.config.cjs"},"_npmUser":{"name":"pilmee","email":"pilmee@gmail.com"},"repository":{"url":"git+https://github.com/ElJijuna/ssignal.git","type":"git"},"_npmVersion":"11.15.0","description":"Lightweight zero-dependency reactive signal built on the native EventTarget API. Supports any value type, reactive Map mutations, updater functions, and AbortSignal integration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","vite":"^8.0.14","eslint":"^9.39.4","ts-jest":"^29.4.4","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.5.2","super-configs":"^1.13.0","@biomejs/biome":"^2.4.16","vite-plugin-dts":"^5.0.1","semantic-release":"^25.0.3","jest-html-reporter":"^4.3.0","jest-test-performance":"^1.0.1","jest-slow-test-reporter":"^1.0.0","@semantic-release/changelog":"^6.0.3","@jest-performance-reporter/core":"^2.1.3"},"_npmOperationalInternal":{"tmp":"tmp/ssignal_1.7.1_1790574407198_0.31709630454139437","host":"s3://npm-registry-packages-npm-production"}},"1.8.0":{"name":"ssignal","version":"1.8.0","keywords":["signal","ssignal","reactive","state-management","observable","eventtarget"],"author":{"name":"Ivan","email":"pilmee@gmail.com"},"license":"MIT","_id":"ssignal@1.8.0","maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"homepage":"https://github.com/ElJijuna/ssignal","bugs":{"url":"https://github.com/ElJijuna/ssignal/issues"},"dist":{"shasum":"dc20ae777a5246d0571cdbbc65f1633b67148a8d","tarball":"https://registry.npmjs.org/ssignal/-/ssignal-1.8.0.tgz","fileCount":14,"integrity":"sha512-I8ay2jXkGkDrlESpqjrvvwT3cf5qqknlBrOLqK0A1UUVq40+G1LMFQmp8t2PiS6SZIaMxXmh7u8+sfT4E30aCw==","signatures":[{"sig":"MEQCIC/hlWV/efGjOGoDeZJ3T6sglcMDQkTN+YC5ZPlV6qjiAiASss7e5CtB3BfVw3szJ/gY7WzP5WO/nqsp4oRHfxCbyw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCICm3ZszpICb5axpYy7qgWWpqTquAlCVvz/Skjrq+UGkGAiAIezZhftV8xywdXGJWGfqLb4iSsDHn9Eovrlp2YNbirw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":40877},"main":"./lib/ssignal.cjs","type":"module","types":"./lib/index.d.ts","unpkg":"./lib/ssignal.umd.js","module":"./lib/ssignal.es.js","engines":{"node":">=18.7.0"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/ssignal.es.js","require":"./lib/ssignal.cjs"}},"gitHead":"1099edf9b958d540c3c4bd6f6fd83ce49016d645","scripts":{"lint":"eslint .","test":"jest --config jest.config.cjs","build":"vite build","check":"npm run lint && npm run format:check && npm run typecheck && npm test","format":"biome check --write .","lint:fix":"eslint . --fix","typecheck":"tsc --noEmit","format:check":"biome check .","test:coverage":"jest --config jest.config.cjs --coverage","test:performance":"jest --config jest.performance.config.cjs"},"_npmUser":{"name":"pilmee","email":"pilmee@gmail.com"},"repository":{"url":"git+https://github.com/ElJijuna/ssignal.git","type":"git"},"_npmVersion":"11.15.0","description":"Lightweight zero-dependency reactive signal built on the native EventTarget API. Supports any value type, reactive Map mutations, updater functions, and AbortSignal integration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","vite":"^8.0.14","eslint":"^9.39.4","ts-jest":"^29.4.4","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.5.2","super-configs":"^1.13.0","@biomejs/biome":"^2.4.16","vite-plugin-dts":"^5.0.1","semantic-release":"^25.0.3","jest-html-reporter":"^4.3.0","jest-test-performance":"^1.0.1","jest-slow-test-reporter":"^1.0.0","@semantic-release/changelog":"^6.0.3","@jest-performance-reporter/core":"^2.1.3"},"_npmOperationalInternal":{"tmp":"tmp/ssignal_1.8.0_1790576088110_0.7422703891904983","host":"s3://npm-registry-packages-npm-production"}},"1.9.0":{"name":"ssignal","version":"1.9.0","keywords":["signal","ssignal","reactive","state-management","observable","eventtarget"],"author":{"name":"Ivan","email":"pilmee@gmail.com"},"license":"MIT","_id":"ssignal@1.9.0","maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"homepage":"https://github.com/ElJijuna/ssignal","bugs":{"url":"https://github.com/ElJijuna/ssignal/issues"},"dist":{"shasum":"d3a7055d53e9460394a9d6b7d2b321e44ed841b9","tarball":"https://registry.npmjs.org/ssignal/-/ssignal-1.9.0.tgz","fileCount":15,"integrity":"sha512-q6tNDSqmjYYNA6zLpING3QJChOb/8PRDGdVEobvty3y0bsK/t1XQq2o8UozWNETRB4i5jjQ5gJbYFiSc6yRLlA==","signatures":[{"sig":"MEUCIQDtbYxvs+2HOWseK4GF7I2nNIPt7wh0GwjOTw6FJoItZgIgYBw9n8x1udOuUOBfJxwWDw5jwZe2b55AD7j5XrlxWsY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIAUVJbrfjDbuwvwqOs3nRB2OdPE7isxCS5EFusgAU4WrAiAl8V5sF5SkS1LH7jTE++IFFdZAr/vgcMcGx4kc74lZow==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":64003},"main":"./lib/ssignal.cjs","type":"module","types":"./lib/index.d.ts","unpkg":"./lib/ssignal.umd.js","module":"./lib/ssignal.es.js","engines":{"node":">=18.7.0"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/ssignal.es.js","require":"./lib/ssignal.cjs"}},"gitHead":"f6a79ca5885b471fb9dbc709dd8fff7daef940f6","scripts":{"lint":"eslint .","test":"jest --config jest.config.cjs","build":"vite build","check":"npm run lint && npm run format:check && npm run typecheck && npm test","format":"biome check --write .","lint:fix":"eslint . --fix","typecheck":"tsc --noEmit","format:check":"biome check .","test:coverage":"jest --config jest.config.cjs --coverage","test:performance":"jest --config jest.performance.config.cjs"},"_npmUser":{"name":"pilmee","email":"pilmee@gmail.com"},"repository":{"url":"git+https://github.com/ElJijuna/ssignal.git","type":"git"},"_npmVersion":"11.15.0","description":"Lightweight zero-dependency reactive signal built on the native EventTarget API. Supports any value type, reactive Map mutations, updater functions, and AbortSignal integration.","directories":{},"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","vite":"^8.0.14","eslint":"^9.39.4","ts-jest":"^29.4.4","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.5.2","super-configs":"^1.13.0","@biomejs/biome":"^2.4.16","vite-plugin-dts":"^5.0.1","semantic-release":"^25.0.3","jest-html-reporter":"^4.3.0","jest-test-performance":"^1.0.1","jest-slow-test-reporter":"^1.0.0","@semantic-release/changelog":"^6.0.3","@jest-performance-reporter/core":"^2.1.3"},"_npmOperationalInternal":{"tmp":"tmp/ssignal_1.9.0_1790659680702_0.2681270194637726","host":"s3://npm-registry-packages-npm-production"}},"1.9.1":{"_id":"ssignal@1.9.1","bugs":{"url":"https://github.com/ElJijuna/ssignal/issues"},"dist":{"shasum":"6a7a9a7fc06256bc2f64f58e6652fc435673e20a","tarball":"https://registry.npmjs.org/ssignal/-/ssignal-1.9.1.tgz","fileCount":15,"integrity":"sha512-FDBMgj/RKsorJAQhiKG+Fg7NWqMJKLYKoUUzilU8XEeN+hl5aITE7mwL606ceHZVCZ11hswshnDnPUkLX9MPpQ==","signatures":[{"sig":"MEYCIQCLzTXD2KjqRx67cS4xJg/cgyiCwCWgBvx91aJCAcYpjwIhAOhdlv1B61hLOSuNGxPMGUUme6LnMylju6G66Dw43rx/","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIA1+TN8SN3gTVjGL6X16jMZKVmVqjudhZsZtacTHzxeJAiEAiDB5OCqSZNhm5q74L3ui3NOg/xNLGREtfBK1F55PiNg="}],"unpackedSize":66183},"main":"./lib/ssignal.cjs","name":"ssignal","type":"module","types":"./lib/index.d.ts","unpkg":"./lib/ssignal.umd.js","author":{"name":"Ivan","email":"pilmee@gmail.com"},"module":"./lib/ssignal.es.js","engines":{"node":">=18.7.0"},"exports":{".":{"types":"./lib/index.d.ts","import":"./lib/ssignal.es.js","require":"./lib/ssignal.cjs"}},"gitHead":"d471a0d0b36ae4d91993a6662a62d2ed9648f203","license":"MIT","scripts":{"lint":"eslint .","test":"jest --config jest.config.cjs","build":"vite build","check":"npm run lint && npm run format:check && npm run typecheck && npm test","format":"biome check --write .","lint:fix":"eslint . --fix","typecheck":"tsc --noEmit","format:check":"biome check .","test:coverage":"jest --config jest.config.cjs --coverage","test:performance":"jest --config jest.performance.config.cjs"},"version":"1.9.1","_npmUser":{"name":"pilmee","email":"pilmee@gmail.com"},"homepage":"https://github.com/ElJijuna/ssignal","keywords":["signal","ssignal","reactive","state-management","observable","eventtarget"],"repository":{"url":"git+https://github.com/ElJijuna/ssignal.git","type":"git"},"_npmVersion":"11.15.0","description":"Lightweight zero-dependency reactive signal built on the native EventTarget API. Supports any value type, reactive Map mutations, updater functions, and AbortSignal integration.","directories":{},"maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"sideEffects":false,"_nodeVersion":"20.20.2","_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","vite":"^8.0.14","eslint":"^9.39.4","ts-jest":"^29.4.4","typescript":"^5.9.2","@types/jest":"^30.0.0","@types/node":"^24.5.2","super-configs":"^1.13.0","@biomejs/biome":"^2.4.16","vite-plugin-dts":"^5.0.1","semantic-release":"^25.0.3","jest-html-reporter":"^4.3.0","jest-test-performance":"^1.0.1","jest-slow-test-reporter":"^1.0.0","@semantic-release/changelog":"^6.0.3","@jest-performance-reporter/core":"^2.1.3"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ssignal_1.9.1_1790688934456_0.6286457444992455"}}},"time":{"created":"2025-09-30T23:10:57.766Z","modified":"2026-09-29T13:35:34.688Z","0.0.1":"2015-05-12T09:29:32.243Z","0.0.4":"2015-05-12T09:42:20.706Z","0.0.5":"2015-05-12T09:54:23.444Z","0.0.6":"2015-05-12T10:02:05.912Z","0.0.7":"2015-05-12T11:23:31.367Z","0.0.8":"2015-05-13T01:57:16.514Z","0.0.9":"2015-05-14T02:27:09.561Z","0.1.0":"2015-05-16T08:31:13.490Z","0.1.1":"2015-05-19T09:26:09.167Z","0.1.2":"2015-05-19T09:31:58.243Z","0.1.4":"2015-08-05T18:59:01.933Z","0.1.5":"2015-08-05T19:09:23.647Z","0.1.7":"2015-08-05T19:32:25.360Z","0.1.8":"2016-01-22T06:46:53.837Z","1.0.0":"2025-09-30T23:10:57.941Z","1.0.1":"2025-09-30T23:23:11.839Z","1.0.2":"2025-10-01T13:22:32.136Z","1.1.0":"2025-10-01T14:59:54.086Z","1.2.0":"2025-10-01T18:45:43.064Z","1.2.1":"2025-10-01T18:55:59.479Z","1.4.0":"2026-05-03T03:17:08.087Z","1.5.0":"2026-05-03T22:13:42.681Z","1.6.0":"2026-05-04T14:54:02.226Z","1.7.0":"2026-06-11T16:14:18.514Z","1.7.1":"2026-09-28T05:46:47.274Z","1.8.0":"2026-09-28T06:14:48.192Z","1.9.0":"2026-09-29T05:28:00.796Z","1.9.1":"2026-09-29T13:35:34.538Z"},"bugs":{"url":"https://github.com/ElJijuna/ssignal/issues"},"author":{"name":"Ivan","email":"pilmee@gmail.com"},"license":"MIT","homepage":"https://github.com/ElJijuna/ssignal","keywords":["signal","ssignal","reactive","state-management","observable","eventtarget"],"repository":{"url":"git+https://github.com/ElJijuna/ssignal.git","type":"git"},"description":"Lightweight zero-dependency reactive signal built on the native EventTarget API. Supports any value type, reactive Map mutations, updater functions, and AbortSignal integration.","maintainers":[{"name":"pilmee","email":"pilmee@gmail.com"}],"readme":"<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/ElJijuna/ssignal/main/public/assets/logo.svg\" alt=\"SSignal logo\" width=\"160\" />\n</p>\n\n# SSignal\n\n[![npm version](https://img.shields.io/npm/v/ssignal.svg)](https://www.npmjs.com/package/ssignal)\n[![npm downloads](https://img.shields.io/npm/dm/ssignal.svg)](https://www.npmjs.com/package/ssignal)\n[![CI](https://github.com/ElJijuna/ssignal/actions/workflows/ci.yml/badge.svg)](https://github.com/ElJijuna/ssignal/actions/workflows/ci.yml)\n[![Release](https://github.com/ElJijuna/ssignal/actions/workflows/release.yml/badge.svg)](https://github.com/ElJijuna/ssignal/actions/workflows/release.yml)\n[![Web Audit Report](https://github.com/ElJijuna/ssignal/actions/workflows/web-audit-report.yml/badge.svg)](https://github.com/ElJijuna/ssignal/actions/workflows/web-audit-report.yml)\n[![bundle size](https://img.shields.io/bundlephobia/minzip/ssignal)](https://bundlephobia.com/package/ssignal)\n[![License: MIT](https://img.shields.io/npm/l/ssignal)](LICENSE)\n[![Node.js](https://img.shields.io/node/v/ssignal)](https://nodejs.org)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5-blue)](https://www.typescriptlang.org)\n[![semantic-release](https://img.shields.io/badge/release-semantic--release-e10079?logo=semantic-release&logoColor=white)](https://semantic-release.gitbook.io/semantic-release/)\n[![GitHub stars](https://img.shields.io/github/stars/ElJijuna/ssignal)](https://github.com/ElJijuna/ssignal/stargazers)\n[![GitHub issues](https://img.shields.io/github/issues/ElJijuna/ssignal)](https://github.com/ElJijuna/ssignal/issues)\n\nA lightweight, zero-dependency reactive signal built on top of the native `EventTarget` API. `SSignal` lets you observe value changes on any data type — including deep mutations on `Map` instances — without a framework, build plugin, or compiler transform.\n\n## Features\n\n- **Simple API** — `value`, `subscribe`, and an unsubscribe function. That's it.\n- **Framework-agnostic** — works in the browser, Node.js ≥ 18.7, and any runtime that supports `EventTarget`.\n- **Reactive `Map` support** — mutations via `set()`, `delete()`, and `clear()` automatically dispatch change events.\n- **Updater functions** — `signal.value = (prev) => prev + 1` for safe derived updates.\n- **In-place mutations** — `signal.mutate((list) => list.push(item))` for arrays and objects, with a single change event.\n- **Immediate mode** — `{ immediate: true }` fires the callback with the current value on subscribe.\n- **One-time subscriptions** — `once()` listens for the next change only, then unsubscribes itself.\n- **Computed signals** — derive read-only signals from one or more sources with `computed()`.\n- **Effects** — `effect()` runs side effects now and on every change, with cleanup and a single dispose.\n- **Custom equality** — `{ equals }` decides when an assigned value counts as a change.\n- **Batched updates** — `batch()` groups several changes into one notification per signal.\n- **Disposable** — `dispose()` removes every subscription at once, and signals work with `using`.\n- **AbortSignal integration** — cancel subscriptions with a standard `AbortController`.\n- **TypeScript-first** — fully typed, zero `any` in the public API.\n- **Tree-shakeable** — `sideEffects: false`, ships ESM + CJS + UMD.\n\n## Installation\n\n```sh\nnpm install ssignal\n```\n\n### CDN (browser)\n\n```html\n<script src=\"https://unpkg.com/ssignal@latest/lib/ssignal.umd.js\"></script>\n```\n\n## API\n\n| Member | Description |\n| :----- | :---------- |\n| `new SSignal(value: T, options?)` | Creates a signal. `Map` values are automatically wrapped in a reactive proxy. Options: `SSignalOptions<T>`. |\n| `signal.value` | Gets the current value. |\n| `signal.value = newValue \\| (prev: T) => T` | Sets a new value. Accepts a direct value or an updater function. No event is fired when the value does not change. |\n| `signal.mutate(mutator)` | Mutates the value in place (arrays, objects…) and fires one change event afterwards. Return `false` from the mutator to skip the event. Throws on computed signals. |\n| `signal.subscribe(callback, options?)` | Registers a listener called on every change. Returns an `Unsubscribe` function. Options: `SubscribeOptions`. |\n| `signal.once(callback, options?)` | Registers a listener called only on the next change, then unsubscribes automatically. Returns an `Unsubscribe` function. Options: `OnceOptions`. With `immediate`, it runs right away with the current value instead, and that is its only call. |\n| `computed(source, fn, options?)` | Creates a read-only `ComputedSignal` derived from one source. Accepts the same `equals` option. |\n| `computed([...sources], fn, options?)` | Creates a read-only `ComputedSignal` derived from multiple sources. Accepts the same `equals` option. |\n| `signal.dispose()` | Removes every `subscribe()`/`once()` subscription at once. The signal stays usable. Also available as `[Symbol.dispose]()` for `using`. |\n| `computed.dispose()` | Removes all source subscriptions and its own subscribers. Call when the signal is no longer needed. |\n| `effect(source, fn, options?)` | Runs `fn` with the current value, then after every change. `fn` may return a cleanup, called before the next run and on dispose. Returns a dispose function. Options: `EffectOptions`. |\n| `effect([...sources], fn, options?)` | Same, with the values of several sources as a tuple. Sources changed together in `batch()` cause a single run. |\n| `batch(fn)` | Runs `fn` and defers change events until it returns, so each changed signal notifies once with its final value. Returns what `fn` returns. |\n\n### Types\n\nAll types are exported from the package entry:\n\n```ts\nimport type {\n  EffectCleanup,\n  EffectOptions,\n  OnceOptions,\n  SSignalOptions,\n  SubscribeOptions,\n  Unsubscribe,\n} from 'ssignal';\n```\n\n| Type | Definition |\n| :--- | :--------- |\n| `Unsubscribe` | `() => void` |\n| `SubscribeOptions` | `{ signal?: AbortSignal; immediate?: boolean }` |\n| `OnceOptions` | `{ signal?: AbortSignal; immediate?: boolean }` |\n| `EffectOptions` | `{ signal?: AbortSignal }` |\n| `EffectCleanup` | `() => void` |\n| `SSignalOptions<T>` | `{ equals?: (prev: T, next: T) => boolean }` |\n\n### Events\n\n| Event | Type | Description |\n| :---- | :--- | :---------- |\n| `change` | `CustomEvent<T>` | Fired when the value changes. The new value is available as `event.detail`. |\n\n## Architecture\n\n```mermaid\nflowchart TD\n  subgraph writes[\"Ways to change a signal\"]\n    set[\"signal.value = next<br/>or (prev) => next\"]\n    mutate[\"signal.mutate(fn)\"]\n    coll[\"Map / Set proxy<br/>set · add · delete · clear\"]\n  end\n\n  set --> equals{\"equals(prev, next)?<br/>default Object.is\"}\n  equals -- \"equal\" --> skip([\"ignored, no event\"])\n  equals -- \"changed\" --> notify\n  mutate -- \"unless fn returns false\" --> notify\n  coll -- \"only if it really changed\" --> notify\n\n  notify[\"#notify()\"] --> inBatch{\"inside batch()?\"}\n  inBatch -- \"yes\" --> queue[(\"batch queue<br/>one entry per signal\")]\n  queue -- \"outermost batch ends\" --> notify\n  inBatch -- \"no\" --> dispatching{\"already dispatching?\"}\n  dispatching -- \"yes\" --> pending[\"mark pending<br/>(new round after the current one)\"]\n  dispatching -- \"no\" --> dispatch[\"EventTarget.dispatchEvent<br/>CustomEvent('change')\"]\n  pending -. \"once every listener has run\" .-> dispatch\n\n  dispatch --> subscribe[\"subscribe() listeners\"]\n  dispatch --> once[\"once() listeners<br/>removed after first call\"]\n  dispatch --> sourcesChanged\n  dispatch --> changed\n\n  subgraph computed[\"ComputedSignal (read-only)\"]\n    sourcesChanged{\"new source values or<br/>in-place mutation?\"}\n    sourcesChanged -- \"no, e.g. second source<br/>of the same batch\" --> noRecompute([\"skipped\"])\n    sourcesChanged -- \"yes\" --> recompute[\"fn(...source values)\"]\n    recompute -- \"source mutated in place,<br/>same object returned\" --> notify2[\"#notify() of the computed\"]\n    recompute -- \"otherwise\" --> equals2[\"equals check of the computed\"]\n  end\n\n  subgraph effects[\"effect()\"]\n    changed{\"new values or<br/>in-place mutation?\"}\n    changed -- \"yes\" --> rerun[\"previous cleanup,<br/>then fn(values)\"]\n    changed -- \"no, e.g. second source<br/>of the same batch\" --> noRun([\"skipped\"])\n  end\n\n  subgraph teardown[\"Removing subscriptions\"]\n    disposeAll[\"signal.dispose()<br/>or end of a using block\"]\n    single[\"unsubscribe()<br/>or AbortSignal abort\"]\n  end\n\n  disposeAll -. \"removes all\" .-> subscribe\n  disposeAll -. \"removes all\" .-> once\n  single -. \"removes one\" .-> subscribe\n```\n\n- **`SSignal`** extends the native `EventTarget`. Every change ends in a single private `#notify()`, which dispatches a `change` event whose `detail` is the current value.\n- **Writes** come from three places: assignments (filtered by `equals`), `mutate()`, and the Map/Set proxy, which only notifies when the collection actually changed. Inside `mutate()`, Map/Set changes are folded into its single event.\n- **`#notify()`** queues the signal while a `batch()` is running, so it notifies once when the batch ends. If a listener changes the signal during a dispatch, the change is delivered in a follow-up round rather than a nested one, so every listener ends on the latest value.\n- **Consumers** all listen to that event: `subscribe()` and `once()` callbacks, `ComputedSignal`, and `effect()`.\n- **`ComputedSignal`** re-runs `fn` when its sources bring new values or were mutated in place, then goes through its own `equals` check, or notifies directly after an in-place mutation. It skips notifications that bring nothing new, so several sources changed in one `batch()`, or both paths of a diamond, cause a single run. Its sources reference it only through a `WeakRef`, but it stays alive while it has listeners. `dispose()` removes its source subscriptions and its own subscribers.\n- **`effect()`** runs the previous cleanup and then `fn` whenever its sources bring new values or were mutated in place, and skips notifications that bring nothing new, so several sources changed in one `batch()` cause a single run. Its dispose function stops it and runs the last cleanup.\n- **Teardown**: `unsubscribe()` or an `AbortSignal` removes one subscription, while `dispose()` (also called at the end of a `using` block) removes every `subscribe()`/`once()` subscription of a signal at once.\n\n## Usage examples\n\n### Plain function / vanilla JS\n\n```ts\nimport SSignal from 'ssignal';\n\nconst counter = new SSignal(0);\n\nconst unsubscribe = counter.subscribe((value) => {\n  console.log('counter changed:', value);\n});\n\ncounter.value = 1;              // logs: counter changed: 1\ncounter.value = (n) => n + 1;  // logs: counter changed: 2\ncounter.value = 2;              // no log — same value, no event fired\n\nunsubscribe();\ncounter.value = 99;             // no log — already unsubscribed\n```\n\n### React component\n\n```tsx\nimport { useEffect, useState } from 'react';\nimport SSignal from 'ssignal';\n\n// Create signals outside the component so they are shared across the app\nexport const themeSignal = new SSignal<'light' | 'dark'>('light');\nexport const cartSignal = new SSignal(new Map<string, number>());\n\n// Generic hook to bind any SSignal to local state\nfunction useSignal<T>(signal: SSignal<T>): T {\n  const [value, setValue] = useState<T>(signal.value);\n\n  useEffect(() => {\n    const controller = new AbortController();\n    // immediate: true keeps state in sync if the signal changes between\n    // render and the effect running\n    signal.subscribe((v) => setValue(v), { signal: controller.signal, immediate: true });\n    return () => controller.abort();\n  }, [signal]);\n\n  return value;\n}\n\nexport function ThemeToggle() {\n  const theme = useSignal(themeSignal);\n\n  return (\n    <button onClick={() => themeSignal.value = theme === 'light' ? 'dark' : 'light'}>\n      Current theme: {theme}\n    </button>\n  );\n}\n\nexport function Cart() {\n  const cart = useSignal(cartSignal);\n\n  const addItem = (id: string) => {\n    cartSignal.value.set(id, (cart.get(id) ?? 0) + 1);\n  };\n\n  return (\n    <div>\n      <p>Items in cart: {cart.size}</p>\n      <button onClick={() => addItem('product-1')}>Add product</button>\n    </div>\n  );\n}\n```\n\n### Express backend\n\n```ts\nimport express from 'express';\nimport SSignal from 'ssignal';\n\nconst app = express();\n\n// Shared application state\nconst connectedClients = new SSignal(0);\nconst featureFlags = new SSignal(new Map<string, boolean>([\n  ['new-checkout', false],\n  ['dark-mode', true],\n]));\n\n// Log every time the client count changes\nconnectedClients.subscribe((count) => {\n  console.log(`[${new Date().toISOString()}] Connected clients: ${count}`);\n});\n\napp.use((req, res, next) => {\n  connectedClients.value = (n) => n + 1;\n  res.on('finish', () => {\n    connectedClients.value = (n) => n - 1;\n  });\n  next();\n});\n\napp.get('/flags', (req, res) => {\n  res.json(Object.fromEntries(featureFlags.value));\n});\n\napp.patch('/flags/:name', express.json(), (req, res) => {\n  const { name } = req.params;\n  featureFlags.value.set(name, req.body.enabled);\n  res.sendStatus(204);\n});\n\napp.listen(3000, () => console.log('Server running on port 3000'));\n```\n\n### Reactive Map\n\n```ts\nimport SSignal from 'ssignal';\n\nconst store = new SSignal(new Map<string, number>());\n\nstore.subscribe((map) => {\n  console.log('store changed, size:', map.size);\n});\n\nstore.value.set('a', 1);    // logs: store changed, size: 1\nstore.value.set('b', 2);    // logs: store changed, size: 2\nstore.value.delete('a');    // logs: store changed, size: 1\nstore.value.clear();        // logs: store changed, size: 0\n```\n\nOnly calls made through `signal.value` are tracked. The signal wraps the collection in a proxy, so if you keep the original `Map`/`Set` you passed in and mutate it directly, no event is fired. `Set` values work the same way with `add()`, `delete()` and `clear()`.\n\n### Arrays and objects\n\nArrays and plain objects are not wrapped, so in-place changes such as `push()` or `obj.x = 1` are not detected on their own. Use `mutate()`: it runs your changes and fires one change event at the end.\n\n```ts\nimport SSignal from 'ssignal';\n\nconst todos = new SSignal<string[]>([]);\ntodos.subscribe((list) => console.log('todos:', list.length));\n\ntodos.mutate((list) => {\n  list.push('write docs');\n  list.push('ship it');\n}); // logs once: todos: 2\n\n// Return false to skip the event when nothing changed\ntodos.mutate((list) => {\n  if (list.includes('ship it')) return false;\n  list.push('ship it');\n}); // no log\n```\n\nAn assigned function is always treated as an updater. To store a function as the value, return it from one: `signal.value = () => handler`.\n\n### Immediate mode\n\n```ts\nimport SSignal from 'ssignal';\n\nconst user = new SSignal({ name: 'Ivan' });\n\n// Fires immediately with current value, then on every change\nuser.subscribe((v) => console.log('user:', v.name), { immediate: true });\n// logs: user: Ivan  ← fired synchronously on subscribe\n\nuser.value = { name: 'Junior' };\n// logs: user: Junior\n```\n\n### One-time subscription\n\n```ts\nimport SSignal from 'ssignal';\n\ntype CheckoutState =\n  | { status: 'idle' }\n  | { status: 'processing'; orderId: string }\n  | { status: 'paid'; orderId: string; receiptUrl: string }\n  | { status: 'failed'; orderId: string; reason: string };\n\nconst checkout = new SSignal<CheckoutState>({ status: 'idle' });\n\nfunction openCheckout(orderId: string) {\n  const controller = new AbortController();\n\n  checkout.value = { status: 'processing', orderId };\n\n  // Registered after 'processing', so it reacts to the next state: the payment result\n  checkout.once((state) => {\n    if (state.status === 'paid') {\n      window.location.assign(state.receiptUrl);\n    }\n  }, { signal: controller.signal });\n\n  return {\n    close: () => controller.abort(),\n  };\n}\n\nconst modal = openCheckout('order_123');\n\ncheckout.value = {\n  status: 'paid',\n  orderId: 'order_123',\n  receiptUrl: '/receipts/order_123',\n}; // redirects once\n\nmodal.close(); // no effect after the one-time listener has already fired\n```\n\nWith `{ immediate: true }`, `once()` runs the callback right away with the current value instead of waiting for a change. That is its only call, so nothing stays registered:\n\n```ts\nconst config = new SSignal({ theme: 'dark' });\n\nconfig.once((c) => applyTheme(c.theme), { immediate: true }); // runs now, once\nconfig.value = { theme: 'light' }; // not called again\n```\n\n### Computed signals\n\n```ts\nimport SSignal, { computed } from 'ssignal';\n\n// Single source\nconst price = new SSignal(100);\nconst withTax = computed(price, (p) => p * 1.21);\n\nwithTax.subscribe((v) => console.log('price with tax:', v), { immediate: true });\n// logs: price with tax: 121\n\nprice.value = 200;\n// logs: price with tax: 242\n\n// Multiple sources\nconst qty = new SSignal(3);\nconst total = computed([price, qty], ([p, q]) => p * q);\n\ntotal.subscribe((v) => console.log('total:', v), { immediate: true }); // logs: total: 600\nqty.value = 5; // logs: total: 1000\n\n// computed signals are read-only\ntotal.value = 0; // throws TypeError\n\n// clean up when no longer needed\ntotal.dispose();\n```\n\nComputed signals skip updates when the derived value is unchanged, except after an in-place mutation of a source (`mutate()` or a Map/Set change). There, a derived object with the same reference still notifies, because it may be what was mutated:\n\n```ts\nconst todos = new SSignal<string[]>([]);\nconst list = computed(todos, (items) => items);\n\nlist.subscribe((items) => console.log(items.length));\ntodos.mutate((items) => items.push('write docs')); // logs: 1\n```\n\n### Effects\n\n`effect()` runs a side effect right away and again whenever its sources change. Dependencies are listed explicitly, like in `computed()`. Return a function to clean up before the next run and when the effect is disposed:\n\n```ts\nimport SSignal, { effect } from 'ssignal';\n\nconst userId = new SSignal(1);\n\nconst dispose = effect(userId, (id) => {\n  const controller = new AbortController();\n  fetch(`/api/users/${id}`, { signal: controller.signal })\n    .then((res) => res.json())\n    .then(render);\n\n  return () => controller.abort(); // cancels the previous request\n});\n\nuserId.value = 2; // aborts the request for user 1, fetches user 2\ndispose();        // aborts the pending request, stops following userId\n```\n\nWith several sources, `fn` receives their values as a tuple, and sources changed together inside `batch()` trigger a single run. Pass `{ signal }` to dispose the effect with an `AbortController`.\n\n### Custom equality\n\nBy default an assignment is ignored when `Object.is(prev, next)` is true. Pass `equals` to compare by content instead, for example when you always build new objects:\n\n```ts\nimport SSignal, { computed } from 'ssignal';\n\nconst samePoint = (a: { x: number; y: number }, b: { x: number; y: number }) =>\n  a.x === b.x && a.y === b.y;\n\nconst point = new SSignal({ x: 0, y: 0 }, { equals: samePoint });\npoint.subscribe((p) => console.log('moved to', p));\n\npoint.value = { x: 0, y: 0 }; // no log, equal by content\npoint.value = { x: 1, y: 0 }; // logs: moved to { x: 1, y: 0 }\n\n// Also on computed signals\nconst size = new SSignal({ width: 1920, height: 1080 });\nconst orientation = computed(size, (s) => ({ landscape: s.width > s.height }), {\n  equals: (a, b) => a.landscape === b.landscape,\n});\n```\n\nReturn `false` to notify on every assignment. `equals` is not consulted by `mutate()` or Map/Set mutations, since the reference does not change.\n\n### Batched updates\n\n```ts\nimport SSignal, { batch, computed } from 'ssignal';\n\nconst price = new SSignal(100);\nconst qty = new SSignal(1);\nconst total = computed([price, qty], ([p, q]) => p * q);\n\ntotal.subscribe((v) => console.log('total:', v));\n\nbatch(() => {\n  price.value = 200;\n  qty.value = 3;\n}); // logs once: total: 600\n```\n\n`total` is computed once, with both new values, even when `fn` returns a new object each time. Values change immediately inside `batch()`; only the events wait. When a listener changes the signal it is listening to, the new value is delivered in a follow-up round after every listener has seen the current one, so all listeners finish on the latest value.\n\n### Disposing subscriptions\n\n`dispose()` removes every subscription made with `subscribe()` or `once()` in one call, without keeping each unsubscribe function around. The signal can still be read, set and subscribed to afterwards.\n\n```ts\nimport SSignal from 'ssignal';\n\nconst status = new SSignal('idle');\nstatus.subscribe(render);\nstatus.subscribe(log);\n\nstatus.dispose(); // both listeners removed\n```\n\nSignals also implement `Symbol.dispose`, so a `using` declaration cleans them up when the block ends:\n\n```ts\n{\n  using status = new SSignal('idle');\n  status.subscribe(render);\n} // status.dispose() runs here\n```\n\nListeners added directly with `addEventListener` are not tracked by `dispose()`. `using` needs TypeScript 5.2+ and a runtime with `Symbol.dispose` (Node 18.18+, recent browsers).\n\n### AbortController\n\n```ts\nimport SSignal from 'ssignal';\n\nconst signal = new SSignal(0);\nconst controller = new AbortController();\n\nsignal.subscribe((v) => console.log(v), { signal: controller.signal });\n\nsignal.value = 1;    // logs: 1\ncontroller.abort();\nsignal.value = 2;    // no log\n```\n\n## Scripts\n\n| Command | Description |\n| :------ | :---------- |\n| `npm run build` | Compile and bundle to `lib/`. |\n| `npm test` | Run unit tests. |\n| `npm run test:coverage` | Run unit tests with coverage report. |\n| `npm run test:performance` | Run performance tests. |\n\n## Performance\n\n`SSignal` handles **200,000 value updates** notifying **10 simultaneous subscribers** in under 500 ms.\n\n![Performance test report](images/test-report.png)\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n\n---\n\nRepository: [github.com/ElJijuna/ssignal](https://github.com/ElJijuna/ssignal)\n","readmeFilename":"README.md"}