summaryrefslogtreecommitdiffhomepage
path: root/packages/sdk/src/internal
diff options
context:
space:
mode:
authorDax <[email protected]>2025-07-31 01:00:29 -0400
committerGitHub <[email protected]>2025-07-31 01:00:29 -0400
commit33cef075d228e80aefb44671ec68e1989c2855a8 (patch)
treed43a5c1bcc40d4d938eacccfd923c80301706cf1 /packages/sdk/src/internal
parentb09ebf464552f3899120b22c7a8572669000a554 (diff)
downloadopencode-33cef075d228e80aefb44671ec68e1989c2855a8.tar.gz
opencode-33cef075d228e80aefb44671ec68e1989c2855a8.zip
ci: new publish method (#1451)
Diffstat (limited to 'packages/sdk/src/internal')
-rw-r--r--packages/sdk/src/internal/README.md3
-rw-r--r--packages/sdk/src/internal/builtin-types.ts93
-rw-r--r--packages/sdk/src/internal/decoders/line.ts135
-rw-r--r--packages/sdk/src/internal/detect-platform.ts196
-rw-r--r--packages/sdk/src/internal/errors.ts33
-rw-r--r--packages/sdk/src/internal/headers.ts97
-rw-r--r--packages/sdk/src/internal/parse.ts64
-rw-r--r--packages/sdk/src/internal/request-options.ts93
-rw-r--r--packages/sdk/src/internal/shim-types.ts26
-rw-r--r--packages/sdk/src/internal/shims.ts107
-rw-r--r--packages/sdk/src/internal/to-file.ts154
-rw-r--r--packages/sdk/src/internal/types.ts95
-rw-r--r--packages/sdk/src/internal/uploads.ts187
-rw-r--r--packages/sdk/src/internal/utils.ts8
-rw-r--r--packages/sdk/src/internal/utils/base64.ts40
-rw-r--r--packages/sdk/src/internal/utils/bytes.ts32
-rw-r--r--packages/sdk/src/internal/utils/env.ts18
-rw-r--r--packages/sdk/src/internal/utils/log.ts126
-rw-r--r--packages/sdk/src/internal/utils/path.ts88
-rw-r--r--packages/sdk/src/internal/utils/sleep.ts3
-rw-r--r--packages/sdk/src/internal/utils/uuid.ts17
-rw-r--r--packages/sdk/src/internal/utils/values.ts105
22 files changed, 0 insertions, 1720 deletions
diff --git a/packages/sdk/src/internal/README.md b/packages/sdk/src/internal/README.md
deleted file mode 100644
index 3ef5a25ba..000000000
--- a/packages/sdk/src/internal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# `internal`
-
-The modules in this directory are not importable outside this package and will change between releases.
diff --git a/packages/sdk/src/internal/builtin-types.ts b/packages/sdk/src/internal/builtin-types.ts
deleted file mode 100644
index c23d3bded..000000000
--- a/packages/sdk/src/internal/builtin-types.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-export type Fetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
-
-/**
- * An alias to the builtin `RequestInit` type so we can
- * easily alias it in import statements if there are name clashes.
- *
- * https://developer.mozilla.org/docs/Web/API/RequestInit
- */
-type _RequestInit = RequestInit;
-
-/**
- * An alias to the builtin `Response` type so we can
- * easily alias it in import statements if there are name clashes.
- *
- * https://developer.mozilla.org/docs/Web/API/Response
- */
-type _Response = Response;
-
-/**
- * The type for the first argument to `fetch`.
- *
- * https://developer.mozilla.org/docs/Web/API/Window/fetch#resource
- */
-type _RequestInfo = Request | URL | string;
-
-/**
- * The type for constructing `RequestInit` Headers.
- *
- * https://developer.mozilla.org/docs/Web/API/RequestInit#setting_headers
- */
-type _HeadersInit = RequestInit['headers'];
-
-/**
- * The type for constructing `RequestInit` body.
- *
- * https://developer.mozilla.org/docs/Web/API/RequestInit#body
- */
-type _BodyInit = RequestInit['body'];
-
-/**
- * An alias to the builtin `Array<T>` type so we can
- * easily alias it in import statements if there are name clashes.
- */
-type _Array<T> = Array<T>;
-
-/**
- * An alias to the builtin `Record<K, T>` type so we can
- * easily alias it in import statements if there are name clashes.
- */
-type _Record<K extends keyof any, T> = Record<K, T>;
-
-export type {
- _Array as Array,
- _BodyInit as BodyInit,
- _HeadersInit as HeadersInit,
- _Record as Record,
- _RequestInfo as RequestInfo,
- _RequestInit as RequestInit,
- _Response as Response,
-};
-
-/**
- * A copy of the builtin `EndingType` type as it isn't fully supported in certain
- * environments and attempting to reference the global version will error.
- *
- * https://github.com/microsoft/TypeScript/blob/49ad1a3917a0ea57f5ff248159256e12bb1cb705/src/lib/dom.generated.d.ts#L27941
- */
-type EndingType = 'native' | 'transparent';
-
-/**
- * A copy of the builtin `BlobPropertyBag` type as it isn't fully supported in certain
- * environments and attempting to reference the global version will error.
- *
- * https://github.com/microsoft/TypeScript/blob/49ad1a3917a0ea57f5ff248159256e12bb1cb705/src/lib/dom.generated.d.ts#L154
- * https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob#options
- */
-export interface BlobPropertyBag {
- endings?: EndingType;
- type?: string;
-}
-
-/**
- * A copy of the builtin `FilePropertyBag` type as it isn't fully supported in certain
- * environments and attempting to reference the global version will error.
- *
- * https://github.com/microsoft/TypeScript/blob/49ad1a3917a0ea57f5ff248159256e12bb1cb705/src/lib/dom.generated.d.ts#L503
- * https://developer.mozilla.org/en-US/docs/Web/API/File/File#options
- */
-export interface FilePropertyBag extends BlobPropertyBag {
- lastModified?: number;
-}
diff --git a/packages/sdk/src/internal/decoders/line.ts b/packages/sdk/src/internal/decoders/line.ts
deleted file mode 100644
index b3bfa97cd..000000000
--- a/packages/sdk/src/internal/decoders/line.ts
+++ /dev/null
@@ -1,135 +0,0 @@
-import { concatBytes, decodeUTF8, encodeUTF8 } from '../utils/bytes';
-
-export type Bytes = string | ArrayBuffer | Uint8Array | null | undefined;
-
-/**
- * A re-implementation of httpx's `LineDecoder` in Python that handles incrementally
- * reading lines from text.
- *
- * https://github.com/encode/httpx/blob/920333ea98118e9cf617f246905d7b202510941c/httpx/_decoders.py#L258
- */
-export class LineDecoder {
- // prettier-ignore
- static NEWLINE_CHARS = new Set(['\n', '\r']);
- static NEWLINE_REGEXP = /\r\n|[\n\r]/g;
-
- #buffer: Uint8Array;
- #carriageReturnIndex: number | null;
-
- constructor() {
- this.#buffer = new Uint8Array();
- this.#carriageReturnIndex = null;
- }
-
- decode(chunk: Bytes): string[] {
- if (chunk == null) {
- return [];
- }
-
- const binaryChunk =
- chunk instanceof ArrayBuffer ? new Uint8Array(chunk)
- : typeof chunk === 'string' ? encodeUTF8(chunk)
- : chunk;
-
- this.#buffer = concatBytes([this.#buffer, binaryChunk]);
-
- const lines: string[] = [];
- let patternIndex;
- while ((patternIndex = findNewlineIndex(this.#buffer, this.#carriageReturnIndex)) != null) {
- if (patternIndex.carriage && this.#carriageReturnIndex == null) {
- // skip until we either get a corresponding `\n`, a new `\r` or nothing
- this.#carriageReturnIndex = patternIndex.index;
- continue;
- }
-
- // we got double \r or \rtext\n
- if (
- this.#carriageReturnIndex != null &&
- (patternIndex.index !== this.#carriageReturnIndex + 1 || patternIndex.carriage)
- ) {
- lines.push(decodeUTF8(this.#buffer.subarray(0, this.#carriageReturnIndex - 1)));
- this.#buffer = this.#buffer.subarray(this.#carriageReturnIndex);
- this.#carriageReturnIndex = null;
- continue;
- }
-
- const endIndex =
- this.#carriageReturnIndex !== null ? patternIndex.preceding - 1 : patternIndex.preceding;
-
- const line = decodeUTF8(this.#buffer.subarray(0, endIndex));
- lines.push(line);
-
- this.#buffer = this.#buffer.subarray(patternIndex.index);
- this.#carriageReturnIndex = null;
- }
-
- return lines;
- }
-
- flush(): string[] {
- if (!this.#buffer.length) {
- return [];
- }
- return this.decode('\n');
- }
-}
-
-/**
- * This function searches the buffer for the end patterns, (\r or \n)
- * and returns an object with the index preceding the matched newline and the
- * index after the newline char. `null` is returned if no new line is found.
- *
- * ```ts
- * findNewLineIndex('abc\ndef') -> { preceding: 2, index: 3 }
- * ```
- */
-function findNewlineIndex(
- buffer: Uint8Array,
- startIndex: number | null,
-): { preceding: number; index: number; carriage: boolean } | null {
- const newline = 0x0a; // \n
- const carriage = 0x0d; // \r
-
- for (let i = startIndex ?? 0; i < buffer.length; i++) {
- if (buffer[i] === newline) {
- return { preceding: i, index: i + 1, carriage: false };
- }
-
- if (buffer[i] === carriage) {
- return { preceding: i, index: i + 1, carriage: true };
- }
- }
-
- return null;
-}
-
-export function findDoubleNewlineIndex(buffer: Uint8Array): number {
- // This function searches the buffer for the end patterns (\r\r, \n\n, \r\n\r\n)
- // and returns the index right after the first occurrence of any pattern,
- // or -1 if none of the patterns are found.
- const newline = 0x0a; // \n
- const carriage = 0x0d; // \r
-
- for (let i = 0; i < buffer.length - 1; i++) {
- if (buffer[i] === newline && buffer[i + 1] === newline) {
- // \n\n
- return i + 2;
- }
- if (buffer[i] === carriage && buffer[i + 1] === carriage) {
- // \r\r
- return i + 2;
- }
- if (
- buffer[i] === carriage &&
- buffer[i + 1] === newline &&
- i + 3 < buffer.length &&
- buffer[i + 2] === carriage &&
- buffer[i + 3] === newline
- ) {
- // \r\n\r\n
- return i + 4;
- }
- }
-
- return -1;
-}
diff --git a/packages/sdk/src/internal/detect-platform.ts b/packages/sdk/src/internal/detect-platform.ts
deleted file mode 100644
index e82d95c92..000000000
--- a/packages/sdk/src/internal/detect-platform.ts
+++ /dev/null
@@ -1,196 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { VERSION } from '../version';
-
-export const isRunningInBrowser = () => {
- return (
- // @ts-ignore
- typeof window !== 'undefined' &&
- // @ts-ignore
- typeof window.document !== 'undefined' &&
- // @ts-ignore
- typeof navigator !== 'undefined'
- );
-};
-
-type DetectedPlatform = 'deno' | 'node' | 'edge' | 'unknown';
-
-/**
- * Note this does not detect 'browser'; for that, use getBrowserInfo().
- */
-function getDetectedPlatform(): DetectedPlatform {
- if (typeof Deno !== 'undefined' && Deno.build != null) {
- return 'deno';
- }
- if (typeof EdgeRuntime !== 'undefined') {
- return 'edge';
- }
- if (
- Object.prototype.toString.call(
- typeof (globalThis as any).process !== 'undefined' ? (globalThis as any).process : 0,
- ) === '[object process]'
- ) {
- return 'node';
- }
- return 'unknown';
-}
-
-declare const Deno: any;
-declare const EdgeRuntime: any;
-type Arch = 'x32' | 'x64' | 'arm' | 'arm64' | `other:${string}` | 'unknown';
-type PlatformName =
- | 'MacOS'
- | 'Linux'
- | 'Windows'
- | 'FreeBSD'
- | 'OpenBSD'
- | 'iOS'
- | 'Android'
- | `Other:${string}`
- | 'Unknown';
-type Browser = 'ie' | 'edge' | 'chrome' | 'firefox' | 'safari';
-type PlatformProperties = {
- 'X-Stainless-Lang': 'js';
- 'X-Stainless-Package-Version': string;
- 'X-Stainless-OS': PlatformName;
- 'X-Stainless-Arch': Arch;
- 'X-Stainless-Runtime': 'node' | 'deno' | 'edge' | `browser:${Browser}` | 'unknown';
- 'X-Stainless-Runtime-Version': string;
-};
-const getPlatformProperties = (): PlatformProperties => {
- const detectedPlatform = getDetectedPlatform();
- if (detectedPlatform === 'deno') {
- return {
- 'X-Stainless-Lang': 'js',
- 'X-Stainless-Package-Version': VERSION,
- 'X-Stainless-OS': normalizePlatform(Deno.build.os),
- 'X-Stainless-Arch': normalizeArch(Deno.build.arch),
- 'X-Stainless-Runtime': 'deno',
- 'X-Stainless-Runtime-Version':
- typeof Deno.version === 'string' ? Deno.version : Deno.version?.deno ?? 'unknown',
- };
- }
- if (typeof EdgeRuntime !== 'undefined') {
- return {
- 'X-Stainless-Lang': 'js',
- 'X-Stainless-Package-Version': VERSION,
- 'X-Stainless-OS': 'Unknown',
- 'X-Stainless-Arch': `other:${EdgeRuntime}`,
- 'X-Stainless-Runtime': 'edge',
- 'X-Stainless-Runtime-Version': (globalThis as any).process.version,
- };
- }
- // Check if Node.js
- if (detectedPlatform === 'node') {
- return {
- 'X-Stainless-Lang': 'js',
- 'X-Stainless-Package-Version': VERSION,
- 'X-Stainless-OS': normalizePlatform((globalThis as any).process.platform ?? 'unknown'),
- 'X-Stainless-Arch': normalizeArch((globalThis as any).process.arch ?? 'unknown'),
- 'X-Stainless-Runtime': 'node',
- 'X-Stainless-Runtime-Version': (globalThis as any).process.version ?? 'unknown',
- };
- }
-
- const browserInfo = getBrowserInfo();
- if (browserInfo) {
- return {
- 'X-Stainless-Lang': 'js',
- 'X-Stainless-Package-Version': VERSION,
- 'X-Stainless-OS': 'Unknown',
- 'X-Stainless-Arch': 'unknown',
- 'X-Stainless-Runtime': `browser:${browserInfo.browser}`,
- 'X-Stainless-Runtime-Version': browserInfo.version,
- };
- }
-
- // TODO add support for Cloudflare workers, etc.
- return {
- 'X-Stainless-Lang': 'js',
- 'X-Stainless-Package-Version': VERSION,
- 'X-Stainless-OS': 'Unknown',
- 'X-Stainless-Arch': 'unknown',
- 'X-Stainless-Runtime': 'unknown',
- 'X-Stainless-Runtime-Version': 'unknown',
- };
-};
-
-type BrowserInfo = {
- browser: Browser;
- version: string;
-};
-
-declare const navigator: { userAgent: string } | undefined;
-
-// Note: modified from https://github.com/JS-DevTools/host-environment/blob/b1ab79ecde37db5d6e163c050e54fe7d287d7c92/src/isomorphic.browser.ts
-function getBrowserInfo(): BrowserInfo | null {
- if (typeof navigator === 'undefined' || !navigator) {
- return null;
- }
-
- // NOTE: The order matters here!
- const browserPatterns = [
- { key: 'edge' as const, pattern: /Edge(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
- { key: 'ie' as const, pattern: /MSIE(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
- { key: 'ie' as const, pattern: /Trident(?:.*rv\:(\d+)\.(\d+)(?:\.(\d+))?)?/ },
- { key: 'chrome' as const, pattern: /Chrome(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
- { key: 'firefox' as const, pattern: /Firefox(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ },
- { key: 'safari' as const, pattern: /(?:Version\W+(\d+)\.(\d+)(?:\.(\d+))?)?(?:\W+Mobile\S*)?\W+Safari/ },
- ];
-
- // Find the FIRST matching browser
- for (const { key, pattern } of browserPatterns) {
- const match = pattern.exec(navigator.userAgent);
- if (match) {
- const major = match[1] || 0;
- const minor = match[2] || 0;
- const patch = match[3] || 0;
-
- return { browser: key, version: `${major}.${minor}.${patch}` };
- }
- }
-
- return null;
-}
-
-const normalizeArch = (arch: string): Arch => {
- // Node docs:
- // - https://nodejs.org/api/process.html#processarch
- // Deno docs:
- // - https://doc.deno.land/deno/stable/~/Deno.build
- if (arch === 'x32') return 'x32';
- if (arch === 'x86_64' || arch === 'x64') return 'x64';
- if (arch === 'arm') return 'arm';
- if (arch === 'aarch64' || arch === 'arm64') return 'arm64';
- if (arch) return `other:${arch}`;
- return 'unknown';
-};
-
-const normalizePlatform = (platform: string): PlatformName => {
- // Node platforms:
- // - https://nodejs.org/api/process.html#processplatform
- // Deno platforms:
- // - https://doc.deno.land/deno/stable/~/Deno.build
- // - https://github.com/denoland/deno/issues/14799
-
- platform = platform.toLowerCase();
-
- // NOTE: this iOS check is untested and may not work
- // Node does not work natively on IOS, there is a fork at
- // https://github.com/nodejs-mobile/nodejs-mobile
- // however it is unknown at the time of writing how to detect if it is running
- if (platform.includes('ios')) return 'iOS';
- if (platform === 'android') return 'Android';
- if (platform === 'darwin') return 'MacOS';
- if (platform === 'win32') return 'Windows';
- if (platform === 'freebsd') return 'FreeBSD';
- if (platform === 'openbsd') return 'OpenBSD';
- if (platform === 'linux') return 'Linux';
- if (platform) return `Other:${platform}`;
- return 'Unknown';
-};
-
-let _platformHeaders: PlatformProperties;
-export const getPlatformHeaders = () => {
- return (_platformHeaders ??= getPlatformProperties());
-};
diff --git a/packages/sdk/src/internal/errors.ts b/packages/sdk/src/internal/errors.ts
deleted file mode 100644
index 82c7b14d5..000000000
--- a/packages/sdk/src/internal/errors.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-export function isAbortError(err: unknown) {
- return (
- typeof err === 'object' &&
- err !== null &&
- // Spec-compliant fetch implementations
- (('name' in err && (err as any).name === 'AbortError') ||
- // Expo fetch
- ('message' in err && String((err as any).message).includes('FetchRequestCanceledException')))
- );
-}
-
-export const castToError = (err: any): Error => {
- if (err instanceof Error) return err;
- if (typeof err === 'object' && err !== null) {
- try {
- if (Object.prototype.toString.call(err) === '[object Error]') {
- // @ts-ignore - not all envs have native support for cause yet
- const error = new Error(err.message, err.cause ? { cause: err.cause } : {});
- if (err.stack) error.stack = err.stack;
- // @ts-ignore - not all envs have native support for cause yet
- if (err.cause && !error.cause) error.cause = err.cause;
- if (err.name) error.name = err.name;
- return error;
- }
- } catch {}
- try {
- return new Error(JSON.stringify(err));
- } catch {}
- }
- return new Error(err);
-};
diff --git a/packages/sdk/src/internal/headers.ts b/packages/sdk/src/internal/headers.ts
deleted file mode 100644
index c724a9d22..000000000
--- a/packages/sdk/src/internal/headers.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { isReadonlyArray } from './utils/values';
-
-type HeaderValue = string | undefined | null;
-export type HeadersLike =
- | Headers
- | readonly HeaderValue[][]
- | Record<string, HeaderValue | readonly HeaderValue[]>
- | undefined
- | null
- | NullableHeaders;
-
-const brand_privateNullableHeaders = /* @__PURE__ */ Symbol('brand.privateNullableHeaders');
-
-/**
- * @internal
- * Users can pass explicit nulls to unset default headers. When we parse them
- * into a standard headers type we need to preserve that information.
- */
-export type NullableHeaders = {
- /** Brand check, prevent users from creating a NullableHeaders. */
- [brand_privateNullableHeaders]: true;
- /** Parsed headers. */
- values: Headers;
- /** Set of lowercase header names explicitly set to null. */
- nulls: Set<string>;
-};
-
-function* iterateHeaders(headers: HeadersLike): IterableIterator<readonly [string, string | null]> {
- if (!headers) return;
-
- if (brand_privateNullableHeaders in headers) {
- const { values, nulls } = headers;
- yield* values.entries();
- for (const name of nulls) {
- yield [name, null];
- }
- return;
- }
-
- let shouldClear = false;
- let iter: Iterable<readonly (HeaderValue | readonly HeaderValue[])[]>;
- if (headers instanceof Headers) {
- iter = headers.entries();
- } else if (isReadonlyArray(headers)) {
- iter = headers;
- } else {
- shouldClear = true;
- iter = Object.entries(headers ?? {});
- }
- for (let row of iter) {
- const name = row[0];
- if (typeof name !== 'string') throw new TypeError('expected header name to be a string');
- const values = isReadonlyArray(row[1]) ? row[1] : [row[1]];
- let didClear = false;
- for (const value of values) {
- if (value === undefined) continue;
-
- // Objects keys always overwrite older headers, they never append.
- // Yield a null to clear the header before adding the new values.
- if (shouldClear && !didClear) {
- didClear = true;
- yield [name, null];
- }
- yield [name, value];
- }
- }
-}
-
-export const buildHeaders = (newHeaders: HeadersLike[]): NullableHeaders => {
- const targetHeaders = new Headers();
- const nullHeaders = new Set<string>();
- for (const headers of newHeaders) {
- const seenHeaders = new Set<string>();
- for (const [name, value] of iterateHeaders(headers)) {
- const lowerName = name.toLowerCase();
- if (!seenHeaders.has(lowerName)) {
- targetHeaders.delete(name);
- seenHeaders.add(lowerName);
- }
- if (value === null) {
- targetHeaders.delete(name);
- nullHeaders.add(lowerName);
- } else {
- targetHeaders.append(name, value);
- nullHeaders.delete(lowerName);
- }
- }
- }
- return { [brand_privateNullableHeaders]: true, values: targetHeaders, nulls: nullHeaders };
-};
-
-export const isEmptyHeaders = (headers: HeadersLike) => {
- for (const _ of iterateHeaders(headers)) return false;
- return true;
-};
diff --git a/packages/sdk/src/internal/parse.ts b/packages/sdk/src/internal/parse.ts
deleted file mode 100644
index dcb4026e3..000000000
--- a/packages/sdk/src/internal/parse.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import type { FinalRequestOptions } from './request-options';
-import { Stream } from '../core/streaming';
-import { type Opencode } from '../client';
-import { formatRequestDetails, loggerFor } from './utils/log';
-
-export type APIResponseProps = {
- response: Response;
- options: FinalRequestOptions;
- controller: AbortController;
- requestLogID: string;
- retryOfRequestLogID: string | undefined;
- startTime: number;
-};
-
-export async function defaultParseResponse<T>(client: Opencode, props: APIResponseProps): Promise<T> {
- const { response, requestLogID, retryOfRequestLogID, startTime } = props;
- const body = await (async () => {
- if (props.options.stream) {
- loggerFor(client).debug('response', response.status, response.url, response.headers, response.body);
-
- // Note: there is an invariant here that isn't represented in the type system
- // that if you set `stream: true` the response type must also be `Stream<T>`
-
- if (props.options.__streamClass) {
- return props.options.__streamClass.fromSSEResponse(response, props.controller, client) as any;
- }
-
- return Stream.fromSSEResponse(response, props.controller, client) as any;
- }
-
- // fetch refuses to read the body when the status code is 204.
- if (response.status === 204) {
- return null as T;
- }
-
- if (props.options.__binaryResponse) {
- return response as unknown as T;
- }
-
- const contentType = response.headers.get('content-type');
- const mediaType = contentType?.split(';')[0]?.trim();
- const isJSON = mediaType?.includes('application/json') || mediaType?.endsWith('+json');
- if (isJSON) {
- const json = await response.json();
- return json as T;
- }
-
- const text = await response.text();
- return text as unknown as T;
- })();
- loggerFor(client).debug(
- `[${requestLogID}] response parsed`,
- formatRequestDetails({
- retryOfRequestLogID,
- url: response.url,
- status: response.status,
- body,
- durationMs: Date.now() - startTime,
- }),
- );
- return body;
-}
diff --git a/packages/sdk/src/internal/request-options.ts b/packages/sdk/src/internal/request-options.ts
deleted file mode 100644
index 56765e5aa..000000000
--- a/packages/sdk/src/internal/request-options.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { NullableHeaders } from './headers';
-
-import type { BodyInit } from './builtin-types';
-import { Stream } from '../core/streaming';
-import type { HTTPMethod, MergedRequestInit } from './types';
-import { type HeadersLike } from './headers';
-
-export type FinalRequestOptions = RequestOptions & { method: HTTPMethod; path: string };
-
-export type RequestOptions = {
- /**
- * The HTTP method for the request (e.g., 'get', 'post', 'put', 'delete').
- */
- method?: HTTPMethod;
-
- /**
- * The URL path for the request.
- *
- * @example "/v1/foo"
- */
- path?: string;
-
- /**
- * Query parameters to include in the request URL.
- */
- query?: object | undefined | null;
-
- /**
- * The request body. Can be a string, JSON object, FormData, or other supported types.
- */
- body?: unknown;
-
- /**
- * HTTP headers to include with the request. Can be a Headers object, plain object, or array of tuples.
- */
- headers?: HeadersLike;
-
- /**
- * The maximum number of times that the client will retry a request in case of a
- * temporary failure, like a network error or a 5XX error from the server.
- *
- * @default 2
- */
- maxRetries?: number;
-
- stream?: boolean | undefined;
-
- /**
- * The maximum amount of time (in milliseconds) that the client should wait for a response
- * from the server before timing out a single request.
- *
- * @unit milliseconds
- */
- timeout?: number;
-
- /**
- * Additional `RequestInit` options to be passed to the underlying `fetch` call.
- * These options will be merged with the client's default fetch options.
- */
- fetchOptions?: MergedRequestInit;
-
- /**
- * An AbortSignal that can be used to cancel the request.
- */
- signal?: AbortSignal | undefined | null;
-
- /**
- * A unique key for this request to enable idempotency.
- */
- idempotencyKey?: string;
-
- /**
- * Override the default base URL for this specific request.
- */
- defaultBaseURL?: string | undefined;
-
- __binaryResponse?: boolean | undefined;
- __streamClass?: typeof Stream;
-};
-
-export type EncodedContent = { bodyHeaders: HeadersLike; body: BodyInit };
-export type RequestEncoder = (request: { headers: NullableHeaders; body: unknown }) => EncodedContent;
-
-export const FallbackEncoder: RequestEncoder = ({ headers, body }) => {
- return {
- bodyHeaders: {
- 'content-type': 'application/json',
- },
- body: JSON.stringify(body),
- };
-};
diff --git a/packages/sdk/src/internal/shim-types.ts b/packages/sdk/src/internal/shim-types.ts
deleted file mode 100644
index 8ddf7b0ad..000000000
--- a/packages/sdk/src/internal/shim-types.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-/**
- * Shims for types that we can't always rely on being available globally.
- *
- * Note: these only exist at the type-level, there is no corresponding runtime
- * version for any of these symbols.
- */
-
-type NeverToAny<T> = T extends never ? any : T;
-
-/** @ts-ignore */
-type _DOMReadableStream<R = any> = globalThis.ReadableStream<R>;
-
-/** @ts-ignore */
-type _NodeReadableStream<R = any> = import('stream/web').ReadableStream<R>;
-
-type _ConditionalNodeReadableStream<R = any> =
- typeof globalThis extends { ReadableStream: any } ? never : _NodeReadableStream<R>;
-
-type _ReadableStream<R = any> = NeverToAny<
- | ([0] extends [1 & _DOMReadableStream<R>] ? never : _DOMReadableStream<R>)
- | ([0] extends [1 & _ConditionalNodeReadableStream<R>] ? never : _ConditionalNodeReadableStream<R>)
->;
-
-export type { _ReadableStream as ReadableStream };
diff --git a/packages/sdk/src/internal/shims.ts b/packages/sdk/src/internal/shims.ts
deleted file mode 100644
index 17a7967aa..000000000
--- a/packages/sdk/src/internal/shims.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-/**
- * This module provides internal shims and utility functions for environments where certain Node.js or global types may not be available.
- *
- * These are used to ensure we can provide a consistent behaviour between different JavaScript environments and good error
- * messages in cases where an environment isn't fully supported.
- */
-
-import type { Fetch } from './builtin-types';
-import type { ReadableStream } from './shim-types';
-
-export function getDefaultFetch(): Fetch {
- if (typeof fetch !== 'undefined') {
- return fetch as any;
- }
-
- throw new Error(
- '`fetch` is not defined as a global; Either pass `fetch` to the client, `new Opencode({ fetch })` or polyfill the global, `globalThis.fetch = fetch`',
- );
-}
-
-type ReadableStreamArgs = ConstructorParameters<typeof ReadableStream>;
-
-export function makeReadableStream(...args: ReadableStreamArgs): ReadableStream {
- const ReadableStream = (globalThis as any).ReadableStream;
- if (typeof ReadableStream === 'undefined') {
- // Note: All of the platforms / runtimes we officially support already define
- // `ReadableStream` as a global, so this should only ever be hit on unsupported runtimes.
- throw new Error(
- '`ReadableStream` is not defined as a global; You will need to polyfill it, `globalThis.ReadableStream = ReadableStream`',
- );
- }
-
- return new ReadableStream(...args);
-}
-
-export function ReadableStreamFrom<T>(iterable: Iterable<T> | AsyncIterable<T>): ReadableStream<T> {
- let iter: AsyncIterator<T> | Iterator<T> =
- Symbol.asyncIterator in iterable ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator]();
-
- return makeReadableStream({
- start() {},
- async pull(controller: any) {
- const { done, value } = await iter.next();
- if (done) {
- controller.close();
- } else {
- controller.enqueue(value);
- }
- },
- async cancel() {
- await iter.return?.();
- },
- });
-}
-
-/**
- * Most browsers don't yet have async iterable support for ReadableStream,
- * and Node has a very different way of reading bytes from its "ReadableStream".
- *
- * This polyfill was pulled from https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490
- */
-export function ReadableStreamToAsyncIterable<T>(stream: any): AsyncIterableIterator<T> {
- if (stream[Symbol.asyncIterator]) return stream;
-
- const reader = stream.getReader();
- return {
- async next() {
- try {
- const result = await reader.read();
- if (result?.done) reader.releaseLock(); // release lock when stream becomes closed
- return result;
- } catch (e) {
- reader.releaseLock(); // release lock when stream becomes errored
- throw e;
- }
- },
- async return() {
- const cancelPromise = reader.cancel();
- reader.releaseLock();
- await cancelPromise;
- return { done: true, value: undefined };
- },
- [Symbol.asyncIterator]() {
- return this;
- },
- };
-}
-
-/**
- * Cancels a ReadableStream we don't need to consume.
- * See https://undici.nodejs.org/#/?id=garbage-collection
- */
-export async function CancelReadableStream(stream: any): Promise<void> {
- if (stream === null || typeof stream !== 'object') return;
-
- if (stream[Symbol.asyncIterator]) {
- await stream[Symbol.asyncIterator]().return?.();
- return;
- }
-
- const reader = stream.getReader();
- const cancelPromise = reader.cancel();
- reader.releaseLock();
- await cancelPromise;
-}
diff --git a/packages/sdk/src/internal/to-file.ts b/packages/sdk/src/internal/to-file.ts
deleted file mode 100644
index 245e84933..000000000
--- a/packages/sdk/src/internal/to-file.ts
+++ /dev/null
@@ -1,154 +0,0 @@
-import { BlobPart, getName, makeFile, isAsyncIterable } from './uploads';
-import type { FilePropertyBag } from './builtin-types';
-import { checkFileSupport } from './uploads';
-
-type BlobLikePart = string | ArrayBuffer | ArrayBufferView | BlobLike | DataView;
-
-/**
- * Intended to match DOM Blob, node-fetch Blob, node:buffer Blob, etc.
- * Don't add arrayBuffer here, node-fetch doesn't have it
- */
-interface BlobLike {
- /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/size) */
- readonly size: number;
- /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/type) */
- readonly type: string;
- /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/text) */
- text(): Promise<string>;
- /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/slice) */
- slice(start?: number, end?: number): BlobLike;
-}
-
-/**
- * This check adds the arrayBuffer() method type because it is available and used at runtime
- */
-const isBlobLike = (value: any): value is BlobLike & { arrayBuffer(): Promise<ArrayBuffer> } =>
- value != null &&
- typeof value === 'object' &&
- typeof value.size === 'number' &&
- typeof value.type === 'string' &&
- typeof value.text === 'function' &&
- typeof value.slice === 'function' &&
- typeof value.arrayBuffer === 'function';
-
-/**
- * Intended to match DOM File, node:buffer File, undici File, etc.
- */
-interface FileLike extends BlobLike {
- /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/lastModified) */
- readonly lastModified: number;
- /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/name) */
- readonly name?: string | undefined;
-}
-
-/**
- * This check adds the arrayBuffer() method type because it is available and used at runtime
- */
-const isFileLike = (value: any): value is FileLike & { arrayBuffer(): Promise<ArrayBuffer> } =>
- value != null &&
- typeof value === 'object' &&
- typeof value.name === 'string' &&
- typeof value.lastModified === 'number' &&
- isBlobLike(value);
-
-/**
- * Intended to match DOM Response, node-fetch Response, undici Response, etc.
- */
-export interface ResponseLike {
- url: string;
- blob(): Promise<BlobLike>;
-}
-
-const isResponseLike = (value: any): value is ResponseLike =>
- value != null &&
- typeof value === 'object' &&
- typeof value.url === 'string' &&
- typeof value.blob === 'function';
-
-export type ToFileInput =
- | FileLike
- | ResponseLike
- | Exclude<BlobLikePart, string>
- | AsyncIterable<BlobLikePart>;
-
-/**
- * Helper for creating a {@link File} to pass to an SDK upload method from a variety of different data formats
- * @param value the raw content of the file. Can be an {@link Uploadable}, {@link BlobLikePart}, or {@link AsyncIterable} of {@link BlobLikePart}s
- * @param {string=} name the name of the file. If omitted, toFile will try to determine a file name from bits if possible
- * @param {Object=} options additional properties
- * @param {string=} options.type the MIME type of the content
- * @param {number=} options.lastModified the last modified timestamp
- * @returns a {@link File} with the given properties
- */
-export async function toFile(
- value: ToFileInput | PromiseLike<ToFileInput>,
- name?: string | null | undefined,
- options?: FilePropertyBag | undefined,
-): Promise<File> {
- checkFileSupport();
-
- // If it's a promise, resolve it.
- value = await value;
-
- // If we've been given a `File` we don't need to do anything
- if (isFileLike(value)) {
- if (value instanceof File) {
- return value;
- }
- return makeFile([await value.arrayBuffer()], value.name);
- }
-
- if (isResponseLike(value)) {
- const blob = await value.blob();
- name ||= new URL(value.url).pathname.split(/[\\/]/).pop();
-
- return makeFile(await getBytes(blob), name, options);
- }
-
- const parts = await getBytes(value);
-
- name ||= getName(value);
-
- if (!options?.type) {
- const type = parts.find((part) => typeof part === 'object' && 'type' in part && part.type);
- if (typeof type === 'string') {
- options = { ...options, type };
- }
- }
-
- return makeFile(parts, name, options);
-}
-
-async function getBytes(value: BlobLikePart | AsyncIterable<BlobLikePart>): Promise<Array<BlobPart>> {
- let parts: Array<BlobPart> = [];
- if (
- typeof value === 'string' ||
- ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.
- value instanceof ArrayBuffer
- ) {
- parts.push(value);
- } else if (isBlobLike(value)) {
- parts.push(value instanceof Blob ? value : await value.arrayBuffer());
- } else if (
- isAsyncIterable(value) // includes Readable, ReadableStream, etc.
- ) {
- for await (const chunk of value) {
- parts.push(...(await getBytes(chunk as BlobLikePart))); // TODO, consider validating?
- }
- } else {
- const constructor = value?.constructor?.name;
- throw new Error(
- `Unexpected data type: ${typeof value}${
- constructor ? `; constructor: ${constructor}` : ''
- }${propsForError(value)}`,
- );
- }
-
- return parts;
-}
-
-function propsForError(value: unknown): string {
- if (typeof value !== 'object' || value === null) return '';
- const props = Object.getOwnPropertyNames(value);
- return `; props: [${props.map((p) => `"${p}"`).join(', ')}]`;
-}
diff --git a/packages/sdk/src/internal/types.ts b/packages/sdk/src/internal/types.ts
deleted file mode 100644
index b668dfc0f..000000000
--- a/packages/sdk/src/internal/types.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-export type PromiseOrValue<T> = T | Promise<T>;
-export type HTTPMethod = 'get' | 'post' | 'put' | 'patch' | 'delete';
-
-export type KeysEnum<T> = { [P in keyof Required<T>]: true };
-
-export type FinalizedRequestInit = RequestInit & { headers: Headers };
-
-type NotAny<T> = [0] extends [1 & T] ? never : T;
-
-/**
- * Some environments overload the global fetch function, and Parameters<T> only gets the last signature.
- */
-type OverloadedParameters<T> =
- T extends (
- {
- (...args: infer A): unknown;
- (...args: infer B): unknown;
- (...args: infer C): unknown;
- (...args: infer D): unknown;
- }
- ) ?
- A | B | C | D
- : T extends (
- {
- (...args: infer A): unknown;
- (...args: infer B): unknown;
- (...args: infer C): unknown;
- }
- ) ?
- A | B | C
- : T extends (
- {
- (...args: infer A): unknown;
- (...args: infer B): unknown;
- }
- ) ?
- A | B
- : T extends (...args: infer A) => unknown ? A
- : never;
-
-/* eslint-disable */
-/**
- * These imports attempt to get types from a parent package's dependencies.
- * Unresolved bare specifiers can trigger [automatic type acquisition][1] in some projects, which
- * would cause typescript to show types not present at runtime. To avoid this, we import
- * directly from parent node_modules folders.
- *
- * We need to check multiple levels because we don't know what directory structure we'll be in.
- * For example, pnpm generates directories like this:
- * ```
- * node_modules
- * ├── .pnpm
- * │ └── [email protected]
- * │ └── node_modules
- * │ └── pkg
- * │ └── internal
- * │ └── types.d.ts
- * ├── pkg -> .pnpm/[email protected]/node_modules/pkg
- * └── undici
- * ```
- *
- * [1]: https://www.typescriptlang.org/tsconfig/#typeAcquisition
- */
-/** @ts-ignore For users with \@types/node */
-type UndiciTypesRequestInit = NotAny<import('../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../node_modules/undici-types/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../../node_modules/undici-types/index.d.ts').RequestInit>;
-/** @ts-ignore For users with undici */
-type UndiciRequestInit = NotAny<import('../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../node_modules/undici/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../../node_modules/undici/index.d.ts').RequestInit>;
-/** @ts-ignore For users with \@types/bun */
-type BunRequestInit = globalThis.FetchRequestInit;
-/** @ts-ignore For users with node-fetch@2 */
-type NodeFetch2RequestInit = NotAny<import('../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit> | NotAny<import('../../../../../../../../../../node_modules/@types/node-fetch/index.d.ts').RequestInit>;
-/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */
-type NodeFetch3RequestInit = NotAny<import('../node_modules/node-fetch').RequestInit> | NotAny<import('../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../../../../node_modules/node-fetch').RequestInit>;
-/** @ts-ignore For users who use Deno */
-type FetchRequestInit = NonNullable<OverloadedParameters<typeof fetch>[1]>;
-/* eslint-enable */
-
-type RequestInits =
- | NotAny<UndiciTypesRequestInit>
- | NotAny<UndiciRequestInit>
- | NotAny<BunRequestInit>
- | NotAny<NodeFetch2RequestInit>
- | NotAny<NodeFetch3RequestInit>
- | NotAny<RequestInit>
- | NotAny<FetchRequestInit>;
-
-/**
- * This type contains `RequestInit` options that may be available on the current runtime,
- * including per-platform extensions like `dispatcher`, `agent`, `client`, etc.
- */
-export type MergedRequestInit = RequestInits &
- /** We don't include these in the types as they'll be overridden for every request. */
- Partial<Record<'body' | 'headers' | 'method' | 'signal', never>>;
diff --git a/packages/sdk/src/internal/uploads.ts b/packages/sdk/src/internal/uploads.ts
deleted file mode 100644
index eb55f834e..000000000
--- a/packages/sdk/src/internal/uploads.ts
+++ /dev/null
@@ -1,187 +0,0 @@
-import { type RequestOptions } from './request-options';
-import type { FilePropertyBag, Fetch } from './builtin-types';
-import type { Opencode } from '../client';
-import { ReadableStreamFrom } from './shims';
-
-export type BlobPart = string | ArrayBuffer | ArrayBufferView | Blob | DataView;
-type FsReadStream = AsyncIterable<Uint8Array> & { path: string | { toString(): string } };
-
-// https://github.com/oven-sh/bun/issues/5980
-interface BunFile extends Blob {
- readonly name?: string | undefined;
-}
-
-export const checkFileSupport = () => {
- if (typeof File === 'undefined') {
- const { process } = globalThis as any;
- const isOldNode =
- typeof process?.versions?.node === 'string' && parseInt(process.versions.node.split('.')) < 20;
- throw new Error(
- '`File` is not defined as a global, which is required for file uploads.' +
- (isOldNode ?
- " Update to Node 20 LTS or newer, or set `globalThis.File` to `import('node:buffer').File`."
- : ''),
- );
- }
-};
-
-/**
- * Typically, this is a native "File" class.
- *
- * We provide the {@link toFile} utility to convert a variety of objects
- * into the File class.
- *
- * For convenience, you can also pass a fetch Response, or in Node,
- * the result of fs.createReadStream().
- */
-export type Uploadable = File | Response | FsReadStream | BunFile;
-
-/**
- * Construct a `File` instance. This is used to ensure a helpful error is thrown
- * for environments that don't define a global `File` yet.
- */
-export function makeFile(
- fileBits: BlobPart[],
- fileName: string | undefined,
- options?: FilePropertyBag,
-): File {
- checkFileSupport();
- return new File(fileBits as any, fileName ?? 'unknown_file', options);
-}
-
-export function getName(value: any): string | undefined {
- return (
- (
- (typeof value === 'object' &&
- value !== null &&
- (('name' in value && value.name && String(value.name)) ||
- ('url' in value && value.url && String(value.url)) ||
- ('filename' in value && value.filename && String(value.filename)) ||
- ('path' in value && value.path && String(value.path)))) ||
- ''
- )
- .split(/[\\/]/)
- .pop() || undefined
- );
-}
-
-export const isAsyncIterable = (value: any): value is AsyncIterable<any> =>
- value != null && typeof value === 'object' && typeof value[Symbol.asyncIterator] === 'function';
-
-/**
- * Returns a multipart/form-data request if any part of the given request body contains a File / Blob value.
- * Otherwise returns the request as is.
- */
-export const maybeMultipartFormRequestOptions = async (
- opts: RequestOptions,
- fetch: Opencode | Fetch,
-): Promise<RequestOptions> => {
- if (!hasUploadableValue(opts.body)) return opts;
-
- return { ...opts, body: await createForm(opts.body, fetch) };
-};
-
-type MultipartFormRequestOptions = Omit<RequestOptions, 'body'> & { body: unknown };
-
-export const multipartFormRequestOptions = async (
- opts: MultipartFormRequestOptions,
- fetch: Opencode | Fetch,
-): Promise<RequestOptions> => {
- return { ...opts, body: await createForm(opts.body, fetch) };
-};
-
-const supportsFormDataMap = /* @__PURE__ */ new WeakMap<Fetch, Promise<boolean>>();
-
-/**
- * node-fetch doesn't support the global FormData object in recent node versions. Instead of sending
- * properly-encoded form data, it just stringifies the object, resulting in a request body of "[object FormData]".
- * This function detects if the fetch function provided supports the global FormData object to avoid
- * confusing error messages later on.
- */
-function supportsFormData(fetchObject: Opencode | Fetch): Promise<boolean> {
- const fetch: Fetch = typeof fetchObject === 'function' ? fetchObject : (fetchObject as any).fetch;
- const cached = supportsFormDataMap.get(fetch);
- if (cached) return cached;
- const promise = (async () => {
- try {
- const FetchResponse = (
- 'Response' in fetch ?
- fetch.Response
- : (await fetch('data:,')).constructor) as typeof Response;
- const data = new FormData();
- if (data.toString() === (await new FetchResponse(data).text())) {
- return false;
- }
- return true;
- } catch {
- // avoid false negatives
- return true;
- }
- })();
- supportsFormDataMap.set(fetch, promise);
- return promise;
-}
-
-export const createForm = async <T = Record<string, unknown>>(
- body: T | undefined,
- fetch: Opencode | Fetch,
-): Promise<FormData> => {
- if (!(await supportsFormData(fetch))) {
- throw new TypeError(
- 'The provided fetch function does not support file uploads with the current global FormData class.',
- );
- }
- const form = new FormData();
- await Promise.all(Object.entries(body || {}).map(([key, value]) => addFormValue(form, key, value)));
- return form;
-};
-
-// We check for Blob not File because Bun.File doesn't inherit from File,
-// but they both inherit from Blob and have a `name` property at runtime.
-const isNamedBlob = (value: unknown) => value instanceof Blob && 'name' in value;
-
-const isUploadable = (value: unknown) =>
- typeof value === 'object' &&
- value !== null &&
- (value instanceof Response || isAsyncIterable(value) || isNamedBlob(value));
-
-const hasUploadableValue = (value: unknown): boolean => {
- if (isUploadable(value)) return true;
- if (Array.isArray(value)) return value.some(hasUploadableValue);
- if (value && typeof value === 'object') {
- for (const k in value) {
- if (hasUploadableValue((value as any)[k])) return true;
- }
- }
- return false;
-};
-
-const addFormValue = async (form: FormData, key: string, value: unknown): Promise<void> => {
- if (value === undefined) return;
- if (value == null) {
- throw new TypeError(
- `Received null for "${key}"; to pass null in FormData, you must use the string 'null'`,
- );
- }
-
- // TODO: make nested formats configurable
- if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
- form.append(key, String(value));
- } else if (value instanceof Response) {
- form.append(key, makeFile([await value.blob()], getName(value)));
- } else if (isAsyncIterable(value)) {
- form.append(key, makeFile([await new Response(ReadableStreamFrom(value)).blob()], getName(value)));
- } else if (isNamedBlob(value)) {
- form.append(key, value, getName(value));
- } else if (Array.isArray(value)) {
- await Promise.all(value.map((entry) => addFormValue(form, key + '[]', entry)));
- } else if (typeof value === 'object') {
- await Promise.all(
- Object.entries(value).map(([name, prop]) => addFormValue(form, `${key}[${name}]`, prop)),
- );
- } else {
- throw new TypeError(
- `Invalid value given to form, expected a string, number, boolean, object, Array, File or Blob but got ${value} instead`,
- );
- }
-};
diff --git a/packages/sdk/src/internal/utils.ts b/packages/sdk/src/internal/utils.ts
deleted file mode 100644
index 3cbfacce2..000000000
--- a/packages/sdk/src/internal/utils.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-export * from './utils/values';
-export * from './utils/base64';
-export * from './utils/env';
-export * from './utils/log';
-export * from './utils/uuid';
-export * from './utils/sleep';
diff --git a/packages/sdk/src/internal/utils/base64.ts b/packages/sdk/src/internal/utils/base64.ts
deleted file mode 100644
index 05d7bd9b4..000000000
--- a/packages/sdk/src/internal/utils/base64.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { OpencodeError } from '../../core/error';
-import { encodeUTF8 } from './bytes';
-
-export const toBase64 = (data: string | Uint8Array | null | undefined): string => {
- if (!data) return '';
-
- if (typeof (globalThis as any).Buffer !== 'undefined') {
- return (globalThis as any).Buffer.from(data).toString('base64');
- }
-
- if (typeof data === 'string') {
- data = encodeUTF8(data);
- }
-
- if (typeof btoa !== 'undefined') {
- return btoa(String.fromCharCode.apply(null, data as any));
- }
-
- throw new OpencodeError('Cannot generate base64 string; Expected `Buffer` or `btoa` to be defined');
-};
-
-export const fromBase64 = (str: string): Uint8Array => {
- if (typeof (globalThis as any).Buffer !== 'undefined') {
- const buf = (globalThis as any).Buffer.from(str, 'base64');
- return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
- }
-
- if (typeof atob !== 'undefined') {
- const bstr = atob(str);
- const buf = new Uint8Array(bstr.length);
- for (let i = 0; i < bstr.length; i++) {
- buf[i] = bstr.charCodeAt(i);
- }
- return buf;
- }
-
- throw new OpencodeError('Cannot decode base64 string; Expected `Buffer` or `atob` to be defined');
-};
diff --git a/packages/sdk/src/internal/utils/bytes.ts b/packages/sdk/src/internal/utils/bytes.ts
deleted file mode 100644
index 8da627abe..000000000
--- a/packages/sdk/src/internal/utils/bytes.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-export function concatBytes(buffers: Uint8Array[]): Uint8Array {
- let length = 0;
- for (const buffer of buffers) {
- length += buffer.length;
- }
- const output = new Uint8Array(length);
- let index = 0;
- for (const buffer of buffers) {
- output.set(buffer, index);
- index += buffer.length;
- }
-
- return output;
-}
-
-let encodeUTF8_: (str: string) => Uint8Array;
-export function encodeUTF8(str: string) {
- let encoder;
- return (
- encodeUTF8_ ??
- ((encoder = new (globalThis as any).TextEncoder()), (encodeUTF8_ = encoder.encode.bind(encoder)))
- )(str);
-}
-
-let decodeUTF8_: (bytes: Uint8Array) => string;
-export function decodeUTF8(bytes: Uint8Array) {
- let decoder;
- return (
- decodeUTF8_ ??
- ((decoder = new (globalThis as any).TextDecoder()), (decodeUTF8_ = decoder.decode.bind(decoder)))
- )(bytes);
-}
diff --git a/packages/sdk/src/internal/utils/env.ts b/packages/sdk/src/internal/utils/env.ts
deleted file mode 100644
index 2d8480077..000000000
--- a/packages/sdk/src/internal/utils/env.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-/**
- * Read an environment variable.
- *
- * Trims beginning and trailing whitespace.
- *
- * Will return undefined if the environment variable doesn't exist or cannot be accessed.
- */
-export const readEnv = (env: string): string | undefined => {
- if (typeof (globalThis as any).process !== 'undefined') {
- return (globalThis as any).process.env?.[env]?.trim() ?? undefined;
- }
- if (typeof (globalThis as any).Deno !== 'undefined') {
- return (globalThis as any).Deno.env?.get?.(env)?.trim();
- }
- return undefined;
-};
diff --git a/packages/sdk/src/internal/utils/log.ts b/packages/sdk/src/internal/utils/log.ts
deleted file mode 100644
index 44ac16a02..000000000
--- a/packages/sdk/src/internal/utils/log.ts
+++ /dev/null
@@ -1,126 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { hasOwn } from './values';
-import { type Opencode } from '../../client';
-import { RequestOptions } from '../request-options';
-
-type LogFn = (message: string, ...rest: unknown[]) => void;
-export type Logger = {
- error: LogFn;
- warn: LogFn;
- info: LogFn;
- debug: LogFn;
-};
-export type LogLevel = 'off' | 'error' | 'warn' | 'info' | 'debug';
-
-const levelNumbers = {
- off: 0,
- error: 200,
- warn: 300,
- info: 400,
- debug: 500,
-};
-
-export const parseLogLevel = (
- maybeLevel: string | undefined,
- sourceName: string,
- client: Opencode,
-): LogLevel | undefined => {
- if (!maybeLevel) {
- return undefined;
- }
- if (hasOwn(levelNumbers, maybeLevel)) {
- return maybeLevel;
- }
- loggerFor(client).warn(
- `${sourceName} was set to ${JSON.stringify(maybeLevel)}, expected one of ${JSON.stringify(
- Object.keys(levelNumbers),
- )}`,
- );
- return undefined;
-};
-
-function noop() {}
-
-function makeLogFn(fnLevel: keyof Logger, logger: Logger | undefined, logLevel: LogLevel) {
- if (!logger || levelNumbers[fnLevel] > levelNumbers[logLevel]) {
- return noop;
- } else {
- // Don't wrap logger functions, we want the stacktrace intact!
- return logger[fnLevel].bind(logger);
- }
-}
-
-const noopLogger = {
- error: noop,
- warn: noop,
- info: noop,
- debug: noop,
-};
-
-let cachedLoggers = /* @__PURE__ */ new WeakMap<Logger, [LogLevel, Logger]>();
-
-export function loggerFor(client: Opencode): Logger {
- const logger = client.logger;
- const logLevel = client.logLevel ?? 'off';
- if (!logger) {
- return noopLogger;
- }
-
- const cachedLogger = cachedLoggers.get(logger);
- if (cachedLogger && cachedLogger[0] === logLevel) {
- return cachedLogger[1];
- }
-
- const levelLogger = {
- error: makeLogFn('error', logger, logLevel),
- warn: makeLogFn('warn', logger, logLevel),
- info: makeLogFn('info', logger, logLevel),
- debug: makeLogFn('debug', logger, logLevel),
- };
-
- cachedLoggers.set(logger, [logLevel, levelLogger]);
-
- return levelLogger;
-}
-
-export const formatRequestDetails = (details: {
- options?: RequestOptions | undefined;
- headers?: Headers | Record<string, string> | undefined;
- retryOfRequestLogID?: string | undefined;
- retryOf?: string | undefined;
- url?: string | undefined;
- status?: number | undefined;
- method?: string | undefined;
- durationMs?: number | undefined;
- message?: unknown;
- body?: unknown;
-}) => {
- if (details.options) {
- details.options = { ...details.options };
- delete details.options['headers']; // redundant + leaks internals
- }
- if (details.headers) {
- details.headers = Object.fromEntries(
- (details.headers instanceof Headers ? [...details.headers] : Object.entries(details.headers)).map(
- ([name, value]) => [
- name,
- (
- name.toLowerCase() === 'authorization' ||
- name.toLowerCase() === 'cookie' ||
- name.toLowerCase() === 'set-cookie'
- ) ?
- '***'
- : value,
- ],
- ),
- );
- }
- if ('retryOfRequestLogID' in details) {
- if (details.retryOfRequestLogID) {
- details.retryOf = details.retryOfRequestLogID;
- }
- delete details.retryOfRequestLogID;
- }
- return details;
-};
diff --git a/packages/sdk/src/internal/utils/path.ts b/packages/sdk/src/internal/utils/path.ts
deleted file mode 100644
index 6ca96e0dd..000000000
--- a/packages/sdk/src/internal/utils/path.ts
+++ /dev/null
@@ -1,88 +0,0 @@
-import { OpencodeError } from '../../core/error';
-
-/**
- * Percent-encode everything that isn't safe to have in a path without encoding safe chars.
- *
- * Taken from https://datatracker.ietf.org/doc/html/rfc3986#section-3.3:
- * > unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
- * > sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
- * > pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
- */
-export function encodeURIPath(str: string) {
- return str.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g, encodeURIComponent);
-}
-
-const EMPTY = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.create(null));
-
-export const createPathTagFunction = (pathEncoder = encodeURIPath) =>
- function path(statics: readonly string[], ...params: readonly unknown[]): string {
- // If there are no params, no processing is needed.
- if (statics.length === 1) return statics[0]!;
-
- let postPath = false;
- const invalidSegments = [];
- const path = statics.reduce((previousValue, currentValue, index) => {
- if (/[?#]/.test(currentValue)) {
- postPath = true;
- }
- const value = params[index];
- let encoded = (postPath ? encodeURIComponent : pathEncoder)('' + value);
- if (
- index !== params.length &&
- (value == null ||
- (typeof value === 'object' &&
- // handle values from other realms
- value.toString ===
- Object.getPrototypeOf(Object.getPrototypeOf((value as any).hasOwnProperty ?? EMPTY) ?? EMPTY)
- ?.toString))
- ) {
- encoded = value + '';
- invalidSegments.push({
- start: previousValue.length + currentValue.length,
- length: encoded.length,
- error: `Value of type ${Object.prototype.toString
- .call(value)
- .slice(8, -1)} is not a valid path parameter`,
- });
- }
- return previousValue + currentValue + (index === params.length ? '' : encoded);
- }, '');
-
- const pathOnly = path.split(/[?#]/, 1)[0]!;
- const invalidSegmentPattern = /(?<=^|\/)(?:\.|%2e){1,2}(?=\/|$)/gi;
- let match;
-
- // Find all invalid segments
- while ((match = invalidSegmentPattern.exec(pathOnly)) !== null) {
- invalidSegments.push({
- start: match.index,
- length: match[0].length,
- error: `Value "${match[0]}" can\'t be safely passed as a path parameter`,
- });
- }
-
- invalidSegments.sort((a, b) => a.start - b.start);
-
- if (invalidSegments.length > 0) {
- let lastEnd = 0;
- const underline = invalidSegments.reduce((acc, segment) => {
- const spaces = ' '.repeat(segment.start - lastEnd);
- const arrows = '^'.repeat(segment.length);
- lastEnd = segment.start + segment.length;
- return acc + spaces + arrows;
- }, '');
-
- throw new OpencodeError(
- `Path parameters result in path with invalid segments:\n${invalidSegments
- .map((e) => e.error)
- .join('\n')}\n${path}\n${underline}`,
- );
- }
-
- return path;
- };
-
-/**
- * URI-encodes path params and ensures no unsafe /./ or /../ path segments are introduced.
- */
-export const path = /* @__PURE__ */ createPathTagFunction(encodeURIPath);
diff --git a/packages/sdk/src/internal/utils/sleep.ts b/packages/sdk/src/internal/utils/sleep.ts
deleted file mode 100644
index 65e52962b..000000000
--- a/packages/sdk/src/internal/utils/sleep.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-export const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));
diff --git a/packages/sdk/src/internal/utils/uuid.ts b/packages/sdk/src/internal/utils/uuid.ts
deleted file mode 100644
index b0e53aaf7..000000000
--- a/packages/sdk/src/internal/utils/uuid.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-/**
- * https://stackoverflow.com/a/2117523
- */
-export let uuid4 = function () {
- const { crypto } = globalThis as any;
- if (crypto?.randomUUID) {
- uuid4 = crypto.randomUUID.bind(crypto);
- return crypto.randomUUID();
- }
- const u8 = new Uint8Array(1);
- const randomByte = crypto ? () => crypto.getRandomValues(u8)[0]! : () => (Math.random() * 0xff) & 0xff;
- return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, (c) =>
- (+c ^ (randomByte() & (15 >> (+c / 4)))).toString(16),
- );
-};
diff --git a/packages/sdk/src/internal/utils/values.ts b/packages/sdk/src/internal/utils/values.ts
deleted file mode 100644
index b2421fd88..000000000
--- a/packages/sdk/src/internal/utils/values.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-import { OpencodeError } from '../../core/error';
-
-// https://url.spec.whatwg.org/#url-scheme-string
-const startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;
-
-export const isAbsoluteURL = (url: string): boolean => {
- return startsWithSchemeRegexp.test(url);
-};
-
-export let isArray = (val: unknown): val is unknown[] => ((isArray = Array.isArray), isArray(val));
-export let isReadonlyArray = isArray as (val: unknown) => val is readonly unknown[];
-
-/** Returns an object if the given value isn't an object, otherwise returns as-is */
-export function maybeObj(x: unknown): object {
- if (typeof x !== 'object') {
- return {};
- }
-
- return x ?? {};
-}
-
-// https://stackoverflow.com/a/34491287
-export function isEmptyObj(obj: Object | null | undefined): boolean {
- if (!obj) return true;
- for (const _k in obj) return false;
- return true;
-}
-
-// https://eslint.org/docs/latest/rules/no-prototype-builtins
-export function hasOwn<T extends object = object>(obj: T, key: PropertyKey): key is keyof T {
- return Object.prototype.hasOwnProperty.call(obj, key);
-}
-
-export function isObj(obj: unknown): obj is Record<string, unknown> {
- return obj != null && typeof obj === 'object' && !Array.isArray(obj);
-}
-
-export const ensurePresent = <T>(value: T | null | undefined): T => {
- if (value == null) {
- throw new OpencodeError(`Expected a value to be given but received ${value} instead.`);
- }
-
- return value;
-};
-
-export const validatePositiveInteger = (name: string, n: unknown): number => {
- if (typeof n !== 'number' || !Number.isInteger(n)) {
- throw new OpencodeError(`${name} must be an integer`);
- }
- if (n < 0) {
- throw new OpencodeError(`${name} must be a positive integer`);
- }
- return n;
-};
-
-export const coerceInteger = (value: unknown): number => {
- if (typeof value === 'number') return Math.round(value);
- if (typeof value === 'string') return parseInt(value, 10);
-
- throw new OpencodeError(`Could not coerce ${value} (type: ${typeof value}) into a number`);
-};
-
-export const coerceFloat = (value: unknown): number => {
- if (typeof value === 'number') return value;
- if (typeof value === 'string') return parseFloat(value);
-
- throw new OpencodeError(`Could not coerce ${value} (type: ${typeof value}) into a number`);
-};
-
-export const coerceBoolean = (value: unknown): boolean => {
- if (typeof value === 'boolean') return value;
- if (typeof value === 'string') return value === 'true';
- return Boolean(value);
-};
-
-export const maybeCoerceInteger = (value: unknown): number | undefined => {
- if (value === undefined) {
- return undefined;
- }
- return coerceInteger(value);
-};
-
-export const maybeCoerceFloat = (value: unknown): number | undefined => {
- if (value === undefined) {
- return undefined;
- }
- return coerceFloat(value);
-};
-
-export const maybeCoerceBoolean = (value: unknown): boolean | undefined => {
- if (value === undefined) {
- return undefined;
- }
- return coerceBoolean(value);
-};
-
-export const safeJSON = (text: string) => {
- try {
- return JSON.parse(text);
- } catch (err) {
- return undefined;
- }
-};