Saltar al contenido

Bundles

Los bundles son los paquetes de actualización principales en Capgo. Cada bundle contiene los recursos web (HTML, CSS, JS) que componen el contenido de tu app. La API de Bundles API te permite gestionar estos paquetes de actualización, incluida su lista y eliminación.

Un bundle representa una versión específica del contenido web de tu app e incluye:

  • Bundle (versión): Número de versión semántica del bundle
  • Checksum: Hash único para verificar la integridad del bundle
  • Info de almacenamiento: Detalles sobre dónde y cómo se almacena el bundle
  • Requisitos nativos: Requisitos mínimos de la versión de la app nativa
  • Metadatos: Fecha de creación, propiedad y otros datos de seguimiento

Así puedes crear y subir bundles manualmente sin usar el Capgo CLI:

Primero, compila los assets web de tu app:

Ventana de terminal
npm run build

Paso 2: Crea el zip del bundle usando los mismos paquetes que Capgo CLI

Sección titulada “Paso 2: Crea el zip del bundle usando los mismos paquetes que Capgo CLI”

Importante: Usa exactamente los mismos paquetes de JavaScript que Capgo CLI utiliza internamente para garantizar la compatibilidad.

Ventana de terminal
npm install adm-zip @tomasklaen/checksum

Crear bundle ZIP con JavaScript (igual que Capgo CLI)

Sección titulada “Crear bundle ZIP con JavaScript (igual que Capgo CLI)”

Nota: en los ejemplos siguientes, version se refiere al nombre del bundle (versión) que usa 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();

Paso 3: Calcular el checksum SHA256 usando el mismo paquete que CLI

Sección titulada “Paso 3: Calcular el checksum SHA256 usando el mismo paquete que 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();

Sube tu archivo zip a cualquier almacenamiento accesible desde la web:

Ventana de 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"

Importante: Tu bundle debe ser accesible públicamente vía URL HTTPS (sin autenticación). Los servidores de Capgo necesitan descargar el bundle desde esta URL.

Ejemplos de URLs públicas válidas:

  • 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

Registra el bundle externo con Capgo usando llamadas directas a API:

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;
}
ParámetroDescripciónObligatorio
app_idIdentificador de tu appSí
versionBundle (versión) versión semántica (p. ej., “1.2.3”)Sí
external_urlAccesible públicamente URL HTTPS desde donde se puede descargar el bundle (sin autenticación)Sí
checksumChecksum SHA256 del archivo zipSí

Tu zip del bundle debe cumplir estos requisitos:

  1. Archivo index en la raíz: Debe tener index.html en el nivel raíz
  2. Integración de Capacitor: Se debe llamar a notifyAppReady() en tu app code
  3. Rutas de assets: Usa rutas relativas para todos los assets
bundle.zip
├── index.html
├── assets/
│ ├── app.js
│ └── styles.css
└── images/

Script simple de Node.js para comprimir, calcular checksum y hacer upload a 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);

Instala las dependencias:

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

Cálculo de checksum en JavaScript (igual que Capgo CLI)

Sección titulada «Cálculo de checksum en JavaScript (igual que Capgo CLI)»

Usa exactamente el mismo paquete y método que Capgo CLI utiliza internamente:

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();
  • Integridad del bundle: Garantiza que el bundle no se haya corrupto durante la transferencia
  • Verificación de API: Capgo verifica las sumas de verificación antes de aceptar bundles
  • Verificación de plugins: El plugin móvil verifica las sumas de verificación antes de aplicar actualizaciones
  1. Gestión de bundles (versiones): Usa versionado semántico consistently
  2. Optimización de almacenamiento: Elimina periódicamente los bundles no utilizados
  3. Compatibilidad de bundles (versiones): Establece los requisitos mínimos de versión nativa adecuados
  4. Estrategia de backup: Mantén copias de seguridad de los bundles críticos (versiones)

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

Recupera información del bundle. Sin filtros, devuelve 50 bundles por página. Con version o id, devuelve la misma forma de array JSON con cero o un bundle.

  • app_id: Obligatorio. El ID de tu app
  • page: Opcional. Número de página para la paginación (se ignora cuando version o id is set)
  • version: Opcional. Nombre exacto de la versión del bundle (app_versions.name, por ejemplo 1.2.3). Devuelve un array JSON con cero o un elemento.
  • id: Opcional. ID numérico del bundle (app_versions.id). Devuelve un array JSON con cero o un elemento.

Usa la misma authorization encabezado y la clave API para el alcance de la app como la lista paginada. Los valores rechazados por la validación del query-schema devuelven un invalid_query error.

Úsalo antes del upload o de la asignación de canal cuando necesites una comprobación HTTP en lugar de CLI:

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

Un array JSON no vacío indica que esa versión ya existe para la app. Un array vacío significa que no.

Para los workflows de upload, el flag Capgo CLI bundle upload --version-exists-ok ya finaliza correctamente cuando la versión de destino existe, lo que cubre muchos jobs de CI sin llamar a este endpoint.

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
}
Ventana de 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/

Elimina uno o todos los bundles de una app. Úsalo con precaución, ya que esta acción no se puede deshacer.

Para eliminar un bundle específico:

interface BundleDelete {
app_id: string
version: string
}

Para eliminar todos los bundles:

interface BundleDeleteAll {
app_id: string
}
Ventana de 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/

Crea un nuevo bundle con una URL externa.

interface CreateBundleBody {
app_id: string
version: string
external_url: string // Must be publicly accessible HTTPS URL
checksum: string
}
Ventana de 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

Actualiza los metadatos del bundle, como el enlace y la información del comentario.

interface UpdateMetadataBody {
app_id: string
version_id: number // bundle (version) id
link?: string
comment?: string
}
Ventana de 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/

Asigna un bundle a un canal específico. Esto vincula un bundle (versión) a un canal para su distribución.

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

target controla dónde se vincula el bundle cuando el canal tiene configurado un progressive rollout:

  • auto — el objetivo del rollout si hay progressive rollout configurado; de lo contrario, stable (por defecto).
  • rollout — siempre define el objetivo de rollout; el fallback estable no cambia.
  • stable — reemplaza el fallback a stable (escape hatch).
Ventana de 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"
}

Todos los errores utilizan el formato estándar descrito en la visión general de API.

Escenarios de error comunes y sus respuestas:

// 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. Limpiar bundles antiguos (versiones)
// Delete outdated beta bundles (versions)
{
"app_id": "app_123",
"version": "1.0.0-beta.1"
}
  1. App Reset
// Remove all bundles to start fresh
{
"app_id": "app_123"
}
  1. Política de retención: Define cuánto tiempo conservar los bundles antiguos
  2. Gestión del tamaño: Monitor bundle sizes and storage usage
  3. Estrategia de backup: Consider backing up critical bundles (versions)
  4. Optimización de costos: Elimina los bundles innecesarios para optimizar los costos de almacenamiento

Si estás usando Bundles para planificar el almacenamiento y la gestión de archivos, conéctalo con @capgo/capacitor-data-storage-sqlite para el detalle de implementación en @capgo/capacitor-data-storage-sqlite, Uso de @capgo/capacitor-data-storage-sqlite para la funcionalidad nativa en Uso de @capgo/capacitor-data-storage-sqlite, @capgo/capacitor-file para el detalle de implementación en @capgo/capacitor-file, Uso de @capgo/capacitor-file para la funcionalidad nativa en Uso de @capgo/capacitor-file, y @capgo/capacitor-uploader para el detalle de implementación en @capgo/capacitor-uploader.