batchwork 0.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -0
  3. package/dist/batch.d.ts +27 -0
  4. package/dist/batch.d.ts.map +1 -0
  5. package/dist/body.d.ts +19 -0
  6. package/dist/body.d.ts.map +1 -0
  7. package/dist/chunk-e6qn48qa.js +301 -0
  8. package/dist/chunk-e6qn48qa.js.map +13 -0
  9. package/dist/chunk-g481f961.js +1212 -0
  10. package/dist/chunk-g481f961.js.map +26 -0
  11. package/dist/chunk-m4n610nm.js +338 -0
  12. package/dist/chunk-m4n610nm.js.map +12 -0
  13. package/dist/chunk-v0bahtg2.js +7 -0
  14. package/dist/chunk-v0bahtg2.js.map +9 -0
  15. package/dist/errors.d.ts +16 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/http.d.ts +5 -0
  18. package/dist/http.d.ts.map +1 -0
  19. package/dist/index.d.ts +6 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +30 -0
  22. package/dist/index.js.map +9 -0
  23. package/dist/job.d.ts +31 -0
  24. package/dist/job.d.ts.map +1 -0
  25. package/dist/jsonl.d.ts +7 -0
  26. package/dist/jsonl.d.ts.map +1 -0
  27. package/dist/limits.d.ts +12 -0
  28. package/dist/limits.d.ts.map +1 -0
  29. package/dist/model.d.ts +32 -0
  30. package/dist/model.d.ts.map +1 -0
  31. package/dist/next/index.d.ts +61 -0
  32. package/dist/next/index.d.ts.map +1 -0
  33. package/dist/next/index.js +64 -0
  34. package/dist/next/index.js.map +10 -0
  35. package/dist/postgres/batch-store.d.ts +19 -0
  36. package/dist/postgres/batch-store.d.ts.map +1 -0
  37. package/dist/postgres/index.d.ts +6 -0
  38. package/dist/postgres/index.d.ts.map +1 -0
  39. package/dist/postgres/index.js +101 -0
  40. package/dist/postgres/index.js.map +12 -0
  41. package/dist/postgres/migrate.d.ts +15 -0
  42. package/dist/postgres/migrate.d.ts.map +1 -0
  43. package/dist/postgres/types.d.ts +26 -0
  44. package/dist/postgres/types.d.ts.map +1 -0
  45. package/dist/providers/adapter.d.ts +25 -0
  46. package/dist/providers/adapter.d.ts.map +1 -0
  47. package/dist/providers/anthropic.d.ts +3 -0
  48. package/dist/providers/anthropic.d.ts.map +1 -0
  49. package/dist/providers/google.d.ts +8 -0
  50. package/dist/providers/google.d.ts.map +1 -0
  51. package/dist/providers/groq.d.ts +8 -0
  52. package/dist/providers/groq.d.ts.map +1 -0
  53. package/dist/providers/ids.d.ts +3 -0
  54. package/dist/providers/ids.d.ts.map +1 -0
  55. package/dist/providers/index.d.ts +5 -0
  56. package/dist/providers/index.d.ts.map +1 -0
  57. package/dist/providers/mistral.d.ts +8 -0
  58. package/dist/providers/mistral.d.ts.map +1 -0
  59. package/dist/providers/openai-compatible.d.ts +41 -0
  60. package/dist/providers/openai-compatible.d.ts.map +1 -0
  61. package/dist/providers/openai.d.ts +7 -0
  62. package/dist/providers/openai.d.ts.map +1 -0
  63. package/dist/providers/shared.d.ts +23 -0
  64. package/dist/providers/shared.d.ts.map +1 -0
  65. package/dist/providers/together.d.ts +8 -0
  66. package/dist/providers/together.d.ts.map +1 -0
  67. package/dist/providers/xai.d.ts +8 -0
  68. package/dist/providers/xai.d.ts.map +1 -0
  69. package/dist/redis/batch-store.d.ts +15 -0
  70. package/dist/redis/batch-store.d.ts.map +1 -0
  71. package/dist/redis/index.d.ts +4 -0
  72. package/dist/redis/index.d.ts.map +1 -0
  73. package/dist/redis/index.js +55 -0
  74. package/dist/redis/index.js.map +11 -0
  75. package/dist/redis/types.d.ts +19 -0
  76. package/dist/redis/types.d.ts.map +1 -0
  77. package/dist/server/events.d.ts +5 -0
  78. package/dist/server/events.d.ts.map +1 -0
  79. package/dist/server/index.d.ts +7 -0
  80. package/dist/server/index.d.ts.map +1 -0
  81. package/dist/server/index.js +19 -0
  82. package/dist/server/index.js.map +9 -0
  83. package/dist/server/poller.d.ts +63 -0
  84. package/dist/server/poller.d.ts.map +1 -0
  85. package/dist/server/signing.d.ts +27 -0
  86. package/dist/server/signing.d.ts.map +1 -0
  87. package/dist/server/store.d.ts +4 -0
  88. package/dist/server/store.d.ts.map +1 -0
  89. package/dist/server/types.d.ts +37 -0
  90. package/dist/server/types.d.ts.map +1 -0
  91. package/dist/types.d.ts +125 -0
  92. package/dist/types.d.ts.map +1 -0
  93. package/dist/util.d.ts +10 -0
  94. package/dist/util.d.ts.map +1 -0
  95. package/package.json +119 -7
@@ -0,0 +1,12 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/model.ts", "../src/body.ts", "../src/batch.ts"],
4
+ "sourcesContent": [
5
+ "import type * as AnthropicModule from \"@ai-sdk/anthropic\";\nimport type * as GoogleModule from \"@ai-sdk/google\";\nimport type * as GroqModule from \"@ai-sdk/groq\";\nimport type * as MistralModule from \"@ai-sdk/mistral\";\nimport type * as OpenAIModule from \"@ai-sdk/openai\";\nimport type * as TogetherModule from \"@ai-sdk/togetherai\";\nimport type * as XaiModule from \"@ai-sdk/xai\";\nimport type { LanguageModel } from \"ai\";\n\nimport { MissingDependencyError, UnsupportedProviderError } from \"./errors\";\nimport type { BatchProvider, ProviderCredentials } from \"./types\";\n\n/** A fetch implementation compatible with the AI SDK provider `fetch` option. */\nexport type CapturingFetch = typeof globalThis.fetch;\n\n/** OpenAI exposes several request shapes; we mirror the one the model implies. */\nexport type OpenAIModelKind = \"chat\" | \"responses\" | \"completion\";\n\nexport interface ResolvedModel {\n /** Relevant for OpenAI; other providers always use a single chat endpoint. */\n kind: OpenAIModelKind;\n modelId: string;\n provider: BatchProvider;\n}\n\n/**\n * Placeholder API key used only when building request bodies. Body building\n * intercepts the request before it is sent, so no real credential is needed —\n * but the provider refuses to construct a model without one.\n */\nconst CAPTURE_API_KEY = \"batchwork-capture\";\n\n/** The optional `@ai-sdk/*` package backing each provider. */\nconst PACKAGE_BY_PROVIDER: Record<\n BatchProvider,\n { label: string; specifier: string }\n> = {\n anthropic: { label: \"Anthropic\", specifier: \"@ai-sdk/anthropic\" },\n google: { label: \"Google Gemini\", specifier: \"@ai-sdk/google\" },\n groq: { label: \"Groq\", specifier: \"@ai-sdk/groq\" },\n mistral: { label: \"Mistral\", specifier: \"@ai-sdk/mistral\" },\n openai: { label: \"OpenAI\", specifier: \"@ai-sdk/openai\" },\n together: { label: \"Together AI\", specifier: \"@ai-sdk/togetherai\" },\n xai: { label: \"xAI\", specifier: \"@ai-sdk/xai\" },\n};\n\n/**\n * AI SDK provider id prefixes (the part before the first `.` in `model.provider`)\n * mapped to batch providers.\n */\nconst PROVIDER_BY_FAMILY: Record<string, BatchProvider> = {\n anthropic: \"anthropic\",\n google: \"google\",\n groq: \"groq\",\n mistral: \"mistral\",\n openai: \"openai\",\n together: \"together\",\n togetherai: \"together\",\n xai: \"xai\",\n};\n\n/** Aliases accepted in the `\"provider/model\"` string form. */\nconst PROVIDER_BY_ALIAS: Record<string, BatchProvider> = {\n ...PROVIDER_BY_FAMILY,\n gemini: \"google\",\n};\n\nconst splitOnce = (value: string, separator: string): [string, string] => {\n const index = value.indexOf(separator);\n if (index === -1) {\n return [value, \"\"];\n }\n return [value.slice(0, index), value.slice(index + separator.length)];\n};\n\nconst openaiKind = (suffix: string): OpenAIModelKind => {\n if (suffix === \"responses\") {\n return \"responses\";\n }\n if (suffix === \"completion\") {\n return \"completion\";\n }\n // Default to chat completions: the most widely supported batch endpoint.\n return \"chat\";\n};\n\n/** Resolve a `\"provider/model\"` string into a provider + model id. */\nconst resolveModelString = (value: string): ResolvedModel => {\n const [providerId, modelId] = splitOnce(value, \"/\");\n if (modelId === \"\") {\n throw new UnsupportedProviderError(value);\n }\n const provider = PROVIDER_BY_ALIAS[providerId];\n if (!provider) {\n throw new UnsupportedProviderError(providerId);\n }\n return { kind: \"chat\", modelId, provider };\n};\n\n/**\n * Resolve any AI SDK `model` (a `\"provider/model\"` string or a provider model\n * object such as `openai(\"gpt-5.5\")`) to a provider + model id + request\n * shape. Gateway/registry model objects whose `modelId` is itself\n * `\"provider/model\"` are also handled.\n */\nexport const resolveModel = (model: LanguageModel): ResolvedModel => {\n if (typeof model === \"string\") {\n return resolveModelString(model);\n }\n\n const [family, suffix] = splitOnce(model.provider, \".\");\n const provider = PROVIDER_BY_FAMILY[family];\n if (provider === \"openai\") {\n return { kind: openaiKind(suffix), modelId: model.modelId, provider };\n }\n if (provider) {\n return { kind: \"chat\", modelId: model.modelId, provider };\n }\n // Gateway/registry providers carry the real target in the model id.\n if (model.modelId.includes(\"/\")) {\n return resolveModelString(model.modelId);\n }\n throw new UnsupportedProviderError(model.provider);\n};\n\nconst importProvider = (provider: BatchProvider): Promise<unknown> => {\n switch (provider) {\n case \"anthropic\": {\n return import(\"@ai-sdk/anthropic\");\n }\n case \"google\": {\n return import(\"@ai-sdk/google\");\n }\n case \"groq\": {\n return import(\"@ai-sdk/groq\");\n }\n case \"mistral\": {\n return import(\"@ai-sdk/mistral\");\n }\n case \"openai\": {\n return import(\"@ai-sdk/openai\");\n }\n case \"together\": {\n return import(\"@ai-sdk/togetherai\");\n }\n case \"xai\": {\n return import(\"@ai-sdk/xai\");\n }\n default: {\n return Promise.reject(new UnsupportedProviderError(provider));\n }\n }\n};\n\n/**\n * Import the `@ai-sdk/*` package for a provider, translating a missing optional\n * dependency into a `MissingDependencyError`. The importer is injectable (like\n * the capturing `fetch`) so tests can drive the failure paths without\n * uninstalling a package. Exported for testing; not part of the public API.\n */\nexport const loadProvider = async <T>(\n provider: BatchProvider,\n load: (target: BatchProvider) => Promise<unknown> = importProvider\n): Promise<T> => {\n try {\n return (await load(provider)) as T;\n } catch (error) {\n if (error instanceof UnsupportedProviderError) {\n throw error;\n }\n const { specifier, label } = PACKAGE_BY_PROVIDER[provider];\n throw new MissingDependencyError(specifier, label);\n }\n};\n\n/**\n * Construct an AI SDK model wired to a capturing `fetch`, used to derive the\n * provider request body for each batch item without making a network call.\n */\nexport const createCaptureModel = async (\n resolved: ResolvedModel,\n credentials: ProviderCredentials,\n fetchImpl: CapturingFetch\n): Promise<LanguageModel> => {\n const settings = {\n apiKey: credentials.apiKey ?? CAPTURE_API_KEY,\n baseURL: credentials.baseURL,\n fetch: fetchImpl,\n headers: credentials.headers,\n };\n\n switch (resolved.provider) {\n case \"openai\": {\n const { createOpenAI } =\n await loadProvider<typeof OpenAIModule>(\"openai\");\n const provider = createOpenAI(settings);\n if (resolved.kind === \"responses\") {\n return provider.responses(resolved.modelId);\n }\n if (resolved.kind === \"completion\") {\n return provider.completion(resolved.modelId);\n }\n return provider.chat(resolved.modelId);\n }\n case \"anthropic\": {\n const { createAnthropic } =\n await loadProvider<typeof AnthropicModule>(\"anthropic\");\n return createAnthropic(settings).messages(resolved.modelId);\n }\n case \"groq\": {\n const { createGroq } = await loadProvider<typeof GroqModule>(\"groq\");\n return createGroq(settings).languageModel(resolved.modelId);\n }\n case \"mistral\": {\n const { createMistral } =\n await loadProvider<typeof MistralModule>(\"mistral\");\n return createMistral(settings).languageModel(resolved.modelId);\n }\n case \"google\": {\n const { createGoogleGenerativeAI } =\n await loadProvider<typeof GoogleModule>(\"google\");\n return createGoogleGenerativeAI(settings).languageModel(resolved.modelId);\n }\n case \"xai\": {\n const { createXai } = await loadProvider<typeof XaiModule>(\"xai\");\n return createXai(settings).languageModel(resolved.modelId);\n }\n case \"together\": {\n const { createTogetherAI } =\n await loadProvider<typeof TogetherModule>(\"together\");\n return createTogetherAI(settings).languageModel(resolved.modelId);\n }\n default: {\n throw new UnsupportedProviderError(resolved.provider);\n }\n }\n};\n",
6
+ "import { generateText } from \"ai\";\nimport type { LanguageModel } from \"ai\";\n\nimport { BatchworkError } from \"./errors\";\nimport {\n assertByteLength,\n mapWithConcurrency,\n resolveBatchLimits,\n} from \"./limits\";\nimport type { ResolvedBatchLimits } from \"./limits\";\nimport { createCaptureModel } from \"./model\";\nimport type { CapturingFetch, ResolvedModel } from \"./model\";\nimport type {\n BatchDefaults,\n BatchLimits,\n BatchRequest,\n ProviderCredentials,\n} from \"./types\";\n\ntype GenerateTextInput = Parameters<typeof generateText>[0];\n\n/** A provider request body derived from a single batch item. */\nexport interface BuiltRequest {\n /** The serialized provider request body (becomes the batch line). */\n body: Record<string, unknown>;\n customId: string;\n /** API endpoint path the model targets, e.g. `/v1/chat/completions`. */\n endpoint: string;\n}\n\nconst MAX_CAUSE_DEPTH = 10;\n\n/**\n * Thrown by the capturing `fetch` to abort the request after its body has been\n * serialized. The body travels inside the error (not shared state), so capture\n * is correct even under concurrency.\n */\nclass CaptureSignalError extends Error {\n readonly url: string;\n readonly rawBody: string;\n\n constructor(url: string, rawBody: string) {\n super(\"batchwork:capture\");\n this.name = \"CaptureSignalError\";\n this.url = url;\n this.rawBody = rawBody;\n }\n}\n\nconst resolveUrl = (input: string | URL | Request): string => {\n if (typeof input === \"string\") {\n return input;\n }\n if (input instanceof URL) {\n return input.toString();\n }\n return input.url;\n};\n\nconst extractBody = (init?: RequestInit): string => {\n const body = init?.body;\n if (typeof body === \"string\") {\n return body;\n }\n if (body instanceof Uint8Array) {\n return new TextDecoder().decode(body);\n }\n throw new BatchworkError(\n \"batchwork: unable to read the provider request body during capture.\"\n );\n};\n\n// `CapturingFetch` is `typeof fetch`, whose shape varies by runtime types (e.g.\n// Bun adds a required `preconnect` method). We only ever call it as a plain\n// fetch, so cast the bare implementation rather than stub the extra members.\nconst captureFetch = ((input: string | URL | Request, init?: RequestInit) =>\n Promise.reject(\n new CaptureSignalError(resolveUrl(input), extractBody(init))\n )) as unknown as CapturingFetch;\n\nconst findCapture = (error: unknown): CaptureSignalError | undefined => {\n let current: unknown = error;\n let depth = 0;\n while (current && depth < MAX_CAUSE_DEPTH) {\n if (current instanceof CaptureSignalError) {\n return current;\n }\n current = (current as { cause?: unknown }).cause;\n depth += 1;\n }\n};\n\nconst endpointFromUrl = (url: string): string => {\n try {\n return new URL(url).pathname;\n } catch {\n return url;\n }\n};\n\nconst mergeDefaults = (\n request: BatchRequest,\n defaults: BatchDefaults | undefined\n): BatchRequest => {\n if (!defaults) {\n return request;\n }\n return { ...defaults, ...request };\n};\n\n/**\n * Map a batch request to AI SDK `generateText` input. Fields are listed\n * explicitly so `customId` never leaks into the provider request.\n */\nconst toGenerateInput = (\n model: LanguageModel,\n request: BatchRequest\n): GenerateTextInput =>\n // `prompt`/`messages` form a discriminated union in the AI SDK types; we\n // pass both keys and let `generateText` validate the XOR at runtime.\n ({\n frequencyPenalty: request.frequencyPenalty,\n maxOutputTokens: request.maxOutputTokens,\n maxRetries: 0,\n messages: request.messages,\n model,\n presencePenalty: request.presencePenalty,\n prompt: request.prompt,\n providerOptions: request.providerOptions,\n seed: request.seed,\n stopSequences: request.stopSequences,\n system: request.system,\n temperature: request.temperature,\n toolChoice: request.toolChoice,\n tools: request.tools,\n topK: request.topK,\n topP: request.topP,\n }) as GenerateTextInput;\n\nconst captureOne = async (\n model: LanguageModel,\n request: BatchRequest,\n customId: string\n): Promise<BuiltRequest> => {\n try {\n await generateText(toGenerateInput(model, request));\n } catch (error) {\n const capture = findCapture(error);\n if (capture) {\n return {\n body: JSON.parse(capture.rawBody) as Record<string, unknown>,\n customId,\n endpoint: endpointFromUrl(capture.url),\n };\n }\n // A genuine failure (e.g. invalid prompt) — surface it to the caller.\n throw error;\n }\n throw new BatchworkError(\n \"batchwork: the request was not intercepted while building the batch body.\"\n );\n};\n\n/**\n * Derive provider request bodies for every batch item by running each through\n * the AI SDK with a capturing `fetch`. This reuses the AI SDK's full message,\n * tool, and multimodal conversion, so the body matches what `generateText`\n * would send — minus the network call.\n */\nexport const buildRequestBodies = async (\n resolved: ResolvedModel,\n requests: readonly BatchRequest[],\n defaults: BatchDefaults | undefined,\n credentials: ProviderCredentials,\n rawLimits?: BatchLimits | ResolvedBatchLimits\n): Promise<BuiltRequest[]> => {\n const limits = resolveBatchLimits(rawLimits);\n if (requests.length > limits.maxRequests) {\n throw new BatchworkError(\n `batchwork: requests length ${requests.length} exceeds the ${limits.maxRequests} request limit.`\n );\n }\n const model = await createCaptureModel(resolved, credentials, captureFetch);\n const seen = new Set<string>();\n\n // Assign and validate customIds up front (sequentially, so duplicates are\n // reported deterministically) before capturing bodies in parallel.\n const items = requests.map((request, index) => {\n const customId = request.customId ?? `request-${index}`;\n if (seen.has(customId)) {\n throw new BatchworkError(\n `batchwork: duplicate customId \"${customId}\". customId values must be unique within a batch.`\n );\n }\n seen.add(customId);\n return { customId, request };\n });\n\n return await mapWithConcurrency(\n items,\n limits.captureConcurrency,\n async (item) => {\n const built = await captureOne(\n model,\n mergeDefaults(item.request, defaults),\n item.customId\n );\n assertByteLength(\n `request \"${item.customId}\"`,\n JSON.stringify(built.body),\n limits.maxRequestBytes\n );\n return built;\n }\n );\n};\n",
7
+ "import { buildRequestBodies } from \"./body\";\nimport { BatchworkError } from \"./errors\";\nimport { BatchJob } from \"./job\";\nimport { resolveBatchLimits } from \"./limits\";\nimport { resolveModel } from \"./model\";\nimport { getAdapter } from \"./providers\";\nimport type {\n BatchOptions,\n BatchProvider,\n BatchRef,\n BatchResult,\n ProviderCredentials,\n} from \"./types\";\n\nconst pickCredentials = (source: ProviderCredentials): ProviderCredentials => ({\n apiKey: source.apiKey,\n baseURL: source.baseURL,\n headers: source.headers,\n});\n\nconst providerFromRef = (ref: BatchRef): BatchProvider => {\n if (ref.provider) {\n return ref.provider;\n }\n if (ref.model !== undefined) {\n return resolveModel(ref.model).provider;\n }\n throw new BatchworkError(\n \"batchwork: provide `provider` or `model` to identify the batch.\"\n );\n};\n\n/**\n * Submit a batch of requests to the model's provider and return a handle.\n *\n * Resolves immediately once the batch is accepted — it does not wait for\n * processing. Use the returned {@link BatchJob} to poll, wait, or stream\n * results.\n *\n * @example\n * const job = await batch({\n * model: openai(\"gpt-5.5\"),\n * requests: [{ customId: \"a\", prompt: \"Say hi\" }],\n * });\n * const results = await job.wait().then(() => job.collect());\n */\nexport const batch = async (options: BatchOptions): Promise<BatchJob> => {\n if (options.requests.length === 0) {\n throw new BatchworkError(\"batchwork: `requests` must not be empty.\");\n }\n\n const resolved = resolveModel(options.model);\n const credentials = pickCredentials(options);\n const limits = resolveBatchLimits(options.limits);\n const adapter = getAdapter(resolved.provider);\n\n const built = await buildRequestBodies(\n resolved,\n options.requests,\n options.defaults,\n credentials,\n limits\n );\n const snapshot = await adapter.submit({\n built,\n credentials,\n endpoint: built[0]?.endpoint ?? \"\",\n limits,\n metadata: options.metadata,\n modelId: resolved.modelId,\n });\n\n return new BatchJob(adapter, credentials, snapshot);\n};\n\n/**\n * Rehydrate a {@link BatchJob} for an existing batch id (e.g. one persisted\n * after submission). Identify the provider with `provider` or `model`.\n */\nexport const getBatch = async (ref: BatchRef): Promise<BatchJob> => {\n const adapter = getAdapter(providerFromRef(ref));\n const credentials = pickCredentials(ref);\n const snapshot = await adapter.retrieve(ref.id, credentials);\n return new BatchJob(adapter, credentials, snapshot);\n};\n\n/** Stream the results of an existing batch by id, without a handle. */\nexport const getBatchResults = (ref: BatchRef): AsyncGenerator<BatchResult> => {\n const adapter = getAdapter(providerFromRef(ref));\n return adapter.results(ref.id, pickCredentials(ref));\n};\n\n/** Request cancellation of an existing batch by id. */\nexport const cancelBatch = async (ref: BatchRef): Promise<void> => {\n const adapter = getAdapter(providerFromRef(ref));\n await adapter.cancel(ref.id, pickCredentials(ref));\n};\n"
8
+ ],
9
+ "mappings": "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",
10
+ "debugId": "C7BCC311BBAF05B464756E2164756E21",
11
+ "names": []
12
+ }
@@ -0,0 +1,7 @@
1
+ import { createRequire } from "node:module";
2
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
+
4
+ export { __require };
5
+
6
+ //# debugId=5F0D92CF7AD4DB9164756E2164756E21
7
+ //# sourceMappingURL=chunk-v0bahtg2.js.map
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [
5
+ ],
6
+ "mappings": "",
7
+ "debugId": "5F0D92CF7AD4DB9164756E2164756E21",
8
+ "names": []
9
+ }
@@ -0,0 +1,16 @@
1
+ /** Base error for all batchwork failures. */
2
+ export declare class BatchworkError extends Error {
3
+ constructor(message: string, options?: {
4
+ cause?: unknown;
5
+ });
6
+ }
7
+ /** Thrown when a model resolves to a provider without a batch adapter. */
8
+ export declare class UnsupportedProviderError extends BatchworkError {
9
+ readonly provider: string;
10
+ constructor(provider: string);
11
+ }
12
+ /** Thrown when an optional provider package is not installed. */
13
+ export declare class MissingDependencyError extends BatchworkError {
14
+ constructor(pkg: string, provider: string);
15
+ }
16
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA,6CAA6C;AAC7C,qBAAa,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAGzD;CACF;AAED,0EAA0E;AAC1E,qBAAa,wBAAyB,SAAQ,cAAc;IAC1D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,YAAY,QAAQ,EAAE,MAAM,EAM3B;CACF;AAED,iEAAiE;AACjE,qBAAa,sBAAuB,SAAQ,cAAc;IACxD,YAAY,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAKxC;CACF"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /** Make a request and parse a JSON response, throwing on non-2xx. */
2
+ export declare const requestJson: <T>(url: string, init: RequestInit) => Promise<T>;
3
+ /** Make a request and return the raw body stream, throwing on non-2xx. */
4
+ export declare const requestStream: (url: string, init: RequestInit) => Promise<ReadableStream<Uint8Array>>;
5
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAUA,qEAAqE;AACrE,eAAO,MAAM,WAAW,GAAU,CAAC,OAC5B,MAAM,QACL,WAAW,KAChB,OAAO,CAAC,CAAC,CAIX,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,aAAa,QACnB,MAAM,QACL,WAAW,KAChB,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAOpC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { batch, cancelBatch, getBatch, getBatchResults } from "./batch";
2
+ export { BatchworkError, MissingDependencyError, UnsupportedProviderError, } from "./errors";
3
+ export { BatchJob, isTerminalStatus } from "./job";
4
+ export { resolveModel } from "./model";
5
+ export type { BatchDefaults, BatchLimits, BatchOptions, BatchProvider, BatchRef, BatchRequest, BatchRequestCounts, BatchRequestSettings, BatchResult, BatchResultError, BatchResultStatus, BatchSnapshot, BatchStatus, BatchUsage, ProviderCredentials, ProviderOptions, WaitOptions, } from "./types";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,YAAY,EACV,aAAa,EACb,WAAW,EACX,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,kBAAkB,EAClB,oBAAoB,EACpB,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,UAAU,EACV,mBAAmB,EACnB,eAAe,EACf,WAAW,GACZ,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,30 @@
1
+ import {
2
+ batch,
3
+ cancelBatch,
4
+ getBatch,
5
+ getBatchResults,
6
+ resolveModel
7
+ } from "./chunk-m4n610nm.js";
8
+ import {
9
+ BatchJob,
10
+ BatchworkError,
11
+ MissingDependencyError,
12
+ UnsupportedProviderError,
13
+ isTerminalStatus
14
+ } from "./chunk-g481f961.js";
15
+ import"./chunk-v0bahtg2.js";
16
+ export {
17
+ resolveModel,
18
+ isTerminalStatus,
19
+ getBatchResults,
20
+ getBatch,
21
+ cancelBatch,
22
+ batch,
23
+ UnsupportedProviderError,
24
+ MissingDependencyError,
25
+ BatchworkError,
26
+ BatchJob
27
+ };
28
+
29
+ //# debugId=503CE7D732E9F8F664756E2164756E21
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [
5
+ ],
6
+ "mappings": "",
7
+ "debugId": "503CE7D732E9F8F664756E2164756E21",
8
+ "names": []
9
+ }
package/dist/job.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ import type { BatchAdapter } from "./providers/adapter";
2
+ import type { BatchProvider, BatchRequestCounts, BatchResult, BatchSnapshot, BatchStatus, ProviderCredentials, WaitOptions } from "./types";
3
+ /** Whether a status means the batch has finished processing. */
4
+ export declare const isTerminalStatus: (status: BatchStatus) => boolean;
5
+ /**
6
+ * A handle to a submitted batch. Returned by `batch()` and `getBatch()`. Use it
7
+ * to poll status, wait for completion, stream results, or cancel.
8
+ */
9
+ export declare class BatchJob {
10
+ #private;
11
+ readonly provider: BatchProvider;
12
+ readonly id: string;
13
+ constructor(adapter: BatchAdapter, credentials: ProviderCredentials, snapshot: BatchSnapshot);
14
+ /** The most recently observed status. */
15
+ get status(): BatchStatus;
16
+ /** The most recently observed per-request tallies. */
17
+ get requestCounts(): BatchRequestCounts;
18
+ /** The most recently observed snapshot. */
19
+ get snapshot(): BatchSnapshot;
20
+ /** Refresh the status from the provider and return the new snapshot. */
21
+ poll(): Promise<BatchSnapshot>;
22
+ /** Poll until the batch reaches a terminal status, then return the snapshot. */
23
+ wait(options?: WaitOptions): Promise<BatchSnapshot>;
24
+ /** Stream normalized results as they are read. Order is not guaranteed. */
25
+ results(): AsyncGenerator<BatchResult>;
26
+ /** Collect all results into an array, keyed by `customId`. */
27
+ collect(): Promise<BatchResult[]>;
28
+ /** Request cancellation, then refresh status. */
29
+ cancel(): Promise<BatchSnapshot>;
30
+ }
31
+ //# sourceMappingURL=job.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../src/job.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EACV,aAAa,EACb,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,WAAW,EACZ,MAAM,SAAS,CAAC;AAWjB,gEAAgE;AAChE,eAAO,MAAM,gBAAgB,WAAY,WAAW,KAAG,OACxB,CAAC;AAoBhC;;;GAGG;AACH,qBAAa,QAAQ;;IACnB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAMpB,YACE,OAAO,EAAE,YAAY,EACrB,WAAW,EAAE,mBAAmB,EAChC,QAAQ,EAAE,aAAa,EAOxB;IAED,yCAAyC;IACzC,IAAI,MAAM,IAAI,WAAW,CAExB;IAED,sDAAsD;IACtD,IAAI,aAAa,IAAI,kBAAkB,CAEtC;IAED,2CAA2C;IAC3C,IAAI,QAAQ,IAAI,aAAa,CAE5B;IAED,wEAAwE;IAClE,IAAI,IAAI,OAAO,CAAC,aAAa,CAAC,CAGnC;IAED,gFAAgF;IAC1E,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CA0B5D;IAED,2EAA2E;IAC3E,OAAO,IAAI,cAAc,CAAC,WAAW,CAAC,CAErC;IAED,8DAA8D;IACxD,OAAO,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAMtC;IAED,iDAAiD;IAC3C,MAAM,IAAI,OAAO,CAAC,aAAa,CAAC,CAGrC;CACF"}
@@ -0,0 +1,7 @@
1
+ export interface JsonlParseOptions {
2
+ maxLineBytes?: number;
3
+ }
4
+ export declare const encodeJsonl: (items: readonly unknown[]) => string;
5
+ export declare const parseJsonl: <T = unknown>(text: string, options?: JsonlParseOptions) => T[];
6
+ export declare function streamJsonl<T = unknown>(source: ReadableStream<Uint8Array> | AsyncIterable<Uint8Array>, options?: JsonlParseOptions): AsyncGenerator<T>;
7
+ //# sourceMappingURL=jsonl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonl.d.ts","sourceRoot":"","sources":["../src/jsonl.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,iBAAiB;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA6CD,eAAO,MAAM,WAAW,UAAW,SAAS,OAAO,EAAE,KAAG,MAMvD,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,CAAC,GAAG,OAAO,QAC9B,MAAM,YACF,iBAAiB,KAC1B,CAAC,EAWH,CAAC;AAmCF,wBAAuB,WAAW,CAAC,CAAC,GAAG,OAAO,EAC5C,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,EAC9D,OAAO,CAAC,EAAE,iBAAiB,GAC1B,cAAc,CAAC,CAAC,CAAC,CA2BnB"}
@@ -0,0 +1,12 @@
1
+ import type { BatchLimits } from "./types";
2
+ export interface ResolvedBatchLimits {
3
+ captureConcurrency: number;
4
+ maxRequests: number;
5
+ maxRequestBytes: number;
6
+ maxUploadBytes: number;
7
+ }
8
+ export declare const resolveBatchLimits: (limits: BatchLimits | undefined) => ResolvedBatchLimits;
9
+ export declare const byteLength: (value: string) => number;
10
+ export declare const assertByteLength: (label: string, value: string, maxBytes: number) => void;
11
+ export declare const mapWithConcurrency: <Input, Output>(items: readonly Input[], concurrency: number, mapper: (item: Input) => Promise<Output>) => Promise<Output[]>;
12
+ //# sourceMappingURL=limits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../src/limits.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,MAAM,WAAW,mBAAmB;IAClC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACxB;AAoBD,eAAO,MAAM,kBAAkB,WACrB,WAAW,GAAG,SAAS,KAC9B,mBAiBD,CAAC;AAEH,eAAO,MAAM,UAAU,UAAW,MAAM,KAAG,MACb,CAAC;AAE/B,eAAO,MAAM,gBAAgB,UACpB,MAAM,SACN,MAAM,YACH,MAAM,KACf,IAOF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAU,KAAK,EAAE,MAAM,SAC7C,SAAS,KAAK,EAAE,eACV,MAAM,UACX,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,MAAM,CAAC,KACvC,OAAO,CAAC,MAAM,EAAE,CAkBlB,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { LanguageModel } from "ai";
2
+ import type { BatchProvider, ProviderCredentials } from "./types";
3
+ /** A fetch implementation compatible with the AI SDK provider `fetch` option. */
4
+ export type CapturingFetch = typeof globalThis.fetch;
5
+ /** OpenAI exposes several request shapes; we mirror the one the model implies. */
6
+ export type OpenAIModelKind = "chat" | "responses" | "completion";
7
+ export interface ResolvedModel {
8
+ /** Relevant for OpenAI; other providers always use a single chat endpoint. */
9
+ kind: OpenAIModelKind;
10
+ modelId: string;
11
+ provider: BatchProvider;
12
+ }
13
+ /**
14
+ * Resolve any AI SDK `model` (a `"provider/model"` string or a provider model
15
+ * object such as `openai("gpt-5.5")`) to a provider + model id + request
16
+ * shape. Gateway/registry model objects whose `modelId` is itself
17
+ * `"provider/model"` are also handled.
18
+ */
19
+ export declare const resolveModel: (model: LanguageModel) => ResolvedModel;
20
+ /**
21
+ * Import the `@ai-sdk/*` package for a provider, translating a missing optional
22
+ * dependency into a `MissingDependencyError`. The importer is injectable (like
23
+ * the capturing `fetch`) so tests can drive the failure paths without
24
+ * uninstalling a package. Exported for testing; not part of the public API.
25
+ */
26
+ export declare const loadProvider: <T>(provider: BatchProvider, load?: (target: BatchProvider) => Promise<unknown>) => Promise<T>;
27
+ /**
28
+ * Construct an AI SDK model wired to a capturing `fetch`, used to derive the
29
+ * provider request body for each batch item without making a network call.
30
+ */
31
+ export declare const createCaptureModel: (resolved: ResolvedModel, credentials: ProviderCredentials, fetchImpl: CapturingFetch) => Promise<LanguageModel>;
32
+ //# sourceMappingURL=model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAGxC,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAElE,iFAAiF;AACjF,MAAM,MAAM,cAAc,GAAG,OAAO,UAAU,CAAC,KAAK,CAAC;AAErD,kFAAkF;AAClF,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,WAAW,GAAG,YAAY,CAAC;AAElE,MAAM,WAAW,aAAa;IAC5B,8EAA8E;IAC9E,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,aAAa,CAAC;CACzB;AA4ED;;;;;GAKG;AACH,eAAO,MAAM,YAAY,UAAW,aAAa,KAAG,aAkBnD,CAAC;AA+BF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAU,CAAC,YACxB,aAAa,SACjB,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,KAChD,OAAO,CAAC,CAAC,CAUX,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,aACnB,aAAa,eACV,mBAAmB,aACrB,cAAc,KACxB,OAAO,CAAC,aAAa,CAqDvB,CAAC"}
@@ -0,0 +1,61 @@
1
+ import type { CredentialResolver, TrackTarget } from "../server/poller";
2
+ import { createMemoryStore } from "../server/store";
3
+ import type { BatchStore, BatchWebhookEvent, TrackedBatch } from "../server/types";
4
+ import type { BatchResult } from "../types";
5
+ export { createMemoryStore };
6
+ export type { BatchStore, BatchWebhookEvent, BatchResult, TrackedBatch, TrackTarget, };
7
+ /**
8
+ * Invoked once per batch when it reaches a terminal status. Persist the results
9
+ * to your database here. `results` streams the parsed result lines for a
10
+ * completed batch and is empty for failure events (`batch.failed` /
11
+ * `batch.expired` / `batch.cancelled`) — inspect `event.type`.
12
+ *
13
+ * May fire more than once for the same batch (a cron tick racing the OpenAI
14
+ * native webhook, or a retry after a partial save), so make persistence
15
+ * idempotent — upsert keyed by `(provider, batchId, customId)`.
16
+ */
17
+ export type OnBatchComplete = (event: BatchWebhookEvent, results: AsyncIterable<BatchResult>) => void | Promise<void>;
18
+ export interface BatchRoutesOptions {
19
+ store: BatchStore;
20
+ /** Called when each batch finishes; persist results here. */
21
+ onComplete: OnBatchComplete;
22
+ /** Falls back to provider env vars (e.g. `OPENAI_API_KEY`) when omitted. */
23
+ credentials?: CredentialResolver;
24
+ /** Requires `Authorization: Bearer <cronSecret>` on the cron `GET`. */
25
+ cronSecret?: string;
26
+ /** Allow unauthenticated cron ticks. Intended only for private/local routes. */
27
+ allowUnauthenticatedCron?: boolean;
28
+ /** When set, mounts an OpenAI native-webhook handler on `POST`. */
29
+ openaiSigningSecret?: string;
30
+ /** Observe per-batch processing errors during a tick; the tick continues. */
31
+ onError?: (record: TrackedBatch, error: unknown) => void;
32
+ }
33
+ export interface BatchRoutes {
34
+ /** Cron-triggered poll tick. Wire to Vercel Cron (or any scheduler). */
35
+ GET: (request: Request) => Promise<Response>;
36
+ /** OpenAI native-webhook handler. Present only with `openaiSigningSecret`. */
37
+ POST?: (request: Request) => Promise<Response>;
38
+ /** Register a submitted batch so the cron polls it (a `BatchJob` works). */
39
+ track: (target: TrackTarget) => Promise<TrackedBatch>;
40
+ }
41
+ /**
42
+ * Build Next.js App Router route handlers that poll your in-flight batches on a
43
+ * cron tick and invoke `onComplete` directly when each finishes — persist
44
+ * results to your DB without round-tripping an HTTP webhook back to your app.
45
+ *
46
+ * @example
47
+ * import { createBatchRoutes, createMemoryStore } from "batchwork/next";
48
+ *
49
+ * export const { GET, POST } = createBatchRoutes({
50
+ * store: createMemoryStore(),
51
+ * cronSecret: process.env.CRON_SECRET,
52
+ * openaiSigningSecret: process.env.OPENAI_WEBHOOK_SECRET,
53
+ * onComplete: async (event, results) => {
54
+ * for await (const r of results) {
55
+ * await db.insert({ id: r.customId, status: r.status, text: r.text });
56
+ * }
57
+ * },
58
+ * });
59
+ */
60
+ export declare const createBatchRoutes: (options: BatchRoutesOptions) => BatchRoutes;
61
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,kBAAkB,EAClB,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EACV,UAAU,EACV,iBAAiB,EACjB,YAAY,EACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAiB,WAAW,EAAuB,MAAM,UAAU,CAAC;AAEhF,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAC7B,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,WAAW,GACZ,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG,CAC5B,KAAK,EAAE,iBAAiB,EACxB,OAAO,EAAE,aAAa,CAAC,WAAW,CAAC,KAChC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,UAAU,CAAC;IAClB,6DAA6D;IAC7D,UAAU,EAAE,eAAe,CAAC;IAC5B,4EAA4E;IAC5E,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,mEAAmE;IACnE,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,6EAA6E;IAC7E,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1D;AAED,MAAM,WAAW,WAAW;IAC1B,wEAAwE;IACxE,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7C,8EAA8E;IAC9E,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/C,4EAA4E;IAC5E,KAAK,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;CACvD;AASD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,iBAAiB,YAAa,kBAAkB,KAAG,WAuD/D,CAAC"}
@@ -0,0 +1,64 @@
1
+ import {
2
+ getBatchResults
3
+ } from "../chunk-m4n610nm.js";
4
+ import {
5
+ createBatchPoller,
6
+ createMemoryStore,
7
+ toEvent
8
+ } from "../chunk-e6qn48qa.js";
9
+ import"../chunk-g481f961.js";
10
+ import"../chunk-v0bahtg2.js";
11
+
12
+ // src/next/index.ts
13
+ var EMPTY_RESULTS = {
14
+ [Symbol.asyncIterator]: () => ({
15
+ next: () => Promise.resolve({ done: true, value: undefined })
16
+ })
17
+ };
18
+ var createBatchRoutes = (options) => {
19
+ const resolveCredentials = (provider) => {
20
+ if (typeof options.credentials === "function") {
21
+ return options.credentials(provider);
22
+ }
23
+ return options.credentials ?? {};
24
+ };
25
+ const sink = async (record, snapshot) => {
26
+ const event = toEvent(record.provider, snapshot);
27
+ const results = event.type === "batch.completed" ? getBatchResults({
28
+ id: record.id,
29
+ provider: record.provider,
30
+ ...resolveCredentials(record.provider)
31
+ }) : EMPTY_RESULTS;
32
+ await options.onComplete(event, results);
33
+ };
34
+ const poller = createBatchPoller({
35
+ credentials: options.credentials,
36
+ onComplete: sink,
37
+ onError: (record, error) => options.onError?.(record, error),
38
+ store: options.store
39
+ });
40
+ const GET = (request) => {
41
+ if (!(options.cronSecret || options.allowUnauthenticatedCron)) {
42
+ return Promise.resolve(new Response("unauthorized", { status: 401 }));
43
+ }
44
+ if (options.cronSecret && request.headers.get("authorization") !== `Bearer ${options.cronSecret}`) {
45
+ return Promise.resolve(new Response("unauthorized", { status: 401 }));
46
+ }
47
+ return poller.tick().then((result) => Response.json(result));
48
+ };
49
+ const track = (target) => poller.track(target, {});
50
+ const routes = { GET, track };
51
+ if (options.openaiSigningSecret) {
52
+ routes.POST = poller.openaiWebhookHandler({
53
+ signingSecret: options.openaiSigningSecret
54
+ });
55
+ }
56
+ return routes;
57
+ };
58
+ export {
59
+ createMemoryStore,
60
+ createBatchRoutes
61
+ };
62
+
63
+ //# debugId=5888D5A3C810FEE564756E2164756E21
64
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/next/index.ts"],
4
+ "sourcesContent": [
5
+ "import { getBatchResults } from \"../batch\";\nimport { toEvent } from \"../server/events\";\nimport { createBatchPoller } from \"../server/poller\";\nimport type {\n CompletionSink,\n CredentialResolver,\n TrackTarget,\n} from \"../server/poller\";\nimport { createMemoryStore } from \"../server/store\";\nimport type {\n BatchStore,\n BatchWebhookEvent,\n TrackedBatch,\n} from \"../server/types\";\nimport type { BatchProvider, BatchResult, ProviderCredentials } from \"../types\";\n\nexport { createMemoryStore };\nexport type {\n BatchStore,\n BatchWebhookEvent,\n BatchResult,\n TrackedBatch,\n TrackTarget,\n};\n\n/**\n * Invoked once per batch when it reaches a terminal status. Persist the results\n * to your database here. `results` streams the parsed result lines for a\n * completed batch and is empty for failure events (`batch.failed` /\n * `batch.expired` / `batch.cancelled`) — inspect `event.type`.\n *\n * May fire more than once for the same batch (a cron tick racing the OpenAI\n * native webhook, or a retry after a partial save), so make persistence\n * idempotent — upsert keyed by `(provider, batchId, customId)`.\n */\nexport type OnBatchComplete = (\n event: BatchWebhookEvent,\n results: AsyncIterable<BatchResult>\n) => void | Promise<void>;\n\nexport interface BatchRoutesOptions {\n store: BatchStore;\n /** Called when each batch finishes; persist results here. */\n onComplete: OnBatchComplete;\n /** Falls back to provider env vars (e.g. `OPENAI_API_KEY`) when omitted. */\n credentials?: CredentialResolver;\n /** Requires `Authorization: Bearer <cronSecret>` on the cron `GET`. */\n cronSecret?: string;\n /** Allow unauthenticated cron ticks. Intended only for private/local routes. */\n allowUnauthenticatedCron?: boolean;\n /** When set, mounts an OpenAI native-webhook handler on `POST`. */\n openaiSigningSecret?: string;\n /** Observe per-batch processing errors during a tick; the tick continues. */\n onError?: (record: TrackedBatch, error: unknown) => void;\n}\n\nexport interface BatchRoutes {\n /** Cron-triggered poll tick. Wire to Vercel Cron (or any scheduler). */\n GET: (request: Request) => Promise<Response>;\n /** OpenAI native-webhook handler. Present only with `openaiSigningSecret`. */\n POST?: (request: Request) => Promise<Response>;\n /** Register a submitted batch so the cron polls it (a `BatchJob` works). */\n track: (target: TrackTarget) => Promise<TrackedBatch>;\n}\n\n/** An already-exhausted async iterable, for non-completed events. */\nconst EMPTY_RESULTS: AsyncIterable<BatchResult> = {\n [Symbol.asyncIterator]: () => ({\n next: () => Promise.resolve({ done: true, value: undefined }),\n }),\n};\n\n/**\n * Build Next.js App Router route handlers that poll your in-flight batches on a\n * cron tick and invoke `onComplete` directly when each finishes — persist\n * results to your DB without round-tripping an HTTP webhook back to your app.\n *\n * @example\n * import { createBatchRoutes, createMemoryStore } from \"batchwork/next\";\n *\n * export const { GET, POST } = createBatchRoutes({\n * store: createMemoryStore(),\n * cronSecret: process.env.CRON_SECRET,\n * openaiSigningSecret: process.env.OPENAI_WEBHOOK_SECRET,\n * onComplete: async (event, results) => {\n * for await (const r of results) {\n * await db.insert({ id: r.customId, status: r.status, text: r.text });\n * }\n * },\n * });\n */\nexport const createBatchRoutes = (options: BatchRoutesOptions): BatchRoutes => {\n const resolveCredentials = (provider: BatchProvider): ProviderCredentials => {\n if (typeof options.credentials === \"function\") {\n return options.credentials(provider);\n }\n return options.credentials ?? {};\n };\n\n const sink: CompletionSink = async (record, snapshot) => {\n const event = toEvent(record.provider, snapshot);\n // Only completed batches have results to fetch — the adapter throws when a\n // terminal batch has no output/error file (failed/expired/cancelled).\n const results =\n event.type === \"batch.completed\"\n ? getBatchResults({\n id: record.id,\n provider: record.provider,\n ...resolveCredentials(record.provider),\n })\n : EMPTY_RESULTS;\n await options.onComplete(event, results);\n };\n\n const poller = createBatchPoller({\n credentials: options.credentials,\n onComplete: sink,\n // Always supply an `onError` so one failing batch can't abort the whole\n // tick; forward to the caller's handler when they provided one.\n onError: (record, error) => options.onError?.(record, error),\n store: options.store,\n });\n\n const GET = (request: Request): Promise<Response> => {\n if (!(options.cronSecret || options.allowUnauthenticatedCron)) {\n return Promise.resolve(new Response(\"unauthorized\", { status: 401 }));\n }\n if (\n options.cronSecret &&\n request.headers.get(\"authorization\") !== `Bearer ${options.cronSecret}`\n ) {\n return Promise.resolve(new Response(\"unauthorized\", { status: 401 }));\n }\n return poller.tick().then((result) => Response.json(result));\n };\n\n const track = (target: TrackTarget): Promise<TrackedBatch> =>\n poller.track(target, {});\n\n const routes: BatchRoutes = { GET, track };\n if (options.openaiSigningSecret) {\n routes.POST = poller.openaiWebhookHandler({\n signingSecret: options.openaiSigningSecret,\n });\n }\n return routes;\n};\n"
6
+ ],
7
+ "mappings": ";;;;;;;;;;;;AAkEA,IAAM,gBAA4C;AAAA,GAC/C,OAAO,gBAAgB,OAAO;AAAA,IAC7B,MAAM,MAAM,QAAQ,QAAQ,EAAE,MAAM,MAAM,OAAO,UAAU,CAAC;AAAA,EAC9D;AACF;AAqBO,IAAM,oBAAoB,CAAC,YAA6C;AAAA,EAC7E,MAAM,qBAAqB,CAAC,aAAiD;AAAA,IAC3E,IAAI,OAAO,QAAQ,gBAAgB,YAAY;AAAA,MAC7C,OAAO,QAAQ,YAAY,QAAQ;AAAA,IACrC;AAAA,IACA,OAAO,QAAQ,eAAe,CAAC;AAAA;AAAA,EAGjC,MAAM,OAAuB,OAAO,QAAQ,aAAa;AAAA,IACvD,MAAM,QAAQ,QAAQ,OAAO,UAAU,QAAQ;AAAA,IAG/C,MAAM,UACJ,MAAM,SAAS,oBACX,gBAAgB;AAAA,MACd,IAAI,OAAO;AAAA,MACX,UAAU,OAAO;AAAA,SACd,mBAAmB,OAAO,QAAQ;AAAA,IACvC,CAAC,IACD;AAAA,IACN,MAAM,QAAQ,WAAW,OAAO,OAAO;AAAA;AAAA,EAGzC,MAAM,SAAS,kBAAkB;AAAA,IAC/B,aAAa,QAAQ;AAAA,IACrB,YAAY;AAAA,IAGZ,SAAS,CAAC,QAAQ,UAAU,QAAQ,UAAU,QAAQ,KAAK;AAAA,IAC3D,OAAO,QAAQ;AAAA,EACjB,CAAC;AAAA,EAED,MAAM,MAAM,CAAC,YAAwC;AAAA,IACnD,IAAI,EAAE,QAAQ,cAAc,QAAQ,2BAA2B;AAAA,MAC7D,OAAO,QAAQ,QAAQ,IAAI,SAAS,gBAAgB,EAAE,QAAQ,IAAI,CAAC,CAAC;AAAA,IACtE;AAAA,IACA,IACE,QAAQ,cACR,QAAQ,QAAQ,IAAI,eAAe,MAAM,UAAU,QAAQ,cAC3D;AAAA,MACA,OAAO,QAAQ,QAAQ,IAAI,SAAS,gBAAgB,EAAE,QAAQ,IAAI,CAAC,CAAC;AAAA,IACtE;AAAA,IACA,OAAO,OAAO,KAAK,EAAE,KAAK,CAAC,WAAW,SAAS,KAAK,MAAM,CAAC;AAAA;AAAA,EAG7D,MAAM,QAAQ,CAAC,WACb,OAAO,MAAM,QAAQ,CAAC,CAAC;AAAA,EAEzB,MAAM,SAAsB,EAAE,KAAK,MAAM;AAAA,EACzC,IAAI,QAAQ,qBAAqB;AAAA,IAC/B,OAAO,OAAO,OAAO,qBAAqB;AAAA,MACxC,eAAe,QAAQ;AAAA,IACzB,CAAC;AAAA,EACH;AAAA,EACA,OAAO;AAAA;",
8
+ "debugId": "5888D5A3C810FEE564756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,19 @@
1
+ import type { BatchStore } from "../server/types";
2
+ import type { PostgresStoreOptions } from "./types";
3
+ /** Options for {@link createPostgresStore}. */
4
+ export interface PostgresBatchStoreOptions extends PostgresStoreOptions {
5
+ /** Table to store tracked batches in. Defaults to `batchwork_batches`. */
6
+ table?: string;
7
+ }
8
+ /** `CREATE TABLE`/index DDL for the tracked-batch table (run by `migratePostgres`). */
9
+ export declare const batchTableDdl: (table?: string) => string;
10
+ /**
11
+ * A Postgres-backed {@link BatchStore} for the poller. Run {@link migratePostgres}
12
+ * (or {@link batchTableDdl}) once to create the table.
13
+ *
14
+ * @example
15
+ * import { Pool } from "pg";
16
+ * const store = createPostgresStore({ client: new Pool({ connectionString }) });
17
+ */
18
+ export declare const createPostgresStore: (options: PostgresBatchStoreOptions) => BatchStore;
19
+ //# sourceMappingURL=batch-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-store.d.ts","sourceRoot":"","sources":["../../src/postgres/batch-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAgB,MAAM,iBAAiB,CAAC;AAGhE,OAAO,KAAK,EAAE,oBAAoB,EAAe,MAAM,SAAS,CAAC;AAEjE,+CAA+C;AAC/C,MAAM,WAAW,yBAA0B,SAAQ,oBAAoB;IACrE,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAyBD,uFAAuF;AACvF,eAAO,MAAM,aAAa,sBAAkC,MAc3D,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,YACrB,yBAAyB,KACjC,UAkDF,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { batchTableDdl, createPostgresStore } from "./batch-store";
2
+ export type { PostgresBatchStoreOptions } from "./batch-store";
3
+ export { migratePostgres } from "./migrate";
4
+ export type { MigrateOptions } from "./migrate";
5
+ export { DEFAULT_BATCH_TABLE, type PostgresStoreOptions, type SqlExecutor, } from "./types";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/postgres/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACnE,YAAY,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EACL,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,KAAK,WAAW,GACjB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,101 @@
1
+ import"../chunk-v0bahtg2.js";
2
+
3
+ // src/postgres/types.ts
4
+ var DEFAULT_BATCH_TABLE = "batchwork_batches";
5
+ var assertSafeTable = (table) => {
6
+ if (!/^[A-Za-z_][A-Za-z0-9_]*(?<schema>\.[A-Za-z_][A-Za-z0-9_]*)?$/u.test(table)) {
7
+ throw new Error(`batchwork: unsafe Postgres table name ${JSON.stringify(table)}.`);
8
+ }
9
+ return table;
10
+ };
11
+
12
+ // src/postgres/batch-store.ts
13
+ var toBatch = (row) => ({
14
+ createdAt: row.created_at,
15
+ id: row.id,
16
+ provider: row.provider,
17
+ status: row.status,
18
+ ...row.webhook_url === null ? {} : { webhookUrl: row.webhook_url },
19
+ ...row.webhook_secret === null ? {} : { webhookSecret: row.webhook_secret },
20
+ ...row.delivered_at === null ? {} : { deliveredAt: row.delivered_at }
21
+ });
22
+ var batchTableDdl = (table = DEFAULT_BATCH_TABLE) => {
23
+ const name = assertSafeTable(table);
24
+ return `
25
+ CREATE TABLE IF NOT EXISTS ${name} (
26
+ id text PRIMARY KEY,
27
+ provider text NOT NULL,
28
+ webhook_url text,
29
+ webhook_secret text,
30
+ status text NOT NULL,
31
+ created_at text NOT NULL,
32
+ delivered_at text
33
+ );
34
+ CREATE INDEX IF NOT EXISTS ${name}_undelivered_idx
35
+ ON ${name} (created_at) WHERE delivered_at IS NULL;`;
36
+ };
37
+ var createPostgresStore = (options) => {
38
+ const { client } = options;
39
+ const table = assertSafeTable(options.table ?? DEFAULT_BATCH_TABLE);
40
+ return {
41
+ delete: async (id) => {
42
+ await client.query(`DELETE FROM ${table} WHERE id = $1`, [id]);
43
+ },
44
+ get: async (id) => {
45
+ const { rows } = await client.query(`SELECT * FROM ${table} WHERE id = $1`, [id]);
46
+ const [row] = rows;
47
+ return row ? toBatch(row) : null;
48
+ },
49
+ list: async (filter) => {
50
+ let text = `SELECT * FROM ${table}`;
51
+ if (filter?.delivered === true) {
52
+ text += " WHERE delivered_at IS NOT NULL";
53
+ } else if (filter?.delivered === false) {
54
+ text += " WHERE delivered_at IS NULL";
55
+ }
56
+ const { rows } = await client.query(text);
57
+ return rows.map(toBatch);
58
+ },
59
+ set: async (record) => {
60
+ await client.query(`INSERT INTO ${table}
61
+ (id, provider, webhook_url, webhook_secret, status, created_at, delivered_at)
62
+ VALUES ($1, $2, $3, $4, $5, $6, $7)
63
+ ON CONFLICT (id) DO UPDATE SET
64
+ provider = EXCLUDED.provider,
65
+ webhook_url = EXCLUDED.webhook_url,
66
+ webhook_secret = EXCLUDED.webhook_secret,
67
+ status = EXCLUDED.status,
68
+ created_at = EXCLUDED.created_at,
69
+ delivered_at = EXCLUDED.delivered_at`, [
70
+ record.id,
71
+ record.provider,
72
+ record.webhookUrl ?? null,
73
+ record.webhookSecret ?? null,
74
+ record.status,
75
+ record.createdAt,
76
+ record.deliveredAt ?? null
77
+ ]);
78
+ }
79
+ };
80
+ };
81
+ // src/postgres/migrate.ts
82
+ var runDdl = async (client, ddl) => {
83
+ for (const statement of ddl.split(";")) {
84
+ const trimmed = statement.trim();
85
+ if (trimmed) {
86
+ await client.query(trimmed);
87
+ }
88
+ }
89
+ };
90
+ var migratePostgres = async (client, options = {}) => {
91
+ await runDdl(client, batchTableDdl(assertSafeTable(options.batchTable ?? DEFAULT_BATCH_TABLE)));
92
+ };
93
+ export {
94
+ migratePostgres,
95
+ createPostgresStore,
96
+ batchTableDdl,
97
+ DEFAULT_BATCH_TABLE
98
+ };
99
+
100
+ //# debugId=119F35EA4B39BF6464756E2164756E21
101
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,12 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/postgres/types.ts", "../src/postgres/batch-store.ts", "../src/postgres/migrate.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * The minimal slice of a Postgres client batchwork's adapters use: a\n * node-postgres-style `query(text, params)` returning `{ rows }`. This is\n * deliberately structural so you can pass a `pg.Pool`/`pg.Client`, a\n * `@neondatabase/serverless` client, or any thin wrapper that exposes `query` —\n * batchwork never imports a driver, so it adds no dependency of its own.\n */\nexport interface SqlExecutor {\n query: <Row = Record<string, unknown>>(\n text: string,\n params?: unknown[]\n ) => Promise<{ rows: Row[] }>;\n}\n\n/** Options for the Postgres-backed batch store. */\nexport interface PostgresStoreOptions {\n /** A `pg.Pool`-compatible client (anything with `query(text, params)`). */\n client: SqlExecutor;\n}\n\n/** Table name defaults to this; override for a custom schema. */\nexport const DEFAULT_BATCH_TABLE = \"batchwork_batches\";\n\n/**\n * Guard against SQL injection through a caller-supplied table name: identifiers\n * can't be parameterized, so they're interpolated directly and must be a plain\n * unquoted identifier (optionally schema-qualified).\n */\nexport const assertSafeTable = (table: string): string => {\n if (\n !/^[A-Za-z_][A-Za-z0-9_]*(?<schema>\\.[A-Za-z_][A-Za-z0-9_]*)?$/u.test(table)\n ) {\n throw new Error(\n `batchwork: unsafe Postgres table name ${JSON.stringify(table)}.`\n );\n }\n return table;\n};\n",
6
+ "import type { BatchStore, TrackedBatch } from \"../server/types\";\nimport type { BatchProvider, BatchStatus } from \"../types\";\nimport { assertSafeTable, DEFAULT_BATCH_TABLE } from \"./types\";\nimport type { PostgresStoreOptions, SqlExecutor } from \"./types\";\n\n/** Options for {@link createPostgresStore}. */\nexport interface PostgresBatchStoreOptions extends PostgresStoreOptions {\n /** Table to store tracked batches in. Defaults to `batchwork_batches`. */\n table?: string;\n}\n\n/** The raw row shape returned by the tracked-batch table. */\ninterface BatchRow {\n id: string;\n provider: BatchProvider;\n webhook_url: string | null;\n webhook_secret: string | null;\n status: BatchStatus;\n created_at: string;\n delivered_at: string | null;\n}\n\nconst toBatch = (row: BatchRow): TrackedBatch => ({\n createdAt: row.created_at,\n id: row.id,\n provider: row.provider,\n status: row.status,\n // Re-add optional fields only when set, so the shape matches `createMemoryStore`\n // (and `list`'s `deliveredAt !== undefined` delivery filter stays correct).\n ...(row.webhook_url === null ? {} : { webhookUrl: row.webhook_url }),\n ...(row.webhook_secret === null ? {} : { webhookSecret: row.webhook_secret }),\n ...(row.delivered_at === null ? {} : { deliveredAt: row.delivered_at }),\n});\n\n/** `CREATE TABLE`/index DDL for the tracked-batch table (run by `migratePostgres`). */\nexport const batchTableDdl = (table = DEFAULT_BATCH_TABLE): string => {\n const name = assertSafeTable(table);\n return `\nCREATE TABLE IF NOT EXISTS ${name} (\n id text PRIMARY KEY,\n provider text NOT NULL,\n webhook_url text,\n webhook_secret text,\n status text NOT NULL,\n created_at text NOT NULL,\n delivered_at text\n);\nCREATE INDEX IF NOT EXISTS ${name}_undelivered_idx\n ON ${name} (created_at) WHERE delivered_at IS NULL;`;\n};\n\n/**\n * A Postgres-backed {@link BatchStore} for the poller. Run {@link migratePostgres}\n * (or {@link batchTableDdl}) once to create the table.\n *\n * @example\n * import { Pool } from \"pg\";\n * const store = createPostgresStore({ client: new Pool({ connectionString }) });\n */\nexport const createPostgresStore = (\n options: PostgresBatchStoreOptions\n): BatchStore => {\n const { client }: { client: SqlExecutor } = options;\n const table = assertSafeTable(options.table ?? DEFAULT_BATCH_TABLE);\n\n return {\n delete: async (id) => {\n await client.query(`DELETE FROM ${table} WHERE id = $1`, [id]);\n },\n get: async (id) => {\n const { rows } = await client.query<BatchRow>(\n `SELECT * FROM ${table} WHERE id = $1`,\n [id]\n );\n const [row] = rows;\n return row ? toBatch(row) : null;\n },\n list: async (filter) => {\n let text = `SELECT * FROM ${table}`;\n if (filter?.delivered === true) {\n text += \" WHERE delivered_at IS NOT NULL\";\n } else if (filter?.delivered === false) {\n text += \" WHERE delivered_at IS NULL\";\n }\n const { rows } = await client.query<BatchRow>(text);\n return rows.map(toBatch);\n },\n set: async (record) => {\n await client.query(\n `INSERT INTO ${table}\n (id, provider, webhook_url, webhook_secret, status, created_at, delivered_at)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ON CONFLICT (id) DO UPDATE SET\n provider = EXCLUDED.provider,\n webhook_url = EXCLUDED.webhook_url,\n webhook_secret = EXCLUDED.webhook_secret,\n status = EXCLUDED.status,\n created_at = EXCLUDED.created_at,\n delivered_at = EXCLUDED.delivered_at`,\n [\n record.id,\n record.provider,\n record.webhookUrl ?? null,\n record.webhookSecret ?? null,\n record.status,\n record.createdAt,\n record.deliveredAt ?? null,\n ]\n );\n },\n };\n};\n",
7
+ "import { batchTableDdl } from \"./batch-store\";\nimport { assertSafeTable, DEFAULT_BATCH_TABLE } from \"./types\";\nimport type { SqlExecutor } from \"./types\";\n\n/** Options for {@link migratePostgres}. */\nexport interface MigrateOptions {\n /** Tracked-batch table name. Defaults to `batchwork_batches`. */\n batchTable?: string;\n}\n\n// Run a multi-statement DDL string one statement at a time: some drivers\n// (notably PGlite's extended protocol) reject multiple statements per query.\nconst runDdl = async (client: SqlExecutor, ddl: string): Promise<void> => {\n for (const statement of ddl.split(\";\")) {\n const trimmed = statement.trim();\n if (trimmed) {\n // oxlint-disable-next-line no-await-in-loop -- DDL must run in order.\n await client.query(trimmed);\n }\n }\n};\n\n/**\n * Create the table the batch store needs. Idempotent (`CREATE TABLE IF NOT\n * EXISTS`), so it's safe to run on every boot. Call once before using the store.\n *\n * @example\n * await migratePostgres(pool);\n */\nexport const migratePostgres = async (\n client: SqlExecutor,\n options: MigrateOptions = {}\n): Promise<void> => {\n await runDdl(\n client,\n batchTableDdl(assertSafeTable(options.batchTable ?? DEFAULT_BATCH_TABLE))\n );\n};\n"
8
+ ],
9
+ "mappings": ";;;AAqBO,IAAM,sBAAsB;AAO5B,IAAM,kBAAkB,CAAC,UAA0B;AAAA,EACxD,IACE,CAAC,gEAAgE,KAAK,KAAK,GAC3E;AAAA,IACA,MAAM,IAAI,MACR,yCAAyC,KAAK,UAAU,KAAK,IAC/D;AAAA,EACF;AAAA,EACA,OAAO;AAAA;;;ACdT,IAAM,UAAU,CAAC,SAAiC;AAAA,EAChD,WAAW,IAAI;AAAA,EACf,IAAI,IAAI;AAAA,EACR,UAAU,IAAI;AAAA,EACd,QAAQ,IAAI;AAAA,KAGR,IAAI,gBAAgB,OAAO,CAAC,IAAI,EAAE,YAAY,IAAI,YAAY;AAAA,KAC9D,IAAI,mBAAmB,OAAO,CAAC,IAAI,EAAE,eAAe,IAAI,eAAe;AAAA,KACvE,IAAI,iBAAiB,OAAO,CAAC,IAAI,EAAE,aAAa,IAAI,aAAa;AACvE;AAGO,IAAM,gBAAgB,CAAC,QAAQ,wBAAgC;AAAA,EACpE,MAAM,OAAO,gBAAgB,KAAK;AAAA,EAClC,OAAO;AAAA,6BACoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6BASA;AAAA,OACtB;AAAA;AAWA,IAAM,sBAAsB,CACjC,YACe;AAAA,EACf,QAAQ,WAAoC;AAAA,EAC5C,MAAM,QAAQ,gBAAgB,QAAQ,SAAS,mBAAmB;AAAA,EAElE,OAAO;AAAA,IACL,QAAQ,OAAO,OAAO;AAAA,MACpB,MAAM,OAAO,MAAM,eAAe,uBAAuB,CAAC,EAAE,CAAC;AAAA;AAAA,IAE/D,KAAK,OAAO,OAAO;AAAA,MACjB,QAAQ,SAAS,MAAM,OAAO,MAC5B,iBAAiB,uBACjB,CAAC,EAAE,CACL;AAAA,MACA,OAAO,OAAO;AAAA,MACd,OAAO,MAAM,QAAQ,GAAG,IAAI;AAAA;AAAA,IAE9B,MAAM,OAAO,WAAW;AAAA,MACtB,IAAI,OAAO,iBAAiB;AAAA,MAC5B,IAAI,QAAQ,cAAc,MAAM;AAAA,QAC9B,QAAQ;AAAA,MACV,EAAO,SAAI,QAAQ,cAAc,OAAO;AAAA,QACtC,QAAQ;AAAA,MACV;AAAA,MACA,QAAQ,SAAS,MAAM,OAAO,MAAgB,IAAI;AAAA,MAClD,OAAO,KAAK,IAAI,OAAO;AAAA;AAAA,IAEzB,KAAK,OAAO,WAAW;AAAA,MACrB,MAAM,OAAO,MACX,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kDAUf;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,OAAO,cAAc;AAAA,QACrB,OAAO,iBAAiB;AAAA,QACxB,OAAO;AAAA,QACP,OAAO;AAAA,QACP,OAAO,eAAe;AAAA,MACxB,CACF;AAAA;AAAA,EAEJ;AAAA;;AClGF,IAAM,SAAS,OAAO,QAAqB,QAA+B;AAAA,EACxE,WAAW,aAAa,IAAI,MAAM,GAAG,GAAG;AAAA,IACtC,MAAM,UAAU,UAAU,KAAK;AAAA,IAC/B,IAAI,SAAS;AAAA,MAEX,MAAM,OAAO,MAAM,OAAO;AAAA,IAC5B;AAAA,EACF;AAAA;AAUK,IAAM,kBAAkB,OAC7B,QACA,UAA0B,CAAC,MACT;AAAA,EAClB,MAAM,OACJ,QACA,cAAc,gBAAgB,QAAQ,cAAc,mBAAmB,CAAC,CAC1E;AAAA;",
10
+ "debugId": "119F35EA4B39BF6464756E2164756E21",
11
+ "names": []
12
+ }
@@ -0,0 +1,15 @@
1
+ import type { SqlExecutor } from "./types";
2
+ /** Options for {@link migratePostgres}. */
3
+ export interface MigrateOptions {
4
+ /** Tracked-batch table name. Defaults to `batchwork_batches`. */
5
+ batchTable?: string;
6
+ }
7
+ /**
8
+ * Create the table the batch store needs. Idempotent (`CREATE TABLE IF NOT
9
+ * EXISTS`), so it's safe to run on every boot. Call once before using the store.
10
+ *
11
+ * @example
12
+ * await migratePostgres(pool);
13
+ */
14
+ export declare const migratePostgres: (client: SqlExecutor, options?: MigrateOptions) => Promise<void>;
15
+ //# sourceMappingURL=migrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/postgres/migrate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,2CAA2C;AAC3C,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAcD;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,WAClB,WAAW,YACV,cAAc,KACtB,OAAO,CAAC,IAAI,CAKd,CAAC"}