Profiles·Public

pusher

semver^5.0.0postconditions8functions6last verified2026-06-24coverage score100%

Postconditions: what we check

  • trigger · api-error
    error
    WhenAny API or network failure: authentication error (401/403), rate limit (429), invalid app configuration (400), server error (5xx), network timeout, or connection failure
    ThrowsPusher.RequestError with properties: status (HTTP code or undefined for network), error (underlying Error for network failures), body (API response text), url (request URL). Common cases: 403 for bad credentials, 429 for rate limit, 5xx for Pusher outage.
    Required handlingCaller MUST wrap in try-catch. pusher.trigger() rejects on all API and network failures — there is no auto-retry. Unhandled rejections crash Node.js workers or produce silent data loss in async route handlers. Minimum handling: try { await pusher.trigger(channel, event, data); } catch (err) { if (err instanceof Pusher.RequestError) { console.error('Pusher trigger failed:', err.status, err.body); } throw err; } For fire-and-forget patterns (where trigger is a side effect), at minimum log the error rather than silently dropping it: pusher.trigger(channel, event, data).catch(err => console.error('Pusher failed:', err));
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[1]
  • trigger · trigger-encrypted-multi-channel-error
    error
    WhenCalling trigger() with an array of channels where any channel name starts with `private-encrypted-` (E2E encrypted channel) and channels.length > 1. Encrypted channels can only be triggered one at a time.
    ThrowsPlain Error: "You cannot trigger to multiple channels when using encrypted channels". Thrown synchronously inside the returned Promise body before any HTTP request — a try-catch around `await pusher.trigger(...)` catches it as a rejected Promise.
    Required handlingCaller MUST handle this error path when triggering across multiple channels with mixed channel types. Either pre-filter encrypted channels and call trigger() per channel for those, or document the constraint in the calling layer. try { await pusher.trigger(channels, event, data); } catch (err) { if (err.message.includes('encrypted channels')) { for (const ch of channels) { await pusher.trigger(ch, event, data); } } throw err; } Bypassing this error means the original event silently never sends — a real-time data loss bug masked as a rejected Promise.
    costmediumin prodimmediate exceptionusers seelost datavisibilitysilent
    Sources[2][3]
  • trigger · trigger-encryption-master-key-missing
    error
    WhenCalling trigger() on a `private-encrypted-` channel when the Pusher client was constructed without `encryptionMasterKeyBase64`. The library has no fallback — E2E encryption requires a master key, and absence is treated as a programming error.
    ThrowsPlain Error: "Set encryptionMasterKey before triggering events on encrypted channels". Thrown synchronously from encrypt() during the trigger() call body. Rejects the returned Promise — visible to a try-catch around `await pusher.trigger(...)`.
    Required handlingCaller MUST configure encryptionMasterKeyBase64 in the Pusher() constructor when any encrypted channel will be triggered. This is a setup-time invariant — failing here means the entire encrypted-channel feature is broken at runtime. const pusher = new Pusher({ appId, key, secret, cluster, encryptionMasterKeyBase64: process.env.PUSHER_ENCRYPTION_KEY, }); try { await pusher.trigger('private-encrypted-room', 'msg', payload); } catch (err) { if (err.message.includes('encryptionMasterKey')) { console.error('Pusher encrypted-channel setup error — check config'); } throw err; } Without handling, encrypted-channel events silently fail every time, leaving end-to-end encrypted UX broken across the entire deployment.
    costhighin prodimmediate exceptionusers seelost datavisibilitysilent
    Sources[4][5]
  • triggerBatch · api-error
    error
    WhenAny API or network failure, including rate limit (429), auth error, server error, or network failure. Batch max of 10 events — exceeding it throws before any network call.
    ThrowsPusher.RequestError (same as trigger) for API/network failures. Plain Error for exceeding batch size limit or invalid event structure.
    Required handlingCaller MUST wrap in try-catch. A batch failure means ALL events in the batch were not delivered — callers should handle this atomically. try { await pusher.triggerBatch(events); } catch (err) { if (err instanceof Pusher.RequestError) { // All events failed — consider retry or fallback } throw err; }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[6]
  • sendToUser · api-error
    error
    WhenAny API or network failure: invalid user ID format, auth error, server error, network failure, or rate limit
    ThrowsPusher.RequestError for API/network failures. Plain Error for invalid userId (empty string, non-string value).
    Required handlingCaller MUST wrap in try-catch. User notification failures should be handled gracefully — the primary action (DB write) may have succeeded even if the real-time notification fails. try { await pusher.sendToUser(userId, event, data); } catch (err) { if (err instanceof Pusher.RequestError) { console.error('Failed to notify user:', userId, err.status); } // Don't re-throw if notification failure should not abort the operation }
    costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[7]
  • terminateUserConnections · terminate-api-error
    error
    WhenAny API or network failure: authentication error (401/403 from Pusher API), server error (5xx), network timeout, or connection failure. Also throws synchronous plain Error for empty or non-string userId before any HTTP call.
    ThrowsPusher.RequestError for API/network failures (status, body, url properties). Plain Error ("Invalid user id: '...'") for empty string or non-string userId — thrown synchronously before any network request.
    Required handlingCaller MUST wrap in try-catch. terminateUserConnections() is typically called in ban/kick flows after a DB write. If the call fails (Pusher outage, auth error), the user may remain connected despite being banned in the database — a security gap. try { await pusher.terminateUserConnections(userId); } catch (err) { if (err instanceof Pusher.RequestError) { // Log and consider queuing for retry — user may still be connected console.error('Failed to terminate connections for', userId, err.status); await scheduleRetry(userId); } throw err; } Important: terminateUserConnections() disconnects existing sessions but does NOT prevent reconnection. Pair with blocking the user's authentication endpoint.
    costhighin prodimmediate exceptionusers seesecurity breachvisibilitysilent
    Sources[8][9]
  • get · get-api-error
    error
    WhenAny API or network failure: authentication error (401), forbidden (403, app disabled or quota exceeded), bad request (400, e.g. requesting user_count on non-presence channel), server error (5xx), or network failure/timeout.
    ThrowsPusher.RequestError with status (HTTP code), body (API error text), url (request URL). Plain Error thrown synchronously if reserved param keys (auth_key, auth_timestamp, auth_version, auth_signature, body_md5) are included in params — throws before any network request.
    Required handlingCaller MUST wrap in try-catch. get() is typically used to fetch presence channel data or verify channel state before performing an action. A 400 from requesting user_count on a non-presence channel is a programming error; 401/403 indicate misconfigured credentials. try { const response = await pusher.get({ path: '/channels', params: { filter_by_prefix: 'presence-', info: 'user_count' } }); if (response.status === 200) { const body = await response.json(); // use body.channels } } catch (err) { if (err instanceof Pusher.RequestError) { if (err.status === 400) { // Invalid params — likely programming error (e.g., user_count on public channel) } console.error('Pusher GET failed:', err.status, err.body); } throw err; }
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[10][11]
  • post · post-api-error
    warning
    WhenAny API or network failure: authentication error (401/403), bad request (400), payload too large (413, event data exceeds 10KB limit), server error (5xx), or network failure. Throws synchronously for reserved param keys in params.
    ThrowsPusher.RequestError for all HTTP 4xx/5xx responses and network errors. Plain Error synchronously for reserved params (auth_key, auth_timestamp, etc.) before any network call. Note: HTTP 413 is returned when event data exceeds the 10KB Pusher payload limit — relevant when posting custom event payloads.
    Required handlingCaller MUST wrap in try-catch. post() is most commonly called indirectly via terminateUserConnections() — see that function's error handling guidance. If calling post() directly, validate path correctness and payload size first. try { const response = await pusher.post({ path: '/events', body: JSON.stringify(payload) }); } catch (err) { if (err instanceof Pusher.RequestError) { if (err.status === 413) { // Payload too large — split or compress } console.error('Pusher POST failed:', err.status, err.body); } throw err; }
    costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
    Sources[12][11]

Sources

Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.

Official documentation
Source code

Research notes

Curator notes from SOURCES.md captured when the profile was written so you can verify the reasoning, not just the rules.

Sources: pusher

Behavioral claims in contract.yaml are derived from the following sources.

Primary Sources

Official Library (GitHub README)

URL: https://github.com/pusher/pusher-http-node

The primary API reference for the pusher Node.js server library. Documents:

  • All method signatures (trigger, triggerBatch, sendToUser, get, authorizeChannel, authenticateUser)
  • Error handling section: RequestError class with status, error, body, url properties
  • Promise-based API (v4+ — callbacks removed)
  • Event format and channel constraints (max 100 channels per trigger, max 10 events per triggerBatch)

Postconditions supported:

  • trigger: api-error — "pusher.trigger will reject the promise with a Pusher.RequestError if the API returns an error status code or there is a network failure"
  • triggerBatch: api-error — same error surface as trigger
  • sendToUser: api-error — same error surface

Pusher REST API Reference

URL: https://pusher.com/docs/channels/library_auth_reference/rest-api/

Documents the underlying HTTP API that the Node.js library wraps. Defines error status codes:

  • 400 Bad Request — validation errors (invalid channel name, event name too long)
  • 401 Unauthorized — invalid app credentials
  • 403 Forbidden — not authorized for this operation
  • 413 Entity Too Large — message body too large
  • 429 Too Many Requests — rate limit exceeded

Pusher Channel Types

URL: https://pusher.com/docs/channels/using_channels/channel-types/

Documents public, private (private-), presence (presence-), and encrypted (private-encrypted-) channels. Relevant for understanding what trigger and sendToUser operate on.

Pusher User Authentication

URL: https://pusher.com/docs/channels/server_api/authenticating-users/

Documents the authenticateUser and sendToUser API for user-bound messaging. sendToUser requires clients to have authenticated via pusher-js signin().

Version History Sources

v5.3.2 Release Notes

URL: https://github.com/pusher/pusher-http-node/releases/tag/v5.3.2

"Fixed missing error types for TypeScript support" — RequestError and WebHookError now properly exported as named TypeScript types (previously not exported).

v5.0.0 Migration

URL: https://github.com/pusher/pusher-http-node/blob/master/CHANGELOG.md

Breaking change: trigger(channel, event, data, socketId)trigger(channel, event, data, { socket_id }). The 4th positional string argument for socket_id exclusion became a params object.

v4.0.0 Migration (Callbacks → Promises)

Documented in CHANGELOG: removed callback-based API, all async methods now return Promises. RequestError.statusCode renamed to RequestError.status.

Real-World Evidence

No real-world TPs confirmed yet — evidence_quality: stub.

TODO: Search GitHub for TypeScript SaaS repos using pusher and confirm TRUE_POSITIVE violations in production code to upgrade evidence_quality to partial or confirmed.

Need a different package?
Request a profile