Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(standalone): api-based standaloneRepository database plugin #83

Merged
merged 8 commits into from
Feb 20, 2025

Conversation

regalstreak
Copy link
Contributor

Use your own existing backend with hot-updater.
Very simple to use

  1. Create the following api endpoints in your backend
  2. Pass http://www.baseUrl.com/api/v1/app/ota/bundles as the endpoint and headers if you have any api keys
interface Bundle {
  id: string;
  enabled: boolean;
  fileUrl: string;
  shouldForceUpdate: boolean;
  fileHash: string;
  gitCommitHash?: string;
  message?: string;
  platform: 'ios' | 'android';
  targetAppVersion: string;
}

// Create/Update Bundles
POST /api/v1/app/ota/bundles
Request: Array<Bundle>
Response: { success: boolean }

// Get All Bundles
GET /api/v1/app/ota/bundles
Response: Array<Bundle>

// Get Single Bundle
GET /api/v1/app/ota/bundles/:bundleId
Response: Bundle | null

// Update Check
GET /api/v1/app/ota/update-server
Headers: {
  'x-bundle-id': string;
  'x-app-platform': 'ios' | 'android';
  'x-app-version': string;
}
Response: {
  id: string;
  shouldForceUpdate: boolean;
  fileUrl: string;
  fileHash: string;
  status: 'UPDATE' | 'ROLLBACK';
} | null

Copy link
Owner

@gronxb gronxb left a comment

Choose a reason for hiding this comment

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

Thank you for your contribution! 😀

Before proceeding with the code review, I have a few questions.

I think it’s a good approach to structure the database connection with the backend using an endpoint-based setup.

However, to apply this plugin, the user’s server must implement the update logic. I’m curious about which reference you used to implement the server logic, as I haven’t written the API spec yet. Could you share how you structured the server logic?

Once this plugin is deployed, library users will need to implement their own update logic according to the spec on their respective servers. We should also consider how to document this properly in the Docs.

@gronxb
Copy link
Owner

gronxb commented Feb 5, 2025

I’m also curious—are you planning to use a cloud provider for the storage plugin? Available options include S3, R2, and Supabase Storage, and you can use any of them. However, I’m interested in knowing which combination you’re planning to use. 😊

@regalstreak
Copy link
Contributor Author

Hey! We're planning to use AWS as all our infra is over there, along with an S3 bucket for storage.

We've created a new service for the OTA specifically with Postgres and using the Supabase migration. We call the get_update_info sql function and cache it on cloudfront based on similar headers, so not much load on db.

But I think it would be better to not call a database function directly for most users if they don't know much about caching. Ideally, we'd also want to migrate to a better setup which doesn't need the need for a db function but as its a new service, everythings fine.

In the process of testing this out, really excited to see this going live!

Copy link
Owner

@gronxb gronxb left a comment

Choose a reason for hiding this comment

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

I approved it by mistake. 😅

@ShaunLWM
Copy link

ShaunLWM commented Feb 7, 2025

sorry, correct me if i'm wrong.

shouldn't this be called under "aws" (or something similar) instead of "self hosting" or "standalone" - since it uses aws + s3. shouldn't self hosting be using bare metal with docker compose (with postgres) + internal storage?

just a thought.

@guillempuche
Copy link

shouldn't this be called under "aws" (or something similar) instead of "self hosting" or "standalone" - since it uses aws + s3. shouldn't self hosting be using bare metal with docker compose (with postgres) + internal storage?

I agree, like self-hosted in https://www.hetzner.com/ and deployed with https://coolify.io/

@regalstreak
Copy link
Contributor Author

@ShaunLWM @guillempuche the point of this plugin is to allow people to host the database anywhere, be it hetzner, aws, digitalocean, etc. and use hot-updater with their currently existing APIs by creating 1 extra endpoint for bundle management (/bundles) and 1 endpoint for the app that checks for updates (/update-server)

All of the plugins in hot-updater are used locally by the CLI tool, or on CI. They don't need to be deployed or hosted.

We internally use AWS, that's just one example!

@gronxb
Copy link
Owner

gronxb commented Feb 7, 2025

@ShaunLWM @guillempuche

Everything @regalstreak mentioned is correct. While i haven’t publicly disclosed how the plugin works yet, it seems @regalstreak has insightfully figured it out.

The hot-updater plugins are only used in the CLI.

When running the hot-updater deploy command, it uses the storage plugin to store bundles and the database plugin to update the database.

When running the hot-updater console command, it uses the database plugin to update and retrieve data from the database.

Since this plugin is purely API-based and has no dependencies, it qualifies as a standalone solution.

In this case, while a storage plugin has not been created yet, existing plugins can already be used, allowing for various combinations.

import { metro } from "@hot-updater/metro";
import { s3Storage } from "@hot-updater/aws";

import { standaloneRepository } from "@hot-updater/standalone-api";
import { defineConfig } from "hot-updater";
import "dotenv/config";

export default defineConfig({
  build: metro(),
  storage: s3Storage({
    // Simply stores the bundle in S3. It only saves the bundle and provides a public URL to the database plugin, allowing it to access the bundle. 
    // Therefore, this could be replaced with R2 storage, Supabase storage, or any other storage provider.
    bucketName: process.env.HOT_UPDATER_SUPABASE_BUCKET_NAME!,
  }),
  database: standaloneRepository({
    // Used exclusively in the CLI. In the deploy command, it updates the database, and in the console, it is used for querying and updating bundles.
    baseUrl: "https://api.example.com",  
    commonHeaders: {},
  }),
});

@guillempuche
Copy link

Thanks @regalstreak and @gronxb for the explanation. HotUpdater seems very exciting. I'm still exploring how different it's from Expo EAS.

@maxaggedon
Copy link

maxaggedon commented Feb 11, 2025

@guillempuche eas from expo was our first guess as well. Tried to install expo to use it on a RN 0.69 project, not as simple as it seems. There is no (easily accessible) documentation on how to install expo on a previous version, only the current one...
If this project allows to self host a bundle and provides some similar options as code push for updating inside the native apps (silent update in the background, mandatory update, manual update), then it's certainly the simplest way to go.

@tanujs95
Copy link

Hey @regalstreak @gronxb ,
Could you please provide an update on the status of this PR? I was looking to try out this plugin, and if I want to contribute, where should I start? It would be helpful to have a checklist of the remaining tasks so contributors can assist in closing this PR.

@gronxb
Copy link
Owner

gronxb commented Feb 14, 2025

@regalstreak Are you planning to continue working on the PR? If you don’t have time, it would be great if you could at leave a comment.

@regalstreak
Copy link
Contributor Author

Planning to continue on it from next week, didn't get a lot of time this week. Will have the changes ready by Wednesday

@gronxb
Copy link
Owner

gronxb commented Feb 14, 2025

@tanujs95

I see the remaining tasks as follows:

  1. The first priority is completing the plugin itself.
  2. The second priority is documenting the API specifications.

This plugin delegates the actual API implementation to the user, so it’s important to define a clear specification and provide utility functions to make the implementation easier.

For example, by passing a list to the following function:
🔗 getUpdateInfo.ts
users can check for updates using only JS logic.

For PostgreSQL, it can be implemented using:
🔗 update-server/index.ts (Supabase)
🔗 get_update_info.sql
🔗 get_update_info.spec.ts

The most important part now is figuring out how to effectively communicate this guidance to users.

@gronxb gronxb changed the title feat: self hosted api plugin feat(standalone): api-based standaloneRepository database plugin Feb 20, 2025
Copy link
Owner

@gronxb gronxb left a comment

Choose a reason for hiding this comment

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

Super Thanks

I’ve added the test code and merged it. Version 0.10.1 has been released. What’s left is to provide users with an implementation that makes it easy to follow the specification. It will probably be something like pnpm create @hot-updater/custom-server --template standalone-node.

https://www.npmjs.com/package/@hot-updater/standalone

@gronxb gronxb merged commit c2dd276 into gronxb:main Feb 20, 2025
1 check 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.

6 participants