# Anonymous Operations (/(advanced-features)/anonymous-operations) Use ArDrive without a wallet for read-only operations: ```typescript const anonymousArDrive = arDriveAnonymousFactory({}); // Read public data const publicFile = await anonymousArDrive.getPublicFile({ fileId }); const folderContents = await anonymousArDrive.listPublicFolder({ folderId }); ``` # Bundle Support (/(advanced-features)/bundle-support) Large uploads are automatically bundled for efficiency: ```typescript // Bundling happens automatically for multiple files const bulkResult = await arDrive.uploadAllEntities({ entitiesToUpload: manyFiles // Bundling is handled internally }); ``` # Caching (/(advanced-features)/caching) ArDrive Core maintains a metadata cache for improved performance: ```shell Windows: /ardrive-caches/metadata Non-Windows: /.ardrive/caches/metadata ``` Enable cache logging: ```bash ``` # Community Features (/(advanced-features)/community-features) Send tips to the ArDrive community: ```typescript // Send community tip await arDrive.sendCommunityTip({ tokenAmount: new Winston(1000000000000), // 1 AR walletAddress, communityWalletAddress }); ``` # Incremental Drive Synchronization (/(advanced-features)/incremental-drive-synchronization) ArDrive Core provides efficient incremental synchronization capabilities for tracking changes in drives over time. This feature enables applications to sync only new or modified content rather than fetching entire drive structures repeatedly. **Note:** The standard `arDriveFactory` creates an ArDrive instance with in-memory sync state caching (5-minute TTL). For persistent storage across sessions, see the [Persistent Storage](#persistent-storage-for-sync-state) section below. #### Basic Sync Operations ```typescript // Important: Requires ArFSDAOIncrementalSync for full functionality // The standard arDriveFactory may not support all sync features // For basic sync with in-memory caching, first create the DAO: const arfsDao = new ArFSDAOIncrementalSync( wallet, arweave, false // dryRun ); const arDrive = arDriveFactory({ wallet: myWallet, arfsDao }); // Now sync operations will work: const syncResult = await arDrive.syncPublicDrive(driveId); console.log(`Found ${syncResult.entities.length} total entities`); console.log(`Added: ${syncResult.changes.added.length}`); console.log(`Modified: ${syncResult.changes.modified.length}`); console.log(`Unreachable: ${syncResult.changes.unreachable.length}`); // Sync a private drive with decryption const privateSyncResult = await arDrive.syncPrivateDrive( driveId, driveKey ); ``` #### Incremental Sync with Previous State ```typescript // First sync - gets all entities const initialSync = await arDrive.syncPublicDrive(driveId); // Save the sync state for later const syncState = initialSync.newSyncState; // Later, sync only changes since last sync const incrementalSync = await arDrive.syncPublicDrive(driveId, undefined, { syncState: syncState // Pass previous state }); // Only new/modified entities since last sync console.log(`New entities: ${incrementalSync.changes.added.length}`); ``` #### Progress Tracking ```typescript // Track sync progress for large drives const result = await arDrive.syncPublicDrive(driveId, undefined, { onProgress: (processed, total) => { console.log(`Progress: ${processed}/${total} entities`); } }); ``` #### Advanced Sync Options ```typescript const syncOptions = { // Include all file revisions (not just latest) includeRevisions: true, // Batch size for GraphQL queries (default: 100, max: 100) batchSize: 50, // Stop early after finding N consecutive known entities (optimization) stopAfterKnownCount: 10, // Progress callback onProgress: (processed, total) => { console.log(`Syncing: ${processed}/${total}`); } }; const result = await arDrive.syncPublicDrive(driveId, owner, syncOptions); ``` #### Working with Sync Results ```typescript // Sync result structure const result = await arDrive.syncPublicDrive(driveId); // All entities in the drive (files and folders) result.entities.forEach(entity => { console.log(`${entity.entityType}: ${entity.name} (${entity.entityId})`); }); // Change detection result.changes.added.forEach(entity => { console.log(`New: ${entity.name}`); }); result.changes.modified.forEach(entity => { console.log(`Modified: ${entity.name} at block ${entity.blockHeight}`); }); result.changes.unreachable.forEach(entity => { console.log(`No longer accessible: ${entity.name}`); }); // Sync statistics console.log(`Processed from cache: ${result.stats.fromCache}`); console.log(`Fetched from network: ${result.stats.fromNetwork}`); console.log(`Block range: ${result.stats.lowestBlockHeight} - ${result.stats.highestBlockHeight}`); ``` #### Error Handling ```typescript try { const result = await arDrive.syncPublicDrive(driveId); } catch (error) { if (error instanceof IncrementalSyncError) { // Partial results are available even if sync failed console.log(`Sync failed but got ${error.partialResult.entities.length} entities`); console.log(`Error: ${error.message}`); // Can continue from partial state const partialState = error.partialResult.newSyncState; } } ``` # Manifest Creation (/(advanced-features)/manifest-creation) Create Arweave manifests for web hosting: ```typescript // Create a manifest for a folder const manifest = await arDrive.uploadPublicManifest({ folderId, destManifestName: 'index.html', conflictResolution: 'upsert' }); // Access: https://arweave.net/{manifestId} ``` # Persistent Storage for Sync State (/(advanced-features)/persistent-storage-for-sync-state) By default, sync state is only cached in memory for 5 minutes. To maintain sync state across application restarts, ArDrive Core provides storage adapters that automatically persist and restore sync state. #### Available Storage Adapters - **MemorySyncStateStore** - In-memory storage (default behavior) - **FileSystemSyncStateStore** - Persists to disk (Node.js) - **LocalStorageSyncStateStore** - Browser localStorage - **IndexedDBSyncStateStore** - Browser IndexedDB for larger datasets - **SQLiteSyncStateStore** - SQLite database (optional, see SQLite section below) #### Quick Start: Persistent Sync (Node.js) ```typescript import { arDriveFactory, ArFSDAOIncrementalSync, FileSystemSyncStateStore } from 'ardrive-core-js'; // 1. Create persistent storage adapter const syncStateStore = new FileSystemSyncStateStore('./.ardrive-cache'); // 2. Create DAO with storage adapter const arfsDao = new ArFSDAOIncrementalSync( wallet, arweave, false, // dryRun 'MyApp', '1.0.0', undefined, // use default settings for these undefined, undefined, syncStateStore // ← Pass storage adapter here ); // 3. Create ArDrive with the DAO const arDrive = arDriveFactory({ wallet, arfsDao }); // 4. Sync operations now persist state automatically const result = await arDrive.syncPublicDrive(driveId); // State is saved to disk and will be reused on next run ``` **Important:** The storage adapter must be passed to `ArFSDAOIncrementalSync`, not to `arDriveFactory`. #### Browser Storage Options ```typescript // Option 1: localStorage (simple, ~5-10MB limit) const syncStateStore = new LocalStorageSyncStateStore('ardrive-sync-'); // Option 2: IndexedDB (for larger datasets) const syncStateStore = new IndexedDBSyncStateStore('ardrive-sync-db'); // Use with ArFSDAOIncrementalSync same as Node.js example const arfsDao = new ArFSDAOIncrementalSync( wallet, arweave, false, 'MyApp', '1.0.0', undefined, undefined, undefined, syncStateStore ); ``` #### Working Example See `examples/persistent-sync-example.js` for a complete working example that demonstrates: - Setting up persistent storage - Performing initial full sync - Simulating app restart - Performing incremental sync from saved state - Managing stored sync states #### SQLite Storage (Optional) The SQLite adapter provides advanced features like statistics, cleanup, and backups. To use it: 1. Install the peer dependency: `yarn add better-sqlite3` 2. Copy `src/utils/sync_state_store_sqlite.ts.optional` to your project 3. Import and use like other storage adapters **Note:** SQLite adapter is not included in the default build to avoid forcing the peer dependency. #### Storage Management Methods All storage adapters implement these methods: ```typescript // List all drives with cached state const driveIds = await syncStateStore.list(); // Load specific drive state const state = await syncStateStore.load(driveId); // Clear specific drive await syncStateStore.clear(driveId); // Clear all cached states await syncStateStore.clearAll(); ``` #### Custom Storage Implementation Create your own storage adapter by implementing the `SyncStateStore` interface: ```typescript class CustomSyncStateStore implements SyncStateStore { async save(driveId: DriveID, state: DriveSyncState): Promise\ { // Your storage logic } async load(driveId: DriveID): Promise\ { // Your retrieval logic } async clear(driveId: DriveID): Promise\ { // Your deletion logic } async list(): Promise { // Return all stored drive IDs } async clearAll(): Promise\ { // Clear all stored states } } ``` #### Serialization for External Storage If you need to store sync state in an external system: ```typescript // Serialize state for storage const result = await arDrive.syncPublicDrive(driveId); const serialized = serializeSyncState(result.newSyncState); const jsonString = JSON.stringify(serialized); // Store in your backend await myAPI.saveSyncState(driveId, jsonString); // Later, retrieve and deserialize const stored = await myAPI.getSyncState(driveId); const parsed = JSON.parse(stored); const syncState = deserializeSyncState(parsed); // Use restored state for incremental sync const nextSync = await arDrive.syncPublicDrive(driveId, undefined, { syncState }); ``` # Progress Tracking (/(advanced-features)/progress-tracking) Enable upload progress logging: ```bash ``` 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% ``` # Turbo Integration (/(advanced-features)/turbo-integration) Enable Turbo for optimized uploads: ```typescript // Node.js const arDriveWithTurbo = arDriveFactory({ wallet: myWallet, turboSettings: { turboUploadUrl: new URL('https://upload.ardrive.io') } }); // Browser const arDrive = arDriveFactory({ signer: myBrowserSigner, turboSettings: { turboUploadUrl: new URL('https://upload.ardrive.io') } }); // Uploads will automatically use Turbo const result = await arDriveWithTurbo.uploadAllEntities({ entitiesToUpload: [{ wrappedEntity, destFolderId }] }); ``` # Bulk Operations (/(api-reference)/bulk-operations) #### Upload Multiple Files and Folders ```typescript // 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 Contents ```typescript // Create folder and upload all children const folderWithContents = await arDrive.createPublicFolderAndUploadChildren({ parentFolderId, wrappedFolder: wrapFileOrFolder('/path/to/folder'), conflictResolution: 'skip' }); ``` # Conflict Resolution (/(api-reference)/conflict-resolution) Available strategies when uploading files/folders that already exist: ```typescript // 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' }); ``` # Custom Metadata (/(api-reference)/custom-metadata) Attach custom metadata to files: ```typescript 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 }); ``` # Download Operations (/(api-reference)/download-operations) #### Download Files ```typescript // 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 Folders ```typescript // 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' }); ``` # Drive Operations (/(api-reference)/drive-operations) #### Creating Drives ```typescript // 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' }); ``` #### Reading Drive Information ```typescript // 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() }); ``` #### Renaming Drives ```typescript // Rename public drive await arDrive.renamePublicDrive({ driveId, newName: 'Updated Drive Name' }); // Rename private drive await arDrive.renamePrivateDrive({ driveId, driveKey, newName: 'Updated Private Name' }); ``` # Encryption & Security (/(api-reference)/encryption-security) #### Key Derivation ```typescript // 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); ``` #### Manual Encryption/Decryption ```typescript // Encrypt data const { cipher, cipherIV } = await driveEncrypt(driveKey, data); // Decrypt data const decrypted = await driveDecrypt(cipherIV, driveKey, cipher); ``` # File Operations (/(api-reference)/file-operations) #### Uploading Files ```typescript // 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 }); ``` #### Reading File Information ```typescript // Get public file metadata const publicFile = await arDrive.getPublicFile({ fileId }); // Get private file metadata const privateFile = await arDrive.getPrivateFile({ fileId, driveKey }); ``` #### Moving and Renaming Files ```typescript // Move file await arDrive.movePublicFile({ fileId, newParentFolderId }); // Rename file await arDrive.renamePublicFile({ fileId, newName: 'renamed-file.pdf' }); ``` # Folder Operations (/(api-reference)/folder-operations) #### Creating Folders ```typescript // Public folder const publicFolder = await arDrive.createPublicFolder({ folderName: 'Documents', driveId, parentFolderId }); // Private folder const privateFolder = await arDrive.createPrivateFolder({ folderName: 'Secret Documents', driveId, driveKey, parentFolderId }); ``` #### Listing Folder Contents ```typescript // 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 }); ``` #### Moving and Renaming Folders ```typescript // Move folder await arDrive.movePublicFolder({ folderId, newParentFolderId }); // Rename folder await arDrive.renamePublicFolder({ folderId, newName: 'New Folder Name' }); ``` # Pricing & Cost Estimation (/(api-reference)/pricing-cost-estimation) ```typescript // 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 ); ``` # Entity IDs (/(core-concepts)/entity-ids) Use the type-safe entity ID constructors: ```typescript // 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'); ``` # Entity Types (/(core-concepts)/entity-types) 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). # Wallet Management (/(core-concepts)/wallet-management) ```typescript // Create wallet from JWK const wallet = new JWKWallet(jwkKey); // Check wallet balance const balance = await wallet.getBalance(); ``` # ArDrive Core JS (/index) **For AI and LLM users**: Access the complete ArDrive Core JS documentation in plain text format at llm.txt for easy consumption by AI agents and language models. The ArDrive Core JS SDK provides a comprehensive TypeScript library for building applications on ArDrive. It offers type-safe interfaces for drive management, file operations, encryption, and seamless integration with Arweave. ## Quick Start ### Install the SDK ```npm npm install ardrive-core-js ``` ### Initialize with a Wallet ```typescript // Load your Arweave wallet const wallet = readJWKFile('./wallet.json'); // Create an ArDrive instance const arDrive = arDriveFactory({ wallet }); ``` ### Create a Drive and Upload Files ```typescript // Create a new public drive const { driveId, rootFolderId } = await arDrive.createPublicDrive({ driveName: 'My-Drive' }); console.log('Drive created:', driveId.toString()); console.log('Root folder:', rootFolderId.toString()); // Upload a file to the drive const wrappedFile = wrapFileOrFolder('./my-file.pdf'); const uploadResult = await arDrive.uploadPublicFile({ parentFolderId: rootFolderId, wrappedFile }); console.log('File uploaded:', uploadResult.fileId.toString()); ``` ### Install the SDK ```npm npm install ardrive-core-js ``` ### Configure Polyfills Polyfills are required for web environments due to Node.js dependencies used by the SDK. ```npm npm install --save-dev vite-plugin-node-polyfills ``` ```js // vite.config.js plugins: [ nodePolyfills({ globals: { Buffer: true, global: true, process: true, }, }), ], }); ``` Configure your bundler (Webpack, Vite, Rollup, etc.) to provide polyfills for `crypto`, `process`, and `buffer`. Refer to your bundler's documentation for polyfill configuration. ### Use the SDK ```typescript // Initialize with a JWK wallet object const arDrive = arDriveFactory({ wallet: jwkWallet }); // Create a public drive const { driveId, rootFolderId } = await arDrive.createPublicDrive({ driveName: 'My-Drive' }); console.log('Drive created:', driveId.toString()); ``` ## Documentation } title="Source Code" description="View the complete source code and contribute on GitHub" href="https://github.com/ardriveapp/ardrive-core-js" /> } title="API Reference" description="Detailed documentation for all SDK methods and classes" href="/sdks/ardrive-core-js/drive-operations" /> ## Core Features } title="Drive Operations" description="Create and manage public and private drives" href="/sdks/ardrive-core-js/drive-operations" /> } title="Folder Operations" description="Create folders, list contents, and organize your data" href="/sdks/ardrive-core-js/folder-operations" /> } title="File Operations" description="Upload, download, and manage files on Arweave" href="/sdks/ardrive-core-js/file-operations" /> } title="Encryption & Security" description="End-to-end encryption for private drives and files" href="/sdks/ardrive-core-js/encryption-security" /> } title="Pricing & Cost Estimation" description="Estimate upload costs before committing transactions" href="/sdks/ardrive-core-js/pricing-cost-estimation" /> } title="Advanced Features" description="Turbo integration, bundling, manifests, and more" href="/sdks/ardrive-core-js/turbo-integration" />