Package Exports
- @cloud-push/expo
- @cloud-push/expo/dist/index.cjs
- @cloud-push/expo/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@cloud-push/expo) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Typescript Only, Zero kotlin, Zero Swift, Zero java, Zero Object-C
OTA Update solution compatible with Expo Updates
โ Self-hosted update distribution system
๐ Documentation
You can find the full usage guide and API reference in the
๐ Cloud Push Docs
๐ Motivation
Expo projects are highly customized React Native projects. Because of this, available CodePush solutions are limited.
This project, inspired by hot-updater, offers an alternative way to manage bundles using storage services like S3, Firebase, Supabase, etc.
It follows Expo Updates technical specs and maintains compatibility with Expo Updates.
๐งช Compatibility
- โ
Works with
expo run:android --variant release - โ
Works with
expo run:ios --configuration Release - โ Compatible with Expo Managed Workflow
โจ Key Features
- ๐ก Self-hosted deployment supported
- ๐ฆ Flexible storage & DB (S3, Supabase, Firebase, etc.)
- ๐ Compatible with Expo Updates APIs
- ๐พ Web-based bundle version dashboard
- ๐ Supports expo.dev environment variables (via EAS Secrets)
- ๐ช Works on Windows
- ๐งช EAS build supported
๐ Configuration Examples
Supabase
import { defineConfig } from "@cloud-push/cli";
import { SupabaseStorageClient, SupabaseDbClient } from "@cloud-push/cloud";
export default defineConfig(() => ({
loadClients: () => {
const storageClient = new SupabaseStorageClient({
bucketName: process.env.SUPABASE_BUCKET_NAME!,
supabaseUrl: process.env.SUPABASE_URL!,
supabaseKey: process.env.SUPABASE_KEY!,
});
const dbClient = new SupabaseDbClient({
tableName: process.env.SUPABASE_TABLE_NAME!,
supabaseUrl: process.env.SUPABASE_URL!,
supabaseKey: process.env.SUPABASE_KEY!,
});
return {
storage: storageClient,
db: dbClient,
};
},
}));AWS S3 + lowdb
import { defineConfig } from "@cloud-push/cli";
import { AWSS3StorageClient, LowDbClient } from "@cloud-push/cloud";
export default defineConfig(() => ({
loadClients: () => {
const storageClient = new AWSS3StorageClient({
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
bucketName: process.env.AWS_BUCKET_NAME!,
region: process.env.AWS_REGION!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
});
const dbClient = new LowDbClient({
downloadJSONFile: () => storageClient.getFile({ key: "cursor.json" }),
uploadJSONFile: (file: Uint8Array) =>
storageClient.uploadFile({ key: "cursor.json", file }),
});
return {
storage: storageClient,
db: dbClient,
};
},
}));Firebase
import { defineConfig } from "@cloud-push/cli";
import { FirebaseStorageClient, FirebaseDbClient } from "@cloud-push/cloud";
export default defineConfig(() => ({
loadClients: () => {
const storageClient = new FirebaseStorageClient({
credential: process.env.FIREBASE_CREDENTIAL!,
bucketName: process.env.BUCKET_NAME!,
});
const dbClient = new FirebaseDbClient({
credential: process.env.FIREBASE_CREDENTIAL!,
databaseId: process.env.FIREBASE_DATABASE_ID!,
});
return {
storage: storageClient,
db: dbClient,
};
},
}));๐ Expo Updates SDK Compatibility
๐งฑ Constants
| Constant | Supported |
|---|---|
Updates.channel |
โ |
Updates.checkAutomatically |
โ |
Updates.createdAt |
โ |
Updates.emergencyLaunchReason |
โณ |
Updates.isEmbeddedLaunch |
โ |
Updates.isEmergencyLaunch |
โณ |
Updates.isEnabled |
โ |
Updates.latestContext |
โ |
Updates.launchDuration |
โ |
Updates.manifest |
โ |
Updates.runtimeVersion |
โ |
Updates.updateId |
โ |
๐งฉ Hooks
| Hook | Supported |
|---|---|
useUpdates() |
โ |
๐ Methods
| Method | Supported |
|---|---|
checkForUpdateAsync() |
โ |
clearLogEntriesAsync() |
โ |
fetchUpdateAsync() |
โ |
getExtraParamsAsync() |
โ |
readLogEntriesAsync() |
โ |
reloadAsync() |
โ |
setExtraParamAsync() |
โ |