diff --git a/examples/node-live/index.js b/examples/node-live/index.js index be79a3aa..ec51c1c3 100644 --- a/examples/node-live/index.js +++ b/examples/node-live/index.js @@ -21,6 +21,10 @@ const live = async () => { console.log(data); }); + connection.on(LiveTranscriptionEvents.Error, (err) => { + console.error(err); + }); + fetch(url) .then((r) => r.body) .then((res) => { diff --git a/src/DeepgramClient.ts b/src/DeepgramClient.ts index 219c477e..c6648ba5 100644 --- a/src/DeepgramClient.ts +++ b/src/DeepgramClient.ts @@ -1,3 +1,4 @@ +import { DeepgramVersionError } from "./lib/errors"; import { AbstractClient } from "./packages/AbstractClient"; import { ListenClient } from "./packages/ListenClient"; import { ManageClient } from "./packages/ManageClient"; @@ -21,4 +22,40 @@ export default class DeepgramClient extends AbstractClient { get onprem(): OnPremClient { return new OnPremClient(this.key, this.options); } + + /** + * Major version fallback errors are below + */ + + get transcription(): any { + throw new DeepgramVersionError(); + } + + get projects(): any { + throw new DeepgramVersionError(); + } + + get keys(): any { + throw new DeepgramVersionError(); + } + + get members(): any { + throw new DeepgramVersionError(); + } + + get scopes(): any { + throw new DeepgramVersionError(); + } + + get invitation(): any { + throw new DeepgramVersionError(); + } + + get usage(): any { + throw new DeepgramVersionError(); + } + + get billing(): any { + throw new DeepgramVersionError(); + } } diff --git a/src/index.ts b/src/index.ts index 0c859252..7c70a48b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,16 @@ import DeepgramClient from "./DeepgramClient"; +import { DeepgramVersionError } from "./lib/errors"; import type { DeepgramClientOptions } from "./lib/types"; +/** + * Major version fallback error + */ +class Deepgram { + constructor(protected apiKey: string, protected apiUrl?: string, protected requireSSL?: boolean) { + throw new DeepgramVersionError(); + } +} + /** * Creates a new Deepgram Client. */ @@ -8,7 +18,7 @@ const createClient = (apiKey: string, options: DeepgramClientOptions = {}): Deep return new DeepgramClient(apiKey, options); }; -export { createClient, DeepgramClient }; +export { createClient, DeepgramClient, Deepgram }; /** * Helpful exports. diff --git a/src/lib/enums/LiveTranscriptionEvents.ts b/src/lib/enums/LiveTranscriptionEvents.ts index cc8de9b4..cad0323c 100644 --- a/src/lib/enums/LiveTranscriptionEvents.ts +++ b/src/lib/enums/LiveTranscriptionEvents.ts @@ -5,4 +5,6 @@ export enum LiveTranscriptionEvents { Metadata = "Metadata", // exact match to data type from API Error = "error", Warning = "warning", + UtteranceEnd = "UtteranceEnd", // exact match to data type from API + SpeechStarted = "SpeechStarted", } diff --git a/src/lib/errors.ts b/src/lib/errors.ts index b67c2010..82cd8063 100644 --- a/src/lib/errors.ts +++ b/src/lib/errors.ts @@ -38,3 +38,13 @@ export class DeepgramUnknownError extends DeepgramError { this.originalError = originalError; } } + +export class DeepgramVersionError extends DeepgramError { + constructor() { + super( + `You are attempting to use an old format for a newer SDK version. Read more here: https://dpgr.am/js-v3` + ); + + this.name = "DeepgramVersionError"; + } +} diff --git a/src/lib/helpers.ts b/src/lib/helpers.ts index de979566..8e18f190 100644 --- a/src/lib/helpers.ts +++ b/src/lib/helpers.ts @@ -1,5 +1,12 @@ import { Headers as CrossFetchHeaders } from "cross-fetch"; -import { DeepgramClientOptions, FileSource, PrerecordedSource, UrlSource } from "./types"; +import { + DeepgramClientOptions, + FileSource, + PrerecordedSource, + UrlSource, + TextSource, + AnalyzeSource, +} from "./types"; import { Readable } from "stream"; import merge from "deepmerge"; @@ -41,12 +48,22 @@ export const resolveHeadersConstructor = () => { return Headers; }; -export const isUrlSource = (providedSource: PrerecordedSource): providedSource is UrlSource => { +export const isUrlSource = ( + providedSource: PrerecordedSource | AnalyzeSource +): providedSource is UrlSource => { if ((providedSource as UrlSource).url) return true; return false; }; +export const isTextSource = ( + providedSource: PrerecordedSource | AnalyzeSource +): providedSource is TextSource => { + if ((providedSource as TextSource).text) return true; + + return false; +}; + export const isFileSource = (providedSource: PrerecordedSource): providedSource is FileSource => { if (isReadStreamSource(providedSource) || isBufferSource(providedSource)) return true; diff --git a/src/lib/types/AnalyzeSchema.ts b/src/lib/types/AnalyzeSchema.ts new file mode 100644 index 00000000..093a41a3 --- /dev/null +++ b/src/lib/types/AnalyzeSchema.ts @@ -0,0 +1,28 @@ +/** + * Options for read analysis + */ +interface AnalyzeSchema extends Record { + callback?: string; + + callback_method?: string; + + custom_intent?: string | string[]; + + custom_intent_mode?: "strict" | "extended"; + + custom_topic?: string | string[]; + + custom_topic_mode?: "strict" | "extended"; + + intents?: boolean; + + language?: string; + + summarize?: boolean; + + sentiment?: boolean; + + topics?: boolean; +} + +export type { AnalyzeSchema }; diff --git a/src/lib/types/AsyncAnalyzeResponse.ts b/src/lib/types/AsyncAnalyzeResponse.ts new file mode 100644 index 00000000..ba7dd76f --- /dev/null +++ b/src/lib/types/AsyncAnalyzeResponse.ts @@ -0,0 +1,3 @@ +export interface AsyncAnalyzeResponse { + request_id: string; +} diff --git a/src/lib/types/PrerecordedSource.ts b/src/lib/types/DeepgramSource.ts similarity index 65% rename from src/lib/types/PrerecordedSource.ts rename to src/lib/types/DeepgramSource.ts index e85d5c02..a22fb4c0 100644 --- a/src/lib/types/PrerecordedSource.ts +++ b/src/lib/types/DeepgramSource.ts @@ -7,3 +7,9 @@ export type FileSource = Buffer | Readable; export interface UrlSource { url: string; } + +export interface TextSource { + text: string; +} + +export type AnalyzeSource = UrlSource | TextSource; diff --git a/src/lib/types/SpeechStartedEvent.ts b/src/lib/types/SpeechStartedEvent.ts new file mode 100644 index 00000000..2a8bdaba --- /dev/null +++ b/src/lib/types/SpeechStartedEvent.ts @@ -0,0 +1,5 @@ +export interface SpeechStartedEvent { + type: "SpeechStarted"; + channel: number[]; + timestamp: number; +} diff --git a/src/lib/types/SyncAnalyzeResponse.ts b/src/lib/types/SyncAnalyzeResponse.ts new file mode 100644 index 00000000..c725eab6 --- /dev/null +++ b/src/lib/types/SyncAnalyzeResponse.ts @@ -0,0 +1,88 @@ +export interface SyncAnalyzeResponse { + model_uuid: string; + metadata: Metadata; + results: Results; +} + +interface IntentsInfo { + model_uuid: string; + input_tokens: number; + output_tokens: number; +} + +interface SentimentInfo { + model_uuid: string; + input_tokens: number; + output_tokens: number; +} + +interface SummaryInfo { + model_uuid: string; + input_tokens: number; + output_tokens: number; +} + +interface TopicsInfo { + model_uuid: string; + input_tokens: number; + output_tokens: number; +} + +interface Metadata { + request_id: string; + created: string; + language: string; + intents_info: IntentsInfo; + sentiment_info: SentimentInfo; + summary_info: SummaryInfo; + topics_info: TopicsInfo; +} + +interface Average { + sentiment: string; + sentiment_score: number; +} + +interface Summary { + text: string; +} + +interface Topic { + topic: string; + confidence_score: number; +} + +interface Intent { + intent: string; + confidence_score: number; +} + +interface Segment { + text: string; + start_word: number; + end_word: number; + sentiment: "positive" | "neutral" | "negative"; + sentiment_score?: number; + topics?: Topic[]; + intents?: Intent[]; +} + +interface Sentiments { + segments: Segment[]; + average: Average; +} + +interface Topics { + segments: Segment[]; +} + +interface Intents { + segments: Segment[]; +} + +interface Results { + sentiments?: Sentiments; + summary?: Summary; + topics?: Topics; + intents?: Intents; +} diff --git a/src/lib/types/SyncPrerecordedResponse.ts b/src/lib/types/SyncPrerecordedResponse.ts index 81d0a6cc..18a5920d 100644 --- a/src/lib/types/SyncPrerecordedResponse.ts +++ b/src/lib/types/SyncPrerecordedResponse.ts @@ -44,8 +44,15 @@ interface Metadata { duration: number; channels: number; models: string[]; - model_info: Record; warnings?: Warning[]; + model_info: Record; + summary_info?: SummaryInfo; + intents_info?: IntentsInfo; + sentiment_info?: SentimentInfo; + topics_info?: TopicsInfo; + extra: { + [key: string]: unknown; + }; } interface ModelInfo { @@ -54,6 +61,30 @@ interface ModelInfo { arch: string; } +interface SummaryInfo { + input_tokens: number; + output_tokens: number; + model_uuid: string; +} + +interface IntentsInfo { + model_uuid: string; + input_tokens: number; + output_tokens: number; +} + +interface SentimentInfo { + model_uuid: string; + input_tokens: number; + output_tokens: number; +} + +interface TopicsInfo { + model_uuid: string; + input_tokens: number; + output_tokens: number; +} + interface Paragraph { sentences: Sentence[]; start: number; @@ -70,6 +101,47 @@ interface Result { channels: Channel[]; utterances?: Utterance[]; summary?: TranscriptionSummary; + sentiments?: Sentiments; + topics?: Topics; + intents?: Intents; +} + +interface Sentiments { + segments: Segment[]; + average: Average; +} + +interface Topics { + segments: Segment[]; +} + +interface Intents { + segments: Segment[]; +} + +interface Intent { + intent: string; + confidence_score: number; +} + +interface Average { + sentiment: string; + sentiment_score: number; +} + +interface Topic { + topic: string; + confidence_score: number; +} + +interface Segment { + text: string; + start_word: number; + end_word: number; + sentiment?: string; + sentiment_score?: number; + topics?: Topic[]; + intents?: Intent[]; } interface Search { diff --git a/src/lib/types/TranscriptionSchema.ts b/src/lib/types/TranscriptionSchema.ts index 68dd775b..139e05f5 100644 --- a/src/lib/types/TranscriptionSchema.ts +++ b/src/lib/types/TranscriptionSchema.ts @@ -8,6 +8,7 @@ interface TranscriptionSchema extends Record { model?: string; /** + * @deprecated * @see https://developers.deepgram.com/docs/tier */ tier?: string; @@ -42,11 +43,21 @@ interface TranscriptionSchema extends Record { */ diarize?: boolean; + /** + * @see https://developers.deepgram.com/docs/diarization + */ + diarize_version?: string; + /** * @see https://developers.deepgram.com/docs/smart-format */ smart_format?: boolean; + /** + * @see https://developers.deepgram.com/docs/filler-words + */ + filler_words?: boolean; + /** * @see https://developers.deepgram.com/docs/multichannel */ @@ -73,6 +84,11 @@ interface TranscriptionSchema extends Record { */ callback?: string; + /** + * @see https://developers.deepgram.com/docs/callback#results + */ + callback_method?: string; + /** * @see https://developers.deepgram.com/docs/keywords */ @@ -83,6 +99,46 @@ interface TranscriptionSchema extends Record { */ tag?: string[]; + /** + * As yet unreleased. + */ + sentiment?: boolean; + + /** + * As yet unreleased. + */ + intents?: boolean; + + /** + * As yet unreleased. + */ + custom_intent?: string[] | string; + + /** + * As yet unreleased. + */ + custom_intent_mode?: "strict" | "extended"; + + /** + * As yet unreleased. + */ + topics?: boolean; + + /** + * As yet unreleased. + */ + custom_topic?: string[] | string; + + /** + * As yet unreleased. + */ + custom_topic_mode?: "strict" | "extended"; + + /** + * @see https://developers.deepgram.com/docs/extra + */ + extra?: boolean; + [key: string]: unknown; } @@ -103,7 +159,11 @@ interface PrerecordedSchema extends TranscriptionSchema { detect_topics?: boolean; /** - * Undocumented feature. + * Alternatives will run your transcription X number of times and return + * that many variations of the transcription, allowing for the selection + * of the most accurate. Cost increases by number of alternatives. + * + * @deprecated */ alternatives?: number; @@ -126,6 +186,16 @@ interface PrerecordedSchema extends TranscriptionSchema { * @see https://developers.deepgram.com/docs/utterance-split */ utt_split?: number; + + /** + * @see https://developers.deepgram.com/docs/smart-format#dictation + */ + dictation?: boolean; + + /** + * @see https://developers.deepgram.com/docs/smart-format#measurements + */ + measurements?: boolean; } interface LiveSchema extends TranscriptionSchema { @@ -147,12 +217,17 @@ interface LiveSchema extends TranscriptionSchema { /** * @see https://developers.deepgram.com/docs/endpointing */ - endpointing?: number; + endpointing?: false | number; /** * @see https://developers.deepgram.com/docs/interim-results */ interim_results?: boolean; + + /** + * @see https://developers.deepgram.com/docs/understanding-end-of-speech-detection + */ + utterance_end_ms?: number; } export type { TranscriptionSchema, PrerecordedSchema, LiveSchema }; diff --git a/src/lib/types/UtteranceEndEvent.ts b/src/lib/types/UtteranceEndEvent.ts new file mode 100644 index 00000000..83e241cc --- /dev/null +++ b/src/lib/types/UtteranceEndEvent.ts @@ -0,0 +1,5 @@ +export interface UtteranceEndEvent { + type: "UtteranceEnd"; + channel: number[]; + last_word_end: number; +} diff --git a/src/lib/types/index.ts b/src/lib/types/index.ts index 7fc52cb9..0acd1827 100644 --- a/src/lib/types/index.ts +++ b/src/lib/types/index.ts @@ -1,4 +1,6 @@ +export type { AnalyzeSchema } from "./AnalyzeSchema"; export type { AsyncPrerecordedResponse } from "./AsyncPrerecordedResponse"; +export type { AsyncAnalyzeResponse } from "./AsyncAnalyzeResponse"; export type { CreateOnPremCredentialsSchema } from "./CreateOnPremCredentialsSchema"; export type { CreateProjectKeySchema } from "./CreateProjectKeySchema"; export type { CreateProjectKeyResponse } from "./CreateProjectKeyResponse"; @@ -32,10 +34,19 @@ export type { LiveConfigOptions } from "./LiveConfigOptions"; export type { LiveMetadataEvent } from "./LiveMetadataEvent"; export type { LiveTranscriptionEvent } from "./LiveTranscriptionEvent"; export type { MessageResponse } from "./MessageResponse"; -export type { FileSource, PrerecordedSource, UrlSource } from "./PrerecordedSource"; +export type { + FileSource, + PrerecordedSource, + UrlSource, + TextSource, + AnalyzeSource, +} from "./DeepgramSource"; export type { SendProjectInviteSchema } from "./SendProjectInviteSchema"; +export type { SpeechStartedEvent } from "./SpeechStartedEvent"; export type { SyncPrerecordedResponse } from "./SyncPrerecordedResponse"; +export type { SyncAnalyzeResponse } from "./SyncAnalyzeResponse"; export type { TranscriptionSchema, PrerecordedSchema, LiveSchema } from "./TranscriptionSchema"; export type { UpdateProjectMemberScopeSchema } from "./UpdateProjectMemberScopeSchema"; export type { UpdateProjectSchema } from "./UpdateProjectSchema"; +export type { UtteranceEndEvent } from "./UtteranceEndEvent"; export type { VoidResponse } from "./VoidResponse"; diff --git a/src/packages/AbstractClient.ts b/src/packages/AbstractClient.ts index 7f0e53ba..1ef95d49 100644 --- a/src/packages/AbstractClient.ts +++ b/src/packages/AbstractClient.ts @@ -31,21 +31,46 @@ export abstract class AbstractClient { ); } - if (this.willProxy()) { + let baseUrlString: string = this.options.global.url; + let proxyUrlString: string; + + /** + * Check if the base URL provided is missing a protocol and warn in the console. + */ + if (!baseUrlString.startsWith("http") && !baseUrlString.startsWith("ws")) { + console.warn( + `The base URL provided does not begin with http, https, ws, or wss and will default to https as standard.` + ); + } + + /** + * Applying proxy to base URL. + */ + if (this.options.restProxy?.url) { + /** + * Prevent client using a real API key when using a proxy configuration. + */ if (this.key !== "proxy") { throw new DeepgramError( `Do not attempt to pass any other API key than the string "proxy" when making proxied REST requests. Please ensure your proxy application is responsible for writing our API key to the Authorization header.` ); } - this.baseUrl = this.resolveBaseUrl(this.options.restProxy?.url as string); + proxyUrlString = this.options.restProxy.url; - if (this.options.global.headers) { - this.options.global.headers["X-Deepgram-Proxy"] = this.options.global.url; + /** + * Check if the proxy URL provided is missing a protocol and warn in the console. + */ + if (!proxyUrlString.startsWith("http") && !proxyUrlString.startsWith("ws")) { + console.warn( + `The proxy URL provided does not begin with http, https, ws, or wss and will default to https as standard.` + ); } - } else { - this.baseUrl = this.resolveBaseUrl(this.options.global.url); + + baseUrlString = proxyUrlString; } + + this.baseUrl = this.resolveBaseUrl(baseUrlString); } protected resolveBaseUrl(url: string) { diff --git a/src/packages/AbstractRestfulClient.ts b/src/packages/AbstractRestfulClient.ts index 90507f5a..6ac59984 100644 --- a/src/packages/AbstractRestfulClient.ts +++ b/src/packages/AbstractRestfulClient.ts @@ -12,7 +12,7 @@ export abstract class AbstractRestfulClient extends AbstractClient { constructor(protected key: string, protected options: DeepgramClientOptions) { super(key, options); - if (isBrowser() && !this.willProxy()) { + if (isBrowser() && !this._willProxy()) { throw new DeepgramError( "Due to CORS we are unable to support REST-based API calls to our API from the browser. Please consider using a proxy, and including a `restProxy: { url: ''}` in your Deepgram client options." ); @@ -130,4 +130,10 @@ export abstract class AbstractRestfulClient extends AbstractClient { ): Promise { return this._handleRequest(fetcher, "DELETE", url, headers, parameters); } + + private _willProxy() { + const proxyUrl = this.options.restProxy?.url; + + return !!proxyUrl; + } } diff --git a/src/packages/LiveClient.ts b/src/packages/LiveClient.ts index 2522e4f1..d1353cb1 100644 --- a/src/packages/LiveClient.ts +++ b/src/packages/LiveClient.ts @@ -11,6 +11,8 @@ import type { LiveMetadataEvent, LiveTranscriptionEvent, DeepgramClientOptions, + UtteranceEndEvent, + SpeechStartedEvent, } from "../lib/types"; export class LiveClient extends AbstractWsClient { @@ -53,6 +55,14 @@ export class LiveClient extends AbstractWsClient { if (data.type === LiveTranscriptionEvents.Transcript) { this.emit(LiveTranscriptionEvents.Transcript, data as LiveTranscriptionEvent); } + + if (data.type === LiveTranscriptionEvents.UtteranceEnd) { + this.emit(LiveTranscriptionEvents.UtteranceEnd, data as UtteranceEndEvent); + } + + if (data.type === LiveTranscriptionEvents.SpeechStarted) { + this.emit(LiveTranscriptionEvents.SpeechStarted, data as SpeechStartedEvent); + } } catch (error) { this.emit(LiveTranscriptionEvents.Error, { event, diff --git a/src/packages/PrerecordedClient.ts b/src/packages/PrerecordedClient.ts index 9277f129..3575fa99 100644 --- a/src/packages/PrerecordedClient.ts +++ b/src/packages/PrerecordedClient.ts @@ -28,7 +28,7 @@ export class PrerecordedClient extends AbstractRestfulClient { if (options !== undefined && "callback" in options) { throw new DeepgramError( - "Callback cannot be provided as an option to a synchronous transcription. Use `asyncPrerecordedUrl` or `asyncPrerecordedFile` instead." + "Callback cannot be provided as an option to a synchronous transcription. Use `transcribeUrlCallback` or `transcribeFileCallback` instead." ); } @@ -65,7 +65,7 @@ export class PrerecordedClient extends AbstractRestfulClient { if (options !== undefined && "callback" in options) { throw new DeepgramError( - "Callback cannot be provided as an option to a synchronous transcription. Use `asyncPrerecordedUrl` or `asyncPrerecordedFile` instead." + "Callback cannot be provided as an option to a synchronous transcription. Use `transcribeUrlCallback` or `transcribeFileCallback` instead." ); } diff --git a/src/packages/ReadClient.ts b/src/packages/ReadClient.ts new file mode 100644 index 00000000..17f82dbb --- /dev/null +++ b/src/packages/ReadClient.ts @@ -0,0 +1,161 @@ +import { AbstractRestfulClient } from "./AbstractRestfulClient"; +import { CallbackUrl, appendSearchParams, isTextSource, isUrlSource } from "../lib/helpers"; +import { DeepgramError, isDeepgramError } from "../lib/errors"; +import type { + AnalyzeSchema, + AsyncAnalyzeResponse, + DeepgramResponse, + Fetch, + PrerecordedSchema, + SyncAnalyzeResponse, + TextSource, + UrlSource, +} from "../lib/types"; + +export class ReadClient extends AbstractRestfulClient { + async analyzeUrl( + source: UrlSource, + options?: AnalyzeSchema, + endpoint = "v1/read" + ): Promise> { + try { + let body; + + if (isUrlSource(source)) { + body = JSON.stringify(source); + } else { + throw new DeepgramError("Unknown source type"); + } + + if (options !== undefined && "callback" in options) { + throw new DeepgramError( + "Callback cannot be provided as an option to a synchronous transcription. Use `analyzeUrlCallback` or `analyzeTextCallback` instead." + ); + } + + const analyzeOptions: AnalyzeSchema = { ...{}, ...options }; + + const url = new URL(endpoint, this.baseUrl); + appendSearchParams(url.searchParams, analyzeOptions); + + const result: SyncAnalyzeResponse = await this.post(this.fetch as Fetch, url, body); + + return { result, error: null }; + } catch (error) { + if (isDeepgramError(error)) { + return { result: null, error }; + } + + throw error; + } + } + + async analyzeText( + source: TextSource, + options?: AnalyzeSchema, + endpoint = "v1/read" + ): Promise> { + try { + let body; + + if (isTextSource(source)) { + body = JSON.stringify(source); + } else { + throw new DeepgramError("Unknown source type"); + } + + if (options !== undefined && "callback" in options) { + throw new DeepgramError( + "Callback cannot be provided as an option to a synchronous requests. Use `analyzeUrlCallback` or `analyzeTextCallback` instead." + ); + } + + const analyzeOptions: AnalyzeSchema = { ...{}, ...options }; + + const url = new URL(endpoint, this.baseUrl); + appendSearchParams(url.searchParams, analyzeOptions); + + const result: SyncAnalyzeResponse = await this.post(this.fetch as Fetch, url, body); + + return { result, error: null }; + } catch (error) { + if (isDeepgramError(error)) { + return { result: null, error }; + } + + throw error; + } + } + + async analyzeUrlCallback( + source: UrlSource, + callback: CallbackUrl, + options?: AnalyzeSchema, + endpoint = "v1/read" + ): Promise> { + try { + let body; + + if (isUrlSource(source)) { + body = JSON.stringify(source); + } else { + throw new DeepgramError("Unknown source type"); + } + + const transcriptionOptions: PrerecordedSchema = { + ...options, + ...{ callback: callback.toString() }, + }; + + const url = new URL(endpoint, this.baseUrl); + appendSearchParams(url.searchParams, transcriptionOptions); + + const result: AsyncAnalyzeResponse = await this.post(this.fetch as Fetch, url, body); + + return { result, error: null }; + } catch (error) { + if (isDeepgramError(error)) { + return { result: null, error }; + } + + throw error; + } + } + + async analyzeTextCallback( + source: TextSource, + callback: CallbackUrl, + options?: AnalyzeSchema, + endpoint = "v1/read" + ): Promise> { + try { + let body; + + if (isTextSource(source)) { + body = source; + } else { + throw new DeepgramError("Unknown source type"); + } + + const transcriptionOptions: PrerecordedSchema = { + ...options, + ...{ callback: callback.toString() }, + }; + + const url = new URL(endpoint, this.baseUrl); + appendSearchParams(url.searchParams, transcriptionOptions); + + const result: AsyncAnalyzeResponse = await this.post(this.fetch as Fetch, url, body, { + "Content-Type": "deepgram/audio+video", + }); + + return { result, error: null }; + } catch (error) { + if (isDeepgramError(error)) { + return { result: null, error }; + } + + throw error; + } + } +} diff --git a/test/legacy.test.ts b/test/legacy.test.ts new file mode 100644 index 00000000..ecb1f872 --- /dev/null +++ b/test/legacy.test.ts @@ -0,0 +1,120 @@ +import { assert, expect } from "chai"; +import { createClient, Deepgram, DeepgramVersionError } from "../src"; +import { faker } from "@faker-js/faker"; +import DeepgramClient from "../src/DeepgramClient"; + +const errorText = + "You are attempting to use an old format for a newer SDK version. Read more here: https://dpgr.am/js-v3"; + +describe("legacy error handling", () => { + let deepgram: DeepgramClient; + + beforeEach(() => { + deepgram = createClient(faker.string.alphanumeric(40), { + global: { url: "https://api.mock.deepgram.com" }, + }); + }); + + it("should create the correct client object", () => { + expect(deepgram).to.not.be.undefined; + expect(deepgram).is.instanceOf(DeepgramClient); + }); + + it("should error when using a v2 client object", async () => { + assert.throw( + () => { + new Deepgram(faker.string.alphanumeric(40)); + }, + DeepgramVersionError, + errorText + ); + }); + + it("should error when using an old v2 callstack for transcription", async () => { + assert.throw( + () => { + deepgram.transcription.preRecorded( + { + url: "https://dpgr.am/spacewalk.wav", + }, + { + model: "nova", + callback: "http://callback/endpoint", + } + ); + }, + DeepgramVersionError, + errorText + ); + }); + + it("should error when using an old v2 callstack for projects", async () => { + assert.throw( + () => { + deepgram.projects.list(); + }, + DeepgramVersionError, + errorText + ); + }); + + it("should error when using an old v2 callstack for keys", async () => { + assert.throw( + () => { + deepgram.keys.list("projectId"); + }, + DeepgramVersionError, + errorText + ); + }); + + it("should error when using an old v2 callstack for members", async () => { + assert.throw( + () => { + deepgram.members.listMembers("projectId"); + }, + DeepgramVersionError, + errorText + ); + }); + + it("should error when using an old v2 callstack for scopes", async () => { + assert.throw( + () => { + deepgram.scopes.get("projectId", "projectMemberId"); + }, + DeepgramVersionError, + errorText + ); + }); + + it("should error when using an old v2 callstack for invitation", async () => { + assert.throw( + () => { + deepgram.invitation.list("projectId"); + }, + DeepgramVersionError, + errorText + ); + }); + + it("should error when using an old v2 callstack for usage", async () => { + assert.throw( + () => { + deepgram.usage.listRequests("projectId", {}); + }, + DeepgramVersionError, + errorText + ); + }); + + it("should error when using an old v2 callstack for billing", async () => { + assert.throw( + () => { + deepgram.billing.listBalances("projectId"); + }, + DeepgramVersionError, + errorText + ); + }); +});