diff --git a/.plans/16c-pr89-remediation-checklist.md b/.plans/16c-pr89-remediation-checklist.md index 74489a13fb19f3206ab6b59791136f8f1cd1aa57..70203677e2ba9a45839a80490f51ca5271e8edf6 100644 --- a/.plans/16c-pr89-remediation-checklist.md +++ b/.plans/16c-pr89-remediation-checklist.md @@ -360,8 +360,8 @@ Counts: active `51` (`valid=33`, `partially-valid=18`), closed-invalid `6` - Threads: PRRT_kwDORLtfbc5wiaR- - Audit note: Decode and SQL errors still collapsed into one persistence error kind. -- [ ] `C049` `JSON.stringify(cause)` returns `undefined` for `undefined`, functions, or symbols, violating the `string` return type. Consider coercing the result to a string (e.g., `String(JSON.stringify(cause))`) or adding a fallback. - - Status: `TODO` +- [x] `C049` `JSON.stringify(cause)` returns `undefined` for `undefined`, functions, or symbols, violating the `string` return type. Consider coercing the result to a string (e.g., `String(JSON.stringify(cause))`) or adding a fallback. + - Status: `DONE` - Verdict: `valid` - Severity: `Low` - Area: `Other` diff --git a/apps/server/src/provider/Layers/ProviderService.ts b/apps/server/src/provider/Layers/ProviderService.ts index 46fa47045a68d555bebdc068993d9300e3682a9b..7b504ef03076c10d52f12574c312c79c141cfb0d 100644 --- a/apps/server/src/provider/Layers/ProviderService.ts +++ b/apps/server/src/provider/Layers/ProviderService.ts @@ -22,7 +22,7 @@ import { type ProviderRuntimeEvent, type ProviderSession, } from "@t3tools/contracts"; -import { Effect, Layer, Option, PubSub, Queue, Ref, Schema, Stream } from "effect"; +import { Effect, Layer, Option, PubSub, Queue, Ref, Schema, SchemaIssue, Stream } from "effect"; import { ProviderSessionNotFoundError, ProviderValidationError } from "../Errors.ts"; import { ProviderAdapterRegistry } from "../Services/ProviderAdapterRegistry.ts"; @@ -54,30 +54,21 @@ function toValidationError( }); } -function decodeIssueMessage(cause: unknown): string { - if (cause instanceof Error && cause.message.length > 0) { - return cause.message; - } - try { - return JSON.stringify(cause); - } catch { - return "Invalid provider input."; - } -} - -function decodeInputOrValidationError(input: { +const decodeInputOrValidationError = (input: { readonly operation: string; readonly schema: S; readonly payload: unknown; -}): Effect.Effect, ProviderValidationError> { - try { - return Effect.succeed( - Schema.decodeUnknownSync(input.schema as never)(input.payload) as Schema.Schema.Type, - ); - } catch (cause) { - return Effect.fail(toValidationError(input.operation, decodeIssueMessage(cause), cause)); - } -} +}) => + Schema.decodeUnknownEffect(input.schema)(input.payload).pipe( + Effect.mapError( + (schemaError) => + new ProviderValidationError({ + operation: input.operation, + issue: SchemaIssue.makeFormatterDefault()(schemaError.issue), + cause: schemaError, + }), + ), + ); function toRuntimeStatus(session: ProviderSession): "starting" | "running" | "stopped" | "error" { switch (session.status) { @@ -265,9 +256,7 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) => provider: existing.provider, threadId: input.binding.threadId, providerThreadId: existingProviderThreadId, - ...(existing.resumeCursor !== undefined - ? { resumeCursor: existing.resumeCursor } - : {}), + ...(existing.resumeCursor !== undefined ? { resumeCursor: existing.resumeCursor } : {}), }); if (existing.sessionId !== input.staleSessionId) { yield* setAlias(input.staleSessionId, existing.sessionId); @@ -310,9 +299,7 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) => provider: resumed.provider, threadId: input.binding.threadId, providerThreadId: resumedProviderThreadId, - ...(resumed.resumeCursor !== undefined - ? { resumeCursor: resumed.resumeCursor } - : {}), + ...(resumed.resumeCursor !== undefined ? { resumeCursor: resumed.resumeCursor } : {}), }); if (resumed.sessionId !== input.staleSessionId) {