aliendrive-sdk 1.0.0 → 1.1.0

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.
Files changed (2) hide show
  1. package/aliendrive.js +84 -5
  2. package/package.json +1 -1
package/aliendrive.js CHANGED
@@ -124,24 +124,103 @@ class AlienDrive {
124
124
  return { DeleteMarker: true };
125
125
  }
126
126
 
127
+ // ── Direct-to-B2 Upload (for large files, bypasses server) ──
128
+
129
+ /**
130
+ * Upload directly to B2 storage — bypasses server for the file data.
131
+ * Use this for large files. The flow:
132
+ * 1. Get signed upload URL from server
133
+ * 2. Upload file directly to B2
134
+ * 3. Confirm upload with server (validates size, type, quota)
135
+ *
136
+ * @param {Object} params
137
+ * @param {string} params.fileName - Original file name
138
+ * @param {Buffer} params.body - File content
139
+ * @param {string} [params.contentType] - MIME type
140
+ * @param {string} [params.parentId] - Parent folder ID
141
+ */
142
+ async directUpload({ fileName, body, contentType = 'application/octet-stream', parentId = null }) {
143
+ const crypto = require('crypto');
144
+
145
+ // Step 1: Get upload URL
146
+ const urlRes = await this._fetch('/api/v1/upload/url', {
147
+ method: 'POST',
148
+ headers: { 'Content-Type': 'application/json' },
149
+ body: JSON.stringify({ fileName, contentType, size: body.length, parentId }),
150
+ });
151
+ if (!urlRes.ok) {
152
+ const err = await urlRes.json().catch(() => ({ error: urlRes.statusText }));
153
+ throw new Error(`Upload URL failed (${urlRes.status}): ${err.error}`);
154
+ }
155
+ const urlData = await urlRes.json();
156
+
157
+ // Step 2: Upload directly to B2
158
+ const sha1 = crypto.createHash('sha1').update(body).digest('hex');
159
+ const b2Res = await fetch(urlData.uploadUrl, {
160
+ method: 'POST',
161
+ headers: {
162
+ 'Authorization': urlData.authToken,
163
+ 'X-Bz-File-Name': encodeURIComponent(urlData.b2FileName),
164
+ 'Content-Type': contentType,
165
+ 'Content-Length': String(body.length),
166
+ 'X-Bz-Content-Sha1': sha1,
167
+ },
168
+ body: body,
169
+ });
170
+ if (!b2Res.ok) {
171
+ const err = await b2Res.text();
172
+ throw new Error(`B2 upload failed (${b2Res.status}): ${err}`);
173
+ }
174
+
175
+ // Step 3: Confirm with server (validates size, type, quota)
176
+ const confirmRes = await this._fetch('/api/v1/upload/confirm', {
177
+ method: 'POST',
178
+ headers: { 'Content-Type': 'application/json' },
179
+ body: JSON.stringify({
180
+ fileKey: urlData.fileKey,
181
+ fileName,
182
+ size: body.length,
183
+ contentType,
184
+ parentId: urlData.parentId,
185
+ }),
186
+ });
187
+ if (!confirmRes.ok) {
188
+ const err = await confirmRes.json().catch(() => ({ error: confirmRes.statusText }));
189
+ throw new Error(`Upload confirm failed (${confirmRes.status}): ${err.error}`);
190
+ }
191
+ return confirmRes.json();
192
+ }
193
+
127
194
  // ── Convenience methods ──
128
195
 
129
196
  /**
130
- * Upload a local file
197
+ * Upload a local file.
198
+ * Uses direct-to-B2 upload for files > 5MB, S3 API for smaller files.
131
199
  */
132
200
  async uploadFile(localPath, remotePath) {
133
201
  const fs = require('fs');
134
202
  const path = require('path');
135
203
  const mime = {
136
- '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.png': 'image/png', '.gif': 'image/gif',
137
- '.pdf': 'application/pdf', '.txt': 'text/plain', '.html': 'text/html',
204
+ '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.png': 'image/png', '.gif': 'image/gif', '.webp': 'image/webp',
205
+ '.pdf': 'application/pdf', '.txt': 'text/plain', '.html': 'text/html', '.css': 'text/css',
138
206
  '.json': 'application/json', '.xml': 'application/xml',
139
- '.zip': 'application/zip', '.mp4': 'video/mp4', '.mp3': 'audio/mpeg',
207
+ '.zip': 'application/zip', '.gz': 'application/gzip',
208
+ '.mp4': 'video/mp4', '.webm': 'video/webm', '.mov': 'video/quicktime',
209
+ '.mp3': 'audio/mpeg', '.wav': 'audio/wav', '.ogg': 'audio/ogg',
210
+ '.doc': 'application/msword', '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
211
+ '.xls': 'application/vnd.ms-excel', '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
140
212
  };
141
213
  const ext = path.extname(localPath).toLowerCase();
142
214
  const body = fs.readFileSync(localPath);
143
215
  const key = remotePath || path.basename(localPath);
144
- return this.putObject({ Key: key, Body: body, ContentType: mime[ext] || 'application/octet-stream' });
216
+ const contentType = mime[ext] || 'application/octet-stream';
217
+
218
+ // Use direct upload for files > 5MB
219
+ if (body.length > 5 * 1024 * 1024) {
220
+ return this.directUpload({ fileName: path.basename(localPath), body, contentType, parentId: null });
221
+ }
222
+
223
+ return this.putObject({ Key: key, Body: body, ContentType: contentType });
145
224
  }
146
225
 
147
226
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aliendrive-sdk",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Official Node.js SDK for the AlienDrive API — S3-like cloud storage",
5
5
  "main": "aliendrive.js",
6
6
  "types": "aliendrive.d.ts",