Skip to content

fix(provider): handle plain-text responses in postUint8Array#183

Open
solidsnakedev wants to merge 2 commits intomainfrom
fix/post-uint8array-plain-text-response
Open

fix(provider): handle plain-text responses in postUint8Array#183
solidsnakedev wants to merge 2 commits intomainfrom
fix/post-uint8array-plain-text-response

Conversation

@solidsnakedev
Copy link
Collaborator

postUint8Array unconditionally calls filteredResponse.json, which runs JSON.parse internally. Endpoints that return plain-text (e.g. an unquoted hex tx hash) fail with a SyntaxError because the body is not valid JSON. This makes the Blockfrost provider incompatible with backends that return raw strings from POST /tx/submit.

postUint8Array now tries filteredResponse.json first and falls back to filteredResponse.text via Effect.orElse. Both Blockfrost-style JSON responses ("hash") and plain-text responses (hash) now decode correctly through the existing schema pipeline.

Closes #181

Copilot AI review requested due to automatic review settings March 4, 2026 15:25
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes postUint8Array to support providers whose POST /tx/submit returns a raw plain-text hash (unquoted), avoiding JSON.parse failures and restoring compatibility with such backends.

Changes:

  • Update postUint8Array to attempt JSON decoding first and fall back to plain-text decoding.
  • Add a changeset to publish the fix as a patch release.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
packages/evolution/src/sdk/provider/internal/HttpUtils.ts Adds JSON→text fallback when decoding postUint8Array responses
.changeset/fix-post-uint8array-plain-text.md Documents patch release for the new fallback behavior

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +81 to +83
// Try JSON first, fall back to plain text for endpoints that return unquoted strings (e.g. Dolos /tx/submit)
const decoded = yield* filteredResponse.json.pipe(Effect.orElse(() => filteredResponse.text))
return yield* Schema.decodeUnknown(schema)(decoded)
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filteredResponse.json followed by a fallback to filteredResponse.text may require consuming the response body twice. In many Fetch/HTTP response implementations, the body can only be read once; if JSON parsing fails after reading the body, text cannot be read afterwards (fallback will fail too). A safer approach is to read the body once as text, then attempt to parse it as JSON (falling back to the raw text when parsing fails) before passing it to Schema.decodeUnknown.

Suggested change
// Try JSON first, fall back to plain text for endpoints that return unquoted strings (e.g. Dolos /tx/submit)
const decoded = yield* filteredResponse.json.pipe(Effect.orElse(() => filteredResponse.text))
return yield* Schema.decodeUnknown(schema)(decoded)
// Read body once as text, then try to parse as JSON; fall back to plain text on parse failure
const bodyText = yield* filteredResponse.text
let decodedBody: unknown
try {
decodedBody = JSON.parse(bodyText)
} catch {
decodedBody = bodyText
}
return yield* Schema.decodeUnknown(schema)(decodedBody)

Copilot uses AI. Check for mistakes.
const json = yield* filteredResponse.json
return yield* Schema.decodeUnknown(schema)(json)
// Try JSON first, fall back to plain text for endpoints that return unquoted strings (e.g. Dolos /tx/submit)
const decoded = yield* filteredResponse.json.pipe(Effect.orElse(() => filteredResponse.text))
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effect.orElse will catch any failure from filteredResponse.json, not just JSON parse errors. That can unintentionally hide unexpected issues (e.g., decoding/transport errors) by silently switching to text. Consider narrowing the fallback to only the JSON-parse failure case (e.g., via a predicate-based catch) so other errors still fail fast.

Suggested change
const decoded = yield* filteredResponse.json.pipe(Effect.orElse(() => filteredResponse.text))
const decoded = yield* filteredResponse.json.pipe(
Effect.catchIf(
(error) => error instanceof SyntaxError,
() => filteredResponse.text
)
)

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

postUint8Array assumes JSON; breaks when endpoint returns plain-text (e.g., Dolos /tx/submit)

2 participants