Skip to content

v7.0.0

Choose a tag to compare

@github-actions github-actions released this 10 May 00:04
d691990

7.0.0 (2026-05-10)

First release after a 5-year dormancy. v7 is a near-total rewrite aimed
at correctness, security, and keeping this library cheap to maintain
going forward. Everything below ships as one major bump.


⚠ BREAKING CHANGES

Relicense under AGPL-3.0-or-later

These affect every consumer. Plan the upgrade before running
npm update.

  • Node.js ≥ 24.12.0 required (was >=10.10). Locked to the Node
    release where native TypeScript type-stripping and node:test are
    both stable.
  • Pure ESM only. The package is "type": "module" with an
    "exports" map. CommonJS consumers must migrate to
    await import('@walletpass/pass-js'). No more
    require('@walletpass/pass-js').
  • Template.certificate shape changed from a forge.pki.Certificate
    object to a PEM string. Only matters if you read the field
    directly. Public API methods (setCertificate, setPrivateKey,
    loadCertificate) are unchanged.
  • Template.key shape changed from a forge.pki.PrivateKey to a
    node:crypto KeyObject.
  • NFCField.setPublicKey(key) takes PEM only. The previously
    undocumented forge.pki.PublicKey object form is gone (it was
    unusable without node-forge anyway).
  • setPrivateKey now rejects non-RSA keys at load time with a
    clear TypeError. Apple Pass Type ID certificates are always RSA;
    this prevents producing signatures that Wallet silently rejects.
  • Unusual ZIP compression methods in Template.fromBuffer
    (BZIP2, LZMA, AES-encrypted) that happened to work with the old
    yauzl dep now throw. Standard pkpass bundles are unaffected — STORE
    and DEFLATE are the only methods Apple emits.
  • Template.fromBuffer is stricter about pass.json: exactly one
    is required; archives with zero or multiple now throw instead of
    silently picking a decoy or returning an empty template.

🔐 Security + correctness

  • Apple WWDR certificate rotated to G4 (valid through 2030-12-10).
    The bundled G1 cert expired 2023-02-07; anything built with 6.9.x or
    earlier has been silently shipping invalid passes for years. Closes
    #616. Thanks to
    @lucyyyyyyy whose 2022 PR
    #626 supplied the
    correct cert.
  • New runtime warning WALLETPASS_WWDR_EXPIRING /
    WALLETPASS_WWDR_EXPIRED
    emitted via process.emitWarning when
    the bundled cert is within 90 days of expiry. Silence with
    node --disable-warning=WalletPassWWDRExpiring, or intercept with
    process.on('warning', ...). Designed to prevent the next silent
    rotation from recurring.
  • node-forge dropped entirely. Six CVEs disclosed Nov 2025 –
    early 2026 against ≤ 1.3.1 (incl. CVE-2025-12816 / CVSS 9.3 ASN.1
    desync, CVE-2026-33894 RSA signature forgery). Replaced with
    pkijs 3.4 +
    node:crypto for PKCS#7 SignedData. Signatures verified end-to-end
    against openssl cms -verify.

🧰 Toolchain rewrite

The devDependency footprint went from 13 packages to 5. None of these
affect what ships on npm — they're the local dev workflow only.

Was Is
typescript@4.4 @typescript/native-preview (tsgo, the Go rewrite)
eslint@8 + @typescript-eslint@5 + prettier oxlint (type-aware via oxlint-tsgolint) + oxfmt
jest@27 + ts-jest + jest-extended + jest-junit + @types/jest Native node:test + node:assert/strict
husky + lint-staged hk — uses Git 2.53 native hooks
renovate.json .github/dependabot.yml
(legacy npm publish with token) npm Trusted Publishing via OIDC — no long-lived secrets, provenance emitted automatically

Test suite migrated to node:test: 84 tests, 83 passing, 1 skipped
(live-APNs opt-in). Coverage now uploaded to Codecov via OIDC — also
tokenless.

📦 Dependencies pruned

Dropped or inlined. Every one shaves external surface area and
supply-chain risk:

  • node-forgepkijs + node:crypto (see above).
  • yauzl + @types/yauzl + event-iterator → ~200-LOC
    in-repo ZIP reader + STORE writer at src/lib/zip.ts.
  • do-not-zip (unmaintained since 2018) → folded into the same
    in-repo zip module.
  • buffer-crc32 → CRC-32 table inlined into zip.ts (~10 LOC).
  • imagesize (created 2013, last touched 2022, still used
    deprecated new Buffer()) → ~30-LOC PNG-only dimensions reader at
    src/lib/png-size.ts covering exactly what pkpass needs.

Runtime dependency count: 4
(pkijs,
color-name,
strip-json-comments,
plus pkijs's one transitive asn1js).

Every prod dep is pure JavaScript — no native addons, so the library
bundles cleanly with esbuild / @vercel/ncc / rollup. CI verifies this
on every PR via a single-file bundle smoke test.

✨ New features

  • iOS 18 semantic tags (semantics on passes and individual
    fields). Closes #75
    — a 6-year-old feature request. Re-applies PR
    #657 by
    @apples-kksk. Includes recursive
    Date → W3C string normalization with cycle detection.
  • iOS 18 poster event tickets: preferredStyleSchemes,
    relevantDates (replacing the singular relevantDate, now
    deprecated).
  • appLaunchURL + NFC requiresAuthentication. Re-applies PR
    #652 by
    @navelencia. The appLaunchURL
    field was previously in the types but never serialized — pure bug
    fix.
  • Options.disableImageCheck. Closes
    #480. Skips PNG
    dimension validation when you're generating passes with
    intentionally non-standard icon sizes. Re-applies PR
    #479 by
    @akoufa.

🧹 Other fixes worth calling out

  • Cross-platform .strings output bug (pre-existing since 2018).
    localizations.ts substituted os.EOL when encoding/decoding \n
    escapes, silently producing different .pkpass bundles on Windows
    vs. macOS/Linux. The previous Jest test matrix only ran on macOS, so
    no one noticed. Fixed to always emit \n per Apple's spec.
  • Validator/parser mismatches in isValidW3CDateString: the Z
    branch wasn't anchored to end-of-string (so trailing garbage
    validated); timezone-minute class only allowed :00 and :30 (so
    +05:45/+12:45/other real offsets failed).
  • Bundle ZIP paths with leading /, \, or .. are now rejected
    by the writer, matching the reader.
  • pass.json selection in Template.fromBuffer no longer matches
    notpass.json.
  • NFCField.setPublicKey now validates the curve is prime256v1
    (P-256 — what Apple requires) rather than accepting any EC key.

🤖 AI-friendly maintenance

  • CLAUDE.md + AGENTS.md at repo root with architecture map,
    non-obvious gotchas, WWDR rotation checklist, and CI debugging
    cheatsheet.
  • CONTRIBUTING.md documents Conventional Commits rules,
    quality-gate commands, and scope guidance.
  • Code complexity metrics posted on every PR via
    ophidiarium/mehen.
  • release-please autopilot — this release itself was produced by
    merging the automated release PR; future releases work the same way.

PR backlog cleared

Every open PR at the start of v7 work was triaged. Community feature
PRs were re-applied on top of the new toolchain with credit preserved
in the commit history; stale renovate bumps and obsolete Snyk PRs were
closed with explanatory comments.

Full detail in PR #658
(14 commits, 40+ review comments addressed across 22 threads).