Push

Push lets an application's backend send a notification to its users' phones and tablets. Turn Zero Cloud delivers it to iPhones through Apple and to Android devices through Google. The backend lists the users or the devices, and the platform finds each device the app registered.

The package provides your backend's side of that service. Its client sends one message under the application's platform credential. It reports what the send accepted, and it throws a typed refusal that gives the platform's refusal name.

Use it when

Use Push when the backend must tell a signed-in user something while the app is closed: a game ended, an order shipped, a turn is waiting. The app must sign its users in through the application's realm and register each device after sign-in. Send push notifications covers the credentials, the declaration, the device registration, and the send route.

Do not use it for a web page in a browser or for a text message. Neither is offered.

What it provides

  • A client. createPushClient({ api, token }) builds a client from the platform's origin and the application's platform credential. An application whose calls already share one transport function of its own passes that instead, as createPushClient({ transport }).
  • A send to users. send(users, message) sends one message to every registered device of the named users. The user identifier is the one the realm returns for the signed-in user.
  • A send to devices. sendToDevices(installations, message) sends one message to the named installations, the identifiers the app registered its devices under.
  • The response. Each send returns messageId, the accepted count of deliveries queued, and the unknownUsers or unknownDevices that had no registration.
  • A typed refusal. Every other response throws a PushRefusal. Its refusal member is the platform's refusal name, and members contains the refusal's other values.
Message member Required What it contains
notification.title Yes Up to 256 characters.
notification.body Yes Up to 4,000 characters.
notification.badge No The count on the app's icon.
notification.sound No A sound the app bundles, or default.
data No String values for the app, under 4 kilobytes.
ttlSeconds No How long an offline device's notification is kept, a day by default.
collapseId No A key under which a newer notification replaces an older one.
priority No high by default, or normal.

The module is published as the npm package @turnzero/push. Use the library shows how to copy it into app/lib/push/, declare it as file:lib/push, and install it with npm install. The module imports nothing, reads no environment variable, starts no timer, and keeps no state.

No test checks this sample. It builds the client from the two values the deploy injects and sends to one user:

import { createPushClient, PushRefusal } from '@turnzero/push';

const push = createPushClient({ api: process.env.TURNZERO_CLOUD_API, token: process.env.TURNZERO_CLOUD_TOKEN });
const sent = await push.send([userId], { notification: { title: 'Game over', body: 'You stumped it.' } });

A test double ships at the package's testing subpath, @turnzero/push/testing. createPushDouble responds to a send as the platform does, from devices and a monthly quota the test gives it, and records every send. Test your application locally shows the doubles in use.

Availability

Version 0.2.2 is the package's current version, and list_library reports the version the platform currently publishes. The entry includes the testing subpath from version 0.1.0. The entry contains the package's product statement, its detailed contract, its integration guide, and the compiled modules.

Turn Zero Cloud runs the push service. A delivery pass sends each accepted delivery to its provider within seconds, retries a transient failure, and marks a device its provider reports gone. read_push returns the device counts, the last hour's outcomes, and the month's count beside the plan's allowance.

Account signs users in and tells the backend who they are. Secrets stores the Apple key and the Google service-account file by name. Logging records the delivery counters and one line per delivery.

Refusals

Branch on the refusal's name, never on its message.

Refusal Status Meaning
invalid_request 400 A member of the message is malformed, and the detail identifies it; or a member contains a NUL character (U+0000) or an unpaired UTF-16 surrogate, which the detail identifies instead.
end_user_credential_not_admitted 403 The send ran under an end-user session, refused ahead of the route's own check.
platform_credential_required 403 The send ran under a session or a minted token.
push_not_configured 409 The environment has no provider configured.
realm_not_declared 404 The application declares no accounts service.
usage_over_quota 429 The send would pass the plan's monthly push allowance.

A send refused usage_over_quota queued nothing. Its members give the month's count, the allowance, and the send's own deliveries.

What an application must do

Declare the push service and the accounts service in the manifest, store both providers' credentials, and call configure_push for each environment the application has. Register each device from the app after sign-in, and register it again when the platform gives the app a new token.

Send once for each event. The client retries nothing, because a send the platform accepted before its response was lost is already queued. Give a message a collapseId where a repeat must replace the earlier notification rather than add one.

Keep a refused send from failing the request that made it. Record the refusal, and respond to the request.