-
-
Notifications
You must be signed in to change notification settings - Fork 112
API Documentation Reference
The flow of execution is really easy (once everything is set up):
- You get your data from somewhere
- You set the needed data in the pass through methods, props and data in fields
- You generate the pass stream or buffer through respectively
.getAsStream()
or.getAsBuffer()
methods - Hooray 😄🎉
Some details:
-
Properties will be checked against schemas, which are built to reflect Apple's specifications, that can be found on Apple Developer Portal, at PassKit Package Format Reference.
-
In case of troubleshooting, you can refer to the Self-help guide in Wiki or open an issue.
-
Keep this as it is always valid for the reference:
// CJS
const { PKPass } = require("passkit-generator");
// ESM
import { PKPass } from "passkit-generator";
const pass = new PKPass({ ... }, { ... }, { ... });
Returns:
PKPass
Description:
PKPass extends an internal class Bundle
, which gives it some props. Only the exposed ones will be listed below.
Arguments:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
buffers | object | The initial files buffers to compose a pass. They must be in form path: Buffer . Set to empty object if none is available yet. |
false | - |
certificates | object | The certificates object. | false | - |
certificates.wwdr | string | Buffer | The content of Apple WWDR certificate. | false | - |
certificates.signerCert | string | Buffer | The content of Developer certificate file. | false | - |
certificates.signerKey | string | Buffer | The content of developer certificate's key. | false | - |
certificates.signerKeyPassphrase | string | The passphrase to decrypt the developer signerKey | true | - |
props | object | Some pass props that will get merged with the ones in pass.json | true | { } |
A pass can be created through its constructor (creating from scratch) or from another pass or from a template. A "template" here is a model saved on disk. Both can be created by using the static method PKPass.from()
.
PKPass.from(source: PKPass | PKPass.Template, props?: Schemas.OverridableProps): Promise<typeof PKPass>;
Throws if the pass source is not valid.
In both cases, additional props can be passed as the second parameter through an object.
Below you can see a few example functions that will be used in the following ways to use PKPass.from
.
function getAdditionalPropsForThisPassSomehow() {
// get your additional props for THIS pass
return {
serialNumber: "12356222",
/** moar props ... */
};
}
function getSomeProps() {
/** Set your base props for all your passes **/
return {
description: "Pass for some business activity",
webServiceURL: "https://example.com/passkit",
/** moar props ... */
};
}
function getCertificatesSomehow() {
return {
signerCert: "" /** string or Buffer **/,
signerKey: "" /** string or Buffer **/,
wwdr: "" /** string or Buffer **/,
signerKeyPassphrase: "" /** string **/,
};
}
Description:
Pass another PKPass
as the source of PKPass.from
to make it clone every property and file in the source object (except manifest and signature).
This is useful if you want to create a runtime template with your buffers and then always use it as a base.
Example:
const passRuntimeTemplate = new PKPass(
getBuffersSomehow(),
getCertificatesSomehow(),
getSomeProps(),
);
// later...
const passToBeServed = await PKPass.from(
passRuntimeTemplate,
getAdditionalPropsForThisPassSomehow(),
);
Description:
Use this if you have a saved model on your File System and want to read it and use it as the source for your pass.
Arguments:
The following are the arguments to be passed in the object in the first position:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
model | string (path) | The path to your model on File System | false |
- |
certificates | object | The object containing certificates data. Refer to PKPass's constructor for all the keys | false |
- |
Example:
const passFromDisk = await PKPass.from(
{
model: "../../path/to/your/disk/model",
certificates: getCertificatesSomehow(),
},
getAdditionalPropsForThisPassSomehow(),
);
pass.addBuffer(filePath: string, buffer: Buffer): void;
Description:
This method allows later additions of files to your pass. It has no filters about the type of file you may want to add but for:
pass.json
personalization.json
\<lang\>.lproj/pass.strings
manifest.json
signature
In these cases, addBuffer
will perform additional checks and might not add the file as-is or at all.
-
pass.json
will be parsed and merged with current props only if not already available. Otherwise, it gets ignored. In case of merging, it might overwrite props you set first, through constructor or methods; -
personalization.json
will be parsed, validated, and then added (only if valid); -
\<lang\>.lproj/pass.strings
will be parsed and, if valid, will be merged within the current translations; -
manifest
will be ignored; -
signature
will be ignored;
Throws if pass is frozen due to a previous export.
Arguments:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
filePath | string (path) | The path, local to your pass.json, where the file should be added (if it is a localization file, it will be like en.lproj/pass.strings , otherwise just the name, like personalization.json ) |
false |
- |
buffer | Buffer | The content of your file | false |
- |
According to Apple Developer Documentation, localization (L10N) is done by creating a .lproj
folder for each language you want to translate your pass, each named with the relative ISO-3166-1 alpha-2 code (e.g. en.lproj
).
There are three ways to include a language in this package:
- By importing a localized buffer or a localized model when creating the instance;
- By adding a file (media or pass.strings) for that specific language through
.addBuffer
method (like.addBuffer("en.lproj/[email protected]", Buffer.from([...]))
); - By specifying translations for a language through
.localize
method below;
If you are designing your pass for a language only, you can directly replace the placeholders in
pass.json
with translation.
pass.localize(lang: string, translations: { [key: string]: string }): void;
Returns:
void
Description:
Use this method to add some translations. Existing translations will be merged with the newly added.
Calling .localize
is the same as calling .addBuffer
for a pass.strings
file, except for the parsing phase.
Pass null
to translations param to delete everything of a language (translations and files).
Throws if pass is frozen due to a previous export, if the last is not a string or if no translations are provided.
Arguments:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
lang | String | The ISO-3166-1 language code | false | - |
translations | Object | null | Translations in format { <PLACEHOLDER>: "TRANSLATED-VALUE"} . Pass null to delete everything of a language |
false | - |
Example:
pass.localize("it", {
EVENT: "Evento",
LOCATION: "Posizione",
});
pass.localize("de", {
EVENT: "Ereignis",
LOCATION: "Ort",
});
pass.setBarcodes(message: string): void;
pass.setBarcodes(...barcodes: schema.Barcodes[]): void;
Returns:
void
Description:
Setting barcodes can happen in two ways: controlled
and uncontrolled
(autogenerated), which means how many barcode structures you will have in your pass.
Passing a string
to the method will lead to an uncontrolled
way: starting from the message (content), all the structures will be generated. Any further parameters will be ignored.
Passing N barcode structures (see below), will only validate them and push only the valid ones.
Setting barcodes will overwrite previously set barcodes (no matter the source).
Pass null
to delete all the barcodes.
Throws if pass is frozen due to a previous export.
Please note that, as the
barcode
property is deprecated, this is the only method available for setting barcodes.
Arguments:
Key | Type | Description | Optional |
---|---|---|---|
message |
String | Barcode
|
first value of barcodes | false |
...rest | Barcode[] |
the other barcode values | true |
Examples:
pass.setBarcodes("11424771526");
// or
pass.setBarcodes({
message: "11424771526",
format: "PKBarcodeFormatCode128",
altText: "11424771526"
}, {
message: "11424771526",
format: "PKBarcodeFormatQR",
altText: "11424771526"
}, {
message: "11424771526",
format: "PKBarcodeFormatPDF417",
altText: "11424771526"
});
See: Barcodes
pass.setExpirationDate(date: Date): void;
Returns:
void
Description:
It sets the date of expiration to the passed argument.
Pass null
as the parameter to remove the value from props.
If date parsing fails, an error will be thrown.
Throws if pass is frozen due to a previous export.
Arguments:
Key | Type | Description | Optional |
---|---|---|---|
date | String/date | The date on which the pass will expire | false |
pass.setBeacons(...data: schema.Beacons[]): void;
Returns:
void
Description:
Sets the beacons information in the passes.
Setting beacons will overwrite previously setted beacons.
Pass null
to delete all the beacons.
Throws if pass is frozen due to a previous export.
Arguments:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
...beacons |
Beacons[] | null
|
The beacons structures | false | - |
See: Beacons
Example:
pass.setBeacons(
{
major: 55,
minor: 0,
proximityUUID: "59da0f96-3fb5-43aa-9028-2bc796c3d0c5",
},
{
major: 65,
minor: 46,
proximityUUID: "fdcbbf48-a4ae-4ffb-9200-f8a373c5c18e",
},
);
pass.setLocations(...data: schema.Locations[]): void;
Returns:
void
Description:
Sets the location-relevance information in the passes.
Setting locations will overwrite previously setted locations (no matter the source).
Pass null
to delete all the locations.
Throws if pass is frozen due to a previous export.
Arguments:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
...locations |
schema.Locations[] | null
|
The location structures | false | - |
See: Locations
Example:
pass.setLocations(
{
latitude: 66.45725212,
longitude: 33.01000442,
},
{
longitude: 4.42634523,
latitude: 5.344233323352,
},
);
pass.setRelevantDates(relevantEntries: RelevantDate[] | null): void;
Returns:
void
Version:
v3.3.0
Description:
Starting from iOS 18, relevantDate
has been deprecated in favor of relevantDates
.
This method allows setting it. A RelevantDate
is an object containing one of these two structures:
{
"startDate": "iso-date",
"endDate": "iso-date",
}
or
{
"relevantDate": "iso-date", // this is the same as deprecated `relevantDate` as a root property
}
Structures can get mixed, but to unlock the new eventTicket layout relevantDates
must be used.
Furthermore, to allow using the event guide and live activies for eventTicket, the first structure must be used as using the second will make the device to fallback to classic notification.
Pass null
as the parameter to remove the value from props.
If date parsing fails, an error will be thrown.
Throws if pass is frozen due to a previous export.
Arguments:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
relevantEntries | RelevantDate[] | null
|
The relevant dates | false | - |
pass.setRelevantDate(date: Date): void;
Returns:
void
Description:
It sets the date of relevance to the passed argument to the iOS 18-deprecated property relevantDate
.
.setRelevantDates
should be preferred when targeting only iOS 18. Both should be used otherwise.
Pass null
as the parameter to remove the value from props.
If date parsing fails, an error will be thrown.
Throws if pass is frozen due to a previous export.
Arguments:
Key | Type | Description | Optional | Default Value |
---|---|---|---|---|
date | Date | null
|
The relevant date | false | - |
pass.setNFC(data: schema.NFC): void
Returns:
void
Description:
It sets NFC info for the current pass.
Pass null
as a parameter to remove its value from props.
Throws if pass is frozen due to a previous export or if parameter validation fails.
Arguments:
Key | Type | Description | Optional |
---|---|---|---|
data | NFC Dictionary | null
|
NFC structure | false |
See: NFC
Personalization (or Reward Enrollment passes) is supported only if:
-
personalization.json
is available and it is a valid json file with valid props; -
[email protected]
(where 'XX' => x2, x3) is available; - NFC is set;
If these conditions are not met, personalization files will get removed from the output pass or not be accepted as an input file.
Notice: There is no way I could test this feature on any real pass 'cause Apple would never give me an encryptionKey for NFC. Also, I don't have an NFC reader. If you need it and this won't work, feel free to contact me and we will investigate together 😄
The opposite is valid as well: if you try to use it and it works, feel free to report it to me, so this warning can be removed
Unlike method-set properties or initialization props, to set fields inside the right property, some getters have been created, one per property. Each extends native Arrays, to let you perform all the operations you need on the fields. Fields already available in pass.json, will be automatically loaded in props.
Please note that they are strictly and directly linked to the pass type property (boardingPass, storeCard, etc...). This means that if pass type is not available, accessing them will throw an error. Changing the type on runtime will clean all them up.
All the fields are linked together through a keys pool: each key must be unique among all the fields of the whole pass.
Each getter will throw if pass is frozen due to a previous export, when a new element is attempted to be added to the related array.
Examples:
pass.headerFields.push(
{
key: "header1",
label: "Data",
value: "25 mag",
textAlignment: "PKTextAlignmentCenter",
},
{
key: "header2",
label: "Volo",
value: "EZY997",
textAlignment: "PKTextAlignmentCenter",
},
);
pass.primaryFields.pop();
pass.auxiliaryFields.push(/*...*/);
pass.secondaryFields.push(/*...*/);
pass.backFields.push(/*...*/);
See: PassFields
pass.transitType = "PKTransitTypeAir";
Description:
Since this property belongs to the "Field Keys" but is not an "array of field dictionaries" like its sibling keys, a setter, and a getter got included to select it.
Allowed values: PKTransitTypeAir, PKTransitTypeBoat, PKTransitTypeBus, PKTransitTypeGeneric, PKTransitTypeTrain", as described in Passkit Package Format Reference.
Please note that it is strictly and directly linked to the pass type property (only boardingPass).
This means that if pass type is not available or is not a boardingPass, accessing or setting it will throw an error. Changing the type on runtime will clean it up.
Pass exporting will throw an error if a boardingPass is exported without transitType
.
Setter throws if pass is frozen due to a previous export, if an invalid pass type is invalid, or if current type is not a boardingPass
.
Generating the pass is the last step of the process (before enjoying 🎉). Generating might happen in three ways: getting a Buffer, a Stream, or Raw files.
All the three ways available, will lock the pass instance to not accept anymore files or props.
pass.getAsBuffer(): Buffer;
Description:
Creates a buffer of the zipped pass. This is useful when passkit-generator is used in contexts where using Streams is not possible, like cloud functions.
Examples:
const passBuffer = pass.getAsBuffer();
doSomethingWithPassBuffer(passBuffer);
pass.getAsStream(): Stream;
Description:
Creates a stream for the zipped pass.
Examples:
const passStream = pass.getAsStream();
doSomethingWithPassStream(passStream);
pass.getAsRaw(): Readonly<{ [path: string]: Buffer }>;
Description:
Returns a frozen object containing all the files along with their buffers (with compiled signature and manifest).
The purpose of this stands in how zips are created. In passkit-generator v2.x.x, a different and asynchronous library was being used to create zips. Due to a worse API, it was replaced by do-not-zip, which acts more like a buffers concatenator instead of a compressor. This compromise improved the creation of zips by making zips generation synchronous, through a very-lightweight package, but with possibly incremented final archives size.
For this reason, if the developer is already using a different zip library and is providing quite large files, better results in terms of pass weight might be obtained by manipulating the list of files provided by this method and feeding them to the already-available zip library.
Examples:
import { toBuffer as doNotZip } from "do-not-zip";
const passFiles = pass.getAsRaw();
const crunchedData = Object.entries(passFiles).map(([path, data]) => ({
path,
data,
}));
doSomethingWithCustomZippedPass(doNotZip(chunchedData));
const currentProps = pass.props;
Returns:
An object containing all the current props;
Description:
This is a way to access the current props. Querying this getter will return a nested clone of the props. Props are organized like you are navigating in pass.json;
Example:
const currentLocations = pass.props["locations"];
pass.locations(
{
latitude: 66.45725212,
longitude: 33.01000442,
},
{
longitude: 4.42634523,
latitude: 5.344233323352,
},
...currentLocations,
);
pass.certificates = { ... };
Description:
Provides a later way to specify or change the used certificates.
It accepts an object which has the same signature as the one requested in constructor
and PKPass.from
.
Throws if pass is frozen due to a previous export or if schema validation on provided object fails.
pass.languages
Description:
Provides a way to get currently added languages from the different possible ways.
It returns a new array made of languages keys (like ["en", "it"]
).
pass.type = "coupon";
pass.type !== undefined;
Description:
Provides a later way to specify a pass type. The availability of this setter allows developers to create a PKPass without the need to have or create a pass.json first and provide it as a file or provide a generic one.
Please note that using this setter will reset all your fields (primaryFields, secondaryFields, ...) and transitType, as they are strictly linked to the type.
Setter throws if pass is frozen due to a previous export or if an invalid type is provided.
Example:
const pass = new PKPass({ ... }, { ... }, { ... });
// Assuming a pass.json with a type inside has been added first and it has 5 valid primaryFields.
console.log(pass.primaryFields.length); // 5
pass.type = "storeCard";
console.log(pass.primaryFields.length); // 0
console.log("Pass type is", pass.type); // "Pass type is storeCard"
pass.mimeType;
Description:
This getter allows to abstract the kind of mimeType is being served when generating a PKPass archive or a PKPasses archive (see below). This property is automatically set when a PKPass is created (application/vnd.apple.pkpass
) or when PKPass.pack
is invoked (application/vnd.apple.pkpasses
).
Starting from iOS 15, developers can serve multiple passes through Safari by zipping multiple passes together in a single Bundle with extension .pkpasses
and serving it with mimeType application/vnd.apple.pkpasses
.
PKPass.pack(...args: PKPass[]): Bundle;
Description
This method accepts a series of PKPass instances and returns a new Bundle instance (the one from which PKPass inherits some properties), and allows you to serve all the passes together.
Please note that, internally, this method invokes .getAsBuffer()
on each pass instance. This method assumes the passes provided won't be edited again and are ready to get distributed. PKPass instances will be, therefore, locked.
Throws if not all the args are instances of PKPass.
Example:
const [passInstance1, passInstance2, passInstance3] = getThreePassesSomehow();
const pkpassesBundle = PKPass.pack(passInstance1, passInstance2, passInstance3);
serveBufferWithMimeTypeSomehow(
pkPassesBundle.getAsBuffer(),
pkPassesBundle.mimeType /** -> application/vnd.apple.pkpasses **/,
);
Thanks for using this library. ❤️ Every contribution is welcome.