@speechweave/node 1.0.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.
package/dist/index.cjs ADDED
@@ -0,0 +1,878 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ SpeechWeave: () => SpeechWeave,
34
+ SpeechWeaveClient: () => SpeechWeaveClient,
35
+ SpeechWeaveError: () => SpeechWeaveError,
36
+ VERSION: () => VERSION,
37
+ createJobFromUrl: () => createJobFromUrl,
38
+ finishCompatJob: () => finishCompatJob,
39
+ shapeAssemblyResponse: () => shapeAssemblyResponse,
40
+ shapeDeepgramResponse: () => shapeDeepgramResponse,
41
+ shapeOpenAiResponse: () => shapeOpenAiResponse,
42
+ uploadAndCreateJob: () => uploadAndCreateJob,
43
+ verifyWebhook: () => verifyWebhook,
44
+ waitForJob: () => waitForJob
45
+ });
46
+ module.exports = __toCommonJS(index_exports);
47
+
48
+ // src/client.ts
49
+ var import_node_fs = require("fs");
50
+ var import_promises = require("fs/promises");
51
+
52
+ // src/errors.ts
53
+ var SpeechWeaveError = class extends Error {
54
+ status;
55
+ code;
56
+ body;
57
+ retry_after;
58
+ constructor(message, status = 500, code, body, retry_after) {
59
+ super(message);
60
+ this.name = "SpeechWeaveError";
61
+ this.status = status;
62
+ this.code = code;
63
+ this.body = body;
64
+ this.retry_after = retry_after;
65
+ }
66
+ };
67
+
68
+ // src/polling.ts
69
+ var TERMINAL = /* @__PURE__ */ new Set([
70
+ "completed",
71
+ "failed",
72
+ "cancelled"
73
+ ]);
74
+ async function waitForJob(client, job_id, opts = {}) {
75
+ const timeout_ms = opts.timeout_ms ?? 36e5;
76
+ const poll_ms = opts.poll_ms ?? 2e3;
77
+ const deadline = Date.now() + timeout_ms;
78
+ while (Date.now() < deadline) {
79
+ const job = await client.getJob(job_id);
80
+ if (TERMINAL.has(String(job.status))) {
81
+ return job;
82
+ }
83
+ await new Promise((r) => setTimeout(r, poll_ms));
84
+ }
85
+ throw new SpeechWeaveError(
86
+ "Timed out waiting for job",
87
+ 504,
88
+ "JOB_WAIT_TIMEOUT",
89
+ { job_id }
90
+ );
91
+ }
92
+
93
+ // src/version.ts
94
+ var VERSION = "1.0.0";
95
+
96
+ // src/client.ts
97
+ function normalizeBaseURL(url) {
98
+ const s = String(url || "").trim().replace(/\/+$/, "");
99
+ return s || "https://api.speechweave.com/v1";
100
+ }
101
+ async function readErrorMessage(response) {
102
+ const content_type = response.headers.get("content-type") || "";
103
+ try {
104
+ if (content_type.includes("application/json")) {
105
+ const json = await response.json();
106
+ return String(json?.error || json?.message || response.statusText);
107
+ }
108
+ const text = await response.text();
109
+ return text.slice(0, 500) || response.statusText;
110
+ } catch {
111
+ return response.statusText;
112
+ }
113
+ }
114
+ async function getBodyLength(body, file_size) {
115
+ if (file_size != null && Number.isFinite(file_size) && file_size >= 0) {
116
+ return file_size;
117
+ }
118
+ if (Buffer.isBuffer(body)) {
119
+ return body.byteLength;
120
+ }
121
+ if (body instanceof Blob) {
122
+ return body.size;
123
+ }
124
+ const path_like = body.path;
125
+ if (typeof path_like === "string" || Buffer.isBuffer(path_like) || path_like instanceof URL) {
126
+ try {
127
+ return (await (0, import_promises.stat)(path_like)).size;
128
+ } catch {
129
+ return void 0;
130
+ }
131
+ }
132
+ return void 0;
133
+ }
134
+ var SpeechWeaveClient = class {
135
+ api_key;
136
+ base_url;
137
+ fetch_func;
138
+ /**
139
+ * @param options.api_key - Falls back to SPEECHWEAVE_API_KEY. Throws if neither is set.
140
+ * @param options.base_url - Defaults to https://api.speechweave.com/v1.
141
+ */
142
+ constructor(options = {}) {
143
+ this.api_key = options.api_key || typeof process !== "undefined" && process.env?.SPEECHWEAVE_API_KEY || "";
144
+ this.base_url = normalizeBaseURL(
145
+ options.base_url || "https://api.speechweave.com/v1"
146
+ );
147
+ this.fetch_func = options.fetch_func || fetch;
148
+ if (!this.api_key) {
149
+ throw new Error("SpeechWeave API key is required (api_key, or SPEECHWEAVE_API_KEY)");
150
+ }
151
+ }
152
+ /**
153
+ * Authenticated fetch against base_url.
154
+ * Adds Bearer and User-Agent when missing. Path is relative (leading `/` optional).
155
+ */
156
+ async rawFetch(path, init = {}) {
157
+ const formatted_path = path.startsWith("/") ? path : `/${path}`;
158
+ const url = `${this.base_url}${formatted_path}`;
159
+ const h = new Headers(init.headers);
160
+ if (!h.has("Authorization")) {
161
+ h.set("Authorization", `Bearer ${this.api_key}`);
162
+ }
163
+ if (!h.has("User-Agent")) {
164
+ h.set("User-Agent", `speechweave-node/${VERSION}`);
165
+ }
166
+ return this.fetch_func(url, {
167
+ ...init,
168
+ headers: h
169
+ });
170
+ }
171
+ async requestJson(method, path, json, params) {
172
+ let request_path = path;
173
+ if (params) {
174
+ const search = new URLSearchParams();
175
+ for (const [
176
+ key,
177
+ value
178
+ ] of Object.entries(params)) {
179
+ if (value === void 0 || value === null) {
180
+ continue;
181
+ }
182
+ search.set(key, String(value));
183
+ }
184
+ const qs = search.toString();
185
+ if (qs) {
186
+ request_path = `${path}${path.includes("?") ? "&" : "?"}${qs}`;
187
+ }
188
+ }
189
+ const headers = { Accept: "application/json" };
190
+ let body;
191
+ if (json !== void 0) {
192
+ headers["Content-Type"] = "application/json";
193
+ body = JSON.stringify(json);
194
+ }
195
+ const response = await this.rawFetch(request_path, {
196
+ method,
197
+ headers,
198
+ body
199
+ });
200
+ if (!response.ok) {
201
+ const ct = response.headers.get("content-type") || "";
202
+ let err_body;
203
+ let message;
204
+ let code = String(response.status);
205
+ let retry_after;
206
+ const header_retry = response.headers.get("Retry-After");
207
+ if (header_retry) {
208
+ const n = parseInt(header_retry, 10);
209
+ if (Number.isFinite(n)) {
210
+ retry_after = n;
211
+ }
212
+ }
213
+ try {
214
+ if (ct.includes("application/json")) {
215
+ err_body = await response.json();
216
+ const j = err_body;
217
+ message = String(j?.error || j?.message || response.statusText);
218
+ if (j?.code) {
219
+ code = j.code;
220
+ }
221
+ if (typeof j?.retry_after === "number") {
222
+ retry_after = j.retry_after;
223
+ }
224
+ } else {
225
+ const t = await response.text();
226
+ message = t.slice(0, 500) || response.statusText;
227
+ }
228
+ } catch {
229
+ message = response.statusText;
230
+ }
231
+ throw new SpeechWeaveError(
232
+ message,
233
+ response.status,
234
+ code,
235
+ err_body,
236
+ retry_after
237
+ );
238
+ }
239
+ return await response.json();
240
+ }
241
+ /**
242
+ * Request a short-lived PUT URL and object_key for direct upload to storage.
243
+ *
244
+ * @param params.filename - Original name (used in the storage key).
245
+ * @param params.content_type - MIME type that must match the subsequent PUT.
246
+ */
247
+ async presignUpload(params) {
248
+ return this.requestJson(
249
+ "POST",
250
+ "/uploads",
251
+ {
252
+ filename: params.filename,
253
+ content_type: params.content_type
254
+ }
255
+ );
256
+ }
257
+ /**
258
+ * PUT audio bytes to a presigned upload_url.
259
+ * Sets Content-Length when the body can be measured; pass file_size for pipes/live streams.
260
+ *
261
+ * @param uploadUrl - upload_url from presignUpload.
262
+ */
263
+ async putToPresignedUrl(uploadUrl, body, contentType, options = {}) {
264
+ const headers = new Headers({ "Content-Type": contentType });
265
+ const content_length = await getBodyLength(body, options.file_size);
266
+ if (content_length != null) {
267
+ headers.set("Content-Length", String(content_length));
268
+ }
269
+ const init = {
270
+ method: "PUT",
271
+ headers,
272
+ body
273
+ };
274
+ const is_node_stream = body && typeof body.pipe === "function";
275
+ if (is_node_stream) {
276
+ init.duplex = "half";
277
+ }
278
+ const response = await this.fetch_func(uploadUrl, init);
279
+ if (!response.ok) {
280
+ const message = await readErrorMessage(response);
281
+ throw new SpeechWeaveError(
282
+ `R2 upload failed: ${message}`,
283
+ response.status,
284
+ "UPLOAD_FAILED"
285
+ );
286
+ }
287
+ }
288
+ /**
289
+ * Presign → PUT → create job. Returns the create ack (no transcript); poll getJob or waitForJob.
290
+ * Omitting service_mode leaves the API default (deferred). Synchronous rejects files over the sync size cap (default 512 MiB).
291
+ *
292
+ * @param options.filename - Defaults to audio.bin.
293
+ * @param options.content_type - Defaults to application/octet-stream.
294
+ * @param options.language - Two-letter ISO code (e.g. 'en', 'es').
295
+ * @param options.file_size - Content-Length when the body cannot be measured (pipes, live streams).
296
+ */
297
+ async transcribeFile(file, options = {}) {
298
+ const filename = options.filename || "audio.bin";
299
+ const content_type = options.content_type || "application/octet-stream";
300
+ const presign = await this.presignUpload({
301
+ filename,
302
+ content_type
303
+ });
304
+ const put_opts = { file_size: options.file_size };
305
+ if (Buffer.isBuffer(file) || file instanceof Blob) {
306
+ await this.putToPresignedUrl(presign.upload_url, file, content_type, put_opts);
307
+ } else {
308
+ await this.putToPresignedUrl(
309
+ presign.upload_url,
310
+ file,
311
+ content_type,
312
+ put_opts
313
+ );
314
+ }
315
+ return this.createJob({
316
+ object_key: presign.object_key,
317
+ model: options.model,
318
+ service_mode: options.service_mode,
319
+ language: options.language,
320
+ metadata: options.metadata
321
+ });
322
+ }
323
+ /**
324
+ * Same as {@link transcribeFile}, then poll until completed, failed, or cancelled.
325
+ *
326
+ * @param options.wait_timeout_ms - Defaults to SPEECHWEAVE_JOB_WAIT_MS or 300_000.
327
+ * @param options.poll_ms - Poll interval; defaults to 1500.
328
+ */
329
+ async transcribeFileBlocking(file, options = {}) {
330
+ const created = await this.transcribeFile(file, options);
331
+ return waitForJob(
332
+ this,
333
+ created.id,
334
+ {
335
+ timeout_ms: options.wait_timeout_ms ?? Number(process.env?.SPEECHWEAVE_JOB_WAIT_MS || 3e5),
336
+ poll_ms: options.poll_ms ?? 1500
337
+ }
338
+ );
339
+ }
340
+ /**
341
+ * Create a transcription job from an already-uploaded object or a remote URL.
342
+ * Provide exactly one of object_key, input_url, or audio_url. type defaults to transcription.
343
+ * Omitting service_mode leaves the API default (deferred).
344
+ *
345
+ * @param params.object_key - From PresignResponse after a successful PUT.
346
+ * @param params.input_url - Publicly reachable audio URL.
347
+ * @param params.audio_url - Alias for input_url.
348
+ * @param params.language - Two-letter ISO code (e.g. 'en', 'es').
349
+ */
350
+ async createJob(params) {
351
+ const payload = {
352
+ type: params.type || "transcription"
353
+ };
354
+ if (params.object_key != null) {
355
+ payload.object_key = params.object_key;
356
+ }
357
+ if (params.input_url != null) {
358
+ payload.input_url = params.input_url;
359
+ }
360
+ if (params.audio_url != null) {
361
+ payload.audio_url = params.audio_url;
362
+ }
363
+ if (params.model != null) {
364
+ payload.model = params.model;
365
+ }
366
+ if (params.service_mode != null) {
367
+ payload.service_mode = params.service_mode;
368
+ }
369
+ if (params.language != null) {
370
+ payload.language = params.language;
371
+ }
372
+ if (params.metadata != null) {
373
+ payload.metadata = params.metadata;
374
+ }
375
+ return this.requestJson("POST", "/jobs", payload);
376
+ }
377
+ /**
378
+ * Fetch the current job record (status, transcript when completed, error when failed).
379
+ *
380
+ * @param job_id - Id from createJob / transcribeFile.
381
+ */
382
+ async getJob(job_id) {
383
+ return this.requestJson(
384
+ "GET",
385
+ `/jobs/${encodeURIComponent(job_id)}`
386
+ );
387
+ }
388
+ /**
389
+ * List jobs for the authenticated account.
390
+ *
391
+ * @param params.status - Filter by PublicJobStatus value.
392
+ * @param params.page - 1-based page; API default if omitted.
393
+ * @param params.limit - Page size; API default if omitted.
394
+ */
395
+ async listJobs(params = {}) {
396
+ return this.requestJson(
397
+ "GET",
398
+ "/jobs",
399
+ void 0,
400
+ {
401
+ page: params.page,
402
+ limit: params.limit,
403
+ status: params.status
404
+ }
405
+ );
406
+ }
407
+ /**
408
+ * Cancel a pending or processing job.
409
+ * Fails if the job is already completed, failed, or cancelled.
410
+ *
411
+ * @param job_id - Id from createJob / transcribeFile.
412
+ */
413
+ async cancelJob(job_id) {
414
+ return this.requestJson(
415
+ "POST",
416
+ `/jobs/${encodeURIComponent(job_id)}/cancel`,
417
+ {}
418
+ );
419
+ }
420
+ /**
421
+ * Open a disk path and run {@link transcribeFile}.
422
+ * filename is taken from the path basename.
423
+ *
424
+ * @param file_path - Absolute or relative path on the local filesystem.
425
+ */
426
+ async transcribeFilePath(file_path, options = {}) {
427
+ const stream = (0, import_node_fs.createReadStream)(file_path);
428
+ const base = file_path.split(/[/\\]/).pop() || "audio.bin";
429
+ return this.transcribeFile(
430
+ stream,
431
+ {
432
+ filename: base,
433
+ content_type: options.content_type,
434
+ model: options.model,
435
+ service_mode: options.service_mode,
436
+ language: options.language,
437
+ metadata: options.metadata,
438
+ file_size: options.file_size
439
+ }
440
+ );
441
+ }
442
+ };
443
+
444
+ // src/compat_shapes.ts
445
+ function jobText(job) {
446
+ const text = job.transcript;
447
+ return typeof text === "string" ? text : "";
448
+ }
449
+ function jobDuration(job) {
450
+ const duration = job.duration;
451
+ if (duration == null) {
452
+ return void 0;
453
+ }
454
+ const value = Number(duration);
455
+ if (!Number.isFinite(value) || value < 0) {
456
+ return void 0;
457
+ }
458
+ return value;
459
+ }
460
+ function jobLanguage(job) {
461
+ const language = job.language;
462
+ if (language == null) {
463
+ return void 0;
464
+ }
465
+ const text = String(language).trim().toLowerCase();
466
+ return text || void 0;
467
+ }
468
+ function shapeOpenAiResponse(job) {
469
+ const response = {
470
+ text: jobText(job),
471
+ task: "transcribe"
472
+ };
473
+ const duration = jobDuration(job);
474
+ if (duration !== void 0) {
475
+ response.duration = duration;
476
+ }
477
+ const language = jobLanguage(job);
478
+ if (language !== void 0) {
479
+ response.language = language;
480
+ }
481
+ return response;
482
+ }
483
+ function shapeDeepgramResponse(job, options = {}) {
484
+ const job_id = String(job.id || "");
485
+ const model_name = options.model || String(job.model || "core");
486
+ const text = jobText(job);
487
+ const language = jobLanguage(job);
488
+ const alternative = {
489
+ transcript: text,
490
+ confidence: 1,
491
+ words: []
492
+ };
493
+ if (language !== void 0) {
494
+ alternative.language = language;
495
+ }
496
+ return {
497
+ metadata: {
498
+ request_id: job_id,
499
+ model_info: {
500
+ name: model_name,
501
+ version: "1",
502
+ arch: "speechweave"
503
+ }
504
+ },
505
+ results: {
506
+ channels: [
507
+ {
508
+ alternatives: [
509
+ alternative
510
+ ]
511
+ }
512
+ ]
513
+ }
514
+ };
515
+ }
516
+ function shapeAssemblyResponse(job) {
517
+ const status = String(job.status || "unknown");
518
+ const pub_status = status === "completed" ? "completed" : status;
519
+ const duration = jobDuration(job);
520
+ const language = jobLanguage(job);
521
+ const error = job.error;
522
+ const response = {
523
+ id: String(job.id || ""),
524
+ status: pub_status,
525
+ text: jobText(job)
526
+ };
527
+ if (duration !== void 0) {
528
+ response.audio_duration = duration;
529
+ }
530
+ if (language !== void 0) {
531
+ response.language = language;
532
+ }
533
+ if (error != null && pub_status === "failed") {
534
+ response.error = String(error);
535
+ } else {
536
+ response.error = null;
537
+ }
538
+ return response;
539
+ }
540
+ async function toUploadBody(data) {
541
+ if (data instanceof Blob) {
542
+ return {
543
+ body: data,
544
+ content_type: data.type || "application/octet-stream"
545
+ };
546
+ }
547
+ if (Buffer.isBuffer(data) || data instanceof Uint8Array) {
548
+ const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
549
+ return {
550
+ body: buf,
551
+ content_type: "application/octet-stream"
552
+ };
553
+ }
554
+ return {
555
+ body: data,
556
+ content_type: "application/octet-stream"
557
+ };
558
+ }
559
+ async function uploadAndCreateJob(client, params) {
560
+ const prepared = await toUploadBody(params.data);
561
+ const content_type = params.content_type || prepared.content_type;
562
+ const body = prepared.body;
563
+ const presign = await client.presignUpload({
564
+ filename: params.filename,
565
+ content_type
566
+ });
567
+ await client.putToPresignedUrl(
568
+ presign.upload_url,
569
+ body,
570
+ content_type,
571
+ { file_size: params.file_size }
572
+ );
573
+ return client.createJob({
574
+ object_key: presign.object_key,
575
+ model: params.model,
576
+ language: params.language,
577
+ service_mode: params.service_mode ?? "synchronous",
578
+ metadata: params.metadata
579
+ });
580
+ }
581
+ async function createJobFromUrl(client, params) {
582
+ return client.createJob({
583
+ input_url: params.url,
584
+ model: params.model,
585
+ language: params.language,
586
+ service_mode: params.service_mode ?? "synchronous",
587
+ metadata: params.metadata
588
+ });
589
+ }
590
+ async function finishCompatJob(client, job, options) {
591
+ if (!options.wait) {
592
+ return job;
593
+ }
594
+ const finished = await waitForJob(
595
+ client,
596
+ String(job.id || ""),
597
+ {
598
+ timeout_ms: options.timeout_ms ?? 3e5,
599
+ poll_ms: options.poll_ms ?? 1500
600
+ }
601
+ );
602
+ if (String(finished.status) === "failed") {
603
+ throw new SpeechWeaveError(
604
+ String(finished.error || "Transcription failed"),
605
+ 500,
606
+ options.error_code,
607
+ finished
608
+ );
609
+ }
610
+ return finished;
611
+ }
612
+
613
+ // src/webhooks.ts
614
+ var import_node_crypto = __toESM(require("crypto"), 1);
615
+ function timingSafeEqual(a, b) {
616
+ const ab = Buffer.from(a, "utf8");
617
+ const bb = Buffer.from(b, "utf8");
618
+ if (ab.length !== bb.length) {
619
+ return false;
620
+ }
621
+ return import_node_crypto.default.timingSafeEqual(ab, bb);
622
+ }
623
+ function verifyWebhook(secret, raw_body, signature_header, tolerance_seconds = 300) {
624
+ const secrets = (Array.isArray(secret) ? secret : [
625
+ secret
626
+ ]).map((s) => String(s || "").trim()).filter(Boolean);
627
+ if (!secrets.length) {
628
+ return {
629
+ ok: false,
630
+ reason: "no_secrets"
631
+ };
632
+ }
633
+ const header = String(signature_header || "").trim();
634
+ const parts = header.split(",").map((p) => p.trim());
635
+ let t = null;
636
+ const v1_list = [];
637
+ for (const part of parts) {
638
+ if (part.startsWith("t=")) {
639
+ t = part.slice(2);
640
+ }
641
+ if (part.startsWith("v1=")) {
642
+ v1_list.push(part.slice(3));
643
+ }
644
+ }
645
+ if (!t || !v1_list.length) {
646
+ return {
647
+ ok: false,
648
+ reason: "missing_t_or_v1"
649
+ };
650
+ }
651
+ const ts = Number(t);
652
+ if (!Number.isFinite(ts)) {
653
+ return {
654
+ ok: false,
655
+ reason: "bad_timestamp"
656
+ };
657
+ }
658
+ const now = Math.floor(Date.now() / 1e3);
659
+ if (Math.abs(now - ts) > tolerance_seconds) {
660
+ return {
661
+ ok: false,
662
+ reason: "timestamp_skew"
663
+ };
664
+ }
665
+ for (const secret2 of secrets) {
666
+ const expected = import_node_crypto.default.createHmac("sha256", secret2).update(`${t}.${raw_body}`).digest("hex");
667
+ for (const v1 of v1_list) {
668
+ if (timingSafeEqual(expected, v1)) {
669
+ return {
670
+ ok: true
671
+ };
672
+ }
673
+ }
674
+ }
675
+ return {
676
+ ok: false,
677
+ reason: "bad_signature"
678
+ };
679
+ }
680
+
681
+ // src/openai/openai_compat.ts
682
+ function createOpenAiAudioNamespace(client) {
683
+ return {
684
+ transcriptions: {
685
+ /** OpenAI-shaped transcription create — drop-in compatibility wrapper. */
686
+ create: async (opts) => {
687
+ const name = opts.filename || "audio.bin";
688
+ const job = await uploadAndCreateJob(client, {
689
+ data: opts.file,
690
+ filename: name,
691
+ model: opts.model,
692
+ language: opts.language,
693
+ file_size: opts.file_size
694
+ });
695
+ const finished = await finishCompatJob(client, job, {
696
+ wait: opts.wait ?? true,
697
+ error_code: "OPENAI_PROXY"
698
+ });
699
+ if (opts.wait === false) {
700
+ return finished;
701
+ }
702
+ return shapeOpenAiResponse(finished);
703
+ }
704
+ }
705
+ };
706
+ }
707
+
708
+ // src/deepgram/deepgram_compat.ts
709
+ function createDeepgramListenNamespace(client) {
710
+ return {
711
+ prerecorded: {
712
+ /** Deepgram-shaped prerecorded file transcription — drop-in compatibility wrapper. */
713
+ transcribeFile: async (stream, options = {}) => {
714
+ const job = await uploadAndCreateJob(client, {
715
+ data: stream,
716
+ filename: options.filename || "audio.bin",
717
+ model: options.model,
718
+ language: options.language,
719
+ file_size: options.file_size
720
+ });
721
+ const finished = await finishCompatJob(client, job, {
722
+ wait: options.wait ?? true,
723
+ error_code: "DEEPGRAM_PROXY"
724
+ });
725
+ if (options.wait === false) {
726
+ return finished;
727
+ }
728
+ return shapeDeepgramResponse(
729
+ finished,
730
+ { model: options.model }
731
+ );
732
+ },
733
+ /** Deepgram-shaped prerecorded URL transcription — drop-in compatibility wrapper. */
734
+ transcribeUrl: async (url, options = {}) => {
735
+ const job = await createJobFromUrl(client, {
736
+ url,
737
+ model: options.model,
738
+ language: options.language
739
+ });
740
+ const finished = await finishCompatJob(client, job, {
741
+ wait: options.wait ?? true,
742
+ error_code: "DEEPGRAM_PROXY"
743
+ });
744
+ if (options.wait === false) {
745
+ return finished;
746
+ }
747
+ return shapeDeepgramResponse(
748
+ finished,
749
+ { model: options.model }
750
+ );
751
+ }
752
+ }
753
+ };
754
+ }
755
+
756
+ // src/assembly/assembly_compat.ts
757
+ function createAssemblyTranscriptsNamespace(client) {
758
+ return {
759
+ /** AssemblyAI-shaped transcription — drop-in compatibility wrapper. Pass a URL string or binary/file body. */
760
+ transcribe: async (audio, config, options = {}) => {
761
+ const cfg = config || {};
762
+ const wait = options.wait ?? true;
763
+ let job;
764
+ if (typeof audio === "string") {
765
+ job = await createJobFromUrl(client, {
766
+ url: audio,
767
+ model: cfg.model,
768
+ language: cfg.language
769
+ });
770
+ } else {
771
+ job = await uploadAndCreateJob(client, {
772
+ data: audio,
773
+ filename: "audio.bin",
774
+ model: cfg.model,
775
+ language: cfg.language,
776
+ file_size: cfg.file_size
777
+ });
778
+ }
779
+ const finished = await finishCompatJob(client, job, {
780
+ wait,
781
+ error_code: "ASSEMBLY_PROXY"
782
+ });
783
+ if (!wait) {
784
+ return finished;
785
+ }
786
+ return shapeAssemblyResponse(finished);
787
+ }
788
+ };
789
+ }
790
+
791
+ // src/index.ts
792
+ function createJobsNamespace(client) {
793
+ return {
794
+ /**
795
+ * Create a job from a local file or a remote URL / object_key.
796
+ * Pass `file` (path, Buffer, Blob, or stream) to presign-upload then create.
797
+ * Otherwise pass one of `object_key`, `input_url`, or `audio_url` (no upload).
798
+ * Omitting service_mode leaves the API default (deferred).
799
+ */
800
+ create: async (params) => {
801
+ if (params.file != null) {
802
+ if (typeof params.file === "string") {
803
+ return client.transcribeFilePath(
804
+ params.file,
805
+ {
806
+ model: params.model,
807
+ service_mode: params.service_mode,
808
+ language: params.language,
809
+ content_type: params.content_type,
810
+ metadata: params.metadata,
811
+ file_size: params.file_size
812
+ }
813
+ );
814
+ }
815
+ return client.transcribeFile(
816
+ params.file,
817
+ {
818
+ filename: params.filename,
819
+ content_type: params.content_type,
820
+ model: params.model,
821
+ service_mode: params.service_mode,
822
+ language: params.language,
823
+ metadata: params.metadata,
824
+ file_size: params.file_size
825
+ }
826
+ );
827
+ }
828
+ return client.createJob({
829
+ object_key: params.object_key,
830
+ input_url: params.input_url,
831
+ audio_url: params.audio_url,
832
+ model: params.model,
833
+ service_mode: params.service_mode,
834
+ language: params.language,
835
+ type: params.type,
836
+ metadata: params.metadata
837
+ });
838
+ },
839
+ /** Fetch the current job record. */
840
+ get: client.getJob.bind(client),
841
+ /** List jobs for the authenticated account. */
842
+ list: client.listJobs.bind(client),
843
+ /**
844
+ * Cancel a pending or processing job.
845
+ * Fails if the job is already completed, failed, or cancelled.
846
+ */
847
+ cancel: client.cancelJob.bind(client)
848
+ };
849
+ }
850
+ var SpeechWeave = class extends SpeechWeaveClient {
851
+ audio;
852
+ listen;
853
+ transcripts;
854
+ jobs;
855
+ constructor(options = {}) {
856
+ super(options);
857
+ this.audio = createOpenAiAudioNamespace(this);
858
+ this.listen = createDeepgramListenNamespace(this);
859
+ this.transcripts = createAssemblyTranscriptsNamespace(this);
860
+ this.jobs = createJobsNamespace(this);
861
+ }
862
+ };
863
+ // Annotate the CommonJS export names for ESM import in node:
864
+ 0 && (module.exports = {
865
+ SpeechWeave,
866
+ SpeechWeaveClient,
867
+ SpeechWeaveError,
868
+ VERSION,
869
+ createJobFromUrl,
870
+ finishCompatJob,
871
+ shapeAssemblyResponse,
872
+ shapeDeepgramResponse,
873
+ shapeOpenAiResponse,
874
+ uploadAndCreateJob,
875
+ verifyWebhook,
876
+ waitForJob
877
+ });
878
+ //# sourceMappingURL=index.cjs.map