Skip to content

fix: publish declarations that resolve under NodeNext - #216

Merged
Bccorb merged 1 commit into
mainfrom
fix/nodenext-declarations
Oct 13, 2026
Merged

Bccorb merged 1 commit into
mainfrom
fix/nodenext-declarations

Conversation

@Bccorb

@Bccorb Bccorb commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Closes #214

Problem

@seamless-auth/express, @seamless-auth/fastify and @seamless-auth/nextjs compiled with moduleResolution: "bundler", so relative imports in src were extensionless and tsc copied them verbatim into the published .d.ts. NodeNext and Node16 consumers cannot resolve those, so requireAuth, createSeamlessAuthHandler, getSeamlessSession and the rest typed as any. skipLibCheck: true hid it.

Core was already NodeNext with .js extensions, but its declarations import JwtPayload from jsonwebtoken while @types/jsonwebtoken was only a dev dependency, so consumers without their own copy got TS7016 (and an any payload).

All four packages are ESM only (exports has types + import, no require condition), so no .d.cts is needed.

Fix

  • Add explicit .js extensions to all 220 relative imports in the three adapters, and compile them with module/moduleResolution: "NodeNext" like core. A missing extension now fails build:types with TS2835, so no separate lint is needed.
  • Move @types/jsonwebtoken into core's dependencies.
  • consumerTypes tests: run with --skipLibCheck false under bundler and NodeNext for all four packages (new for core and nextjs). Each fixture has @ts-expect-error on wrong calls (requireAuth(42), createSeamlessAuthHandler(42), getSeamlessSession(42), verifyCookieJwt(42), loginHandler(42) from @seamless-auth/core/handlers/login, ...). If an export degrades to any, the directive is unused and tsc fails.
  • Lockfile: zod 4.4.3 to 4.6.5. With skipLibCheck off, @seamless-auth/types@0.28.0 declarations use the two-argument ZodPreprocess, which 4.4.3 lacks (TS2707). That is a too-low zod floor in @seamless-auth/types (^4.3.6), worth fixing there separately.
  • Changesets: patch for express, fastify and nextjs (declarations) and core (types dependency).

Emitted JavaScript is unchanged: diffing the packed tarballs before and after, only .d.ts, .d.ts.map and core's package.json differ.

Reproduction (packed tarballs, scratch consumer)

pnpm pack of each package, installed into a scratch project with "module": "NodeNext", "moduleResolution": "NodeNext", "strict": true, "skipLibCheck": false:

import { requireAuth } from "@seamless-auth/express";
import { requireAuth as fastifyRequireAuth } from "@seamless-auth/fastify";
import { createSeamlessAuthHandler, getSeamlessSession } from "@seamless-auth/nextjs";
import { verifyCookieJwt } from "@seamless-auth/core";

requireAuth(42);
fastifyRequireAuth(42);
createSeamlessAuthHandler(42);
getSeamlessSession(42);
verifyCookieJwt(42);

Before (origin/main)

skipLibCheck: false: 26 errors. 23 x TS2834 in the adapters (7 express, 9 fastify, 7 nextjs), 2 x TS7016 in core, for example:

node_modules/@seamless-auth/express/dist/index.d.ts(2,87): error TS2834: Relative import paths need explicit file extensions in ECMAScript imports when '--moduleResolution' is 'node16' or 'nodenext'. Consider adding an extension to the import path.
node_modules/@seamless-auth/core/dist/verifyCookieJwt.d.ts(1,33): error TS7016: Could not find a declaration file for module 'jsonwebtoken'.
src/index.ts(11,1): error TS2554: Expected 2 arguments, but got 1.

skipLibCheck: true: only the core call is flagged. The four wrong adapter calls pass, because the exports are any:

src/index.ts(11,1): error TS2554: Expected 2 arguments, but got 1.

After

skipLibCheck: false and true give the same output, no library errors, and every wrong call is flagged:

src/index.ts(7,13): error TS2345: Argument of type 'number' is not assignable to parameter of type 'RequireAuthOptions'.
src/index.ts(8,20): error TS2345: Argument of type 'number' is not assignable to parameter of type 'RequireAuthOptions'.
src/index.ts(9,27): error TS2345: Argument of type 'number' is not assignable to parameter of type 'SeamlessAuthHandlerOptions'.
src/index.ts(10,1): error TS2554: Expected 2 arguments, but got 1.
src/index.ts(11,1): error TS2554: Expected 2 arguments, but got 1.

(After run uses @types/node@24 to match .nvmrc. With @types/node@26, fastify's transitive thread-stream@4.2.0 declarations fail on TransferListItem, which is unrelated to this repo and was only invisible before because fastify's own types never loaded.)

Runtime import of all four packed packages from the consumer still works.

consumerTypes tests

New fixtures against the old source (skipLibCheck off):

package bundler NodeNext
core pass pass
express pass fail (TS2834 in dist, TS2578 unused @ts-expect-error)
fastify pass fail (same)
nextjs pass fail (same)

After the fix, all 8 pass.

arethetypeswrong (attw --pack --profile esm-only)

package node16 (from ESM) before after bundler
core OK OK OK
express Internal resolution error OK OK
fastify Internal resolution error OK OK
nextjs Internal resolution error OK OK

The remaining CJSResolvesToESM note is expected: the packages are ESM only.

Checks

  • pnpm build: passes
  • pnpm test: core 410, express 213, fastify 169, nextjs 168, all passing

No public API change; no cross-repo impact on seamless-auth-api or the SDKs.

The adapters compiled with moduleResolution bundler, so relative imports in
src had no extension and tsc copied them into the published .d.ts files.
Consumers on NodeNext or Node16 could not resolve them and every exported
function typed as any, hidden by skipLibCheck.

- Add explicit .js extensions to every relative import in express, fastify
  and nextjs, and compile those packages with NodeNext like core already
  does, so a missing extension fails the build with TS2835. The emitted
  JavaScript is byte-identical.
- Move @types/jsonwebtoken to core's dependencies, since core's public
  declarations import JwtPayload from jsonwebtoken.
- Run every package's consumerTypes test with skipLibCheck off under bundler
  and NodeNext, and assert real function types with @ts-expect-error on
  wrong calls, which fails if an export degrades to any. Add the test to
  core and nextjs.
- Refresh zod in the lockfile to 4.6.5. @seamless-auth/types 0.28.0
  declarations need the two-argument ZodPreprocess, which zod 4.4.3 lacks.

Closes #214
@Bccorb
Bccorb merged commit 8ff942d into main Oct 13, 2026
4 checks passed
@Bccorb
Bccorb deleted the fix/nodenext-declarations branch October 13, 2026 01:47
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.

Published .d.ts files use extensionless relative imports, so NodeNext consumers get any types

1 participant