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 type { Buffer } from "node: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"; import { RGB_HEX_COLOR_REGEX, URL_REGEX } from "./regexps"; export type PreferredStyleSchemes = ("posterEventTicket" | "eventTicket")[]; export const PreferredStyleSchemes = Joi.array().items( "posterEventTicket", "eventTicket", ) satisfies Joi.Schema; /** * A single interval can span at most 24 hours */ export interface RelevancyInterval { startDate: string | Date; endDate: string | Date; } export interface RelevancyEntry { relevantDate: string | Date; } /** * @iOSVersion 18 * * Using a RelevancyInterval, will trigger a live activity on * new event ticket passes. * * Using a RelevancyEntry, will match the behavior of the * currently deprecated property `relevantDate`. */ export type RelevantDate = RelevancyInterval | RelevancyEntry; export const RelevantDate = Joi.alternatives( Joi.object().keys({ startDate: Joi.alternatives( Joi.string().isoDate(), Joi.date().iso(), ).required(), endDate: Joi.alternatives( Joi.string().isoDate(), Joi.date().iso(), ).required(), }), Joi.object().keys({ relevantDate: Joi.alternatives( Joi.string().isoDate(), Joi.date().iso(), ).required(), }), ); 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[]; /** * @deprecated starting from iOS 18 * Use `relevantDates` */ relevantDate?: string; relevantDates?: RelevantDate[]; expirationDate?: string; locations?: Location[]; boardingPass?: PassFields & { transitType: TransitType }; eventTicket?: PassFields; coupon?: PassFields; generic?: PassFields; storeCard?: PassFields; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) */ preferredStyleSchemes?: PreferredStyleSchemes; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * To show buttons in the event guide, * at least two among those marked with * "@passDomain event guide" must be used. */ bagPolicyURL?: string; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ orderFoodURL?: string; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ parkingInformationURL?: string; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ directionsInformationURL?: string; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * @description * * URL to a resource to buy or access * the parking spot. * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ purchaseParkingURL?: string; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * @description * * URL to a resource to buy the * merchandise. * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ merchandiseURL?: string; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * @description * * URL to a resource about public or * private transportation to reach the * venue. * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ transitInformationURL?: string; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * @description * * URL to a resource about accessibility * in the events venue. * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ accessibilityURL?: string; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * @description * * An URL to link experiences to the * pass (upgrades and more). * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ addOnURL?: string; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ contactVenueEmail?: string; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ contactVenuePhoneNumber?: string; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ contactVenueWebsite?: string; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Menu dropdown * * @description * * Will add a button among options near "share" */ transferURL?: string; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Menu dropdown * * @description * * Will add a button among options near "share" */ sellURL?: string; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * * @description * * Will remove an automatic shadow in the new * event ticket layouts. */ suppressHeaderDarkening?: boolean; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * * @description * * By default, the chin is colored with a * blur. Through this option, it is possible * to specify a different and specific color * for it. */ footerBackgroundColor?: string; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * * @description * * Enables the automatic calculation of the * `foregroundColor` and `labelColor` based * on the background image in the new event * ticket passes. * * If enabled, `foregroundColor` and `labelColor` * are ignored. */ useAutomaticColor?: boolean; /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * * @description * * Applications AppStore Identifiers * related to the event ticket. * * It is not mandatory for the app to * be related to the pass issuer. * * Such applications won't be able to read * the passes users has (probably differently * by `associatedStoreIdentifiers`). */ auxiliaryStoreIdentifiers?: number[]; } /** * These are the properties passkit-generator will * handle through its methods */ type PassMethodsProps = | "nfc" | "beacons" | "barcodes" | "relevantDate" | "relevantDates" | "expirationDate" | "locations" | "preferredStyleSchemes"; 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(), relevantDates: Joi.array().items(RelevantDate), expirationDate: Joi.string().isoDate(), locations: Joi.array().items(Location), preferredStyleSchemes: PreferredStyleSchemes, }); 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_HEX_COLOR_REGEX), backgroundColor: Joi.string().regex(RGB_HEX_COLOR_REGEX), foregroundColor: Joi.string().regex(RGB_HEX_COLOR_REGEX), associatedStoreIdentifiers: Joi.array().items(Joi.number()), userInfo: Joi.alternatives(Joi.object().unknown(), Joi.array()), webServiceURL: Joi.string().regex(URL_REGEX), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ bagPolicyURL: Joi.string().regex(URL_REGEX), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ orderFoodURL: Joi.string().regex(URL_REGEX), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ parkingInformationURL: Joi.string().regex(URL_REGEX), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ directionsInformationURL: Joi.string(), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * @description * * URL to a resource to buy or access * the parking spot. * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ purchaseParkingURL: Joi.string(), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * @description * * URL to a resource to buy the * merchandise. * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ merchandiseURL: Joi.string(), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * @description * * URL to a resource about public or * private transportation to reach the * venue. * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ transitInformationURL: Joi.string(), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * @description * * URL to a resource about accessibility * in the events venue. * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ accessibilityURL: Joi.string(), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * @description * * An URL to link experiences to the * pass (upgrades and more). * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ addOnURL: Joi.string(), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * @description * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ contactVenueEmail: Joi.string(), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * @description * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ contactVenuePhoneNumber: Joi.string(), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * @passDomain Event Guide * * @description * * To show buttons in the event guide, * at least two among those marked with * "@passDomain Event Guide" must be used. */ contactVenueWebsite: Joi.string(), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * * @description * * Will add a button among options near "share" */ transferURL: Joi.string(), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * * @description * * Will add a button among options near "share" */ sellURL: Joi.string(), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * * @description * * Will remove an automatic shadow in the new * event ticket layouts. */ suppressHeaderDarkening: Joi.boolean(), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * * @description * * By default, the chin is colored with a * blur. Through this option, it is possible * to specify a different and specific color * for it. */ footerBackgroundColor: Joi.string().regex(RGB_HEX_COLOR_REGEX), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * * @description * * Enables the automatic calculation of the * `foregroundColor` and `labelColor` based * on the background image in the new event * ticket passes. * * If enabled, `foregroundColor` and `labelColor` * are ignored. */ useAutomaticColor: Joi.boolean(), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * * @description * * Applications AppStore Identifiers * related to the event ticket. * * It is not mandatory for the app to * be related to the pass issuer. * * Such applications won't be able to read * the passes users has (probably differently * by `associatedStoreIdentifiers`). */ auxiliaryStoreIdentifiers: Joi.array().items(Joi.number()), }).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