@oxyhq/ship
v0.2.0
Published
oxy-ship — publish Expo OTA updates to the Oxy Updates service
Downloads
322
Readme
@oxyhq/ship — oxy-ship
Publish Expo OTA updates to the self-hosted Oxy Updates service (the
expo-updates protocol server inside oxy-api). Runs under Bun and Node.
Auth
oxy-ship authenticates with a service-type ApplicationCredential for the
target app, granted the updates:publish scope. The credential's applicationId
must equal the app being published to (the CLI reads it from the minted service
token — you never pass it).
| Flag | Env | Default |
|------|-----|---------|
| --client-id | OXY_SHIP_CLIENT_ID | — (required) |
| --secret | OXY_SHIP_SECRET | — (required) |
| --url (or --api-url) | OXY_API_URL | https://api.oxy.so |
Every command accepts --json for machine-readable stdout (progress goes to
stderr, so stdout stays clean for CI parsing).
Commands
# Export + publish the current project to a channel (both platforms by default)
oxy-ship publish --channel production [--platform ios|android|all] \
[--rollout 25] [--message "..."] [--runtime-version 1.2.3] \
[--dist-dir dist] [--project-dir .] [--skip-export] [--dry-run]
# Emergency rollback: mark the channel head rolled_back (previous update becomes head)
oxy-ship rollback --channel production --runtime-version 1.2.3 --platform ios
# Fall back to the binary-embedded update for a runtime+platform
oxy-ship rollback-to-embedded --channel production --runtime-version 1.2.3 --platform ios
# Promote an existing update into another channel (new UUID, same assets)
oxy-ship promote --update-id <uuid> --to-channel production [--rollout 100]
# List the app's channels
oxy-ship channel:list
# List recent updates (optionally filtered)
oxy-ship update:list [--channel production] [--runtime-version 1.2.3] [--platform ios] [--limit 20]publish derives gitCommit/gitBranch from git rev-parse (overridable with
--git-commit/--git-branch, or GITHUB_SHA/GITHUB_REF_NAME in CI).
What publish does
expo export(skippable with--skip-export) → readsdist/metadata.json.expo config --json --type public→runtimeVersion(appVersion policy) andextra.expoClient(soConstants.expoConfigworks after an OTA update).- Content-addresses every asset (sha256) + computes its expo key (md5).
assets/init→ presigned PUT for anything not already stored → uploads →assets/complete(HEAD-verified).POST /updatesonce per platform (channel created on demand).
--dry-run performs steps 1–3 and prints a summary without contacting the API.
CI
Copy templates/publish-update.yml into an app repo. It publishes to
production on push to main and to pr-<n> on pull requests.
