Skip to content

feat(cli): expo APNs key setup on @expo/apple-utils - #1994

Merged
ArnabChatterjee20k merged 3 commits into
messaging-provider-cli-apns-adaptersfrom
messaging-provider-cli-apns-adapter-expo
Oct 9, 2026
Merged

ArnabChatterjee20k merged 3 commits into
messaging-provider-cli-apns-adaptersfrom
messaging-provider-cli-apns-adapter-expo

Conversation

@ArnabChatterjee20k

Copy link
Copy Markdown
Member

Stacked on #1992 (the APNs key setup adapters). This is the expo adapter, the fallback to switch to with --provider expo or APPWRITE_APNS_SETUP=expo when the default setup breaks. It replaces #1989, which had the same helper before the adapter split.

What

internal/apns/expo: an apns.Adapter named expo that creates the key with @expo/apple-utils 2.2.1 (MIT), the library eas-cli uses (see pushKey.ts).

appwrite init apns --create-key --provider expo
# or
APPWRITE_APNS_SETUP=expo appwrite init apns --create-key

How

  • Embedded files: helper/helper.js, package.json and package-lock.json are embedded with go:embed. The lockfile pins the package's integrity hash.
  • Install: on first use the adapter checks for Node.js 18 or later, then writes the files into the session folder (~/.appwrite/apns/expo/) and runs npm ci --ignore-scripts. It reinstalls only when the embedded files change. A missing or old Node.js, or a failed npm ci, returns apns.ErrUnavailable before anything is sent to Apple.
  • The helper runs Auth.loginAsync({ teamId }), using authState.context as the request context the way eas-cli's getRequestContext does, then Keys.createKeyAsync(ctx, { name, isApns: true }) and Keys.downloadKeyAsync. With no team, apple-utils picks the account's only team or asks.
  • Terminal: the helper runs attached to the terminal, so apple-utils asks for the two-factor code itself, plus anything the request leaves out.
    • Its logging goes to stdout, so the result goes to a 0600 file in a private temp folder.
    • The request's Apple ID and password are passed as EXPO_APPLE_ID / EXPO_APPLE_PASSWORD, filled by the CLI from APPWRITE_APPLE_ID / APPWRITE_APPLE_PASSWORD.
    • EXPO_NO_KEYCHAIN=1 keeps the password out of the macOS Keychain.
  • Errors:
    • InvalidUserCredentialsError becomes apns.ErrInvalidCredentials.
    • MaxKeysCreatedError, or Apple's "maximum allowed number of Keys" text, becomes apns.MaxKeysError with the team's keys.
    • Anything else comes back as apple-utils' message.
  • Environment: apple-utils always creates keys for both APNs environments (it hard-codes environment: "all"). For --environment production|sandbox the adapter logs that the key also covers that environment. The providers still follow --environment.

Tests

  • Node version parsing, and result decoding (key, full team, invalid credentials, failure, empty).
  • With stand-in node and npm:
    • it installs once and reuses the install
    • it runs the helper with --name, --out and --team-id
    • it passes EXPO_NO_KEYCHAIN=1 and the Apple ID
    • it notes the environment for a single-environment request
    • it refuses an old or missing Node.js without running npm or the helper
  • Earlier manual check (feat(cli): init apns --create-key creates the APNs key with the Apple ID #1989): npm ci of the embedded lockfile, and the helper reaching apple-utils' Apple sign-in, which then fails cleanly without a terminal. A key was created with a real Apple account through this helper.

Note

This PR and the appwrite one (#1993) each add one line to apnsAdapters(). Whichever merges second needs both: apns.NewRegistry(appwrite.New(), expo.New()).

The expo adapter creates APNs keys with @expo/apple-utils 2.2.1 (MIT),
the library eas-cli uses. A small Node script, its package.json and a
lockfile pinning the package hash are embedded with go:embed and
installed into the session folder with npm ci --ignore-scripts when they
change. It needs Node.js 18 or later and reports apns.ErrUnavailable
otherwise, before contacting Apple.

apple-utils prompts on the terminal for the two-factor code and for
anything the request leaves out; the request's Apple ID and password
are passed as EXPO_APPLE_ID and EXPO_APPLE_PASSWORD, and
EXPO_NO_KEYCHAIN=1 keeps the password out of the macOS Keychain. Its
InvalidUserCredentialsError maps to apns.ErrInvalidCredentials and a full
team to apns.MaxKeysError. apple-utils always creates keys for both
environments, which also serve a single-environment request.
Registers the expo adapter, picked with --provider expo or
APPWRITE_APNS_SETUP=expo.
@hansi-codes

hansi-codes Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

🟢 Tier S · Ready to merge

The incremental change only adds meaningful coverage for the existing no-team behavior and introduces no defects.

Adds an Expo-backed APNs key setup adapter using an embedded Node helper and pinned @expo/apple-utils dependency, with Node version checks, installation reuse, Apple sign-in, and result decoding. Registers the adapter with the CLI and covers its setup and error paths with tests. The latest change extends the test for requests without a known team to verify that no --team-id is passed to the helper.

Latest changes: The newest commit clarifies the no-team test scenario and asserts that the helper invocation omits --team-id.

Verdict New comments Fixed Still open
✅ Approved 0 0 0
📂 Walkthrough · 7
File Change
src/SDK/Language/CLI.php Registers the Expo adapter, its tests, and the embedded helper files for CLI generation.
templates/cli/internal/apns/expo/adapter.go Adds the Expo APNs adapter, Node/npm setup, helper execution, and result/error decoding.
templates/cli/internal/apns/expo/adapter_test.go Tests adapter behavior, including the latest assertion that no team ID is passed when none is known.
templates/cli/internal/apns/expo/helper/helper.js Uses apple-utils to sign in, create and download an APNs key, and write structured results.
templates/cli/internal/apns/expo/helper/package.json Declares the helper's Node requirement and pinned apple-utils dependency.
templates/cli/internal/apns/expo/helper/package-lock.json Locks the helper dependency tree and package integrity hashes.
templates/cli/internal/cmd/initpush.go Registers the Expo provider for CLI APNs key setup.

Reviewed the commits since 85da856 · Details · Comment @hansi-codes review to re-run, or mention @hansi-codes with a question.

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Tier S · Looks good to merge. Summary

The CLI leaves the team out when none is known and lets the sign-in pick
it. The test now checks that the helper then gets no --team-id.
@ArnabChatterjee20k
ArnabChatterjee20k merged commit f900aaa into messaging-provider-cli-apns-adapters Oct 9, 2026
54 of 61 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant