UNPKG

passkit-generator

Version:

The easiest way to generate custom Apple Wallet passes in Node.js

487 lines 24.8 kB
export * from "./Barcode.js"; export * from "./Beacon.js"; export * from "./Location.js"; export * from "./PassFieldContent.js"; export * from "./NFC.js"; export * from "./Semantics.js"; export * from "./PassFields.js"; export * from "./Personalize.js"; export * from "./Certificates.js"; export * from "./UpcomingPassInformation.js"; import Joi from "joi"; import { Barcode } from "./Barcode.js"; import { Location } from "./Location.js"; import { Beacon } from "./Beacon.js"; import { NFC } from "./NFC.js"; import { PassFields } from "./PassFields.js"; import { Semantics } from "./Semantics.js"; import { UpcomingPassInformationEntry } from "./UpcomingPassInformation.js"; import * as Messages from "../messages.js"; import { RGB_HEX_COLOR_REGEX, URL_REGEX } from "./regexps.js"; export const PreferredStyleSchemes = Joi.array().items("posterEventTicket", "eventTicket", // or, since iOS 26 "boardingPass", "semanticBoardingPass"); 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({ /** * Since iOS 26 */ date: Joi.alternatives(Joi.string().isoDate(), Joi.date().iso()), /** * Since iOS 18, then was renamed in * 'date' in iOS 26 (what a breaking change) */ relevantDate: Joi.alternatives(Joi.string().isoDate(), Joi.date().iso()).required(), })); 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, upcomingPassInformation: Joi.array().items(UpcomingPassInformationEntry), }); 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().uri(), 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), stripColor: 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 posterEventTicket, semanticBoardingPasses * @passDomain Event Guide, Semantic Boarding Passes * * 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().regex(URL_REGEX), /** * @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().regex(URL_REGEX), /** * @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().regex(URL_REGEX), /** * @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().regex(URL_REGEX), /** * @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().regex(URL_REGEX), /** * @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().regex(URL_REGEX), /** * @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().regex(URL_REGEX), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * * @description * * Will add a button among options near "share" */ transferURL: Joi.string().regex(URL_REGEX), /** * @iOSVersion 18 * @passStyle eventTicket (new layout) * * @description * * Will add a button among options near "share" */ sellURL: Joi.string().regex(URL_REGEX), /** * @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. */ useAutomaticColors: 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()), /** * @iOSVersion 18.1 * * The text to display next to the logo on posterEventTicket passes. */ eventLogoText: Joi.string(), /** * @iOSVersion 26 * * @description * * A URL for changing the seat for the ticket. * Available only with Enhanced (or semantic) Boarding Passes */ changeSeatURL: Joi.string().regex(URL_REGEX), /** * @iOSVersion 26 * * @description * * A URL for in-flight entertainment. * Available only with Enhanced (or semantic) Boarding Passes */ entertainmentURL: Joi.string().regex(URL_REGEX), /** * @iOSVersion 26 * * @description * * A URL for adding checked bags for the ticket. * Available only with Enhanced (or semantic) Boarding Passes */ purchaseAdditionalBaggageURL: Joi.string().regex(URL_REGEX), /** * @iOSVersion 26 * * @description * * A URL that links to information to purchase lounge access. * Available only with Enhanced (or semantic) Boarding Passes */ purchaseLoungeAccessURL: Joi.string().regex(URL_REGEX), /** * @iOSVersion 26 * * @description * * A URL for purchasing in-flight wifi. * Available only with Enhanced (or semantic) Boarding Passes */ purchaseWifiURL: Joi.string().regex(URL_REGEX), /** * @iOSVersion 26 * * @description * * A URL for upgrading the flight. * Available only with Enhanced (or semantic) Boarding Passes */ upgradeURL: Joi.string().regex(URL_REGEX), /** * @iOSVersion 26 * * @description * * A URL for management. * Available only with Enhanced (or semantic) Boarding Passes */ managementURL: Joi.string().regex(URL_REGEX), /** * @iOSVersion 26 * * @description * * A URL for registering a service animal. * Available only with Enhanced (or semantic) Boarding Passes */ registerServiceAnimalURL: Joi.string().regex(URL_REGEX), /** * @iOSVersion 26 * * @description * * A URL to report a lost bag. * Available only with Enhanced (or semantic) Boarding Passes */ reportLostBagURL: Joi.string().regex(URL_REGEX), /** * @iOSVersion 26 * * @description * * A URL to request a wheel chair. * Available only with Enhanced (or semantic) Boarding Passes */ requestWheelchairURL: Joi.string().regex(URL_REGEX), /** * @iOSVersion 26 * * @description * * The email for the transit provider. * Available only with Enhanced (or semantic) Boarding Passes */ transitProviderEmail: Joi.string(), /** * @iOSVersion 26 * * @description * * The phone number for the transit provider. * Available only with Enhanced (or semantic) Boarding Passes */ transitProviderPhoneNumber: Joi.string(), /** * @iOSVersion 26 * * @description * * The URL for the transit provider. * Available only with Enhanced (or semantic) Boarding Passes */ transitProviderWebsiteURL: Joi.string().regex(URL_REGEX), }).with("webServiceURL", "authenticationToken"); export const PassProps = Joi.object() .concat(OverridablePassProps) .concat(PassKindsProps) .concat(PassPropsFromMethods); export const Template = Joi.object({ model: Joi.string().required(), certificates: Joi.object().required(), }); // --------- UTILITIES ---------- // /** * Performs validation of a schema on an object. * If it fails, will throw an error. * * @param schema * @param data */ export function assertValidity(schema, data, customErrorMessage) { const validation = schema.validate(data); if (validation.error) { if (customErrorMessage) { console.warn(validation.error); throw new TypeError(`${validation.error.name} happened. ${Messages.format(customErrorMessage, validation.error.message)}`); } throw new TypeError(validation.error.message); } } /** * Performs validation and throws the error if there's one. * Otherwise returns a (possibly patched) version of the specified * options (it depends on the schema) * * @param schema * @param options * @returns */ export function validate(schema, options) { const validationResult = schema.validate(options, { stripUnknown: true, abortEarly: true, }); if (validationResult.error) { throw validationResult.error; } return validationResult.value; } export function filterValid(schema, source) { if (!source) { return []; } return source.reduce((acc, current) => { try { return [...acc, validate(schema, current)]; } catch (err) { console.warn(Messages.format(Messages.FILTER_VALID.INVALID, err)); return [...acc]; } }, []); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc2NoZW1hcy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLGVBQWUsQ0FBQztBQUM5QixjQUFjLHVCQUF1QixDQUFDO0FBQ3RDLGNBQWMsVUFBVSxDQUFDO0FBQ3pCLGNBQWMsZ0JBQWdCLENBQUM7QUFDL0IsY0FBYyxpQkFBaUIsQ0FBQztBQUNoQyxjQUFjLGtCQUFrQixDQUFDO0FBQ2pDLGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYyw4QkFBOEIsQ0FBQztBQUU3QyxPQUFPLEdBQUcsTUFBTSxLQUFLLENBQUM7QUFHdEIsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN2QyxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDckMsT0FBTyxFQUFFLEdBQUcsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUMvQixPQUFPLEVBQUUsVUFBVSxFQUFlLE1BQU0saUJBQWlCLENBQUM7QUFDMUQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTNDLE9BQU8sRUFBRSw0QkFBNEIsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRTVFLE9BQU8sS0FBSyxRQUFRLE1BQU0sZ0JBQWdCLENBQUM7QUFDM0MsT0FBTyxFQUFFLG1CQUFtQixFQUFFLFNBQVMsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQU85RCxNQUFNLENBQUMsTUFBTSxxQkFBcUIsR0FBRyxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUMsS0FBSyxDQUNyRCxtQkFBbUIsRUFDbkIsYUFBYTtBQUNiLG1CQUFtQjtBQUNuQixjQUFjLEVBQ2Qsc0JBQXNCLENBQ3NCLENBQUM7QUFvQzlDLE1BQU0sQ0FB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