@unboundcx/sdk 1.0.3 → 1.0.6
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/package.json +1 -1
- package/services/storage.js +137 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unboundcx/sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
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
|
@@ -11,6 +11,7 @@ export class StorageService {
|
|
|
11
11
|
isPublic = false,
|
|
12
12
|
country = 'US',
|
|
13
13
|
expireAfter,
|
|
14
|
+
relatedId,
|
|
14
15
|
createAccessKey = false,
|
|
15
16
|
accessKeyExpiresIn,
|
|
16
17
|
}) {
|
|
@@ -23,6 +24,7 @@ export class StorageService {
|
|
|
23
24
|
isPublic,
|
|
24
25
|
country,
|
|
25
26
|
expireAfter,
|
|
27
|
+
relatedId,
|
|
26
28
|
createAccessKey,
|
|
27
29
|
accessKeyExpiresIn,
|
|
28
30
|
},
|
|
@@ -34,6 +36,7 @@ export class StorageService {
|
|
|
34
36
|
isPublic: { type: 'boolean', required: false },
|
|
35
37
|
country: { type: 'string', required: false },
|
|
36
38
|
expireAfter: { type: 'string', required: false },
|
|
39
|
+
relatedId: { type: 'string', required: false },
|
|
37
40
|
createAccessKey: { type: 'boolean', required: false },
|
|
38
41
|
accessKeyExpiresIn: { type: 'string', required: false },
|
|
39
42
|
},
|
|
@@ -46,7 +49,9 @@ export class StorageService {
|
|
|
46
49
|
if (isNode) {
|
|
47
50
|
// Node.js environment - use direct buffer approach
|
|
48
51
|
// Create a simple body with the file buffer and metadata
|
|
49
|
-
const boundary = `----formdata-${Date.now()}-${Math.random().toString(
|
|
52
|
+
const boundary = `----formdata-${Date.now()}-${Math.random().toString(
|
|
53
|
+
36,
|
|
54
|
+
)}`;
|
|
50
55
|
const CRLF = '\r\n';
|
|
51
56
|
let body = '';
|
|
52
57
|
|
|
@@ -128,18 +133,24 @@ export class StorageService {
|
|
|
128
133
|
}
|
|
129
134
|
|
|
130
135
|
body += `--${boundary}${CRLF}`;
|
|
131
|
-
body += `Content-Disposition: form-data; name="files"; filename="${
|
|
136
|
+
body += `Content-Disposition: form-data; name="files"; filename="${
|
|
137
|
+
fileName || 'file'
|
|
138
|
+
}"${CRLF}`;
|
|
132
139
|
body += `Content-Type: ${contentType}${CRLF}${CRLF}`;
|
|
133
140
|
|
|
134
141
|
// Add other form fields
|
|
135
142
|
const formFields = [];
|
|
136
143
|
if (classification) formFields.push(['classification', classification]);
|
|
137
144
|
if (folder) formFields.push(['folder', folder]);
|
|
138
|
-
if (isPublic !== undefined)
|
|
145
|
+
if (isPublic !== undefined)
|
|
146
|
+
formFields.push(['isPublic', isPublic.toString()]);
|
|
139
147
|
if (country) formFields.push(['country', country]);
|
|
140
148
|
if (expireAfter) formFields.push(['expireAfter', expireAfter]);
|
|
141
|
-
if (
|
|
142
|
-
if (
|
|
149
|
+
if (relatedId) formFields.push(['relatedId', relatedId]);
|
|
150
|
+
if (createAccessKey !== undefined)
|
|
151
|
+
formFields.push(['createAccessKey', createAccessKey.toString()]);
|
|
152
|
+
if (accessKeyExpiresIn)
|
|
153
|
+
formFields.push(['accessKeyExpiresIn', accessKeyExpiresIn]);
|
|
143
154
|
|
|
144
155
|
// Convert to buffers and combine
|
|
145
156
|
const headerBuffer = Buffer.from(body, 'utf8');
|
|
@@ -149,14 +160,22 @@ export class StorageService {
|
|
|
149
160
|
let fieldsBuffer = Buffer.alloc(0);
|
|
150
161
|
for (const [name, value] of formFields) {
|
|
151
162
|
const fieldData = `${CRLF}--${boundary}${CRLF}Content-Disposition: form-data; name="${name}"${CRLF}${CRLF}${value}`;
|
|
152
|
-
fieldsBuffer = Buffer.concat([
|
|
163
|
+
fieldsBuffer = Buffer.concat([
|
|
164
|
+
fieldsBuffer,
|
|
165
|
+
Buffer.from(fieldData, 'utf8'),
|
|
166
|
+
]);
|
|
153
167
|
}
|
|
154
168
|
|
|
155
169
|
// Final boundary
|
|
156
170
|
const endBoundary = Buffer.from(`${CRLF}--${boundary}--${CRLF}`, 'utf8');
|
|
157
171
|
|
|
158
172
|
// Combine all parts
|
|
159
|
-
formData = Buffer.concat([
|
|
173
|
+
formData = Buffer.concat([
|
|
174
|
+
headerBuffer,
|
|
175
|
+
fileBuffer,
|
|
176
|
+
fieldsBuffer,
|
|
177
|
+
endBoundary,
|
|
178
|
+
]);
|
|
160
179
|
|
|
161
180
|
// Set proper Content-Type header
|
|
162
181
|
headers['content-type'] = `multipart/form-data; boundary=${boundary}`;
|
|
@@ -171,18 +190,24 @@ export class StorageService {
|
|
|
171
190
|
} else if (file instanceof File) {
|
|
172
191
|
formData.append('files', file);
|
|
173
192
|
} else {
|
|
174
|
-
throw new Error(
|
|
193
|
+
throw new Error(
|
|
194
|
+
'In browser environment, file must be a Buffer or File object',
|
|
195
|
+
);
|
|
175
196
|
}
|
|
176
197
|
|
|
177
198
|
// Add other parameters
|
|
178
199
|
if (classification) formData.append('classification', classification);
|
|
179
200
|
if (folder) formData.append('folder', folder);
|
|
180
|
-
if (isPublic !== undefined)
|
|
201
|
+
if (isPublic !== undefined)
|
|
202
|
+
formData.append('isPublic', isPublic.toString());
|
|
181
203
|
if (country) formData.append('country', country);
|
|
182
204
|
if (expireAfter) formData.append('expireAfter', expireAfter);
|
|
183
|
-
if (
|
|
184
|
-
if (
|
|
185
|
-
|
|
205
|
+
if (relatedId) formData.append('relatedId', relatedId);
|
|
206
|
+
if (createAccessKey !== undefined)
|
|
207
|
+
formData.append('createAccessKey', createAccessKey.toString());
|
|
208
|
+
if (accessKeyExpiresIn)
|
|
209
|
+
formData.append('accessKeyExpiresIn', accessKeyExpiresIn);
|
|
210
|
+
|
|
186
211
|
// Don't set Content-Type - let browser handle it automatically
|
|
187
212
|
}
|
|
188
213
|
|
|
@@ -191,7 +216,12 @@ export class StorageService {
|
|
|
191
216
|
headers,
|
|
192
217
|
};
|
|
193
218
|
|
|
194
|
-
const result = await this.sdk._fetch(
|
|
219
|
+
const result = await this.sdk._fetch(
|
|
220
|
+
'/storage/upload',
|
|
221
|
+
'POST',
|
|
222
|
+
params,
|
|
223
|
+
true,
|
|
224
|
+
);
|
|
195
225
|
return result;
|
|
196
226
|
}
|
|
197
227
|
|
|
@@ -247,7 +277,12 @@ export class StorageService {
|
|
|
247
277
|
// Remove Content-Type to let FormData set it properly
|
|
248
278
|
delete params.headers['Content-Type'];
|
|
249
279
|
|
|
250
|
-
const result = await this.sdk._fetch(
|
|
280
|
+
const result = await this.sdk._fetch(
|
|
281
|
+
'/storage/upload',
|
|
282
|
+
'POST',
|
|
283
|
+
params,
|
|
284
|
+
true,
|
|
285
|
+
);
|
|
251
286
|
return result;
|
|
252
287
|
}
|
|
253
288
|
|
|
@@ -284,9 +319,9 @@ export class StorageService {
|
|
|
284
319
|
|
|
285
320
|
let url;
|
|
286
321
|
if (this.sdk.environment === 'node') {
|
|
287
|
-
url = `${this.sdk.baseURL}/storage
|
|
322
|
+
url = `${this.sdk.baseURL}/storage/${storageId}`;
|
|
288
323
|
} else {
|
|
289
|
-
url = `${this.sdk.fullUrl}/storage
|
|
324
|
+
url = `${this.sdk.fullUrl}/storage/${storageId}`;
|
|
290
325
|
}
|
|
291
326
|
|
|
292
327
|
if (download) {
|
|
@@ -316,6 +351,92 @@ export class StorageService {
|
|
|
316
351
|
return result;
|
|
317
352
|
}
|
|
318
353
|
|
|
354
|
+
async uploadProfileImage({
|
|
355
|
+
file,
|
|
356
|
+
classification = 'user_images',
|
|
357
|
+
fileName,
|
|
358
|
+
}) {
|
|
359
|
+
this.sdk.validateParams(
|
|
360
|
+
{ file, classification },
|
|
361
|
+
{
|
|
362
|
+
file: { type: 'object', required: true },
|
|
363
|
+
classification: { type: 'string', required: true },
|
|
364
|
+
fileName: { type: 'string', required: false },
|
|
365
|
+
},
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
// Validate classification
|
|
369
|
+
const validClassifications = ['user_images', 'account_logo'];
|
|
370
|
+
if (!validClassifications.includes(classification)) {
|
|
371
|
+
throw new Error('Invalid classification. Must be "user_images" or "account_logo"');
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const isNode = typeof window === 'undefined';
|
|
375
|
+
let formData;
|
|
376
|
+
const headers = {};
|
|
377
|
+
|
|
378
|
+
if (isNode) {
|
|
379
|
+
// Node.js environment
|
|
380
|
+
const boundary = `----formdata-${Date.now()}-${Math.random().toString(36)}`;
|
|
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="${fileName || 'profile-image.jpg'}"${CRLF}`;
|
|
400
|
+
body += `Content-Type: ${contentType}${CRLF}${CRLF}`;
|
|
401
|
+
|
|
402
|
+
const headerBuffer = Buffer.from(body, 'utf8');
|
|
403
|
+
const fileBuffer = Buffer.isBuffer(file) ? file : Buffer.from(file);
|
|
404
|
+
|
|
405
|
+
// Add classification field
|
|
406
|
+
const classificationField = `${CRLF}--${boundary}${CRLF}Content-Disposition: form-data; name="classification"${CRLF}${CRLF}${classification}`;
|
|
407
|
+
const fieldsBuffer = Buffer.from(classificationField, 'utf8');
|
|
408
|
+
|
|
409
|
+
// Final boundary
|
|
410
|
+
const endBoundary = Buffer.from(`${CRLF}--${boundary}--${CRLF}`, 'utf8');
|
|
411
|
+
|
|
412
|
+
// Combine all parts
|
|
413
|
+
formData = Buffer.concat([headerBuffer, fileBuffer, fieldsBuffer, endBoundary]);
|
|
414
|
+
headers['content-type'] = `multipart/form-data; boundary=${boundary}`;
|
|
415
|
+
} else {
|
|
416
|
+
// Browser environment
|
|
417
|
+
formData = new FormData();
|
|
418
|
+
|
|
419
|
+
if (Buffer.isBuffer(file)) {
|
|
420
|
+
const blob = new Blob([file]);
|
|
421
|
+
formData.append('files', blob, fileName || 'profile-image.jpg');
|
|
422
|
+
} else if (file instanceof File) {
|
|
423
|
+
formData.append('files', file);
|
|
424
|
+
} else {
|
|
425
|
+
throw new Error('In browser environment, file must be a Buffer or File object');
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
formData.append('classification', classification);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const params = {
|
|
432
|
+
body: formData,
|
|
433
|
+
headers,
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
const result = await this.sdk._fetch('/storage/upload-profile-image', 'POST', params, true);
|
|
437
|
+
return result;
|
|
438
|
+
}
|
|
439
|
+
|
|
319
440
|
async getFileInfo(storageId) {
|
|
320
441
|
this.sdk.validateParams(
|
|
321
442
|
{ storageId },
|