fix(resources): accept bare object/array responses on create/update paths - #59
Merged
Conversation
…aths
HaloPSA returns created/updated entities in three shapes depending on
endpoint and version: enveloped ({ actions: [...] }), bare object, or
bare array. All 41 create/update/me/addAction/addAttachment sites read
response.<key>[0] unguarded, throwing "Cannot read properties of
undefined (reading '0')" on unwrapped responses — after the 2xx write
had already landed, so callers that retried duplicated records.
Route every write path through unwrapSingle (already used on GET paths)
and extend it to also handle bare-array responses.
Refs wyre-technology/halopsa-mcp#76
github-actions Bot
pushed a commit
that referenced
this pull request
Aug 11, 2026
## [1.0.9](v1.0.8...v1.0.9) (2026-08-11) ### Bug Fixes * **resources:** accept bare object/array responses on create/update paths ([#59](#59)) ([41e30fc](41e30fc)), closes [wyre-technology/halopsa-mcp#76](wyre-technology/halopsa-mcp#76)
asachs01
added a commit
to wyre-technology/node-it-glue
that referenced
this pull request
Aug 11, 2026
…a is empty (#59) getOne, postAndDeserialize, and patchAndDeserialize unwrapped the JSON:API envelope with `data[0]` / `data`, so a 2xx response whose `data` member was an empty array silently resolved `undefined` typed as T, and a body with no `data` member threw an anonymous TypeError inside deserializeResource. The POST/PATCH variants are the dangerous ones: the write already landed on the server, the caller got `undefined`, downstream property access threw an anonymous TypeError, and a retrying caller turned that into duplicate records. All three methods now route through a private deserializeOne helper that throws a descriptive ITGlueError naming the method and path when the response contains no resource. Part of the fleet sweep for unchecked response-envelope access on write paths, following wyre-technology/halopsa-mcp#76 and wyre-technology/node-halopsa#59.
asachs01
added a commit
to wyre-technology/node-mimecast
that referenced
this pull request
Aug 11, 2026
… responses (#32) messages.getInfo and queue.getStatus unwrapped data[0] from a possibly-empty Mimecast envelope and cast the result straight to the entity type, resolving undefined (or a fabricated {}) silently typed as the entity. They now throw a descriptive MimecastNotFoundError / MimecastError when the envelope carries no data. The TTP log methods in threats.ts similarly resolved undefined for empty envelopes despite a declared array return type; they now fall back to [] while leaving the existing data[0] unwrap untouched. Part of the fleet sweep following wyre-technology/halopsa-mcp#76 (unchecked response-envelope access, cf. wyre-technology/node-halopsa#59).
asachs01
added a commit
to wyre-technology/node-auvik
that referenced
this pull request
Aug 11, 2026
…r absent (#33) All 13 single-resource get* methods unwrapped response.data with 'Array.isArray(response.data) ? response.data[0] : response.data' and then immediately read data.id, so an empty array or a body without data crashed with an anonymous 'TypeError: Cannot read properties of undefined (reading id)'. Route all 13 sites through a shared unwrapJsonApiData() helper in json-api-mapper.ts that throws a descriptive AuvikError ('Auvik returned no <entity> for <id>') instead. Part of the fleet sweep for unchecked response-envelope access, following wyre-technology/halopsa-mcp#76 and wyre-technology/node-halopsa#59 (mirrors node-halopsa's centralized unwrapSingle).
github-actions Bot
pushed a commit
to wyre-technology/node-auvik
that referenced
this pull request
Aug 11, 2026
## [1.3.1](v1.3.0...v1.3.1) (2026-08-11) ### Bug Fixes * **resources:** throw descriptive error when JSON:API data is empty or absent ([#33](#33)) ([62cf835](62cf835)), closes [wyre-technology/halopsa-mcp#76](wyre-technology/halopsa-mcp#76) [wyre-technology/node-halopsa#59](wyre-technology/node-halopsa#59)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the systemic write-path crash reported in wyre-technology/halopsa-mcp#76: every
create()/update()(plusagents.me(),tickets.addAction(),tickets.addAttachment()) read the response envelope unguarded (response.<key>[0]), so when HaloPSA returns the created entity bare instead of enveloped, the SDK throwsTypeError: Cannot read properties of undefined (reading '0')— after the 2xx write landed. Callers that retried on the error duplicated records in production.unwrapSingleto handle all three response shapes HaloPSA emits: enveloped ({ actions: [{...}] }), bare object ({ id: 1, ... }), and bare array ([{ id: 1, ... }]). The bare-array case previously fell through toreturn response as T, silently handing back an array typed as a single entity.unwrapSingle, matching the idiom theget()paths already use. The per-siteFailed to create/update <entity>throws are now actually reachable when no entity comes back.Test plan
tests/unit/resources.test.ts: table-driven over all 41 sites × 4 shapes (enveloped, bare object, bare array, empty envelope → throw). The bare-object and bare-array cases fail onmain(84 failures) and pass with this change.unwrapSingleunit tests extended with bare-array and empty-bare-array cases.npm run build,npm test(260/260), andnpm run lintall green.Refs wyre-technology/halopsa-mcp#76
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is enabled.