Skip to content

@gj-kit/toss-payments-nestjs

A DI token carries no type — TossPaymentsFor<typeof config> gives it back, so unwired flows stay compile errors.

  • npm 0.4.5
  • 0 runtime dependencies
  • 9 rejections pinned by @ts-expect-error
  • Nest 10 and 11 boot-verified
  • 20 unit tests, 8 boot real Nest DI

A DI token carries no type: forRoot() returns a DynamicModule bound to a unique symbol, so the constructor annotation you wrote is the only remaining truth — toss.billing type-checks on a kit whose config never wired a BillingKeyStore, and the property is undefined at runtime. Then you add a webhook controller and Nest has already parsed the body: signature verification cannot be recovered from re-serialized JSON.

  • Unwired flows have no property — TossPaymentsFor<typeof config> rebuilds the conditional kit type after DI, so toss.billing is a compile error without a wired BillingKeyStore.
  • Missing rawBody fails loudly — Without req.rawBody, toNestWebhookHandler never calls a handler: it answers 500 and logs the three settings to check — rawBody: true on NestFactory.create, Fastify raw-body support, and a JSON middleware applied ahead of the webhook route.
  • Source IP survives the wrapper — The handler forwards the original Node socket, keeping the core’s fail-closed IP check; trusting a proxy header requires passing an explicit sourceIp extractor.
  • One token across ESM and CJS — TOSS_PAYMENTS and getTossPaymentsToken(name) are Symbol.for lookups, so a dual-loaded package still resolves to one provider binding.
  • No emitDecoratorMetadata needed — InjectTossPayments() is a thin @Inject(token) delegate and no code under src/ reads design:paramtypes, so the package ships emitDecoratorMetadata: false — and the Nest DI tests still resolve under vitest’s esbuild transform, which cannot emit that metadata at all.

Outcome: One Nest provider that injects a typed payment kit.

Terminal window
pnpm add @gj-kit/toss-payments-nestjs

Build the core payment config, register it once, and preserve raw request bytes for webhook routes.

Copy this first, then replace only the app-owned values named above.

import { orThrow } from '@gj-kit/toss-payments';
import { defineTossPaymentsConfig, parseApiSecretKey } from '@gj-kit/toss-payments/server';
import { TossPaymentsModule } from '@gj-kit/toss-payments-nestjs';
declare const apiSecretFromEnv: string; // Read this once from your server environment.
const config = defineTossPaymentsConfig({
secretKey: orThrow(parseApiSecretKey(apiSecretFromEnv)),
});
export const payments = TossPaymentsModule.forRoot(config);

The commented line is a real TS2339: this config wired no BillingKeyStore, so the injected kit has no billing property at all — even though the value arrived through an untyped DI token.

import { Injectable } from '@nestjs/common';
import { orThrow } from '@gj-kit/toss-payments';
import { defineTossPaymentsConfig, parseApiSecretKey, type OrderStore } from '@gj-kit/toss-payments/server';
import { InjectTossPayments, TossPaymentsModule, type TossPaymentsFor } from '@gj-kit/toss-payments-nestjs';
declare const SECRET: string; // the app owns this (process.env)
declare const orders: OrderStore; // the app owns this (its own DB adapter)
export const tossConfig = defineTossPaymentsConfig({ secretKey: orThrow(parseApiSecretKey(SECRET)), orders });
export type AppToss = TossPaymentsFor<typeof tossConfig>;
export const tossModule = TossPaymentsModule.forRoot(tossConfig);
@Injectable()
export class PaymentsService {
constructor(@InjectTossPayments() private readonly toss: AppToss) {}
order = () => this.toss.confirm.createOrder({ amount: 9_900, orderName: 'Pro' });
// this.toss.billing — TS2339: the config wired no BillingKeyStore, so there is no property.
}

Use it when a Nest application needs to keep the core payment kit’s types and safety boundary through dependency injection.

Do not reimplement payment verification in controllers or rely on parsed JSON when webhook verification requires raw bytes.

Engines: node >=20

Peer Supported range Required for
@gj-kit/toss-payments `^0.2.0
@nestjs/common `^10
reflect-metadata `^0.1.13
rxjs ^7 the package integration
Entry Exported symbols
Root entry 14

Preserve raw request bytes for verified webhooks and make every store dependency explicit in the host Nest module.

complete API reference contains every public function, class, type, constant, and error contract generated from release declarations. Each item shows its import path, release signature, and package version.

Relationship Package Why combine them
Required @gj-kit/toss-payments This package implements or consumes its public contract.
Optional companion @gj-kit/toss-payments-postgresql Supply PostgreSQL-backed core stores to the Nest module when the host chooses PostgreSQL.

npm · GitHub