wip(app): provider settings
This commit is contained in:
@@ -39,16 +39,30 @@ export const DialogSettings: Component = () => {
|
|||||||
"padding-top": "12px",
|
"padding-top": "12px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Tabs.SectionTitle>{language.t("settings.section.desktop")}</Tabs.SectionTitle>
|
<div style={{ display: "flex", "flex-direction": "column", gap: "12px" }}>
|
||||||
<div style={{ display: "flex", "flex-direction": "column", gap: "6px", width: "100%" }}>
|
<div style={{ display: "flex", "flex-direction": "column", gap: "6px" }}>
|
||||||
<Tabs.Trigger value="general">
|
<Tabs.SectionTitle>{language.t("settings.section.desktop")}</Tabs.SectionTitle>
|
||||||
<Icon name="sliders" />
|
<div style={{ display: "flex", "flex-direction": "column", gap: "6px", width: "100%" }}>
|
||||||
{language.t("settings.tab.general")}
|
<Tabs.Trigger value="general">
|
||||||
</Tabs.Trigger>
|
<Icon name="sliders" />
|
||||||
<Tabs.Trigger value="shortcuts">
|
{language.t("settings.tab.general")}
|
||||||
<Icon name="keyboard" />
|
</Tabs.Trigger>
|
||||||
{language.t("settings.tab.shortcuts")}
|
<Tabs.Trigger value="shortcuts">
|
||||||
</Tabs.Trigger>
|
<Icon name="keyboard" />
|
||||||
|
{language.t("settings.tab.shortcuts")}
|
||||||
|
</Tabs.Trigger>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ display: "flex", "flex-direction": "column", gap: "6px" }}>
|
||||||
|
<Tabs.SectionTitle>{language.t("settings.section.server")}</Tabs.SectionTitle>
|
||||||
|
<div style={{ display: "flex", "flex-direction": "column", gap: "6px", width: "100%" }}>
|
||||||
|
<Tabs.Trigger value="providers">
|
||||||
|
<Icon name="server" />
|
||||||
|
{language.t("settings.providers.title")}
|
||||||
|
</Tabs.Trigger>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-1 pl-1 py-1 text-12-medium text-text-weak">
|
<div class="flex flex-col gap-1 pl-1 py-1 text-12-medium text-text-weak">
|
||||||
@@ -56,31 +70,6 @@ export const DialogSettings: Component = () => {
|
|||||||
<span class="text-11-regular">v{platform.version}</span>
|
<span class="text-11-regular">v{platform.version}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* <Tabs.SectionTitle>Server</Tabs.SectionTitle> */}
|
|
||||||
{/* <Tabs.Trigger value="permissions"> */}
|
|
||||||
{/* <Icon name="checklist" /> */}
|
|
||||||
{/* Permissions */}
|
|
||||||
{/* </Tabs.Trigger> */}
|
|
||||||
{/* <Tabs.Trigger value="providers"> */}
|
|
||||||
{/* <Icon name="server" /> */}
|
|
||||||
{/* Providers */}
|
|
||||||
{/* </Tabs.Trigger> */}
|
|
||||||
{/* <Tabs.Trigger value="models"> */}
|
|
||||||
{/* <Icon name="brain" /> */}
|
|
||||||
{/* Models */}
|
|
||||||
{/* </Tabs.Trigger> */}
|
|
||||||
{/* <Tabs.Trigger value="agents"> */}
|
|
||||||
{/* <Icon name="task" /> */}
|
|
||||||
{/* Agents */}
|
|
||||||
{/* </Tabs.Trigger> */}
|
|
||||||
{/* <Tabs.Trigger value="commands"> */}
|
|
||||||
{/* <Icon name="console" /> */}
|
|
||||||
{/* Commands */}
|
|
||||||
{/* </Tabs.Trigger> */}
|
|
||||||
{/* <Tabs.Trigger value="mcp"> */}
|
|
||||||
{/* <Icon name="mcp" /> */}
|
|
||||||
{/* MCP */}
|
|
||||||
{/* </Tabs.Trigger> */}
|
|
||||||
</Tabs.List>
|
</Tabs.List>
|
||||||
<Tabs.Content value="general" class="no-scrollbar">
|
<Tabs.Content value="general" class="no-scrollbar">
|
||||||
<SettingsGeneral />
|
<SettingsGeneral />
|
||||||
@@ -88,12 +77,9 @@ export const DialogSettings: Component = () => {
|
|||||||
<Tabs.Content value="shortcuts" class="no-scrollbar">
|
<Tabs.Content value="shortcuts" class="no-scrollbar">
|
||||||
<SettingsKeybinds />
|
<SettingsKeybinds />
|
||||||
</Tabs.Content>
|
</Tabs.Content>
|
||||||
{/* <Tabs.Content value="permissions" class="no-scrollbar"> */}
|
<Tabs.Content value="providers" class="no-scrollbar">
|
||||||
{/* <SettingsPermissions /> */}
|
<SettingsProviders />
|
||||||
{/* </Tabs.Content> */}
|
</Tabs.Content>
|
||||||
{/* <Tabs.Content value="providers" class="no-scrollbar"> */}
|
|
||||||
{/* <SettingsProviders /> */}
|
|
||||||
{/* </Tabs.Content> */}
|
|
||||||
{/* <Tabs.Content value="models" class="no-scrollbar"> */}
|
{/* <Tabs.Content value="models" class="no-scrollbar"> */}
|
||||||
{/* <SettingsModels /> */}
|
{/* <SettingsModels /> */}
|
||||||
{/* </Tabs.Content> */}
|
{/* </Tabs.Content> */}
|
||||||
|
|||||||
@@ -1,14 +1,153 @@
|
|||||||
import { Component } from "solid-js"
|
import { Button } from "@opencode-ai/ui/button"
|
||||||
|
import { useDialog } from "@opencode-ai/ui/context/dialog"
|
||||||
|
import { ProviderIcon } from "@opencode-ai/ui/provider-icon"
|
||||||
|
import { Tag } from "@opencode-ai/ui/tag"
|
||||||
|
import { showToast } from "@opencode-ai/ui/toast"
|
||||||
|
import type { IconName } from "@opencode-ai/ui/icons/provider"
|
||||||
|
import { popularProviders, useProviders } from "@/hooks/use-providers"
|
||||||
|
import { createMemo, type Component, For, Show } from "solid-js"
|
||||||
import { useLanguage } from "@/context/language"
|
import { useLanguage } from "@/context/language"
|
||||||
|
import { useGlobalSDK } from "@/context/global-sdk"
|
||||||
|
import { DialogConnectProvider } from "./dialog-connect-provider"
|
||||||
|
import { DialogSelectProvider } from "./dialog-select-provider"
|
||||||
|
|
||||||
|
type ProviderSource = "env" | "api" | "config" | "custom"
|
||||||
|
type ProviderMeta = { source?: ProviderSource }
|
||||||
|
|
||||||
export const SettingsProviders: Component = () => {
|
export const SettingsProviders: Component = () => {
|
||||||
|
const dialog = useDialog()
|
||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
|
const globalSDK = useGlobalSDK()
|
||||||
|
const providers = useProviders()
|
||||||
|
|
||||||
|
const connected = createMemo(() => providers.connected())
|
||||||
|
const popular = createMemo(() => {
|
||||||
|
const items = providers.popular().slice()
|
||||||
|
items.sort((a, b) => popularProviders.indexOf(a.id) - popularProviders.indexOf(b.id))
|
||||||
|
return items
|
||||||
|
})
|
||||||
|
|
||||||
|
const source = (item: unknown) => (item as ProviderMeta).source
|
||||||
|
|
||||||
|
const disconnect = async (providerID: string, name: string) => {
|
||||||
|
await globalSDK.client.auth
|
||||||
|
.remove({ providerID })
|
||||||
|
.then(async () => {
|
||||||
|
await globalSDK.client.global.dispose()
|
||||||
|
showToast({
|
||||||
|
variant: "success",
|
||||||
|
icon: "circle-check",
|
||||||
|
title: language.t("provider.disconnect.toast.disconnected.title", { provider: name }),
|
||||||
|
description: language.t("provider.disconnect.toast.disconnected.description", { provider: name }),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch((err: unknown) => {
|
||||||
|
const message = err instanceof Error ? err.message : String(err)
|
||||||
|
showToast({ title: language.t("common.requestFailed"), description: message })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="flex flex-col h-full overflow-y-auto">
|
<div class="flex flex-col h-full overflow-y-auto no-scrollbar" style={{ padding: "0 40px 40px 40px" }}>
|
||||||
<div class="flex flex-col gap-6 p-6 max-w-[600px]">
|
<div
|
||||||
<h2 class="text-16-medium text-text-strong">{language.t("settings.providers.title")}</h2>
|
class="sticky top-0 z-10"
|
||||||
<p class="text-14-regular text-text-weak">{language.t("settings.providers.description")}</p>
|
style={{
|
||||||
|
background:
|
||||||
|
"linear-gradient(to bottom, var(--surface-raised-stronger-non-alpha) calc(100% - 24px), transparent)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class="flex flex-col gap-4 pt-6 pb-6 max-w-[720px]">
|
||||||
|
<div class="flex items-center justify-between gap-4">
|
||||||
|
<h2 class="text-16-medium text-text-strong">{language.t("settings.providers.title")}</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-8 max-w-[720px]">
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.providers.section.connected")}</h3>
|
||||||
|
<div class="bg-surface-raised-base px-4 rounded-lg">
|
||||||
|
<Show
|
||||||
|
when={connected().length > 0}
|
||||||
|
fallback={
|
||||||
|
<div class="py-4 text-14-regular text-text-weak">
|
||||||
|
{language.t("settings.providers.connected.empty")}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<For each={connected()}>
|
||||||
|
{(item) => (
|
||||||
|
<div class="flex items-center justify-between gap-4 py-3 border-b border-border-weak-base last:border-none">
|
||||||
|
<div class="flex items-center gap-3 min-w-0">
|
||||||
|
<ProviderIcon id={item.id as IconName} class="size-5 shrink-0 icon-strong-base" />
|
||||||
|
<span class="text-14-regular text-text-strong truncate">{item.name}</span>
|
||||||
|
<Show when={source(item) === "env"}>
|
||||||
|
<Tag>{language.t("settings.providers.tag.environment")}</Tag>
|
||||||
|
</Show>
|
||||||
|
<Show when={source(item) === "api"}>
|
||||||
|
<Tag>{language.t("provider.connect.method.apiKey")}</Tag>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
<Show when={source(item) === "api"}>
|
||||||
|
<Button size="small" variant="ghost" onClick={() => void disconnect(item.id, item.name)}>
|
||||||
|
{language.t("common.disconnect")}
|
||||||
|
</Button>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.providers.section.popular")}</h3>
|
||||||
|
<div class="bg-surface-raised-base px-4 rounded-lg">
|
||||||
|
<For each={popular()}>
|
||||||
|
{(item) => (
|
||||||
|
<div class="flex items-center justify-between gap-4 py-3 border-b border-border-weak-base last:border-none">
|
||||||
|
<div class="flex items-center gap-x-3 min-w-0">
|
||||||
|
<ProviderIcon id={item.id as IconName} class="size-5 shrink-0 icon-strong-base" />
|
||||||
|
<span class="text-14-regular text-text-strong">{item.name}</span>
|
||||||
|
<Show when={item.id === "opencode"}>
|
||||||
|
<Tag>{language.t("dialog.provider.tag.recommended")}</Tag>
|
||||||
|
</Show>
|
||||||
|
<Show when={item.id === "anthropic"}>
|
||||||
|
<div class="text-14-regular text-text-weak">{language.t("dialog.provider.anthropic.note")}</div>
|
||||||
|
</Show>
|
||||||
|
<Show when={item.id === "openai"}>
|
||||||
|
<div class="text-14-regular text-text-weak">{language.t("dialog.provider.openai.note")}</div>
|
||||||
|
</Show>
|
||||||
|
<Show when={item.id.startsWith("github-copilot")}>
|
||||||
|
<div class="text-14-regular text-text-weak">{language.t("dialog.provider.copilot.note")}</div>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
variant="secondary"
|
||||||
|
icon="plus-small"
|
||||||
|
onClick={() => {
|
||||||
|
dialog.show(() => <DialogConnectProvider provider={item.id} />)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{language.t("common.connect")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
class="w-full justify-start px-[11px] py-3.5 gap-4.5 text-14-medium"
|
||||||
|
icon="dot-grid"
|
||||||
|
onClick={() => {
|
||||||
|
dialog.show(() => <DialogSelectProvider />)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{language.t("dialog.provider.viewAll")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -137,6 +137,9 @@ export const dict = {
|
|||||||
"provider.connect.toast.connected.title": "{{provider}} connected",
|
"provider.connect.toast.connected.title": "{{provider}} connected",
|
||||||
"provider.connect.toast.connected.description": "{{provider}} models are now available to use.",
|
"provider.connect.toast.connected.description": "{{provider}} models are now available to use.",
|
||||||
|
|
||||||
|
"provider.disconnect.toast.disconnected.title": "{{provider}} disconnected",
|
||||||
|
"provider.disconnect.toast.disconnected.description": "{{provider}} models are no longer available.",
|
||||||
|
|
||||||
"model.tag.free": "Free",
|
"model.tag.free": "Free",
|
||||||
"model.tag.latest": "Latest",
|
"model.tag.latest": "Latest",
|
||||||
"model.provider.anthropic": "Anthropic",
|
"model.provider.anthropic": "Anthropic",
|
||||||
@@ -159,6 +162,8 @@ export const dict = {
|
|||||||
"common.loading": "Loading",
|
"common.loading": "Loading",
|
||||||
"common.loading.ellipsis": "...",
|
"common.loading.ellipsis": "...",
|
||||||
"common.cancel": "Cancel",
|
"common.cancel": "Cancel",
|
||||||
|
"common.connect": "Connect",
|
||||||
|
"common.disconnect": "Disconnect",
|
||||||
"common.submit": "Submit",
|
"common.submit": "Submit",
|
||||||
"common.save": "Save",
|
"common.save": "Save",
|
||||||
"common.saving": "Saving...",
|
"common.saving": "Saving...",
|
||||||
@@ -491,6 +496,7 @@ export const dict = {
|
|||||||
"sidebar.project.viewAllSessions": "View all sessions",
|
"sidebar.project.viewAllSessions": "View all sessions",
|
||||||
|
|
||||||
"settings.section.desktop": "Desktop",
|
"settings.section.desktop": "Desktop",
|
||||||
|
"settings.section.server": "Server",
|
||||||
"settings.tab.general": "General",
|
"settings.tab.general": "General",
|
||||||
"settings.tab.shortcuts": "Shortcuts",
|
"settings.tab.shortcuts": "Shortcuts",
|
||||||
|
|
||||||
@@ -599,6 +605,10 @@ export const dict = {
|
|||||||
|
|
||||||
"settings.providers.title": "Providers",
|
"settings.providers.title": "Providers",
|
||||||
"settings.providers.description": "Provider settings will be configurable here.",
|
"settings.providers.description": "Provider settings will be configurable here.",
|
||||||
|
"settings.providers.section.connected": "Connected providers",
|
||||||
|
"settings.providers.connected.empty": "No connected providers",
|
||||||
|
"settings.providers.section.popular": "Popular providers",
|
||||||
|
"settings.providers.tag.environment": "Environment",
|
||||||
"settings.models.title": "Models",
|
"settings.models.title": "Models",
|
||||||
"settings.models.description": "Model settings will be configurable here.",
|
"settings.models.description": "Model settings will be configurable here.",
|
||||||
"settings.agents.title": "Agents",
|
"settings.agents.title": "Agents",
|
||||||
|
|||||||
@@ -441,6 +441,36 @@ export namespace Server {
|
|||||||
return c.json(true)
|
return c.json(true)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
.delete(
|
||||||
|
"/auth/:providerID",
|
||||||
|
describeRoute({
|
||||||
|
summary: "Remove auth credentials",
|
||||||
|
description: "Remove authentication credentials",
|
||||||
|
operationId: "auth.remove",
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: "Successfully removed authentication credentials",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: resolver(z.boolean()),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
...errors(400),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
validator(
|
||||||
|
"param",
|
||||||
|
z.object({
|
||||||
|
providerID: z.string(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
async (c) => {
|
||||||
|
const providerID = c.req.valid("param").providerID
|
||||||
|
await Auth.remove(providerID)
|
||||||
|
return c.json(true)
|
||||||
|
},
|
||||||
|
)
|
||||||
.get(
|
.get(
|
||||||
"/event",
|
"/event",
|
||||||
describeRoute({
|
describeRoute({
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import type {
|
|||||||
AppLogResponses,
|
AppLogResponses,
|
||||||
AppSkillsResponses,
|
AppSkillsResponses,
|
||||||
Auth as Auth3,
|
Auth as Auth3,
|
||||||
|
AuthRemoveErrors,
|
||||||
|
AuthRemoveResponses,
|
||||||
AuthSetErrors,
|
AuthSetErrors,
|
||||||
AuthSetResponses,
|
AuthSetResponses,
|
||||||
CommandListResponses,
|
CommandListResponses,
|
||||||
@@ -3054,6 +3056,36 @@ export class Formatter extends HeyApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Auth2 extends HeyApiClient {
|
export class Auth2 extends HeyApiClient {
|
||||||
|
/**
|
||||||
|
* Remove auth credentials
|
||||||
|
*
|
||||||
|
* Remove authentication credentials
|
||||||
|
*/
|
||||||
|
public remove<ThrowOnError extends boolean = false>(
|
||||||
|
parameters: {
|
||||||
|
providerID: string
|
||||||
|
directory?: string
|
||||||
|
},
|
||||||
|
options?: Options<never, ThrowOnError>,
|
||||||
|
) {
|
||||||
|
const params = buildClientParams(
|
||||||
|
[parameters],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
args: [
|
||||||
|
{ in: "path", key: "providerID" },
|
||||||
|
{ in: "query", key: "directory" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
return (options?.client ?? this.client).delete<AuthRemoveResponses, AuthRemoveErrors, ThrowOnError>({
|
||||||
|
url: "/auth/{providerID}",
|
||||||
|
...options,
|
||||||
|
...params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set auth credentials
|
* Set auth credentials
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -4867,6 +4867,35 @@ export type FormatterStatusResponses = {
|
|||||||
|
|
||||||
export type FormatterStatusResponse = FormatterStatusResponses[keyof FormatterStatusResponses]
|
export type FormatterStatusResponse = FormatterStatusResponses[keyof FormatterStatusResponses]
|
||||||
|
|
||||||
|
export type AuthRemoveData = {
|
||||||
|
body?: never
|
||||||
|
path: {
|
||||||
|
providerID: string
|
||||||
|
}
|
||||||
|
query?: {
|
||||||
|
directory?: string
|
||||||
|
}
|
||||||
|
url: "/auth/{providerID}"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AuthRemoveErrors = {
|
||||||
|
/**
|
||||||
|
* Bad request
|
||||||
|
*/
|
||||||
|
400: BadRequestError
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AuthRemoveError = AuthRemoveErrors[keyof AuthRemoveErrors]
|
||||||
|
|
||||||
|
export type AuthRemoveResponses = {
|
||||||
|
/**
|
||||||
|
* Successfully removed authentication credentials
|
||||||
|
*/
|
||||||
|
200: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AuthRemoveResponse = AuthRemoveResponses[keyof AuthRemoveResponses]
|
||||||
|
|
||||||
export type AuthSetData = {
|
export type AuthSetData = {
|
||||||
body?: Auth
|
body?: Auth
|
||||||
path: {
|
path: {
|
||||||
|
|||||||
@@ -5709,6 +5709,56 @@
|
|||||||
"source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.auth.set({\n ...\n})"
|
"source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.auth.set({\n ...\n})"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"operationId": "auth.remove",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "directory",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "providerID",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"summary": "Remove auth credentials",
|
||||||
|
"description": "Remove authentication credentials",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Successfully removed authentication credentials",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad request",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/BadRequestError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-codeSamples": [
|
||||||
|
{
|
||||||
|
"lang": "js",
|
||||||
|
"source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.auth.remove({\n ...\n})"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/event": {
|
"/event": {
|
||||||
|
|||||||
Reference in New Issue
Block a user