{"_id":"@absolutejs/autoscaler","_rev":"4-b7d82b7a5817dcfec1ad6e9ecd03e7f1","name":"@absolutejs/autoscaler","dist-tags":{"latest":"0.2.2"},"versions":{"0.1.0":{"name":"@absolutejs/autoscaler","version":"0.1.0","keywords":["absolutejs","autoscaler","scaling","horizontal","cluster","elasticity"],"author":"Alex Kahn","license":"BSL-1.1","_id":"@absolutejs/autoscaler@0.1.0","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"dist":{"shasum":"0ae3b129f08f02762d3ac080ad869cc72c897857","tarball":"https://registry.npmjs.org/@absolutejs/autoscaler/-/autoscaler-0.1.0.tgz","fileCount":6,"integrity":"sha512-Rl16eWM/5F4So9GULIqwrS76xh1m4UOUy7jzrJAs2253n3ZNJCOpOUPMr2rQGDpXWuL5CbNuPCbkUvPR4N8dQw==","signatures":[{"sig":"MEYCIQCAReLOs92/vXM3IMxzYGtA2nHSBGuAU3EkaEnW+vNiagIhANtHpvMxIpqT8+zR/ewJq7QmU9b6Z4KDPYPzhQpCIfr1","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":45392},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","shasum":"0ae3b129f08f02762d3ac080ad869cc72c897857","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-Rl16eWM/5F4So9GULIqwrS76xh1m4UOUy7jzrJAs2253n3ZNJCOpOUPMr2rQGDpXWuL5CbNuPCbkUvPR4N8dQw==","repository":{"url":"git+https://github.com/absolutejs/autoscaler.git","type":"git"},"_npmVersion":"10.8.3","description":"Horizontal-scaling policy substrate for the AbsoluteJS PaaS. createAutoscaler periodically evaluates pluggable signals (CPU, queue depth, latency, ...) against a declarative policy (min/max instances, scale-up/down thresholds, cooldowns) and drives a call","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.8.3","@types/bun":"^1.3.14","typescript":"^5.9.0"},"peerDependencies":{"bun-types":"^1.3.14"},"_npmOperationalInternal":{"tmp":"tmp/autoscaler_0.1.0_1780249309175_0.027398134903136473","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@absolutejs/autoscaler","version":"0.2.0","keywords":["absolutejs","autoscaler","scaling","horizontal","cluster","elasticity"],"author":{"name":"Alex Kahn"},"license":"BSL-1.1","_id":"@absolutejs/autoscaler@0.2.0","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"homepage":"https://github.com/absolutejs/autoscaler","bugs":{"url":"https://github.com/absolutejs/autoscaler/issues"},"dist":{"shasum":"ab98fdf01fcebe1f40d4bc81f029fd33f1f6db66","tarball":"https://registry.npmjs.org/@absolutejs/autoscaler/-/autoscaler-0.2.0.tgz","fileCount":6,"integrity":"sha512-P6wkgxru0/fV2ENw+ZpkZyKO10b4WjmnG9GXaZK+qGXAwLsI+Ve6ZgwhvnnxeCZK6sGz7LHIvZ7+/IhkPFzufg==","signatures":[{"sig":"MEYCIQD6snqXVrzDiQaahGoOydZEFjoab8d+nTshmaWw4xrSzwIhAPoSce/qlbpxxAi7N7Bkabuw6GTtox+Tqitzn2IOJAZZ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":52022},"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"}},"gitHead":"63b72c468dafeda79f3d9621fcf367b3061cb6d2","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"},"repository":{"url":"git+https://github.com/absolutejs/autoscaler.git","type":"git"},"_npmVersion":"10.9.2","description":"Horizontal-scaling policy substrate for the AbsoluteJS PaaS. createAutoscaler periodically evaluates pluggable signals (CPU, queue depth, latency, ...) against a declarative policy (min/max instances, scale-up/down thresholds, cooldowns) and drives a call","directories":{},"_nodeVersion":"22.14.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"prettier":"^3.8.3","@types/bun":"^1.3.14","typescript":"^5.9.0"},"peerDependencies":{"bun-types":"^1.3.14"},"_npmOperationalInternal":{"tmp":"tmp/autoscaler_0.2.0_1784341684673_0.9978609334582442","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@absolutejs/autoscaler","version":"0.2.1","keywords":["absolutejs","autoscaler","scaling","horizontal","cluster","elasticity"],"author":"Alex Kahn","license":"BSL-1.1","_id":"@absolutejs/autoscaler@0.2.1","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"homepage":"https://github.com/absolutejs/autoscaler","bugs":{"url":"https://github.com/absolutejs/autoscaler/issues"},"dist":{"shasum":"53b4a0d2261ccaf8c92e8b814c39a935d5d72935","tarball":"https://registry.npmjs.org/@absolutejs/autoscaler/-/autoscaler-0.2.1.tgz","fileCount":6,"integrity":"sha512-xFYG5LxJFgjKN/pVnbDuq5BJ8pPuvyAzQwKca/neR07E71Nk6BZmnTbpuyQERK1W6o3GzBh1B2wtoeUfMU3fBg==","signatures":[{"sig":"MEUCIQC0rJpVR3diF5G/icB+BCc6oSFFE4+Q4rNRsUpYDcPkTwIgcYUSPGgI5kQHsO6oFu+otiu7ZcwMtG9CKcBc8oJEtAs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":51963},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","shasum":"53b4a0d2261ccaf8c92e8b814c39a935d5d72935","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-xFYG5LxJFgjKN/pVnbDuq5BJ8pPuvyAzQwKca/neR07E71Nk6BZmnTbpuyQERK1W6o3GzBh1B2wtoeUfMU3fBg==","repository":{"url":"git+https://github.com/absolutejs/autoscaler.git","type":"git"},"_npmVersion":"10.8.3","description":"Horizontal-scaling policy substrate for the AbsoluteJS PaaS. createAutoscaler periodically evaluates pluggable signals (CPU, queue depth, latency, ...) against a declarative policy (min/max instances, scale-up/down thresholds, cooldowns) and drives a call","directories":{},"_nodeVersion":"24.3.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"prettier":"3.8.3","@types/bun":"1.3.14","typescript":"5.9.3"},"_npmOperationalInternal":{"tmp":"tmp/autoscaler_0.2.1_1784958293790_0.2191247979359452","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@absolutejs/autoscaler","version":"0.2.2","description":"Horizontal-scaling policy used by the hosted AbsoluteJS.ai platform and available to any Bun control plane. Evaluates pluggable signals against declarative scaling policy and drives a caller-supplied actuator.","repository":{"type":"git","url":"git+https://github.com/absolutejs/autoscaler.git"},"homepage":"https://github.com/absolutejs/autoscaler","bugs":{"url":"https://github.com/absolutejs/autoscaler/issues"},"main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","type":"module","license":"BSL-1.1","author":"Alex Kahn","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"}},"publishConfig":{"access":"public"},"scripts":{"build":"rm -rf dist && bun build src/index.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"},"keywords":["absolutejs","autoscaler","scaling","horizontal","cluster","elasticity"],"devDependencies":{"@types/bun":"1.3.14","prettier":"3.8.3","typescript":"5.9.3"},"_id":"@absolutejs/autoscaler@0.2.2","_integrity":"sha512-XQqVEljIWgUpO5dTvaVkqBSF6Z38l7ONbPPEhJkPmSRk51WkAg6F+vjGCGGIdcuBR2rl3h0CL9+P7fqtw2XBWQ==","_nodeVersion":"24.3.0","_npmVersion":"10.8.3","shasum":"b52571e2b31ad4283fb73ac72bc2ab2a7e921800","dist":{"integrity":"sha512-XQqVEljIWgUpO5dTvaVkqBSF6Z38l7ONbPPEhJkPmSRk51WkAg6F+vjGCGGIdcuBR2rl3h0CL9+P7fqtw2XBWQ==","shasum":"b52571e2b31ad4283fb73ac72bc2ab2a7e921800","tarball":"https://registry.npmjs.org/@absolutejs/autoscaler/-/autoscaler-0.2.2.tgz","fileCount":6,"unpackedSize":53002,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDaHgxZEJdo2I2tL2cb4smqOILYwP2OiiBHQQsp3riwbQIhAMyTQJ/g88YQzX7ZvqbfDLi5mJEE5TFXZOplPHTEEsIh"}]},"_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/autoscaler_0.2.2_1785888398561_0.9382447024677405"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-31T17:41:48.999Z","modified":"2026-08-05T00:06:38.902Z","0.1.0":"2026-05-31T17:41:49.313Z","0.2.0":"2026-07-18T02:28:04.807Z","0.2.1":"2026-07-25T05:44:53.936Z","0.2.2":"2026-08-05T00:06:38.740Z"},"bugs":{"url":"https://github.com/absolutejs/autoscaler/issues"},"author":"Alex Kahn","license":"BSL-1.1","homepage":"https://github.com/absolutejs/autoscaler","keywords":["absolutejs","autoscaler","scaling","horizontal","cluster","elasticity"],"repository":{"type":"git","url":"git+https://github.com/absolutejs/autoscaler.git"},"description":"Horizontal-scaling policy used by the hosted AbsoluteJS.ai platform and available to any Bun control plane. Evaluates pluggable signals against declarative scaling policy and drives a caller-supplied actuator.","maintainers":[{"name":"alexkahndev","email":"alexkahn2019@gmail.com"}],"readme":"# `@absolutejs/autoscaler`\n\n> Horizontal-scaling policy used by the hosted AbsoluteJS.ai platform and available to any Bun control plane.\n\n`@absolutejs/autoscaler` owns the **decision** half of an\nautoscaler. The actuator half — actually provisioning a VM,\ndraining a pod, killing a process — lives in your control plane\nvia an injected `Actuator`, so the substrate stays cloud-agnostic\nand runtime-agnostic.\n\nThe same substrate fits:\n\n- a 10-VM fleet across DigitalOcean / Hetzner / Linode\n- a 10000-isolate fleet on one box via `@absolutejs/isolated-jsc`\n- a pod-per-tenant cluster on Kubernetes\n\nThe actuator defines what \"instance\" means.\n\n## Loop\n\n```\nread capacity + signals  →  restore hard min/max bounds first  →\notherwise compare the combined score to thresholds  →\nif past threshold & cooldown elapsed  →  ask actuator to spawn/drain\n```\n\n## API\n\n```ts\nimport {\n  createAutoscaler,\n  createPolicy,\n  ratioSignal,\n} from \"@absolutejs/autoscaler\";\n\nconst scaler = createAutoscaler({\n  policy: createPolicy({\n    min: 1,\n    max: 20,\n    scaleUp: { threshold: 0.75, cooldownMs: 60_000, step: 1 },\n    scaleDown: { threshold: 0.3, cooldownMs: 300_000, step: 1 },\n  }),\n  signals: [\n    ratioSignal(\"cpu\", 0.8, async () => await meter.cpuUtilization()),\n    ratioSignal(\"queue\", 100, async () => await queue.depth(), {\n      observedKey: \"depth\",\n    }),\n    ratioSignal(\"latencyP95\", 200, async () => await metrics.p95()),\n  ],\n  combine: \"max\", // worst pressure wins. or 'avg', or a custom fn\n  actuator: {\n    list: () => fleet.list(),\n    spawn: () => fleet.provision(),\n    drain: (id) => loadBalancer.remove(id),\n    terminate: (id) => fleet.destroy(id),\n  },\n  audit: broker, // optional; emits autoscaler.scale.up etc.\n  intervalMs: 30_000,\n});\n\nscaler.start();\n// fires every 30s\n\nconst reviewedPlan = await scaler.evaluate();\nawait scaler.applyDecision(reviewedPlan, { maxAgeMs: 300_000 });\n// applies that exact plan only while its capacity precondition still holds\n\nconst oneShot = await scaler.step();\n// { action: 'scale-up' | 'scale-down' | 'hold', score, currentCount,\n//   desiredCount, reason, readings: [...], at }\n```\n\n## Signals\n\nA `Signal` is `{ name, read: () => SignalReading | Promise<SignalReading> }`.\n\nA `SignalReading` is `{ score, observed? }`. `score` is normalized:\n`1.0` = \"at the scale-up target.\" Going past 1.0 represents over-\ntarget pressure.\n\nThe bundled `ratioSignal(name, target, read)` helper builds the\ncanonical \"observed / target\" shape for CPU utilization, memory\npressure, queue depth, latency, etc.\n\nA signal that throws is captured as `{ failed: true, error }` in\nthe decision readings and excluded from the combined score. The\nloop never breaks because one metric source is offline.\n\n## Combine strategies\n\n- **`'max'`** (default) — worst pressure wins. The safe choice for\n  elasticity: any one over-stressed dimension scales the fleet.\n- **`'avg'`** — weighted mean using each signal's `weight`. Zero-\n  weight signals are ignored.\n- **Custom function** — `(readings) => number` for arbitrary\n  composition (latency-weighted CPU, percentile-of-percentile, …).\n\n## Cooldowns\n\n`scaleUp` and `scaleDown` have **independent** cooldown timers — a\nfleet that just scaled up can still scale down moments later if the\nload drops. Default `cooldownMs` is 60 seconds.\n\n## Audit trail\n\nWhen an `audit` broker is supplied, every applied decision emits:\n\n- `autoscaler.scale.up` — with `{ score, currentCount, desiredCount, reason }`\n- `autoscaler.scale.down`\n- `autoscaler.hold`\n\nAll three are emitted (even `hold`) so the audit trail tells the\nfull story of why the fleet is where it is. Broker failures are\nisolated; they bump the `metrics().errors` counter but never break\nthe loop.\n\n## License\n\nBSL-1.1 with named carveout against hosted autoscaling /\nelasticity SaaS (Karpenter SaaS offerings, Spot.io, CAST AI,\nPerfectScale, Densify, Granulate). See `LICENSE`. Change date:\n**2030-05-31** → Apache 2.0.\n","readmeFilename":"README.md"}