1+ /**
2+ * Core gSpeak class and SaveCallback type.
3+ *
4+ * @module
5+ */
16import generateToken from './gToken.ts'
27import LANGUAGES from './languages.ts'
38
@@ -9,6 +14,8 @@ const escapeRegExp = (s: string): string => s.replace(/[|\\{}()[\]^$+*?.]/g, '\\
914/**
1015 * Callback passed to the Node-style {@link gSpeak.save} overload.
1116 * Receives `null` on success or an `Error` on failure.
17+ *
18+ * @param err - `null` on success, `Error` on failure.
1219 */
1320// deno-lint-ignore no-explicit-any
1421export type SaveCallback = ( err : any ) => void
@@ -17,7 +24,7 @@ export type SaveCallback = (err: any) => void
1724 * Google Text-to-Speech client.
1825 *
1926 * Converts text to spoken MP3 audio via the Google TTS endpoint.
20- * Long text is automatically split into ≤100-character chunks and reassembled.
27+ * Long text is automatically split into chunks of ≤100 characters and reassembled.
2128 *
2229 * Compatible with **Node.js**, **Deno**, **Bun**, **browsers**, and **Cloudflare Workers**.
2330 * Use {@link stream} or {@link bytes} in browser and worker environments.
@@ -30,9 +37,16 @@ export type SaveCallback = (err: any) => void
3037 * ```
3138 */
3239export class gSpeak {
40+ /** The BCP 47 language code used for this instance. */
3341 private lang : string
42+
43+ /** The original text passed to the constructor. */
3444 private text : string
45+
46+ /** The text split into ≤100-character chunks ready for requests. */
3547 private text_parts : string [ ]
48+
49+ /** Whether debug logging is enabled. */
3650 private debug : boolean
3751
3852 /**
@@ -65,6 +79,11 @@ export class gSpeak {
6579 this . text_parts = parts
6680 }
6781
82+ /**
83+ * Returns the HTTP headers required by the Google TTS endpoint.
84+ *
85+ * @returns Headers object with `Referer` and `User-Agent`.
86+ */
6887 private getHeaders ( ) : Record < string , string > {
6988 return {
7089 'Referer' : 'http://translate.google.com/' ,
@@ -73,6 +92,13 @@ export class gSpeak {
7392 }
7493 }
7594
95+ /**
96+ * Builds the Google TTS request URL for a single text chunk.
97+ *
98+ * @param part - The text chunk to synthesize.
99+ * @param idx - The index of this chunk within the full text.
100+ * @returns The fully constructed request URL string.
101+ */
76102 private getUrl ( part : string , idx : number ) : string {
77103 const params = new URLSearchParams ( {
78104 ie : 'UTF-8' ,
@@ -90,13 +116,16 @@ export class gSpeak {
90116 /**
91117 * Returns a Web `ReadableStream<Uint8Array>` of the MP3 audio data.
92118 *
93- * Uses only the Web Fetch API and Streams API — compatible with
119+ * Uses only the Web Fetch and Streams APIs — compatible with
94120 * **Node.js 18+**, **Deno**, **Bun**, **browsers**, and **Cloudflare Workers**.
95121 *
122+ * @returns A `ReadableStream` that emits MP3 audio chunks.
123+ *
96124 * @example
97125 * ```ts
126+ * // Cloudflare Worker / browser
98127 * const stream = new gSpeak("Hello", "en").stream()
99- * const response = new Response(stream, { headers: { "Content-Type": "audio/mpeg" } })
128+ * return new Response(stream, { headers: { "Content-Type": "audio/mpeg" } })
100129 * ```
101130 */
102131 stream ( ) : ReadableStream < Uint8Array > {
@@ -130,10 +159,11 @@ export class gSpeak {
130159 *
131160 * Works in every runtime — **Node.js**, **Deno**, **Bun**, **browsers**, and **Cloudflare Workers**.
132161 *
162+ * @returns A `Promise` that resolves to a `Uint8Array` containing the full MP3 data.
163+ *
133164 * @example
134165 * ```ts
135166 * const bytes = await new gSpeak("Hello", "en").bytes()
136- * // bytes is a Uint8Array containing the MP3 data
137167 * ```
138168 */
139169 async bytes ( ) : Promise < Uint8Array > {
@@ -160,10 +190,8 @@ export class gSpeak {
160190 * - **Deno**: uses `Deno.writeFile`
161191 * - **Node.js / Bun**: uses `node:fs/promises`
162192 *
163- * > **Not available in browsers or Cloudflare Workers.** Use {@link stream} or {@link bytes} instead.
164- *
165- * Accepts an optional Node-style callback for backward compatibility.
166- * If no callback is provided, returns a `Promise<void>`.
193+ * > **Not available in browsers or Cloudflare Workers.**
194+ * > Use {@link stream} or {@link bytes} instead.
167195 *
168196 * @param filePath - Path to write the MP3 file to.
169197 * @param callback - Optional Node-style callback `(err) => void`.
@@ -202,12 +230,27 @@ export class gSpeak {
202230 }
203231 }
204232
233+ /**
234+ * Splits text into chunks that respect sentence boundaries and fit within `max_size`.
235+ *
236+ * @param text - The full text to split.
237+ * @param max_size - Maximum character length per chunk.
238+ * @returns An array of text chunks.
239+ */
205240 private _tokenize ( text : string , max_size : number ) : string [ ] {
206241 const punc = '¡!()[]¿?.,;:—«»\n' . split ( '' ) . map ( escapeRegExp )
207242 const parts = text . split ( new RegExp ( punc . join ( '|' ) ) )
208243 return parts . flatMap ( p => this . _minimize ( p , ' ' , max_size ) )
209244 }
210245
246+ /**
247+ * Recursively splits a string by `delim` until all parts fit within `max_size`.
248+ *
249+ * @param str - The string to split.
250+ * @param delim - The delimiter to split on.
251+ * @param max_size - Maximum character length per part.
252+ * @returns An array of strings each within `max_size`.
253+ */
211254 private _minimize ( str : string , delim : string , max_size : number ) : string [ ] {
212255 if ( str . length <= max_size ) return [ str ]
213256 const idx = str . lastIndexOf ( delim )
@@ -217,10 +260,12 @@ export class gSpeak {
217260 /**
218261 * A map of all supported BCP 47 language codes to their display names.
219262 *
263+ * @returns A `Record<string, string>` of language code to display name.
264+ *
220265 * @example
221266 * ```ts
222- * console.log(gSpeak.languages["en"]) // "English"
223- * console.log(gSpeak.languages["zh-cn"]) // "Chinese (Simplified)"
267+ * console.log(gSpeak.languages["en"]) // "English"
268+ * console.log(gSpeak.languages["zh-cn"]) // "Chinese (Simplified)"
224269 * ```
225270 */
226271 static get languages ( ) : Record < string , string > {
0 commit comments