Fix API ESM module resolution (production 500s) - #52
Merged
Conversation
…lution Vercel's Node runtime resolves compiled functions as ESM, which requires explicit file extensions on relative imports. The extensionless imports crashed every /api function with ERR_MODULE_NOT_FOUND once the project was rebuilt with the current Vercel builder. Adding .js works for both ESM and CJS and is resolved by vite/esbuild in dev and tests.
There was a problem hiding this comment.
Pull request overview
This PR addresses production 500s on Vercel caused by ESM module resolution requiring explicit file extensions on relative imports in compiled /api/* serverless functions. It updates API code to use .js extensions in relative import specifiers so the deployed ESM output can be loaded correctly.
Changes:
- Added
.jsextensions to relative imports across API endpoints and shared modules to satisfy Vercel’s ESM loader. - Updated booking endpoint internal imports under
api/booking/_libto use explicit.jsspecifiers. - Updated a booking library test import to match the new explicit extension style.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| api/send.ts | Adds explicit .js extensions for shared API imports to avoid ESM runtime resolution failures. |
| api/newsletter.ts | Adds explicit .js extensions for shared API imports to avoid ESM runtime resolution failures. |
| api/booking/create.ts | Adds explicit .js extensions for booking endpoint internal module imports for ESM compatibility. |
| api/booking/cancel.ts | Adds explicit .js extensions for booking endpoint internal module imports for ESM compatibility. |
| api/booking/lookup.ts | Adds explicit .js extensions for booking endpoint internal module imports for ESM compatibility. |
| api/booking/reschedule.ts | Adds explicit .js extensions for booking endpoint internal module imports for ESM compatibility. |
| api/booking/availability.ts | Adds explicit .js extensions for booking endpoint internal module imports for ESM compatibility. |
| api/booking/_lib/tokens.ts | Adds explicit .js extension for internal config import used at runtime. |
| api/booking/_lib/slots.ts | Adds explicit .js extension for internal config import used at runtime. |
| api/booking/_lib/mailer.ts | Adds explicit .js extension for internal config import used at runtime. |
| api/booking/_lib/google-calendar.ts | Adds explicit .js extension for internal config import used at runtime. |
| api/booking/_lib/d1.ts | Adds explicit .js extension for internal config import used at runtime. |
| api/booking/_lib/slots.test.ts | Updates test import to use explicit .js extension for consistency with ESM-style specifiers. |
| api/_shared/rate-limit.ts | Adds explicit .js extension for shared type import to align specifiers under ESM. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+13
to
+17
| } from './_lib/config.js'; | ||
| import { exec, isUniqueConstraintError, queryFirst } from './_lib/d1.js'; | ||
| import { createEvent, deleteEvent, getBusyIntervals } from './_lib/google-calendar.js'; | ||
| import { sendBookingConfirmation } from './_lib/mailer.js'; | ||
| import { isSlotValid } from './_lib/slots.js'; |
Comment on lines
4
to
+8
| import { | ||
| applyRateLimitHeaders, | ||
| checkRateLimit, | ||
| getRateLimitIdentifier, | ||
| } from './_shared/rate-limit'; | ||
| } from './_shared/rate-limit.js'; |
Comment on lines
1
to
+3
| import { createHmac, randomUUID, timingSafeEqual } from 'crypto'; | ||
|
|
||
| import { getRuntimeEnv } from './config'; | ||
| import { getRuntimeEnv } from './config.js'; |
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.
Incident fix
Every
/api/*function was returning HTTP 500FUNCTION_INVOCATION_FAILEDin production with:Vercel's Node runtime loads the compiled functions as ESM, which requires explicit file extensions on relative imports. The extensionless imports (pre-existing) only surfaced now because this was the first production rebuild in 43 days and the Vercel builder changed. This affected contact, newsletter, and all booking endpoints.
Adds
.jsextensions to all relative imports underapi/(44 imports, 14 files). Works for both ESM and CJS; vite/esbuild resolves.js→.tsin dev and tests (109 tests still pass).