{"_id":"@bazariodev/fsm-delays","_rev":"3-57904a79dc0d60806b6c31e8a95410cc","name":"@bazariodev/fsm-delays","dist-tags":{"latest":"2.0.0"},"versions":{"0.1.0":{"name":"@bazariodev/fsm-delays","version":"0.1.0","keywords":["fsm","finite-state-machine","state-machine","delays","timers","timeout","backoff","typescript","realtime","telephony","sip","ucaas"],"author":{"name":"Bazario"},"license":"MIT","_id":"@bazariodev/fsm-delays@0.1.0","maintainers":[{"name":"bazario","email":"bazario.dev@gmail.com"}],"homepage":"https://github.com/Bazariodev/bazario-labs/tree/main/packages/fsm-delays#readme","bugs":{"url":"https://github.com/Bazariodev/bazario-labs/issues"},"dist":{"shasum":"aa88060dfe5206908c0503b8a8963066480fe348","tarball":"https://registry.npmjs.org/@bazariodev/fsm-delays/-/fsm-delays-0.1.0.tgz","fileCount":9,"integrity":"sha512-Z1JkFax8Jpibkhc9y8AHSXWSalS2IZHm5Pizv99G89QXVu8aTz60w8JHIxJ3xII3YCIpN9srH16a7HUOtRw/DA==","signatures":[{"sig":"MEUCIFWnJhIMZoEz2ZwLRl5vrqZpxTxuPzn9uIMUWT5wvLbvAiEA1DVCEW0vdpepbrBswtTbVgTieVEAXSbtj0aYeW8TBK8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":48105},"main":"./dist/index.cjs","type":"module","_from":"file:bazariodev-fsm-delays-0.1.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"bazario","email":"bazario.dev@gmail.com"},"_resolved":"/private/var/folders/xk/pm_239nx0cjgz296_sbs_f1c0000gn/T/3bffa12c7dfa7fa037c9a9a2a5bbaf63/bazariodev-fsm-delays-0.1.0.tgz","_integrity":"sha512-Z1JkFax8Jpibkhc9y8AHSXWSalS2IZHm5Pizv99G89QXVu8aTz60w8JHIxJ3xII3YCIpN9srH16a7HUOtRw/DA==","repository":{"url":"git+https://github.com/Bazariodev/bazario-labs.git","type":"git","directory":"packages/fsm-delays"},"_npmVersion":"11.5.1","description":"Declarative delays and intervals for @bazariodev/fsm — timeouts, repeating timers, and context-derived backoff that cancel on state leave, built on @bazariodev/fsm-effects.","directories":{},"sideEffects":false,"_nodeVersion":"24.7.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@bazariodev/fsm":"^0.1.0","@bazariodev/fsm-effects":"^0.1.0"},"peerDependencies":{"@bazariodev/fsm":"^0.1.0","@bazariodev/fsm-effects":"^0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/fsm-delays_0.1.0_1780241361359_0.6933320408350452","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@bazariodev/fsm-delays","version":"1.0.0","keywords":["fsm","finite-state-machine","state-machine","delays","timers","timeout","backoff","typescript","realtime","telephony","sip","ucaas"],"author":{"name":"Bazario"},"license":"MIT","_id":"@bazariodev/fsm-delays@1.0.0","maintainers":[{"name":"bazario","email":"bazario.dev@gmail.com"}],"homepage":"https://github.com/Bazariodev/bazario-labs/tree/main/packages/fsm-delays#readme","bugs":{"url":"https://github.com/Bazariodev/bazario-labs/issues"},"dist":{"shasum":"79254145813c82dcf85b8dbf73a3f21144620cd5","tarball":"https://registry.npmjs.org/@bazariodev/fsm-delays/-/fsm-delays-1.0.0.tgz","fileCount":9,"integrity":"sha512-uisXmW0zJcti7yvldV1yLKw+q9cptsPWere4yvA1Wkui53kqQtiy0DxsOLaamQlZSxIT7siO/E0k8IyLx6ozfg==","signatures":[{"sig":"MEUCICYZoptb9+9iAETWxld5kENyZMBGi0CFi3K8XkOh7lyGAiEAxFcMEd1+KfEJjspyeaZCYEPpwNn9kIawf25s9YRcoUQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":48105},"main":"./dist/index.cjs","type":"module","_from":"file:bazariodev-fsm-delays-1.0.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"bazario","email":"bazario.dev@gmail.com"},"_resolved":"/private/var/folders/xk/pm_239nx0cjgz296_sbs_f1c0000gn/T/7c694bd9a4c358c21f76aaa9dcd2e7cb/bazariodev-fsm-delays-1.0.0.tgz","_integrity":"sha512-uisXmW0zJcti7yvldV1yLKw+q9cptsPWere4yvA1Wkui53kqQtiy0DxsOLaamQlZSxIT7siO/E0k8IyLx6ozfg==","repository":{"url":"git+https://github.com/Bazariodev/bazario-labs.git","type":"git","directory":"packages/fsm-delays"},"_npmVersion":"11.5.1","description":"Declarative delays and intervals for @bazariodev/fsm — timeouts, repeating timers, and context-derived backoff that cancel on state leave, built on @bazariodev/fsm-effects.","directories":{},"sideEffects":false,"_nodeVersion":"24.7.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@bazariodev/fsm":"^1.0.0","@bazariodev/fsm-effects":"^1.0.0"},"peerDependencies":{"@bazariodev/fsm":"^1.0.0","@bazariodev/fsm-effects":"^1.0.0"},"_npmOperationalInternal":{"tmp":"tmp/fsm-delays_1.0.0_1783331033481_0.16286244778240677","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"_id":"@bazariodev/fsm-delays@2.0.0","bugs":{"url":"https://github.com/Bazariodev/bazario-labs/issues"},"dist":{"shasum":"53e2212268f901d6aa29a271ed9ae1533620a234","tarball":"https://registry.npmjs.org/@bazariodev/fsm-delays/-/fsm-delays-2.0.0.tgz","fileCount":9,"integrity":"sha512-P9kxac4lE8+ni4xeUqZbJRsCTO23LQfJDLcRvais92moXTI0AnRpEEyxGPVaAc+n7nl8CE7AY4aOUIl8/UaPhQ==","signatures":[{"sig":"MEYCIQDHzoDupFzryQYIIc7oMv0FsfWkOi0cSUbyFR562DgHwQIhANCmy9EnA3iIcqpAqGui883knJ5IV0JvwLhR1eXFKj3r","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCVt/v7du8UItG6nc3Q2kkYvHOBpOySyc+kvIBy5UtXoQIhAMeUpPXA/cNptUqsjmIw6JJlbKJH3wt2HSyuiMym/s4z"}],"unpackedSize":38592},"main":"./dist/index.cjs","name":"@bazariodev/fsm-delays","type":"module","_from":"file:bazariodev-fsm-delays-2.0.0.tgz","types":"./dist/index.d.ts","author":{"name":"Bazario"},"module":"./dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"license":"MIT","scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc --noEmit && tsc --noEmit --lib ES2022,WebWorker","test:watch":"vitest"},"version":"2.0.0","_npmUser":{"name":"bazario","email":"bazario.dev@gmail.com"},"homepage":"https://github.com/Bazariodev/bazario-labs/tree/main/packages/fsm-delays#readme","keywords":["fsm","finite-state-machine","state-machine","delays","timers","timeout","backoff","typescript","realtime","telephony","sip","ucaas"],"_resolved":"/private/var/folders/xk/pm_239nx0cjgz296_sbs_f1c0000gn/T/e7565ec27c8f9922cd6ed77b69291aab/bazariodev-fsm-delays-2.0.0.tgz","_integrity":"sha512-P9kxac4lE8+ni4xeUqZbJRsCTO23LQfJDLcRvais92moXTI0AnRpEEyxGPVaAc+n7nl8CE7AY4aOUIl8/UaPhQ==","repository":{"url":"git+https://github.com/Bazariodev/bazario-labs.git","type":"git","directory":"packages/fsm-delays"},"_npmVersion":"11.5.1","description":"Declarative delays and intervals for @bazariodev/fsm — timeouts, repeating timers, and context-derived backoff that cancel on state leave, built on @bazariodev/fsm-effects.","directories":{},"maintainers":[{"name":"bazario","email":"bazario.dev@gmail.com"}],"sideEffects":false,"_nodeVersion":"24.7.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@bazariodev/fsm":"^1.1.0","@bazariodev/fsm-effects":"^2.0.0"},"peerDependencies":{"@bazariodev/fsm":"^1.1.0","@bazariodev/fsm-effects":"^2.0.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/fsm-delays_2.0.0_1790588682771_0.25812051618011034"}}},"time":{"created":"2026-05-31T15:29:21.230Z","modified":"2026-09-28T09:44:43.232Z","0.1.0":"2026-05-31T15:29:21.535Z","1.0.0":"2026-07-06T09:43:53.648Z","2.0.0":"2026-09-28T09:44:42.861Z"},"bugs":{"url":"https://github.com/Bazariodev/bazario-labs/issues"},"author":{"name":"Bazario"},"license":"MIT","homepage":"https://github.com/Bazariodev/bazario-labs/tree/main/packages/fsm-delays#readme","keywords":["fsm","finite-state-machine","state-machine","delays","timers","timeout","backoff","typescript","realtime","telephony","sip","ucaas"],"repository":{"url":"git+https://github.com/Bazariodev/bazario-labs.git","type":"git","directory":"packages/fsm-delays"},"description":"Declarative delays and intervals for @bazariodev/fsm — timeouts, repeating timers, and context-derived backoff that cancel on state leave, built on @bazariodev/fsm-effects.","maintainers":[{"name":"bazario","email":"bazario.dev@gmail.com"}],"readme":"# @bazariodev/fsm-delays\n\nDeclarative delays and intervals for [`@bazariodev/fsm`](https://github.com/Bazariodev/bazario-labs/tree/main/packages/fsm). Attach time-driven events to states — one-shot `after` timeouts and repeating `every` intervals — that arm on entry and cancel on leave. Built on [`@bazariodev/fsm-effects`](https://github.com/Bazariodev/bazario-labs/tree/main/packages/fsm-effects).\n\nFull design rationale: [`Delays.md` ADR](https://github.com/Bazariodev/bazario-labs/blob/main/.agent/ADR/Modules/Delays.md).\n\n## Install\n\n```sh\npnpm add @bazariodev/fsm-delays @bazariodev/fsm @bazariodev/fsm-effects\n```\n\n`@bazariodev/fsm` and `@bazariodev/fsm-effects` are peer dependencies.\n\n## Usage\n\n```ts\nimport { FsmDelays } from '@bazariodev/fsm-delays';\n\nconst delays = new FsmDelays(callMachine, {\n  delays: {\n    // ring-no-answer timeout\n    ringing: { after: 30_000, send: { type: 'NO_ANSWER' } },\n\n    // heartbeat while connected\n    connected: { every: 5_000, send: { type: 'PING' } },\n\n    // exponential reconnect backoff, derived from context\n    reconnecting: {\n      after: (snapshot) => Math.min(30_000, 1_000 * 2 ** snapshot.context.attempts),\n      send: { type: 'RETRY' },\n    },\n  },\n});\n\ndelays.stop(); // or `using delays = new FsmDelays(...)`\n```\n\nA spec carries exactly one of `after` (one-shot) or `every` (repeating). `after`/`every` (ms) and `send` may be static values or functions of the entry `snapshot`. Multiple specs per state and wildcard (`*`) specs are supported.\n\n### Composing with hand-written effects\n\n`compileDelays` returns an effects fragment you can merge into your own `FsmEffects`, so one subscriber drives both delays and effects:\n\n```ts\nimport { FsmEffects } from '@bazariodev/fsm-effects';\nimport { compileDelays } from '@bazariodev/fsm-delays';\n\nnew FsmEffects(machine, {\n  effects: {\n    ...compileDelays({ delays: { ringing: { after: 30_000, send: { type: 'NO_ANSWER' } } } }),\n    dialing: (snapshot, { signal, send }) => {\n      // hand-written effect alongside the compiled delays\n    },\n  },\n});\n```\n\nMerge per state: a delay map and an effect map that share a state key would overwrite on spread — keep their keys distinct unless you intend to override.\n\n## Design decisions\n\n- **Built on the effects runner.** A delay compiles to an effect that arms a timer on entry and returns `() => clearTimeout(handle)`. Cancellation, re-entrancy safety, and the guarded `send` all come from `@bazariodev/fsm-effects`. Because cleanup runs synchronously when the leaving state's controller aborts, **a pending timer can never fire for a state the machine has already left**.\n- **`after` and `every`.** One-shot timeouts and repeating intervals, modelled as a union so a spec carries exactly one. `every` covers heartbeat and registration-refresh as first-class.\n- **Dynamic resolvers.** `after`/`every`/`send` resolve against the entry snapshot — once when an `after` fires, on each tick for an `every`. Exponential backoff falls out of a dynamic `after` plus an attempt counter in `context`; no separate retry DSL.\n- **Injectable scheduler.** An optional `scheduler` (`{ setTimeout, clearTimeout, setInterval, clearInterval }`) defaults to the global timers. Tests inject a deterministic clock instead of relying on fake timers.\n- **Self-transitions don't restart timers** (inherited from the effects runner): a heartbeat `every` keeps ticking across the self-transitions its own events cause.\n- **Validation.** Construction fails fast on a `delays` map that is not a plain object, a spec that is not a plain object (including `null`), a spec without exactly one of `after`/`every`, a missing `send`, or a static `after`/`every` that is not a finite number in range (`after >= 0`, `every > 0`; a string such as `\"100\"` is rejected). A dynamic resolver that yields an invalid duration is logged at `warn` and skipped for that entry; the rest still arm. These checks stay in JavaScript because a delay only fails inside a timer, where errors are logged rather than thrown; without them a typo such as `{ afer: 100 }` would silently never fire.\n- **Error containment.** The timer callback fires after the effect body returns, outside the runner's try/catch, so the module wraps it: a throw from resolving `send`, or a machine error from the delayed `api.send` (guard/reducer/hook failure), is caught and logged via `logger` as `fsm-delays: delayed send threw` rather than escaping as an uncaught timer exception. No error event is auto-sent.\n\n## API\n\n- `FsmDelays` — convenience runner that owns an internal `FsmEffects`; `stop()` and `[Symbol.dispose]`.\n- `compileDelays(config)` — pure compiler returning an `EffectsConfig['effects']` fragment.\n- Types: `AfterSpec`, `EverySpec`, `DelaySpec`, `DelaysConfig`, `Scheduler`, `Resolvable`.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}