Skip to content

NestJS adapter (v1.2.0) crashes at load: untranspiled decorator on a class expression (SyntaxError under Node CJS/ESM) #87

Description

@nightlaro

Summary

@supabase/server/adapters/nestjs (v1.2.0) cannot be loaded under Node. The compiled adapter ships an untranspiled decorator applied to a class expression inside withSupabase(), which Node's module loader rejects with SyntaxError: Invalid or unexpected token. Both the CJS and ESM builds are affected.

The main entry (@supabase/server) and @supabase/server/core load fine — only the NestJS adapter is broken.

Environment

  • @supabase/server: 1.2.0
  • Node: v24.0.1 (also fails under Jest's CommonJS runtime)
  • NestJS: 11

Reproduction

$ node -e "require('@supabase/server/adapters/nestjs')"
/path/node_modules/@supabase/server/dist/adapters/nestjs/index.cjs:62
	@((0, _nestjs_common.Injectable)()) class SupabaseAuthGuard {
	^
SyntaxError: Invalid or unexpected token
    at wrapSafe (node:internal/modules/cjs/loader:1666:18)
    ...

For contrast, these load without error:

$ node -e "require('@supabase/server'); require('@supabase/server/core'); console.log('ok')"
ok

Root cause

dist/adapters/nestjs/index.cjs (and index.mjs) emits a decorator on a class expression returned from withSupabase():

function withSupabase(config) {
  @((0, _nestjs_common.Injectable)()) class SupabaseAuthGuard {
    async canActivate(executionContext) { /* ... */ }
  }
  return SupabaseAuthGuard;
}

Decorators-on-class-expressions are not valid in current V8/Node, so the file fails to parse at load time. (Legacy TypeScript experimentalDecorators also does not support decorators on class expressions, so consumers can't transpile around it from their own tsconfig either.)

Impact

The NestJS adapter is unusable in a standard NestJS-on-Node (CommonJS) application — it throws at import/require before any handler runs.

Suggested fix

Transpile the decorator in the published build, e.g. emit Injectable()(SupabaseAuthGuard) after a plain class declaration rather than @Injectable() class { ... } on an expression, or lower decorators to a syntax all supported runtimes accept.

Workaround (for anyone hitting this)

Rebuild the two adapter exports locally on top of createSupabaseContext (which loads fine):

import { Injectable, createParamDecorator, HttpException } from '@nestjs/common';
import { createSupabaseContext, type SupabaseContext } from '@supabase/server';

@Injectable()
export class SupabaseUserGuard /* implements CanActivate */ {
  async canActivate(ctx) {
    const req = ctx.switchToHttp().getRequest();
    const { data, error } = await createSupabaseContext(toWebRequest(req), { auth: 'user' });
    if (error) throw new HttpException({ message: error.message, code: error.code }, error.status, { cause: error });
    req.supabaseContext = data;
    return true;
  }
}

export const SupabaseCtx = createParamDecorator((key, ctx) => {
  const c = ctx.switchToHttp().getRequest().supabaseContext;
  return key ? c?.[key] : c;
});

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions