fedaeea9da
Add a real effect-style scoped state data type built on ScopedCache and cover its caching, invalidation, concurrency, and scope-finalization semantics with focused tests. Move ProviderAuthService onto the new abstraction so the service no longer depends on Instance.state directly.
72 lines
2.0 KiB
TypeScript
72 lines
2.0 KiB
TypeScript
import { Effect, ManagedRuntime } from "effect"
|
|
import z from "zod"
|
|
|
|
import { fn } from "@/util/fn"
|
|
import * as S from "./auth-service"
|
|
import { ProviderID } from "./schema"
|
|
|
|
// Separate runtime: ProviderAuthService can't join the shared runtime because
|
|
// runtime.ts → auth-service.ts → provider/auth.ts creates a circular import.
|
|
// AuthService is stateless file I/O so the duplicate instance is harmless.
|
|
const rt = ManagedRuntime.make(S.ProviderAuthService.defaultLayer)
|
|
|
|
function runPromise<A>(f: (service: S.ProviderAuthService.Service) => Effect.Effect<A, S.ProviderAuthError>) {
|
|
return rt.runPromise(S.ProviderAuthService.use(f))
|
|
}
|
|
|
|
export namespace ProviderAuth {
|
|
export const Method = z
|
|
.object({
|
|
type: z.union([z.literal("oauth"), z.literal("api")]),
|
|
label: z.string(),
|
|
})
|
|
.meta({
|
|
ref: "ProviderAuthMethod",
|
|
})
|
|
export type Method = z.infer<typeof Method>
|
|
|
|
export async function methods() {
|
|
return runPromise((service) => service.methods())
|
|
}
|
|
|
|
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>
|
|
|
|
export const authorize = fn(
|
|
z.object({
|
|
providerID: ProviderID.zod,
|
|
method: z.number(),
|
|
}),
|
|
async (input): Promise<Authorization | undefined> => runPromise((service) => service.authorize(input)),
|
|
)
|
|
|
|
export const callback = fn(
|
|
z.object({
|
|
providerID: ProviderID.zod,
|
|
method: z.number(),
|
|
code: z.string().optional(),
|
|
}),
|
|
async (input) => runPromise((service) => service.callback(input)),
|
|
)
|
|
|
|
export const api = fn(
|
|
z.object({
|
|
providerID: ProviderID.zod,
|
|
key: z.string(),
|
|
}),
|
|
async (input) => runPromise((service) => service.api(input)),
|
|
)
|
|
|
|
export import OauthMissing = S.OauthMissing
|
|
export import OauthCodeMissing = S.OauthCodeMissing
|
|
export import OauthCallbackFailed = S.OauthCallbackFailed
|
|
}
|