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