@dcd-sdk/storage-client 0.0.0-stage → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,171 @@
1
- # Temporary Holding Version
1
+ # @dcd-sdk/storage-client
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Official Node.js & TypeScript Client SDK for **DevCloudDesk Storage Engine**.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@dcd-sdk/storage-client?color=blue)](https://www.npmjs.com/package/@dcd-sdk/storage-client)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue)](https://www.typescriptlang.org/)
8
+ [![Node.js](https://img.shields.io/badge/Node.js-18%2B-green)](https://nodejs.org/)
9
+
10
+ High-performance, Cloudinary-compatible on-the-fly media transformations and ultra-fast asset delivery backed by your self-hosted DevCloudDesk storage clusters.
11
+
12
+ ---
13
+
14
+ ## 📦 Installation
15
+
16
+ ```bash
17
+ # npm
18
+ npm install @dcd-sdk/storage-client
19
+
20
+ # pnpm
21
+ pnpm add @dcd-sdk/storage-client
22
+
23
+ # yarn
24
+ yarn add @dcd-sdk/storage-client
25
+ ```
26
+
27
+ Universal compatibility: **CommonJS (`require`)**, **ES Modules (`import`)**, **TypeScript**, **Next.js**, **Vite**, **Bun**, and **Deno**.
28
+
29
+ ---
30
+
31
+ ## 🚀 Quickstart
32
+
33
+ ### 1. Initialize the Client
34
+
35
+ ```typescript
36
+ import { createBucketClient } from '@dcd-sdk/storage-client';
37
+
38
+ const bucket = createBucketClient({
39
+ endpoint: 'http://YOUR_SERVER_IP:7100', // or https://storage.yourdomain.com
40
+ apiKey: process.env.STORAGE_API_KEY, // API Key from DevCloudDesk Dashboard
41
+ });
42
+ ```
43
+
44
+ *CommonJS is also fully supported:*
45
+ ```javascript
46
+ const { createBucketClient } = require('@dcd-sdk/storage-client');
47
+ ```
48
+
49
+ ---
50
+
51
+ ### 2. Uploading Files (Node.js or Browser)
52
+
53
+ Supports file paths (Node.js), `Buffer`, `Blob`, `File`, or `ArrayBuffer`:
54
+
55
+ ```typescript
56
+ // Upload from Buffer, File, or local file path
57
+ const asset = await bucket.upload(fileBuffer, {
58
+ folder: 'avatars',
59
+ filename: 'user-profile.png',
60
+ onProgress: (percent) => {
61
+ console.log(`Upload progress: ${percent}%`);
62
+ },
63
+ });
64
+
65
+ console.log('Public ID:', asset.publicId);
66
+ console.log('CDN URL:', asset.url);
67
+ ```
68
+
69
+ ---
70
+
71
+ ### 3. Dynamic On-The-Fly Transformations
72
+
73
+ Generate real-time optimized WebP/AVIF images with automatic resizing, blur, and sharpening:
74
+
75
+ ```typescript
76
+ const avatarUrl = bucket
77
+ .url(asset.publicId)
78
+ .resize({ width: 400, height: 400, crop: 'cover' })
79
+ .format('webp')
80
+ .quality(80)
81
+ .blur(4)
82
+ .build();
83
+
84
+ // Output: http://YOUR_SERVER_IP:7100/v1/image/w_400,h_400,c_cover,f_webp,q_80,e_blur_4/avatars/user-profile.png
85
+ ```
86
+
87
+ #### Transformation Options Reference
88
+
89
+ | Method | Parameters | Description |
90
+ | :--- | :--- | :--- |
91
+ | `.resize({ width, height, crop })` | `number, number, CropMode` | Resizes image dimension with crop strategy |
92
+ | `.crop(mode)` | `'fill' \| 'fit' \| 'crop' \| 'scale'` | Crop strategy |
93
+ | `.format(fmt)` | `'auto' \| 'webp' \| 'avif' \| 'jpeg' \| 'png'` | Output image format |
94
+ | `.quality(q)` | `number (1-100) \| 'auto'` | Compression quality |
95
+ | `.blur(sigma)` | `number (1-100)` | Applies Gaussian blur filter |
96
+ | `.grayscale()` | `boolean` | Converts image to black and white |
97
+ | `.sharpen()` | `boolean` | Enhances edge sharpness |
98
+ | `.rotation(deg)` | `number \| 'auto'` | Rotates image by degrees (e.g. 90, 180, 270) |
99
+
100
+ ---
101
+
102
+ ### 4. Client-Side Uploads via Signed Tokens (Zero Secret Exposure)
103
+
104
+ Keep your master API keys safely on your backend server. Generate short-lived, tamper-proof signed upload tokens for your frontend React/Next.js/Mobile apps:
105
+
106
+ ```typescript
107
+ // Backend endpoint (Node.js / Next.js / Express):
108
+ app.post('/api/get-upload-token', async (req, res) => {
109
+ const tokenData = await bucket.createSignedUploadToken({
110
+ folder: 'user-uploads',
111
+ expiresInSeconds: 300, // 5 minutes
112
+ maxBytes: 10 * 1024 * 1024, // 10 MB limit
113
+ });
114
+ res.json(tokenData);
115
+ });
116
+
117
+ // Frontend client (Browser / React / Vue):
118
+ const { token } = await res.json();
119
+ await bucket.uploadWithToken(file, token, {
120
+ onProgress: (percent) => setProgress(percent),
121
+ });
122
+ ```
123
+
124
+ ---
125
+
126
+ ### 5. Listing Files & Server Stats
127
+
128
+ ```typescript
129
+ // List files in a bucket / folder
130
+ const result = await bucket.listFiles({
131
+ folder: 'avatars',
132
+ page: 1,
133
+ limit: 20,
134
+ });
135
+ console.log('Files count:', result.data.files.length);
136
+
137
+ // Server metrics
138
+ const stats = await bucket.getStats();
139
+ console.log('Total files:', stats.filesCount, 'Storage used:', stats.totalStorageBytes);
140
+ ```
141
+
142
+ ---
143
+
144
+ ### 6. Robust Error Handling
145
+
146
+ ```typescript
147
+ import {
148
+ AuthenticationError,
149
+ NotFoundError,
150
+ PayloadTooLargeError,
151
+ UploadError,
152
+ } from '@dcd-sdk/storage-client';
153
+
154
+ try {
155
+ await bucket.upload(file);
156
+ } catch (error) {
157
+ if (error instanceof AuthenticationError) {
158
+ console.error('Check your API key:', error.message);
159
+ } else if (error instanceof PayloadTooLargeError) {
160
+ console.error('File size exceeds server limits:', error.message);
161
+ } else if (error instanceof UploadError) {
162
+ console.error('Upload failed:', error.message);
163
+ }
164
+ }
165
+ ```
166
+
167
+ ---
168
+
169
+ ## 📄 License
170
+
171
+ MIT © [DevCloudDesk](https://devclouddesk.com)
@@ -0,0 +1,214 @@
1
+ type CropMode = 'fill' | 'fit' | 'crop' | 'scale';
2
+ type OutputFormat = 'auto' | 'webp' | 'avif' | 'jpeg' | 'png';
3
+ interface StorageClientConfig {
4
+ /** The base URL of the storage engine cluster (e.g. 'https://storage.mycoolapp.com' or 'http://192.168.1.50:7100') */
5
+ endpoint: string;
6
+ /** Public API key (dcd_pk_...), Secret key (dcd_sk_...), or Master key */
7
+ apiKey?: string;
8
+ /** Request timeout in milliseconds (default: 30000) */
9
+ timeoutMs?: number;
10
+ }
11
+ type MediaClientConfig = StorageClientConfig;
12
+ type BucketClientConfig = StorageClientConfig;
13
+ interface TransformationOptions {
14
+ width?: number;
15
+ height?: number;
16
+ crop?: CropMode;
17
+ format?: OutputFormat;
18
+ quality?: number | 'auto';
19
+ blur?: number;
20
+ grayscale?: boolean;
21
+ sharpen?: boolean;
22
+ rotation?: number | 'auto';
23
+ }
24
+ interface UploadOptions {
25
+ folder?: string;
26
+ publicId?: string;
27
+ filename?: string;
28
+ overwrite?: boolean;
29
+ uniqueFilename?: boolean;
30
+ /** Optional client signed upload token (dcd_sig_...) to upload without API key */
31
+ token?: string;
32
+ tags?: string[];
33
+ /** Progress tracking callback (supported in browser environments) */
34
+ onProgress?: (percent: number) => void;
35
+ /** Request timeout in milliseconds */
36
+ timeoutMs?: number;
37
+ }
38
+ interface SignUploadOptions {
39
+ folder?: string;
40
+ maxBytes?: number;
41
+ expiresInSeconds?: number;
42
+ }
43
+ interface SignedUploadResult {
44
+ success: boolean;
45
+ token: string;
46
+ uploadUrl: string;
47
+ expiresInSeconds: number;
48
+ folder?: string | null;
49
+ maxBytes?: number | null;
50
+ }
51
+ interface AssetResult {
52
+ public_id: string;
53
+ publicId: string;
54
+ filename: string;
55
+ format: string;
56
+ resource_type?: string;
57
+ resourceType?: string;
58
+ width?: number;
59
+ height?: number;
60
+ bytes: number;
61
+ storageDriver: string;
62
+ etag: string;
63
+ url: string;
64
+ secure_url: string;
65
+ secureUrl: string;
66
+ rawUrl?: string;
67
+ created_at: number;
68
+ createdAt: number;
69
+ }
70
+ type StorageAssetResult = AssetResult;
71
+ type BucketAssetResult = AssetResult;
72
+ interface Pagination {
73
+ page: number;
74
+ limit: number;
75
+ total: number;
76
+ totalPages: number;
77
+ hasNext: boolean;
78
+ hasPrev: boolean;
79
+ }
80
+ interface FileListOptions {
81
+ folder?: string;
82
+ page?: number;
83
+ limit?: number;
84
+ }
85
+ interface FileListResult {
86
+ success: boolean;
87
+ data: {
88
+ files: AssetResult[];
89
+ pagination: Pagination;
90
+ };
91
+ }
92
+ interface ServerStats {
93
+ filesCount: number;
94
+ totalStorageBytes: number;
95
+ cacheVariantsCount: number;
96
+ cacheSizeBytes: number;
97
+ uptimeSeconds: number;
98
+ memoryUsageMb: number;
99
+ storageDriver: string;
100
+ }
101
+ interface HealthCheckResult {
102
+ status: 'ok' | 'error';
103
+ uptime?: number;
104
+ timestamp?: number;
105
+ version?: string;
106
+ }
107
+
108
+ declare class TransformationBuilder {
109
+ private endpoint;
110
+ private publicId;
111
+ private options;
112
+ constructor(endpoint: string, publicId: string);
113
+ width(w: number): this;
114
+ height(h: number): this;
115
+ resize(params: {
116
+ width?: number;
117
+ height?: number;
118
+ crop?: CropMode;
119
+ }): this;
120
+ crop(mode: CropMode): this;
121
+ format(fmt: OutputFormat): this;
122
+ quality(q: number | 'auto'): this;
123
+ blur(sigma?: number): this;
124
+ grayscale(enable?: boolean): this;
125
+ sharpen(enable?: boolean): this;
126
+ rotation(rot: number | 'auto'): this;
127
+ /**
128
+ * Builds the formatted transformation string (e.g. w_400,h_300,c_fill,f_auto)
129
+ */
130
+ toParamsString(): string;
131
+ /**
132
+ * Returns the final full URL string
133
+ */
134
+ build(): string;
135
+ toString(): string;
136
+ }
137
+
138
+ declare class StorageClient {
139
+ private endpoint;
140
+ private apiKey;
141
+ private defaultTimeoutMs;
142
+ constructor(config: StorageClientConfig);
143
+ /**
144
+ * Initializes a fluent URL builder for on-the-fly CDN image transformations
145
+ */
146
+ url(publicId: string): TransformationBuilder;
147
+ /**
148
+ * Checks the health and connectivity of the storage engine server
149
+ */
150
+ healthCheck(): Promise<HealthCheckResult>;
151
+ /**
152
+ * Retrieves server performance, storage, and cache statistics (requires authorized API key)
153
+ */
154
+ getStats(): Promise<ServerStats>;
155
+ /**
156
+ * Lists files in the storage cluster with pagination and optional folder filter
157
+ */
158
+ listFiles(options?: FileListOptions): Promise<FileListResult>;
159
+ /**
160
+ * Generates a short-lived cryptographically signed upload token for safe client-side browser/mobile uploads.
161
+ * Keeps master API keys strictly on backend servers.
162
+ */
163
+ createSignedUploadToken(options?: SignUploadOptions): Promise<SignedUploadResult>;
164
+ /**
165
+ * Directly uploads a file to the storage server.
166
+ * Supports:
167
+ * - String file path (Node.js)
168
+ * - Buffer / Uint8Array / ArrayBuffer
169
+ * - File / Blob (Browser and universal runtimes)
170
+ * Auth:
171
+ * - Master API Key OR Client Signed Upload Token (dcd_sig_...)
172
+ */
173
+ upload(file: any, options?: UploadOptions): Promise<AssetResult>;
174
+ /**
175
+ * Helper method for frontend browser/mobile clients to upload using only a signed upload token (zero API key)
176
+ */
177
+ uploadWithToken(file: any, token: string, options?: Omit<UploadOptions, 'token'>): Promise<AssetResult>;
178
+ /**
179
+ * Permanently deletes a storage asset (requires API key with delete permissions)
180
+ */
181
+ delete(publicId: string): Promise<boolean>;
182
+ private getAuthHeaders;
183
+ private fetchWithTimeout;
184
+ private parseJsonResponse;
185
+ }
186
+ declare function createStorageClient(config: StorageClientConfig): StorageClient;
187
+ declare const BucketClient: typeof StorageClient;
188
+ type BucketClient = StorageClient;
189
+ declare const createBucketClient: typeof createStorageClient;
190
+ declare const MediaClient: typeof StorageClient;
191
+ type MediaClient = StorageClient;
192
+ declare const createMediaClient: typeof createStorageClient;
193
+
194
+ declare class DCDStorageError extends Error {
195
+ status?: number;
196
+ code?: string;
197
+ details?: any;
198
+ constructor(message: string, status?: number, code?: string, details?: any);
199
+ }
200
+ declare class AuthenticationError extends DCDStorageError {
201
+ constructor(message?: string, status?: number, details?: any);
202
+ }
203
+ declare class NotFoundError extends DCDStorageError {
204
+ constructor(message?: string, status?: number, details?: any);
205
+ }
206
+ declare class PayloadTooLargeError extends DCDStorageError {
207
+ constructor(message?: string, status?: number, details?: any);
208
+ }
209
+ declare class UploadError extends DCDStorageError {
210
+ constructor(message: string, status?: number, details?: any);
211
+ }
212
+
213
+ export { AuthenticationError, BucketClient, DCDStorageError, MediaClient, NotFoundError, PayloadTooLargeError, StorageClient, TransformationBuilder, UploadError, createBucketClient, createMediaClient, createStorageClient };
214
+ export type { AssetResult, BucketAssetResult, BucketClientConfig, CropMode, FileListOptions, FileListResult, HealthCheckResult, MediaClientConfig, OutputFormat, Pagination, ServerStats, SignUploadOptions, SignedUploadResult, StorageAssetResult, StorageClientConfig, TransformationOptions, UploadOptions };
@@ -0,0 +1,214 @@
1
+ type CropMode = 'fill' | 'fit' | 'crop' | 'scale';
2
+ type OutputFormat = 'auto' | 'webp' | 'avif' | 'jpeg' | 'png';
3
+ interface StorageClientConfig {
4
+ /** The base URL of the storage engine cluster (e.g. 'https://storage.mycoolapp.com' or 'http://192.168.1.50:7100') */
5
+ endpoint: string;
6
+ /** Public API key (dcd_pk_...), Secret key (dcd_sk_...), or Master key */
7
+ apiKey?: string;
8
+ /** Request timeout in milliseconds (default: 30000) */
9
+ timeoutMs?: number;
10
+ }
11
+ type MediaClientConfig = StorageClientConfig;
12
+ type BucketClientConfig = StorageClientConfig;
13
+ interface TransformationOptions {
14
+ width?: number;
15
+ height?: number;
16
+ crop?: CropMode;
17
+ format?: OutputFormat;
18
+ quality?: number | 'auto';
19
+ blur?: number;
20
+ grayscale?: boolean;
21
+ sharpen?: boolean;
22
+ rotation?: number | 'auto';
23
+ }
24
+ interface UploadOptions {
25
+ folder?: string;
26
+ publicId?: string;
27
+ filename?: string;
28
+ overwrite?: boolean;
29
+ uniqueFilename?: boolean;
30
+ /** Optional client signed upload token (dcd_sig_...) to upload without API key */
31
+ token?: string;
32
+ tags?: string[];
33
+ /** Progress tracking callback (supported in browser environments) */
34
+ onProgress?: (percent: number) => void;
35
+ /** Request timeout in milliseconds */
36
+ timeoutMs?: number;
37
+ }
38
+ interface SignUploadOptions {
39
+ folder?: string;
40
+ maxBytes?: number;
41
+ expiresInSeconds?: number;
42
+ }
43
+ interface SignedUploadResult {
44
+ success: boolean;
45
+ token: string;
46
+ uploadUrl: string;
47
+ expiresInSeconds: number;
48
+ folder?: string | null;
49
+ maxBytes?: number | null;
50
+ }
51
+ interface AssetResult {
52
+ public_id: string;
53
+ publicId: string;
54
+ filename: string;
55
+ format: string;
56
+ resource_type?: string;
57
+ resourceType?: string;
58
+ width?: number;
59
+ height?: number;
60
+ bytes: number;
61
+ storageDriver: string;
62
+ etag: string;
63
+ url: string;
64
+ secure_url: string;
65
+ secureUrl: string;
66
+ rawUrl?: string;
67
+ created_at: number;
68
+ createdAt: number;
69
+ }
70
+ type StorageAssetResult = AssetResult;
71
+ type BucketAssetResult = AssetResult;
72
+ interface Pagination {
73
+ page: number;
74
+ limit: number;
75
+ total: number;
76
+ totalPages: number;
77
+ hasNext: boolean;
78
+ hasPrev: boolean;
79
+ }
80
+ interface FileListOptions {
81
+ folder?: string;
82
+ page?: number;
83
+ limit?: number;
84
+ }
85
+ interface FileListResult {
86
+ success: boolean;
87
+ data: {
88
+ files: AssetResult[];
89
+ pagination: Pagination;
90
+ };
91
+ }
92
+ interface ServerStats {
93
+ filesCount: number;
94
+ totalStorageBytes: number;
95
+ cacheVariantsCount: number;
96
+ cacheSizeBytes: number;
97
+ uptimeSeconds: number;
98
+ memoryUsageMb: number;
99
+ storageDriver: string;
100
+ }
101
+ interface HealthCheckResult {
102
+ status: 'ok' | 'error';
103
+ uptime?: number;
104
+ timestamp?: number;
105
+ version?: string;
106
+ }
107
+
108
+ declare class TransformationBuilder {
109
+ private endpoint;
110
+ private publicId;
111
+ private options;
112
+ constructor(endpoint: string, publicId: string);
113
+ width(w: number): this;
114
+ height(h: number): this;
115
+ resize(params: {
116
+ width?: number;
117
+ height?: number;
118
+ crop?: CropMode;
119
+ }): this;
120
+ crop(mode: CropMode): this;
121
+ format(fmt: OutputFormat): this;
122
+ quality(q: number | 'auto'): this;
123
+ blur(sigma?: number): this;
124
+ grayscale(enable?: boolean): this;
125
+ sharpen(enable?: boolean): this;
126
+ rotation(rot: number | 'auto'): this;
127
+ /**
128
+ * Builds the formatted transformation string (e.g. w_400,h_300,c_fill,f_auto)
129
+ */
130
+ toParamsString(): string;
131
+ /**
132
+ * Returns the final full URL string
133
+ */
134
+ build(): string;
135
+ toString(): string;
136
+ }
137
+
138
+ declare class StorageClient {
139
+ private endpoint;
140
+ private apiKey;
141
+ private defaultTimeoutMs;
142
+ constructor(config: StorageClientConfig);
143
+ /**
144
+ * Initializes a fluent URL builder for on-the-fly CDN image transformations
145
+ */
146
+ url(publicId: string): TransformationBuilder;
147
+ /**
148
+ * Checks the health and connectivity of the storage engine server
149
+ */
150
+ healthCheck(): Promise<HealthCheckResult>;
151
+ /**
152
+ * Retrieves server performance, storage, and cache statistics (requires authorized API key)
153
+ */
154
+ getStats(): Promise<ServerStats>;
155
+ /**
156
+ * Lists files in the storage cluster with pagination and optional folder filter
157
+ */
158
+ listFiles(options?: FileListOptions): Promise<FileListResult>;
159
+ /**
160
+ * Generates a short-lived cryptographically signed upload token for safe client-side browser/mobile uploads.
161
+ * Keeps master API keys strictly on backend servers.
162
+ */
163
+ createSignedUploadToken(options?: SignUploadOptions): Promise<SignedUploadResult>;
164
+ /**
165
+ * Directly uploads a file to the storage server.
166
+ * Supports:
167
+ * - String file path (Node.js)
168
+ * - Buffer / Uint8Array / ArrayBuffer
169
+ * - File / Blob (Browser and universal runtimes)
170
+ * Auth:
171
+ * - Master API Key OR Client Signed Upload Token (dcd_sig_...)
172
+ */
173
+ upload(file: any, options?: UploadOptions): Promise<AssetResult>;
174
+ /**
175
+ * Helper method for frontend browser/mobile clients to upload using only a signed upload token (zero API key)
176
+ */
177
+ uploadWithToken(file: any, token: string, options?: Omit<UploadOptions, 'token'>): Promise<AssetResult>;
178
+ /**
179
+ * Permanently deletes a storage asset (requires API key with delete permissions)
180
+ */
181
+ delete(publicId: string): Promise<boolean>;
182
+ private getAuthHeaders;
183
+ private fetchWithTimeout;
184
+ private parseJsonResponse;
185
+ }
186
+ declare function createStorageClient(config: StorageClientConfig): StorageClient;
187
+ declare const BucketClient: typeof StorageClient;
188
+ type BucketClient = StorageClient;
189
+ declare const createBucketClient: typeof createStorageClient;
190
+ declare const MediaClient: typeof StorageClient;
191
+ type MediaClient = StorageClient;
192
+ declare const createMediaClient: typeof createStorageClient;
193
+
194
+ declare class DCDStorageError extends Error {
195
+ status?: number;
196
+ code?: string;
197
+ details?: any;
198
+ constructor(message: string, status?: number, code?: string, details?: any);
199
+ }
200
+ declare class AuthenticationError extends DCDStorageError {
201
+ constructor(message?: string, status?: number, details?: any);
202
+ }
203
+ declare class NotFoundError extends DCDStorageError {
204
+ constructor(message?: string, status?: number, details?: any);
205
+ }
206
+ declare class PayloadTooLargeError extends DCDStorageError {
207
+ constructor(message?: string, status?: number, details?: any);
208
+ }
209
+ declare class UploadError extends DCDStorageError {
210
+ constructor(message: string, status?: number, details?: any);
211
+ }
212
+
213
+ export { AuthenticationError, BucketClient, DCDStorageError, MediaClient, NotFoundError, PayloadTooLargeError, StorageClient, TransformationBuilder, UploadError, createBucketClient, createMediaClient, createStorageClient };
214
+ export type { AssetResult, BucketAssetResult, BucketClientConfig, CropMode, FileListOptions, FileListResult, HealthCheckResult, MediaClientConfig, OutputFormat, Pagination, ServerStats, SignUploadOptions, SignedUploadResult, StorageAssetResult, StorageClientConfig, TransformationOptions, UploadOptions };