From 34ff87d504836ff71b3bb2d466842c00ee3c5ec2 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sat, 8 Nov 2025 01:59:02 +0000 Subject: chore: format code --- packages/console/app/src/app.tsx | 5 +- packages/console/app/src/component/faq.tsx | 5 +- packages/console/app/src/component/icon.tsx | 133 +--- packages/console/app/src/lib/github.ts | 5 +- packages/console/app/src/routes/auth/authorize.ts | 5 +- packages/console/app/src/routes/brand/index.tsx | 144 +--- .../console/app/src/routes/enterprise/index.tsx | 57 +- packages/console/app/src/routes/index.tsx | 778 +++------------------ packages/console/app/src/routes/stripe/webhook.ts | 23 +- packages/console/app/src/routes/temp.tsx | 10 +- .../console/app/src/routes/workspace-picker.tsx | 11 +- .../workspace/[id]/billing/billing-section.tsx | 32 +- .../[id]/billing/monthly-limit-section.tsx | 8 +- .../workspace/[id]/billing/payment-section.tsx | 5 +- .../workspace/[id]/billing/reload-section.tsx | 14 +- .../app/src/routes/workspace/[id]/index.tsx | 4 +- .../src/routes/workspace/[id]/keys/key-section.tsx | 10 +- .../workspace/[id]/members/member-section.tsx | 7 +- .../src/routes/workspace/[id]/model-section.tsx | 13 +- .../src/routes/workspace/[id]/new-user-section.tsx | 15 +- .../src/routes/workspace/[id]/provider-section.tsx | 16 +- .../console/app/src/routes/workspace/common.tsx | 5 +- packages/console/app/src/routes/zen/index.tsx | 132 +--- .../console/app/src/routes/zen/util/handler.ts | 64 +- .../app/src/routes/zen/util/provider/anthropic.ts | 26 +- .../routes/zen/util/provider/openai-compatible.ts | 31 +- .../app/src/routes/zen/util/provider/openai.ts | 38 +- packages/console/app/src/routes/zen/v1/models.ts | 5 +- packages/console/app/src/style/token/font.css | 3 +- packages/console/core/script/lookup-user.ts | 13 +- packages/console/core/script/reset-db.ts | 10 +- packages/console/core/src/aws.ts | 53 +- packages/console/core/src/drizzle/index.ts | 10 +- packages/console/core/src/key.ts | 10 +- packages/console/core/src/model.ts | 4 +- packages/console/core/src/provider.ts | 11 +- packages/console/core/src/schema/auth.sql.ts | 9 +- packages/console/core/src/schema/model.sql.ts | 5 +- packages/console/core/src/schema/provider.sql.ts | 5 +- packages/console/core/src/schema/user.sql.ts | 10 +- packages/console/core/src/user.ts | 28 +- .../console/mail/emails/templates/InviteEmail.tsx | 25 +- 42 files changed, 340 insertions(+), 1457 deletions(-) (limited to 'packages/console') diff --git a/packages/console/app/src/app.tsx b/packages/console/app/src/app.tsx index 7976f6b3b..1cf963642 100644 --- a/packages/console/app/src/app.tsx +++ b/packages/console/app/src/app.tsx @@ -12,10 +12,7 @@ export default function App() { root={(props) => ( opencode - + {props.children} )} diff --git a/packages/console/app/src/component/faq.tsx b/packages/console/app/src/component/faq.tsx index 47dca9513..753a0dce4 100644 --- a/packages/console/app/src/component/faq.tsx +++ b/packages/console/app/src/component/faq.tsx @@ -13,10 +13,7 @@ export function Faq(props: ParentProps & { question: string }) { fill="currentColor" xmlns="http://www.w3.org/2000/svg" > - + ) { - - + + - + ) { fill-opacity="0.2" /> - - + + @@ -61,21 +40,9 @@ export function IconLogo(props: JSX.SvgSVGAttributes) { - - - + + + @@ -86,40 +53,16 @@ export function IconLogo(props: JSX.SvgSVGAttributes) { - - + + - - + + - - + + ) @@ -127,14 +70,7 @@ export function IconLogo(props: JSX.SvgSVGAttributes) { export function IconCopy(props: JSX.SvgSVGAttributes) { return ( - + ) { export function IconCheck(props: JSX.SvgSVGAttributes) { return ( - - + + ) } @@ -189,14 +113,7 @@ export function IconStripe(props: JSX.SvgSVGAttributes) { export function IconChevron(props: JSX.SvgSVGAttributes) { return ( - + ) { export function IconWorkspaceLogo(props: JSX.SvgSVGAttributes) { return ( - + ) @@ -234,10 +144,7 @@ export function IconOpenAI(props: JSX.SvgSVGAttributes) { export function IconAnthropic(props: JSX.SvgSVGAttributes) { return ( - + { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36", } - const apiBaseUrl = config.github.repoUrl.replace( - "https://github.com/", - "https://api.github.com/repos/", - ) + const apiBaseUrl = config.github.repoUrl.replace("https://github.com/", "https://api.github.com/repos/") try { const [meta, releases, contributors] = await Promise.all([ fetch(apiBaseUrl, { headers }).then((res) => res.json()), diff --git a/packages/console/app/src/routes/auth/authorize.ts b/packages/console/app/src/routes/auth/authorize.ts index 293e9ede7..166466ef8 100644 --- a/packages/console/app/src/routes/auth/authorize.ts +++ b/packages/console/app/src/routes/auth/authorize.ts @@ -2,9 +2,6 @@ import type { APIEvent } from "@solidjs/start/server" import { AuthClient } from "~/context/auth" export async function GET(input: APIEvent) { - const result = await AuthClient.authorize( - new URL("./callback", input.request.url).toString(), - "code", - ) + const result = await AuthClient.authorize(new URL("./callback", input.request.url).toString(), "code") return Response.redirect(result.url, 302) } diff --git a/packages/console/app/src/routes/brand/index.tsx b/packages/console/app/src/routes/brand/index.tsx index 72ea0f150..6aac4517a 100644 --- a/packages/console/app/src/routes/brand/index.tsx +++ b/packages/console/app/src/routes/brand/index.tsx @@ -68,13 +68,7 @@ export default function Brand() { onClick={() => downloadFile(brandAssets, "opencode-brand-assets.zip")} > Download all assets - + OpenCode brand guidelines
- - - - -
@@ -232,31 +215,29 @@ export default function Enterprise() {
  • - OpenCode Enterprise is for organizations that want to ensure that their code and - data never leaves their infrastructure. It can do this by using a centralized - config that integrates with your SSO and internal AI gateway. + OpenCode Enterprise is for organizations that want to ensure that their code and data never leaves + their infrastructure. It can do this by using a centralized config that integrates with your SSO and + internal AI gateway.
  • - Simply start with an internal trial with your team. OpenCode by default does not - store your code or context data, making it easy to get started. Then contact us to - discuss pricing and implementation options. + Simply start with an internal trial with your team. OpenCode by default does not store your code or + context data, making it easy to get started. Then contact us to discuss pricing and implementation + options.
  • - We offer per-seat enterprise pricing. If you have your own LLM gateway, we do not - charge for tokens used. For further details, contact us for a custom quote based - on your organization's needs. + We offer per-seat enterprise pricing. If you have your own LLM gateway, we do not charge for tokens + used. For further details, contact us for a custom quote based on your organization's needs.
  • - Yes. OpenCode does not store your code or context data. All processing happens - locally or through direct API calls to your AI provider. With central config and - SSO integration, your data remains secure within your organization's - infrastructure. + Yes. OpenCode does not store your code or context data. All processing happens locally or through + direct API calls to your AI provider. With central config and SSO integration, your data remains + secure within your organization's infrastructure.
diff --git a/packages/console/app/src/routes/index.tsx b/packages/console/app/src/routes/index.tsx index ee138e140..8b8f44999 100644 --- a/packages/console/app/src/routes/index.tsx +++ b/packages/console/app/src/routes/index.tsx @@ -42,10 +42,7 @@ export default function Home() { return (
- + OpenCode | The AI coding agent built for the terminal @@ -57,27 +54,17 @@ export default function Home() {
- + What’s new in {release()?.name ?? "the latest release"}

The AI coding agent built for the terminal

- OpenCode is fully open source, giving you control and freedom to use any provider, - any model, and any editor. + OpenCode is fully open source, giving you control and freedom to use any provider, any model, and any + editor.

Read docs - +

What is OpenCode?

-

- OpenCode is an open source agent that helps you write and run code directly from the - terminal. -

+

OpenCode is an open source agent that helps you write and run code directly from the terminal.

  • @@ -197,8 +181,7 @@ export default function Home() {
  • [*]
    - Multi-session Start multiple agents in parallel on the same - project + Multi-session Start multiple agents in parallel on the same project
  • @@ -210,15 +193,13 @@ export default function Home() {
  • [*]
    - Claude Pro Log in with Anthropic to use your Claude Pro or Max - account + Claude Pro Log in with Anthropic to use your Claude Pro or Max account
  • [*]
    - Any model 75+ LLM providers through Models.dev, including local - models + Any model 75+ LLM providers through Models.dev, including local models
  • @@ -238,21 +219,15 @@ export default function Home() {

    With over {config.github.starsFormatted.full} GitHub stars,{" "} {config.stats.contributors} contributors, and almost{" "} - {config.stats.commits} commits, OpenCode is used and trusted by - over {config.stats.monthlyUsers} developers every month. + {config.stats.commits} commits, OpenCode is used and trusted by over{" "} + {config.stats.monthlyUsers} developers every month.

- +
-
Fig 1.
{config.github.starsFormatted.compact}{" "} - GitHub Stars +
Fig 1.
{config.github.starsFormatted.compact} GitHub Stars
- + @@ -440,54 +408,12 @@ export default function Home() { - - - - - - + + + + + + @@ -496,55 +422,13 @@ export default function Home() { - - - + + + - - - + + + @@ -553,55 +437,13 @@ export default function Home() { - - - - + + + + - - + + @@ -610,47 +452,12 @@ export default function Home() { - - - + + + - - + + @@ -659,55 +466,13 @@ export default function Home() { - - - + + + - - - + + + @@ -716,55 +481,13 @@ export default function Home() { - - - - + + + + - - + + @@ -773,62 +496,13 @@ export default function Home() { - - - - - - - + + + + + + + @@ -837,55 +511,13 @@ export default function Home() { - + - - - - - + + + + + @@ -895,54 +527,12 @@ export default function Home() { - - - - - - + + + + + + @@ -951,62 +541,13 @@ export default function Home() { - - - - - - - + + + + + + + @@ -1015,54 +556,12 @@ export default function Home() { - - - - - - + + + + + + @@ -1071,31 +570,19 @@ export default function Home() { - +
-
Fig 2.
{config.stats.contributors}{" "} - Contributors +
Fig 2.
{config.stats.contributors} Contributors
- + @@ -1131,8 +618,7 @@ export default function Home() {
-
Fig 3.
{config.stats.monthlyUsers} Monthly - Devs +
Fig 3.
{config.stats.monthlyUsers} Monthly Devs
@@ -1146,9 +632,8 @@ export default function Home() { [*]

- OpenCode does not store any of your code or context data, so that it can operate - in privacy sensitive environments. Learn more about{" "} - privacy. + OpenCode does not store any of your code or context data, so that it can operate in privacy sensitive + environments. Learn more about privacy.

@@ -1161,9 +646,9 @@ export default function Home() {
  • - OpenCode is an open source agent that helps you write and run code directly from - the terminal. You can pair OpenCode with any AI model, and because it’s - terminal-based you can pair it with your preferred code editor. + OpenCode is an open source agent that helps you write and run code directly from the terminal. You can + pair OpenCode with any AI model, and because it’s terminal-based you can pair it with your preferred + code editor.
  • @@ -1173,32 +658,30 @@ export default function Home() {
  • - Not necessarily, but probably. You’ll need an AI subscription if you want to - connect OpenCode to a paid provider, although you can work with{" "} + Not necessarily, but probably. You’ll need an AI subscription if you want to connect OpenCode to a + paid provider, although you can work with{" "} local models {" "} - for free. While we encourage users to use Zen, OpenCode works - with all popular providers such as OpenAI, Anthropic, xAI etc. + for free. While we encourage users to use Zen, OpenCode works with all popular + providers such as OpenAI, Anthropic, xAI etc.
  • - Yes, for now. We are actively working on a desktop app. Join the waitlist for - early access. + Yes, for now. We are actively working on a desktop app. Join the waitlist for early access.
  • - OpenCode is 100% free to use. Any additional costs will come from your - subscription to a model provider. While OpenCode works with any model provider, we - recommend using Zen. + OpenCode is 100% free to use. Any additional costs will come from your subscription to a model + provider. While OpenCode works with any model provider, we recommend using Zen.
  • - Your data and information is only stored when you create sharable links in - OpenCode. Learn more about share pages. + Your data and information is only stored when you create sharable links in OpenCode. Learn more about{" "} + share pages.
  • @@ -1211,8 +694,8 @@ export default function Home() { MIT License - , meaning anyone can use, modify, or contribute to its development. Anyone from - the community can file issues, submit pull requests, and extend functionality. + , meaning anyone can use, modify, or contribute to its development. Anyone from the community can file + issues, submit pull requests, and extend functionality.
@@ -1222,19 +705,13 @@ export default function Home() {
Access reliable optimized models for coding agents

- Zen gives you access to a handpicked set of AI models that OpenCode has tested and - benchmarked specifically for coding agents. No need to worry about inconsistent - performance and quality across providers, use validated models that work. + Zen gives you access to a handpicked set of AI models that OpenCode has tested and benchmarked + specifically for coding agents. No need to worry about inconsistent performance and quality across + providers, use validated models that work.

- +
- - + +
- +
- +
- + Learn about Zen - + { const customer = await Billing.get() - if (customer?.customerID && customer.customerID !== customerID) - throw new Error("Customer ID mismatch") + if (customer?.customerID && customer.customerID !== customerID) throw new Error("Customer ID mismatch") // set customer metadata if (!customer?.customerID) { @@ -72,8 +70,7 @@ export async function POST(input: APIEvent) { expand: ["payment_method"], }) const paymentMethod = paymentIntent.payment_method - if (!paymentMethod || typeof paymentMethod === "string") - throw new Error("Payment method not expanded") + if (!paymentMethod || typeof paymentMethod === "string") throw new Error("Payment method not expanded") await Database.transaction(async (tx) => { await tx @@ -128,12 +125,7 @@ export async function POST(input: APIEvent) { amount: PaymentTable.amount, }) .from(PaymentTable) - .where( - and( - eq(PaymentTable.paymentID, paymentIntentID), - eq(PaymentTable.workspaceID, workspaceID), - ), - ) + .where(and(eq(PaymentTable.paymentID, paymentIntentID), eq(PaymentTable.workspaceID, workspaceID))) .then((rows) => rows[0]?.amount), ) if (!amount) throw new Error("Payment not found") @@ -144,12 +136,7 @@ export async function POST(input: APIEvent) { .set({ timeRefunded: new Date(body.created * 1000), }) - .where( - and( - eq(PaymentTable.paymentID, paymentIntentID), - eq(PaymentTable.workspaceID, workspaceID), - ), - ) + .where(and(eq(PaymentTable.paymentID, paymentIntentID), eq(PaymentTable.workspaceID, workspaceID))) await tx .update(BillingTable) diff --git a/packages/console/app/src/routes/temp.tsx b/packages/console/app/src/routes/temp.tsx index 59987e4d0..b0aef00e7 100644 --- a/packages/console/app/src/routes/temp.tsx +++ b/packages/console/app/src/routes/temp.tsx @@ -79,19 +79,17 @@ export default function Home() { LSP enabled Automatically loads the right LSPs for the LLM
  • - opencode zen A curated list of models{" "} - provided by opencode + opencode zen A curated list of models provided by opencode{" "} +
  • Multi-session Start multiple agents in parallel on the same project
  • - Shareable links Share a link to any sessions for reference or to - debug + Shareable links Share a link to any sessions for reference or to debug
  • - Claude Pro Log in with Anthropic to use your Claude Pro or Max - account + Claude Pro Log in with Anthropic to use your Claude Pro or Max account
  • Use any model Supports 75+ LLM providers through{" "} diff --git a/packages/console/app/src/routes/workspace-picker.tsx b/packages/console/app/src/routes/workspace-picker.tsx index 4e218227c..fa8cf1d21 100644 --- a/packages/console/app/src/routes/workspace-picker.tsx +++ b/packages/console/app/src/routes/workspace-picker.tsx @@ -85,10 +85,7 @@ export function WorkspacePicker() { {(workspace) => ( - handleSelectWorkspace(workspace.id)} - > + handleSelectWorkspace(workspace.id)}> {workspace.name || workspace.slug} )} @@ -98,11 +95,7 @@ export function WorkspacePicker() { - setStore("showForm", false)} - title="Create New Workspace" - > + setStore("showForm", false)} title="Create New Workspace">

    Billing

    - Manage payments methods. Contact us if you have any - questions. + Manage payments methods. Contact us if you have any questions.

    @@ -164,32 +163,20 @@ export function BillingSection() { placeholder="Enter amount" />
    -
    - + {(err: any) =>
    {err()}
    }
  • @@ -210,10 +197,7 @@ export function BillingSection() {
    - ----} - > + ----}> •••• {billingInfo()?.paymentMethodLast4} @@ -241,9 +225,7 @@ export function BillingSection() { disabled={checkoutSubmission.pending || store.checkoutRedirecting} onClick={onClickCheckout} > - {checkoutSubmission.pending || store.checkoutRedirecting - ? "Loading..." - : "Enable Billing"} + {checkoutSubmission.pending || store.checkoutRedirecting ? "Loading..." : "Enable Billing"}
    diff --git a/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx index e6461ac83..77c017964 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx @@ -104,13 +104,9 @@ export function MonthlyLimitSection() {
    - No usage limit set.

    } - > + No usage limit set.

    }>

    - Current usage for{" "} - {new Date().toLocaleDateString("en-US", { month: "long", timeZone: "UTC" })} is $ + Current usage for {new Date().toLocaleDateString("en-US", { month: "long", timeZone: "UTC" })} is $ {(() => { const dateLastUsed = billingInfo()?.timeMonthlyUsageUpdated if (!dateLastUsed) return "0" diff --git a/packages/console/app/src/routes/workspace/[id]/billing/payment-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/payment-section.tsx index a7218546d..0fb2a0df6 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/payment-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/payment-section.tsx @@ -89,10 +89,7 @@ export function PaymentSection() { } > diff --git a/packages/console/app/src/routes/workspace/[id]/keys/key-section.tsx b/packages/console/app/src/routes/workspace/[id]/keys/key-section.tsx index e1c2c00cf..565981c7f 100644 --- a/packages/console/app/src/routes/workspace/[id]/keys/key-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/keys/key-section.tsx @@ -146,20 +146,14 @@ export function KeySection() { title="Copy API key" > {key.keyDisplay} - } - > + }> {key.email} - + {key.timeUsed ? formatDateForTable(key.timeUsed) : "-"} diff --git a/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx b/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx index 4b2a12fdc..5aa1b969e 100644 --- a/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx @@ -85,12 +85,7 @@ const updateMember = action(async (form: FormData) => { ) }, "member.update") -function MemberRow(props: { - member: any - workspaceID: string - actorID: string - actorRole: string -}) { +function MemberRow(props: { member: any; workspaceID: string; actorID: string; actorRole: string }) { const submission = useSubmission(updateMember) const isCurrentUser = () => props.actorID === props.member.id const isAdmin = () => props.actorRole === "admin" diff --git a/packages/console/app/src/routes/workspace/[id]/model-section.tsx b/packages/console/app/src/routes/workspace/[id]/model-section.tsx index 223d69fc8..7a1980ebe 100644 --- a/packages/console/app/src/routes/workspace/[id]/model-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/model-section.tsx @@ -5,15 +5,7 @@ import { withActor } from "~/context/auth.withActor" import { ZenData } from "@opencode-ai/console-core/model.js" import styles from "./model-section.module.css" import { querySessionInfo } from "../common" -import { - IconAlibaba, - IconAnthropic, - IconMoonshotAI, - IconOpenAI, - IconStealth, - IconXai, - IconZai, -} from "~/component/icon" +import { IconAlibaba, IconAnthropic, IconMoonshotAI, IconOpenAI, IconStealth, IconXai, IconZai } from "~/component/icon" const getModelLab = (modelId: string) => { if (modelId.startsWith("claude")) return "Anthropic" @@ -76,8 +68,7 @@ export function ModelSection() {

    Models

    - Manage which models workspace members can access.{" "} - Learn more. + Manage which models workspace members can access. Learn more.

    diff --git a/packages/console/app/src/routes/workspace/[id]/new-user-section.tsx b/packages/console/app/src/routes/workspace/[id]/new-user-section.tsx index 7b949c661..65edc6847 100644 --- a/packages/console/app/src/routes/workspace/[id]/new-user-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/new-user-section.tsx @@ -43,24 +43,15 @@ export function NewUserSection() {

    Tested & Verified Models

    -

    - We've benchmarked and tested models specifically for coding agents to ensure the best - performance. -

    +

    We've benchmarked and tested models specifically for coding agents to ensure the best performance.

    Highest Quality

    -

    - Access models configured for optimal performance - no downgrades or routing to cheaper - providers. -

    +

    Access models configured for optimal performance - no downgrades or routing to cheaper providers.

    No Lock-in

    -

    - Use Zen with any coding agent, and continue using other providers with opencode - whenever you want. -

    +

    Use Zen with any coding agent, and continue using other providers with opencode whenever you want.

    diff --git a/packages/console/app/src/routes/workspace/[id]/provider-section.tsx b/packages/console/app/src/routes/workspace/[id]/provider-section.tsx index 67314fbdc..5419ed7fb 100644 --- a/packages/console/app/src/routes/workspace/[id]/provider-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/provider-section.tsx @@ -55,10 +55,7 @@ const listProviders = query(async (workspaceID: string) => { function ProviderRow(props: { provider: Provider }) { const params = useParams() const providers = createAsync(() => listProviders(params.id)) - const saveSubmission = useSubmission( - saveProvider, - ([fd]) => fd.get("provider")?.toString() === props.provider.key, - ) + const saveSubmission = useSubmission(saveProvider, ([fd]) => fd.get("provider")?.toString() === props.provider.key) const removeSubmission = useSubmission( removeProvider, ([fd]) => fd.get("provider")?.toString() === props.provider.key, @@ -94,16 +91,9 @@ function ProviderRow(props: { provider: Provider }) { {providerData() ? maskCredentials(providerData()!.credentials) : "-"} - } + fallback={{providerData() ? maskCredentials(providerData()!.credentials) : "-"}} > - +
    (input = r)} diff --git a/packages/console/app/src/routes/workspace/common.tsx b/packages/console/app/src/routes/workspace/common.tsx index 5b638192c..a6eaaeb1e 100644 --- a/packages/console/app/src/routes/workspace/common.tsx +++ b/packages/console/app/src/routes/workspace/common.tsx @@ -67,10 +67,7 @@ export const querySessionInfo = query(async (workspaceID: string) => { return withActor(() => { return { isAdmin: Actor.userRole() === "admin", - isBeta: - Resource.App.stage === "production" - ? workspaceID === "wrk_01K46JDFR0E75SG2Q8K172KF3Y" - : true, + isBeta: Resource.App.stage === "production" ? workspaceID === "wrk_01K46JDFR0E75SG2Q8K172KF3Y" : true, } }, workspaceID) }, "session.get") diff --git a/packages/console/app/src/routes/zen/index.tsx b/packages/console/app/src/routes/zen/index.tsx index a096b52d7..4eab4dcb9 100644 --- a/packages/console/app/src/routes/zen/index.tsx +++ b/packages/console/app/src/routes/zen/index.tsx @@ -29,10 +29,7 @@ export default function Home() { createAsync(() => checkLoggedIn()) return (
    - + OpenCode Zen | A curated set of reliable optimized models for coding agents @@ -49,19 +46,13 @@ export default function Home() { zen logo dark

    Reliable optimized models for coding agents

    - Zen gives you access to a curated set of AI models that OpenCode has tested and - benchmarked specifically for coding agents. No need to worry about inconsistent - performance and quality, use validated models that work. + Zen gives you access to a curated set of AI models that OpenCode has tested and benchmarked specifically + for coding agents. No need to worry about inconsistent performance and quality, use validated models + that work.

    - +
    - - + +
    - +
    - +
    - + Get started with Zen - +

    - Add $20 Pay as you go balance{" "} - (+$1.23 card processing fee) + Add $20 Pay as you go balance (+$1.23 card processing fee)

    Use with any agent. Set monthly spend limits. Cancel any time.

    -
    @@ -193,8 +142,8 @@ export default function Home() {

    What problem is Zen solving?

    - There are so many models available, but only a few work well with coding agents. - Most providers configure them differently with varying results. + There are so many models available, but only a few work well with coding agents. Most providers + configure them differently with varying results.

    We're fixing this for everyone, not just OpenCode users.

    @@ -229,15 +178,14 @@ export default function Home() {
  • [2]
    - Use Zen with transparent pricing -{" "} - pay per request with zero markups + Use Zen with transparent pricing - pay per request{" "} + with zero markups
  • [3]
    - Auto-top up - when your balance reaches $5 we’ll automatically - add $20 + Auto-top up - when your balance reaches $5 we’ll automatically add $20
  • @@ -249,9 +197,8 @@ export default function Home() {
    [*]

    - All Zen models are hosted in the US. Providers follow a zero-retention policy and - do not use your data for model training, with the{" "} - following exceptions. + All Zen models are hosted in the US. Providers follow a zero-retention policy and do not use your data + for model training, with the following exceptions.

    @@ -306,8 +253,7 @@ export default function Home() { ex-Head of Design, Laravel
    - With @OpenCode Zen I know all the models are tested and perfect for - coding agents. + With @OpenCode Zen I know all the models are tested and perfect for coding agents.
    @@ -331,44 +277,38 @@ export default function Home() {
    • - Zen is a curated set of AI models tested and benchmarked for coding agents created - by the team behind OpenCode. + Zen is a curated set of AI models tested and benchmarked for coding agents created by the team behind + OpenCode.
    • - Zen only provides models that have been specifically tested and benchmarked for - coding agents. You wouldn’t use a butter knife to cut steak, don’t use poor models - for coding. + Zen only provides models that have been specifically tested and benchmarked for coding agents. You + wouldn’t use a butter knife to cut steak, don’t use poor models for coding.
    • - Zen is not for profit. Zen passes through the costs from the model providers to - you. The higher Zen’s usage the more OpenCode can negotiate better rates and pass - those to you. + Zen is not for profit. Zen passes through the costs from the model providers to you. The higher Zen’s + usage the more OpenCode can negotiate better rates and pass those to you.
    • - Zen charges per request with zero markups, so you - pay exactly what the model provider charges. Your total cost depends on usage, and - you can set monthly spend limits in your account. To cover - costs, OpenCode adds only a small payment processing fee of $1.23 per $20 balance - top-up. + Zen charges per request with zero markups, so you pay exactly what + the model provider charges. Your total cost depends on usage, and you can set monthly spend limits in + your account. To cover costs, OpenCode adds only a small payment processing fee of + $1.23 per $20 balance top-up.
    • - All Zen models are hosted in the US. Providers follow a zero-retention policy and - do not use your data for model training, with the{" "} - following exceptions. + All Zen models are hosted in the US. Providers follow a zero-retention policy and do not use your data + for model training, with the following exceptions.
    • - - Yes, you can set monthly spending limits in your account. - + Yes, you can set monthly spending limits in your account.
    • @@ -377,8 +317,8 @@ export default function Home() {
    • - While Zen works great with OpenCode, you can use Zen with any agent. Follow the - setup instructions in your preferred coding agent. + While Zen works great with OpenCode, you can use Zen with any agent. Follow the setup instructions in + your preferred coding agent.
    diff --git a/packages/console/app/src/routes/zen/util/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts index deab7ded2..194a7c71e 100644 --- a/packages/console/app/src/routes/zen/util/handler.ts +++ b/packages/console/app/src/routes/zen/util/handler.ts @@ -13,11 +13,7 @@ import { ModelTable } from "@opencode-ai/console-core/schema/model.sql.js" import { ProviderTable } from "@opencode-ai/console-core/schema/provider.sql.js" import { logger } from "./logger" import { AuthError, CreditsError, MonthlyLimitError, UserLimitError, ModelError } from "./error" -import { - createBodyConverter, - createStreamPartConverter, - createResponseConverter, -} from "./provider/provider" +import { createBodyConverter, createStreamPartConverter, createResponseConverter } from "./provider/provider" import { anthropicHelper } from "./provider/anthropic" import { openaiHelper } from "./provider/openai" import { oaCompatHelper } from "./provider/openai-compatible" @@ -46,11 +42,7 @@ export async function handler( }) const zenData = ZenData.list() const modelInfo = validateModel(zenData, body.model) - const providerInfo = selectProvider( - zenData, - modelInfo, - input.request.headers.get("x-real-ip") ?? "", - ) + const providerInfo = selectProvider(zenData, modelInfo, input.request.headers.get("x-real-ip") ?? "") const authInfo = await authenticate(modelInfo, providerInfo) validateBilling(modelInfo, authInfo) validateModelSettings(authInfo) @@ -229,11 +221,7 @@ export async function handler( return { id: modelId, ...modelData } } - function selectProvider( - zenData: ZenData, - model: Awaited>, - ip: string, - ) { + function selectProvider(zenData: ZenData, model: Awaited>, ip: string) { const providers = model.providers .filter((provider) => !provider.disabled) .flatMap((provider) => Array(provider.weight ?? 1).fill(provider)) @@ -252,11 +240,7 @@ export async function handler( return { ...provider, ...zenData.providers[provider.id], - ...(format === "anthropic" - ? anthropicHelper - : format === "openai" - ? openaiHelper - : oaCompatHelper), + ...(format === "anthropic" ? anthropicHelper : format === "openai" ? openaiHelper : oaCompatHelper), } } @@ -297,20 +281,11 @@ export async function handler( .from(KeyTable) .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID)) .innerJoin(BillingTable, eq(BillingTable.workspaceID, KeyTable.workspaceID)) - .innerJoin( - UserTable, - and(eq(UserTable.workspaceID, KeyTable.workspaceID), eq(UserTable.id, KeyTable.userID)), - ) - .leftJoin( - ModelTable, - and(eq(ModelTable.workspaceID, KeyTable.workspaceID), eq(ModelTable.model, model.id)), - ) + .innerJoin(UserTable, and(eq(UserTable.workspaceID, KeyTable.workspaceID), eq(UserTable.id, KeyTable.userID))) + .leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), eq(ModelTable.model, model.id))) .leftJoin( ProviderTable, - and( - eq(ProviderTable.workspaceID, KeyTable.workspaceID), - eq(ProviderTable.provider, providerInfo.id), - ), + and(eq(ProviderTable.workspaceID, KeyTable.workspaceID), eq(ProviderTable.provider, providerInfo.id)), ) .where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted))) .then((rows) => rows[0]), @@ -401,19 +376,12 @@ export async function handler( providerInfo: Awaited>, usage: any, ) { - const { - inputTokens, - outputTokens, - reasoningTokens, - cacheReadTokens, - cacheWrite5mTokens, - cacheWrite1hTokens, - } = providerInfo.normalizeUsage(usage) + const { inputTokens, outputTokens, reasoningTokens, cacheReadTokens, cacheWrite5mTokens, cacheWrite1hTokens } = + providerInfo.normalizeUsage(usage) const modelCost = modelInfo.cost200K && - inputTokens + (cacheReadTokens ?? 0) + (cacheWrite5mTokens ?? 0) + (cacheWrite1hTokens ?? 0) > - 200_000 + inputTokens + (cacheReadTokens ?? 0) + (cacheWrite5mTokens ?? 0) + (cacheWrite1hTokens ?? 0) > 200_000 ? modelInfo.cost200K : modelInfo.cost @@ -464,8 +432,7 @@ export async function handler( if (!authInfo) return - const cost = - authInfo.isFree || authInfo.provider?.credentials ? 0 : centsToMicroCents(totalCostInCent) + const cost = authInfo.isFree || authInfo.provider?.credentials ? 0 : centsToMicroCents(totalCostInCent) await Database.transaction(async (tx) => { await tx.insert(UsageTable).values({ workspaceID: authInfo.workspaceID, @@ -505,9 +472,7 @@ export async function handler( `, timeMonthlyUsageUpdated: sql`now()`, }) - .where( - and(eq(UserTable.workspaceID, authInfo.workspaceID), eq(UserTable.id, authInfo.user.id)), - ) + .where(and(eq(UserTable.workspaceID, authInfo.workspaceID), eq(UserTable.id, authInfo.user.id))) }) await Database.use((tx) => @@ -537,10 +502,7 @@ export async function handler( BillingTable.balance, centsToMicroCents((authInfo.billing.reloadTrigger ?? Billing.RELOAD_TRIGGER) * 100), ), - or( - isNull(BillingTable.timeReloadLockedTill), - lt(BillingTable.timeReloadLockedTill, sql`now()`), - ), + or(isNull(BillingTable.timeReloadLockedTill), lt(BillingTable.timeReloadLockedTill, sql`now()`)), ), ), ) diff --git a/packages/console/app/src/routes/zen/util/provider/anthropic.ts b/packages/console/app/src/routes/zen/util/provider/anthropic.ts index f4e8dc44d..d8d1cd741 100644 --- a/packages/console/app/src/routes/zen/util/provider/anthropic.ts +++ b/packages/console/app/src/routes/zen/util/provider/anthropic.ts @@ -123,15 +123,12 @@ export function fromAnthropicRequest(body: any): CommonRequest { if ((p as any).type === "tool_result") { const id = (p as any).tool_use_id const content = - typeof (p as any).content === "string" - ? (p as any).content - : JSON.stringify((p as any).content) + typeof (p as any).content === "string" ? (p as any).content : JSON.stringify((p as any).content) msgs.push({ role: "tool", tool_call_id: id, content }) } } if (partsOut.length > 0) { - if (partsOut.length === 1 && partsOut[0].type === "text") - msgs.push({ role: "user", content: partsOut[0].text }) + if (partsOut.length === 1 && partsOut[0].type === "text") msgs.push({ role: "user", content: partsOut[0].text }) else msgs.push({ role: "user", content: partsOut }) } continue @@ -143,8 +140,7 @@ export function fromAnthropicRequest(body: any): CommonRequest { const tcs: any[] = [] for (const p of partsIn) { if (!p || !(p as any).type) continue - if ((p as any).type === "text" && typeof (p as any).text === "string") - texts.push((p as any).text) + if ((p as any).type === "text" && typeof (p as any).text === "string") texts.push((p as any).text) if ((p as any).type === "tool_use") { const name = (p as any).name const id = (p as any).id @@ -214,9 +210,7 @@ export function fromAnthropicRequest(body: any): CommonRequest { export function toAnthropicRequest(body: CommonRequest) { if (!body || typeof body !== "object") return body - const sysIn = Array.isArray(body.messages) - ? body.messages.filter((m: any) => m && m.role === "system") - : [] + const sysIn = Array.isArray(body.messages) ? body.messages.filter((m: any) => m && m.role === "system") : [] let ccCount = 0 const cc = () => { ccCount++ @@ -367,9 +361,7 @@ export function fromAnthropicResponse(resp: any): CommonResponse { const idIn = (resp as any).id const id = - typeof idIn === "string" - ? idIn.replace(/^msg_/, "chatcmpl_") - : `chatcmpl_${Math.random().toString(36).slice(2)}` + typeof idIn === "string" ? idIn.replace(/^msg_/, "chatcmpl_") : `chatcmpl_${Math.random().toString(36).slice(2)}` const model = (resp as any).model const blocks: any[] = Array.isArray((resp as any).content) ? (resp as any).content : [] @@ -412,9 +404,7 @@ export function fromAnthropicResponse(resp: any): CommonResponse { const ct = typeof (u as any).output_tokens === "number" ? (u as any).output_tokens : undefined const total = pt != null && ct != null ? pt + ct : undefined const cached = - typeof (u as any).cache_read_input_tokens === "number" - ? (u as any).cache_read_input_tokens - : undefined + typeof (u as any).cache_read_input_tokens === "number" ? (u as any).cache_read_input_tokens : undefined const details = cached != null ? { cached_tokens: cached } : undefined return { prompt_tokens: pt, @@ -591,9 +581,7 @@ export function fromAnthropicChunk(chunk: string): CommonChunk | string { prompt_tokens: u.input_tokens, completion_tokens: u.output_tokens, total_tokens: (u.input_tokens || 0) + (u.output_tokens || 0), - ...(u.cache_read_input_tokens - ? { prompt_tokens_details: { cached_tokens: u.cache_read_input_tokens } } - : {}), + ...(u.cache_read_input_tokens ? { prompt_tokens_details: { cached_tokens: u.cache_read_input_tokens } } : {}), } } diff --git a/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts b/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts index d69985728..8a9170ef1 100644 --- a/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts +++ b/packages/console/app/src/routes/zen/util/provider/openai-compatible.ts @@ -57,8 +57,7 @@ export const oaCompatHelper = { const inputTokens = usage.prompt_tokens ?? 0 const outputTokens = usage.completion_tokens ?? 0 const reasoningTokens = usage.completion_tokens_details?.reasoning_tokens ?? undefined - const cacheReadTokens = - usage.cached_tokens ?? usage.prompt_tokens_details?.cached_tokens ?? undefined + const cacheReadTokens = usage.cached_tokens ?? usage.prompt_tokens_details?.cached_tokens ?? undefined return { inputTokens: inputTokens - (cacheReadTokens ?? 0), outputTokens, @@ -80,8 +79,7 @@ export function fromOaCompatibleRequest(body: any): CommonRequest { if (!m || !m.role) continue if (m.role === "system") { - if (typeof m.content === "string" && m.content.length > 0) - msgsOut.push({ role: "system", content: m.content }) + if (typeof m.content === "string" && m.content.length > 0) msgsOut.push({ role: "system", content: m.content }) continue } @@ -92,12 +90,10 @@ export function fromOaCompatibleRequest(body: any): CommonRequest { const parts: any[] = [] for (const p of m.content) { if (!p || !p.type) continue - if (p.type === "text" && typeof p.text === "string") - parts.push({ type: "text", text: p.text }) + if (p.type === "text" && typeof p.text === "string") parts.push({ type: "text", text: p.text }) if (p.type === "image_url") parts.push({ type: "image_url", image_url: p.image_url }) } - if (parts.length === 1 && parts[0].type === "text") - msgsOut.push({ role: "user", content: parts[0].text }) + if (parts.length === 1 && parts[0].type === "text") msgsOut.push({ role: "user", content: parts[0].text }) else if (parts.length > 0) msgsOut.push({ role: "user", content: parts }) } continue @@ -141,8 +137,7 @@ export function toOaCompatibleRequest(body: CommonRequest) { if (p.type === "image_url" && p.image_url) return { type: "image_url", image_url: p.image_url } const s = (p as any).source if (!s || typeof s !== "object") return undefined - if (s.type === "url" && typeof s.url === "string") - return { type: "image_url", image_url: { url: s.url } } + if (s.type === "url" && typeof s.url === "string") return { type: "image_url", image_url: { url: s.url } } if (s.type === "base64" && typeof s.media_type === "string" && typeof s.data === "string") return { type: "image_url", image_url: { url: `data:${s.media_type};base64,${s.data}` } } return undefined @@ -152,8 +147,7 @@ export function toOaCompatibleRequest(body: CommonRequest) { if (!m || !m.role) continue if (m.role === "system") { - if (typeof m.content === "string" && m.content.length > 0) - msgsOut.push({ role: "system", content: m.content }) + if (typeof m.content === "string" && m.content.length > 0) msgsOut.push({ role: "system", content: m.content }) continue } @@ -166,13 +160,11 @@ export function toOaCompatibleRequest(body: CommonRequest) { const parts: any[] = [] for (const p of m.content) { if (!p || !p.type) continue - if (p.type === "text" && typeof p.text === "string") - parts.push({ type: "text", text: p.text }) + if (p.type === "text" && typeof p.text === "string") parts.push({ type: "text", text: p.text }) const ip = toImg(p) if (ip) parts.push(ip) } - if (parts.length === 1 && parts[0].type === "text") - msgsOut.push({ role: "user", content: parts[0].text }) + if (parts.length === 1 && parts[0].type === "text") msgsOut.push({ role: "user", content: parts[0].text }) else if (parts.length > 0) msgsOut.push({ role: "user", content: parts }) } continue @@ -325,9 +317,7 @@ export function toOaCompatibleResponse(resp: CommonResponse) { const idIn = (resp as any).id const id = - typeof idIn === "string" - ? idIn.replace(/^msg_/, "chatcmpl_") - : `chatcmpl_${Math.random().toString(36).slice(2)}` + typeof idIn === "string" ? idIn.replace(/^msg_/, "chatcmpl_") : `chatcmpl_${Math.random().toString(36).slice(2)}` const model = (resp as any).model const blocks: any[] = Array.isArray((resp as any).content) ? (resp as any).content : [] @@ -369,8 +359,7 @@ export function toOaCompatibleResponse(resp: CommonResponse) { const pt = typeof u.input_tokens === "number" ? u.input_tokens : undefined const ct = typeof u.output_tokens === "number" ? u.output_tokens : undefined const total = pt != null && ct != null ? pt + ct : undefined - const cached = - typeof u.cache_read_input_tokens === "number" ? u.cache_read_input_tokens : undefined + const cached = typeof u.cache_read_input_tokens === "number" ? u.cache_read_input_tokens : undefined const details = cached != null ? { cached_tokens: cached } : undefined return { prompt_tokens: pt, diff --git a/packages/console/app/src/routes/zen/util/provider/openai.ts b/packages/console/app/src/routes/zen/util/provider/openai.ts index fa0776b7a..e79e83579 100644 --- a/packages/console/app/src/routes/zen/util/provider/openai.ts +++ b/packages/console/app/src/routes/zen/util/provider/openai.ts @@ -86,11 +86,7 @@ export function fromOpenaiRequest(body: any): CommonRequest { const msgs: any[] = [] - const inMsgs = Array.isArray(body.input) - ? body.input - : Array.isArray(body.messages) - ? body.messages - : [] + const inMsgs = Array.isArray(body.input) ? body.input : Array.isArray(body.messages) ? body.messages : [] for (const m of inMsgs) { if (!m) continue @@ -103,9 +99,7 @@ export function fromOpenaiRequest(body: any): CommonRequest { const args = typeof a === "string" ? a : JSON.stringify(a ?? {}) msgs.push({ role: "assistant", - tool_calls: [ - { id: (m as any).id, type: "function", function: { name, arguments: args } }, - ], + tool_calls: [{ id: (m as any).id, type: "function", function: { name, arguments: args } }], }) } if ((m as any).type === "function_call_output") { @@ -122,8 +116,7 @@ export function fromOpenaiRequest(body: any): CommonRequest { if (typeof c === "string" && c.length > 0) msgs.push({ role: "system", content: c }) if (Array.isArray(c)) { const t = c.find((p: any) => p && typeof p.text === "string") - if (t && typeof t.text === "string" && t.text.length > 0) - msgs.push({ role: "system", content: t.text }) + if (t && typeof t.text === "string" && t.text.length > 0) msgs.push({ role: "system", content: t.text }) } continue } @@ -136,24 +129,18 @@ export function fromOpenaiRequest(body: any): CommonRequest { const parts: any[] = [] for (const p of c) { if (!p || !(p as any).type) continue - if ( - ((p as any).type === "text" || (p as any).type === "input_text") && - typeof (p as any).text === "string" - ) + if (((p as any).type === "text" || (p as any).type === "input_text") && typeof (p as any).text === "string") parts.push({ type: "text", text: (p as any).text }) const ip = toImg(p) if (ip) parts.push(ip) if ((p as any).type === "tool_result") { const id = (p as any).tool_call_id const content = - typeof (p as any).content === "string" - ? (p as any).content - : JSON.stringify((p as any).content) + typeof (p as any).content === "string" ? (p as any).content : JSON.stringify((p as any).content) msgs.push({ role: "tool", tool_call_id: id, content }) } } - if (parts.length === 1 && parts[0].type === "text") - msgs.push({ role: "user", content: parts[0].text }) + if (parts.length === 1 && parts[0].type === "text") msgs.push({ role: "user", content: parts[0].text }) else if (parts.length > 0) msgs.push({ role: "user", content: parts }) } continue @@ -280,10 +267,7 @@ export function toOpenaiRequest(body: CommonRequest) { } if ((m as any).role === "tool") { - const out = - typeof (m as any).content === "string" - ? (m as any).content - : JSON.stringify((m as any).content) + const out = typeof (m as any).content === "string" ? (m as any).content : JSON.stringify((m as any).content) input.push({ type: "function_call_output", call_id: (m as any).tool_call_id, output: out }) continue } @@ -351,9 +335,7 @@ export function fromOpenaiResponse(resp: any): CommonResponse { const idIn = (r as any).id const id = - typeof idIn === "string" - ? idIn.replace(/^resp_/, "chatcmpl_") - : `chatcmpl_${Math.random().toString(36).slice(2)}` + typeof idIn === "string" ? idIn.replace(/^resp_/, "chatcmpl_") : `chatcmpl_${Math.random().toString(36).slice(2)}` const model = (r as any).model ?? (resp as any).model const out = Array.isArray((r as any).output) ? (r as any).output : [] @@ -480,9 +462,7 @@ export function toOpenaiResponse(resp: CommonResponse) { })() return { - id: - (resp as any).id?.replace(/^chatcmpl_/, "resp_") ?? - `resp_${Math.random().toString(36).slice(2)}`, + id: (resp as any).id?.replace(/^chatcmpl_/, "resp_") ?? `resp_${Math.random().toString(36).slice(2)}`, object: "response", model: (resp as any).model, output: outputItems, diff --git a/packages/console/app/src/routes/zen/v1/models.ts b/packages/console/app/src/routes/zen/v1/models.ts index 3d0c31470..ee2b3ab54 100644 --- a/packages/console/app/src/routes/zen/v1/models.ts +++ b/packages/console/app/src/routes/zen/v1/models.ts @@ -50,10 +50,7 @@ export async function GET(input: APIEvent) { }) .from(KeyTable) .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID)) - .leftJoin( - ModelTable, - and(eq(ModelTable.workspaceID, KeyTable.workspaceID), isNull(ModelTable.timeDeleted)), - ) + .leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), isNull(ModelTable.timeDeleted))) .where(and(eq(KeyTable.key, apiKey), isNull(KeyTable.timeDeleted))) .then((rows) => rows.map((row) => row.model)), ) diff --git a/packages/console/app/src/style/token/font.css b/packages/console/app/src/style/token/font.css index dc0d298f1..67143e662 100644 --- a/packages/console/app/src/style/token/font.css +++ b/packages/console/app/src/style/token/font.css @@ -15,7 +15,6 @@ body { --font-size-9xl: 8rem; --font-mono: - "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", - "Courier New", monospace; + "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; --font-sans: var(--font-mono); } diff --git a/packages/console/core/script/lookup-user.ts b/packages/console/core/script/lookup-user.ts index af9bcc3a1..1ae18c4dd 100644 --- a/packages/console/core/script/lookup-user.ts +++ b/packages/console/core/script/lookup-user.ts @@ -8,22 +8,15 @@ if (!email) { process.exit(1) } -const authData = await printTable("Auth", (tx) => - tx.select().from(AuthTable).where(eq(AuthTable.subject, email)), -) +const authData = await printTable("Auth", (tx) => tx.select().from(AuthTable).where(eq(AuthTable.subject, email))) if (authData.length === 0) { console.error("User not found") process.exit(1) } -await printTable("Auth", (tx) => - tx.select().from(AuthTable).where(eq(AuthTable.accountID, authData[0].accountID)), -) +await printTable("Auth", (tx) => tx.select().from(AuthTable).where(eq(AuthTable.accountID, authData[0].accountID))) -function printTable( - title: string, - callback: (tx: Database.TxOrDb) => Promise, -): Promise { +function printTable(title: string, callback: (tx: Database.TxOrDb) => Promise): Promise { return Database.use(async (tx) => { const data = await callback(tx) console.log(`== ${title} ==`) diff --git a/packages/console/core/script/reset-db.ts b/packages/console/core/script/reset-db.ts index bd00e1962..02d498901 100644 --- a/packages/console/core/script/reset-db.ts +++ b/packages/console/core/script/reset-db.ts @@ -8,14 +8,6 @@ import { KeyTable } from "../src/schema/key.sql.js" if (Resource.App.stage !== "frank") throw new Error("This script is only for frank") -for (const table of [ - AccountTable, - BillingTable, - KeyTable, - PaymentTable, - UsageTable, - UserTable, - WorkspaceTable, -]) { +for (const table of [AccountTable, BillingTable, KeyTable, PaymentTable, UsageTable, UserTable, WorkspaceTable]) { await Database.use((tx) => tx.delete(table)) } diff --git a/packages/console/core/src/aws.ts b/packages/console/core/src/aws.ts index ce4a20f44..e87ada6ef 100644 --- a/packages/console/core/src/aws.ts +++ b/packages/console/core/src/aws.ts @@ -24,40 +24,37 @@ export namespace AWS { body: z.string(), }), async (input) => { - const res = await createClient().fetch( - "https://email.us-east-1.amazonaws.com/v2/email/outbound-emails", - { - method: "POST", - headers: { - "X-Amz-Target": "SES.SendEmail", - "Content-Type": "application/json", + const res = await createClient().fetch("https://email.us-east-1.amazonaws.com/v2/email/outbound-emails", { + method: "POST", + headers: { + "X-Amz-Target": "SES.SendEmail", + "Content-Type": "application/json", + }, + body: JSON.stringify({ + FromEmailAddress: `OpenCode Zen `, + Destination: { + ToAddresses: [input.to], }, - body: JSON.stringify({ - FromEmailAddress: `OpenCode Zen `, - Destination: { - ToAddresses: [input.to], - }, - Content: { - Simple: { - Subject: { + Content: { + Simple: { + Subject: { + Charset: "UTF-8", + Data: input.subject, + }, + Body: { + Text: { Charset: "UTF-8", - Data: input.subject, + Data: input.body, }, - Body: { - Text: { - Charset: "UTF-8", - Data: input.body, - }, - Html: { - Charset: "UTF-8", - Data: input.body, - }, + Html: { + Charset: "UTF-8", + Data: input.body, }, }, }, - }), - }, - ) + }, + }), + }) if (!res.ok) { throw new Error(`Failed to send email: ${res.statusText}`) } diff --git a/packages/console/core/src/drizzle/index.ts b/packages/console/core/src/drizzle/index.ts index 8b37b1f9c..f0f065de4 100644 --- a/packages/console/core/src/drizzle/index.ts +++ b/packages/console/core/src/drizzle/index.ts @@ -5,10 +5,7 @@ import { Client } from "@planetscale/database" import { MySqlTransaction, type MySqlTransactionConfig } from "drizzle-orm/mysql-core" import type { ExtractTablesWithRelations } from "drizzle-orm" -import type { - PlanetScalePreparedQueryHKT, - PlanetscaleQueryResultHKT, -} from "drizzle-orm/planetscale-serverless" +import type { PlanetScalePreparedQueryHKT, PlanetscaleQueryResultHKT } from "drizzle-orm/planetscale-serverless" import { Context } from "../context" import { memo } from "../util/memo" @@ -70,10 +67,7 @@ export namespace Database { } } - export async function transaction( - callback: (tx: TxOrDb) => Promise, - config?: MySqlTransactionConfig, - ) { + export async function transaction(callback: (tx: TxOrDb) => Promise, config?: MySqlTransactionConfig) { try { const { tx } = TransactionContext.use() return callback(tx) diff --git a/packages/console/core/src/key.ts b/packages/console/core/src/key.ts index 6396fd0b8..688f19b3d 100644 --- a/packages/console/core/src/key.ts +++ b/packages/console/core/src/key.ts @@ -20,14 +20,8 @@ export namespace Key { email: AuthTable.subject, }) .from(KeyTable) - .innerJoin( - UserTable, - and(eq(KeyTable.userID, UserTable.id), eq(KeyTable.workspaceID, UserTable.workspaceID)), - ) - .innerJoin( - AuthTable, - and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")), - ) + .innerJoin(UserTable, and(eq(KeyTable.userID, UserTable.id), eq(KeyTable.workspaceID, UserTable.workspaceID))) + .innerJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email"))) .where( and( ...[ diff --git a/packages/console/core/src/model.ts b/packages/console/core/src/model.ts index 30cc15e45..ea719534d 100644 --- a/packages/console/core/src/model.ts +++ b/packages/console/core/src/model.ts @@ -60,9 +60,7 @@ export namespace Model { export const enable = fn(z.object({ model: z.string() }), ({ model }) => { Actor.assertAdmin() return Database.use((db) => - db - .delete(ModelTable) - .where(and(eq(ModelTable.workspaceID, Actor.workspace()), eq(ModelTable.model, model))), + db.delete(ModelTable).where(and(eq(ModelTable.workspaceID, Actor.workspace()), eq(ModelTable.model, model))), ) }) diff --git a/packages/console/core/src/provider.ts b/packages/console/core/src/provider.ts index 0af642f71..cf2040b59 100644 --- a/packages/console/core/src/provider.ts +++ b/packages/console/core/src/provider.ts @@ -11,9 +11,7 @@ export namespace Provider { tx .select() .from(ProviderTable) - .where( - and(eq(ProviderTable.workspaceID, Actor.workspace()), isNull(ProviderTable.timeDeleted)), - ), + .where(and(eq(ProviderTable.workspaceID, Actor.workspace()), isNull(ProviderTable.timeDeleted))), ), ) @@ -52,12 +50,7 @@ export namespace Provider { return Database.transaction((tx) => tx .delete(ProviderTable) - .where( - and( - eq(ProviderTable.provider, provider), - eq(ProviderTable.workspaceID, Actor.workspace()), - ), - ), + .where(and(eq(ProviderTable.provider, provider), eq(ProviderTable.workspaceID, Actor.workspace()))), ) }, ) diff --git a/packages/console/core/src/schema/auth.sql.ts b/packages/console/core/src/schema/auth.sql.ts index d55e605aa..27c926d6f 100644 --- a/packages/console/core/src/schema/auth.sql.ts +++ b/packages/console/core/src/schema/auth.sql.ts @@ -1,11 +1,4 @@ -import { - index, - mysqlEnum, - mysqlTable, - primaryKey, - uniqueIndex, - varchar, -} from "drizzle-orm/mysql-core" +import { index, mysqlEnum, mysqlTable, primaryKey, uniqueIndex, varchar } from "drizzle-orm/mysql-core" import { id, timestamps, ulid } from "../drizzle/types" export const AuthProvider = ["email", "github", "google"] as const diff --git a/packages/console/core/src/schema/model.sql.ts b/packages/console/core/src/schema/model.sql.ts index 343b0c4f3..1c032aad2 100644 --- a/packages/console/core/src/schema/model.sql.ts +++ b/packages/console/core/src/schema/model.sql.ts @@ -9,8 +9,5 @@ export const ModelTable = mysqlTable( ...timestamps, model: varchar("model", { length: 64 }).notNull(), }, - (table) => [ - ...workspaceIndexes(table), - uniqueIndex("model_workspace_model").on(table.workspaceID, table.model), - ], + (table) => [...workspaceIndexes(table), uniqueIndex("model_workspace_model").on(table.workspaceID, table.model)], ) diff --git a/packages/console/core/src/schema/provider.sql.ts b/packages/console/core/src/schema/provider.sql.ts index 04d11e2e5..11be5b4d7 100644 --- a/packages/console/core/src/schema/provider.sql.ts +++ b/packages/console/core/src/schema/provider.sql.ts @@ -10,8 +10,5 @@ export const ProviderTable = mysqlTable( provider: varchar("provider", { length: 64 }).notNull(), credentials: text("credentials").notNull(), }, - (table) => [ - ...workspaceIndexes(table), - uniqueIndex("workspace_provider").on(table.workspaceID, table.provider), - ], + (table) => [...workspaceIndexes(table), uniqueIndex("workspace_provider").on(table.workspaceID, table.provider)], ) diff --git a/packages/console/core/src/schema/user.sql.ts b/packages/console/core/src/schema/user.sql.ts index ce5b6c53e..7fd7f5e1e 100644 --- a/packages/console/core/src/schema/user.sql.ts +++ b/packages/console/core/src/schema/user.sql.ts @@ -1,12 +1,4 @@ -import { - mysqlTable, - uniqueIndex, - varchar, - int, - mysqlEnum, - index, - bigint, -} from "drizzle-orm/mysql-core" +import { mysqlTable, uniqueIndex, varchar, int, mysqlEnum, index, bigint } from "drizzle-orm/mysql-core" import { timestamps, ulid, utc, workspaceColumns } from "../drizzle/types" import { workspaceIndexes } from "./workspace.sql" diff --git a/packages/console/core/src/user.ts b/packages/console/core/src/user.ts index cbb1ac827..8b7a96f44 100644 --- a/packages/console/core/src/user.ts +++ b/packages/console/core/src/user.ts @@ -26,10 +26,7 @@ export namespace User { authEmail: AuthTable.subject, }) .from(UserTable) - .leftJoin( - AuthTable, - and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")), - ) + .leftJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email"))) .where(and(eq(UserTable.workspaceID, Actor.workspace()), isNull(UserTable.timeDeleted))), ), ) @@ -39,13 +36,7 @@ export namespace User { tx .select() .from(UserTable) - .where( - and( - eq(UserTable.workspaceID, Actor.workspace()), - eq(UserTable.id, id), - isNull(UserTable.timeDeleted), - ), - ) + .where(and(eq(UserTable.workspaceID, Actor.workspace()), eq(UserTable.id, id), isNull(UserTable.timeDeleted))) .then((rows) => rows[0]), ), ) @@ -57,10 +48,7 @@ export namespace User { email: AuthTable.subject, }) .from(UserTable) - .leftJoin( - AuthTable, - and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")), - ) + .leftJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email"))) .where(and(eq(UserTable.workspaceID, Actor.workspace()), eq(UserTable.id, id))) .then((rows) => rows[0]?.email), ), @@ -142,16 +130,10 @@ export namespace User { workspaceName: WorkspaceTable.name, }) .from(UserTable) - .innerJoin( - AuthTable, - and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email")), - ) + .innerJoin(AuthTable, and(eq(UserTable.accountID, AuthTable.accountID), eq(AuthTable.provider, "email"))) .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, workspaceID)) .where( - and( - eq(UserTable.workspaceID, workspaceID), - eq(UserTable.id, Actor.assert("user").properties.userID), - ), + and(eq(UserTable.workspaceID, workspaceID), eq(UserTable.id, Actor.assert("user").properties.userID)), ) .then((rows) => rows[0]), ) diff --git a/packages/console/mail/emails/templates/InviteEmail.tsx b/packages/console/mail/emails/templates/InviteEmail.tsx index e94eb564c..baf0d383f 100644 --- a/packages/console/mail/emails/templates/InviteEmail.tsx +++ b/packages/console/mail/emails/templates/InviteEmail.tsx @@ -1,18 +1,6 @@ // @ts-nocheck import React from "react" -import { - Img, - Row, - Html, - Link, - Body, - Head, - Button, - Column, - Preview, - Section, - Container, -} from "@jsx-email/all" +import { Img, Row, Html, Link, Body, Head, Button, Column, Preview, Section, Container } from "@jsx-email/all" import { Text, Fonts, Title, A, Span } from "../components" import { unit, @@ -64,8 +52,8 @@ export const InviteEmail = ({
    Join your team's OpenCode workspace - You have been invited by {inviter} to join - the {workspaceName} workspace on OpenCode. + You have been invited by {inviter} to join the{" "} + {workspaceName} workspace on OpenCode.
    @@ -73,12 +61,7 @@ export const InviteEmail = ({ -- cgit v1.2.3 From 17479795680d334c036f29f46966bcdfe8526d5e Mon Sep 17 00:00:00 2001 From: opencode Date: Sat, 8 Nov 2025 02:25:51 +0000 Subject: release: v1.0.45 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/extensions/zed/extension.toml | 12 ++++++------ packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 4 ++-- packages/sdk/js/package.json | 4 ++-- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 15 files changed, 32 insertions(+), 32 deletions(-) (limited to 'packages/console') diff --git a/bun.lock b/bun.lock index 9bed68120..cb66b9b8e 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.44", + "version": "1.0.45", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.44", + "version": "1.0.45", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.44", + "version": "1.0.45", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -111,7 +111,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.44", + "version": "1.0.45", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -151,7 +151,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.44", + "version": "1.0.45", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -167,7 +167,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.44", + "version": "1.0.45", "bin": { "opencode": "./bin/opencode", }, @@ -245,7 +245,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.44", + "version": "1.0.45", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -265,7 +265,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.44", + "version": "1.0.45", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -276,7 +276,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.44", + "version": "1.0.45", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -289,7 +289,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.44", + "version": "1.0.45", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -319,7 +319,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.44", + "version": "1.0.45", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 3074cfc16..f2bc6fd1b 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "./script/generate-sitemap.ts && vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.44" + "version": "1.0.45" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index a06f59295..0f8558630 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.44", + "version": "1.0.45", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 2c3b5da28..87d838d1b 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.44", + "version": "1.0.45", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index 9019c7167..a48709737 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.44", + "version": "1.0.45", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index e837c0991..1e50e474b 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.44", + "version": "1.0.45", "description": "", "type": "module", "scripts": { diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 4e93745ad..384af6597 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The AI coding agent built for the terminal" -version = "1.0.44" +version = "1.0.45" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/sst/opencode" @@ -11,26 +11,26 @@ name = "OpenCode" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.44/opencode-darwin-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.45/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.44/opencode-darwin-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.45/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.44/opencode-linux-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.45/opencode-linux-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.44/opencode-linux-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.45/opencode-linux-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.44/opencode-windows-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.45/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index 9eb02d591..efc10d5a0 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.44", + "version": "1.0.45", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index c6b03e65e..8f5e8028f 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.44", + "version": "1.0.45", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 99b80ed72..6d9df4516 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.44", + "version": "1.0.45", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} +} \ No newline at end of file diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index c04d88856..622878742 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.44", + "version": "1.0.45", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} +} \ No newline at end of file diff --git a/packages/slack/package.json b/packages/slack/package.json index 1e3f0c6bd..2e7fa1fb7 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.44", + "version": "1.0.45", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index b2505a9d2..27cbd43d6 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.44", + "version": "1.0.45", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index 9755c0f9d..86b5bf106 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.44", + "version": "1.0.45", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index 17afb3e4b..f4d5f5e46 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.44", + "version": "1.0.45", "publisher": "sst-dev", "repository": { "type": "git", -- cgit v1.2.3 From 30b1ae5d4b071f5637c1a590a177b5017a28c90b Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 8 Nov 2025 10:15:35 -0500 Subject: zen: rate limit --- bun.lock | 53 ++++-- github/sst-env.d.ts | 2 +- infra/console.ts | 11 ++ package.json | 2 +- packages/console/app/src/routes/zen/util/error.ts | 1 + .../console/app/src/routes/zen/util/handler.ts | 73 ++++---- .../console/app/src/routes/zen/util/rateLimiter.ts | 36 ++++ packages/console/app/sst-env.d.ts | 2 +- packages/console/core/script/update-models.ts | 1 - packages/console/core/src/model.ts | 1 + packages/console/core/sst-env.d.ts | 183 +++++++++++---------- packages/console/function/sst-env.d.ts | 183 +++++++++++---------- packages/console/mail/sst-env.d.ts | 2 +- packages/console/resource/package.json | 5 +- packages/console/resource/resource.node.ts | 65 +++++++- packages/console/resource/sst-env.d.ts | 183 +++++++++++---------- packages/desktop/src/sst-env.d.ts | 6 +- packages/desktop/sst-env.d.ts | 2 +- packages/function/sst-env.d.ts | 183 +++++++++++---------- packages/opencode/sst-env.d.ts | 2 +- packages/plugin/sst-env.d.ts | 2 +- packages/script/sst-env.d.ts | 2 +- packages/sdk/js/sst-env.d.ts | 2 +- packages/sdk/python/sst.pyi | 10 ++ packages/slack/sst-env.d.ts | 2 +- packages/ui/sst-env.d.ts | 2 +- packages/web/sst-env.d.ts | 2 +- sdks/vscode/sst-env.d.ts | 2 +- sst-env.d.ts | 163 +++++++++--------- 29 files changed, 692 insertions(+), 491 deletions(-) create mode 100644 packages/console/app/src/routes/zen/util/rateLimiter.ts (limited to 'packages/console') diff --git a/bun.lock b/bun.lock index cb66b9b8e..a4d0ecbe3 100644 --- a/bun.lock +++ b/bun.lock @@ -11,7 +11,7 @@ "@tsconfig/bun": "catalog:", "husky": "9.1.7", "prettier": "3.6.2", - "sst": "3.17.22", + "sst": "3.17.23", "turbo": "2.5.6", }, }, @@ -106,7 +106,10 @@ "@cloudflare/workers-types": "catalog:", }, "devDependencies": { + "@cloudflare/workers-types": "catalog:", "@tsconfig/node22": "22.0.2", + "@types/node": "catalog:", + "cloudflare": "5.2.0", }, }, "packages/desktop": { @@ -1432,6 +1435,8 @@ "@types/node": ["@types/node@22.13.9", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw=="], + "@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="], + "@types/promise.allsettled": ["@types/promise.allsettled@1.0.6", "", {}, "sha512-wA0UT0HeT2fGHzIFV9kWpYz5mdoyLxKrTgMdZQM++5h6pYAFH73HXcQhefg24nD1yivUFEn5KU+EF4b+CXJ4Wg=="], "@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="], @@ -1518,6 +1523,8 @@ "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], + "agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="], + "ai": ["ai@5.0.8", "", { "dependencies": { "@ai-sdk/gateway": "1.0.4", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.1", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-qbnhj046UvG30V1S5WhjBn+RBGEAmi8PSZWqMhRsE3EPxvO5BcePXTZFA23e9MYyWS9zr4Vm8Mv3wQXwLmtIBw=="], "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], @@ -1742,6 +1749,8 @@ "clone": ["clone@2.1.2", "", {}, "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="], + "cloudflare": ["cloudflare@5.2.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" } }, "sha512-dVzqDpPFYR9ApEC9e+JJshFJZXcw4HzM8W+3DHzO5oy9+8rLC53G7x6fEf9A7/gSuSCxuvndzui5qJKftfIM9A=="], + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], "cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="], @@ -2068,7 +2077,11 @@ "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], - "form-data": ["form-data@2.5.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.35", "safe-buffer": "^5.2.1" } }, "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A=="], + "form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="], + + "form-data-encoder": ["form-data-encoder@1.7.2", "", {}, "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A=="], + + "formdata-node": ["formdata-node@4.4.1", "", { "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "4.0.0-beta.3" } }, "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ=="], "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], @@ -2258,6 +2271,8 @@ "human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="], + "humanize-ms": ["humanize-ms@1.2.1", "", { "dependencies": { "ms": "^2.0.0" } }, "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ=="], + "husky": ["husky@9.1.7", "", { "bin": { "husky": "bin.js" } }, "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA=="], "i18next": ["i18next@23.16.8", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-06r/TitrM88Mg5FdUXAKL96dJMzgqLE5dv3ryBAra4KCwD9mJ4ndOTS95ZuymIGoE+2hzfdaMak2X11/es7ZWg=="], @@ -2716,6 +2731,8 @@ "node-addon-api": ["node-addon-api@6.1.0", "", {}, "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA=="], + "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], + "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], @@ -3178,23 +3195,23 @@ "sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="], - "sst": ["sst@3.17.22", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.17.22", "sst-darwin-x64": "3.17.22", "sst-linux-arm64": "3.17.22", "sst-linux-x64": "3.17.22", "sst-linux-x86": "3.17.22", "sst-win32-arm64": "3.17.22", "sst-win32-x64": "3.17.22", "sst-win32-x86": "3.17.22" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-C+XMTbm6fx+7eT+ESAMATqG7qV7+pyVfxYQb6osdH3jd4u91QW1VU/xlEru+RU1rs1ZE58ixXdRP75UGPn+gog=="], + "sst": ["sst@3.17.23", "", { "dependencies": { "aws-sdk": "2.1692.0", "aws4fetch": "1.0.18", "jose": "5.2.3", "opencontrol": "0.0.6", "openid-client": "5.6.4" }, "optionalDependencies": { "sst-darwin-arm64": "3.17.23", "sst-darwin-x64": "3.17.23", "sst-linux-arm64": "3.17.23", "sst-linux-x64": "3.17.23", "sst-linux-x86": "3.17.23", "sst-win32-arm64": "3.17.23", "sst-win32-x64": "3.17.23", "sst-win32-x86": "3.17.23" }, "bin": { "sst": "bin/sst.mjs" } }, "sha512-TwKgUgDnZdc1Swe+bvCNeyO4dQnYz5cTodMpYj3jlXZdK9/KNz0PVxT1f0u5E76i1pmilXrUBL/f7iiMPw4RDg=="], - "sst-darwin-arm64": ["sst-darwin-arm64@3.17.22", "", { "os": "darwin", "cpu": "arm64" }, "sha512-B2pKq1dWc60+7HfXQ6/9etskxxNv9axxlQKveCLQAuG2a3mmtv2/jcR0Ch3mvSTGtW+KfhzUXda2kj7nZ/phBA=="], + "sst-darwin-arm64": ["sst-darwin-arm64@3.17.23", "", { "os": "darwin", "cpu": "arm64" }, "sha512-R6kvmF+rUideOoU7KBs2SdvrIupoE+b+Dor/eq9Uo4Dojj7KvYDZI/EDm8sSCbbcx/opiWeyNqKtlnLEdCxE6g=="], - "sst-darwin-x64": ["sst-darwin-x64@3.17.22", "", { "os": "darwin", "cpu": "x64" }, "sha512-flikYqXvhwwrS6x2FDOde+MQODHaZCIbUkVHYO3/gYo99rbAMQ8VpC/3LXnmnPEQkLOwWCSzLp4S4F9nG/PW2g=="], + "sst-darwin-x64": ["sst-darwin-x64@3.17.23", "", { "os": "darwin", "cpu": "x64" }, "sha512-WW4P1S35iYCifQXxD+sE3wuzcN+LHLpuKMaNoaBqEcWGZnH3IPaDJ7rpLF0arkDAo/z3jZmWWzOCkr0JuqJ8vQ=="], - "sst-linux-arm64": ["sst-linux-arm64@3.17.22", "", { "os": "linux", "cpu": "arm64" }, "sha512-+pyD8Oej9js8XeCCebiEIde02vC5hc+bLl2/jR02K+9gYkGVJ6n5bkT8AlR8zWdS4FJKPyeJYUfjliT1T33j+g=="], + "sst-linux-arm64": ["sst-linux-arm64@3.17.23", "", { "os": "linux", "cpu": "arm64" }, "sha512-TjtNqgIh7RlAWgPLFCAt0mXvIB+J7WjmRvIRrAdX0mXsndOiBJ/DMOgXSLVsIWHCfPj8MIEot/hWpnJgXgIeag=="], - "sst-linux-x64": ["sst-linux-x64@3.17.22", "", { "os": "linux", "cpu": "x64" }, "sha512-A5p941edP9wgfgsbLUMeEPvi9JExj0OSaxgtFAC6/6BYoW4zruGAPzq206Ln6dNYP3gRdo5TJbSjio3F0ot8qg=="], + "sst-linux-x64": ["sst-linux-x64@3.17.23", "", { "os": "linux", "cpu": "x64" }, "sha512-qdqJiEbYfCjZlI3F/TA6eoIU7JXVkEEI/UMILNf2JWhky0KQdCW2Xyz+wb6c0msVJCWdUM/uj+1DaiP2eXvghw=="], - "sst-linux-x86": ["sst-linux-x86@3.17.22", "", { "os": "linux", "cpu": "none" }, "sha512-pFDIi+ZwH8GOvy5He9wsbAjRGf/sTGhGE/V480w0A6itb9BC4jQ9sblJkk3Jx/fP2g27pKN2RNz+ifOU+GrUYQ=="], + "sst-linux-x86": ["sst-linux-x86@3.17.23", "", { "os": "linux", "cpu": "none" }, "sha512-aGmUujIvoNlmAABEGsOgfY1rxD9koC6hN8bnTLbDI+oI/u/zjHYh50jsbL0p3TlaHpwF/lxP3xFSuT6IKp+KgA=="], - "sst-win32-arm64": ["sst-win32-arm64@3.17.22", "", { "os": "win32", "cpu": "arm64" }, "sha512-9KaIrk+Z6hLDNi9GShf9NLrZi9jC/NNGpUAn6HvTXr8c6HUyQzg6takMH8nrISGCPn92y+IYWqdglaqbgnJTog=="], + "sst-win32-arm64": ["sst-win32-arm64@3.17.23", "", { "os": "win32", "cpu": "arm64" }, "sha512-ZxdkGqYDrrZGz98rijDCN+m5yuCcwD6Bc9/6hubLsvdpNlVorUqzpg801Ec97xSK0nIC9g6pNiRyxAcsQQstUg=="], - "sst-win32-x64": ["sst-win32-x64@3.17.22", "", { "os": "win32", "cpu": "x64" }, "sha512-cvzyet4octGHK7w05jPUSPmUdlAWyh8IzjB8Pcs873K9AUGJEtQCftOKZjXaFdIG9DTvFWCCBi9zdzClxT9jJg=="], + "sst-win32-x64": ["sst-win32-x64@3.17.23", "", { "os": "win32", "cpu": "x64" }, "sha512-yc9cor4MS49Ccy2tQCF1tf6M81yLeSGzGL+gjhUxpVKo2pN3bxl3w70eyU/mTXSEeyAmG9zEfbt6FNu4sy5cUA=="], - "sst-win32-x86": ["sst-win32-x86@3.17.22", "", { "os": "win32", "cpu": "none" }, "sha512-ol5icDJuHzG+AjbGbCIQoF8z3oiikTF9CtccdK/udqEF861DnngWzM99IY5TJvmJlN+38yOV0MY4XI5hM6SEQA=="], + "sst-win32-x86": ["sst-win32-x86@3.17.23", "", { "os": "win32", "cpu": "none" }, "sha512-DIp3s54IpNAfdYjSRt6McvkbEPQDMxUu6RUeRAd2C+FcTJgTloon/ghAPQBaDgu2VoVgymjcJARO/XyfKcCLOQ=="], "stackframe": ["stackframe@1.3.4", "", {}, "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="], @@ -3480,6 +3497,8 @@ "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], + "web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="], + "web-tree-sitter": ["web-tree-sitter@0.25.10", "", { "peerDependencies": { "@types/emscripten": "^1.40.0" }, "optionalPeers": ["@types/emscripten"] }, "sha512-Y09sF44/13XvgVKgO2cNDw5rGk6s26MgoZPXLESvMXeefBf7i6/73eFurre0IsTW6E14Y0ArIzhUMmjoc7xyzA=="], "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], @@ -3754,6 +3773,8 @@ "@slack/web-api/eventemitter3": ["eventemitter3@3.1.2", "", {}, "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="], + "@slack/web-api/form-data": ["form-data@2.5.5", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.35", "safe-buffer": "^5.2.1" } }, "sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A=="], + "@slack/web-api/p-queue": ["p-queue@6.6.2", "", { "dependencies": { "eventemitter3": "^4.0.4", "p-timeout": "^3.2.0" } }, "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ=="], "@solidjs/start/shiki": ["shiki@1.29.2", "", { "dependencies": { "@shikijs/core": "1.29.2", "@shikijs/engine-javascript": "1.29.2", "@shikijs/engine-oniguruma": "1.29.2", "@shikijs/langs": "1.29.2", "@shikijs/themes": "1.29.2", "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-njXuliz/cP+67jU2hukkxCNuH1yUi4QfdZZY+sMr5PPrIyXSu5iTb/qYC4BiWWB0vZ+7TbdvYUCeL23zpwCfbg=="], @@ -3814,8 +3835,6 @@ "astro/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "axios/form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="], - "babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="], "babel-plugin-module-resolver/glob": ["glob@9.3.5", "", { "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" } }, "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q=="], @@ -4350,6 +4369,8 @@ "@pierre/precision-diffs/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="], + "@slack/web-api/form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "@slack/web-api/p-queue/eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], "@slack/web-api/p-queue/p-timeout": ["p-timeout@3.2.0", "", { "dependencies": { "p-finally": "^1.0.0" } }, "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg=="], @@ -4402,8 +4423,6 @@ "astro/shiki/@shikijs/types": ["@shikijs/types@3.14.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-bQGgC6vrY8U/9ObG1Z/vTro+uclbjjD/uG58RvfxKZVD5p9Yc1ka3tVyEFy7BNJLzxuWyHH5NWynP9zZZS59eQ=="], - "axios/form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], - "babel-plugin-module-resolver/glob/minimatch": ["minimatch@8.0.4", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA=="], "babel-plugin-module-resolver/glob/minipass": ["minipass@4.2.8", "", {}, "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ=="], @@ -4700,6 +4719,8 @@ "@modelcontextprotocol/sdk/express/type-is/media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], + "@slack/web-api/form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "@solidjs/start/shiki/@shikijs/engine-javascript/oniguruma-to-es": ["oniguruma-to-es@2.3.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^5.1.1", "regex-recursion": "^5.1.1" } }, "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g=="], "@vercel/nft/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], @@ -4708,8 +4729,6 @@ "archiver-utils/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "axios/form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], - "babel-plugin-module-resolver/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "babel-plugin-module-resolver/glob/path-scurry/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], diff --git a/github/sst-env.d.ts b/github/sst-env.d.ts index 6b69016e7..f742a1200 100644 --- a/github/sst-env.d.ts +++ b/github/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} +export {} \ No newline at end of file diff --git a/infra/console.ts b/infra/console.ts index 98cc4c3f0..fabc86587 100644 --- a/infra/console.ts +++ b/infra/console.ts @@ -106,6 +106,7 @@ const AUTH_API_URL = new sst.Linkable("AUTH_API_URL", { const STRIPE_WEBHOOK_SECRET = new sst.Linkable("STRIPE_WEBHOOK_SECRET", { properties: { value: stripeWebhook.secret }, }) +const gatewayKv = new sst.cloudflare.Kv("GatewayKv") //////////////// // CONSOLE @@ -136,6 +137,16 @@ new sst.cloudflare.x.SolidStart("Console", { EMAILOCTOPUS_API_KEY, AWS_SES_ACCESS_KEY_ID, AWS_SES_SECRET_ACCESS_KEY, + ...($dev + ? [ + new sst.Secret( + "CLOUDFLARE_DEFAULT_ACCOUNT_ID", + process.env.CLOUDFLARE_DEFAULT_ACCOUNT_ID!, + ), + new sst.Secret("CLOUDFLARE_API_TOKEN", process.env.CLOUDFLARE_API_TOKEN!), + ] + : []), + gatewayKv, ], environment: { //VITE_DOCS_URL: web.url.apply((url) => url!), diff --git a/package.json b/package.json index 41b74dae9..0e6ab4c68 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "@tsconfig/bun": "catalog:", "husky": "9.1.7", "prettier": "3.6.2", - "sst": "3.17.22", + "sst": "3.17.23", "turbo": "2.5.6" }, "dependencies": { diff --git a/packages/console/app/src/routes/zen/util/error.ts b/packages/console/app/src/routes/zen/util/error.ts index dfc7e9fcd..f1e131468 100644 --- a/packages/console/app/src/routes/zen/util/error.ts +++ b/packages/console/app/src/routes/zen/util/error.ts @@ -3,3 +3,4 @@ export class CreditsError extends Error {} export class MonthlyLimitError extends Error {} export class UserLimitError extends Error {} export class ModelError extends Error {} +export class RateLimitError extends Error {} diff --git a/packages/console/app/src/routes/zen/util/handler.ts b/packages/console/app/src/routes/zen/util/handler.ts index 194a7c71e..edaac3a7b 100644 --- a/packages/console/app/src/routes/zen/util/handler.ts +++ b/packages/console/app/src/routes/zen/util/handler.ts @@ -12,14 +12,14 @@ import { UserTable } from "@opencode-ai/console-core/schema/user.sql.js" import { ModelTable } from "@opencode-ai/console-core/schema/model.sql.js" import { ProviderTable } from "@opencode-ai/console-core/schema/provider.sql.js" import { logger } from "./logger" -import { AuthError, CreditsError, MonthlyLimitError, UserLimitError, ModelError } from "./error" +import { AuthError, CreditsError, MonthlyLimitError, UserLimitError, ModelError, RateLimitError } from "./error" import { createBodyConverter, createStreamPartConverter, createResponseConverter } from "./provider/provider" import { anthropicHelper } from "./provider/anthropic" import { openaiHelper } from "./provider/openai" import { oaCompatHelper } from "./provider/openai-compatible" +import { createRateLimiter } from "./rateLimiter" type ZenData = Awaited> -type Model = ZenData["models"][string] export async function handler( input: APIEvent, @@ -28,6 +28,10 @@ export async function handler( parseApiKey: (headers: Headers) => string | undefined }, ) { + type AuthInfo = Awaited> + type ModelInfo = Awaited> + type ProviderInfo = Awaited> + const FREE_WORKSPACES = [ "wrk_01K46JDFR0E75SG2Q8K172KF3Y", // frank "wrk_01K6W1A3VE0KMNVSCQT43BG2SX", // opencode bench @@ -35,6 +39,7 @@ export async function handler( try { const body = await input.request.json() + const ip = input.request.headers.get("x-real-ip") ?? "" logger.metric({ is_tream: !!body.stream, session: input.request.headers.get("x-opencode-session"), @@ -42,9 +47,11 @@ export async function handler( }) const zenData = ZenData.list() const modelInfo = validateModel(zenData, body.model) - const providerInfo = selectProvider(zenData, modelInfo, input.request.headers.get("x-real-ip") ?? "") + const providerInfo = selectProvider(zenData, modelInfo, ip) const authInfo = await authenticate(modelInfo, providerInfo) - validateBilling(modelInfo, authInfo) + const rateLimiter = createRateLimiter(modelInfo.id, modelInfo.rateLimit, ip) + await rateLimiter?.check() + validateBilling(authInfo, modelInfo) validateModelSettings(authInfo) updateProviderKey(authInfo, providerInfo) logger.metric({ provider: providerInfo.id }) @@ -59,7 +66,7 @@ export async function handler( }), ) logger.debug("REQUEST URL: " + reqUrl) - logger.debug("REQUEST: " + reqBody) + logger.debug("REQUEST: " + reqBody.substring(0, 300) + "...") const res = await fetch(reqUrl, { method: "POST", headers: (() => { @@ -84,9 +91,6 @@ export async function handler( } } logger.debug("STATUS: " + res.status + " " + res.statusText) - if (res.status === 400 || res.status === 503) { - logger.debug("RESPONSE: " + (await res.text())) - } // Handle non-streaming response if (!body.stream) { @@ -95,6 +99,7 @@ export async function handler( const body = JSON.stringify(responseConverter(json)) logger.metric({ response_length: body.length }) logger.debug("RESPONSE: " + body) + await rateLimiter?.track() await trackUsage(authInfo, modelInfo, providerInfo, json.usage) await reload(authInfo) return new Response(body, { @@ -123,6 +128,7 @@ export async function handler( response_length: responseLength, "timestamp.last_byte": Date.now(), }) + await rateLimiter?.track() const usage = usageParser.retrieve() if (usage) { await trackUsage(authInfo, modelInfo, providerInfo, usage) @@ -197,6 +203,15 @@ export async function handler( { status: 401 }, ) + if (error instanceof RateLimitError) + return new Response( + JSON.stringify({ + type: "error", + error: { type: error.constructor.name, message: error.message }, + }), + { status: 429 }, + ) + return new Response( JSON.stringify({ type: "error", @@ -221,8 +236,8 @@ export async function handler( return { id: modelId, ...modelData } } - function selectProvider(zenData: ZenData, model: Awaited>, ip: string) { - const providers = model.providers + function selectProvider(zenData: ZenData, modelInfo: ModelInfo, ip: string) { + const providers = modelInfo.providers .filter((provider) => !provider.disabled) .flatMap((provider) => Array(provider.weight ?? 1).fill(provider)) @@ -235,22 +250,22 @@ export async function handler( throw new ModelError(`Provider ${provider.id} not supported`) } - const format = zenData.providers[provider.id].format - return { ...provider, ...zenData.providers[provider.id], - ...(format === "anthropic" ? anthropicHelper : format === "openai" ? openaiHelper : oaCompatHelper), + ...(() => { + const format = zenData.providers[provider.id].format + if (format === "anthropic") return anthropicHelper + if (format === "openai") return openaiHelper + return oaCompatHelper + })(), } } - async function authenticate( - model: Awaited>, - providerInfo: Awaited>, - ) { + async function authenticate(modelInfo: ModelInfo, providerInfo: ProviderInfo) { const apiKey = opts.parseApiKey(input.request.headers) if (!apiKey) { - if (model.allowAnonymous) return + if (modelInfo.allowAnonymous) return throw new AuthError("Missing API key.") } @@ -282,7 +297,7 @@ export async function handler( .innerJoin(WorkspaceTable, eq(WorkspaceTable.id, KeyTable.workspaceID)) .innerJoin(BillingTable, eq(BillingTable.workspaceID, KeyTable.workspaceID)) .innerJoin(UserTable, and(eq(UserTable.workspaceID, KeyTable.workspaceID), eq(UserTable.id, KeyTable.userID))) - .leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), eq(ModelTable.model, model.id))) + .leftJoin(ModelTable, and(eq(ModelTable.workspaceID, KeyTable.workspaceID), eq(ModelTable.model, modelInfo.id))) .leftJoin( ProviderTable, and(eq(ProviderTable.workspaceID, KeyTable.workspaceID), eq(ProviderTable.provider, providerInfo.id)), @@ -308,11 +323,11 @@ export async function handler( } } - function validateBilling(model: Model, authInfo: Awaited>) { + function validateBilling(authInfo: AuthInfo, modelInfo: ModelInfo) { if (!authInfo) return if (authInfo.provider?.credentials) return if (authInfo.isFree) return - if (model.allowAnonymous) return + if (modelInfo.allowAnonymous) return const billing = authInfo.billing if (!billing.paymentMethodID) @@ -356,26 +371,18 @@ export async function handler( } } - function validateModelSettings(authInfo: Awaited>) { + function validateModelSettings(authInfo: AuthInfo) { if (!authInfo) return if (authInfo.isDisabled) throw new ModelError("Model is disabled") } - function updateProviderKey( - authInfo: Awaited>, - providerInfo: Awaited>, - ) { + function updateProviderKey(authInfo: AuthInfo, providerInfo: ProviderInfo) { if (!authInfo) return if (!authInfo.provider?.credentials) return providerInfo.apiKey = authInfo.provider.credentials } - async function trackUsage( - authInfo: Awaited>, - modelInfo: ReturnType, - providerInfo: Awaited>, - usage: any, - ) { + async function trackUsage(authInfo: AuthInfo, modelInfo: ModelInfo, providerInfo: ProviderInfo, usage: any) { const { inputTokens, outputTokens, reasoningTokens, cacheReadTokens, cacheWrite5mTokens, cacheWrite1hTokens } = providerInfo.normalizeUsage(usage) @@ -483,7 +490,7 @@ export async function handler( ) } - async function reload(authInfo: Awaited>) { + async function reload(authInfo: AuthInfo) { if (!authInfo) return if (authInfo.isFree) return if (authInfo.provider?.credentials) return diff --git a/packages/console/app/src/routes/zen/util/rateLimiter.ts b/packages/console/app/src/routes/zen/util/rateLimiter.ts new file mode 100644 index 000000000..84cd5253e --- /dev/null +++ b/packages/console/app/src/routes/zen/util/rateLimiter.ts @@ -0,0 +1,36 @@ +import { Resource } from "@opencode-ai/console-resource" +import { RateLimitError } from "./error" +import { logger } from "./logger" + +export function createRateLimiter(model: string, limit: number | undefined, ip: string) { + if (!limit) return + + const now = Date.now() + const currKey = `usage:${ip}:${model}:${buildYYYYMMDDHH(now)}` + const prevKey = `usage:${ip}:${model}:${buildYYYYMMDDHH(now - 3_600_000)}` + let currRate: number + let prevRate: number + + return { + track: async () => { + await Resource.GatewayKv.put(currKey, currRate + 1, { expirationTtl: 3600 }) + }, + check: async () => { + const values = await Resource.GatewayKv.get([currKey, prevKey]) + const prevValue = values?.get(prevKey) + const currValue = values?.get(currKey) + prevRate = prevValue ? parseInt(prevValue) : 0 + currRate = currValue ? parseInt(currValue) : 0 + logger.debug(`rate limit ${model} prev/curr: ${prevRate}/${currRate}`) + if (prevRate + currRate >= limit) + throw new RateLimitError(`Rate limit exceeded. Please try again later.`) + }, + } +} + +function buildYYYYMMDDHH(timestamp: number) { + return new Date(timestamp) + .toISOString() + .replace(/[^0-9]/g, "") + .substring(0, 10) +} diff --git a/packages/console/app/sst-env.d.ts b/packages/console/app/sst-env.d.ts index bd5588217..9b9de7327 100644 --- a/packages/console/app/sst-env.d.ts +++ b/packages/console/app/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} +export {} \ No newline at end of file diff --git a/packages/console/core/script/update-models.ts b/packages/console/core/script/update-models.ts index e7a245515..807d57826 100755 --- a/packages/console/core/script/update-models.ts +++ b/packages/console/core/script/update-models.ts @@ -7,7 +7,6 @@ import { ZenData } from "../src/model" const root = path.resolve(process.cwd(), "..", "..", "..") const models = await $`bun sst secret list`.cwd(root).text() -console.log("models", models) // read the line starting with "ZEN_MODELS" const oldValue1 = models diff --git a/packages/console/core/src/model.ts b/packages/console/core/src/model.ts index ea719534d..46b2aa557 100644 --- a/packages/console/core/src/model.ts +++ b/packages/console/core/src/model.ts @@ -24,6 +24,7 @@ export namespace ZenData { cost: ModelCostSchema, cost200K: ModelCostSchema.optional(), allowAnonymous: z.boolean().optional(), + rateLimit: z.number().optional(), providers: z.array( z.object({ id: z.string(), diff --git a/packages/console/core/sst-env.d.ts b/packages/console/core/sst-env.d.ts index ba4c5a623..63c2af977 100644 --- a/packages/console/core/sst-env.d.ts +++ b/packages/console/core/sst-env.d.ts @@ -6,99 +6,108 @@ import "sst" declare module "sst" { export interface Resource { - ADMIN_SECRET: { - type: "sst.sst.Secret" - value: string - } - AUTH_API_URL: { - type: "sst.sst.Linkable" - value: string - } - AWS_SES_ACCESS_KEY_ID: { - type: "sst.sst.Secret" - value: string - } - AWS_SES_SECRET_ACCESS_KEY: { - type: "sst.sst.Secret" - value: string - } - Console: { - type: "sst.cloudflare.SolidStart" - url: string - } - Database: { - database: string - host: string - password: string - port: number - type: "sst.sst.Linkable" - username: string - } - Desktop: { - type: "sst.cloudflare.StaticSite" - url: string - } - EMAILOCTOPUS_API_KEY: { - type: "sst.sst.Secret" - value: string - } - GITHUB_APP_ID: { - type: "sst.sst.Secret" - value: string - } - GITHUB_APP_PRIVATE_KEY: { - type: "sst.sst.Secret" - value: string - } - GITHUB_CLIENT_ID_CONSOLE: { - type: "sst.sst.Secret" - value: string - } - GITHUB_CLIENT_SECRET_CONSOLE: { - type: "sst.sst.Secret" - value: string - } - GOOGLE_CLIENT_ID: { - type: "sst.sst.Secret" - value: string - } - HONEYCOMB_API_KEY: { - type: "sst.sst.Secret" - value: string - } - STRIPE_SECRET_KEY: { - type: "sst.sst.Secret" - value: string - } - STRIPE_WEBHOOK_SECRET: { - type: "sst.sst.Linkable" - value: string - } - Web: { - type: "sst.cloudflare.Astro" - url: string - } - ZEN_MODELS1: { - type: "sst.sst.Secret" - value: string - } - ZEN_MODELS2: { - type: "sst.sst.Secret" - value: string + "ADMIN_SECRET": { + "type": "sst.sst.Secret" + "value": string + } + "AUTH_API_URL": { + "type": "sst.sst.Linkable" + "value": string + } + "AWS_SES_ACCESS_KEY_ID": { + "type": "sst.sst.Secret" + "value": string + } + "AWS_SES_SECRET_ACCESS_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "CLOUDFLARE_API_TOKEN": { + "type": "sst.sst.Secret" + "value": string + } + "CLOUDFLARE_DEFAULT_ACCOUNT_ID": { + "type": "sst.sst.Secret" + "value": string + } + "Console": { + "type": "sst.cloudflare.SolidStart" + "url": string + } + "Database": { + "database": string + "host": string + "password": string + "port": number + "type": "sst.sst.Linkable" + "username": string + } + "Desktop": { + "type": "sst.cloudflare.StaticSite" + "url": string + } + "EMAILOCTOPUS_API_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_APP_ID": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_APP_PRIVATE_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_CLIENT_ID_CONSOLE": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_CLIENT_SECRET_CONSOLE": { + "type": "sst.sst.Secret" + "value": string + } + "GOOGLE_CLIENT_ID": { + "type": "sst.sst.Secret" + "value": string + } + "HONEYCOMB_API_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "STRIPE_SECRET_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "STRIPE_WEBHOOK_SECRET": { + "type": "sst.sst.Linkable" + "value": string + } + "Web": { + "type": "sst.cloudflare.Astro" + "url": string + } + "ZEN_MODELS1": { + "type": "sst.sst.Secret" + "value": string + } + "ZEN_MODELS2": { + "type": "sst.sst.Secret" + "value": string } } } -// cloudflare -import * as cloudflare from "@cloudflare/workers-types" +// cloudflare +import * as cloudflare from "@cloudflare/workers-types"; declare module "sst" { export interface Resource { - Api: cloudflare.Service - AuthApi: cloudflare.Service - AuthStorage: cloudflare.KVNamespace - Bucket: cloudflare.R2Bucket - LogProcessor: cloudflare.Service + "Api": cloudflare.Service + "AuthApi": cloudflare.Service + "AuthStorage": cloudflare.KVNamespace + "Bucket": cloudflare.R2Bucket + "GatewayKv": cloudflare.KVNamespace + "LogProcessor": cloudflare.Service } } import "sst" -export {} +export {} \ No newline at end of file diff --git a/packages/console/function/sst-env.d.ts b/packages/console/function/sst-env.d.ts index ba4c5a623..63c2af977 100644 --- a/packages/console/function/sst-env.d.ts +++ b/packages/console/function/sst-env.d.ts @@ -6,99 +6,108 @@ import "sst" declare module "sst" { export interface Resource { - ADMIN_SECRET: { - type: "sst.sst.Secret" - value: string - } - AUTH_API_URL: { - type: "sst.sst.Linkable" - value: string - } - AWS_SES_ACCESS_KEY_ID: { - type: "sst.sst.Secret" - value: string - } - AWS_SES_SECRET_ACCESS_KEY: { - type: "sst.sst.Secret" - value: string - } - Console: { - type: "sst.cloudflare.SolidStart" - url: string - } - Database: { - database: string - host: string - password: string - port: number - type: "sst.sst.Linkable" - username: string - } - Desktop: { - type: "sst.cloudflare.StaticSite" - url: string - } - EMAILOCTOPUS_API_KEY: { - type: "sst.sst.Secret" - value: string - } - GITHUB_APP_ID: { - type: "sst.sst.Secret" - value: string - } - GITHUB_APP_PRIVATE_KEY: { - type: "sst.sst.Secret" - value: string - } - GITHUB_CLIENT_ID_CONSOLE: { - type: "sst.sst.Secret" - value: string - } - GITHUB_CLIENT_SECRET_CONSOLE: { - type: "sst.sst.Secret" - value: string - } - GOOGLE_CLIENT_ID: { - type: "sst.sst.Secret" - value: string - } - HONEYCOMB_API_KEY: { - type: "sst.sst.Secret" - value: string - } - STRIPE_SECRET_KEY: { - type: "sst.sst.Secret" - value: string - } - STRIPE_WEBHOOK_SECRET: { - type: "sst.sst.Linkable" - value: string - } - Web: { - type: "sst.cloudflare.Astro" - url: string - } - ZEN_MODELS1: { - type: "sst.sst.Secret" - value: string - } - ZEN_MODELS2: { - type: "sst.sst.Secret" - value: string + "ADMIN_SECRET": { + "type": "sst.sst.Secret" + "value": string + } + "AUTH_API_URL": { + "type": "sst.sst.Linkable" + "value": string + } + "AWS_SES_ACCESS_KEY_ID": { + "type": "sst.sst.Secret" + "value": string + } + "AWS_SES_SECRET_ACCESS_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "CLOUDFLARE_API_TOKEN": { + "type": "sst.sst.Secret" + "value": string + } + "CLOUDFLARE_DEFAULT_ACCOUNT_ID": { + "type": "sst.sst.Secret" + "value": string + } + "Console": { + "type": "sst.cloudflare.SolidStart" + "url": string + } + "Database": { + "database": string + "host": string + "password": string + "port": number + "type": "sst.sst.Linkable" + "username": string + } + "Desktop": { + "type": "sst.cloudflare.StaticSite" + "url": string + } + "EMAILOCTOPUS_API_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_APP_ID": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_APP_PRIVATE_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_CLIENT_ID_CONSOLE": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_CLIENT_SECRET_CONSOLE": { + "type": "sst.sst.Secret" + "value": string + } + "GOOGLE_CLIENT_ID": { + "type": "sst.sst.Secret" + "value": string + } + "HONEYCOMB_API_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "STRIPE_SECRET_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "STRIPE_WEBHOOK_SECRET": { + "type": "sst.sst.Linkable" + "value": string + } + "Web": { + "type": "sst.cloudflare.Astro" + "url": string + } + "ZEN_MODELS1": { + "type": "sst.sst.Secret" + "value": string + } + "ZEN_MODELS2": { + "type": "sst.sst.Secret" + "value": string } } } -// cloudflare -import * as cloudflare from "@cloudflare/workers-types" +// cloudflare +import * as cloudflare from "@cloudflare/workers-types"; declare module "sst" { export interface Resource { - Api: cloudflare.Service - AuthApi: cloudflare.Service - AuthStorage: cloudflare.KVNamespace - Bucket: cloudflare.R2Bucket - LogProcessor: cloudflare.Service + "Api": cloudflare.Service + "AuthApi": cloudflare.Service + "AuthStorage": cloudflare.KVNamespace + "Bucket": cloudflare.R2Bucket + "GatewayKv": cloudflare.KVNamespace + "LogProcessor": cloudflare.Service } } import "sst" -export {} +export {} \ No newline at end of file diff --git a/packages/console/mail/sst-env.d.ts b/packages/console/mail/sst-env.d.ts index bd5588217..9b9de7327 100644 --- a/packages/console/mail/sst-env.d.ts +++ b/packages/console/mail/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} +export {} \ No newline at end of file diff --git a/packages/console/resource/package.json b/packages/console/resource/package.json index 6553feed1..f110f6c2a 100644 --- a/packages/console/resource/package.json +++ b/packages/console/resource/package.json @@ -13,6 +13,9 @@ } }, "devDependencies": { - "@tsconfig/node22": "22.0.2" + "@cloudflare/workers-types": "catalog:", + "@tsconfig/node22": "22.0.2", + "@types/node": "catalog:", + "cloudflare": "5.2.0" } } diff --git a/packages/console/resource/resource.node.ts b/packages/console/resource/resource.node.ts index d7dbb6c6d..2369eab98 100644 --- a/packages/console/resource/resource.node.ts +++ b/packages/console/resource/resource.node.ts @@ -1 +1,64 @@ -export { Resource } from "sst" +import type { + KVNamespaceListOptions, + KVNamespaceListResult, + KVNamespacePutOptions, +} from "@cloudflare/workers-types" +import { Resource as ResourceBase } from "sst" +import Cloudflare from "cloudflare" + +export const Resource = new Proxy( + {}, + { + get(_target, prop: keyof typeof ResourceBase) { + const value = ResourceBase[prop] + // @ts-ignore + if ("type" in value && value.type === "sst.cloudflare.Kv") { + const client = new Cloudflare({ + apiToken: ResourceBase.CLOUDFLARE_API_TOKEN.value, + }) + // @ts-ignore + const namespaceId = value.namespaceId + const accountId = ResourceBase.CLOUDFLARE_DEFAULT_ACCOUNT_ID.value + return { + get: (k: string | string[]) => { + const isMulti = Array.isArray(k) + return client.kv.namespaces + .bulkGet(namespaceId, { + keys: Array.isArray(k) ? k : [k], + account_id: accountId, + }) + .then((result) => + isMulti ? new Map(Object.entries(result?.values ?? {})) : result?.values?.[k], + ) + }, + put: (k: string, v: string, opts?: KVNamespacePutOptions) => + client.kv.namespaces.values.update(namespaceId, k, { + account_id: accountId, + value: v, + expiration: opts?.expiration, + expiration_ttl: opts?.expirationTtl, + metadata: opts?.metadata, + }), + delete: (k: string) => + client.kv.namespaces.values.delete(namespaceId, k, { + account_id: accountId, + }), + list: (opts?: KVNamespaceListOptions): Promise> => + client.kv.namespaces.keys + .list(namespaceId, { + account_id: accountId, + prefix: opts?.prefix ?? undefined, + }) + .then((result) => { + return { + keys: result.result, + list_complete: true, + cacheStatus: null, + } + }), + } + } + return value + }, + }, +) as Record diff --git a/packages/console/resource/sst-env.d.ts b/packages/console/resource/sst-env.d.ts index ba4c5a623..63c2af977 100644 --- a/packages/console/resource/sst-env.d.ts +++ b/packages/console/resource/sst-env.d.ts @@ -6,99 +6,108 @@ import "sst" declare module "sst" { export interface Resource { - ADMIN_SECRET: { - type: "sst.sst.Secret" - value: string - } - AUTH_API_URL: { - type: "sst.sst.Linkable" - value: string - } - AWS_SES_ACCESS_KEY_ID: { - type: "sst.sst.Secret" - value: string - } - AWS_SES_SECRET_ACCESS_KEY: { - type: "sst.sst.Secret" - value: string - } - Console: { - type: "sst.cloudflare.SolidStart" - url: string - } - Database: { - database: string - host: string - password: string - port: number - type: "sst.sst.Linkable" - username: string - } - Desktop: { - type: "sst.cloudflare.StaticSite" - url: string - } - EMAILOCTOPUS_API_KEY: { - type: "sst.sst.Secret" - value: string - } - GITHUB_APP_ID: { - type: "sst.sst.Secret" - value: string - } - GITHUB_APP_PRIVATE_KEY: { - type: "sst.sst.Secret" - value: string - } - GITHUB_CLIENT_ID_CONSOLE: { - type: "sst.sst.Secret" - value: string - } - GITHUB_CLIENT_SECRET_CONSOLE: { - type: "sst.sst.Secret" - value: string - } - GOOGLE_CLIENT_ID: { - type: "sst.sst.Secret" - value: string - } - HONEYCOMB_API_KEY: { - type: "sst.sst.Secret" - value: string - } - STRIPE_SECRET_KEY: { - type: "sst.sst.Secret" - value: string - } - STRIPE_WEBHOOK_SECRET: { - type: "sst.sst.Linkable" - value: string - } - Web: { - type: "sst.cloudflare.Astro" - url: string - } - ZEN_MODELS1: { - type: "sst.sst.Secret" - value: string - } - ZEN_MODELS2: { - type: "sst.sst.Secret" - value: string + "ADMIN_SECRET": { + "type": "sst.sst.Secret" + "value": string + } + "AUTH_API_URL": { + "type": "sst.sst.Linkable" + "value": string + } + "AWS_SES_ACCESS_KEY_ID": { + "type": "sst.sst.Secret" + "value": string + } + "AWS_SES_SECRET_ACCESS_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "CLOUDFLARE_API_TOKEN": { + "type": "sst.sst.Secret" + "value": string + } + "CLOUDFLARE_DEFAULT_ACCOUNT_ID": { + "type": "sst.sst.Secret" + "value": string + } + "Console": { + "type": "sst.cloudflare.SolidStart" + "url": string + } + "Database": { + "database": string + "host": string + "password": string + "port": number + "type": "sst.sst.Linkable" + "username": string + } + "Desktop": { + "type": "sst.cloudflare.StaticSite" + "url": string + } + "EMAILOCTOPUS_API_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_APP_ID": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_APP_PRIVATE_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_CLIENT_ID_CONSOLE": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_CLIENT_SECRET_CONSOLE": { + "type": "sst.sst.Secret" + "value": string + } + "GOOGLE_CLIENT_ID": { + "type": "sst.sst.Secret" + "value": string + } + "HONEYCOMB_API_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "STRIPE_SECRET_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "STRIPE_WEBHOOK_SECRET": { + "type": "sst.sst.Linkable" + "value": string + } + "Web": { + "type": "sst.cloudflare.Astro" + "url": string + } + "ZEN_MODELS1": { + "type": "sst.sst.Secret" + "value": string + } + "ZEN_MODELS2": { + "type": "sst.sst.Secret" + "value": string } } } -// cloudflare -import * as cloudflare from "@cloudflare/workers-types" +// cloudflare +import * as cloudflare from "@cloudflare/workers-types"; declare module "sst" { export interface Resource { - Api: cloudflare.Service - AuthApi: cloudflare.Service - AuthStorage: cloudflare.KVNamespace - Bucket: cloudflare.R2Bucket - LogProcessor: cloudflare.Service + "Api": cloudflare.Service + "AuthApi": cloudflare.Service + "AuthStorage": cloudflare.KVNamespace + "Bucket": cloudflare.R2Bucket + "GatewayKv": cloudflare.KVNamespace + "LogProcessor": cloudflare.Service } } import "sst" -export {} +export {} \ No newline at end of file diff --git a/packages/desktop/src/sst-env.d.ts b/packages/desktop/src/sst-env.d.ts index 1b1683a1e..47a8fbec7 100644 --- a/packages/desktop/src/sst-env.d.ts +++ b/packages/desktop/src/sst-env.d.ts @@ -2,7 +2,9 @@ /* tslint:disable */ /* eslint-disable */ /// -interface ImportMetaEnv {} +interface ImportMetaEnv { + +} interface ImportMeta { readonly env: ImportMetaEnv -} +} \ No newline at end of file diff --git a/packages/desktop/sst-env.d.ts b/packages/desktop/sst-env.d.ts index 0397645b5..b6a7e9066 100644 --- a/packages/desktop/sst-env.d.ts +++ b/packages/desktop/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} +export {} \ No newline at end of file diff --git a/packages/function/sst-env.d.ts b/packages/function/sst-env.d.ts index ba4c5a623..63c2af977 100644 --- a/packages/function/sst-env.d.ts +++ b/packages/function/sst-env.d.ts @@ -6,99 +6,108 @@ import "sst" declare module "sst" { export interface Resource { - ADMIN_SECRET: { - type: "sst.sst.Secret" - value: string - } - AUTH_API_URL: { - type: "sst.sst.Linkable" - value: string - } - AWS_SES_ACCESS_KEY_ID: { - type: "sst.sst.Secret" - value: string - } - AWS_SES_SECRET_ACCESS_KEY: { - type: "sst.sst.Secret" - value: string - } - Console: { - type: "sst.cloudflare.SolidStart" - url: string - } - Database: { - database: string - host: string - password: string - port: number - type: "sst.sst.Linkable" - username: string - } - Desktop: { - type: "sst.cloudflare.StaticSite" - url: string - } - EMAILOCTOPUS_API_KEY: { - type: "sst.sst.Secret" - value: string - } - GITHUB_APP_ID: { - type: "sst.sst.Secret" - value: string - } - GITHUB_APP_PRIVATE_KEY: { - type: "sst.sst.Secret" - value: string - } - GITHUB_CLIENT_ID_CONSOLE: { - type: "sst.sst.Secret" - value: string - } - GITHUB_CLIENT_SECRET_CONSOLE: { - type: "sst.sst.Secret" - value: string - } - GOOGLE_CLIENT_ID: { - type: "sst.sst.Secret" - value: string - } - HONEYCOMB_API_KEY: { - type: "sst.sst.Secret" - value: string - } - STRIPE_SECRET_KEY: { - type: "sst.sst.Secret" - value: string - } - STRIPE_WEBHOOK_SECRET: { - type: "sst.sst.Linkable" - value: string - } - Web: { - type: "sst.cloudflare.Astro" - url: string - } - ZEN_MODELS1: { - type: "sst.sst.Secret" - value: string - } - ZEN_MODELS2: { - type: "sst.sst.Secret" - value: string + "ADMIN_SECRET": { + "type": "sst.sst.Secret" + "value": string + } + "AUTH_API_URL": { + "type": "sst.sst.Linkable" + "value": string + } + "AWS_SES_ACCESS_KEY_ID": { + "type": "sst.sst.Secret" + "value": string + } + "AWS_SES_SECRET_ACCESS_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "CLOUDFLARE_API_TOKEN": { + "type": "sst.sst.Secret" + "value": string + } + "CLOUDFLARE_DEFAULT_ACCOUNT_ID": { + "type": "sst.sst.Secret" + "value": string + } + "Console": { + "type": "sst.cloudflare.SolidStart" + "url": string + } + "Database": { + "database": string + "host": string + "password": string + "port": number + "type": "sst.sst.Linkable" + "username": string + } + "Desktop": { + "type": "sst.cloudflare.StaticSite" + "url": string + } + "EMAILOCTOPUS_API_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_APP_ID": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_APP_PRIVATE_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_CLIENT_ID_CONSOLE": { + "type": "sst.sst.Secret" + "value": string + } + "GITHUB_CLIENT_SECRET_CONSOLE": { + "type": "sst.sst.Secret" + "value": string + } + "GOOGLE_CLIENT_ID": { + "type": "sst.sst.Secret" + "value": string + } + "HONEYCOMB_API_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "STRIPE_SECRET_KEY": { + "type": "sst.sst.Secret" + "value": string + } + "STRIPE_WEBHOOK_SECRET": { + "type": "sst.sst.Linkable" + "value": string + } + "Web": { + "type": "sst.cloudflare.Astro" + "url": string + } + "ZEN_MODELS1": { + "type": "sst.sst.Secret" + "value": string + } + "ZEN_MODELS2": { + "type": "sst.sst.Secret" + "value": string } } } -// cloudflare -import * as cloudflare from "@cloudflare/workers-types" +// cloudflare +import * as cloudflare from "@cloudflare/workers-types"; declare module "sst" { export interface Resource { - Api: cloudflare.Service - AuthApi: cloudflare.Service - AuthStorage: cloudflare.KVNamespace - Bucket: cloudflare.R2Bucket - LogProcessor: cloudflare.Service + "Api": cloudflare.Service + "AuthApi": cloudflare.Service + "AuthStorage": cloudflare.KVNamespace + "Bucket": cloudflare.R2Bucket + "GatewayKv": cloudflare.KVNamespace + "LogProcessor": cloudflare.Service } } import "sst" -export {} +export {} \ No newline at end of file diff --git a/packages/opencode/sst-env.d.ts b/packages/opencode/sst-env.d.ts index 0397645b5..b6a7e9066 100644 --- a/packages/opencode/sst-env.d.ts +++ b/packages/opencode/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} +export {} \ No newline at end of file diff --git a/packages/plugin/sst-env.d.ts b/packages/plugin/sst-env.d.ts index 0397645b5..b6a7e9066 100644 --- a/packages/plugin/sst-env.d.ts +++ b/packages/plugin/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} +export {} \ No newline at end of file diff --git a/packages/script/sst-env.d.ts b/packages/script/sst-env.d.ts index 0397645b5..b6a7e9066 100644 --- a/packages/script/sst-env.d.ts +++ b/packages/script/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} +export {} \ No newline at end of file diff --git a/packages/sdk/js/sst-env.d.ts b/packages/sdk/js/sst-env.d.ts index bd5588217..9b9de7327 100644 --- a/packages/sdk/js/sst-env.d.ts +++ b/packages/sdk/js/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} +export {} \ No newline at end of file diff --git a/packages/sdk/python/sst.pyi b/packages/sdk/python/sst.pyi index c64110c5b..b9353f7f7 100644 --- a/packages/sdk/python/sst.pyi +++ b/packages/sdk/python/sst.pyi @@ -25,10 +25,17 @@ class Resource: type: str url: str class AuthStorage: + namespaceId: str type: str class Bucket: name: str type: str + class CLOUDFLARE_API_TOKEN: + type: str + value: str + class CLOUDFLARE_DEFAULT_ACCOUNT_ID: + type: str + value: str class Console: type: str url: str @@ -60,6 +67,9 @@ class Resource: class GOOGLE_CLIENT_ID: type: str value: str + class GatewayKv: + namespaceId: str + type: str class HONEYCOMB_API_KEY: type: str value: str diff --git a/packages/slack/sst-env.d.ts b/packages/slack/sst-env.d.ts index 0397645b5..b6a7e9066 100644 --- a/packages/slack/sst-env.d.ts +++ b/packages/slack/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} +export {} \ No newline at end of file diff --git a/packages/ui/sst-env.d.ts b/packages/ui/sst-env.d.ts index 0397645b5..b6a7e9066 100644 --- a/packages/ui/sst-env.d.ts +++ b/packages/ui/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} +export {} \ No newline at end of file diff --git a/packages/web/sst-env.d.ts b/packages/web/sst-env.d.ts index 0397645b5..b6a7e9066 100644 --- a/packages/web/sst-env.d.ts +++ b/packages/web/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} +export {} \ No newline at end of file diff --git a/sdks/vscode/sst-env.d.ts b/sdks/vscode/sst-env.d.ts index 0397645b5..b6a7e9066 100644 --- a/sdks/vscode/sst-env.d.ts +++ b/sdks/vscode/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} +export {} \ No newline at end of file diff --git a/sst-env.d.ts b/sst-env.d.ts index b80f971ab..876f05228 100644 --- a/sst-env.d.ts +++ b/sst-env.d.ts @@ -5,107 +5,120 @@ declare module "sst" { export interface Resource { - ADMIN_SECRET: { - type: "sst.sst.Secret" - value: string + "ADMIN_SECRET": { + "type": "sst.sst.Secret" + "value": string + } + "AUTH_API_URL": { + "type": "sst.sst.Linkable" + "value": string + } + "AWS_SES_ACCESS_KEY_ID": { + "type": "sst.sst.Secret" + "value": string } - AUTH_API_URL: { - type: "sst.sst.Linkable" - value: string + "AWS_SES_SECRET_ACCESS_KEY": { + "type": "sst.sst.Secret" + "value": string } - AWS_SES_ACCESS_KEY_ID: { - type: "sst.sst.Secret" - value: string + "Api": { + "type": "sst.cloudflare.Worker" + "url": string } - AWS_SES_SECRET_ACCESS_KEY: { - type: "sst.sst.Secret" - value: string + "AuthApi": { + "type": "sst.cloudflare.Worker" + "url": string } - Api: { - type: "sst.cloudflare.Worker" - url: string + "AuthStorage": { + "namespaceId": string + "type": "sst.cloudflare.Kv" } - AuthApi: { - type: "sst.cloudflare.Worker" - url: string + "Bucket": { + "name": string + "type": "sst.cloudflare.Bucket" } - AuthStorage: { - type: "sst.cloudflare.Kv" + "CLOUDFLARE_API_TOKEN": { + "type": "sst.sst.Secret" + "value": string } - Bucket: { - name: string - type: "sst.cloudflare.Bucket" + "CLOUDFLARE_DEFAULT_ACCOUNT_ID": { + "type": "sst.sst.Secret" + "value": string } - Console: { - type: "sst.cloudflare.SolidStart" - url: string + "Console": { + "type": "sst.cloudflare.SolidStart" + "url": string } - Database: { - database: string - host: string - password: string - port: number - type: "sst.sst.Linkable" - username: string + "Database": { + "database": string + "host": string + "password": string + "port": number + "type": "sst.sst.Linkable" + "username": string } - Desktop: { - type: "sst.cloudflare.StaticSite" - url: string + "Desktop": { + "type": "sst.cloudflare.StaticSite" + "url": string } - EMAILOCTOPUS_API_KEY: { - type: "sst.sst.Secret" - value: string + "EMAILOCTOPUS_API_KEY": { + "type": "sst.sst.Secret" + "value": string } - GITHUB_APP_ID: { - type: "sst.sst.Secret" - value: string + "GITHUB_APP_ID": { + "type": "sst.sst.Secret" + "value": string } - GITHUB_APP_PRIVATE_KEY: { - type: "sst.sst.Secret" - value: string + "GITHUB_APP_PRIVATE_KEY": { + "type": "sst.sst.Secret" + "value": string } - GITHUB_CLIENT_ID_CONSOLE: { - type: "sst.sst.Secret" - value: string + "GITHUB_CLIENT_ID_CONSOLE": { + "type": "sst.sst.Secret" + "value": string } - GITHUB_CLIENT_SECRET_CONSOLE: { - type: "sst.sst.Secret" - value: string + "GITHUB_CLIENT_SECRET_CONSOLE": { + "type": "sst.sst.Secret" + "value": string } - GOOGLE_CLIENT_ID: { - type: "sst.sst.Secret" - value: string + "GOOGLE_CLIENT_ID": { + "type": "sst.sst.Secret" + "value": string } - HONEYCOMB_API_KEY: { - type: "sst.sst.Secret" - value: string + "GatewayKv": { + "namespaceId": string + "type": "sst.cloudflare.Kv" } - LogProcessor: { - type: "sst.cloudflare.Worker" + "HONEYCOMB_API_KEY": { + "type": "sst.sst.Secret" + "value": string } - STRIPE_SECRET_KEY: { - type: "sst.sst.Secret" - value: string + "LogProcessor": { + "type": "sst.cloudflare.Worker" } - STRIPE_WEBHOOK_SECRET: { - type: "sst.sst.Linkable" - value: string + "STRIPE_SECRET_KEY": { + "type": "sst.sst.Secret" + "value": string } - Web: { - type: "sst.cloudflare.Astro" - url: string + "STRIPE_WEBHOOK_SECRET": { + "type": "sst.sst.Linkable" + "value": string } - ZEN_MODELS1: { - type: "sst.sst.Secret" - value: string + "Web": { + "type": "sst.cloudflare.Astro" + "url": string } - ZEN_MODELS2: { - type: "sst.sst.Secret" - value: string + "ZEN_MODELS1": { + "type": "sst.sst.Secret" + "value": string + } + "ZEN_MODELS2": { + "type": "sst.sst.Secret" + "value": string } } } /// import "sst" -export {} +export {} \ No newline at end of file -- cgit v1.2.3 From 6ecaf83f76cf5a7c87dc118c01303f18aac35419 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sat, 8 Nov 2025 15:20:53 +0000 Subject: chore: format code --- github/sst-env.d.ts | 2 +- infra/console.ts | 5 +- .../console/app/src/routes/zen/util/rateLimiter.ts | 3 +- packages/console/app/sst-env.d.ts | 2 +- packages/console/core/sst-env.d.ts | 192 ++++++++++----------- packages/console/function/sst-env.d.ts | 192 ++++++++++----------- packages/console/mail/sst-env.d.ts | 2 +- packages/console/resource/resource.node.ts | 10 +- packages/console/resource/sst-env.d.ts | 192 ++++++++++----------- packages/desktop/src/sst-env.d.ts | 6 +- packages/desktop/sst-env.d.ts | 2 +- packages/function/sst-env.d.ts | 192 ++++++++++----------- packages/opencode/sst-env.d.ts | 2 +- packages/plugin/package.json | 2 +- packages/plugin/sst-env.d.ts | 2 +- packages/script/sst-env.d.ts | 2 +- packages/sdk/js/package.json | 2 +- packages/sdk/js/sst-env.d.ts | 2 +- packages/slack/sst-env.d.ts | 2 +- packages/ui/sst-env.d.ts | 2 +- packages/web/sst-env.d.ts | 2 +- sdks/vscode/sst-env.d.ts | 2 +- sst-env.d.ts | 174 +++++++++---------- 23 files changed, 491 insertions(+), 503 deletions(-) (limited to 'packages/console') diff --git a/github/sst-env.d.ts b/github/sst-env.d.ts index f742a1200..6b69016e7 100644 --- a/github/sst-env.d.ts +++ b/github/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/infra/console.ts b/infra/console.ts index fabc86587..d8e4e5bd6 100644 --- a/infra/console.ts +++ b/infra/console.ts @@ -139,10 +139,7 @@ new sst.cloudflare.x.SolidStart("Console", { AWS_SES_SECRET_ACCESS_KEY, ...($dev ? [ - new sst.Secret( - "CLOUDFLARE_DEFAULT_ACCOUNT_ID", - process.env.CLOUDFLARE_DEFAULT_ACCOUNT_ID!, - ), + new sst.Secret("CLOUDFLARE_DEFAULT_ACCOUNT_ID", process.env.CLOUDFLARE_DEFAULT_ACCOUNT_ID!), new sst.Secret("CLOUDFLARE_API_TOKEN", process.env.CLOUDFLARE_API_TOKEN!), ] : []), diff --git a/packages/console/app/src/routes/zen/util/rateLimiter.ts b/packages/console/app/src/routes/zen/util/rateLimiter.ts index 84cd5253e..b3c036815 100644 --- a/packages/console/app/src/routes/zen/util/rateLimiter.ts +++ b/packages/console/app/src/routes/zen/util/rateLimiter.ts @@ -22,8 +22,7 @@ export function createRateLimiter(model: string, limit: number | undefined, ip: prevRate = prevValue ? parseInt(prevValue) : 0 currRate = currValue ? parseInt(currValue) : 0 logger.debug(`rate limit ${model} prev/curr: ${prevRate}/${currRate}`) - if (prevRate + currRate >= limit) - throw new RateLimitError(`Rate limit exceeded. Please try again later.`) + if (prevRate + currRate >= limit) throw new RateLimitError(`Rate limit exceeded. Please try again later.`) }, } } diff --git a/packages/console/app/sst-env.d.ts b/packages/console/app/sst-env.d.ts index 9b9de7327..bd5588217 100644 --- a/packages/console/app/sst-env.d.ts +++ b/packages/console/app/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/console/core/sst-env.d.ts b/packages/console/core/sst-env.d.ts index 63c2af977..bcd7c2650 100644 --- a/packages/console/core/sst-env.d.ts +++ b/packages/console/core/sst-env.d.ts @@ -6,108 +6,108 @@ import "sst" declare module "sst" { export interface Resource { - "ADMIN_SECRET": { - "type": "sst.sst.Secret" - "value": string - } - "AUTH_API_URL": { - "type": "sst.sst.Linkable" - "value": string - } - "AWS_SES_ACCESS_KEY_ID": { - "type": "sst.sst.Secret" - "value": string - } - "AWS_SES_SECRET_ACCESS_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "CLOUDFLARE_API_TOKEN": { - "type": "sst.sst.Secret" - "value": string - } - "CLOUDFLARE_DEFAULT_ACCOUNT_ID": { - "type": "sst.sst.Secret" - "value": string - } - "Console": { - "type": "sst.cloudflare.SolidStart" - "url": string - } - "Database": { - "database": string - "host": string - "password": string - "port": number - "type": "sst.sst.Linkable" - "username": string - } - "Desktop": { - "type": "sst.cloudflare.StaticSite" - "url": string - } - "EMAILOCTOPUS_API_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_APP_ID": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_APP_PRIVATE_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_CLIENT_ID_CONSOLE": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_CLIENT_SECRET_CONSOLE": { - "type": "sst.sst.Secret" - "value": string - } - "GOOGLE_CLIENT_ID": { - "type": "sst.sst.Secret" - "value": string - } - "HONEYCOMB_API_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "STRIPE_SECRET_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "STRIPE_WEBHOOK_SECRET": { - "type": "sst.sst.Linkable" - "value": string - } - "Web": { - "type": "sst.cloudflare.Astro" - "url": string - } - "ZEN_MODELS1": { - "type": "sst.sst.Secret" - "value": string - } - "ZEN_MODELS2": { - "type": "sst.sst.Secret" - "value": string + ADMIN_SECRET: { + type: "sst.sst.Secret" + value: string + } + AUTH_API_URL: { + type: "sst.sst.Linkable" + value: string + } + AWS_SES_ACCESS_KEY_ID: { + type: "sst.sst.Secret" + value: string + } + AWS_SES_SECRET_ACCESS_KEY: { + type: "sst.sst.Secret" + value: string + } + CLOUDFLARE_API_TOKEN: { + type: "sst.sst.Secret" + value: string + } + CLOUDFLARE_DEFAULT_ACCOUNT_ID: { + type: "sst.sst.Secret" + value: string + } + Console: { + type: "sst.cloudflare.SolidStart" + url: string + } + Database: { + database: string + host: string + password: string + port: number + type: "sst.sst.Linkable" + username: string + } + Desktop: { + type: "sst.cloudflare.StaticSite" + url: string + } + EMAILOCTOPUS_API_KEY: { + type: "sst.sst.Secret" + value: string + } + GITHUB_APP_ID: { + type: "sst.sst.Secret" + value: string + } + GITHUB_APP_PRIVATE_KEY: { + type: "sst.sst.Secret" + value: string + } + GITHUB_CLIENT_ID_CONSOLE: { + type: "sst.sst.Secret" + value: string + } + GITHUB_CLIENT_SECRET_CONSOLE: { + type: "sst.sst.Secret" + value: string + } + GOOGLE_CLIENT_ID: { + type: "sst.sst.Secret" + value: string + } + HONEYCOMB_API_KEY: { + type: "sst.sst.Secret" + value: string + } + STRIPE_SECRET_KEY: { + type: "sst.sst.Secret" + value: string + } + STRIPE_WEBHOOK_SECRET: { + type: "sst.sst.Linkable" + value: string + } + Web: { + type: "sst.cloudflare.Astro" + url: string + } + ZEN_MODELS1: { + type: "sst.sst.Secret" + value: string + } + ZEN_MODELS2: { + type: "sst.sst.Secret" + value: string } } } -// cloudflare -import * as cloudflare from "@cloudflare/workers-types"; +// cloudflare +import * as cloudflare from "@cloudflare/workers-types" declare module "sst" { export interface Resource { - "Api": cloudflare.Service - "AuthApi": cloudflare.Service - "AuthStorage": cloudflare.KVNamespace - "Bucket": cloudflare.R2Bucket - "GatewayKv": cloudflare.KVNamespace - "LogProcessor": cloudflare.Service + Api: cloudflare.Service + AuthApi: cloudflare.Service + AuthStorage: cloudflare.KVNamespace + Bucket: cloudflare.R2Bucket + GatewayKv: cloudflare.KVNamespace + LogProcessor: cloudflare.Service } } import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/console/function/sst-env.d.ts b/packages/console/function/sst-env.d.ts index 63c2af977..bcd7c2650 100644 --- a/packages/console/function/sst-env.d.ts +++ b/packages/console/function/sst-env.d.ts @@ -6,108 +6,108 @@ import "sst" declare module "sst" { export interface Resource { - "ADMIN_SECRET": { - "type": "sst.sst.Secret" - "value": string - } - "AUTH_API_URL": { - "type": "sst.sst.Linkable" - "value": string - } - "AWS_SES_ACCESS_KEY_ID": { - "type": "sst.sst.Secret" - "value": string - } - "AWS_SES_SECRET_ACCESS_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "CLOUDFLARE_API_TOKEN": { - "type": "sst.sst.Secret" - "value": string - } - "CLOUDFLARE_DEFAULT_ACCOUNT_ID": { - "type": "sst.sst.Secret" - "value": string - } - "Console": { - "type": "sst.cloudflare.SolidStart" - "url": string - } - "Database": { - "database": string - "host": string - "password": string - "port": number - "type": "sst.sst.Linkable" - "username": string - } - "Desktop": { - "type": "sst.cloudflare.StaticSite" - "url": string - } - "EMAILOCTOPUS_API_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_APP_ID": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_APP_PRIVATE_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_CLIENT_ID_CONSOLE": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_CLIENT_SECRET_CONSOLE": { - "type": "sst.sst.Secret" - "value": string - } - "GOOGLE_CLIENT_ID": { - "type": "sst.sst.Secret" - "value": string - } - "HONEYCOMB_API_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "STRIPE_SECRET_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "STRIPE_WEBHOOK_SECRET": { - "type": "sst.sst.Linkable" - "value": string - } - "Web": { - "type": "sst.cloudflare.Astro" - "url": string - } - "ZEN_MODELS1": { - "type": "sst.sst.Secret" - "value": string - } - "ZEN_MODELS2": { - "type": "sst.sst.Secret" - "value": string + ADMIN_SECRET: { + type: "sst.sst.Secret" + value: string + } + AUTH_API_URL: { + type: "sst.sst.Linkable" + value: string + } + AWS_SES_ACCESS_KEY_ID: { + type: "sst.sst.Secret" + value: string + } + AWS_SES_SECRET_ACCESS_KEY: { + type: "sst.sst.Secret" + value: string + } + CLOUDFLARE_API_TOKEN: { + type: "sst.sst.Secret" + value: string + } + CLOUDFLARE_DEFAULT_ACCOUNT_ID: { + type: "sst.sst.Secret" + value: string + } + Console: { + type: "sst.cloudflare.SolidStart" + url: string + } + Database: { + database: string + host: string + password: string + port: number + type: "sst.sst.Linkable" + username: string + } + Desktop: { + type: "sst.cloudflare.StaticSite" + url: string + } + EMAILOCTOPUS_API_KEY: { + type: "sst.sst.Secret" + value: string + } + GITHUB_APP_ID: { + type: "sst.sst.Secret" + value: string + } + GITHUB_APP_PRIVATE_KEY: { + type: "sst.sst.Secret" + value: string + } + GITHUB_CLIENT_ID_CONSOLE: { + type: "sst.sst.Secret" + value: string + } + GITHUB_CLIENT_SECRET_CONSOLE: { + type: "sst.sst.Secret" + value: string + } + GOOGLE_CLIENT_ID: { + type: "sst.sst.Secret" + value: string + } + HONEYCOMB_API_KEY: { + type: "sst.sst.Secret" + value: string + } + STRIPE_SECRET_KEY: { + type: "sst.sst.Secret" + value: string + } + STRIPE_WEBHOOK_SECRET: { + type: "sst.sst.Linkable" + value: string + } + Web: { + type: "sst.cloudflare.Astro" + url: string + } + ZEN_MODELS1: { + type: "sst.sst.Secret" + value: string + } + ZEN_MODELS2: { + type: "sst.sst.Secret" + value: string } } } -// cloudflare -import * as cloudflare from "@cloudflare/workers-types"; +// cloudflare +import * as cloudflare from "@cloudflare/workers-types" declare module "sst" { export interface Resource { - "Api": cloudflare.Service - "AuthApi": cloudflare.Service - "AuthStorage": cloudflare.KVNamespace - "Bucket": cloudflare.R2Bucket - "GatewayKv": cloudflare.KVNamespace - "LogProcessor": cloudflare.Service + Api: cloudflare.Service + AuthApi: cloudflare.Service + AuthStorage: cloudflare.KVNamespace + Bucket: cloudflare.R2Bucket + GatewayKv: cloudflare.KVNamespace + LogProcessor: cloudflare.Service } } import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/console/mail/sst-env.d.ts b/packages/console/mail/sst-env.d.ts index 9b9de7327..bd5588217 100644 --- a/packages/console/mail/sst-env.d.ts +++ b/packages/console/mail/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/console/resource/resource.node.ts b/packages/console/resource/resource.node.ts index 2369eab98..f63d7bada 100644 --- a/packages/console/resource/resource.node.ts +++ b/packages/console/resource/resource.node.ts @@ -1,8 +1,4 @@ -import type { - KVNamespaceListOptions, - KVNamespaceListResult, - KVNamespacePutOptions, -} from "@cloudflare/workers-types" +import type { KVNamespaceListOptions, KVNamespaceListResult, KVNamespacePutOptions } from "@cloudflare/workers-types" import { Resource as ResourceBase } from "sst" import Cloudflare from "cloudflare" @@ -27,9 +23,7 @@ export const Resource = new Proxy( keys: Array.isArray(k) ? k : [k], account_id: accountId, }) - .then((result) => - isMulti ? new Map(Object.entries(result?.values ?? {})) : result?.values?.[k], - ) + .then((result) => (isMulti ? new Map(Object.entries(result?.values ?? {})) : result?.values?.[k])) }, put: (k: string, v: string, opts?: KVNamespacePutOptions) => client.kv.namespaces.values.update(namespaceId, k, { diff --git a/packages/console/resource/sst-env.d.ts b/packages/console/resource/sst-env.d.ts index 63c2af977..bcd7c2650 100644 --- a/packages/console/resource/sst-env.d.ts +++ b/packages/console/resource/sst-env.d.ts @@ -6,108 +6,108 @@ import "sst" declare module "sst" { export interface Resource { - "ADMIN_SECRET": { - "type": "sst.sst.Secret" - "value": string - } - "AUTH_API_URL": { - "type": "sst.sst.Linkable" - "value": string - } - "AWS_SES_ACCESS_KEY_ID": { - "type": "sst.sst.Secret" - "value": string - } - "AWS_SES_SECRET_ACCESS_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "CLOUDFLARE_API_TOKEN": { - "type": "sst.sst.Secret" - "value": string - } - "CLOUDFLARE_DEFAULT_ACCOUNT_ID": { - "type": "sst.sst.Secret" - "value": string - } - "Console": { - "type": "sst.cloudflare.SolidStart" - "url": string - } - "Database": { - "database": string - "host": string - "password": string - "port": number - "type": "sst.sst.Linkable" - "username": string - } - "Desktop": { - "type": "sst.cloudflare.StaticSite" - "url": string - } - "EMAILOCTOPUS_API_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_APP_ID": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_APP_PRIVATE_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_CLIENT_ID_CONSOLE": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_CLIENT_SECRET_CONSOLE": { - "type": "sst.sst.Secret" - "value": string - } - "GOOGLE_CLIENT_ID": { - "type": "sst.sst.Secret" - "value": string - } - "HONEYCOMB_API_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "STRIPE_SECRET_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "STRIPE_WEBHOOK_SECRET": { - "type": "sst.sst.Linkable" - "value": string - } - "Web": { - "type": "sst.cloudflare.Astro" - "url": string - } - "ZEN_MODELS1": { - "type": "sst.sst.Secret" - "value": string - } - "ZEN_MODELS2": { - "type": "sst.sst.Secret" - "value": string + ADMIN_SECRET: { + type: "sst.sst.Secret" + value: string + } + AUTH_API_URL: { + type: "sst.sst.Linkable" + value: string + } + AWS_SES_ACCESS_KEY_ID: { + type: "sst.sst.Secret" + value: string + } + AWS_SES_SECRET_ACCESS_KEY: { + type: "sst.sst.Secret" + value: string + } + CLOUDFLARE_API_TOKEN: { + type: "sst.sst.Secret" + value: string + } + CLOUDFLARE_DEFAULT_ACCOUNT_ID: { + type: "sst.sst.Secret" + value: string + } + Console: { + type: "sst.cloudflare.SolidStart" + url: string + } + Database: { + database: string + host: string + password: string + port: number + type: "sst.sst.Linkable" + username: string + } + Desktop: { + type: "sst.cloudflare.StaticSite" + url: string + } + EMAILOCTOPUS_API_KEY: { + type: "sst.sst.Secret" + value: string + } + GITHUB_APP_ID: { + type: "sst.sst.Secret" + value: string + } + GITHUB_APP_PRIVATE_KEY: { + type: "sst.sst.Secret" + value: string + } + GITHUB_CLIENT_ID_CONSOLE: { + type: "sst.sst.Secret" + value: string + } + GITHUB_CLIENT_SECRET_CONSOLE: { + type: "sst.sst.Secret" + value: string + } + GOOGLE_CLIENT_ID: { + type: "sst.sst.Secret" + value: string + } + HONEYCOMB_API_KEY: { + type: "sst.sst.Secret" + value: string + } + STRIPE_SECRET_KEY: { + type: "sst.sst.Secret" + value: string + } + STRIPE_WEBHOOK_SECRET: { + type: "sst.sst.Linkable" + value: string + } + Web: { + type: "sst.cloudflare.Astro" + url: string + } + ZEN_MODELS1: { + type: "sst.sst.Secret" + value: string + } + ZEN_MODELS2: { + type: "sst.sst.Secret" + value: string } } } -// cloudflare -import * as cloudflare from "@cloudflare/workers-types"; +// cloudflare +import * as cloudflare from "@cloudflare/workers-types" declare module "sst" { export interface Resource { - "Api": cloudflare.Service - "AuthApi": cloudflare.Service - "AuthStorage": cloudflare.KVNamespace - "Bucket": cloudflare.R2Bucket - "GatewayKv": cloudflare.KVNamespace - "LogProcessor": cloudflare.Service + Api: cloudflare.Service + AuthApi: cloudflare.Service + AuthStorage: cloudflare.KVNamespace + Bucket: cloudflare.R2Bucket + GatewayKv: cloudflare.KVNamespace + LogProcessor: cloudflare.Service } } import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/desktop/src/sst-env.d.ts b/packages/desktop/src/sst-env.d.ts index 47a8fbec7..1b1683a1e 100644 --- a/packages/desktop/src/sst-env.d.ts +++ b/packages/desktop/src/sst-env.d.ts @@ -2,9 +2,7 @@ /* tslint:disable */ /* eslint-disable */ /// -interface ImportMetaEnv { - -} +interface ImportMetaEnv {} interface ImportMeta { readonly env: ImportMetaEnv -} \ No newline at end of file +} diff --git a/packages/desktop/sst-env.d.ts b/packages/desktop/sst-env.d.ts index b6a7e9066..0397645b5 100644 --- a/packages/desktop/sst-env.d.ts +++ b/packages/desktop/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/function/sst-env.d.ts b/packages/function/sst-env.d.ts index 63c2af977..bcd7c2650 100644 --- a/packages/function/sst-env.d.ts +++ b/packages/function/sst-env.d.ts @@ -6,108 +6,108 @@ import "sst" declare module "sst" { export interface Resource { - "ADMIN_SECRET": { - "type": "sst.sst.Secret" - "value": string - } - "AUTH_API_URL": { - "type": "sst.sst.Linkable" - "value": string - } - "AWS_SES_ACCESS_KEY_ID": { - "type": "sst.sst.Secret" - "value": string - } - "AWS_SES_SECRET_ACCESS_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "CLOUDFLARE_API_TOKEN": { - "type": "sst.sst.Secret" - "value": string - } - "CLOUDFLARE_DEFAULT_ACCOUNT_ID": { - "type": "sst.sst.Secret" - "value": string - } - "Console": { - "type": "sst.cloudflare.SolidStart" - "url": string - } - "Database": { - "database": string - "host": string - "password": string - "port": number - "type": "sst.sst.Linkable" - "username": string - } - "Desktop": { - "type": "sst.cloudflare.StaticSite" - "url": string - } - "EMAILOCTOPUS_API_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_APP_ID": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_APP_PRIVATE_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_CLIENT_ID_CONSOLE": { - "type": "sst.sst.Secret" - "value": string - } - "GITHUB_CLIENT_SECRET_CONSOLE": { - "type": "sst.sst.Secret" - "value": string - } - "GOOGLE_CLIENT_ID": { - "type": "sst.sst.Secret" - "value": string - } - "HONEYCOMB_API_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "STRIPE_SECRET_KEY": { - "type": "sst.sst.Secret" - "value": string - } - "STRIPE_WEBHOOK_SECRET": { - "type": "sst.sst.Linkable" - "value": string - } - "Web": { - "type": "sst.cloudflare.Astro" - "url": string - } - "ZEN_MODELS1": { - "type": "sst.sst.Secret" - "value": string - } - "ZEN_MODELS2": { - "type": "sst.sst.Secret" - "value": string + ADMIN_SECRET: { + type: "sst.sst.Secret" + value: string + } + AUTH_API_URL: { + type: "sst.sst.Linkable" + value: string + } + AWS_SES_ACCESS_KEY_ID: { + type: "sst.sst.Secret" + value: string + } + AWS_SES_SECRET_ACCESS_KEY: { + type: "sst.sst.Secret" + value: string + } + CLOUDFLARE_API_TOKEN: { + type: "sst.sst.Secret" + value: string + } + CLOUDFLARE_DEFAULT_ACCOUNT_ID: { + type: "sst.sst.Secret" + value: string + } + Console: { + type: "sst.cloudflare.SolidStart" + url: string + } + Database: { + database: string + host: string + password: string + port: number + type: "sst.sst.Linkable" + username: string + } + Desktop: { + type: "sst.cloudflare.StaticSite" + url: string + } + EMAILOCTOPUS_API_KEY: { + type: "sst.sst.Secret" + value: string + } + GITHUB_APP_ID: { + type: "sst.sst.Secret" + value: string + } + GITHUB_APP_PRIVATE_KEY: { + type: "sst.sst.Secret" + value: string + } + GITHUB_CLIENT_ID_CONSOLE: { + type: "sst.sst.Secret" + value: string + } + GITHUB_CLIENT_SECRET_CONSOLE: { + type: "sst.sst.Secret" + value: string + } + GOOGLE_CLIENT_ID: { + type: "sst.sst.Secret" + value: string + } + HONEYCOMB_API_KEY: { + type: "sst.sst.Secret" + value: string + } + STRIPE_SECRET_KEY: { + type: "sst.sst.Secret" + value: string + } + STRIPE_WEBHOOK_SECRET: { + type: "sst.sst.Linkable" + value: string + } + Web: { + type: "sst.cloudflare.Astro" + url: string + } + ZEN_MODELS1: { + type: "sst.sst.Secret" + value: string + } + ZEN_MODELS2: { + type: "sst.sst.Secret" + value: string } } } -// cloudflare -import * as cloudflare from "@cloudflare/workers-types"; +// cloudflare +import * as cloudflare from "@cloudflare/workers-types" declare module "sst" { export interface Resource { - "Api": cloudflare.Service - "AuthApi": cloudflare.Service - "AuthStorage": cloudflare.KVNamespace - "Bucket": cloudflare.R2Bucket - "GatewayKv": cloudflare.KVNamespace - "LogProcessor": cloudflare.Service + Api: cloudflare.Service + AuthApi: cloudflare.Service + AuthStorage: cloudflare.KVNamespace + Bucket: cloudflare.R2Bucket + GatewayKv: cloudflare.KVNamespace + LogProcessor: cloudflare.Service } } import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/opencode/sst-env.d.ts b/packages/opencode/sst-env.d.ts index b6a7e9066..0397645b5 100644 --- a/packages/opencode/sst-env.d.ts +++ b/packages/opencode/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 6d9df4516..d1c5c3039 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} \ No newline at end of file +} diff --git a/packages/plugin/sst-env.d.ts b/packages/plugin/sst-env.d.ts index b6a7e9066..0397645b5 100644 --- a/packages/plugin/sst-env.d.ts +++ b/packages/plugin/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/script/sst-env.d.ts b/packages/script/sst-env.d.ts index b6a7e9066..0397645b5 100644 --- a/packages/script/sst-env.d.ts +++ b/packages/script/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index 622878742..a5e9cf311 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} \ No newline at end of file +} diff --git a/packages/sdk/js/sst-env.d.ts b/packages/sdk/js/sst-env.d.ts index 9b9de7327..bd5588217 100644 --- a/packages/sdk/js/sst-env.d.ts +++ b/packages/sdk/js/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/slack/sst-env.d.ts b/packages/slack/sst-env.d.ts index b6a7e9066..0397645b5 100644 --- a/packages/slack/sst-env.d.ts +++ b/packages/slack/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/ui/sst-env.d.ts b/packages/ui/sst-env.d.ts index b6a7e9066..0397645b5 100644 --- a/packages/ui/sst-env.d.ts +++ b/packages/ui/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/packages/web/sst-env.d.ts b/packages/web/sst-env.d.ts index b6a7e9066..0397645b5 100644 --- a/packages/web/sst-env.d.ts +++ b/packages/web/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/sdks/vscode/sst-env.d.ts b/sdks/vscode/sst-env.d.ts index b6a7e9066..0397645b5 100644 --- a/sdks/vscode/sst-env.d.ts +++ b/sdks/vscode/sst-env.d.ts @@ -6,4 +6,4 @@ /// import "sst" -export {} \ No newline at end of file +export {} diff --git a/sst-env.d.ts b/sst-env.d.ts index 876f05228..361aff315 100644 --- a/sst-env.d.ts +++ b/sst-env.d.ts @@ -5,120 +5,120 @@ declare module "sst" { export interface Resource { - "ADMIN_SECRET": { - "type": "sst.sst.Secret" - "value": string - } - "AUTH_API_URL": { - "type": "sst.sst.Linkable" - "value": string - } - "AWS_SES_ACCESS_KEY_ID": { - "type": "sst.sst.Secret" - "value": string + ADMIN_SECRET: { + type: "sst.sst.Secret" + value: string + } + AUTH_API_URL: { + type: "sst.sst.Linkable" + value: string + } + AWS_SES_ACCESS_KEY_ID: { + type: "sst.sst.Secret" + value: string } - "AWS_SES_SECRET_ACCESS_KEY": { - "type": "sst.sst.Secret" - "value": string + AWS_SES_SECRET_ACCESS_KEY: { + type: "sst.sst.Secret" + value: string } - "Api": { - "type": "sst.cloudflare.Worker" - "url": string + Api: { + type: "sst.cloudflare.Worker" + url: string } - "AuthApi": { - "type": "sst.cloudflare.Worker" - "url": string + AuthApi: { + type: "sst.cloudflare.Worker" + url: string } - "AuthStorage": { - "namespaceId": string - "type": "sst.cloudflare.Kv" + AuthStorage: { + namespaceId: string + type: "sst.cloudflare.Kv" } - "Bucket": { - "name": string - "type": "sst.cloudflare.Bucket" + Bucket: { + name: string + type: "sst.cloudflare.Bucket" } - "CLOUDFLARE_API_TOKEN": { - "type": "sst.sst.Secret" - "value": string + CLOUDFLARE_API_TOKEN: { + type: "sst.sst.Secret" + value: string } - "CLOUDFLARE_DEFAULT_ACCOUNT_ID": { - "type": "sst.sst.Secret" - "value": string + CLOUDFLARE_DEFAULT_ACCOUNT_ID: { + type: "sst.sst.Secret" + value: string } - "Console": { - "type": "sst.cloudflare.SolidStart" - "url": string + Console: { + type: "sst.cloudflare.SolidStart" + url: string } - "Database": { - "database": string - "host": string - "password": string - "port": number - "type": "sst.sst.Linkable" - "username": string + Database: { + database: string + host: string + password: string + port: number + type: "sst.sst.Linkable" + username: string } - "Desktop": { - "type": "sst.cloudflare.StaticSite" - "url": string + Desktop: { + type: "sst.cloudflare.StaticSite" + url: string } - "EMAILOCTOPUS_API_KEY": { - "type": "sst.sst.Secret" - "value": string + EMAILOCTOPUS_API_KEY: { + type: "sst.sst.Secret" + value: string } - "GITHUB_APP_ID": { - "type": "sst.sst.Secret" - "value": string + GITHUB_APP_ID: { + type: "sst.sst.Secret" + value: string } - "GITHUB_APP_PRIVATE_KEY": { - "type": "sst.sst.Secret" - "value": string + GITHUB_APP_PRIVATE_KEY: { + type: "sst.sst.Secret" + value: string } - "GITHUB_CLIENT_ID_CONSOLE": { - "type": "sst.sst.Secret" - "value": string + GITHUB_CLIENT_ID_CONSOLE: { + type: "sst.sst.Secret" + value: string } - "GITHUB_CLIENT_SECRET_CONSOLE": { - "type": "sst.sst.Secret" - "value": string + GITHUB_CLIENT_SECRET_CONSOLE: { + type: "sst.sst.Secret" + value: string } - "GOOGLE_CLIENT_ID": { - "type": "sst.sst.Secret" - "value": string + GOOGLE_CLIENT_ID: { + type: "sst.sst.Secret" + value: string } - "GatewayKv": { - "namespaceId": string - "type": "sst.cloudflare.Kv" + GatewayKv: { + namespaceId: string + type: "sst.cloudflare.Kv" } - "HONEYCOMB_API_KEY": { - "type": "sst.sst.Secret" - "value": string + HONEYCOMB_API_KEY: { + type: "sst.sst.Secret" + value: string } - "LogProcessor": { - "type": "sst.cloudflare.Worker" + LogProcessor: { + type: "sst.cloudflare.Worker" } - "STRIPE_SECRET_KEY": { - "type": "sst.sst.Secret" - "value": string + STRIPE_SECRET_KEY: { + type: "sst.sst.Secret" + value: string } - "STRIPE_WEBHOOK_SECRET": { - "type": "sst.sst.Linkable" - "value": string + STRIPE_WEBHOOK_SECRET: { + type: "sst.sst.Linkable" + value: string } - "Web": { - "type": "sst.cloudflare.Astro" - "url": string + Web: { + type: "sst.cloudflare.Astro" + url: string } - "ZEN_MODELS1": { - "type": "sst.sst.Secret" - "value": string + ZEN_MODELS1: { + type: "sst.sst.Secret" + value: string } - "ZEN_MODELS2": { - "type": "sst.sst.Secret" - "value": string + ZEN_MODELS2: { + type: "sst.sst.Secret" + value: string } } } /// import "sst" -export {} \ No newline at end of file +export {} -- cgit v1.2.3 From f8a1a0b26fee9afbc9c66d5a1c95336486b3a6ed Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 8 Nov 2025 10:33:54 -0500 Subject: zen: fix billing button --- .../app/src/routes/workspace/[id]/billing/billing-section.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'packages/console') diff --git a/packages/console/app/src/routes/workspace/[id]/billing/billing-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/billing-section.tsx index 05f8edd01..fe4e08b7c 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/billing-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/billing-section.tsx @@ -34,10 +34,17 @@ export function BillingSection() { const sessionSubmission = useSubmission(createSessionUrl) const [store, setStore] = createStore({ showAddBalanceForm: false, - addBalanceAmount: "", + addBalanceAmount: billingInfo()?.reloadAmount.toString() ?? "", checkoutRedirecting: false, sessionRedirecting: false, }) + + createEffect(() => { + const info = billingInfo() + if (info) { + setStore("addBalanceAmount", info.reloadAmount.toString()) + } + }) const balance = createMemo(() => formatBalance(billingInfo()?.balance ?? 0)) async function onClickCheckout() { @@ -67,7 +74,6 @@ export function BillingSection() { } setStore({ showAddBalanceForm: true, - addBalanceAmount: billingInfo()!.reloadAmount.toString(), }) } -- cgit v1.2.3 From 47b4cc6d53d9382a222b5ef3819bc9a3a45a24f3 Mon Sep 17 00:00:00 2001 From: opencode Date: Sat, 8 Nov 2025 21:48:37 +0000 Subject: release: v1.0.46 --- bun.lock | 22 +++++++++++----------- packages/console/app/package.json | 2 +- packages/console/core/package.json | 2 +- packages/console/function/package.json | 2 +- packages/console/mail/package.json | 2 +- packages/desktop/package.json | 2 +- packages/extensions/zed/extension.toml | 12 ++++++------ packages/function/package.json | 2 +- packages/opencode/package.json | 2 +- packages/plugin/package.json | 4 ++-- packages/sdk/js/package.json | 4 ++-- packages/slack/package.json | 2 +- packages/ui/package.json | 2 +- packages/web/package.json | 2 +- sdks/vscode/package.json | 2 +- 15 files changed, 32 insertions(+), 32 deletions(-) (limited to 'packages/console') diff --git a/bun.lock b/bun.lock index a4d0ecbe3..e1101abfc 100644 --- a/bun.lock +++ b/bun.lock @@ -39,7 +39,7 @@ }, "packages/console/core": { "name": "@opencode-ai/console-core", - "version": "1.0.45", + "version": "1.0.46", "dependencies": { "@aws-sdk/client-sts": "3.782.0", "@jsx-email/render": "1.1.1", @@ -66,7 +66,7 @@ }, "packages/console/function": { "name": "@opencode-ai/console-function", - "version": "1.0.45", + "version": "1.0.46", "dependencies": { "@ai-sdk/anthropic": "2.0.0", "@ai-sdk/openai": "2.0.2", @@ -90,7 +90,7 @@ }, "packages/console/mail": { "name": "@opencode-ai/console-mail", - "version": "1.0.45", + "version": "1.0.46", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", @@ -114,7 +114,7 @@ }, "packages/desktop": { "name": "@opencode-ai/desktop", - "version": "1.0.45", + "version": "1.0.46", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -154,7 +154,7 @@ }, "packages/function": { "name": "@opencode-ai/function", - "version": "1.0.45", + "version": "1.0.46", "dependencies": { "@octokit/auth-app": "8.0.1", "@octokit/rest": "22.0.0", @@ -170,7 +170,7 @@ }, "packages/opencode": { "name": "opencode", - "version": "1.0.45", + "version": "1.0.46", "bin": { "opencode": "./bin/opencode", }, @@ -248,7 +248,7 @@ }, "packages/plugin": { "name": "@opencode-ai/plugin", - "version": "1.0.45", + "version": "1.0.46", "dependencies": { "@opencode-ai/sdk": "workspace:*", "zod": "catalog:", @@ -268,7 +268,7 @@ }, "packages/sdk/js": { "name": "@opencode-ai/sdk", - "version": "1.0.45", + "version": "1.0.46", "devDependencies": { "@hey-api/openapi-ts": "0.81.0", "@tsconfig/node22": "catalog:", @@ -279,7 +279,7 @@ }, "packages/slack": { "name": "@opencode-ai/slack", - "version": "1.0.45", + "version": "1.0.46", "dependencies": { "@opencode-ai/sdk": "workspace:*", "@slack/bolt": "^3.17.1", @@ -292,7 +292,7 @@ }, "packages/ui": { "name": "@opencode-ai/ui", - "version": "1.0.45", + "version": "1.0.46", "dependencies": { "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", @@ -322,7 +322,7 @@ }, "packages/web": { "name": "@opencode-ai/web", - "version": "1.0.45", + "version": "1.0.46", "dependencies": { "@astrojs/cloudflare": "12.6.3", "@astrojs/markdown-remark": "6.3.1", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index f2bc6fd1b..671a31ab8 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -7,7 +7,7 @@ "dev:remote": "VITE_AUTH_URL=https://auth.dev.opencode.ai bun sst shell --stage=dev bun dev", "build": "./script/generate-sitemap.ts && vinxi build && ../../opencode/script/schema.ts ./.output/public/config.json", "start": "vinxi start", - "version": "1.0.45" + "version": "1.0.46" }, "dependencies": { "@ibm/plex": "6.4.1", diff --git a/packages/console/core/package.json b/packages/console/core/package.json index 0f8558630..afc8aca16 100644 --- a/packages/console/core/package.json +++ b/packages/console/core/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/console-core", - "version": "1.0.45", + "version": "1.0.46", "private": true, "type": "module", "dependencies": { diff --git a/packages/console/function/package.json b/packages/console/function/package.json index 87d838d1b..04696534a 100644 --- a/packages/console/function/package.json +++ b/packages/console/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-function", - "version": "1.0.45", + "version": "1.0.46", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/console/mail/package.json b/packages/console/mail/package.json index a48709737..2af5850a6 100644 --- a/packages/console/mail/package.json +++ b/packages/console/mail/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/console-mail", - "version": "1.0.45", + "version": "1.0.46", "dependencies": { "@jsx-email/all": "2.2.3", "@jsx-email/cli": "1.4.3", diff --git a/packages/desktop/package.json b/packages/desktop/package.json index 1e50e474b..d992b550c 100644 --- a/packages/desktop/package.json +++ b/packages/desktop/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/desktop", - "version": "1.0.45", + "version": "1.0.46", "description": "", "type": "module", "scripts": { diff --git a/packages/extensions/zed/extension.toml b/packages/extensions/zed/extension.toml index 384af6597..498f03b6d 100644 --- a/packages/extensions/zed/extension.toml +++ b/packages/extensions/zed/extension.toml @@ -1,7 +1,7 @@ id = "opencode" name = "OpenCode" description = "The AI coding agent built for the terminal" -version = "1.0.45" +version = "1.0.46" schema_version = 1 authors = ["Anomaly"] repository = "https://github.com/sst/opencode" @@ -11,26 +11,26 @@ name = "OpenCode" icon = "./icons/opencode.svg" [agent_servers.opencode.targets.darwin-aarch64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.45/opencode-darwin-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.46/opencode-darwin-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.darwin-x86_64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.45/opencode-darwin-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.46/opencode-darwin-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-aarch64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.45/opencode-linux-arm64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.46/opencode-linux-arm64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.linux-x86_64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.45/opencode-linux-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.46/opencode-linux-x64.zip" cmd = "./opencode" args = ["acp"] [agent_servers.opencode.targets.windows-x86_64] -archive = "https://github.com/sst/opencode/releases/download/v1.0.45/opencode-windows-x64.zip" +archive = "https://github.com/sst/opencode/releases/download/v1.0.46/opencode-windows-x64.zip" cmd = "./opencode.exe" args = ["acp"] diff --git a/packages/function/package.json b/packages/function/package.json index efc10d5a0..004a5db0a 100644 --- a/packages/function/package.json +++ b/packages/function/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/function", - "version": "1.0.45", + "version": "1.0.46", "$schema": "https://json.schemastore.org/package.json", "private": true, "type": "module", diff --git a/packages/opencode/package.json b/packages/opencode/package.json index 8f5e8028f..10e8bfc00 100644 --- a/packages/opencode/package.json +++ b/packages/opencode/package.json @@ -1,6 +1,6 @@ { "$schema": "https://json.schemastore.org/package.json", - "version": "1.0.45", + "version": "1.0.46", "name": "opencode", "type": "module", "private": true, diff --git a/packages/plugin/package.json b/packages/plugin/package.json index d1c5c3039..28bcc1421 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/plugin", - "version": "1.0.45", + "version": "1.0.46", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -24,4 +24,4 @@ "typescript": "catalog:", "@typescript/native-preview": "catalog:" } -} +} \ No newline at end of file diff --git a/packages/sdk/js/package.json b/packages/sdk/js/package.json index a5e9cf311..1a1dea3d3 100644 --- a/packages/sdk/js/package.json +++ b/packages/sdk/js/package.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@opencode-ai/sdk", - "version": "1.0.45", + "version": "1.0.46", "type": "module", "scripts": { "typecheck": "tsgo --noEmit", @@ -26,4 +26,4 @@ "publishConfig": { "directory": "dist" } -} +} \ No newline at end of file diff --git a/packages/slack/package.json b/packages/slack/package.json index 2e7fa1fb7..182eeaea3 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/slack", - "version": "1.0.45", + "version": "1.0.46", "type": "module", "scripts": { "dev": "bun run src/index.ts", diff --git a/packages/ui/package.json b/packages/ui/package.json index 27cbd43d6..0f4242bba 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "@opencode-ai/ui", - "version": "1.0.45", + "version": "1.0.46", "type": "module", "exports": { ".": "./src/components/index.ts", diff --git a/packages/web/package.json b/packages/web/package.json index 86b5bf106..f7936f34d 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@opencode-ai/web", "type": "module", - "version": "1.0.45", + "version": "1.0.46", "scripts": { "dev": "astro dev", "dev:remote": "VITE_API_URL=https://api.opencode.ai astro dev", diff --git a/sdks/vscode/package.json b/sdks/vscode/package.json index f4d5f5e46..13a3536a1 100644 --- a/sdks/vscode/package.json +++ b/sdks/vscode/package.json @@ -2,7 +2,7 @@ "name": "opencode", "displayName": "opencode", "description": "opencode for VS Code", - "version": "1.0.45", + "version": "1.0.46", "publisher": "sst-dev", "repository": { "type": "git", -- cgit v1.2.3