Skip to content

fix(resources): accept bare object/array responses on create/update paths - #59

Merged
asachs01 merged 1 commit into
mainfrom
fix/unwrap-write-responses
Aug 11, 2026
Merged

fix(resources): accept bare object/array responses on create/update paths#59
asachs01 merged 1 commit into
mainfrom
fix/unwrap-write-responses

Conversation

@asachs01

@asachs01 asachs01 commented Aug 11, 2026

Copy link
Copy Markdown
Member

Summary

Fixes the systemic write-path crash reported in wyre-technology/halopsa-mcp#76: every create()/update() (plus agents.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 throws TypeError: Cannot read properties of undefined (reading '0')after the 2xx write landed. Callers that retried on the error duplicated records in production.

  • Extend unwrapSingle to 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 to return response as T, silently handing back an array typed as a single entity.
  • Route all 41 unguarded sites across 17 resource files through unwrapSingle, matching the idiom the get() paths already use. The per-site Failed to create/update <entity> throws are now actually reachable when no entity comes back.

Test plan

  • New 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 on main (84 failures) and pass with this change.
  • unwrapSingle unit tests extended with bare-array and empty-bare-array cases.
  • npm run build, npm test (260/260), and npm run lint all green.

Refs wyre-technology/halopsa-mcp#76


View with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is enabled.

…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
@asachs01
asachs01 merged commit 41e30fc into main Aug 11, 2026
3 checks passed
@asachs01
asachs01 deleted the fix/unwrap-write-responses branch August 11, 2026 11:08
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)
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.

1 participant