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

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.
@@ -1,19 +1,10 @@
1
1
  import type { ServerFrame, SubscriberFrame, TranscriptSnapshot } from '@vocalstack/contract';
2
2
  export interface SubscribeOptions {
3
- /** Read (and hear) the recording in this language. */
4
3
  lang?: string;
5
- /** Which voice speaks `lang` for this listener: a voice id from
6
- * `vs.voices.available(lang)`. Omitted means the recording's
7
- * `settings.voiceByLang` pin, then the engine's pick. */
8
4
  voice?: string;
9
- /** A private broadcast's listener token (the one VocalStack's listener page holds). */
10
5
  listenerToken?: string;
11
- /** Read a transcription through its share link. */
12
6
  shareCode?: string;
13
- /** With a token the socket is an owner subscriber (full frames, audience
14
- * counts); `false` listens as a plain listener. */
15
7
  asOwner?: boolean;
16
- /** Live original audio (binary Opus frames) from the start. */
17
8
  audio?: boolean;
18
9
  }
19
10
  export type SubscriptionEvent = {
@@ -32,22 +23,14 @@ export type SubscriptionEvent = {
32
23
  reason?: string;
33
24
  };
34
25
  type Snapshotter = (after: number | undefined) => Promise<TranscriptSnapshot>;
35
- /** A recording's live fan-out (`vs.recordings.subscribe`). It resolves
36
- * once the backfill snapshot is in place; live frames follow through the
37
- * async iterator, with gaps detected on the cursor and healed by
38
- * re-snapshotting. */
39
26
  export declare class Subscription implements AsyncIterable<SubscriptionEvent> {
40
27
  #private;
41
28
  readonly recordingId: string;
42
- /** Highest durable cursor applied (snapshot or frame). */
43
29
  cursor: number;
44
30
  snapshot: TranscriptSnapshot | null;
45
31
  private constructor();
46
- /** @internal */
47
32
  static open(recordingId: string, url: string, bearer: string | undefined, opts: SubscribeOptions, snap: Snapshotter): Promise<Subscription>;
48
- /** Switch the target language (`null` = as spoken). */
49
33
  setLanguage(lang: string | null): void;
50
- /** Opt in or out of live original audio. */
51
34
  setAudio(enabled: boolean): void;
52
35
  close(): void;
53
36
  [Symbol.asyncIterator](): AsyncIterator<SubscriptionEvent>;
@@ -1,12 +1,7 @@
1
1
  import { VocalStackError } from './errors.js';
2
2
  import { openWebSocket, WS_OPEN } from './ws.js';
3
- /** A recording's live fan-out (`vs.recordings.subscribe`). It resolves
4
- * once the backfill snapshot is in place; live frames follow through the
5
- * async iterator, with gaps detected on the cursor and healed by
6
- * re-snapshotting. */
7
3
  export class Subscription {
8
4
  recordingId;
9
- /** Highest durable cursor applied (snapshot or frame). */
10
5
  cursor = -1;
11
6
  snapshot = null;
12
7
  #snap;
@@ -23,7 +18,6 @@ export class Subscription {
23
18
  this.#opts = opts;
24
19
  this.#snap = snap;
25
20
  }
26
- /** @internal */
27
21
  static async open(recordingId, url, bearer, opts, snap) {
28
22
  const ws = await openWebSocket(url, bearer);
29
23
  ws.binaryType = 'arraybuffer';
@@ -77,7 +71,6 @@ export class Subscription {
77
71
  this.#onFrame(b.frame);
78
72
  }
79
73
  #onFrame(frame) {
80
- // The relay cursor is `cursor`; segment-scoped frames use `seq` for the segment.
81
74
  const seq = typeof frame.cursor === 'number' ? frame.cursor : typeof frame.seq === 'number' ? frame.seq : undefined;
82
75
  if (this.#buffering) {
83
76
  this.#buffering.push({ seq, frame });
@@ -85,7 +78,7 @@ export class Subscription {
85
78
  }
86
79
  if (seq !== undefined) {
87
80
  if (seq <= this.cursor)
88
- return; // already in the snapshot
81
+ return;
89
82
  if (seq > this.cursor + 1 && !this.#healing) {
90
83
  this.#healing = true;
91
84
  this.#buffering = [{ seq, frame }];
@@ -106,13 +99,10 @@ export class Subscription {
106
99
  this.#queue.push(ev);
107
100
  this.#wake?.();
108
101
  }
109
- /** Switch the target language (`null` = as spoken). */
110
102
  setLanguage(lang) {
111
- // A gap heal re-reads the snapshot in the language being read now.
112
103
  this.#opts.lang = lang ?? undefined;
113
104
  this.#send({ type: 'subscribe.update', lang: lang ?? 'none' });
114
105
  }
115
- /** Opt in or out of live original audio. */
116
106
  setAudio(enabled) {
117
107
  this.#send({ type: 'subscribe.update', audio: enabled });
118
108
  }
@@ -128,7 +118,6 @@ export class Subscription {
128
118
  this.#ws.close();
129
119
  }
130
120
  catch {
131
- // already closed
132
121
  }
133
122
  this.#wake?.();
134
123
  }
package/dist/ws.d.ts CHANGED
@@ -6,7 +6,4 @@ export interface WsLike {
6
6
  addEventListener(type: string, listener: (ev: any) => void): void;
7
7
  }
8
8
  export declare const WS_OPEN = 1;
9
- /** Open a socket. `bearer` is the caller's credential: Node sends it as
10
- * an `Authorization` header (an API key is refused in a URL); a browser
11
- * cannot set socket headers, so it rides in `access_token` instead. */
12
9
  export declare function openWebSocket(url: string, bearer?: string): Promise<WsLike>;
package/dist/ws.js CHANGED
@@ -2,9 +2,6 @@ export const WS_OPEN = 1;
2
2
  const isNode = () => typeof globalThis.process?.versions?.node === 'string' &&
3
3
  !globalThis.Deno &&
4
4
  !globalThis.Bun;
5
- /** Open a socket. `bearer` is the caller's credential: Node sends it as
6
- * an `Authorization` header (an API key is refused in a URL); a browser
7
- * cannot set socket headers, so it rides in `access_token` instead. */
8
5
  export async function openWebSocket(url, bearer) {
9
6
  if (!isNode() && typeof globalThis.WebSocket === 'function') {
10
7
  const u = bearer ? `${url}${url.includes('?') ? '&' : '?'}access_token=${encodeURIComponent(bearer)}` : url;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vocalstack/js-sdk",
3
- "version": "2.0.0-alpha.0",
3
+ "version": "2.0.0-alpha.1",
4
4
  "description": "VocalStack speech API SDK for Node and browsers: one client (VocalStack) grouped by resource, typed from the generated contract, with realtime WebSocket streaming.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -29,7 +29,7 @@
29
29
  "test": "node --test test/*.test.mjs"
30
30
  },
31
31
  "dependencies": {
32
- "@vocalstack/contract": "1.0.0-alpha.0",
32
+ "@vocalstack/contract": "1.0.0-alpha.1",
33
33
  "ws": "^8.18.0"
34
34
  },
35
35
  "devDependencies": {
@@ -33,11 +33,8 @@ npm init -y && npm pkg set type=module # in a new folder: the programs below a
33
33
  npm i @vocalstack/js-sdk # Node 20 or newer
34
34
  ```
35
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
36
+ To run code newer than the npm release, install it from a clone of
37
+ https://github.com/vocalstack/js-sdk. Build it
41
38
  first (`npm run build` also builds the bundled `contract/` package):
42
39
 
43
40
  ```sh
@@ -105,7 +102,7 @@ const vs = new VocalStack({ baseUrl: process.env.VOCALSTACK_BASE_URL, apiKey: pr
105
102
 
106
103
  const tx = await vs.transcriptions.create({
107
104
  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'
105
+ settings: { spokenLanguage: 'en', speakerLabels: 'on' }, // both optional; speakerLabels: 'auto' (default) | 'on' | 'off'
109
106
  // Off unless asked for: settings.summary, settings.title, settings.summaryTranslations,
110
107
  // settings.voice (spoken translations), and shareLink: true (a public share link).
111
108
  });