/** * push/subscription-validation.ts * * The ONE place a push subscription's endpoint and key material are judged * well-formed. Two callers share it and must never disagree: * * - Registration (`routes/push.ts`, `routes/pairing-handoff.ts`, * `PushSubscriptionStore.reconcile`), junk is refused with a plain reason at * the moment it is offered, so a record that could never receive a push is * never written to disk in the first place. * - Delivery (`push/encryption.ts`), the same predicates, with the same * wording, guard the encryption path. * * Sharing the predicates is the point: before this module, registration checked * only that the strings were non-empty while delivery checked the byte lengths, * so `p256dh: "not-base64!!!!"` was accepted at 200 and only failed weeks later * as a delivery error. The two now fail on exactly the same inputs with exactly * the same message. */ /** RFC 8291: the receiver's public key is an uncompressed P-256 point. */ export declare const P256DH_POINT_BYTES = 65; /** RFC 8291: the receiver's authentication secret is 16 bytes. */ export declare const AUTH_SECRET_BYTES = 16; /** * Upper bound on a stored endpoint. Real push endpoints (FCM, Mozilla, WNS) are * a few hundred characters; anything past this is not an endpoint the daemon * should be persisting, and an unbounded one is a way to grow the store on disk * without registering anything usable. */ export declare const MAX_PUSH_ENDPOINT_LENGTH = 2048; /** * The delivery path's wording, kept verbatim so registration and delivery * report the same failure in the same words. */ export declare const P256DH_INVALID_MESSAGE = "Push subscription p256dh key is not a 65-byte uncompressed P-256 point"; export declare const AUTH_SECRET_INVALID_MESSAGE = "Push subscription auth secret is not 16 bytes"; /** The field a validation problem belongs to, as the caller names it on the wire. */ export type PushSubscriptionField = 'endpoint' | 'keys.p256dh' | 'keys.auth'; /** A refused subscription: which field, and why, in plain language. */ export interface PushSubscriptionProblem { readonly field: PushSubscriptionField; readonly reason: string; } /** Thrown when a subscription is offered for storage with unusable content. */ export declare class PushSubscriptionValidationError extends Error { readonly field: PushSubscriptionField; constructor(problem: PushSubscriptionProblem); } /** Why this p256dh cannot be used, or null when it is a valid point. */ export declare function describeP256dhProblem(value: unknown): string | null; /** Why this auth secret cannot be used, or null when it is 16 bytes. */ export declare function describeAuthSecretProblem(value: unknown): string | null; /** Why this endpoint cannot be used, or null when it is a bounded http(s) URL. */ export declare function describeEndpointProblem(value: unknown): string | null; /** The structural slice validated, the wire shape of a subscription offer. */ export interface PushSubscriptionCandidate { readonly endpoint: unknown; readonly keys?: { readonly p256dh?: unknown; readonly auth?: unknown; } | undefined; } /** * The first problem with a candidate subscription, or null when every field is * usable. Endpoint first, then the key material, so the caller reports the most * structural failure rather than a downstream one. */ export declare function describeSubscriptionProblem(candidate: PushSubscriptionCandidate): PushSubscriptionProblem | null; /** Throwing form of {@link describeSubscriptionProblem}. */ export declare function assertUsableSubscription(candidate: PushSubscriptionCandidate): void; //# sourceMappingURL=subscription-validation.d.ts.map