Skip to content

fix(github-lambda): bundle via esbuild + inline resolveGitToken#182

Open
eipasteur wants to merge 1 commit into
mainfrom
fix/lambda-github-esbuild-runtime
Open

fix(github-lambda): bundle via esbuild + inline resolveGitToken#182
eipasteur wants to merge 1 commit into
mainfrom
fix/lambda-github-esbuild-runtime

Conversation

@eipasteur
Copy link
Copy Markdown
Contributor

Problem

Two layered runtime regressions blocked /api/github/* endpoints in deployed environments:

  1. PR test(github): add unit tests for lambda/github handler #176 ("Migrate lambda/github to ESM") changed require('./shared/...') to import '../shared/response.js', but the Terraform packaging copied shared/ at the same level as index.js in the zip. At runtime, the ESM resolver dereferenced '../shared/response.js' to /var/shared/response.js — one level above /var/task/, which doesn't exist. Every cold start threw ERR_MODULE_NOT_FOUND.

  2. shared/git-token.js is CommonJS and uses require('@aws-sdk/client-ssm') at the module top level. Even after fixing the path, esbuild bundles a CJS shim that the Node.js ESM runtime rejects with Dynamic require of "@aws-sdk/client-ssm" is not supported.

Solution

Apply the same packaging pattern adopted for lambda/github-issues in #180:

  • terraform/modules/api/lambda/main.tf: replace npm_requirements + prefix_in_zip='shared' with the commands + :zip esbuild build pattern; bump runtime to nodejs24.x to match the workspace --target=node24.
  • lambda/github/index.js: inline resolveGitToken locally (mirroring the pattern adopted by lambda/github-issues). shared/response.js continues to be imported from shared since it has no top-level require of an external package and esbuild can statically bundle it.

Validation

  • ✅ All 153 unit tests pass (7 test files)
  • ✅ TypeScript clean
  • ✅ Terraform validate clean
  • ✅ Manual test on staging: aws lambda invoke returns statusCode: 200 with valid JSON {"connected": false}
  • /api/github/status returns proper JSON 401 (was returning HTML 200 before)

Why inline resolveGitToken rather than refactor shared/

10+ other CJS lambdas import shared/response and shared/git-token. Migrating shared/ to ESM would force a coordinated rewrite of all of them, well beyond the scope of this fix. Inlining mirrors the pragmatic precedent set by #180.

Closes the regression introduced in #176.

Two layered runtime regressions blocked /api/github/* on staging:

1. PR #176 migrated lambda/github from CommonJS to ESM but the Terraform
   packaging used npm_requirements + prefix_in_zip='shared'. The ESM
   resolver dereferenced '../shared/response.js' to /var/shared/...
   (one level above /var/task/), which doesn't exist, throwing
   ERR_MODULE_NOT_FOUND on every cold start.

2. shared/git-token.js is CommonJS and does require('@aws-sdk/client-ssm')
   at the module top level. esbuild bundles a CJS shim around it, but
   the Node.js ESM runtime rejects the resulting dynamic require:
   'Dynamic require of @aws-sdk/client-ssm is not supported'.

Fix:
- terraform/modules/api/lambda/main.tf: switch github_lambda from
  npm_requirements to the build/:zip pattern (mirroring github_issues
  per PR #180), bumping runtime to nodejs24.x to match the esbuild
  --target=node24 the workspace already uses.
- lambda/github/index.js: inline resolveGitToken locally, mirroring the
  exact pattern adopted by lambda/github-issues. shared/response.js
  remains imported because esbuild can statically bundle it without
  hitting a dynamic require (it has no top-level require of an external
  package).

Validated end-to-end on staging:
- terraform apply succeeded (no drift)
- aws lambda invoke returns statusCode 200 with valid JSON body
  ({connected: false}) for /api/github/status
- 153 unit tests across the repo continue to pass

Closes the runtime regression introduced in #176.
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