Bundles
Bundles adalah paket pembaruan inti di Capgo. Setiap bundle berisi aset web (HTML, CSS, JS) yang membentuk konten aplikasi Anda. API Bundles memungkinkan Anda mengelola paket pembaruan ini, termasuk daftar dan penghapusannya.
Memahami Bundles
Section titled “Memahami Bundles”Sebuah bundle mewakili versi spesifik dari konten web aplikasi Anda dan mencakup:
- Version: Nomor versi semantik dari bundle
- Checksum: Hash unik untuk memverifikasi integritas bundle
- Storage Info: Detail tentang di mana dan bagaimana bundle disimpan
- Native Requirements: Persyaratan versi aplikasi native minimum
- Metadata: Waktu pembuatan, kepemilikan, dan informasi pelacakan lainnya
Pembuatan Bundle Manual (Tanpa CLI)
Section titled “Pembuatan Bundle Manual (Tanpa CLI)”Berikut cara membuat dan mengunggah bundle secara manual tanpa menggunakan Capgo CLI:
Langkah 1: Bangun Aplikasi Anda
Section titled “Langkah 1: Bangun Aplikasi Anda”Pertama, bangun aset web aplikasi Anda:
npm run buildLangkah 2: Buat Bundle Zip Menggunakan Paket yang Sama dengan Capgo CLI
Section titled “Langkah 2: Buat Bundle Zip Menggunakan Paket yang Sama dengan Capgo CLI”Penting: Gunakan paket JavaScript yang persis sama dengan yang digunakan Capgo CLI secara internal untuk memastikan kompatibilitas.
Instal Paket yang Diperlukan
Section titled “Instal Paket yang Diperlukan”npm install adm-zip @tomasklaen/checksumBuat Bundle Zip dengan JavaScript (Sama dengan Capgo CLI)
Section titled “Buat Bundle Zip dengan JavaScript (Sama dengan Capgo CLI)”const fs = require('node:fs');const path = require('node:path');const os = require('node:os');const AdmZip = require('adm-zip');const { checksum: getChecksum } = require('@tomasklaen/checksum');
// Exact same implementation as Capgo CLIfunction zipFileUnix(filePath) { const zip = new AdmZip(); zip.addLocalFolder(filePath); return zip.toBuffer();}
async function zipFileWindows(filePath) { console.log('Zipping file windows mode'); const zip = new AdmZip();
const addToZip = (folderPath, zipPath) => { const items = fs.readdirSync(folderPath);
for (const item of items) { const itemPath = path.join(folderPath, item); const stats = fs.statSync(itemPath);
if (stats.isFile()) { const fileContent = fs.readFileSync(itemPath); zip.addFile(path.join(zipPath, item).split(path.sep).join('/'), fileContent); } else if (stats.isDirectory()) { addToZip(itemPath, path.join(zipPath, item)); } } };
addToZip(filePath, ''); return zip.toBuffer();}
// Main zipFile function (exact same logic as CLI)async function zipFile(filePath) { if (os.platform() === 'win32') { return zipFileWindows(filePath); } else { return zipFileUnix(filePath); }}
async function createBundle(inputPath, outputPath, version) { // Create zip using exact same method as Capgo CLI const zipped = await zipFile(inputPath);
// Write to file fs.writeFileSync(outputPath, zipped);
// Calculate checksum using exact same package as CLI const checksum = await getChecksum(zipped, 'sha256');
return { filename: path.basename(outputPath), version: version, size: zipped.length, checksum: checksum };}
// Usageasync function main() { try { const result = await createBundle('./dist', './my-app-1.2.3.zip', '1.2.3'); console.log('Bundle info:', JSON.stringify(result, null, 2)); } catch (error) { console.error('Error creating bundle:', error); }}
main();Langkah 3: Hitung Checksum SHA256 Menggunakan Paket yang Sama dengan CLI
Section titled “Langkah 3: Hitung Checksum SHA256 Menggunakan Paket yang Sama dengan CLI”const fs = require('node:fs');const { checksum: getChecksum } = require('@tomasklaen/checksum');
async function calculateChecksum(filePath) { const fileBuffer = fs.readFileSync(filePath); // Use exact same package and method as Capgo CLI const checksum = await getChecksum(fileBuffer, 'sha256'); return checksum;}
// Usageasync function main() { const checksum = await calculateChecksum('./my-app-1.2.3.zip'); console.log('Checksum:', checksum);}
main();Langkah 4: Unggah Bundle ke Penyimpanan Anda
Section titled “Langkah 4: Unggah Bundle ke Penyimpanan Anda”Upload your zip file to any web-accessible storage:
# Example: Upload to your server via scpscp my-app-1.2.3.zip user@your-server.com:/var/www/bundles/
# Example: Upload to S3 using AWS CLIaws s3 cp my-app-1.2.3.zip s3://your-bucket/bundles/
# Example: Upload via curl to a custom endpointcurl -X POST https://your-storage-api.com/upload \ -H "Authorization: Bearer YOUR_TOKEN" \ -F "file=@my-app-1.2.3.zip"Important: Your bundle must be publicly accessible via HTTPS URL (no authentication required). Capgo’s servers need to download the bundle from this URL.
Examples of valid public URLs:
https://your-storage.com/bundles/my-app-1.2.3.ziphttps://github.com/username/repo/releases/download/v1.2.3/bundle.ziphttps://cdn.jsdelivr.net/gh/username/repo@v1.2.3/dist.zip
Langkah 5: Daftarkan Bundle dengan API Capgo
Section titled “Langkah 5: Daftarkan Bundle dengan API Capgo”Register the external bundle with Capgo using direct API calls:
async function registerWithCapgo(appId, version, bundleUrl, checksum, apiKey) { const fetch = require('node-fetch');
// Create bundle version const response = await fetch('https://api.capgo.app/bundle/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'authorization': apiKey }, body: JSON.stringify({ app_id: appId, version: version, external_url: bundleUrl, checksum: checksum }) });
if (!response.ok) { throw new Error(`Failed to create bundle: ${response.statusText}`); }
const data = await response.json(); console.log('Bundle created:', data);
return data;}Parameter API
Section titled “Parameter API”| Parameter | Description | Required |
|---|---|---|
app_id | Your app identifier | Yes |
version | Semantic version (e.g., “1.2.3”) | Yes |
external_url | Publicly accessible HTTPS URL where bundle can be downloaded (no auth required) | Yes |
checksum | SHA256 checksum of the zip file | Yes |
Persyaratan Struktur Bundle
Section titled “Persyaratan Struktur Bundle”Your bundle zip must follow these requirements:
- Root Index File: Must have
index.htmlat the root level - Capacitor Integration: Must call
notifyAppReady()in your app code - Asset Paths: Use relative paths for all assets
Struktur Bundle yang Valid
Section titled “Struktur Bundle yang Valid”bundle.zip├── index.html├── assets/│ ├── app.js│ └── styles.css└── images/Contoh Alur Kerja Manual Lengkap
Section titled “Contoh Alur Kerja Manual Lengkap”Simple Node.js script to zip, checksum, and upload to Capgo:
const fs = require('node:fs');const os = require('node:os');const AdmZip = require('adm-zip');const { checksum: getChecksum } = require('@tomasklaen/checksum');const fetch = require('node-fetch');
async function deployToCapgo() { const APP_ID = 'com.example.app'; const VERSION = '1.2.3'; const BUNDLE_URL = 'https://your-storage.com/bundles/app-1.2.3.zip'; const API_KEY = process.env.CAPGO_API_KEY;
// 1. Create zip (same as Capgo CLI) const zip = new AdmZip(); zip.addLocalFolder('./dist'); const zipped = zip.toBuffer();
// 2. Calculate checksum (same as Capgo CLI) const checksum = await getChecksum(zipped, 'sha256'); console.log('Checksum:', checksum);
// 3. Upload to your storage (replace with your upload logic) // fs.writeFileSync('./bundle.zip', zipped); // ... upload bundle.zip to your storage ...
// 4. Register with Capgo API const response = await fetch('https://api.capgo.app/bundle/', { method: 'POST', headers: { 'Content-Type': 'application/json', 'authorization': API_KEY }, body: JSON.stringify({ app_id: APP_ID, version: VERSION, external_url: BUNDLE_URL, checksum: checksum }) });
if (!response.ok) { throw new Error(`Failed: ${response.statusText}`); }
console.log('Bundle registered with Capgo!');}
deployToCapgo().catch(console.error);Install dependencies:
npm install adm-zip @tomasklaen/checksum node-fetchVerifikasi Checksum
Section titled “Verifikasi Checksum”Perhitungan Checksum JavaScript (Sama dengan Capgo CLI)
Section titled “Perhitungan Checksum JavaScript (Sama dengan Capgo CLI)”Use the exact same package and method that Capgo CLI uses internally:
const fs = require('node:fs');const { checksum: getChecksum } = require('@tomasklaen/checksum');
async function calculateChecksum(filePath) { const fileBuffer = fs.readFileSync(filePath); // Use exact same package and method as Capgo CLI const checksum = await getChecksum(fileBuffer, 'sha256'); return checksum;}
// Verify checksum matchesasync function verifyChecksum(filePath, expectedChecksum) { const actualChecksum = await calculateChecksum(filePath); const isValid = actualChecksum === expectedChecksum;
console.log(`File: ${filePath}`); console.log(`Expected: ${expectedChecksum}`); console.log(`Actual: ${actualChecksum}`); console.log(`Valid: ${isValid}`);
return isValid;}
// Usageasync function main() { const bundleChecksum = await calculateChecksum('./my-app-1.2.3.zip'); console.log('SHA256 Checksum:', bundleChecksum);}
main();Pentingnya Checksum
Section titled “Pentingnya Checksum”- Bundle Integrity: Ensures the bundle hasn’t been corrupted during transfer
- API Verification: Capgo verifies checksums before accepting bundles
- Plugin Verification: The mobile plugin verifies checksums before applying updates
Best Practices
Section titled “Best Practices”- Version Management: Use semantic versioning consistently
- Storage Optimization: Remove unused bundles periodically
- Version Compatibility: Set appropriate minimum native version requirements
- Backup Strategy: Maintain backups of critical bundle versions
Endpoints
Section titled “Endpoints”https://api.capgo.app/bundle/
Retrieve bundle information. Returns 50 bundles per page.
Parameter Query
Section titled “Parameter Query”app_id: Required. The ID of your apppage: Optional. Page number for pagination
Tipe Respons
Section titled “Tipe Respons”interface Bundle { app_id: string bucket_id: string | null checksum: string | null created_at: string | null deleted: boolean external_url: string | null id: number minUpdateVersion: string | null name: string native_packages: Json[] | null owner_org: string r2_path: string | null session_key: string | null storage_provider: string updated_at: string | null user_id: string | null}Contoh Permintaan
Section titled “Contoh Permintaan”# Get all bundlescurl -H "authorization: your-api-key" \ "https://api.capgo.app/bundle/?app_id=app_123"
# Get next pagecurl -H "authorization: your-api-key" \ "https://api.capgo.app/bundle/?app_id=app_123&page=1"Contoh Respons
Section titled “Contoh Respons”{ "data": [ { "id": 1, "app_id": "app_123", "name": "1.0.0", "checksum": "abc123...", "minUpdateVersion": "1.0.0", "storage_provider": "r2", "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z", "deleted": false, "owner_org": "org_123", "user_id": "user_123" } ]}DELETE
Section titled “DELETE”https://api.capgo.app/bundle/
Delete one or all bundles for an app. Use with caution as this action cannot be undone.
Parameter Query
Section titled “Parameter Query”For deleting a specific bundle:
interface BundleDelete { app_id: string version: string}For deleting all bundles:
interface BundleDeleteAll { app_id: string}Contoh Permintaans
Section titled “Contoh Permintaans”# Delete specific bundlecurl -X DELETE \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "app_id": "app_123", "version": "1.0.0" }' \ https://api.capgo.app/bundle/
# Delete all bundlescurl -X DELETE \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "app_id": "app_123" }' \ https://api.capgo.app/bundle/Respons Sukses
Section titled “Respons Sukses”{ "status": "ok"}https://api.capgo.app/bundle/
Create a new bundle with external URL.
Request Body
Section titled “Request Body”interface CreateBundleBody { app_id: string version: string external_url: string // Must be publicly accessible HTTPS URL checksum: string}Contoh Permintaan
Section titled “Contoh Permintaan”curl -X POST \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "app_id": "com.example.app", "version": "1.2.3", "external_url": "https://your-storage.com/bundles/app-1.2.3.zip", "checksum": "a1b2c3d4e5f6789abcdef123456789abcdef123456789abcdef123456789abcd" }' \ https://api.capgo.app/bundle/Respons Sukses
Section titled “Respons Sukses”{ "status": "ok"}POST (Metadata)
Section titled “POST (Metadata)”https://api.capgo.app/bundle/metadata
Update bundle metadata such as link and comment information.
Request Body
Section titled “Request Body”interface UpdateMetadataBody { app_id: string version_id: number link?: string comment?: string}Contoh Permintaan
Section titled “Contoh Permintaan”curl -X POST \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "app_id": "app_123", "version_id": 456, "link": "https://github.com/myorg/myapp/releases/tag/v1.0.0", "comment": "Fixed critical bug in authentication" }' \ https://api.capgo.app/bundle/metadataRespons Sukses
Section titled “Respons Sukses”{ "status": "success"}https://api.capgo.app/bundle/
Set a bundle to a specific channel. This links a bundle version to a channel for distribution.
Request Body
Section titled “Request Body”interface SetChannelBody { app_id: string version_id: number channel_id: number}Contoh Permintaan
Section titled “Contoh Permintaan”curl -X PUT \ -H "authorization: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "app_id": "app_123", "version_id": 456, "channel_id": 789 }' \ https://api.capgo.app/bundle/Respons Sukses
Section titled “Respons Sukses”{ "status": "success", "message": "Bundle 1.0.0 set to channel production"}Penanganan Kesalahan
Section titled “Penanganan Kesalahan”Common error scenarios and their responses:
// Bundle not found{ "error": "Bundle not found", "status": "KO"}
// Invalid version format{ "error": "Invalid version format", "status": "KO"}
// Storage error{ "error": "Failed to delete bundle from storage", "status": "KO"}
// Permission denied{ "error": "Insufficient permissions to manage bundles", "status": "KO"}Kasus Penggunaan Umum
Section titled “Kasus Penggunaan Umum”- Cleanup Old Versions
// Delete outdated beta versions{ "app_id": "app_123", "version": "1.0.0-beta.1"}- App Reset
// Remove all bundles to start fresh{ "app_id": "app_123"}Pertimbangan Penyimpanan
Section titled “Pertimbangan Penyimpanan”- Retention Policy: Define how long to keep old bundles
- Size Management: Monitor bundle sizes and storage usage
- Backup Strategy: Consider backing up critical versions
- Cost Optimization: Remove unnecessary bundles to optimize storage costs