Compare commits

...

4 Commits

Author SHA1 Message Date
Dax Raad 09446605ec Snapshot release v0.0.0-202508022055 2025-08-02 16:55:53 -04:00
Dax Raad 1f9e8cc4a5 Snapshot release v0.0.0-202508022053 2025-08-02 16:55:35 -04:00
Dax Raad 09c4b71632 wip: plugins 2025-08-02 16:47:11 -04:00
Dax Raad c9bffc0f46 ignore: i am a senior engineer 2025-08-02 16:29:45 -04:00
38 changed files with 2769 additions and 2498 deletions
+13
View File
@@ -38,6 +38,7 @@
"@octokit/graphql": "9.0.1",
"@octokit/rest": "22.0.0",
"@openauthjs/openauth": "0.4.3",
"@opencode-ai/plugin": "workspace:*",
"@standard-schema/spec": "1.0.0",
"@zip.js/zip.js": "2.7.62",
"ai": "catalog:",
@@ -74,6 +75,16 @@
"zod-to-json-schema": "3.24.5",
},
},
"packages/plugin": {
"name": "@opencode-ai/plugin",
"version": "0.0.0",
"devDependencies": {
"@hey-api/openapi-ts": "0.80.1",
"@opencode-ai/sdk": "workspace:*",
"@tsconfig/node22": "catalog:",
"typescript": "catalog:",
},
},
"packages/sdk/js": {
"name": "@opencode-ai/sdk",
"version": "0.0.0",
@@ -416,6 +427,8 @@
"@openauthjs/openauth": ["@openauthjs/openauth@0.4.3", "", { "dependencies": { "@standard-schema/spec": "1.0.0-beta.3", "aws4fetch": "1.0.20", "jose": "5.9.6" }, "peerDependencies": { "arctic": "^2.2.2", "hono": "^4.0.0" } }, "sha512-RlnjqvHzqcbFVymEwhlUEuac4utA5h4nhSK/i2szZuQmxTIqbGUxZ+nM+avM+VV4Ing+/ZaNLKILoXS3yrkOOw=="],
"@opencode-ai/plugin": ["@opencode-ai/plugin@workspace:packages/plugin"],
"@opencode-ai/sdk": ["@opencode-ai/sdk@workspace:packages/sdk/js"],
"@opencode/function": ["@opencode/function@workspace:packages/function"],
+1 -11
View File
@@ -1,16 +1,6 @@
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"cerebras": {
"options": {
"apiKey": "csk-m33xrvt43whkypn8r4ph9xc8fenhx2f68c3pj22ext45v5k9"
},
"npm": "@ai-sdk/cerebras",
"models": {
"qwen-3-coder-480b": {}
}
}
},
"plugin": ["./packages/plugin/src/example.ts"],
"mcp": {
"context7": {
"type": "remote",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode/function",
"version": "0.0.1",
"version": "0.0.0-202508022053",
"$schema": "https://json.schemastore.org/package.json",
"private": true,
"type": "module",
+2 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://json.schemastore.org/package.json",
"version": "0.0.0",
"version": "0.0.0-202508022053",
"name": "opencode",
"type": "module",
"private": true,
@@ -36,6 +36,7 @@
"@octokit/graphql": "9.0.1",
"@octokit/rest": "22.0.0",
"@openauthjs/openauth": "0.4.3",
"@opencode-ai/plugin": "workspace:*",
"@standard-schema/spec": "1.0.0",
"@zip.js/zip.js": "2.7.62",
"ai": "catalog:",
+2
View File
@@ -2,6 +2,7 @@ import { App } from "../app/app"
import { ConfigHooks } from "../config/hooks"
import { Format } from "../format"
import { LSP } from "../lsp"
import { Plugin } from "../plugin"
import { Share } from "../share/share"
import { Snapshot } from "../snapshot"
@@ -9,6 +10,7 @@ export async function bootstrap<T>(input: App.Input, cb: (app: App.Info) => Prom
return App.provide(input, async (app) => {
Share.init()
Format.init()
Plugin.init()
ConfigHooks.init()
LSP.init()
Snapshot.init()
+28 -16
View File
@@ -23,13 +23,13 @@ export namespace Config {
for (const file of ["opencode.jsonc", "opencode.json"]) {
const found = await Filesystem.findUp(file, app.path.cwd, app.path.root)
for (const resolved of found.toReversed()) {
result = mergeDeep(result, await load(resolved))
result = mergeDeep(result, await loadFile(resolved))
}
}
// Override with custom config if provided
if (Flag.OPENCODE_CONFIG) {
result = mergeDeep(result, await load(Flag.OPENCODE_CONFIG))
result = mergeDeep(result, await loadFile(Flag.OPENCODE_CONFIG))
log.debug("loaded custom config", { path: Flag.OPENCODE_CONFIG })
}
@@ -37,7 +37,7 @@ export namespace Config {
if (value.type === "wellknown") {
process.env[value.key] = value.token
const wellknown = await fetch(`${key}/.well-known/opencode`).then((x) => x.json())
result = mergeDeep(result, await loadRaw(JSON.stringify(wellknown.config ?? {}), process.cwd()))
result = mergeDeep(result, await load(JSON.stringify(wellknown.config ?? {}), process.cwd()))
}
}
@@ -223,6 +223,7 @@ export namespace Config {
$schema: z.string().optional().describe("JSON schema reference for configuration validation"),
theme: z.string().optional().describe("Theme name to use for the interface"),
keybinds: Keybinds.optional().describe("Custom keybind configurations"),
plugin: z.string().array().optional(),
share: z
.enum(["manual", "auto", "disabled"])
.optional()
@@ -352,9 +353,9 @@ export namespace Config {
export const global = lazy(async () => {
let result: Info = pipe(
{},
mergeDeep(await load(path.join(Global.Path.config, "config.json"))),
mergeDeep(await load(path.join(Global.Path.config, "opencode.json"))),
mergeDeep(await load(path.join(Global.Path.config, "opencode.jsonc"))),
mergeDeep(await loadFile(path.join(Global.Path.config, "config.json"))),
mergeDeep(await loadFile(path.join(Global.Path.config, "opencode.json"))),
mergeDeep(await loadFile(path.join(Global.Path.config, "opencode.jsonc"))),
)
await import(path.join(Global.Path.config, "config"), {
@@ -375,25 +376,26 @@ export namespace Config {
return result
})
async function load(configPath: string): Promise<Info> {
let text = await Bun.file(configPath)
async function loadFile(filepath: string): Promise<Info> {
log.info("loading", { path: filepath })
let text = await Bun.file(filepath)
.text()
.catch((err) => {
if (err.code === "ENOENT") return
throw new JsonError({ path: configPath }, { cause: err })
throw new JsonError({ path: filepath }, { cause: err })
})
if (!text) return {}
return loadRaw(text, configPath)
return load(text, filepath)
}
async function loadRaw(text: string, configPath: string) {
async function load(text: string, filepath: string) {
text = text.replace(/\{env:([^}]+)\}/g, (_, varName) => {
return process.env[varName] || ""
})
const fileMatches = text.match(/\{file:[^}]+\}/g)
if (fileMatches) {
const configDir = path.dirname(configPath)
const configDir = path.dirname(filepath)
const lines = text.split("\n")
for (const match of fileMatches) {
@@ -428,7 +430,7 @@ export namespace Config {
.join("\n")
throw new JsonError({
path: configPath,
path: filepath,
message: `\n--- JSONC Input ---\n${text}\n--- Errors ---\n${errorDetails}\n--- End ---`,
})
}
@@ -437,11 +439,21 @@ export namespace Config {
if (parsed.success) {
if (!parsed.data.$schema) {
parsed.data.$schema = "https://opencode.ai/config.json"
await Bun.write(configPath, JSON.stringify(parsed.data, null, 2))
await Bun.write(filepath, JSON.stringify(parsed.data, null, 2))
}
return parsed.data
const data = parsed.data
if (data.plugin) {
for (let i = 0; i < data.plugin?.length; i++) {
const plugin = data.plugin[i]
if (typeof plugin === "string") {
data.plugin[i] = path.resolve(path.dirname(filepath), plugin)
}
}
}
return data
}
throw new InvalidError({ path: configPath, issues: parsed.error.issues })
throw new InvalidError({ path: filepath, issues: parsed.error.issues })
}
export const JsonError = NamedError.create(
"ConfigJsonError",
+14 -1
View File
@@ -3,6 +3,7 @@ import { z } from "zod"
import { Bus } from "../bus"
import { Log } from "../util/log"
import { Identifier } from "../id/id"
import { Plugin } from "../plugin"
export namespace Permission {
const log = Log.create({ service: "permission" })
@@ -67,7 +68,7 @@ export namespace Permission {
},
)
export function ask(input: {
export async function ask(input: {
type: Info["type"]
title: Info["title"]
pattern?: Info["pattern"]
@@ -95,6 +96,18 @@ export namespace Permission {
created: Date.now(),
},
}
switch (
await Plugin.trigger("permission.ask", info, {
status: "ask",
}).then((x) => x.status)
) {
case "deny":
throw new RejectedError(info.sessionID, info.id, info.callID)
case "allow":
return
}
pending[input.sessionID] = pending[input.sessionID] || {}
return new Promise<void>((resolve, reject) => {
pending[input.sessionID][info.id] = {
+85
View File
@@ -0,0 +1,85 @@
import type { Hooks, Plugin as PluginInstance } from "@opencode-ai/plugin"
import { App } from "../app/app"
import { Config } from "../config/config"
import { Bus } from "../bus"
import { Log } from "../util/log"
import { createOpencodeClient } from "@opencode-ai/sdk"
import { Server } from "../server/server"
import { pathOr } from "remeda"
export namespace Plugin {
const log = Log.create({ service: "plugin" })
const state = App.state("plugin", async (app) => {
const client = createOpencodeClient({
baseUrl: "http://localhost:4096",
fetch: async (...args) => Server.app().fetch(...args),
})
const config = await Config.get()
const hooks = []
for (const plugin of config.plugin ?? []) {
log.info("loading plugin", { path: plugin })
const mod = await import(plugin)
for (const [_name, fn] of Object.entries<PluginInstance>(mod)) {
const init = await fn({
client,
app,
$: Bun.$,
})
hooks.push(init)
}
}
return {
hooks,
}
})
type Path<T, Prefix extends string = ""> = T extends object
? {
[K in keyof T]: K extends string
? T[K] extends Function | undefined
? `${Prefix}${K}`
: Path<T[K], `${Prefix}${K}.`>
: never
}[keyof T]
: never
export type FunctionFromKey<T, P extends Path<T>> = P extends `${infer K}.${infer R}`
? K extends keyof T
? R extends Path<T[K]>
? FunctionFromKey<T[K], R>
: never
: never
: P extends keyof T
? T[P]
: never
export async function trigger<
Name extends Path<Required<Hooks>>,
Input = Parameters<FunctionFromKey<Required<Hooks>, Name>>[0],
Output = Parameters<FunctionFromKey<Required<Hooks>, Name>>[1],
>(fn: Name, input: Input, output: Output): Promise<Output> {
if (!fn) return output
const path = fn.split(".")
for (const hook of await state().then((x) => x.hooks)) {
// @ts-expect-error
const fn = pathOr(hook, path, undefined)
if (!fn) continue
// @ts-expect-error
await fn(input, output)
}
return output
}
export function init() {
Bus.subscribeAll(async (input) => {
const hooks = await state().then((x) => x.hooks)
for (const hook of hooks) {
hook["event"]?.({
event: input,
})
}
})
}
}
+18 -14
View File
@@ -97,7 +97,7 @@ export namespace Provider {
Array.isArray(msg.content) && msg.content.some((part: any) => part.type === "image_url"),
)
}
} catch { }
} catch {}
const headers: Record<string, string> = {
...init.headers,
...copilot.HEADERS,
@@ -283,26 +283,26 @@ export namespace Provider {
cost:
!model.cost && !existing?.cost
? {
input: 0,
output: 0,
cache_read: 0,
cache_write: 0,
}
input: 0,
output: 0,
cache_read: 0,
cache_write: 0,
}
: {
cache_read: 0,
cache_write: 0,
...existing?.cost,
...model.cost,
},
cache_read: 0,
cache_write: 0,
...existing?.cost,
...model.cost,
},
options: {
...existing?.options,
...model.options,
},
limit: model.limit ??
existing?.limit ?? {
context: 0,
output: 0,
},
context: 0,
output: 0,
},
}
parsed.models[modelID] = parsedModel
}
@@ -386,6 +386,10 @@ export namespace Provider {
})
}
export async function getProvider(providerID: string) {
return state().then((s) => s.providers[providerID])
}
export async function getModel(providerID: string, modelID: string) {
const key = `${providerID}/${modelID}`
const s = await state()
+3 -2
View File
@@ -19,6 +19,7 @@ import { MessageV2 } from "../session/message-v2"
import { Mode } from "../session/mode"
import { callTui, TuiRoute } from "./tui"
import { Permission } from "../permission"
import { lazy } from "../util/lazy"
const ERRORS = {
400: {
@@ -48,7 +49,7 @@ export namespace Server {
Connected: Bus.event("server.connected", z.object({})),
}
function app() {
export const app = lazy(() => {
const app = new Hono()
const result = app
@@ -1022,7 +1023,7 @@ export namespace Server {
.route("/tui/control", TuiRoute)
return result
}
})
export async function openapi() {
const a = app()
+46 -5
View File
@@ -41,6 +41,7 @@ import { LSP } from "../lsp"
import { ReadTool } from "../tool/read"
import { mergeDeep, pipe, splitWhen } from "remeda"
import { ToolRegistry } from "../tool/registry"
import { Plugin } from "../plugin"
export namespace Session {
const log = Log.create({ service: "session" })
@@ -571,7 +572,14 @@ export namespace Session {
text: PROMPT_PLAN,
synthetic: true,
})
await Plugin.trigger(
"chat.message",
{},
{
message: userMsg,
parts: userParts,
},
)
await updateMessage(userMsg)
for (const part of userParts) {
await updatePart(part)
@@ -716,6 +724,17 @@ export namespace Session {
description: item.description,
inputSchema: item.parameters as ZodSchema,
async execute(args, options) {
await Plugin.trigger(
"tool.execute.before",
{
tool: item.id,
sessionID: input.sessionID,
callID: options.toolCallId,
},
{
args,
},
)
await processor.track(options.toolCallId)
const result = await item.execute(args, {
sessionID: input.sessionID,
@@ -740,6 +759,15 @@ export namespace Session {
}
},
})
await Plugin.trigger(
"tool.execute.after",
{
tool: item.id,
sessionID: input.sessionID,
callID: options.toolCallId,
},
result,
)
return result
},
toModelOutput(result) {
@@ -776,6 +804,21 @@ export namespace Session {
tools[key] = item
}
const params = {
temperature: model.info.temperature
? (mode.temperature ?? ProviderTransform.temperature(input.providerID, input.modelID))
: undefined,
topP: mode.topP ?? ProviderTransform.topP(input.providerID, input.modelID),
}
await Plugin.trigger(
"chat.params",
{
model: model.info,
provider: await Provider.getProvider(input.providerID),
message: userMsg,
},
params,
)
const stream = streamText({
onError(e) {
log.error("streamText error", {
@@ -835,6 +878,8 @@ export namespace Session {
providerOptions: {
[input.providerID]: model.info.options,
},
temperature: params.temperature,
topP: params.topP,
messages: [
...system.map(
(x): ModelMessage => ({
@@ -844,10 +889,6 @@ export namespace Session {
),
...MessageV2.toModelMessage(msgs),
],
temperature: model.info.temperature
? (mode.temperature ?? ProviderTransform.temperature(input.providerID, input.modelID))
: undefined,
topP: mode.topP ?? ProviderTransform.topP(input.providerID, input.modelID),
tools: model.info.tool_call === false ? undefined : tools,
model: wrapLanguageModel({
model: model.language,
+5 -1
View File
@@ -1,5 +1,9 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@tsconfig/bun/tsconfig.json",
"compilerOptions": {}
"compilerOptions": {
"customConditions": [
"development"
]
}
}
+1
View File
@@ -0,0 +1 @@
dist
+21
View File
@@ -0,0 +1,21 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/plugin",
"version": "0.0.0",
"type": "module",
"scripts": {
"typecheck": "tsc --noEmit"
},
"exports": {
".": "./src/index.ts"
},
"files": [
"dist"
],
"devDependencies": {
"typescript": "catalog:",
"@hey-api/openapi-ts": "0.80.1",
"@tsconfig/node22": "catalog:",
"@opencode-ai/sdk": "workspace:*"
}
}
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/env bun
const dir = new URL("..", import.meta.url).pathname
process.chdir(dir)
import { $ } from "bun"
const snapshot = process.env["OPENCODE_SNAPSHOT"] === "true"
await $`bun tsc`
if (snapshot) {
await $`bun publish --tag snapshot --access public`
await $`git checkout package.json`
}
if (!snapshot) {
await $`bun publish --access public`
}
+7
View File
@@ -0,0 +1,7 @@
import { Plugin } from "./index"
export const ExamplePlugin: Plugin = async ({ app, client }) => {
return {
permission: {},
}
}
+56
View File
@@ -0,0 +1,56 @@
import type { Event, createOpencodeClient, App, Model, Provider, Permission, UserMessage, Part } from "@opencode-ai/sdk"
import { $ } from "bun"
export type PluginInput = {
client: ReturnType<typeof createOpencodeClient>
app: App
$: $
}
export type Plugin = (input: PluginInput) => Promise<Hooks>
export interface Hooks {
event?: (input: { event: Event }) => Promise<void>
chat?: {
/**
* Called when a new message is received
*/
message?: (input: {}, output: { message: UserMessage; parts: Part[] }) => Promise<void>
/**
* Modify parameters sent to LLM
*/
params?: (
input: { model: Model; provider: Provider; message: UserMessage },
output: { temperature: number; topP: number },
) => Promise<void>
}
permission?: {
/**
* Called when a permission is asked
*/
ask?: (input: Permission, output: { status: "ask" | "deny" | "allow" }) => Promise<void>
}
tool?: {
execute?: {
/**
* Called before a tool is executed
*/
before?: (
input: { tool: string; sessionID: string; callID: string },
output: {
args: any
},
) => Promise<void>
/**
* Called after a tool is executed
*/
after?: (
input: { tool: string; sessionID: string; callID: string },
output: {
title: string
output: string
metadata: any
},
) => Promise<void>
}
}
}
+16
View File
@@ -0,0 +1,16 @@
{
"$schema": "https://json.schemastore.org/tsconfig.json",
"extends": "@tsconfig/node22/tsconfig.json",
"compilerOptions": {
"outDir": "dist",
"module": "preserve",
"declaration": true,
"moduleResolution": "bundler",
"customConditions": [
"development"
]
},
"include": [
"src"
]
}
+8 -2
View File
@@ -1,10 +1,16 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@opencode-ai/sdk",
"version": "0.0.0",
"version": "0.0.0-202508022053",
"type": "module",
"scripts": {
"typecheck": "tsc --noEmit"
},
"exports": {
".": "./dist/index.js"
".": {
"development": "./src/index.ts",
"import": "./dist/index.js"
}
},
"files": [
"dist"
+1
View File
@@ -36,6 +36,7 @@ await createClient({
},
],
})
await $`bun prettier --write src/gen`
await $`rm -rf dist`
await $`bun tsc`
-7
View File
@@ -5,20 +5,13 @@ process.chdir(dir)
import { $ } from "bun"
const version = process.env["OPENCODE_VERSION"]
if (!version) {
throw new Error("OPENCODE_VERSION is required")
}
await import("./generate")
const snapshot = process.env["OPENCODE_SNAPSHOT"] === "true"
await $`bun pm version --allow-same-version --no-git-tag-version ${version}`
if (snapshot) {
await $`bun publish --tag snapshot`
}
if (!snapshot) {
await $`bun publish`
}
await $`bun pm version 0.0.0 --no-git-tag-version`
+10 -6
View File
@@ -1,7 +1,7 @@
// 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';
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
@@ -11,8 +11,12 @@ import { type Config, type ClientOptions as DefaultClientOptions, createClient,
* `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 type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> = (
override?: Config<DefaultClientOptions & T>,
) => Config<Required<DefaultClientOptions> & T>
export const client = createClient(createConfig<ClientOptions>({
baseUrl: 'http://localhost:4096'
}));
export const client = createClient(
createConfig<ClientOptions>({
baseUrl: "http://localhost:4096",
}),
)
+70 -80
View File
@@ -1,4 +1,4 @@
import type { Client, Config, RequestOptions } from './types';
import type { Client, Config, RequestOptions } from "./types"
import {
buildUrl,
createConfig,
@@ -7,189 +7,179 @@ import {
mergeConfigs,
mergeHeaders,
setAuthParams,
} from './utils';
} from "./utils"
type ReqInit = Omit<RequestInit, 'body' | 'headers'> & {
body?: any;
headers: ReturnType<typeof mergeHeaders>;
};
type ReqInit = Omit<RequestInit, "body" | "headers"> & {
body?: any
headers: ReturnType<typeof mergeHeaders>
}
export const createClient = (config: Config = {}): Client => {
let _config = mergeConfigs(createConfig(), config);
let _config = mergeConfigs(createConfig(), config)
const getConfig = (): Config => ({ ..._config });
const getConfig = (): Config => ({ ..._config })
const setConfig = (config: Config): Config => {
_config = mergeConfigs(_config, config);
return getConfig();
};
_config = mergeConfigs(_config, config)
return getConfig()
}
const interceptors = createInterceptors<
Request,
Response,
unknown,
RequestOptions
>();
const interceptors = createInterceptors<Request, Response, unknown, RequestOptions>()
const request: Client['request'] = async (options) => {
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);
await opts.requestValidator(opts)
}
if (opts.body && opts.bodySerializer) {
opts.body = opts.bodySerializer(opts.body);
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');
if (opts.body === undefined || opts.body === "") {
opts.headers.delete("Content-Type")
}
const url = buildUrl(opts);
const url = buildUrl(opts)
const requestInit: ReqInit = {
redirect: 'follow',
redirect: "follow",
...opts,
};
}
let request = new Request(url, requestInit);
let request = new Request(url, requestInit)
for (const fn of interceptors.request._fns) {
if (fn) {
request = await fn(request, opts);
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);
const _fetch = opts.fetch!
let response = await _fetch(request)
for (const fn of interceptors.response._fns) {
if (fn) {
response = await fn(response, request, opts);
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'
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';
(opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json"
let data: any;
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'
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 (parseAs === "json") {
if (opts.responseValidator) {
await opts.responseValidator(data);
await opts.responseValidator(data)
}
if (opts.responseTransformer) {
data = await opts.responseTransformer(data);
data = await opts.responseTransformer(data)
}
}
return opts.responseStyle === 'data'
return opts.responseStyle === "data"
? data
: {
data,
...result,
};
}
}
const textError = await response.text();
let jsonError: unknown;
const textError = await response.text()
let jsonError: unknown
try {
jsonError = JSON.parse(textError);
jsonError = JSON.parse(textError)
} catch {
// noop
}
const error = jsonError ?? textError;
let finalError = error;
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 = (await fn(error, response, request, opts)) as string
}
}
finalError = finalError || ({} as string);
finalError = finalError || ({} as string)
if (opts.throwOnError) {
throw finalError;
throw finalError
}
// TODO: we probably want to return error and improve types
return opts.responseStyle === 'data'
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' }),
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' }),
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' }),
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' }),
};
};
trace: (options) => request({ ...options, method: "TRACE" }),
}
}
+7 -11
View File
@@ -1,12 +1,8 @@
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 { 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,
@@ -18,5 +14,5 @@ export type {
RequestResult,
ResponseStyle,
TDataShape,
} from './types';
export { createConfig, mergeHeaders } from './utils';
} from "./types"
export { createConfig, mergeHeaders } from "./utils"
+67 -98
View File
@@ -1,33 +1,30 @@
import type { Auth } from '../core/auth';
import type {
Client as CoreClient,
Config as CoreConfig,
} from '../core/types';
import type { Middleware } from './utils';
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 type ResponseStyle = "data" | "fields"
export interface Config<T extends ClientOptions = ClientOptions>
extends Omit<RequestInit, 'body' | 'headers' | 'method'>,
extends Omit<RequestInit, "body" | "headers" | "method">,
CoreConfig {
/**
* Base URL for all requests made by this client.
*/
baseUrl?: T['baseUrl'];
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>;
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;
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.
@@ -36,135 +33,118 @@ export interface Config<T extends ClientOptions = ClientOptions>
*
* @default 'auto'
*/
parseAs?:
| 'arrayBuffer'
| 'auto'
| 'blob'
| 'formData'
| 'json'
| 'stream'
| 'text';
parseAs?: "arrayBuffer" | "auto" | "blob" | "formData" | "json" | "stream" | "text"
/**
* Should we return only data or multiple fields (data, error, response, etc.)?
*
* @default 'fields'
*/
responseStyle?: ResponseStyle;
responseStyle?: ResponseStyle
/**
* Throw an error instead of returning it in the response?
*
* @default false
*/
throwOnError?: T['throwOnError'];
throwOnError?: T["throwOnError"]
}
export interface RequestOptions<
TResponseStyle extends ResponseStyle = 'fields',
TResponseStyle extends ResponseStyle = "fields",
ThrowOnError extends boolean = boolean,
Url extends string = string,
> extends Config<{
responseStyle: TResponseStyle;
throwOnError: ThrowOnError;
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>;
body?: unknown
path?: Record<string, unknown>
query?: Record<string, unknown>
/**
* Security mechanism(s) to use for the request.
*/
security?: ReadonlyArray<Auth>;
url: Url;
security?: ReadonlyArray<Auth>
url: Url
}
export type RequestResult<
TData = unknown,
TError = unknown,
ThrowOnError extends boolean = boolean,
TResponseStyle extends ResponseStyle = 'fields',
TResponseStyle extends ResponseStyle = "fields",
> = ThrowOnError extends true
? Promise<
TResponseStyle extends 'data'
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;
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
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: TData extends Record<string, unknown> ? TData[keyof TData] : TData
error: undefined
}
| {
data: undefined;
error: TError extends Record<string, unknown>
? TError[keyof TError]
: TError;
data: undefined
error: TError extends Record<string, unknown> ? TError[keyof TError] : TError
}
) & {
request: Request;
response: Response;
request: Request
response: Response
}
>;
>
export interface ClientOptions {
baseUrl?: string;
responseStyle?: ResponseStyle;
throwOnError?: boolean;
baseUrl?: string
responseStyle?: ResponseStyle
throwOnError?: boolean
}
type MethodFn = <
TData = unknown,
TError = unknown,
ThrowOnError extends boolean = false,
TResponseStyle extends ResponseStyle = 'fields',
TResponseStyle extends ResponseStyle = "fields",
>(
options: Omit<RequestOptions<TResponseStyle, ThrowOnError>, 'method'>,
) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>;
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',
TResponseStyle extends ResponseStyle = "fields",
>(
options: Omit<RequestOptions<TResponseStyle, ThrowOnError>, 'method'> &
Pick<Required<RequestOptions<TResponseStyle, ThrowOnError>>, 'method'>,
) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>;
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;
body?: unknown
path?: Record<string, unknown>
query?: Record<string, unknown>
url: string
},
>(
options: Pick<TData, 'url'> & Options<TData>,
) => string;
options: Pick<TData, "url"> & Options<TData>,
) => string
export type Client = CoreClient<RequestFn, Config, MethodFn, BuildUrlFn> & {
interceptors: Middleware<Request, Response, unknown, RequestOptions>;
};
interceptors: Middleware<Request, Response, unknown, RequestOptions>
}
/**
* The `createClientConfig()` function will be called on client initialization
@@ -176,47 +156,36 @@ export type Client = CoreClient<RequestFn, Config, MethodFn, BuildUrlFn> & {
*/
export type CreateClientConfig<T extends ClientOptions = ClientOptions> = (
override?: Config<ClientOptions & T>,
) => Config<Required<ClientOptions> & T>;
) => Config<Required<ClientOptions> & T>
export interface TDataShape {
body?: unknown;
headers?: unknown;
path?: unknown;
query?: unknown;
url: string;
body?: unknown
headers?: unknown
path?: unknown
query?: unknown
url: string
}
type OmitKeys<T, K> = Pick<T, Exclude<keyof T, K>>;
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'>;
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',
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'> &
? OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, "body" | "headers" | "url"> & TData
: OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, "body" | "url"> &
TData &
Pick<RequestOptions<TResponseStyle, ThrowOnError>, 'headers'>
Pick<RequestOptions<TResponseStyle, ThrowOnError>, "headers">
: TData extends { headers?: any }
? OmitKeys<
RequestOptions<TResponseStyle, ThrowOnError>,
'headers' | 'url'
> &
? OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, "headers" | "url"> &
TData &
Pick<RequestOptions<TResponseStyle, ThrowOnError>, 'body'>
: OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, 'url'> & TData;
Pick<RequestOptions<TResponseStyle, ThrowOnError>, "body">
: OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, "url"> & TData
+154 -198
View File
@@ -1,64 +1,54 @@
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';
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;
path: Record<string, unknown>
url: string
}
const PATH_PARAM_RE = /\{[^{}]+\}/g;
const PATH_PARAM_RE = /\{[^{}]+\}/g
type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited';
type MatrixStyle = 'label' | 'matrix' | 'simple';
type ArraySeparatorStyle = ArrayStyle | MatrixStyle;
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);
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';
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.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';
if (name.startsWith(".")) {
name = name.substring(1)
style = "label"
} else if (name.startsWith(";")) {
name = name.substring(1)
style = "matrix"
}
const value = path[name];
const value = path[name]
if (value === undefined || value === null) {
continue;
continue
}
if (Array.isArray(value)) {
url = url.replace(
match,
serializeArrayParam({ explode, name, style, value }),
);
continue;
url = url.replace(match, serializeArrayParam({ explode, name, style, value }))
continue
}
if (typeof value === 'object') {
if (typeof value === "object") {
url = url.replace(
match,
serializeObjectParam({
@@ -68,43 +58,37 @@ const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => {
value: value as Record<string, unknown>,
valueOnly: true,
}),
);
continue;
)
continue
}
if (style === 'matrix') {
if (style === "matrix") {
url = url.replace(
match,
`;${serializePrimitiveParam({
name,
value: value as string,
})}`,
);
continue;
)
continue
}
const replaceValue = encodeURIComponent(
style === 'label' ? `.${value as string}` : (value as string),
);
url = url.replace(match, replaceValue);
const replaceValue = encodeURIComponent(style === "label" ? `.${value as string}` : (value as string))
url = url.replace(match, replaceValue)
}
}
return url;
};
return url
}
export const createQuerySerializer = <T = unknown>({
allowReserved,
array,
object,
}: QuerySerializerOptions = {}) => {
export const createQuerySerializer = <T = unknown>({ allowReserved, array, object }: QuerySerializerOptions = {}) => {
const querySerializer = (queryParams: T) => {
const search: string[] = [];
if (queryParams && typeof queryParams === 'object') {
const search: string[] = []
if (queryParams && typeof queryParams === "object") {
for (const name in queryParams) {
const value = queryParams[name];
const value = queryParams[name]
if (value === undefined || value === null) {
continue;
continue
}
if (Array.isArray(value)) {
@@ -112,129 +96,120 @@ export const createQuerySerializer = <T = unknown>({
allowReserved,
explode: true,
name,
style: 'form',
style: "form",
value,
...array,
});
if (serializedArray) search.push(serializedArray);
} else if (typeof value === 'object') {
})
if (serializedArray) search.push(serializedArray)
} else if (typeof value === "object") {
const serializedObject = serializeObjectParam({
allowReserved,
explode: true,
name,
style: 'deepObject',
style: "deepObject",
value: value as Record<string, unknown>,
...object,
});
if (serializedObject) search.push(serializedObject);
})
if (serializedObject) search.push(serializedObject)
} else {
const serializedPrimitive = serializePrimitiveParam({
allowReserved,
name,
value: value as string,
});
if (serializedPrimitive) search.push(serializedPrimitive);
})
if (serializedPrimitive) search.push(serializedPrimitive)
}
}
}
return search.join('&');
};
return querySerializer;
};
return search.join("&")
}
return querySerializer
}
/**
* Infers parseAs value from provided Content-Type header.
*/
export const getParseAs = (
contentType: string | null,
): Exclude<Config['parseAs'], 'auto'> => {
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';
return "stream"
}
const cleanContent = contentType.split(';')[0]?.trim();
const cleanContent = contentType.split(";")[0]?.trim()
if (!cleanContent) {
return;
return
}
if (
cleanContent.startsWith('application/json') ||
cleanContent.endsWith('+json')
) {
return 'json';
if (cleanContent.startsWith("application/json") || cleanContent.endsWith("+json")) {
return "json"
}
if (cleanContent === 'multipart/form-data') {
return 'formData';
if (cleanContent === "multipart/form-data") {
return "formData"
}
if (
['application/', 'audio/', 'image/', 'video/'].some((type) =>
cleanContent.startsWith(type),
)
) {
return 'blob';
if (["application/", "audio/", "image/", "video/"].some((type) => cleanContent.startsWith(type))) {
return "blob"
}
if (cleanContent.startsWith('text/')) {
return 'text';
if (cleanContent.startsWith("text/")) {
return "text"
}
return;
};
return
}
export const setAuthParams = async ({
security,
...options
}: Pick<Required<RequestOptions>, 'security'> &
Pick<RequestOptions, 'auth' | 'query'> & {
headers: Headers;
}: Pick<Required<RequestOptions>, "security"> &
Pick<RequestOptions, "auth" | "query"> & {
headers: Headers
}) => {
for (const auth of security) {
const token = await getAuthToken(auth, options.auth);
const token = await getAuthToken(auth, options.auth)
if (!token) {
continue;
continue
}
const name = auth.name ?? 'Authorization';
const name = auth.name ?? "Authorization"
switch (auth.in) {
case 'query':
case "query":
if (!options.query) {
options.query = {};
options.query = {}
}
options.query[name] = token;
break;
case 'cookie':
options.headers.append('Cookie', `${name}=${token}`);
break;
case 'header':
options.query[name] = token
break
case "cookie":
options.headers.append("Cookie", `${name}=${token}`)
break
case "header":
default:
options.headers.set(name, token);
break;
options.headers.set(name, token)
break
}
return;
return
}
};
}
export const buildUrl: Client['buildUrl'] = (options) => {
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'
typeof options.querySerializer === "function"
? options.querySerializer
: createQuerySerializer(options.querySerializer),
url: options.url,
});
return url;
};
})
return url
}
export const getUrl = ({
baseUrl,
@@ -243,144 +218,125 @@ export const getUrl = ({
querySerializer,
url: _url,
}: {
baseUrl?: string;
path?: Record<string, unknown>;
query?: Record<string, unknown>;
querySerializer: QuerySerializer;
url: string;
baseUrl?: string
path?: Record<string, unknown>
query?: Record<string, unknown>
querySerializer: QuerySerializer
url: string
}) => {
const pathUrl = _url.startsWith('/') ? _url : `/${_url}`;
let url = (baseUrl ?? '') + pathUrl;
const pathUrl = _url.startsWith("/") ? _url : `/${_url}`
let url = (baseUrl ?? "") + pathUrl
if (path) {
url = defaultPathSerializer({ path, url });
url = defaultPathSerializer({ path, url })
}
let search = query ? querySerializer(query) : '';
if (search.startsWith('?')) {
search = search.substring(1);
let search = query ? querySerializer(query) : ""
if (search.startsWith("?")) {
search = search.substring(1)
}
if (search) {
url += `?${search}`;
url += `?${search}`
}
return url;
};
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);
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;
};
config.headers = mergeHeaders(a.headers, b.headers)
return config
}
export const mergeHeaders = (
...headers: Array<Required<Config>['headers'] | undefined>
): Headers => {
const mergedHeaders = new Headers();
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;
if (!header || typeof header !== "object") {
continue
}
const iterator =
header instanceof Headers ? header.entries() : Object.entries(header);
const iterator = header instanceof Headers ? header.entries() : Object.entries(header)
for (const [key, value] of iterator) {
if (value === null) {
mergedHeaders.delete(key);
mergedHeaders.delete(key)
} else if (Array.isArray(value)) {
for (const v of value) {
mergedHeaders.append(key, v as string);
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),
);
mergedHeaders.set(key, typeof value === "object" ? JSON.stringify(value) : (value as string))
}
}
}
return mergedHeaders;
};
return mergedHeaders
}
type ErrInterceptor<Err, Res, Req, Options> = (
error: Err,
response: Res,
request: Req,
options: Options,
) => Err | Promise<Err>;
) => Err | Promise<Err>
type ReqInterceptor<Req, Options> = (
request: Req,
options: Options,
) => Req | Promise<Req>;
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>;
type ResInterceptor<Res, Req, Options> = (response: Res, request: Req, options: Options) => Res | Promise<Res>
class Interceptors<Interceptor> {
_fns: (Interceptor | null)[];
_fns: (Interceptor | null)[]
constructor() {
this._fns = [];
this._fns = []
}
clear() {
this._fns = [];
this._fns = []
}
getInterceptorIndex(id: number | Interceptor): number {
if (typeof id === 'number') {
return this._fns[id] ? id : -1;
if (typeof id === "number") {
return this._fns[id] ? id : -1
} else {
return this._fns.indexOf(id);
return this._fns.indexOf(id)
}
}
exists(id: number | Interceptor) {
const index = this.getInterceptorIndex(id);
return !!this._fns[index];
const index = this.getInterceptorIndex(id)
return !!this._fns[index]
}
eject(id: number | Interceptor) {
const index = this.getInterceptorIndex(id);
const index = this.getInterceptorIndex(id)
if (this._fns[index]) {
this._fns[index] = null;
this._fns[index] = null
}
}
update(id: number | Interceptor, fn: Interceptor) {
const index = this.getInterceptorIndex(id);
const index = this.getInterceptorIndex(id)
if (this._fns[index]) {
this._fns[index] = fn;
return id;
this._fns[index] = fn
return id
} else {
return false;
return false
}
}
use(fn: Interceptor) {
this._fns = [...this._fns, fn];
return this._fns.length - 1;
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'
>;
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
@@ -388,30 +344,30 @@ 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',
style: "form",
},
object: {
explode: true,
style: 'deepObject',
style: "deepObject",
},
});
})
const defaultHeaders = {
'Content-Type': 'application/json',
};
"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',
parseAs: "auto",
querySerializer: defaultQuerySerializer,
...override,
});
})
+13 -14
View File
@@ -1,4 +1,4 @@
export type AuthToken = string | undefined;
export type AuthToken = string | undefined
export interface Auth {
/**
@@ -6,35 +6,34 @@ export interface Auth {
*
* @default 'header'
*/
in?: 'header' | 'query' | 'cookie';
in?: "header" | "query" | "cookie"
/**
* Header or query parameter name.
*
* @default 'Authorization'
*/
name?: string;
scheme?: 'basic' | 'bearer';
type: 'apiKey' | 'http';
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;
const token = typeof callback === "function" ? await callback(auth) : callback
if (!token) {
return;
return
}
if (auth.scheme === 'bearer') {
return `Bearer ${token}`;
if (auth.scheme === "bearer") {
return `Bearer ${token}`
}
if (auth.scheme === 'basic') {
return `Basic ${btoa(token)}`;
if (auth.scheme === "basic") {
return `Basic ${btoa(token)}`
}
return token;
};
return token
}
+34 -52
View File
@@ -1,88 +1,70 @@
import type {
ArrayStyle,
ObjectStyle,
SerializerOptions,
} from './pathSerializer';
import type { ArrayStyle, ObjectStyle, SerializerOptions } from "./pathSerializer"
export type QuerySerializer = (query: Record<string, unknown>) => string;
export type QuerySerializer = (query: Record<string, unknown>) => string
export type BodySerializer = (body: any) => any;
export type BodySerializer = (body: any) => any
export interface QuerySerializerOptions {
allowReserved?: boolean;
array?: SerializerOptions<ArrayStyle>;
object?: SerializerOptions<ObjectStyle>;
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);
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));
data.append(key, JSON.stringify(value))
}
};
}
const serializeUrlSearchParamsPair = (
data: URLSearchParams,
key: string,
value: unknown,
): void => {
if (typeof value === 'string') {
data.append(key, 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));
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();
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;
return
}
if (Array.isArray(value)) {
value.forEach((v) => serializeFormDataPair(data, key, v));
value.forEach((v) => serializeFormDataPair(data, key, v))
} else {
serializeFormDataPair(data, key, value);
serializeFormDataPair(data, key, value)
}
});
})
return data;
return data
},
};
}
export const jsonBodySerializer = {
bodySerializer: <T>(body: T): string =>
JSON.stringify(body, (_key, value) =>
typeof value === 'bigint' ? value.toString() : value,
),
};
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();
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;
return
}
if (Array.isArray(value)) {
value.forEach((v) => serializeUrlSearchParamsPair(data, key, v));
value.forEach((v) => serializeUrlSearchParamsPair(data, key, v))
} else {
serializeUrlSearchParamsPair(data, key, value);
serializeUrlSearchParamsPair(data, key, value)
}
});
})
return data.toString();
return data.toString()
},
};
}
+56 -65
View File
@@ -1,142 +1,133 @@
type Slot = 'body' | 'headers' | 'path' | 'query';
type Slot = "body" | "headers" | "path" | "query"
export type Field =
| {
in: Exclude<Slot, 'body'>;
in: Exclude<Slot, "body">
/**
* Field name. This is the name we want the user to see and use.
*/
key: string;
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;
map?: string
}
| {
in: Extract<Slot, 'body'>;
in: Extract<Slot, "body">
/**
* Key isn't required for bodies.
*/
key?: string;
map?: string;
};
key?: string
map?: string
}
export interface Fields {
allowExtra?: Partial<Record<Slot, boolean>>;
args?: ReadonlyArray<Field>;
allowExtra?: Partial<Record<Slot, boolean>>
args?: ReadonlyArray<Field>
}
export type FieldsConfig = ReadonlyArray<Field | Fields>;
export type FieldsConfig = ReadonlyArray<Field | Fields>
const extraPrefixesMap: Record<string, Slot> = {
$body_: 'body',
$headers_: 'headers',
$path_: 'path',
$query_: 'query',
};
const extraPrefixes = Object.entries(extraPrefixesMap);
$body_: "body",
$headers_: "headers",
$path_: "path",
$query_: "query",
}
const extraPrefixes = Object.entries(extraPrefixesMap)
type KeyMap = Map<
string,
{
in: Slot;
map?: string;
in: Slot
map?: string
}
>;
>
const buildKeyMap = (fields: FieldsConfig, map?: KeyMap): KeyMap => {
if (!map) {
map = new Map();
map = new Map()
}
for (const config of fields) {
if ('in' in config) {
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);
buildKeyMap(config.args, map)
}
}
return map;
};
return map
}
interface Params {
body: unknown;
headers: Record<string, unknown>;
path: Record<string, unknown>;
query: Record<string, unknown>;
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];
if (value && typeof value === "object" && !Object.keys(value).length) {
delete params[slot as Slot]
}
}
};
}
export const buildClientParams = (
args: ReadonlyArray<unknown>,
fields: FieldsConfig,
) => {
export const buildClientParams = (args: ReadonlyArray<unknown>, fields: FieldsConfig) => {
const params: Params = {
body: {},
headers: {},
path: {},
query: {},
};
}
const map = buildKeyMap(fields);
const map = buildKeyMap(fields)
let config: FieldsConfig[number] | undefined;
let config: FieldsConfig[number] | undefined
for (const [index, arg] of args.entries()) {
if (fields[index]) {
config = fields[index];
config = fields[index]
}
if (!config) {
continue;
continue
}
if ('in' in config) {
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;
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;
params.body = arg
}
} else {
for (const [key, value] of Object.entries(arg ?? {})) {
const field = map.get(key);
const field = map.get(key)
if (field) {
const name = field.map || key;
(params[field.in] as Record<string, unknown>)[name] = value;
const name = field.map || key
;(params[field.in] as Record<string, unknown>)[name] = value
} else {
const extra = extraPrefixes.find(([prefix]) =>
key.startsWith(prefix),
);
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;
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 ?? {},
)) {
for (const [slot, allowed] of Object.entries(config.allowExtra ?? {})) {
if (allowed) {
(params[slot as Slot] as Record<string, unknown>)[key] = value;
break;
;(params[slot as Slot] as Record<string, unknown>)[key] = value
break
}
}
}
@@ -145,7 +136,7 @@ export const buildClientParams = (
}
}
stripEmptySlots(params);
stripEmptySlots(params)
return params;
};
return params
}
+80 -94
View File
@@ -1,68 +1,66 @@
interface SerializeOptions<T>
extends SerializePrimitiveOptions,
SerializerOptions<T> {}
interface SerializeOptions<T> extends SerializePrimitiveOptions, SerializerOptions<T> {}
interface SerializePrimitiveOptions {
allowReserved?: boolean;
name: string;
allowReserved?: boolean
name: string
}
export interface SerializerOptions<T> {
/**
* @default true
*/
explode: boolean;
style: T;
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;
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;
value: string
}
export const separatorArrayExplode = (style: ArraySeparatorStyle) => {
switch (style) {
case 'label':
return '.';
case 'matrix':
return ';';
case 'simple':
return ',';
case "label":
return "."
case "matrix":
return ";"
case "simple":
return ","
default:
return '&';
return "&"
}
};
}
export const separatorArrayNoExplode = (style: ArraySeparatorStyle) => {
switch (style) {
case 'form':
return ',';
case 'pipeDelimited':
return '|';
case 'spaceDelimited':
return '%20';
case "form":
return ","
case "pipeDelimited":
return "|"
case "spaceDelimited":
return "%20"
default:
return ',';
return ","
}
};
}
export const separatorObjectExplode = (style: ObjectSeparatorStyle) => {
switch (style) {
case 'label':
return '.';
case 'matrix':
return ';';
case 'simple':
return ',';
case "label":
return "."
case "matrix":
return ";"
case "simple":
return ","
default:
return '&';
return "&"
}
};
}
export const serializeArrayParam = ({
allowReserved,
@@ -71,60 +69,54 @@ export const serializeArrayParam = ({
style,
value,
}: SerializeOptions<ArraySeparatorStyle> & {
value: unknown[];
value: unknown[]
}) => {
if (!explode) {
const joinedValues = (
allowReserved ? value : value.map((v) => encodeURIComponent(v as string))
).join(separatorArrayNoExplode(style));
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;
case "label":
return `.${joinedValues}`
case "matrix":
return `;${name}=${joinedValues}`
case "simple":
return joinedValues
default:
return `${name}=${joinedValues}`;
return `${name}=${joinedValues}`
}
}
const separator = separatorArrayExplode(style);
const separator = separatorArrayExplode(style)
const joinedValues = value
.map((v) => {
if (style === 'label' || style === 'simple') {
return allowReserved ? v : encodeURIComponent(v as string);
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;
};
.join(separator)
return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues
}
export const serializePrimitiveParam = ({
allowReserved,
name,
value,
}: SerializePrimitiveParam) => {
export const serializePrimitiveParam = ({ allowReserved, name, value }: SerializePrimitiveParam) => {
if (value === undefined || value === null) {
return '';
return ""
}
if (typeof value === 'object') {
if (typeof value === "object") {
throw new Error(
'Deeply-nested arrays/objects arent supported. Provide your own `querySerializer()` to handle these.',
);
"Deeply-nested arrays/objects arent supported. Provide your own `querySerializer()` to handle these.",
)
}
return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
};
return `${name}=${allowReserved ? value : encodeURIComponent(value)}`
}
export const serializeObjectParam = ({
allowReserved,
@@ -134,46 +126,40 @@ export const serializeObjectParam = ({
value,
valueOnly,
}: SerializeOptions<ObjectSeparatorStyle> & {
value: Record<string, unknown> | Date;
valueOnly?: boolean;
value: Record<string, unknown> | Date
valueOnly?: boolean
}) => {
if (value instanceof Date) {
return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`
}
if (style !== 'deepObject' && !explode) {
let values: string[] = [];
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(',');
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}`;
case "form":
return `${name}=${joinedValues}`
case "label":
return `.${joinedValues}`
case "matrix":
return `;${name}=${joinedValues}`
default:
return joinedValues;
return joinedValues
}
}
const separator = separatorObjectExplode(style);
const separator = separatorObjectExplode(style)
const joinedValues = Object.entries(value)
.map(([key, v]) =>
serializePrimitiveParam({
allowReserved,
name: style === 'deepObject' ? `${name}[${key}]` : key,
name: style === "deepObject" ? `${name}[${key}]` : key,
value: v as string,
}),
)
.join(separator);
return style === 'label' || style === 'matrix'
? separator + joinedValues
: joinedValues;
};
.join(separator)
return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues
}
+28 -57
View File
@@ -1,32 +1,23 @@
import type { Auth, AuthToken } from './auth';
import type {
BodySerializer,
QuerySerializer,
QuerySerializerOptions,
} from './bodySerializer';
import type { Auth, AuthToken } from "./auth"
import type { BodySerializer, QuerySerializer, QuerySerializerOptions } from "./bodySerializer"
export interface Client<
RequestFn = never,
Config = unknown,
MethodFn = never,
BuildUrlFn = never,
> {
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;
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 {
@@ -34,12 +25,12 @@ 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;
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;
bodySerializer?: BodySerializer | null
/**
* An object containing any HTTP headers that you want to pre-populate your
* `Headers` object with.
@@ -47,32 +38,14 @@ export interface Config {
* {@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
>;
| 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';
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
@@ -83,24 +56,24 @@ export interface Config {
*
* {@link https://swagger.io/docs/specification/serialization/#query View examples}
*/
querySerializer?: QuerySerializer | QuerySerializerOptions;
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>;
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>;
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>;
responseValidator?: (data: unknown) => Promise<unknown>
}
type IsExactlyNeverOrNeverUndefined<T> = [T] extends [never]
@@ -109,10 +82,8 @@ type IsExactlyNeverOrNeverUndefined<T> = [T] extends [never]
? [undefined] extends [T]
? false
: true
: false;
: false
export type OmitNever<T extends Record<string, unknown>> = {
[K in keyof T as IsExactlyNeverOrNeverUndefined<T[K]> extends true
? never
: K]: T[K];
};
[K in keyof T as IsExactlyNeverOrNeverUndefined<T[K]> extends true ? never : K]: T[K]
}
+473 -396
View File
@@ -1,426 +1,503 @@
// 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, SessionMessageData, SessionMessageResponses, SessionRevertData, SessionRevertResponses, SessionUnrevertData, SessionUnrevertResponses, PostSessionByIdPermissionsByPermissionIdData, PostSessionByIdPermissionsByPermissionIdResponses, ConfigProvidersData, ConfigProvidersResponses, FindTextData, FindTextResponses, FindFilesData, FindFilesResponses, FindSymbolsData, FindSymbolsResponses, FileReadData, FileReadResponses, FileStatusData, FileStatusResponses, AppLogData, AppLogResponses, AppModesData, AppModesResponses, TuiAppendPromptData, TuiAppendPromptResponses, TuiOpenHelpData, TuiOpenHelpResponses, TuiOpenSessionsData, TuiOpenSessionsResponses, TuiOpenThemesData, TuiOpenThemesResponses, TuiOpenModelsData, TuiOpenModelsResponses, TuiSubmitPromptData, TuiSubmitPromptResponses, TuiClearPromptData, TuiClearPromptResponses, TuiExecuteCommandData, TuiExecuteCommandResponses } from './types.gen';
import { client as _heyApiClient } from './client.gen';
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,
SessionMessageData,
SessionMessageResponses,
SessionRevertData,
SessionRevertResponses,
SessionUnrevertData,
SessionUnrevertResponses,
PostSessionByIdPermissionsByPermissionIdData,
PostSessionByIdPermissionsByPermissionIdResponses,
ConfigProvidersData,
ConfigProvidersResponses,
FindTextData,
FindTextResponses,
FindFilesData,
FindFilesResponses,
FindSymbolsData,
FindSymbolsResponses,
FileReadData,
FileReadResponses,
FileStatusData,
FileStatusResponses,
AppLogData,
AppLogResponses,
AppModesData,
AppModesResponses,
TuiAppendPromptData,
TuiAppendPromptResponses,
TuiOpenHelpData,
TuiOpenHelpResponses,
TuiOpenSessionsData,
TuiOpenSessionsResponses,
TuiOpenThemesData,
TuiOpenThemesResponses,
TuiOpenModelsData,
TuiOpenModelsResponses,
TuiSubmitPromptData,
TuiSubmitPromptResponses,
TuiClearPromptData,
TuiClearPromptResponses,
TuiExecuteCommandData,
TuiExecuteCommandResponses,
} 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>;
};
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;
}
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
});
}
/**
* 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
});
}
/**
* 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
});
}
/**
* 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
}
});
}
/**
* Get a message from a session
*/
public message<ThrowOnError extends boolean = false>(options: Options<SessionMessageData, ThrowOnError>) {
return (options.client ?? this._client).get<SessionMessageResponses, unknown, ThrowOnError>({
url: '/session/{id}/message/{messageID}',
...options
});
}
/**
* 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
});
}
/**
* 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,
},
})
}
/**
* Get a message from a session
*/
public message<ThrowOnError extends boolean = false>(options: Options<SessionMessageData, ThrowOnError>) {
return (options.client ?? this._client).get<SessionMessageResponses, unknown, ThrowOnError>({
url: "/session/{id}/message/{messageID}",
...options,
})
}
/**
* 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
});
}
/**
* 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
});
}
/**
* 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
});
}
/**
* Open the session dialog
*/
public openSessions<ThrowOnError extends boolean = false>(options?: Options<TuiOpenSessionsData, ThrowOnError>) {
return (options?.client ?? this._client).post<TuiOpenSessionsResponses, unknown, ThrowOnError>({
url: '/tui/open-sessions',
...options
});
}
/**
* Open the theme dialog
*/
public openThemes<ThrowOnError extends boolean = false>(options?: Options<TuiOpenThemesData, ThrowOnError>) {
return (options?.client ?? this._client).post<TuiOpenThemesResponses, unknown, ThrowOnError>({
url: '/tui/open-themes',
...options
});
}
/**
* Open the model dialog
*/
public openModels<ThrowOnError extends boolean = false>(options?: Options<TuiOpenModelsData, ThrowOnError>) {
return (options?.client ?? this._client).post<TuiOpenModelsResponses, unknown, ThrowOnError>({
url: '/tui/open-models',
...options
});
}
/**
* Submit the prompt
*/
public submitPrompt<ThrowOnError extends boolean = false>(options?: Options<TuiSubmitPromptData, ThrowOnError>) {
return (options?.client ?? this._client).post<TuiSubmitPromptResponses, unknown, ThrowOnError>({
url: '/tui/submit-prompt',
...options
});
}
/**
* Clear the prompt
*/
public clearPrompt<ThrowOnError extends boolean = false>(options?: Options<TuiClearPromptData, ThrowOnError>) {
return (options?.client ?? this._client).post<TuiClearPromptResponses, unknown, ThrowOnError>({
url: '/tui/clear-prompt',
...options
});
}
/**
* Execute a TUI command (e.g. switch_mode)
*/
public executeCommand<ThrowOnError extends boolean = false>(options?: Options<TuiExecuteCommandData, ThrowOnError>) {
return (options?.client ?? this._client).post<TuiExecuteCommandResponses, unknown, ThrowOnError>({
url: '/tui/execute-command',
...options,
headers: {
'Content-Type': 'application/json',
...options?.headers
}
});
}
/**
* 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,
})
}
/**
* Open the session dialog
*/
public openSessions<ThrowOnError extends boolean = false>(options?: Options<TuiOpenSessionsData, ThrowOnError>) {
return (options?.client ?? this._client).post<TuiOpenSessionsResponses, unknown, ThrowOnError>({
url: "/tui/open-sessions",
...options,
})
}
/**
* Open the theme dialog
*/
public openThemes<ThrowOnError extends boolean = false>(options?: Options<TuiOpenThemesData, ThrowOnError>) {
return (options?.client ?? this._client).post<TuiOpenThemesResponses, unknown, ThrowOnError>({
url: "/tui/open-themes",
...options,
})
}
/**
* Open the model dialog
*/
public openModels<ThrowOnError extends boolean = false>(options?: Options<TuiOpenModelsData, ThrowOnError>) {
return (options?.client ?? this._client).post<TuiOpenModelsResponses, unknown, ThrowOnError>({
url: "/tui/open-models",
...options,
})
}
/**
* Submit the prompt
*/
public submitPrompt<ThrowOnError extends boolean = false>(options?: Options<TuiSubmitPromptData, ThrowOnError>) {
return (options?.client ?? this._client).post<TuiSubmitPromptResponses, unknown, ThrowOnError>({
url: "/tui/submit-prompt",
...options,
})
}
/**
* Clear the prompt
*/
public clearPrompt<ThrowOnError extends boolean = false>(options?: Options<TuiClearPromptData, ThrowOnError>) {
return (options?.client ?? this._client).post<TuiClearPromptResponses, unknown, ThrowOnError>({
url: "/tui/clear-prompt",
...options,
})
}
/**
* Execute a TUI command (e.g. switch_mode)
*/
public executeCommand<ThrowOnError extends boolean = false>(options?: Options<TuiExecuteCommandData, ThrowOnError>) {
return (options?.client ?? this._client).post<TuiExecuteCommandResponses, unknown, ThrowOnError>({
url: "/tui/execute-command",
...options,
headers: {
"Content-Type": "application/json",
...options?.headers,
},
})
}
}
export class OpencodeClient extends _HeyApiClient {
/**
* Respond to a permission request
*/
public postSessionByIdPermissionsByPermissionId<ThrowOnError extends boolean = false>(options: Options<PostSessionByIdPermissionsByPermissionIdData, ThrowOnError>) {
return (options.client ?? this._client).post<PostSessionByIdPermissionsByPermissionIdResponses, unknown, ThrowOnError>({
url: '/session/{id}/permissions/{permissionID}',
...options,
headers: {
'Content-Type': 'application/json',
...options.headers
}
});
}
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 });
}
/**
* Respond to a permission request
*/
public postSessionByIdPermissionsByPermissionId<ThrowOnError extends boolean = false>(
options: Options<PostSessionByIdPermissionsByPermissionIdData, ThrowOnError>,
) {
return (options.client ?? this._client).post<
PostSessionByIdPermissionsByPermissionIdResponses,
unknown,
ThrowOnError
>({
url: "/session/{id}/permissions/{permissionID}",
...options,
headers: {
"Content-Type": "application/json",
...options.headers,
},
})
}
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 })
}
+1413 -1362
View File
@@ -1,1639 +1,1690 @@
// 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: 'permission.replied';
} & EventPermissionReplied) | ({
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 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: "file.edited"
} & EventFileEdited)
| ({
type: "server.connected"
} & EventServerConnected)
| ({
type: "permission.updated"
} & EventPermissionUpdated)
| ({
type: "permission.replied"
} & EventPermissionReplied)
| ({
type: "session.updated"
} & EventSessionUpdated)
| ({
type: "session.deleted"
} & EventSessionDeleted)
| ({
type: "session.idle"
} & EventSessionIdle)
| ({
type: "session.error"
} & EventSessionError)
| ({
type: "file.watcher.updated"
} & EventFileWatcherUpdated)
| ({
type: "ide.installed"
} & EventIdeInstalled)
export type EventInstallationUpdated = {
type: string;
properties: {
version: string;
};
};
type: string
properties: {
version: string
}
}
export type EventLspClientDiagnostics = {
type: string;
properties: {
serverID: string;
path: string;
};
};
type: string
properties: {
serverID: string
path: string
}
}
export type EventMessageUpdated = {
type: string;
properties: {
info: Message;
};
};
type: string
properties: {
info: Message
}
}
export type Message = ({
role: 'user';
} & UserMessage) | ({
role: 'assistant';
} & AssistantMessage);
export type Message =
| ({
role: "user"
} & UserMessage)
| ({
role: "assistant"
} & AssistantMessage)
export type UserMessage = {
id: string;
sessionID: string;
role: string;
time: {
created: number;
};
};
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;
};
};
};
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;
};
};
name: string
data: {
providerID: string
message: string
}
}
export type UnknownError = {
name: string;
data: {
message: string;
};
};
name: string
data: {
message: string
}
}
export type MessageOutputLengthError = {
name: string;
data: {
[key: string]: unknown;
};
};
name: string
data: {
[key: string]: unknown
}
}
export type MessageAbortedError = {
name: string;
data: {
[key: string]: unknown;
};
};
name: string
data: {
[key: string]: unknown
}
}
export type EventMessageRemoved = {
type: string;
properties: {
sessionID: string;
messageID: string;
};
};
type: string
properties: {
sessionID: string
messageID: string
}
}
export type EventMessagePartUpdated = {
type: string;
properties: {
part: Part;
};
};
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 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;
};
};
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;
};
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 FilePartSource =
| ({
type: "file"
} & FileSource)
| ({
type: "symbol"
} & SymbolSource)
export type FileSource = {
text: FilePartSourceText;
type: string;
path: string;
};
text: FilePartSourceText
type: string
path: string
}
export type FilePartSourceText = {
value: string;
start: number;
end: number;
};
value: string
start: number
end: number
}
export type SymbolSource = {
text: FilePartSourceText;
type: string;
path: string;
range: Range;
name: string;
kind: number;
};
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;
};
};
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;
};
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 ToolState =
| ({
status: "pending"
} & ToolStatePending)
| ({
status: "running"
} & ToolStateRunning)
| ({
status: "completed"
} & ToolStateCompleted)
| ({
status: "error"
} & ToolStateError)
export type ToolStatePending = {
status: string;
};
status: string
}
export type ToolStateRunning = {
status: string;
input?: unknown;
title?: string;
metadata?: {
[key: string]: unknown;
};
time: {
start: number;
};
};
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;
};
};
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;
};
};
status: string
input: {
[key: string]: unknown
}
error: string
time: {
start: number
end: number
}
}
export type StepStartPart = {
id: string;
sessionID: string;
messageID: string;
type: string;
};
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;
};
};
};
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;
};
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>;
};
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;
};
};
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: Permission;
};
export type Permission = {
id: string;
type: string;
pattern?: string;
sessionID: string;
messageID: string;
callID?: string;
title: string;
metadata: {
[key: string]: unknown;
};
time: {
created: number;
};
};
export type EventPermissionReplied = {
type: string;
properties: {
sessionID: string;
permissionID: string;
response: string;
};
};
type: string
properties: {
key: string
content?: unknown
}
}
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);
};
};
type: string
properties: {
file: string
}
}
export type EventServerConnected = {
type: string;
properties: {
[key: string]: unknown;
};
};
type: string
properties: {
[key: string]: unknown
}
}
export type EventPermissionUpdated = {
type: string
properties: Permission
}
export type Permission = {
id: string
type: string
pattern?: string
sessionID: string
messageID: string
callID?: string
title: string
metadata: {
[key: string]: unknown
}
time: {
created: number
}
}
export type EventPermissionReplied = {
type: string
properties: {
sessionID: string
permissionID: string
response: 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 EventFileWatcherUpdated = {
type: string;
properties: {
file: string;
event: string;
};
};
type: string
properties: {
file: string
event: string
}
}
export type EventIdeInstalled = {
type: string;
properties: {
ide: string;
};
};
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;
};
};
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?: {
/**
* JSON schema reference for configuration validation
*/
$schema?: string
/**
* Theme name to use for the interface
*/
theme?: string
keybinds?: KeybindsConfig
plugin?: Array<string>
/**
* 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]: {
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);
};
formatter?: {
[key: string]: {
disabled?: boolean;
command?: Array<string>;
environment?: {
[key: string]: string;
};
extensions?: Array<string>;
};
};
lsp?: {
[key: string]: {
disabled: boolean;
} | {
command: Array<string>;
extensions?: Array<string>;
disabled?: boolean;
env?: {
[key: string]: string;
};
initialization?: {
[key: string]: unknown;
};
};
};
/**
* 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;
};
}>;
};
};
};
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)
}
formatter?: {
[key: string]: {
disabled?: boolean
command?: Array<string>
environment?: {
[key: string]: string
}
extensions?: Array<string>
}
}
lsp?: {
[key: string]:
| {
disabled: boolean
}
| {
command: Array<string>
extensions?: Array<string>
disabled?: boolean
env?: {
[key: string]: string
}
initialization?: {
[key: string]: unknown
}
}
}
/**
* 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;
};
/**
* 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;
top_p?: number;
prompt?: string;
tools?: {
[key: string]: boolean;
};
disable?: boolean;
};
model?: string
temperature?: number
top_p?: number
prompt?: string
tools?: {
[key: string]: boolean
}
disable?: boolean
}
export type AgentConfig = ModeConfig & {
description: string;
};
description: string
}
export type Provider = {
api?: string;
name: string;
env: Array<string>;
id: string;
npm?: string;
models: {
[key: string]: Model;
};
};
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;
};
};
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;
};
/**
* 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;
};
};
/**
* 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 LayoutConfig = "auto" | "stretch"
export type _Error = {
data: {
[key: string]: unknown;
};
};
data: {
[key: string]: unknown
}
}
export type TextPartInput = {
id?: string;
type: string;
text: string;
synthetic?: boolean;
time?: {
start: number;
end?: number;
};
};
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;
};
id?: string
type: string
mime: string
filename?: string
url: string
source?: FilePartSource
}
export type Symbol = {
name: string;
kind: number;
location: {
uri: string;
range: Range;
};
};
name: string
kind: number
location: {
uri: string
range: Range
}
}
export type File = {
path: string;
added: number;
removed: number;
status: 'added' | 'deleted' | 'modified';
};
path: string
added: number
removed: number
status: "added" | "deleted" | "modified"
}
export type Mode = {
name: string;
temperature?: number;
topP?: number;
model?: {
modelID: string;
providerID: string;
};
prompt?: string;
tools: {
[key: string]: boolean;
};
};
name: string
temperature?: number
topP?: number
model?: {
modelID: string
providerID: string
}
prompt?: string
tools: {
[key: string]: boolean
}
}
export type EventSubscribeData = {
body?: never;
path?: never;
query?: never;
url: '/event';
};
body?: never
path?: never
query?: never
url: "/event"
}
export type EventSubscribeResponses = {
/**
* Event stream
*/
200: Event;
};
/**
* Event stream
*/
200: Event
}
export type EventSubscribeResponse = EventSubscribeResponses[keyof EventSubscribeResponses];
export type EventSubscribeResponse = EventSubscribeResponses[keyof EventSubscribeResponses]
export type AppGetData = {
body?: never;
path?: never;
query?: never;
url: '/app';
};
body?: never
path?: never
query?: never
url: "/app"
}
export type AppGetResponses = {
/**
* 200
*/
200: App;
};
/**
* 200
*/
200: App
}
export type AppGetResponse = AppGetResponses[keyof AppGetResponses];
export type AppGetResponse = AppGetResponses[keyof AppGetResponses]
export type AppInitData = {
body?: never;
path?: never;
query?: never;
url: '/app/init';
};
body?: never
path?: never
query?: never
url: "/app/init"
}
export type AppInitResponses = {
/**
* Initialize the app
*/
200: boolean;
};
/**
* Initialize the app
*/
200: boolean
}
export type AppInitResponse = AppInitResponses[keyof AppInitResponses];
export type AppInitResponse = AppInitResponses[keyof AppInitResponses]
export type ConfigGetData = {
body?: never;
path?: never;
query?: never;
url: '/config';
};
body?: never
path?: never
query?: never
url: "/config"
}
export type ConfigGetResponses = {
/**
* Get config info
*/
200: Config;
};
/**
* Get config info
*/
200: Config
}
export type ConfigGetResponse = ConfigGetResponses[keyof ConfigGetResponses];
export type ConfigGetResponse = ConfigGetResponses[keyof ConfigGetResponses]
export type SessionListData = {
body?: never;
path?: never;
query?: never;
url: '/session';
};
body?: never
path?: never
query?: never
url: "/session"
}
export type SessionListResponses = {
/**
* List of sessions
*/
200: Array<Session>;
};
/**
* List of sessions
*/
200: Array<Session>
}
export type SessionListResponse = SessionListResponses[keyof SessionListResponses];
export type SessionListResponse = SessionListResponses[keyof SessionListResponses]
export type SessionCreateData = {
body?: never;
path?: never;
query?: never;
url: '/session';
};
body?: never
path?: never
query?: never
url: "/session"
}
export type SessionCreateErrors = {
/**
* Bad request
*/
400: _Error;
};
/**
* Bad request
*/
400: _Error
}
export type SessionCreateError = SessionCreateErrors[keyof SessionCreateErrors];
export type SessionCreateError = SessionCreateErrors[keyof SessionCreateErrors]
export type SessionCreateResponses = {
/**
* Successfully created session
*/
200: Session;
};
/**
* Successfully created session
*/
200: Session
}
export type SessionCreateResponse = SessionCreateResponses[keyof SessionCreateResponses];
export type SessionCreateResponse = SessionCreateResponses[keyof SessionCreateResponses]
export type SessionDeleteData = {
body?: never;
path: {
id: string;
};
query?: never;
url: '/session/{id}';
};
body?: never
path: {
id: string
}
query?: never
url: "/session/{id}"
}
export type SessionDeleteResponses = {
/**
* Successfully deleted session
*/
200: boolean;
};
/**
* Successfully deleted session
*/
200: boolean
}
export type SessionDeleteResponse = SessionDeleteResponses[keyof SessionDeleteResponses];
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';
};
body?: {
messageID: string
providerID: string
modelID: string
}
path: {
/**
* Session ID
*/
id: string
}
query?: never
url: "/session/{id}/init"
}
export type SessionInitResponses = {
/**
* 200
*/
200: boolean;
};
/**
* 200
*/
200: boolean
}
export type SessionInitResponse = SessionInitResponses[keyof SessionInitResponses];
export type SessionInitResponse = SessionInitResponses[keyof SessionInitResponses]
export type SessionAbortData = {
body?: never;
path: {
id: string;
};
query?: never;
url: '/session/{id}/abort';
};
body?: never
path: {
id: string
}
query?: never
url: "/session/{id}/abort"
}
export type SessionAbortResponses = {
/**
* Aborted session
*/
200: boolean;
};
/**
* Aborted session
*/
200: boolean
}
export type SessionAbortResponse = SessionAbortResponses[keyof SessionAbortResponses];
export type SessionAbortResponse = SessionAbortResponses[keyof SessionAbortResponses]
export type SessionUnshareData = {
body?: never;
path: {
id: string;
};
query?: never;
url: '/session/{id}/share';
};
body?: never
path: {
id: string
}
query?: never
url: "/session/{id}/share"
}
export type SessionUnshareResponses = {
/**
* Successfully unshared session
*/
200: Session;
};
/**
* Successfully unshared session
*/
200: Session
}
export type SessionUnshareResponse = SessionUnshareResponses[keyof SessionUnshareResponses];
export type SessionUnshareResponse = SessionUnshareResponses[keyof SessionUnshareResponses]
export type SessionShareData = {
body?: never;
path: {
id: string;
};
query?: never;
url: '/session/{id}/share';
};
body?: never
path: {
id: string
}
query?: never
url: "/session/{id}/share"
}
export type SessionShareResponses = {
/**
* Successfully shared session
*/
200: Session;
};
/**
* Successfully shared session
*/
200: Session
}
export type SessionShareResponse = SessionShareResponses[keyof SessionShareResponses];
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';
};
body?: {
providerID: string
modelID: string
}
path: {
/**
* Session ID
*/
id: string
}
query?: never
url: "/session/{id}/summarize"
}
export type SessionSummarizeResponses = {
/**
* Summarized session
*/
200: boolean;
};
/**
* Summarized session
*/
200: boolean
}
export type SessionSummarizeResponse = SessionSummarizeResponses[keyof SessionSummarizeResponses];
export type SessionSummarizeResponse = SessionSummarizeResponses[keyof SessionSummarizeResponses]
export type SessionMessagesData = {
body?: never;
path: {
/**
* Session ID
*/
id: string;
};
query?: never;
url: '/session/{id}/message';
};
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>;
}>;
};
/**
* List of messages
*/
200: Array<{
info: Message
parts: Array<Part>
}>
}
export type SessionMessagesResponse = SessionMessagesResponses[keyof SessionMessagesResponses];
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';
};
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;
};
/**
* Created message
*/
200: AssistantMessage
}
export type SessionChatResponse = SessionChatResponses[keyof SessionChatResponses];
export type SessionChatResponse = SessionChatResponses[keyof SessionChatResponses]
export type SessionMessageData = {
body?: never;
path: {
/**
* Session ID
*/
id: string;
/**
* Message ID
*/
messageID: string;
};
query?: never;
url: '/session/{id}/message/{messageID}';
};
body?: never
path: {
/**
* Session ID
*/
id: string
/**
* Message ID
*/
messageID: string
}
query?: never
url: "/session/{id}/message/{messageID}"
}
export type SessionMessageResponses = {
/**
* Message
*/
200: {
info: Message;
parts: Array<Part>;
};
};
/**
* Message
*/
200: {
info: Message
parts: Array<Part>
}
}
export type SessionMessageResponse = SessionMessageResponses[keyof SessionMessageResponses];
export type SessionMessageResponse = SessionMessageResponses[keyof SessionMessageResponses]
export type SessionRevertData = {
body?: {
messageID: string;
partID?: string;
};
path: {
id: string;
};
query?: never;
url: '/session/{id}/revert';
};
body?: {
messageID: string
partID?: string
}
path: {
id: string
}
query?: never
url: "/session/{id}/revert"
}
export type SessionRevertResponses = {
/**
* Updated session
*/
200: Session;
};
/**
* Updated session
*/
200: Session
}
export type SessionRevertResponse = SessionRevertResponses[keyof SessionRevertResponses];
export type SessionRevertResponse = SessionRevertResponses[keyof SessionRevertResponses]
export type SessionUnrevertData = {
body?: never;
path: {
id: string;
};
query?: never;
url: '/session/{id}/unrevert';
};
body?: never
path: {
id: string
}
query?: never
url: "/session/{id}/unrevert"
}
export type SessionUnrevertResponses = {
/**
* Updated session
*/
200: Session;
};
/**
* Updated session
*/
200: Session
}
export type SessionUnrevertResponse = SessionUnrevertResponses[keyof SessionUnrevertResponses];
export type SessionUnrevertResponse = SessionUnrevertResponses[keyof SessionUnrevertResponses]
export type PostSessionByIdPermissionsByPermissionIdData = {
body?: {
response: 'once' | 'always' | 'reject';
};
path: {
id: string;
permissionID: string;
};
query?: never;
url: '/session/{id}/permissions/{permissionID}';
};
body?: {
response: "once" | "always" | "reject"
}
path: {
id: string
permissionID: string
}
query?: never
url: "/session/{id}/permissions/{permissionID}"
}
export type PostSessionByIdPermissionsByPermissionIdResponses = {
/**
* Permission processed successfully
*/
200: boolean;
};
/**
* Permission processed successfully
*/
200: boolean
}
export type PostSessionByIdPermissionsByPermissionIdResponse = PostSessionByIdPermissionsByPermissionIdResponses[keyof PostSessionByIdPermissionsByPermissionIdResponses];
export type PostSessionByIdPermissionsByPermissionIdResponse =
PostSessionByIdPermissionsByPermissionIdResponses[keyof PostSessionByIdPermissionsByPermissionIdResponses]
export type ConfigProvidersData = {
body?: never;
path?: never;
query?: never;
url: '/config/providers';
};
body?: never
path?: never
query?: never
url: "/config/providers"
}
export type ConfigProvidersResponses = {
/**
* List of providers
*/
200: {
providers: Array<Provider>;
default: {
[key: string]: string;
};
};
};
/**
* List of providers
*/
200: {
providers: Array<Provider>
default: {
[key: string]: string
}
}
}
export type ConfigProvidersResponse = ConfigProvidersResponses[keyof ConfigProvidersResponses];
export type ConfigProvidersResponse = ConfigProvidersResponses[keyof ConfigProvidersResponses]
export type FindTextData = {
body?: never;
path?: never;
query: {
pattern: string;
};
url: '/find';
};
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;
}>;
}>;
};
/**
* 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 FindTextResponse = FindTextResponses[keyof FindTextResponses]
export type FindFilesData = {
body?: never;
path?: never;
query: {
query: string;
};
url: '/find/file';
};
body?: never
path?: never
query: {
query: string
}
url: "/find/file"
}
export type FindFilesResponses = {
/**
* File paths
*/
200: Array<string>;
};
/**
* File paths
*/
200: Array<string>
}
export type FindFilesResponse = FindFilesResponses[keyof FindFilesResponses];
export type FindFilesResponse = FindFilesResponses[keyof FindFilesResponses]
export type FindSymbolsData = {
body?: never;
path?: never;
query: {
query: string;
};
url: '/find/symbol';
};
body?: never
path?: never
query: {
query: string
}
url: "/find/symbol"
}
export type FindSymbolsResponses = {
/**
* Symbols
*/
200: Array<Symbol>;
};
/**
* Symbols
*/
200: Array<Symbol>
}
export type FindSymbolsResponse = FindSymbolsResponses[keyof FindSymbolsResponses];
export type FindSymbolsResponse = FindSymbolsResponses[keyof FindSymbolsResponses]
export type FileReadData = {
body?: never;
path?: never;
query: {
path: string;
};
url: '/file';
};
body?: never
path?: never
query: {
path: string
}
url: "/file"
}
export type FileReadResponses = {
/**
* File content
*/
200: {
type: 'raw' | 'patch';
content: string;
};
};
/**
* File content
*/
200: {
type: "raw" | "patch"
content: string
}
}
export type FileReadResponse = FileReadResponses[keyof FileReadResponses];
export type FileReadResponse = FileReadResponses[keyof FileReadResponses]
export type FileStatusData = {
body?: never;
path?: never;
query?: never;
url: '/file/status';
};
body?: never
path?: never
query?: never
url: "/file/status"
}
export type FileStatusResponses = {
/**
* File status
*/
200: Array<File>;
};
/**
* File status
*/
200: Array<File>
}
export type FileStatusResponse = FileStatusResponses[keyof FileStatusResponses];
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';
};
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;
};
/**
* Log entry written successfully
*/
200: boolean
}
export type AppLogResponse = AppLogResponses[keyof AppLogResponses];
export type AppLogResponse = AppLogResponses[keyof AppLogResponses]
export type AppModesData = {
body?: never;
path?: never;
query?: never;
url: '/mode';
};
body?: never
path?: never
query?: never
url: "/mode"
}
export type AppModesResponses = {
/**
* List of modes
*/
200: Array<Mode>;
};
/**
* List of modes
*/
200: Array<Mode>
}
export type AppModesResponse = AppModesResponses[keyof AppModesResponses];
export type AppModesResponse = AppModesResponses[keyof AppModesResponses]
export type TuiAppendPromptData = {
body?: {
text: string;
};
path?: never;
query?: never;
url: '/tui/append-prompt';
};
body?: {
text: string
}
path?: never
query?: never
url: "/tui/append-prompt"
}
export type TuiAppendPromptResponses = {
/**
* Prompt processed successfully
*/
200: boolean;
};
/**
* Prompt processed successfully
*/
200: boolean
}
export type TuiAppendPromptResponse = TuiAppendPromptResponses[keyof TuiAppendPromptResponses];
export type TuiAppendPromptResponse = TuiAppendPromptResponses[keyof TuiAppendPromptResponses]
export type TuiOpenHelpData = {
body?: never;
path?: never;
query?: never;
url: '/tui/open-help';
};
body?: never
path?: never
query?: never
url: "/tui/open-help"
}
export type TuiOpenHelpResponses = {
/**
* Help dialog opened successfully
*/
200: boolean;
};
/**
* Help dialog opened successfully
*/
200: boolean
}
export type TuiOpenHelpResponse = TuiOpenHelpResponses[keyof TuiOpenHelpResponses];
export type TuiOpenHelpResponse = TuiOpenHelpResponses[keyof TuiOpenHelpResponses]
export type TuiOpenSessionsData = {
body?: never;
path?: never;
query?: never;
url: '/tui/open-sessions';
};
body?: never
path?: never
query?: never
url: "/tui/open-sessions"
}
export type TuiOpenSessionsResponses = {
/**
* Session dialog opened successfully
*/
200: boolean;
};
/**
* Session dialog opened successfully
*/
200: boolean
}
export type TuiOpenSessionsResponse = TuiOpenSessionsResponses[keyof TuiOpenSessionsResponses];
export type TuiOpenSessionsResponse = TuiOpenSessionsResponses[keyof TuiOpenSessionsResponses]
export type TuiOpenThemesData = {
body?: never;
path?: never;
query?: never;
url: '/tui/open-themes';
};
body?: never
path?: never
query?: never
url: "/tui/open-themes"
}
export type TuiOpenThemesResponses = {
/**
* Theme dialog opened successfully
*/
200: boolean;
};
/**
* Theme dialog opened successfully
*/
200: boolean
}
export type TuiOpenThemesResponse = TuiOpenThemesResponses[keyof TuiOpenThemesResponses];
export type TuiOpenThemesResponse = TuiOpenThemesResponses[keyof TuiOpenThemesResponses]
export type TuiOpenModelsData = {
body?: never;
path?: never;
query?: never;
url: '/tui/open-models';
};
body?: never
path?: never
query?: never
url: "/tui/open-models"
}
export type TuiOpenModelsResponses = {
/**
* Model dialog opened successfully
*/
200: boolean;
};
/**
* Model dialog opened successfully
*/
200: boolean
}
export type TuiOpenModelsResponse = TuiOpenModelsResponses[keyof TuiOpenModelsResponses];
export type TuiOpenModelsResponse = TuiOpenModelsResponses[keyof TuiOpenModelsResponses]
export type TuiSubmitPromptData = {
body?: never;
path?: never;
query?: never;
url: '/tui/submit-prompt';
};
body?: never
path?: never
query?: never
url: "/tui/submit-prompt"
}
export type TuiSubmitPromptResponses = {
/**
* Prompt submitted successfully
*/
200: boolean;
};
/**
* Prompt submitted successfully
*/
200: boolean
}
export type TuiSubmitPromptResponse = TuiSubmitPromptResponses[keyof TuiSubmitPromptResponses];
export type TuiSubmitPromptResponse = TuiSubmitPromptResponses[keyof TuiSubmitPromptResponses]
export type TuiClearPromptData = {
body?: never;
path?: never;
query?: never;
url: '/tui/clear-prompt';
};
body?: never
path?: never
query?: never
url: "/tui/clear-prompt"
}
export type TuiClearPromptResponses = {
/**
* Prompt cleared successfully
*/
200: boolean;
};
/**
* Prompt cleared successfully
*/
200: boolean
}
export type TuiClearPromptResponse = TuiClearPromptResponses[keyof TuiClearPromptResponses];
export type TuiClearPromptResponse = TuiClearPromptResponses[keyof TuiClearPromptResponses]
export type TuiExecuteCommandData = {
body?: {
command: string;
};
path?: never;
query?: never;
url: '/tui/execute-command';
};
body?: {
command: string
}
path?: never
query?: never
url: "/tui/execute-command"
}
export type TuiExecuteCommandResponses = {
/**
* Command executed successfully
*/
200: boolean;
};
/**
* Command executed successfully
*/
200: boolean
}
export type TuiExecuteCommandResponse = TuiExecuteCommandResponses[keyof TuiExecuteCommandResponses];
export type TuiExecuteCommandResponse = TuiExecuteCommandResponses[keyof TuiExecuteCommandResponses]
export type ClientOptions = {
baseUrl: `${string}://${string}` | (string & {});
};
baseUrl: `${string}://${string}` | (string & {})
}
+1
View File
@@ -1,6 +1,7 @@
import { createClient } from "./gen/client/client"
import { type Config } from "./gen/client/types"
import { OpencodeClient } from "./gen/sdk.gen"
export * from "./gen/types.gen"
export function createOpencodeClient(config?: Config) {
const client = createClient(config)
+5 -1
View File
@@ -5,7 +5,11 @@
"outDir": "dist",
"module": "preserve",
"declaration": true,
"moduleResolution": "bundler"
"moduleResolution": "bundler",
"lib": [
"dom",
"dom.iterable"
]
},
"include": [
"src"
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@opencode/web",
"type": "module",
"version": "0.0.1",
"version": "0.0.0-202508022053",
"scripts": {
"dev": "astro dev",
"dev:remote": "sst shell --stage=dev --target=Web astro dev",
+10 -1
View File
@@ -11,8 +11,17 @@ if (!version) {
}
process.env["OPENCODE_VERSION"] = version
await import(`../packages/opencode/script/publish.ts`)
for await (const file of new Bun.Glob("**/package.json").scan({
absolute: true,
})) {
let pkg = await Bun.file(file).text()
pkg = pkg.replaceAll(/"version": "[^"]+"/g, `"version": "${version}"`)
await Bun.file(file).write(pkg)
}
// await import(`../packages/opencode/script/publish.ts`)
await import(`../packages/sdk/js/script/publish.ts`)
await import(`../packages/plugin/script/publish.ts`)
// await import(`../packages/sdk/stainless/generate.ts`)
if (!snapshot) {
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "opencode",
"displayName": "opencode",
"description": "opencode for VS Code",
"version": "0.0.0",
"version": "0.0.0-202508022053",
"publisher": "sst-dev",
"repository": {
"type": "git",