JavaScript SDK for Qiniu Cloud Storage that enables browser-based file uploads with resumable transfer, image processing, and comprehensive error handling.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Regional configuration and upload settings for optimal performance across different geographic locations, along with API management functions.
Qiniu Cloud Storage operates in multiple regions worldwide. Choose the appropriate region for optimal upload performance.
const region = {
/** East China (Huadong) */
z0: 'z0',
/** North China (Huabei) */
z1: 'z1',
/** South China (Huanan) */
z2: 'z2',
/** North America */
na0: 'na0',
/** Southeast Asia */
as0: 'as0',
/** East China 2 (Huadong-Zhejiang 2) */
cnEast2: 'cn-east-2'
} as const;Usage Examples:
import { upload, region } from "qiniu-js";
// Upload to East China region (most common)
const subscription = upload(file, key, token, {
fname: file.name
}, {
region: region.z0,
useCdnDomain: true
});
// Upload to North America region for US users
const usUpload = upload(file, key, token, {
fname: file.name
}, {
region: region.na0,
upprotocol: 'https'
});
// Upload to Southeast Asia for Asian users
const asiaUpload = upload(file, key, token, {
fname: file.name
}, {
region: region.as0
});
// Dynamic region selection based on user location
function selectOptimalRegion(userCountry: string): string {
const regionMap: { [key: string]: string } = {
'US': region.na0,
'CA': region.na0,
'SG': region.as0,
'MY': region.as0,
'TH': region.as0,
'CN': region.z0,
'default': region.z0
};
return regionMap[userCountry] || regionMap['default'];
}Functions for managing upload endpoints and cleaning up failed uploads.
/**
* Get the optimal upload URL for given configuration
* @param config - Upload URL configuration
* @param token - Upload token
* @returns Promise resolving to upload URL
*/
function getUploadUrl(config: UploadUrlConfig, token: string): Promise<string>;
/**
* Delete uploaded chunks from a failed or cancelled resumable upload
* @param token - Upload token
* @param key - Target file key
* @param uploadinfo - Upload session information
* @returns Promise for cleanup completion
*/
function deleteUploadedChunks(
token: string,
key: string | null | undefined,
uploadinfo: UploadInfo
): Promise<ResponseSuccess<void>>;
interface UploadUrlConfig {
/** Upload protocol */
upprotocol?: 'https' | 'http';
/** Custom upload host */
uphost?: string[];
/** Target region */
region?: string;
/** Use CDN domain */
useCdnDomain?: boolean;
}
interface UploadInfo {
/** Upload session ID */
id: string;
/** Upload endpoint URL */
url: string;
}Usage Examples:
import { getUploadUrl, deleteUploadedChunks } from "qiniu-js";
// Get upload URL for specific configuration
async function getCustomUploadUrl(token: string) {
try {
const uploadUrl = await getUploadUrl({
region: 'z0',
upprotocol: 'https',
useCdnDomain: true
}, token);
console.log('Upload URL:', uploadUrl);
return uploadUrl;
} catch (error) {
console.error('Failed to get upload URL:', error);
throw error;
}
}
// Clean up failed resumable upload
async function cleanupFailedUpload(token: string, key: string, uploadInfo: UploadInfo) {
try {
await deleteUploadedChunks(token, key, uploadInfo);
console.log('Cleanup completed for upload session:', uploadInfo.id);
} catch (error) {
console.error('Cleanup failed:', error);
}
}
// Advanced upload URL management
class UploadManager {
private uploadUrls: Map<string, string> = new Map();
async getOrCreateUploadUrl(region: string, token: string): Promise<string> {
const cacheKey = `${region}-${token.substring(0, 10)}`;
if (this.uploadUrls.has(cacheKey)) {
return this.uploadUrls.get(cacheKey)!;
}
const url = await getUploadUrl({
region,
upprotocol: 'https',
useCdnDomain: true
}, token);
this.uploadUrls.set(cacheKey, url);
return url;
}
clearCache() {
this.uploadUrls.clear();
}
}Choose the appropriate region based on your users' geographic location for optimal performance:
| Region | Code | Location | Best For |
|---|---|---|---|
| East China | z0 | Shanghai | China mainland users |
| North China | z1 | Beijing | Northern China users |
| South China | z2 | Guangzhou | Southern China users |
| North America | na0 | USA | US and Canada users |
| Southeast Asia | as0 | Singapore | Asian users outside China |
| East China 2 | cnEast2 | Zhejiang | Backup for East China |
Region Performance Example:
import { upload, region } from "qiniu-js";
// Measure upload performance across regions
async function benchmarkRegions(file: File, token: string): Promise<void> {
const regions = [region.z0, region.z1, region.z2, region.na0, region.as0];
const results: { region: string; time: number; speed: number }[] = [];
for (const reg of regions) {
const startTime = Date.now();
try {
await new Promise((resolve, reject) => {
upload(file, `benchmark-${reg}.test`, token, {}, { region: reg })
.subscribe({
complete: resolve,
error: reject
});
});
const duration = Date.now() - startTime;
const speed = (file.size / 1024) / (duration / 1000); // KB/s
results.push({
region: reg,
time: duration,
speed: Math.round(speed)
});
} catch (error) {
console.error(`Region ${reg} failed:`, error);
}
}
// Sort by speed
results.sort((a, b) => b.speed - a.speed);
console.log('Region performance results:', results);
}Optimize upload settings for different scenarios.
import { upload, region } from "qiniu-js";
// Configuration for different use cases
const configurations = {
// Fast uploads for small files
smallFiles: {
forceDirect: true,
useCdnDomain: true,
retryCount: 3,
region: region.z0
},
// Reliable uploads for large files
largeFiles: {
chunkSize: 8, // 8MB chunks
concurrentRequestLimit: 3,
retryCount: 5,
useCdnDomain: true,
region: region.z0
},
// Conservative settings for unstable networks
unstableNetwork: {
chunkSize: 2, // Smaller chunks
concurrentRequestLimit: 1,
retryCount: 10,
useCdnDomain: false, // Direct to origin
region: region.z0
},
// High-performance settings for stable networks
highPerformance: {
chunkSize: 16, // Large chunks
concurrentRequestLimit: 6,
retryCount: 3,
useCdnDomain: true,
region: region.z0
}
};
// Smart configuration selection
function selectConfiguration(file: File, networkQuality: 'fast' | 'normal' | 'slow') {
const fileSize = file.size;
const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
if (fileSize < 4 * 1024 * 1024) { // < 4MB
return configurations.smallFiles;
}
if (networkQuality === 'slow' || isMobile) {
return configurations.unstableNetwork;
}
if (networkQuality === 'fast' && fileSize > 100 * 1024 * 1024) { // > 100MB
return configurations.highPerformance;
}
return configurations.largeFiles;
}
// Usage with smart configuration
function smartUpload(file: File, key: string, token: string, networkQuality: 'fast' | 'normal' | 'slow' = 'normal') {
const config = selectConfiguration(file, networkQuality);
return upload(file, key, token, {
fname: file.name
}, config);
}Configure custom upload hosts for enterprise deployments.
import { upload } from "qiniu-js";
// Custom host configuration
const enterpriseConfig = {
uphost: [
'upload.your-domain.com',
'upload-backup.your-domain.com'
],
upprotocol: 'https' as const,
useCdnDomain: false,
retryCount: 3
};
// Upload using custom hosts
const enterpriseUpload = upload(file, key, token, {
fname: file.name
}, enterpriseConfig);
// Fallback configuration with multiple hosts
const redundantConfig = {
uphost: [
'primary-upload.example.com',
'secondary-upload.example.com',
'tertiary-upload.example.com'
],
upprotocol: 'https' as const,
retryCount: 5 // Will try different hosts on failure
};Adapt configuration based on runtime conditions.
import { upload, region } from "qiniu-js";
class DynamicUploadConfig {
private userLocation: string = 'unknown';
private networkSpeed: number = 0;
private deviceType: 'mobile' | 'desktop' = 'desktop';
constructor() {
this.detectEnvironment();
}
private detectEnvironment() {
// Detect device type
this.deviceType = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
? 'mobile' : 'desktop';
// Estimate network speed (simplified)
if ('connection' in navigator) {
const connection = (navigator as any).connection;
this.networkSpeed = connection.downlink || 1;
}
}
getOptimalConfig(fileSize: number) {
const config: any = {
useCdnDomain: true,
upprotocol: 'https'
};
// Region selection
config.region = this.selectRegion();
// Chunk size based on network and device
if (this.deviceType === 'mobile' || this.networkSpeed < 2) {
config.chunkSize = 2; // 2MB for mobile/slow networks
config.concurrentRequestLimit = 1;
} else if (this.networkSpeed > 10) {
config.chunkSize = 16; // 16MB for fast networks
config.concurrentRequestLimit = 6;
} else {
config.chunkSize = 8; // 8MB default
config.concurrentRequestLimit = 3;
}
// Retry logic
config.retryCount = this.deviceType === 'mobile' ? 5 : 3;
// Force direct for small files
if (fileSize < 4 * 1024 * 1024) {
config.forceDirect = true;
}
return config;
}
private selectRegion(): string {
// Simplified region selection
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
if (timezone.includes('America')) {
return region.na0;
} else if (timezone.includes('Asia') && !timezone.includes('China')) {
return region.as0;
} else {
return region.z0; // Default to East China
}
}
}
// Usage
const dynamicConfig = new DynamicUploadConfig();
function adaptiveUpload(file: File, key: string, token: string) {
const config = dynamicConfig.getOptimalConfig(file.size);
console.log('Using adaptive configuration:', config);
return upload(file, key, token, {
fname: file.name
}, config);
}Install with Tessl CLI
npx tessl i tessl/npm-qiniu-js