@unboundcx/sdk 1.0.4 → 1.0.7
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/base.js +1 -1
- package/package.json +1 -1
- package/services/storage.js +146 -16
package/base.js
CHANGED
|
@@ -238,7 +238,7 @@ export class BaseSDK {
|
|
|
238
238
|
body &&
|
|
239
239
|
(body.constructor.name === 'FormData' ||
|
|
240
240
|
typeof body.getBoundary === 'function');
|
|
241
|
-
const isBuffer = Buffer && Buffer.isBuffer && Buffer.isBuffer(body);
|
|
241
|
+
const isBuffer = (typeof Buffer !== 'undefined') && Buffer.isBuffer && Buffer.isBuffer(body);
|
|
242
242
|
|
|
243
243
|
if (isFormData || isBuffer) {
|
|
244
244
|
options.body = body;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unboundcx/sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Official JavaScript SDK for the Unbound API - A comprehensive toolkit for integrating with Unbound's communication, AI, and data management services",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
package/services/storage.js
CHANGED
|
@@ -49,7 +49,9 @@ export class StorageService {
|
|
|
49
49
|
if (isNode) {
|
|
50
50
|
// Node.js environment - use direct buffer approach
|
|
51
51
|
// Create a simple body with the file buffer and metadata
|
|
52
|
-
const boundary = `----formdata-${Date.now()}-${Math.random().toString(
|
|
52
|
+
const boundary = `----formdata-${Date.now()}-${Math.random().toString(
|
|
53
|
+
36,
|
|
54
|
+
)}`;
|
|
53
55
|
const CRLF = '\r\n';
|
|
54
56
|
let body = '';
|
|
55
57
|
|
|
@@ -131,19 +133,24 @@ export class StorageService {
|
|
|
131
133
|
}
|
|
132
134
|
|
|
133
135
|
body += `--${boundary}${CRLF}`;
|
|
134
|
-
body += `Content-Disposition: form-data; name="files"; filename="${
|
|
136
|
+
body += `Content-Disposition: form-data; name="files"; filename="${
|
|
137
|
+
fileName || 'file'
|
|
138
|
+
}"${CRLF}`;
|
|
135
139
|
body += `Content-Type: ${contentType}${CRLF}${CRLF}`;
|
|
136
140
|
|
|
137
141
|
// Add other form fields
|
|
138
142
|
const formFields = [];
|
|
139
143
|
if (classification) formFields.push(['classification', classification]);
|
|
140
144
|
if (folder) formFields.push(['folder', folder]);
|
|
141
|
-
if (isPublic !== undefined)
|
|
145
|
+
if (isPublic !== undefined)
|
|
146
|
+
formFields.push(['isPublic', isPublic.toString()]);
|
|
142
147
|
if (country) formFields.push(['country', country]);
|
|
143
148
|
if (expireAfter) formFields.push(['expireAfter', expireAfter]);
|
|
144
149
|
if (relatedId) formFields.push(['relatedId', relatedId]);
|
|
145
|
-
if (createAccessKey !== undefined)
|
|
146
|
-
|
|
150
|
+
if (createAccessKey !== undefined)
|
|
151
|
+
formFields.push(['createAccessKey', createAccessKey.toString()]);
|
|
152
|
+
if (accessKeyExpiresIn)
|
|
153
|
+
formFields.push(['accessKeyExpiresIn', accessKeyExpiresIn]);
|
|
147
154
|
|
|
148
155
|
// Convert to buffers and combine
|
|
149
156
|
const headerBuffer = Buffer.from(body, 'utf8');
|
|
@@ -153,14 +160,22 @@ export class StorageService {
|
|
|
153
160
|
let fieldsBuffer = Buffer.alloc(0);
|
|
154
161
|
for (const [name, value] of formFields) {
|
|
155
162
|
const fieldData = `${CRLF}--${boundary}${CRLF}Content-Disposition: form-data; name="${name}"${CRLF}${CRLF}${value}`;
|
|
156
|
-
fieldsBuffer = Buffer.concat([
|
|
163
|
+
fieldsBuffer = Buffer.concat([
|
|
164
|
+
fieldsBuffer,
|
|
165
|
+
Buffer.from(fieldData, 'utf8'),
|
|
166
|
+
]);
|
|
157
167
|
}
|
|
158
168
|
|
|
159
169
|
// Final boundary
|
|
160
170
|
const endBoundary = Buffer.from(`${CRLF}--${boundary}--${CRLF}`, 'utf8');
|
|
161
171
|
|
|
162
172
|
// Combine all parts
|
|
163
|
-
formData = Buffer.concat([
|
|
173
|
+
formData = Buffer.concat([
|
|
174
|
+
headerBuffer,
|
|
175
|
+
fileBuffer,
|
|
176
|
+
fieldsBuffer,
|
|
177
|
+
endBoundary,
|
|
178
|
+
]);
|
|
164
179
|
|
|
165
180
|
// Set proper Content-Type header
|
|
166
181
|
headers['content-type'] = `multipart/form-data; boundary=${boundary}`;
|
|
@@ -175,19 +190,24 @@ export class StorageService {
|
|
|
175
190
|
} else if (file instanceof File) {
|
|
176
191
|
formData.append('files', file);
|
|
177
192
|
} else {
|
|
178
|
-
throw new Error(
|
|
193
|
+
throw new Error(
|
|
194
|
+
'In browser environment, file must be a Buffer or File object',
|
|
195
|
+
);
|
|
179
196
|
}
|
|
180
197
|
|
|
181
198
|
// Add other parameters
|
|
182
199
|
if (classification) formData.append('classification', classification);
|
|
183
200
|
if (folder) formData.append('folder', folder);
|
|
184
|
-
if (isPublic !== undefined)
|
|
201
|
+
if (isPublic !== undefined)
|
|
202
|
+
formData.append('isPublic', isPublic.toString());
|
|
185
203
|
if (country) formData.append('country', country);
|
|
186
204
|
if (expireAfter) formData.append('expireAfter', expireAfter);
|
|
187
205
|
if (relatedId) formData.append('relatedId', relatedId);
|
|
188
|
-
if (createAccessKey !== undefined)
|
|
189
|
-
|
|
190
|
-
|
|
206
|
+
if (createAccessKey !== undefined)
|
|
207
|
+
formData.append('createAccessKey', createAccessKey.toString());
|
|
208
|
+
if (accessKeyExpiresIn)
|
|
209
|
+
formData.append('accessKeyExpiresIn', accessKeyExpiresIn);
|
|
210
|
+
|
|
191
211
|
// Don't set Content-Type - let browser handle it automatically
|
|
192
212
|
}
|
|
193
213
|
|
|
@@ -196,7 +216,12 @@ export class StorageService {
|
|
|
196
216
|
headers,
|
|
197
217
|
};
|
|
198
218
|
|
|
199
|
-
const result = await this.sdk._fetch(
|
|
219
|
+
const result = await this.sdk._fetch(
|
|
220
|
+
'/storage/upload',
|
|
221
|
+
'POST',
|
|
222
|
+
params,
|
|
223
|
+
true,
|
|
224
|
+
);
|
|
200
225
|
return result;
|
|
201
226
|
}
|
|
202
227
|
|
|
@@ -252,7 +277,12 @@ export class StorageService {
|
|
|
252
277
|
// Remove Content-Type to let FormData set it properly
|
|
253
278
|
delete params.headers['Content-Type'];
|
|
254
279
|
|
|
255
|
-
const result = await this.sdk._fetch(
|
|
280
|
+
const result = await this.sdk._fetch(
|
|
281
|
+
'/storage/upload',
|
|
282
|
+
'POST',
|
|
283
|
+
params,
|
|
284
|
+
true,
|
|
285
|
+
);
|
|
256
286
|
return result;
|
|
257
287
|
}
|
|
258
288
|
|
|
@@ -289,9 +319,9 @@ export class StorageService {
|
|
|
289
319
|
|
|
290
320
|
let url;
|
|
291
321
|
if (this.sdk.environment === 'node') {
|
|
292
|
-
url = `${this.sdk.baseURL}/storage
|
|
322
|
+
url = `${this.sdk.baseURL}/storage/${storageId}`;
|
|
293
323
|
} else {
|
|
294
|
-
url = `${this.sdk.fullUrl}/storage
|
|
324
|
+
url = `${this.sdk.fullUrl}/storage/${storageId}`;
|
|
295
325
|
}
|
|
296
326
|
|
|
297
327
|
if (download) {
|
|
@@ -321,6 +351,106 @@ export class StorageService {
|
|
|
321
351
|
return result;
|
|
322
352
|
}
|
|
323
353
|
|
|
354
|
+
async uploadProfileImage({ file, classification = 'user_images', fileName }) {
|
|
355
|
+
this.sdk.validateParams(
|
|
356
|
+
{ file, classification },
|
|
357
|
+
{
|
|
358
|
+
file: { type: 'object', required: true },
|
|
359
|
+
classification: { type: 'string', required: true },
|
|
360
|
+
fileName: { type: 'string', required: false },
|
|
361
|
+
},
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
// Validate classification
|
|
365
|
+
const validClassifications = ['user_images', 'account_logo'];
|
|
366
|
+
if (!validClassifications.includes(classification)) {
|
|
367
|
+
throw new Error(
|
|
368
|
+
'Invalid classification. Must be "user_images" or "account_logo"',
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const isNode = typeof window === 'undefined';
|
|
373
|
+
let formData;
|
|
374
|
+
const headers = {};
|
|
375
|
+
|
|
376
|
+
if (isNode) {
|
|
377
|
+
// Node.js environment
|
|
378
|
+
const boundary = `----formdata-${Date.now()}-${Math.random().toString(
|
|
379
|
+
36,
|
|
380
|
+
)}`;
|
|
381
|
+
const CRLF = '\r\n';
|
|
382
|
+
let body = '';
|
|
383
|
+
|
|
384
|
+
// Add file field
|
|
385
|
+
let contentType = 'application/octet-stream';
|
|
386
|
+
if (fileName) {
|
|
387
|
+
const ext = fileName.split('.').pop().toLowerCase();
|
|
388
|
+
const imageTypes = {
|
|
389
|
+
jpg: 'image/jpeg',
|
|
390
|
+
jpeg: 'image/jpeg',
|
|
391
|
+
png: 'image/png',
|
|
392
|
+
gif: 'image/gif',
|
|
393
|
+
webp: 'image/webp',
|
|
394
|
+
};
|
|
395
|
+
contentType = imageTypes[ext] || 'image/jpeg';
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
body += `--${boundary}${CRLF}`;
|
|
399
|
+
body += `Content-Disposition: form-data; name="files"; filename="${
|
|
400
|
+
fileName || 'profile-image.jpg'
|
|
401
|
+
}"${CRLF}`;
|
|
402
|
+
body += `Content-Type: ${contentType}${CRLF}${CRLF}`;
|
|
403
|
+
|
|
404
|
+
const headerBuffer = Buffer.from(body, 'utf8');
|
|
405
|
+
const fileBuffer = Buffer.isBuffer(file) ? file : Buffer.from(file);
|
|
406
|
+
|
|
407
|
+
// Add classification field
|
|
408
|
+
const classificationField = `${CRLF}--${boundary}${CRLF}Content-Disposition: form-data; name="classification"${CRLF}${CRLF}${classification}`;
|
|
409
|
+
const fieldsBuffer = Buffer.from(classificationField, 'utf8');
|
|
410
|
+
|
|
411
|
+
// Final boundary
|
|
412
|
+
const endBoundary = Buffer.from(`${CRLF}--${boundary}--${CRLF}`, 'utf8');
|
|
413
|
+
|
|
414
|
+
// Combine all parts
|
|
415
|
+
formData = Buffer.concat([
|
|
416
|
+
headerBuffer,
|
|
417
|
+
fileBuffer,
|
|
418
|
+
fieldsBuffer,
|
|
419
|
+
endBoundary,
|
|
420
|
+
]);
|
|
421
|
+
headers['content-type'] = `multipart/form-data; boundary=${boundary}`;
|
|
422
|
+
} else {
|
|
423
|
+
// Browser environment
|
|
424
|
+
formData = new FormData();
|
|
425
|
+
|
|
426
|
+
if (Buffer.isBuffer(file)) {
|
|
427
|
+
const blob = new Blob([file]);
|
|
428
|
+
formData.append('files', blob, fileName || 'profile-image.jpg');
|
|
429
|
+
} else if (file instanceof File) {
|
|
430
|
+
formData.append('files', file);
|
|
431
|
+
} else {
|
|
432
|
+
throw new Error(
|
|
433
|
+
'In browser environment, file must be a Buffer or File object',
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
formData.append('classification', classification);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const params = {
|
|
441
|
+
body: formData,
|
|
442
|
+
headers,
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
const result = await this.sdk._fetch(
|
|
446
|
+
'/storage/upload-profile-image',
|
|
447
|
+
'POST',
|
|
448
|
+
params,
|
|
449
|
+
true,
|
|
450
|
+
);
|
|
451
|
+
return result;
|
|
452
|
+
}
|
|
453
|
+
|
|
324
454
|
async getFileInfo(storageId) {
|
|
325
455
|
this.sdk.validateParams(
|
|
326
456
|
{ storageId },
|