PushHub JavaScript and TypeScript SDK

Release: 2.0.0-beta.1 source candidate

Runtime: Node.js 18+ or a modern fetch implementation

Security: client-safe installation credentials

The Phase Four client replaces embedded ph_live_ server keys with an app-bound publishable key and one rotatable credential per installation. The package currently builds and tests from source in this repository. It is not yet published to npm; use the release archive only after it appears in the verified PushHub downloads manifest.

Build from source

cd sdk/javascript
npm ci
npm test
npm run build

The build must produce dist/index.js, dist/index.cjs, dist/index.d.ts, and dist/index.d.cts. npm pack --dry-run verifies the public package contents.

Configure

Create a publishable key in Workspace → Apps → your app → Integrations. A publishable key begins with ph_pub_ and can be included in a client bundle. A privileged ph_live_ API key must remain on a trusted server.

import PushHubClient from 'pushhub-js'

const pushhub = new PushHubClient({
  appId: 'your-app-uuid',
  publishableKey: 'ph_pub_your_publishable_key',
  storage: secureStorage,
})

storage implements asynchronous getItem, setItem, and removeItem. Mobile and game clients must use Keychain, Keystore-backed, or equivalent encrypted storage. The default in-memory adapter is intended only for server processes and tests.

Register an installation

Ask for notification permission in your own product flow, obtain the current FCM or APNs token, then register it:

const installation = await pushhub.registerInstallation({
  deviceToken: providerToken,
  platform: 'Android', // or 'iOS'
  userId: currentUser?.id,
  metadata: {
    appVersion: '3.4.0',
    language: 'en',
  },
})

PushHub creates a five-minute, single-use challenge and exchanges it for an installation credential. The SDK stores the returned state through the configured storage adapter. Call registerInstallation again when the provider token rotates; PushHub rotates the installation credential without exposing a server key.

Identity and consent

await pushhub.identify('player-42', { level: 18 })
await pushhub.setConsent('Granted')

// On logout:
await pushhub.unlinkUser()

// When notification consent is withdrawn:
await pushhub.setConsent('Denied')

Denied consent deactivates the device for future targeting. Identification does not grant notification consent.

Track an event

await pushhub.trackEvent({
  name: 'level_up',
  properties: { level: '18', world: 'north-realm' },
  idempotencyKey: 'level-up-player-42-18',
})

Event properties are string values. Use a stable idempotency key for the same logical action.

Track receipt and open

PushHub notifications sent to an SDK installation contain pushhub_receipt_token. Do not construct or replace it.

await pushhub.trackReceipt(message.data.pushhub_receipt_token, 'received')
await pushhub.trackReceipt(message.data.pushhub_receipt_token, 'opened')
await pushhub.trackReceipt(message.data.pushhub_receipt_token, 'action', 'claim_reward')

The signed token binds the notification to one installation. “Provider accepted,” “received,” and “opened” remain separate outcomes.

Errors and retry

Methods reject with PushHubError, containing statusCode, optional code, and a retryable convenience property. HTTP 429 and 5xx failures are classified as retryable. Authentication and validation failures require configuration or input correction.

Do not create an unbounded retry loop. Native SDKs add the persistent bounded queue in Phase 4B; JavaScript hosts should use their platform's durable job mechanism.

API summary

Method Purpose
restore() Restore installation state from configured storage
registerInstallation(options) Bootstrap or recover one provider-token installation
updateInstallation(options) Refresh token, identity, attributes, consent, or SDK metadata
identify(userId, metadata?) Associate the installation with a customer user ID
unlinkUser() Remove that association on logout
setConsent(status) Store Unknown, Granted, or Denied
trackEvent(options) Submit an installation-bound event
trackReceipt(token, event, actionId?) Report signed receipt/open/action evidence
reset() Remove locally stored installation state

See the hosted OpenAPI reference for the exact /sdk contract. Direct server-to-server event and campaign operations continue to use scoped ph_live_ API keys.