Langsung ke konten

Bundle

Bundle adalah paket update utama di Capgo. Setiap bundle berisi aset web (HTML, CSS, JS) yang membentuk konten aplikasi Anda. API Bundles memungkinkan Anda mengelola paket update ini, termasuk melihat daftar dan menghapusnya.

Sebuah bundle merepresentasikan versi spesifik dari konten web aplikasi Anda dan mencakup:

  • Bundle (versi): Nomor versi semantik untuk bundle tersebut
  • Checksum: Hash unik untuk verifikasi integritas bundle
  • Info Penyimpanan: Detail mengenai lokasi dan cara bundle disimpan
  • Persyaratan Native: Syarat minimum versi aplikasi native
  • Metadata: Waktu pembuatan, kepemilikan, dan info pelacakan lainnya

Membuat Bundle Secara Manual (Tanpa CLI)

Bagian berjudul “Pembuatan Bundle Manual (Tanpa CLI)”

Berikut cara membuat dan upload bundle secara manual tanpa menggunakan Capgo CLI:

Pertama, build web assets aplikasi Anda:

Jendela terminal
npm run build

Langkah 2: Buat Bundle Zip Menggunakan Package yang Sama dengan Capgo CLI

Bagian berjudul “Langkah 2: Buat Bundle Zip Menggunakan Package yang Sama dengan Capgo CLI”

Penting: Gunakan package JavaScript yang persis sama dengan yang digunakan Capgo CLI secara internal untuk memastikan kompatibilitas.

Jendela terminal
npm install adm-zip @tomasklaen/checksum

Buat Zip Bundle dengan JavaScript (Sama dengan Capgo CLI)

Bagian berjudul “Buat Zip Bundle dengan JavaScript (Sama dengan Capgo CLI)”

Catatan: Dalam contoh di bawah ini, version merujuk pada nama bundle (versi) yang digunakan oleh API.

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 CLI
function 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
};
}
// Usage
async 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 Package yang Sama dengan CLI

Bagian berjudul “Langkah 3: Hitung SHA256 Checksum Menggunakan Package 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;
}
// Usage
async function main() {
const checksum = await calculateChecksum('./my-app-1.2.3.zip');
console.log('Checksum:', checksum);
}
main();

Unggah file zip Anda ke penyimpanan web apa pun:

Jendela terminal
# Example: Upload to your server via scp
scp my-app-1.2.3.zip user@your-server.com:/var/www/bundles/
# Example: Upload to S3 using AWS CLI
aws s3 cp my-app-1.2.3.zip s3://your-bucket/bundles/
# Example: Upload via curl to a custom endpoint
curl -X POST https://your-storage-api.com/upload \
-H "Authorization: Bearer YOUR_TOKEN" \
-F "file=@my-app-1.2.3.zip"

Penting: Bundle Anda harus dapat diakses secara publik melalui URL HTTPS (tanpa autentikasi). Server Capgo perlu mengunduh bundle dari URL ini.

Contoh URL publik yang valid:

  • https://your-storage.com/bundles/my-app-1.2.3.zip
  • https://github.com/username/repo/releases/download/v1.2.3/bundle.zip
  • https://cdn.jsdelivr.net/gh/username/repo@v1.2.3/dist.zip

Daftarkan bundle eksternal ke Capgo menggunakan panggilan API langsung:

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;
}
ParameterDeskripsiWajib
app_idIdentifier aplikasi AndaYa
versionBundle (versi) versi semantik (misalnya, “1.2.3”)Ya
external_urlDapat diakses publik URL HTTPS untuk download bundle (tanpa auth)Ya
checksumChecksum SHA256 dari file zipYa

Zip bundle Anda harus memenuhi persyaratan berikut:

  1. File Index Root: Wajib memiliki index.html di level root
  2. Integrasi Capacitor: Wajib memanggil notifyAppReady() di app Anda code
  3. Path Aset: Gunakan path relatif untuk semua aset
bundle.zip
├── index.html
├── assets/
│ ├── app.js
│ └── styles.css
└── images/

Script Node.js sederhana untuk zip, checksum, dan upload ke 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);

Instal dependensi:

Jendela terminal
npm install adm-zip @tomasklaen/checksum node-fetch

Perhitungan Checksum JavaScript (Sama dengan Capgo CLI)

Bagian berjudul “Perhitungan Checksum JavaScript (Sama dengan Capgo CLI)”

Gunakan package dan method yang sama persis seperti yang dipakai Capgo CLI secara internal:

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 matches
async 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;
}
// Usage
async function main() {
const bundleChecksum = await calculateChecksum('./my-app-1.2.3.zip');
console.log('SHA256 Checksum:', bundleChecksum);
}
main();
  • Integritas Bundle: Memastikan bundle tidak rusak selama transfer
  • Verifikasi API: Capgo memverifikasi checksum sebelum menerima bundle
  • Verifikasi Plugin: Plugin mobile memverifikasi checksum sebelum menerapkan update
  1. Manajemen Bundle (versi): Gunakan semantic versioning secara konsisten
  2. Optimasi Penyimpanan: Hapus bundle yang tidak terpakai secara berkala
  3. Kompatibilitas Bundle (versi): Atur persyaratan versi native minimum yang sesuai
  4. Strategi Backup: Simpan backup bundle penting (versi)

https://api.capgo.app/bundle/

Ambil informasi bundle. Tanpa filter, mengembalikan 50 bundle per halaman. Dengan version atau id, mengembalikan bentuk array JSON yang sama dengan nol atau satu bundle.

  • app_id: Wajib. ID aplikasi Anda
  • page: Opsional. Nomor halaman untuk paginasi (diabaikan saat version atau id telah diatur)
  • version: Opsional. Nama versi bundle yang tepat ("app_versions.name, contohnya 1.2.3). Mengembalikan array JSON dengan nol atau satu item.
  • id: Opsional. ID bundle numerik ("app_versions.id). Mengembalikan array JSON dengan nol atau satu item.

Gunakan yang sama authorization header dan kunci API untuk pembatasan scope aplikasi seperti pada daftar paginasi. Nilai yang ditolak oleh validasi query-schema akan mengembalikan invalid_query error.

Gunakan ini sebelum upload atau penugasan channel jika Anda memerlukan pengecekan HTTP alih-alih CLI:

Jendela terminal
curl -H "authorization: YOUR_API_KEY" \
"https://api.capgo.app/bundle/?app_id=com.example.app&version=1.2.3"

Array JSON yang tidak kosong berarti versi tersebut sudah ada untuk aplikasi ini. Array kosong berarti belum ada.

Untuk workflow upload, flag Capgo CLI bundle upload --version-exists-ok sudah berhasil dieksekusi jika versi target sudah ada, sehingga banyak job CI tidak perlu memanggil endpoint ini.

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
}
Jendela terminal
# Get all bundles
curl -H "authorization: your-api-key" \
"https://api.capgo.app/bundle/?app_id=app_123"
# Get next page
curl -H "authorization: your-api-key" \
"https://api.capgo.app/bundle/?app_id=app_123&page=1"
# Look up one bundle by version name
curl -H "authorization: your-api-key" \
"https://api.capgo.app/bundle/?app_id=app_123&version=1.0.0"
# Look up one bundle by id
curl -H "authorization: your-api-key" \
"https://api.capgo.app/bundle/?app_id=app_123&id=456"
[
{
"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"
}
]

https://api.capgo.app/bundle/

Hapus satu atau semua bundle untuk sebuah app. Gunakan dengan hati-hati karena tindakan ini tidak bisa dibatalkan.

Untuk menghapus bundle tertentu:

interface BundleDelete {
app_id: string
version: string
}

Untuk menghapus semua bundle:

interface BundleDeleteAll {
app_id: string
}
Jendela terminal
# Delete specific bundle
curl -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 bundles
curl -X DELETE \
-H "authorization: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"app_id": "app_123"
}' \
https://api.capgo.app/bundle/
{
"status": "ok"
}

https://api.capgo.app/bundle/

Buat bundle baru dengan URL eksternal.

interface CreateBundleBody {
app_id: string
version: string
external_url: string // Must be publicly accessible HTTPS URL
checksum: string
}
Jendela terminal
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/
{
"status": "ok"
}

https://api.capgo.app/bundle/metadata

Perbarui metadata bundle seperti informasi link dan komentar.

interface UpdateMetadataBody {
app_id: string
version_id: number // bundle (version) id
link?: string
comment?: string
}
Jendela terminal
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/metadata
{
"status": "success"
}

https://api.capgo.app/bundle/

Atur bundle ke channel tertentu. Ini menghubungkan bundle (versi) ke channel untuk distribusi.

interface SetChannelBody {
app_id: string
version_id: number // bundle (version) id
channel_id: number
target?: "auto" | "stable" | "rollout" // default: auto
}

target mengontrol ke mana bundle di-link saat channel dikonfigurasi dengan progressive rollout:

  • auto — target rollout saat progressive rollout dikonfigurasi; jika tidak, stable (default).
  • rollout — selalu set target rollout; fallback stable tidak berubah.
  • stable — ganti fallback stable (escape hatch).
Jendela terminal
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/
{
"status": "success",
"message": "Bundle 1.0.0 set to channel production"
}

Semua error menggunakan format error standar yang dijelaskan di Ikhtisar API.

Skenario error umum dan responsnya:

// app_id is not a reverse-domain identifier
{
"error": "invalid_app_id",
"message": "App ID must be a reverse domain string",
"moreInfo": { "app_id": "my app" }
}
// Deleting a bundle without access to the app
{
"error": "cannot_delete_bundle",
"message": "You can't access this app",
"moreInfo": { "app_id": "com.example.app" }
}
// Deleting a bundle that a channel still uses
{
"error": "cannot_delete_linked_version",
"message": "Cannot delete a bundle linked to a channel",
"moreInfo": { "app_id": "com.example.app", "version": "1.0.0" }
}
// Creating a bundle whose version is not valid semver
{
"error": "invalid_version_format",
"message": "Version must be valid semver format (e.g., 1.0.0, 1.0.0-alpha.1)",
"moreInfo": { "version": "v1" }
}
// Setting a channel to a bundle that does not exist
{
"error": "cannot_find_version",
"message": "Cannot find version",
"moreInfo": {}
}
  1. Bersihkan Bundle Lama (Versi)
// Delete outdated beta bundles (versions)
{
"app_id": "app_123",
"version": "1.0.0-beta.1"
}
  1. Reset Aplikasi
// Remove all bundles to start fresh
{
"app_id": "app_123"
}
  1. Kebijakan Retensi: Tentukan berapa lama bundle lama disimpan
  2. Manajemen Ukuran: Pantau ukuran bundle dan penggunaan storage
  3. Strategi Backup: Pertimbangkan backup bundle penting (versi)
  4. Optimasi Biaya: Hapus bundle yang tidak perlu untuk optimasi biaya storage

Jika Anda menggunakan Bundle untuk merencanakan penyimpanan dan penanganan file, hubungkan dengan @capgo/capacitor-data-storage-sqlite untuk detail implementasi di @capgo/capacitor-data-storage-sqlite, Menggunakan @capgo/capacitor-data-storage-sqlite untuk kapabilitas native di Menggunakan @capgo/capacitor-data-storage-sqlite, @capgo/capacitor-file untuk detail implementasi di @capgo/capacitor-file, Menggunakan @capgo/capacitor-file untuk kemampuan native di Menggunakan @capgo/capacitor-file, dan @capgo/capacitor-uploader untuk detail implementasi di @capgo/capacitor-uploader.