/** Sandbox default: the app's `aps-environment` is still `development`. */ export declare const APNS_HOST_SANDBOX = "api.sandbox.push.apple.com"; export declare const APNS_HOST_PRODUCTION = "api.push.apple.com"; /** * APNs rejects a payload over 4 KB. * * Checked before sending rather than after a rejection, so an oversized payload * is a diagnosable local error instead of an opaque 413 from Apple. */ export declare const APNS_MAX_PAYLOAD_BYTES = 4096; export interface ApnsCredentials { /** p8 PEM contents. Never a filesystem path. */ key: string; keyId: string; teamId: string; bundleId: string; host: string; } export interface ApnsSendResult { ok: boolean; status: number; /** APNs `reason`, e.g. `BadDeviceToken` / `ExpiredToken`. */ reason?: string; /** * True when APNs says this token will never work again. The caller must stop * using it rather than retrying — retrying a dead token fails forever and * makes the health report read "failing" instead of "this device is gone". */ tokenDead: boolean; } /** * Read APNs credentials from the environment. * * Returns null when `APNS_KEY` is absent, which is the normal case for a * developer machine and for CI. Callers treat null as "Live Activity push is * off" and skip sending — the server must not fail to boot because an optional * push credential is missing. * * Every identifier comes from the environment with no default. Baking one * deployment's Apple account into the source would make this package silently * sign for the wrong team when someone else deploys it, and the resulting APNs * rejection names none of that. Only the host has a default, because sandbox * versus production is a deployment choice rather than an account identity. * * Returns null (rather than throwing) when the key is present but an identifier * is missing, so a half-configured environment disables the feature instead of * taking the server down. `describeMissingApnsCredentials` explains which one. */ export declare function readApnsCredentialsFromEnv(env?: NodeJS.ProcessEnv): ApnsCredentials | null; /** * Why Live Activity push is unavailable, as a message safe to log. * * Says which variable is missing and nothing about its value, so a boot log can * explain the feature being off without becoming a place secrets leak. */ export declare function describeMissingApnsCredentials(env?: NodeJS.ProcessEnv): string | null; export declare class ApnsClient { private readonly creds; private session; private cachedJwt; constructor(creds: ApnsCredentials); /** * The `apns-topic` for Live Activity pushes. * * The `.push-type.liveactivity` suffix is mandatory and is why the signing key * must be Team Scoped (All Topics) — a key scoped to the bundle id alone * cannot sign this topic. */ get topic(): string; /** * Mint or reuse the provider JWT. * * ES256 over the p8 key. Cached until shortly before expiry: Apple rejects a * token older than an hour, but minting one per request is wasteful and can * trip APNs' provider-token-update throttle. */ private getJwt; /** * Reuse one HTTP/2 session across sends. * * APNs expects a long-lived connection; a fresh TLS handshake per push is slow * and Apple treats connection churn as abuse. */ private getSession; /** * Send one push. * * Resolves with a result rather than rejecting on an APNs rejection: a * rejected push is an expected outcome the caller must act on (retire the * token), not an exception. Only a genuinely unexpected local failure throws, * and the caller logs it. */ send(args: { deviceToken: string; payload: unknown; /** 10 for a user-visible change, 5 to let iOS batch. */ priority?: 5 | 10; /** Seconds since epoch after which APNs stops trying. */ expirationSeconds?: number; timeoutMs?: number; }): Promise; /** Close the shared connection. Called on server shutdown. */ close(): void; } //# sourceMappingURL=apnsClient.d.ts.map