Node.js SDK

The norq npm package provides a TypeScript SDK for sending and linting notification templates from Node.js applications.

Install

npm install @suprsend/norq

The package includes the norq binary for your platform (via optional dependencies for each OS/architecture).

Quick start

import { Norq } from "@suprsend/norq";
 
const notif = new Norq();
 
// Send a notification
const result = await notif.send("transactional/order-shipped", {
  to: { email: "gaurav@example.com", phone: "+1234567890" },
  data: { user: { first_name: "Gaurav" }, order: { id: "ORD-123" } },
});

Constructor options

const notif = new Norq({
  config: "./path/to/norq.config.yaml",  // config file path
  binaryPath: "/usr/local/bin/norq",     // explicit binary path
  cwd: "/path/to/project",                  // working directory
  logger: myLogger,                         // structured logger
  recipientResolver: myResolver,            // user ID -> Recipient
});
Option Type Description
config string Path to norq.config.yaml
binaryPath string Explicit path to the norq binary
cwd string Working directory (defaults to process.cwd())
logger Logger Structured logger for send/compile events
recipientResolver RecipientResolver Resolves user ID strings to Recipient objects

API

send(id, opts)

Compile and deliver a notification.

const result = await notif.send("transactional/welcome", {
  to: { email: "user@example.com" },           // Recipient object
  // or: to: "user-123",                       // user ID (requires recipientResolver)
  data: { user: { first_name: "Gaurav" } },
  channels: ["email"],                          // optional: send only these channels
  dryRun: false,                                // optional: compile without sending
});
 
// result.results   -> SendResult[] (one per channel)
// result.skipped   -> SkippedChannel[] (channels that were skipped and why)

lint(id?)

Lint notification templates.

const results = await notif.lint();              // all notifications
const results = await notif.lint("transactional/welcome");     // one notification
 
for (const result of results) {
  for (const diag of result.diagnostics) {
    console.log(`${diag.severity}: ${diag.message} [${diag.rule}]`);
  }
}

Recipient

const recipient: Recipient = {
  email: "user@example.com",
  phone: "+1234567890",
  slack: { channel_id: "C01234567" },
  push: {
    tokens: [
      { token: "fcm-token-here", platform: "android" },
      { token: "apns-token-here", platform: "ios" },
    ],
  },
  whatsapp: { phone: "+1234567890" },
  msteams: { webhook_url: "https://..." },
};

The SDK intersects available channels (notification templates vs. recipient contact info) and silently skips unreachable channels, reporting skip reasons in result.skipped.

RecipientResolver

To send by user ID, implement a RecipientResolver:

const notif = new Norq({
  recipientResolver: {
    async resolve(userId: string): Promise<Recipient> {
      const user = await db.users.findById(userId);
      return {
        email: user.email,
        phone: user.phone,
      };
    },
  },
});
 
await notif.send("transactional/welcome", { to: "user-123", data: { ... } });

Logger

const notif = new Norq({
  logger: {
    info(msg, meta) { console.log(msg, meta); },
    warn(msg, meta) { console.warn(msg, meta); },
    error(msg, meta) { console.error(msg, meta); },
  },
});

The SDK logs compile and send events with timing, channel, and provider metadata.

Payload types

interface EmailPayload {
  subject: string;
  html: string;
  text: string;
}
 
interface SmsPayload {
  body: string;
  segments: number;
  encoding: string;       // "gsm7" or "ucs2"
}
 
interface SlackPayload {
  blocks: unknown[];
  text: string;
}
 
interface PushPayload {
  title: string;
  body: string;
  image: string | null;
  action_url: string | null;
  platforms: string[];
}
 
interface WhatsAppPayload {
  type: string;
  payload: unknown;
}
 
interface TeamsPayload {
  card: unknown;
}

Error handling

import { NorqError } from "@suprsend/norq";
 
try {
  await notif.send("transactional/welcome", { to: "user-123", data: { ... } });
} catch (err) {
  if (err instanceof NorqError) {
    console.error("Norq error:", err.message);
  }
}

Codegen

Generate typed bindings for compile-time type safety:

norq codegen --lang typescript --out src/generated/norq.ts

This generates typed interfaces for each notification's data shape and channel availability.