npm package: @nodules/linode-storage
Description: A production-ready, fully-typed Linode Object Storage client, following fs/promises interface that provides seamless cloud operations with enterprise-grade reliability and developer experience.
Author: Nodules Team
Latest version: 1.0.2

# Nodules Linode Object Storage

A production-ready, fully-typed Linode Object Storage client, following fs/promises interface that provides seamless cloud operations with enterprise-grade reliability and developer experience.

## Installation

```bash
npm install @nodules/linode-storage
```

## Usage

### Simple Factory Pattern

The easiest way to get started - works with any IAsyncFileSystem implementation:

```typescript
import { FS } from '@nodules/linode-storage';

// Development - local filesystem
const devFs = FS.async.node();

// Testing - in-memory filesystem  
const testFs = FS.async.memory();

// Production - Linode Object Storage
const prodFs = FS.async.linode({
  region: 'us-southeast-1',
  bucket: 'my-bucket',
  accessKey: process.env.LINODE_ACCESS_KEY,
  secretKey: process.env.LINODE_SECRET_KEY
});

// All share the same interface - swap implementations instantly
await prodFs.writeFile('data.json', JSON.stringify(data));
const content = await prodFs.readFile('data.json');
```

### Interface Injection Pattern

Design your services to accept any filesystem implementation:

```typescript
import { IAsyncFileSystem } from '@nodules/linode-storage';

class DocumentService {
  constructor(private fs: IAsyncFileSystem) {}
  
  async saveDocument(id: string, content: string) {
    await this.fs.writeFile(`documents/${id}.txt`, content);
  }
  
  async loadDocument(id: string): Promise<string> {
    return await this.fs.readFile(`documents/${id}.txt`);
  }
}

// Development environment
const devService = new DocumentService(FS.async.node());

// Test environment  
const testService = new DocumentService(FS.async.memory());

// Production environment
const prodService = new DocumentService(FS.async.linode({
  region: 'us-southeast-1',
  bucket: 'production-storage',
  accessKey: process.env.LINODE_ACCESS_KEY,
  secretKey: process.env.LINODE_SECRET_KEY
}));
```

### Environment-Based Configuration

```typescript
import { FS } from '@nodules/linode-storage';

function createFileSystem() {
  switch (process.env.NODE_ENV) {
    case 'test':
      return FS.async.memory();
    case 'development':
      return FS.async.node();
    case 'production':
      return FS.async.linode({
        region: process.env.LINODE_REGION!,
        bucket: process.env.LINODE_BUCKET!,
        accessKey: process.env.LINODE_ACCESS_KEY!,
        secretKey: process.env.LINODE_SECRET_KEY!
      });
    default:
      throw new Error('Unknown environment');
  }
}

const fs = createFileSystem();
await fs.writeFile('config.json', '{}');
```

### Direct Class Usage

For advanced configuration, use the class directly:

```typescript
import { LinodeObjectStorageFileSystem } from '@nodules/linode-storage';

const storage = new LinodeObjectStorageFileSystem({
  region: 'us-southeast-1',
  bucket: 'my-bucket',
  accessKey: process.env.LINODE_ACCESS_KEY,
  secretKey: process.env.LINODE_SECRET_KEY
});

// Same interface as FS factory methods
await storage.writeFile('documents/file.txt', 'content');
const content = await storage.readFile('documents/file.txt');
const exists = await storage.exists('documents/file.txt');
```

## Benefits of this approach:

**Seamless Environment Switching**
- Same code works across development, testing, and production
- No vendor lock-in - switch storage providers without code changes
- Easy A/B testing between different storage solutions

**Developer Experience**  
- Three-line setup for any environment
- TypeScript-first with complete type safety
- Familiar fs/promises interface - no learning curve

**Production Ready**
- Stable interface used across all  applications
- Reverse dependency makes testing trivial
- Zero configuration required for basic usage


## Configuration Options

```typescript
interface LinodeObjectStorageOptions {
  region: string;           // Linode region (e.g., 'us-southeast-1')
  bucket: string;           // Bucket name
  accessKey: string;        // Linode Object Storage access key
  secretKey: string;        // Linode Object Storage secret key
  prefix?: string;          // Optional path prefix
  endpoint?: string;        // Custom endpoint (optional)
}
```

## Complete API Reference

All implementations follow the same `IAsyncFileSystem` interface:

### File Operations

```typescript
// Write file
await fs.writeFile(path: string, content: string): Promise<void>

// Read file
await fs.readFile(path: string): Promise<string>

// Check if file exists
await fs.exists(path: string): Promise<boolean>

// Delete file
await fs.deleteFile(path: string): Promise<void>
await fs.unlink(path: string): Promise<void>  // Alias

// Get file statistics
await fs.stat(path: string): Promise<FileStats>
```

### Directory Operations

```typescript
// List directory contents
await fs.readDir(path: string): Promise<string[]>

// Create directory (no-op in object storage)
await fs.mkdir(path: string): Promise<void>
await fs.ensureDir(path: string): Promise<void>  // Alias

// Remove directory and contents
await fs.rmdir(path: string): Promise<void>
await fs.deleteDir(path: string): Promise<void>  // Alias
```

### File Permissions

```typescript
// Set file permissions (no-op in object storage)
await fs.chmod(path: string, mode: number): Promise<void>
```

## Real-World Examples

### Testing with In-Memory Filesystem

```typescript
import { FS } from '@nodules/linode-storage';

describe('DocumentService', () => {
  const testFs = FS.async.memory();
  const service = new DocumentService(testFs);
  
  beforeEach(() => {
    // In-memory filesystem is automatically clean for each test
  });
  
  it('should save and load documents', async () => {
    await service.saveDocument('test-doc', 'content');
    const content = await service.loadDocument('test-doc');
    expect(content).toBe('content');
  });
});
```

### Development with Local Filesystem

```typescript
import { FS } from '@nodules/linode-storage';

// Development environment - files stored locally
const fs = FS.async.node();
const service = new DocumentService(fs);

// Files go to local filesystem for easy debugging
await service.saveDocument('debug-doc', 'debug content');
// Check ./documents/debug-doc.txt on your filesystem
```

### Production with Linode Object Storage

```typescript
import { FS } from '@nodules/linode-storage';

const fs = FS.async.linode({
  region: 'us-southeast-1',
  bucket: 'production-documents', 
  accessKey: process.env.LINODE_ACCESS_KEY,
  secretKey: process.env.LINODE_SECRET_KEY,
  prefix: 'app-v2/'  // Namespace your application data
});

const service = new DocumentService(fs);
// Same code, now running on cloud storage
```

## Error Handling

```typescript
try {
  const content = await fs.readFile('nonexistent.txt');
} catch (error) {
  if (error.message.includes('not found')) {
    console.log('File does not exist');
  } else {
    console.error('Storage error:', error.message);
  }
}
```

## Testing

```typescript
import { FS } from '@nodules/linode-storage';

// Testing is simple - use memory filesystem
const testFs = FS.async.memory();
const service = new DocumentService(testFs);

// No setup required, no cleanup needed
await service.saveDocument('test', 'content');
expect(await service.loadDocument('test')).toBe('content');
```

## TypeScript Support

Full TypeScript definitions included. No additional @types packages required.

```typescript
interface FileStats {
  size: number;
  mtime: Date;
  ctime: Date;
  atime: Date;
  mode: number;
  isFile(): boolean;
  isDirectory(): boolean;
  isSymbolicLink(): boolean;
}
```

## Changelog

See [CHANGELOG.md](./CHANGELOG.md) for version history and migration notes.


## Support

- **Issues**: [GitHub Issues](https://github.com/nodules-io/linode-storage/issues)
- **Documentation**: [GitHub Wiki](https://github.com/nodules-io/linode-storage/wiki)
- **More examles**  See [nodules.io/docs/linode-storage]
- **Contact us** core@nodules.io

## Enterprise Services

**Professional support available through [Nodules.io](https://nodules.io)**

- **Enterprise licensing** for commercial applications
- **Priority support** with SLA guarantees
- **Security audits** with every release
- **Penetration testing** and vulnerability assessment programs
- **Dedicated technical account management** and escalation procedures
- **Comprehensive testing** and validation reports 
- **Compliance validation** for SOC 2, GDPR, HIPAA, and industry-specific regulations 
- **White-glove onboarding** and integration support
- **Private module development** and customization

Contact: enterprise@nodules.io

## License

MIT License - see [LICENSE](./LICENSE) for details.

---

**Security**: Report vulnerabilities to security@nodules.io