batchwork 1.3.0 → 1.4.1

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/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A unified **batch API** for AI providers. Submit thousands of LLM requests at roughly half the cost with a single call — `batchwork` handles JSONL, file uploads, inline submission, polling, and result parsing across every major provider.
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/batchwork.svg)](https://www.npmjs.com/package/batchwork) [![npm downloads](https://img.shields.io/npm/dm/batchwork.svg)](https://www.npmjs.com/package/batchwork) [![license](https://img.shields.io/npm/l/batchwork.svg)](#license) [![Socket Badge](https://socket.dev/api/badge/npm/package/batchwork)](https://socket.dev/npm/package/batchwork)
5
+ [![npm downloads](https://img.shields.io/npm/dm/batchwork.svg)](https://www.npmjs.com/package/batchwork) [![Socket Badge](https://socket.dev/api/badge/npm/package/batchwork)](https://socket.dev/npm/package/batchwork) ![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/haydenbleasel/batchwork?utm_source=oss&utm_medium=github&utm_campaign=haydenbleasel%2Fbatchwork&labelColor=171717&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+Reviews)
6
6
 
7
7
  📖 **Full documentation: [batchwork.dev](https://batchwork.dev)**
8
8
 
@@ -11,7 +11,7 @@ A unified **batch API** for AI providers. Submit thousands of LLM requests at ro
11
11
  ```bash
12
12
  npm install batchwork
13
13
  # plus the provider package(s) you use:
14
- npm install @ai-sdk/openai @ai-sdk/anthropic
14
+ npm install @ai-sdk/openai @ai-sdk/anthropic @ai-sdk/azure
15
15
  ```
16
16
 
17
17
  `batchwork` depends only on `ai`. The `@ai-sdk/*` provider packages are **optional peer dependencies** — install only the ones you batch with. Requires Node.js 20 or newer.
@@ -179,7 +179,7 @@ Batch moderation is available for **OpenAI** (`omni-moderation-latest`, text + i
179
179
 
180
180
  ## Features
181
181
 
182
- - **One API, many providers** — OpenAI, Anthropic, Google Gemini, Groq, Mistral, Together AI, and xAI.
182
+ - **One API, many providers** — OpenAI, Azure OpenAI, Anthropic, Google Gemini, Groq, Mistral, Together AI, and xAI.
183
183
  - **AI SDK native** — author requests in the familiar `generateText` shape.
184
184
  - **Chat, embeddings, images, video, audio & moderation** — `batch()` for completions, `batch.embeddings()` for vectors, `batch.images()` for image generation, `batch.videos()` for video generation, `batch.transcriptions()` for audio transcription, `batch.moderations()` for content moderation.
185
185
  - **~50% cheaper** — every request runs against the provider's batch window.
@@ -1 +1 @@
1
- {"version":3,"file":"body.d.ts","sourceRoot":"","sources":["../src/body.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAUpD,OAAO,KAAK,EAAkB,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,KAAK,EACV,aAAa,EACb,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EAErB,iBAAiB,EACjB,WAAW,EACX,sBAAsB,EACtB,YAAY,EACZ,0BAA0B,EAC1B,yBAAyB,EACzB,wBAAwB,EACxB,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EAEpB,MAAM,SAAS,CAAC;AAIjB,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAgOD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,aACnB,aAAa,YACb,SAAS,YAAY,EAAE,YACvB,aAAa,GAAG,SAAS,eACtB,mBAAmB,cACpB,WAAW,GAAG,mBAAmB,KAC5C,OAAO,CAAC,YAAY,EAAE,CA4BxB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,aACrB,aAAa,YACb,SAAS,qBAAqB,EAAE,eAC7B,mBAAmB,cACpB,WAAW,GAAG,mBAAmB,KAC5C,OAAO,CAAC,YAAY,EAAE,CAgCxB,CAAC;AAyDF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,aACtB,aAAa,YACb,SAAS,sBAAsB,EAAE,cAC/B,WAAW,GAAG,mBAAmB,KAC5C,YAAY,EAgBd,CAAC;AA0FF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,aACzB,aAAa,YACb,SAAS,yBAAyB,EAAE,YACpC,0BAA0B,GAAG,SAAS,cACpC,WAAW,GAAG,mBAAmB,KAC5C,YAAY,EAOZ,CAAC;AAEJ;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,aACvB,aAAa,YACb,SAAS,uBAAuB,EAAE,YAClC,wBAAwB,GAAG,SAAS,cAClC,WAAW,GAAG,mBAAmB,KAC5C,YAAY,EAOZ,CAAC;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,aACjB,aAAa,YACb,SAAS,iBAAiB,EAAE,YAC5B,kBAAkB,GAAG,SAAS,eAC3B,mBAAmB,cACpB,WAAW,GAAG,mBAAmB,KAC5C,OAAO,CAAC,YAAY,EAAE,CAgCxB,CAAC;AAmEF;;;GAGG;AACH,eAAO,MAAM,oBAAoB,aACrB,aAAa,YACb,SAAS,qBAAqB,EAAE,YAChC,sBAAsB,GAAG,SAAS,cAChC,WAAW,GAAG,mBAAmB,KAC5C,YAAY,EAoBd,CAAC;AAiCF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,aACjB,aAAa,YACb,SAAS,iBAAiB,EAAE,YAC5B,kBAAkB,GAAG,SAAS,eAC3B,mBAAmB,cACpB,WAAW,GAAG,mBAAmB,KAC5C,OAAO,CAAC,YAAY,EAAE,CAgCxB,CAAC"}
1
+ {"version":3,"file":"body.d.ts","sourceRoot":"","sources":["../src/body.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAUpD,OAAO,KAAK,EAAkB,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,KAAK,EACV,aAAa,EACb,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EAErB,iBAAiB,EACjB,WAAW,EACX,sBAAsB,EACtB,YAAY,EACZ,0BAA0B,EAC1B,yBAAyB,EACzB,wBAAwB,EACxB,uBAAuB,EACvB,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EAEpB,MAAM,SAAS,CAAC;AAIjB,gEAAgE;AAChE,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAgOD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,aACnB,aAAa,YACb,SAAS,YAAY,EAAE,YACvB,aAAa,GAAG,SAAS,eACtB,mBAAmB,cACpB,WAAW,GAAG,mBAAmB,KAC5C,OAAO,CAAC,YAAY,EAAE,CA4BxB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,aACrB,aAAa,YACb,SAAS,qBAAqB,EAAE,eAC7B,mBAAmB,cACpB,WAAW,GAAG,mBAAmB,KAC5C,OAAO,CAAC,YAAY,EAAE,CAgCxB,CAAC;AAyDF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,aACtB,aAAa,YACb,SAAS,sBAAsB,EAAE,cAC/B,WAAW,GAAG,mBAAmB,KAC5C,YAAY,EAgBd,CAAC;AA0FF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,aACzB,aAAa,YACb,SAAS,yBAAyB,EAAE,YACpC,0BAA0B,GAAG,SAAS,cACpC,WAAW,GAAG,mBAAmB,KAC5C,YAAY,EAOZ,CAAC;AAEJ;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,aACvB,aAAa,YACb,SAAS,uBAAuB,EAAE,YAClC,wBAAwB,GAAG,SAAS,cAClC,WAAW,GAAG,mBAAmB,KAC5C,YAAY,EAOZ,CAAC;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,aACjB,aAAa,YACb,SAAS,iBAAiB,EAAE,YAC5B,kBAAkB,GAAG,SAAS,eAC3B,mBAAmB,cACpB,WAAW,GAAG,mBAAmB,KAC5C,OAAO,CAAC,YAAY,EAAE,CAgCxB,CAAC;AAmEF;;;GAGG;AACH,eAAO,MAAM,oBAAoB,aACrB,aAAa,YACb,SAAS,qBAAqB,EAAE,YAChC,sBAAsB,GAAG,SAAS,cAChC,WAAW,GAAG,mBAAmB,KAC5C,YAAY,EAoBd,CAAC;AAiCF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,aACjB,aAAa,YACb,SAAS,iBAAiB,EAAE,YAC5B,kBAAkB,GAAG,SAAS,eAC3B,mBAAmB,cACpB,WAAW,GAAG,mBAAmB,KAC5C,OAAO,CAAC,YAAY,EAAE,CAgCxB,CAAC"}
@@ -5,17 +5,31 @@ import {
5
5
  UnsupportedProviderError,
6
6
  assertByteLength,
7
7
  getAdapter,
8
- mapWithConcurrency,
9
- resolveBatchLimits
10
- } from "./chunk-gwa0dkhj.js";
8
+ resolveBatchLimits,
9
+ trimTrailingSlashes
10
+ } from "./chunk-n50t31ca.js";
11
11
  import {
12
12
  __require
13
13
  } from "./chunk-v0bahtg2.js";
14
14
 
15
15
  // src/model.ts
16
16
  var CAPTURE_API_KEY = "batchwork-capture";
17
+ var azureCaptureBaseUrl = (baseURL) => {
18
+ if (!baseURL) {
19
+ return;
20
+ }
21
+ const normalized = trimTrailingSlashes(baseURL);
22
+ try {
23
+ if (new URL(normalized).hostname.endsWith(".openai.azure.com")) {
24
+ const root = normalized.replace(/\/v1$/u, "");
25
+ return root.endsWith("/openai") ? root : `${root}/openai`;
26
+ }
27
+ } catch {}
28
+ return normalized;
29
+ };
17
30
  var PACKAGE_BY_PROVIDER = {
18
31
  anthropic: { label: "Anthropic", specifier: "@ai-sdk/anthropic" },
32
+ azure: { label: "Azure OpenAI", specifier: "@ai-sdk/azure" },
19
33
  google: { label: "Google Gemini", specifier: "@ai-sdk/google" },
20
34
  groq: { label: "Groq", specifier: "@ai-sdk/groq" },
21
35
  mistral: { label: "Mistral", specifier: "@ai-sdk/mistral" },
@@ -25,6 +39,7 @@ var PACKAGE_BY_PROVIDER = {
25
39
  };
26
40
  var PROVIDER_BY_FAMILY = {
27
41
  anthropic: "anthropic",
42
+ azure: "azure",
28
43
  google: "google",
29
44
  groq: "groq",
30
45
  mistral: "mistral",
@@ -70,7 +85,7 @@ var resolveModel = (model) => {
70
85
  }
71
86
  const [family, suffix] = splitOnce(model.provider, ".");
72
87
  const provider = PROVIDER_BY_FAMILY[family];
73
- if (provider === "openai") {
88
+ if (provider === "openai" || provider === "azure") {
74
89
  return { kind: openaiKind(suffix), modelId: model.modelId, provider };
75
90
  }
76
91
  if (provider) {
@@ -86,6 +101,9 @@ var importProvider = (provider) => {
86
101
  case "anthropic": {
87
102
  return import("@ai-sdk/anthropic");
88
103
  }
104
+ case "azure": {
105
+ return import("@ai-sdk/azure");
106
+ }
89
107
  case "google": {
90
108
  return import("@ai-sdk/google");
91
109
  }
@@ -139,6 +157,20 @@ var createCaptureModel = async (resolved, credentials, fetchImpl) => {
139
157
  }
140
158
  return provider.chat(resolved.modelId);
141
159
  }
160
+ case "azure": {
161
+ const { createAzure } = await loadProvider("azure");
162
+ const provider = createAzure({
163
+ ...settings,
164
+ baseURL: azureCaptureBaseUrl(credentials.baseURL)
165
+ });
166
+ if (resolved.kind === "responses") {
167
+ return provider.responses(resolved.modelId);
168
+ }
169
+ if (resolved.kind === "completion") {
170
+ return provider.completion(resolved.modelId);
171
+ }
172
+ return provider.chat(resolved.modelId);
173
+ }
142
174
  case "anthropic": {
143
175
  const { createAnthropic } = await loadProvider("anthropic");
144
176
  return createAnthropic(settings).messages(resolved.modelId);
@@ -270,6 +302,7 @@ import {
270
302
  generateImage,
271
303
  generateText
272
304
  } from "ai";
305
+ import pMap from "p-map";
273
306
  var MAX_CAUSE_DEPTH = 10;
274
307
 
275
308
  class CaptureSignalError extends Error {
@@ -413,11 +446,11 @@ var buildRequestBodies = async (resolved, requests, defaults, credentials, rawLi
413
446
  }
414
447
  const model = await createCaptureModel(resolved, credentials, captureFetch);
415
448
  const items = assignCustomIds(requests);
416
- return await mapWithConcurrency(items, limits.captureConcurrency, async (item) => {
449
+ return await pMap(items, async (item) => {
417
450
  const built = await captureOne(model, mergeDefaults(item.request, defaults), item.customId, limits.maxRequestBytes);
418
451
  assertByteLength(`request "${item.customId}"`, JSON.stringify(built.body), limits.maxRequestBytes);
419
452
  return built;
420
- });
453
+ }, { concurrency: limits.captureConcurrency });
421
454
  };
422
455
  var buildEmbeddingBodies = async (resolved, requests, credentials, rawLimits) => {
423
456
  const limits = resolveBatchLimits(rawLimits);
@@ -426,11 +459,11 @@ var buildEmbeddingBodies = async (resolved, requests, credentials, rawLimits) =>
426
459
  }
427
460
  const model = await createCaptureEmbeddingModel(resolved, credentials, captureFetch);
428
461
  const items = assignCustomIds(requests);
429
- return await mapWithConcurrency(items, limits.captureConcurrency, async (item) => {
462
+ return await pMap(items, async (item) => {
430
463
  const built = await captureEmbeddingOne(model, item.request, item.customId, limits.maxRequestBytes);
431
464
  assertByteLength(`request "${item.customId}"`, JSON.stringify(built.body), limits.maxRequestBytes);
432
465
  return built;
433
- });
466
+ }, { concurrency: limits.captureConcurrency });
434
467
  };
435
468
  var MODERATION_ENDPOINT = "/v1/moderations";
436
469
  var moderationInput = (request) => {
@@ -532,11 +565,11 @@ var buildImageBodies = async (resolved, requests, defaults, credentials, rawLimi
532
565
  }
533
566
  const model = await createCaptureImageModel(resolved, credentials, captureFetch);
534
567
  const items = assignCustomIds(requests);
535
- return await mapWithConcurrency(items, limits.captureConcurrency, async (item) => {
568
+ return await pMap(items, async (item) => {
536
569
  const built = await captureImageOne(model, mergeDefaults(item.request, defaults), item.customId, limits.maxRequestBytes);
537
570
  assertByteLength(`request "${item.customId}"`, JSON.stringify(built.body), limits.maxRequestBytes);
538
571
  return built;
539
- });
572
+ }, { concurrency: limits.captureConcurrency });
540
573
  };
541
574
  var IMAGE_EDIT_ENDPOINT = "/v1/images/edits";
542
575
  var openaiImageRef = (ref) => ("fileId" in ref) ? { file_id: ref.fileId } : { image_url: ref.imageUrl };
@@ -613,11 +646,11 @@ var buildVideoBodies = async (resolved, requests, defaults, credentials, rawLimi
613
646
  }
614
647
  const model = await createCaptureVideoModel(resolved, credentials, captureFetch);
615
648
  const items = assignCustomIds(requests);
616
- return await mapWithConcurrency(items, limits.captureConcurrency, async (item) => {
649
+ return await pMap(items, async (item) => {
617
650
  const built = await captureVideoOne(model, mergeDefaults(item.request, defaults), item.customId, limits.maxRequestBytes);
618
651
  assertByteLength(`request "${item.customId}"`, JSON.stringify(built.body), limits.maxRequestBytes);
619
652
  return built;
620
- });
653
+ }, { concurrency: limits.captureConcurrency });
621
654
  };
622
655
 
623
656
  // src/batch.ts
@@ -840,5 +873,5 @@ var cancelBatch = async (ref) => {
840
873
 
841
874
  export { resolveModel, batch, batchEmbeddings, batchImages, getBatch, getBatchResults, cancelBatch };
842
875
 
843
- //# debugId=0D659D78B4576A4164756E2164756E21
844
- //# sourceMappingURL=chunk-qqz5h9v6.js.map
876
+ //# debugId=BF4E08ACD1170D0064756E2164756E21
877
+ //# sourceMappingURL=chunk-14qcscwd.js.map
@@ -0,0 +1,12 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/model.ts", "../src/body.ts", "../src/batch.ts"],
4
+ "sourcesContent": [
5
+ "import type { createAnthropic } from \"@ai-sdk/anthropic\";\nimport type { createAzure } from \"@ai-sdk/azure\";\nimport type { createGoogleGenerativeAI } from \"@ai-sdk/google\";\nimport type { createGroq } from \"@ai-sdk/groq\";\nimport type { createMistral } from \"@ai-sdk/mistral\";\nimport type { createOpenAI } from \"@ai-sdk/openai\";\nimport type { createTogetherAI } from \"@ai-sdk/togetherai\";\nimport type { createXai } from \"@ai-sdk/xai\";\nimport type {\n EmbeddingModel,\n ImageModel,\n LanguageModel,\n TranscriptionModel,\n} from \"ai\";\n\nimport { MissingDependencyError, UnsupportedProviderError } from \"./errors\";\nimport type { BatchProvider, ProviderCredentials, VideoModel } from \"./types\";\nimport { trimTrailingSlashes } from \"./util\";\n\n/** The shape `loadProvider` expects from each optional `@ai-sdk/*` package. */\ninterface AnthropicModule {\n createAnthropic: typeof createAnthropic;\n}\ninterface AzureModule {\n createAzure: typeof createAzure;\n}\ninterface GoogleModule {\n createGoogleGenerativeAI: typeof createGoogleGenerativeAI;\n}\ninterface GroqModule {\n createGroq: typeof createGroq;\n}\ninterface MistralModule {\n createMistral: typeof createMistral;\n}\ninterface OpenAIModule {\n createOpenAI: typeof createOpenAI;\n}\ninterface TogetherModule {\n createTogetherAI: typeof createTogetherAI;\n}\ninterface XaiModule {\n createXai: typeof createXai;\n}\n\n/** A fetch implementation compatible with the AI SDK provider `fetch` option. */\nexport type CapturingFetch = typeof globalThis.fetch;\n\n/** OpenAI exposes several request shapes; we mirror the one the model implies. */\nexport type OpenAIModelKind = \"chat\" | \"responses\" | \"completion\";\n\nexport interface ResolvedModel {\n /** Relevant for OpenAI; other providers always use a single chat endpoint. */\n kind: OpenAIModelKind;\n modelId: string;\n provider: BatchProvider;\n}\n\n/**\n * Placeholder API key used only when building request bodies. Body building\n * intercepts the request before it is sent, so no real credential is needed —\n * but the provider refuses to construct a model without one.\n */\nconst CAPTURE_API_KEY = \"batchwork-capture\";\n\nconst azureCaptureBaseUrl = (\n baseURL: string | undefined\n): string | undefined => {\n if (!baseURL) {\n return;\n }\n const normalized = trimTrailingSlashes(baseURL);\n try {\n if (new URL(normalized).hostname.endsWith(\".openai.azure.com\")) {\n // The AI SDK appends `/v1` itself, so it wants the `/openai` root —\n // accept the bare resource URL, `/openai`, or `/openai/v1` forms.\n const root = normalized.replace(/\\/v1$/u, \"\");\n return root.endsWith(\"/openai\") ? root : `${root}/openai`;\n }\n } catch {\n // Let the provider report malformed URLs with its normal error.\n }\n return normalized;\n};\n\n/** The optional `@ai-sdk/*` package backing each provider. */\nconst PACKAGE_BY_PROVIDER: Record<\n BatchProvider,\n { label: string; specifier: string }\n> = {\n anthropic: { label: \"Anthropic\", specifier: \"@ai-sdk/anthropic\" },\n azure: { label: \"Azure OpenAI\", specifier: \"@ai-sdk/azure\" },\n google: { label: \"Google Gemini\", specifier: \"@ai-sdk/google\" },\n groq: { label: \"Groq\", specifier: \"@ai-sdk/groq\" },\n mistral: { label: \"Mistral\", specifier: \"@ai-sdk/mistral\" },\n openai: { label: \"OpenAI\", specifier: \"@ai-sdk/openai\" },\n together: { label: \"Together AI\", specifier: \"@ai-sdk/togetherai\" },\n xai: { label: \"xAI\", specifier: \"@ai-sdk/xai\" },\n};\n\n/**\n * AI SDK provider id prefixes (the part before the first `.` in `model.provider`)\n * mapped to batch providers.\n */\nconst PROVIDER_BY_FAMILY: Record<string, BatchProvider> = {\n anthropic: \"anthropic\",\n azure: \"azure\",\n google: \"google\",\n groq: \"groq\",\n mistral: \"mistral\",\n openai: \"openai\",\n together: \"together\",\n togetherai: \"together\",\n xai: \"xai\",\n};\n\n/** Aliases accepted in the `\"provider/model\"` string form. */\nconst PROVIDER_BY_ALIAS: Record<string, BatchProvider> = {\n ...PROVIDER_BY_FAMILY,\n gemini: \"google\",\n};\n\nconst splitOnce = (value: string, separator: string): [string, string] => {\n const index = value.indexOf(separator);\n if (index === -1) {\n return [value, \"\"];\n }\n return [value.slice(0, index), value.slice(index + separator.length)];\n};\n\nconst openaiKind = (suffix: string): OpenAIModelKind => {\n if (suffix === \"responses\") {\n return \"responses\";\n }\n if (suffix === \"completion\") {\n return \"completion\";\n }\n // Default to chat completions: the most widely supported batch endpoint.\n return \"chat\";\n};\n\n/** Resolve a `\"provider/model\"` string into a provider + model id. */\nconst resolveModelString = (value: string): ResolvedModel => {\n const [providerId, modelId] = splitOnce(value, \"/\");\n if (modelId === \"\") {\n throw new UnsupportedProviderError(value);\n }\n const provider = PROVIDER_BY_ALIAS[providerId];\n if (!provider) {\n throw new UnsupportedProviderError(providerId);\n }\n return { kind: \"chat\", modelId, provider };\n};\n\n/**\n * Resolve any AI SDK `model` (a `\"provider/model\"` string or a provider model\n * object such as `openai(\"gpt-5.5\")`) to a provider + model id + request\n * shape. Gateway/registry model objects whose `modelId` is itself\n * `\"provider/model\"` are also handled.\n */\nexport const resolveModel = (\n model:\n | LanguageModel\n | EmbeddingModel\n | ImageModel\n | TranscriptionModel\n | VideoModel\n): ResolvedModel => {\n if (typeof model === \"string\") {\n return resolveModelString(model);\n }\n\n const [family, suffix] = splitOnce(model.provider, \".\");\n const provider = PROVIDER_BY_FAMILY[family];\n if (provider === \"openai\" || provider === \"azure\") {\n return { kind: openaiKind(suffix), modelId: model.modelId, provider };\n }\n if (provider) {\n return { kind: \"chat\", modelId: model.modelId, provider };\n }\n // Gateway/registry providers carry the real target in the model id.\n if (model.modelId.includes(\"/\")) {\n return resolveModelString(model.modelId);\n }\n throw new UnsupportedProviderError(model.provider);\n};\n\nconst importProvider = (provider: BatchProvider): Promise<unknown> => {\n switch (provider) {\n case \"anthropic\": {\n return import(\"@ai-sdk/anthropic\");\n }\n case \"azure\": {\n return import(\"@ai-sdk/azure\");\n }\n case \"google\": {\n return import(\"@ai-sdk/google\");\n }\n case \"groq\": {\n return import(\"@ai-sdk/groq\");\n }\n case \"mistral\": {\n return import(\"@ai-sdk/mistral\");\n }\n case \"openai\": {\n return import(\"@ai-sdk/openai\");\n }\n case \"together\": {\n return import(\"@ai-sdk/togetherai\");\n }\n case \"xai\": {\n return import(\"@ai-sdk/xai\");\n }\n default: {\n return Promise.reject(new UnsupportedProviderError(provider));\n }\n }\n};\n\n/**\n * Import the `@ai-sdk/*` package for a provider, translating a missing optional\n * dependency into a `MissingDependencyError`. The importer is injectable (like\n * the capturing `fetch`) so tests can drive the failure paths without\n * uninstalling a package. Exported for testing; not part of the public API.\n */\nexport const loadProvider = async <T>(\n provider: BatchProvider,\n load: (target: BatchProvider) => Promise<unknown> = importProvider\n): Promise<T> => {\n try {\n return (await load(provider)) as T;\n } catch (error) {\n if (error instanceof UnsupportedProviderError) {\n throw error;\n }\n const { specifier, label } = PACKAGE_BY_PROVIDER[provider];\n throw new MissingDependencyError(specifier, label);\n }\n};\n\n/**\n * Construct an AI SDK model wired to a capturing `fetch`, used to derive the\n * provider request body for each batch item without making a network call.\n */\nexport const createCaptureModel = async (\n resolved: ResolvedModel,\n credentials: ProviderCredentials,\n fetchImpl: CapturingFetch\n): Promise<LanguageModel> => {\n const settings = {\n apiKey: credentials.apiKey ?? CAPTURE_API_KEY,\n baseURL: credentials.baseURL,\n fetch: fetchImpl,\n headers: credentials.headers,\n };\n\n switch (resolved.provider) {\n case \"openai\": {\n const { createOpenAI } = await loadProvider<OpenAIModule>(\"openai\");\n const provider = createOpenAI(settings);\n if (resolved.kind === \"responses\") {\n return provider.responses(resolved.modelId);\n }\n if (resolved.kind === \"completion\") {\n return provider.completion(resolved.modelId);\n }\n return provider.chat(resolved.modelId);\n }\n case \"azure\": {\n const { createAzure } = await loadProvider<AzureModule>(\"azure\");\n const provider = createAzure({\n ...settings,\n // Batchwork documents Azure base URLs as the API root ending in\n // `/openai/v1`; the AI SDK expects the Azure root before `/v1`.\n baseURL: azureCaptureBaseUrl(credentials.baseURL),\n });\n if (resolved.kind === \"responses\") {\n return provider.responses(resolved.modelId);\n }\n if (resolved.kind === \"completion\") {\n return provider.completion(resolved.modelId);\n }\n return provider.chat(resolved.modelId);\n }\n case \"anthropic\": {\n const { createAnthropic } =\n await loadProvider<AnthropicModule>(\"anthropic\");\n return createAnthropic(settings).messages(resolved.modelId);\n }\n case \"groq\": {\n const { createGroq } = await loadProvider<GroqModule>(\"groq\");\n return createGroq(settings).languageModel(resolved.modelId);\n }\n case \"mistral\": {\n const { createMistral } = await loadProvider<MistralModule>(\"mistral\");\n return createMistral(settings).languageModel(resolved.modelId);\n }\n case \"google\": {\n const { createGoogleGenerativeAI } =\n await loadProvider<GoogleModule>(\"google\");\n return createGoogleGenerativeAI(settings).languageModel(resolved.modelId);\n }\n case \"xai\": {\n const { createXai } = await loadProvider<XaiModule>(\"xai\");\n return createXai(settings).languageModel(resolved.modelId);\n }\n case \"together\": {\n const { createTogetherAI } =\n await loadProvider<TogetherModule>(\"together\");\n return createTogetherAI(settings).languageModel(resolved.modelId);\n }\n default: {\n throw new UnsupportedProviderError(resolved.provider);\n }\n }\n};\n\n/**\n * Providers whose batch API accepts embeddings. Together is excluded: it exposes\n * an embedding model, but its batch endpoint rejects `/v1/embeddings`. Anthropic,\n * Groq, and xAI have no embedding model at all.\n */\nexport const EMBEDDING_PROVIDERS = new Set<BatchProvider>([\n \"google\",\n \"mistral\",\n \"openai\",\n]);\n\nexport const unsupportedEmbeddingProvider = (\n provider: BatchProvider\n): UnsupportedProviderError =>\n new UnsupportedProviderError(\n provider,\n `batchwork: provider \"${provider}\" does not offer batch embeddings. Embeddings are supported for: openai, mistral, google.`\n );\n\n/**\n * Construct an AI SDK text embedding model wired to a capturing `fetch`, used to\n * derive the provider embedding request body for each batch item without making\n * a network call. Throws for providers without an embedding model.\n */\nexport const createCaptureEmbeddingModel = async (\n resolved: ResolvedModel,\n credentials: ProviderCredentials,\n fetchImpl: CapturingFetch\n): Promise<EmbeddingModel> => {\n const settings = {\n apiKey: credentials.apiKey ?? CAPTURE_API_KEY,\n baseURL: credentials.baseURL,\n fetch: fetchImpl,\n headers: credentials.headers,\n };\n\n switch (resolved.provider) {\n case \"openai\": {\n const { createOpenAI } = await loadProvider<OpenAIModule>(\"openai\");\n return createOpenAI(settings).embeddingModel(resolved.modelId);\n }\n case \"mistral\": {\n const { createMistral } = await loadProvider<MistralModule>(\"mistral\");\n return createMistral(settings).embeddingModel(resolved.modelId);\n }\n case \"google\": {\n const { createGoogleGenerativeAI } =\n await loadProvider<GoogleModule>(\"google\");\n return createGoogleGenerativeAI(settings).embeddingModel(\n resolved.modelId\n );\n }\n default: {\n throw unsupportedEmbeddingProvider(resolved.provider);\n }\n }\n};\n\n/**\n * Providers whose batch API accepts image editing. OpenAI and xAI both expose\n * `/v1/images/edits` as a batch endpoint (JSON bodies with asset references —\n * OpenAI takes uploaded file ids or image URLs plus an optional mask; xAI\n * takes image URLs only). Google's Gemini batch has no edit endpoint.\n */\nexport const IMAGE_EDIT_PROVIDERS = new Set<BatchProvider>([\"openai\", \"xai\"]);\n\nexport const unsupportedImageEditProvider = (\n provider: BatchProvider\n): UnsupportedProviderError =>\n new UnsupportedProviderError(\n provider,\n `batchwork: provider \"${provider}\" does not offer batch image editing. Image edits are supported for: openai, xai.`\n );\n\n/**\n * Providers whose batch API accepts video generation. xAI exposes\n * `/v1/videos/generations` (plus `/edits` and `/extensions`) as batch\n * endpoints for Grok Imagine. OpenAI's Videos API (Sora) is deprecated and\n * shuts down 2026-09-24, so it is deliberately not supported; Google's Veo\n * models are not batch-compatible.\n */\nexport const VIDEO_PROVIDERS = new Set<BatchProvider>([\"xai\"]);\n\nexport const unsupportedVideoProvider = (\n provider: BatchProvider\n): UnsupportedProviderError =>\n new UnsupportedProviderError(\n provider,\n `batchwork: provider \"${provider}\" does not offer batch video generation. Videos are supported for: xai.`\n );\n\n/**\n * Construct an AI SDK video model wired to a capturing `fetch`, used to derive\n * the provider video request body for each batch item without making a network\n * call. Throws for providers without batch video support.\n */\nexport const createCaptureVideoModel = async (\n resolved: ResolvedModel,\n credentials: ProviderCredentials,\n fetchImpl: CapturingFetch\n): Promise<VideoModel> => {\n if (resolved.provider !== \"xai\") {\n throw unsupportedVideoProvider(resolved.provider);\n }\n const { createXai } = await loadProvider<XaiModule>(\"xai\");\n return createXai({\n apiKey: credentials.apiKey ?? CAPTURE_API_KEY,\n baseURL: credentials.baseURL,\n fetch: fetchImpl,\n headers: credentials.headers,\n }).video(resolved.modelId);\n};\n\n/**\n * Providers whose batch API accepts audio translation (Whisper's\n * translate-to-English task). Groq and Together expose\n * `/v1/audio/translations` as a batch endpoint; Mistral batches\n * transcriptions but not translations.\n */\nexport const TRANSLATION_PROVIDERS = new Set<BatchProvider>([\n \"groq\",\n \"together\",\n]);\n\nexport const unsupportedTranslationProvider = (\n provider: BatchProvider\n): UnsupportedProviderError =>\n new UnsupportedProviderError(\n provider,\n `batchwork: provider \"${provider}\" does not offer batch translation. Translations are supported for: groq, together.`\n );\n\n/**\n * Providers whose batch API accepts moderation. OpenAI exposes\n * `/v1/moderations` as a batch endpoint (omni moderation, text + images);\n * Mistral runs its moderation models through the same batch job flow\n * (text-only). No other provider has a standalone moderation API.\n */\nexport const MODERATION_PROVIDERS = new Set<BatchProvider>([\n \"mistral\",\n \"openai\",\n]);\n\nexport const unsupportedModerationProvider = (\n provider: BatchProvider\n): UnsupportedProviderError =>\n new UnsupportedProviderError(\n provider,\n `batchwork: provider \"${provider}\" does not offer batch moderation. Moderations are supported for: openai, mistral.`\n );\n\n/**\n * Providers whose batch API accepts audio transcription. Groq, Mistral, and\n * Together expose `/v1/audio/transcriptions` as a batch endpoint; OpenAI's\n * batch API does not accept audio endpoints, and the remaining providers have\n * no standalone transcription API.\n */\nexport const TRANSCRIPTION_PROVIDERS = new Set<BatchProvider>([\n \"groq\",\n \"mistral\",\n \"together\",\n]);\n\nexport const unsupportedTranscriptionProvider = (\n provider: BatchProvider\n): UnsupportedProviderError =>\n new UnsupportedProviderError(\n provider,\n `batchwork: provider \"${provider}\" does not offer batch transcription. Transcriptions are supported for: groq, mistral, together.`\n );\n\n/**\n * Providers whose batch API accepts image generation. OpenAI and xAI expose\n * `/v1/images/generations` as a batch endpoint; Google runs Gemini image models\n * through `:batchGenerateContent`. Imagen (Google `:predict`) is not\n * batch-supported, Together's batch API is chat/audio only, and Anthropic, Groq,\n * and Mistral have no image model.\n */\nexport const IMAGE_PROVIDERS = new Set<BatchProvider>([\n \"google\",\n \"openai\",\n \"xai\",\n]);\n\nexport const unsupportedImageProvider = (\n provider: BatchProvider\n): UnsupportedProviderError =>\n new UnsupportedProviderError(\n provider,\n `batchwork: provider \"${provider}\" does not offer batch image generation. Image batches are supported for: openai, google, xai.`\n );\n\n/**\n * Construct an AI SDK image model wired to a capturing `fetch`, used to derive\n * the provider image-generation request body for each batch item without making\n * a network call. Throws for providers without batch image support.\n */\nexport const createCaptureImageModel = async (\n resolved: ResolvedModel,\n credentials: ProviderCredentials,\n fetchImpl: CapturingFetch\n): Promise<ImageModel> => {\n const settings = {\n apiKey: credentials.apiKey ?? CAPTURE_API_KEY,\n baseURL: credentials.baseURL,\n fetch: fetchImpl,\n headers: credentials.headers,\n };\n\n switch (resolved.provider) {\n case \"openai\": {\n const { createOpenAI } = await loadProvider<OpenAIModule>(\"openai\");\n return createOpenAI(settings).image(resolved.modelId);\n }\n case \"google\": {\n const { createGoogleGenerativeAI } =\n await loadProvider<GoogleModule>(\"google\");\n return createGoogleGenerativeAI(settings).image(resolved.modelId);\n }\n case \"xai\": {\n const { createXai } = await loadProvider<XaiModule>(\"xai\");\n return createXai(settings).image(resolved.modelId);\n }\n default: {\n throw unsupportedImageProvider(resolved.provider);\n }\n }\n};\n",
6
+ "import {\n embed,\n experimental_generateVideo,\n generateImage,\n generateText,\n} from \"ai\";\nimport type { EmbeddingModel, ImageModel, LanguageModel } from \"ai\";\nimport pMap from \"p-map\";\n\nimport { BatchworkError } from \"./errors\";\nimport { assertByteLength, resolveBatchLimits } from \"./limits\";\nimport type { ResolvedBatchLimits } from \"./limits\";\nimport {\n createCaptureEmbeddingModel,\n createCaptureImageModel,\n createCaptureModel,\n createCaptureVideoModel,\n unsupportedImageEditProvider,\n unsupportedModerationProvider,\n unsupportedTranscriptionProvider,\n} from \"./model\";\nimport type { CapturingFetch, ResolvedModel } from \"./model\";\nimport type {\n BatchDefaults,\n BatchEmbeddingRequest,\n BatchImageDefaults,\n BatchImageEditDefaults,\n BatchImageEditRequest,\n BatchImageRef,\n BatchImageRequest,\n BatchLimits,\n BatchModerationRequest,\n BatchRequest,\n BatchTranscriptionDefaults,\n BatchTranscriptionRequest,\n BatchTranslationDefaults,\n BatchTranslationRequest,\n BatchVideoDefaults,\n BatchVideoRequest,\n ProviderCredentials,\n VideoModel,\n} from \"./types\";\n\ntype GenerateTextInput = Parameters<typeof generateText>[0];\n\n/** A provider request body derived from a single batch item. */\nexport interface BuiltRequest {\n /** The serialized provider request body (becomes the batch line). */\n body: Record<string, unknown>;\n customId: string;\n /** API endpoint path the model targets, e.g. `/v1/chat/completions`. */\n endpoint: string;\n}\n\nconst MAX_CAUSE_DEPTH = 10;\n\n/**\n * Thrown by the capturing `fetch` to abort the request after its body has been\n * serialized. The body travels inside the error (not shared state), so capture\n * is correct even under concurrency.\n */\nclass CaptureSignalError extends Error {\n readonly url: string;\n readonly rawBody: string;\n\n constructor(url: string, rawBody: string) {\n super(\"batchwork:capture\");\n this.name = \"CaptureSignalError\";\n this.url = url;\n this.rawBody = rawBody;\n }\n}\n\nconst resolveUrl = (input: string | URL | Request): string => {\n if (typeof input === \"string\") {\n return input;\n }\n if (input instanceof URL) {\n return input.toString();\n }\n return input.url;\n};\n\nconst extractBody = (init?: RequestInit): string => {\n const body = init?.body;\n if (typeof body === \"string\") {\n return body;\n }\n if (body instanceof Uint8Array) {\n return new TextDecoder().decode(body);\n }\n throw new BatchworkError(\n \"batchwork: unable to read the provider request body during capture.\"\n );\n};\n\n// `CapturingFetch` is `typeof fetch`, whose shape varies by runtime types (e.g.\n// Bun adds a required `preconnect` method). We only ever call it as a plain\n// fetch, so cast the bare implementation rather than stub the extra members.\nconst captureFetch = ((input: string | URL | Request, init?: RequestInit) =>\n Promise.reject(\n new CaptureSignalError(resolveUrl(input), extractBody(init))\n )) as unknown as CapturingFetch;\n\nconst findCapture = (error: unknown): CaptureSignalError | undefined => {\n let current: unknown = error;\n let depth = 0;\n while (current && depth < MAX_CAUSE_DEPTH) {\n if (current instanceof CaptureSignalError) {\n return current;\n }\n current = (current as { cause?: unknown }).cause;\n depth += 1;\n }\n};\n\nconst endpointFromUrl = (url: string): string => {\n try {\n return new URL(url).pathname;\n } catch {\n return url;\n }\n};\n\nconst mergeDefaults = <Request extends object>(\n request: Request,\n defaults: NoInfer<Partial<Request>> | undefined\n): Request => {\n if (!defaults) {\n return request;\n }\n return { ...defaults, ...request };\n};\n\n/**\n * Map a batch request to AI SDK `generateText` input. Fields are listed\n * explicitly so `customId` never leaks into the provider request.\n */\nconst toGenerateInput = (\n model: LanguageModel,\n request: BatchRequest\n): GenerateTextInput =>\n // `prompt`/`messages` form a discriminated union in the AI SDK types; we\n // pass both keys and let `generateText` validate the XOR at runtime.\n ({\n frequencyPenalty: request.frequencyPenalty,\n maxOutputTokens: request.maxOutputTokens,\n maxRetries: 0,\n messages: request.messages,\n model,\n presencePenalty: request.presencePenalty,\n prompt: request.prompt,\n providerOptions: request.providerOptions,\n seed: request.seed,\n stopSequences: request.stopSequences,\n system: request.system,\n temperature: request.temperature,\n toolChoice: request.toolChoice,\n tools: request.tools,\n topK: request.topK,\n topP: request.topP,\n }) as GenerateTextInput;\n\n/**\n * Turn a thrown capture into a {@link BuiltRequest}. A genuine failure (one that\n * never reached the capturing `fetch`, e.g. an invalid prompt) is rethrown.\n */\nconst bodyFromCapture = (\n error: unknown,\n customId: string,\n maxRequestBytes: number\n): BuiltRequest => {\n const capture = findCapture(error);\n if (capture) {\n assertByteLength(`request \"${customId}\"`, capture.rawBody, maxRequestBytes);\n return {\n body: JSON.parse(capture.rawBody) as Record<string, unknown>,\n customId,\n endpoint: endpointFromUrl(capture.url),\n };\n }\n throw error;\n};\n\nconst captureOne = async (\n model: LanguageModel,\n request: BatchRequest,\n customId: string,\n maxRequestBytes: number\n): Promise<BuiltRequest> => {\n try {\n await generateText(toGenerateInput(model, request));\n } catch (error) {\n return bodyFromCapture(error, customId, maxRequestBytes);\n }\n throw new BatchworkError(\n \"batchwork: the request was not intercepted while building the batch body.\"\n );\n};\n\nconst captureEmbeddingOne = async (\n model: EmbeddingModel,\n request: BatchEmbeddingRequest,\n customId: string,\n maxRequestBytes: number\n): Promise<BuiltRequest> => {\n try {\n // `maxRetries: 0` is load-bearing: with retries enabled the capture error\n // is wrapped in a `RetryError` (under `.errors`, not `.cause`) and\n // `findCapture`'s cause walk would miss it.\n await embed({\n maxRetries: 0,\n model,\n providerOptions: request.providerOptions,\n value: request.value,\n });\n } catch (error) {\n return bodyFromCapture(error, customId, maxRequestBytes);\n }\n throw new BatchworkError(\n \"batchwork: the request was not intercepted while building the embedding body.\"\n );\n};\n\nconst captureImageOne = async (\n model: ImageModel,\n request: BatchImageRequest,\n customId: string,\n maxRequestBytes: number\n): Promise<BuiltRequest> => {\n try {\n await generateImage({\n aspectRatio: request.aspectRatio,\n // `maxImagesPerCall: n` forces a single `doGenerate` call so the captured\n // body carries the requested `n` rather than a fanned-out per-call count.\n maxImagesPerCall: request.n,\n // `maxRetries: 0` is load-bearing: with retries enabled the capture error\n // is wrapped in a `RetryError` (under `.errors`, not `.cause`) and\n // `findCapture`'s cause walk would miss it.\n maxRetries: 0,\n model,\n n: request.n,\n prompt: request.prompt,\n providerOptions: request.providerOptions,\n seed: request.seed,\n size: request.size,\n });\n } catch (error) {\n return bodyFromCapture(error, customId, maxRequestBytes);\n }\n throw new BatchworkError(\n \"batchwork: the request was not intercepted while building the image body.\"\n );\n};\n\n/**\n * Assign and validate a unique `customId` for each request (sequentially, so\n * duplicates are reported deterministically before bodies are captured in\n * parallel). Auto-generates `request-{index}` when omitted.\n */\nconst assignCustomIds = <T extends { customId?: string }>(\n requests: readonly T[]\n): { customId: string; request: T }[] => {\n const seen = new Set<string>();\n return requests.map((request, index) => {\n const customId = request.customId ?? `request-${index}`;\n if (seen.has(customId)) {\n throw new BatchworkError(\n `batchwork: duplicate customId \"${customId}\". customId values must be unique within a batch.`\n );\n }\n seen.add(customId);\n return { customId, request };\n });\n};\n\n/**\n * Derive provider request bodies for every batch item by running each through\n * the AI SDK with a capturing `fetch`. This reuses the AI SDK's full message,\n * tool, and multimodal conversion, so the body matches what `generateText`\n * would send — minus the network call.\n */\nexport const buildRequestBodies = async (\n resolved: ResolvedModel,\n requests: readonly BatchRequest[],\n defaults: BatchDefaults | undefined,\n credentials: ProviderCredentials,\n rawLimits?: BatchLimits | ResolvedBatchLimits\n): Promise<BuiltRequest[]> => {\n const limits = resolveBatchLimits(rawLimits);\n if (requests.length > limits.maxRequests) {\n throw new BatchworkError(\n `batchwork: requests length ${requests.length} exceeds the ${limits.maxRequests} request limit.`\n );\n }\n const model = await createCaptureModel(resolved, credentials, captureFetch);\n const items = assignCustomIds(requests);\n\n return await pMap(\n items,\n async (item) => {\n const built = await captureOne(\n model,\n mergeDefaults(item.request, defaults),\n item.customId,\n limits.maxRequestBytes\n );\n assertByteLength(\n `request \"${item.customId}\"`,\n JSON.stringify(built.body),\n limits.maxRequestBytes\n );\n return built;\n },\n { concurrency: limits.captureConcurrency }\n );\n};\n\n/**\n * Derive provider embedding request bodies for every batch item by running each\n * through the AI SDK `embed` with a capturing `fetch`. Mirrors\n * {@link buildRequestBodies} for the embedding endpoint; each item maps to a\n * single embedding (`input: [value]`), correlated by `customId`.\n */\nexport const buildEmbeddingBodies = async (\n resolved: ResolvedModel,\n requests: readonly BatchEmbeddingRequest[],\n credentials: ProviderCredentials,\n rawLimits?: BatchLimits | ResolvedBatchLimits\n): Promise<BuiltRequest[]> => {\n const limits = resolveBatchLimits(rawLimits);\n if (requests.length > limits.maxRequests) {\n throw new BatchworkError(\n `batchwork: requests length ${requests.length} exceeds the ${limits.maxRequests} request limit.`\n );\n }\n const model = await createCaptureEmbeddingModel(\n resolved,\n credentials,\n captureFetch\n );\n const items = assignCustomIds(requests);\n\n return await pMap(\n items,\n async (item) => {\n const built = await captureEmbeddingOne(\n model,\n item.request,\n item.customId,\n limits.maxRequestBytes\n );\n assertByteLength(\n `request \"${item.customId}\"`,\n JSON.stringify(built.body),\n limits.maxRequestBytes\n );\n return built;\n },\n { concurrency: limits.captureConcurrency }\n );\n};\n\nconst MODERATION_ENDPOINT = \"/v1/moderations\";\n\n/**\n * Build the moderation `input`: a bare string for text, or the OpenAI omni\n * moderation content-part array when images are involved.\n */\nconst moderationInput = (request: BatchModerationRequest): unknown => {\n const imageUrls = request.imageUrls ?? [];\n if (imageUrls.length === 0) {\n return request.value;\n }\n return [\n ...(request.value === undefined\n ? []\n : [{ text: request.value, type: \"text\" }]),\n ...imageUrls.map((url) => ({ image_url: { url }, type: \"image_url\" })),\n ];\n};\n\n/**\n * Build the provider moderation body directly — the AI SDK has no moderation\n * call to capture. Both providers take `{ input }`; OpenAI carries the model\n * per line, Mistral on the job.\n */\nconst moderationBody = (\n resolved: ResolvedModel,\n request: BatchModerationRequest,\n customId: string\n): Record<string, unknown> => {\n if (request.value === undefined && !request.imageUrls?.length) {\n throw new BatchworkError(\n `batchwork: moderation request \"${customId}\" needs \\`value\\` or \\`imageUrls\\`.`\n );\n }\n const options = request.providerOptions?.[resolved.provider];\n if (resolved.provider === \"openai\") {\n return {\n input: moderationInput(request),\n model: resolved.modelId,\n ...options,\n };\n }\n if (resolved.provider === \"mistral\") {\n if (request.imageUrls?.length) {\n throw new BatchworkError(\n `batchwork: moderation request \"${customId}\" has \\`imageUrls\\`, but Mistral moderation is text-only.`\n );\n }\n // `model` is included for uniformity; the Mistral adapter strips it from\n // each line and sets it on the job instead.\n return { input: request.value, model: resolved.modelId, ...options };\n }\n throw unsupportedModerationProvider(resolved.provider);\n};\n\n/**\n * Build provider moderation request bodies for every batch item. Each item\n * maps to a single moderation verdict, correlated by `customId`.\n */\nexport const buildModerationBodies = (\n resolved: ResolvedModel,\n requests: readonly BatchModerationRequest[],\n rawLimits?: BatchLimits | ResolvedBatchLimits\n): BuiltRequest[] => {\n const limits = resolveBatchLimits(rawLimits);\n if (requests.length > limits.maxRequests) {\n throw new BatchworkError(\n `batchwork: requests length ${requests.length} exceeds the ${limits.maxRequests} request limit.`\n );\n }\n return assignCustomIds(requests).map((item) => {\n const body = moderationBody(resolved, item.request, item.customId);\n assertByteLength(\n `request \"${item.customId}\"`,\n JSON.stringify(body),\n limits.maxRequestBytes\n );\n return { body, customId: item.customId, endpoint: MODERATION_ENDPOINT };\n });\n};\n\nconst TRANSCRIPTION_ENDPOINT = \"/v1/audio/transcriptions\";\n\n/**\n * Build the provider transcription body directly. Batch audio endpoints take\n * JSON with a hosted audio URL — unlike the synchronous transcription APIs\n * (and the AI SDK's `transcribe`), which upload the file as multipart form\n * data — so there is no SDK call to capture.\n */\nconst transcriptionBody = (\n resolved: ResolvedModel,\n request: BatchTranscriptionRequest\n): Record<string, unknown> => {\n const options = request.providerOptions?.[resolved.provider];\n if (resolved.provider === \"groq\") {\n return {\n model: resolved.modelId,\n url: request.audioUrl,\n ...(request.language ? { language: request.language } : {}),\n // Timestamps require the verbose response shape; providerOptions can\n // still override `response_format` since it spreads last.\n ...(request.timestampGranularities\n ? {\n response_format: \"verbose_json\",\n timestamp_granularities: request.timestampGranularities,\n }\n : {}),\n ...options,\n };\n }\n if (resolved.provider === \"mistral\") {\n // `model` is included for uniformity; the Mistral adapter strips it from\n // each line and sets it on the job instead.\n return {\n file_url: request.audioUrl,\n model: resolved.modelId,\n ...(request.language ? { language: request.language } : {}),\n ...(request.timestampGranularities\n ? { timestamp_granularities: request.timestampGranularities }\n : {}),\n ...options,\n };\n }\n if (resolved.provider === \"together\") {\n // Together's audio batch lines carry the hosted URL in `file`; extra\n // fields pass through to the underlying transcription API.\n return {\n file: request.audioUrl,\n model: resolved.modelId,\n ...(request.language ? { language: request.language } : {}),\n ...(request.timestampGranularities\n ? {\n response_format: \"verbose_json\",\n timestamp_granularities: request.timestampGranularities,\n }\n : {}),\n ...options,\n };\n }\n throw unsupportedTranscriptionProvider(resolved.provider);\n};\n\nconst buildAudioBodies = (\n resolved: ResolvedModel,\n requests: readonly BatchTranscriptionRequest[],\n defaults: BatchTranscriptionDefaults | undefined,\n endpoint: string,\n rawLimits?: BatchLimits | ResolvedBatchLimits\n): BuiltRequest[] => {\n const limits = resolveBatchLimits(rawLimits);\n if (requests.length > limits.maxRequests) {\n throw new BatchworkError(\n `batchwork: requests length ${requests.length} exceeds the ${limits.maxRequests} request limit.`\n );\n }\n return assignCustomIds(requests).map((item) => {\n const body = transcriptionBody(\n resolved,\n mergeDefaults(item.request, defaults)\n );\n assertByteLength(\n `request \"${item.customId}\"`,\n JSON.stringify(body),\n limits.maxRequestBytes\n );\n return { body, customId: item.customId, endpoint };\n });\n};\n\n/**\n * Build provider transcription request bodies for every batch item. Each item\n * maps to a single transcription of a hosted audio URL, correlated by\n * `customId`.\n */\nexport const buildTranscriptionBodies = (\n resolved: ResolvedModel,\n requests: readonly BatchTranscriptionRequest[],\n defaults: BatchTranscriptionDefaults | undefined,\n rawLimits?: BatchLimits | ResolvedBatchLimits\n): BuiltRequest[] =>\n buildAudioBodies(\n resolved,\n requests,\n defaults,\n TRANSCRIPTION_ENDPOINT,\n rawLimits\n );\n\n/**\n * Build provider audio-translation request bodies for every batch item. The\n * body shape is identical to transcription (minus `language` — the output is\n * always English); only the endpoint differs.\n */\nexport const buildTranslationBodies = (\n resolved: ResolvedModel,\n requests: readonly BatchTranslationRequest[],\n defaults: BatchTranslationDefaults | undefined,\n rawLimits?: BatchLimits | ResolvedBatchLimits\n): BuiltRequest[] =>\n buildAudioBodies(\n resolved,\n requests,\n defaults,\n \"/v1/audio/translations\",\n rawLimits\n );\n\n/**\n * Derive provider image-generation request bodies for every batch item by\n * running each through the AI SDK `generateImage` with a capturing `fetch`.\n * Mirrors {@link buildRequestBodies} for the image endpoint; each item maps to a\n * single image-generation call, correlated by `customId`.\n */\nexport const buildImageBodies = async (\n resolved: ResolvedModel,\n requests: readonly BatchImageRequest[],\n defaults: BatchImageDefaults | undefined,\n credentials: ProviderCredentials,\n rawLimits?: BatchLimits | ResolvedBatchLimits\n): Promise<BuiltRequest[]> => {\n const limits = resolveBatchLimits(rawLimits);\n if (requests.length > limits.maxRequests) {\n throw new BatchworkError(\n `batchwork: requests length ${requests.length} exceeds the ${limits.maxRequests} request limit.`\n );\n }\n const model = await createCaptureImageModel(\n resolved,\n credentials,\n captureFetch\n );\n const items = assignCustomIds(requests);\n\n return await pMap(\n items,\n async (item) => {\n const built = await captureImageOne(\n model,\n mergeDefaults(item.request, defaults),\n item.customId,\n limits.maxRequestBytes\n );\n assertByteLength(\n `request \"${item.customId}\"`,\n JSON.stringify(built.body),\n limits.maxRequestBytes\n );\n return built;\n },\n { concurrency: limits.captureConcurrency }\n );\n};\n\nconst IMAGE_EDIT_ENDPOINT = \"/v1/images/edits\";\n\nconst openaiImageRef = (ref: BatchImageRef): Record<string, string> =>\n \"fileId\" in ref ? { file_id: ref.fileId } : { image_url: ref.imageUrl };\n\n/**\n * Build the provider image-edit body directly — the AI SDK's `generateImage`\n * has no way to pass input images, so there is no call to capture. Both\n * providers take JSON with asset references: OpenAI `{ images: [{ file_id |\n * image_url }], mask? }`, xAI `{ image: { url } }` (URLs only, no masks).\n */\nconst imageEditBody = (\n resolved: ResolvedModel,\n request: BatchImageEditRequest,\n customId: string\n): Record<string, unknown> => {\n if (request.images.length === 0) {\n throw new BatchworkError(\n `batchwork: image-edit request \"${customId}\" needs at least one entry in \\`images\\`.`\n );\n }\n const options = request.providerOptions?.[resolved.provider];\n if (resolved.provider === \"openai\") {\n return {\n images: request.images.map(openaiImageRef),\n model: resolved.modelId,\n prompt: request.prompt,\n ...(request.mask ? { mask: openaiImageRef(request.mask) } : {}),\n ...(request.n === undefined ? {} : { n: request.n }),\n ...(request.size ? { size: request.size } : {}),\n ...options,\n };\n }\n if (resolved.provider === \"xai\") {\n if (request.mask) {\n throw new BatchworkError(\n `batchwork: image-edit request \"${customId}\" has a \\`mask\\`, but xAI image edits do not support masks.`\n );\n }\n if (request.size) {\n throw new BatchworkError(\n `batchwork: image-edit request \"${customId}\" has \\`size\\`, but xAI image edits take \\`providerOptions.xai.aspect_ratio\\` instead.`\n );\n }\n const urls = request.images.map((ref) => {\n if (\"fileId\" in ref) {\n throw new BatchworkError(\n `batchwork: image-edit request \"${customId}\" uses a \\`fileId\\` reference, but xAI image edits accept image URLs only.`\n );\n }\n return ref.imageUrl;\n });\n return {\n model: resolved.modelId,\n prompt: request.prompt,\n ...(urls.length === 1\n ? { image: { url: urls[0] } }\n : { images: urls.map((url) => ({ url })) }),\n ...(request.n === undefined ? {} : { n: request.n }),\n ...options,\n };\n }\n throw unsupportedImageEditProvider(resolved.provider);\n};\n\n/**\n * Build provider image-edit request bodies for every batch item. Each item\n * maps to a single edit call, correlated by `customId`.\n */\nexport const buildImageEditBodies = (\n resolved: ResolvedModel,\n requests: readonly BatchImageEditRequest[],\n defaults: BatchImageEditDefaults | undefined,\n rawLimits?: BatchLimits | ResolvedBatchLimits\n): BuiltRequest[] => {\n const limits = resolveBatchLimits(rawLimits);\n if (requests.length > limits.maxRequests) {\n throw new BatchworkError(\n `batchwork: requests length ${requests.length} exceeds the ${limits.maxRequests} request limit.`\n );\n }\n return assignCustomIds(requests).map((item) => {\n const body = imageEditBody(\n resolved,\n mergeDefaults(item.request, defaults),\n item.customId\n );\n assertByteLength(\n `request \"${item.customId}\"`,\n JSON.stringify(body),\n limits.maxRequestBytes\n );\n return { body, customId: item.customId, endpoint: IMAGE_EDIT_ENDPOINT };\n });\n};\n\nconst captureVideoOne = async (\n model: VideoModel,\n request: BatchVideoRequest,\n customId: string,\n maxRequestBytes: number\n): Promise<BuiltRequest> => {\n try {\n // The provider's first network call is the JSON job-creation POST (polling\n // only starts afterwards), so the capturing `fetch` intercepts the exact\n // body a batch line needs. Edit/extend modes (via `providerOptions`) are\n // captured against their own endpoints, which xAI batch also accepts.\n await experimental_generateVideo({\n aspectRatio: request.aspectRatio,\n duration: request.duration,\n // `maxRetries: 0` is load-bearing: with retries enabled the capture error\n // is wrapped in a `RetryError` (under `.errors`, not `.cause`) and\n // `findCapture`'s cause walk would miss it.\n maxRetries: 0,\n model,\n prompt: request.prompt,\n providerOptions: request.providerOptions,\n resolution: request.resolution,\n });\n } catch (error) {\n return bodyFromCapture(error, customId, maxRequestBytes);\n }\n throw new BatchworkError(\n \"batchwork: the request was not intercepted while building the video body.\"\n );\n};\n\n/**\n * Derive provider video-generation request bodies for every batch item by\n * running each through the AI SDK `generateVideo` with a capturing `fetch`.\n * Mirrors {@link buildRequestBodies} for the video endpoints; each item maps to\n * a single video job, correlated by `customId`.\n */\nexport const buildVideoBodies = async (\n resolved: ResolvedModel,\n requests: readonly BatchVideoRequest[],\n defaults: BatchVideoDefaults | undefined,\n credentials: ProviderCredentials,\n rawLimits?: BatchLimits | ResolvedBatchLimits\n): Promise<BuiltRequest[]> => {\n const limits = resolveBatchLimits(rawLimits);\n if (requests.length > limits.maxRequests) {\n throw new BatchworkError(\n `batchwork: requests length ${requests.length} exceeds the ${limits.maxRequests} request limit.`\n );\n }\n const model = await createCaptureVideoModel(\n resolved,\n credentials,\n captureFetch\n );\n const items = assignCustomIds(requests);\n\n return await pMap(\n items,\n async (item) => {\n const built = await captureVideoOne(\n model,\n mergeDefaults(item.request, defaults),\n item.customId,\n limits.maxRequestBytes\n );\n assertByteLength(\n `request \"${item.customId}\"`,\n JSON.stringify(built.body),\n limits.maxRequestBytes\n );\n return built;\n },\n { concurrency: limits.captureConcurrency }\n );\n};\n",
7
+ "import {\n buildEmbeddingBodies,\n buildImageBodies,\n buildImageEditBodies,\n buildModerationBodies,\n buildRequestBodies,\n buildTranscriptionBodies,\n buildTranslationBodies,\n buildVideoBodies,\n} from \"./body\";\nimport { BatchworkError } from \"./errors\";\nimport { BatchJob } from \"./job\";\nimport { resolveBatchLimits } from \"./limits\";\nimport {\n EMBEDDING_PROVIDERS,\n IMAGE_EDIT_PROVIDERS,\n IMAGE_PROVIDERS,\n MODERATION_PROVIDERS,\n resolveModel,\n TRANSCRIPTION_PROVIDERS,\n TRANSLATION_PROVIDERS,\n unsupportedEmbeddingProvider,\n unsupportedImageEditProvider,\n unsupportedImageProvider,\n unsupportedModerationProvider,\n unsupportedTranscriptionProvider,\n unsupportedTranslationProvider,\n unsupportedVideoProvider,\n VIDEO_PROVIDERS,\n} from \"./model\";\nimport { getAdapter } from \"./providers\";\nimport type {\n BatchEmbeddingsOptions,\n BatchImageEditOptions,\n BatchImageOptions,\n BatchModerationOptions,\n BatchOptions,\n BatchProvider,\n BatchRef,\n BatchResult,\n BatchTranscriptionOptions,\n BatchTranslationOptions,\n BatchVideoOptions,\n ProviderCredentials,\n} from \"./types\";\n\nconst EMPTY_REQUESTS_MESSAGE = \"batchwork: `requests` must not be empty.\";\n\nconst pickCredentials = (source: ProviderCredentials): ProviderCredentials => ({\n apiKey: source.apiKey,\n baseURL: source.baseURL,\n headers: source.headers,\n});\n\nconst providerFromRef = (ref: BatchRef): BatchProvider => {\n if (ref.provider) {\n return ref.provider;\n }\n if (ref.model !== undefined) {\n return resolveModel(ref.model).provider;\n }\n throw new BatchworkError(\n \"batchwork: provide `provider` or `model` to identify the batch.\"\n );\n};\n\n/**\n * Submit a batch of text/chat requests to the model's provider and return a\n * handle. Reachable as both `batch()` (shorthand) and `batch.text()`.\n *\n * Resolves immediately once the batch is accepted — it does not wait for\n * processing. Use the returned {@link BatchJob} to poll, wait, or stream\n * results.\n *\n * @example\n * const job = await batch({\n * model: openai(\"gpt-5.5\"),\n * requests: [{ customId: \"a\", prompt: \"Say hi\" }],\n * });\n * const results = await job.wait().then(() => job.collect());\n */\nconst submitText = async (options: BatchOptions): Promise<BatchJob> => {\n if (options.requests.length === 0) {\n throw new BatchworkError(EMPTY_REQUESTS_MESSAGE);\n }\n\n const resolved = resolveModel(options.model);\n const credentials = pickCredentials(options);\n const limits = resolveBatchLimits(options.limits);\n const adapter = getAdapter(resolved.provider);\n\n const built = await buildRequestBodies(\n resolved,\n options.requests,\n options.defaults,\n credentials,\n limits\n );\n const snapshot = await adapter.submit({\n built,\n credentials,\n endpoint: built[0]?.endpoint ?? \"\",\n limits,\n metadata: options.metadata,\n modelId: resolved.modelId,\n });\n\n return new BatchJob(adapter, credentials, snapshot);\n};\n\n/**\n * Submit a batch of embedding requests to the model's provider and return a\n * handle. Each request's `value` produces one vector, correlated by `customId`\n * via {@link BatchJob.results}. Supported for OpenAI, Mistral, Together, and\n * Google; other providers throw {@link UnsupportedProviderError}.\n *\n * @example\n * const job = await batch.embeddings({\n * model: openai.embeddingModel(\"text-embedding-3-small\"),\n * requests: [{ customId: \"a\", value: \"hello world\" }],\n * });\n * const results = await job.wait().then(() => job.collect());\n * for (const r of results) {\n * console.log(r.customId, r.embedding?.length);\n * }\n */\nconst submitEmbeddings = async (\n options: BatchEmbeddingsOptions\n): Promise<BatchJob> => {\n if (options.requests.length === 0) {\n throw new BatchworkError(EMPTY_REQUESTS_MESSAGE);\n }\n\n const resolved = resolveModel(options.model);\n if (!EMBEDDING_PROVIDERS.has(resolved.provider)) {\n throw unsupportedEmbeddingProvider(resolved.provider);\n }\n const credentials = pickCredentials(options);\n const limits = resolveBatchLimits(options.limits);\n const adapter = getAdapter(resolved.provider);\n\n const built = await buildEmbeddingBodies(\n resolved,\n options.requests,\n credentials,\n limits\n );\n const snapshot = await adapter.submit({\n built,\n credentials,\n endpoint: built[0]?.endpoint ?? \"\",\n limits,\n metadata: options.metadata,\n modelId: resolved.modelId,\n });\n\n return new BatchJob(adapter, credentials, snapshot);\n};\n\n/**\n * Submit a batch of image-generation requests to the model's provider and\n * return a handle. Each request's `prompt` produces one or more images,\n * correlated by `customId` via {@link BatchJob.results}. Supported for OpenAI\n * and Google; other providers throw {@link UnsupportedProviderError}.\n *\n * @example\n * const job = await batch.images({\n * model: openai.image(\"gpt-image-2\"),\n * requests: [{ customId: \"a\", prompt: \"a red bicycle\" }],\n * });\n * const results = await job.wait().then(() => job.collect());\n * for (const r of results) {\n * console.log(r.customId, r.images?.length);\n * }\n */\nconst submitImages = async (options: BatchImageOptions): Promise<BatchJob> => {\n if (options.requests.length === 0) {\n throw new BatchworkError(EMPTY_REQUESTS_MESSAGE);\n }\n\n const resolved = resolveModel(options.model);\n if (!IMAGE_PROVIDERS.has(resolved.provider)) {\n throw unsupportedImageProvider(resolved.provider);\n }\n const credentials = pickCredentials(options);\n const limits = resolveBatchLimits(options.limits);\n const adapter = getAdapter(resolved.provider);\n\n const built = await buildImageBodies(\n resolved,\n options.requests,\n options.defaults,\n credentials,\n limits\n );\n const snapshot = await adapter.submit({\n built,\n credentials,\n endpoint: built[0]?.endpoint ?? \"\",\n limits,\n metadata: options.metadata,\n modelId: resolved.modelId,\n });\n\n return new BatchJob(adapter, credentials, snapshot);\n};\n\n/**\n * Submit a batch of image-edit requests to the model's provider and return a\n * handle. Each request's `prompt` is applied to its source `images` (uploaded\n * file ids or hosted URLs — batch bodies are JSON, so raw uploads aren't\n * possible), producing edited images on `result.images`, correlated by\n * `customId` via {@link BatchJob.results}. Supported for OpenAI and xAI; other\n * providers throw {@link UnsupportedProviderError}.\n *\n * @example\n * const job = await batch.images.edit({\n * model: openai.image(\"gpt-image-2\"),\n * requests: [\n * {\n * customId: \"a\",\n * prompt: \"Make the bicycle blue.\",\n * images: [{ imageUrl: \"https://example.com/bicycle.png\" }],\n * },\n * ],\n * });\n * const results = await job.wait().then(() => job.collect());\n */\nconst submitImageEdits = async (\n options: BatchImageEditOptions\n): Promise<BatchJob> => {\n if (options.requests.length === 0) {\n throw new BatchworkError(EMPTY_REQUESTS_MESSAGE);\n }\n\n const resolved = resolveModel(options.model);\n if (!IMAGE_EDIT_PROVIDERS.has(resolved.provider)) {\n throw unsupportedImageEditProvider(resolved.provider);\n }\n const credentials = pickCredentials(options);\n const limits = resolveBatchLimits(options.limits);\n const adapter = getAdapter(resolved.provider);\n\n const built = buildImageEditBodies(\n resolved,\n options.requests,\n options.defaults,\n limits\n );\n const snapshot = await adapter.submit({\n built,\n credentials,\n endpoint: built[0]?.endpoint ?? \"\",\n limits,\n metadata: options.metadata,\n modelId: resolved.modelId,\n });\n\n return new BatchJob(adapter, credentials, snapshot);\n};\n\n/**\n * Submit a batch of moderation requests to the model's provider and return a\n * handle. Each request's `value` (and/or `imageUrls`, OpenAI omni moderation\n * only) produces one verdict on `result.moderation`, correlated by `customId`\n * via {@link BatchJob.results}. Supported for OpenAI and Mistral; other\n * providers throw {@link UnsupportedProviderError}. Pass the model as a\n * `\"provider/model\"` string — the AI SDK has no moderation model type.\n *\n * @example\n * const job = await batch.moderations({\n * model: \"openai/omni-moderation-latest\",\n * requests: [{ customId: \"a\", value: \"…user-generated content…\" }],\n * });\n * const results = await job.wait().then(() => job.collect());\n * for (const r of results) {\n * console.log(r.customId, r.moderation?.flagged);\n * }\n */\nconst submitModerations = async (\n options: BatchModerationOptions\n): Promise<BatchJob> => {\n if (options.requests.length === 0) {\n throw new BatchworkError(EMPTY_REQUESTS_MESSAGE);\n }\n\n const resolved = resolveModel(options.model);\n if (!MODERATION_PROVIDERS.has(resolved.provider)) {\n throw unsupportedModerationProvider(resolved.provider);\n }\n const credentials = pickCredentials(options);\n const limits = resolveBatchLimits(options.limits);\n const adapter = getAdapter(resolved.provider);\n\n const built = buildModerationBodies(resolved, options.requests, limits);\n const snapshot = await adapter.submit({\n built,\n credentials,\n endpoint: built[0]?.endpoint ?? \"\",\n limits,\n metadata: options.metadata,\n modelId: resolved.modelId,\n });\n\n return new BatchJob(adapter, credentials, snapshot);\n};\n\n/**\n * Submit a batch of audio-transcription requests to the model's provider and\n * return a handle. Each request's `audioUrl` (a hosted audio file — batch\n * audio endpoints accept URLs, not file uploads) produces one transcript,\n * correlated by `customId` via {@link BatchJob.results}. Supported for Groq\n * and Mistral; other providers throw {@link UnsupportedProviderError}.\n *\n * @example\n * const job = await batch.transcriptions({\n * model: groq.transcription(\"whisper-large-v3\"),\n * requests: [{ customId: \"a\", audioUrl: \"https://example.com/call.wav\" }],\n * });\n * const results = await job.wait().then(() => job.collect());\n * for (const r of results) {\n * console.log(r.customId, r.text);\n * }\n */\nconst submitTranscriptions = async (\n options: BatchTranscriptionOptions\n): Promise<BatchJob> => {\n if (options.requests.length === 0) {\n throw new BatchworkError(EMPTY_REQUESTS_MESSAGE);\n }\n\n const resolved = resolveModel(options.model);\n if (!TRANSCRIPTION_PROVIDERS.has(resolved.provider)) {\n throw unsupportedTranscriptionProvider(resolved.provider);\n }\n const credentials = pickCredentials(options);\n const limits = resolveBatchLimits(options.limits);\n const adapter = getAdapter(resolved.provider);\n\n const built = buildTranscriptionBodies(\n resolved,\n options.requests,\n options.defaults,\n limits\n );\n const snapshot = await adapter.submit({\n built,\n credentials,\n endpoint: built[0]?.endpoint ?? \"\",\n limits,\n metadata: options.metadata,\n modelId: resolved.modelId,\n });\n\n return new BatchJob(adapter, credentials, snapshot);\n};\n\n/**\n * Submit a batch of video-generation requests to the model's provider and\n * return a handle. Each request's `prompt` produces one video, correlated by\n * `customId` via {@link BatchJob.results}. Supported for xAI (Grok Imagine);\n * other providers throw {@link UnsupportedProviderError} — OpenAI's Videos API\n * (Sora) is deprecated and Google's Veo models are not batch-compatible.\n *\n * Results come back as signed URLs on `result.videos` that **expire ~1h**\n * after completion — download promptly.\n *\n * @example\n * const job = await batch.videos({\n * model: xai.video(\"grok-imagine-video\"),\n * requests: [{ customId: \"a\", prompt: \"A red bicycle rolling downhill.\" }],\n * });\n * const results = await job.wait().then(() => job.collect());\n * for (const r of results) {\n * console.log(r.customId, r.videos?.[0]?.url);\n * }\n */\nconst submitVideos = async (options: BatchVideoOptions): Promise<BatchJob> => {\n if (options.requests.length === 0) {\n throw new BatchworkError(EMPTY_REQUESTS_MESSAGE);\n }\n\n const resolved = resolveModel(options.model);\n if (!VIDEO_PROVIDERS.has(resolved.provider)) {\n throw unsupportedVideoProvider(resolved.provider);\n }\n const credentials = pickCredentials(options);\n const limits = resolveBatchLimits(options.limits);\n const adapter = getAdapter(resolved.provider);\n\n const built = await buildVideoBodies(\n resolved,\n options.requests,\n options.defaults,\n credentials,\n limits\n );\n const snapshot = await adapter.submit({\n built,\n credentials,\n endpoint: built[0]?.endpoint ?? \"\",\n limits,\n metadata: options.metadata,\n modelId: resolved.modelId,\n });\n\n return new BatchJob(adapter, credentials, snapshot);\n};\n\n/**\n * Submit a batch of audio-translation requests (Whisper's translate task —\n * audio in any language, English text out) and return a handle. Mirrors\n * {@link batch.transcriptions} minus `language`: each request's `audioUrl`\n * produces one English transcript on `result.text`, correlated by `customId`.\n * Supported for Groq and Together; other providers throw\n * {@link UnsupportedProviderError} — Mistral batches transcriptions but not\n * translations.\n *\n * @example\n * const job = await batch.translations({\n * model: groq.transcription(\"whisper-large-v3\"),\n * requests: [{ customId: \"a\", audioUrl: \"https://example.com/french.wav\" }],\n * });\n * const results = await job.wait().then(() => job.collect());\n */\nconst submitTranslations = async (\n options: BatchTranslationOptions\n): Promise<BatchJob> => {\n if (options.requests.length === 0) {\n throw new BatchworkError(EMPTY_REQUESTS_MESSAGE);\n }\n\n const resolved = resolveModel(options.model);\n if (!TRANSLATION_PROVIDERS.has(resolved.provider)) {\n throw unsupportedTranslationProvider(resolved.provider);\n }\n const credentials = pickCredentials(options);\n const limits = resolveBatchLimits(options.limits);\n const adapter = getAdapter(resolved.provider);\n\n const built = buildTranslationBodies(\n resolved,\n options.requests,\n options.defaults,\n limits\n );\n const snapshot = await adapter.submit({\n built,\n credentials,\n endpoint: built[0]?.endpoint ?? \"\",\n limits,\n metadata: options.metadata,\n modelId: resolved.modelId,\n });\n\n return new BatchJob(adapter, credentials, snapshot);\n};\n\n/**\n * Submit a batch of requests and return a {@link BatchJob} handle.\n *\n * Callable directly as a shorthand for text/chat batches, with one method per\n * modality:\n *\n * - `batch()` / {@link batch.text} — text & chat completions\n * - {@link batch.embeddings} — embedding vectors\n * - {@link batch.images} / {@link batch.images.create} — image generation\n * - {@link batch.images.edit} — image editing\n * - {@link batch.transcriptions} — audio transcription\n * - {@link batch.translations} — audio translation to English\n * - {@link batch.moderations} — content moderation\n * - {@link batch.videos} — video generation\n *\n * @example\n * const job = await batch({\n * model: openai(\"gpt-5.5\"),\n * requests: [{ customId: \"a\", prompt: \"Say hi\" }],\n * });\n */\nexport const batch = Object.assign(submitText, {\n /** Submit a batch of embedding requests. */\n embeddings: submitEmbeddings,\n /**\n * Submit a batch of image-generation requests. Also exposes\n * {@link batch.images.create} (an alias of calling it directly) and\n * {@link batch.images.edit} for editing existing images.\n */\n images: Object.assign(submitImages, {\n /** Submit a batch of image-generation requests. Equivalent to `batch.images()`. */\n create: submitImages,\n /** Submit a batch of image-edit requests. */\n edit: submitImageEdits,\n }),\n /** Submit a batch of moderation requests. */\n moderations: submitModerations,\n /** Submit a batch of text/chat requests. Equivalent to calling `batch()`. */\n text: submitText,\n /** Submit a batch of audio-transcription requests. */\n transcriptions: submitTranscriptions,\n /** Submit a batch of audio-translation (to English) requests. */\n translations: submitTranslations,\n /** Submit a batch of video-generation requests. */\n videos: submitVideos,\n});\n\n/**\n * @deprecated Use {@link batch.embeddings} instead. Kept as a standalone alias\n * for backward compatibility; it will be removed in a future major.\n */\nexport const batchEmbeddings = submitEmbeddings;\n\n/**\n * @deprecated Use {@link batch.images} instead. Kept as a standalone alias for\n * backward compatibility; it will be removed in a future major.\n */\nexport const batchImages = submitImages;\n\n/**\n * Rehydrate a {@link BatchJob} for an existing batch id (e.g. one persisted\n * after submission). Identify the provider with `provider` or `model`.\n */\nexport const getBatch = async (ref: BatchRef): Promise<BatchJob> => {\n const adapter = getAdapter(providerFromRef(ref));\n const credentials = pickCredentials(ref);\n const snapshot = await adapter.retrieve(ref.id, credentials);\n return new BatchJob(adapter, credentials, snapshot);\n};\n\n/** Stream the results of an existing batch by id, without a handle. */\nexport const getBatchResults = (ref: BatchRef): AsyncGenerator<BatchResult> => {\n const adapter = getAdapter(providerFromRef(ref));\n return adapter.results(ref.id, pickCredentials(ref));\n};\n\n/** Request cancellation of an existing batch by id. */\nexport const cancelBatch = async (ref: BatchRef): Promise<void> => {\n const adapter = getAdapter(providerFromRef(ref));\n await adapter.cancel(ref.id, pickCredentials(ref));\n};\n"
8
+ ],
9
+ "mappings": "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",
10
+ "debugId": "BF4E08ACD1170D0064756E2164756E21",
11
+ "names": []
12
+ }
@@ -2,7 +2,7 @@ import {
2
2
  BatchworkError,
3
3
  getAdapter,
4
4
  isTerminalStatus
5
- } from "./chunk-gwa0dkhj.js";
5
+ } from "./chunk-n50t31ca.js";
6
6
 
7
7
  // src/server/events.ts
8
8
  var EVENT_BY_STATUS = {
@@ -21,10 +21,11 @@ var toEvent = (provider, snapshot) => ({
21
21
  });
22
22
 
23
23
  // src/server/signing.ts
24
- var SIGNATURE_VERSION = "v1";
24
+ import { Webhook, WebhookVerificationError } from "standardwebhooks";
25
25
  var TOLERANCE_SECONDS = 300;
26
26
  var SECRET_PREFIX = "whsec_";
27
27
  var encoder = new TextEncoder;
28
+ var createWebhook = (secret) => secret.startsWith(SECRET_PREFIX) ? new Webhook(secret) : new Webhook(encoder.encode(secret), { format: "raw" });
28
29
  var replayCache = new Map;
29
30
  var replayLocks = new WeakMap;
30
31
  var pruneReplayCache = (now) => {
@@ -73,27 +74,6 @@ var withReplayLock = async (store, id, task) => {
73
74
  }
74
75
  }
75
76
  };
76
- var base64ToBytes = (value) => Uint8Array.from(atob(value), (char) => char.codePointAt(0) ?? 0);
77
- var bytesToBase64 = (bytes) => {
78
- let binary = "";
79
- for (const byte of bytes) {
80
- binary += String.fromCodePoint(byte);
81
- }
82
- return btoa(binary);
83
- };
84
- var importKey = (secret) => {
85
- const raw = secret.startsWith(SECRET_PREFIX) ? base64ToBytes(secret.slice(SECRET_PREFIX.length)) : encoder.encode(secret);
86
- return crypto.subtle.importKey("raw", raw, { hash: "SHA-256", name: "HMAC" }, false, ["sign", "verify"]);
87
- };
88
- var signContent = async (secret, content) => {
89
- const key = await importKey(secret);
90
- const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(content));
91
- return bytesToBase64(new Uint8Array(signature));
92
- };
93
- var verifyContent = async (secret, content, signature) => {
94
- const key = await importKey(secret);
95
- return crypto.subtle.verify("HMAC", key, base64ToBytes(signature), encoder.encode(content));
96
- };
97
77
  var rememberWebhookId = async (id, timestamp, now, store) => {
98
78
  const expiresAt = timestamp + TOLERANCE_SECONDS;
99
79
  if (store.claim) {
@@ -114,14 +94,14 @@ var rememberWebhookId = async (id, timestamp, now, store) => {
114
94
  await store.set(id, expiresAt);
115
95
  });
116
96
  };
117
- var signWebhook = async (secret, id, body, timestampSeconds) => {
118
- const timestamp = Math.floor(timestampSeconds).toString();
119
- const signature = await signContent(secret, `${id}.${timestamp}.${body}`);
120
- return {
97
+ var signWebhook = (secret, id, body, timestampSeconds) => {
98
+ const timestamp = Math.floor(timestampSeconds);
99
+ const signature = createWebhook(secret).sign(id, new Date(timestamp * 1000), body);
100
+ return Promise.resolve({
121
101
  "webhook-id": id,
122
- "webhook-signature": `${SIGNATURE_VERSION},${signature}`,
123
- "webhook-timestamp": timestamp
124
- };
102
+ "webhook-signature": signature,
103
+ "webhook-timestamp": timestamp.toString()
104
+ });
125
105
  };
126
106
  var verifyWebhook = async (request, secret, options) => {
127
107
  const id = request.headers.get("webhook-id");
@@ -136,21 +116,17 @@ var verifyWebhook = async (request, secret, options) => {
136
116
  throw new BatchworkError("batchwork: webhook timestamp outside tolerance.");
137
117
  }
138
118
  const body = await request.text();
139
- const content = `${id}.${timestamp}.${body}`;
140
- const signatures = signatureHeader.split(" ").map((part) => {
141
- const comma = part.indexOf(",");
142
- return comma === -1 ? part : part.slice(comma + 1);
143
- });
144
- let valid = false;
145
- for (const signature of signatures) {
146
- if (await verifyContent(secret, content, signature)) {
147
- valid = true;
148
- break;
119
+ try {
120
+ createWebhook(secret).verify(body, {
121
+ "webhook-id": id,
122
+ "webhook-signature": signatureHeader,
123
+ "webhook-timestamp": timestamp
124
+ });
125
+ } catch (error) {
126
+ if (error instanceof WebhookVerificationError) {
127
+ throw new BatchworkError(error.message.toLowerCase().includes("timestamp") ? "batchwork: webhook timestamp outside tolerance." : "batchwork: webhook signature verification failed.", { cause: error });
149
128
  }
150
129
  }
151
- if (!valid) {
152
- throw new BatchworkError("batchwork: webhook signature verification failed.");
153
- }
154
130
  await rememberWebhookId(id, seconds, now, options?.replayStore ?? defaultReplayStore);
155
131
  return { body, id, timestamp: seconds };
156
132
  };
@@ -160,83 +136,16 @@ var verifyBatchWebhook = async (request, secret, options) => {
160
136
  };
161
137
 
162
138
  // src/server/poller.ts
163
- var parseIpv4 = (host) => {
164
- if (!/^\d{1,3}(?:\.\d{1,3}){3}$/u.test(host)) {
165
- return;
166
- }
167
- const parts = host.split(".").map(Number);
168
- const valid = parts.every((part) => Number.isInteger(part) && part >= 0 && part <= 255);
169
- return valid ? parts : undefined;
170
- };
171
- var isPrivateIpv4 = (parts) => {
172
- const [a = 0, b = 0] = parts;
173
- if (a === 0 || a === 10 || a === 127 || a >= 224) {
174
- return true;
175
- }
176
- switch (a) {
177
- case 100: {
178
- return b >= 64 && b <= 127;
179
- }
180
- case 169: {
181
- return b === 254;
182
- }
183
- case 172: {
184
- return b >= 16 && b <= 31;
185
- }
186
- case 192: {
187
- return b === 168;
188
- }
189
- case 198: {
190
- return b === 18 || b === 19;
191
- }
192
- default: {
193
- return false;
194
- }
195
- }
196
- };
197
- var isHextet = (value) => Number.isInteger(value) && value >= 0 && value <= 65535;
198
- var parseIpv4MappedIpv6 = (host) => {
199
- const normalized = host.replace(/^\[/u, "").replace(/\]$/u, "").toLowerCase();
200
- if (!normalized.startsWith("::ffff:")) {
201
- return;
202
- }
203
- const suffix = normalized.slice("::ffff:".length);
204
- const dotted = parseIpv4(suffix);
205
- if (dotted) {
206
- return dotted;
207
- }
208
- const [high, low, extra] = suffix.split(":");
209
- if (!(high && low) || extra !== undefined) {
210
- return;
211
- }
212
- const highBits = Number.parseInt(high, 16);
213
- const lowBits = Number.parseInt(low, 16);
214
- if (!(isHextet(highBits) && isHextet(lowBits))) {
215
- return;
216
- }
217
- return [
218
- Math.floor(highBits / 256),
219
- highBits % 256,
220
- Math.floor(lowBits / 256),
221
- lowBits % 256
222
- ];
223
- };
224
- var isPrivateIpv6 = (host) => {
225
- const normalized = host.replace(/^\[/u, "").replace(/\]$/u, "").toLowerCase();
226
- if (!normalized.includes(":")) {
227
- return false;
228
- }
229
- if (normalized === "::" || normalized === "::1") {
230
- return true;
231
- }
232
- return normalized.startsWith("fc") || normalized.startsWith("fd") || normalized.startsWith("fe80:");
233
- };
139
+ import ipaddr from "ipaddr.js";
234
140
  var isPrivateHost = (host) => {
235
141
  if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local")) {
236
142
  return true;
237
143
  }
238
- const ipv4 = parseIpv4(host) ?? parseIpv4MappedIpv6(host);
239
- return (ipv4 ? isPrivateIpv4(ipv4) : false) || isPrivateIpv6(host);
144
+ const literal = host.replace(/^\[/u, "").replace(/\]$/u, "");
145
+ if (!ipaddr.isValid(literal)) {
146
+ return false;
147
+ }
148
+ return ipaddr.process(literal).range() !== "unicast";
240
149
  };
241
150
  var isRedirectStatus = (status) => status >= 300 && status < 400;
242
151
  var assertSafeWebhookUrl = (url) => {
@@ -401,5 +310,5 @@ var createMemoryStore = () => {
401
310
 
402
311
  export { toEvent, signWebhook, verifyWebhook, verifyBatchWebhook, createBatchPoller, createMemoryStore };
403
312
 
404
- //# debugId=F1B4BA11C9A6AE3364756E2164756E21
405
- //# sourceMappingURL=chunk-9cwfwzm4.js.map
313
+ //# debugId=CAEF2BF262DED87C64756E2164756E21
314
+ //# sourceMappingURL=chunk-mathjpg6.js.map