@leiboss/dsh-tts 0.0.0-stage → 0.3.0

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 (89) hide show
  1. package/CHANGELOG.md +111 -0
  2. package/LICENSE +21 -0
  3. package/README.md +374 -2
  4. package/cordis.patch.yml +4 -0
  5. package/dist/audio/mp3-duration.d.ts +23 -0
  6. package/dist/audio/mp3-duration.d.ts.map +1 -0
  7. package/dist/audio/mp3-duration.js +140 -0
  8. package/dist/audio/mp3-duration.js.map +1 -0
  9. package/dist/audio-route.d.ts +122 -0
  10. package/dist/audio-route.d.ts.map +1 -0
  11. package/dist/audio-route.js +408 -0
  12. package/dist/audio-route.js.map +1 -0
  13. package/dist/cache.d.ts +50 -0
  14. package/dist/cache.d.ts.map +1 -0
  15. package/dist/cache.js +105 -0
  16. package/dist/cache.js.map +1 -0
  17. package/dist/chunked-tts.d.ts +34 -0
  18. package/dist/chunked-tts.d.ts.map +1 -0
  19. package/dist/chunked-tts.js +121 -0
  20. package/dist/chunked-tts.js.map +1 -0
  21. package/dist/chunker.d.ts +19 -0
  22. package/dist/chunker.d.ts.map +1 -0
  23. package/dist/chunker.js +98 -0
  24. package/dist/chunker.js.map +1 -0
  25. package/dist/client.js +90 -0
  26. package/dist/concurrency.d.ts +33 -0
  27. package/dist/concurrency.d.ts.map +1 -0
  28. package/dist/concurrency.js +95 -0
  29. package/dist/concurrency.js.map +1 -0
  30. package/dist/config.d.ts +174 -0
  31. package/dist/config.d.ts.map +1 -0
  32. package/dist/config.js +186 -0
  33. package/dist/config.js.map +1 -0
  34. package/dist/edge-tts.d.ts +74 -0
  35. package/dist/edge-tts.d.ts.map +1 -0
  36. package/dist/edge-tts.js +161 -0
  37. package/dist/edge-tts.js.map +1 -0
  38. package/dist/engine-health.d.ts +108 -0
  39. package/dist/engine-health.d.ts.map +1 -0
  40. package/dist/engine-health.js +170 -0
  41. package/dist/engine-health.js.map +1 -0
  42. package/dist/engines/edge-js.d.ts +51 -0
  43. package/dist/engines/edge-js.d.ts.map +1 -0
  44. package/dist/engines/edge-js.js +98 -0
  45. package/dist/engines/edge-js.js.map +1 -0
  46. package/dist/errors.d.ts +66 -0
  47. package/dist/errors.d.ts.map +1 -0
  48. package/dist/errors.js +110 -0
  49. package/dist/errors.js.map +1 -0
  50. package/dist/fallback.d.ts +69 -0
  51. package/dist/fallback.d.ts.map +1 -0
  52. package/dist/fallback.js +89 -0
  53. package/dist/fallback.js.map +1 -0
  54. package/dist/index.d.ts +72 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +723 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/probe.d.ts +42 -0
  59. package/dist/probe.d.ts.map +1 -0
  60. package/dist/probe.js +63 -0
  61. package/dist/probe.js.map +1 -0
  62. package/dist/provider.d.ts +33 -0
  63. package/dist/provider.d.ts.map +1 -0
  64. package/dist/provider.js +7 -0
  65. package/dist/provider.js.map +1 -0
  66. package/dist/register-service.d.ts +25 -0
  67. package/dist/register-service.d.ts.map +1 -0
  68. package/dist/register-service.js +33 -0
  69. package/dist/register-service.js.map +1 -0
  70. package/dist/sapi-tts.d.ts +29 -0
  71. package/dist/sapi-tts.d.ts.map +1 -0
  72. package/dist/sapi-tts.js +131 -0
  73. package/dist/sapi-tts.js.map +1 -0
  74. package/dist/self-check.d.ts +32 -0
  75. package/dist/self-check.d.ts.map +1 -0
  76. package/dist/self-check.js +75 -0
  77. package/dist/self-check.js.map +1 -0
  78. package/dist/service.d.ts +119 -0
  79. package/dist/service.d.ts.map +1 -0
  80. package/dist/service.js +404 -0
  81. package/dist/service.js.map +1 -0
  82. package/dist/voices.d.ts +21 -0
  83. package/dist/voices.d.ts.map +1 -0
  84. package/dist/voices.js +74 -0
  85. package/dist/voices.js.map +1 -0
  86. package/icon.svg +6 -0
  87. package/locale/en.json +6 -0
  88. package/locale/zh.json +6 -0
  89. package/package.json +93 -3
@@ -0,0 +1,408 @@
1
+ /**
2
+ * Same-origin HTTP route for generated audio.
3
+ *
4
+ * The DSH Web host owns the HTTP server; this module only registers a prefix
5
+ * route on the host `webServer` service (never listens on its own port). URLs
6
+ * carry an HMAC-signed, expiring token that names a file *relative to the
7
+ * configured output directory*, so a token can never be turned into an
8
+ * arbitrary path read. Range requests are answered with `206 Partial Content`,
9
+ * which is what lets an `<audio>` element seek inside a long file.
10
+ */
11
+ import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
12
+ import { chmodSync, createReadStream, mkdirSync, readFileSync, writeFileSync, } from 'node:fs';
13
+ import { stat } from 'node:fs/promises';
14
+ import { dirname, extname, isAbsolute, join, relative, resolve } from 'node:path';
15
+ /** Path prefix owned by this plugin. The signed token is the next segment. */
16
+ export const AUDIO_ROUTE_PREFIX = '/dsh-tts/audio';
17
+ /** Signed URLs stay valid for six hours by default. */
18
+ export const DEFAULT_URL_TTL_MS = 6 * 60 * 60 * 1000;
19
+ /** Name of the persisted HMAC secret inside the output directory. */
20
+ export const SECRET_FILE_NAME = '.audio-route-secret';
21
+ /** Longest suffix accepted by {@link parseRange}; keeps the parser simple. */
22
+ const RANGE_PATTERN = /^bytes=(\d*)-(\d*)$/;
23
+ function parseRange(header, size) {
24
+ const match = RANGE_PATTERN.exec(header.trim());
25
+ if (!match)
26
+ return undefined;
27
+ const startRaw = match[1] ?? '';
28
+ const endRaw = match[2] ?? '';
29
+ if (startRaw === '' && endRaw === '')
30
+ return undefined;
31
+ if (startRaw === '') {
32
+ const suffix = Number(endRaw);
33
+ if (!Number.isInteger(suffix) || suffix <= 0)
34
+ return undefined;
35
+ const start = Math.max(0, size - suffix);
36
+ return { start, end: size - 1 };
37
+ }
38
+ const start = Number(startRaw);
39
+ if (!Number.isInteger(start) || start < 0 || start >= size)
40
+ return undefined;
41
+ const end = endRaw === '' ? size - 1 : Number(endRaw);
42
+ if (!Number.isInteger(end) || end < start)
43
+ return undefined;
44
+ return { start, end: Math.min(end, size - 1) };
45
+ }
46
+ function sendText(res, status, message, headers = {}) {
47
+ const body = Buffer.from(message, 'utf8');
48
+ res.statusCode = status;
49
+ res.setHeader('Content-Type', 'text/plain; charset=utf-8');
50
+ res.setHeader('Content-Length', String(body.length));
51
+ for (const [name, value] of Object.entries(headers)) {
52
+ res.setHeader(name, value);
53
+ }
54
+ res.end(body);
55
+ }
56
+ function headerValue(value) {
57
+ return Array.isArray(value) ? value[0] : value;
58
+ }
59
+ /**
60
+ * Hostnames trusted by default for a bind address. Wildcard binds accept any
61
+ * hostname (the port and same-origin checks still apply), because the public
62
+ * hostname is not knowable from `0.0.0.0`.
63
+ */
64
+ function defaultAllowedHosts(host) {
65
+ const normalized = host.replace(/^\[|\]$/g, '').toLowerCase();
66
+ if (normalized === '0.0.0.0' || normalized === '::' || normalized === '*') {
67
+ return [];
68
+ }
69
+ return [...new Set(['localhost', '127.0.0.1', '::1', normalized])];
70
+ }
71
+ function isLoopbackHost(host) {
72
+ if (host === undefined)
73
+ return true;
74
+ const normalized = host.replace(/^\[|\]$/g, '').toLowerCase();
75
+ return (normalized === '' ||
76
+ normalized === 'localhost' ||
77
+ normalized === '::1' ||
78
+ normalized.startsWith('127.'));
79
+ }
80
+ function describe(error) {
81
+ return error instanceof Error ? error.message : String(error);
82
+ }
83
+ /**
84
+ * Load the persisted HMAC secret, creating it on first use. Persistence keeps
85
+ * previously issued URLs valid across plugin reloads. Any filesystem failure
86
+ * degrades to an in-memory secret instead of failing plugin load.
87
+ */
88
+ function loadOrCreateSecret(path, debug) {
89
+ try {
90
+ const hex = readFileSync(path, 'utf8').trim();
91
+ if (/^[0-9a-f]{64}$/i.test(hex))
92
+ return Buffer.from(hex, 'hex');
93
+ debug?.('audio route secret was malformed; rotating');
94
+ }
95
+ catch (error) {
96
+ const code = typeof error === 'object' && error !== null && 'code' in error
97
+ ? error.code
98
+ : undefined;
99
+ if (code !== 'ENOENT') {
100
+ debug?.(`audio route secret read failed: ${describe(error)}`);
101
+ }
102
+ }
103
+ const secret = randomBytes(32);
104
+ try {
105
+ mkdirSync(dirname(path), { recursive: true });
106
+ writeFileSync(path, secret.toString('hex'), { encoding: 'utf8', mode: 0o600 });
107
+ try {
108
+ chmodSync(path, 0o600);
109
+ }
110
+ catch {
111
+ // Windows does not implement POSIX modes; best effort only.
112
+ }
113
+ }
114
+ catch (error) {
115
+ debug?.(`audio route secret persistence failed: ${describe(error)}`);
116
+ }
117
+ return secret;
118
+ }
119
+ /**
120
+ * Owns the signed-token format and the HTTP handler. One instance per plugin
121
+ * load; `register` binds it to the host router and returns a disposer.
122
+ */
123
+ export class AudioRoute {
124
+ root;
125
+ prefix;
126
+ ttlMs;
127
+ secret;
128
+ now;
129
+ debug;
130
+ trustedHosts;
131
+ connection;
132
+ allowedHosts;
133
+ expectedPort;
134
+ skipPortCheck = false;
135
+ active = false;
136
+ origin;
137
+ constructor(options) {
138
+ this.root = resolve(options.outputDir);
139
+ this.prefix = options.prefix ?? AUDIO_ROUTE_PREFIX;
140
+ this.ttlMs = options.ttlMs ?? DEFAULT_URL_TTL_MS;
141
+ this.now = options.now ?? Date.now;
142
+ this.debug = options.debug;
143
+ this.connection = options.connection;
144
+ this.trustedHosts = (options.trustedHosts ?? [])
145
+ .map((host) => host.trim().toLowerCase())
146
+ .filter((host) => host.length > 0);
147
+ this.allowedHosts = options.allowedHosts;
148
+ this.expectedPort = options.expectedPort;
149
+ this.secret =
150
+ options.secret ??
151
+ loadOrCreateSecret(options.secretPath ?? join(this.root, SECRET_FILE_NAME), this.debug);
152
+ }
153
+ /** True once the host router accepted the route. */
154
+ get registered() {
155
+ return this.active;
156
+ }
157
+ /** Register on the DSH host router; the disposer unregisters and disables URLs. */
158
+ register(server) {
159
+ const remote = this.connection?.allowsRemoteAuthorities === true;
160
+ if (this.trustedHosts.length > 0) {
161
+ // A configured whitelist implies a proxy that may rewrite the port.
162
+ this.allowedHosts = this.trustedHosts;
163
+ this.skipPortCheck = true;
164
+ }
165
+ else if (remote && !isLoopbackHost(server.host)) {
166
+ this.allowedHosts = [];
167
+ this.skipPortCheck = true;
168
+ this.debug?.('audio route relaxed Host checks for remote authorities');
169
+ }
170
+ else if (this.expectedPort === undefined) {
171
+ this.expectedPort = server.port;
172
+ if (this.allowedHosts === undefined && server.host) {
173
+ this.allowedHosts = defaultAllowedHosts(server.host);
174
+ }
175
+ }
176
+ const dispose = server.register({
177
+ kind: 'prefix',
178
+ path: this.prefix,
179
+ handler: (req, res) => this.handle(req, res),
180
+ });
181
+ this.active = true;
182
+ let disposed = false;
183
+ return () => {
184
+ if (disposed)
185
+ return;
186
+ disposed = true;
187
+ this.active = false;
188
+ dispose();
189
+ };
190
+ }
191
+ /**
192
+ * Browser-openable same-origin URL, or `undefined` when the route is not
193
+ * registered or the file is outside the output directory / not an MP3.
194
+ */
195
+ urlFor(filePath) {
196
+ if (!this.active)
197
+ return undefined;
198
+ const relativePath = this.relativePath(filePath);
199
+ if (relativePath === undefined)
200
+ return undefined;
201
+ const expires = Math.ceil((this.now() + this.ttlMs) / 1000);
202
+ const encoded = Buffer.from(relativePath, 'utf8').toString('base64url');
203
+ const payload = `${expires}.${encoded}`;
204
+ return `${this.prefix}/${payload}.${this.sign(payload)}`;
205
+ }
206
+ /** Remember the host-advertised origin, trimmed of any trailing slash. */
207
+ setOrigin(origin) {
208
+ const trimmed = origin.trim().replace(/\/+$/, '');
209
+ if (trimmed.length > 0)
210
+ this.origin = trimmed;
211
+ }
212
+ /**
213
+ * Absolute playback URL for humans, or `undefined` when the host did not
214
+ * advertise an origin. Never guesses a host: callers fall back to the
215
+ * relative {@link urlFor} result instead.
216
+ */
217
+ absoluteUrlFor(filePath) {
218
+ const relative = this.urlFor(filePath);
219
+ if (relative === undefined || this.origin === undefined)
220
+ return undefined;
221
+ return `${this.origin}${relative}`;
222
+ }
223
+ /** Serve one request. Exported behaviour is exercised directly by tests. */
224
+ async handle(req, res) {
225
+ const method = req.method ?? 'GET';
226
+ if (method !== 'GET' && method !== 'HEAD') {
227
+ sendText(res, 405, 'Method Not Allowed', { Allow: 'GET, HEAD' });
228
+ return;
229
+ }
230
+ const rejection = this.connection?.requestRejection?.({
231
+ headers: req.headers,
232
+ });
233
+ if (rejection === 401 || rejection === 403) {
234
+ this.debug?.(`audio route rejected by host connection: ${rejection}`);
235
+ sendText(res, rejection, rejection === 401 ? 'Unauthorized' : 'Forbidden');
236
+ return;
237
+ }
238
+ const originRejection = this.checkOrigin(req);
239
+ if (originRejection !== undefined) {
240
+ this.debug?.(`audio route rejected: ${originRejection}`);
241
+ sendText(res, 403, 'Forbidden');
242
+ return;
243
+ }
244
+ const rawUrl = req.url ?? '';
245
+ const query = rawUrl.indexOf('?');
246
+ const pathname = query === -1 ? rawUrl : rawUrl.slice(0, query);
247
+ if (!pathname.startsWith(`${this.prefix}/`)) {
248
+ sendText(res, 404, 'Not Found');
249
+ return;
250
+ }
251
+ let token;
252
+ try {
253
+ token = decodeURIComponent(pathname.slice(this.prefix.length + 1));
254
+ }
255
+ catch {
256
+ sendText(res, 404, 'Not Found');
257
+ return;
258
+ }
259
+ const target = this.verify(token);
260
+ if (target === undefined) {
261
+ sendText(res, 404, 'Not Found');
262
+ return;
263
+ }
264
+ let size;
265
+ try {
266
+ const info = await stat(target);
267
+ if (!info.isFile() || info.size <= 0) {
268
+ sendText(res, 404, 'Not Found');
269
+ return;
270
+ }
271
+ size = info.size;
272
+ }
273
+ catch {
274
+ sendText(res, 404, 'Not Found');
275
+ return;
276
+ }
277
+ const header = req.headers.range;
278
+ const rangeHeader = Array.isArray(header) ? header[0] : header;
279
+ let range;
280
+ if (rangeHeader !== undefined) {
281
+ range = parseRange(rangeHeader, size);
282
+ if (range === undefined) {
283
+ sendText(res, 416, 'Range Not Satisfiable', {
284
+ 'Content-Range': `bytes */${size}`,
285
+ });
286
+ return;
287
+ }
288
+ }
289
+ res.setHeader('Content-Type', 'audio/mpeg');
290
+ res.setHeader('Accept-Ranges', 'bytes');
291
+ res.setHeader('Cache-Control', 'private, max-age=300');
292
+ if (range === undefined) {
293
+ res.statusCode = 200;
294
+ res.setHeader('Content-Length', String(size));
295
+ }
296
+ else {
297
+ res.statusCode = 206;
298
+ res.setHeader('Content-Range', `bytes ${range.start}-${range.end}/${size}`);
299
+ res.setHeader('Content-Length', String(range.end - range.start + 1));
300
+ }
301
+ if (method === 'HEAD') {
302
+ res.end();
303
+ return;
304
+ }
305
+ const stream = createReadStream(target, range);
306
+ stream.on('error', () => {
307
+ res.destroy();
308
+ });
309
+ stream.pipe(res);
310
+ }
311
+ /** HMAC-SHA-256 over the payload, base64url-encoded. */
312
+ sign(payload) {
313
+ return createHmac('sha256', this.secret).update(payload, 'utf8').digest('base64url');
314
+ }
315
+ /**
316
+ * Same-origin fence in front of the token check. Returns a reason when the
317
+ * request must be rejected. Missing headers are tolerated only when neither
318
+ * a port nor an Origin pins the request to a browser origin, which keeps
319
+ * non-browser callers working while DSH provides no trust-fence API.
320
+ */
321
+ checkOrigin(req) {
322
+ const host = headerValue(req.headers.host);
323
+ const origin = headerValue(req.headers.origin);
324
+ if (host === undefined) {
325
+ return origin === undefined ? undefined : 'origin present without host';
326
+ }
327
+ let parsed;
328
+ try {
329
+ parsed = new URL(`http://${host}`);
330
+ }
331
+ catch {
332
+ return 'malformed host header';
333
+ }
334
+ const hostname = parsed.hostname.replace(/^\[|\]$/g, '').toLowerCase();
335
+ if (this.allowedHosts !== undefined &&
336
+ this.allowedHosts.length > 0 &&
337
+ !this.allowedHosts.includes(hostname)) {
338
+ return `untrusted host ${hostname}`;
339
+ }
340
+ if (this.expectedPort !== undefined && !this.skipPortCheck) {
341
+ const port = parsed.port === ''
342
+ ? parsed.protocol === 'https:'
343
+ ? 443
344
+ : 80
345
+ : Number(parsed.port);
346
+ if (port !== this.expectedPort) {
347
+ return `host port ${port} does not match ${this.expectedPort}`;
348
+ }
349
+ }
350
+ if (origin !== undefined) {
351
+ let parsedOrigin;
352
+ try {
353
+ parsedOrigin = new URL(origin);
354
+ }
355
+ catch {
356
+ return 'malformed origin header';
357
+ }
358
+ if (parsedOrigin.protocol !== 'http:' &&
359
+ parsedOrigin.protocol !== 'https:') {
360
+ return `unsupported origin scheme ${parsedOrigin.protocol}`;
361
+ }
362
+ if (parsedOrigin.host.toLowerCase() !== host.toLowerCase()) {
363
+ return 'origin and host differ';
364
+ }
365
+ }
366
+ return undefined;
367
+ }
368
+ /** Path relative to the ledger root, using `/` on every platform. */
369
+ relativePath(filePath) {
370
+ if (extname(filePath).toLowerCase() !== '.mp3')
371
+ return undefined;
372
+ const target = resolve(filePath);
373
+ const rel = relative(this.root, target);
374
+ if (rel === '' || rel.startsWith('..') || isAbsolute(rel))
375
+ return undefined;
376
+ return rel.split('\\').join('/');
377
+ }
378
+ /** Verify signature + expiry, then confine the decoded path to the root. */
379
+ verify(token) {
380
+ const segments = token.split('.');
381
+ if (segments.length !== 3)
382
+ return undefined;
383
+ const expiresRaw = segments[0] ?? '';
384
+ const encoded = segments[1] ?? '';
385
+ const signature = segments[2] ?? '';
386
+ if (!expiresRaw || !encoded || !signature)
387
+ return undefined;
388
+ const expected = Buffer.from(this.sign(`${expiresRaw}.${encoded}`), 'utf8');
389
+ const actual = Buffer.from(signature, 'utf8');
390
+ if (expected.length !== actual.length || !timingSafeEqual(expected, actual)) {
391
+ return undefined;
392
+ }
393
+ const expires = Number(expiresRaw);
394
+ if (!Number.isFinite(expires) || this.now() > expires * 1000)
395
+ return undefined;
396
+ const rel = Buffer.from(encoded, 'base64url').toString('utf8');
397
+ if (rel.length === 0 || rel.includes('\u0000'))
398
+ return undefined;
399
+ const target = resolve(this.root, rel);
400
+ const check = relative(this.root, target);
401
+ if (check === '' || check.startsWith('..') || isAbsolute(check))
402
+ return undefined;
403
+ if (extname(target).toLowerCase() !== '.mp3')
404
+ return undefined;
405
+ return target;
406
+ }
407
+ }
408
+ //# sourceMappingURL=audio-route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-route.js","sourceRoot":"","sources":["../src/audio-route.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /** Audio container Edge-TTS writes. */
2
+ export declare const AUDIO_FORMAT = "mp3";
3
+ /**
4
+ * Stable cache key for one synthesis request. The first 16 hex characters of
5
+ * SHA-256 are enough to name a file while keeping names short.
6
+ */
7
+ export declare function cacheKey(text: string, voice: string, rate: string): string;
8
+ /** Local-calendar `YYYY-MM-DD` bucket for a timestamp. */
9
+ export declare function dateDirName(date?: Date): string;
10
+ /**
11
+ * Target path for a fresh synthesis: `<outputDir>/<date>/<hash>-<epochMs>.mp3`.
12
+ * The timestamp keeps concurrent first-time syntheses from colliding.
13
+ */
14
+ export declare function outputFilePath(outputDir: string, hash: string, date?: Date): string;
15
+ /**
16
+ * Diagnostic record stored next to a finished MP3. It never participates in
17
+ * cache lookup; it only lets a later cache hit report which engine produced
18
+ * the file (for example `sapi` after a fallback).
19
+ */
20
+ export interface CacheMetadata {
21
+ engine: string;
22
+ voice: string;
23
+ rate: string;
24
+ pitch: string;
25
+ volume: string;
26
+ createdAt: string;
27
+ /**
28
+ * Word timings the backend reported. Persisted so a later cache hit keeps
29
+ * exact subtitle timing instead of silently degrading to an estimate.
30
+ */
31
+ words?: {
32
+ text: string;
33
+ offsetMs: number;
34
+ durationMs: number;
35
+ }[];
36
+ }
37
+ /** Sidecar path for one audio file. */
38
+ export declare function metadataPath(filePath: string): string;
39
+ /** Best-effort metadata write; diagnostics must never fail synthesis. */
40
+ export declare function writeCacheMetadata(filePath: string, metadata: CacheMetadata): Promise<void>;
41
+ /** Read a sidecar, treating missing, unreadable, or malformed data as absent. */
42
+ export declare function readCacheMetadata(filePath: string): Promise<CacheMetadata | undefined>;
43
+ /**
44
+ * Find an existing non-empty file for `hash`, newest date bucket first. Only
45
+ * files carrying the exact key prefix and a positive size qualify, so a
46
+ * partial or unrelated file never satisfies the cache. The `.mp3.json`
47
+ * sidecars and the `.audio-route-secret` file never match this filter.
48
+ */
49
+ export declare function findCachedFile(outputDir: string, hash: string): Promise<string | undefined>;
50
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAOA,uCAAuC;AACvC,eAAO,MAAM,YAAY,QAAQ,CAAA;AAEjC;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAK1E;AAED,0DAA0D;AAC1D,wBAAgB,WAAW,CAAC,IAAI,GAAE,IAAiB,GAAG,MAAM,CAK3D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,IAAiB,GACtB,MAAM,CAER;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CACjE;AAED,uCAAuC;AACvC,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,yEAAyE;AACzE,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,IAAI,CAAC,CAMf;AAED,iFAAiF;AACjF,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAapC;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAmC7B"}
package/dist/cache.js ADDED
@@ -0,0 +1,105 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readdir, readFile, stat, writeFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ /** Directory names this module owns: `YYYY-MM-DD`. */
5
+ const DATE_DIRECTORY = /^\d{4}-\d{2}-\d{2}$/;
6
+ /** Audio container Edge-TTS writes. */
7
+ export const AUDIO_FORMAT = 'mp3';
8
+ /**
9
+ * Stable cache key for one synthesis request. The first 16 hex characters of
10
+ * SHA-256 are enough to name a file while keeping names short.
11
+ */
12
+ export function cacheKey(text, voice, rate) {
13
+ return createHash('sha256')
14
+ .update(`${text}\u0000${voice}\u0000${rate}`, 'utf8')
15
+ .digest('hex')
16
+ .slice(0, 16);
17
+ }
18
+ /** Local-calendar `YYYY-MM-DD` bucket for a timestamp. */
19
+ export function dateDirName(date = new Date()) {
20
+ const year = String(date.getFullYear()).padStart(4, '0');
21
+ const month = String(date.getMonth() + 1).padStart(2, '0');
22
+ const day = String(date.getDate()).padStart(2, '0');
23
+ return `${year}-${month}-${day}`;
24
+ }
25
+ /**
26
+ * Target path for a fresh synthesis: `<outputDir>/<date>/<hash>-<epochMs>.mp3`.
27
+ * The timestamp keeps concurrent first-time syntheses from colliding.
28
+ */
29
+ export function outputFilePath(outputDir, hash, date = new Date()) {
30
+ return join(outputDir, dateDirName(date), `${hash}-${date.getTime()}.${AUDIO_FORMAT}`);
31
+ }
32
+ /** Sidecar path for one audio file. */
33
+ export function metadataPath(filePath) {
34
+ return `${filePath}.json`;
35
+ }
36
+ /** Best-effort metadata write; diagnostics must never fail synthesis. */
37
+ export async function writeCacheMetadata(filePath, metadata) {
38
+ try {
39
+ await writeFile(metadataPath(filePath), JSON.stringify(metadata), 'utf8');
40
+ }
41
+ catch {
42
+ // The audio file is already valid; a missing sidecar only loses engine info.
43
+ }
44
+ }
45
+ /** Read a sidecar, treating missing, unreadable, or malformed data as absent. */
46
+ export async function readCacheMetadata(filePath) {
47
+ try {
48
+ const parsed = JSON.parse(await readFile(metadataPath(filePath), 'utf8'));
49
+ if (typeof parsed !== 'object' || parsed === null)
50
+ return undefined;
51
+ if (typeof parsed.engine !== 'string' || parsed.engine.length === 0) {
52
+ return undefined;
53
+ }
54
+ return parsed;
55
+ }
56
+ catch {
57
+ return undefined;
58
+ }
59
+ }
60
+ /**
61
+ * Find an existing non-empty file for `hash`, newest date bucket first. Only
62
+ * files carrying the exact key prefix and a positive size qualify, so a
63
+ * partial or unrelated file never satisfies the cache. The `.mp3.json`
64
+ * sidecars and the `.audio-route-secret` file never match this filter.
65
+ */
66
+ export async function findCachedFile(outputDir, hash) {
67
+ let entries;
68
+ try {
69
+ entries = await readdir(outputDir, { withFileTypes: true });
70
+ }
71
+ catch {
72
+ return undefined;
73
+ }
74
+ const dateDirs = entries
75
+ .filter((entry) => entry.isDirectory() && DATE_DIRECTORY.test(entry.name))
76
+ .map((entry) => entry.name)
77
+ .sort()
78
+ .reverse();
79
+ const prefix = `${hash}-`;
80
+ for (const dirName of dateDirs) {
81
+ const dir = join(outputDir, dirName);
82
+ let names;
83
+ try {
84
+ names = await readdir(dir);
85
+ }
86
+ catch {
87
+ continue;
88
+ }
89
+ for (const name of names) {
90
+ if (!name.startsWith(prefix) || !name.endsWith(`.${AUDIO_FORMAT}`))
91
+ continue;
92
+ const filePath = join(dir, name);
93
+ try {
94
+ const info = await stat(filePath);
95
+ if (info.isFile() && info.size > 0)
96
+ return filePath;
97
+ }
98
+ catch {
99
+ // Raced with a cleanup; try the next candidate.
100
+ }
101
+ }
102
+ }
103
+ return undefined;
104
+ }
105
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { type SpawnFunction, type SynthesizedAudio } from './edge-tts.ts';
2
+ /** Pause between chunk subprocesses so Edge-TTS is not rate-limited. */
3
+ export declare const DEFAULT_INTER_CHUNK_DELAY_MS = 200;
4
+ export interface ChunkedSynthesisOptions {
5
+ voice: string;
6
+ rate: string;
7
+ /** Applied uniformly to every chunk. */
8
+ pitch?: string;
9
+ /** Applied uniformly to every chunk. */
10
+ volume?: string;
11
+ /** Forwarded to every chunk subprocess as `--proxy`. */
12
+ proxy?: string;
13
+ binary: string;
14
+ outputDir: string;
15
+ /** Cache key of the full original text. */
16
+ hash: string;
17
+ timeoutMs: number;
18
+ /** Whole-call budget across every chunk and inter-chunk delay. */
19
+ totalTimeoutMs?: number;
20
+ chunkSize: number;
21
+ signal?: AbortSignal;
22
+ spawnImpl?: SpawnFunction;
23
+ now?: Date;
24
+ /** Injectable sleep, used by tests to avoid real delays. */
25
+ delay?: (ms: number) => Promise<void>;
26
+ interChunkDelayMs?: number;
27
+ }
28
+ /**
29
+ * Synthesize `text` chunk by chunk and return one concatenated MP3. Callers
30
+ * only use this above the chunk threshold; calling it with one chunk simply
31
+ * delegates to the one-shot path.
32
+ */
33
+ export declare function synthesizeChunked(text: string, options: ChunkedSynthesisOptions): Promise<SynthesizedAudio>;
34
+ //# sourceMappingURL=chunked-tts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunked-tts.d.ts","sourceRoot":"","sources":["../src/chunked-tts.ts"],"names":[],"mappings":"AAeA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAA;AAGtB,wEAAwE;AACxE,eAAO,MAAM,4BAA4B,MAAM,CAAA;AAE/C,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,wCAAwC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,SAAS,CAAC,EAAE,aAAa,CAAA;IACzB,GAAG,CAAC,EAAE,IAAI,CAAA;IACV,4DAA4D;IAC5D,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AA8CD;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CAqF3B"}