summaryrefslogtreecommitdiffhomepage
path: root/packages/sdk/js/src
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/js/src
parentb09ebf464552f3899120b22c7a8572669000a554 (diff)
downloadopencode-33cef075d228e80aefb44671ec68e1989c2855a8.tar.gz
opencode-33cef075d228e80aefb44671ec68e1989c2855a8.zip
ci: new publish method (#1451)
Diffstat (limited to 'packages/sdk/js/src')
-rw-r--r--packages/sdk/js/src/gen/client.gen.ts18
-rw-r--r--packages/sdk/js/src/gen/client/client.ts195
-rw-r--r--packages/sdk/js/src/gen/client/index.ts22
-rw-r--r--packages/sdk/js/src/gen/client/types.ts222
-rw-r--r--packages/sdk/js/src/gen/client/utils.ts417
-rw-r--r--packages/sdk/js/src/gen/core/auth.ts40
-rw-r--r--packages/sdk/js/src/gen/core/bodySerializer.ts88
-rw-r--r--packages/sdk/js/src/gen/core/params.ts151
-rw-r--r--packages/sdk/js/src/gen/core/pathSerializer.ts179
-rw-r--r--packages/sdk/js/src/gen/core/types.ts118
-rw-r--r--packages/sdk/js/src/gen/sdk.gen.ts339
-rw-r--r--packages/sdk/js/src/gen/types.gen.ts1450
-rw-r--r--packages/sdk/js/src/index.ts8
13 files changed, 3247 insertions, 0 deletions
diff --git a/packages/sdk/js/src/gen/client.gen.ts b/packages/sdk/js/src/gen/client.gen.ts
new file mode 100644
index 000000000..3bb22b24a
--- /dev/null
+++ b/packages/sdk/js/src/gen/client.gen.ts
@@ -0,0 +1,18 @@
+// This file is auto-generated by @hey-api/openapi-ts
+
+import type { ClientOptions } from './types.gen';
+import { type Config, type ClientOptions as DefaultClientOptions, createClient, createConfig } from './client';
+
+/**
+ * The `createClientConfig()` function will be called on client initialization
+ * and the returned object will become the client's initial configuration.
+ *
+ * You may want to initialize your client this way instead of calling
+ * `setConfig()`. This is useful for example if you're using Next.js
+ * to ensure your client always has the correct values.
+ */
+export type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> = (override?: Config<DefaultClientOptions & T>) => Config<Required<DefaultClientOptions> & T>;
+
+export const client = createClient(createConfig<ClientOptions>({
+ baseUrl: 'http://localhost:4096'
+})); \ No newline at end of file
diff --git a/packages/sdk/js/src/gen/client/client.ts b/packages/sdk/js/src/gen/client/client.ts
new file mode 100644
index 000000000..89d1e3158
--- /dev/null
+++ b/packages/sdk/js/src/gen/client/client.ts
@@ -0,0 +1,195 @@
+import type { Client, Config, RequestOptions } from './types';
+import {
+ buildUrl,
+ createConfig,
+ createInterceptors,
+ getParseAs,
+ mergeConfigs,
+ mergeHeaders,
+ setAuthParams,
+} from './utils';
+
+type ReqInit = Omit<RequestInit, 'body' | 'headers'> & {
+ body?: any;
+ headers: ReturnType<typeof mergeHeaders>;
+};
+
+export const createClient = (config: Config = {}): Client => {
+ let _config = mergeConfigs(createConfig(), config);
+
+ const getConfig = (): Config => ({ ..._config });
+
+ const setConfig = (config: Config): Config => {
+ _config = mergeConfigs(_config, config);
+ return getConfig();
+ };
+
+ const interceptors = createInterceptors<
+ Request,
+ Response,
+ unknown,
+ RequestOptions
+ >();
+
+ const request: Client['request'] = async (options) => {
+ const opts = {
+ ..._config,
+ ...options,
+ fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
+ headers: mergeHeaders(_config.headers, options.headers),
+ };
+
+ if (opts.security) {
+ await setAuthParams({
+ ...opts,
+ security: opts.security,
+ });
+ }
+
+ if (opts.requestValidator) {
+ await opts.requestValidator(opts);
+ }
+
+ if (opts.body && opts.bodySerializer) {
+ opts.body = opts.bodySerializer(opts.body);
+ }
+
+ // remove Content-Type header if body is empty to avoid sending invalid requests
+ if (opts.body === undefined || opts.body === '') {
+ opts.headers.delete('Content-Type');
+ }
+
+ const url = buildUrl(opts);
+ const requestInit: ReqInit = {
+ redirect: 'follow',
+ ...opts,
+ };
+
+ let request = new Request(url, requestInit);
+
+ for (const fn of interceptors.request._fns) {
+ if (fn) {
+ request = await fn(request, opts);
+ }
+ }
+
+ // fetch must be assigned here, otherwise it would throw the error:
+ // TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
+ const _fetch = opts.fetch!;
+ let response = await _fetch(request);
+
+ for (const fn of interceptors.response._fns) {
+ if (fn) {
+ response = await fn(response, request, opts);
+ }
+ }
+
+ const result = {
+ request,
+ response,
+ };
+
+ if (response.ok) {
+ if (
+ response.status === 204 ||
+ response.headers.get('Content-Length') === '0'
+ ) {
+ return opts.responseStyle === 'data'
+ ? {}
+ : {
+ data: {},
+ ...result,
+ };
+ }
+
+ const parseAs =
+ (opts.parseAs === 'auto'
+ ? getParseAs(response.headers.get('Content-Type'))
+ : opts.parseAs) ?? 'json';
+
+ let data: any;
+ switch (parseAs) {
+ case 'arrayBuffer':
+ case 'blob':
+ case 'formData':
+ case 'json':
+ case 'text':
+ data = await response[parseAs]();
+ break;
+ case 'stream':
+ return opts.responseStyle === 'data'
+ ? response.body
+ : {
+ data: response.body,
+ ...result,
+ };
+ }
+
+ if (parseAs === 'json') {
+ if (opts.responseValidator) {
+ await opts.responseValidator(data);
+ }
+
+ if (opts.responseTransformer) {
+ data = await opts.responseTransformer(data);
+ }
+ }
+
+ return opts.responseStyle === 'data'
+ ? data
+ : {
+ data,
+ ...result,
+ };
+ }
+
+ const textError = await response.text();
+ let jsonError: unknown;
+
+ try {
+ jsonError = JSON.parse(textError);
+ } catch {
+ // noop
+ }
+
+ const error = jsonError ?? textError;
+ let finalError = error;
+
+ for (const fn of interceptors.error._fns) {
+ if (fn) {
+ finalError = (await fn(error, response, request, opts)) as string;
+ }
+ }
+
+ finalError = finalError || ({} as string);
+
+ if (opts.throwOnError) {
+ throw finalError;
+ }
+
+ // TODO: we probably want to return error and improve types
+ return opts.responseStyle === 'data'
+ ? undefined
+ : {
+ error: finalError,
+ ...result,
+ };
+ };
+
+ return {
+ buildUrl,
+ connect: (options) => request({ ...options, method: 'CONNECT' }),
+ delete: (options) => request({ ...options, method: 'DELETE' }),
+ get: (options) => request({ ...options, method: 'GET' }),
+ getConfig,
+ head: (options) => request({ ...options, method: 'HEAD' }),
+ interceptors,
+ options: (options) => request({ ...options, method: 'OPTIONS' }),
+ patch: (options) => request({ ...options, method: 'PATCH' }),
+ post: (options) => request({ ...options, method: 'POST' }),
+ put: (options) => request({ ...options, method: 'PUT' }),
+ request,
+ setConfig,
+ trace: (options) => request({ ...options, method: 'TRACE' }),
+ };
+};
diff --git a/packages/sdk/js/src/gen/client/index.ts b/packages/sdk/js/src/gen/client/index.ts
new file mode 100644
index 000000000..5da1f7aee
--- /dev/null
+++ b/packages/sdk/js/src/gen/client/index.ts
@@ -0,0 +1,22 @@
+export type { Auth } from '../core/auth';
+export type { QuerySerializerOptions } from '../core/bodySerializer';
+export {
+ formDataBodySerializer,
+ jsonBodySerializer,
+ urlSearchParamsBodySerializer,
+} from '../core/bodySerializer';
+export { buildClientParams } from '../core/params';
+export { createClient } from './client';
+export type {
+ Client,
+ ClientOptions,
+ Config,
+ CreateClientConfig,
+ Options,
+ OptionsLegacyParser,
+ RequestOptions,
+ RequestResult,
+ ResponseStyle,
+ TDataShape,
+} from './types';
+export { createConfig, mergeHeaders } from './utils';
diff --git a/packages/sdk/js/src/gen/client/types.ts b/packages/sdk/js/src/gen/client/types.ts
new file mode 100644
index 000000000..85295df07
--- /dev/null
+++ b/packages/sdk/js/src/gen/client/types.ts
@@ -0,0 +1,222 @@
+import type { Auth } from '../core/auth';
+import type {
+ Client as CoreClient,
+ Config as CoreConfig,
+} from '../core/types';
+import type { Middleware } from './utils';
+
+export type ResponseStyle = 'data' | 'fields';
+
+export interface Config<T extends ClientOptions = ClientOptions>
+ extends Omit<RequestInit, 'body' | 'headers' | 'method'>,
+ CoreConfig {
+ /**
+ * Base URL for all requests made by this client.
+ */
+ baseUrl?: T['baseUrl'];
+ /**
+ * Fetch API implementation. You can use this option to provide a custom
+ * fetch instance.
+ *
+ * @default globalThis.fetch
+ */
+ fetch?: (request: Request) => ReturnType<typeof fetch>;
+ /**
+ * Please don't use the Fetch client for Next.js applications. The `next`
+ * options won't have any effect.
+ *
+ * Install {@link https://www.npmjs.com/package/@hey-api/client-next `@hey-api/client-next`} instead.
+ */
+ next?: never;
+ /**
+ * Return the response data parsed in a specified format. By default, `auto`
+ * will infer the appropriate method from the `Content-Type` response header.
+ * You can override this behavior with any of the {@link Body} methods.
+ * Select `stream` if you don't want to parse response data at all.
+ *
+ * @default 'auto'
+ */
+ parseAs?:
+ | 'arrayBuffer'
+ | 'auto'
+ | 'blob'
+ | 'formData'
+ | 'json'
+ | 'stream'
+ | 'text';
+ /**
+ * Should we return only data or multiple fields (data, error, response, etc.)?
+ *
+ * @default 'fields'
+ */
+ responseStyle?: ResponseStyle;
+ /**
+ * Throw an error instead of returning it in the response?
+ *
+ * @default false
+ */
+ throwOnError?: T['throwOnError'];
+}
+
+export interface RequestOptions<
+ TResponseStyle extends ResponseStyle = 'fields',
+ ThrowOnError extends boolean = boolean,
+ Url extends string = string,
+> extends Config<{
+ responseStyle: TResponseStyle;
+ throwOnError: ThrowOnError;
+ }> {
+ /**
+ * Any body that you want to add to your request.
+ *
+ * {@link https://developer.mozilla.org/docs/Web/API/fetch#body}
+ */
+ body?: unknown;
+ path?: Record<string, unknown>;
+ query?: Record<string, unknown>;
+ /**
+ * Security mechanism(s) to use for the request.
+ */
+ security?: ReadonlyArray<Auth>;
+ url: Url;
+}
+
+export type RequestResult<
+ TData = unknown,
+ TError = unknown,
+ ThrowOnError extends boolean = boolean,
+ TResponseStyle extends ResponseStyle = 'fields',
+> = ThrowOnError extends true
+ ? Promise<
+ TResponseStyle extends 'data'
+ ? TData extends Record<string, unknown>
+ ? TData[keyof TData]
+ : TData
+ : {
+ data: TData extends Record<string, unknown>
+ ? TData[keyof TData]
+ : TData;
+ request: Request;
+ response: Response;
+ }
+ >
+ : Promise<
+ TResponseStyle extends 'data'
+ ?
+ | (TData extends Record<string, unknown>
+ ? TData[keyof TData]
+ : TData)
+ | undefined
+ : (
+ | {
+ data: TData extends Record<string, unknown>
+ ? TData[keyof TData]
+ : TData;
+ error: undefined;
+ }
+ | {
+ data: undefined;
+ error: TError extends Record<string, unknown>
+ ? TError[keyof TError]
+ : TError;
+ }
+ ) & {
+ request: Request;
+ response: Response;
+ }
+ >;
+
+export interface ClientOptions {
+ baseUrl?: string;
+ responseStyle?: ResponseStyle;
+ throwOnError?: boolean;
+}
+
+type MethodFn = <
+ TData = unknown,
+ TError = unknown,
+ ThrowOnError extends boolean = false,
+ TResponseStyle extends ResponseStyle = 'fields',
+>(
+ options: Omit<RequestOptions<TResponseStyle, ThrowOnError>, 'method'>,
+) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>;
+
+type RequestFn = <
+ TData = unknown,
+ TError = unknown,
+ ThrowOnError extends boolean = false,
+ TResponseStyle extends ResponseStyle = 'fields',
+>(
+ options: Omit<RequestOptions<TResponseStyle, ThrowOnError>, 'method'> &
+ Pick<Required<RequestOptions<TResponseStyle, ThrowOnError>>, 'method'>,
+) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>;
+
+type BuildUrlFn = <
+ TData extends {
+ body?: unknown;
+ path?: Record<string, unknown>;
+ query?: Record<string, unknown>;
+ url: string;
+ },
+>(
+ options: Pick<TData, 'url'> & Options<TData>,
+) => string;
+
+export type Client = CoreClient<RequestFn, Config, MethodFn, BuildUrlFn> & {
+ interceptors: Middleware<Request, Response, unknown, RequestOptions>;
+};
+
+/**
+ * The `createClientConfig()` function will be called on client initialization
+ * and the returned object will become the client's initial configuration.
+ *
+ * You may want to initialize your client this way instead of calling
+ * `setConfig()`. This is useful for example if you're using Next.js
+ * to ensure your client always has the correct values.
+ */
+export type CreateClientConfig<T extends ClientOptions = ClientOptions> = (
+ override?: Config<ClientOptions & T>,
+) => Config<Required<ClientOptions> & T>;
+
+export interface TDataShape {
+ body?: unknown;
+ headers?: unknown;
+ path?: unknown;
+ query?: unknown;
+ url: string;
+}
+
+type OmitKeys<T, K> = Pick<T, Exclude<keyof T, K>>;
+
+export type Options<
+ TData extends TDataShape = TDataShape,
+ ThrowOnError extends boolean = boolean,
+ TResponseStyle extends ResponseStyle = 'fields',
+> = OmitKeys<
+ RequestOptions<TResponseStyle, ThrowOnError>,
+ 'body' | 'path' | 'query' | 'url'
+> &
+ Omit<TData, 'url'>;
+
+export type OptionsLegacyParser<
+ TData = unknown,
+ ThrowOnError extends boolean = boolean,
+ TResponseStyle extends ResponseStyle = 'fields',
+> = TData extends { body?: any }
+ ? TData extends { headers?: any }
+ ? OmitKeys<
+ RequestOptions<TResponseStyle, ThrowOnError>,
+ 'body' | 'headers' | 'url'
+ > &
+ TData
+ : OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, 'body' | 'url'> &
+ TData &
+ Pick<RequestOptions<TResponseStyle, ThrowOnError>, 'headers'>
+ : TData extends { headers?: any }
+ ? OmitKeys<
+ RequestOptions<TResponseStyle, ThrowOnError>,
+ 'headers' | 'url'
+ > &
+ TData &
+ Pick<RequestOptions<TResponseStyle, ThrowOnError>, 'body'>
+ : OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, 'url'> & TData;
diff --git a/packages/sdk/js/src/gen/client/utils.ts b/packages/sdk/js/src/gen/client/utils.ts
new file mode 100644
index 000000000..a52e67292
--- /dev/null
+++ b/packages/sdk/js/src/gen/client/utils.ts
@@ -0,0 +1,417 @@
+import { getAuthToken } from '../core/auth';
+import type {
+ QuerySerializer,
+ QuerySerializerOptions,
+} from '../core/bodySerializer';
+import { jsonBodySerializer } from '../core/bodySerializer';
+import {
+ serializeArrayParam,
+ serializeObjectParam,
+ serializePrimitiveParam,
+} from '../core/pathSerializer';
+import type { Client, ClientOptions, Config, RequestOptions } from './types';
+
+interface PathSerializer {
+ path: Record<string, unknown>;
+ url: string;
+}
+
+const PATH_PARAM_RE = /\{[^{}]+\}/g;
+
+type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited';
+type MatrixStyle = 'label' | 'matrix' | 'simple';
+type ArraySeparatorStyle = ArrayStyle | MatrixStyle;
+
+const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => {
+ let url = _url;
+ const matches = _url.match(PATH_PARAM_RE);
+ if (matches) {
+ for (const match of matches) {
+ let explode = false;
+ let name = match.substring(1, match.length - 1);
+ let style: ArraySeparatorStyle = 'simple';
+
+ if (name.endsWith('*')) {
+ explode = true;
+ name = name.substring(0, name.length - 1);
+ }
+
+ if (name.startsWith('.')) {
+ name = name.substring(1);
+ style = 'label';
+ } else if (name.startsWith(';')) {
+ name = name.substring(1);
+ style = 'matrix';
+ }
+
+ const value = path[name];
+
+ if (value === undefined || value === null) {
+ continue;
+ }
+
+ if (Array.isArray(value)) {
+ url = url.replace(
+ match,
+ serializeArrayParam({ explode, name, style, value }),
+ );
+ continue;
+ }
+
+ if (typeof value === 'object') {
+ url = url.replace(
+ match,
+ serializeObjectParam({
+ explode,
+ name,
+ style,
+ value: value as Record<string, unknown>,
+ valueOnly: true,
+ }),
+ );
+ continue;
+ }
+
+ if (style === 'matrix') {
+ url = url.replace(
+ match,
+ `;${serializePrimitiveParam({
+ name,
+ value: value as string,
+ })}`,
+ );
+ continue;
+ }
+
+ const replaceValue = encodeURIComponent(
+ style === 'label' ? `.${value as string}` : (value as string),
+ );
+ url = url.replace(match, replaceValue);
+ }
+ }
+ return url;
+};
+
+export const createQuerySerializer = <T = unknown>({
+ allowReserved,
+ array,
+ object,
+}: QuerySerializerOptions = {}) => {
+ const querySerializer = (queryParams: T) => {
+ const search: string[] = [];
+ if (queryParams && typeof queryParams === 'object') {
+ for (const name in queryParams) {
+ const value = queryParams[name];
+
+ if (value === undefined || value === null) {
+ continue;
+ }
+
+ if (Array.isArray(value)) {
+ const serializedArray = serializeArrayParam({
+ allowReserved,
+ explode: true,
+ name,
+ style: 'form',
+ value,
+ ...array,
+ });
+ if (serializedArray) search.push(serializedArray);
+ } else if (typeof value === 'object') {
+ const serializedObject = serializeObjectParam({
+ allowReserved,
+ explode: true,
+ name,
+ style: 'deepObject',
+ value: value as Record<string, unknown>,
+ ...object,
+ });
+ if (serializedObject) search.push(serializedObject);
+ } else {
+ const serializedPrimitive = serializePrimitiveParam({
+ allowReserved,
+ name,
+ value: value as string,
+ });
+ if (serializedPrimitive) search.push(serializedPrimitive);
+ }
+ }
+ }
+ return search.join('&');
+ };
+ return querySerializer;
+};
+
+/**
+ * Infers parseAs value from provided Content-Type header.
+ */
+export const getParseAs = (
+ contentType: string | null,
+): Exclude<Config['parseAs'], 'auto'> => {
+ if (!contentType) {
+ // If no Content-Type header is provided, the best we can do is return the raw response body,
+ // which is effectively the same as the 'stream' option.
+ return 'stream';
+ }
+
+ const cleanContent = contentType.split(';')[0]?.trim();
+
+ if (!cleanContent) {
+ return;
+ }
+
+ if (
+ cleanContent.startsWith('application/json') ||
+ cleanContent.endsWith('+json')
+ ) {
+ return 'json';
+ }
+
+ if (cleanContent === 'multipart/form-data') {
+ return 'formData';
+ }
+
+ if (
+ ['application/', 'audio/', 'image/', 'video/'].some((type) =>
+ cleanContent.startsWith(type),
+ )
+ ) {
+ return 'blob';
+ }
+
+ if (cleanContent.startsWith('text/')) {
+ return 'text';
+ }
+
+ return;
+};
+
+export const setAuthParams = async ({
+ security,
+ ...options
+}: Pick<Required<RequestOptions>, 'security'> &
+ Pick<RequestOptions, 'auth' | 'query'> & {
+ headers: Headers;
+ }) => {
+ for (const auth of security) {
+ const token = await getAuthToken(auth, options.auth);
+
+ if (!token) {
+ continue;
+ }
+
+ const name = auth.name ?? 'Authorization';
+
+ switch (auth.in) {
+ case 'query':
+ if (!options.query) {
+ options.query = {};
+ }
+ options.query[name] = token;
+ break;
+ case 'cookie':
+ options.headers.append('Cookie', `${name}=${token}`);
+ break;
+ case 'header':
+ default:
+ options.headers.set(name, token);
+ break;
+ }
+
+ return;
+ }
+};
+
+export const buildUrl: Client['buildUrl'] = (options) => {
+ const url = getUrl({
+ baseUrl: options.baseUrl as string,
+ path: options.path,
+ query: options.query,
+ querySerializer:
+ typeof options.querySerializer === 'function'
+ ? options.querySerializer
+ : createQuerySerializer(options.querySerializer),
+ url: options.url,
+ });
+ return url;
+};
+
+export const getUrl = ({
+ baseUrl,
+ path,
+ query,
+ querySerializer,
+ url: _url,
+}: {
+ baseUrl?: string;
+ path?: Record<string, unknown>;
+ query?: Record<string, unknown>;
+ querySerializer: QuerySerializer;
+ url: string;
+}) => {
+ const pathUrl = _url.startsWith('/') ? _url : `/${_url}`;
+ let url = (baseUrl ?? '') + pathUrl;
+ if (path) {
+ url = defaultPathSerializer({ path, url });
+ }
+ let search = query ? querySerializer(query) : '';
+ if (search.startsWith('?')) {
+ search = search.substring(1);
+ }
+ if (search) {
+ url += `?${search}`;
+ }
+ return url;
+};
+
+export const mergeConfigs = (a: Config, b: Config): Config => {
+ const config = { ...a, ...b };
+ if (config.baseUrl?.endsWith('/')) {
+ config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1);
+ }
+ config.headers = mergeHeaders(a.headers, b.headers);
+ return config;
+};
+
+export const mergeHeaders = (
+ ...headers: Array<Required<Config>['headers'] | undefined>
+): Headers => {
+ const mergedHeaders = new Headers();
+ for (const header of headers) {
+ if (!header || typeof header !== 'object') {
+ continue;
+ }
+
+ const iterator =
+ header instanceof Headers ? header.entries() : Object.entries(header);
+
+ for (const [key, value] of iterator) {
+ if (value === null) {
+ mergedHeaders.delete(key);
+ } else if (Array.isArray(value)) {
+ for (const v of value) {
+ mergedHeaders.append(key, v as string);
+ }
+ } else if (value !== undefined) {
+ // assume object headers are meant to be JSON stringified, i.e. their
+ // content value in OpenAPI specification is 'application/json'
+ mergedHeaders.set(
+ key,
+ typeof value === 'object' ? JSON.stringify(value) : (value as string),
+ );
+ }
+ }
+ }
+ return mergedHeaders;
+};
+
+type ErrInterceptor<Err, Res, Req, Options> = (
+ error: Err,
+ response: Res,
+ request: Req,
+ options: Options,
+) => Err | Promise<Err>;
+
+type ReqInterceptor<Req, Options> = (
+ request: Req,
+ options: Options,
+) => Req | Promise<Req>;
+
+type ResInterceptor<Res, Req, Options> = (
+ response: Res,
+ request: Req,
+ options: Options,
+) => Res | Promise<Res>;
+
+class Interceptors<Interceptor> {
+ _fns: (Interceptor | null)[];
+
+ constructor() {
+ this._fns = [];
+ }
+
+ clear() {
+ this._fns = [];
+ }
+
+ getInterceptorIndex(id: number | Interceptor): number {
+ if (typeof id === 'number') {
+ return this._fns[id] ? id : -1;
+ } else {
+ return this._fns.indexOf(id);
+ }
+ }
+ exists(id: number | Interceptor) {
+ const index = this.getInterceptorIndex(id);
+ return !!this._fns[index];
+ }
+
+ eject(id: number | Interceptor) {
+ const index = this.getInterceptorIndex(id);
+ if (this._fns[index]) {
+ this._fns[index] = null;
+ }
+ }
+
+ update(id: number | Interceptor, fn: Interceptor) {
+ const index = this.getInterceptorIndex(id);
+ if (this._fns[index]) {
+ this._fns[index] = fn;
+ return id;
+ } else {
+ return false;
+ }
+ }
+
+ use(fn: Interceptor) {
+ this._fns = [...this._fns, fn];
+ return this._fns.length - 1;
+ }
+}
+
+// `createInterceptors()` response, meant for external use as it does not
+// expose internals
+export interface Middleware<Req, Res, Err, Options> {
+ error: Pick<
+ Interceptors<ErrInterceptor<Err, Res, Req, Options>>,
+ 'eject' | 'use'
+ >;
+ request: Pick<Interceptors<ReqInterceptor<Req, Options>>, 'eject' | 'use'>;
+ response: Pick<
+ Interceptors<ResInterceptor<Res, Req, Options>>,
+ 'eject' | 'use'
+ >;
+}
+
+// do not add `Middleware` as return type so we can use _fns internally
+export const createInterceptors = <Req, Res, Err, Options>() => ({
+ error: new Interceptors<ErrInterceptor<Err, Res, Req, Options>>(),
+ request: new Interceptors<ReqInterceptor<Req, Options>>(),
+ response: new Interceptors<ResInterceptor<Res, Req, Options>>(),
+});
+
+const defaultQuerySerializer = createQuerySerializer({
+ allowReserved: false,
+ array: {
+ explode: true,
+ style: 'form',
+ },
+ object: {
+ explode: true,
+ style: 'deepObject',
+ },
+});
+
+const defaultHeaders = {
+ 'Content-Type': 'application/json',
+};
+
+export const createConfig = <T extends ClientOptions = ClientOptions>(
+ override: Config<Omit<ClientOptions, keyof T> & T> = {},
+): Config<Omit<ClientOptions, keyof T> & T> => ({
+ ...jsonBodySerializer,
+ headers: defaultHeaders,
+ parseAs: 'auto',
+ querySerializer: defaultQuerySerializer,
+ ...override,
+});
diff --git a/packages/sdk/js/src/gen/core/auth.ts b/packages/sdk/js/src/gen/core/auth.ts
new file mode 100644
index 000000000..451c7f30f
--- /dev/null
+++ b/packages/sdk/js/src/gen/core/auth.ts
@@ -0,0 +1,40 @@
+export type AuthToken = string | undefined;
+
+export interface Auth {
+ /**
+ * Which part of the request do we use to send the auth?
+ *
+ * @default 'header'
+ */
+ in?: 'header' | 'query' | 'cookie';
+ /**
+ * Header or query parameter name.
+ *
+ * @default 'Authorization'
+ */
+ name?: string;
+ scheme?: 'basic' | 'bearer';
+ type: 'apiKey' | 'http';
+}
+
+export const getAuthToken = async (
+ auth: Auth,
+ callback: ((auth: Auth) => Promise<AuthToken> | AuthToken) | AuthToken,
+): Promise<string | undefined> => {
+ const token =
+ typeof callback === 'function' ? await callback(auth) : callback;
+
+ if (!token) {
+ return;
+ }
+
+ if (auth.scheme === 'bearer') {
+ return `Bearer ${token}`;
+ }
+
+ if (auth.scheme === 'basic') {
+ return `Basic ${btoa(token)}`;
+ }
+
+ return token;
+};
diff --git a/packages/sdk/js/src/gen/core/bodySerializer.ts b/packages/sdk/js/src/gen/core/bodySerializer.ts
new file mode 100644
index 000000000..98ce7791f
--- /dev/null
+++ b/packages/sdk/js/src/gen/core/bodySerializer.ts
@@ -0,0 +1,88 @@
+import type {
+ ArrayStyle,
+ ObjectStyle,
+ SerializerOptions,
+} from './pathSerializer';
+
+export type QuerySerializer = (query: Record<string, unknown>) => string;
+
+export type BodySerializer = (body: any) => any;
+
+export interface QuerySerializerOptions {
+ allowReserved?: boolean;
+ array?: SerializerOptions<ArrayStyle>;
+ object?: SerializerOptions<ObjectStyle>;
+}
+
+const serializeFormDataPair = (
+ data: FormData,
+ key: string,
+ value: unknown,
+): void => {
+ if (typeof value === 'string' || value instanceof Blob) {
+ data.append(key, value);
+ } else {
+ data.append(key, JSON.stringify(value));
+ }
+};
+
+const serializeUrlSearchParamsPair = (
+ data: URLSearchParams,
+ key: string,
+ value: unknown,
+): void => {
+ if (typeof value === 'string') {
+ data.append(key, value);
+ } else {
+ data.append(key, JSON.stringify(value));
+ }
+};
+
+export const formDataBodySerializer = {
+ bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(
+ body: T,
+ ): FormData => {
+ const data = new FormData();
+
+ Object.entries(body).forEach(([key, value]) => {
+ if (value === undefined || value === null) {
+ return;
+ }
+ if (Array.isArray(value)) {
+ value.forEach((v) => serializeFormDataPair(data, key, v));
+ } else {
+ serializeFormDataPair(data, key, value);
+ }
+ });
+
+ return data;
+ },
+};
+
+export const jsonBodySerializer = {
+ bodySerializer: <T>(body: T): string =>
+ JSON.stringify(body, (_key, value) =>
+ typeof value === 'bigint' ? value.toString() : value,
+ ),
+};
+
+export const urlSearchParamsBodySerializer = {
+ bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(
+ body: T,
+ ): string => {
+ const data = new URLSearchParams();
+
+ Object.entries(body).forEach(([key, value]) => {
+ if (value === undefined || value === null) {
+ return;
+ }
+ if (Array.isArray(value)) {
+ value.forEach((v) => serializeUrlSearchParamsPair(data, key, v));
+ } else {
+ serializeUrlSearchParamsPair(data, key, value);
+ }
+ });
+
+ return data.toString();
+ },
+};
diff --git a/packages/sdk/js/src/gen/core/params.ts b/packages/sdk/js/src/gen/core/params.ts
new file mode 100644
index 000000000..ba35263d8
--- /dev/null
+++ b/packages/sdk/js/src/gen/core/params.ts
@@ -0,0 +1,151 @@
+type Slot = 'body' | 'headers' | 'path' | 'query';
+
+export type Field =
+ | {
+ in: Exclude<Slot, 'body'>;
+ /**
+ * Field name. This is the name we want the user to see and use.
+ */
+ key: string;
+ /**
+ * Field mapped name. This is the name we want to use in the request.
+ * If omitted, we use the same value as `key`.
+ */
+ map?: string;
+ }
+ | {
+ in: Extract<Slot, 'body'>;
+ /**
+ * Key isn't required for bodies.
+ */
+ key?: string;
+ map?: string;
+ };
+
+export interface Fields {
+ allowExtra?: Partial<Record<Slot, boolean>>;
+ args?: ReadonlyArray<Field>;
+}
+
+export type FieldsConfig = ReadonlyArray<Field | Fields>;
+
+const extraPrefixesMap: Record<string, Slot> = {
+ $body_: 'body',
+ $headers_: 'headers',
+ $path_: 'path',
+ $query_: 'query',
+};
+const extraPrefixes = Object.entries(extraPrefixesMap);
+
+type KeyMap = Map<
+ string,
+ {
+ in: Slot;
+ map?: string;
+ }
+>;
+
+const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => {
+ if (!map) {
+ map = new Map();
+ }
+
+ for (const config of fields) {
+ if ('in' in config) {
+ if (config.key) {
+ map.set(config.key, {
+ in: config.in,
+ map: config.map,
+ });
+ }
+ } else if (config.args) {
+ buildKeyMap(config.args, map);
+ }
+ }
+
+ return map;
+};
+
+interface Params {
+ body: unknown;
+ headers: Record<string, unknown>;
+ path: Record<string, unknown>;
+ query: Record<string, unknown>;
+}
+
+const stripEmptySlots = (params: Params) => {
+ for (const [slot, value] of Object.entries(params)) {
+ if (value && typeof value === 'object' && !Object.keys(value).length) {
+ delete params[slot as Slot];
+ }
+ }
+};
+
+export const buildClientParams = (
+ args: ReadonlyArray<unknown>,
+ fields: FieldsConfig,
+) => {
+ const params: Params = {
+ body: {},
+ headers: {},
+ path: {},
+ query: {},
+ };
+
+ const map = buildKeyMap(fields);
+
+ let config: FieldsConfig[number] | undefined;
+
+ for (const [index, arg] of args.entries()) {
+ if (fields[index]) {
+ config = fields[index];
+ }
+
+ if (!config) {
+ continue;
+ }
+
+ if ('in' in config) {
+ if (config.key) {
+ const field = map.get(config.key)!;
+ const name = field.map || config.key;
+ (params[field.in] as Record<string, unknown>)[name] = arg;
+ } else {
+ params.body = arg;
+ }
+ } else {
+ for (const [key, value] of Object.entries(arg ?? {})) {
+ const field = map.get(key);
+
+ if (field) {
+ const name = field.map || key;
+ (params[field.in] as Record<string, unknown>)[name] = value;
+ } else {
+ const extra = extraPrefixes.find(([prefix]) =>
+ key.startsWith(prefix),
+ );
+
+ if (extra) {
+ const [prefix, slot] = extra;
+ (params[slot] as Record<string, unknown>)[
+ key.slice(prefix.length)
+ ] = value;
+ } else {
+ for (const [slot, allowed] of Object.entries(
+ config.allowExtra ?? {},
+ )) {
+ if (allowed) {
+ (params[slot as Slot] as Record<string, unknown>)[key] = value;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ stripEmptySlots(params);
+
+ return params;
+};
diff --git a/packages/sdk/js/src/gen/core/pathSerializer.ts b/packages/sdk/js/src/gen/core/pathSerializer.ts
new file mode 100644
index 000000000..d692cf0a3
--- /dev/null
+++ b/packages/sdk/js/src/gen/core/pathSerializer.ts
@@ -0,0 +1,179 @@
+interface SerializeOptions<T>
+ extends SerializePrimitiveOptions,
+ SerializerOptions<T> {}
+
+interface SerializePrimitiveOptions {
+ allowReserved?: boolean;
+ name: string;
+}
+
+export interface SerializerOptions<T> {
+ /**
+ * @default true
+ */
+ explode: boolean;
+ style: T;
+}
+
+export type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited';
+export type ArraySeparatorStyle = ArrayStyle | MatrixStyle;
+type MatrixStyle = 'label' | 'matrix' | 'simple';
+export type ObjectStyle = 'form' | 'deepObject';
+type ObjectSeparatorStyle = ObjectStyle | MatrixStyle;
+
+interface SerializePrimitiveParam extends SerializePrimitiveOptions {
+ value: string;
+}
+
+export const separatorArrayExplode = (style: ArraySeparatorStyle) => {
+ switch (style) {
+ case 'label':
+ return '.';
+ case 'matrix':
+ return ';';
+ case 'simple':
+ return ',';
+ default:
+ return '&';
+ }
+};
+
+export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => {
+ switch (style) {
+ case 'form':
+ return ',';
+ case 'pipeDelimited':
+ return '|';
+ case 'spaceDelimited':
+ return '%20';
+ default:
+ return ',';
+ }
+};
+
+export const separatorObjectExplode = (style: ObjectSeparatorStyle) => {
+ switch (style) {
+ case 'label':
+ return '.';
+ case 'matrix':
+ return ';';
+ case 'simple':
+ return ',';
+ default:
+ return '&';
+ }
+};
+
+export const serializeArrayParam = ({
+ allowReserved,
+ explode,
+ name,
+ style,
+ value,
+}: SerializeOptions<ArraySeparatorStyle> & {
+ value: unknown[];
+}) => {
+ if (!explode) {
+ const joinedValues = (
+ allowReserved ? value : value.map((v) => encodeURIComponent(v as string))
+ ).join(separatorArrayNoExplode(style));
+ switch (style) {
+ case 'label':
+ return `.${joinedValues}`;
+ case 'matrix':
+ return `;${name}=${joinedValues}`;
+ case 'simple':
+ return joinedValues;
+ default:
+ return `${name}=${joinedValues}`;
+ }
+ }
+
+ const separator = separatorArrayExplode(style);
+ const joinedValues = value
+ .map((v) => {
+ if (style === 'label' || style === 'simple') {
+ return allowReserved ? v : encodeURIComponent(v as string);
+ }
+
+ return serializePrimitiveParam({
+ allowReserved,
+ name,
+ value: v as string,
+ });
+ })
+ .join(separator);
+ return style === 'label' || style === 'matrix'
+ ? separator + joinedValues
+ : joinedValues;
+};
+
+export const serializePrimitiveParam = ({
+ allowReserved,
+ name,
+ value,
+}: SerializePrimitiveParam) => {
+ if (value === undefined || value === null) {
+ return '';
+ }
+
+ if (typeof value === 'object') {
+ throw new Error(
+ 'Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.',
+ );
+ }
+
+ return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
+};
+
+export const serializeObjectParam = ({
+ allowReserved,
+ explode,
+ name,
+ style,
+ value,
+ valueOnly,
+}: SerializeOptions<ObjectSeparatorStyle> & {
+ value: Record<string, unknown> | Date;
+ valueOnly?: boolean;
+}) => {
+ if (value instanceof Date) {
+ return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
+ }
+
+ if (style !== 'deepObject' && !explode) {
+ let values: string[] = [];
+ Object.entries(value).forEach(([key, v]) => {
+ values = [
+ ...values,
+ key,
+ allowReserved ? (v as string) : encodeURIComponent(v as string),
+ ];
+ });
+ const joinedValues = values.join(',');
+ switch (style) {
+ case 'form':
+ return `${name}=${joinedValues}`;
+ case 'label':
+ return `.${joinedValues}`;
+ case 'matrix':
+ return `;${name}=${joinedValues}`;
+ default:
+ return joinedValues;
+ }
+ }
+
+ const separator = separatorObjectExplode(style);
+ const joinedValues = Object.entries(value)
+ .map(([key, v]) =>
+ serializePrimitiveParam({
+ allowReserved,
+ name: style === 'deepObject' ? `${name}[${key}]` : key,
+ value: v as string,
+ }),
+ )
+ .join(separator);
+ return style === 'label' || style === 'matrix'
+ ? separator + joinedValues
+ : joinedValues;
+};
diff --git a/packages/sdk/js/src/gen/core/types.ts b/packages/sdk/js/src/gen/core/types.ts
new file mode 100644
index 000000000..2dd4106fb
--- /dev/null
+++ b/packages/sdk/js/src/gen/core/types.ts
@@ -0,0 +1,118 @@
+import type { Auth, AuthToken } from './auth';
+import type {
+ BodySerializer,
+ QuerySerializer,
+ QuerySerializerOptions,
+} from './bodySerializer';
+
+export interface Client<
+ RequestFn = never,
+ Config = unknown,
+ MethodFn = never,
+ BuildUrlFn = never,
+> {
+ /**
+ * Returns the final request URL.
+ */
+ buildUrl: BuildUrlFn;
+ connect: MethodFn;
+ delete: MethodFn;
+ get: MethodFn;
+ getConfig: () => Config;
+ head: MethodFn;
+ options: MethodFn;
+ patch: MethodFn;
+ post: MethodFn;
+ put: MethodFn;
+ request: RequestFn;
+ setConfig: (config: Config) => Config;
+ trace: MethodFn;
+}
+
+export interface Config {
+ /**
+ * Auth token or a function returning auth token. The resolved value will be
+ * added to the request payload as defined by its `security` array.
+ */
+ auth?: ((auth: Auth) => Promise<AuthToken> | AuthToken) | AuthToken;
+ /**
+ * A function for serializing request body parameter. By default,
+ * {@link JSON.stringify()} will be used.
+ */
+ bodySerializer?: BodySerializer | null;
+ /**
+ * An object containing any HTTP headers that you want to pre-populate your
+ * `Headers` object with.
+ *
+ * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more}
+ */
+ headers?:
+ | RequestInit['headers']
+ | Record<
+ string,
+ | string
+ | number
+ | boolean
+ | (string | number | boolean)[]
+ | null
+ | undefined
+ | unknown
+ >;
+ /**
+ * The request method.
+ *
+ * {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more}
+ */
+ method?:
+ | 'CONNECT'
+ | 'DELETE'
+ | 'GET'
+ | 'HEAD'
+ | 'OPTIONS'
+ | 'PATCH'
+ | 'POST'
+ | 'PUT'
+ | 'TRACE';
+ /**
+ * A function for serializing request query parameters. By default, arrays
+ * will be exploded in form style, objects will be exploded in deepObject
+ * style, and reserved characters are percent-encoded.
+ *
+ * This method will have no effect if the native `paramsSerializer()` Axios
+ * API function is used.
+ *
+ * {@link https://swagger.io/docs/specification/serialization/#query View examples}
+ */
+ querySerializer?: QuerySerializer | QuerySerializerOptions;
+ /**
+ * A function validating request data. This is useful if you want to ensure
+ * the request conforms to the desired shape, so it can be safely sent to
+ * the server.
+ */
+ requestValidator?: (data: unknown) => Promise<unknown>;
+ /**
+ * A function transforming response data before it's returned. This is useful
+ * for post-processing data, e.g. converting ISO strings into Date objects.
+ */
+ responseTransformer?: (data: unknown) => Promise<unknown>;
+ /**
+ * A function validating response data. This is useful if you want to ensure
+ * the response conforms to the desired shape, so it can be safely passed to
+ * the transformers and returned to the user.
+ */
+ responseValidator?: (data: unknown) => Promise<unknown>;
+}
+
+type IsExactlyNeverOrNeverUndefined<T> = [T] extends [never]
+ ? true
+ : [T] extends [never | undefined]
+ ? [undefined] extends [T]
+ ? false
+ : true
+ : false;
+
+export type OmitNever<T extends Record<string, unknown>> = {
+ [K in keyof T as IsExactlyNeverOrNeverUndefined<T[K]> extends true
+ ? never
+ : K]: T[K];
+};
diff --git a/packages/sdk/js/src/gen/sdk.gen.ts b/packages/sdk/js/src/gen/sdk.gen.ts
new file mode 100644
index 000000000..312084856
--- /dev/null
+++ b/packages/sdk/js/src/gen/sdk.gen.ts
@@ -0,0 +1,339 @@
+// This file is auto-generated by @hey-api/openapi-ts
+
+import type { Options as ClientOptions, TDataShape, Client } from './client';
+import type { EventSubscribeData, EventSubscribeResponses, AppGetData, AppGetResponses, AppInitData, AppInitResponses, ConfigGetData, ConfigGetResponses, SessionListData, SessionListResponses, SessionCreateData, SessionCreateResponses, SessionCreateErrors, SessionDeleteData, SessionDeleteResponses, SessionInitData, SessionInitResponses, SessionAbortData, SessionAbortResponses, SessionUnshareData, SessionUnshareResponses, SessionShareData, SessionShareResponses, SessionSummarizeData, SessionSummarizeResponses, SessionMessagesData, SessionMessagesResponses, SessionChatData, SessionChatResponses, SessionRevertData, SessionRevertResponses, SessionUnrevertData, SessionUnrevertResponses, ConfigProvidersData, ConfigProvidersResponses, FindTextData, FindTextResponses, FindFilesData, FindFilesResponses, FindSymbolsData, FindSymbolsResponses, FileReadData, FileReadResponses, FileStatusData, FileStatusResponses, AppLogData, AppLogResponses, AppModesData, AppModesResponses, TuiAppendPromptData, TuiAppendPromptResponses, TuiOpenHelpData, TuiOpenHelpResponses } from './types.gen';
+import { client as _heyApiClient } from './client.gen';
+
+export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {
+ /**
+ * You can provide a client instance returned by `createClient()` instead of
+ * individual options. This might be also useful if you want to implement a
+ * custom client.
+ */
+ client?: Client;
+ /**
+ * You can pass arbitrary values through the `meta` object. This can be
+ * used to access values that aren't defined as part of the SDK function.
+ */
+ meta?: Record<string, unknown>;
+};
+
+class _HeyApiClient {
+ protected _client: Client = _heyApiClient;
+
+ constructor(args?: {
+ client?: Client;
+ }) {
+ if (args?.client) {
+ this._client = args.client;
+ }
+ }
+}
+
+class Event extends _HeyApiClient {
+ /**
+ * Get events
+ */
+ public subscribe<ThrowOnError extends boolean = false>(options?: Options<EventSubscribeData, ThrowOnError>) {
+ return (options?.client ?? this._client).get<EventSubscribeResponses, unknown, ThrowOnError>({
+ url: '/event',
+ ...options
+ });
+ }
+}
+
+class App extends _HeyApiClient {
+ /**
+ * Get app info
+ */
+ public get<ThrowOnError extends boolean = false>(options?: Options<AppGetData, ThrowOnError>) {
+ return (options?.client ?? this._client).get<AppGetResponses, unknown, ThrowOnError>({
+ url: '/app',
+ ...options
+ });
+ }
+
+ /**
+ * Initialize the app
+ */
+ public init<ThrowOnError extends boolean = false>(options?: Options<AppInitData, ThrowOnError>) {
+ return (options?.client ?? this._client).post<AppInitResponses, unknown, ThrowOnError>({
+ url: '/app/init',
+ ...options
+ });
+ }
+
+ /**
+ * Write a log entry to the server logs
+ */
+ public log<ThrowOnError extends boolean = false>(options?: Options<AppLogData, ThrowOnError>) {
+ return (options?.client ?? this._client).post<AppLogResponses, unknown, ThrowOnError>({
+ url: '/log',
+ ...options,
+ headers: {
+ 'Content-Type': 'application/json',
+ ...options?.headers
+ }
+ });
+ }
+
+ /**
+ * List all modes
+ */
+ public modes<ThrowOnError extends boolean = false>(options?: Options<AppModesData, ThrowOnError>) {
+ return (options?.client ?? this._client).get<AppModesResponses, unknown, ThrowOnError>({
+ url: '/mode',
+ ...options
+ });
+ }
+}
+
+class Config extends _HeyApiClient {
+ /**
+ * Get config info
+ */
+ public get<ThrowOnError extends boolean = false>(options?: Options<ConfigGetData, ThrowOnError>) {
+ return (options?.client ?? this._client).get<ConfigGetResponses, unknown, ThrowOnError>({
+ url: '/config',
+ ...options
+ });
+ }
+
+ /**
+ * List all providers
+ */
+ public providers<ThrowOnError extends boolean = false>(options?: Options<ConfigProvidersData, ThrowOnError>) {
+ return (options?.client ?? this._client).get<ConfigProvidersResponses, unknown, ThrowOnError>({
+ url: '/config/providers',
+ ...options
+ });
+ }
+}
+
+class Session extends _HeyApiClient {
+ /**
+ * List all sessions
+ */
+ public list<ThrowOnError extends boolean = false>(options?: Options<SessionListData, ThrowOnError>) {
+ return (options?.client ?? this._client).get<SessionListResponses, unknown, ThrowOnError>({
+ url: '/session',
+ ...options
+ });
+ }
+
+ /**
+ * Create a new session
+ */
+ public create<ThrowOnError extends boolean = false>(options?: Options<SessionCreateData, ThrowOnError>) {
+ return (options?.client ?? this._client).post<SessionCreateResponses, SessionCreateErrors, ThrowOnError>({
+ url: '/session',
+ ...options
+ });
+ }
+
+ /**
+ * Delete a session and all its data
+ */
+ public delete<ThrowOnError extends boolean = false>(options: Options<SessionDeleteData, ThrowOnError>) {
+ return (options.client ?? this._client).delete<SessionDeleteResponses, unknown, ThrowOnError>({
+ url: '/session/{id}',
+ ...options
+ });
+ }
+
+ /**
+ * Analyze the app and create an AGENTS.md file
+ */
+ public init<ThrowOnError extends boolean = false>(options: Options<SessionInitData, ThrowOnError>) {
+ return (options.client ?? this._client).post<SessionInitResponses, unknown, ThrowOnError>({
+ url: '/session/{id}/init',
+ ...options,
+ headers: {
+ 'Content-Type': 'application/json',
+ ...options.headers
+ }
+ });
+ }
+
+ /**
+ * Abort a session
+ */
+ public abort<ThrowOnError extends boolean = false>(options: Options<SessionAbortData, ThrowOnError>) {
+ return (options.client ?? this._client).post<SessionAbortResponses, unknown, ThrowOnError>({
+ url: '/session/{id}/abort',
+ ...options
+ });
+ }
+
+ /**
+ * Unshare the session
+ */
+ public unshare<ThrowOnError extends boolean = false>(options: Options<SessionUnshareData, ThrowOnError>) {
+ return (options.client ?? this._client).delete<SessionUnshareResponses, unknown, ThrowOnError>({
+ url: '/session/{id}/share',
+ ...options
+ });
+ }
+
+ /**
+ * Share a session
+ */
+ public share<ThrowOnError extends boolean = false>(options: Options<SessionShareData, ThrowOnError>) {
+ return (options.client ?? this._client).post<SessionShareResponses, unknown, ThrowOnError>({
+ url: '/session/{id}/share',
+ ...options
+ });
+ }
+
+ /**
+ * Summarize the session
+ */
+ public summarize<ThrowOnError extends boolean = false>(options: Options<SessionSummarizeData, ThrowOnError>) {
+ return (options.client ?? this._client).post<SessionSummarizeResponses, unknown, ThrowOnError>({
+ url: '/session/{id}/summarize',
+ ...options,
+ headers: {
+ 'Content-Type': 'application/json',
+ ...options.headers
+ }
+ });
+ }
+
+ /**
+ * List messages for a session
+ */
+ public messages<ThrowOnError extends boolean = false>(options: Options<SessionMessagesData, ThrowOnError>) {
+ return (options.client ?? this._client).get<SessionMessagesResponses, unknown, ThrowOnError>({
+ url: '/session/{id}/message',
+ ...options
+ });
+ }
+
+ /**
+ * Create and send a new message to a session
+ */
+ public chat<ThrowOnError extends boolean = false>(options: Options<SessionChatData, ThrowOnError>) {
+ return (options.client ?? this._client).post<SessionChatResponses, unknown, ThrowOnError>({
+ url: '/session/{id}/message',
+ ...options,
+ headers: {
+ 'Content-Type': 'application/json',
+ ...options.headers
+ }
+ });
+ }
+
+ /**
+ * Revert a message
+ */
+ public revert<ThrowOnError extends boolean = false>(options: Options<SessionRevertData, ThrowOnError>) {
+ return (options.client ?? this._client).post<SessionRevertResponses, unknown, ThrowOnError>({
+ url: '/session/{id}/revert',
+ ...options,
+ headers: {
+ 'Content-Type': 'application/json',
+ ...options.headers
+ }
+ });
+ }
+
+ /**
+ * Restore all reverted messages
+ */
+ public unrevert<ThrowOnError extends boolean = false>(options: Options<SessionUnrevertData, ThrowOnError>) {
+ return (options.client ?? this._client).post<SessionUnrevertResponses, unknown, ThrowOnError>({
+ url: '/session/{id}/unrevert',
+ ...options
+ });
+ }
+}
+
+class Find extends _HeyApiClient {
+ /**
+ * Find text in files
+ */
+ public text<ThrowOnError extends boolean = false>(options: Options<FindTextData, ThrowOnError>) {
+ return (options.client ?? this._client).get<FindTextResponses, unknown, ThrowOnError>({
+ url: '/find',
+ ...options
+ });
+ }
+
+ /**
+ * Find files
+ */
+ public files<ThrowOnError extends boolean = false>(options: Options<FindFilesData, ThrowOnError>) {
+ return (options.client ?? this._client).get<FindFilesResponses, unknown, ThrowOnError>({
+ url: '/find/file',
+ ...options
+ });
+ }
+
+ /**
+ * Find workspace symbols
+ */
+ public symbols<ThrowOnError extends boolean = false>(options: Options<FindSymbolsData, ThrowOnError>) {
+ return (options.client ?? this._client).get<FindSymbolsResponses, unknown, ThrowOnError>({
+ url: '/find/symbol',
+ ...options
+ });
+ }
+}
+
+class File extends _HeyApiClient {
+ /**
+ * Read a file
+ */
+ public read<ThrowOnError extends boolean = false>(options: Options<FileReadData, ThrowOnError>) {
+ return (options.client ?? this._client).get<FileReadResponses, unknown, ThrowOnError>({
+ url: '/file',
+ ...options
+ });
+ }
+
+ /**
+ * Get file status
+ */
+ public status<ThrowOnError extends boolean = false>(options?: Options<FileStatusData, ThrowOnError>) {
+ return (options?.client ?? this._client).get<FileStatusResponses, unknown, ThrowOnError>({
+ url: '/file/status',
+ ...options
+ });
+ }
+}
+
+class Tui extends _HeyApiClient {
+ /**
+ * Append prompt to the TUI
+ */
+ public appendPrompt<ThrowOnError extends boolean = false>(options?: Options<TuiAppendPromptData, ThrowOnError>) {
+ return (options?.client ?? this._client).post<TuiAppendPromptResponses, unknown, ThrowOnError>({
+ url: '/tui/append-prompt',
+ ...options,
+ headers: {
+ 'Content-Type': 'application/json',
+ ...options?.headers
+ }
+ });
+ }
+
+ /**
+ * Open the help dialog
+ */
+ public openHelp<ThrowOnError extends boolean = false>(options?: Options<TuiOpenHelpData, ThrowOnError>) {
+ return (options?.client ?? this._client).post<TuiOpenHelpResponses, unknown, ThrowOnError>({
+ url: '/tui/open-help',
+ ...options
+ });
+ }
+}
+
+export class OpencodeClient extends _HeyApiClient {
+ event = new Event({ client: this._client });
+ app = new App({ client: this._client });
+ config = new Config({ client: this._client });
+ session = new Session({ client: this._client });
+ find = new Find({ client: this._client });
+ file = new File({ client: this._client });
+ tui = new Tui({ client: this._client });
+} \ No newline at end of file
diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts
new file mode 100644
index 000000000..6fcd1c415
--- /dev/null
+++ b/packages/sdk/js/src/gen/types.gen.ts
@@ -0,0 +1,1450 @@
+// This file is auto-generated by @hey-api/openapi-ts
+
+export type Event = ({
+ type: 'installation.updated';
+} & EventInstallationUpdated) | ({
+ type: 'lsp.client.diagnostics';
+} & EventLspClientDiagnostics) | ({
+ type: 'message.updated';
+} & EventMessageUpdated) | ({
+ type: 'message.removed';
+} & EventMessageRemoved) | ({
+ type: 'message.part.updated';
+} & EventMessagePartUpdated) | ({
+ type: 'message.part.removed';
+} & EventMessagePartRemoved) | ({
+ type: 'storage.write';
+} & EventStorageWrite) | ({
+ type: 'permission.updated';
+} & EventPermissionUpdated) | ({
+ type: 'file.edited';
+} & EventFileEdited) | ({
+ type: 'session.updated';
+} & EventSessionUpdated) | ({
+ type: 'session.deleted';
+} & EventSessionDeleted) | ({
+ type: 'session.idle';
+} & EventSessionIdle) | ({
+ type: 'session.error';
+} & EventSessionError) | ({
+ type: 'server.connected';
+} & EventServerConnected) | ({
+ type: 'file.watcher.updated';
+} & EventFileWatcherUpdated) | ({
+ type: 'ide.installed';
+} & EventIdeInstalled);
+
+export type EventInstallationUpdated = {
+ type: string;
+ properties: {
+ version: string;
+ };
+};
+
+export type EventLspClientDiagnostics = {
+ type: string;
+ properties: {
+ serverID: string;
+ path: string;
+ };
+};
+
+export type EventMessageUpdated = {
+ type: string;
+ properties: {
+ info: Message;
+ };
+};
+
+export type Message = ({
+ role: 'user';
+} & UserMessage) | ({
+ role: 'assistant';
+} & AssistantMessage);
+
+export type UserMessage = {
+ id: string;
+ sessionID: string;
+ role: string;
+ time: {
+ created: number;
+ };
+};
+
+export type AssistantMessage = {
+ id: string;
+ sessionID: string;
+ role: string;
+ time: {
+ created: number;
+ completed?: number;
+ };
+ error?: ({
+ name: 'ProviderAuthError';
+ } & ProviderAuthError) | ({
+ name: 'UnknownError';
+ } & UnknownError) | ({
+ name: 'MessageOutputLengthError';
+ } & MessageOutputLengthError) | ({
+ name: 'MessageAbortedError';
+ } & MessageAbortedError);
+ system: Array<string>;
+ modelID: string;
+ providerID: string;
+ mode: string;
+ path: {
+ cwd: string;
+ root: string;
+ };
+ summary?: boolean;
+ cost: number;
+ tokens: {
+ input: number;
+ output: number;
+ reasoning: number;
+ cache: {
+ read: number;
+ write: number;
+ };
+ };
+};
+
+export type ProviderAuthError = {
+ name: string;
+ data: {
+ providerID: string;
+ message: string;
+ };
+};
+
+export type UnknownError = {
+ name: string;
+ data: {
+ message: string;
+ };
+};
+
+export type MessageOutputLengthError = {
+ name: string;
+ data: {
+ [key: string]: unknown;
+ };
+};
+
+export type MessageAbortedError = {
+ name: string;
+ data: {
+ [key: string]: unknown;
+ };
+};
+
+export type EventMessageRemoved = {
+ type: string;
+ properties: {
+ sessionID: string;
+ messageID: string;
+ };
+};
+
+export type EventMessagePartUpdated = {
+ type: string;
+ properties: {
+ part: Part;
+ };
+};
+
+export type Part = ({
+ type: 'text';
+} & TextPart) | ({
+ type: 'file';
+} & FilePart) | ({
+ type: 'tool';
+} & ToolPart) | ({
+ type: 'step-start';
+} & StepStartPart) | ({
+ type: 'step-finish';
+} & StepFinishPart) | ({
+ type: 'snapshot';
+} & SnapshotPart) | ({
+ type: 'patch';
+} & PatchPart);
+
+export type TextPart = {
+ id: string;
+ sessionID: string;
+ messageID: string;
+ type: string;
+ text: string;
+ synthetic?: boolean;
+ time?: {
+ start: number;
+ end?: number;
+ };
+};
+
+export type FilePart = {
+ id: string;
+ sessionID: string;
+ messageID: string;
+ type: string;
+ mime: string;
+ filename?: string;
+ url: string;
+ source?: FilePartSource;
+};
+
+export type FilePartSource = ({
+ type: 'file';
+} & FileSource) | ({
+ type: 'symbol';
+} & SymbolSource);
+
+export type FileSource = {
+ text: FilePartSourceText;
+ type: string;
+ path: string;
+};
+
+export type FilePartSourceText = {
+ value: string;
+ start: number;
+ end: number;
+};
+
+export type SymbolSource = {
+ text: FilePartSourceText;
+ type: string;
+ path: string;
+ range: Range;
+ name: string;
+ kind: number;
+};
+
+export type Range = {
+ start: {
+ line: number;
+ character: number;
+ };
+ end: {
+ line: number;
+ character: number;
+ };
+};
+
+export type ToolPart = {
+ id: string;
+ sessionID: string;
+ messageID: string;
+ type: string;
+ callID: string;
+ tool: string;
+ state: ToolState;
+};
+
+export type ToolState = ({
+ status: 'pending';
+} & ToolStatePending) | ({
+ status: 'running';
+} & ToolStateRunning) | ({
+ status: 'completed';
+} & ToolStateCompleted) | ({
+ status: 'error';
+} & ToolStateError);
+
+export type ToolStatePending = {
+ status: string;
+};
+
+export type ToolStateRunning = {
+ status: string;
+ input?: unknown;
+ title?: string;
+ metadata?: {
+ [key: string]: unknown;
+ };
+ time: {
+ start: number;
+ };
+};
+
+export type ToolStateCompleted = {
+ status: string;
+ input: {
+ [key: string]: unknown;
+ };
+ output: string;
+ title: string;
+ metadata: {
+ [key: string]: unknown;
+ };
+ time: {
+ start: number;
+ end: number;
+ };
+};
+
+export type ToolStateError = {
+ status: string;
+ input: {
+ [key: string]: unknown;
+ };
+ error: string;
+ time: {
+ start: number;
+ end: number;
+ };
+};
+
+export type StepStartPart = {
+ id: string;
+ sessionID: string;
+ messageID: string;
+ type: string;
+};
+
+export type StepFinishPart = {
+ id: string;
+ sessionID: string;
+ messageID: string;
+ type: string;
+ cost: number;
+ tokens: {
+ input: number;
+ output: number;
+ reasoning: number;
+ cache: {
+ read: number;
+ write: number;
+ };
+ };
+};
+
+export type SnapshotPart = {
+ id: string;
+ sessionID: string;
+ messageID: string;
+ type: string;
+ snapshot: string;
+};
+
+export type PatchPart = {
+ id: string;
+ sessionID: string;
+ messageID: string;
+ type: string;
+ hash: string;
+ files: Array<string>;
+};
+
+export type EventMessagePartRemoved = {
+ type: string;
+ properties: {
+ sessionID: string;
+ messageID: string;
+ partID: string;
+ };
+};
+
+export type EventStorageWrite = {
+ type: string;
+ properties: {
+ key: string;
+ content?: unknown;
+ };
+};
+
+export type EventPermissionUpdated = {
+ type: string;
+ properties: PermissionInfo;
+};
+
+export type PermissionInfo = {
+ id: string;
+ sessionID: string;
+ title: string;
+ metadata: {
+ [key: string]: unknown;
+ };
+ time: {
+ created: number;
+ };
+};
+
+export type EventFileEdited = {
+ type: string;
+ properties: {
+ file: string;
+ };
+};
+
+export type EventSessionUpdated = {
+ type: string;
+ properties: {
+ info: Session;
+ };
+};
+
+export type Session = {
+ id: string;
+ parentID?: string;
+ share?: {
+ url: string;
+ };
+ title: string;
+ version: string;
+ time: {
+ created: number;
+ updated: number;
+ };
+ revert?: {
+ messageID: string;
+ partID?: string;
+ snapshot?: string;
+ diff?: string;
+ };
+};
+
+export type EventSessionDeleted = {
+ type: string;
+ properties: {
+ info: Session;
+ };
+};
+
+export type EventSessionIdle = {
+ type: string;
+ properties: {
+ sessionID: string;
+ };
+};
+
+export type EventSessionError = {
+ type: string;
+ properties: {
+ sessionID?: string;
+ error?: ({
+ name: 'ProviderAuthError';
+ } & ProviderAuthError) | ({
+ name: 'UnknownError';
+ } & UnknownError) | ({
+ name: 'MessageOutputLengthError';
+ } & MessageOutputLengthError) | ({
+ name: 'MessageAbortedError';
+ } & MessageAbortedError);
+ };
+};
+
+export type EventServerConnected = {
+ type: string;
+ properties: {
+ [key: string]: unknown;
+ };
+};
+
+export type EventFileWatcherUpdated = {
+ type: string;
+ properties: {
+ file: string;
+ event: string;
+ };
+};
+
+export type EventIdeInstalled = {
+ type: string;
+ properties: {
+ ide: string;
+ };
+};
+
+export type App = {
+ hostname: string;
+ git: boolean;
+ path: {
+ config: string;
+ data: string;
+ root: string;
+ cwd: string;
+ state: string;
+ };
+ time: {
+ initialized?: number;
+ };
+};
+
+export type Config = {
+ /**
+ * JSON schema reference for configuration validation
+ */
+ $schema?: string;
+ /**
+ * Theme name to use for the interface
+ */
+ theme?: string;
+ keybinds?: KeybindsConfig;
+ /**
+ * Control sharing behavior:'manual' allows manual sharing via commands, 'auto' enables automatic sharing, 'disabled' disables all sharing
+ */
+ share?: 'manual' | 'auto' | 'disabled';
+ /**
+ * @deprecated Use 'share' field instead. Share newly created sessions automatically
+ */
+ autoshare?: boolean;
+ /**
+ * Automatically update to the latest version
+ */
+ autoupdate?: boolean;
+ /**
+ * Disable providers that are loaded automatically
+ */
+ disabled_providers?: Array<string>;
+ /**
+ * Model to use in the format of provider/model, eg anthropic/claude-2
+ */
+ model?: string;
+ /**
+ * Small model to use for tasks like summarization and title generation in the format of provider/model
+ */
+ small_model?: string;
+ /**
+ * Custom username to display in conversations instead of system username
+ */
+ username?: string;
+ /**
+ * Modes configuration, see https://opencode.ai/docs/modes
+ */
+ mode?: {
+ build?: ModeConfig;
+ plan?: ModeConfig;
+ [key: string]: ModeConfig | undefined;
+ };
+ /**
+ * Modes configuration, see https://opencode.ai/docs/modes
+ */
+ agent?: {
+ general?: AgentConfig;
+ [key: string]: AgentConfig | undefined;
+ };
+ /**
+ * Custom provider configurations and model overrides
+ */
+ provider?: {
+ [key: string]: {
+ api?: string;
+ name?: string;
+ env?: Array<string>;
+ id?: string;
+ npm?: string;
+ models: {
+ [key: string]: {
+ id?: string;
+ name?: string;
+ release_date?: string;
+ attachment?: boolean;
+ reasoning?: boolean;
+ temperature?: boolean;
+ tool_call?: boolean;
+ cost?: {
+ input: number;
+ output: number;
+ cache_read?: number;
+ cache_write?: number;
+ };
+ limit?: {
+ context: number;
+ output: number;
+ };
+ options?: {
+ [key: string]: unknown;
+ };
+ };
+ };
+ options?: {
+ apiKey?: string;
+ baseURL?: string;
+ [key: string]: unknown | string | undefined;
+ };
+ };
+ };
+ /**
+ * MCP (Model Context Protocol) server configurations
+ */
+ mcp?: {
+ [key: string]: ({
+ type: 'local';
+ } & McpLocalConfig) | ({
+ type: 'remote';
+ } & McpRemoteConfig);
+ };
+ /**
+ * Additional instruction files or patterns to include
+ */
+ instructions?: Array<string>;
+ layout?: LayoutConfig;
+ permission?: {
+ edit?: string;
+ bash?: string | {
+ [key: string]: string;
+ };
+ };
+ experimental?: {
+ hook?: {
+ file_edited?: {
+ [key: string]: Array<{
+ command: Array<string>;
+ environment?: {
+ [key: string]: string;
+ };
+ }>;
+ };
+ session_completed?: Array<{
+ command: Array<string>;
+ environment?: {
+ [key: string]: string;
+ };
+ }>;
+ };
+ };
+};
+
+export type KeybindsConfig = {
+ /**
+ * Leader key for keybind combinations
+ */
+ leader: string;
+ /**
+ * Show help dialog
+ */
+ app_help: string;
+ /**
+ * Next mode
+ */
+ switch_mode: string;
+ /**
+ * Previous Mode
+ */
+ switch_mode_reverse: string;
+ /**
+ * Open external editor
+ */
+ editor_open: string;
+ /**
+ * Export session to editor
+ */
+ session_export: string;
+ /**
+ * Create a new session
+ */
+ session_new: string;
+ /**
+ * List all sessions
+ */
+ session_list: string;
+ /**
+ * Share current session
+ */
+ session_share: string;
+ /**
+ * Unshare current session
+ */
+ session_unshare: string;
+ /**
+ * Interrupt current session
+ */
+ session_interrupt: string;
+ /**
+ * Compact the session
+ */
+ session_compact: string;
+ /**
+ * Toggle tool details
+ */
+ tool_details: string;
+ /**
+ * List available models
+ */
+ model_list: string;
+ /**
+ * List available themes
+ */
+ theme_list: string;
+ /**
+ * List files
+ */
+ file_list: string;
+ /**
+ * Close file
+ */
+ file_close: string;
+ /**
+ * Search file
+ */
+ file_search: string;
+ /**
+ * Split/unified diff
+ */
+ file_diff_toggle: string;
+ /**
+ * Create/update AGENTS.md
+ */
+ project_init: string;
+ /**
+ * Clear input field
+ */
+ input_clear: string;
+ /**
+ * Paste from clipboard
+ */
+ input_paste: string;
+ /**
+ * Submit input
+ */
+ input_submit: string;
+ /**
+ * Insert newline in input
+ */
+ input_newline: string;
+ /**
+ * Scroll messages up by one page
+ */
+ messages_page_up: string;
+ /**
+ * Scroll messages down by one page
+ */
+ messages_page_down: string;
+ /**
+ * Scroll messages up by half page
+ */
+ messages_half_page_up: string;
+ /**
+ * Scroll messages down by half page
+ */
+ messages_half_page_down: string;
+ /**
+ * Navigate to previous message
+ */
+ messages_previous: string;
+ /**
+ * Navigate to next message
+ */
+ messages_next: string;
+ /**
+ * Navigate to first message
+ */
+ messages_first: string;
+ /**
+ * Navigate to last message
+ */
+ messages_last: string;
+ /**
+ * Toggle layout
+ */
+ messages_layout_toggle: string;
+ /**
+ * Copy message
+ */
+ messages_copy: string;
+ /**
+ * @deprecated use messages_undo. Revert message
+ */
+ messages_revert: string;
+ /**
+ * Undo message
+ */
+ messages_undo: string;
+ /**
+ * Redo message
+ */
+ messages_redo: string;
+ /**
+ * Exit the application
+ */
+ app_exit: string;
+};
+
+export type ModeConfig = {
+ model?: string;
+ temperature?: number;
+ prompt?: string;
+ tools?: {
+ [key: string]: boolean;
+ };
+ disable?: boolean;
+};
+
+export type AgentConfig = ModeConfig & {
+ description: string;
+};
+
+export type Provider = {
+ api?: string;
+ name: string;
+ env: Array<string>;
+ id: string;
+ npm?: string;
+ models: {
+ [key: string]: Model;
+ };
+};
+
+export type Model = {
+ id: string;
+ name: string;
+ release_date: string;
+ attachment: boolean;
+ reasoning: boolean;
+ temperature: boolean;
+ tool_call: boolean;
+ cost: {
+ input: number;
+ output: number;
+ cache_read?: number;
+ cache_write?: number;
+ };
+ limit: {
+ context: number;
+ output: number;
+ };
+ options: {
+ [key: string]: unknown;
+ };
+};
+
+export type McpLocalConfig = {
+ /**
+ * Type of MCP server connection
+ */
+ type: string;
+ /**
+ * Command and arguments to run the MCP server
+ */
+ command: Array<string>;
+ /**
+ * Environment variables to set when running the MCP server
+ */
+ environment?: {
+ [key: string]: string;
+ };
+ /**
+ * Enable or disable the MCP server on startup
+ */
+ enabled?: boolean;
+};
+
+export type McpRemoteConfig = {
+ /**
+ * Type of MCP server connection
+ */
+ type: string;
+ /**
+ * URL of the remote MCP server
+ */
+ url: string;
+ /**
+ * Enable or disable the MCP server on startup
+ */
+ enabled?: boolean;
+ /**
+ * Headers to send with the request
+ */
+ headers?: {
+ [key: string]: string;
+ };
+};
+
+export type LayoutConfig = 'auto' | 'stretch';
+
+export type _Error = {
+ data: {
+ [key: string]: unknown;
+ };
+};
+
+export type TextPartInput = {
+ id?: string;
+ type: string;
+ text: string;
+ synthetic?: boolean;
+ time?: {
+ start: number;
+ end?: number;
+ };
+};
+
+export type FilePartInput = {
+ id?: string;
+ type: string;
+ mime: string;
+ filename?: string;
+ url: string;
+ source?: FilePartSource;
+};
+
+export type Symbol = {
+ name: string;
+ kind: number;
+ location: {
+ uri: string;
+ range: Range;
+ };
+};
+
+export type File = {
+ path: string;
+ added: number;
+ removed: number;
+ status: 'added' | 'deleted' | 'modified';
+};
+
+export type Mode = {
+ name: string;
+ temperature?: number;
+ model?: {
+ modelID: string;
+ providerID: string;
+ };
+ prompt?: string;
+ tools: {
+ [key: string]: boolean;
+ };
+};
+
+export type EventSubscribeData = {
+ body?: never;
+ path?: never;
+ query?: never;
+ url: '/event';
+};
+
+export type EventSubscribeResponses = {
+ /**
+ * Event stream
+ */
+ 200: Event;
+};
+
+export type EventSubscribeResponse = EventSubscribeResponses[keyof EventSubscribeResponses];
+
+export type AppGetData = {
+ body?: never;
+ path?: never;
+ query?: never;
+ url: '/app';
+};
+
+export type AppGetResponses = {
+ /**
+ * 200
+ */
+ 200: App;
+};
+
+export type AppGetResponse = AppGetResponses[keyof AppGetResponses];
+
+export type AppInitData = {
+ body?: never;
+ path?: never;
+ query?: never;
+ url: '/app/init';
+};
+
+export type AppInitResponses = {
+ /**
+ * Initialize the app
+ */
+ 200: boolean;
+};
+
+export type AppInitResponse = AppInitResponses[keyof AppInitResponses];
+
+export type ConfigGetData = {
+ body?: never;
+ path?: never;
+ query?: never;
+ url: '/config';
+};
+
+export type ConfigGetResponses = {
+ /**
+ * Get config info
+ */
+ 200: Config;
+};
+
+export type ConfigGetResponse = ConfigGetResponses[keyof ConfigGetResponses];
+
+export type SessionListData = {
+ body?: never;
+ path?: never;
+ query?: never;
+ url: '/session';
+};
+
+export type SessionListResponses = {
+ /**
+ * List of sessions
+ */
+ 200: Array<Session>;
+};
+
+export type SessionListResponse = SessionListResponses[keyof SessionListResponses];
+
+export type SessionCreateData = {
+ body?: never;
+ path?: never;
+ query?: never;
+ url: '/session';
+};
+
+export type SessionCreateErrors = {
+ /**
+ * Bad request
+ */
+ 400: _Error;
+};
+
+export type SessionCreateError = SessionCreateErrors[keyof SessionCreateErrors];
+
+export type SessionCreateResponses = {
+ /**
+ * Successfully created session
+ */
+ 200: Session;
+};
+
+export type SessionCreateResponse = SessionCreateResponses[keyof SessionCreateResponses];
+
+export type SessionDeleteData = {
+ body?: never;
+ path: {
+ id: string;
+ };
+ query?: never;
+ url: '/session/{id}';
+};
+
+export type SessionDeleteResponses = {
+ /**
+ * Successfully deleted session
+ */
+ 200: boolean;
+};
+
+export type SessionDeleteResponse = SessionDeleteResponses[keyof SessionDeleteResponses];
+
+export type SessionInitData = {
+ body?: {
+ messageID: string;
+ providerID: string;
+ modelID: string;
+ };
+ path: {
+ /**
+ * Session ID
+ */
+ id: string;
+ };
+ query?: never;
+ url: '/session/{id}/init';
+};
+
+export type SessionInitResponses = {
+ /**
+ * 200
+ */
+ 200: boolean;
+};
+
+export type SessionInitResponse = SessionInitResponses[keyof SessionInitResponses];
+
+export type SessionAbortData = {
+ body?: never;
+ path: {
+ id: string;
+ };
+ query?: never;
+ url: '/session/{id}/abort';
+};
+
+export type SessionAbortResponses = {
+ /**
+ * Aborted session
+ */
+ 200: boolean;
+};
+
+export type SessionAbortResponse = SessionAbortResponses[keyof SessionAbortResponses];
+
+export type SessionUnshareData = {
+ body?: never;
+ path: {
+ id: string;
+ };
+ query?: never;
+ url: '/session/{id}/share';
+};
+
+export type SessionUnshareResponses = {
+ /**
+ * Successfully unshared session
+ */
+ 200: Session;
+};
+
+export type SessionUnshareResponse = SessionUnshareResponses[keyof SessionUnshareResponses];
+
+export type SessionShareData = {
+ body?: never;
+ path: {
+ id: string;
+ };
+ query?: never;
+ url: '/session/{id}/share';
+};
+
+export type SessionShareResponses = {
+ /**
+ * Successfully shared session
+ */
+ 200: Session;
+};
+
+export type SessionShareResponse = SessionShareResponses[keyof SessionShareResponses];
+
+export type SessionSummarizeData = {
+ body?: {
+ providerID: string;
+ modelID: string;
+ };
+ path: {
+ /**
+ * Session ID
+ */
+ id: string;
+ };
+ query?: never;
+ url: '/session/{id}/summarize';
+};
+
+export type SessionSummarizeResponses = {
+ /**
+ * Summarized session
+ */
+ 200: boolean;
+};
+
+export type SessionSummarizeResponse = SessionSummarizeResponses[keyof SessionSummarizeResponses];
+
+export type SessionMessagesData = {
+ body?: never;
+ path: {
+ /**
+ * Session ID
+ */
+ id: string;
+ };
+ query?: never;
+ url: '/session/{id}/message';
+};
+
+export type SessionMessagesResponses = {
+ /**
+ * List of messages
+ */
+ 200: Array<{
+ info: Message;
+ parts: Array<Part>;
+ }>;
+};
+
+export type SessionMessagesResponse = SessionMessagesResponses[keyof SessionMessagesResponses];
+
+export type SessionChatData = {
+ body?: {
+ messageID?: string;
+ providerID: string;
+ modelID: string;
+ mode?: string;
+ system?: string;
+ tools?: {
+ [key: string]: boolean;
+ };
+ parts: Array<({
+ type: 'text';
+ } & TextPartInput) | ({
+ type: 'file';
+ } & FilePartInput)>;
+ };
+ path: {
+ /**
+ * Session ID
+ */
+ id: string;
+ };
+ query?: never;
+ url: '/session/{id}/message';
+};
+
+export type SessionChatResponses = {
+ /**
+ * Created message
+ */
+ 200: AssistantMessage;
+};
+
+export type SessionChatResponse = SessionChatResponses[keyof SessionChatResponses];
+
+export type SessionRevertData = {
+ body?: {
+ messageID: string;
+ partID?: string;
+ };
+ path: {
+ id: string;
+ };
+ query?: never;
+ url: '/session/{id}/revert';
+};
+
+export type SessionRevertResponses = {
+ /**
+ * Updated session
+ */
+ 200: Session;
+};
+
+export type SessionRevertResponse = SessionRevertResponses[keyof SessionRevertResponses];
+
+export type SessionUnrevertData = {
+ body?: never;
+ path: {
+ id: string;
+ };
+ query?: never;
+ url: '/session/{id}/unrevert';
+};
+
+export type SessionUnrevertResponses = {
+ /**
+ * Updated session
+ */
+ 200: Session;
+};
+
+export type SessionUnrevertResponse = SessionUnrevertResponses[keyof SessionUnrevertResponses];
+
+export type ConfigProvidersData = {
+ body?: never;
+ path?: never;
+ query?: never;
+ url: '/config/providers';
+};
+
+export type ConfigProvidersResponses = {
+ /**
+ * List of providers
+ */
+ 200: {
+ providers: Array<Provider>;
+ default: {
+ [key: string]: string;
+ };
+ };
+};
+
+export type ConfigProvidersResponse = ConfigProvidersResponses[keyof ConfigProvidersResponses];
+
+export type FindTextData = {
+ body?: never;
+ path?: never;
+ query: {
+ pattern: string;
+ };
+ url: '/find';
+};
+
+export type FindTextResponses = {
+ /**
+ * Matches
+ */
+ 200: Array<{
+ path: {
+ text: string;
+ };
+ lines: {
+ text: string;
+ };
+ line_number: number;
+ absolute_offset: number;
+ submatches: Array<{
+ match: {
+ text: string;
+ };
+ start: number;
+ end: number;
+ }>;
+ }>;
+};
+
+export type FindTextResponse = FindTextResponses[keyof FindTextResponses];
+
+export type FindFilesData = {
+ body?: never;
+ path?: never;
+ query: {
+ query: string;
+ };
+ url: '/find/file';
+};
+
+export type FindFilesResponses = {
+ /**
+ * File paths
+ */
+ 200: Array<string>;
+};
+
+export type FindFilesResponse = FindFilesResponses[keyof FindFilesResponses];
+
+export type FindSymbolsData = {
+ body?: never;
+ path?: never;
+ query: {
+ query: string;
+ };
+ url: '/find/symbol';
+};
+
+export type FindSymbolsResponses = {
+ /**
+ * Symbols
+ */
+ 200: Array<Symbol>;
+};
+
+export type FindSymbolsResponse = FindSymbolsResponses[keyof FindSymbolsResponses];
+
+export type FileReadData = {
+ body?: never;
+ path?: never;
+ query: {
+ path: string;
+ };
+ url: '/file';
+};
+
+export type FileReadResponses = {
+ /**
+ * File content
+ */
+ 200: {
+ type: 'raw' | 'patch';
+ content: string;
+ };
+};
+
+export type FileReadResponse = FileReadResponses[keyof FileReadResponses];
+
+export type FileStatusData = {
+ body?: never;
+ path?: never;
+ query?: never;
+ url: '/file/status';
+};
+
+export type FileStatusResponses = {
+ /**
+ * File status
+ */
+ 200: Array<File>;
+};
+
+export type FileStatusResponse = FileStatusResponses[keyof FileStatusResponses];
+
+export type AppLogData = {
+ body?: {
+ /**
+ * Service name for the log entry
+ */
+ service: string;
+ /**
+ * Log level
+ */
+ level: 'debug' | 'info' | 'error' | 'warn';
+ /**
+ * Log message
+ */
+ message: string;
+ /**
+ * Additional metadata for the log entry
+ */
+ extra?: {
+ [key: string]: unknown;
+ };
+ };
+ path?: never;
+ query?: never;
+ url: '/log';
+};
+
+export type AppLogResponses = {
+ /**
+ * Log entry written successfully
+ */
+ 200: boolean;
+};
+
+export type AppLogResponse = AppLogResponses[keyof AppLogResponses];
+
+export type AppModesData = {
+ body?: never;
+ path?: never;
+ query?: never;
+ url: '/mode';
+};
+
+export type AppModesResponses = {
+ /**
+ * List of modes
+ */
+ 200: Array<Mode>;
+};
+
+export type AppModesResponse = AppModesResponses[keyof AppModesResponses];
+
+export type TuiAppendPromptData = {
+ body?: {
+ text: string;
+ };
+ path?: never;
+ query?: never;
+ url: '/tui/append-prompt';
+};
+
+export type TuiAppendPromptResponses = {
+ /**
+ * Prompt processed successfully
+ */
+ 200: boolean;
+};
+
+export type TuiAppendPromptResponse = TuiAppendPromptResponses[keyof TuiAppendPromptResponses];
+
+export type TuiOpenHelpData = {
+ body?: never;
+ path?: never;
+ query?: never;
+ url: '/tui/open-help';
+};
+
+export type TuiOpenHelpResponses = {
+ /**
+ * Help dialog opened successfully
+ */
+ 200: boolean;
+};
+
+export type TuiOpenHelpResponse = TuiOpenHelpResponses[keyof TuiOpenHelpResponses];
+
+export type ClientOptions = {
+ baseUrl: `${string}://${string}` | (string & {});
+}; \ No newline at end of file
diff --git a/packages/sdk/js/src/index.ts b/packages/sdk/js/src/index.ts
new file mode 100644
index 000000000..bdabf5f43
--- /dev/null
+++ b/packages/sdk/js/src/index.ts
@@ -0,0 +1,8 @@
+import { createClient } from "./gen/client/client"
+import { type Config } from "./gen/client/types"
+import { OpencodeClient } from "./gen/sdk.gen"
+
+export function createOpencodeClient(config?: Config) {
+ const client = createClient(config)
+ return new OpencodeClient({ client })
+}