
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
@notifyhub/node
Advanced tools
@notifyhub/node is the privileged server package for NotifyHub.
It is for trusted backend code only and is the package that should own your NotifyHub secret key.
It handles:
It also exposes a small @notifyhub/node/next helper for Next.js route handlers.
npm install @notifyhub/node
Use @notifyhub/node when you need to:
Do not use this package in browser bundles.
import {createNotifyHub} from '@notifyhub/node';
const notifyhub = createNotifyHub({
baseUrl: 'https://notifyhub.example.com',
secretKey: process.env.NOTIFYHUB_SECRET_KEY!,
});
await notifyhub.users.upsert({
id: 'user-123',
profile: {
email: 'user@example.com',
name: 'Taylor Example',
},
});
const session = await notifyhub.auth.issueSessionToken({
recipient: {id: 'user-123'},
expiresIn: '30m',
});
await notifyhub.notifications.send({
to: {
id: 'user-123',
profile: {
email: 'user@example.com',
name: 'Taylor Example',
},
},
title: 'Order shipped',
body: 'Your order is on the way.',
});
| Export | Description |
|---|---|
new NotifyHub(config) | Creates the server client directly |
createNotifyHub(config) | Factory helper |
NotifyHubNodeConfig| Field | Type | Required | Description |
|---|---|---|---|
baseUrl | string | yes | Base URL for the NotifyHub API |
secretKey | string | yes | Trusted server secret key |
fetch | typeof fetch | no | Fetch override for tests or custom runtimes |
notifyhub.authissueSessionToken(params)Issues a short-lived, recipient-scoped session token for browser clients.
| Field | Type | Required | Description |
|---|---|---|---|
recipient | NotifyHubRecipient | yes | Recipient identity used for the token |
expiresIn | number | string | no | Token lifetime such as 30m, 15m, or a millisecond value |
scopes | NotifyHubSessionScope[] | no | Explicit scope list |
Returns Promise<NotifyHubSession>.
Supported scopes:
inbox:readinbox:writepreferences:readpreferences:writenotifyhub.usersupsert(params)Upserts a recipient profile in NotifyHub.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Your application's canonical recipient ID |
profile | NotifyHubRecipientProfile | no | Optional profile fields to merge |
Returns Promise<UpsertUserResponse>.
notifyhub.notificationssend(params)Sends an inbox notification from trusted server code.
| Field | Type | Required | Description |
|---|---|---|---|
to | NotifyHubRecipient | yes | Recipient to target |
title | string | yes | Notification title |
body | string | yes | Notification body |
type | NotifyHubNotificationType | no | Visual notification type |
priority | NotifyHubNotificationPriority | no | Delivery priority |
data | Record<string, unknown> | no | Extra payload |
topicId | string | no | Topic association |
channels | string[] | no | Explicit channels, defaults to ['inbox'] |
Returns Promise<SendNotificationResponse>.
to.profile can be included during send() so the recipient can be upserted as part of the privileged send path.
The @notifyhub/node/next subpath exports createSessionRouteHandler() for App Router route handlers.
import {createNotifyHub} from '@notifyhub/node';
import {createSessionRouteHandler} from '@notifyhub/node/next';
const notifyhub = createNotifyHub({
baseUrl: process.env.NOTIFYHUB_BASE_URL!,
secretKey: process.env.NOTIFYHUB_SECRET_KEY!,
});
export const POST = createSessionRouteHandler({
notifyhub,
resolveRecipient: async (request) => {
const session = await getSignedInUserFromYourApp(request);
if (!session) {
return null;
}
return {
id: session.userId,
profile: {
email: session.email,
name: session.name,
},
};
},
getSessionOptions: async () => ({
expiresIn: '30m',
scopes: ['inbox:read', 'inbox:write', 'preferences:read', 'preferences:write'],
}),
});
createSessionRouteHandler(options)| Option | Type | Required | Description |
|---|---|---|---|
notifyhub | NotifyHub | yes | Configured server client |
resolveRecipient | (request) => NotifyHubRecipient | null | yes | Resolves the authenticated recipient from your app |
getSessionOptions | (request, recipient) => NotifyHubSessionHandlerOptions | null | undefined | no | Per-request token options |
onUnauthorized | (request) => Response | no | Custom unauthorized response |
The helper returns a handler that responds with a JSON NotifyHubSession on success and 401 on failure unless overridden.
NotifyHubNodeConfigNotifyHubSessionNotifyHubSessionScopeNotifyHubSessionHandlerOptionsNotifyHubApiErrorNotifyHubRecipientNotifyHubRecipientProfileNotifyHubUserUpsertUserParamsUpsertUserResponseIssueSessionTokenParamsSendNotificationParamsSendNotificationResponseNotifyHubNotificationTypeNotifyHubNotificationPriorityNotifyHubRecipientProfile supports these optional fields:
emailemailVerifiedphonephoneVerifiednamefirstNamelastNameavatarUrlcompanyjobTitlelocaletimezonetagscustomAttributessecretKey to a browser client.send() is intentionally server-only and is not part of @notifyhub/client.Error with a status property when the backend returns an HTTP error.From the monorepo root:
bun install
cd packages/node && bun run test
cd packages/node && bun run build
cd packages/node && bun run check-types
FAQs
Privileged server package for NotifyHub.
We found that @notifyhub/node demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.