feat: add well-known auth service

This commit is contained in:
Dax Raad
2026-05-17 16:27:50 -04:00
parent f98449c9b5
commit c25128a6f5
11 changed files with 658 additions and 357 deletions
@@ -12,6 +12,7 @@ import { Flag } from "@opencode-ai/core/flag/flag"
import { isRecord } from "@/util/record"
import { Global } from "@opencode-ai/core/global"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { Substitution } from "@opencode-ai/core/substitution"
import { CurrentWorkingDirectory } from "./cwd"
import { ConfigPlugin } from "@/config/plugin"
import { TuiKeybind } from "./keybind"
@@ -19,7 +20,6 @@ import { InstallationLocal, InstallationVersion } from "@opencode-ai/core/instal
import { makeRuntime } from "@opencode-ai/core/effect/runtime"
import { Filesystem } from "@/util/filesystem"
import * as Log from "@opencode-ai/core/util/log"
import { ConfigVariable } from "@/config/variable"
import { Npm } from "@opencode-ai/core/npm"
import type { DeepMutable } from "@opencode-ai/core/schema"
import type { TuiAttentionSoundName } from "@opencode-ai/plugin/tui"
@@ -98,6 +98,7 @@ function dropUnknownKeybinds(input: Record<string, unknown>, configFilepath: str
const loadState = Effect.fn("TuiConfig.loadState")(function* (ctx: { directory: string }) {
const afs = yield* AppFileSystem.Service
const substitution = yield* Substitution.Service
let appliedOrder = 0
const resolvePlugins = (config: Info, configFilepath: string): Effect.Effect<Info> =>
@@ -112,9 +113,7 @@ const loadState = Effect.fn("TuiConfig.loadState")(function* (ctx: { directory:
const load = (text: string, configFilepath: string): Effect.Effect<Info> =>
Effect.gen(function* () {
const expanded = yield* Effect.promise(() =>
ConfigVariable.substitute({ text, type: "path", path: configFilepath, missing: "empty" }),
)
const expanded = yield* substitution.substitute({ text, type: "path", path: configFilepath, missing: "empty" }).pipe(Effect.orDie)
const data = ConfigParse.jsonc(expanded, configFilepath)
if (!isRecord(data)) return {} as Info
// Flatten a nested "tui" key so users who wrote `{ "tui": { ... } }` inside tui.json
@@ -295,7 +294,11 @@ export const layer = Layer.effect(
}).pipe(Effect.withSpan("TuiConfig.layer")),
)
export const defaultLayer = layer.pipe(Layer.provide(Npm.defaultLayer), Layer.provide(AppFileSystem.defaultLayer))
export const defaultLayer = layer.pipe(
Layer.provide(Npm.defaultLayer),
Layer.provide(AppFileSystem.defaultLayer),
Layer.provide(Substitution.defaultLayer),
)
const { runPromise } = makeRuntime(Service, defaultLayer)
+16 -81
View File
@@ -7,7 +7,8 @@ import { Global } from "@opencode-ai/core/global"
import fsNode from "fs/promises"
import { NamedError } from "@opencode-ai/core/util/error"
import { Flag } from "@opencode-ai/core/flag/flag"
import { Auth } from "../auth"
import { AuthWellKnown } from "@opencode-ai/core/auth-well-known"
import { Substitution } from "@opencode-ai/core/substitution"
import { Env } from "../env"
import { applyEdits, modify } from "jsonc-parser"
import { InstallationLocal, InstallationVersion } from "@opencode-ai/core/installation/version"
@@ -38,7 +39,6 @@ import { ConfigProvider } from "./provider"
import { ConfigReference } from "./reference"
import { ConfigServer } from "./server"
import { ConfigSkills } from "./skills"
import { ConfigVariable } from "./variable"
import { Npm } from "@opencode-ai/core/npm"
const log = Log.create({ service: "config" })
@@ -69,36 +69,6 @@ function normalizeLoadedConfig(data: unknown, source: string) {
return copy
}
async function substituteWellKnownRemoteConfig(input: { value: unknown; dir: string; source: string }) {
if (!isRecord(input.value) || typeof input.value.url !== "string") return
const url = await ConfigVariable.substitute({
text: input.value.url,
type: "virtual",
dir: input.dir,
source: input.source,
})
const headers = isRecord(input.value.headers)
? Object.fromEntries(
await Promise.all(
Object.entries(input.value.headers)
.filter((entry): entry is [string, string] => typeof entry[1] === "string")
.map(async ([key, value]) => [
key,
await ConfigVariable.substitute({
text: value,
type: "virtual",
dir: input.dir,
source: input.source,
}),
]),
),
)
: undefined
return { url, headers }
}
async function resolveLoadedPlugins<T extends { plugin?: ConfigPlugin.Spec[] }>(config: T, filepath: string) {
if (!config.plugin) return config
for (let i = 0; i < config.plugin.length; i++) {
@@ -365,7 +335,8 @@ export const layer = Layer.effect(
Service,
Effect.gen(function* () {
const fs = yield* AppFileSystem.Service
const authSvc = yield* Auth.Service
const authWellKnown = yield* AuthWellKnown.Service
const substitution = yield* Substitution.Service
const accountSvc = yield* Account.Service
const env = yield* Env.Service
const npmSvc = yield* Npm.Service
@@ -377,11 +348,9 @@ export const layer = Layer.effect(
options: { path: string } | { dir: string; source: string },
) {
const source = "path" in options ? options.path : options.source
const expanded = yield* Effect.promise(() =>
ConfigVariable.substitute(
"path" in options ? { text, type: "path", path: options.path } : { text, type: "virtual", ...options },
),
)
const expanded = yield* substitution.substitute(
"path" in options ? { text, type: "path", path: options.path } : { text, type: "virtual", ...options },
).pipe(Effect.orDie)
const parsed = ConfigParse.jsonc(expanded, source)
const data = ConfigParse.schema(Info, normalizeLoadedConfig(parsed, source), source)
if (!("path" in options)) return data
@@ -471,8 +440,6 @@ export const layer = Layer.effect(
const loadInstanceState = Effect.fn("Config.loadInstanceState")(
function* (ctx: InstanceContext) {
const auth = yield* authSvc.all().pipe(Effect.orDie)
let result: Info = {}
const consoleManagedProviders = new Set<string>()
let activeOrgName: string | undefined
@@ -510,46 +477,13 @@ export const layer = Layer.effect(
return mergePluginOrigins(source, next.plugin, kind)
}
for (const [key, value] of Object.entries(auth)) {
if (value.type === "wellknown") {
const url = key.replace(/\/+$/, "")
process.env[value.key] = value.token
log.debug("fetching remote config", { url: `${url}/.well-known/opencode` })
const response = yield* Effect.promise(() => fetch(`${url}/.well-known/opencode`))
if (!response.ok) {
throw new Error(`failed to fetch remote config from ${url}: ${response.status}`)
}
const wellknown = (yield* Effect.promise(() => response.json())) as {
config?: Record<string, unknown>
remote_config?: unknown
}
const remote = yield* Effect.promise(() =>
substituteWellKnownRemoteConfig({
value: wellknown.remote_config,
dir: url,
source: `${url}/.well-known/opencode`,
}),
)
const fetchedConfig = remote
? ((yield* Effect.promise(async () => {
log.debug("fetching remote config", { url: remote.url })
const response = await fetch(remote.url, { headers: remote.headers })
if (!response.ok)
throw new Error(`failed to fetch remote config from ${remote.url}: ${response.status}`)
const data = await response.json()
return isRecord(data) && isRecord(data.config) ? data.config : data
})) as Record<string, unknown>)
: {}
const remoteConfig = mergeConfig(wellknown.config ?? {}, fetchedConfig as Info)
if (!remoteConfig.$schema) remoteConfig.$schema = "https://opencode.ai/config.json"
const source = `${url}/.well-known/opencode`
const next = yield* loadConfig(JSON.stringify(remoteConfig), {
dir: path.dirname(source),
source,
})
yield* merge(source, next, "global")
log.debug("loaded remote config from well-known", { url })
}
for (const item of yield* authWellKnown.configs().pipe(Effect.orDie)) {
yield* merge(
item.source,
yield* loadConfig(JSON.stringify(item.content), { dir: item.dir, source: item.source }),
"global",
)
log.debug("loaded well-known config", { url: item.url })
}
const global = yield* getGlobal()
@@ -825,7 +759,8 @@ export const defaultLayer = layer.pipe(
Layer.provide(EffectFlock.defaultLayer),
Layer.provide(AppFileSystem.defaultLayer),
Layer.provide(Env.defaultLayer),
Layer.provide(Auth.defaultLayer),
Layer.provide(AuthWellKnown.defaultLayer),
Layer.provide(Substitution.defaultLayer),
Layer.provide(Account.defaultLayer),
Layer.provide(Npm.defaultLayer),
)
-90
View File
@@ -1,90 +0,0 @@
export * as ConfigVariable from "./variable"
import path from "path"
import os from "os"
import { Filesystem } from "@/util/filesystem"
import { InvalidError } from "./error"
type ParseSource =
| {
type: "path"
path: string
}
| {
type: "virtual"
source: string
dir: string
}
type SubstituteInput = ParseSource & {
text: string
missing?: "error" | "empty"
}
function source(input: ParseSource) {
return input.type === "path" ? input.path : input.source
}
function dir(input: ParseSource) {
return input.type === "path" ? path.dirname(input.path) : input.dir
}
/** Apply {env:VAR} and {file:path} substitutions to config text. */
export async function substitute(input: SubstituteInput) {
const missing = input.missing ?? "error"
let text = input.text.replace(/\{env:([^}]+)\}/g, (_, varName) => {
return process.env[varName] || ""
})
const fileMatches = Array.from(text.matchAll(/\{file:[^}]+\}/g))
if (!fileMatches.length) return text
const configDir = dir(input)
const configSource = source(input)
let out = ""
let cursor = 0
for (const match of fileMatches) {
const token = match[0]
const index = match.index!
out += text.slice(cursor, index)
const lineStart = text.lastIndexOf("\n", index - 1) + 1
const prefix = text.slice(lineStart, index).trimStart()
if (prefix.startsWith("//")) {
out += token
cursor = index + token.length
continue
}
let filePath = token.replace(/^\{file:/, "").replace(/\}$/, "")
if (filePath.startsWith("~/")) {
filePath = path.join(os.homedir(), filePath.slice(2))
}
const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(configDir, filePath)
const fileContent = (
await Filesystem.readText(resolvedPath).catch((error: NodeJS.ErrnoException) => {
if (missing === "empty") return ""
const errMsg = `bad file reference: "${token}"`
if (error.code === "ENOENT") {
throw new InvalidError(
{
path: configSource,
message: errMsg + ` ${resolvedPath} does not exist`,
},
{ cause: error },
)
}
throw new InvalidError({ path: configSource, message: errMsg }, { cause: error })
})
).trim()
out += JSON.stringify(fileContent).slice(1, -1)
cursor = index + token.length
}
out += text.slice(cursor)
return out
}
@@ -1,5 +1,7 @@
import { expect } from "bun:test"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { AuthWellKnown } from "@opencode-ai/core/auth-well-known"
import { Substitution } from "@opencode-ai/core/substitution"
import { Effect, Layer } from "effect"
import path from "path"
import { pathToFileURL } from "url"
@@ -23,8 +25,13 @@ import { PLUGIN_AGENT } from "../fixture/agent-plugin.constants"
const pluginUrl = pathToFileURL(path.join(import.meta.dir, "..", "fixture", "agent-plugin.ts")).href
const provider = ProviderTest.fake()
const emptyAuthWellKnown = Layer.mock(AuthWellKnown.Service)({
configs: () => Effect.succeed([]),
})
const configLayer = Config.layer.pipe(
Layer.provide(AppFileSystem.defaultLayer),
Layer.provide(emptyAuthWellKnown),
Layer.provide(Substitution.defaultLayer),
Layer.provide(Env.defaultLayer),
Layer.provide(AuthTest.empty),
Layer.provide(AccountTest.empty),
+64 -181
View File
@@ -8,7 +8,7 @@ import { EffectFlock } from "@opencode-ai/core/util/effect-flock"
import { InstanceRef } from "../../src/effect/instance-ref"
import type { InstanceContext } from "../../src/project/instance-context"
import { Auth } from "../../src/auth"
import { AuthWellKnown } from "@opencode-ai/core/auth-well-known"
import { Account } from "../../src/account/account"
import { AccessToken, AccountID, OrgID } from "../../src/account/schema"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
@@ -31,14 +31,15 @@ import { ProjectID } from "../../src/project/schema"
import { Filesystem } from "@/util/filesystem"
import { ConfigPlugin } from "@/config/plugin"
import { Npm } from "@opencode-ai/core/npm"
import { Substitution } from "@opencode-ai/core/substitution"
const emptyAccount = Layer.mock(Account.Service)({
active: () => Effect.succeed(Option.none()),
activeOrg: () => Effect.succeed(Option.none()),
})
const emptyAuth = Layer.mock(Auth.Service)({
all: () => Effect.succeed({}),
const emptyAuthWellKnown = Layer.mock(AuthWellKnown.Service)({
configs: () => Effect.succeed([]),
})
const testFlock = EffectFlock.defaultLayer
@@ -49,11 +50,15 @@ const noopNpm = Layer.mock(Npm.Service)({
which: () => Effect.succeed(Option.none()),
})
const runSubstitution = <A, E>(effect: Effect.Effect<A, E, Substitution.Service>) =>
Effect.runPromise(effect.pipe(Effect.provide(Substitution.defaultLayer)))
const layer = Config.layer.pipe(
Layer.provide(testFlock),
Layer.provide(AppFileSystem.defaultLayer),
Layer.provide(Substitution.defaultLayer),
Layer.provide(Env.defaultLayer),
Layer.provide(emptyAuth),
Layer.provide(emptyAuthWellKnown),
Layer.provide(emptyAccount),
Layer.provideMerge(infra),
Layer.provide(noopNpm),
@@ -486,6 +491,30 @@ test("handles environment variable substitution", async () => {
}
})
test("environment variable substitution accepts an env overlay", async () => {
const originalEnv = process.env["TEST_VAR"]
delete process.env["TEST_VAR"]
try {
expect(
await runSubstitution(
Substitution.Service.use((substitution) =>
substitution.substitute({
text: "{env:TEST_VAR}",
type: "virtual",
dir: "/tmp",
source: "test",
env: { TEST_VAR: "overlay" },
}),
),
),
).toBe("overlay")
} finally {
if (originalEnv === undefined) delete process.env["TEST_VAR"]
else process.env["TEST_VAR"] = originalEnv
}
})
test("preserves env variables when adding $schema to config", async () => {
const originalEnv = process.env["PRESERVE_VAR"]
process.env["PRESERVE_VAR"] = "secret_value"
@@ -564,8 +593,9 @@ test("resolves env templates in account config with account token", async () =>
const layer = Config.layer.pipe(
Layer.provide(testFlock),
Layer.provide(AppFileSystem.defaultLayer),
Layer.provide(Substitution.defaultLayer),
Layer.provide(Env.defaultLayer),
Layer.provide(emptyAuth),
Layer.provide(emptyAuthWellKnown),
Layer.provide(fakeAccount),
Layer.provideMerge(infra),
Layer.provide(noopNpm),
@@ -1075,8 +1105,9 @@ test("installs dependencies in writable OPENCODE_CONFIG_DIR", async () => {
const testLayer = Config.layer.pipe(
Layer.provide(testFlock),
Layer.provide(AppFileSystem.defaultLayer),
Layer.provide(Substitution.defaultLayer),
Layer.provide(Env.defaultLayer),
Layer.provide(emptyAuth),
Layer.provide(emptyAuthWellKnown),
Layer.provide(emptyAccount),
Layer.provideMerge(infra),
Layer.provide(noopNpm),
@@ -1938,192 +1969,44 @@ test("local .opencode config can override MCP from project config", async () =>
})
test("project config overrides remote well-known config", async () => {
const originalFetch = globalThis.fetch
let fetchedUrl: string | undefined
globalThis.fetch = mock((url: string | URL | Request) => {
const urlStr = url instanceof Request ? url.url : url instanceof URL ? url.href : url
if (urlStr.includes(".well-known/opencode")) {
fetchedUrl = urlStr
return Promise.resolve(
new Response(
JSON.stringify({
config: {
mcp: { jira: { type: "remote", url: "https://jira.example.com/mcp", enabled: false } },
},
}),
{ status: 200 },
),
)
}
return originalFetch(url)
}) as unknown as typeof fetch
const fakeAuth = Layer.mock(Auth.Service)({
all: () =>
Effect.succeed({
"https://example.com": new Auth.WellKnown({ type: "wellknown", key: "TEST_TOKEN", token: "test-token" }),
}),
const fakeAuthWellKnown = Layer.mock(AuthWellKnown.Service)({
configs: () =>
Effect.succeed([
{
url: "https://example.com",
source: "https://example.com/.well-known/opencode",
dir: "https://example.com/.well-known",
content: {
mcp: { jira: { type: "remote", url: "https://jira.example.com/mcp", enabled: false } },
},
},
]),
})
const layer = Config.layer.pipe(
Layer.provide(testFlock),
Layer.provide(AppFileSystem.defaultLayer),
Layer.provide(Substitution.defaultLayer),
Layer.provide(Env.defaultLayer),
Layer.provide(fakeAuth),
Layer.provide(fakeAuthWellKnown),
Layer.provide(emptyAccount),
Layer.provideMerge(infra),
Layer.provide(noopNpm),
)
try {
await provideTmpdirInstance(
() =>
Config.Service.use((svc) =>
Effect.gen(function* () {
const config = yield* svc.get()
expect(fetchedUrl).toBe("https://example.com/.well-known/opencode")
expect(config.mcp?.jira?.enabled).toBe(true)
}),
),
{
git: true,
config: { mcp: { jira: { type: "remote", url: "https://jira.example.com/mcp", enabled: true } } },
},
).pipe(Effect.scoped, Effect.provide(layer), Effect.runPromise)
} finally {
globalThis.fetch = originalFetch
}
})
test("wellknown URL with trailing slash is normalized", async () => {
const originalFetch = globalThis.fetch
let fetchedUrl: string | undefined
globalThis.fetch = mock((url: string | URL | Request) => {
const urlStr = url instanceof Request ? url.url : url instanceof URL ? url.href : url
if (urlStr.includes(".well-known/opencode")) {
fetchedUrl = urlStr
return Promise.resolve(
new Response(
JSON.stringify({
config: {
mcp: { slack: { type: "remote", url: "https://slack.example.com/mcp", enabled: true } },
},
}),
{ status: 200 },
),
)
}
return originalFetch(url)
}) as unknown as typeof fetch
const fakeAuth = Layer.mock(Auth.Service)({
all: () =>
Effect.succeed({
"https://example.com/": new Auth.WellKnown({ type: "wellknown", key: "TEST_TOKEN", token: "test-token" }),
}),
})
const layer = Config.layer.pipe(
Layer.provide(testFlock),
Layer.provide(AppFileSystem.defaultLayer),
Layer.provide(Env.defaultLayer),
Layer.provide(fakeAuth),
Layer.provide(emptyAccount),
Layer.provideMerge(infra),
Layer.provide(noopNpm),
)
try {
await provideTmpdirInstance(
() =>
Config.Service.use((svc) =>
Effect.gen(function* () {
yield* svc.get()
expect(fetchedUrl).toBe("https://example.com/.well-known/opencode")
}),
),
{ git: true },
).pipe(Effect.scoped, Effect.provide(layer), Effect.runPromise)
} finally {
globalThis.fetch = originalFetch
}
})
test("wellknown remote_config supports templated env vars in headers", async () => {
const originalFetch = globalThis.fetch
const originalToken = process.env.TEST_TOKEN
let wellknownFetchedUrl: string | undefined
let remoteFetchedUrl: string | undefined
let remoteHeaders: HeadersInit | undefined
globalThis.fetch = mock((url: string | URL | Request, init?: RequestInit) => {
const urlStr = url instanceof Request ? url.url : url instanceof URL ? url.href : url
if (urlStr.includes(".well-known/opencode")) {
wellknownFetchedUrl = urlStr
return Promise.resolve(
new Response(
JSON.stringify({
remote_config: {
url: "https://config.example.com/opencode.json",
headers: {
Authorization: "Bearer {env:TEST_TOKEN}",
},
},
}),
{ status: 200 },
),
)
}
if (urlStr.includes("config.example.com")) {
remoteFetchedUrl = urlStr
remoteHeaders = init?.headers
return Promise.resolve(
new Response(
JSON.stringify({
mcp: { confluence: { type: "remote", url: "https://confluence.example.com/mcp", enabled: true } },
}),
{ status: 200 },
),
)
}
return originalFetch(url, init)
}) as unknown as typeof fetch
const fakeAuth = Layer.mock(Auth.Service)({
all: () =>
Effect.succeed({
"https://example.com": new Auth.WellKnown({ type: "wellknown", key: "TEST_TOKEN", token: "test-token" }),
}),
})
const layer = Config.layer.pipe(
Layer.provide(testFlock),
Layer.provide(AppFileSystem.defaultLayer),
Layer.provide(Env.defaultLayer),
Layer.provide(fakeAuth),
Layer.provide(emptyAccount),
Layer.provideMerge(infra),
Layer.provide(noopNpm),
)
try {
await provideTmpdirInstance(
() =>
Config.Service.use((svc) =>
Effect.gen(function* () {
const config = yield* svc.get()
expect(wellknownFetchedUrl).toBe("https://example.com/.well-known/opencode")
expect(remoteFetchedUrl).toBe("https://config.example.com/opencode.json")
expect(remoteHeaders).toEqual({ Authorization: "Bearer test-token" })
expect(config.mcp?.confluence?.enabled).toBe(true)
}),
),
{ git: true },
).pipe(Effect.scoped, Effect.provide(layer), Effect.runPromise)
} finally {
globalThis.fetch = originalFetch
if (originalToken === undefined) delete process.env.TEST_TOKEN
else process.env.TEST_TOKEN = originalToken
}
await provideTmpdirInstance(
() =>
Config.Service.use((svc) =>
Effect.gen(function* () {
const config = yield* svc.get()
expect(config.mcp?.jira?.enabled).toBe(true)
}),
),
{
git: true,
config: { mcp: { jira: { type: "remote", url: "https://jira.example.com/mcp", enabled: true } } },
},
).pipe(Effect.scoped, Effect.provide(layer), Effect.runPromise)
})
describe("resolvePluginSpec", () => {
@@ -3,6 +3,8 @@ import { Effect, Layer, Option } from "effect"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { EffectFlock } from "@opencode-ai/core/util/effect-flock"
import { AuthWellKnown } from "@opencode-ai/core/auth-well-known"
import { Substitution } from "@opencode-ai/core/substitution"
import path from "path"
import { pathToFileURL } from "url"
import { Account } from "../../src/account/account"
@@ -24,9 +26,14 @@ const emptyAccount = Layer.mock(Account.Service)({
const emptyAuth = Layer.mock(Auth.Service)({
all: () => Effect.succeed({}),
})
const emptyAuthWellKnown = Layer.mock(AuthWellKnown.Service)({
configs: () => Effect.succeed([]),
})
const configLayer = Config.layer.pipe(
Layer.provide(EffectFlock.defaultLayer),
Layer.provide(AppFileSystem.defaultLayer),
Layer.provide(emptyAuthWellKnown),
Layer.provide(Substitution.defaultLayer),
Layer.provide(Env.defaultLayer),
Layer.provide(emptyAuth),
Layer.provide(emptyAccount),
@@ -4,6 +4,8 @@ import { FetchHttpClient } from "effect/unstable/http"
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { EffectFlock } from "@opencode-ai/core/util/effect-flock"
import { AuthWellKnown } from "@opencode-ai/core/auth-well-known"
import { Substitution } from "@opencode-ai/core/substitution"
import path from "path"
import { pathToFileURL } from "url"
import { Account } from "../../src/account/account"
@@ -33,9 +35,14 @@ const emptyAccount = Layer.mock(Account.Service)({
const emptyAuth = Layer.mock(Auth.Service)({
all: () => Effect.succeed({}),
})
const emptyAuthWellKnown = Layer.mock(AuthWellKnown.Service)({
configs: () => Effect.succeed([]),
})
const configLayer = Config.layer.pipe(
Layer.provide(EffectFlock.defaultLayer),
Layer.provide(AppFileSystem.defaultLayer),
Layer.provide(emptyAuthWellKnown),
Layer.provide(Substitution.defaultLayer),
Layer.provide(Env.defaultLayer),
Layer.provide(emptyAuth),
Layer.provide(emptyAccount),