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

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions