@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 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.4",
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",
@@ -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(36)}`;
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="${fileName || 'file'}"${CRLF}`;
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) formFields.push(['isPublic', isPublic.toString()]);
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) formFields.push(['createAccessKey', createAccessKey.toString()]);
146
- if (accessKeyExpiresIn) formFields.push(['accessKeyExpiresIn', accessKeyExpiresIn]);
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([fieldsBuffer, Buffer.from(fieldData, 'utf8')]);
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([headerBuffer, fileBuffer, fieldsBuffer, endBoundary]);
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('In browser environment, file must be a Buffer or File object');
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) formData.append('isPublic', isPublic.toString());
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) formData.append('createAccessKey', createAccessKey.toString());
189
- if (accessKeyExpiresIn) formData.append('accessKeyExpiresIn', accessKeyExpiresIn);
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('/storage/upload', 'POST', params, true);
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('/storage/upload', 'POST', params, true);
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/file/${storageId}`;
322
+ url = `${this.sdk.baseURL}/storage/${storageId}`;
293
323
  } else {
294
- url = `${this.sdk.fullUrl}/storage/file/${storageId}`;
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 },