batchwork 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/body.d.ts +2 -2
  2. package/dist/body.d.ts.map +1 -1
  3. package/dist/chunk-6jgvqdpc.js +52 -0
  4. package/dist/chunk-6jgvqdpc.js.map +11 -0
  5. package/dist/{chunk-n50t31ca.js → chunk-7y95mhvm.js} +118 -139
  6. package/dist/chunk-7y95mhvm.js.map +27 -0
  7. package/dist/{chunk-mathjpg6.js → chunk-k7n7k3et.js} +46 -41
  8. package/dist/chunk-k7n7k3et.js.map +13 -0
  9. package/dist/{chunk-14qcscwd.js → chunk-zss8h417.js} +203 -191
  10. package/dist/chunk-zss8h417.js.map +12 -0
  11. package/dist/guards.d.ts +5 -0
  12. package/dist/guards.d.ts.map +1 -0
  13. package/dist/http.d.ts +3 -2
  14. package/dist/http.d.ts.map +1 -1
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +27 -28
  18. package/dist/index.js.map +1 -1
  19. package/dist/jsonl.d.ts +3 -2
  20. package/dist/jsonl.d.ts.map +1 -1
  21. package/dist/model.d.ts +48 -1
  22. package/dist/model.d.ts.map +1 -1
  23. package/dist/next/index.d.ts +1 -1
  24. package/dist/next/index.d.ts.map +1 -1
  25. package/dist/next/index.js +14 -20
  26. package/dist/next/index.js.map +3 -3
  27. package/dist/postgres/batch-store.d.ts.map +1 -1
  28. package/dist/postgres/index.js +22 -15
  29. package/dist/postgres/index.js.map +4 -4
  30. package/dist/postgres/types.d.ts +1 -1
  31. package/dist/postgres/types.d.ts.map +1 -1
  32. package/dist/providers/anthropic.d.ts.map +1 -1
  33. package/dist/providers/azure.d.ts.map +1 -1
  34. package/dist/providers/google.d.ts.map +1 -1
  35. package/dist/providers/mistral.d.ts.map +1 -1
  36. package/dist/providers/openai-compatible.d.ts +2 -2
  37. package/dist/providers/openai-compatible.d.ts.map +1 -1
  38. package/dist/providers/shared.d.ts +8 -8
  39. package/dist/providers/shared.d.ts.map +1 -1
  40. package/dist/providers/xai.d.ts.map +1 -1
  41. package/dist/redis/index.js +40 -6
  42. package/dist/redis/index.js.map +4 -4
  43. package/dist/redis/types.d.ts +18 -5
  44. package/dist/redis/types.d.ts.map +1 -1
  45. package/dist/server/index.js +13 -14
  46. package/dist/server/index.js.map +1 -1
  47. package/dist/server/poller.d.ts +6 -4
  48. package/dist/server/poller.d.ts.map +1 -1
  49. package/dist/server/signing.d.ts.map +1 -1
  50. package/dist/types.d.ts +16 -2
  51. package/dist/types.d.ts.map +1 -1
  52. package/dist/util.d.ts +16 -7
  53. package/dist/util.d.ts.map +1 -1
  54. package/package.json +19 -19
  55. package/dist/chunk-14qcscwd.js.map +0 -12
  56. package/dist/chunk-mathjpg6.js.map +0 -13
  57. package/dist/chunk-n50t31ca.js.map +0 -28
  58. package/dist/chunk-v0bahtg2.js +0 -7
  59. package/dist/chunk-v0bahtg2.js.map +0 -9
@@ -0,0 +1,27 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/errors.ts", "../src/job.ts", "../src/limits.ts", "../src/http.ts", "../src/jsonl.ts", "../src/payload.ts", "../src/providers/ids.ts", "../src/providers/anthropic.ts", "../src/providers/shared.ts", "../src/providers/openai-compatible.ts", "../src/providers/azure.ts", "../src/providers/google.ts", "../src/providers/groq.ts", "../src/providers/mistral.ts", "../src/providers/openai.ts", "../src/providers/together.ts", "../src/providers/xai.ts", "../src/providers/index.ts"],
4
+ "sourcesContent": [
5
+ "// oxlint-disable max-classes-per-file -- the error hierarchy is co-located by design.\n\n/** Base error for all batchwork failures. */\nexport class BatchworkError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = \"BatchworkError\";\n }\n}\n\n/** Thrown when a model resolves to a provider without a batch adapter. */\nexport class UnsupportedProviderError extends BatchworkError {\n readonly provider: string;\n\n constructor(provider: string, detail?: string) {\n super(\n detail ??\n `batchwork: provider \"${provider}\" is not supported yet. Supported providers: openai, azure, anthropic, google, groq, mistral, together, xai.`\n );\n this.name = \"UnsupportedProviderError\";\n this.provider = provider;\n }\n}\n\n/** Thrown when an optional provider package is not installed. */\nexport class MissingDependencyError extends BatchworkError {\n constructor(pkg: string, provider: string) {\n super(\n `batchwork: install \\`${pkg}\\` to batch ${provider} models (\\`npm install ${pkg}\\`).`\n );\n this.name = \"MissingDependencyError\";\n }\n}\n",
6
+ "import { BatchworkError } from \"./errors\";\nimport type { BatchAdapter } from \"./providers/adapter\";\nimport type {\n BatchProvider,\n BatchRequestCounts,\n BatchResult,\n BatchSnapshot,\n BatchStatus,\n ProviderCredentials,\n WaitOptions,\n} from \"./types\";\n\nconst WAIT_ABORTED_MESSAGE = \"batchwork: wait aborted.\";\nconst DEFAULT_POLL_INTERVAL_MS = 15_000;\n\nconst TERMINAL_STATUSES: ReadonlySet<BatchStatus> = new Set<BatchStatus>([\n \"completed\",\n \"failed\",\n \"expired\",\n \"cancelled\",\n]);\n\n/** Whether a status means the batch has finished processing. */\nexport const isTerminalStatus = (status: BatchStatus): boolean =>\n TERMINAL_STATUSES.has(status);\n\nconst delay = (ms: number, signal?: AbortSignal): Promise<void> =>\n // oxlint-disable-next-line promise/avoid-new -- wrapping the callback-based setTimeout.\n new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new BatchworkError(WAIT_ABORTED_MESSAGE));\n return;\n }\n // oxlint-disable-next-line prefer-const -- assigned below, after `onAbort` closes over it.\n let timer: ReturnType<typeof setTimeout>;\n const onAbort = (): void => {\n clearTimeout(timer);\n reject(new BatchworkError(WAIT_ABORTED_MESSAGE));\n };\n timer = setTimeout(() => {\n // Detach so a reused signal (one per poll across a long wait) doesn't\n // accumulate listeners that only fire on abort.\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n\n/**\n * A handle to a submitted batch. Returned by `batch()` and `getBatch()`. Use it\n * to poll status, wait for completion, stream results, or cancel.\n */\nexport class BatchJob {\n readonly provider: BatchProvider;\n readonly id: string;\n\n readonly #adapter: BatchAdapter;\n readonly #credentials: ProviderCredentials;\n #snapshot: BatchSnapshot;\n\n constructor(\n adapter: BatchAdapter,\n credentials: ProviderCredentials,\n snapshot: BatchSnapshot\n ) {\n this.#adapter = adapter;\n this.#credentials = credentials;\n this.#snapshot = snapshot;\n this.id = snapshot.id;\n this.provider = snapshot.provider;\n }\n\n /** The most recently observed status. */\n get status(): BatchStatus {\n return this.#snapshot.status;\n }\n\n /** The most recently observed per-request tallies. */\n get requestCounts(): BatchRequestCounts {\n return this.#snapshot.requestCounts;\n }\n\n /** The most recently observed snapshot. */\n get snapshot(): BatchSnapshot {\n return this.#snapshot;\n }\n\n /** Refresh the status from the provider and return the new snapshot. */\n async poll(): Promise<BatchSnapshot> {\n this.#snapshot = await this.#adapter.retrieve(this.id, this.#credentials);\n return this.#snapshot;\n }\n\n /** Poll until the batch reaches a terminal status, then return the snapshot. */\n async wait(options: WaitOptions = {}): Promise<BatchSnapshot> {\n const interval = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;\n const deadline = options.timeoutMs\n ? Date.now() + options.timeoutMs\n : undefined;\n\n let snapshot = await this.poll();\n options.onPoll?.(snapshot);\n\n while (!isTerminalStatus(snapshot.status)) {\n if (options.signal?.aborted) {\n throw new BatchworkError(WAIT_ABORTED_MESSAGE);\n }\n if (deadline !== undefined && Date.now() > deadline) {\n throw new BatchworkError(\n `batchwork: timed out waiting for batch \"${this.id}\".`\n );\n }\n // oxlint-disable-next-line no-await-in-loop, react-doctor/async-await-in-loop -- polling is inherently sequential.\n await delay(interval, options.signal);\n // oxlint-disable-next-line no-await-in-loop, react-doctor/async-await-in-loop -- polling is inherently sequential.\n snapshot = await this.poll();\n options.onPoll?.(snapshot);\n }\n\n return snapshot;\n }\n\n /** Stream normalized results as they are read. Order is not guaranteed. */\n results(): AsyncGenerator<BatchResult> {\n return this.#adapter.results(this.id, this.#credentials);\n }\n\n /** Collect all results into an array, keyed by `customId`. */\n async collect(): Promise<BatchResult[]> {\n const out: BatchResult[] = [];\n for await (const result of this.results()) {\n out.push(result);\n }\n return out;\n }\n\n /** Request cancellation, then refresh status. */\n async cancel(): Promise<BatchSnapshot> {\n await this.#adapter.cancel(this.id, this.#credentials);\n return await this.poll();\n }\n}\n",
7
+ "import { BatchworkError } from \"./errors\";\nimport type { BatchLimits } from \"./types\";\n\nexport interface ResolvedBatchLimits {\n captureConcurrency: number;\n maxRequests: number;\n maxRequestBytes: number;\n maxUploadBytes: number;\n}\n\nconst DEFAULT_LIMITS: ResolvedBatchLimits = {\n captureConcurrency: 16,\n maxRequestBytes: 20 * 1024 * 1024,\n maxRequests: 50_000,\n maxUploadBytes: 200 * 1024 * 1024,\n};\n\nconst encoder = new TextEncoder();\n\nconst positiveInteger = (name: string, value: number): number => {\n if (!(Number.isInteger(value) && value > 0)) {\n throw new BatchworkError(\n `batchwork: limits.${name} must be a positive integer.`\n );\n }\n return value;\n};\n\nexport const resolveBatchLimits = (\n limits: BatchLimits | undefined\n): ResolvedBatchLimits => ({\n captureConcurrency: positiveInteger(\n \"captureConcurrency\",\n limits?.captureConcurrency ?? DEFAULT_LIMITS.captureConcurrency\n ),\n maxRequestBytes: positiveInteger(\n \"maxRequestBytes\",\n limits?.maxRequestBytes ?? DEFAULT_LIMITS.maxRequestBytes\n ),\n maxRequests: positiveInteger(\n \"maxRequests\",\n limits?.maxRequests ?? DEFAULT_LIMITS.maxRequests\n ),\n maxUploadBytes: positiveInteger(\n \"maxUploadBytes\",\n limits?.maxUploadBytes ?? DEFAULT_LIMITS.maxUploadBytes\n ),\n});\n\nexport const byteLength = (value: string): number =>\n encoder.encode(value).length;\n\nexport const assertByteCount = (\n label: string,\n bytes: number,\n maxBytes: number\n): void => {\n if (bytes > maxBytes) {\n throw new BatchworkError(\n `batchwork: ${label} is ${bytes} bytes, exceeding the ${maxBytes} byte limit.`\n );\n }\n};\n\nexport const assertByteLength = (\n label: string,\n value: string,\n maxBytes: number\n): void => {\n assertByteCount(label, byteLength(value), maxBytes);\n};\n",
8
+ "import { BatchworkError } from \"./errors\";\nimport type { JsonValue } from \"./types\";\nimport { parseJson } from \"./util\";\n\nconst assertOk = (url: string, init: RequestInit, response: Response) => {\n if (!response.ok) {\n throw new BatchworkError(\n `batchwork: ${init.method ?? \"GET\"} ${url} failed with ${response.status}.`\n );\n }\n};\n\n/** Make a request and parse its JSON response body, throwing on non-2xx. */\nexport const requestJson = async (\n url: string,\n init: RequestInit\n): Promise<JsonValue> => {\n const response = await fetch(url, init);\n assertOk(url, init, response);\n return parseJson(await response.text());\n};\n\n/** Make a request and return the raw body stream, throwing on non-2xx. */\nexport const requestStream = async (\n url: string,\n init: RequestInit\n): Promise<ReadableStream<Uint8Array>> => {\n const response = await fetch(url, init);\n assertOk(url, init, response);\n if (!response.body) {\n throw new BatchworkError(`batchwork: ${url} returned an empty body.`);\n }\n return response.body;\n};\n",
9
+ "import { BatchworkError } from \"./errors\";\nimport { assertByteCount, byteLength } from \"./limits\";\nimport type { JsonValue } from \"./types\";\nimport { parseJson } from \"./util\";\n\nconst NEWLINE = \"\\n\";\nconst DEFAULT_MAX_JSONL_LINE_BYTES = 20 * 1024 * 1024;\n\nexport interface JsonlParseOptions {\n maxLineBytes?: number;\n}\n\nexport interface JsonlEncodeOptions {\n label?: string;\n maxBytes?: number;\n}\n\nconst NEWLINE_BYTES = byteLength(NEWLINE);\n\nconst resolveMaxLineBytes = (options?: JsonlParseOptions): number => {\n const maxLineBytes = options?.maxLineBytes ?? DEFAULT_MAX_JSONL_LINE_BYTES;\n if (!(Number.isInteger(maxLineBytes) && maxLineBytes > 0)) {\n throw new BatchworkError(\n \"batchwork: JSONL maxLineBytes must be a positive integer.\"\n );\n }\n return maxLineBytes;\n};\n\nconst assertLineSize = (\n line: string,\n lineNumber: number,\n maxLineBytes: number\n): void => {\n const bytes = byteLength(line);\n if (bytes > maxLineBytes) {\n throw new BatchworkError(\n `batchwork: JSONL line ${lineNumber} is ${bytes} bytes, exceeding the ${maxLineBytes} byte limit.`\n );\n }\n};\n\nconst parseLine = (\n line: string,\n lineNumber: number,\n maxLineBytes: number\n): JsonValue | undefined => {\n assertLineSize(line, lineNumber, maxLineBytes);\n const trimmed = line.trim();\n if (trimmed.length === 0) {\n return;\n }\n try {\n return parseJson(trimmed);\n } catch (error) {\n throw new BatchworkError(\n `batchwork: invalid JSONL at line ${lineNumber}.`,\n { cause: error }\n );\n }\n};\n\nconst resolveMaxBytes = (options?: JsonlEncodeOptions): number | undefined => {\n const maxBytes = options?.maxBytes;\n if (maxBytes !== undefined && !(Number.isInteger(maxBytes) && maxBytes > 0)) {\n throw new BatchworkError(\n \"batchwork: JSONL maxBytes must be a positive integer.\"\n );\n }\n return maxBytes;\n};\n\nexport const encodeJsonl = (\n items: readonly unknown[],\n options?: JsonlEncodeOptions\n): string => {\n if (items.length === 0) {\n return \"\";\n }\n const lines: string[] = [];\n const maxBytes = resolveMaxBytes(options);\n const label = options?.label ?? \"JSONL\";\n let bytes = 0;\n for (const item of items) {\n const line = JSON.stringify(item);\n if (line === undefined) {\n throw new BatchworkError(\n `batchwork: ${label} contains a value that cannot be JSON encoded.`\n );\n }\n bytes += byteLength(line) + NEWLINE_BYTES;\n if (maxBytes !== undefined) {\n assertByteCount(label, bytes, maxBytes);\n }\n lines.push(line);\n }\n return `${lines.join(NEWLINE)}${NEWLINE}`;\n};\n\nexport const parseJsonl = (\n text: string,\n options?: JsonlParseOptions\n): JsonValue[] => {\n const maxLineBytes = resolveMaxLineBytes(options);\n const results: JsonValue[] = [];\n const lines = text.split(NEWLINE);\n for (const [index, line] of lines.entries()) {\n const parsed = parseLine(line, index + 1, maxLineBytes);\n if (parsed !== undefined) {\n results.push(parsed);\n }\n }\n return results;\n};\n\nconst isReadableStream = (\n source: ReadableStream<Uint8Array> | AsyncIterable<Uint8Array>\n): source is ReadableStream<Uint8Array> =>\n \"getReader\" in source && typeof source.getReader === \"function\";\n\n// oxlint-disable-next-line func-style -- generators cannot be arrow functions.\nasync function* toByteIterable(\n source: ReadableStream<Uint8Array> | AsyncIterable<Uint8Array>\n): AsyncGenerator<Uint8Array> {\n // Prefer an explicit reader: a web `ReadableStream` (e.g. `fetch` response\n // bodies) is not reliably async-iterable at runtime across platforms.\n if (isReadableStream(source)) {\n const reader = source.getReader();\n try {\n let chunk = await reader.read();\n while (!chunk.done) {\n if (chunk.value) {\n yield chunk.value;\n }\n // oxlint-disable-next-line no-await-in-loop, react-doctor/async-await-in-loop -- a stream is read sequentially.\n chunk = await reader.read();\n }\n } finally {\n reader.releaseLock();\n }\n return;\n }\n\n yield* source;\n}\n\n// oxlint-disable-next-line func-style -- generators cannot be arrow functions.\nexport async function* streamJsonl(\n source: ReadableStream<Uint8Array> | AsyncIterable<Uint8Array>,\n options?: JsonlParseOptions\n): AsyncGenerator<JsonValue> {\n const decoder = new TextDecoder();\n const maxLineBytes = resolveMaxLineBytes(options);\n let buffer = \"\";\n let lineNumber = 1;\n\n for await (const chunk of toByteIterable(source)) {\n buffer += decoder.decode(chunk, { stream: true });\n let newlineIndex = buffer.indexOf(NEWLINE);\n while (newlineIndex !== -1) {\n const line = buffer.slice(0, newlineIndex);\n buffer = buffer.slice(newlineIndex + 1);\n const parsed = parseLine(line, lineNumber, maxLineBytes);\n if (parsed !== undefined) {\n yield parsed;\n }\n lineNumber += 1;\n newlineIndex = buffer.indexOf(NEWLINE);\n }\n assertLineSize(buffer, lineNumber, maxLineBytes);\n }\n\n buffer += decoder.decode();\n const parsed = parseLine(buffer, lineNumber, maxLineBytes);\n if (parsed !== undefined) {\n yield parsed;\n }\n}\n",
10
+ "import { BatchworkError } from \"./errors\";\nimport { assertByteCount, byteLength } from \"./limits\";\n\ninterface JsonArrayPayloadOptions {\n items: readonly unknown[];\n label: string;\n maxBytes: number;\n prefix: string;\n suffix: string;\n}\n\nexport const encodeJsonArrayPayload = ({\n items,\n label,\n maxBytes,\n prefix,\n suffix,\n}: JsonArrayPayloadOptions): string => {\n const encodedItems: string[] = [];\n let bytes = byteLength(prefix) + byteLength(suffix);\n assertByteCount(label, bytes, maxBytes);\n\n for (const [index, item] of items.entries()) {\n const encoded = JSON.stringify(item);\n if (encoded === undefined) {\n throw new BatchworkError(\n `batchwork: ${label} contains a value that cannot be JSON encoded.`\n );\n }\n bytes += byteLength(encoded);\n if (index > 0) {\n bytes += 1;\n }\n assertByteCount(label, bytes, maxBytes);\n encodedItems.push(encoded);\n }\n\n return `${prefix}${encodedItems.join(\",\")}${suffix}`;\n};\n",
11
+ "import { BatchworkError } from \"../errors\";\n\nconst SIMPLE_PROVIDER_ID = /^[A-Za-z0-9_-]+$/u;\n\nexport const assertSimpleProviderId = (label: string, id: string): string => {\n if (!SIMPLE_PROVIDER_ID.test(id)) {\n throw new BatchworkError(`batchwork: invalid ${label}.`);\n }\n return id;\n};\n\nexport const assertPrefixedProviderId = (\n label: string,\n id: string,\n prefix: string\n): string => {\n const [actualPrefix, value, ...rest] = id.split(\"/\");\n if (\n rest.length > 0 ||\n actualPrefix !== prefix ||\n !value ||\n !SIMPLE_PROVIDER_ID.test(value)\n ) {\n throw new BatchworkError(`batchwork: invalid ${label}.`);\n }\n return id;\n};\n",
12
+ "import { BatchworkError } from \"../errors\";\nimport { requestJson, requestStream } from \"../http\";\nimport { streamJsonl } from \"../jsonl\";\nimport { resolveBatchLimits } from \"../limits\";\nimport { encodeJsonArrayPayload } from \"../payload\";\nimport type {\n BatchResult,\n BatchSnapshot,\n BatchStatus,\n BatchUsage,\n HttpHeaders,\n JsonValue,\n ProviderCredentials,\n} from \"../types\";\nimport { asArray, asNumber, asRecord, asString, omit, toDate } from \"../util\";\nimport type { BatchAdapter, SubmitInput } from \"./adapter\";\nimport { assertSimpleProviderId } from \"./ids\";\n\nconst ANTHROPIC_BASE = \"https://api.anthropic.com\";\nconst ANTHROPIC_VERSION = \"2023-06-01\";\n\nconst apiKey = (credentials: ProviderCredentials): string => {\n const key = credentials.apiKey ?? process.env.ANTHROPIC_API_KEY;\n if (!key) {\n throw new BatchworkError(\n \"batchwork: missing Anthropic API key. Set ANTHROPIC_API_KEY or pass `apiKey`.\"\n );\n }\n return key;\n};\n\nconst baseUrl = (credentials: ProviderCredentials): string =>\n credentials.baseURL ?? ANTHROPIC_BASE;\n\nconst validateResultsUrl = (\n rawUrl: string,\n credentials: ProviderCredentials\n): string => {\n let resultsUrl: URL;\n let expectedBase: URL;\n try {\n resultsUrl = new URL(rawUrl);\n expectedBase = new URL(baseUrl(credentials));\n } catch (error) {\n throw new BatchworkError(\"batchwork: invalid Anthropic results_url.\", {\n cause: error,\n });\n }\n if (resultsUrl.origin !== expectedBase.origin) {\n throw new BatchworkError(\n \"batchwork: Anthropic results_url must match the configured API origin.\"\n );\n }\n if (resultsUrl.username || resultsUrl.password) {\n throw new BatchworkError(\n \"batchwork: Anthropic results_url must not include credentials.\"\n );\n }\n return resultsUrl.toString();\n};\n\nconst headers = (credentials: ProviderCredentials): HttpHeaders => ({\n \"anthropic-version\": ANTHROPIC_VERSION,\n \"content-type\": \"application/json\",\n \"x-api-key\": apiKey(credentials),\n ...credentials.headers,\n});\n\nconst mapStatus = (status: string | undefined): BatchStatus => {\n if (status === \"ended\") {\n return \"completed\";\n }\n if (status === \"canceling\") {\n return \"cancelling\";\n }\n return \"in_progress\";\n};\n\nconst normalizeSnapshot = (raw: JsonValue): BatchSnapshot => {\n const obj = asRecord(raw);\n const counts = asRecord(obj.request_counts);\n const succeeded = asNumber(counts.succeeded) ?? 0;\n const errored = asNumber(counts.errored) ?? 0;\n const processing = asNumber(counts.processing) ?? 0;\n const canceled = asNumber(counts.canceled) ?? 0;\n const expired = asNumber(counts.expired) ?? 0;\n\n return {\n completedAt: toDate(obj.ended_at),\n createdAt: toDate(obj.created_at),\n expiresAt: toDate(obj.expires_at),\n id: asString(obj.id) ?? \"\",\n provider: \"anthropic\",\n raw,\n requestCounts: {\n canceled,\n completed: succeeded,\n expired,\n failed: errored,\n processing,\n total: succeeded + errored + processing + canceled + expired,\n },\n status: mapStatus(asString(obj.processing_status)),\n };\n};\n\nconst textFromMessage = (\n message: JsonValue | undefined\n): string | undefined => {\n let text = \"\";\n for (const item of asArray(asRecord(message).content)) {\n const block = asRecord(item);\n if (block.type === \"text\") {\n text += asString(block.text) ?? \"\";\n }\n }\n return text.length > 0 ? text : undefined;\n};\n\nconst usageFromMessage = (\n message: JsonValue | undefined\n): BatchUsage | undefined => {\n const usage = asRecord(asRecord(message).usage);\n const inputTokens = asNumber(usage.input_tokens);\n const outputTokens = asNumber(usage.output_tokens);\n if (inputTokens === undefined && outputTokens === undefined) {\n return;\n }\n return {\n inputTokens,\n outputTokens,\n totalTokens: (inputTokens ?? 0) + (outputTokens ?? 0),\n };\n};\n\nconst normalizeResult = (line: JsonValue): BatchResult => {\n const obj = asRecord(line);\n const customId = asString(obj.custom_id) ?? \"\";\n const result = asRecord(obj.result);\n const type = asString(result.type);\n\n if (type === \"succeeded\") {\n return {\n customId,\n response: result.message,\n status: \"succeeded\",\n text: textFromMessage(result.message),\n usage: usageFromMessage(result.message),\n };\n }\n if (type === \"errored\") {\n const error = asRecord(result.error);\n const nested = asRecord(error.error);\n const source = Object.keys(nested).length > 0 ? nested : error;\n return {\n customId,\n error: {\n message: asString(source.message) ?? \"Request errored.\",\n type: asString(source.type),\n },\n response: result.error,\n status: \"errored\",\n };\n }\n if (type === \"expired\") {\n return { customId, status: \"expired\" };\n }\n return { customId, status: \"canceled\" };\n};\n\nconst submit = async (input: SubmitInput): Promise<BatchSnapshot> => {\n const limits = resolveBatchLimits(input.limits);\n const requests = input.built.map((item) => ({\n custom_id: item.customId,\n params: omit(item.body, \"stream\"),\n }));\n const body = encodeJsonArrayPayload({\n items: requests,\n label: \"batch upload payload\",\n maxBytes: limits.maxUploadBytes,\n prefix: '{\"requests\":[',\n suffix: \"]}\",\n });\n const raw = await requestJson(\n `${baseUrl(input.credentials)}/v1/messages/batches`,\n {\n body,\n headers: headers(input.credentials),\n method: \"POST\",\n }\n );\n return normalizeSnapshot(raw);\n};\n\nconst retrieve = async (\n id: string,\n credentials: ProviderCredentials\n): Promise<BatchSnapshot> => {\n const batchId = assertSimpleProviderId(\"Anthropic batch id\", id);\n const raw = await requestJson(\n `${baseUrl(credentials)}/v1/messages/batches/${batchId}`,\n { headers: headers(credentials) }\n );\n return normalizeSnapshot(raw);\n};\n\n// oxlint-disable-next-line func-style -- generators cannot be arrow functions.\nasync function* results(\n id: string,\n credentials: ProviderCredentials\n): AsyncGenerator<BatchResult> {\n const snapshot = await retrieve(id, credentials);\n const resultsUrl = asString(asRecord(snapshot.raw).results_url);\n if (!resultsUrl) {\n throw new BatchworkError(\n `batchwork: results are not ready for batch \"${id}\" (status: ${snapshot.status}).`\n );\n }\n const stream = await requestStream(\n validateResultsUrl(resultsUrl, credentials),\n {\n headers: headers(credentials),\n redirect: \"manual\",\n }\n );\n for await (const line of streamJsonl(stream)) {\n yield normalizeResult(line);\n }\n}\n\nconst cancel = async (\n id: string,\n credentials: ProviderCredentials\n): Promise<void> => {\n const batchId = assertSimpleProviderId(\"Anthropic batch id\", id);\n await requestJson(\n `${baseUrl(credentials)}/v1/messages/batches/${batchId}/cancel`,\n {\n headers: headers(credentials),\n method: \"POST\",\n }\n );\n};\n\nexport const anthropicAdapter: BatchAdapter = {\n cancel,\n id: \"anthropic\",\n results,\n retrieve,\n submit,\n};\n",
13
+ "/**\n * Helpers shared across the OpenAI-shaped adapters (OpenAI, Groq, Together,\n * Mistral). These providers all upload JSONL via a Files API, return results as\n * JSONL keyed by `custom_id`, and shape each result line like OpenAI's\n * (`{ custom_id, response: { status_code, body }, error }`).\n */\n\nimport { BatchworkError } from \"../errors\";\nimport { isBoolean } from \"../guards\";\nimport { requestJson, requestStream } from \"../http\";\nimport { streamJsonl } from \"../jsonl\";\nimport type {\n BatchImage,\n BatchModeration,\n BatchResult,\n BatchResultError,\n BatchTranscriptionSegment,\n BatchUsage,\n JsonValue,\n ProviderCredentials,\n} from \"../types\";\nimport { asArray, asNumber, asNumberArray, asRecord, asString } from \"../util\";\n\nconst HTTP_OK_MIN = 200;\nconst HTTP_OK_MAX = 300;\n\n/** Resolve an API key from credentials or the provider's env var, or throw. */\nexport const resolveApiKey = (\n credentials: ProviderCredentials,\n envVar: string,\n label: string\n): string => {\n const key = credentials.apiKey ?? process.env[envVar];\n if (!key) {\n throw new BatchworkError(\n `batchwork: missing ${label} API key. Set ${envVar} or pass \\`apiKey\\`.`\n );\n }\n return key;\n};\n\nexport const textFromBody = (\n body: JsonValue | undefined\n): string | undefined => {\n const obj = asRecord(body);\n const choices = asArray(obj.choices);\n if (choices.length > 0) {\n const content = asString(asRecord(asRecord(choices[0]).message).content);\n if (content) {\n return content;\n }\n }\n // `text` is the top-level field of transcription responses.\n const directText = asString(obj.output_text) ?? asString(obj.text);\n if (directText !== undefined) {\n return directText;\n }\n // Responses API batches return message content under `output`, unlike the\n // convenience `output_text` field exposed by some SDK response helpers.\n // Reasoning models emit non-message items (e.g. `reasoning`) ahead of the\n // answer, so only `message` items and their `output_text` parts count, and\n // multi-part answers concatenate like OpenAI's `output_text` helper.\n const parts: string[] = [];\n for (const output of asArray(obj.output)) {\n const item = asRecord(output);\n if (item.type !== \"message\") {\n continue;\n }\n for (const content of asArray(item.content)) {\n const part = asRecord(content);\n if (part.type !== \"output_text\") {\n continue;\n }\n const text = asString(part.text);\n if (text !== undefined) {\n parts.push(text);\n }\n }\n }\n if (parts.length > 0) {\n return parts.join(\"\");\n }\n};\n\n/**\n * Read timestamped segments from a transcription-shaped response body\n * (`{ text, segments: [{ text, start, end }] }`, Groq `verbose_json` and\n * Mistral alike). Returns undefined when the body carries no segments, so\n * chat/embedding/image results are unaffected.\n */\nexport const segmentsFromBody = (\n body: JsonValue | undefined\n): BatchTranscriptionSegment[] | undefined => {\n const obj = asRecord(body);\n if (asString(obj.text) === undefined) {\n return;\n }\n const segments: BatchTranscriptionSegment[] = [];\n for (const item of asArray(obj.segments)) {\n const segment = asRecord(item);\n const text = asString(segment.text);\n if (text !== undefined) {\n segments.push({\n endSecond: asNumber(segment.end),\n startSecond: asNumber(segment.start),\n text,\n });\n }\n }\n return segments.length > 0 ? segments : undefined;\n};\n\n/** Read the embedding vector from an OpenAI-shaped embeddings response body. */\nexport const embeddingFromBody = (\n body: JsonValue | undefined\n): number[] | undefined => {\n const data = asArray(asRecord(body).data);\n if (data.length === 0) {\n return;\n }\n return asNumberArray(asRecord(data[0]).embedding);\n};\n\n/**\n * Read base64 images from an OpenAI-shaped images response body\n * (`{ data: [{ b64_json }], output_format? }`). Returns undefined when the body\n * carries no image data, so chat/embedding results are unaffected.\n */\nexport const imagesFromBody = (\n body: JsonValue | undefined\n): BatchImage[] | undefined => {\n const obj = asRecord(body);\n const mediaType = `image/${asString(obj.output_format) ?? \"png\"}`;\n const images: BatchImage[] = [];\n for (const item of asArray(obj.data)) {\n const b64 = asString(asRecord(item).b64_json);\n if (b64) {\n images.push({ data: b64, mediaType });\n }\n }\n return images.length > 0 ? images : undefined;\n};\n\n/**\n * Read the verdict from a moderation-shaped response body\n * (`{ results: [{ flagged?, categories, category_scores }] }`, OpenAI and\n * Mistral alike). Mistral reports no `flagged`, so it falls back to \"any\n * category flagged\". Returns undefined when the body carries no categories, so\n * other result shapes are unaffected.\n */\nexport const moderationFromBody = (\n body: JsonValue | undefined\n): BatchModeration | undefined => {\n const results = asArray(asRecord(body).results);\n if (results.length === 0) {\n return;\n }\n const first = asRecord(results[0]);\n const categories: Record<string, boolean> = {};\n for (const [key, value] of Object.entries(asRecord(first.categories))) {\n if (isBoolean(value)) {\n categories[key] = value;\n }\n }\n if (Object.keys(categories).length === 0) {\n return;\n }\n const categoryScores: Record<string, number> = {};\n for (const [key, value] of Object.entries(asRecord(first.category_scores))) {\n const score = asNumber(value);\n if (score !== undefined) {\n categoryScores[key] = score;\n }\n }\n const flagged = isBoolean(first.flagged)\n ? first.flagged\n : Object.values(categories).some(Boolean);\n return { categories, categoryScores, flagged };\n};\n\nexport const usageFromBody = (\n body: JsonValue | undefined\n): BatchUsage | undefined => {\n const usage = asRecord(asRecord(body).usage);\n const inputTokens =\n asNumber(usage.prompt_tokens) ?? asNumber(usage.input_tokens);\n const outputTokens =\n asNumber(usage.completion_tokens) ?? asNumber(usage.output_tokens);\n const totalTokens = asNumber(usage.total_tokens);\n if (\n inputTokens === undefined &&\n outputTokens === undefined &&\n totalTokens === undefined\n ) {\n return;\n }\n return {\n inputTokens,\n outputTokens,\n totalTokens: totalTokens ?? (inputTokens ?? 0) + (outputTokens ?? 0),\n };\n};\n\nconst errorFromValue = (\n value: JsonValue | undefined,\n fallback: string\n): BatchResultError => {\n const obj = asRecord(value);\n const nested = asRecord(obj.error);\n const source = nested.message ? nested : obj;\n return {\n code: asNumber(source.code) ?? asString(source.code),\n message: asString(source.message) ?? fallback,\n type: asString(source.type),\n };\n};\n\n/** Normalize an OpenAI-shaped result line into a {@link BatchResult}. */\nexport const normalizeOpenAIResult = (line: JsonValue): BatchResult => {\n const obj = asRecord(line);\n const customId = asString(obj.custom_id) ?? \"\";\n\n if (obj.error) {\n return {\n customId,\n error: errorFromValue(obj.error, \"Request errored.\"),\n response: obj.error,\n status: \"errored\",\n };\n }\n\n const response = asRecord(obj.response);\n const statusCode = asNumber(response.status_code) ?? 0;\n if (statusCode >= HTTP_OK_MIN && statusCode < HTTP_OK_MAX) {\n return {\n customId,\n embedding: embeddingFromBody(response.body),\n images: imagesFromBody(response.body),\n moderation: moderationFromBody(response.body),\n response: response.body,\n segments: segmentsFromBody(response.body),\n status: \"succeeded\",\n text: textFromBody(response.body),\n usage: usageFromBody(response.body),\n };\n }\n\n return {\n customId,\n error: errorFromValue(\n response.body,\n `Request failed with status ${statusCode}.`\n ),\n response: response.body,\n status: \"errored\",\n };\n};\n\n// Upload a JSONL batch input file and return its id. Purpose defaults to `batch`.\nexport const uploadInputFile = async (\n jsonl: string,\n baseUrl: string,\n headers: Record<string, string>,\n options: { purpose?: string | null } = {}\n): Promise<string> => {\n const form = new FormData();\n const purpose = options.purpose === undefined ? \"batch\" : options.purpose;\n if (purpose !== null) {\n form.append(\"purpose\", purpose);\n }\n form.append(\n \"file\",\n new Blob([jsonl], { type: \"application/jsonl\" }),\n \"batchwork.jsonl\"\n );\n const raw = await requestJson(`${baseUrl}/files`, {\n body: form,\n headers,\n method: \"POST\",\n redirect: \"manual\",\n });\n const id = asString(asRecord(raw).id);\n if (!id) {\n throw new BatchworkError(\n \"batchwork: the file upload response carried no file id.\"\n );\n }\n return id;\n};\n\n/**\n * Stream a JSONL result file's content as normalized OpenAI-shaped results.\n *\n * @yields {BatchResult} the normalized result for each line.\n */\n// oxlint-disable-next-line func-style -- generators cannot be arrow functions.\nexport async function* streamResultFile(\n fileId: string,\n baseUrl: string,\n headers: Record<string, string>\n): AsyncGenerator<BatchResult> {\n const stream = await requestStream(`${baseUrl}/files/${fileId}/content`, {\n headers,\n redirect: \"manual\",\n });\n for await (const line of streamJsonl(stream)) {\n yield normalizeOpenAIResult(line);\n }\n}\n",
14
+ "/**\n * Factory for OpenAI-compatible batch adapters. OpenAI, Groq, and Together AI\n * all share the same lifecycle — upload JSONL via the Files API, create a batch\n * referencing the file, poll a `status` field, then download output/error files\n * — differing only in base URL, credentials, and minor request-line shape.\n */\n\nimport { BatchworkError } from \"../errors\";\nimport { requestJson } from \"../http\";\nimport { encodeJsonl } from \"../jsonl\";\nimport { resolveBatchLimits } from \"../limits\";\nimport type {\n BatchProvider,\n BatchResult,\n BatchSnapshot,\n BatchStatus,\n HttpHeaders,\n JsonObject,\n JsonValue,\n ProviderCredentials,\n} from \"../types\";\nimport { asNumber, asRecord, asString, omit, toDate } from \"../util\";\nimport type { BatchAdapter, SubmitInput } from \"./adapter\";\nimport { assertSimpleProviderId } from \"./ids\";\nimport { resolveApiKey, streamResultFile, uploadInputFile } from \"./shared\";\n\n// How a batch input line is shaped.\nexport type BatchLineFormat = \"body-only\" | \"method-url\";\n\nexport interface OpenAICompatibleConfig {\n /** Env var for the default Bearer auth; unused when `authHeaders` is set. */\n apiKeyEnv: string;\n apiKeyLabel: string;\n /**\n * Default API root. Providers with a resource-specific endpoint (Azure) can\n * resolve it from credentials or environment configuration instead.\n */\n baseUrl?: string;\n /** Build provider authentication headers instead of the default Bearer key. */\n authHeaders?: (credentials: ProviderCredentials) => Record<string, string>;\n /**\n * Resolve a provider API root when `credentials.baseURL` is not provided.\n */\n resolveBaseUrl?: (credentials: ProviderCredentials) => string;\n // How long the provider may take to finish (OpenAI/Groq/Together).\n completionWindow?: string;\n // Files API purpose value for uploaded JSONL batch inputs.\n filePurpose?: string;\n id: BatchProvider;\n /**\n * Override the JSONL upload. Defaults to a direct multipart POST to the Files\n * API (OpenAI, Groq); Together replaces it with its presigned-URL flow.\n * Returns the uploaded file id.\n */\n uploadFile?: (args: {\n baseUrl: string;\n headers: Record<string, string>;\n jsonl: string;\n purpose: string;\n }) => Promise<string>;\n /**\n * Input-line shape. `method-url` writes `{ custom_id, method, url, body }`\n * (OpenAI, Groq); `body-only` writes `{ custom_id, body }` (Together).\n */\n lineFormat?: BatchLineFormat;\n /**\n * Extra fields merged into each `body-only` line for a given endpoint\n * (e.g. Together audio lines require `method: \"FILE\"`).\n */\n lineExtras?: (endpoint: string) => JsonObject | undefined;\n /**\n * Map the captured endpoint path to the value the provider expects in the\n * batch `url`/`endpoint` field (e.g. Groq serves under `/openai/v1` but its\n * batch `url` must be `/v1/chat/completions`).\n */\n normalizeEndpoint?: (endpoint: string) => string;\n /**\n * Map the JSONL request URL to the value required by batch creation. Azure\n * requires `/chat/completions` here while its input lines use `/v1/...`.\n */\n batchEndpoint?: (endpoint: string) => string;\n}\n\nconst DEFAULT_COMPLETION_WINDOW = \"24h\";\n\nconst mapStatus = (status: string | undefined): BatchStatus => {\n const normalized = status?.toLowerCase();\n switch (normalized) {\n case \"validating\":\n case \"in_progress\":\n case \"finalizing\":\n case \"completed\":\n case \"failed\":\n case \"expired\":\n case \"cancelling\":\n case \"cancelled\": {\n return normalized;\n }\n default: {\n return \"in_progress\";\n }\n }\n};\n\nconst normalizeSnapshot = (\n raw: JsonValue,\n provider: BatchProvider\n): BatchSnapshot => {\n const outer = asRecord(raw);\n const obj = asRecord(outer.job);\n const source = Object.keys(obj).length > 0 ? obj : outer;\n const counts = asRecord(source.request_counts);\n return {\n completedAt: toDate(source.completed_at),\n createdAt: toDate(source.created_at),\n expiresAt: toDate(source.expires_at),\n id: asString(source.id) ?? \"\",\n provider,\n raw: source,\n requestCounts: {\n completed: asNumber(counts.completed) ?? 0,\n failed: asNumber(counts.failed) ?? 0,\n total: asNumber(counts.total) ?? 0,\n },\n status: mapStatus(asString(source.status)),\n };\n};\n\n// Build an OpenAI-compatible adapter from a provider config.\nexport const createOpenAICompatibleAdapter = (\n config: OpenAICompatibleConfig\n): BatchAdapter => {\n const completionWindow = config.completionWindow ?? DEFAULT_COMPLETION_WINDOW;\n const lineFormat = config.lineFormat ?? \"method-url\";\n\n const baseUrl = (credentials: ProviderCredentials): string =>\n config.resolveBaseUrl?.(credentials) ??\n credentials.baseURL ??\n config.baseUrl ??\n (() => {\n throw new BatchworkError(\n `batchwork: missing ${config.apiKeyLabel} base URL. Pass \\`baseURL\\`.`\n );\n })();\n\n const authHeaders = (credentials: ProviderCredentials): HttpHeaders => ({\n ...(config.authHeaders\n ? config.authHeaders(credentials)\n : {\n Authorization: `Bearer ${resolveApiKey(\n credentials,\n config.apiKeyEnv,\n config.apiKeyLabel\n )}`,\n }),\n ...credentials.headers,\n });\n\n const submit = async (input: SubmitInput): Promise<BatchSnapshot> => {\n const limits = resolveBatchLimits(input.limits);\n const endpoint = config.normalizeEndpoint\n ? config.normalizeEndpoint(input.endpoint)\n : input.endpoint;\n const batchEndpoint = config.batchEndpoint?.(endpoint) ?? endpoint;\n const jsonl = encodeJsonl(\n input.built.map((item) => {\n const body = omit(item.body, \"stream\");\n if (lineFormat === \"body-only\") {\n return {\n body,\n custom_id: item.customId,\n ...config.lineExtras?.(endpoint),\n };\n }\n return {\n body,\n custom_id: item.customId,\n method: \"POST\",\n url: endpoint,\n };\n }),\n { label: \"batch upload JSONL\", maxBytes: limits.maxUploadBytes }\n );\n const headers = authHeaders(input.credentials);\n const url = baseUrl(input.credentials);\n const purpose = config.filePurpose ?? \"batch\";\n const inputFileId = await (config.uploadFile\n ? config.uploadFile({ baseUrl: url, headers, jsonl, purpose })\n : uploadInputFile(jsonl, url, headers, { purpose }));\n const raw = await requestJson(`${url}/batches`, {\n body: JSON.stringify({\n completion_window: completionWindow,\n endpoint: batchEndpoint,\n input_file_id: inputFileId,\n metadata: input.metadata,\n }),\n headers: { ...headers, \"content-type\": \"application/json\" },\n method: \"POST\",\n });\n return normalizeSnapshot(raw, config.id);\n };\n\n const retrieve = async (\n id: string,\n credentials: ProviderCredentials\n ): Promise<BatchSnapshot> => {\n const batchId = assertSimpleProviderId(`${config.id} batch id`, id);\n const raw = await requestJson(\n `${baseUrl(credentials)}/batches/${batchId}`,\n {\n headers: authHeaders(credentials),\n }\n );\n return normalizeSnapshot(raw, config.id);\n };\n\n // oxlint-disable-next-line func-style -- generators cannot be arrow functions.\n async function* results(\n id: string,\n credentials: ProviderCredentials\n ): AsyncGenerator<BatchResult> {\n const snapshot = await retrieve(id, credentials);\n const raw = asRecord(snapshot.raw);\n const outputFileId = asString(raw.output_file_id);\n const errorFileId = asString(raw.error_file_id);\n\n if (!(outputFileId || errorFileId)) {\n throw new BatchworkError(\n `batchwork: results are not ready for batch \"${id}\" (status: ${snapshot.status}).`\n );\n }\n const headers = authHeaders(credentials);\n if (outputFileId) {\n yield* streamResultFile(\n assertSimpleProviderId(`${config.id} output file id`, outputFileId),\n baseUrl(credentials),\n headers\n );\n }\n if (errorFileId) {\n yield* streamResultFile(\n assertSimpleProviderId(`${config.id} error file id`, errorFileId),\n baseUrl(credentials),\n headers\n );\n }\n }\n\n const cancel = async (\n id: string,\n credentials: ProviderCredentials\n ): Promise<void> => {\n const batchId = assertSimpleProviderId(`${config.id} batch id`, id);\n await requestJson(`${baseUrl(credentials)}/batches/${batchId}/cancel`, {\n headers: authHeaders(credentials),\n method: \"POST\",\n });\n };\n\n return { cancel, id: config.id, results, retrieve, submit };\n};\n",
15
+ "import { BatchworkError } from \"../errors\";\nimport type { HttpHeaders, ProviderCredentials } from \"../types\";\nimport { trimTrailingSlashes } from \"../util\";\nimport { createOpenAICompatibleAdapter } from \"./openai-compatible\";\n\nconst isAzureOpenAIUrl = (value: string): boolean => {\n try {\n return new URL(value).hostname.endsWith(\".openai.azure.com\");\n } catch {\n return false;\n }\n};\n\nconst baseUrl = (credentials: ProviderCredentials): string => {\n const configured =\n credentials.baseURL ??\n (process.env.AZURE_RESOURCE_NAME\n ? `https://${process.env.AZURE_RESOURCE_NAME}.openai.azure.com/openai`\n : undefined);\n if (!configured) {\n throw new BatchworkError(\n \"batchwork: missing Azure OpenAI resource. Set AZURE_RESOURCE_NAME or pass `baseURL`.\"\n );\n }\n\n const normalized = trimTrailingSlashes(configured);\n if (!isAzureOpenAIUrl(normalized)) {\n return normalized;\n }\n // Accept the bare resource URL, its `/openai` URL, or its `/openai/v1` API\n // root — batch calls always need the full `/openai/v1` root.\n if (normalized.endsWith(\"/v1\")) {\n return normalized;\n }\n return normalized.endsWith(\"/openai\")\n ? `${normalized}/v1`\n : `${normalized}/openai/v1`;\n};\n\nconst hasCallerAuth = (headers: Record<string, string> | undefined): boolean =>\n Object.keys(headers ?? {}).some((name) => {\n const normalized = name.toLowerCase();\n return normalized === \"api-key\" || normalized === \"authorization\";\n });\n\nconst authHeaders = (credentials: ProviderCredentials): HttpHeaders => {\n if (credentials.apiKey) {\n return { \"api-key\": credentials.apiKey };\n }\n if (hasCallerAuth(credentials.headers)) {\n return {};\n }\n const apiKey = process.env.AZURE_API_KEY ?? process.env.AZURE_OPENAI_API_KEY;\n if (apiKey) {\n return { \"api-key\": apiKey };\n }\n throw new BatchworkError(\n \"batchwork: missing Azure OpenAI API key. Set AZURE_API_KEY or pass `apiKey`.\"\n );\n};\n\n/**\n * Azure OpenAI batch adapter. Azure uses OpenAI's JSONL Files + Batches shape,\n * with a resource-specific `/openai/v1` API root and `api-key` authentication.\n * Input lines use `/v1/...`, while batch creation uses `/v1/chat/completions`\n * for text batches (including Responses input).\n */\nexport const azureAdapter = createOpenAICompatibleAdapter({\n apiKeyEnv: \"AZURE_API_KEY\",\n apiKeyLabel: \"Azure OpenAI\",\n authHeaders,\n // Azure batch creation only accepts `/v1/chat/completions` for text batches\n // and, unlike OpenAI, does not validate JSONL line URLs against it — so\n // Responses input lines (`/v1/responses`) ride on this endpoint. Verified\n // against a live Global Batch deployment; revisit if Azure adds validation\n // or a `/v1/responses` batch endpoint.\n batchEndpoint: () => \"/v1/chat/completions\",\n id: \"azure\",\n normalizeEndpoint: (endpoint) => endpoint.replace(/^\\/openai/u, \"\"),\n resolveBaseUrl: baseUrl,\n});\n",
16
+ "import { BatchworkError } from \"../errors\";\nimport { requestJson } from \"../http\";\nimport { resolveBatchLimits } from \"../limits\";\nimport { encodeJsonArrayPayload } from \"../payload\";\nimport type {\n BatchImage,\n BatchResult,\n BatchSnapshot,\n BatchStatus,\n BatchUsage,\n HttpHeaders,\n JsonObject,\n JsonValue,\n ProviderCredentials,\n} from \"../types\";\nimport {\n asArray,\n asNumber,\n asNumberArray,\n asRecord,\n asString,\n omit,\n} from \"../util\";\nimport type { BatchAdapter, SubmitInput } from \"./adapter\";\nimport { assertPrefixedProviderId } from \"./ids\";\n\nconst GOOGLE_BASE = \"https://generativelanguage.googleapis.com/v1beta\";\nconst OPERATION_ID_LABEL = \"Google operation id\";\nconst GOOGLE_BATCH_PREFIX = \"batches\";\n\nconst apiKey = (credentials: ProviderCredentials): string => {\n const key =\n credentials.apiKey ??\n process.env.GOOGLE_GENERATIVE_AI_API_KEY ??\n process.env.GEMINI_API_KEY;\n if (!key) {\n throw new BatchworkError(\n \"batchwork: missing Google Gemini API key. Set GOOGLE_GENERATIVE_AI_API_KEY (or GEMINI_API_KEY) or pass `apiKey`.\"\n );\n }\n return key;\n};\n\nconst baseUrl = (credentials: ProviderCredentials): string =>\n credentials.baseURL ?? GOOGLE_BASE;\n\nconst headers = (credentials: ProviderCredentials): HttpHeaders => ({\n \"content-type\": \"application/json\",\n \"x-goog-api-key\": apiKey(credentials),\n ...credentials.headers,\n});\n\n/** Gemini operation state. Live ops use `JOB_STATE_*`; match on the suffix. */\nconst mapState = (state: string | undefined, done: boolean): BatchStatus => {\n if (state) {\n if (state.endsWith(\"SUCCEEDED\")) {\n return \"completed\";\n }\n if (state.endsWith(\"FAILED\")) {\n return \"failed\";\n }\n if (state.endsWith(\"CANCELLED\")) {\n return \"cancelled\";\n }\n if (state.endsWith(\"EXPIRED\")) {\n return \"expired\";\n }\n if (state.endsWith(\"PENDING\")) {\n return \"validating\";\n }\n if (state.endsWith(\"RUNNING\")) {\n return \"in_progress\";\n }\n }\n return done ? \"completed\" : \"in_progress\";\n};\n\nconst inlinedResponses = (raw: JsonValue): JsonValue[] => {\n const obj = asRecord(raw);\n const response = asRecord(obj.response);\n const dest = asRecord(obj.dest);\n const responseInline =\n response.inlinedResponses ?? response.inlined_responses;\n const destInline = dest.inlinedResponses ?? dest.inlined_responses;\n const nestedResponseInline = asRecord(responseInline);\n const nestedDestInline = asRecord(destInline);\n return [\n ...asArray(responseInline),\n ...asArray(nestedResponseInline.inlinedResponses),\n ...asArray(nestedResponseInline.inlined_responses),\n ...asArray(destInline),\n ...asArray(nestedDestInline.inlinedResponses),\n ...asArray(nestedDestInline.inlined_responses),\n ];\n};\n\nconst normalizeSnapshot = (raw: JsonValue): BatchSnapshot => {\n const obj = asRecord(raw);\n const items = inlinedResponses(raw);\n const failed = items.filter((item) => asRecord(item).error).length;\n const id = asString(obj.name) ?? \"\";\n return {\n id: id\n ? assertPrefixedProviderId(OPERATION_ID_LABEL, id, GOOGLE_BATCH_PREFIX)\n : \"\",\n provider: \"google\",\n raw,\n requestCounts: {\n completed: items.length - failed,\n failed,\n total: items.length,\n },\n status: mapState(\n asString(obj.state) ??\n asString(asRecord(obj.state).name) ??\n asString(asRecord(obj.metadata).state),\n obj.done === true\n ),\n };\n};\n\nconst textFromResponse = (\n response: JsonValue | undefined\n): string | undefined => {\n const candidate = asRecord(asArray(asRecord(response).candidates)[0]);\n const text = asArray(asRecord(candidate.content).parts)\n .map((part) => asString(asRecord(part).text) ?? \"\")\n .join(\"\");\n return text.length > 0 ? text : undefined;\n};\n\nconst embeddingFromResponse = (\n response: JsonValue | undefined\n): number[] | undefined =>\n asNumberArray(asRecord(asRecord(response).embedding).values);\n\n/**\n * Read inline base64 images from a Gemini `generateContent` response\n * (`candidates[0].content.parts[].inlineData`). Returns undefined when no part\n * carries image data, so text/embedding results are unaffected.\n */\nconst imagesFromResponse = (\n response: JsonValue | undefined\n): BatchImage[] | undefined => {\n const candidate = asRecord(asArray(asRecord(response).candidates)[0]);\n const images: BatchImage[] = [];\n for (const part of asArray(asRecord(candidate.content).parts)) {\n const partObj = asRecord(part);\n const inline = asRecord(partObj.inlineData ?? partObj.inline_data);\n const data = asString(inline.data);\n const mediaType = asString(inline.mimeType) ?? asString(inline.mime_type);\n if (data && mediaType?.startsWith(\"image/\")) {\n images.push({ data, mediaType });\n }\n }\n return images.length > 0 ? images : undefined;\n};\n\nconst usageFromResponse = (\n response: JsonValue | undefined\n): BatchUsage | undefined => {\n const usage = asRecord(asRecord(response).usageMetadata);\n const inputTokens = asNumber(usage.promptTokenCount);\n const outputTokens = asNumber(usage.candidatesTokenCount);\n const totalTokens = asNumber(usage.totalTokenCount);\n if (\n inputTokens === undefined &&\n outputTokens === undefined &&\n totalTokens === undefined\n ) {\n return;\n }\n return {\n inputTokens,\n outputTokens,\n totalTokens: totalTokens ?? (inputTokens ?? 0) + (outputTokens ?? 0),\n };\n};\n\nconst normalizeResult = (item: JsonValue): BatchResult => {\n const obj = asRecord(item);\n const customId =\n asString(asRecord(obj.metadata).key) ??\n asString(obj.key) ??\n asString(obj.custom_id) ??\n \"\";\n if (obj.error) {\n const error = asRecord(obj.error);\n return {\n customId,\n error: {\n code: asNumber(error.code) ?? asString(error.code),\n message: asString(error.message) ?? \"Request errored.\",\n type: asString(error.status),\n },\n response: obj.error,\n status: \"errored\",\n };\n }\n return {\n customId,\n embedding: embeddingFromResponse(obj.response),\n images: imagesFromResponse(obj.response),\n response: obj.response,\n status: \"succeeded\",\n text: textFromResponse(obj.response),\n usage: usageFromResponse(obj.response),\n };\n};\n\n// Fields the single-value embedding capture emits flat, but the async batch\n// embedding API expects nested under `embedContentConfig`.\nconst EMBED_CONFIG_KEYS = new Set([\n \"outputDimensionality\",\n \"taskType\",\n \"title\",\n]);\n\n/** Reshape a captured `:embedContent` body into an async-batch `request`. */\nconst toEmbedRequest = (body: JsonObject): JsonObject => {\n const request: JsonObject = {};\n const config: JsonObject = {};\n for (const [key, value] of Object.entries(body)) {\n if (EMBED_CONFIG_KEYS.has(key)) {\n config[key] = value;\n } else {\n request[key] = value;\n }\n }\n if (Object.keys(config).length > 0) {\n request.embedContentConfig = config;\n }\n return request;\n};\n\nconst submit = async (input: SubmitInput): Promise<BatchSnapshot> => {\n const limits = resolveBatchLimits(input.limits);\n // Embeddings capture targets `:embedContent`; route to the async batch\n // embedding method and reshape each request, otherwise generate content.\n const isEmbedding = input.endpoint.toLowerCase().includes(\"embedcontent\");\n const method = isEmbedding\n ? \"asyncBatchEmbedContent\"\n : \"batchGenerateContent\";\n const requests = input.built.map((item) => {\n const payload = omit(item.body, \"stream\");\n return {\n metadata: { key: item.customId },\n request: isEmbedding ? toEmbedRequest(payload) : payload,\n };\n });\n const body = encodeJsonArrayPayload({\n items: requests,\n label: \"batch upload payload\",\n maxBytes: limits.maxUploadBytes,\n prefix:\n '{\"batch\":{\"display_name\":\"batchwork\",\"input_config\":{\"requests\":{\"requests\":[',\n suffix: \"]}}}}\",\n });\n const raw = await requestJson(\n `${baseUrl(input.credentials)}/models/${input.modelId}:${method}`,\n {\n body,\n headers: headers(input.credentials),\n method: \"POST\",\n }\n );\n return normalizeSnapshot(raw);\n};\n\nconst retrieve = async (\n id: string,\n credentials: ProviderCredentials\n): Promise<BatchSnapshot> => {\n const operationId = assertPrefixedProviderId(\n OPERATION_ID_LABEL,\n id,\n GOOGLE_BATCH_PREFIX\n );\n const raw = await requestJson(`${baseUrl(credentials)}/${operationId}`, {\n headers: headers(credentials),\n });\n return normalizeSnapshot(raw);\n};\n\n/** A file reference may be a bare name string or an object with a `name`. */\nconst fileNameFrom = (value: JsonValue | undefined): string | undefined =>\n asString(asRecord(value).name) ?? asString(value);\n\n// oxlint-disable-next-line func-style -- generators cannot be arrow functions.\nasync function* results(\n id: string,\n credentials: ProviderCredentials\n): AsyncGenerator<BatchResult> {\n const snapshot = await retrieve(id, credentials);\n const raw = asRecord(snapshot.raw);\n const response = asRecord(raw.response);\n const dest = asRecord(raw.dest);\n const responsesFile =\n fileNameFrom(response.responsesFile) ??\n fileNameFrom(response.responses_file) ??\n asString(dest.fileName) ??\n asString(dest.file_name);\n if (responsesFile) {\n throw new BatchworkError(\n `batchwork: batch \"${id}\" returned file-mode results, which are not supported yet.`\n );\n }\n const items = inlinedResponses(raw);\n if (items.length === 0) {\n throw new BatchworkError(\n `batchwork: results are not ready for batch \"${id}\" (status: ${snapshot.status}).`\n );\n }\n for (const item of items) {\n yield normalizeResult(item);\n }\n}\n\nconst cancel = async (\n id: string,\n credentials: ProviderCredentials\n): Promise<void> => {\n const operationId = assertPrefixedProviderId(\n OPERATION_ID_LABEL,\n id,\n GOOGLE_BATCH_PREFIX\n );\n await requestJson(`${baseUrl(credentials)}/${operationId}:cancel`, {\n headers: headers(credentials),\n method: \"POST\",\n });\n};\n\n/**\n * Google Gemini (Developer API) batch adapter: submits inline requests via\n * `:batchGenerateContent`, polls the returned long-running operation, then reads\n * the inline responses keyed by each request's `metadata.key`.\n */\nexport const googleAdapter: BatchAdapter = {\n cancel,\n id: \"google\",\n results,\n retrieve,\n submit,\n};\n",
17
+ "import { createOpenAICompatibleAdapter } from \"./openai-compatible\";\n\n/**\n * Groq batch adapter. Groq's batch API is OpenAI-compatible (Files API +\n * `/batches`), so it reuses the OpenAI-compatible flow. Groq is served under\n * `/openai/v1`, but its batch `url` must be `/v1/chat/completions`, so the\n * captured endpoint's `/openai` prefix is stripped.\n */\nexport const groqAdapter = createOpenAICompatibleAdapter({\n apiKeyEnv: \"GROQ_API_KEY\",\n apiKeyLabel: \"Groq\",\n baseUrl: \"https://api.groq.com/openai/v1\",\n id: \"groq\",\n lineFormat: \"method-url\",\n normalizeEndpoint: (endpoint) => endpoint.replace(/^\\/openai/u, \"\"),\n});\n",
18
+ "import { BatchworkError } from \"../errors\";\nimport { requestJson } from \"../http\";\nimport { encodeJsonl } from \"../jsonl\";\nimport { resolveBatchLimits } from \"../limits\";\nimport type {\n BatchResult,\n BatchSnapshot,\n BatchStatus,\n HttpHeaders,\n JsonValue,\n ProviderCredentials,\n} from \"../types\";\nimport { asNumber, asRecord, asString, omit, toDate } from \"../util\";\nimport type { BatchAdapter, SubmitInput } from \"./adapter\";\nimport { assertSimpleProviderId } from \"./ids\";\nimport { resolveApiKey, streamResultFile, uploadInputFile } from \"./shared\";\n\nconst MISTRAL_BASE = \"https://api.mistral.ai/v1\";\n\nconst JOB_ID_LABEL = \"Mistral job id\";\n\nconst apiKey = (credentials: ProviderCredentials): string =>\n resolveApiKey(credentials, \"MISTRAL_API_KEY\", \"Mistral\");\n\nconst baseUrl = (credentials: ProviderCredentials): string =>\n credentials.baseURL ?? MISTRAL_BASE;\n\nconst authHeaders = (credentials: ProviderCredentials): HttpHeaders => ({\n Authorization: `Bearer ${apiKey(credentials)}`,\n ...credentials.headers,\n});\n\nconst mapStatus = (status: string | undefined): BatchStatus => {\n switch (status) {\n case \"QUEUED\": {\n return \"validating\";\n }\n case \"SUCCESS\": {\n return \"completed\";\n }\n case \"FAILED\": {\n return \"failed\";\n }\n case \"TIMEOUT_EXCEEDED\": {\n return \"expired\";\n }\n case \"CANCELLATION_REQUESTED\": {\n return \"cancelling\";\n }\n case \"CANCELLED\": {\n return \"cancelled\";\n }\n default: {\n return \"in_progress\";\n }\n }\n};\n\nconst normalizeSnapshot = (raw: JsonValue): BatchSnapshot => {\n const obj = asRecord(raw);\n const succeeded = asNumber(obj.succeeded_requests) ?? 0;\n const failed = asNumber(obj.failed_requests) ?? 0;\n const id = asString(obj.id) ?? \"\";\n return {\n completedAt: toDate(obj.completed_at),\n createdAt: toDate(obj.created_at),\n id: id ? assertSimpleProviderId(JOB_ID_LABEL, id) : \"\",\n provider: \"mistral\",\n raw,\n requestCounts: {\n completed: succeeded,\n failed,\n total: asNumber(obj.total_requests) ?? succeeded + failed,\n },\n status: mapStatus(asString(obj.status)),\n };\n};\n\nconst submit = async (input: SubmitInput): Promise<BatchSnapshot> => {\n const limits = resolveBatchLimits(input.limits);\n // Mistral sets the model on the job, so strip it (and `stream`) from each line.\n const jsonl = encodeJsonl(\n input.built.map((item) => ({\n body: omit(omit(item.body, \"stream\"), \"model\"),\n custom_id: item.customId,\n })),\n { label: \"batch upload JSONL\", maxBytes: limits.maxUploadBytes }\n );\n const inputFileId = await uploadInputFile(\n jsonl,\n baseUrl(input.credentials),\n authHeaders(input.credentials)\n );\n const raw = await requestJson(`${baseUrl(input.credentials)}/batch/jobs`, {\n body: JSON.stringify({\n endpoint: input.endpoint,\n input_files: [inputFileId],\n metadata: input.metadata,\n model: input.modelId,\n }),\n headers: {\n ...authHeaders(input.credentials),\n \"content-type\": \"application/json\",\n },\n method: \"POST\",\n });\n return normalizeSnapshot(raw);\n};\n\nconst retrieve = async (\n id: string,\n credentials: ProviderCredentials\n): Promise<BatchSnapshot> => {\n const jobId = assertSimpleProviderId(JOB_ID_LABEL, id);\n const raw = await requestJson(`${baseUrl(credentials)}/batch/jobs/${jobId}`, {\n headers: authHeaders(credentials),\n });\n return normalizeSnapshot(raw);\n};\n\n// oxlint-disable-next-line func-style -- generators cannot be arrow functions.\nasync function* results(\n id: string,\n credentials: ProviderCredentials\n): AsyncGenerator<BatchResult> {\n const snapshot = await retrieve(id, credentials);\n const raw = asRecord(snapshot.raw);\n const outputFileId = asString(raw.output_file);\n const errorFileId = asString(raw.error_file);\n const headers = authHeaders(credentials);\n if (outputFileId) {\n yield* streamResultFile(\n assertSimpleProviderId(\"Mistral output file id\", outputFileId),\n baseUrl(credentials),\n headers\n );\n }\n if (errorFileId) {\n yield* streamResultFile(\n assertSimpleProviderId(\"Mistral error file id\", errorFileId),\n baseUrl(credentials),\n headers\n );\n }\n if (!(outputFileId || errorFileId)) {\n throw new BatchworkError(\n `batchwork: results are not ready for batch \"${id}\" (status: ${snapshot.status}).`\n );\n }\n}\n\nconst cancel = async (\n id: string,\n credentials: ProviderCredentials\n): Promise<void> => {\n const jobId = assertSimpleProviderId(JOB_ID_LABEL, id);\n await requestJson(`${baseUrl(credentials)}/batch/jobs/${jobId}/cancel`, {\n headers: authHeaders(credentials),\n method: \"POST\",\n });\n};\n\n/**\n * Mistral batch adapter: uploads JSONL (`purpose=batch`), creates a job with the\n * model/endpoint set on the job, polls `status`, then downloads the OpenAI-shaped\n * output/error files.\n */\nexport const mistralAdapter: BatchAdapter = {\n cancel,\n id: \"mistral\",\n results,\n retrieve,\n submit,\n};\n",
19
+ "import { createOpenAICompatibleAdapter } from \"./openai-compatible\";\n\n/**\n * OpenAI batch adapter: builds JSONL, uploads it via the Files API\n * (`purpose=batch`), creates the batch, polls `status`, then downloads and\n * parses the output and error files.\n */\nexport const openaiAdapter = createOpenAICompatibleAdapter({\n apiKeyEnv: \"OPENAI_API_KEY\",\n apiKeyLabel: \"OpenAI\",\n baseUrl: \"https://api.openai.com/v1\",\n id: \"openai\",\n lineFormat: \"method-url\",\n});\n",
20
+ "import { BatchworkError } from \"../errors\";\nimport { requestJson } from \"../http\";\nimport { assertSimpleProviderId } from \"./ids\";\nimport { createOpenAICompatibleAdapter } from \"./openai-compatible\";\n\nconst INPUT_FILE_NAME = \"batchwork.jsonl\";\nconst HTTP_FOUND = 302;\n\nconst parseIpv4 = (host: string): number[] | undefined => {\n if (!/^\\d{1,3}(?:\\.\\d{1,3}){3}$/u.test(host)) {\n return;\n }\n const parts = host.split(\".\").map(Number);\n const valid = parts.every(\n (part) => Number.isInteger(part) && part >= 0 && part <= 255\n );\n return valid ? parts : undefined;\n};\n\nconst isPrivateIpv4 = (parts: number[]): boolean => {\n const [a = 0, b = 0] = parts;\n if (a === 0 || a === 10 || a === 127 || a >= 224) {\n return true;\n }\n switch (a) {\n case 100: {\n return b >= 64 && b <= 127;\n }\n case 169: {\n return b === 254;\n }\n case 172: {\n return b >= 16 && b <= 31;\n }\n case 192: {\n return b === 168;\n }\n case 198: {\n return b === 18 || b === 19;\n }\n default: {\n return false;\n }\n }\n};\n\nconst isPrivateIpv6 = (host: string): boolean => {\n const normalized = host.replace(/^\\[/u, \"\").replace(/\\]$/u, \"\").toLowerCase();\n // Only an IPv6 literal can be a private address, and one always contains a\n // colon — guard so a bare DNS name like `fc2.com` is not mistaken for `fc00::/7`.\n if (!normalized.includes(\":\")) {\n return false;\n }\n if (normalized === \"::\" || normalized === \"::1\") {\n return true;\n }\n return (\n normalized.startsWith(\"fc\") ||\n normalized.startsWith(\"fd\") ||\n normalized.startsWith(\"fe80:\")\n );\n};\n\n/** Whether a hostname points at localhost or a private network. */\nconst isPrivateHost = (host: string): boolean => {\n if (\n host === \"localhost\" ||\n host.endsWith(\".localhost\") ||\n host.endsWith(\".local\")\n ) {\n return true;\n }\n const ipv4 = parseIpv4(host);\n return (ipv4 ? isPrivateIpv4(ipv4) : false) || isPrivateIpv6(host);\n};\n\nconst validateUploadLocation = (location: string): string => {\n let url: URL;\n try {\n url = new URL(location);\n } catch (error) {\n throw new BatchworkError(\n \"batchwork: Together upload Location must be a valid URL.\",\n { cause: error }\n );\n }\n if (url.protocol !== \"https:\") {\n throw new BatchworkError(\n \"batchwork: Together upload Location must use https.\"\n );\n }\n if (url.username || url.password) {\n throw new BatchworkError(\n \"batchwork: Together upload Location must not include credentials.\"\n );\n }\n if (isPrivateHost(url.hostname.toLowerCase())) {\n throw new BatchworkError(\n \"batchwork: Together upload Location must not target localhost or private networks.\"\n );\n }\n return url.toString();\n};\n\n/**\n * Together uploads files via a presigned URL rather than a direct multipart\n * upload of the bytes. The flow is three steps:\n *\n * 1. `POST /files` with multipart *metadata only* (`purpose`, `file_name`,\n * `file_type` — no file part) responds `302` with a `Location` (the\n * presigned storage URL) and an `X-Together-File-Id` header.\n * 2. `PUT` the raw bytes to that `Location` (no auth — the URL is signed).\n * 3. `POST /files/{id}/preprocess` to finalize the upload.\n */\nconst uploadTogetherFile = async (args: {\n baseUrl: string;\n headers: Record<string, string>;\n jsonl: string;\n purpose: string;\n}): Promise<string> => {\n const metadata = new FormData();\n metadata.append(\"purpose\", args.purpose);\n metadata.append(\"file_name\", INPUT_FILE_NAME);\n metadata.append(\"file_type\", \"jsonl\");\n const init = await fetch(`${args.baseUrl}/files`, {\n body: metadata,\n // Let fetch set the multipart content-type/boundary; only auth is needed.\n headers: args.headers,\n method: \"POST\",\n // Together signals the presigned URL via a redirect we must read, not follow.\n redirect: \"manual\",\n });\n const location = init.headers.get(\"location\");\n const fileId = init.headers.get(\"x-together-file-id\");\n if (init.status !== HTTP_FOUND || !(location && fileId)) {\n throw new BatchworkError(\n `batchwork: Together upload could not be initiated (${init.status}).`\n );\n }\n\n // The presigned URL carries its own auth; sending Together's would break it.\n const uploadLocation = validateUploadLocation(location);\n const upload = await fetch(uploadLocation, {\n body: args.jsonl,\n method: \"PUT\",\n redirect: \"manual\",\n });\n if (!upload.ok) {\n throw new BatchworkError(\n `batchwork: Together file upload failed (${upload.status}).`\n );\n }\n\n const safeFileId = assertSimpleProviderId(\"Together file id\", fileId);\n await requestJson(`${args.baseUrl}/files/${safeFileId}/preprocess`, {\n headers: args.headers,\n method: \"POST\",\n });\n return safeFileId;\n};\n\n/**\n * Together AI batch adapter. Together's batch API mirrors OpenAI's (Files API +\n * `/batches`) but uses the leaner `{ custom_id, body }` input-line shape, with\n * the endpoint declared on the batch rather than per line, and a presigned-URL\n * file upload in place of OpenAI's direct multipart POST.\n */\nexport const togetherAdapter = createOpenAICompatibleAdapter({\n apiKeyEnv: \"TOGETHER_API_KEY\",\n apiKeyLabel: \"Together AI\",\n baseUrl: \"https://api.together.xyz/v1\",\n filePurpose: \"batch-api\",\n id: \"together\",\n // Audio endpoints expect multipart on the sync API; the batch worker uses\n // `method: \"FILE\"` to switch its dispatch mode and fetch `body.file`.\n lineExtras: (endpoint) =>\n endpoint.startsWith(\"/v1/audio/\") ? { method: \"FILE\" } : undefined,\n lineFormat: \"body-only\",\n uploadFile: uploadTogetherFile,\n});\n",
21
+ "import { requestJson } from \"../http\";\nimport { encodeJsonl } from \"../jsonl\";\nimport { resolveBatchLimits } from \"../limits\";\nimport type {\n BatchImage,\n BatchResult,\n BatchSnapshot,\n BatchStatus,\n BatchVideo,\n HttpHeaders,\n JsonObject,\n JsonValue,\n ProviderCredentials,\n} from \"../types\";\nimport { asArray, asNumber, asRecord, asString, omit, toDate } from \"../util\";\nimport type { BatchAdapter, SubmitInput } from \"./adapter\";\nimport { assertSimpleProviderId } from \"./ids\";\nimport {\n resolveApiKey,\n textFromBody,\n uploadInputFile,\n usageFromBody,\n} from \"./shared\";\n\nconst XAI_BASE = \"https://api.x.ai/v1\";\nconst BATCH_ID_LABEL = \"xAI batch id\";\nconst RESULTS_PAGE_SIZE = 100;\n\nconst apiKey = (credentials: ProviderCredentials): string =>\n resolveApiKey(credentials, \"XAI_API_KEY\", \"xAI\");\n\nconst baseUrl = (credentials: ProviderCredentials): string =>\n credentials.baseURL ?? XAI_BASE;\n\nconst authHeaders = (credentials: ProviderCredentials): HttpHeaders => ({\n Authorization: `Bearer ${apiKey(credentials)}`,\n ...credentials.headers,\n});\n\nconst deriveStatus = (state: JsonObject): BatchStatus => {\n const pending = asNumber(state.num_pending);\n // No counts yet (e.g. immediately after creation): still processing.\n if (pending === undefined) {\n return \"in_progress\";\n }\n const total = asNumber(state.num_requests) ?? 0;\n const cancelled = asNumber(state.num_cancelled) ?? 0;\n if (total === 0) {\n return \"in_progress\";\n }\n if (pending > 0) {\n return \"in_progress\";\n }\n if (cancelled > 0 && cancelled === total) {\n return \"cancelled\";\n }\n return \"completed\";\n};\n\nconst normalizeSnapshot = (raw: JsonValue): BatchSnapshot => {\n const obj = asRecord(raw);\n const state = asRecord(obj.state);\n const id = asString(obj.batch_id) ?? asString(obj.id) ?? \"\";\n return {\n // xAI reports the completion time on `finish_time`; `cancel_time` is only\n // set when a batch is cancelled, so it must not stand in for completedAt.\n completedAt: toDate(obj.finish_time ?? obj.completed_at),\n createdAt: toDate(obj.create_time),\n expiresAt: toDate(obj.expire_time ?? obj.expires_at),\n id: id ? assertSimpleProviderId(BATCH_ID_LABEL, id) : \"\",\n provider: \"xai\",\n raw,\n requestCounts: {\n canceled: asNumber(state.num_cancelled) ?? 0,\n completed: asNumber(state.num_success) ?? 0,\n failed: asNumber(state.num_error) ?? 0,\n processing: asNumber(state.num_pending) ?? 0,\n total: asNumber(state.num_requests) ?? 0,\n },\n status: deriveStatus(state),\n };\n};\n\n/**\n * Read images from an xAI batch image result. The `image_response` op carries\n * either an OpenAI-like `data: [{ base64|b64_json, url }]` array or a single\n * `{ base64, url }`; xAI batch hands back signed `url`s (expiring ~1h) and/or\n * inline `base64`. Returns undefined for chat results, which carry neither.\n */\nconst imagesFromXaiCompletion = (\n completion: JsonValue | undefined\n): BatchImage[] | undefined => {\n const obj = asRecord(completion);\n const entries = asArray(obj.data);\n const sources = entries.length > 0 ? entries : [obj];\n const images: BatchImage[] = [];\n for (const source of sources) {\n const record = asRecord(source);\n const data = asString(record.base64) ?? asString(record.b64_json);\n const url = asString(record.url);\n if (data || url) {\n const image: BatchImage = {};\n if (data) {\n image.data = data;\n }\n if (url) {\n image.url = url;\n }\n images.push(image);\n }\n }\n return images.length > 0 ? images : undefined;\n};\n\n/**\n * Read videos from an xAI batch video result. The completion carries either\n * the status-response shape (`{ video: { url, duration } }`) or a flat\n * `{ url, duration }`; either way the signed `url` expires ~1h after\n * completion. Only called for video ops, so image/chat results are unaffected.\n */\nconst videosFromXaiCompletion = (\n completion: JsonValue | undefined\n): BatchVideo[] | undefined => {\n const obj = asRecord(completion);\n const entries = asArray(obj.data);\n const sources = entries.length > 0 ? entries : [obj];\n const videos: BatchVideo[] = [];\n for (const source of sources) {\n const record = asRecord(source);\n const video = asRecord(record.video);\n const url = asString(video.url) ?? asString(record.url);\n if (url) {\n const entry: BatchVideo = { url };\n const duration = asNumber(video.duration) ?? asNumber(record.duration);\n if (duration !== undefined) {\n entry.durationSeconds = duration;\n }\n videos.push(entry);\n }\n }\n return videos.length > 0 ? videos : undefined;\n};\n\nconst normalizeResult = (item: JsonValue): BatchResult => {\n const obj = asRecord(item);\n const customId = asString(obj.batch_request_id) ?? \"\";\n const batchResult = asRecord(obj.batch_result);\n const resultError = batchResult.error;\n const errorMessage =\n asString(obj.error_message) ??\n asString(resultError) ??\n asString(asRecord(resultError).message);\n if (errorMessage) {\n return {\n customId,\n error: {\n message: errorMessage,\n type: asString(asRecord(resultError).type),\n },\n response: obj,\n status: \"errored\",\n };\n }\n // `batch_result.response` is keyed by operation type; chat lives under\n // `chat_get_completion`. Fall back to the first value for other op types,\n // using the key to tell video ops apart from image ops (a video completion's\n // `{ url }` would otherwise read as a hosted image).\n const response = asRecord(batchResult.response);\n const [opKey] = Object.keys(response);\n const completion = response.chat_get_completion ?? Object.values(response)[0];\n const isVideo =\n response.chat_get_completion === undefined &&\n opKey !== undefined &&\n opKey.includes(\"video\");\n return {\n customId,\n ...(isVideo\n ? { videos: videosFromXaiCompletion(completion) }\n : { images: imagesFromXaiCompletion(completion) }),\n response: completion,\n status: \"succeeded\",\n text: textFromBody(completion),\n usage: usageFromBody(completion),\n };\n};\n\nconst submit = async (input: SubmitInput): Promise<BatchSnapshot> => {\n const limits = resolveBatchLimits(input.limits);\n const jsonl = encodeJsonl(\n input.built.map((item) => ({\n body: omit(item.body, \"stream\"),\n custom_id: item.customId,\n // Per-line endpoint: xAI sets no endpoint on the batch itself, and video\n // batches can mix generate/edit/extend lines with different URLs.\n method: \"POST\",\n url: item.endpoint || input.endpoint,\n })),\n { label: \"batch upload JSONL\", maxBytes: limits.maxUploadBytes }\n );\n const inputFileId = await uploadInputFile(\n jsonl,\n baseUrl(input.credentials),\n authHeaders(input.credentials),\n { purpose: null }\n );\n const raw = await requestJson(`${baseUrl(input.credentials)}/batches`, {\n body: JSON.stringify({ input_file_id: inputFileId, name: \"batchwork\" }),\n headers: {\n ...authHeaders(input.credentials),\n \"content-type\": \"application/json\",\n },\n method: \"POST\",\n });\n return normalizeSnapshot(raw);\n};\n\nconst retrieve = async (\n id: string,\n credentials: ProviderCredentials\n): Promise<BatchSnapshot> => {\n const batchId = assertSimpleProviderId(BATCH_ID_LABEL, id);\n const raw = await requestJson(`${baseUrl(credentials)}/batches/${batchId}`, {\n headers: authHeaders(credentials),\n });\n return normalizeSnapshot(raw);\n};\n\n// oxlint-disable-next-line func-style -- generators cannot be arrow functions.\nasync function* results(\n id: string,\n credentials: ProviderCredentials\n): AsyncGenerator<BatchResult> {\n const batchId = assertSimpleProviderId(BATCH_ID_LABEL, id);\n const headers = authHeaders(credentials);\n let token: string | undefined;\n do {\n const query = new URLSearchParams({ limit: String(RESULTS_PAGE_SIZE) });\n if (token) {\n query.set(\"pagination_token\", token);\n }\n // oxlint-disable-next-line no-await-in-loop, react-doctor/async-await-in-loop -- pages are read sequentially.\n const raw = await requestJson(\n `${baseUrl(credentials)}/batches/${batchId}/results?${query.toString()}`,\n { headers }\n );\n const page = asRecord(raw);\n for (const item of asArray(page.results)) {\n yield normalizeResult(item);\n }\n token = asString(page.pagination_token);\n } while (token);\n}\n\nconst cancel = async (\n id: string,\n credentials: ProviderCredentials\n): Promise<void> => {\n const batchId = assertSimpleProviderId(BATCH_ID_LABEL, id);\n await requestJson(`${baseUrl(credentials)}/batches/${batchId}:cancel`, {\n headers: authHeaders(credentials),\n method: \"POST\",\n });\n};\n\n/**\n * xAI (Grok) batch adapter. Uses xAI's OpenAI-compatible file-upload path\n * (`/v1/files` + `/v1/batches` with `input_file_id`), but its status, paginated\n * `/results`, and `:cancel` shapes are proprietary.\n */\nexport const xaiAdapter: BatchAdapter = {\n cancel,\n id: \"xai\",\n results,\n retrieve,\n submit,\n};\n",
22
+ "import type { BatchProvider } from \"../types\";\nimport type { BatchAdapter } from \"./adapter\";\nimport { anthropicAdapter } from \"./anthropic\";\nimport { azureAdapter } from \"./azure\";\nimport { googleAdapter } from \"./google\";\nimport { groqAdapter } from \"./groq\";\nimport { mistralAdapter } from \"./mistral\";\nimport { openaiAdapter } from \"./openai\";\nimport { togetherAdapter } from \"./together\";\nimport { xaiAdapter } from \"./xai\";\n\nconst adapters: Record<BatchProvider, BatchAdapter> = {\n anthropic: anthropicAdapter,\n azure: azureAdapter,\n google: googleAdapter,\n groq: groqAdapter,\n mistral: mistralAdapter,\n openai: openaiAdapter,\n together: togetherAdapter,\n xai: xaiAdapter,\n};\n\nexport const getAdapter = (provider: BatchProvider): BatchAdapter =>\n adapters[provider];\n\nexport type { BatchAdapter, SubmitInput } from \"./adapter\";\n"
23
+ ],
24
+ "mappings": "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",
25
+ "debugId": "7B0EC738FEADB97E64756E2164756E21",
26
+ "names": []
27
+ }
@@ -1,8 +1,13 @@
1
1
  import {
2
- BatchworkError,
3
- getAdapter,
4
- isTerminalStatus
5
- } from "./chunk-n50t31ca.js";
2
+ BatchworkError2,
3
+ isTerminalStatus2,
4
+ getAdapter
5
+ } from "./chunk-7y95mhvm.js";
6
+ import {
7
+ parseJson,
8
+ asRecord,
9
+ asString
10
+ } from "./chunk-6jgvqdpc.js";
6
11
 
7
12
  // src/server/events.ts
8
13
  var EVENT_BY_STATUS = {
@@ -79,7 +84,7 @@ var rememberWebhookId = async (id, timestamp, now, store) => {
79
84
  if (store.claim) {
80
85
  const claimed = await store.claim(id, expiresAt, now);
81
86
  if (!claimed) {
82
- throw new BatchworkError("batchwork: webhook replay detected.");
87
+ throw new BatchworkError2("batchwork: webhook replay detected.");
83
88
  }
84
89
  return;
85
90
  }
@@ -89,12 +94,12 @@ var rememberWebhookId = async (id, timestamp, now, store) => {
89
94
  }
90
95
  const existing = await store.get(id);
91
96
  if (existing && existing > now) {
92
- throw new BatchworkError("batchwork: webhook replay detected.");
97
+ throw new BatchworkError2("batchwork: webhook replay detected.");
93
98
  }
94
99
  await store.set(id, expiresAt);
95
100
  });
96
101
  };
97
- var signWebhook = (secret, id, body, timestampSeconds) => {
102
+ var signWebhook2 = (secret, id, body, timestampSeconds) => {
98
103
  const timestamp = Math.floor(timestampSeconds);
99
104
  const signature = createWebhook(secret).sign(id, new Date(timestamp * 1000), body);
100
105
  return Promise.resolve({
@@ -103,17 +108,17 @@ var signWebhook = (secret, id, body, timestampSeconds) => {
103
108
  "webhook-timestamp": timestamp.toString()
104
109
  });
105
110
  };
106
- var verifyWebhook = async (request, secret, options) => {
111
+ var verifyWebhook2 = async (request, secret, options) => {
107
112
  const id = request.headers.get("webhook-id");
108
113
  const timestamp = request.headers.get("webhook-timestamp");
109
114
  const signatureHeader = request.headers.get("webhook-signature");
110
115
  if (!(id && timestamp && signatureHeader)) {
111
- throw new BatchworkError("batchwork: missing webhook signature headers.");
116
+ throw new BatchworkError2("batchwork: missing webhook signature headers.");
112
117
  }
113
118
  const seconds = Number(timestamp);
114
119
  const now = Date.now() / 1000;
115
120
  if (!Number.isFinite(seconds) || Math.abs(now - seconds) > TOLERANCE_SECONDS) {
116
- throw new BatchworkError("batchwork: webhook timestamp outside tolerance.");
121
+ throw new BatchworkError2("batchwork: webhook timestamp outside tolerance.");
117
122
  }
118
123
  const body = await request.text();
119
124
  try {
@@ -124,19 +129,26 @@ var verifyWebhook = async (request, secret, options) => {
124
129
  });
125
130
  } catch (error) {
126
131
  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 });
132
+ throw new BatchworkError2(error.message.toLowerCase().includes("timestamp") ? "batchwork: webhook timestamp outside tolerance." : "batchwork: webhook signature verification failed.", { cause: error });
128
133
  }
129
134
  }
130
135
  await rememberWebhookId(id, seconds, now, options?.replayStore ?? defaultReplayStore);
131
136
  return { body, id, timestamp: seconds };
132
137
  };
133
- var verifyBatchWebhook = async (request, secret, options) => {
134
- const { body } = await verifyWebhook(request, secret, options);
138
+ var verifyBatchWebhook2 = async (request, secret, options) => {
139
+ const { body } = await verifyWebhook2(request, secret, options);
135
140
  return JSON.parse(body);
136
141
  };
137
142
 
138
143
  // src/server/poller.ts
139
144
  import ipaddr from "ipaddr.js";
145
+ var isCredentialFunction = (credentials) => typeof credentials === "function";
146
+ var resolveProviderCredentials = (credentials, provider) => {
147
+ if (credentials === undefined) {
148
+ return {};
149
+ }
150
+ return isCredentialFunction(credentials) ? credentials(provider) : credentials;
151
+ };
140
152
  var isPrivateHost = (host) => {
141
153
  if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local")) {
142
154
  return true;
@@ -150,13 +162,13 @@ var isPrivateHost = (host) => {
150
162
  var isRedirectStatus = (status) => status >= 300 && status < 400;
151
163
  var assertSafeWebhookUrl = (url) => {
152
164
  if (url.protocol !== "https:") {
153
- throw new BatchworkError("batchwork: webhookUrl must use https.");
165
+ throw new BatchworkError2("batchwork: webhookUrl must use https.");
154
166
  }
155
167
  if (url.username || url.password) {
156
- throw new BatchworkError("batchwork: webhookUrl must not include credentials.");
168
+ throw new BatchworkError2("batchwork: webhookUrl must not include credentials.");
157
169
  }
158
170
  if (isPrivateHost(url.hostname.toLowerCase())) {
159
- throw new BatchworkError("batchwork: webhookUrl must not target localhost or private networks.");
171
+ throw new BatchworkError2("batchwork: webhookUrl must not target localhost or private networks.");
160
172
  }
161
173
  };
162
174
  var validateWebhookUrl = async (rawUrl, validator) => {
@@ -164,7 +176,7 @@ var validateWebhookUrl = async (rawUrl, validator) => {
164
176
  try {
165
177
  url = new URL(rawUrl);
166
178
  } catch (error) {
167
- throw new BatchworkError("batchwork: webhookUrl must be a valid URL.", {
179
+ throw new BatchworkError2("batchwork: webhookUrl must be a valid URL.", {
168
180
  cause: error
169
181
  });
170
182
  }
@@ -173,15 +185,13 @@ var validateWebhookUrl = async (rawUrl, validator) => {
173
185
  };
174
186
  var createWebhookSink = (validator) => async (record, snapshot) => {
175
187
  if (!record.webhookUrl) {
176
- throw new BatchworkError("batchwork: tracked batch has no webhookUrl to deliver to.");
188
+ throw new BatchworkError2("batchwork: tracked batch has no webhookUrl to deliver to.");
177
189
  }
178
190
  const webhookUrl = await validateWebhookUrl(record.webhookUrl, validator);
179
191
  const body = JSON.stringify(toEvent(record.provider, snapshot));
180
- const headers = {
181
- "content-type": "application/json"
182
- };
192
+ const headers = { "content-type": "application/json" };
183
193
  if (record.webhookSecret) {
184
- Object.assign(headers, await signWebhook(record.webhookSecret, record.id, body, Date.now() / 1000));
194
+ Object.assign(headers, await signWebhook2(record.webhookSecret, record.id, body, Date.now() / 1000));
185
195
  }
186
196
  const response = await fetch(webhookUrl, {
187
197
  body,
@@ -190,19 +200,14 @@ var createWebhookSink = (validator) => async (record, snapshot) => {
190
200
  redirect: "manual"
191
201
  });
192
202
  if (isRedirectStatus(response.status)) {
193
- throw new BatchworkError(`batchwork: webhook delivery to ${webhookUrl} redirected (${response.status}).`);
203
+ throw new BatchworkError2(`batchwork: webhook delivery to ${webhookUrl} redirected (${response.status}).`);
194
204
  }
195
205
  if (!response.ok) {
196
- throw new BatchworkError(`batchwork: webhook delivery to ${webhookUrl} failed (${response.status}).`);
206
+ throw new BatchworkError2(`batchwork: webhook delivery to ${webhookUrl} failed (${response.status}).`);
197
207
  }
198
208
  };
199
- var createBatchPoller = (options) => {
200
- const resolveCredentials = (provider) => {
201
- if (typeof options.credentials === "function") {
202
- return options.credentials(provider);
203
- }
204
- return options.credentials ?? {};
205
- };
209
+ var createBatchPoller2 = (options) => {
210
+ const resolveCredentials = (provider) => resolveProviderCredentials(options.credentials, provider);
206
211
  const webhookUrlValidator = options.validateWebhookUrl ?? assertSafeWebhookUrl;
207
212
  const sink = options.onComplete ?? createWebhookSink(webhookUrlValidator);
208
213
  const deliver = async (record, snapshot) => {
@@ -229,7 +234,7 @@ var createBatchPoller = (options) => {
229
234
  const process = async (record, delivered) => {
230
235
  const adapter = getAdapter(record.provider);
231
236
  const snapshot = await adapter.retrieve(record.id, resolveCredentials(record.provider));
232
- if (isTerminalStatus(snapshot.status)) {
237
+ if (isTerminalStatus2(snapshot.status)) {
233
238
  await deliver(record, snapshot);
234
239
  delivered.push(record.id);
235
240
  } else if (snapshot.status !== record.status) {
@@ -259,15 +264,15 @@ var createBatchPoller = (options) => {
259
264
  const openaiWebhookHandler = (config) => async (request) => {
260
265
  let verified;
261
266
  try {
262
- verified = await verifyWebhook(request, config.signingSecret);
267
+ verified = await verifyWebhook2(request, config.signingSecret);
263
268
  } catch {
264
269
  return new Response("invalid signature", { status: 400 });
265
270
  }
266
- const payload = JSON.parse(verified.body);
267
- if (!payload.type?.startsWith("batch.")) {
271
+ const payload = asRecord(parseJson(verified.body));
272
+ if (!asString(payload.type)?.startsWith("batch.")) {
268
273
  return new Response("ignored", { status: 202 });
269
274
  }
270
- const id = payload.data?.id;
275
+ const id = asString(asRecord(payload.data).id);
271
276
  if (!id) {
272
277
  return new Response("missing batch id", { status: 400 });
273
278
  }
@@ -276,7 +281,7 @@ var createBatchPoller = (options) => {
276
281
  return new Response("ok", { status: 200 });
277
282
  }
278
283
  const snapshot = await getAdapter("openai").retrieve(id, resolveCredentials("openai"));
279
- if (isTerminalStatus(snapshot.status)) {
284
+ if (isTerminalStatus2(snapshot.status)) {
280
285
  await deliver(record, snapshot);
281
286
  }
282
287
  return new Response("ok", { status: 200 });
@@ -285,7 +290,7 @@ var createBatchPoller = (options) => {
285
290
  };
286
291
 
287
292
  // src/server/store.ts
288
- var createMemoryStore = () => {
293
+ var createMemoryStore2 = () => {
289
294
  const records = new Map;
290
295
  return {
291
296
  delete: (id) => {
@@ -308,7 +313,7 @@ var createMemoryStore = () => {
308
313
  };
309
314
  };
310
315
 
311
- export { toEvent, signWebhook, verifyWebhook, verifyBatchWebhook, createBatchPoller, createMemoryStore };
316
+ export { toEvent, signWebhook2, verifyWebhook2, verifyBatchWebhook2, resolveProviderCredentials, createBatchPoller2, createMemoryStore2 };
312
317
 
313
- //# debugId=CAEF2BF262DED87C64756E2164756E21
314
- //# sourceMappingURL=chunk-mathjpg6.js.map
318
+ //# debugId=A205BBC0AF616CBE64756E2164756E21
319
+ //# sourceMappingURL=chunk-k7n7k3et.js.map
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/server/events.ts", "../src/server/signing.ts", "../src/server/poller.ts", "../src/server/store.ts"],
4
+ "sourcesContent": [
5
+ "import type { BatchProvider, BatchSnapshot, BatchStatus } from \"../types\";\nimport type { BatchWebhookEvent, BatchWebhookEventType } from \"./types\";\n\nconst EVENT_BY_STATUS: Partial<Record<BatchStatus, BatchWebhookEventType>> = {\n cancelled: \"batch.cancelled\",\n completed: \"batch.completed\",\n expired: \"batch.expired\",\n failed: \"batch.failed\",\n};\n\n/** Map a terminal snapshot to the unified webhook event batchwork delivers. */\nexport const toEvent = (\n provider: BatchProvider,\n snapshot: BatchSnapshot\n): BatchWebhookEvent => ({\n completedAt: snapshot.completedAt?.toISOString(),\n createdAt: snapshot.createdAt?.toISOString(),\n id: snapshot.id,\n provider,\n requestCounts: snapshot.requestCounts,\n type: EVENT_BY_STATUS[snapshot.status] ?? \"batch.completed\",\n});\n",
6
+ "import { Webhook, WebhookVerificationError } from \"standardwebhooks\";\n\nimport { BatchworkError } from \"../errors\";\nimport type { BatchWebhookEvent } from \"./types\";\n\n// Standard Webhooks HMAC-SHA256 signing via the reference `standardwebhooks`\n// implementation, compatible with OpenAI's webhook signatures (so the same\n// verifier handles inbound OpenAI events and batchwork's own outbound\n// deliveries). The library is pure JS, so it runs on edge runtimes.\n\nconst TOLERANCE_SECONDS = 300;\nconst SECRET_PREFIX = \"whsec_\";\nconst encoder = new TextEncoder();\n\n/**\n * A `whsec_` secret is base64-encoded key material (the library decodes it);\n * anything else is used as raw UTF-8 bytes, matching OpenAI's conventions.\n */\nconst createWebhook = (secret: string): Webhook =>\n secret.startsWith(SECRET_PREFIX)\n ? new Webhook(secret)\n : new Webhook(encoder.encode(secret), { format: \"raw\" });\n\nexport interface WebhookReplayStore {\n claim?: (\n id: string,\n expiresAt: number,\n now: number\n ) => boolean | Promise<boolean>;\n get: (id: string) => number | Promise<number | undefined> | undefined;\n set: (id: string, expiresAt: number) => Promise<void> | void;\n}\n\nexport interface VerifyWebhookOptions {\n replayStore?: WebhookReplayStore;\n}\n\nconst replayCache = new Map<string, number>();\nconst replayLocks = new WeakMap<\n WebhookReplayStore,\n Map<string, Promise<void>>\n>();\n\nconst pruneReplayCache = (now: number): void => {\n for (const [id, expiresAt] of replayCache) {\n if (expiresAt <= now) {\n replayCache.delete(id);\n }\n }\n};\n\nconst defaultReplayStore: WebhookReplayStore = {\n claim: (id, expiresAt, now) => {\n pruneReplayCache(now);\n const existing = replayCache.get(id);\n if (existing && existing > now) {\n return false;\n }\n replayCache.set(id, expiresAt);\n return true;\n },\n get: (id) => replayCache.get(id),\n set: (id, expiresAt) => {\n replayCache.set(id, expiresAt);\n },\n};\n\nconst withReplayLock = async <Result>(\n store: WebhookReplayStore,\n id: string,\n task: () => Promise<Result>\n): Promise<Result> => {\n let locks = replayLocks.get(store);\n if (!locks) {\n locks = new Map();\n replayLocks.set(store, locks);\n }\n\n const previous = locks.get(id);\n let release!: () => void;\n // oxlint-disable-next-line promise/avoid-new -- a per-id lock needs a deferred release signal.\n const current = new Promise<void>((resolve) => {\n release = resolve;\n });\n locks.set(id, current);\n\n if (previous) {\n await previous;\n }\n try {\n return await task();\n } finally {\n release();\n if (locks.get(id) === current) {\n locks.delete(id);\n }\n }\n};\n\nconst rememberWebhookId = async (\n id: string,\n timestamp: number,\n now: number,\n store: WebhookReplayStore\n): Promise<void> => {\n const expiresAt = timestamp + TOLERANCE_SECONDS;\n if (store.claim) {\n const claimed = await store.claim(id, expiresAt, now);\n if (!claimed) {\n throw new BatchworkError(\"batchwork: webhook replay detected.\");\n }\n return;\n }\n\n await withReplayLock(store, id, async () => {\n if (store === defaultReplayStore) {\n pruneReplayCache(now);\n }\n const existing = await store.get(id);\n if (existing && existing > now) {\n throw new BatchworkError(\"batchwork: webhook replay detected.\");\n }\n await store.set(id, expiresAt);\n });\n};\n\n/** Build Standard Webhooks signature headers for an outbound delivery. */\nexport const signWebhook = (\n secret: string,\n id: string,\n body: string,\n timestampSeconds: number\n): Promise<Record<string, string>> => {\n const timestamp = Math.floor(timestampSeconds);\n // `sign` returns the already version-prefixed signature (`v1,…`).\n const signature = createWebhook(secret).sign(\n id,\n new Date(timestamp * 1000),\n body\n );\n return Promise.resolve({\n \"webhook-id\": id,\n \"webhook-signature\": signature,\n \"webhook-timestamp\": timestamp.toString(),\n });\n};\n\nexport interface VerifiedWebhook {\n id: string;\n timestamp: number;\n body: string;\n}\n\n/**\n * Verify a Standard Webhooks-signed request and return its raw body. Throws if\n * headers are missing, the timestamp is outside tolerance, or no signature\n * matches. Consumes the request body.\n */\nexport const verifyWebhook = async (\n request: Request,\n secret: string,\n options?: VerifyWebhookOptions\n): Promise<VerifiedWebhook> => {\n const id = request.headers.get(\"webhook-id\");\n const timestamp = request.headers.get(\"webhook-timestamp\");\n const signatureHeader = request.headers.get(\"webhook-signature\");\n if (!(id && timestamp && signatureHeader)) {\n throw new BatchworkError(\"batchwork: missing webhook signature headers.\");\n }\n\n const seconds = Number(timestamp);\n const now = Date.now() / 1000;\n if (\n !Number.isFinite(seconds) ||\n Math.abs(now - seconds) > TOLERANCE_SECONDS\n ) {\n throw new BatchworkError(\"batchwork: webhook timestamp outside tolerance.\");\n }\n\n const body = await request.text();\n try {\n createWebhook(secret).verify(body, {\n \"webhook-id\": id,\n \"webhook-signature\": signatureHeader,\n \"webhook-timestamp\": timestamp,\n });\n } catch (error) {\n if (error instanceof WebhookVerificationError) {\n // The library re-checks the timestamp with the same tolerance; map its\n // failures onto the tolerance error above for a stable error surface.\n throw new BatchworkError(\n error.message.toLowerCase().includes(\"timestamp\")\n ? \"batchwork: webhook timestamp outside tolerance.\"\n : \"batchwork: webhook signature verification failed.\",\n { cause: error }\n );\n }\n // Any other error means the signature verified but the library's trailing\n // `JSON.parse` of the payload failed. `verifyWebhook` returns the raw body\n // and does not require JSON, so a non-JSON body is not an error here.\n }\n\n await rememberWebhookId(\n id,\n seconds,\n now,\n options?.replayStore ?? defaultReplayStore\n );\n\n return { body, id, timestamp: seconds };\n};\n\n/**\n * Verify and parse a batchwork webhook on your receiving endpoint. Returns the\n * unified {@link BatchWebhookEvent}.\n */\nexport const verifyBatchWebhook = async (\n request: Request,\n secret: string,\n options?: VerifyWebhookOptions\n): Promise<BatchWebhookEvent> => {\n const { body } = await verifyWebhook(request, secret, options);\n // SAFETY: the signature just verified against the shared secret proves the\n // body was produced by batchwork's own delivery, which serializes `toEvent`.\n return JSON.parse(body) as BatchWebhookEvent;\n};\n",
7
+ "import ipaddr from \"ipaddr.js\";\n\nimport { BatchworkError } from \"../errors\";\nimport { isTerminalStatus } from \"../job\";\nimport { getAdapter } from \"../providers\";\nimport type {\n BatchProvider,\n BatchSnapshot,\n BatchStatus,\n HttpHeaders,\n ProviderCredentials,\n} from \"../types\";\nimport { asRecord, asString, parseJson } from \"../util\";\nimport { toEvent } from \"./events\";\nimport { signWebhook, verifyWebhook } from \"./signing\";\nimport type { BatchStore, TrackedBatch } from \"./types\";\n\n/** Credentials for polling: a fixed config, or one resolved per provider. */\nexport type CredentialResolver =\n | ProviderCredentials\n | ((provider: BatchProvider) => ProviderCredentials);\n\nconst isCredentialFunction = (\n credentials: CredentialResolver\n): credentials is (provider: BatchProvider) => ProviderCredentials =>\n typeof credentials === \"function\";\n\n/** Resolve the credentials to poll a provider with; env vars when omitted. */\nexport const resolveProviderCredentials = (\n credentials: CredentialResolver | undefined,\n provider: BatchProvider\n): ProviderCredentials => {\n if (credentials === undefined) {\n return {};\n }\n return isCredentialFunction(credentials)\n ? credentials(provider)\n : credentials;\n};\n\n/**\n * Handles a batch reaching a terminal status. Replaces the default signed\n * webhook delivery — e.g. to invoke a callback instead (see `batchwork/next`).\n */\nexport type CompletionSink = (\n record: TrackedBatch,\n snapshot: BatchSnapshot\n) => Promise<void>;\n\nexport type WebhookUrlValidator = (url: URL) => void | Promise<void>;\n\nexport interface BatchPollerOptions {\n store: BatchStore;\n /** Falls back to provider env vars (e.g. `OPENAI_API_KEY`) when omitted. */\n credentials?: CredentialResolver;\n /** Replaces signed-webhook delivery when a batch finishes. */\n onComplete?: CompletionSink;\n /** Override the default webhook URL policy with an application allowlist. */\n validateWebhookUrl?: WebhookUrlValidator;\n /**\n * Called with the thrown value when processing a single batch fails during\n * `tick`. When provided, the tick reports the error and continues to the\n * next batch; when omitted, the error propagates out of `tick`.\n */\n onError?: (record: TrackedBatch, cause: unknown) => void;\n}\n\nexport interface TrackTarget {\n id: string;\n provider: BatchProvider;\n status?: BatchStatus;\n}\n\nexport interface TrackOptions {\n /** Where to POST the completion webhook. Omit for callback-based delivery. */\n webhookUrl?: string;\n /** Signs the outbound webhook (Standard Webhooks HMAC) when provided. */\n secret?: string;\n}\n\nexport interface TickResult {\n checked: number;\n delivered: string[];\n /** Batches whose processing threw this tick (only when `onError` is set). */\n failed?: { id: string; error: string }[];\n}\n\nexport interface OpenAIWebhookOptions {\n /** The OpenAI webhook signing secret (`whsec_…`). */\n signingSecret: string;\n}\n\nexport interface BatchPoller {\n track: (target: TrackTarget, options: TrackOptions) => Promise<TrackedBatch>;\n tick: () => Promise<TickResult>;\n deliver: (record: TrackedBatch, snapshot: BatchSnapshot) => Promise<void>;\n openaiWebhookHandler: (\n options: OpenAIWebhookOptions\n ) => (request: Request) => Promise<Response>;\n}\n\n/** Whether a hostname points at localhost or a private network. */\nconst isPrivateHost = (host: string): boolean => {\n if (\n host === \"localhost\" ||\n host.endsWith(\".localhost\") ||\n host.endsWith(\".local\")\n ) {\n return true;\n }\n // A URL hostname wraps IPv6 literals in brackets; ipaddr.js expects them bare.\n const literal = host.replace(/^\\[/u, \"\").replace(/\\]$/u, \"\");\n if (!ipaddr.isValid(literal)) {\n // A DNS name; only literal addresses are classified here.\n return false;\n }\n // `process` unwraps IPv4-mapped IPv6 (`::ffff:127.0.0.1`) to IPv4 first.\n // Anything but plain public unicast (loopback, private, link-local, CGNAT,\n // multicast, reserved, teredo/6to4 with embedded addresses, …) is refused.\n return ipaddr.process(literal).range() !== \"unicast\";\n};\n\nconst isRedirectStatus = (status: number): boolean =>\n status >= 300 && status < 400;\n\nconst assertSafeWebhookUrl: WebhookUrlValidator = (url) => {\n if (url.protocol !== \"https:\") {\n throw new BatchworkError(\"batchwork: webhookUrl must use https.\");\n }\n if (url.username || url.password) {\n throw new BatchworkError(\n \"batchwork: webhookUrl must not include credentials.\"\n );\n }\n\n if (isPrivateHost(url.hostname.toLowerCase())) {\n throw new BatchworkError(\n \"batchwork: webhookUrl must not target localhost or private networks.\"\n );\n }\n};\n\nconst validateWebhookUrl = async (\n rawUrl: string,\n validator: WebhookUrlValidator\n): Promise<string> => {\n let url: URL;\n try {\n url = new URL(rawUrl);\n } catch (error) {\n throw new BatchworkError(\"batchwork: webhookUrl must be a valid URL.\", {\n cause: error,\n });\n }\n await validator(url);\n return url.toString();\n};\n\n/** The default completion sink: POST a signed webhook to the tracked URL. */\nconst createWebhookSink =\n (validator: WebhookUrlValidator): CompletionSink =>\n async (record, snapshot) => {\n if (!record.webhookUrl) {\n throw new BatchworkError(\n \"batchwork: tracked batch has no webhookUrl to deliver to.\"\n );\n }\n const webhookUrl = await validateWebhookUrl(record.webhookUrl, validator);\n const body = JSON.stringify(toEvent(record.provider, snapshot));\n const headers: HttpHeaders = { \"content-type\": \"application/json\" };\n if (record.webhookSecret) {\n Object.assign(\n headers,\n await signWebhook(\n record.webhookSecret,\n record.id,\n body,\n Date.now() / 1000\n )\n );\n }\n const response = await fetch(webhookUrl, {\n body,\n headers,\n method: \"POST\",\n redirect: \"manual\",\n });\n if (isRedirectStatus(response.status)) {\n throw new BatchworkError(\n `batchwork: webhook delivery to ${webhookUrl} redirected (${response.status}).`\n );\n }\n if (!response.ok) {\n throw new BatchworkError(\n `batchwork: webhook delivery to ${webhookUrl} failed (${response.status}).`\n );\n }\n };\n\n/**\n * Create a managed poller: register submitted batches with `track`, then run\n * `tick` on a schedule (cron) to poll open batches and deliver one unified,\n * signed webhook per batch when it finishes. For OpenAI, mount\n * `openaiWebhookHandler` to skip polling and react to native webhooks instead.\n */\nexport const createBatchPoller = (options: BatchPollerOptions): BatchPoller => {\n const resolveCredentials = (provider: BatchProvider): ProviderCredentials =>\n resolveProviderCredentials(options.credentials, provider);\n\n const webhookUrlValidator =\n options.validateWebhookUrl ?? assertSafeWebhookUrl;\n const sink = options.onComplete ?? createWebhookSink(webhookUrlValidator);\n\n const deliver = async (\n record: TrackedBatch,\n snapshot: BatchSnapshot\n ): Promise<void> => {\n // Run the side effect before marking delivered: if it throws, the record\n // stays pending and is retried on the next tick (at-least-once delivery).\n await sink(record, snapshot);\n await options.store.set({\n ...record,\n deliveredAt: new Date().toISOString(),\n status: snapshot.status,\n });\n };\n\n const track = async (\n target: TrackTarget,\n opts: TrackOptions\n ): Promise<TrackedBatch> => {\n const webhookUrl =\n opts.webhookUrl && !options.onComplete\n ? await validateWebhookUrl(opts.webhookUrl, webhookUrlValidator)\n : opts.webhookUrl;\n const record: TrackedBatch = {\n createdAt: new Date().toISOString(),\n id: target.id,\n provider: target.provider,\n status: target.status ?? \"in_progress\",\n webhookSecret: opts.secret,\n webhookUrl,\n };\n await options.store.set(record);\n return record;\n };\n\n const process = async (\n record: TrackedBatch,\n delivered: string[]\n ): Promise<void> => {\n const adapter = getAdapter(record.provider);\n const snapshot = await adapter.retrieve(\n record.id,\n resolveCredentials(record.provider)\n );\n if (isTerminalStatus(snapshot.status)) {\n await deliver(record, snapshot);\n delivered.push(record.id);\n } else if (snapshot.status !== record.status) {\n await options.store.set({ ...record, status: snapshot.status });\n }\n };\n\n const tick = async (): Promise<TickResult> => {\n const pending = await options.store.list({ delivered: false });\n const delivered: string[] = [];\n const failed: { id: string; error: string }[] = [];\n for (const record of pending) {\n // oxlint-disable-next-line no-await-in-loop -- batches are polled serially\n // to avoid hammering provider rate limits; deliver before the next.\n try {\n // oxlint-disable-next-line no-await-in-loop, react-doctor/async-await-in-loop -- see above.\n await process(record, delivered);\n } catch (error) {\n // Without an `onError` handler, preserve the propagate-the-throw\n // behavior; with one, report and continue so a single failing batch\n // can't starve the rest of the queue. Either way the record stays\n // pending (it was never marked delivered) and retries next tick.\n if (!options.onError) {\n throw error;\n }\n options.onError(record, error);\n failed.push({\n error: error instanceof Error ? error.message : String(error),\n id: record.id,\n });\n }\n }\n return failed.length > 0\n ? { checked: pending.length, delivered, failed }\n : { checked: pending.length, delivered };\n };\n\n const openaiWebhookHandler =\n (config: OpenAIWebhookOptions) =>\n async (request: Request): Promise<Response> => {\n let verified: { body: string };\n try {\n verified = await verifyWebhook(request, config.signingSecret);\n } catch {\n return new Response(\"invalid signature\", { status: 400 });\n }\n\n const payload = asRecord(parseJson(verified.body));\n if (!asString(payload.type)?.startsWith(\"batch.\")) {\n return new Response(\"ignored\", { status: 202 });\n }\n const id = asString(asRecord(payload.data).id);\n if (!id) {\n return new Response(\"missing batch id\", { status: 400 });\n }\n const record = await options.store.get(id);\n if (!record || record.deliveredAt) {\n return new Response(\"ok\", { status: 200 });\n }\n const snapshot = await getAdapter(\"openai\").retrieve(\n id,\n resolveCredentials(\"openai\")\n );\n if (isTerminalStatus(snapshot.status)) {\n await deliver(record, snapshot);\n }\n return new Response(\"ok\", { status: 200 });\n };\n\n return { deliver, openaiWebhookHandler, tick, track };\n};\n",
8
+ "import type { BatchStore, TrackedBatch } from \"./types\";\n\n/** An in-memory `BatchStore`. Suitable for development and single-process use. */\nexport const createMemoryStore = (): BatchStore => {\n const records = new Map<string, TrackedBatch>();\n\n return {\n delete: (id) => {\n records.delete(id);\n return Promise.resolve();\n },\n get: (id) => Promise.resolve(records.get(id) ?? null),\n list: (filter) => {\n const all = [...records.values()];\n if (filter?.delivered === undefined) {\n return Promise.resolve(all);\n }\n const { delivered } = filter;\n return Promise.resolve(\n all.filter((record) => (record.deliveredAt !== undefined) === delivered)\n );\n },\n set: (record) => {\n records.set(record.id, record);\n return Promise.resolve();\n },\n };\n};\n"
9
+ ],
10
+ "mappings": "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",
11
+ "debugId": "A205BBC0AF616CBE64756E2164756E21",
12
+ "names": []
13
+ }