cloudapp-dl
Version:
CloudApp/Zight API client and CLI. Use as a CLI tool to download videos or as a programmatic library to interact with the Zight API.
433 lines (382 loc) • 12.7 kB
JavaScript
import { performLogin } from './auth.js';
import * as api from './api.js';
/**
* ZightClient - Programmatic client for Zight/CloudApp API
*
* @example
* // Initialize with email/password
* const client = new ZightClient({ email: 'user@example.com', password: 'pass' });
* await client.login();
*
* @example
* // Initialize with existing session
* const client = new ZightClient({ sessionId: 'abc123' });
*
* @example
* // Enable debug logging
* const client = new ZightClient({ email: '...', password: '...', debug: true });
*
* @example
* // Use API methods
* const account = await client.getAccountDetails();
* const notifications = await client.getNotifications({ limit: 10 });
*/
export class ZightClient {
/**
* Create a new ZightClient instance
* @param {Object} options - Configuration options
* @param {string} [options.email] - Email for authentication
* @param {string} [options.password] - Password for authentication
* @param {string} [options.sessionId] - Existing session ID (alternative to email/password)
* @param {string} [options.sessionExpiry] - Session expiry ISO string (optional)
* @param {boolean} [options.debug=false] - Enable debug logging
*/
constructor(options = {}) {
const { email, password, sessionId, sessionExpiry, debug = false } = options;
this._email = email || null;
this._password = password || null;
this._sessionId = sessionId || null;
this._sessionExpiry = sessionExpiry || null;
this._userId = null;
this._userName = null;
this._debug = debug;
}
/**
* Log a debug message (only if debug mode is enabled)
* @private
*/
_log(...args) {
if (this._debug) {
console.log('[ZightClient]', ...args);
}
}
/**
* Get the session context for API calls
* @private
* @returns {Object} Session context
*/
_getContext() {
return {
sessionId: this._sessionId,
sessionExpiry: this._sessionExpiry,
email: this._email,
password: this._password,
debug: this._debug,
log: this._log.bind(this),
onSessionUpdate: (sessionInfo) => {
this._sessionId = sessionInfo.sessionId;
this._sessionExpiry = sessionInfo.sessionExpiry;
this._log('Session updated, expires:', sessionInfo.sessionExpiry);
}
};
}
/**
* Check if the client has a valid session
* @returns {boolean}
*/
get isAuthenticated() {
return !!this._sessionId;
}
/**
* Get the current session ID
* @returns {string|null}
*/
get sessionId() {
return this._sessionId;
}
/**
* Get the session expiry
* @returns {string|null}
*/
get sessionExpiry() {
return this._sessionExpiry;
}
/**
* Get the user ID (available after getAccountDetails)
* @returns {string|null}
*/
get userId() {
return this._userId;
}
/**
* Get the user name (available after getAccountDetails)
* @returns {string|null}
*/
get userName() {
return this._userName;
}
/**
* Login with email and password
* @returns {Promise<Object>} Login result with sessionId and sessionExpiry
*/
async login() {
if (!this._email || !this._password) {
throw new Error('Email and password are required for login');
}
this._log('Logging in...');
const result = await performLogin(this._email, this._password);
this._sessionId = result.sessionId;
this._sessionExpiry = result.sessionExpiry;
this._log('Login successful, session expires:', this._sessionExpiry);
return {
success: true,
sessionId: this._sessionId,
sessionExpiry: this._sessionExpiry
};
}
/**
* Set session directly (for when you already have a session ID)
* @param {string} sessionId - The session ID
* @param {string} [sessionExpiry] - Optional expiry ISO string
*/
setSession(sessionId, sessionExpiry = null) {
this._sessionId = sessionId;
this._sessionExpiry = sessionExpiry;
}
/**
* Clear the current session
*/
logout() {
this._sessionId = null;
this._sessionExpiry = null;
this._userId = null;
this._userName = null;
}
// ==================== Account Methods ====================
/**
* Get current user account details
* @returns {Promise<Object>} User account data
*/
async getAccountDetails() {
const response = await api.getAccountDetails(this._getContext());
// Store user info
if (response.data?.user) {
this._userId = response.data.user.id;
this._userName = response.data.user.attributes?.name;
}
return response;
}
/**
* Get organization details
* @param {string} [orgId] - Organization ID (optional)
* @returns {Promise<Object>} Organization data
*/
async getOrganization(orgId = null) {
return await api.getOrganization(orgId, this._getContext());
}
// ==================== Items/Drops Methods ====================
/**
* Get list of drops (files/items)
* @param {Object} [options] - Query options
* @param {number} [options.page=1] - Page number
* @param {number} [options.perPage=20] - Items per page
* @param {string} [options.filter] - Filter type
* @returns {Promise<Object>} Drops data
*/
async getDrops(options = {}) {
return await api.getDrops(options, this._getContext());
}
/**
* Get details of a specific drop
* @param {string} dropId - The drop ID
* @returns {Promise<Object>} Drop data
*/
async getDrop(dropId) {
return await api.getDrop(dropId, this._getContext());
}
/**
* Get single item/drop details
* @param {string} itemId - The item ID
* @returns {Promise<Object>} Item details
*/
async getItem(itemId) {
return await api.getItem(itemId, this._getContext());
}
/**
* Search drops
* @param {string} query - Search query
* @param {Object} [options] - Search options
* @returns {Promise<Object>} Search results
*/
async searchDrops(query, options = {}) {
return await api.searchDrops(query, options, this._getContext());
}
/**
* Get items from dashboard with pagination
* @param {Object} [options] - Options
* @param {number} [options.page=1] - Starting page number
* @param {number} [options.perPage=12] - Items per page
* @param {Function} [options.onProgress] - Progress callback
* @returns {Promise<Object>} Items and pagination info
*/
async getItemsFromDashboard(options = {}) {
return await api.getItemsFromDashboard(options, this._getContext());
}
/**
* Get ALL items from dashboard
* @param {Object} [options] - Options
* @param {Function} [options.onProgress] - Progress callback
* @param {number} [options.startPage=1] - Start from this page
* @param {number} [options.endPage] - End at this page
* @returns {Promise<Object>} All items and metadata
*/
async getAllItems(options = {}) {
return await api.getAllItems(options, this._getContext());
}
// ==================== Collections Methods ====================
/**
* Get list of collections
* @param {Object} [options] - Options
* @returns {Promise<Object>} Collections data
*/
async getCollections(options = {}) {
return await api.getCollections(options, this._getContext());
}
/**
* Get all collections
* @returns {Promise<Array>} Array of all collections
*/
async getAllCollections() {
return await api.getAllCollections(this._getContext());
}
// ==================== Video Request Methods ====================
/**
* Create a video recording request link
* @param {Object} options - Request options
* @param {string} options.name - Title of the request (required)
* @param {string} options.message - Message/instructions (required)
* @param {string} [options.customId] - Custom identifier
* @param {string} [options.expiresAt] - Expiration date ISO format
* @param {string} [options.collectionId] - Collection ID
* @param {boolean} [options.collectLogs=false] - Collect logs
* @returns {Promise<Object>} Request content data with link
*/
async createVideoRequest(options) {
return await api.createVideoRequest(options, this._getContext());
}
/**
* Get list of video requests
* @param {Object} [options] - Options
* @returns {Promise<Object>} Video requests data
*/
async getVideoRequests(options = {}) {
return await api.getVideoRequests(options, this._getContext());
}
/**
* Get a specific video request by ID
* @param {string} requestId - The request ID
* @returns {Promise<Object|null>} Request data or null
*/
async getVideoRequest(requestId) {
return await api.getVideoRequest(requestId, this._getContext());
}
/**
* Update a video request
* @param {string} requestId - The request ID
* @param {Object} options - Update options
* @returns {Promise<Object>} Updated request data
*/
async updateVideoRequest(requestId, options) {
return await api.updateVideoRequest(requestId, options, this._getContext());
}
/**
* Delete a video request
* @param {string} requestId - The request ID
* @returns {Promise<Object>} Deleted request data
*/
async deleteVideoRequest(requestId) {
return await api.deleteVideoRequest(requestId, this._getContext());
}
// ==================== Upload Methods ====================
/**
* Upload a file to Zight
* @param {string} filePath - Path to the file
* @param {Function} [onProgress] - Progress callback
* @returns {Promise<Object>} Uploaded item data with share URL
*/
async uploadFile(filePath, onProgress = null) {
return await api.uploadFile(filePath, onProgress, this._getContext());
}
/**
* Create an upload request (step 1 of upload process)
* @param {string} filename - The filename
* @param {number} fileSize - File size in bytes
* @param {string} contentType - MIME type
* @returns {Promise<Object>} Upload credentials
*/
async createUploadRequest(filename, fileSize, contentType) {
return await api.createUploadRequest(filename, fileSize, contentType, this._getContext());
}
/**
* Confirm upload completion (step 3 of upload process)
* @param {string} slug - The item slug
* @param {string} s3Key - The S3 key
* @param {string} checksum - The checksum
* @returns {Promise<Object>} Completed item data
*/
async confirmUploadComplete(slug, s3Key, checksum) {
return await api.confirmUploadComplete(slug, s3Key, checksum, this._getContext());
}
// ==================== Delete/Trash Methods ====================
/**
* Delete an item
* @param {string} itemId - The item ID
* @param {boolean} [permanent=false] - Permanently delete
* @returns {Promise<Object>} Delete response
*/
async deleteItem(itemId, permanent = false) {
return await api.deleteItem(itemId, permanent, this._getContext());
}
/**
* Restore an item from trash
* @param {string} itemId - The item ID
* @returns {Promise<Object>} Restore response
*/
async restoreItem(itemId) {
return await api.restoreItem(itemId, this._getContext());
}
/**
* Get items from trash
* @returns {Promise<Array>} Array of trash items
*/
async getTrashItems() {
return await api.getTrashItems(this._getContext());
}
/**
* Empty the trash
* @param {Function} [onProgress] - Progress callback
* @returns {Promise<Object>} Results summary
*/
async emptyTrash(onProgress = null) {
return await api.emptyTrash(onProgress, this._getContext());
}
// ==================== Notification Methods ====================
/**
* Get notifications
* @param {Object} [options] - Options
* @param {string} [options.viewed='no'] - 'yes', 'no', or 'all'
* @param {number} [options.limit=20] - Number to fetch
* @param {string} [options.createdBefore] - ISO date for pagination
* @returns {Promise<Object>} Notifications data
*/
async getNotifications(options = {}) {
return await api.getNotifications(options, this._getContext());
}
/**
* Mark a notification as viewed
* @param {string} notificationId - The notification ID
* @returns {Promise<Object>} Response
*/
async markNotificationViewed(notificationId) {
return await api.markNotificationViewed(notificationId, this._getContext());
}
/**
* Mark all notifications as viewed
* @param {Function} [onProgress] - Progress callback
* @returns {Promise<Object>} Results summary
*/
async markAllNotificationsViewed(onProgress = null) {
return await api.markAllNotificationsViewed(onProgress, this._getContext());
}
}
export default ZightClient;