{"_id":"@clarionhq/azure","_rev":"2-61304c1b0821c4f86fcafec111b0fcd7","name":"@clarionhq/azure","dist-tags":{"latest":"0.2.0"},"versions":{"0.0.1":{"name":"@clarionhq/azure","version":"0.0.1","keywords":["react-native","audio","speech","voice"],"license":"MIT","_id":"@clarionhq/azure@0.0.1","maintainers":[{"name":"anvesh-dev","email":"anveshk282@gmail.com"}],"homepage":"https://github.com/clarionhq/clarion","bugs":{"url":"https://github.com/clarionhq/clarion/issues"},"dist":{"shasum":"0a149ba47c5fb5d46d0d5fe2fbf0f910aa68f523","tarball":"https://registry.npmjs.org/@clarionhq/azure/-/azure-0.0.1.tgz","fileCount":2,"integrity":"sha512-WNXOuRGdC0rEQo46ePV87sGXAwdoLaJkoR4Gj/Mh9QY8Tb8BcUjtUWnt/y+4CUZZH7iwFcHetMorUBj+w+vqYg==","signatures":[{"sig":"MEYCIQDQl++PLIVApQ78aQx4cQAqhYD4LZ+dQeQrKtHtvhDxAAIhANCceKD2NnFLoc4ZmXG9BqgBpTGmUcFoM48cBZH6wTOX","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":490},"main":"index.js","_npmUser":{"name":"anvesh-dev","email":"anveshk282@gmail.com"},"repository":{"url":"git+https://github.com/clarionhq/clarion.git","type":"git"},"_npmVersion":"11.5.1","description":"Clarion azure — placeholder, full release coming soon","directories":{},"_nodeVersion":"24.5.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/azure_0.0.1_1779084522409_0.9748920327426465","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@clarionhq/azure","version":"0.2.0","description":"Clarion azure — Microsoft Cognitive Services Speech SDK wrapper for React Native","main":"lib/index.js","types":"lib/index.d.ts","react-native":"src/index.ts","source":"src/index.ts","keywords":["react-native","speech","speech-recognition","stt","voice","transcription","azure","microsoft-cognitive-services","cognitive-services","nitro-modules","turbomodule","fabric","new-architecture"],"dependencies":{"@clarionhq/core":"0.2.0"},"peerDependencies":{"react":">=18.3.1","react-native":">=0.77.0","react-native-nitro-modules":">=0.35.0"},"devDependencies":{"nitrogen":"^0.35.6","react":"18.3.1","react-native":"0.77.3","react-native-nitro-modules":"^0.35.6"},"license":"MIT","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/Th4nderG0d/clarion.git","directory":"packages/azure"},"scripts":{"build":"tsc -p tsconfig.json","typecheck":"tsc -p tsconfig.json --noEmit","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","nitro:codegen":"nitrogen","clean":"rm -rf lib nitrogen"},"_id":"@clarionhq/azure@0.2.0","bugs":{"url":"https://github.com/Th4nderG0d/clarion/issues"},"homepage":"https://github.com/Th4nderG0d/clarion#readme","_integrity":"sha512-RSwy/MJjszoI03xRZ8IMKMlspnWuNCqhpKflJgGVp6BHsbjA9j4pCWlcUIV5FOPfC0b9ZaEzPLjgZmxNseFb3Q==","_resolved":"/private/var/folders/l1/vglrz9gn7ln7_4j02tyqjpjc0000gp/T/cedd34c47084c38cc3f0459ba4f1692e/clarionhq-azure-0.2.0.tgz","_from":"file:clarionhq-azure-0.2.0.tgz","_nodeVersion":"24.5.0","_npmVersion":"11.5.1","dist":{"integrity":"sha512-RSwy/MJjszoI03xRZ8IMKMlspnWuNCqhpKflJgGVp6BHsbjA9j4pCWlcUIV5FOPfC0b9ZaEzPLjgZmxNseFb3Q==","shasum":"9bc9ee66730b5dc4bf7b7ef0121f05338515a7cb","tarball":"https://registry.npmjs.org/@clarionhq/azure/-/azure-0.2.0.tgz","fileCount":124,"unpackedSize":482823,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFbsEnt6vIBnC88DoAAlENaH0jExVGhTHbEMc97RaukRAiEArilcEEA4JzaLAaujS1CE8AJUB6esneZGnK220l35lZw="}]},"_npmUser":{"name":"anvesh-dev","email":"anveshk282@gmail.com"},"directories":{},"maintainers":[{"name":"anvesh-dev","email":"anveshk282@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/azure_0.2.0_1779700062023_0.24209166281626948"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-18T06:08:42.333Z","modified":"2026-05-25T09:07:42.310Z","0.0.1":"2026-05-18T06:08:42.597Z","0.2.0":"2026-05-25T09:07:42.190Z"},"bugs":{"url":"https://github.com/Th4nderG0d/clarion/issues"},"license":"MIT","homepage":"https://github.com/Th4nderG0d/clarion#readme","keywords":["react-native","speech","speech-recognition","stt","voice","transcription","azure","microsoft-cognitive-services","cognitive-services","nitro-modules","turbomodule","fabric","new-architecture"],"repository":{"type":"git","url":"git+https://github.com/Th4nderG0d/clarion.git","directory":"packages/azure"},"description":"Clarion azure — Microsoft Cognitive Services Speech SDK wrapper for React Native","maintainers":[{"name":"anvesh-dev","email":"anveshk282@gmail.com"}],"readme":"# @clarionhq/azure\n\nReact Native wrapper for the **Microsoft Cognitive Services Speech SDK** — high-quality streaming speech-to-text with per-word timestamps, speaker diarization, custom vocab, mid-session resilience, and structured errors. Built on the New Architecture with [Nitro Modules](https://nitro.margelo.com). 16 KB page-size compliant.\n\n```tsx\nimport { AzureEngine } from '@clarionhq/azure';\n\nconst engine = new AzureEngine({\n  auth: { subscriptionKey: process.env.AZURE_SPEECH_KEY!, region: 'eastus' },\n  recognition: { language: 'en-US' },\n});\n\nengine.on(e => {\n  if (e.type === 'partial')         setLive(e.result.text);\n  if (e.type === 'final')           appendPhrase(e.result);\n  if (e.type === 'speech-started')  showRecordingIndicator();\n  if (e.type === 'speech-ended')    hideRecordingIndicator();\n  if (e.type === 'error')           handleError(e.error);\n  if (e.type === 'warning')         logWarning(e.warning);\n});\n\nawait engine.start();   // permission + prepare + listen — one call\n// later…\nawait engine.stop();    // returns immediately; final transcript arrives via 'final'\n```\n\n## Install\n\n```sh\npnpm add @clarionhq/azure @clarionhq/core react-native-nitro-modules\ncd ios && pod install\n```\n\nOptional companion packages (gracefully degraded if missing):\n\n```sh\npnpm add @react-native-community/netinfo   # enables mid-session network drop detection\n```\n\nThe pod resolves `MicrosoftCognitiveServicesSpeech-iOS ~> 1.40` automatically. On Android, `com.microsoft.cognitiveservices.speech:client-sdk:1.40.0` is pulled via Maven Central — no extra setup.\n\n## Requirements\n\n| | |\n|---|---|\n| React Native | 0.77+ with New Architecture + Hermes |\n| Android | API 26+, `INTERNET` (auto-merged) |\n| iOS | 15.1+ |\n| Network | Required at all times (Azure is server-side) |\n\n## Permissions\n\n### iOS — add to `Info.plist`\n\n```xml\n<key>NSMicrophoneUsageDescription</key>\n<string>We use the microphone for transcription.</string>\n```\n\nFor backgrounding support, also:\n\n```xml\n<key>UIBackgroundModes</key>\n<array><string>audio</string></array>\n```\n\n### Android — already merged into your manifest\n\n`RECORD_AUDIO`, `INTERNET`, `ACCESS_NETWORK_STATE` come in automatically. You're responsible for requesting `RECORD_AUDIO` at runtime — see [`PermissionsAndroid`](https://reactnative.dev/docs/permissionsandroid).\n\n## Configuration\n\nThe constructor takes a single grouped object: `{ auth, recognition, advanced?, telemetry? }`.\n\n### Auth (pick one variant)\n\n```ts\n// Simplest — ships the key in the app. Fine for prototypes.\n{ auth: { subscriptionKey: '...', region: 'eastus' } }\n\n// Recommended for production — short-lived token from your server.\n{ auth: { authToken: '...', region: 'eastus' } }\n\n// Best for production — token provider callback the engine calls when fresh tokens are needed.\n{ auth: {\n    tokenProvider: async () => fetch('/api/azure-token').then(r => r.text()),\n    region: 'eastus',\n    tokenTtlMs: 10 * 60 * 1000,   // optional — defaults to Azure's 10-minute TTL\n  } }\n\n// Custom endpoint — sovereign clouds, private endpoints, custom speech models.\n{ auth: { endpoint: 'wss://...', subscriptionKey: '...' } }\n```\n\nWith `tokenProvider`, the engine **proactively refreshes** the token ~60 s before expiry, and **on-demand** when a `TOKEN_EXPIRED` error surfaces mid-session. You also get `warning[TOKEN_NEAR_EXPIRY]` events for observability.\n\n### Recognition\n\n```ts\n{\n  language: 'en-US',                          // BCP-47, required\n  emitPartials: true,                         // interim transcripts as user speaks\n  partialDebounceMs: 100,                     // smooth flicker by throttling partials\n  outputFormat: 'detailed',                   // 'simple' | 'detailed' (enables word segments)\n  profanity: 'masked',                        // 'masked' | 'removed' | 'raw' | 'none'\n  silenceTimeoutMs: 0,                        // auto-stop after N ms silence (0 = off)\n  lowConfidenceThreshold: 0,                  // emit 'audio-confidence' below this (0 = off)\n  phraseHints: ['Clarionhq', 'Margelo'],      // bias recognition on custom vocab\n  enableSpeakerDiarization: false,            // S0 + en-US only\n  degradeOnTierMismatch: false,               // if diarization unavailable, fall back silently\n  autoDetectLanguages: ['en-US', 'es-MX'],    // empty = disabled\n}\n```\n\n### Advanced\n\n```ts\n{\n  emitAudioLevel: false,                      // Azure ignores (SDK owns the mic)\n  audioLevelIntervalMs: 50,\n  prepareTimeoutMs: 15_000,                   // hard timeout for prepare() handshake\n  allowMultipleInstances: false,              // 2nd instance throws by default\n  autoStopOnBackground: true,                 // stop on AppState='background'\n  maxClockSkewMs: 5 * 60 * 1000,              // 0 = disable check\n  skipAuthPreflight: false,                   // disable JS-side /issueToken check (sovereign clouds, etc.)\n  autoRetry: {                                // exponential backoff on transient errors\n    maxAttempts: 2,\n    baseDelayMs: 500,\n    retryOn: ['NETWORK_DROPPED', 'SERVICE_DOWN', 'NETWORK_UNAVAILABLE'],\n  },\n  persistFinals: {                            // recover transcripts across app crashes\n    storage: AsyncStorage,                    // any { getItem, setItem, removeItem }\n  },\n}\n```\n\n### Telemetry\n\n```ts\n{\n  onSessionStart: ({ sessionId, language }) => track('azure_session_start', { sessionId }),\n  onSessionEnd:   summary => track('azure_session_end', summary),\n  onError:        error   => track('azure_error',       error.toJSON()),\n  onWarning:      warn    => track('azure_warning',     warn),\n  onUsageUpdate:  ({ sessionId, elapsedMs }) => updateUsageMeter(sessionId, elapsedMs),\n}\n```\n\n## API\n\n`AzureEngine` implements the shared [`ClarionEngine`](https://github.com/Th4nderG0d/clarion/tree/main/packages/core) interface.\n\n```ts\nclass AzureEngine implements ClarionEngine {\n  readonly kind = 'azure-recognizer';\n  readonly state: EngineState;\n  readonly options: Readonly<AzureEngineOptions>;\n\n  // One-shot probe — builds the config without contacting the service.\n  static isAvailable(options: AzureEngineOptions): Promise<boolean>;\n\n  prepare(): Promise<void>;       // optional; start() auto-prepares\n  start(): Promise<void>;\n  stop(): Promise<void>;          // optimistic — emits 'final' immediately, tail finals continue ~2s\n  discard(): Promise<void>;\n  release(): Promise<void>;       // idempotent\n\n  updateAuthToken(token: string): Promise<void>;\n  replay(sessionId: string): Promise<number>;   // re-emit persisted finals\n\n  on(listener: (e: ClarionEvent) => void): Unsubscribe;\n}\n```\n\n### Events\n\n| Event | When |\n|---|---|\n| `state` | Lifecycle transitions: `idle → preparing → ready → starting → recording → stopping → idle` |\n| `partial` | Mid-phrase interim transcripts (debounced) |\n| `final` | One per phrase during the session; also a session-stitched final from `stop()` |\n| `speech-started` | Recognizer detected the start of speech |\n| `speech-ended` | Recognizer detected the end of speech |\n| `audio-confidence` | Phrase final's confidence is below `lowConfidenceThreshold` |\n| `audio-level` | RMS + peak meter ticks (Azure-side: no-op) |\n| `warning` | Non-fatal advisory (token-near-expiry, retry-attempted, backgrounded, network blip) |\n| `error` | Typed `ClarionError` (see below) |\n\n### Errors\n\nEvery error is a `ClarionError` with:\n\n```ts\ninterface ClarionError {\n  code: ErrorCode;             // typed enum below\n  message: string;             // technical, safe to log\n  userMessage?: string;        // non-technical, safe to show\n  recoverable: boolean;        // true for transient errors the caller can retry\n  retryAfterMs?: number;       // backoff hint when recoverable\n  openSettings?: boolean;      // true for permission errors (deep-link helper)\n  where?: ErrorOrigin;         // 'prepare' | 'start' | 'mid-session' | ...\n  details?: { sessionId, nativeCode, nativeDomain, ... };\n  toJSON(): Record<string, unknown>;\n}\n```\n\n| Code | Meaning |\n|---|---|\n| `INVALID_CONFIG` | Bad option (region shape, key length, missing auth) — caught at construction |\n| `PERMISSION_DENIED` / `PERMISSION_REVOKED` | Mic permission not granted / revoked mid-session |\n| `AUTH_FAILED` / `TOKEN_EXPIRED` | Bad key / expired token |\n| `NETWORK_UNAVAILABLE` / `NETWORK_TIMEOUT` / `NETWORK_DROPPED` / `DNS_FAILURE` | Connectivity |\n| `SERVICE_DOWN` / `QUOTA_EXCEEDED` | Azure-side |\n| `UNSUPPORTED_LANGUAGE` / `UNSUPPORTED_FORMAT` / `TIER_INSUFFICIENT` | Feature not available on this tier / locale |\n| `AUDIO_BUSY` / `AUDIO_SESSION_INTERRUPTED` / `AUDIO_ROUTE_CHANGED` | Mic in use / phone call / BT swap |\n| `STORAGE_FULL` | Recorder only — not relevant to Azure |\n| `ENGINE_NOT_READY` / `INVALID_STATE` | API misuse |\n| `INTERRUPTED` / `CANCELLED` | Session terminated mid-flight |\n| `INTERNAL_ERROR` / `UNKNOWN` | Catch-all |\n\nUse [`openAppSettings()`](https://github.com/Th4nderG0d/clarion/tree/main/packages/core/src/settings.ts) from `@clarionhq/core` to deep-link to system Settings when `error.openSettings === true`.\n\n## Regions\n\n```ts\nimport { AZURE_REGIONS, AZURE_DIARIZATION_REGIONS, isKnownAzureRegion } from '@clarionhq/azure';\n\n// AZURE_REGIONS  — 30+ curated slugs, IDE autocomplete\n// AZURE_DIARIZATION_REGIONS — subset that confirmed-host conversation transcriber\n```\n\nThe validator only **shape-checks** region slugs, so future regions still work — these constants are for autocomplete + sensible defaults.\n\n## Cost\n\nAzure Speech billing as of writing: **$1 / audio-hour** on Standard. 5 free hours/month on the F0 tier. See [azure.microsoft.com/pricing](https://azure.microsoft.com/pricing/details/cognitive-services/speech-services).\n\nTips:\n\n- Always `release()` when the user navigates away — a hung session keeps billing.\n- Set `silenceTimeoutMs` for hands-free UIs to auto-end sessions.\n- Use `telemetry.onUsageUpdate` to surface \"X of 5 free hours used\" to your users.\n- Use `@clarionhq/hybrid` (sibling package) to route to native recognizer when offline.\n\n## Production checklist\n\nSee [`PRODUCTION.md`](./PRODUCTION.md) for the full pre-ship checklist (token-server pattern, observability wiring, region selection, etc.).\n\n## Smoke test\n\nStep-by-step verification matrix in [`SMOKE_TEST.md`](./SMOKE_TEST.md).\n\n## Migration from 0.1.x\n\nThe 0.2.0 release reshaped the constructor from flat to grouped. The flat shape is still accepted with a one-time deprecation warning. To migrate:\n\n```ts\n// 0.1.x (still works, deprecated)\nnew AzureEngine({\n  subscriptionKey: '...', region: 'eastus', language: 'en-US',\n  emitPartials: true, outputFormat: 'detailed',\n});\n\n// 0.2.x (preferred)\nnew AzureEngine({\n  auth: { subscriptionKey: '...', region: 'eastus' },\n  recognition: { language: 'en-US', emitPartials: true, outputFormat: 'detailed' },\n});\n```\n\nAll other behavior is backward-compatible. See [`CHANGELOG.md`](./CHANGELOG.md) for the full list.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}