npm package: @deepankalsinghs/pikpakjs
Description: TypeScript/JavaScript client for PikPak API with full type support and Electron integration
Author: Your Name
Latest version: 1.0.0

# PikPakJS

A TypeScript/JavaScript client library for the PikPak API. Fully typed, supports both Node.js and Electron environments with persistent session management.

## Features

- ✅ **Full API Coverage** - All PikPak API endpoints implemented
- ✅ **TypeScript Support** - Complete type definitions
- ✅ **Automatic Retries** - Exponential backoff with configurable retry logic
- ✅ **Token Management** - Automatic token refresh and encoding/decoding
- ✅ **Session Persistence** - Save and restore sessions with encoded tokens
- ✅ **Electron Ready** - Works seamlessly in Electron main/preload processes
- ✅ **File Operations** - Create, move, copy, delete, rename files and folders
- ✅ **Offline Downloads** - Create and manage offline download tasks
- ✅ **Sharing** - Share files with password protection and expiration
- ✅ **Path Caching** - Efficient path-to-ID conversion with built-in caching

## Installation

```bash
npm install pikpakjs
```

## Quick Start

### Basic Login

```typescript
import PikPakApiClient from 'pikpakjs';

const client = new PikPakApiClient({
  username: 'your-email@example.com',
  password: 'your-password',
});

// Login
await client.login();

// Get user info
const userInfo = client.getUserInfo();
console.log(`Logged in as: ${userInfo.username}`);

// Get quota
const quota = await client.getQuotaInfo();
console.log(`Storage used: ${quota.quota.usage} bytes`);
```

### Using Encoded Token (Session Persistence)

```typescript
// After login, save the encoded token
const encodedToken = client.encodedToken;

// Later, restore the session
const newClient = new PikPakApiClient({
  encodedToken: encodedToken,
});

// No need to login again!
const files = await newClient.fileList();
```

### File Operations

```typescript
// List files
const fileList = await client.fileList(100);

// Create folder
await client.createFolder('My Folder');

// Rename file
await client.fileRename('file-id', 'new-name.txt');

// Move files
await client.fileBatchMove(['file-id-1', 'file-id-2'], 'destination-folder-id');

// Copy files
await client.fileBatchCopy(['file-id-1'], 'destination-folder-id');

// Delete to trash
await client.deleteToTrash(['file-id']);

// Permanently delete
await client.deleteForever(['file-id']);
```

### Path-based Operations

```typescript
// Convert path to file ID with caching
const pathIds = await client.pathToId('/Folder/SubFolder/File.txt');

// Move files by path
await client.fileMoveOrCopyByPath(
  ['/source/file.txt'],
  '/destination/',
  true, // true = move, false = copy
  true  // create destination if it doesn't exist
);
```

### Offline Downloads

```typescript
// Create offline download
await client.offlineDownload('https://example.com/file.zip', 'parent-folder-id');

// List offline tasks
const tasks = await client.offlineList();

// Get task status
const status = await client.getTaskStatus('task-id', 'file-id');

// Retry failed task
await client.offlineTaskRetry('task-id');

// Delete tasks
await client.deleteTasks(['task-id-1', 'task-id-2']);
```

### Sharing Files

```typescript
// Share files
const shareInfo = await client.fileBatchShare(
  ['file-id-1', 'file-id-2'],
  true,  // require password
  7      // expiration days
);

console.log(`Share URL: ${shareInfo.share_url}`);
console.log(`Password: ${shareInfo.pass_code}`);

// Get share info
const info = await client.getShareInfo('https://mypikpak.com/s/share-id');

// Restore shared files to account
await client.restore('share-id', 'passcode-token', ['file-id']);
```

### Token Refresh Callback (Electron)

```typescript
// Set callback to persist tokens when they refresh
const client = new PikPakApiClient({
  username: 'user@example.com',
  password: 'password',
  tokenRefreshCallback: async (client, kwargs) => {
    // Save new encoded token to persistent storage
    const encodedToken = client.encodedToken;
    // e.g., save to Electron store, localStorage, etc.
    console.log('Token refreshed and saved');
  },
  tokenRefreshCallbackKwargs: {
    storage: 'electron-store', // custom data
  },
});
```

## Configuration Options

```typescript
interface PikPakApiConfig {
  // Authentication
  username?: string;           // Username/email/phone for login
  password?: string;           // Password for login
  encodedToken?: string;       // Pre-encoded token for session restoration

  // HTTP Client
  httpxClientArgs?: Record<string, any>;  // Custom fetch options (timeout, etc)

  // Device
  deviceId?: string;           // Custom device ID (32 chars, auto-generated if not provided)

  // Retry Logic
  requestMaxRetries?: number;  // Max retry attempts (default: 3)
  requestInitialBackoff?: number;  // Initial backoff in seconds (default: 3.0)

  // Callbacks
  tokenRefreshCallback?: (client: PikPakApi, kwargs?: Record<string, any>) => Promise<void>;
  tokenRefreshCallbackKwargs?: Record<string, any>;
}
```

## API Methods

### Authentication
- `login()` - Login with credentials
- `refreshAccessToken()` - Refresh expired tokens
- `getUserInfo()` - Get current user information
- `encodeToken()` / `decodeToken()` - Token serialization

### File Operations
- `createFolder(name, parentId)` - Create new folder
- `fileRename(id, newFileName)` - Rename file
- `fileList(size, parentId, nextPageToken, filters)` - List files with pagination
- `fileStarList(size, nextPageToken)` - List starred files

### File Management
- `fileBatchMove(ids, toParentId)` - Move multiple files
- `fileBatchCopy(ids, toParentId)` - Copy multiple files
- `fileBatchStar(ids)` / `fileBatchUnstar(ids)` - Star/unstar files
- `deleteToTrash(ids)` - Move to trash
- `untrash(ids)` - Restore from trash
- `deleteForever(ids)` - Permanently delete

### Path Operations
- `pathToId(path, create)` - Convert path to file IDs
- `fileMoveOrCopyByPath(fromPath, toPath, move, create)` - Path-based operations
- `getDownloadUrl(fileId)` - Get file download link

### Offline Downloads
- `offlineDownload(url, parentId, name)` - Create download task
- `offlineList(size, nextPageToken, phase)` - List offline tasks
- `offlineFileInfo(fileId)` - Get task file info
- `offlineTaskRetry(taskId)` - Retry failed task
- `deleteTasks(taskIds, deleteFiles)` - Delete tasks
- `getTaskStatus(taskId, fileId)` - Get task status

### Sharing
- `fileBatchShare(ids, needPassword, expirationDays)` - Create share links
- `getShareInfo(shareLink, passCode)` - Get share information
- `getShareFolder(shareId, passcodeToken, parentId)` - List shared folder
- `restore(shareId, passcodeToken, fileIds)` - Restore shared files

### Account
- `getQuotaInfo()` - Get storage quota
- `getTransferQuota()` - Get transfer quota
- `vipInfo()` - Get VIP information
- `getInviteCode()` - Get referral code
- `events(size, nextPageToken)` - Get recent activity

## Error Handling

```typescript
import { PikpakException, PikpakRetryException } from 'pikpakjs';

try {
  await client.login();
} catch (error) {
  if (error instanceof PikpakException) {
    console.error(`API Error: ${error.message}`);
  } else {
    console.error('Unexpected error:', error);
  }
}
```

## Electron Integration

For use in Electron main process with persistent sessions:

```typescript
import { app, ipcMain } from 'electron';
import { safeStorage } from 'electron';
import PikPakApiClient from 'pikpakjs';

let pikpakClient: PikPakApiClient;

// Initialize on app start
app.on('ready', async () => {
  const encrypted = await safeStorage.getPassword('pikpak_token');
  
  if (encrypted) {
    // Restore session from saved token
    const encodedToken = encrypted;
    pikpakClient = new PikPakApiClient({
      encodedToken,
      tokenRefreshCallback: saveToken,
    });
  } else {
    // Create new client for login
    pikpakClient = new PikPakApiClient({
      username: process.env.PIKPAK_USERNAME,
      password: process.env.PIKPAK_PASSWORD,
      tokenRefreshCallback: saveToken,
    });
    await pikpakClient.login();
  }
});

async function saveToken(client: PikPakApiClient) {
  await safeStorage.setPassword('pikpak_token', client.encodedToken);
}

// Expose methods via IPC
ipcMain.handle('pikpak:fileList', (event, size, parentId) => {
  return pikpakClient.fileList(size, parentId);
});

ipcMain.handle('pikpak:createFolder', (event, name, parentId) => {
  return pikpakClient.createFolder(name, parentId);
});
```

## License

MIT

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## Support

For issues, questions, or suggestions, please open an issue on GitHub.

## Changelog

### v1.0.0 (Initial Release)
- Full PikPak API implementation
- TypeScript support
- Automatic retries with exponential backoff
- Token persistence
- Electron ready