export * from "./Barcode"; export * from "./Beacon"; export * from "./Location"; export * from "./Field"; export * from "./NFC"; export * from "./Semantics"; export * from "./PassFields"; export * from "./Personalize"; export * from "./Certificates"; import Joi from "joi"; import { Buffer } from "buffer"; import { Barcode } from "./Barcode"; import { Location } from "./Location"; import { Beacon } from "./Beacon"; import { NFC } from "./NFC"; import { PassFields, TransitType } from "./PassFields"; import { Semantics } from "./Semantics"; import { CertificatesSchema } from "./Certificates"; import * as Messages from "../messages"; const RGB_COLOR_REGEX = /rgb\(\s*(?:[01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\s*,\s*(?:[01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\s*,\s*(?:[01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\s*\)/; const URL_REGEX = /https?:\/\/(?:[a-z0-9]+\.?)+(?::\d{2,})?(?:\/[\S]+)*/; export type PreferredStyleSchemes = ("posterEventTicket" | "eventTicket")[]; export const PreferredStyleSchemes = Joi.array().items( "posterEventTicket", "eventTicket", ) satisfies Joi.Schema; export interface FileBuffers { [key: string]: Buffer; } export interface PassProps { formatVersion?: 1; serialNumber?: string; description?: string; organizationName?: string; passTypeIdentifier?: string; teamIdentifier?: string; appLaunchURL?: string; voided?: boolean; userInfo?: { [key: string]: any }; sharingProhibited?: boolean; groupingIdentifier?: string; suppressStripShine?: boolean; logoText?: string; maxDistance?: number; semantics?: Semantics; webServiceURL?: string; associatedStoreIdentifiers?: Array; authenticationToken?: string; backgroundColor?: string; foregroundColor?: string; labelColor?: string; nfc?: NFC; beacons?: Beacon[]; barcodes?: Barcode[]; relevantDate?: string; expirationDate?: string; locations?: Location[]; boardingPass?: PassFields & { transitType: TransitType }; eventTicket?: PassFields; coupon?: PassFields; generic?: PassFields; storeCard?: PassFields; /** * New field for iOS 18 * Event Ticket */ bagPolicyURL?: string; /** * New field for iOS 18 * Event Ticket */ orderFoodURL?: string; /** * New field for iOS 18 * Event Ticket */ parkingInformationURL?: string; /** * New field for iOS 18 * Event Ticket */ preferredStyleSchemes?: PreferredStyleSchemes; } /** * These are the properties passkit-generator will * handle through its methods */ type PassMethodsProps = | "nfc" | "beacons" | "barcodes" | "relevantDate" | "expirationDate" | "locations"; export type PassTypesProps = | "boardingPass" | "eventTicket" | "coupon" | "generic" | "storeCard"; export type OverridablePassProps = Omit< PassProps, PassMethodsProps | PassTypesProps >; export type PassPropsFromMethods = { [K in PassMethodsProps]: PassProps[K] }; export type PassKindsProps = { [K in PassTypesProps]: PassProps[K] }; export type PassColors = Pick< OverridablePassProps, "backgroundColor" | "foregroundColor" | "labelColor" >; export const PassPropsFromMethods = Joi.object({ nfc: NFC, beacons: Joi.array().items(Beacon), barcodes: Joi.array().items(Barcode), relevantDate: Joi.string().isoDate(), expirationDate: Joi.string().isoDate(), locations: Joi.array().items(Location), }); export const PassKindsProps = Joi.object({ coupon: PassFields.disallow("transitType"), generic: PassFields.disallow("transitType"), storeCard: PassFields.disallow("transitType"), eventTicket: PassFields.disallow("transitType"), boardingPass: PassFields, }); export const PassType = Joi.string().regex( /(boardingPass|coupon|eventTicket|storeCard|generic)/, ); export const OverridablePassProps = Joi.object({ formatVersion: Joi.number().default(1), semantics: Semantics, voided: Joi.boolean(), logoText: Joi.string(), description: Joi.string(), serialNumber: Joi.string(), appLaunchURL: Joi.string(), teamIdentifier: Joi.string(), organizationName: Joi.string(), passTypeIdentifier: Joi.string(), sharingProhibited: Joi.boolean(), groupingIdentifier: Joi.string(), suppressStripShine: Joi.boolean(), maxDistance: Joi.number().positive(), authenticationToken: Joi.string().min(16), labelColor: Joi.string().regex(RGB_COLOR_REGEX), backgroundColor: Joi.string().regex(RGB_COLOR_REGEX), foregroundColor: Joi.string().regex(RGB_COLOR_REGEX), associatedStoreIdentifiers: Joi.array().items(Joi.number()), userInfo: Joi.alternatives(Joi.object().unknown(), Joi.array()), webServiceURL: Joi.string().regex(URL_REGEX), /** * New field for iOS 18 * Event Ticket */ bagPolicyURL: Joi.string().regex(URL_REGEX), /** * New field for iOS 18 * Event Ticket */ orderFoodURL: Joi.string().regex(URL_REGEX), /** * New field for iOS 18 * Event Ticket * `"eventTicket"` is the legacy style. * * Passkit will try to render a style based on the order * of the properties */ parkingInformationURL: Joi.string().regex(URL_REGEX), }).with("webServiceURL", "authenticationToken"); export const PassProps = Joi.object< OverridablePassProps & PassKindsProps & PassPropsFromMethods >() .concat(OverridablePassProps) .concat(PassKindsProps) .concat(PassPropsFromMethods); export interface Template { model: string; certificates?: CertificatesSchema; } export const Template = Joi.object