refactor(provider): effectify ProviderAuthService (#17227)

This commit is contained in:
Kit Langton
2026-03-12 22:08:37 -04:00
committed by GitHub
parent 84df96eaef
commit dd68b85f58
7 changed files with 520 additions and 117 deletions

View File

@@ -0,0 +1,115 @@
import { afterEach, expect, test } from "bun:test"
import { Instance } from "../../src/project/instance"
import { tmpdir } from "../fixture/fixture"
afterEach(async () => {
await Instance.disposeAll()
})
test("Instance.state caches values for the same instance", async () => {
await using tmp = await tmpdir()
let n = 0
const state = Instance.state(() => ({ n: ++n }))
await Instance.provide({
directory: tmp.path,
fn: async () => {
const a = state()
const b = state()
expect(a).toBe(b)
expect(n).toBe(1)
},
})
})
test("Instance.state isolates values by directory", async () => {
await using a = await tmpdir()
await using b = await tmpdir()
let n = 0
const state = Instance.state(() => ({ n: ++n }))
const x = await Instance.provide({
directory: a.path,
fn: async () => state(),
})
const y = await Instance.provide({
directory: b.path,
fn: async () => state(),
})
const z = await Instance.provide({
directory: a.path,
fn: async () => state(),
})
expect(x).toBe(z)
expect(x).not.toBe(y)
expect(n).toBe(2)
})
test("Instance.state is disposed on instance reload", async () => {
await using tmp = await tmpdir()
const seen: string[] = []
let n = 0
const state = Instance.state(
() => ({ n: ++n }),
async (value) => {
seen.push(String(value.n))
},
)
const a = await Instance.provide({
directory: tmp.path,
fn: async () => state(),
})
await Instance.reload({ directory: tmp.path })
const b = await Instance.provide({
directory: tmp.path,
fn: async () => state(),
})
expect(a).not.toBe(b)
expect(seen).toEqual(["1"])
})
test("Instance.state is disposed on disposeAll", async () => {
await using a = await tmpdir()
await using b = await tmpdir()
const seen: string[] = []
const state = Instance.state(
() => ({ dir: Instance.directory }),
async (value) => {
seen.push(value.dir)
},
)
await Instance.provide({
directory: a.path,
fn: async () => state(),
})
await Instance.provide({
directory: b.path,
fn: async () => state(),
})
await Instance.disposeAll()
expect(seen.sort()).toEqual([a.path, b.path].sort())
})
test("Instance.state dedupes concurrent promise initialization", async () => {
await using tmp = await tmpdir()
let n = 0
const state = Instance.state(async () => {
n += 1
await Bun.sleep(10)
return { n }
})
const [a, b] = await Instance.provide({
directory: tmp.path,
fn: async () => Promise.all([state(), state()]),
})
expect(a).toBe(b)
expect(n).toBe(1)
})

View File

@@ -0,0 +1,20 @@
import { afterEach, expect, test } from "bun:test"
import { Auth } from "../../src/auth"
import { ProviderAuth } from "../../src/provider/auth"
import { ProviderID } from "../../src/provider/schema"
afterEach(async () => {
await Auth.remove("test-provider-auth")
})
test("ProviderAuth.api persists auth via AuthService", async () => {
await ProviderAuth.api({
providerID: ProviderID.make("test-provider-auth"),
key: "sk-test",
})
expect(await Auth.get("test-provider-auth")).toEqual({
type: "api",
key: "sk-test",
})
})

View File

@@ -0,0 +1,139 @@
import { afterEach, expect, test } from "bun:test"
import { Effect } from "effect"
import { Instance } from "../../src/project/instance"
import { InstanceState } from "../../src/util/instance-state"
import { tmpdir } from "../fixture/fixture"
async function access<A, E>(state: InstanceState.State<A, E>, dir: string) {
return Instance.provide({
directory: dir,
fn: () => Effect.runPromise(InstanceState.get(state)),
})
}
afterEach(async () => {
await Instance.disposeAll()
})
test("InstanceState caches values for the same instance", async () => {
await using tmp = await tmpdir()
let n = 0
await Effect.runPromise(
Effect.scoped(
Effect.gen(function* () {
const state = yield* InstanceState.make({
lookup: () => Effect.sync(() => ({ n: ++n })),
})
const a = yield* Effect.promise(() => access(state, tmp.path))
const b = yield* Effect.promise(() => access(state, tmp.path))
expect(a).toBe(b)
expect(n).toBe(1)
}),
),
)
})
test("InstanceState isolates values by directory", async () => {
await using a = await tmpdir()
await using b = await tmpdir()
let n = 0
await Effect.runPromise(
Effect.scoped(
Effect.gen(function* () {
const state = yield* InstanceState.make({
lookup: (dir) => Effect.sync(() => ({ dir, n: ++n })),
})
const x = yield* Effect.promise(() => access(state, a.path))
const y = yield* Effect.promise(() => access(state, b.path))
const z = yield* Effect.promise(() => access(state, a.path))
expect(x).toBe(z)
expect(x).not.toBe(y)
expect(n).toBe(2)
}),
),
)
})
test("InstanceState is disposed on instance reload", async () => {
await using tmp = await tmpdir()
const seen: string[] = []
let n = 0
await Effect.runPromise(
Effect.scoped(
Effect.gen(function* () {
const state = yield* InstanceState.make({
lookup: () => Effect.sync(() => ({ n: ++n })),
release: (value) =>
Effect.sync(() => {
seen.push(String(value.n))
}),
})
const a = yield* Effect.promise(() => access(state, tmp.path))
yield* Effect.promise(() => Instance.reload({ directory: tmp.path }))
const b = yield* Effect.promise(() => access(state, tmp.path))
expect(a).not.toBe(b)
expect(seen).toEqual(["1"])
}),
),
)
})
test("InstanceState is disposed on disposeAll", async () => {
await using a = await tmpdir()
await using b = await tmpdir()
const seen: string[] = []
await Effect.runPromise(
Effect.scoped(
Effect.gen(function* () {
const state = yield* InstanceState.make({
lookup: (dir) => Effect.sync(() => ({ dir })),
release: (value) =>
Effect.sync(() => {
seen.push(value.dir)
}),
})
yield* Effect.promise(() => access(state, a.path))
yield* Effect.promise(() => access(state, b.path))
yield* Effect.promise(() => Instance.disposeAll())
expect(seen.sort()).toEqual([a.path, b.path].sort())
}),
),
)
})
test("InstanceState dedupes concurrent lookups for the same directory", async () => {
await using tmp = await tmpdir()
let n = 0
await Effect.runPromise(
Effect.scoped(
Effect.gen(function* () {
const state = yield* InstanceState.make({
lookup: () =>
Effect.promise(async () => {
n += 1
await Bun.sleep(10)
return { n }
}),
})
const [a, b] = yield* Effect.promise(() => Promise.all([access(state, tmp.path), access(state, tmp.path)]))
expect(a).toBe(b)
expect(n).toBe(1)
}),
),
)
})