mirror of
https://fastgit.cc/https://github.com/anomalyco/opencode
synced 2026-04-20 21:00:29 +08:00
add experimental provider auth HttpApi slice (#22389)
This commit is contained in:
14
bun.lock
14
bun.lock
@@ -358,7 +358,6 @@
|
||||
"@opencode-ai/plugin": "workspace:*",
|
||||
"@opencode-ai/script": "workspace:*",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@opencode-ai/server": "workspace:*",
|
||||
"@openrouter/ai-sdk-provider": "2.5.1",
|
||||
"@opentelemetry/api": "1.9.0",
|
||||
"@opentelemetry/context-async-hooks": "2.6.1",
|
||||
@@ -506,17 +505,6 @@
|
||||
"typescript": "catalog:",
|
||||
},
|
||||
},
|
||||
"packages/server": {
|
||||
"name": "@opencode-ai/server",
|
||||
"version": "1.4.6",
|
||||
"dependencies": {
|
||||
"effect": "catalog:",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
},
|
||||
},
|
||||
"packages/shared": {
|
||||
"name": "@opencode-ai/shared",
|
||||
"version": "1.4.6",
|
||||
@@ -1568,8 +1556,6 @@
|
||||
|
||||
"@opencode-ai/sdk": ["@opencode-ai/sdk@workspace:packages/sdk/js"],
|
||||
|
||||
"@opencode-ai/server": ["@opencode-ai/server@workspace:packages/server"],
|
||||
|
||||
"@opencode-ai/shared": ["@opencode-ai/shared@workspace:packages/shared"],
|
||||
|
||||
"@opencode-ai/slack": ["@opencode-ai/slack@workspace:packages/slack"],
|
||||
|
||||
@@ -115,7 +115,6 @@
|
||||
"@opencode-ai/plugin": "workspace:*",
|
||||
"@opencode-ai/script": "workspace:*",
|
||||
"@opencode-ai/sdk": "workspace:*",
|
||||
"@opencode-ai/server": "workspace:*",
|
||||
"@openrouter/ai-sdk-provider": "2.5.1",
|
||||
"@opentelemetry/api": "1.9.0",
|
||||
"@opentelemetry/context-async-hooks": "2.6.1",
|
||||
|
||||
@@ -156,6 +156,14 @@ Ordering for a route-group migration:
|
||||
3. move tagged route-facing errors to `Schema.TaggedErrorClass` where needed
|
||||
4. switch existing Zod boundary validators to derived `.zod`
|
||||
5. define the `HttpApi` contract from the canonical Effect schemas
|
||||
6. regenerate the SDK (`./packages/sdk/js/script/build.ts`) and verify zero diff against `dev`
|
||||
|
||||
SDK shape rule:
|
||||
|
||||
- every schema migration must preserve the generated SDK output byte-for-byte
|
||||
- `Schema.Class` emits a named `$ref` in OpenAPI via its identifier — use it only for types that already had `.meta({ ref })` in the old Zod schema
|
||||
- inner / nested types that were anonymous in the old Zod schema should stay as `Schema.Struct` (not `Schema.Class`) to avoid introducing new named components in the OpenAPI spec
|
||||
- if a diff appears in `packages/sdk/js/src/v2/gen/types.gen.ts`, the migration introduced an unintended API surface change — fix it before merging
|
||||
|
||||
Temporary exception:
|
||||
|
||||
@@ -195,8 +203,9 @@ Use the same sequence for each route group.
|
||||
4. Define the `HttpApi` contract separately from the handlers.
|
||||
5. Implement handlers by yielding the existing service from context.
|
||||
6. Mount the new surface in parallel under an experimental prefix.
|
||||
7. Add one end-to-end test and one OpenAPI-focused test.
|
||||
8. Compare ergonomics before migrating the next endpoint.
|
||||
7. Regenerate the SDK and verify zero diff against `dev` (see SDK shape rule above).
|
||||
8. Add one end-to-end test and one OpenAPI-focused test.
|
||||
9. Compare ergonomics before migrating the next endpoint.
|
||||
|
||||
Rule of thumb:
|
||||
|
||||
|
||||
@@ -2,70 +2,62 @@ import type { AuthOAuthResult, Hooks } from "@opencode-ai/plugin"
|
||||
import { NamedError } from "@opencode-ai/shared/util/error"
|
||||
import { Auth } from "@/auth"
|
||||
import { InstanceState } from "@/effect/instance-state"
|
||||
import { zod } from "@/util/effect-zod"
|
||||
import { withStatics } from "@/util/schema"
|
||||
import { Plugin } from "../plugin"
|
||||
import { ProviderID } from "./schema"
|
||||
import { Array as Arr, Effect, Layer, Record, Result, Context } from "effect"
|
||||
import { Array as Arr, Effect, Layer, Record, Result, Context, Schema } from "effect"
|
||||
import z from "zod"
|
||||
|
||||
export namespace ProviderAuth {
|
||||
export const Method = z
|
||||
.object({
|
||||
type: z.union([z.literal("oauth"), z.literal("api")]),
|
||||
label: z.string(),
|
||||
prompts: z
|
||||
.array(
|
||||
z.union([
|
||||
z.object({
|
||||
type: z.literal("text"),
|
||||
key: z.string(),
|
||||
message: z.string(),
|
||||
placeholder: z.string().optional(),
|
||||
when: z
|
||||
.object({
|
||||
key: z.string(),
|
||||
op: z.union([z.literal("eq"), z.literal("neq")]),
|
||||
value: z.string(),
|
||||
})
|
||||
.optional(),
|
||||
}),
|
||||
z.object({
|
||||
type: z.literal("select"),
|
||||
key: z.string(),
|
||||
message: z.string(),
|
||||
options: z.array(
|
||||
z.object({
|
||||
label: z.string(),
|
||||
value: z.string(),
|
||||
hint: z.string().optional(),
|
||||
}),
|
||||
),
|
||||
when: z
|
||||
.object({
|
||||
key: z.string(),
|
||||
op: z.union([z.literal("eq"), z.literal("neq")]),
|
||||
value: z.string(),
|
||||
})
|
||||
.optional(),
|
||||
}),
|
||||
]),
|
||||
)
|
||||
.optional(),
|
||||
})
|
||||
.meta({
|
||||
ref: "ProviderAuthMethod",
|
||||
})
|
||||
export type Method = z.infer<typeof Method>
|
||||
const When = Schema.Struct({
|
||||
key: Schema.String,
|
||||
op: Schema.Literals(["eq", "neq"]),
|
||||
value: Schema.String,
|
||||
})
|
||||
|
||||
export const Authorization = z
|
||||
.object({
|
||||
url: z.string(),
|
||||
method: z.union([z.literal("auto"), z.literal("code")]),
|
||||
instructions: z.string(),
|
||||
})
|
||||
.meta({
|
||||
ref: "ProviderAuthAuthorization",
|
||||
})
|
||||
export type Authorization = z.infer<typeof Authorization>
|
||||
const TextPrompt = Schema.Struct({
|
||||
type: Schema.Literal("text"),
|
||||
key: Schema.String,
|
||||
message: Schema.String,
|
||||
placeholder: Schema.optional(Schema.String),
|
||||
when: Schema.optional(When),
|
||||
})
|
||||
|
||||
const SelectOption = Schema.Struct({
|
||||
label: Schema.String,
|
||||
value: Schema.String,
|
||||
hint: Schema.optional(Schema.String),
|
||||
})
|
||||
|
||||
const SelectPrompt = Schema.Struct({
|
||||
type: Schema.Literal("select"),
|
||||
key: Schema.String,
|
||||
message: Schema.String,
|
||||
options: Schema.Array(SelectOption),
|
||||
when: Schema.optional(When),
|
||||
})
|
||||
|
||||
const Prompt = Schema.Union([TextPrompt, SelectPrompt])
|
||||
|
||||
export class Method extends Schema.Class<Method>("ProviderAuthMethod")({
|
||||
type: Schema.Literals(["oauth", "api"]),
|
||||
label: Schema.String,
|
||||
prompts: Schema.optional(Schema.Array(Prompt)),
|
||||
}) {
|
||||
static readonly zod = zod(this)
|
||||
}
|
||||
|
||||
export const Methods = Schema.Record(Schema.String, Schema.Array(Method)).pipe(withStatics((s) => ({ zod: zod(s) })))
|
||||
export type Methods = typeof Methods.Type
|
||||
|
||||
export class Authorization extends Schema.Class<Authorization>("ProviderAuthAuthorization")({
|
||||
url: Schema.String,
|
||||
method: Schema.Literals(["auto", "code"]),
|
||||
instructions: Schema.String,
|
||||
}) {
|
||||
static readonly zod = zod(this)
|
||||
}
|
||||
|
||||
export const OauthMissing = NamedError.create("ProviderAuthOauthMissing", z.object({ providerID: ProviderID.zod }))
|
||||
|
||||
@@ -94,7 +86,7 @@ export namespace ProviderAuth {
|
||||
type Hook = NonNullable<Hooks["auth"]>
|
||||
|
||||
export interface Interface {
|
||||
readonly methods: () => Effect.Effect<Record<ProviderID, Method[]>>
|
||||
readonly methods: () => Effect.Effect<Methods>
|
||||
readonly authorize: (input: {
|
||||
providerID: ProviderID
|
||||
method: number
|
||||
@@ -131,11 +123,12 @@ export namespace ProviderAuth {
|
||||
}),
|
||||
)
|
||||
|
||||
const decode = Schema.decodeUnknownSync(Methods)
|
||||
const methods = Effect.fn("ProviderAuth.methods")(function* () {
|
||||
const hooks = (yield* InstanceState.get(state)).hooks
|
||||
return Record.map(hooks, (item) =>
|
||||
item.methods.map(
|
||||
(method): Method => ({
|
||||
return decode(
|
||||
Record.map(hooks, (item) =>
|
||||
item.methods.map((method) => ({
|
||||
type: method.type,
|
||||
label: method.label,
|
||||
prompts: method.prompts?.map((prompt) => {
|
||||
@@ -156,7 +149,7 @@ export namespace ProviderAuth {
|
||||
when: prompt.when,
|
||||
}
|
||||
}),
|
||||
}),
|
||||
})),
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
46
packages/opencode/src/server/instance/httpapi/provider.ts
Normal file
46
packages/opencode/src/server/instance/httpapi/provider.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { ProviderAuth } from "@/provider/auth"
|
||||
import { Effect, Layer } from "effect"
|
||||
import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
|
||||
|
||||
const root = "/experimental/httpapi/provider"
|
||||
|
||||
export const ProviderApi = HttpApi.make("provider")
|
||||
.add(
|
||||
HttpApiGroup.make("provider")
|
||||
.add(
|
||||
HttpApiEndpoint.get("auth", `${root}/auth`, {
|
||||
success: ProviderAuth.Methods,
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "provider.auth",
|
||||
summary: "Get provider auth methods",
|
||||
description: "Retrieve available authentication methods for all AI providers.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
title: "provider",
|
||||
description: "Experimental HttpApi provider routes.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
title: "opencode experimental HttpApi",
|
||||
version: "0.0.1",
|
||||
description: "Experimental HttpApi surface for selected instance routes.",
|
||||
}),
|
||||
)
|
||||
|
||||
export const ProviderLive = Layer.unwrap(
|
||||
Effect.gen(function* () {
|
||||
const svc = yield* ProviderAuth.Service
|
||||
|
||||
const auth = Effect.fn("ProviderHttpApi.auth")(function* () {
|
||||
return yield* svc.methods()
|
||||
})
|
||||
|
||||
return HttpApiBuilder.group(ProviderApi, "provider", (handlers) => handlers.handle("auth", auth))
|
||||
}),
|
||||
).pipe(Layer.provide(ProviderAuth.defaultLayer))
|
||||
@@ -10,8 +10,10 @@ import { InstanceBootstrap } from "@/project/bootstrap"
|
||||
import { Instance } from "@/project/instance"
|
||||
import { Filesystem } from "@/util/filesystem"
|
||||
import { Permission } from "@/permission"
|
||||
import { ProviderAuth } from "@/provider/auth"
|
||||
import { Question } from "@/question"
|
||||
import { PermissionApi, PermissionLive } from "./permission"
|
||||
import { ProviderApi, ProviderLive } from "./provider"
|
||||
import { QuestionApi, QuestionLive } from "./question"
|
||||
|
||||
const Query = Schema.Struct({
|
||||
@@ -108,6 +110,7 @@ export namespace ExperimentalHttpApiServer {
|
||||
|
||||
const QuestionSecured = QuestionApi.middleware(Authorization)
|
||||
const PermissionSecured = PermissionApi.middleware(Authorization)
|
||||
const ProviderSecured = ProviderApi.middleware(Authorization)
|
||||
|
||||
export const routes = Layer.mergeAll(
|
||||
HttpApiBuilder.layer(QuestionSecured, { openapiPath: "/experimental/httpapi/question/doc" }).pipe(
|
||||
@@ -116,6 +119,9 @@ export namespace ExperimentalHttpApiServer {
|
||||
HttpApiBuilder.layer(PermissionSecured, { openapiPath: "/experimental/httpapi/permission/doc" }).pipe(
|
||||
Layer.provide(PermissionLive),
|
||||
),
|
||||
HttpApiBuilder.layer(ProviderSecured, { openapiPath: "/experimental/httpapi/provider/doc" }).pipe(
|
||||
Layer.provide(ProviderLive),
|
||||
),
|
||||
).pipe(Layer.provide(auth), Layer.provide(normalize), Layer.provide(instance))
|
||||
|
||||
export const layer = (opts: { hostname: string; port: number }) =>
|
||||
@@ -127,5 +133,6 @@ export namespace ExperimentalHttpApiServer {
|
||||
Layer.provideMerge(NodeHttpServer.layerTest),
|
||||
Layer.provideMerge(Question.defaultLayer),
|
||||
Layer.provideMerge(Permission.defaultLayer),
|
||||
Layer.provideMerge(ProviderAuth.defaultLayer),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ export const ProviderRoutes = lazy(() =>
|
||||
description: "Provider auth methods",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(z.record(z.string(), z.array(ProviderAuth.Method))),
|
||||
schema: resolver(ProviderAuth.Methods.zod),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -103,7 +103,7 @@ export const ProviderRoutes = lazy(() =>
|
||||
description: "Authorization URL and method",
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: resolver(ProviderAuth.Authorization.optional()),
|
||||
schema: resolver(ProviderAuth.Authorization.zod.optional()),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/package.json",
|
||||
"name": "@opencode-ai/server",
|
||||
"version": "1.4.6",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./openapi": "./src/openapi.ts",
|
||||
"./definition": "./src/definition/index.ts",
|
||||
"./definition/api": "./src/definition/api.ts",
|
||||
"./definition/question": "./src/definition/question.ts",
|
||||
"./api": "./src/api/index.ts",
|
||||
"./api/question": "./src/api/question.ts"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"typecheck": "tsgo --noEmit",
|
||||
"build": "tsc"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript/native-preview": "catalog:",
|
||||
"typescript": "catalog:"
|
||||
},
|
||||
"dependencies": {
|
||||
"effect": "catalog:"
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
export { makeQuestionHandler } from "./question.js"
|
||||
export type { QuestionOps } from "./question.js"
|
||||
@@ -1,37 +0,0 @@
|
||||
import { Effect, Schema } from "effect"
|
||||
import { HttpApiBuilder } from "effect/unstable/httpapi"
|
||||
import { QuestionReply, QuestionRequest, questionApi } from "../definition/question.js"
|
||||
|
||||
export interface QuestionOps<R = never> {
|
||||
readonly list: () => Effect.Effect<ReadonlyArray<unknown>, never, R>
|
||||
readonly reply: (input: {
|
||||
requestID: string
|
||||
answers: Schema.Schema.Type<typeof QuestionReply>["answers"]
|
||||
}) => Effect.Effect<void, never, R>
|
||||
}
|
||||
|
||||
export const makeQuestionHandler = <R>(ops: QuestionOps<R>) =>
|
||||
HttpApiBuilder.group(
|
||||
questionApi,
|
||||
"question",
|
||||
Effect.fn("QuestionHttpApi.handlers")(function* (handlers) {
|
||||
const decode = Schema.decodeUnknownSync(Schema.Array(QuestionRequest))
|
||||
|
||||
const list = Effect.fn("QuestionHttpApi.list")(function* () {
|
||||
return decode(yield* ops.list())
|
||||
})
|
||||
|
||||
const reply = Effect.fn("QuestionHttpApi.reply")(function* (ctx: {
|
||||
params: { requestID: string }
|
||||
payload: Schema.Schema.Type<typeof QuestionReply>
|
||||
}) {
|
||||
yield* ops.reply({
|
||||
requestID: ctx.params.requestID,
|
||||
answers: ctx.payload.answers,
|
||||
})
|
||||
return true
|
||||
})
|
||||
|
||||
return handlers.handle("list", list).handle("reply", reply)
|
||||
}),
|
||||
)
|
||||
@@ -1,12 +0,0 @@
|
||||
import { HttpApi, OpenApi } from "effect/unstable/httpapi"
|
||||
import { questionApi } from "./question.js"
|
||||
|
||||
export const api = HttpApi.make("opencode")
|
||||
.addHttpApi(questionApi)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
title: "opencode experimental HttpApi",
|
||||
version: "0.0.1",
|
||||
description: "Experimental HttpApi surface for selected instance routes.",
|
||||
}),
|
||||
)
|
||||
@@ -1,2 +0,0 @@
|
||||
export { api } from "./api.js"
|
||||
export { questionApi, QuestionReply, QuestionRequest } from "./question.js"
|
||||
@@ -1,94 +0,0 @@
|
||||
import { Schema } from "effect"
|
||||
import { HttpApi, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
|
||||
|
||||
const root = "/experimental/httpapi/question"
|
||||
|
||||
// Temporary transport-local schemas until canonical question schemas move into packages/core.
|
||||
export const QuestionID = Schema.String.annotate({ identifier: "QuestionID" })
|
||||
export const SessionID = Schema.String.annotate({ identifier: "SessionID" })
|
||||
export const MessageID = Schema.String.annotate({ identifier: "MessageID" })
|
||||
|
||||
export class QuestionOption extends Schema.Class<QuestionOption>("QuestionOption")({
|
||||
label: Schema.String.annotate({
|
||||
description: "Display text (1-5 words, concise)",
|
||||
}),
|
||||
description: Schema.String.annotate({
|
||||
description: "Explanation of choice",
|
||||
}),
|
||||
}) {}
|
||||
|
||||
const base = {
|
||||
question: Schema.String.annotate({
|
||||
description: "Complete question",
|
||||
}),
|
||||
header: Schema.String.annotate({
|
||||
description: "Very short label (max 30 chars)",
|
||||
}),
|
||||
options: Schema.Array(QuestionOption).annotate({
|
||||
description: "Available choices",
|
||||
}),
|
||||
multiple: Schema.optional(Schema.Boolean).annotate({
|
||||
description: "Allow selecting multiple choices",
|
||||
}),
|
||||
}
|
||||
|
||||
export class QuestionInfo extends Schema.Class<QuestionInfo>("QuestionInfo")({
|
||||
...base,
|
||||
custom: Schema.optional(Schema.Boolean).annotate({
|
||||
description: "Allow typing a custom answer (default: true)",
|
||||
}),
|
||||
}) {}
|
||||
|
||||
export class QuestionTool extends Schema.Class<QuestionTool>("QuestionTool")({
|
||||
messageID: MessageID,
|
||||
callID: Schema.String,
|
||||
}) {}
|
||||
|
||||
export class QuestionRequest extends Schema.Class<QuestionRequest>("QuestionRequest")({
|
||||
id: QuestionID,
|
||||
sessionID: SessionID,
|
||||
questions: Schema.Array(QuestionInfo).annotate({
|
||||
description: "Questions to ask",
|
||||
}),
|
||||
tool: Schema.optional(QuestionTool),
|
||||
}) {}
|
||||
|
||||
export const QuestionAnswer = Schema.Array(Schema.String).annotate({ identifier: "QuestionAnswer" })
|
||||
|
||||
export class QuestionReply extends Schema.Class<QuestionReply>("QuestionReply")({
|
||||
answers: Schema.Array(QuestionAnswer).annotate({
|
||||
description: "User answers in order of questions (each answer is an array of selected labels)",
|
||||
}),
|
||||
}) {}
|
||||
|
||||
export const questionApi = HttpApi.make("question").add(
|
||||
HttpApiGroup.make("question")
|
||||
.add(
|
||||
HttpApiEndpoint.get("list", root, {
|
||||
success: Schema.Array(QuestionRequest),
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "question.list",
|
||||
summary: "List pending questions",
|
||||
description: "Get all pending question requests across all sessions.",
|
||||
}),
|
||||
),
|
||||
HttpApiEndpoint.post("reply", `${root}/:requestID/reply`, {
|
||||
params: { requestID: QuestionID },
|
||||
payload: QuestionReply,
|
||||
success: Schema.Boolean,
|
||||
}).annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "question.reply",
|
||||
summary: "Reply to question request",
|
||||
description: "Provide answers to a question request from the AI assistant.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
title: "question",
|
||||
description: "Experimental HttpApi question routes.",
|
||||
}),
|
||||
),
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
export { openapi } from "./openapi.js"
|
||||
export { makeQuestionHandler } from "./api/question.js"
|
||||
export { api } from "./definition/api.js"
|
||||
export { questionApi, QuestionReply, QuestionRequest } from "./definition/question.js"
|
||||
export type { OpenApiSpec, ServerApi } from "./types.js"
|
||||
export type { QuestionOps } from "./api/question.js"
|
||||
@@ -1,5 +0,0 @@
|
||||
import { OpenApi } from "effect/unstable/httpapi"
|
||||
import { api } from "./definition/api.js"
|
||||
import type { OpenApiSpec } from "./types.js"
|
||||
|
||||
export const openapi = (): OpenApiSpec => OpenApi.fromApi(api)
|
||||
@@ -1,5 +0,0 @@
|
||||
import type { HttpApi, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
|
||||
|
||||
export type ServerApi = HttpApi.HttpApi<string, HttpApiGroup.Any>
|
||||
|
||||
export type OpenApiSpec = OpenApi.OpenAPISpec
|
||||
10
packages/server/sst-env.d.ts
vendored
10
packages/server/sst-env.d.ts
vendored
@@ -1,10 +0,0 @@
|
||||
/* This file is auto-generated by SST. Do not edit. */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/* deno-fmt-ignore-file */
|
||||
/* biome-ignore-all lint: auto-generated */
|
||||
|
||||
/// <reference path="../../sst-env.d.ts" />
|
||||
|
||||
import "sst"
|
||||
export {}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"module": "nodenext",
|
||||
"declaration": true,
|
||||
"moduleResolution": "nodenext",
|
||||
"lib": ["es2022", "dom", "dom.iterable"],
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
Reference in New Issue
Block a user