Skip to content

Commit 486fd86

Browse files
committed
feat: abstract client rebuilt for namespace options
1 parent c11a0a3 commit 486fd86

5 files changed

Lines changed: 112 additions & 100 deletions

File tree

src/lib/constants.ts

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { isBrowser } from "./helpers";
2-
import { DeepgramClientOptions } from "./types/DeepgramClientOptions";
3-
import { FetchOptions } from "./types/Fetch";
1+
import { convertProtocolToWs, isBrowser } from "./helpers";
2+
import { DefaultNamespaceOptions, DefaultClientOptions } from "./types/DeepgramClientOptions";
43
import { version } from "./version";
54

65
export const NODE_VERSION =
@@ -16,15 +15,11 @@ export const DEFAULT_HEADERS = {
1615

1716
export const DEFAULT_URL = "https://api.deepgram.com";
1817

19-
export const DEFAULT_GLOBAL_OPTIONS = {
20-
url: DEFAULT_URL,
18+
export const DEFAULT_GLOBAL_OPTIONS: DefaultNamespaceOptions = {
19+
fetch: { options: { url: DEFAULT_URL, headers: DEFAULT_HEADERS } },
20+
websocket: { options: { url: convertProtocolToWs(DEFAULT_URL) } },
2121
};
2222

23-
export const DEFAULT_FETCH_OPTIONS: FetchOptions = {
24-
headers: DEFAULT_HEADERS,
25-
};
26-
27-
export const DEFAULT_OPTIONS: DeepgramClientOptions = {
23+
export const DEFAULT_OPTIONS: DefaultClientOptions = {
2824
global: DEFAULT_GLOBAL_OPTIONS,
29-
fetch: DEFAULT_FETCH_OPTIONS,
3025
};

src/lib/helpers.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,8 @@ export function stripTrailingSlash(url: string): string {
1717
export const isBrowser = () => typeof window !== "undefined";
1818
export const isServer = () => typeof process !== "undefined";
1919

20-
export function applySettingDefaults(
21-
options: DeepgramClientOptions,
22-
defaults: DeepgramClientOptions
23-
): DeepgramClientOptions {
24-
return merge(defaults, options);
20+
export function applyDefaults<O, S>(options: Partial<O>, subordinate: Partial<S>): S {
21+
return merge(subordinate, options);
2522
}
2623

2724
export function appendSearchParams(
@@ -83,5 +80,19 @@ const isReadStreamSource = (providedSource: PrerecordedSource): providedSource i
8380
};
8481

8582
export class CallbackUrl extends URL {
86-
private callbackUrl = true;
83+
public callbackUrl = true;
8784
}
85+
86+
export const convertProtocolToWs = (url: string | URL) => {
87+
const convert = (string: string) => string.toLowerCase().replace(/(http)(s)?/gi, "ws$2");
88+
89+
if (url instanceof URL) {
90+
return new URL(convert(url.toString()));
91+
}
92+
93+
if (typeof url === "string") {
94+
return new URL(convert(url));
95+
}
96+
97+
throw new Error("URL must be a string or `URL` object");
98+
};
Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,62 @@
1-
import { Fetch, FetchOptions } from "./Fetch";
1+
import { FetchOptions } from "./Fetch";
22

3+
export type IFetch = typeof fetch;
4+
export type IWebSocket = typeof WebSocket;
5+
6+
/**
7+
* Configures the options for a Deepgram client.
8+
*
9+
* The `DeepgramClientOptions` interface defines the configuration options for a Deepgram client. It includes options for various namespaces, such as `global`, `listen`, `manage`, `onprem`, `read`, and `speak`. Each namespace has its own options for configuring the transport, including the URL, proxy, and options for the fetch and WebSocket clients.
10+
*
11+
* The `global` namespace is used to configure options that apply globally to the Deepgram client. The other namespaces are used to configure options specific to different Deepgram API endpoints.
12+
*/
313
export interface DeepgramClientOptions {
4-
global?: {
5-
/**
6-
* Optional headers for initializing the client.
7-
*/
8-
headers?: Record<string, string>;
9-
10-
/**
11-
* The URL used to interact with production, On-prem and other Deepgram environments. Defaults to `api.deepgram.com`.
12-
*/
13-
url?: string;
14-
};
15-
fetch?: FetchOptions;
16-
_experimentalCustomFetch?: Fetch;
17-
restProxy?: {
18-
url: null | string;
14+
global?: NamespaceOptions;
15+
listen?: NamespaceOptions;
16+
manage?: NamespaceOptions;
17+
onprem?: NamespaceOptions;
18+
read?: NamespaceOptions;
19+
speak?: NamespaceOptions;
20+
21+
/**
22+
* Support introductory format
23+
*/
24+
[index: string]: any;
25+
// _experimentalCustomFetch?: Fetch;
26+
// restProxy?: {
27+
// url: null | string;
28+
// };
29+
}
30+
31+
interface TransportFetchOptions extends TransportOptions, FetchOptions {}
32+
33+
type TransportUrl = URL | string;
34+
35+
interface TransportOptions {
36+
url?: TransportUrl;
37+
proxy?: {
38+
url?: null | TransportUrl;
1939
};
2040
}
41+
42+
interface ITransport<C, O> {
43+
client?: C;
44+
options?: O;
45+
}
46+
export interface NamespaceOptions {
47+
fetch?: ITransport<IFetch, TransportFetchOptions>;
48+
websocket?: ITransport<IWebSocket, TransportOptions>;
49+
}
50+
51+
export type DefaultNamespaceOptions = {
52+
fetch: {
53+
options: { url: TransportUrl };
54+
};
55+
websocket: {
56+
options: { url: TransportUrl };
57+
};
58+
} & NamespaceOptions;
59+
60+
export type DefaultClientOptions = {
61+
global: DefaultNamespaceOptions;
62+
} & DeepgramClientOptions;

src/packages/AbstractClient.ts

Lines changed: 28 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,29 @@
1-
import { DEFAULT_OPTIONS, DEFAULT_URL } from "../lib/constants";
1+
import { DEFAULT_OPTIONS } from "../lib/constants";
22
import { DeepgramError } from "../lib/errors";
3-
import { applySettingDefaults, stripTrailingSlash } from "../lib/helpers";
3+
import { applyDefaults } from "../lib/helpers";
44
import { DeepgramClientOptions } from "../lib/types";
5+
import {
6+
DefaultClientOptions,
7+
DefaultNamespaceOptions,
8+
NamespaceOptions,
9+
} from "../lib/types/DeepgramClientOptions";
510

611
/**
7-
* Deepgram Client.
12+
* Represents an abstract Deepgram client that provides a base implementation for interacting with the Deepgram API.
813
*
9-
* An isomorphic Javascript client for interacting with the Deepgram API.
10-
* @see https://developers.deepgram.com
14+
* The `AbstractClient` class is responsible for:
15+
* - Initializing the Deepgram API key
16+
* - Applying default options for the client and namespace
17+
* - Providing a namespace for organizing API requests
18+
*
19+
* Subclasses of `AbstractClient` should implement the specific functionality for interacting with the Deepgram API.
1120
*/
1221
export abstract class AbstractClient {
13-
protected baseUrl: URL;
22+
public namespace: string = "global";
23+
protected namespaceOptions: DefaultNamespaceOptions;
24+
protected options: DefaultClientOptions;
1425

15-
constructor(protected key: string, protected options: DeepgramClientOptions) {
26+
constructor(protected key: string, options: DeepgramClientOptions) {
1627
this.key = key;
1728

1829
if (!key) {
@@ -23,67 +34,20 @@ export abstract class AbstractClient {
2334
throw new DeepgramError("A deepgram API key is required");
2435
}
2536

26-
this.options = applySettingDefaults(options, DEFAULT_OPTIONS);
27-
28-
if (!this.options.global?.url) {
29-
throw new DeepgramError(
30-
`An API URL is required. It should be set to ${DEFAULT_URL} by default. No idea what happened!`
31-
);
32-
}
33-
34-
let baseUrlString: string = this.options.global.url;
35-
let proxyUrlString: string;
36-
3737
/**
38-
* Check if the base URL provided is missing a protocol and warn in the console.
38+
* Apply default options.
3939
*/
40-
if (!baseUrlString.startsWith("http") && !baseUrlString.startsWith("ws")) {
41-
console.warn(
42-
`The base URL provided does not begin with http, https, ws, or wss and will default to https as standard.`
43-
);
44-
}
40+
this.options = applyDefaults<DeepgramClientOptions, DefaultClientOptions>(
41+
options,
42+
DEFAULT_OPTIONS
43+
);
4544

4645
/**
47-
* Applying proxy to base URL.
46+
* Roll up options for this namespace.
4847
*/
49-
if (this.options.restProxy?.url) {
50-
/**
51-
* Prevent client using a real API key when using a proxy configuration.
52-
*/
53-
if (this.key !== "proxy") {
54-
throw new DeepgramError(
55-
`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.`
56-
);
57-
}
58-
59-
proxyUrlString = this.options.restProxy.url;
60-
61-
/**
62-
* Check if the proxy URL provided is missing a protocol and warn in the console.
63-
*/
64-
if (!proxyUrlString.startsWith("http") && !proxyUrlString.startsWith("ws")) {
65-
console.warn(
66-
`The proxy URL provided does not begin with http, https, ws, or wss and will default to https as standard.`
67-
);
68-
}
69-
70-
baseUrlString = proxyUrlString;
71-
}
72-
73-
this.baseUrl = this.resolveBaseUrl(baseUrlString);
74-
}
75-
76-
protected resolveBaseUrl(url: string) {
77-
if (!/^https?:\/\//i.test(url)) {
78-
url = "https://" + url;
79-
}
80-
81-
return new URL(stripTrailingSlash(url));
82-
}
83-
84-
protected willProxy() {
85-
const proxyUrl = this.options.restProxy?.url;
86-
87-
return !!proxyUrl;
48+
this.namespaceOptions = applyDefaults<NamespaceOptions, DefaultNamespaceOptions>(
49+
this.options[this.namespace],
50+
this.options.global!
51+
);
8852
}
8953
}

src/packages/AbstractRestfulClient.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { isBrowser } from "../lib/helpers";
99
export abstract class AbstractRestfulClient extends AbstractClient {
1010
protected fetch: Fetch;
1111

12-
constructor(protected key: string, protected options: DeepgramClientOptions) {
12+
constructor(protected key: string, options: DeepgramClientOptions) {
1313
super(key, options);
1414

1515
if (isBrowser() && !this._willProxy()) {
@@ -18,7 +18,7 @@ export abstract class AbstractRestfulClient extends AbstractClient {
1818
);
1919
}
2020

21-
this.fetch = fetchWithAuth(this.key, options._experimentalCustomFetch);
21+
this.fetch = fetchWithAuth(this.key, this.namespaceOptions.fetch.client);
2222
}
2323

2424
protected _getErrorMessage(err: any): string {
@@ -153,7 +153,7 @@ export abstract class AbstractRestfulClient extends AbstractClient {
153153
}
154154

155155
private _willProxy() {
156-
const proxyUrl = this.options.restProxy?.url;
156+
const proxyUrl = this.key === "proxy" && !!this.namespaceOptions.fetch.options.proxy?.url;
157157

158158
return !!proxyUrl;
159159
}

0 commit comments

Comments
 (0)