@rimelabs/sdk 0.1.0-alpha.5 → 0.1.0-alpha.7

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 (43) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/LICENSE-PRISM +201 -0
  3. package/NOTICE-PRISM +9 -0
  4. package/README.md +50 -123
  5. package/dist/auth.d.ts +8 -3
  6. package/dist/auth.js +8 -3
  7. package/dist/cancellation.d.ts +1 -0
  8. package/dist/cancellation.js +18 -0
  9. package/dist/client.d.ts +11 -23
  10. package/dist/client.js +22 -91
  11. package/dist/index.d.ts +4 -2
  12. package/dist/index.js +4 -2
  13. package/dist/realtime/async.d.ts +27 -0
  14. package/dist/realtime/async.js +122 -0
  15. package/dist/realtime/audio.d.ts +13 -0
  16. package/dist/realtime/audio.js +54 -0
  17. package/dist/realtime/client.d.ts +12 -0
  18. package/dist/realtime/client.js +156 -0
  19. package/dist/realtime/protocol.d.ts +80 -0
  20. package/dist/realtime/protocol.js +354 -0
  21. package/dist/realtime/session.d.ts +67 -0
  22. package/dist/realtime/session.js +730 -0
  23. package/dist/realtime/transport.d.ts +16 -0
  24. package/dist/realtime/transport.js +83 -0
  25. package/dist/realtime/types.d.ts +190 -0
  26. package/dist/realtime/types.js +10 -0
  27. package/dist/{audio.js → tts/audio.js} +1 -1
  28. package/dist/tts/client.d.ts +36 -0
  29. package/dist/tts/client.js +111 -0
  30. package/dist/{policy.d.ts → tts/policy.d.ts} +0 -1
  31. package/dist/{policy.js → tts/policy.js} +1 -19
  32. package/dist/{sentences.js → tts/sentences.js} +2 -2
  33. package/dist/{stream.js → tts/stream.js} +3 -2
  34. package/dist/{transport.d.ts → tts/transport.d.ts} +1 -1
  35. package/dist/{transport.js → tts/transport.js} +3 -2
  36. package/docs/realtime.md +220 -0
  37. package/docs/tts.md +132 -0
  38. package/package.json +12 -5
  39. /package/dist/{audio.d.ts → tts/audio.d.ts} +0 -0
  40. /package/dist/{queue.d.ts → tts/queue.d.ts} +0 -0
  41. /package/dist/{queue.js → tts/queue.js} +0 -0
  42. /package/dist/{sentences.d.ts → tts/sentences.d.ts} +0 -0
  43. /package/dist/{stream.d.ts → tts/stream.d.ts} +0 -0
@@ -0,0 +1,16 @@
1
+ import { RimeError } from "../errors.js";
2
+ /** Private transport. The public declarations do not require ws types. */
3
+ export declare class RealtimeConnection {
4
+ private readonly socket;
5
+ private readonly opened;
6
+ private readonly ended;
7
+ private closing;
8
+ private connected;
9
+ readonly ready: Promise<void>;
10
+ onMessage: (raw: string) => void;
11
+ onFailure: (error: RimeError) => void;
12
+ constructor(endpoint: string, authorization: string);
13
+ private failure;
14
+ send(encoded: string): Promise<void>;
15
+ close(): Promise<void>;
16
+ }
@@ -0,0 +1,83 @@
1
+ import WebSocket from "ws";
2
+ import { RimeAuthenticationError, RimeStreamError, RimeUnavailableError, } from "../errors.js";
3
+ import { Deferred } from "./async.js";
4
+ /** Private transport. The public declarations do not require ws types. */
5
+ export class RealtimeConnection {
6
+ socket;
7
+ opened = new Deferred();
8
+ ended = new Deferred();
9
+ closing = null;
10
+ connected = false;
11
+ ready = this.opened.promise;
12
+ onMessage = () => { };
13
+ onFailure = () => { };
14
+ constructor(endpoint, authorization) {
15
+ this.socket = new WebSocket(endpoint, {
16
+ headers: { Authorization: authorization },
17
+ followRedirects: false,
18
+ perMessageDeflate: false,
19
+ maxPayload: 1024 * 1024,
20
+ });
21
+ this.socket.on("open", () => {
22
+ this.connected = true;
23
+ this.opened.resolve();
24
+ });
25
+ this.socket.on("unexpected-response", (request, response) => {
26
+ const error = [401, 403].includes(response.statusCode ?? 0)
27
+ ? new RimeAuthenticationError("Realtime endpoint rejected credentials")
28
+ : new RimeUnavailableError("Realtime endpoint rejected the connection");
29
+ this.failure(error);
30
+ response.destroy();
31
+ request.destroy();
32
+ this.socket.terminate();
33
+ });
34
+ this.socket.on("error", () => this.failure(!this.connected
35
+ ? new RimeUnavailableError("Realtime handshake failed")
36
+ : new RimeStreamError("Invalid event or lost realtime connection")));
37
+ this.socket.on("message", (data, binary) => {
38
+ if (binary) {
39
+ this.failure(new RimeStreamError("Expected a JSON text event"));
40
+ return;
41
+ }
42
+ this.onMessage(data.toString());
43
+ });
44
+ this.socket.on("close", () => {
45
+ this.ended.resolve();
46
+ this.failure(new RimeStreamError("Realtime connection closed; reconnect is not automatic"));
47
+ });
48
+ }
49
+ failure(error) {
50
+ this.opened.reject(error);
51
+ this.onFailure(error);
52
+ }
53
+ send(encoded) {
54
+ return new Promise((resolve, reject) => {
55
+ this.socket.send(encoded, (error) => {
56
+ if (error)
57
+ reject(new RimeStreamError("Realtime write failed; outcome unknown"));
58
+ else
59
+ resolve();
60
+ });
61
+ });
62
+ }
63
+ close() {
64
+ if (!this.closing) {
65
+ this.closing = (async () => {
66
+ if (this.socket.readyState === WebSocket.CLOSED)
67
+ return;
68
+ const timer = setTimeout(() => this.socket.terminate(), 2000);
69
+ try {
70
+ if (this.socket.readyState === WebSocket.CONNECTING)
71
+ this.socket.terminate();
72
+ else
73
+ this.socket.close();
74
+ await this.ended.promise;
75
+ }
76
+ finally {
77
+ clearTimeout(timer);
78
+ }
79
+ })();
80
+ }
81
+ return this.closing;
82
+ }
83
+ }
@@ -0,0 +1,190 @@
1
+ import { RimeError, RimeTimeoutError } from "../errors.js";
2
+ export type JsonValue = null | boolean | number | string | JsonValue[] | JsonObject;
3
+ export interface JsonObject {
4
+ [key: string]: JsonValue;
5
+ }
6
+ /** All durations are positive, finite seconds. */
7
+ export interface RealtimeTimeouts {
8
+ readonly connectS?: number;
9
+ readonly readyS?: number;
10
+ readonly requestS?: number;
11
+ }
12
+ export interface RealtimeOperationOptions {
13
+ readonly signal?: AbortSignal;
14
+ }
15
+ export interface ToolDefinition {
16
+ readonly name: string;
17
+ readonly parameters: JsonObject;
18
+ readonly description?: string;
19
+ }
20
+ export interface RealtimeConnectOptions extends RealtimeOperationOptions {
21
+ readonly endpoint: string;
22
+ readonly model?: "prism";
23
+ readonly voice?: string | null;
24
+ readonly instructions?: string | null;
25
+ readonly tools?: readonly ToolDefinition[];
26
+ readonly interruptOnSpeech?: boolean;
27
+ readonly timeouts?: RealtimeTimeouts;
28
+ }
29
+ export interface ReplyOptions extends RealtimeOperationOptions {
30
+ readonly instruction?: string | null;
31
+ readonly toolCall?: ToolCallRef | null;
32
+ }
33
+ /** Omitted fields mean 16 kHz, mono, signed little-endian PCM16. */
34
+ export interface PCMFormat {
35
+ readonly sampleRate?: 8000 | 16000 | 24000 | 48000;
36
+ readonly channels?: 1 | 2;
37
+ readonly encoding?: "pcm_s16le";
38
+ }
39
+ export interface AudioChunk {
40
+ readonly data: Uint8Array;
41
+ readonly format?: PCMFormat;
42
+ }
43
+ export interface ResponseRef {
44
+ readonly sessionId: string;
45
+ readonly responseId: string;
46
+ }
47
+ export interface ItemRef {
48
+ readonly sessionId: string;
49
+ readonly itemId: string;
50
+ }
51
+ export interface ToolCallRef extends ResponseRef {
52
+ readonly callId: string;
53
+ }
54
+ export interface OutputRef {
55
+ readonly response: ResponseRef;
56
+ readonly itemId: string;
57
+ readonly outputIndex: number;
58
+ readonly contentIndex: number;
59
+ }
60
+ export interface SessionInfo {
61
+ readonly sessionId: string;
62
+ readonly model: "prism";
63
+ readonly voice: string;
64
+ readonly interruptOnSpeech: boolean;
65
+ readonly toolResultTimeoutS: number | null;
66
+ readonly toolContinuationTimeoutS: number | null;
67
+ }
68
+ export interface RealtimeFault {
69
+ readonly code: string;
70
+ readonly message: string;
71
+ readonly scope: "event" | "utterance" | "response" | "tool_roundtrip" | "session" | "unknown";
72
+ readonly requestId: string | null;
73
+ readonly responseId: string | null;
74
+ readonly itemId: string | null;
75
+ readonly callIds: readonly string[];
76
+ readonly correlationId: string | null;
77
+ readonly parameter: string | null;
78
+ }
79
+ export declare class RealtimeAdmissionTimeout extends RimeTimeoutError {
80
+ }
81
+ export declare class RimeRealtimeError extends RimeError {
82
+ readonly fault: RealtimeFault;
83
+ constructor(fault: RealtimeFault);
84
+ }
85
+ export interface InputReady {
86
+ readonly kind: "input.ready";
87
+ }
88
+ export interface SpeechStarted {
89
+ readonly kind: "speech.started";
90
+ readonly itemId: string;
91
+ readonly audioStartMs: number;
92
+ }
93
+ export interface SpeechStopped {
94
+ readonly kind: "speech.stopped";
95
+ readonly itemId: string;
96
+ readonly audioEndMs: number;
97
+ }
98
+ export interface InputCommitted {
99
+ readonly kind: "input.committed";
100
+ readonly itemId: string;
101
+ }
102
+ export interface TranscriptDelta {
103
+ readonly kind: "transcript.delta";
104
+ readonly itemId: string;
105
+ readonly delta: string;
106
+ }
107
+ export interface TranscriptFinal {
108
+ readonly kind: "transcript.final";
109
+ readonly itemId: string;
110
+ readonly text: string;
111
+ }
112
+ export interface TranscriptFailed {
113
+ readonly kind: "transcript.failed";
114
+ readonly itemId: string;
115
+ readonly error: RealtimeFault;
116
+ }
117
+ export interface ResponseStarted {
118
+ readonly kind: "response.started";
119
+ readonly response: ResponseRef;
120
+ readonly cause: "speech" | "text" | "proactive" | "tools" | "unknown";
121
+ readonly parent: ResponseRef | null;
122
+ readonly inputItemId: string | null;
123
+ }
124
+ export interface MessageStarted {
125
+ readonly kind: "message.started";
126
+ readonly output: OutputRef;
127
+ }
128
+ export interface TextDelta {
129
+ readonly kind: "text.delta";
130
+ readonly output: OutputRef;
131
+ readonly delta: string;
132
+ }
133
+ export interface TextDone {
134
+ readonly kind: "text.done";
135
+ readonly output: OutputRef;
136
+ readonly text: string;
137
+ }
138
+ export interface AudioDelta {
139
+ readonly kind: "audio.delta";
140
+ readonly output: OutputRef;
141
+ readonly audio: {
142
+ readonly data: Uint8Array;
143
+ readonly format: Required<PCMFormat>;
144
+ };
145
+ }
146
+ export interface AudioDone {
147
+ readonly kind: "audio.done";
148
+ readonly output: OutputRef;
149
+ }
150
+ export interface ToolCall {
151
+ readonly kind: "tool.call";
152
+ readonly call: ToolCallRef;
153
+ readonly itemId: string;
154
+ readonly name: string;
155
+ readonly arguments: JsonObject;
156
+ }
157
+ export interface ResponseAbandoned {
158
+ readonly kind: "response.abandoned";
159
+ readonly response: ResponseRef;
160
+ }
161
+ export interface ResponseEnded {
162
+ readonly kind: "response.ended";
163
+ readonly response: ResponseRef;
164
+ readonly status: "completed" | "cancelled" | "failed" | "unknown";
165
+ readonly reason: string | null;
166
+ }
167
+ export interface FaultEvent {
168
+ readonly kind: "error";
169
+ readonly error: RealtimeFault;
170
+ }
171
+ export type InputEvent = InputReady | SpeechStarted | SpeechStopped | InputCommitted | TranscriptDelta | TranscriptFinal | TranscriptFailed;
172
+ export type ResponseEvent = ResponseStarted | ResponseAbandoned | MessageStarted | TextDelta | TextDone | AudioDelta | AudioDone | ToolCall | ResponseEnded;
173
+ export interface SessionEvent {
174
+ readonly sessionId: string;
175
+ readonly eventId: string;
176
+ readonly requestId: string | null;
177
+ readonly payload: InputEvent | ResponseEvent | FaultEvent;
178
+ }
179
+ export interface PlaybackInterrupted {
180
+ readonly kind: "interrupted";
181
+ readonly output: OutputRef;
182
+ readonly audioEndMs: number;
183
+ }
184
+ export interface PlaybackFinished {
185
+ readonly kind: "finished";
186
+ readonly response: ResponseRef;
187
+ readonly playedMs?: number | null;
188
+ readonly audibleTailMs?: number | null;
189
+ }
190
+ export type PlaybackReport = PlaybackInterrupted | PlaybackFinished;
@@ -0,0 +1,10 @@
1
+ import { RimeError, RimeTimeoutError } from "../errors.js";
2
+ export class RealtimeAdmissionTimeout extends RimeTimeoutError {
3
+ }
4
+ export class RimeRealtimeError extends RimeError {
5
+ fault;
6
+ constructor(fault) {
7
+ super(`${fault.code}: ${fault.message}`, fault.requestId);
8
+ this.fault = fault;
9
+ }
10
+ }
@@ -1,4 +1,4 @@
1
- import { RimeAudioFormatError } from "./errors.js";
1
+ import { RimeAudioFormatError } from "../errors.js";
2
2
  export class AudioFormat {
3
3
  encoding;
4
4
  sampleRate;
@@ -0,0 +1,36 @@
1
+ import { AudioFormat } from "./audio.js";
2
+ import { AudioStream, type TextSource } from "./stream.js";
3
+ import { Credentials } from "../auth.js";
4
+ import { policy } from "./policy.js";
5
+ export interface SynthesisOptions {
6
+ voice?: string | null;
7
+ language?: string;
8
+ audioFormat?: AudioFormat | null;
9
+ timeout?: number | null;
10
+ }
11
+ export interface DiscoveryOptions {
12
+ timeout?: number | null;
13
+ }
14
+ export interface VoiceListOptions extends DiscoveryOptions {
15
+ language?: string | null;
16
+ }
17
+ export declare class TTS {
18
+ private readonly credentials;
19
+ private readonly deployment;
20
+ private readonly defaultTimeout;
21
+ private readonly checkOpen;
22
+ private client;
23
+ private streams;
24
+ private discoveryOperations;
25
+ readonly voices: {
26
+ list: (options?: VoiceListOptions) => Promise<string[]>;
27
+ };
28
+ readonly languages: {
29
+ list: (options?: DiscoveryOptions) => Promise<string[]>;
30
+ };
31
+ constructor(credentials: Credentials, deployment: Readonly<typeof policy>, defaultTimeout: number | null, checkOpen: () => void);
32
+ private prepare;
33
+ stream(text: TextSource, options?: SynthesisOptions): AudioStream;
34
+ private discover;
35
+ close(): Promise<void>;
36
+ }
@@ -0,0 +1,111 @@
1
+ import { AudioFormat } from "./audio.js";
2
+ import { AudioStream, constructionKey } from "./stream.js";
3
+ import { policy, timeout, nonempty } from "./policy.js";
4
+ import { abortable } from "../cancellation.js";
5
+ import { transport, connect, metadata, discover, } from "./transport.js";
6
+ import { RimeInputError, RimeAudioFormatError, RimeCancelledError, RimeTimeoutError, RimeUnavailableError, } from "../errors.js";
7
+ export class TTS {
8
+ credentials;
9
+ deployment;
10
+ defaultTimeout;
11
+ checkOpen;
12
+ client = null;
13
+ streams = new Set();
14
+ discoveryOperations = new Map();
15
+ voices;
16
+ languages;
17
+ constructor(credentials, deployment, defaultTimeout, checkOpen) {
18
+ this.credentials = credentials;
19
+ this.deployment = deployment;
20
+ this.defaultTimeout = defaultTimeout;
21
+ this.checkOpen = checkOpen;
22
+ this.voices = {
23
+ list: async (options = {}) => {
24
+ if (options.language !== undefined && options.language !== null)
25
+ nonempty(options.language, "language");
26
+ return this.discover("voices", options.language, options.timeout);
27
+ },
28
+ };
29
+ this.languages = {
30
+ list: (options = {}) => this.discover("languages", undefined, options.timeout),
31
+ };
32
+ }
33
+ async prepare(signal) {
34
+ this.checkOpen();
35
+ const auth = await this.credentials.metadata(signal);
36
+ this.checkOpen();
37
+ this.client ??= transport.makeClient(this.deployment.target);
38
+ await connect(this.client, signal);
39
+ return { client: this.client, metadata: metadata(auth) };
40
+ }
41
+ stream(text, options = {}) {
42
+ this.checkOpen();
43
+ if (typeof text === "string") {
44
+ if (!text.trim())
45
+ throw new RimeInputError("Text must contain non-whitespace characters");
46
+ }
47
+ else if (!text || typeof text[Symbol.asyncIterator] !== "function")
48
+ throw new RimeInputError("text must be a string or an async iterable of strings");
49
+ const voice = options.voice === undefined || options.voice === null
50
+ ? this.deployment.defaultVoice
51
+ : nonempty(options.voice, "voice");
52
+ const language = nonempty(options.language ?? "en", "language");
53
+ const format = options.audioFormat ?? AudioFormat.PCM_24000;
54
+ if (format !== AudioFormat.PCM_24000 && format !== AudioFormat.MULAW_8000)
55
+ throw new RimeAudioFormatError("Select a named AudioFormat profile");
56
+ const audio = new AudioStream(constructionKey, {
57
+ prepare: (s) => this.prepare(s),
58
+ checkOpen: () => this.checkOpen(),
59
+ forget: (s) => this.streams.delete(s),
60
+ }, text, voice, language, format, timeout(options.timeout, this.defaultTimeout));
61
+ this.streams.add(audio);
62
+ return audio;
63
+ }
64
+ async discover(kind, language, override) {
65
+ this.checkOpen();
66
+ const budget = Math.min(timeout(override, this.defaultTimeout) ?? Infinity, policy.discoveryTimeout);
67
+ const controller = new AbortController();
68
+ let requestId = null;
69
+ const timer = setTimeout(() => controller.abort(new RimeTimeoutError("Discovery deadline expired")), budget * 1000);
70
+ const operation = (async () => {
71
+ try {
72
+ const prepared = await this.prepare(controller.signal);
73
+ for (let attempt = 0;; attempt++) {
74
+ requestId = null;
75
+ try {
76
+ return await discover(prepared, kind, language, controller.signal);
77
+ }
78
+ catch (error) {
79
+ if (!(error instanceof RimeUnavailableError) || attempt === 2)
80
+ throw error;
81
+ requestId = error.requestId;
82
+ await abortable(new Promise((resolve) => setTimeout(resolve, 50 * 2 ** attempt)), controller.signal);
83
+ }
84
+ }
85
+ }
86
+ catch (error) {
87
+ if (error instanceof RimeTimeoutError && requestId !== null)
88
+ throw new RimeTimeoutError(error.message, requestId, {
89
+ cause: error.cause,
90
+ });
91
+ throw error;
92
+ }
93
+ finally {
94
+ clearTimeout(timer);
95
+ this.discoveryOperations.delete(controller);
96
+ }
97
+ })();
98
+ this.discoveryOperations.set(controller, operation);
99
+ return operation;
100
+ }
101
+ async close() {
102
+ const discoveries = [...this.discoveryOperations.values()];
103
+ for (const controller of this.discoveryOperations.keys())
104
+ controller.abort(new RimeCancelledError("Client closed during discovery"));
105
+ await Promise.all([
106
+ ...[...this.streams].map((stream) => stream.cancel()),
107
+ Promise.allSettled(discoveries),
108
+ ]);
109
+ this.client?.close();
110
+ }
111
+ }
@@ -18,4 +18,3 @@ export declare const policy: {
18
18
  export declare function resolve(model: string, endpoint?: string | null): Readonly<typeof policy>;
19
19
  export declare function timeout(value: unknown, inherited?: number | null): number | null;
20
20
  export declare function nonempty(value: unknown, name: string): string;
21
- export declare function abortable<T>(promise: PromiseLike<T>, signal: AbortSignal): Promise<T>;
@@ -1,4 +1,4 @@
1
- import { RimeInputError } from "./errors.js";
1
+ import { RimeInputError } from "../errors.js";
2
2
  const codaHostname = "coda.api.rime.ai";
3
3
  export const policy = {
4
4
  target: `${codaHostname}:443`,
@@ -62,21 +62,3 @@ export function nonempty(value, name) {
62
62
  throw new RimeInputError(`${name} must be a non-empty string`);
63
63
  return value;
64
64
  }
65
- export function abortable(promise, signal) {
66
- if (signal.aborted)
67
- return Promise.reject(signal.reason);
68
- return new Promise((resolve, reject) => {
69
- const abort = () => {
70
- signal.removeEventListener("abort", abort);
71
- reject(signal.reason);
72
- };
73
- signal.addEventListener("abort", abort, { once: true });
74
- Promise.resolve(promise).then((value) => {
75
- signal.removeEventListener("abort", abort);
76
- resolve(value);
77
- }, (error) => {
78
- signal.removeEventListener("abort", abort);
79
- reject(error);
80
- });
81
- });
82
- }
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from "node:module";
2
- import { RimeInputError, RimeResourceLimitError } from "./errors.js";
2
+ import { RimeInputError, RimeResourceLimitError } from "../errors.js";
3
3
  const require = createRequire(import.meta.url);
4
- const module = require("../vendor/blingfire.cjs");
4
+ const module = require("../../vendor/blingfire.cjs");
5
5
  export const ready = module.ready;
6
6
  // These marks schedule scans. Only BlingFire decides sentence boundaries.
7
7
  // Keep the set and code-point counts in sync with Python's _sentences.py.
@@ -2,11 +2,12 @@ import { randomUUID } from "node:crypto";
2
2
  import { debuglog } from "node:util";
3
3
  const log = debuglog("rime-sdk");
4
4
  import { Converter } from "./audio.js";
5
- import { policy, abortable } from "./policy.js";
5
+ import { policy } from "./policy.js";
6
+ import { abortable } from "../cancellation.js";
6
7
  import { ByteQueue } from "./queue.js";
7
8
  import { SentenceBuffer, ready } from "./sentences.js";
8
9
  import { SynthesisCall } from "./transport.js";
9
- import { RimeError, RimeInputError, RimeCancelledError, RimeTimeoutError, RimeStreamError, } from "./errors.js";
10
+ import { RimeError, RimeInputError, RimeCancelledError, RimeTimeoutError, RimeStreamError, } from "../errors.js";
10
11
  export const constructionKey = Symbol("private stream constructor");
11
12
  export class AudioStream {
12
13
  owner;
@@ -1,5 +1,5 @@
1
1
  import * as grpc from "@grpc/grpc-js";
2
- import * as errors from "./errors.js";
2
+ import * as errors from "../errors.js";
3
3
  export type Connection = grpc.Client;
4
4
  export interface PreparedConnection {
5
5
  client: Connection;
@@ -1,8 +1,9 @@
1
1
  import * as grpc from "@grpc/grpc-js";
2
2
  import { create, fromBinary, toBinary, } from "@bufbuild/protobuf";
3
3
  import * as schema from "@rimelabs/api";
4
- import { policy, abortable } from "./policy.js";
5
- import * as errors from "./errors.js";
4
+ import { policy } from "./policy.js";
5
+ import { abortable } from "../cancellation.js";
6
+ import * as errors from "../errors.js";
6
7
  export function rpcError(code, requestId = null) {
7
8
  const classes = {
8
9
  [grpc.status.UNAUTHENTICATED]: errors.RimeAuthenticationError,