feat: add isNotFound, isConflict and isMalformedId error predicates - #83
Conversation
Consumers currently re-implement these on top of CommsRequestError. The comms-cli has its own copies, and the MCP needs the same checks, so they belong next to the error they inspect. isMalformedId keys on error_code 217 rather than the message, because the API pairs that code with two different strings: one for an id that does not base58-decode to 16 bytes, and one for a version nibble that is not 7. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The two read the same error body and a consumer surfacing a Comms failure wants both: the code to branch on, the string to show. Shipping only the code left the pair half-done. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
@doistbot /review |
doistbot
left a comment
There was a problem hiding this comment.
Adds five focused exports beside CommsRequestError — isNotFound, isConflict, getCommsErrorCode, getCommsErrorString, and isMalformedId — giving consumers a single home for response-error checks instead of per-repo copies, with isMalformedId sensibly keyed on error code 217 rather than prose. The helpers narrow via instanceof, guard the response-body shapes, are re-exported through the package root, and come with solid edge-case coverage plus mutation testing. No inline issues were flagged; the security and reuse passes found no concerns, noting the functions are pure read-only inspectors with no duplicated existing utility.
I also included a few optional follow-up notes in the details below.
Optional follow-up notes (2)
src/types/errors.ts:62: The TSDoc example calls
api.threads.getThread({ id }), butThreadsClient.getThreadis declared asgetThread(id: string). Passing an object will not type-check. Change the example toapi.threads.getThread(id).src/types/errors.test.ts:84: This assertion duplicates line 71 exactly: both call
getCommsErrorString(requestError(409)), andrequestErroralways supplies the same'request failed'message. The block therefore adds no regression signal beyond the earlier "no error_string" case. Either delete thisitblock or make the intended scenario distinct, e.g. constructnew CommsRequestError('server text', 409)so the test explicitly shows the message is not used as a fallback.
The TSDoc example passed an object to getThread, which takes a bare id. The fallback test repeated the no-error_string case verbatim; it now constructs an error with its own message, so it actually shows the message is not used as a fallback. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Fixed. It's
Fixed. Now builds its own |
## [3.3.0](v3.2.0...v3.3.0) (2026-10-01) ### Features * add isNotFound, isConflict and isMalformedId error predicates ([#83](#83)) ([f4d2213](f4d2213))
|
🎉 This PR is included in version 3.3.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Why
Consumers keep re-implementing the same checks on top of
CommsRequestError. comms-cli has its own copies, added in comms-cli#66, and the MCP needs the same ones for checking ids. @scottlovegrove raised it on that PR: they belong here, next to the error they inspect.Change
Five exports in
types/errors.ts, besideCommsRequestError:isNotFound(error)andisConflict(error), 404 and 409.getCommsErrorCode(error)andgetCommsErrorString(error), theerror_codeanderror_stringfrom the response body, ornull. Branch on the code, display the string.isMalformedId(error), a 409 carryingerror_code217, which is a bad reference rather than a conflict.isMalformedIdkeys on the code rather than the message, because the API pairs 217 with two different strings: one for an id that does not base58-decode to 16 bytes, and one for a version nibble that is not 7. comms-cli originally matched on the prose and missed the second.They narrow with
instanceof CommsRequestError, matchingmigration.tsandfetch-with-retry.tsrather than duck-typing the shape.Not included: comms-cli's 401 and 403 helpers.
isForbiddenis defined there as "a 403 that is not an OAuth-scope failure", which is CLI policy rather than a property of the response, so it stays there for now.Checks
npm run check,npm run type-check,npm test: passed (246 tests, 19 new).npm run build,npm run attw: passed. All five are exported from the package root.isMalformedIdignoring the code,getCommsErrorCodecoercing a string,getCommsErrorStringcoercing a non-string,getCommsErrorStringfalling back toerror.message, andinstanceofrelaxed to duck-typing in both readers.Follow-up: a comms-cli PR deleting its copies once this is released. comms-cli#67 does the same for the id validator.
🤖 Generated with Claude Code