Skip to content

unknown-studio-dev/app-store-server-library-node

 
 

Repository files navigation

Apple App Store Server Library — Workers Fork

Fork of @apple/app-store-server-library-node (v3.0.0), rewritten to run natively on Cloudflare Workers and any WebCrypto-compatible runtime.

Covers the App Store Server API, App Store Server Notifications V2, and Retention Messaging API.

What changed from upstream

Upstream (Node.js) This fork (Workers)
jsonwebtoken jose
jsrsasign (X509, ASN1HEX, OCSP) @peculiar/x509 + manual DER parser
crypto (X509Certificate, KeyObject, createHash, verify) @peculiar/x509 + crypto.subtle
node-fetch native fetch
Buffer Uint8Array / atob / btoa
base64url manual base64url

OCSP revocation checking is fully implemented using manual DER encoding/decoding and crypto.subtle for signature verification — no Node.js crypto dependencies.

Production dependencies

jose              ^5.9.0
@peculiar/x509    ^1.12.0

Zero Node.js-specific dependencies. Both packages work on Workers, Deno, Bun, and browsers.

Installation

# npm
npm install @studium-ignotum/app-store-server-library

# yarn
yarn add @studium-ignotum/app-store-server-library

# pnpm
pnpm add @studium-ignotum/app-store-server-library

Or install directly from GitHub:

# npm
npm install github:studium-ignotum/app-store-server-library-node

# yarn
yarn add studium-ignotum/app-store-server-library-node

# pnpm
pnpm add github:studium-ignotum/app-store-server-library-node

Requires a runtime with Web Crypto API (crypto.subtle) and native fetch.

Usage

API Client

import { AppStoreServerAPIClient, Environment } from "@studium-ignotum/app-store-server-library"

const client = new AppStoreServerAPIClient(
  encodedKey, keyId, issuerId, bundleId, Environment.SANDBOX
)

const response = await client.requestTestNotification()

Verify Signed Data (JWS)

import { SignedDataVerifier, Environment } from "@studium-ignotum/app-store-server-library"

const rootCAs: Uint8Array[] = [appleRootG3DER]  // DER-encoded Apple root certificates
const verifier = new SignedDataVerifier(rootCAs, true, Environment.PRODUCTION, bundleId, appAppleId)

const notification = await verifier.verifyAndDecodeNotification(signedPayload)

Constructor accepts Uint8Array[] (not Buffer[]). Buffer still works at runtime since it extends Uint8Array.

Receipt Utility

import { ReceiptUtility } from "@studium-ignotum/app-store-server-library"

const receiptUtil = new ReceiptUtility()
const transactionId = receiptUtil.extractTransactionIdFromAppReceipt(appReceipt)

Promotional Offer Signature

import { PromotionalOfferSignatureCreator } from "@studium-ignotum/app-store-server-library"

const creator = new PromotionalOfferSignatureCreator(encodedKey, keyId, bundleId)
const signature = await creator.createSignature(productId, offerId, appAccountToken, nonce, timestamp)

createSignature is now async (returns Promise<string>).

Cloudflare Workers Example

import { AppStoreServerAPIClient, SignedDataVerifier, Environment } from "@studium-ignotum/app-store-server-library"

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const verifier = new SignedDataVerifier(
      [base64ToUint8Array(env.APPLE_ROOT_CA_G3)],
      true,
      Environment.PRODUCTION,
      env.BUNDLE_ID,
      Number(env.APP_APPLE_ID)
    )

    const { signedPayload } = await request.json<{ signedPayload: string }>()
    const notification = await verifier.verifyAndDecodeNotification(signedPayload)

    return Response.json({ type: notification.notificationType })
  }
}

API Changes from Upstream

Method / Constructor Change
new SignedDataVerifier(certs, ...) certs type: Buffer[]Uint8Array[]
verifyCertificateChain(...) Returns Promise<CryptoKey> instead of Promise<KeyObject>
PromotionalOfferSignatureCreator.createSignature(...) Now async — returns Promise<string>
PromotionalOfferV2SignatureCreator.createSignature(...) Now async — returns Promise<string>
IntroductoryOfferEligibilitySignatureCreator.createSignature(...) Now async — returns Promise<string>
AdvancedCommerceInAppSignatureCreator.createSignature(...) Now async — returns Promise<string>
AppStoreServerAPIClient.uploadImage(id, image) image type: BufferUint8Array

All other public APIs remain unchanged.

Obtaining Apple Root Certificates

Download the root certificates from the Apple PKI site (Apple Root Certificates section). Store them as DER-encoded Uint8Array values and pass to SignedDataVerifier.

License

MIT — see LICENSE.txt. Original library by Apple Inc.

About

The Node.js server library for the App Store Server API and App Store Server Notifications.

Resources

License

Code of conduct

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • TypeScript 99.9%
  • Other 0.1%