| 123456789101112131415161718192021222324252627282930313233343536 |
- import { Option, Schema } from "effect"
- import type { RequestSnapshot } from "./schema"
- const JsonValue = Schema.fromJsonString(Schema.Unknown)
- export const decodeJson = Schema.decodeUnknownOption(JsonValue)
- const isRecord = (value: unknown): value is Record<string, unknown> =>
- value !== null && typeof value === "object" && !Array.isArray(value)
- export const canonicalizeJson = (value: unknown): unknown => {
- if (Array.isArray(value)) return value.map(canonicalizeJson)
- if (isRecord(value)) {
- return Object.fromEntries(
- Object.keys(value)
- .toSorted()
- .map((key) => [key, canonicalizeJson(value[key])]),
- )
- }
- return value
- }
- export type RequestMatcher = (incoming: RequestSnapshot, recorded: RequestSnapshot) => boolean
- export const canonicalSnapshot = (snapshot: RequestSnapshot): string =>
- JSON.stringify({
- method: snapshot.method,
- url: snapshot.url,
- headers: canonicalizeJson(snapshot.headers),
- body: Option.match(decodeJson(snapshot.body), {
- onNone: () => snapshot.body,
- onSome: canonicalizeJson,
- }),
- })
- export const defaultMatcher: RequestMatcher = (incoming, recorded) =>
- canonicalSnapshot(incoming) === canonicalSnapshot(recorded)
|