# Changelog

All notable changes to `@audin.ai/operator-sdk` are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

Because the SDK talks to the Audin operator service over a versioned wire
protocol (currently **v1**), an **incompatible change to that protocol is a
breaking change** and triggers a MAJOR version bump.

## [Unreleased]

### Changed

- License changed from `UNLICENSED` to **MIT** ahead of the first public npm
  release. The SDK is now distributable under the MIT terms (see `LICENSE`).

## [0.4.0] - 2026-06-10

### Added

- **`call_ended` presence notification handling.** The platform now pushes
  `{ type: "call_ended", callSid, reason }` on the presence channel whenever a
  call terminates — remote hangup, no answer, busy — INCLUDING the cases where
  the audio leg never opened (e.g. an outbound the far end never answered),
  which the audio-WS close alone could never signal. The SDK ends the matching
  active call, tears the audio bridge down, and emits a single `callEnded`
  with `endReason` mapped to `remote_hangup` / `no_answer` / `failed`.
  Additive protocol change (still **v1**): older SDKs simply ignore the new
  message and keep relying on the audio-WS close.

### Fixed

- Internal call teardown paths (`goOffline` with an active call, audio start
  failure) could emit `callEnded` TWICE for the same call — once from the
  bridge's synchronous `onClosed` and once from the teardown helper — and the
  bridge's `remote_hangup` reason would override the intended one (`offline` /
  `failed`). Teardown now clears the call refs before closing the bridge, so
  exactly one `callEnded` is emitted, with the correct reason.

## [0.3.0] - 2026-06-10

### Added

- **`setAudioConstraints(constraints)`** on `AudinOperator` — switch the
  microphone input device (or any `MediaTrackConstraints`) at runtime, e.g.
  `op.setAudioConstraints({ deviceId: { exact: id }, echoCancellation: true })`.
  The new constraints are read when the next call's audio leg opens, so the
  change takes effect from the NEXT `dial()`/accepted inbound call; a call
  already in progress keeps the device its bridge opened with (the microphone is
  not re-opened mid-call).

## [0.2.1] - 2026-06-10

### Fixed

- Capture/playback frozen after first audio block — resample read-head
  overshoot caused a `RangeError` in the worklet. The capture resampler's
  fractional read head could advance past the end of the accumulated buffer,
  so on the next `process()` the buffer-grow step computed a negative offset
  and threw, stopping the processor after the very first block and muting both
  directions. The read head is now clamped to the buffer length so it never
  produces a negative offset. Also added an `onprocessorerror` handler so any
  future worklet error is logged instead of failing silently.

## [0.2.0] - 2026-06-10

### Added

- **`listPhoneNumbers()`** on `AudinOperator` — fetch the phone numbers the
  account owns (`{ id, phoneNumber, displayName }[]`) directly via the SDK using
  the same short-lived session token as the WebSockets. The Account API Key
  never enters the browser. On a `401` the cached token is dropped and the
  request is retried once with a fresh token; a persistent `401` throws an
  `OperatorRequestError` with code `UNAUTHORIZED`. New exports:
  `OperatorPhoneNumber` (type) and `OperatorRequestError` (class).
- **Token manager (internal)** — session tokens are now obtained through a
  central cache shared by the REST helper, the presence WebSocket and the audio
  WebSocket. A valid cached token is reused (using its `expiresAt` when present,
  with a safety skew, or a conservative TTL otherwise) so a `listPhoneNumbers()`
  → `goOnline()` → `dial()` sequence mints a single token. Concurrent callers
  share one in-flight `getToken()`. The cache is invalidated on auth failures
  (REST `401` / auth-related WebSocket close) so the next use re-mints.

## [0.1.0] - 2026-06-09

Initial public release.

### Added

- **Presence client** — connect/disconnect an operator presence channel, go
  online on a set of phone numbers and receive availability confirmations,
  with automatic reconnection (configurable backoff) and heartbeats.
- **Audio client** — microphone capture and full-duplex audio over the call's
  audio channel, with mute/unmute.
- **AudioWorklet μ-law pipeline** — capture-side downsampling to 8 kHz +
  G.711 μ-law encoding, playback-side μ-law decoding + upsampling, run off the
  main thread. Codec and resampling helpers (`encodeMuLaw`, `decodeMuLaw`,
  `resampleLinear`, …) are also exported for advanced integrators.
- **Outbound calls** — `dial(to, { callerId })` placing an outbound call.
- **Inbound calls** — `incomingCall` events with `accept()` / `reject()`.
- **Active-call controls** — `mute(on)` and `hangup()`.
- **Single-active-call concurrency (MVP)** — while a call is live, new inbound
  offers are auto-declined and `dial()` rejects.
- **Typed event API** — `on` / `off` / `once` for `presenceStateChanged`,
  `availabilityChanged`, `incomingCall`, `callStarted`, `callEnded`, `error`.
- Ships as **ESM** (`dist/audin-operator-sdk.js`) and **UMD**
  (`dist/audin-operator-sdk.umd.cjs`) with full **TypeScript declarations**
  (`dist/index.d.ts`). Zero runtime dependencies.

### Known limitations

- **`sendDtmf` is not yet supported end-to-end.** The digit is validated and
  emitted as a control message, but the server does not yet forward the tones
  onto the telephone network, so the far end will not hear them. The method and
  its wire message are kept so that enabling it server-side in a future release
  needs no SDK change.

[Unreleased]: https://bitbucket.org/thecovesrl/audin-ai/branches/compare/main%0Av0.3.0
[0.3.0]: https://bitbucket.org/thecovesrl/audin-ai/branches/compare/v0.3.0%0Av0.2.1
[0.2.1]: https://bitbucket.org/thecovesrl/audin-ai/branches/compare/v0.2.1%0Av0.2.0
[0.2.0]: https://bitbucket.org/thecovesrl/audin-ai/branches/compare/v0.2.0%0Av0.1.0
[0.1.0]: https://bitbucket.org/thecovesrl/audin-ai/src/v0.1.0/audin-operator-sdk
