Overview
Assets are files (APKs, iOS app bundles) stored in Limrun for deployment to instances. The SDK provides methods to create, upload, list, retrieve, and delete assets.
Asset Type
The Asset type contains metadata about uploaded files:
interface Asset {
id : string ;
name : string ;
displayName ?: string ;
os ?: 'ios' | 'android' ;
md5 ?: string ; // Only present if file is uploaded
signedDownloadUrl ?: string ;
signedUploadUrl ?: string ;
}
Creating and Uploading Assets
Get or Create an Asset
Use getOrCreate to reserve an asset name and get upload/download URLs: import Limrun from '@limrun/api' ;
const client = new Limrun ({
apiKey: process . env . LIM_API_KEY ,
});
const asset = await client . assets . getOrCreate ({
name: 'my-app-v1.2.3.apk' ,
});
console . log ( 'Asset ID:' , asset . id );
console . log ( 'Upload URL:' , asset . signedUploadUrl );
console . log ( 'Download URL:' , asset . signedDownloadUrl );
If an asset with this name already exists, md5 will be present in the response.
Check if Upload is Needed
If md5 is present, the file already exists. Compare checksums to skip re-upload: import { createHash } from 'crypto' ;
import { readFile } from 'fs/promises' ;
const data = await readFile ( './my-app.apk' );
const localMd5 = createHash ( 'md5' ). update ( data ). digest ( 'hex' );
if ( asset . md5 && asset . md5 === localMd5 ) {
console . log ( 'File already uploaded, skipping upload' );
} else {
console . log ( 'File needs to be uploaded' );
}
Upload the File
Use the signed upload URL to upload your file: const uploadResponse = await fetch ( asset . signedUploadUrl , {
method: 'PUT' ,
headers: {
'Content-Length' : data . length . toString (),
'Content-Type' : 'application/octet-stream' ,
},
body: data ,
});
if ( uploadResponse . status !== 200 ) {
throw new Error ( `Upload failed: ${ uploadResponse . status } ` );
}
console . log ( 'Upload successful!' );
Simplified Upload with getOrUpload
The SDK provides a convenience method that handles the entire workflow:
import { basename } from 'path' ;
const result = await client . assets . getOrUpload ({
path: './my-app.apk' ,
name: 'my-app-v1.2.3.apk' , // Optional, defaults to filename
});
console . log ( 'Asset ID:' , result . id );
console . log ( 'MD5:' , result . md5 );
console . log ( 'Download URL:' , result . signedDownloadUrl );
This method:
Calls getOrCreate to reserve the asset name
Calculates local file MD5
Compares with server MD5 (if exists)
Uploads only if checksums differ
Returns asset metadata with MD5
Listing Assets
List all assets in your organization:
List All Assets
Filter by Name
Include Download URLs
Include App Store Assets
Limit Results
const assets = await client . assets . list ();
for ( const asset of assets ) {
console . log ( asset . name , asset . id , asset . os );
}
Getting an Asset
Retrieve a specific asset by ID:
const asset = await client . assets . get ( 'asset-id-here' , {
includeDownloadUrl: true ,
includeUploadUrl: true ,
});
console . log ( 'Asset name:' , asset . name );
console . log ( 'MD5:' , asset . md5 );
console . log ( 'Download URL:' , asset . signedDownloadUrl );
Deleting an Asset
Remove an asset when no longer needed:
await client . assets . delete ( 'asset-id-here' );
console . log ( 'Asset deleted' );
Deleting an asset removes both the metadata and the uploaded file. This operation cannot be undone.
Using Assets with Instances
Deploy assets to instances during creation:
Android Instance
const asset = await client . assets . getOrUpload ({
path: './my-app.apk' ,
name: 'my-app-v1.2.3.apk' ,
});
const instance = await client . androidInstances . create ({
wait: true ,
spec: {
initialAssets: [
{
kind: 'App' ,
source: 'AssetName' ,
assetName: asset . name ,
},
],
},
});
iOS Instance
const asset = await client . assets . getOrUpload ({
path: './MyApp.app.zip' ,
name: 'my-ios-app-v2.1.0' ,
});
const instance = await client . iosInstances . create ({
wait: true ,
spec: {
initialAssets: [
{
kind: 'App' ,
source: 'AssetName' ,
assetName: asset . name ,
launchMode: 'ForegroundIfRunning' ,
},
],
},
});
Asset Sources
You can reference assets in multiple ways:
By Name
By ID
By URL
Multiple IDs (Android)
Multiple URLs (Android)
{
kind : 'App' ,
source : 'AssetName' ,
assetName : 'my-app-v1.2.3.apk' ,
}
Best Practices
Version Your Assets
Include version numbers in asset names for easy management:
const asset = await client . assets . getOrUpload ({
path: './dist/app.apk' ,
name: `my-app- ${ version } .apk` ,
});
Use MD5 for Caching
The getOrUpload method automatically skips uploads when MD5 matches:
// First upload
const asset1 = await client . assets . getOrUpload ({
path: './my-app.apk' ,
name: 'my-app.apk' ,
});
// File uploaded
// Second call with same content
const asset2 = await client . assets . getOrUpload ({
path: './my-app.apk' ,
name: 'my-app.apk' ,
});
// Upload skipped, MD5 matches
Clean Up Old Assets
Regularly remove unused assets to save storage:
const assets = await client . assets . list ({
nameFilter: 'my-app' ,
});
// Keep only the latest 5 versions
const toDelete = assets . slice ( 5 );
for ( const asset of toDelete ) {
await client . assets . delete ( asset . id );
console . log ( 'Deleted old version:' , asset . name );
}
Use the displayName field to add human-readable descriptions to your assets.