passkit-generator
Version:
The easiest way to generate custom Apple Wallet passes in Node.js
487 lines • 24.8 kB
JavaScript
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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