Select the types of activity you want to include in your feed.
refactor: update AltStore ADP handling by removing static source.json; implement dynamic serving via site Worker and adjust related documentation for clarity
···5555- **Config:** [wrangler.jsonc](wrangler.jsonc) — assets binding, ORBYT_API service, R2 bucket binding
5656- **Deploy Command:** `npm run build && npx wrangler deploy`
5757- **Pages cleanup:** If you previously created a Pages project, see [docs/CLOUDFLARE_PAGES_CLEANUP.md](docs/CLOUDFLARE_PAGES_CLEANUP.md)
5858-- **AltStore ADP:** hosted in Cloudflare R2; only `public/altstore/source.json` and `public/altstore/orbyt-icon.png` stay in site assets
5858+- **AltStore ADP:** hosted in Cloudflare R2; source JSON is served dynamically at `/altstore/source.json` via `src/pages/altstore/source.json.ts`, and `public/altstore/orbyt-icon.png` remains static
5959- **AltStore Runbook:** see [docs/ALTSTORE_FINISH_SETUP.md](docs/ALTSTORE_FINISH_SETUP.md) → "Quick Release Checklist"
60606161## Project Structure
+9-7
docs/ALTSTORE_FINISH_SETUP.md
···4455**Prerequisites:** These instructions assume `orbyt-app` and `orbyt-site` are sibling directories (e.g. both under `orbyt-master`). Run commands from the parent directory, or adjust paths to your layout.
6677-**Cloudflare note:** Do not deploy the ADP folder from `public/`. The IPA files are larger than Cloudflare Workers static asset limits. Use R2 for the ADP payload and keep only `source.json` and the icon on the website.
77+**Cloudflare note:** Do not deploy the ADP folder from `public/`. The IPA files are larger than Cloudflare Workers static asset limits. Use R2 for the ADP payload. The public source URL (`https://getorbyt.com/altstore/source.json`) is served dynamically by the site Worker and should be managed via `orbyt-api` admin.
8899**Routing note:** `getorbyt.com/*` is served by the Cloudflare Worker route configured in `wrangler.jsonc`, so deploy production with `wrangler deploy`.
1010···91911. create the R2 bucket if needed
92922. enable the public `r2.dev` URL (fallback)
93933. upload `manifest.json`, `signature`, and `variant/*.ipa`
9494-4. update `public/altstore/source.json` so `downloadURL` points to `https://downloads.getorbyt.com/manifest.json` when available, otherwise it falls back to `r2.dev`
9494+4. print the preferred manifest URL (`https://downloads.getorbyt.com/manifest.json` when available, otherwise `r2.dev`) for use in `orbyt-api` admin publish flow
95959696If you want to use a different bucket name, replace `orbyt-altstore-adp` with your preferred name.
9797···124124125125 https://getorbyt.com/altstore/source.json
126126127127-3. Verify the ADP manifest URL stored inside `source.json` returns `200`.
127127+3. Verify the ADP manifest URL referenced by published source JSON returns `200`.
128128129129---
130130···177177rm -rf .altstore/adp
178178mv ../orbyt-app/adp-extracted .altstore/adp
179179180180-# 4) Upload ADP to R2 and update public/altstore/source.json downloadURL
180180+# 4) Upload ADP to R2 and note printed manifest URL
181181npm run altstore:r2 -- setup orbyt-altstore-adp
182182183183-# 5) Deploy production route (getorbyt.com/*)
183183+# 5) In orbyt-api admin, update source downloadURL to printed manifest URL, then publish
184184+185185+# 6) Deploy production route (getorbyt.com/*)
184186npm run build
185187npx wrangler deploy
186188187187-# 6) Verify live URLs
189189+# 7) Verify live URLs
188190curl -sS -o /dev/null -w 'source %{http_code}\n' https://getorbyt.com/altstore/source.json
189191curl -sS -o /dev/null -w 'manifest %{http_code}\n' https://downloads.getorbyt.com/manifest.json
190192191191-# 7) Federate source
193193+# 8) Federate source
192194curl -X POST -H "Content-Type: application/json" -d '{"source":"https://getorbyt.com/altstore/source.json"}' https://api.altstore.io/federate
193195```
194196
+1-1
public/altstore/README.md
···11# AltStore PAL assets
2233- `orbyt-icon.png` — App icon (1024×1024), already added
44-- `source.json` — Hosted from this site at `https://getorbyt.com/altstore/source.json`
44+- `source.json` — Served dynamically at `https://getorbyt.com/altstore/source.json` via the site Worker route (`src/pages/altstore/source.json.ts`)
55- `.altstore/adp/` — Keep extracted ADP contents here locally, then upload them to R2
6677Default manifest host is `https://downloads.getorbyt.com/manifest.json`.
-47
public/altstore/source.json
···11-{
22- "name": "Orbyt",
33- "subtitle": "Video app for Bluesky",
44- "description": "Orbyt is a video-first social app for the Bluesky network, built on the AT Protocol. Available for EU and Japan via AltStore PAL.",
55- "iconURL": "https://getorbyt.com/altstore/orbyt-icon.png",
66- "headerURL": "https://getorbyt.com/images/orbyt-logotype.png",
77- "website": "https://getorbyt.com",
88- "tintColor": "#9B59B6",
99- "fediUsername": "orbyt",
1010- "featuredApps": [
1111- "com.getorbyt.app"
1212- ],
1313- "apps": [
1414- {
1515- "name": "Orbyt",
1616- "bundleIdentifier": "com.getorbyt.app",
1717- "marketplaceID": "6751679299",
1818- "developerName": "Orbyt",
1919- "subtitle": "Video app for Bluesky",
2020- "localizedDescription": "Orbyt is a video-first social app for the Bluesky network.\n\n• Browse video feeds from Bluesky\n• Create and share short-form videos\n• Connect with the AT Protocol community\n• Built with React Native and Expo",
2121- "iconURL": "https://getorbyt.com/altstore/orbyt-icon.png",
2222- "tintColor": "#9B59B6",
2323- "category": "social",
2424- "screenshots": [],
2525- "versions": [
2626- {
2727- "version": "1.1.2",
2828- "buildVersion": "62",
2929- "date": "2026-03-12",
3030- "localizedDescription": "Latest release.",
3131- "downloadURL": "https://downloads.getorbyt.com/manifest.json",
3232- "size": 70307293,
3333- "minOSVersion": "16.4"
3434- }
3535- ],
3636- "appPermissions": {
3737- "privacy": {
3838- "NSCameraUsageDescription": "We need camera access to record videos for posts and take profile photos.",
3939- "NSMicrophoneUsageDescription": "We need microphone access to record audio with your videos.",
4040- "NSPhotoLibraryUsageDescription": "We need access to your photo library to select videos for posts and photos for your profile.",
4141- "NSPhotoLibraryAddUsageDescription": "We need permission to save your videos to the camera roll."
4242- }
4343- }
4444- }
4545- ],
4646- "news": []
4747-}
+4-34
scripts/altstore-r2.sh
···3344ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
55DEFAULT_ADP_DIR="${ALTSTORE_ADP_DIR:-$ROOT_DIR/.altstore/adp}"
66-SOURCE_JSON="$ROOT_DIR/public/altstore/source.json"
76DEFAULT_BUCKET_LOCATION="${R2_BUCKET_LOCATION:-weur}"
87DEFAULT_CUSTOM_MANIFEST_URL="${ALTSTORE_CUSTOM_MANIFEST_URL:-https://downloads.getorbyt.com/manifest.json}"
98···1211Usage:
1312 ./scripts/altstore-r2.sh setup <bucket> [adp_dir]
1413 ./scripts/altstore-r2.sh upload <bucket> [adp_dir]
1515- ./scripts/altstore-r2.sh set-source-url <manifest_url>
1614 ./scripts/altstore-r2.sh check <manifest_url>
17151816Commands:
1917 setup Create the R2 bucket if needed, enable the public r2.dev URL,
2020- upload the ADP directory, and update public/altstore/source.json.
1818+ and upload the ADP directory.
2119 upload Upload the ADP directory to an existing R2 bucket.
2222- set-source-url Update public/altstore/source.json to point at a manifest URL.
2320 check Fetch a manifest URL and print the HTTP status.
24212522Environment:
···4744}
48454946ensure_prereqs() {
5050- require_file "$SOURCE_JSON"
4747+ :
5148}
52495350ensure_adp_dir() {
···133130 done < <(find "$adp_dir" -type f | sort)
134131}
135132136136-set_source_url() {
137137- local manifest_url="$1"
138138-139139- require_file "$SOURCE_JSON"
140140-141141- node --input-type=commonjs - "$SOURCE_JSON" "$manifest_url" <<'NODE'
142142-const fs = require('node:fs');
143143-const [filePath, manifestUrl] = process.argv.slice(2);
144144-const raw = fs.readFileSync(filePath, 'utf8');
145145-const json = JSON.parse(raw);
146146-if (!Array.isArray(json.apps) || json.apps.length === 0) {
147147- throw new Error('source.json has no apps array');
148148-}
149149-if (!Array.isArray(json.apps[0].versions) || json.apps[0].versions.length === 0) {
150150- throw new Error('source.json has no versions array');
151151-}
152152-json.apps[0].versions[0].downloadURL = manifestUrl;
153153-fs.writeFileSync(filePath, `${JSON.stringify(json, null, 2)}\n`);
154154-NODE
155155-156156- echo "Updated source download URL to: $manifest_url"
157157-}
158158-159133check_url() {
160134 local url="$1"
161135 curl -sS -o /dev/null -w '%{http_code} %{url_effective}\n' "$url"
···191165 [[ -n "$dev_url" ]] || fail "Unable to determine r2.dev URL for bucket '$bucket'"
192166193167 manifest_url="$(pick_manifest_url "$dev_url")"
194194- set_source_url "$manifest_url"
195168196169 echo
197170 echo "R2 setup complete."
198171 echo "Manifest URL: $manifest_url"
199199- echo "Next: deploy the site so https://getorbyt.com/altstore/source.json serves the updated metadata."
172172+ echo "Next: update source JSON in orbyt-api admin (downloadURL=$manifest_url), publish, then verify:"
173173+ echo " https://getorbyt.com/altstore/source.json"
200174}
201175202176main() {
···211185 [[ $# -ge 2 ]] || fail "upload requires a bucket name"
212186 ensure_adp_dir "${3:-$DEFAULT_ADP_DIR}"
213187 upload_adp "$2" "${3:-$DEFAULT_ADP_DIR}"
214214- ;;
215215- set-source-url)
216216- [[ $# -eq 2 ]] || fail "set-source-url requires a manifest URL"
217217- set_source_url "$2"
218188 ;;
219189 check)
220190 [[ $# -eq 2 ]] || fail "check requires a manifest URL"
···5858}>;
59596060const DEFAULT_ALTSTORE_SOURCE = 'https://getorbyt.com/altstore/source.json';
6161-/** Same marketplace ID as `public/altstore/source.json` */
6161+/** Same marketplace ID as the canonical source served at `/altstore/source.json` */
6262const DEFAULT_APP_STORE = 'https://apps.apple.com/app/id6751679299';
63636464/** Builds iOS download options based on the visitor's country; AltStore PAL is primary for EU and Japan. */