refactor(auth): clarify auth entry filtering
Use Effect Record.filterMap to keep the existing permissive auth-file semantics while making the decode path easier to read. Add service method docs that explain key normalization and why old trailing-slash variants are removed during writes.pull/17212/head
parent
7f12976ea0
commit
201e80956a
|
|
@ -1,5 +1,5 @@
|
|||
import path from "path"
|
||||
import { Effect, Layer, Option, Schema, ServiceMap } from "effect"
|
||||
import { Effect, Layer, Record, Result, Schema, ServiceMap } from "effect"
|
||||
import { Global } from "../global"
|
||||
import { Filesystem } from "../util/filesystem"
|
||||
|
||||
|
|
@ -39,9 +39,36 @@ const fail = (message: string) => (cause: unknown) => new AuthServiceError({ mes
|
|||
|
||||
export namespace AuthService {
|
||||
export interface Service {
|
||||
/**
|
||||
* Loads the auth entry stored under the given key.
|
||||
*
|
||||
* Keys are usually provider IDs, but some callers store URL-shaped keys.
|
||||
*/
|
||||
readonly get: (providerID: string) => Effect.Effect<Info | undefined, AuthServiceError>
|
||||
|
||||
/**
|
||||
* Loads all persisted auth entries.
|
||||
*
|
||||
* Invalid entries are ignored instead of failing the whole file so older or
|
||||
* partially-corrupt auth records do not break unrelated providers.
|
||||
*/
|
||||
readonly all: () => Effect.Effect<Record<string, Info>, AuthServiceError>
|
||||
|
||||
/**
|
||||
* Stores an auth entry under a normalized key.
|
||||
*
|
||||
* URL-shaped keys are normalized by trimming trailing slashes. Before
|
||||
* writing, we delete both the original key and the normalized-with-slash
|
||||
* variant so historical duplicates collapse to one canonical entry.
|
||||
*/
|
||||
readonly set: (key: string, info: Info) => Effect.Effect<void, AuthServiceError>
|
||||
|
||||
/**
|
||||
* Removes the auth entry stored under the provided key.
|
||||
*
|
||||
* The raw key and its normalized form are both deleted so callers can pass
|
||||
* either version during cleanup.
|
||||
*/
|
||||
readonly remove: (key: string) => Effect.Effect<void, AuthServiceError>
|
||||
}
|
||||
}
|
||||
|
|
@ -56,15 +83,7 @@ export class AuthService extends ServiceMap.Service<AuthService, AuthService.Ser
|
|||
Effect.tryPromise({
|
||||
try: async () => {
|
||||
const data = await Filesystem.readJson<Record<string, unknown>>(file).catch(() => ({}))
|
||||
return Object.entries(data).reduce(
|
||||
(acc, [key, value]) => {
|
||||
const parsed = decode(value)
|
||||
if (Option.isNone(parsed)) return acc
|
||||
acc[key] = parsed.value
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, Info>,
|
||||
)
|
||||
return Record.filterMap(data, (value) => Result.fromOption(decode(value), () => undefined))
|
||||
},
|
||||
catch: fail("Failed to read auth data"),
|
||||
}),
|
||||
|
|
|
|||
Loading…
Reference in New Issue