ArDrive Core is a TypeScript library that contains the essential back end application features to support the ArDrive CLI and Desktop apps, such as file management, Permaweb upload/download, wallet management, and other common functions.
Engage with the community in Discord for more information.
- Installation
- Quick Start
- Core Concepts
- API Reference
- Advanced Features
- Development
- Testing
- Contributing
To add the ArDrive Core library to your project:
# Using yarn
yarn add ardrive-core-js
# Using npm
npm install ardrive-core-js
The recommended approach for integrating with ArDrive Core is through the ArDrive
class, constructed using the arDriveFactory
function:
import { readJWKFile, arDriveFactory } from 'ardrive-core-js';
// Read wallet from file
const myWallet = readJWKFile('/path/to/wallet.json');
// Construct ArDrive class
const arDrive = arDriveFactory({ wallet: myWallet });
// Create a public drive and its root folder
const createDriveResult = await arDrive.createPublicDrive({
driveName: 'My-Drive'
});
console.log('Drive ID:', createDriveResult.driveId);
console.log('Root Folder ID:', createDriveResult.rootFolderId);
ArDrive uses a hierarchical structure:
- Drives: Top-level containers (public or private)
- Folders: Organize files within drives
- Files: Individual files stored on Arweave
Each entity has a unique ID (DriveID
, FolderID
, FileID
) and can be either public (unencrypted) or private (encrypted).
import { JWKWallet } from 'ardrive-core-js';
// Create wallet from JWK
const wallet = new JWKWallet(jwkKey);
// Check wallet balance
const balance = await wallet.getBalance();
Use the type-safe entity ID constructors:
import { EID, DriveID, FolderID, FileID } from 'ardrive-core-js';
// Generic entity ID
const entityId = EID('10108b54a-eb5e-4134-8ae2-a3946a428ec7');
// Specific entity IDs
const driveId = new DriveID('12345674a-eb5e-4134-8ae2-a3946a428ec7');
const folderId = new FolderID('47162534a-eb5e-4134-8ae2-a3946a428ec7');
const fileId = new FileID('98765432a-eb5e-4134-8ae2-a3946a428ec7');
// Public drive
const publicDrive = await arDrive.createPublicDrive({
driveName: 'My Public Drive'
});
// Private drive with password
const privateDrive = await arDrive.createPrivateDrive({
driveName: 'My Private Drive',
drivePassword: 'mySecretPassword'
});
// Get public drive
const publicDriveInfo = await arDrive.getPublicDrive({
driveId
});
// Get private drive (requires drive key)
const privateDriveInfo = await arDrive.getPrivateDrive({
driveId,
driveKey
});
// Get all drives for an address
const allDrives = await arDrive.getAllDrivesForAddress({
address: walletAddress,
privateKeyData: wallet.getPrivateKey()
});
// Rename public drive
await arDrive.renamePublicDrive({
driveId,
newName: 'Updated Drive Name'
});
// Rename private drive
await arDrive.renamePrivateDrive({
driveId,
driveKey,
newName: 'Updated Private Name'
});
// Public folder
const publicFolder = await arDrive.createPublicFolder({
folderName: 'Documents',
driveId,
parentFolderId
});
// Private folder
const privateFolder = await arDrive.createPrivateFolder({
folderName: 'Secret Documents',
driveId,
driveKey,
parentFolderId
});
// List public folder
const publicContents = await arDrive.listPublicFolder({
folderId,
maxDepth: 2, // Optional: limit recursion depth
includeRoot: true // Optional: include root folder in results
});
// List private folder
const privateContents = await arDrive.listPrivateFolder({
folderId,
driveKey,
maxDepth: 1
});
// Move folder
await arDrive.movePublicFolder({
folderId,
newParentFolderId
});
// Rename folder
await arDrive.renamePublicFolder({
folderId,
newName: 'New Folder Name'
});
import { wrapFileOrFolder } from 'ardrive-core-js';
// Wrap file for upload
const wrappedFile = wrapFileOrFolder('/path/to/file.pdf');
// Upload public file
const publicUpload = await arDrive.uploadPublicFile({
parentFolderId,
wrappedFile,
conflictResolution: 'upsert' // skip, replace, upsert, or error
});
// Upload private file
const privateUpload = await arDrive.uploadPrivateFile({
parentFolderId,
driveKey,
wrappedFile
});
// Get public file metadata
const publicFile = await arDrive.getPublicFile({ fileId });
// Get private file metadata
const privateFile = await arDrive.getPrivateFile({
fileId,
driveKey
});
// Move file
await arDrive.movePublicFile({
fileId,
newParentFolderId
});
// Rename file
await arDrive.renamePublicFile({
fileId,
newName: 'renamed-file.pdf'
});
import { wrapFileOrFolder, EntityKey } from 'ardrive-core-js';
// Prepare entities for upload
const folder1 = wrapFileOrFolder('/path/to/folder1');
const folder2 = wrapFileOrFolder('/path/to/folder2');
const file1 = wrapFileOrFolder('/path/to/file1.txt');
// Upload everything in one operation
const bulkUpload = await arDrive.uploadAllEntities({
entitiesToUpload: [
// Public folder
{
wrappedEntity: folder1,
destFolderId: rootFolderId
},
// Private folder
{
wrappedEntity: folder2,
destFolderId: rootFolderId,
driveKey: privateDriveKey
},
// Public file
{
wrappedEntity: file1,
destFolderId: someFolderId
}
],
conflictResolution: 'upsert'
});
// Results include all created entities
console.log('Created folders:', bulkUpload.created.length);
console.log('Total cost:', bulkUpload.totalCost.toString());
// Create folder and upload all children
const folderWithContents = await arDrive.createPublicFolderAndUploadChildren({
parentFolderId,
wrappedFolder: wrapFileOrFolder('/path/to/folder'),
conflictResolution: 'skip'
});
// Download public file
const publicData = await arDrive.downloadPublicFile({
fileId
});
// publicData is a Buffer/Uint8Array
// Download private file (automatically decrypted)
const privateData = await arDrive.downloadPrivateFile({
fileId,
driveKey
});
// Download entire folder
const folderData = await arDrive.downloadPublicFolder({
folderId,
destFolderPath: '/local/download/path'
});
// Download private folder
const privateFolderData = await arDrive.downloadPrivateFolder({
folderId,
driveKey,
destFolderPath: '/local/download/path'
});
import { deriveDriveKey, deriveFileKey } from 'ardrive-core-js';
// Derive drive key from password
const driveKey = await deriveDriveKey(
'myPassword',
driveId.toString(),
JSON.stringify(wallet.getPrivateKey())
);
// File keys are automatically derived from drive keys
const fileKey = await deriveFileKey(driveKey, fileId);
import { driveEncrypt, driveDecrypt } from 'ardrive-core-js';
// Encrypt data
const { cipher, cipherIV } = await driveEncrypt(driveKey, data);
// Decrypt data
const decrypted = await driveDecrypt(cipherIV, driveKey, cipher);
// Get price estimator
const priceEstimator = arDrive.getArDataPriceEstimator();
// Estimate cost for data size
const cost = await priceEstimator.getARPriceForByteCount(
new ByteCount(1024 * 1024) // 1MB
);
// Get base Winston price (without tips)
const basePrice = await priceEstimator.getBaseWinstonPriceForByteCount(
new ByteCount(5 * 1024 * 1024) // 5MB
);
Attach custom metadata to files:
const fileWithMetadata = wrapFileOrFolder(
'/path/to/file.txt',
'text/plain',
{
metaDataJson: {
'Custom-Field': 'Custom Value',
'Version': '1.0'
},
metaDataGqlTags: {
'App-Name': ['MyApp'],
'App-Version': ['1.0.0']
},
dataGqlTags: {
'Content-Type': ['text/plain']
}
}
);
// Upload with custom metadata
await arDrive.uploadPublicFile({
parentFolderId,
wrappedFile: fileWithMetadata
});
Available strategies when uploading files/folders that already exist:
// Skip existing files
await arDrive.uploadAllEntities({
entitiesToUpload: [...],
conflictResolution: 'skip'
});
// Replace all existing files
await arDrive.uploadAllEntities({
entitiesToUpload: [...],
conflictResolution: 'replace'
});
// Update only if content differs (default)
await arDrive.uploadAllEntities({
entitiesToUpload: [...],
conflictResolution: 'upsert'
});
// Rename conflicting files
await arDrive.uploadAllEntities({
entitiesToUpload: [...],
conflictResolution: 'rename'
});
// Throw error on conflicts
await arDrive.uploadAllEntities({
entitiesToUpload: [...],
conflictResolution: 'error'
});
// Interactive prompt (CLI only)
await arDrive.uploadAllEntities({
entitiesToUpload: [...],
conflictResolution: 'ask'
});
Enable Turbo for optimized uploads:
// Enable Turbo
const arDriveWithTurbo = arDriveFactory({
wallet: myWallet,
turboSettings: {}
});
// Uploads will automatically use Turbo
const result = await arDriveWithTurbo.uploadAllEntities({
entitiesToUpload: [{ wrappedEntity, destFolderId }]
});
Large uploads are automatically bundled for efficiency:
// Bundling happens automatically for multiple files
const bulkResult = await arDrive.uploadAllEntities({
entitiesToUpload: manyFiles,
// Bundling is handled internally
});
Create Arweave manifests for web hosting:
// Create a manifest for a folder
const manifest = await arDrive.uploadPublicManifest({
folderId,
destManifestName: 'index.html',
conflictResolution: 'upsert'
});
// Access: https://arweave.net/{manifestId}
Enable upload progress logging:
# Set environment variable
export ARDRIVE_PROGRESS_LOG=1
Progress will be logged to stderr:
Uploading file transaction 1 of total 2 transactions...
Transaction _GKQasQX194a364Hph8Oe-oku1AdfHwxWOw9_JC1yjc Upload Progress: 0%
Transaction _GKQasQX194a364Hph8Oe-oku1AdfHwxWOw9_JC1yjc Upload Progress: 35%
Transaction _GKQasQX194a364Hph8Oe-oku1AdfHwxWOw9_JC1yjc Upload Progress: 66%
Transaction _GKQasQX194a364Hph8Oe-oku1AdfHwxWOw9_JC1yjc Upload Progress: 100%
ArDrive Core maintains a metadata cache for improved performance:
# Cache locations
Windows: <os.homedir()>/ardrive-caches/metadata
Non-Windows: <os.homedir()>/.ardrive/caches/metadata
Enable cache logging:
export ARDRIVE_CACHE_LOG=1
Use ArDrive without a wallet for read-only operations:
import { arDriveAnonymousFactory } from 'ardrive-core-js';
const anonymousArDrive = arDriveAnonymousFactory({});
// Read public data
const publicFile = await anonymousArDrive.getPublicFile({ fileId });
const folderContents = await anonymousArDrive.listPublicFolder({ folderId });
Send tips to the ArDrive community:
// Send community tip
await arDrive.sendCommunityTip({
tokenAmount: new Winston(1000000000000), // 1 AR
walletAddress,
communityWalletAddress
});
We use nvm and Yarn for development:
- Install nvm using their instructions
- Install correct Node version:
nvm install && nvm use
- Install Yarn 3.x: Follow Yarn installation
- Enable git hooks:
yarn husky install
- Install dependencies:
yarn install --check-cache
# Build the library
yarn build
# Development mode with watch
yarn dev
# Run linter
yarn lint
# Fix linting issues
yarn lintfix
# Format code
yarn format
# Type checking
yarn typecheck
This library uses Mocha with Chai and Sinon for testing.
# Run all tests
yarn test
# Run specific tests
yarn test -g 'My specific test'
# Run with coverage
yarn coverage
# Power assert for debugging
yarn power-assert -g 'My test case'
- Unit tests: Located next to source files (
*.test.ts
) - Integration tests: Located in
/tests
directory
For integration testing with a local Arweave instance:
yarn arlocal-docker-test
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
AGPL-3.0-or-later