@vocalstack/js-sdk 1.0.13 → 2.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +112 -69
  3. package/SKILL.md +252 -0
  4. package/dist/errors.d.ts +40 -0
  5. package/dist/errors.js +74 -0
  6. package/dist/file.d.ts +2 -0
  7. package/dist/file.js +38 -0
  8. package/dist/http.d.ts +75 -0
  9. package/dist/http.js +122 -0
  10. package/dist/index.d.ts +56 -2
  11. package/dist/index.js +65 -17
  12. package/dist/mic.d.ts +75 -0
  13. package/dist/mic.js +258 -0
  14. package/dist/realtime.d.ts +132 -0
  15. package/dist/realtime.js +450 -0
  16. package/dist/resources.d.ts +521 -0
  17. package/dist/resources.js +787 -0
  18. package/dist/subscription.d.ts +55 -0
  19. package/dist/subscription.js +164 -0
  20. package/dist/ws.d.ts +12 -0
  21. package/dist/ws.js +15 -0
  22. package/package.json +32 -36
  23. package/skills/vocalstack/SKILL.md +252 -0
  24. package/dist/RestApi.d.ts +0 -21
  25. package/dist/RestApi.js +0 -94
  26. package/dist/VocalStackApi.d.ts +0 -20
  27. package/dist/VocalStackApi.js +0 -51
  28. package/dist/WebsocketApi.d.ts +0 -38
  29. package/dist/WebsocketApi.js +0 -150
  30. package/dist/apis/Billing.d.ts +0 -59
  31. package/dist/apis/Billing.js +0 -21
  32. package/dist/apis/LiveTranscription.d.ts +0 -58
  33. package/dist/apis/LiveTranscription.js +0 -55
  34. package/dist/apis/Polyglot.d.ts +0 -113
  35. package/dist/apis/Polyglot.js +0 -68
  36. package/dist/apis/Security.d.ts +0 -25
  37. package/dist/apis/Security.js +0 -35
  38. package/dist/apis/Transcriptions.d.ts +0 -61
  39. package/dist/apis/Transcriptions.js +0 -43
  40. package/dist/apis/UrlTranscription.d.ts +0 -59
  41. package/dist/apis/UrlTranscription.js +0 -53
  42. package/dist/apis/index.d.ts +0 -6
  43. package/dist/apis/index.js +0 -22
  44. package/dist/esm/ApiVersion.d.ts +0 -2
  45. package/dist/esm/ApiVersion.js +0 -28
  46. package/dist/esm/RestApi.d.ts +0 -21
  47. package/dist/esm/RestApi.js +0 -91
  48. package/dist/esm/VocalStackApi.d.ts +0 -19
  49. package/dist/esm/VocalStackApi.js +0 -46
  50. package/dist/esm/WebsocketApi.d.ts +0 -38
  51. package/dist/esm/WebsocketApi.js +0 -146
  52. package/dist/esm/apis/Billing.d.ts +0 -59
  53. package/dist/esm/apis/Billing.js +0 -17
  54. package/dist/esm/apis/LiveTranscription.d.ts +0 -58
  55. package/dist/esm/apis/LiveTranscription.js +0 -51
  56. package/dist/esm/apis/Polyglot.d.ts +0 -113
  57. package/dist/esm/apis/Polyglot.js +0 -64
  58. package/dist/esm/apis/Security.d.ts +0 -25
  59. package/dist/esm/apis/Security.js +0 -31
  60. package/dist/esm/apis/Transcriptions.d.ts +0 -61
  61. package/dist/esm/apis/Transcriptions.js +0 -39
  62. package/dist/esm/apis/UrlTranscription.d.ts +0 -59
  63. package/dist/esm/apis/UrlTranscription.js +0 -49
  64. package/dist/esm/apis/index.d.ts +0 -6
  65. package/dist/esm/apis/index.js +0 -6
  66. package/dist/esm/generics.zod.d.ts +0 -77
  67. package/dist/esm/generics.zod.js +0 -45
  68. package/dist/esm/index.d.ts +0 -2
  69. package/dist/esm/index.js +0 -2
  70. package/dist/esm/version.d.ts +0 -1
  71. package/dist/esm/version.js +0 -1
  72. package/dist/generics.zod.d.ts +0 -77
  73. package/dist/generics.zod.js +0 -48
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- VocalStack Proprietary License
2
-
3
- Copyright (C) 2024 VocalStack
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to use the Software solely in connection with the VocalStack service, subject to the following conditions:
6
-
7
- ## Usage Limitations
8
-
9
- 1. **Compliance with Terms of Service**: The Software must be used in a manner that does not violate the VocalStack terms of service ([https://www.vocalstack.com/terms-of-service](https://www.vocalstack.com/terms-of-service)).
10
-
11
- 2. **Commercial Use Allowed**: The Licensed Work may be used for commercial purposes, provided the user has a valid API key and an active subscription to the VocalStack service. Unauthorized use is strictly prohibited.
12
-
13
- 3. **Modification and Contributions**: You may view and modify the Licensed Work for internal use only. Contributions to the Licensed Work may be made through pull requests. By submitting a contribution, you agree to assign the rights of the contribution to VocalStack.
14
-
15
- 4. **Redistribution Allowed**: Redistribution of the Software, in whole or in part, whether modified or unmodified, is permitted, provided that it does not violate the company's terms of service.
16
-
17
- 5. **Termination**: VocalStack reserves the right to terminate your access to and use of the Software at any time if you fail to comply with these terms.
18
-
19
- ## Disclaimer
20
-
21
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 VocalStack
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,89 +1,132 @@
1
- [![](/logo.svg 'VocalStack')](https://vocalstack.com)
1
+ # @vocalstack/js-sdk
2
2
 
3
- > VocalStack is a platform that can be used for building voice applications. See more at [https://vocalstack.com](vocalstack.com).
3
+ The VocalStack speech API for Node (20 or newer) and browsers: one client,
4
+ `VocalStack`, with one group per resource, typed from the API's one OpenAPI
5
+ document (`/v1/openapi.json`, generated into `@vocalstack/contract`).
4
6
 
5
- This repository contains the official VocalStack SDK for JavaScript. It provides a simple way
6
- to interact with the [VocalStack API](https://vocalstack.com/api).
7
- Most notably, it helps implement asynchronous bidirectional communication
8
- such as live stream transcriptions in just a few lines of code.
9
- This SDK will work in both Node.js and the browser.
7
+ ```ts
8
+ import { VocalStack } from '@vocalstack/js-sdk';
10
9
 
10
+ const vs = new VocalStack({ apiKey: process.env.VOCALSTACK_API_KEY }); // baseUrl defaults to https://api.vocalstack.com
11
11
 
12
- # Installation
12
+ // A stored transcription of a link (or `file:` a path, Blob or bytes).
13
+ const tx = await vs.transcriptions.create({ url: 'https://example.com/talk.mp3' });
14
+ const job = await vs.jobs.wait(tx.job!.recordingId); // done | failed | cropping
15
+ const { sentences } = await vs.recordings.transcript(job.recordingId);
13
16
 
14
- Before you start, install the VocalStack JavaScript SDK using your preferred Node package manager, such as npm:
15
-
16
- ```bash
17
- npm install @vocalstack/js-sdk
17
+ const srt = await (await vs.recordings.export(job.recordingId, 'srt')).text();
18
18
  ```
19
19
 
20
- Also make sure to have a [VocalStack account](https://vocalstack.com) and an API key, which you can generate
21
- at https://vocalstack.com/dashboard/api-keys.
22
- There is a free tier available, so you can start experimenting right away.
23
-
24
-
25
- # Quick Example
26
-
27
- Here is a quick example of how to use the SDK to transcribe a file from a URL:
28
- ```javascript
29
- import { UrlTranscription } from '@vocalstack/js-sdk';
30
-
31
- const sdk = new UrlTranscription({ apiKey: 'YOUR-API-KEY' });
32
- const transcription = await sdk.connect({
33
- url: 'http://example.com/files/meaningless.mp3',
20
+ <!-- sdk-docs: generated from the VocalStack API guides; edits here are overwritten -->
21
+
22
+ ## Install
23
+
24
+ Not on npm yet. The API serves its own builds to every account: [https://api.vocalstack.com/docs/guides/quickstart.md](https://api.vocalstack.com/docs/guides/quickstart.md) has the install command for the current build (it sends your API key to that host only).
25
+
26
+ ## Guides
27
+
28
+ - [Quickstart](https://github.com/vocalstack/js-sdk/blob/main/docs/quickstart.md): An API key, the SDK, and your first transcript in a dozen lines.
29
+ - [Transcribe a file](https://github.com/vocalstack/js-sdk/blob/main/docs/transcribe-a-file.md): Upload a file, wait for its job, read the transcript and export it. Asynchronous; nothing to keep open.
30
+ - [Transcribe a link](https://github.com/vocalstack/js-sdk/blob/main/docs/transcribe-a-link.md): The server fetches a public URL or a YouTube video, then transcribes it like a file. Asynchronous, with a fetch phase first.
31
+ - [Transcribe a batch of files](https://github.com/vocalstack/js-sdk/blob/main/docs/transcribe-a-batch.md): Send many files or links as one batch, start it once, and read every transcript when it is done. Cheaper than one transcription per file.
32
+ - [Stream a microphone](https://github.com/vocalstack/js-sdk/blob/main/docs/stream-a-microphone.md): Live audio in, transcript events out, over one WebSocket. Drafts replace the live tail; commits append.
33
+ - [Stream a file at full speed](https://github.com/vocalstack/js-sdk/blob/main/docs/stream-a-file.md): Send a file's bytes through a realtime session and read the transcript as fast as the server makes it. Nothing is stored.
34
+ - [Go live](https://github.com/vocalstack/js-sdk/blob/main/docs/go-live.md): Publish live audio to a stored transcription, and put it on a broadcast link listeners open. Control is HTTP; audio is one WebSocket.
35
+ - [Listen](https://github.com/vocalstack/js-sdk/blob/main/docs/listen.md): Follow a recording as it happens, in any language: subscribe, catch up from a snapshot, then apply live frames in order.
36
+ - [Live translation and spoken translations](https://github.com/vocalstack/js-sdk/blob/main/docs/translation-and-voices.md): Translate a stream as it is spoken, and have each translated sentence spoken back in a voice. Text frames and audio clips, over the same socket.
37
+ - [Connect an app with one click](https://github.com/vocalstack/js-sdk/blob/main/docs/connect-an-app.md): Let the people who use your app connect their VocalStack account with one Authenticate click — OAuth 2.0 authorization code with PKCE, where the access token is an API key — instead of pasting a key.
38
+ - [Errors, retries and limits](https://github.com/vocalstack/js-sdk/blob/main/docs/errors-and-limits.md): One error envelope everywhere; what to retry (429, 503 unavailable) and how to make a retry safe (Idempotency-Key); credit, plan limits and the 402s.
39
+
40
+ <!-- /sdk-docs -->
41
+
42
+ ## What is what
43
+
44
+ | Name | What it is | Group |
45
+ |---|---|---|
46
+ | realtime session | a signed token plus one socket; nothing stored | `vs.realtime` |
47
+ | broadcast | the link listeners open | `vs.broadcasts` |
48
+ | transcription | a file, link, microphone or stream, transcribed and stored (`live: true` for a microphone or stream) | `vs.transcriptions` |
49
+ | recording | one take inside a broadcast or a transcription | `vs.recordings` |
50
+ | job | a file or link recording's transcription work | `vs.jobs` |
51
+ | batch | many files transcribed together, for less than one transcription each | `vs.batches` |
52
+
53
+ The other groups: `vs.corrections`, `vs.shareLinks`, `vs.voices`,
54
+ `vs.search`, `vs.me`, `vs.languages`, `vs.rtmp`, `vs.events`, `vs.meta`.
55
+ Method names follow the document's `operationId`s (`broadcasts.startRecording`
56
+ is `POST /v1/broadcasts/{id}/recordings`); lists return arrays.
57
+
58
+ ## Options
59
+
60
+ ```ts
61
+ new VocalStack({
62
+ baseUrl, // default https://api.vocalstack.com
63
+ apiKey, // an API key (vs_key_…), for a server
64
+ token, // or, in a browser: an access token / browser token, or a getter (read per request)
65
+ actingPrincipal, // act for an organization (X-Acting-Principal)
66
+ deviceId, // correlation only (X-Device-Id)
67
+ fetch, // any fetch
68
+ maxRetries: 2, // 429s, and 503 unavailable on safe calls, retried after Retry-After (at most 60 s each)
69
+ readyDeadlineMs, // how long a realtime socket may take to report ready
34
70
  });
35
-
36
- transcription.start();
37
-
38
- // This will print the transcription data as it comes in
39
- transcription.onData(console.log);
40
-
41
- /*
42
- {
43
- status: 'processing',
44
- data: {
45
- id: 'd1e7b3b0-7b3b-4b3b-8b3b-0b3b7b3b3b3b',
46
- operation: 'transcription-prerecorded',
47
- progress: 0.1,
48
- timeline: [
49
- {
50
- start: 0,
51
- end: 7.52,
52
- text: 'Meaningless, meaningless, says the teacher, utterly meaningless, everything is meaningless.',
53
- language: 'en',
54
- translations: { ... },
55
- },
56
- ...
57
- ]
58
- }
59
- }
60
- */
61
71
  ```
62
72
 
73
+ Every call that creates something takes `{ idempotencyKey }` last.
63
74
 
64
- # Documentation Index
75
+ ## Realtime sessions
65
76
 
66
- - [Transcribe Audio from URL](https://github.com/vocalstack/js-sdk/blob/main/documentation/transcribe-audio-from-url-to-text.md):
67
- Transcribe speech from pre-recorded audio in a URL to plain text. Major file formats are supported, including MP3, WAV, FLAC, and OGG.
77
+ ```ts
78
+ const session = await vs.realtime.connect({ spokenLanguage: 'en' });
79
+ session.sendAudio(pcmChunk); // raw PCM, f32le, 16 kHz, mono, as binary frames
80
+ for await (const event of session) {
81
+ if (event.type === 'transcript.committed') render(event.segment);
82
+ }
83
+ session.eof(); // at end of source: final commits, then session.done
68
84
 
69
- - [Transcribe from a Microphone or LiveStream](https://github.com/vocalstack/js-sdk/blob/main/documentation/transcribe-from-a-microphone-or-live-stream.md):
70
- Transcribe live speech from a microphone or live stream. Integrate with Polyglot to create a public shareable link for the transcription which users can read in any language.
85
+ // A whole file through one socket, nothing stored:
86
+ const { text, segments } = await vs.realtime.transcribeFile('meeting.mp3', { spokenLanguage: 'en' });
87
+ ```
71
88
 
72
- - [Transcribe and Present a Polyglot Session](https://github.com/vocalstack/js-sdk/blob/main/documentation/transcribe-and-present-a-polyglot-session.md):
73
- Create a session that can be used to broadcast a live transcription via a public shareable link. Users can read live transcriptions in their preferred language, and even past transcriptions when your session is inactive.
89
+ - `transcript.draft` frames **fully replace** the live tail; never append them.
90
+ - `transcript.committed` segments are immutable, gapless by `segment.seq`,
91
+ and carry word timings.
92
+ - A dropped connection ends the session (no resume): start a new one.
93
+
94
+ ## Live recordings and listeners
95
+
96
+ ```ts
97
+ const b = await vs.broadcasts.create({ name: 'Release standup' }); // b.code is the link
98
+ const grant = await vs.broadcasts.startRecording(b.id); // 409 conflict + details.takeover
99
+ // when another device records
100
+ const stream = await vs.recordings.publish(grant); // the publisher socket
101
+ await vs.recordings.pause(grant.recording.id);
102
+ await vs.recordings.resume(grant.recording.id);
103
+ await vs.recordings.stop(grant.recording.id); // only from paused
104
+
105
+ // A listener (no account), holding a share link's code:
106
+ const link = await vs.broadcasts.createShareLink(b.id, { label: 'Audience' });
107
+ const anon = new VocalStack({ baseUrl, deviceId });
108
+ const sub = await anon.recordings.subscribe(grant.recording.id, { lang: 'es', shareCode: link.code, asOwner: false });
109
+ for await (const ev of sub) {
110
+ if (ev.type === 'snapshot') render(ev.snapshot); // backfill, initial or after a gap
111
+ if (ev.type === 'frame') apply(ev.frame); // transcript.*, recording.state, ...
112
+ }
113
+ ```
74
114
 
75
- - [Translate a Transcription](https://github.com/vocalstack/js-sdk/blob/main/documentation/translate-transcription-to-another-language.md):
76
- Translate transcribed text to another language. This can be done for any transcription, including prerecorded transcriptions, live transcriptions or Polyglot session transcriptions.
115
+ Browser microphone capture ships as `@vocalstack/js-sdk/mic`
116
+ (`streamMicrophone(session, { onStall, onRecover })`).
77
117
 
78
- - [Get Transcription Data](https://github.com/vocalstack/js-sdk/blob/main/documentation/get-transcription-data.md):
79
- Get data from pending or completed transcriptions. This includes the transcription timeline, key words, summary, and paragraph segments.
118
+ ## Errors
80
119
 
81
- - [Client Side Authentication Tokens](https://github.com/vocalstack/js-sdk/blob/main/documentation/transcribe-on-the-front-end-with-auth-tokens.md):
82
- Create a temporary authentication token for client side requests. Safely implement API requests in web browsers without exposing your API keys.
120
+ `VocalStackError` carries `code` (the contract's closed enum), `message`,
121
+ `status`, `retryable`, `details` (quota numbers, code suggestions,
122
+ `{ recordingId, takeover }`), `headers` and `retryAfter`.
83
123
 
84
- - [Transcription Sessions](https://github.com/vocalstack/js-sdk/blob/main/documentation/transcription-sessions.md):
85
- Monitor and manage transcription state with sessions. Using sessions you can reconnect to a previously created asynchronous connection.
124
+ ## Binary answers
86
125
 
87
- - [Transcription Request and Response](https://github.com/vocalstack/js-sdk/blob/main/documentation/transcription-request-and-response.md):
88
- Common request options and responses for all transcription operations. Use options to configure the transcription settings.
126
+ `recordings.export`, `recordings.clip`, `recordings.voiceClip`, `jobs.preview`,
127
+ `voices.preview`, `voices.clonePreview` and `voices.sample` return the
128
+ `Response` itself: `.text()`, `.arrayBuffer()` or stream it.
129
+ `recordings.audioUrl` returns the signed media URL.
89
130
 
131
+ Verified against a language-agnostic conformance suite shared by every
132
+ VocalStack SDK and against a running API. For agents: `SKILL.md`.
package/SKILL.md ADDED
@@ -0,0 +1,252 @@
1
+ ---
2
+ name: vocalstack
3
+ description: Use when writing Node or TypeScript code that calls the VocalStack speech API with @vocalstack/js-sdk, for example to transcribe an audio or video URL or a local file, stream live audio for realtime transcription, fetch or export a transcript (JSON, SRT, XLSX, PDF), or search transcripts. Covers installing, API keys, base URLs, five copy-paste programs and error handling (401, 402, 403, 429).
4
+ ---
5
+
6
+ # VocalStack TypeScript SDK
7
+
8
+ The VocalStack API transcribes speech (files, links, live audio), with speaker
9
+ labels and translation. `@vocalstack/js-sdk` has one client, `VocalStack`, with
10
+ one group per resource: `vs.transcriptions`, `vs.jobs`, `vs.recordings`,
11
+ `vs.broadcasts`, `vs.search`, `vs.realtime` and a few more (listed at the end).
12
+
13
+ ## What is what
14
+
15
+ - A **transcription** is a file, a link, a microphone or a stream, transcribed
16
+ and stored. Create one with `vs.transcriptions.create(...)`.
17
+ - A **recording** is one take inside it. Its id (`recordingId`) is what you
18
+ read the transcript and exports with: `vs.recordings.transcript(recordingId)`.
19
+ - A **job** is a file or link recording's transcription work:
20
+ `vs.jobs.wait(recordingId)` polls it until it is `done` or `failed`
21
+ (`{ onProgress: (job) => … }` sees each read: `job.state`, `job.progress.pct`).
22
+ - A **batch** is many files transcribed together for less than one
23
+ transcription each: `vs.batches.create()`, `addFile`/`addUrl` per file,
24
+ `start`, then `wait` (section 6).
25
+ - A **broadcast** is a link listeners open to follow a live recording.
26
+ - A **realtime session** (`vs.realtime`) is a socket you stream audio into and
27
+ read the transcript from. Nothing is stored. "Session" means only this.
28
+
29
+ ## Install
30
+
31
+ ```sh
32
+ npm init -y && npm pkg set type=module # in a new folder: the programs below are ESM
33
+ npm i @vocalstack/js-sdk # Node 20 or newer
34
+ ```
35
+
36
+ Before the package is published, any account installs
37
+ the private build its environment serves: the API reference's Install section
38
+ (`<base>/docs`, or Developers -> API reference in the app) and `<base>/sdk/latest`
39
+ give the exact commands, which send `VOCALSTACK_API_KEY` to that host only.
40
+ Or install it from a clone of https://github.com/vocalstack/js-sdk. Build it
41
+ first (`npm run build` also builds the bundled `contract/` package):
42
+
43
+ ```sh
44
+ git clone https://github.com/vocalstack/js-sdk && (cd js-sdk && npm install && npm run build)
45
+ npm i ./js-sdk
46
+ ```
47
+
48
+ Use ESM (`"type": "module"` in package.json, or `.mjs` files).
49
+
50
+ Speaker numbers start at 0. A speaker of `-1` means speaker labels were off
51
+ for that transcription, so print the text without a speaker.
52
+
53
+ ## Auth and base URL
54
+
55
+ - Read the key from `VOCALSTACK_API_KEY` and pass it as `apiKey`. It goes out
56
+ as `Authorization: Bearer <key>`, also on sockets.
57
+ - An API key starts with `vs_key_`. There is one kind of key: every call is
58
+ real usage on the account's tier and quotas.
59
+ - Keys are for servers. Never put a key in browser code or in a URL. The API
60
+ refuses a key sent from a web page (`Origin` header) or in a query string.
61
+ - Scopes: `read` (read transcripts, search, export), `write` and
62
+ `recordings:publish` (create transcriptions, stream live audio), or `*`.
63
+ - Base URL: `https://api.vocalstack.com` (the default). Override it with
64
+ `VOCALSTACK_BASE_URL` (for example, a local or staging server).
65
+
66
+ Every program below starts like this:
67
+
68
+ ```js
69
+ import { VocalStack } from '@vocalstack/js-sdk';
70
+ const vs = new VocalStack({
71
+ baseUrl: process.env.VOCALSTACK_BASE_URL, // absent: https://api.vocalstack.com
72
+ apiKey: process.env.VOCALSTACK_API_KEY,
73
+ });
74
+ ```
75
+
76
+ ## 1. Transcribe a URL and wait for the result
77
+
78
+ The server fetches the link itself, so it must be a public http(s) address.
79
+ Private, loopback and cloud-metadata addresses are refused.
80
+
81
+ ```js
82
+ import { VocalStack } from '@vocalstack/js-sdk';
83
+ const vs = new VocalStack({ baseUrl: process.env.VOCALSTACK_BASE_URL, apiKey: process.env.VOCALSTACK_API_KEY });
84
+
85
+ const tx = await vs.transcriptions.create({
86
+ url: 'https://raw.githubusercontent.com/openai/whisper/main/tests/jfk.flac',
87
+ name: 'JFK sample',
88
+ });
89
+ const recordingId = tx.job.recordingId;
90
+
91
+ // queued -> fetching -> transcribing -> done | failed
92
+ const job = await vs.jobs.wait(recordingId);
93
+ if (job.state !== 'done') throw new Error(`transcription ${job.state}: ${job.error}`);
94
+
95
+ const { sentences } = await vs.recordings.transcript(recordingId);
96
+ for (const s of sentences) console.log(s.speaker >= 0 ? `[speaker ${s.speaker}] ${s.text}` : s.text);
97
+ console.log('recordingId', recordingId);
98
+ ```
99
+
100
+ ## 2. Transcribe a local file
101
+
102
+ ```js
103
+ import { VocalStack } from '@vocalstack/js-sdk';
104
+ const vs = new VocalStack({ baseUrl: process.env.VOCALSTACK_BASE_URL, apiKey: process.env.VOCALSTACK_API_KEY });
105
+
106
+ const tx = await vs.transcriptions.create({
107
+ file: process.argv[2], // a path (mp3, wav, flac, ogg, m4a, mp4 ...), a Blob or bytes
108
+ settings: { spokenLanguage: 'en', speakerLabels: 'on' }, // both optional; speakerLabels: 'off' (default) | 'auto' | 'on'
109
+ // Off unless asked for: settings.summary, settings.title, settings.summaryTranslations,
110
+ // settings.voice (spoken translations), and shareLink: true (a public share link).
111
+ });
112
+ const job = await vs.jobs.wait(tx.job.recordingId);
113
+ if (job.state !== 'done') throw new Error(`transcription ${job.state}: ${job.error}`);
114
+
115
+ const { sentences } = await vs.recordings.transcript(job.recordingId);
116
+ console.log(sentences.map((s) => s.text).join(' '));
117
+ ```
118
+
119
+ ## 3. Fetch a transcript or an export file
120
+
121
+ `recordings.transcript` returns segments (with word timings), sentences and
122
+ speakers. `recordings.export` returns the file as a `Response`: formats `json`,
123
+ `srt`, `xlsx`, `pdf`; add `{ lang: '<code>' }` for a translated file.
124
+
125
+ ```js
126
+ import { writeFile } from 'node:fs/promises';
127
+ import { VocalStack } from '@vocalstack/js-sdk';
128
+ const vs = new VocalStack({ baseUrl: process.env.VOCALSTACK_BASE_URL, apiKey: process.env.VOCALSTACK_API_KEY });
129
+ const recordingId = process.argv[2];
130
+
131
+ const snap = await vs.recordings.transcript(recordingId);
132
+ console.log(`${snap.segments.length} segments, ${snap.sentences.length} sentences, state ${snap.state}`);
133
+
134
+ const res = await vs.recordings.export(recordingId, 'srt');
135
+ await writeFile('transcript.srt', Buffer.from(await res.arrayBuffer()));
136
+ ```
137
+
138
+ ## 4. Live transcription from a microphone or a file
139
+
140
+ A live transcription takes raw PCM: 32-bit float little-endian, 16 kHz, mono.
141
+ Create it, start a recording, and open the publisher socket the grant names.
142
+ Here ffmpeg decodes a file at realtime speed (`-re`). For a microphone, swap
143
+ the input: `-f avfoundation -i :0` on macOS, `-f pulse -i default` on Linux.
144
+ (`@vocalstack/js-sdk/mic` is for browsers, and browsers must not hold API keys.)
145
+
146
+ ```js
147
+ import { spawn } from 'node:child_process';
148
+ import { VocalStack } from '@vocalstack/js-sdk';
149
+ const vs = new VocalStack({ baseUrl: process.env.VOCALSTACK_BASE_URL, apiKey: process.env.VOCALSTACK_API_KEY });
150
+
151
+ const tx = await vs.transcriptions.createLive({ name: 'Live demo', settings: { spokenLanguage: 'en' } });
152
+ const grant = await vs.transcriptions.startRecording(tx.id);
153
+ const stream = await vs.recordings.publish(grant, { readyDeadlineMs: 180_000 }); // a cold engine can take a while
154
+
155
+ const ff = spawn('ffmpeg', ['-loglevel', 'error', '-re', '-i', process.argv[2],
156
+ '-f', 'f32le', '-ac', '1', '-ar', '16000', '-']);
157
+ ff.stdout.on('data', (chunk) => stream.sendAudio(new Uint8Array(chunk)));
158
+ ff.on('close', () => stream.eof()); // eof() ends the recording
159
+
160
+ for await (const ev of stream) {
161
+ if (ev.type === 'transcript.committed') console.log(`[speaker ${ev.segment.speaker}] ${ev.segment.text}`);
162
+ // also: 'transcript.draft' (replaces the live tail), 'transcript.sentence', 'transcript.translated'
163
+ }
164
+
165
+ // To end a recording without eof(): vs.recordings.pause(id), then vs.recordings.stop(id).
166
+ const { sentences } = await vs.recordings.transcript(grant.recording.id);
167
+ console.log('final:', sentences.map((s) => s.text).join(' '));
168
+ ```
169
+
170
+ To transcribe without storing anything, use a realtime session instead:
171
+ `await vs.realtime.transcribeFile('talk.mp3')` returns `{ text, segments }`.
172
+
173
+ ## 5. Search transcripts
174
+
175
+ ```js
176
+ import { VocalStack } from '@vocalstack/js-sdk';
177
+ const vs = new VocalStack({ baseUrl: process.env.VOCALSTACK_BASE_URL, apiKey: process.env.VOCALSTACK_API_KEY });
178
+
179
+ const { hits } = await vs.search.query(process.argv[2] ?? 'country', { limit: 5 }); // q: 2+ characters
180
+ for (const h of hits) {
181
+ console.log(`${h.linkName} @ ${h.mediaStart.toFixed(1)}s [speaker ${h.speaker}]: ${h.text} (recording ${h.recordingId})`);
182
+ }
183
+ ```
184
+
185
+ ## 6. A batch of files
186
+
187
+ Many files at once cost less as a batch: one create, one minimum charge for
188
+ the whole batch. Its files get transcripts, exports and speaker labels (when
189
+ `settings.speakerLabels` asks), never a summary, title, share link or voices.
190
+
191
+ ```js
192
+ import { VocalStack } from '@vocalstack/js-sdk';
193
+ const vs = new VocalStack({ baseUrl: process.env.VOCALSTACK_BASE_URL, apiKey: process.env.VOCALSTACK_API_KEY });
194
+
195
+ const batch = await vs.batches.create({ name: 'Interviews', settings: { spokenLanguage: 'en' } });
196
+ for (const path of process.argv.slice(2)) await vs.batches.addFile(batch.id, { file: path }); // or addUrl(batch.id, url)
197
+ await vs.batches.start(batch.id);
198
+ const done = await vs.batches.wait(batch.id); // done (or stopped); check done.counts.failed
199
+ for (const tx of done.files ?? []) {
200
+ if (tx.job?.state !== 'done') continue;
201
+ const { sentences } = await vs.recordings.transcript(tx.job.recordingId);
202
+ console.log(tx.name, sentences.map((s) => s.text).join(' '));
203
+ }
204
+ // vs.batches.export(batch.id, 'srt') is every finished transcript in one zip.
205
+ ```
206
+
207
+ ## Errors
208
+
209
+ A failed call throws `VocalStackError` with `code`, `message`, `status`,
210
+ `retryable`, `details` (the body's `data.details`), `headers` and
211
+ `retryAfter` (seconds, from `Retry-After`). A `429`, and a `503 unavailable`
212
+ on a call that is safe to repeat, is retried for you after its `Retry-After`,
213
+ twice by default (`maxRetries` on the client).
214
+
215
+ | Status | `code` | What to do |
216
+ |---|---|---|
217
+ | 401 | `invalid_token`, `key_expired`, `key_revoked` | Check `VOCALSTACK_API_KEY`. Use the replacement key, or create a new one. |
218
+ | 403 | `forbidden` | Usually a missing scope: the message names it, and `err.headers.get('www-authenticate')` lists the scopes the route needs. A suspended key or account gets `suspended`. |
219
+ | 403 | `terms_acceptance_required` | The account has not accepted the current Terms of Service and Privacy Policy: someone signs in to the Dashboard and accepts them (an organisation's keys work once an owner or admin has). Not retryable until then. |
220
+ | 402 | `insufficient_credit` | The account's credit is out, or does not cover the transcription: every transcription is billed at least the plan's minimum (`rates.minimumSeconds`, 5 minutes). `details`: `balance`, `plan`, `topUpUrl`, and `required` when the cost was known up front. Add credit; `vs.billing.get()` shows the balance. |
221
+ | 409 | `payment_method_required` | Auto top-up (`vs.billing.setAutoTopUp`) and the portal (`vs.billing.portal()`) need a payment first (`vs.billing.createCheckout({ kind: 'topup', amount, acceptTerms: true })` opens one; a signed-in person's token, never an API key). |
222
+ | 402 | `quota_exceeded` | The plan's transcriptions-at-once limit is reached. `details`: `metric` (`concurrent_transcriptions`), `limit`, `used`, `plan`, `topUpUrl`. |
223
+ | 429 | `rate_limited` | Retried automatically; if it still fails, wait `err.retryAfter` seconds. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`. |
224
+ | 503 | `unavailable` | The service is waking (its database was asleep). Retried automatically after `Retry-After` (2 s) on calls that are safe to repeat: GET, HEAD, DELETE, or any call with `{ idempotencyKey }`. A create without a key is not retried: retry it yourself, with an `idempotencyKey` so it cannot run twice. A realtime socket refused this way throws `unavailable`; a bare 503 there is `capacity_exceeded`. |
225
+
226
+ ```js
227
+ import { VocalStack, VocalStackError } from '@vocalstack/js-sdk';
228
+ const vs = new VocalStack({ baseUrl: process.env.VOCALSTACK_BASE_URL, apiKey: process.env.VOCALSTACK_API_KEY });
229
+
230
+ try {
231
+ await vs.search.query('country');
232
+ } catch (err) {
233
+ if (!(err instanceof VocalStackError)) throw err;
234
+ if (err.code === 'insufficient_credit' || err.code === 'quota_exceeded') console.error(err.message, err.details);
235
+ else console.error(err.status, err.code, err.message);
236
+ }
237
+ ```
238
+
239
+ ## More
240
+
241
+ - The other groups: `vs.transcriptions` (`list`, `get`, `update`, `archive`,
242
+ `restore`, `purge`, `listShareLinks`, `createShareLink`), `vs.recordings`
243
+ (`get`, `summarize`, `summary`, `translation`, `audioUrl`, `subscribe` for a
244
+ live transcript feed), `vs.batches` (`create`, `addFile`, `addUrl`, `start`,
245
+ `wait`, `get`, `list`, `export`, `stop`, `delete`), `vs.corrections`, `vs.shareLinks`, `vs.voices`,
246
+ `vs.broadcasts`, `vs.me` (`get`, `usage`), `vs.languages`,
247
+ `vs.rtmp`, `vs.events`, `vs.meta`. Each method is named after its operation
248
+ in the OpenAPI document (`transcriptions.create` is `POST /v1/transcriptions`).
249
+ - `<base>/llms.txt` lists every operation in a form written for agents.
250
+ `<base>/llms-full.txt` adds parameters, auth mode, tier and scopes.
251
+ - `<base>/docs` is the interactive reference. `<base>/v1/openapi.json` is
252
+ the OpenAPI document; the SDK's types are generated from it.
@@ -0,0 +1,40 @@
1
+ import type { ErrorCode } from '@vocalstack/contract';
2
+ /** The OAuth errors `vs.connect.token()` raises (RFC 6749 §5.2): the token
3
+ * endpoint answers `400 { error, error_description }`, not the envelope. */
4
+ export type ConnectTokenErrorCode = 'invalid_request' | 'invalid_grant' | 'unsupported_grant_type';
5
+ export interface VocalStackErrorOptions {
6
+ retryable?: boolean;
7
+ status?: number;
8
+ details?: unknown;
9
+ headers?: Headers;
10
+ requestId?: string;
11
+ }
12
+ /** Every failure this SDK surfaces: an HTTP error envelope, a socket
13
+ * `error` frame, or one the transport synthesizes (`capacity_exceeded`). */
14
+ export declare class VocalStackError extends Error {
15
+ /** The envelope's code; on `vs.connect.token()`, the OAuth `error`. */
16
+ readonly code: ErrorCode | ConnectTokenErrorCode;
17
+ readonly retryable: boolean;
18
+ /** HTTP status, when the error came from an HTTP response. */
19
+ readonly status?: number;
20
+ /** The envelope's `data.details`: for example `{ balance, required,
21
+ * plan, topUpUrl }` on `insufficient_credit`, code suggestions on a
22
+ * link conflict, `{ recordingId, takeover: true }` when another device
23
+ * is recording. */
24
+ readonly details?: unknown;
25
+ /** The response headers (`Retry-After`, `RateLimit-*`,
26
+ * `WWW-Authenticate`), when the error came from an HTTP response. */
27
+ readonly headers?: Headers;
28
+ /** The request's id (the envelope's `requestId`, else the `X-Request-Id`
29
+ * header): quote it when reporting a failure. */
30
+ readonly requestId?: string;
31
+ constructor(code: ErrorCode | ConnectTokenErrorCode, message: string, opts?: VocalStackErrorOptions);
32
+ /** Seconds the server asked the caller to wait (`Retry-After`), if it said. */
33
+ get retryAfter(): number | undefined;
34
+ }
35
+ export declare function capacityExceeded(message: string): VocalStackError;
36
+ export declare function fromEnvelope(body: unknown, status?: number, headers?: Headers): VocalStackError;
37
+ /** A token endpoint's `400 { error, error_description }` (RFC 6749 §5.2) as
38
+ * a `VocalStackError` whose `code` is the `error`; any other answer goes
39
+ * through the envelope. */
40
+ export declare function fromOAuth(body: unknown, status?: number, headers?: Headers): VocalStackError;
package/dist/errors.js ADDED
@@ -0,0 +1,74 @@
1
+ /** Every failure this SDK surfaces: an HTTP error envelope, a socket
2
+ * `error` frame, or one the transport synthesizes (`capacity_exceeded`). */
3
+ export class VocalStackError extends Error {
4
+ /** The envelope's code; on `vs.connect.token()`, the OAuth `error`. */
5
+ code;
6
+ retryable;
7
+ /** HTTP status, when the error came from an HTTP response. */
8
+ status;
9
+ /** The envelope's `data.details`: for example `{ balance, required,
10
+ * plan, topUpUrl }` on `insufficient_credit`, code suggestions on a
11
+ * link conflict, `{ recordingId, takeover: true }` when another device
12
+ * is recording. */
13
+ details;
14
+ /** The response headers (`Retry-After`, `RateLimit-*`,
15
+ * `WWW-Authenticate`), when the error came from an HTTP response. */
16
+ headers;
17
+ /** The request's id (the envelope's `requestId`, else the `X-Request-Id`
18
+ * header): quote it when reporting a failure. */
19
+ requestId;
20
+ constructor(code, message, opts = {}) {
21
+ super(message);
22
+ this.name = 'VocalStackError';
23
+ this.code = code;
24
+ this.retryable = opts.retryable ?? false;
25
+ this.status = opts.status;
26
+ this.details = opts.details;
27
+ this.headers = opts.headers;
28
+ this.requestId = opts.requestId;
29
+ }
30
+ /** Seconds the server asked the caller to wait (`Retry-After`), if it said. */
31
+ get retryAfter() {
32
+ const v = this.headers?.get('retry-after');
33
+ if (v == null || v === '')
34
+ return undefined;
35
+ const n = Number(v);
36
+ if (Number.isFinite(n))
37
+ return n;
38
+ const at = Date.parse(v);
39
+ return Number.isNaN(at) ? undefined : Math.max(0, (at - Date.now()) / 1000);
40
+ }
41
+ }
42
+ export function capacityExceeded(message) {
43
+ return new VocalStackError('capacity_exceeded', message, { retryable: true });
44
+ }
45
+ export function fromEnvelope(body, status, headers) {
46
+ const b = body;
47
+ // The envelope names the request; a header the page cannot read across
48
+ // origins (when it is not exposed) is the fallback.
49
+ const requestId = (b && typeof b.requestId === 'string' ? b.requestId : undefined) ?? headers?.get('x-request-id') ?? undefined;
50
+ if (b && typeof b.code === 'string') {
51
+ return new VocalStackError(b.code, b.message ?? b.code, {
52
+ retryable: b.data?.retryable ?? false,
53
+ status,
54
+ details: b.data?.details,
55
+ headers,
56
+ requestId,
57
+ });
58
+ }
59
+ return new VocalStackError('internal', `unexpected error (status ${status})`, { status, headers, requestId });
60
+ }
61
+ /** A token endpoint's `400 { error, error_description }` (RFC 6749 §5.2) as
62
+ * a `VocalStackError` whose `code` is the `error`; any other answer goes
63
+ * through the envelope. */
64
+ export function fromOAuth(body, status, headers) {
65
+ const b = body;
66
+ if (status === 400 && b && typeof b.error === 'string') {
67
+ return new VocalStackError(b.error, b.error_description ?? b.error, {
68
+ status,
69
+ headers,
70
+ requestId: headers?.get('x-request-id') ?? undefined,
71
+ });
72
+ }
73
+ return fromEnvelope(body, status, headers);
74
+ }
package/dist/file.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export type FileInput = string | Uint8Array | ArrayBuffer | Blob | AsyncIterable<Uint8Array>;
2
+ export declare function fileChunks(input: FileInput): AsyncIterable<Uint8Array>;