/** * Everything Apple requires of a pass, in one file, with a citation per rule. * * This is the substitute for a device. Nothing here can be proved by installing * a pass on a phone we do not have, so the rules the phone would apply are * written down and applied first — which catches the same failures earlier and * for every pass rather than for one. * * **Two obligations come with that.** * * The first is the citation. Every rule names the published requirement it * encodes, so a reader can check it rather than trust it, and a rule nobody can * source is a rule somebody invented. * * The second is {@link RULES_REVIEWED}. Apple and Google change wallet * requirements without much notice, and the usual defence is a canary that * installs a real pass daily and fails when they do. There is no canary here, so * the defence is weaker and is written down as weaker: a human reads the current * requirements on a schedule and this file changes when they have. It is the * plan's own weakest mitigation, and it is listed as such there too. */ /** * When the rules below were last read against Apple's published documentation. * * Bumped **only** by somebody who has actually re-read them. The renewal * runbook carries the obligation and the calendar carries the date, because * software that reminds itself is software that stops reminding itself the day * it breaks. */ export declare const RULES_REVIEWED = "2026-09-17"; /** Where a rule comes from. */ export interface Citation { /** The document, named as a reader would search for it. */ source: string; /** Anything a reader needs that the source does not say plainly. */ note?: string; } export interface Rule { id: string; citation: Citation; } /** The rules, as data, so a README and a test can both enumerate them. */ export declare const RULES: { readonly formatVersion: { readonly id: "format-version"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Pass (pass.json top-level keys)"; readonly note: "formatVersion is 1 and there has never been another."; }; }; readonly requiredKeys: { readonly id: "required-keys"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Pass (pass.json top-level keys)"; readonly note: "description, formatVersion, organizationName, passTypeIdentifier, serialNumber and teamIdentifier are all required."; }; }; readonly singleStyle: { readonly id: "single-style"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Pass (pass.json top-level keys)"; readonly note: "Exactly one of boardingPass, coupon, eventTicket, generic or storeCard."; }; }; readonly colourSyntax: { readonly id: "colour-syntax"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Pass (pass.json top-level keys)"; readonly note: "Colours are a CSS-style RGB triple, e.g. rgb(23, 187, 82). Written from a typed triple here so the string cannot be malformed; the check guards a hand-edited pass.json."; }; }; readonly fieldKeysUnique: { readonly id: "field-keys-unique"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: PassFieldContent"; readonly note: "A field key must be unique within the pass. Duplicates make the device diff the wrong field on update."; }; }; readonly changeMessagePlaceholder: { readonly id: "change-message-placeholder"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: PassFieldContent"; readonly note: "changeMessage must contain %@, where the new value is substituted. Without it the message is never shown — silently."; }; }; readonly fieldCounts: { readonly id: "field-counts"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Pass Design and Creation (layout per style)"; readonly note: "Apple truncates rather than refuses, so this is our rule enforced against their layout: a field that is silently dropped is worse than a build that fails."; }; }; readonly barcodeFormat: { readonly id: "barcode-format"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Pass.Barcodes"; readonly note: "PKBarcodeFormatQR, PKBarcodeFormatPDF417, PKBarcodeFormatAztec or PKBarcodeFormatCode128. Only the plural `barcodes` key is written: the singular `barcode` has been superseded since iOS 9."; }; }; readonly barcodeEncodable: { readonly id: "barcode-encodable"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Pass.Barcodes"; readonly note: "The message must be representable in messageEncoding. Defaulting to iso-8859-1 and then putting a non-Latin-1 character in it produces a barcode no scanner reads."; }; }; readonly locationCount: { readonly id: "location-count"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Pass.Locations"; readonly note: "At most ten locations per pass."; }; }; readonly locationRange: { readonly id: "location-range"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Pass.Locations"; readonly note: "Latitude -90..90, longitude -180..180. A transposed pair is a valid-looking pass that surfaces in the sea."; }; }; readonly webServiceHttps: { readonly id: "web-service-https"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Adding a Web Service to Update Passes"; readonly note: "webServiceURL must be HTTPS, and is required whenever authenticationToken is present. Neither is useful alone."; }; }; readonly authenticationTokenLength: { readonly id: "authentication-token-length"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Adding a Web Service to Update Passes"; readonly note: "At least sixteen characters. It is a per-pass secret, so the floor is a minimum rather than a target."; }; }; readonly iconRequired: { readonly id: "icon-required"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Pass Design and Creation (image sizes)"; readonly note: "icon.png is required. A pass without one installs and then shows nothing in notifications."; }; }; readonly styleAssets: { readonly id: "style-assets"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Pass Design and Creation (image sizes)"; readonly note: "A storeCard and a coupon draw their band from strip.png; an eventTicket uses a background or a thumbnail. Our rule: a style is given the image its layout is built around."; }; }; readonly densityMultiples: { readonly id: "density-multiples"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Pass Design and Creation (image sizes)"; readonly note: "@2x and @3x are exactly two and three times the base in both dimensions. Apple scales what it is given, so a mismatch is a blurred image rather than an error."; }; }; readonly pngOnly: { readonly id: "png-only"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Pass Design and Creation (image sizes)"; readonly note: "Pass images are PNG."; }; }; readonly manifestCoversArchive: { readonly id: "manifest-covers-archive"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Building a Pass (manifest and signature)"; readonly note: "manifest.json holds the SHA-1 of every file in the archive. Checked in both directions here: a file present and unhashed fails on the device with no useful message."; }; }; readonly signatureVerifies: { readonly id: "signature-verifies"; readonly citation: { readonly source: "Apple Developer — Wallet Passes: Building a Pass (manifest and signature)"; readonly note: "signature is a detached PKCS#7 over the bytes of manifest.json, signed with the Pass Type ID certificate and chaining to Apple’s root through the WWDR intermediate."; }; }; }; export type RuleName = keyof typeof RULES; /** One thing wrong with a pass, said in the words somebody can act on. */ export interface PassProblem { rule: RuleName; /** Where in the pass, e.g. `primaryFields[0].changeMessage` or `strip@2x`. */ path: string; message: string; } /** * How many fields of each kind a style's layout holds. * * `back` is absent because it scrolls and has no limit. `primary` differs by * style, which is the one that bites: two primary fields on a `storeCard` shows * one of them, and which one is not documented. */ export declare const FIELD_LIMITS: Record; /** * The image each style's layout is built around, beyond the required icon. * * Empty for `generic` and `boardingPass`, which lay out from their fields alone. */ export declare const STYLE_ASSETS: Record; /** Pixel dimensions of each image at 1x, as Apple publishes them. */ export declare const ASSET_SIZES: Record; export declare const MAX_LOCATIONS = 10; export declare const MIN_AUTHENTICATION_TOKEN = 16; export declare const BARCODE_FORMATS: { readonly qr: "PKBarcodeFormatQR"; readonly pdf417: "PKBarcodeFormatPDF417"; readonly aztec: "PKBarcodeFormatAztec"; readonly code128: "PKBarcodeFormatCode128"; }; export declare const DEFAULT_BARCODE_ENCODING = "iso-8859-1"; //# sourceMappingURL=rules.d.ts.map