Bundles
Copia un prompt de configuración con los pasos de instalación y la guía completa en markdown para este plugin.
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.
Comprender los bundles
Sección titulada “Comprender los bundles”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
Creación manual de bundles (sin CLI)
Sección titulada “Creación manual de bundles (sin CLI)”Así puedes crear y subir bundles manualmente sin usar el Capgo CLI:
Paso 1: Compila tu app
Sección titulada “Paso 1: Compila tu app”Primero, compila los assets web de tu app:
npm run buildPaso 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.
Instala los paquetes necesarios
Sección titulada “Instala los paquetes requeridos”npm install adm-zip @tomasklaen/checksumCrear 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 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();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;}
// Usageasync function main() { const checksum = await calculateChecksum('./my-app-1.2.3.zip'); console.log('Checksum:', checksum);}
main();Paso 4: Subir el bundle a tu almacenamiento
Sección titulada “Paso 4: Subir el bundle a tu almacenamiento”Sube tu archivo zip a cualquier almacenamiento accesible desde la web:
# 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"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.ziphttps://github.com/username/repo/releases/download/v1.2.3/bundle.ziphttps://cdn.jsdelivr.net/gh/username/repo@v1.2.3/dist.zip
Paso 5: Registrar el bundle con Capgo API
Sección titulada «Paso 5: Registrar el bundle con Capgo API»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ámetros de API
Sección titulada “Parámetros de API”| Parámetro | Descripción | Obligatorio |
|---|---|---|
app_id | Identificador de tu app | Sí |
version | Bundle (versión) versión semántica (p. ej., “1.2.3”) | Sí |
external_url | Accesible públicamente URL HTTPS desde donde se puede descargar el bundle (sin autenticación) | Sí |
checksum | Checksum SHA256 del archivo zip | Sí |
Requisitos de estructura del bundle
Sección titulada “Requisitos de estructura del bundle”Tu zip del bundle debe cumplir estos requisitos:
- Archivo index en la raíz: Debe tener
index.htmlen el nivel raíz - Integración de Capacitor: Se debe llamar a
notifyAppReady()en tu app code - Rutas de assets: Usa rutas relativas para todos los assets
Estructura de bundle válida
Sección titulada “Estructura de bundle válida”bundle.zip├── index.html├── assets/│ ├── app.js│ └── styles.css└── images/Ejemplo completo de flujo manual
Sección titulada “Ejemplo completo de flujo manual”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:
npm install adm-zip @tomasklaen/checksum node-fetchVerificación de checksum
Sección titulada «Verificación de checksum»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 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();Importancia del checksum
Sección titulada «Importancia del checksum»- 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
Buenas prácticas
Sección titulada “Buenas prácticas”- Gestión de bundles (versiones): Usa versionado semántico consistently
- Optimización de almacenamiento: Elimina periódicamente los bundles no utilizados
- Compatibilidad de bundles (versiones): Establece los requisitos mínimos de versión nativa adecuados
- Estrategia de backup: Mantén copias de seguridad de los bundles críticos (versiones)
Endpoints
Sección titulada “Endpoints”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.
Parámetros de consulta
Sección titulada “Parámetros de consulta”app_id: Obligatorio. El ID de tu apppage: Opcional. Número de página para la paginación (se ignora cuandoversionoidis set)version: Opcional. Nombre exacto de la versión del bundle (app_versions.name, por ejemplo1.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.
Comprobar si existe una versión (CI)
Sección titulada “Comprobar si existe una versión (CI)”Úsalo antes del upload o de la asignación de canal cuando necesites una comprobación HTTP en lugar de CLI:
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.
Tipo de respuesta
Sección titulada “Tipo de respuesta”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}Ejemplo de solicitud
Sección titulada “Ejemplo de solicitud”# 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"
# Look up one bundle by version namecurl -H "authorization: your-api-key" \ "https://api.capgo.app/bundle/?app_id=app_123&version=1.0.0"
# Look up one bundle by idcurl -H "authorization: your-api-key" \ "https://api.capgo.app/bundle/?app_id=app_123&id=456"Ejemplo de respuesta
Sección titulada “Respuesta de ejemplo”[ { "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" }]ELIMINAR
Sección titulada “DELETE”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.
Parámetros de consulta
Sección titulada “Parámetros de consulta”Para eliminar un bundle específico:
interface BundleDelete { app_id: string version: string}Para eliminar todos los bundles:
interface BundleDeleteAll { app_id: string}Solicitudes de ejemplo
Sección titulada “Solicitudes de ejemplo”# 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/Respuesta exitosa
Sección titulada “Respuesta exitosa”{ "status": "ok"}https://api.capgo.app/bundle/
Crea un nuevo bundle con una URL externa.
Cuerpo de la solicitud
Sección titulada “Cuerpo de la solicitud”interface CreateBundleBody { app_id: string version: string external_url: string // Must be publicly accessible HTTPS URL checksum: string}Ejemplo de solicitud
Sección titulada “Ejemplo de solicitud”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/Respuesta exitosa
Sección titulada “Respuesta exitosa”{ "status": "ok"}POST (Metadatos)
Sección titulada “POST (Metadata)”https://api.capgo.app/bundle/metadata
Actualiza los metadatos del bundle, como el enlace y la información del comentario.
Cuerpo de la solicitud
Sección titulada “Cuerpo de la solicitud”interface UpdateMetadataBody { app_id: string version_id: number // bundle (version) id link?: string comment?: string}Ejemplo de solicitud
Sección titulada “Ejemplo de solicitud”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/metadataRespuesta exitosa
Sección titulada “Respuesta exitosa”{ "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.
Cuerpo de la solicitud
Sección titulada “Cuerpo de la solicitud”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).
Ejemplo de solicitud
Sección titulada “Ejemplo de solicitud”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/Respuesta exitosa
Sección titulada “Respuesta exitosa”{ "status": "success", "message": "Bundle 1.0.0 set to channel production"}Manejo de errores
Sección titulada “Manejo de errores”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": {}}Casos de uso comunes
Sección titulada “Casos de uso comunes”- Limpiar bundles antiguos (versiones)
// Delete outdated beta bundles (versions){ "app_id": "app_123", "version": "1.0.0-beta.1"}- App Reset
// Remove all bundles to start fresh{ "app_id": "app_123"}Consideraciones de almacenamiento
Sección titulada “Consideraciones de almacenamiento”- Política de retención: Define cuánto tiempo conservar los bundles antiguos
- Gestión del tamaño: Monitor bundle sizes and storage usage
- Estrategia de backup: Consider backing up critical bundles (versions)
- Optimización de costos: Elimina los bundles innecesarios para optimizar los costos de almacenamiento
Continuar desde Bundles
Sección titulada “Continuar desde Bundles”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.