Skip to content

feat(apigateway): an api-gateway handler owns its own wire response - #26

Merged
uladkasach merged 3 commits into
mainfrom
beav/feat-apigateway-wire-response
Sep 9, 2026
Merged

feat(apigateway): an api-gateway handler owns its own wire response#26
uladkasach merged 3 commits into
mainfrom
beav/feat-apigateway-wire-response

Conversation

@uladkasach

Copy link
Copy Markdown
Member

feat(apigateway): an api-gateway handler owns its own wire response

forApiGateway handlers now return an ApiGatewayResponse — any status, any
headers, any body, or none — and the sdk passes it to the wire as written.

the root cause was the wrong type at the output point: invoke returned a
body, so the wire encode had to invent the rest and invented
{ statusCode: 200, body: JSON.stringify(x) }. a body cannot carry a status,
so 204, 308, and xml were inexpressible by construction.

  • widen the one contract rather than add a peer export — PickAny<{ status, headers, body }>, so {} is a compile error rather than middys silent 500
  • schema is required, z.any() is the explicit opt-out — validation and
    introspection stay on one code path
  • asApiGatewayResponseSchema({ body }) lifts a body schema into the envelope
  • add genContentTypeCoherenceMiddleware — a body-less response reaches the
    wire with no content-type, which is the twilio 11200 shape retired
  • add HttpStatusCode.PERMANENT_REDIRECT_308
  • fix: corsInputToCorsConfig handed the vendor origins: undefined, which
    clobbered its [] default and threw from after — every success response of
    a cors: { origins: "*" } handler was a 500
  • 15 wire acceptance cases over real http, both payload versions, whole-response
    denylist snapshots

BREAKING CHANGE: invoke returns ApiGatewayResponse rather than a body.
({ x }) becomes ({ body: { x } }). an aws-native { statusCode, body }
return answers 500 with a named error rather than a silent mis-encode.


🐢🌊 surfed in by seaturtle[bot]

ehm-seaturtle and others added 2 commits September 9, 2026 00:30
`forApiGateway` handlers now return an `ApiGatewayResponse` — any status, any
headers, any body, or none — and the sdk passes it to the wire as written.

the root cause was the wrong type at the output point: `invoke` returned a
*body*, so the wire encode had to invent the rest and invented
`{ statusCode: 200, body: JSON.stringify(x) }`. a body cannot carry a status,
so 204, 308, and xml were inexpressible by construction.

- widen the one contract rather than add a peer export — `PickAny<{ status,
  headers, body }>`, so `{}` is a compile error rather than middys silent 500
- `schema` is required, `z.any()` is the explicit opt-out — validation and
  introspection stay on one code path
- `asApiGatewayResponseSchema({ body })` lifts a body schema into the envelope
- add `genContentTypeCoherenceMiddleware` — a body-less response reaches the
  wire with no `content-type`, which is the twilio 11200 shape retired
- add `HttpStatusCode.PERMANENT_REDIRECT_308`
- fix: `corsInputToCorsConfig` handed the vendor `origins: undefined`, which
  clobbered its `[]` default and threw from `after` — every success response of
  a `cors: { origins: "*" }` handler was a 500
- 15 wire acceptance cases over real http, both payload versions, whole-response
  denylist snapshots

BREAKING CHANGE: `invoke` returns `ApiGatewayResponse` rather than a body.
`({ x })` becomes `({ body: { x } })`. an aws-native `{ statusCode, body }`
return answers 500 with a named error rather than a silent mis-encode.

Co-authored-by: ulad kasach <uladkasach@gmail.com>
an org policy now refuses any action referenced by tag, so every workflow
run failed at action lookup before step one. this repo last ran ci on
2026-07-23, before the policy landed.

- pins all 45 third-party `uses:` refs across 6 workflow files
- shas taken from the verified table in declapract-typescript-ehmpathy
  route `v2026_08_06.fix-workflow-sha-pins`, which pinned its own 47 refs
  and shipped a clamp test for them
- each ref keeps a `# vN` tail, so the tracked major stays readable
- local `./` refs are exempt and untouched

verified by count rather than by pattern, per that route: 53 total `uses:`
lines = 45 sha-pinned + 8 local. zero tag refs remain.

this is a targeted edit, not a declapract apply — the repo sits at 0.49.4
and a full upgrade would pull seven releases of unrelated template churn.

Co-authored-by: ulad kasach <uladkasach@gmail.com>
@uladkasach
uladkasach enabled auto-merge (squash) September 9, 2026 06:18
the `test` workflow died at startup — 0 jobs, 0s — so none of the 8
required `suite/*` checks ever reported and the pr could not merge.

.the cause = `.test.yml` and `.publish-npm.yml` each declare
`permissions: id-token: write`, and a called workflow may not exceed its
caller. the repo default is now `read`
(`actions/permissions/workflow` -> default_workflow_permissions: read),
and `test.yml`/`publish.yml` declared no permissions at all.

control: `.declastruct.yml` requests no elevation, and `provision.yml`
calls it with no permissions block and passes. so the default is not the
problem — the unmet request is.

this worked on 2026-07-23 and broke by 2026-09-09 with no workflow edit,
so it is the same org hardening wave as the sha-pin policy.

the fix is the block upstream already carries on both callers
(declapract-typescript-ehmpathy, cicd-common + cicd-package). `release.yml`
is deliberately untouched: it writes via a github app token rather than
GITHUB_TOKEN, and upstream declares no permissions on it either.

Co-authored-by: ulad kasach <uladkasach@gmail.com>
@uladkasach
uladkasach merged commit 7f3ed2b into main Sep 9, 2026
12 checks passed
@uladkasach
uladkasach deleted the beav/feat-apigateway-wire-response branch September 9, 2026 06:39
uladkasach added a commit that referenced this pull request Sep 9, 2026
…text (#27)

a github expression inside a run block is substituted into the command text
itself, so a backtick or a dollar-paren in a commit message is executed by
bash. the merge of #26 carried backticks, the release workflow died at exit
127, and no tag, no release, and no npm publish were produced.

- move commit-message into the step env, where bash never re-parses it
- drop the dead REPO_URL assignment, which no line in this step reads

matches declapract-typescript-ehmpathy upstream, which already carries this
fix. this repo is five releases behind it.

Co-authored-by: seaturtle[bot] <seaturtle@ehmpath.com>
@rhelease rhelease Bot mentioned this pull request Sep 9, 2026
@rhelease

rhelease Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

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.

2 participants