@pipe0/client 1.0.31 → 1.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/generated/openapi.types.d.mts +442 -2430
- package/dist/generated/openapi.types.d.mts.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/pipe0.d.mts +21 -23
- package/dist/pipe0.d.mts.map +1 -1
- package/dist/pipe0.mjs +0 -2
- package/dist/pipe0.mjs.map +1 -1
- package/package.json +1 -1
package/dist/pipe0.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipe0.mjs","names":[],"sources":["../src/pipe0.ts"],"sourcesContent":["import createFetchClient, { type Client } from \"openapi-fetch\";\nimport { type CapacitySnapshot, CapacityTracker } from \"./capacity-tracker.js\";\nimport type { paths } from \"./generated/openapi.types.js\";\n\nexport type PipesRequest =\n paths[\"/v1/pipes/run\"][\"post\"][\"requestBody\"][\"content\"][\"application/json\"];\nexport type PipesResponse =\n paths[\"/v1/pipes/check/{run_id}\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport type SearchesRequest =\n paths[\"/v1/searches/run\"][\"post\"][\"requestBody\"][\"content\"][\"application/json\"];\nexport type SearchesResponse =\n paths[\"/v1/searches/check/{run_id}\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport type SearchRequest =\n paths[\"/v1/search/run\"][\"post\"][\"requestBody\"][\"content\"][\"application/json\"];\nexport type SearchResponse =\n paths[\"/v1/search/check/{run_id}\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport type SheetEffectsRequest =\n paths[\"/v1/sheets/{sheet_id}/effects/run\"][\"post\"][\"requestBody\"][\"content\"][\"application/json\"];\nexport type SheetEffectsResponse =\n paths[\"/v1/sheets/{sheet_id}/effects/check/{run_id}\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport class Pipe0TimeoutError extends Error {\n constructor(\n message: string,\n public readonly runId?: string,\n ) {\n super(message);\n this.name = \"Pipe0TimeoutError\";\n this.runId = runId;\n }\n}\n\nexport class Pipe0AbortError extends Error {\n constructor(\n message: string,\n public readonly runId?: string,\n ) {\n super(message);\n this.name = \"Pipe0AbortError\";\n this.runId = runId;\n }\n}\n\n/**\n * The server reports the run as `canceled` (via `pipes.cancel` /\n * `searches.cancel` or another client). Subclasses {@link Pipe0AbortError} so\n * existing `instanceof Pipe0AbortError` handling keeps working.\n */\nexport class Pipe0CanceledError extends Pipe0AbortError {\n constructor(message: string, runId?: string) {\n super(message, runId);\n this.name = \"Pipe0CanceledError\";\n }\n}\n\nexport class Pipe0BatchError extends Error {\n constructor(\n message: string,\n public readonly errors: Array<{ batchIndex: number; error: Error }>,\n public readonly successfulBatches: PipesResponse[],\n ) {\n super(message);\n this.name = \"Pipe0BatchError\";\n this.errors = errors;\n this.successfulBatches = successfulBatches;\n }\n}\n\nexport class Pipe0TaskError extends Error {\n constructor(\n message: string,\n public readonly responseBody?: unknown,\n ) {\n super(message);\n this.name = \"Pipe0TaskError\";\n this.responseBody = responseBody;\n }\n}\n\nexport class Pipe0ServerError extends Error {\n /** HTTP status of the error response, when known. */\n public readonly status?: number;\n /** RFC 7807 problem `type` discriminator (e.g. \"queue-limit-exceeded\", \"org-rate-limited\"). */\n public readonly problemType?: string;\n\n constructor(message: string, options: { status?: number; problemType?: string } = {}) {\n super(message);\n this.name = \"Pipe0ServerError\";\n this.status = options.status;\n this.problemType = options.problemType;\n }\n}\n\n/**\n * Thrown only after the SDK's automatic 429 handling exhausted its wait\n * budget (`rateLimitMaxWaitMs` / `queueFullMaxWaitMs`), or immediately when\n * `autoRetry429` is disabled the error surfaces as a plain\n * {@link Pipe0ServerError} instead. Subclasses Pipe0ServerError so existing\n * handling keeps working.\n */\nexport class Pipe0RateLimitError extends Pipe0ServerError {\n /** The delay the SDK would have waited next, in ms. */\n public readonly retryAfterMs?: number;\n /** Attempts made before giving up. */\n public readonly attempts: number;\n\n constructor(\n message: string,\n options: { problemType?: string; retryAfterMs?: number; attempts?: number } = {},\n ) {\n super(message, { status: 429, problemType: options.problemType });\n this.name = \"Pipe0RateLimitError\";\n this.retryAfterMs = options.retryAfterMs;\n this.attempts = options.attempts ?? 1;\n }\n}\n\nexport interface BatchOptions {\n /**\n * Callback invoked on each poll for any batch\n */\n onPoll?: (_batchIndex: number, _response: PipesResponse) => void;\n /**\n * Callback invoked when each batch completes\n */\n onBatchComplete?: (_batchIndex: number, _result: PipesResponse) => void;\n /**\n * Whether to stop all batches if one fails\n * @default true\n */\n stopOnError?: boolean;\n /**\n * AbortSignal to cancel all batch operations\n */\n signal?: AbortSignal;\n /**\n * The worst task priority the pool will voluntarily submit at. When the\n * next batch would land below this floor, submission waits for capacity\n * (returned by your own runs completing) instead. `3` means only the hard\n * ceiling paces you. @default the instance `priorityFloor` (2)\n */\n priorityFloor?: 1 | 2 | 3;\n /**\n * Cancel still-pending runs server-side when the AbortSignal fires.\n * @default the instance `cancelOnAbort` (true)\n */\n cancelOnAbort?: boolean;\n}\n\nexport interface SearchAllItem {\n /** The search payload (`search_id` + `config`), same shape as `searches.search`. */\n search: SearchRequest[\"search\"];\n /**\n * Max pages to fetch for this search. Pagination is auto-detected from each\n * response's `next_page`, so cursor- and page-number-based searches both work.\n * @default the call-level `maxPages`\n */\n maxPages?: number;\n}\n\nexport interface SearchAllOptions {\n /** Searches to run concurrently. Results are merged into one array. */\n searches: SearchAllItem[];\n /** Shared request config (e.g. `{ environment }`) applied to every search. */\n config?: SearchRequest[\"config\"];\n /**\n * Field names to dedupe the merged results by, compared on each field's\n * resolved `.value`. Multiple fields form a composite key; first match wins.\n * Rows missing any key field are kept as-is (never deduped away).\n */\n dedupeBy?: string[];\n /**\n * Default max pages per search when an item doesn't set its own. Pass\n * `Infinity` to fetch every page until the server reports no `next_page`.\n * @default 1\n */\n maxPages?: number;\n /**\n * Normalize the merged results to a single shape: every row gets the union of\n * all field names seen across every search, with absent fields set to `null`\n * (e.g. so `crustdata_company_match` / `amplemarket_company_match` both exist\n * on every row). @default true\n */\n normalize?: boolean;\n /** Max searches to run at once. @default maxConcurrentBatches */\n maxConcurrency?: number;\n /** AbortSignal to cancel all searches. */\n signal?: AbortSignal;\n /**\n * Throw on the first search error. When `false`, failed searches are collected\n * in `errors` and partial results are returned. @default true\n */\n stopOnError?: boolean;\n /**\n * Cancel still-pending search runs server-side when the AbortSignal fires.\n * @default the instance `cancelOnAbort` (true)\n */\n cancelOnAbort?: boolean;\n}\n\nexport interface SearchAllResult {\n /** Merged (and optionally deduped) results across every search and page. */\n results: SearchResponse[\"results\"];\n /** Per-search failures, populated only when `stopOnError` is `false`. */\n errors: Array<{ searchIndex: number; error: Error }>;\n}\n\nexport interface Pipe0Options {\n apiKey?: string;\n baseUrl?: string;\n credentials?: RequestInit[\"credentials\"];\n /**\n * Default timeout for polling operations in milliseconds\n * @default 900000 (15 minutes)\n */\n pollingTimeoutMs?: number;\n /**\n * Default polling interval in milliseconds\n * @default 1000 (1 second)\n */\n minPollingIntervalMs?: number;\n /**\n * Maximum polling interval in milliseconds (for exponential backoff)\n * @default 3000 (3 seconds)\n */\n maxPollingIntervalMs?: number;\n /**\n * Default batch size for large payloads\n * @default 100\n */\n defaultBatchSize?: number;\n /**\n * Maximum number of concurrent batch requests\n * @default 5\n */\n maxConcurrentBatches?: number;\n /**\n * Automatically absorb 429 responses: `org-rate-limited` sleeps the\n * server's Retry-After and retries; `queue-limit-exceeded` (queued-record\n * hard ceiling) backoff-retries the create until capacity frees. A\n * {@link Pipe0RateLimitError} is thrown only after the wait budget below is\n * exhausted. @default true\n */\n autoRetry429?: boolean;\n /**\n * Upper bound on a single Retry-After wait in milliseconds.\n * @default 30000 (30 seconds)\n */\n retryAfterCapMs?: number;\n /**\n * Total wait budget for `org-rate-limited` retries per request.\n * @default 120000 (2 minutes)\n */\n rateLimitMaxWaitMs?: number;\n /**\n * Total wait budget for `queue-limit-exceeded` retries per create.\n * @default 900000 (15 minutes)\n */\n queueFullMaxWaitMs?: number;\n /**\n * When an AbortSignal fires while the SDK is waiting on runs, cancel the\n * still-pending runs server-side (best-effort) so their records return to\n * your capacity immediately. Set `false` for abort-but-keep-running\n * semantics. @default true\n */\n cancelOnAbort?: boolean;\n /**\n * Default priority floor for `pipeInBatches`: the worst task priority the\n * batch pool voluntarily submits at (see the X-P1/P2/P3-Capacity headers).\n * @default 2\n */\n priorityFloor?: 1 | 2 | 3;\n /**\n * When batch submission is capacity-blocked with nothing of its own in\n * flight (capacity held by other clients), the pool re-probes by submitting\n * one batch after this delay — its response headers re-baseline the\n * capacity estimate. @default 15000 (15 seconds)\n */\n pacingProbeMs?: number;\n /** Observer invoked whenever fresh capacity headers are seen. */\n onCapacity?: (snapshot: CapacitySnapshot) => void;\n /** Custom fetch implementation (e.g. for testing). */\n fetch?: (input: Request) => Promise<Response>;\n}\n\n// Utility type for any possible API response data shape\ntype Pipe0TaskStatusResponse = PipesResponse | SearchResponse | SheetEffectsResponse;\n\n/** The run-creating endpoints — the only responses that carry capacity headers. */\nconst CAPACITY_HEADER_PATHS = new Set([\n \"/v1/pipes/run\",\n \"/v1/pipes/run/sync\",\n \"/v1/search/run\",\n \"/v1/search/run/sync\",\n \"/v1/searches/run\",\n \"/v1/searches/run/sync\",\n \"/v1/pipes/cancel/{run_id}\",\n \"/v1/search/cancel/{run_id}\",\n]);\n\nfunction extractProblemType(error: unknown): string | undefined {\n if (\n error !== null &&\n typeof error === \"object\" &&\n \"type\" in error &&\n typeof (error as { type: unknown }).type === \"string\"\n ) {\n return (error as { type: string }).type;\n }\n return undefined;\n}\n\nexport class Pipe0 {\n public client: Client<paths, `${string}/${string}`>;\n private apiKey?: string;\n\n private pollingTimeoutMs: number;\n private minPollingIntervalMs: number;\n private maxPollingIntervalMs: number;\n private defaultBatchSize: number;\n private maxConcurrentBatches: number;\n private autoRetry429: boolean;\n private retryAfterCapMs: number;\n private rateLimitMaxWaitMs: number;\n private queueFullMaxWaitMs: number;\n private defaultCancelOnAbort: boolean;\n private defaultPriorityFloor: 1 | 2 | 3;\n private pacingProbeMs: number;\n private onCapacity?: (snapshot: CapacitySnapshot) => void;\n private tracker = new CapacityTracker();\n\n constructor(options: Pipe0Options = {}) {\n // eslint-disable-next-line turbo/no-undeclared-env-vars\n const envApiKey = typeof process !== \"undefined\" ? process.env?.PIPE0_API_KEY : undefined;\n this.apiKey = options.apiKey ?? envApiKey;\n\n this.pollingTimeoutMs = options.pollingTimeoutMs ?? 900000;\n this.minPollingIntervalMs = options.minPollingIntervalMs ?? 1000;\n this.maxPollingIntervalMs = options.maxPollingIntervalMs ?? this.minPollingIntervalMs * 3;\n this.defaultBatchSize = options.defaultBatchSize ?? 100;\n this.maxConcurrentBatches = options.maxConcurrentBatches ?? 5;\n this.autoRetry429 = options.autoRetry429 ?? true;\n this.retryAfterCapMs = options.retryAfterCapMs ?? 30_000;\n this.rateLimitMaxWaitMs = options.rateLimitMaxWaitMs ?? 120_000;\n this.queueFullMaxWaitMs = options.queueFullMaxWaitMs ?? 900_000;\n this.defaultCancelOnAbort = options.cancelOnAbort ?? true;\n this.defaultPriorityFloor = options.priorityFloor ?? 2;\n this.pacingProbeMs = options.pacingProbeMs ?? 15_000;\n this.onCapacity = options.onCapacity;\n\n const headers: Record<string, string> = {};\n\n if (this.apiKey) {\n headers.Authorization = `Bearer ${this.apiKey}`;\n }\n\n this.client = createFetchClient<paths>({\n baseUrl: options.baseUrl ?? \"https://api.pipe0.com\",\n credentials: options.credentials\n ? options.credentials\n : options.baseUrl\n ? \"same-origin\"\n : \"include\",\n headers,\n fetch: options.fetch,\n });\n\n // Observe-only middleware: feeds the capacity tracker from response\n // headers so even direct `pipe0.client.POST(...)` usage keeps the\n // estimate fresh. Retrying lives in `request()` — middleware cannot\n // re-issue a request.\n this.client.use({\n onResponse: ({ schemaPath, response }) => {\n if (!CAPACITY_HEADER_PATHS.has(schemaPath)) return undefined;\n const snapshot = this.tracker.observeHeaders(response.headers);\n if (snapshot && this.onCapacity) {\n try {\n this.onCapacity(snapshot);\n } catch {\n // observer errors must never break requests\n }\n }\n return undefined;\n },\n });\n }\n\n /**\n * The SDK's current estimate of your organization's queue capacity, from\n * the most recent run-creating response's headers adjusted by runs the SDK\n * has since observed completing. Null until the first create.\n */\n get capacity(): CapacitySnapshot | null {\n return this.tracker.snapshot();\n }\n\n /**\n * The single request funnel: every API call goes through here so 429\n * handling and capacity bookkeeping live in exactly one place.\n *\n * - `org-rate-limited` (request bucket, has Retry-After): sleep and retry,\n * budget `rateLimitMaxWaitMs`.\n * - `queue-limit-exceeded` (queued-record hard ceiling, no Retry-After):\n * exponential backoff retry, budget `queueFullMaxWaitMs` — re-issuing the\n * create is safe because the ceiling rejects before anything is queued.\n * - Anything else throws {@link Pipe0ServerError} with `status` +\n * `problemType` attached.\n */\n private async request<T>(\n fn: () => Promise<{ data?: T; error?: unknown; response: Response }>,\n opts: {\n signal?: AbortSignal;\n retry?: boolean;\n /** Present ⇒ this is a run-creating call carrying this many records. */\n capacity?: { records: number };\n } = {},\n ): Promise<T> {\n const retryEnabled = opts.retry ?? this.autoRetry429;\n const startedAt = Date.now();\n let attempts = 0;\n let queueDelayMs = 5_000;\n\n while (true) {\n attempts += 1;\n // Debit BEFORE the await so concurrent submitters can't double-spend\n // the same capacity estimate.\n if (opts.capacity) this.tracker.onCreateIssued(opts.capacity.records);\n let result: { data?: T; error?: unknown; response: Response };\n try {\n result = await fn();\n } finally {\n // The middleware re-baselined from headers before this runs.\n if (opts.capacity) this.tracker.onCreateSettled(opts.capacity.records);\n }\n\n if (!result.error) return result.data as T;\n\n const status = result.response?.status;\n const problemType = extractProblemType(result.error);\n\n if (status !== 429 || !retryEnabled) {\n throw new Pipe0ServerError(JSON.stringify(result.error), { status, problemType });\n }\n\n const isQueueFull = problemType === \"queue-limit-exceeded\";\n let delayMs: number;\n let budgetMs: number;\n if (isQueueFull) {\n delayMs = queueDelayMs;\n queueDelayMs = Math.min(queueDelayMs * 2, 60_000);\n budgetMs = this.queueFullMaxWaitMs;\n } else {\n // org-rate-limited (or an unknown 429): honor Retry-After when present.\n const retryAfterSeconds = Number(result.response.headers.get(\"Retry-After\"));\n const baseMs =\n Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0\n ? retryAfterSeconds * 1000\n : 5_000;\n delayMs = Math.min(Math.max(baseMs, 1_000), this.retryAfterCapMs);\n budgetMs = this.rateLimitMaxWaitMs;\n }\n delayMs = Math.round(delayMs * (1 + Math.random() * 0.25));\n\n if (Date.now() - startedAt + delayMs > budgetMs) {\n throw new Pipe0RateLimitError(\n `Request still rate limited (${problemType ?? \"429\"}) after ${attempts} attempt(s) over ${Date.now() - startedAt}ms`,\n { problemType, retryAfterMs: delayMs, attempts },\n );\n }\n await this.sleep(delayMs, opts.signal);\n }\n }\n\n /**\n * Centralized logic to poll until a task completes, fails, or times out.\n */\n private async _pollUntilComplete<TResponse extends Pipe0TaskStatusResponse>(\n runId: string | Promise<string>,\n checkFn: (_id: string) => Promise<TResponse>,\n taskType: \"Pipe\" | \"Search\" | \"Effects\",\n options: {\n onPoll?: (_response: TResponse) => unknown;\n signal?: AbortSignal;\n /** Cancel the run server-side (best-effort) when the signal aborts. */\n cancelOnAbort?: boolean;\n /** How to cancel this run remotely; absent = surface has no cancel endpoint. */\n cancelFn?: (_id: string) => Promise<unknown>;\n } = {},\n ): Promise<TResponse> {\n const resolvedRunId = await runId;\n\n const timeout = this.pollingTimeoutMs;\n const initialInterval = this.minPollingIntervalMs;\n const maxInterval = this.maxPollingIntervalMs;\n const cancelOnAbort = options.cancelOnAbort ?? this.defaultCancelOnAbort;\n // We can hardcode backoff for simplicity since it's the only logic\n const useBackoff = true;\n\n const startTime = Date.now();\n let currentInterval = initialInterval;\n\n try {\n while (true) {\n if (Date.now() - startTime >= timeout) {\n throw new Pipe0TimeoutError(\n `${taskType} polling timed out after ${timeout}ms`,\n resolvedRunId,\n );\n }\n\n if (options.signal?.aborted) {\n throw new Pipe0AbortError(`${taskType} polling was aborted`, resolvedRunId);\n }\n\n const polledResponse = await checkFn(resolvedRunId);\n\n if (options.onPoll) {\n await options.onPoll(polledResponse);\n }\n\n if (polledResponse.status === \"completed\") {\n this.tracker.creditTerminal(resolvedRunId);\n return polledResponse;\n }\n\n // Effects-only terminal states: \"skipped\" means every step was a no-op —\n // a conclusion, not an error. \"canceled\" ends the run from the outside.\n if (polledResponse.status === \"skipped\") {\n this.tracker.creditTerminal(resolvedRunId);\n return polledResponse;\n }\n\n if (polledResponse.status === \"canceled\") {\n this.tracker.creditTerminal(resolvedRunId);\n throw new Pipe0CanceledError(`${taskType} run was canceled`, resolvedRunId);\n }\n\n if (polledResponse.status === \"failed\") {\n this.tracker.creditTerminal(resolvedRunId);\n throw new Pipe0TaskError(\n `${taskType} failed with status: ${polledResponse.status}`,\n polledResponse,\n );\n }\n\n await this.sleep(currentInterval, options.signal);\n\n if (useBackoff) {\n currentInterval = Math.min(currentInterval * 1.1, maxInterval);\n }\n }\n } catch (error) {\n // Abort exits (explicit check, aborted sleep, aborted fetch): the run is\n // still pending/processing server-side — best-effort cancel it so its\n // records return to the organization's capacity. Server-side \"canceled\"\n // is already terminal — nothing to cancel.\n if (\n cancelOnAbort &&\n options.cancelFn &&\n options.signal?.aborted &&\n !(error instanceof Pipe0CanceledError)\n ) {\n void options.cancelFn(resolvedRunId).catch(() => {});\n }\n throw error;\n }\n }\n\n public pipes = {\n /**\n * Create and immediately wait for completion (convenience method)\n */\n pipe: async (\n payload: PipesRequest,\n options: {\n onPoll?: (_response: PipesResponse) => unknown;\n signal?: AbortSignal;\n cancelOnAbort?: boolean;\n } = {},\n ): Promise<PipesResponse> => {\n return this.pipes.waitUntilComplete(await this.pipes.create(payload, options), options);\n },\n /**\n * Create a pipes task but don't wait for it. Use this method if you want to fire and forget.\n */\n create: async (payload: PipesRequest, options: { signal?: AbortSignal } = {}) => {\n const records = Array.isArray(payload.input) ? payload.input.length : 1;\n // No fetch-level signal on creates: the SDK must always learn the run id\n // so an abort can cancel the run remotely instead of orphaning it.\n const data = await this.request(() => this.client.POST(\"/v1/pipes/run\", { body: payload }), {\n signal: options.signal,\n capacity: { records },\n });\n this.tracker.registerRun(data.id, records);\n return data.id;\n },\n /**\n * Check the status of a pipes task manually.\n */\n check: async (runId: string, options: { signal?: AbortSignal } = {}) => {\n return this.request(\n () =>\n this.client.GET(\"/v1/pipes/check/{run_id}\", {\n params: { path: { run_id: runId } },\n signal: options.signal,\n }),\n { signal: options.signal },\n );\n },\n /**\n * Cancel a still-pending pipes run. Its records return to your\n * organization's capacity immediately. Runs that are already processing\n * or finished throw a {@link Pipe0ServerError} with `status: 409`.\n */\n cancel: async (runId: string, options: { signal?: AbortSignal } = {}) => {\n const data = await this.request(\n () =>\n this.client.POST(\"/v1/pipes/cancel/{run_id}\", {\n params: { path: { run_id: runId } },\n signal: options.signal,\n }),\n { signal: options.signal },\n );\n this.tracker.creditTerminal(runId);\n return data;\n },\n waitUntilComplete: async (\n runId: string | Promise<string>,\n options: {\n /**\n * Callback invoked on each poll with the current status\n */\n onPoll?: (_response: PipesResponse) => unknown;\n /**\n * AbortSignal to cancel the polling operation\n */\n signal?: AbortSignal;\n /**\n * Cancel the run server-side (best-effort) when the signal aborts.\n * @default the instance `cancelOnAbort` (true)\n */\n cancelOnAbort?: boolean;\n } = {},\n ): Promise<PipesResponse> => {\n return this._pollUntilComplete<PipesResponse>(\n runId,\n (id) => this.pipes.check(id, { signal: options.signal }),\n \"Pipe\",\n { ...options, cancelFn: (id) => this.pipes.cancel(id) },\n );\n },\n /**\n * Process a large payload by batching the input array through a rolling\n * pool: the next batch is submitted whenever a concurrency slot is free\n * AND the capacity estimate says it would still be admitted at\n * `priorityFloor` or better (see the X-P1/P2/P3-Capacity headers).\n * @param payload - The pipe request payload with a large input array\n * @param options - Batching options\n * @returns Array of completed batch responses\n */\n pipeInBatches: async (\n payload: PipesRequest,\n { stopOnError = true, priorityFloor, cancelOnAbort, ...options }: BatchOptions = {},\n ): Promise<PipesResponse[]> => {\n const batchSize = this.defaultBatchSize;\n const maxConcurrency = this.maxConcurrentBatches;\n const floor = priorityFloor ?? this.defaultPriorityFloor;\n const doCancelOnAbort = cancelOnAbort ?? this.defaultCancelOnAbort;\n\n // Extract and validate input array\n if (!Array.isArray(payload.input)) {\n throw new Error(\"payload.input must be an array for batched operations\");\n }\n\n const inputArray = payload.input;\n\n // Create batches\n const batches: PipesRequest[] = [];\n for (let i = 0; i < inputArray.length; i += batchSize) {\n batches.push({ ...payload, input: inputArray.slice(i, i + batchSize) });\n }\n\n const results: (PipesResponse | undefined)[] = new Array(batches.length);\n const errors: Array<{ batchIndex: number; error: Error }> = [];\n const inFlight = new Set<Promise<void>>();\n /** batchIndex → runId while the run is still cancelable. */\n const pendingRuns = new Map<number, string>();\n let next = 0;\n let stopped = false;\n\n const sweepCancel = () => {\n if (!doCancelOnAbort) return;\n for (const runId of pendingRuns.values()) {\n void this.pipes.cancel(runId).catch(() => {});\n }\n pendingRuns.clear();\n };\n\n const runBatch = async (batchIndex: number) => {\n try {\n const runId = await this.pipes.create(batches[batchIndex]!, { signal: options.signal });\n pendingRuns.set(batchIndex, runId);\n const result = await this.pipes.waitUntilComplete(runId, {\n signal: options.signal,\n // The pool owns remote cancellation via sweepCancel — avoid\n // duplicate cancel requests from every inner waiter.\n cancelOnAbort: false,\n onPoll: options.onPoll\n ? (response) => options.onPoll!(batchIndex, response)\n : undefined,\n });\n pendingRuns.delete(batchIndex);\n results[batchIndex] = result;\n if (options.onBatchComplete) {\n options.onBatchComplete(batchIndex, result);\n }\n } catch (error) {\n if (error instanceof Pipe0AbortError && options.signal?.aborted) {\n // Aborted mid-run: keep the pendingRuns entry — the sweep cancels\n // it — and don't record abort noise as a batch failure.\n return;\n }\n pendingRuns.delete(batchIndex);\n errors.push({\n batchIndex,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n if (stopOnError) stopped = true;\n }\n };\n\n const submit = (batchIndex: number) => {\n const p: Promise<void> = runBatch(batchIndex).finally(() => inFlight.delete(p));\n inFlight.add(p);\n };\n\n try {\n while ((next < batches.length && !stopped) || inFlight.size > 0) {\n if (options.signal?.aborted) {\n throw new Pipe0AbortError(\"Batch operation was aborted\");\n }\n\n if (!stopped && next < batches.length && inFlight.size < maxConcurrency) {\n const records = (batches[next]!.input as unknown[]).length;\n const estimate = this.tracker.estimate(floor);\n if (estimate === null || estimate >= records) {\n submit(next++);\n continue; // greedily fill remaining slots\n }\n if (inFlight.size === 0) {\n // Capacity is held by other clients and nothing of ours is in\n // flight to wait on — timed probe: submit one batch regardless;\n // its response headers re-baseline the estimate. A bounded,\n // self-correcting floor violation.\n await this.sleep(this.pacingProbeMs, options.signal);\n if (options.signal?.aborted) {\n throw new Pipe0AbortError(\"Batch operation was aborted\");\n }\n submit(next++);\n continue;\n }\n }\n\n if (inFlight.size > 0) {\n // runBatch never rejects, so race only ever observes settles.\n await Promise.race(inFlight);\n }\n }\n } catch (error) {\n sweepCancel();\n throw error;\n }\n\n const compact = results.filter((r): r is PipesResponse => r !== undefined);\n\n if (stopped) {\n throw new Pipe0BatchError(\n `Batch ${errors[0]?.batchIndex} failed and stopOnError is enabled`,\n errors,\n compact,\n );\n }\n if (errors.length > 0) {\n throw new Pipe0BatchError(\n `${errors.length} batch(es) failed out of ${batches.length} total`,\n errors,\n compact,\n );\n }\n\n return compact;\n },\n };\n\n searches = {\n /**\n * Create and immediately wait for completion (convenience method)\n */\n search: async (\n payload: SearchRequest,\n options: {\n onPoll?: (_response: SearchResponse) => unknown;\n signal?: AbortSignal;\n cancelOnAbort?: boolean;\n } = {},\n ): Promise<SearchResponse> => {\n return this.searches.waitUntilComplete(await this.searches.create(payload, options), options);\n },\n\n /**\n * Create a searches task but don't wait for it.\n * Use this if you want fire and forget.\n */\n create: async (payload: SearchRequest, options: { signal?: AbortSignal } = {}) => {\n // One search = one queued record, regardless of result count.\n const data = await this.request(() => this.client.POST(\"/v1/search/run\", { body: payload }), {\n signal: options.signal,\n capacity: { records: 1 },\n });\n this.tracker.registerRun(data.id, 1);\n return data.id;\n },\n\n /**\n * Check the status of a search task manually.\n */\n check: async (runId: string, options: { signal?: AbortSignal } = {}) => {\n return this.request(\n () =>\n this.client.GET(\"/v1/search/check/{run_id}\", {\n params: { path: { run_id: runId } },\n signal: options.signal,\n }),\n { signal: options.signal },\n );\n },\n\n /**\n * Cancel a still-pending search run. It returns to your organization's\n * capacity immediately. Runs that are already processing or finished\n * throw a {@link Pipe0ServerError} with `status: 409`.\n */\n cancel: async (runId: string, options: { signal?: AbortSignal } = {}) => {\n const data = await this.request(\n () =>\n this.client.POST(\"/v1/search/cancel/{run_id}\", {\n params: { path: { run_id: runId } },\n signal: options.signal,\n }),\n { signal: options.signal },\n );\n this.tracker.creditTerminal(runId);\n return data;\n },\n\n /**\n * Poll until the search completes or fails.\n */\n waitUntilComplete: async (\n runId: string | Promise<string>,\n options: {\n onPoll?: (_response: SearchResponse) => unknown;\n signal?: AbortSignal;\n /**\n * Cancel the run server-side (best-effort) when the signal aborts.\n * @default the instance `cancelOnAbort` (true)\n */\n cancelOnAbort?: boolean;\n } = {},\n ): Promise<SearchResponse> => {\n return this._pollUntilComplete<SearchResponse>(\n runId,\n (id) => this.searches.check(id, { signal: options.signal }),\n \"Search\",\n { ...options, cancelFn: (id) => this.searches.cancel(id) },\n );\n },\n\n /**\n * Run several searches concurrently, auto-paginate each, and return one merged\n * (optionally deduped) result set. Pagination is detected from each response's\n * `next_page` token — which is itself a ready-to-send payload — so cursor- and\n * page-number-based searches are handled transparently.\n *\n * @example\n * const { results } = await pipe0.searches.searchAll({\n * config: { environment: \"production\" },\n * dedupeBy: [\"company_domain\"],\n * maxPages: 3,\n * searches: [\n * { search: { search_id: \"companies:profiles:crustdata@2\", config: { filters } } },\n * { search: { search_id: \"companies:profiles:amplemarket@2\", config: { filters } } },\n * ],\n * });\n */\n searchAll: async ({\n searches,\n config,\n dedupeBy,\n maxPages = 1,\n normalize = true,\n maxConcurrency = this.maxConcurrentBatches,\n signal,\n stopOnError = true,\n cancelOnAbort,\n }: SearchAllOptions): Promise<SearchAllResult> => {\n const errors: SearchAllResult[\"errors\"] = [];\n const merged: SearchResponse[\"results\"] = [];\n\n const runItem = async (item: SearchAllItem): Promise<SearchResponse[\"results\"]> => {\n const rows: SearchResponse[\"results\"] = [];\n let search = item.search;\n const pages = item.maxPages ?? maxPages;\n for (let page = 0; page < pages; page++) {\n if (signal?.aborted) throw new Pipe0AbortError(\"searchAll was aborted\");\n const res = await this.searches.search({ config, search }, { signal, cancelOnAbort });\n rows.push(...res.results);\n // `next_page` is a complete, re-sendable payload (original filters +\n // output_fields with only the cursor/page_number advanced), so we send\n // it verbatim — no need to know which pagination style the search uses.\n const next = res.next_page as SearchRequest[\"search\"] | null;\n if (!next) break;\n search = next;\n }\n return rows;\n };\n\n for (let i = 0; i < searches.length; i += maxConcurrency) {\n if (signal?.aborted) throw new Pipe0AbortError(\"searchAll was aborted\");\n const group = searches.slice(i, i + maxConcurrency);\n const settled = await Promise.all(\n group.map(async (item, groupIndex) => {\n try {\n return await runItem(item);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n errors.push({ searchIndex: i + groupIndex, error });\n if (stopOnError) throw error;\n return [] as SearchResponse[\"results\"];\n }\n }),\n );\n for (const rows of settled) merged.push(...rows);\n }\n\n const deduped = dedupeBy?.length ? dedupeResults(merged, dedupeBy) : merged;\n return {\n results: normalize ? normalizeResults(deduped) : deduped,\n errors,\n };\n },\n };\n\n sheets = {\n effects: {\n /**\n * Start an effects run on a sheet and return as soon as the server has\n * accepted it — the effects themselves keep running server-side, so the\n * returned run is normally still `processing`. This is the fire-and-forget\n * entry point; poll with `check` / `waitUntilComplete` only if you care\n * about the outcome.\n *\n * @example\n * await pipe0.sheets.effects.run(sheetId, {\n * config: { run_added_rows: true },\n * effects: [\n * {\n * effect_id: \"rows:add@1\",\n * connector: null,\n * config: { input: [{ email: \"ada@example.com\" }], allow_field_creation: false },\n * },\n * ],\n * });\n */\n run: async (sheetId: string, payload: SheetEffectsRequest): Promise<SheetEffectsResponse> => {\n return this.request(() =>\n this.client.POST(\"/v1/sheets/{sheet_id}/effects/run\", {\n params: { path: { sheet_id: sheetId } },\n body: payload,\n }),\n );\n },\n\n /**\n * Check the status of an effects run manually.\n */\n check: async (\n sheetId: string,\n runId: string,\n options: { signal?: AbortSignal } = {},\n ): Promise<SheetEffectsResponse> => {\n return this.request(\n () =>\n this.client.GET(\"/v1/sheets/{sheet_id}/effects/check/{run_id}\", {\n params: { path: { sheet_id: sheetId, run_id: runId } },\n signal: options.signal,\n }),\n { signal: options.signal },\n );\n },\n\n /**\n * Poll until the effects run concludes (`completed` / `skipped`), fails,\n * or is canceled.\n */\n waitUntilComplete: async (\n sheetId: string,\n runId: string | Promise<string>,\n options: {\n onPoll?: (_response: SheetEffectsResponse) => unknown;\n signal?: AbortSignal;\n } = {},\n ): Promise<SheetEffectsResponse> => {\n return this._pollUntilComplete<SheetEffectsResponse>(\n runId,\n (id) => this.sheets.effects.check(sheetId, id, { signal: options.signal }),\n \"Effects\",\n // No task-level cancel endpoint for effects runs — no cancelFn.\n options,\n );\n },\n\n /**\n * Run the effects and wait for the run to conclude (convenience method).\n */\n runUntilComplete: async (\n sheetId: string,\n payload: SheetEffectsRequest,\n options: {\n onPoll?: (_response: SheetEffectsResponse) => unknown;\n signal?: AbortSignal;\n } = {},\n ): Promise<SheetEffectsResponse> => {\n const { id } = await this.sheets.effects.run(sheetId, payload);\n return this.sheets.effects.waitUntilComplete(sheetId, id, options);\n },\n },\n };\n\n private sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(resolve, ms);\n\n if (signal) {\n const onAbort = () => {\n clearTimeout(timeout);\n reject(new Pipe0AbortError(\"Sleep was aborted\"));\n };\n\n if (signal.aborted) {\n clearTimeout(timeout);\n reject(new Pipe0AbortError(\"Sleep was aborted\"));\n return;\n }\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n });\n }\n}\n\n/**\n * Dedupe search-result rows by the resolved `.value` of one or more fields.\n * First occurrence wins; rows missing any key field are kept (can't be deduped).\n */\nfunction dedupeResults(\n rows: SearchResponse[\"results\"],\n fields: string[],\n): SearchResponse[\"results\"] {\n const seen = new Set<string>();\n const out: SearchResponse[\"results\"] = [];\n for (const row of rows) {\n const cells = row as Record<string, { value?: unknown } | null>;\n const parts: string[] = [];\n let keyable = true;\n for (const field of fields) {\n const cell = cells[field];\n if (cell == null || cell.value == null) {\n keyable = false;\n break;\n }\n parts.push(JSON.stringify(cell.value));\n }\n if (!keyable) {\n out.push(row);\n continue;\n }\n const key = parts.join(\" \");\n if (seen.has(key)) continue;\n seen.add(key);\n out.push(row);\n }\n return out;\n}\n\n/**\n * Normalize merged rows to a uniform shape: every row gains the union of all\n * field names seen across the set, with absent fields set to `null`. A field\n * already present (even if its value is null) is left untouched.\n */\nfunction normalizeResults(rows: SearchResponse[\"results\"]): SearchResponse[\"results\"] {\n const keys = new Set<string>();\n for (const row of rows) {\n for (const key of Object.keys(row)) keys.add(key);\n }\n return rows.map((row) => {\n const source = row as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const key of keys) {\n out[key] = key in source ? source[key] : null;\n }\n return out as SearchResponse[\"results\"][number];\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pipe0.mjs","names":[],"sources":["../src/pipe0.ts"],"sourcesContent":["import createFetchClient, { type Client } from \"openapi-fetch\";\nimport { type CapacitySnapshot, CapacityTracker } from \"./capacity-tracker.js\";\nimport type { paths } from \"./generated/openapi.types.js\";\n\nexport type PipesRequest =\n paths[\"/v1/pipes/run\"][\"post\"][\"requestBody\"][\"content\"][\"application/json\"];\nexport type PipesResponse =\n paths[\"/v1/pipes/check/{run_id}\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport type SearchRequest =\n paths[\"/v1/search/run\"][\"post\"][\"requestBody\"][\"content\"][\"application/json\"];\nexport type SearchResponse =\n paths[\"/v1/search/check/{run_id}\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport type SheetEffectsRequest =\n paths[\"/v1/sheets/{sheet_id}/effects/run\"][\"post\"][\"requestBody\"][\"content\"][\"application/json\"];\nexport type SheetEffectsResponse =\n paths[\"/v1/sheets/{sheet_id}/effects/check/{run_id}\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport class Pipe0TimeoutError extends Error {\n constructor(\n message: string,\n public readonly runId?: string,\n ) {\n super(message);\n this.name = \"Pipe0TimeoutError\";\n this.runId = runId;\n }\n}\n\nexport class Pipe0AbortError extends Error {\n constructor(\n message: string,\n public readonly runId?: string,\n ) {\n super(message);\n this.name = \"Pipe0AbortError\";\n this.runId = runId;\n }\n}\n\n/**\n * The server reports the run as `canceled` (via `pipes.cancel` /\n * `searches.cancel` or another client). Subclasses {@link Pipe0AbortError} so\n * existing `instanceof Pipe0AbortError` handling keeps working.\n */\nexport class Pipe0CanceledError extends Pipe0AbortError {\n constructor(message: string, runId?: string) {\n super(message, runId);\n this.name = \"Pipe0CanceledError\";\n }\n}\n\nexport class Pipe0BatchError extends Error {\n constructor(\n message: string,\n public readonly errors: Array<{ batchIndex: number; error: Error }>,\n public readonly successfulBatches: PipesResponse[],\n ) {\n super(message);\n this.name = \"Pipe0BatchError\";\n this.errors = errors;\n this.successfulBatches = successfulBatches;\n }\n}\n\nexport class Pipe0TaskError extends Error {\n constructor(\n message: string,\n public readonly responseBody?: unknown,\n ) {\n super(message);\n this.name = \"Pipe0TaskError\";\n this.responseBody = responseBody;\n }\n}\n\nexport class Pipe0ServerError extends Error {\n /** HTTP status of the error response, when known. */\n public readonly status?: number;\n /** RFC 7807 problem `type` discriminator (e.g. \"queue-limit-exceeded\", \"org-rate-limited\"). */\n public readonly problemType?: string;\n\n constructor(message: string, options: { status?: number; problemType?: string } = {}) {\n super(message);\n this.name = \"Pipe0ServerError\";\n this.status = options.status;\n this.problemType = options.problemType;\n }\n}\n\n/**\n * Thrown only after the SDK's automatic 429 handling exhausted its wait\n * budget (`rateLimitMaxWaitMs` / `queueFullMaxWaitMs`), or immediately when\n * `autoRetry429` is disabled the error surfaces as a plain\n * {@link Pipe0ServerError} instead. Subclasses Pipe0ServerError so existing\n * handling keeps working.\n */\nexport class Pipe0RateLimitError extends Pipe0ServerError {\n /** The delay the SDK would have waited next, in ms. */\n public readonly retryAfterMs?: number;\n /** Attempts made before giving up. */\n public readonly attempts: number;\n\n constructor(\n message: string,\n options: { problemType?: string; retryAfterMs?: number; attempts?: number } = {},\n ) {\n super(message, { status: 429, problemType: options.problemType });\n this.name = \"Pipe0RateLimitError\";\n this.retryAfterMs = options.retryAfterMs;\n this.attempts = options.attempts ?? 1;\n }\n}\n\nexport interface BatchOptions {\n /**\n * Callback invoked on each poll for any batch\n */\n onPoll?: (_batchIndex: number, _response: PipesResponse) => void;\n /**\n * Callback invoked when each batch completes\n */\n onBatchComplete?: (_batchIndex: number, _result: PipesResponse) => void;\n /**\n * Whether to stop all batches if one fails\n * @default true\n */\n stopOnError?: boolean;\n /**\n * AbortSignal to cancel all batch operations\n */\n signal?: AbortSignal;\n /**\n * The worst task priority the pool will voluntarily submit at. When the\n * next batch would land below this floor, submission waits for capacity\n * (returned by your own runs completing) instead. `3` means only the hard\n * ceiling paces you. @default the instance `priorityFloor` (2)\n */\n priorityFloor?: 1 | 2 | 3;\n /**\n * Cancel still-pending runs server-side when the AbortSignal fires.\n * @default the instance `cancelOnAbort` (true)\n */\n cancelOnAbort?: boolean;\n}\n\nexport interface SearchAllItem {\n /** The search payload (`search_id` + `config`), same shape as `searches.search`. */\n search: SearchRequest[\"search\"];\n /**\n * Max pages to fetch for this search. Pagination is auto-detected from each\n * response's `next_page`, so cursor- and page-number-based searches both work.\n * @default the call-level `maxPages`\n */\n maxPages?: number;\n}\n\nexport interface SearchAllOptions {\n /** Searches to run concurrently. Results are merged into one array. */\n searches: SearchAllItem[];\n /** Shared request config (e.g. `{ environment }`) applied to every search. */\n config?: SearchRequest[\"config\"];\n /**\n * Field names to dedupe the merged results by, compared on each field's\n * resolved `.value`. Multiple fields form a composite key; first match wins.\n * Rows missing any key field are kept as-is (never deduped away).\n */\n dedupeBy?: string[];\n /**\n * Default max pages per search when an item doesn't set its own. Pass\n * `Infinity` to fetch every page until the server reports no `next_page`.\n * @default 1\n */\n maxPages?: number;\n /**\n * Normalize the merged results to a single shape: every row gets the union of\n * all field names seen across every search, with absent fields set to `null`\n * (e.g. so `crustdata_company_match` / `amplemarket_company_match` both exist\n * on every row). @default true\n */\n normalize?: boolean;\n /** Max searches to run at once. @default maxConcurrentBatches */\n maxConcurrency?: number;\n /** AbortSignal to cancel all searches. */\n signal?: AbortSignal;\n /**\n * Throw on the first search error. When `false`, failed searches are collected\n * in `errors` and partial results are returned. @default true\n */\n stopOnError?: boolean;\n /**\n * Cancel still-pending search runs server-side when the AbortSignal fires.\n * @default the instance `cancelOnAbort` (true)\n */\n cancelOnAbort?: boolean;\n}\n\nexport interface SearchAllResult {\n /** Merged (and optionally deduped) results across every search and page. */\n results: SearchResponse[\"results\"];\n /** Per-search failures, populated only when `stopOnError` is `false`. */\n errors: Array<{ searchIndex: number; error: Error }>;\n}\n\nexport interface Pipe0Options {\n apiKey?: string;\n baseUrl?: string;\n credentials?: RequestInit[\"credentials\"];\n /**\n * Default timeout for polling operations in milliseconds\n * @default 900000 (15 minutes)\n */\n pollingTimeoutMs?: number;\n /**\n * Default polling interval in milliseconds\n * @default 1000 (1 second)\n */\n minPollingIntervalMs?: number;\n /**\n * Maximum polling interval in milliseconds (for exponential backoff)\n * @default 3000 (3 seconds)\n */\n maxPollingIntervalMs?: number;\n /**\n * Default batch size for large payloads\n * @default 100\n */\n defaultBatchSize?: number;\n /**\n * Maximum number of concurrent batch requests\n * @default 5\n */\n maxConcurrentBatches?: number;\n /**\n * Automatically absorb 429 responses: `org-rate-limited` sleeps the\n * server's Retry-After and retries; `queue-limit-exceeded` (queued-record\n * hard ceiling) backoff-retries the create until capacity frees. A\n * {@link Pipe0RateLimitError} is thrown only after the wait budget below is\n * exhausted. @default true\n */\n autoRetry429?: boolean;\n /**\n * Upper bound on a single Retry-After wait in milliseconds.\n * @default 30000 (30 seconds)\n */\n retryAfterCapMs?: number;\n /**\n * Total wait budget for `org-rate-limited` retries per request.\n * @default 120000 (2 minutes)\n */\n rateLimitMaxWaitMs?: number;\n /**\n * Total wait budget for `queue-limit-exceeded` retries per create.\n * @default 900000 (15 minutes)\n */\n queueFullMaxWaitMs?: number;\n /**\n * When an AbortSignal fires while the SDK is waiting on runs, cancel the\n * still-pending runs server-side (best-effort) so their records return to\n * your capacity immediately. Set `false` for abort-but-keep-running\n * semantics. @default true\n */\n cancelOnAbort?: boolean;\n /**\n * Default priority floor for `pipeInBatches`: the worst task priority the\n * batch pool voluntarily submits at (see the X-P1/P2/P3-Capacity headers).\n * @default 2\n */\n priorityFloor?: 1 | 2 | 3;\n /**\n * When batch submission is capacity-blocked with nothing of its own in\n * flight (capacity held by other clients), the pool re-probes by submitting\n * one batch after this delay — its response headers re-baseline the\n * capacity estimate. @default 15000 (15 seconds)\n */\n pacingProbeMs?: number;\n /** Observer invoked whenever fresh capacity headers are seen. */\n onCapacity?: (snapshot: CapacitySnapshot) => void;\n /** Custom fetch implementation (e.g. for testing). */\n fetch?: (input: Request) => Promise<Response>;\n}\n\n// Utility type for any possible API response data shape\ntype Pipe0TaskStatusResponse = PipesResponse | SearchResponse | SheetEffectsResponse;\n\n/** The run-creating endpoints — the only responses that carry capacity headers. */\nconst CAPACITY_HEADER_PATHS = new Set([\n \"/v1/pipes/run\",\n \"/v1/pipes/run/sync\",\n \"/v1/search/run\",\n \"/v1/search/run/sync\",\n \"/v1/pipes/cancel/{run_id}\",\n \"/v1/search/cancel/{run_id}\",\n]);\n\nfunction extractProblemType(error: unknown): string | undefined {\n if (\n error !== null &&\n typeof error === \"object\" &&\n \"type\" in error &&\n typeof (error as { type: unknown }).type === \"string\"\n ) {\n return (error as { type: string }).type;\n }\n return undefined;\n}\n\nexport class Pipe0 {\n public client: Client<paths, `${string}/${string}`>;\n private apiKey?: string;\n\n private pollingTimeoutMs: number;\n private minPollingIntervalMs: number;\n private maxPollingIntervalMs: number;\n private defaultBatchSize: number;\n private maxConcurrentBatches: number;\n private autoRetry429: boolean;\n private retryAfterCapMs: number;\n private rateLimitMaxWaitMs: number;\n private queueFullMaxWaitMs: number;\n private defaultCancelOnAbort: boolean;\n private defaultPriorityFloor: 1 | 2 | 3;\n private pacingProbeMs: number;\n private onCapacity?: (snapshot: CapacitySnapshot) => void;\n private tracker = new CapacityTracker();\n\n constructor(options: Pipe0Options = {}) {\n // eslint-disable-next-line turbo/no-undeclared-env-vars\n const envApiKey = typeof process !== \"undefined\" ? process.env?.PIPE0_API_KEY : undefined;\n this.apiKey = options.apiKey ?? envApiKey;\n\n this.pollingTimeoutMs = options.pollingTimeoutMs ?? 900000;\n this.minPollingIntervalMs = options.minPollingIntervalMs ?? 1000;\n this.maxPollingIntervalMs = options.maxPollingIntervalMs ?? this.minPollingIntervalMs * 3;\n this.defaultBatchSize = options.defaultBatchSize ?? 100;\n this.maxConcurrentBatches = options.maxConcurrentBatches ?? 5;\n this.autoRetry429 = options.autoRetry429 ?? true;\n this.retryAfterCapMs = options.retryAfterCapMs ?? 30_000;\n this.rateLimitMaxWaitMs = options.rateLimitMaxWaitMs ?? 120_000;\n this.queueFullMaxWaitMs = options.queueFullMaxWaitMs ?? 900_000;\n this.defaultCancelOnAbort = options.cancelOnAbort ?? true;\n this.defaultPriorityFloor = options.priorityFloor ?? 2;\n this.pacingProbeMs = options.pacingProbeMs ?? 15_000;\n this.onCapacity = options.onCapacity;\n\n const headers: Record<string, string> = {};\n\n if (this.apiKey) {\n headers.Authorization = `Bearer ${this.apiKey}`;\n }\n\n this.client = createFetchClient<paths>({\n baseUrl: options.baseUrl ?? \"https://api.pipe0.com\",\n credentials: options.credentials\n ? options.credentials\n : options.baseUrl\n ? \"same-origin\"\n : \"include\",\n headers,\n fetch: options.fetch,\n });\n\n // Observe-only middleware: feeds the capacity tracker from response\n // headers so even direct `pipe0.client.POST(...)` usage keeps the\n // estimate fresh. Retrying lives in `request()` — middleware cannot\n // re-issue a request.\n this.client.use({\n onResponse: ({ schemaPath, response }) => {\n if (!CAPACITY_HEADER_PATHS.has(schemaPath)) return undefined;\n const snapshot = this.tracker.observeHeaders(response.headers);\n if (snapshot && this.onCapacity) {\n try {\n this.onCapacity(snapshot);\n } catch {\n // observer errors must never break requests\n }\n }\n return undefined;\n },\n });\n }\n\n /**\n * The SDK's current estimate of your organization's queue capacity, from\n * the most recent run-creating response's headers adjusted by runs the SDK\n * has since observed completing. Null until the first create.\n */\n get capacity(): CapacitySnapshot | null {\n return this.tracker.snapshot();\n }\n\n /**\n * The single request funnel: every API call goes through here so 429\n * handling and capacity bookkeeping live in exactly one place.\n *\n * - `org-rate-limited` (request bucket, has Retry-After): sleep and retry,\n * budget `rateLimitMaxWaitMs`.\n * - `queue-limit-exceeded` (queued-record hard ceiling, no Retry-After):\n * exponential backoff retry, budget `queueFullMaxWaitMs` — re-issuing the\n * create is safe because the ceiling rejects before anything is queued.\n * - Anything else throws {@link Pipe0ServerError} with `status` +\n * `problemType` attached.\n */\n private async request<T>(\n fn: () => Promise<{ data?: T; error?: unknown; response: Response }>,\n opts: {\n signal?: AbortSignal;\n retry?: boolean;\n /** Present ⇒ this is a run-creating call carrying this many records. */\n capacity?: { records: number };\n } = {},\n ): Promise<T> {\n const retryEnabled = opts.retry ?? this.autoRetry429;\n const startedAt = Date.now();\n let attempts = 0;\n let queueDelayMs = 5_000;\n\n while (true) {\n attempts += 1;\n // Debit BEFORE the await so concurrent submitters can't double-spend\n // the same capacity estimate.\n if (opts.capacity) this.tracker.onCreateIssued(opts.capacity.records);\n let result: { data?: T; error?: unknown; response: Response };\n try {\n result = await fn();\n } finally {\n // The middleware re-baselined from headers before this runs.\n if (opts.capacity) this.tracker.onCreateSettled(opts.capacity.records);\n }\n\n if (!result.error) return result.data as T;\n\n const status = result.response?.status;\n const problemType = extractProblemType(result.error);\n\n if (status !== 429 || !retryEnabled) {\n throw new Pipe0ServerError(JSON.stringify(result.error), { status, problemType });\n }\n\n const isQueueFull = problemType === \"queue-limit-exceeded\";\n let delayMs: number;\n let budgetMs: number;\n if (isQueueFull) {\n delayMs = queueDelayMs;\n queueDelayMs = Math.min(queueDelayMs * 2, 60_000);\n budgetMs = this.queueFullMaxWaitMs;\n } else {\n // org-rate-limited (or an unknown 429): honor Retry-After when present.\n const retryAfterSeconds = Number(result.response.headers.get(\"Retry-After\"));\n const baseMs =\n Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0\n ? retryAfterSeconds * 1000\n : 5_000;\n delayMs = Math.min(Math.max(baseMs, 1_000), this.retryAfterCapMs);\n budgetMs = this.rateLimitMaxWaitMs;\n }\n delayMs = Math.round(delayMs * (1 + Math.random() * 0.25));\n\n if (Date.now() - startedAt + delayMs > budgetMs) {\n throw new Pipe0RateLimitError(\n `Request still rate limited (${problemType ?? \"429\"}) after ${attempts} attempt(s) over ${Date.now() - startedAt}ms`,\n { problemType, retryAfterMs: delayMs, attempts },\n );\n }\n await this.sleep(delayMs, opts.signal);\n }\n }\n\n /**\n * Centralized logic to poll until a task completes, fails, or times out.\n */\n private async _pollUntilComplete<TResponse extends Pipe0TaskStatusResponse>(\n runId: string | Promise<string>,\n checkFn: (_id: string) => Promise<TResponse>,\n taskType: \"Pipe\" | \"Search\" | \"Effects\",\n options: {\n onPoll?: (_response: TResponse) => unknown;\n signal?: AbortSignal;\n /** Cancel the run server-side (best-effort) when the signal aborts. */\n cancelOnAbort?: boolean;\n /** How to cancel this run remotely; absent = surface has no cancel endpoint. */\n cancelFn?: (_id: string) => Promise<unknown>;\n } = {},\n ): Promise<TResponse> {\n const resolvedRunId = await runId;\n\n const timeout = this.pollingTimeoutMs;\n const initialInterval = this.minPollingIntervalMs;\n const maxInterval = this.maxPollingIntervalMs;\n const cancelOnAbort = options.cancelOnAbort ?? this.defaultCancelOnAbort;\n // We can hardcode backoff for simplicity since it's the only logic\n const useBackoff = true;\n\n const startTime = Date.now();\n let currentInterval = initialInterval;\n\n try {\n while (true) {\n if (Date.now() - startTime >= timeout) {\n throw new Pipe0TimeoutError(\n `${taskType} polling timed out after ${timeout}ms`,\n resolvedRunId,\n );\n }\n\n if (options.signal?.aborted) {\n throw new Pipe0AbortError(`${taskType} polling was aborted`, resolvedRunId);\n }\n\n const polledResponse = await checkFn(resolvedRunId);\n\n if (options.onPoll) {\n await options.onPoll(polledResponse);\n }\n\n if (polledResponse.status === \"completed\") {\n this.tracker.creditTerminal(resolvedRunId);\n return polledResponse;\n }\n\n // Effects-only terminal states: \"skipped\" means every step was a no-op —\n // a conclusion, not an error. \"canceled\" ends the run from the outside.\n if (polledResponse.status === \"skipped\") {\n this.tracker.creditTerminal(resolvedRunId);\n return polledResponse;\n }\n\n if (polledResponse.status === \"canceled\") {\n this.tracker.creditTerminal(resolvedRunId);\n throw new Pipe0CanceledError(`${taskType} run was canceled`, resolvedRunId);\n }\n\n if (polledResponse.status === \"failed\") {\n this.tracker.creditTerminal(resolvedRunId);\n throw new Pipe0TaskError(\n `${taskType} failed with status: ${polledResponse.status}`,\n polledResponse,\n );\n }\n\n await this.sleep(currentInterval, options.signal);\n\n if (useBackoff) {\n currentInterval = Math.min(currentInterval * 1.1, maxInterval);\n }\n }\n } catch (error) {\n // Abort exits (explicit check, aborted sleep, aborted fetch): the run is\n // still pending/processing server-side — best-effort cancel it so its\n // records return to the organization's capacity. Server-side \"canceled\"\n // is already terminal — nothing to cancel.\n if (\n cancelOnAbort &&\n options.cancelFn &&\n options.signal?.aborted &&\n !(error instanceof Pipe0CanceledError)\n ) {\n void options.cancelFn(resolvedRunId).catch(() => {});\n }\n throw error;\n }\n }\n\n public pipes = {\n /**\n * Create and immediately wait for completion (convenience method)\n */\n pipe: async (\n payload: PipesRequest,\n options: {\n onPoll?: (_response: PipesResponse) => unknown;\n signal?: AbortSignal;\n cancelOnAbort?: boolean;\n } = {},\n ): Promise<PipesResponse> => {\n return this.pipes.waitUntilComplete(await this.pipes.create(payload, options), options);\n },\n /**\n * Create a pipes task but don't wait for it. Use this method if you want to fire and forget.\n */\n create: async (payload: PipesRequest, options: { signal?: AbortSignal } = {}) => {\n const records = Array.isArray(payload.input) ? payload.input.length : 1;\n // No fetch-level signal on creates: the SDK must always learn the run id\n // so an abort can cancel the run remotely instead of orphaning it.\n const data = await this.request(() => this.client.POST(\"/v1/pipes/run\", { body: payload }), {\n signal: options.signal,\n capacity: { records },\n });\n this.tracker.registerRun(data.id, records);\n return data.id;\n },\n /**\n * Check the status of a pipes task manually.\n */\n check: async (runId: string, options: { signal?: AbortSignal } = {}) => {\n return this.request(\n () =>\n this.client.GET(\"/v1/pipes/check/{run_id}\", {\n params: { path: { run_id: runId } },\n signal: options.signal,\n }),\n { signal: options.signal },\n );\n },\n /**\n * Cancel a still-pending pipes run. Its records return to your\n * organization's capacity immediately. Runs that are already processing\n * or finished throw a {@link Pipe0ServerError} with `status: 409`.\n */\n cancel: async (runId: string, options: { signal?: AbortSignal } = {}) => {\n const data = await this.request(\n () =>\n this.client.POST(\"/v1/pipes/cancel/{run_id}\", {\n params: { path: { run_id: runId } },\n signal: options.signal,\n }),\n { signal: options.signal },\n );\n this.tracker.creditTerminal(runId);\n return data;\n },\n waitUntilComplete: async (\n runId: string | Promise<string>,\n options: {\n /**\n * Callback invoked on each poll with the current status\n */\n onPoll?: (_response: PipesResponse) => unknown;\n /**\n * AbortSignal to cancel the polling operation\n */\n signal?: AbortSignal;\n /**\n * Cancel the run server-side (best-effort) when the signal aborts.\n * @default the instance `cancelOnAbort` (true)\n */\n cancelOnAbort?: boolean;\n } = {},\n ): Promise<PipesResponse> => {\n return this._pollUntilComplete<PipesResponse>(\n runId,\n (id) => this.pipes.check(id, { signal: options.signal }),\n \"Pipe\",\n { ...options, cancelFn: (id) => this.pipes.cancel(id) },\n );\n },\n /**\n * Process a large payload by batching the input array through a rolling\n * pool: the next batch is submitted whenever a concurrency slot is free\n * AND the capacity estimate says it would still be admitted at\n * `priorityFloor` or better (see the X-P1/P2/P3-Capacity headers).\n * @param payload - The pipe request payload with a large input array\n * @param options - Batching options\n * @returns Array of completed batch responses\n */\n pipeInBatches: async (\n payload: PipesRequest,\n { stopOnError = true, priorityFloor, cancelOnAbort, ...options }: BatchOptions = {},\n ): Promise<PipesResponse[]> => {\n const batchSize = this.defaultBatchSize;\n const maxConcurrency = this.maxConcurrentBatches;\n const floor = priorityFloor ?? this.defaultPriorityFloor;\n const doCancelOnAbort = cancelOnAbort ?? this.defaultCancelOnAbort;\n\n // Extract and validate input array\n if (!Array.isArray(payload.input)) {\n throw new Error(\"payload.input must be an array for batched operations\");\n }\n\n const inputArray = payload.input;\n\n // Create batches\n const batches: PipesRequest[] = [];\n for (let i = 0; i < inputArray.length; i += batchSize) {\n batches.push({ ...payload, input: inputArray.slice(i, i + batchSize) });\n }\n\n const results: (PipesResponse | undefined)[] = new Array(batches.length);\n const errors: Array<{ batchIndex: number; error: Error }> = [];\n const inFlight = new Set<Promise<void>>();\n /** batchIndex → runId while the run is still cancelable. */\n const pendingRuns = new Map<number, string>();\n let next = 0;\n let stopped = false;\n\n const sweepCancel = () => {\n if (!doCancelOnAbort) return;\n for (const runId of pendingRuns.values()) {\n void this.pipes.cancel(runId).catch(() => {});\n }\n pendingRuns.clear();\n };\n\n const runBatch = async (batchIndex: number) => {\n try {\n const runId = await this.pipes.create(batches[batchIndex]!, { signal: options.signal });\n pendingRuns.set(batchIndex, runId);\n const result = await this.pipes.waitUntilComplete(runId, {\n signal: options.signal,\n // The pool owns remote cancellation via sweepCancel — avoid\n // duplicate cancel requests from every inner waiter.\n cancelOnAbort: false,\n onPoll: options.onPoll\n ? (response) => options.onPoll!(batchIndex, response)\n : undefined,\n });\n pendingRuns.delete(batchIndex);\n results[batchIndex] = result;\n if (options.onBatchComplete) {\n options.onBatchComplete(batchIndex, result);\n }\n } catch (error) {\n if (error instanceof Pipe0AbortError && options.signal?.aborted) {\n // Aborted mid-run: keep the pendingRuns entry — the sweep cancels\n // it — and don't record abort noise as a batch failure.\n return;\n }\n pendingRuns.delete(batchIndex);\n errors.push({\n batchIndex,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n if (stopOnError) stopped = true;\n }\n };\n\n const submit = (batchIndex: number) => {\n const p: Promise<void> = runBatch(batchIndex).finally(() => inFlight.delete(p));\n inFlight.add(p);\n };\n\n try {\n while ((next < batches.length && !stopped) || inFlight.size > 0) {\n if (options.signal?.aborted) {\n throw new Pipe0AbortError(\"Batch operation was aborted\");\n }\n\n if (!stopped && next < batches.length && inFlight.size < maxConcurrency) {\n const records = (batches[next]!.input as unknown[]).length;\n const estimate = this.tracker.estimate(floor);\n if (estimate === null || estimate >= records) {\n submit(next++);\n continue; // greedily fill remaining slots\n }\n if (inFlight.size === 0) {\n // Capacity is held by other clients and nothing of ours is in\n // flight to wait on — timed probe: submit one batch regardless;\n // its response headers re-baseline the estimate. A bounded,\n // self-correcting floor violation.\n await this.sleep(this.pacingProbeMs, options.signal);\n if (options.signal?.aborted) {\n throw new Pipe0AbortError(\"Batch operation was aborted\");\n }\n submit(next++);\n continue;\n }\n }\n\n if (inFlight.size > 0) {\n // runBatch never rejects, so race only ever observes settles.\n await Promise.race(inFlight);\n }\n }\n } catch (error) {\n sweepCancel();\n throw error;\n }\n\n const compact = results.filter((r): r is PipesResponse => r !== undefined);\n\n if (stopped) {\n throw new Pipe0BatchError(\n `Batch ${errors[0]?.batchIndex} failed and stopOnError is enabled`,\n errors,\n compact,\n );\n }\n if (errors.length > 0) {\n throw new Pipe0BatchError(\n `${errors.length} batch(es) failed out of ${batches.length} total`,\n errors,\n compact,\n );\n }\n\n return compact;\n },\n };\n\n searches = {\n /**\n * Create and immediately wait for completion (convenience method)\n */\n search: async (\n payload: SearchRequest,\n options: {\n onPoll?: (_response: SearchResponse) => unknown;\n signal?: AbortSignal;\n cancelOnAbort?: boolean;\n } = {},\n ): Promise<SearchResponse> => {\n return this.searches.waitUntilComplete(await this.searches.create(payload, options), options);\n },\n\n /**\n * Create a searches task but don't wait for it.\n * Use this if you want fire and forget.\n */\n create: async (payload: SearchRequest, options: { signal?: AbortSignal } = {}) => {\n // One search = one queued record, regardless of result count.\n const data = await this.request(() => this.client.POST(\"/v1/search/run\", { body: payload }), {\n signal: options.signal,\n capacity: { records: 1 },\n });\n this.tracker.registerRun(data.id, 1);\n return data.id;\n },\n\n /**\n * Check the status of a search task manually.\n */\n check: async (runId: string, options: { signal?: AbortSignal } = {}) => {\n return this.request(\n () =>\n this.client.GET(\"/v1/search/check/{run_id}\", {\n params: { path: { run_id: runId } },\n signal: options.signal,\n }),\n { signal: options.signal },\n );\n },\n\n /**\n * Cancel a still-pending search run. It returns to your organization's\n * capacity immediately. Runs that are already processing or finished\n * throw a {@link Pipe0ServerError} with `status: 409`.\n */\n cancel: async (runId: string, options: { signal?: AbortSignal } = {}) => {\n const data = await this.request(\n () =>\n this.client.POST(\"/v1/search/cancel/{run_id}\", {\n params: { path: { run_id: runId } },\n signal: options.signal,\n }),\n { signal: options.signal },\n );\n this.tracker.creditTerminal(runId);\n return data;\n },\n\n /**\n * Poll until the search completes or fails.\n */\n waitUntilComplete: async (\n runId: string | Promise<string>,\n options: {\n onPoll?: (_response: SearchResponse) => unknown;\n signal?: AbortSignal;\n /**\n * Cancel the run server-side (best-effort) when the signal aborts.\n * @default the instance `cancelOnAbort` (true)\n */\n cancelOnAbort?: boolean;\n } = {},\n ): Promise<SearchResponse> => {\n return this._pollUntilComplete<SearchResponse>(\n runId,\n (id) => this.searches.check(id, { signal: options.signal }),\n \"Search\",\n { ...options, cancelFn: (id) => this.searches.cancel(id) },\n );\n },\n\n /**\n * Run several searches concurrently, auto-paginate each, and return one merged\n * (optionally deduped) result set. Pagination is detected from each response's\n * `next_page` token — which is itself a ready-to-send payload — so cursor- and\n * page-number-based searches are handled transparently.\n *\n * @example\n * const { results } = await pipe0.searches.searchAll({\n * config: { environment: \"production\" },\n * dedupeBy: [\"company_domain\"],\n * maxPages: 3,\n * searches: [\n * { search: { search_id: \"companies:profiles:crustdata@2\", config: { filters } } },\n * { search: { search_id: \"companies:profiles:amplemarket@2\", config: { filters } } },\n * ],\n * });\n */\n searchAll: async ({\n searches,\n config,\n dedupeBy,\n maxPages = 1,\n normalize = true,\n maxConcurrency = this.maxConcurrentBatches,\n signal,\n stopOnError = true,\n cancelOnAbort,\n }: SearchAllOptions): Promise<SearchAllResult> => {\n const errors: SearchAllResult[\"errors\"] = [];\n const merged: SearchResponse[\"results\"] = [];\n\n const runItem = async (item: SearchAllItem): Promise<SearchResponse[\"results\"]> => {\n const rows: SearchResponse[\"results\"] = [];\n let search = item.search;\n const pages = item.maxPages ?? maxPages;\n for (let page = 0; page < pages; page++) {\n if (signal?.aborted) throw new Pipe0AbortError(\"searchAll was aborted\");\n const res = await this.searches.search({ config, search }, { signal, cancelOnAbort });\n rows.push(...res.results);\n // `next_page` is a complete, re-sendable payload (original filters +\n // output_fields with only the cursor/page_number advanced), so we send\n // it verbatim — no need to know which pagination style the search uses.\n const next = res.next_page as SearchRequest[\"search\"] | null;\n if (!next) break;\n search = next;\n }\n return rows;\n };\n\n for (let i = 0; i < searches.length; i += maxConcurrency) {\n if (signal?.aborted) throw new Pipe0AbortError(\"searchAll was aborted\");\n const group = searches.slice(i, i + maxConcurrency);\n const settled = await Promise.all(\n group.map(async (item, groupIndex) => {\n try {\n return await runItem(item);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n errors.push({ searchIndex: i + groupIndex, error });\n if (stopOnError) throw error;\n return [] as SearchResponse[\"results\"];\n }\n }),\n );\n for (const rows of settled) merged.push(...rows);\n }\n\n const deduped = dedupeBy?.length ? dedupeResults(merged, dedupeBy) : merged;\n return {\n results: normalize ? normalizeResults(deduped) : deduped,\n errors,\n };\n },\n };\n\n sheets = {\n effects: {\n /**\n * Start an effects run on a sheet and return as soon as the server has\n * accepted it — the effects themselves keep running server-side, so the\n * returned run is normally still `processing`. This is the fire-and-forget\n * entry point; poll with `check` / `waitUntilComplete` only if you care\n * about the outcome.\n *\n * @example\n * await pipe0.sheets.effects.run(sheetId, {\n * config: { run_added_rows: true },\n * effects: [\n * {\n * effect_id: \"rows:add@1\",\n * connector: null,\n * config: { input: [{ email: \"ada@example.com\" }], allow_field_creation: false },\n * },\n * ],\n * });\n */\n run: async (sheetId: string, payload: SheetEffectsRequest): Promise<SheetEffectsResponse> => {\n return this.request(() =>\n this.client.POST(\"/v1/sheets/{sheet_id}/effects/run\", {\n params: { path: { sheet_id: sheetId } },\n body: payload,\n }),\n );\n },\n\n /**\n * Check the status of an effects run manually.\n */\n check: async (\n sheetId: string,\n runId: string,\n options: { signal?: AbortSignal } = {},\n ): Promise<SheetEffectsResponse> => {\n return this.request(\n () =>\n this.client.GET(\"/v1/sheets/{sheet_id}/effects/check/{run_id}\", {\n params: { path: { sheet_id: sheetId, run_id: runId } },\n signal: options.signal,\n }),\n { signal: options.signal },\n );\n },\n\n /**\n * Poll until the effects run concludes (`completed` / `skipped`), fails,\n * or is canceled.\n */\n waitUntilComplete: async (\n sheetId: string,\n runId: string | Promise<string>,\n options: {\n onPoll?: (_response: SheetEffectsResponse) => unknown;\n signal?: AbortSignal;\n } = {},\n ): Promise<SheetEffectsResponse> => {\n return this._pollUntilComplete<SheetEffectsResponse>(\n runId,\n (id) => this.sheets.effects.check(sheetId, id, { signal: options.signal }),\n \"Effects\",\n // No task-level cancel endpoint for effects runs — no cancelFn.\n options,\n );\n },\n\n /**\n * Run the effects and wait for the run to conclude (convenience method).\n */\n runUntilComplete: async (\n sheetId: string,\n payload: SheetEffectsRequest,\n options: {\n onPoll?: (_response: SheetEffectsResponse) => unknown;\n signal?: AbortSignal;\n } = {},\n ): Promise<SheetEffectsResponse> => {\n const { id } = await this.sheets.effects.run(sheetId, payload);\n return this.sheets.effects.waitUntilComplete(sheetId, id, options);\n },\n },\n };\n\n private sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(resolve, ms);\n\n if (signal) {\n const onAbort = () => {\n clearTimeout(timeout);\n reject(new Pipe0AbortError(\"Sleep was aborted\"));\n };\n\n if (signal.aborted) {\n clearTimeout(timeout);\n reject(new Pipe0AbortError(\"Sleep was aborted\"));\n return;\n }\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n });\n }\n}\n\n/**\n * Dedupe search-result rows by the resolved `.value` of one or more fields.\n * First occurrence wins; rows missing any key field are kept (can't be deduped).\n */\nfunction dedupeResults(\n rows: SearchResponse[\"results\"],\n fields: string[],\n): SearchResponse[\"results\"] {\n const seen = new Set<string>();\n const out: SearchResponse[\"results\"] = [];\n for (const row of rows) {\n const cells = row as Record<string, { value?: unknown } | null>;\n const parts: string[] = [];\n let keyable = true;\n for (const field of fields) {\n const cell = cells[field];\n if (cell == null || cell.value == null) {\n keyable = false;\n break;\n }\n parts.push(JSON.stringify(cell.value));\n }\n if (!keyable) {\n out.push(row);\n continue;\n }\n const key = parts.join(\" \");\n if (seen.has(key)) continue;\n seen.add(key);\n out.push(row);\n }\n return out;\n}\n\n/**\n * Normalize merged rows to a uniform shape: every row gains the union of all\n * field names seen across the set, with absent fields set to `null`. A field\n * already present (even if its value is null) is left untouched.\n */\nfunction normalizeResults(rows: SearchResponse[\"results\"]): SearchResponse[\"results\"] {\n const keys = new Set<string>();\n for (const row of rows) {\n for (const key of Object.keys(row)) keys.add(key);\n }\n return rows.map((row) => {\n const source = row as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const key of keys) {\n out[key] = key in source ? source[key] : null;\n }\n return out as SearchResponse[\"results\"][number];\n });\n}\n"],"mappings":"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"}
|