{"_id":"@absolutejs/router","_rev":"10-db57496e2af008437c4e2bab2ca30220","name":"@absolutejs/router","dist-tags":{"latest":"0.6.0"},"versions":{"0.0.1":{"name":"@absolutejs/router","version":"0.0.1","keywords":["absolutejs","bun","paas","multi-tenant","router","consistent-hash","rate-limit","websocket"],"author":"Alex Kahn","license":"BSL-1.1","_id":"@absolutejs/router@0.0.1","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"dist":{"shasum":"fe704413fe3ea898b8014ffd09de93bd772710c9","tarball":"https://registry.npmjs.org/@absolutejs/router/-/router-0.0.1.tgz","fileCount":6,"integrity":"sha512-m5Pnanm7osILIfPv+RungBm0PH3SPkXQ0/3QoL35WQ69WTewZ2A7MyGRam/9fv2I+NJuGIhBaGq/I2b+6zk8QQ==","signatures":[{"sig":"MEQCIGhwykBsHIinQWbDovmshIwKmTqPfkfbQXXESfKKG0KUAiBph+N0Pl0jO32TgqztfI2/rGT29x8iKjubbfaR8xZWhQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33948},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","shasum":"fe704413fe3ea898b8014ffd09de93bd772710c9","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"scripts":{"test":"bun test tests/","build":"rm -rf dist && bun build src/index.ts --outdir dist --sourcemap --target=bun && tsc --project tsconfig.build.json","format":"prettier --write \"./**/*.{ts,json,md}\"","release":"bun run format && bun run check:package && bun publish","typecheck":"tsc --noEmit","check:package":"bun run typecheck && bun run build && bun run test"},"_npmUser":{"name":"alexkahndev","email":"alexkahn2019@gmail.com"},"_integrity":"sha512-m5Pnanm7osILIfPv+RungBm0PH3SPkXQ0/3QoL35WQ69WTewZ2A7MyGRam/9fv2I+NJuGIhBaGq/I2b+6zk8QQ==","repository":{"url":"git+https://github.com/absolutejs/router.git","type":"git"},"_npmVersion":"10.8.3","description":"Multi-tenant connection routing primitive for Bun PaaS gateways. Consistent-hash tenant→shard, per-tenant connection cap, per-tenant rate limit, healthy-shard skip. The library that goes in front of N @absolutejs/runtime instances.","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.8.3","@types/bun":"^1.3.14","typescript":"^6.0.3"},"peerDependencies":{"bun-types":"^1.3.14"},"_npmOperationalInternal":{"tmp":"tmp/router_0.0.1_1780082399474_0.4913669033738963","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@absolutejs/router","version":"0.1.0","keywords":["absolutejs","bun","paas","multi-tenant","router","consistent-hash","rate-limit","websocket"],"author":"Alex Kahn","license":"BSL-1.1","_id":"@absolutejs/router@0.1.0","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"dist":{"shasum":"218169e02981db537f472eb8c8e069bd030535c3","tarball":"https://registry.npmjs.org/@absolutejs/router/-/router-0.1.0.tgz","fileCount":6,"integrity":"sha512-redXeCjO9kNBcHYDTZ9CXv2kCpAY4tHITGuCOlUrGoYyx1QlOZzcJ5rKRd5GBazmiNf1YdQSJvSm46U2aebDCQ==","signatures":[{"sig":"MEUCICa5W8uZ+DccgG5MDezyUt4eVfUg7F1LsovTD3WPTzwoAiEAo59rwIavoHQDmoWM0aNO/E8nxP4K0upqXrHDxdHSGyU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":51198},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","shasum":"218169e02981db537f472eb8c8e069bd030535c3","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"scripts":{"test":"bun test tests/","build":"rm -rf dist && bun build src/index.ts --outdir dist --sourcemap --target=bun && tsc --project tsconfig.build.json","format":"prettier --write \"./**/*.{ts,json,md}\"","release":"bun run format && bun run check:package && bun publish","typecheck":"tsc --noEmit","check:package":"bun run typecheck && bun run build && bun run test"},"_npmUser":{"name":"alexkahndev","email":"alexkahn2019@gmail.com"},"_integrity":"sha512-redXeCjO9kNBcHYDTZ9CXv2kCpAY4tHITGuCOlUrGoYyx1QlOZzcJ5rKRd5GBazmiNf1YdQSJvSm46U2aebDCQ==","repository":{"url":"git+https://github.com/absolutejs/router.git","type":"git"},"_npmVersion":"10.8.3","description":"Multi-tenant connection routing primitive for Bun PaaS gateways. Consistent-hash tenant→shard, per-tenant connection cap, per-tenant rate limit, healthy-shard skip. The library that goes in front of N @absolutejs/runtime instances.","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.8.3","@types/bun":"^1.3.14","typescript":"^6.0.3"},"peerDependencies":{"bun-types":"^1.3.14"},"_npmOperationalInternal":{"tmp":"tmp/router_0.1.0_1780086390941_0.436385728932541","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@absolutejs/router","version":"0.2.0","keywords":["absolutejs","bun","paas","multi-tenant","router","consistent-hash","rate-limit","websocket"],"author":"Alex Kahn","license":"BSL-1.1","_id":"@absolutejs/router@0.2.0","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"dist":{"shasum":"3b30ed56828a058f5942ab4f0e5d4db98874386a","tarball":"https://registry.npmjs.org/@absolutejs/router/-/router-0.2.0.tgz","fileCount":6,"integrity":"sha512-i0X3SIlaUhINSbJ3FHxHXjiRjtJI2SNr5UwSVf4LtgVgmtCdyimDmy+aFNL4slJ9hfulTZl3LlTHkKvcjhSDLQ==","signatures":[{"sig":"MEYCIQCI7xqZNSa0fPvt5TYHJJ6EOE+E681Qt8ucJikKya3sSAIhAK1a4HOn72KhRMnrjmy+rGT+MoWOlXAk2kPTmvSffKLJ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":57899},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","shasum":"3b30ed56828a058f5942ab4f0e5d4db98874386a","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"scripts":{"test":"bun test tests/","build":"rm -rf dist && bun build src/index.ts --outdir dist --sourcemap --target=bun && tsc --project tsconfig.build.json","format":"prettier --write \"./**/*.{ts,json,md}\"","release":"bun run format && bun run check:package && bun publish","typecheck":"tsc --noEmit","check:package":"bun run typecheck && bun run build && bun run test"},"_npmUser":{"name":"alexkahndev","email":"alexkahn2019@gmail.com"},"_integrity":"sha512-i0X3SIlaUhINSbJ3FHxHXjiRjtJI2SNr5UwSVf4LtgVgmtCdyimDmy+aFNL4slJ9hfulTZl3LlTHkKvcjhSDLQ==","repository":{"url":"git+https://github.com/absolutejs/router.git","type":"git"},"_npmVersion":"10.8.3","description":"Multi-tenant connection routing primitive for Bun PaaS gateways. Consistent-hash tenant→shard, per-tenant connection cap, per-tenant rate limit, healthy-shard skip. The library that goes in front of N @absolutejs/runtime instances.","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.8.3","@types/bun":"^1.3.14","typescript":"^6.0.3"},"peerDependencies":{"bun-types":"^1.3.14"},"_npmOperationalInternal":{"tmp":"tmp/router_0.2.0_1780110513362_0.26984308719852557","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@absolutejs/router","version":"0.3.0","keywords":["absolutejs","bun","paas","multi-tenant","router","consistent-hash","rate-limit","websocket"],"author":"Alex Kahn","license":"BSL-1.1","_id":"@absolutejs/router@0.3.0","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"dist":{"shasum":"ea1a2e91487ef8d41a7f0dd49e8329858a0b8e5b","tarball":"https://registry.npmjs.org/@absolutejs/router/-/router-0.3.0.tgz","fileCount":6,"integrity":"sha512-GrlfOZGrQCq2rLgRLqASrunxAA0apR7GreXLK85/1tusVi/WHQzAMIzD8RXd8IFLEm9WFjHnHlTGyjJf0kXQ9w==","signatures":[{"sig":"MEUCIFzBYtl20q8TgITZizB9vU0s8bwfI/FCQPeJVFHyX45/AiEAwbFpUI4sKZxqS6YGoH/bY364oB4WzEyAF1adH2WyD24=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":68179},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","shasum":"ea1a2e91487ef8d41a7f0dd49e8329858a0b8e5b","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"scripts":{"test":"bun test tests/","build":"rm -rf dist && bun build src/index.ts --outdir dist --sourcemap --target=bun && tsc --project tsconfig.build.json","format":"prettier --write \"./**/*.{ts,json,md}\"","release":"bun run format && bun run check:package && bun publish","typecheck":"tsc --noEmit","check:package":"bun run typecheck && bun run build && bun run test"},"_npmUser":{"name":"alexkahndev","email":"alexkahn2019@gmail.com"},"_integrity":"sha512-GrlfOZGrQCq2rLgRLqASrunxAA0apR7GreXLK85/1tusVi/WHQzAMIzD8RXd8IFLEm9WFjHnHlTGyjJf0kXQ9w==","repository":{"url":"git+https://github.com/absolutejs/router.git","type":"git"},"_npmVersion":"10.8.3","description":"Multi-tenant connection routing primitive for Bun PaaS gateways. Consistent-hash tenant→shard, per-tenant connection cap, per-tenant rate limit, healthy-shard skip. The library that goes in front of N @absolutejs/runtime instances.","directories":{},"_nodeVersion":"24.3.0","dependencies":{"@absolutejs/telemetry":"^0.0.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.8.3","@types/bun":"^1.3.14","typescript":"^6.0.3","@absolutejs/telemetry":"^0.0.2"},"peerDependencies":{"bun-types":"^1.3.14"},"_npmOperationalInternal":{"tmp":"tmp/router_0.3.0_1780169194891_0.3379750111042399","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@absolutejs/router","version":"0.4.0","keywords":["absolutejs","bun","paas","multi-tenant","router","consistent-hash","rate-limit","websocket"],"author":"Alex Kahn","license":"BSL-1.1","_id":"@absolutejs/router@0.4.0","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"homepage":"https://github.com/absolutejs/router","bugs":{"url":"https://github.com/absolutejs/router/issues"},"dist":{"shasum":"59ea34731d430766a6a35194780bfcf99f43a0e6","tarball":"https://registry.npmjs.org/@absolutejs/router/-/router-0.4.0.tgz","fileCount":8,"integrity":"sha512-ZDlDVGZwn/7JKhD/QpwIrZNFZxh6nhLw377jREChwVwtj9Mh6octP6lOecxd5RXhKr9q/dsOF/rDXgTErFcdXA==","signatures":[{"sig":"MEQCIC2MtO+VPAXevdjI7L3Pg0zuLUbAtSFmBxOODwqMyqqOAiB5TR5pSDp1ZUmqeA58d74Ll2ROR0u/iIukHvWb7M1D8Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":117124},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","shasum":"59ea34731d430766a6a35194780bfcf99f43a0e6","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"scripts":{"test":"bun test tests/","build":"rm -rf dist && bun build src/index.ts --outdir dist --sourcemap --target=bun && tsc --project tsconfig.build.json","format":"prettier --write \"./**/*.{ts,json,md}\"","release":"bun run format && bun run check:package && bun publish","typecheck":"tsc --noEmit","check:package":"bun run typecheck && bun run build && bun run test"},"_npmUser":{"name":"alexkahndev","email":"alexkahn2019@gmail.com"},"_integrity":"sha512-ZDlDVGZwn/7JKhD/QpwIrZNFZxh6nhLw377jREChwVwtj9Mh6octP6lOecxd5RXhKr9q/dsOF/rDXgTErFcdXA==","repository":{"url":"git+https://github.com/absolutejs/router.git","type":"git"},"_npmVersion":"10.8.3","description":"Multi-tenant connection routing primitive for Bun PaaS gateways. Consistent-hash tenant→shard, per-tenant connection cap, per-tenant rate limit, healthy-shard skip. The library that goes in front of N @absolutejs/runtime instances.","directories":{},"_nodeVersion":"24.3.0","dependencies":{"@absolutejs/telemetry":"^0.0.2"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.8.3","@types/bun":"^1.3.14","typescript":"^6.0.3","@absolutejs/telemetry":"^0.0.2"},"peerDependencies":{"bun-types":"^1.3.14"},"_npmOperationalInternal":{"tmp":"tmp/router_0.4.0_1783975242776_0.5438198455617345","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@absolutejs/router","version":"0.5.0","keywords":["absolutejs","bun","paas","multi-tenant","router","consistent-hash","rate-limit","websocket"],"author":{"name":"Alex Kahn"},"license":"BSL-1.1","_id":"@absolutejs/router@0.5.0","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"homepage":"https://github.com/absolutejs/router","bugs":{"url":"https://github.com/absolutejs/router/issues"},"dist":{"shasum":"28c22e872469b049eef2dd17503ce575fad1f0d2","tarball":"https://registry.npmjs.org/@absolutejs/router/-/router-0.5.0.tgz","fileCount":11,"integrity":"sha512-znh3z8vpmDDTP9mhF7AHwOjHl8OBXriyf3ulS7DIPIzcKFcUgcAYRAywh9khiRoWpNFbDR+uUMdqdreaAn6uyw==","signatures":[{"sig":"MEYCIQDSSXubknU43mIgdpJWzU/J8qYeJci/Hd3k+uLr14RFoQIhALP8udQcSWyY4n+bAxHwGdUCL6ewB3tfyII8W0Fl1fOf","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":146415},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./bun":{"types":"./dist/bun.d.ts","import":"./dist/bun.js","default":"./dist/bun.js"}},"gitHead":"0496ab27c780efcb76f5f8ddea9d75960b5d2e14","scripts":{"test":"bun test tests/","build":"rm -rf dist && bun build src/index.ts src/bun.ts --outdir dist --sourcemap --target=bun && tsc --project tsconfig.build.json","format":"prettier --write \"./**/*.{ts,json,md}\"","release":"bun run format && bun run check:package && bun publish","typecheck":"tsc --noEmit","check:package":"bun run typecheck && bun run build && bun run test"},"_npmUser":{"name":"alexkahndev","email":"alexkahn2019@gmail.com"},"repository":{"url":"git+https://github.com/absolutejs/router.git","type":"git"},"_npmVersion":"10.9.2","description":"Multi-tenant connection routing primitive for Bun PaaS gateways. Consistent-hash tenant→shard, per-tenant connection cap, per-tenant rate limit, healthy-shard skip. The library that goes in front of N @absolutejs/runtime instances.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"@absolutejs/telemetry":"^0.1.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.8.3","@types/bun":"^1.3.14","typescript":"^6.0.3"},"peerDependencies":{"bun-types":"^1.3.14"},"_npmOperationalInternal":{"tmp":"tmp/router_0.5.0_1784059936947_0.14293957868980733","host":"s3://npm-registry-packages-npm-production"}},"0.5.1":{"name":"@absolutejs/router","version":"0.5.1","keywords":["absolutejs","bun","paas","multi-tenant","router","consistent-hash","rate-limit","websocket"],"author":"Alex Kahn","license":"BSL-1.1","_id":"@absolutejs/router@0.5.1","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"homepage":"https://github.com/absolutejs/router","bugs":{"url":"https://github.com/absolutejs/router/issues"},"dist":{"shasum":"98b522b0626bc770df22702b03471afe6a7c014b","tarball":"https://registry.npmjs.org/@absolutejs/router/-/router-0.5.1.tgz","fileCount":11,"integrity":"sha512-K7FpRRn5SYQcFj2VY4oR1ubvDdDlKKX7dvRPG0tswjwkAaeV8uO0KsuIodFGedOGF4oA5u4jWsF2DQQCouuwQw==","signatures":[{"sig":"MEYCIQDNjPXGhGj3m7qk+LriBZ7szGlDSSaL6pUtkmGA73Oy2gIhAPV3YOmbqUJg7XB6k4gCTREcYTI/XELz2mlFJK2mvVBf","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":146363},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","shasum":"98b522b0626bc770df22702b03471afe6a7c014b","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./bun":{"types":"./dist/bun.d.ts","import":"./dist/bun.js","default":"./dist/bun.js"}},"scripts":{"test":"bun test tests/","build":"rm -rf dist && bun build src/index.ts src/bun.ts --outdir dist --sourcemap --target=bun && tsc --project tsconfig.build.json","format":"prettier --write \"./**/*.{ts,json,md}\"","release":"bun run format && bun run check:package && bun publish","typecheck":"tsc --noEmit","check:package":"bun run typecheck && bun run build && bun run test"},"_npmUser":{"name":"alexkahndev","email":"alexkahn2019@gmail.com"},"_integrity":"sha512-K7FpRRn5SYQcFj2VY4oR1ubvDdDlKKX7dvRPG0tswjwkAaeV8uO0KsuIodFGedOGF4oA5u4jWsF2DQQCouuwQw==","repository":{"url":"git+https://github.com/absolutejs/router.git","type":"git"},"_npmVersion":"10.8.3","description":"Multi-tenant connection routing primitive for Bun PaaS gateways. Consistent-hash tenant→shard, per-tenant connection cap, per-tenant rate limit, healthy-shard skip. The library that goes in front of N @absolutejs/runtime instances.","directories":{},"_nodeVersion":"24.3.0","dependencies":{"@absolutejs/telemetry":"^0.1.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.8.3","@types/bun":"^1.3.14","typescript":"^6.0.3"},"_npmOperationalInternal":{"tmp":"tmp/router_0.5.1_1784916418259_0.33159443127607036","host":"s3://npm-registry-packages-npm-production"}},"0.5.2":{"name":"@absolutejs/router","version":"0.5.2","keywords":["absolutejs","bun","paas","multi-tenant","router","consistent-hash","rate-limit","websocket"],"author":"Alex Kahn","license":"BSL-1.1","_id":"@absolutejs/router@0.5.2","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"homepage":"https://github.com/absolutejs/router","bugs":{"url":"https://github.com/absolutejs/router/issues"},"dist":{"shasum":"3317d9c9cfb6046ab5cf5755a7071b1d26c7763e","tarball":"https://registry.npmjs.org/@absolutejs/router/-/router-0.5.2.tgz","fileCount":11,"integrity":"sha512-eK6JxbCMn8vmQL49290BbKK6JQz8dazYw+ckA+at4m/UcHqBwYdNLorF1rxiAdzQmst0EJhBtEo7RzBNRMVFvg==","signatures":[{"sig":"MEUCIQD4nk/GXaxrgBP2iCXw6tqdgeGcTwO5oSn04QR9I4t+DQIgKn68GgHP4lTb+RYvHFvDajnM0ejxB6iuUjLqS3Uc3PI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":148843},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","shasum":"3317d9c9cfb6046ab5cf5755a7071b1d26c7763e","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./bun":{"types":"./dist/bun.d.ts","import":"./dist/bun.js","default":"./dist/bun.js"}},"scripts":{"test":"bun test tests/","build":"rm -rf dist && bun build src/index.ts src/bun.ts --outdir dist --sourcemap --target=bun && tsc --project tsconfig.build.json","format":"prettier --write \"./**/*.{ts,json,md}\"","release":"bun run format && bun run check:package && bun publish","typecheck":"tsc --noEmit","check:package":"bun run typecheck && bun run build && bun run test"},"_npmUser":{"name":"alexkahndev","email":"alexkahn2019@gmail.com"},"_integrity":"sha512-eK6JxbCMn8vmQL49290BbKK6JQz8dazYw+ckA+at4m/UcHqBwYdNLorF1rxiAdzQmst0EJhBtEo7RzBNRMVFvg==","repository":{"url":"git+https://github.com/absolutejs/router.git","type":"git"},"_npmVersion":"10.8.3","description":"Multi-tenant connection routing primitive for Bun PaaS gateways. Consistent-hash tenant→shard, per-tenant connection cap, per-tenant rate limit, healthy-shard skip. The library that goes in front of N @absolutejs/runtime instances.","directories":{},"_nodeVersion":"24.3.0","dependencies":{"@absolutejs/telemetry":"^0.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.8.3","@types/bun":"^1.3.14","typescript":"^6.0.3"},"_npmOperationalInternal":{"tmp":"tmp/router_0.5.2_1784958315476_0.828532173843328","host":"s3://npm-registry-packages-npm-production"}},"0.5.3":{"name":"@absolutejs/router","version":"0.5.3","keywords":["absolutejs","bun","paas","multi-tenant","router","consistent-hash","rate-limit","websocket"],"author":{"name":"Alex Kahn"},"license":"BSL-1.1","_id":"@absolutejs/router@0.5.3","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"homepage":"https://github.com/absolutejs/router","bugs":{"url":"https://github.com/absolutejs/router/issues"},"dist":{"shasum":"ee16337df815eee4d6325f6bee9f4731bf9e2d2b","tarball":"https://registry.npmjs.org/@absolutejs/router/-/router-0.5.3.tgz","fileCount":11,"integrity":"sha512-G3cPSn8h4o2gIoFbA5N3g6f5W3VWn0xbqd0m45cWbtKUdiCfMXr5NO3S7cd7KZEba0MMIrYgb+gMD0erBStNuQ==","signatures":[{"sig":"MEUCIQD8zN1B21VabjXgm7577N830k8otPWozv1vpNiF8YVNHAIgBu2T+SA3ru7ZJeqydldrI07zdeP+GJiXr3FOLr8EWIg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":159059},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./bun":{"types":"./dist/bun.d.ts","import":"./dist/bun.js","default":"./dist/bun.js"}},"scripts":{"test":"bun test tests/","build":"rm -rf dist && bun build src/index.ts src/bun.ts --outdir dist --sourcemap --target=bun && tsc --project tsconfig.build.json","format":"prettier --write \"./**/*.{ts,json,md}\"","release":"bun run format && bun run check:package && bun publish","typecheck":"tsc --noEmit","check:package":"bun run typecheck && bun run build && bun run test"},"_npmUser":{"name":"alexkahndev","email":"alexkahn2019@gmail.com"},"repository":{"url":"git+https://github.com/absolutejs/router.git","type":"git"},"_npmVersion":"10.9.2","description":"Multi-tenant connection routing primitive for Bun PaaS gateways. Consistent-hash tenant→shard, per-tenant connection cap, per-tenant rate limit, healthy-shard skip. The library that goes in front of N @absolutejs/runtime instances.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"@absolutejs/telemetry":"^0.3.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.8.3","@types/bun":"^1.3.14","typescript":"^6.0.3"},"_npmOperationalInternal":{"tmp":"tmp/router_0.5.3_1786078109482_0.6139921091945459","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@absolutejs/router","version":"0.6.0","description":"Multi-tenant connection routing primitive for Bun PaaS gateways. Consistent-hash tenant→shard, per-tenant connection cap, per-tenant rate limit, healthy-shard skip. The library that goes in front of N @absolutejs/runtime instances.","repository":{"type":"git","url":"git+https://github.com/absolutejs/router.git"},"homepage":"https://github.com/absolutejs/router","bugs":{"url":"https://github.com/absolutejs/router/issues"},"main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","type":"module","license":"BSL-1.1","author":"Alex Kahn","publishConfig":{"access":"public"},"keywords":["absolutejs","bun","paas","multi-tenant","router","consistent-hash","rate-limit","websocket"],"scripts":{"build":"rm -rf dist && bun build src/index.ts src/bun.ts --outdir dist --sourcemap --target=bun && tsc --project tsconfig.build.json","test":"bun test tests/","typecheck":"tsc --noEmit","format":"prettier --write \"./**/*.{ts,json,md}\"","check:package":"bun run typecheck && bun run build && bun run test","release":"bun run format && bun run check:package && bun publish"},"dependencies":{"@absolutejs/telemetry":"^0.3.0"},"devDependencies":{"@types/bun":"^1.3.14","prettier":"^3.8.3","typescript":"^6.0.3"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./bun":{"types":"./dist/bun.d.ts","import":"./dist/bun.js","default":"./dist/bun.js"}},"_id":"@absolutejs/router@0.6.0","_integrity":"sha512-uxm/c3MdI6FP8xB7Clr9sxvaEHvdbNWf220MgHvbWewanu0ClwxFFJoHs86xoTgDut1wldyNPWFL04DB0SdKpQ==","_nodeVersion":"24.3.0","_npmVersion":"10.8.3","shasum":"35a728cd9f1fb08bad15e79410d53ebd3c20be94","dist":{"integrity":"sha512-uxm/c3MdI6FP8xB7Clr9sxvaEHvdbNWf220MgHvbWewanu0ClwxFFJoHs86xoTgDut1wldyNPWFL04DB0SdKpQ==","shasum":"35a728cd9f1fb08bad15e79410d53ebd3c20be94","tarball":"https://registry.npmjs.org/@absolutejs/router/-/router-0.6.0.tgz","fileCount":11,"unpackedSize":179689,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDWJ5iG8KeaZ5yoiCsN20B0uvTf2299x80h1tJhzv0GhAiBBRRNUxeqjvA5vdriHQGpmNnvVIBIKApgs3lKcA+2IDw=="}]},"_npmUser":{"name":"alexkahndev","email":"alexkahn2019@gmail.com"},"directories":{},"maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/router_0.6.0_1786687622061_0.5356174123906561"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-29T19:19:59.300Z","modified":"2026-08-14T06:07:02.363Z","0.0.1":"2026-05-29T19:19:59.755Z","0.1.0":"2026-05-29T20:26:31.131Z","0.2.0":"2026-05-30T03:08:33.497Z","0.3.0":"2026-05-30T19:26:35.029Z","0.4.0":"2026-07-13T20:40:42.902Z","0.5.0":"2026-07-14T20:12:17.097Z","0.5.1":"2026-07-24T18:06:58.444Z","0.5.2":"2026-07-25T05:45:15.621Z","0.5.3":"2026-08-07T04:48:29.654Z","0.6.0":"2026-08-14T06:07:02.193Z"},"bugs":{"url":"https://github.com/absolutejs/router/issues"},"author":"Alex Kahn","license":"BSL-1.1","homepage":"https://github.com/absolutejs/router","keywords":["absolutejs","bun","paas","multi-tenant","router","consistent-hash","rate-limit","websocket"],"repository":{"type":"git","url":"git+https://github.com/absolutejs/router.git"},"description":"Multi-tenant connection routing primitive for Bun PaaS gateways. Consistent-hash tenant→shard, per-tenant connection cap, per-tenant rate limit, healthy-shard skip. The library that goes in front of N @absolutejs/runtime instances.","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"readme":"# @absolutejs/router\n\nMulti-tenant connection routing primitive for Bun PaaS gateways. Sits in front\nof N backend processes (each a [`@absolutejs/runtime`](https://github.com/absolutejs/runtime)\ninstance hosting a [`@absolutejs/sync`](https://github.com/absolutejs/sync) engine\nfor a subset of tenants) and decides — per request:\n\n1. Which shard owns this tenant (consistent hash, sticky)\n2. Is the tenant over its connection cap?\n3. Is the tenant over its rate limit?\n4. Is the chosen shard healthy?\n\nThe core remains transport-independent. For Bun, the `/bun` subpath provides\nstreaming HTTP proxying and a bidirectional WebSocket bridge while holding the\nrouter acquire handle for the real request/socket lifetime.\n\n```ts\nimport { createBunGateway } from '@absolutejs/router/bun';\n\nconst gateway = createBunGateway({\n\trouter,\n\tresolve: (request) => {\n\t\tconst hit = domainMap.resolve(request.headers.get('host') ?? '');\n\n\t\treturn hit\n\t\t\t? { route: new URL(request.url).pathname, tenantId: hit.tenantId }\n\t\t\t: null;\n\t}\n});\n\nBun.serve({ port: 3001, ...gateway });\n```\n\nDedicated runtimes register shards with `tenants: [tenantId]`; shared shard\nhosts omit `tenants`. A request without an eligible dedicated/shared shard\nfails closed with `no-tenant-shards`.\n\n```ts\nimport { createRouter } from '@absolutejs/router';\n\nconst router = createRouter({\n\tshards: [\n\t\t{ id: 'engine-1', url: 'ws://10.0.0.11:3000' },\n\t\t{ id: 'engine-2', url: 'ws://10.0.0.12:3000' }\n\t],\n\thashStrategy: 'jump',\n\tperTenantConnectionCap: 100,\n\tperTenantRateLimit: { tokens: 100, refillPerSecond: 10 }\n});\n\n// In your WS upgrade handler:\nconst decision = router.route({ tenantId, channelId });\nif (decision.decision !== 'allow') {\n\treturn new Response(decision.decision, { status: 429 });\n}\nconst handle = router.acquire(tenantId);\nws.data = {\n\t...ws.data,\n\trelease: handle.release,\n\tupstream: decision.shard!.url\n};\n// ...proxy WS frames to decision.shard.url; call handle.release() on close.\n```\n\n## Surface (0.1.0)\n\n| API                                                       | Purpose                                                                                                                                                            |\n| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `createRouter(options)`                                   | Factory. Returns a `Router`.                                                                                                                                       |\n| `router.route({ tenantId, channelId?, route?, region? })` | Returns `{ shard, decision, emptiedBucket? }`. Decision is `allow` / `rate-limited` / `capped` / `no-shards` / `no-tenant-shards` / `no-region-shards` / `denied`. |\n| `router.acquire(tenantId)`                                | Increment active-connection counter; returns `{ active, release }`. `release` is idempotent.                                                                       |\n| `router.markHealthy(id)` / `router.markUnhealthy(id)`     | Caller-driven health state. Unhealthy shards are skipped.                                                                                                          |\n| `router.drainShard(id)`                                   | Refuse new routes; existing acquires unaffected. Operator-intentional state distinct from unhealthy. `markHealthy` cancels it.                                     |\n| `router.isHealthy(id)` / `router.isDraining(id)`          | Inspect state.                                                                                                                                                     |\n| `router.addShard(shard)` / `router.removeShard(id)`       | Runtime shard membership changes.                                                                                                                                  |\n| `router.shards()`                                         | Inspect shard list.                                                                                                                                                |\n| `router.snapshot()` / `router.restore(snap, options?)`    | Serializable state. `resetConnections` preserves rate-limit tokens while clearing dead connections after an edge restart.                                          |\n| `createBunGateway(options)` (`/bun`)                      | Bun HTTP/WebSocket proxy adapter with admission lifetime, forwarding headers, protocol bridging, and decision status mapping.                                      |\n| `router.dispose()`                                        | Stop accepting routes; all subsequent `route()` returns `no-shards`.                                                                                               |\n\n### Hash strategies + load bias\n\n- **`jump`** (default) — Lamping & Veach 2014. O(log n) with no memory, exactly 1/N keys move when shards are added at the tail. Ignores `weight` AND `load` (its design property is unconditional stickiness).\n- **`rendezvous`** — HRW hash. Supports per-shard `weight` for heterogeneous engine sizes; ALSO supports the `load: (shardId) => number` hook for runtime hot-spot avoidance — `effectiveWeight = weight / load`. O(N) per lookup.\n- **Custom**: pass `(key, shards) => index`.\n\nHash strategies only apply to `'sticky'` balancing — see below.\n\n### Balance strategies (0.6.0)\n\nA hash strategy answers \"which shard OWNS this key?\". That is the right question when a shard holds the key's state, and the wrong one when the shards are interchangeable replicas of one stateless app — hashing pins all of a tenant's traffic to a single replica however many are registered. `balance` picks the question:\n\n- **`'sticky'`** (default) — consistent hash through `hashStrategy`. Same key, same shard. For *session affinity*, pass a per-client `channelId`: each client sticks to one replica while different clients spread out.\n- **`'round-robin'`** — successive calls for the same key cycle the eligible shards. The cursor is per routing key, so one busy tenant can't skew another's spread.\n- **`'least-connections'`** — fewest active connections wins, from shard-tagged `acquire()` calls. Ties break round-robin so an idle field of replicas still spreads.\n\nSet a router-wide default and override per call:\n\n```ts\nconst router = createRouter({ balance: 'round-robin', shards });\n\nrouter.route({ tenantId }); // round-robin across replicas\nrouter.route({ tenantId, balance: 'sticky', channelId: sessionId }); // affinity\n```\n\nAll three respect health, draining, tenant allowlists and region filters identically. `'round-robin'` and `'least-connections'` ignore `hashStrategy` and make no cross-call stability promise.\n\n### Per-shard connection accounting (0.6.0)\n\n`acquire(tenantId, shardId?)` takes the shard the connection was routed to. Tagged acquires maintain a live per-shard active count — what `'least-connections'` reads, and what `metrics().shardActiveConnections` reports next to the cumulative `shardLoadDistribution`. `createBunGateway` tags automatically. Omitting the id keeps the pre-0.6.0 behaviour: the tenant cap is still enforced, the connection is just invisible per-shard.\n\n### Drain mode\n\n`drainShard(id)` excludes a shard from new routing without marking it broken. Use this before a planned shard shutdown — tenants on the draining shard rehash to healthy non-draining shards on their NEXT route, but in-flight requests aren't torn down. The caller waits for the shard to be quiet (e.g. via the runtime's stats), then `removeShard()`. `markHealthy()` cancels a drain in case ops changes their mind.\n\n### Connection cap\n\n`perTenantConnectionCap` is the max concurrent connections one tenant can hold,\ncounted via `acquire()` / the returned `release()`. When reached, `route()`\nreturns `capped` — your gateway should refuse the upgrade with `429` /\n`503`. Default `Infinity` (no cap).\n\n### Rate limits — tenant + per-route\n\n`perTenantRateLimit` is a token bucket per tenant: `tokens` is bucket capacity AND starting balance; `refillPerSecond` continuously refills up to capacity. Each successful `route()` costs one token. Bucket is computed lazily at lookup time — no timer churn for idle tenants. Default `{ tokens: Infinity, refillPerSecond: 0 }` (no limit).\n\n`perRouteRateLimits: Record<string, RateLimit>` layers a SECOND per-route bucket on top of the tenant-wide one. `route({ route: 'expensive' })` checks both; if either is empty, the call returns `rate-limited` with `emptiedBucket` reporting which one. Useful for \"100 cheap calls / minute, 5 expensive calls / minute\" shapes where one tenant-wide cap won't express the policy. **A failed route bucket does NOT consume the tenant bucket** — neither token is deducted unless both pass.\n\n### Allow hook (meter integration)\n\n`allow: (tenantId) => boolean` is a caller-supplied gate. Returning `false` makes `route()` return `{ decision: 'denied' }` immediately, before any bucket is touched. The intended pairing is `@absolutejs/metering`'s `meter.allow` — pass it directly:\n\n```ts\nconst meter = createMeter({ ... });\nconst router = createRouter({\n  shards,\n  allow: meter.allow,                // refuse routes for over-quota tenants\n  load: (id) => runtimeRoster.load(id), // and bias toward less-loaded shards\n});\n```\n\n### Health\n\nThe router does not probe backends itself — keeping it bun/elysia-free means no I/O. Wire your own health-check loop and call `markHealthy` / `markUnhealthy`. A live health-checking adapter is a candidate for a later 0.0.x subpath.\n\n### Snapshot + restore\n\n```ts\nconst json = JSON.stringify(router.snapshot());\nawait persistToDisk('/var/lib/router/state.json', json);\n\n// On edge restart:\nconst restored = createRouter({ ... same config ... });\nrestored.restore(JSON.parse(await readFromDisk('/var/lib/router/state.json')));\n```\n\nCaptures rate-limit token counts, per-route bucket state, shard health + drain state, per-tenant active connection counts. Without this, an edge restart hands every tenant a fresh full bucket — instant rate-limit-bypass for anyone watching the deploy times.\n\n## Region-aware routing (0.4.0)\n\n`createRouter` shards WITHIN a region; `createRegionDirectory` decides which\nregion a tenant lives in. Sticky, deterministic assignment — weighted\nrendezvous over region ids by default, so every replica computes the same\nanswer without coordination — plus an optional caller hook for latency-based\nplacement and explicit overrides for control-plane onboarding decisions.\n\n```ts\nimport { createRegionDirectory, createRouter } from '@absolutejs/router';\n\nconst directory = createRegionDirectory({\n\tregions: [\n\t\t{ id: 'us-east', weight: 2 }, // twice the tenants of eu-west\n\t\t{ id: 'eu-west' }\n\t],\n\t// Optional: latency-based placement. Return undefined to fall back to\n\t// the default weighted-rendezvous strategy.\n\tassign: (tenantId) => edgeProbe.closestRegion(tenantId)\n});\n\nconst router = createRouter({\n\tshards: [\n\t\t{ id: 'us-1', url: 'ws://10.0.0.11:3000', region: 'us-east' },\n\t\t{ id: 'us-2', url: 'ws://10.0.0.12:3000', region: 'us-east' },\n\t\t{ id: 'eu-1', url: 'ws://10.1.0.11:3000', region: 'eu-west' }\n\t]\n});\n\n// The wire-up: the directory picks the region, the router picks the shard.\nconst decision = router.route({\n\ttenantId,\n\tregion: directory.regionFor(tenantId)\n});\n```\n\n| API                                                                    | Purpose                                                                                |\n| ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |\n| `createRegionDirectory({ regions, assign?, clock?, tracerProvider? })` | Factory. At least one region required.                                                 |\n| `directory.regionFor(tenantId)`                                        | Sticky assignment, created on first call. Re-assigns lazily if the region was removed. |\n| `directory.assignRegion(tenantId, regionId)`                           | Explicit override (control-plane onboarding). Throws on unknown region.                |\n| `directory.release(tenantId)`                                          | Forget the assignment; next `regionFor` re-assigns.                                    |\n| `directory.addRegion(region)` / `directory.removeRegion(id)`           | Runtime region membership. Removal re-assigns its tenants lazily.                      |\n| `directory.regions()`                                                  | Inspect the region list.                                                               |\n| `directory.snapshot()` / `directory.restore(snap)`                     | Assignments (+ override flags) survive control-plane restarts.                         |\n| `directory.metrics()`                                                  | `{ assignments, byRegion, overrides }`.                                                |\n\nShards without a `region` are region-agnostic — they remain candidates for\nANY requested region (back-compat: an existing single-region deployment keeps\nworking untouched). A `route({ region })` with no candidate shards in that\nregion returns `decision: 'no-region-shards'` — distinguishable from the\ncluster-wide `no-shards` in `metrics().rejectsByDecision`, so \"region drained\"\nand \"cluster empty\" alert separately.\n\n## Custom-domain map (0.4.0)\n\nA tenant's traffic arrives as `app.acme.com` (their CNAME), not as a tenant\nid. `createDomainMap` is the first lookup in the edge gateway: hostname →\ntenant, dependency-free and O(1)-ish (a Map for exact hosts, a Map keyed by\nsuffix for wildcards).\n\n```ts\nimport { createDomainMap } from '@absolutejs/router';\n\nconst domainMap = createDomainMap({\n\t// Resolver of last resort — the platform's own subdomain scheme.\n\tfallback: (host) =>\n\t\thost.endsWith('.cloud.absolutejs.com')\n\t\t\t? host.slice(0, -'.cloud.absolutejs.com'.length)\n\t\t\t: undefined\n});\n\ndomainMap.add('app.acme.com', 'acme'); // exact custom domain\ndomainMap.add('*.acme.com', 'acme'); // wildcard — exactly one label deep\n\n// Edge gateway: host header → tenant → region → shard.\nconst hit = domainMap.resolve(request.headers.get('host') ?? '');\nif (!hit) return new Response('unknown domain', { status: 404 });\nconst decision = router.route({\n\ttenantId: hit.tenantId,\n\tregion: directory.regionFor(hit.tenantId)\n});\n```\n\n| API                                                       | Purpose                                                                                                                                       |\n| --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |\n| `createDomainMap({ fallback?, clock?, tracerProvider? })` | Factory.                                                                                                                                      |\n| `map.add(hostname, tenantId)`                             | Lowercases. Exact hosts and `*.example.com` wildcards (one label depth — TLS-wildcard-certificate scoping). Throws on other `*` placements.   |\n| `map.remove(hostname)`                                    | Delete an entry (exact or `*.` form).                                                                                                         |\n| `map.resolve(hostname)`                                   | `{ tenantId, matched: 'exact' \\| 'wildcard' \\| 'fallback' } \\| null`. Strips port, lowercases. Exact beats wildcard beats fallback.           |\n| `map.list()`                                              | Every entry; wildcards in their `*.` form.                                                                                                    |\n| `map.snapshot()` / `map.restore(snap)`                    | Entries survive edge restarts.                                                                                                                |\n| `map.metrics()`                                           | `{ entries, resolves, hits, misses, lastResolveMs }`. A climbing miss rate usually means stale DNS pointing at the gateway after an offboard. |\n\n## Architectural role\n\n- **`@absolutejs/sync`** — the engine each backend shard runs.\n- **`@absolutejs/runtime`** — the process pool each backend shard spawns from.\n- **`@absolutejs/metering`** — counts the bill; `meter.allow(tenant)` reads.\n- **`@absolutejs/router`** — _this library_. The edge decision before traffic reaches a shard. `meter.allow()` can be wired into the gateway alongside `router.route()` to refuse over-quota tenants without paying for the upstream hop.\n\n## What v0.0.1 does NOT include\n\n- The actual WS proxy implementation. Caller wires `Bun.serve` (or any HTTP/WS layer) to `router.route()` and forwards bytes themselves.\n- The Elysia adapter (subpath in a later 0.0.x).\n- Distributed router state across multiple edge replicas (v0.2+).\n- Backend health-checking probe loop.\n- TLS / HTTP3 termination.\n\n## License\n\nBSL 1.1 with a named carveout for the hosted multi-tenant connection routing / WebSocket edge gateway category (Cloudflare Workers WebSockets, Cloudflare Smart Placement, Vercel edge router, Liveblocks' WebSocket fan-out, PartyKit, Ably, Pusher, Soketi). See [LICENSE](./LICENSE). Change Date: 4 years from first release; Change License: Apache 2.0.\n","readmeFilename":"README.md"}