From e45b6ef1dec3795d0daa3a4e8d8744a52e0d8841 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Sun, 10 May 2026 12:43:33 -0400 Subject: [PATCH] refactor(http-recorder): use Schema.TaggedErrorClass for cassette errors (#26729) --- packages/http-recorder/src/cassette.ts | 9 +++++---- packages/http-recorder/src/recorder.ts | 12 ++++++------ packages/http-recorder/src/redaction.ts | 11 +++++++---- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/http-recorder/src/cassette.ts b/packages/http-recorder/src/cassette.ts index d6f7e6d3af..527afe8251 100644 --- a/packages/http-recorder/src/cassette.ts +++ b/packages/http-recorder/src/cassette.ts @@ -1,4 +1,4 @@ -import { Context, Data, Effect, FileSystem, Layer } from "effect" +import { Context, Effect, FileSystem, Layer, Schema } from "effect" import * as fs from "node:fs" import * as path from "node:path" import { secretFindings, type SecretFinding } from "./redaction" @@ -6,9 +6,10 @@ import { decodeCassette, encodeCassette, type Cassette, type CassetteMetadata, t const DEFAULT_RECORDINGS_DIR = path.resolve(process.cwd(), "test", "fixtures", "recordings") -export class CassetteNotFoundError extends Data.TaggedError("CassetteNotFoundError")<{ - readonly cassetteName: string -}> { +export class CassetteNotFoundError extends Schema.TaggedErrorClass()( + "CassetteNotFoundError", + { cassetteName: Schema.String }, +) { override get message() { return `Cassette "${this.cassetteName}" not found` } diff --git a/packages/http-recorder/src/recorder.ts b/packages/http-recorder/src/recorder.ts index 381122d31c..460b427c2a 100644 --- a/packages/http-recorder/src/recorder.ts +++ b/packages/http-recorder/src/recorder.ts @@ -1,13 +1,13 @@ -import { Data, Effect, Ref, Scope } from "effect" +import { Effect, Ref, Schema, Scope } from "effect" import type * as CassetteService from "./cassette" import type { CassetteNotFoundError } from "./cassette" -import type { SecretFinding } from "./redaction" +import { SecretFindingSchema } from "./redaction" import type { CassetteMetadata, Interaction } from "./schema" -export class UnsafeCassetteError extends Data.TaggedError("UnsafeCassetteError")<{ - readonly cassetteName: string - readonly findings: ReadonlyArray -}> { +export class UnsafeCassetteError extends Schema.TaggedErrorClass()("UnsafeCassetteError", { + cassetteName: Schema.String, + findings: Schema.Array(SecretFindingSchema), +}) { override get message() { return `Refusing to write cassette "${this.cassetteName}" because it contains possible secrets: ${this.findings .map((finding) => `${finding.path} (${finding.reason})`) diff --git a/packages/http-recorder/src/redaction.ts b/packages/http-recorder/src/redaction.ts index 07534d9520..b6aa8b3b87 100644 --- a/packages/http-recorder/src/redaction.ts +++ b/packages/http-recorder/src/redaction.ts @@ -95,10 +95,13 @@ export const redactHeaders = ( ) } -export type SecretFinding = { - readonly path: string - readonly reason: string -} +import { Schema } from "effect" + +export const SecretFindingSchema = Schema.Struct({ + path: Schema.String, + reason: Schema.String, +}) +export type SecretFinding = Schema.Schema.Type export const secretFindings = (value: unknown): ReadonlyArray => stringEntries(value).flatMap((entry) => [