refactor: unwrap ExperimentalHttpApiServer namespace + self-reexport (#22979)
This commit is contained in:
@@ -25,106 +25,106 @@ const Headers = Schema.Struct({
|
|||||||
"x-opencode-directory": Schema.optional(Schema.String),
|
"x-opencode-directory": Schema.optional(Schema.String),
|
||||||
})
|
})
|
||||||
|
|
||||||
export namespace ExperimentalHttpApiServer {
|
function decode(input: string) {
|
||||||
function decode(input: string) {
|
try {
|
||||||
try {
|
return decodeURIComponent(input)
|
||||||
return decodeURIComponent(input)
|
} catch {
|
||||||
} catch {
|
return input
|
||||||
return input
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Unauthorized extends Schema.TaggedErrorClass<Unauthorized>()(
|
|
||||||
"Unauthorized",
|
|
||||||
{ message: Schema.String },
|
|
||||||
{ httpApiStatus: 401 },
|
|
||||||
) {}
|
|
||||||
|
|
||||||
class Authorization extends HttpApiMiddleware.Service<Authorization>()("@opencode/ExperimentalHttpApiAuthorization", {
|
|
||||||
error: Unauthorized,
|
|
||||||
security: {
|
|
||||||
basic: HttpApiSecurity.basic,
|
|
||||||
},
|
|
||||||
}) {}
|
|
||||||
|
|
||||||
const normalize = HttpRouter.middleware()(
|
|
||||||
Effect.gen(function* () {
|
|
||||||
return (effect) =>
|
|
||||||
Effect.gen(function* () {
|
|
||||||
const query = yield* HttpServerRequest.schemaSearchParams(Query)
|
|
||||||
if (!query.auth_token) return yield* effect
|
|
||||||
const req = yield* HttpServerRequest.HttpServerRequest
|
|
||||||
const next = req.modify({
|
|
||||||
headers: {
|
|
||||||
...req.headers,
|
|
||||||
authorization: `Basic ${query.auth_token}`,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return yield* effect.pipe(Effect.provideService(HttpServerRequest.HttpServerRequest, next))
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
).layer
|
|
||||||
|
|
||||||
const auth = Layer.succeed(
|
|
||||||
Authorization,
|
|
||||||
Authorization.of({
|
|
||||||
basic: (effect, { credential }) =>
|
|
||||||
Effect.gen(function* () {
|
|
||||||
if (!Flag.OPENCODE_SERVER_PASSWORD) return yield* effect
|
|
||||||
|
|
||||||
const user = Flag.OPENCODE_SERVER_USERNAME ?? "opencode"
|
|
||||||
if (credential.username !== user) {
|
|
||||||
return yield* new Unauthorized({ message: "Unauthorized" })
|
|
||||||
}
|
|
||||||
if (Redacted.value(credential.password) !== Flag.OPENCODE_SERVER_PASSWORD) {
|
|
||||||
return yield* new Unauthorized({ message: "Unauthorized" })
|
|
||||||
}
|
|
||||||
return yield* effect
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
const instance = HttpRouter.middleware()(
|
|
||||||
Effect.gen(function* () {
|
|
||||||
return (effect) =>
|
|
||||||
Effect.gen(function* () {
|
|
||||||
const query = yield* HttpServerRequest.schemaSearchParams(Query)
|
|
||||||
const headers = yield* HttpServerRequest.schemaHeaders(Headers)
|
|
||||||
const raw = query.directory || headers["x-opencode-directory"] || process.cwd()
|
|
||||||
const workspace = query.workspace || undefined
|
|
||||||
const ctx = yield* Effect.promise(() =>
|
|
||||||
Instance.provide({
|
|
||||||
directory: Filesystem.resolve(decode(raw)),
|
|
||||||
init: () => AppRuntime.runPromise(InstanceBootstrap),
|
|
||||||
fn: () => Instance.current,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
const next = workspace ? effect.pipe(Effect.provideService(WorkspaceRef, workspace)) : effect
|
|
||||||
return yield* next.pipe(Effect.provideService(InstanceRef, ctx))
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
).layer
|
|
||||||
|
|
||||||
const QuestionSecured = QuestionApi.middleware(Authorization)
|
|
||||||
const PermissionSecured = PermissionApi.middleware(Authorization)
|
|
||||||
const ProviderSecured = ProviderApi.middleware(Authorization)
|
|
||||||
|
|
||||||
export const routes = Layer.mergeAll(
|
|
||||||
HttpApiBuilder.layer(QuestionSecured).pipe(Layer.provide(questionHandlers)),
|
|
||||||
HttpApiBuilder.layer(PermissionSecured).pipe(Layer.provide(permissionHandlers)),
|
|
||||||
HttpApiBuilder.layer(ProviderSecured).pipe(Layer.provide(providerHandlers)),
|
|
||||||
).pipe(
|
|
||||||
Layer.provide(auth),
|
|
||||||
Layer.provide(normalize),
|
|
||||||
Layer.provide(instance),
|
|
||||||
Layer.provide(HttpServer.layerServices),
|
|
||||||
Layer.provideMerge(Observability.layer),
|
|
||||||
)
|
|
||||||
|
|
||||||
export const webHandler = lazy(() =>
|
|
||||||
HttpRouter.toWebHandler(routes, {
|
|
||||||
memoMap,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Unauthorized extends Schema.TaggedErrorClass<Unauthorized>()(
|
||||||
|
"Unauthorized",
|
||||||
|
{ message: Schema.String },
|
||||||
|
{ httpApiStatus: 401 },
|
||||||
|
) {}
|
||||||
|
|
||||||
|
class Authorization extends HttpApiMiddleware.Service<Authorization>()("@opencode/ExperimentalHttpApiAuthorization", {
|
||||||
|
error: Unauthorized,
|
||||||
|
security: {
|
||||||
|
basic: HttpApiSecurity.basic,
|
||||||
|
},
|
||||||
|
}) {}
|
||||||
|
|
||||||
|
const normalize = HttpRouter.middleware()(
|
||||||
|
Effect.gen(function* () {
|
||||||
|
return (effect) =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const query = yield* HttpServerRequest.schemaSearchParams(Query)
|
||||||
|
if (!query.auth_token) return yield* effect
|
||||||
|
const req = yield* HttpServerRequest.HttpServerRequest
|
||||||
|
const next = req.modify({
|
||||||
|
headers: {
|
||||||
|
...req.headers,
|
||||||
|
authorization: `Basic ${query.auth_token}`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return yield* effect.pipe(Effect.provideService(HttpServerRequest.HttpServerRequest, next))
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
).layer
|
||||||
|
|
||||||
|
const auth = Layer.succeed(
|
||||||
|
Authorization,
|
||||||
|
Authorization.of({
|
||||||
|
basic: (effect, { credential }) =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
if (!Flag.OPENCODE_SERVER_PASSWORD) return yield* effect
|
||||||
|
|
||||||
|
const user = Flag.OPENCODE_SERVER_USERNAME ?? "opencode"
|
||||||
|
if (credential.username !== user) {
|
||||||
|
return yield* new Unauthorized({ message: "Unauthorized" })
|
||||||
|
}
|
||||||
|
if (Redacted.value(credential.password) !== Flag.OPENCODE_SERVER_PASSWORD) {
|
||||||
|
return yield* new Unauthorized({ message: "Unauthorized" })
|
||||||
|
}
|
||||||
|
return yield* effect
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
const instance = HttpRouter.middleware()(
|
||||||
|
Effect.gen(function* () {
|
||||||
|
return (effect) =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const query = yield* HttpServerRequest.schemaSearchParams(Query)
|
||||||
|
const headers = yield* HttpServerRequest.schemaHeaders(Headers)
|
||||||
|
const raw = query.directory || headers["x-opencode-directory"] || process.cwd()
|
||||||
|
const workspace = query.workspace || undefined
|
||||||
|
const ctx = yield* Effect.promise(() =>
|
||||||
|
Instance.provide({
|
||||||
|
directory: Filesystem.resolve(decode(raw)),
|
||||||
|
init: () => AppRuntime.runPromise(InstanceBootstrap),
|
||||||
|
fn: () => Instance.current,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
const next = workspace ? effect.pipe(Effect.provideService(WorkspaceRef, workspace)) : effect
|
||||||
|
return yield* next.pipe(Effect.provideService(InstanceRef, ctx))
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
).layer
|
||||||
|
|
||||||
|
const QuestionSecured = QuestionApi.middleware(Authorization)
|
||||||
|
const PermissionSecured = PermissionApi.middleware(Authorization)
|
||||||
|
const ProviderSecured = ProviderApi.middleware(Authorization)
|
||||||
|
|
||||||
|
export const routes = Layer.mergeAll(
|
||||||
|
HttpApiBuilder.layer(QuestionSecured).pipe(Layer.provide(questionHandlers)),
|
||||||
|
HttpApiBuilder.layer(PermissionSecured).pipe(Layer.provide(permissionHandlers)),
|
||||||
|
HttpApiBuilder.layer(ProviderSecured).pipe(Layer.provide(providerHandlers)),
|
||||||
|
).pipe(
|
||||||
|
Layer.provide(auth),
|
||||||
|
Layer.provide(normalize),
|
||||||
|
Layer.provide(instance),
|
||||||
|
Layer.provide(HttpServer.layerServices),
|
||||||
|
Layer.provideMerge(Observability.layer),
|
||||||
|
)
|
||||||
|
|
||||||
|
export const webHandler = lazy(() =>
|
||||||
|
HttpRouter.toWebHandler(routes, {
|
||||||
|
memoMap,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
export * as ExperimentalHttpApiServer from "./server"
|
||||||
|
|||||||
Reference in New Issue
Block a user