@unboundcx/sdk 4.9.3 → 4.10.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.
package/index.js CHANGED
@@ -20,6 +20,7 @@ import { PortalsService } from './services/portals.js';
20
20
  import { SipEndpointsService } from './services/sipEndpoints.js';
21
21
  import { ExternalOAuthService } from './services/externalOAuth.js';
22
22
  import { GoogleCalendarService } from './services/googleCalendar.js';
23
+ import { DriveService } from './services/drive.js';
23
24
  import { EnrollService } from './services/enroll.js';
24
25
  import { PhoneNumbersService } from './services/phoneNumbers.js';
25
26
  import { RecordTypesService } from './services/recordTypes.js';
@@ -97,6 +98,7 @@ class UnboundSDK extends BaseSDK {
97
98
  this.sipEndpoints = new SipEndpointsService(this);
98
99
  this.externalOAuth = new ExternalOAuthService(this);
99
100
  this.googleCalendar = new GoogleCalendarService(this);
101
+ this.drive = new DriveService(this);
100
102
  this.enroll = new EnrollService(this);
101
103
  this.phoneNumbers = new PhoneNumbersService(this);
102
104
  this.recordTypes = new RecordTypesService(this);
@@ -278,6 +280,7 @@ export { PortalsService } from './services/portals.js';
278
280
  export { SipEndpointsService } from './services/sipEndpoints.js';
279
281
  export { ExternalOAuthService } from './services/externalOAuth.js';
280
282
  export { GoogleCalendarService } from './services/googleCalendar.js';
283
+ export { DriveService } from './services/drive.js';
281
284
  export { EnrollService } from './services/enroll.js';
282
285
  export {
283
286
  PhoneNumbersService,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unboundcx/sdk",
3
- "version": "4.9.3",
3
+ "version": "4.10.0",
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",
@@ -0,0 +1,231 @@
1
+ import { internalRequest } from '../base.js';
2
+ import { StorageService } from './storage.js';
3
+
4
+ export class DriveService {
5
+ constructor(sdk) {
6
+ this.sdk = sdk;
7
+ }
8
+
9
+ async status() {
10
+ const result = await internalRequest(this.sdk, '/drive/status', 'GET');
11
+ return result;
12
+ }
13
+
14
+ /**
15
+ * List Google Drive files and folders.
16
+ * @param {Object} [options]
17
+ * @param {string} [options.folderId]
18
+ * @param {string} [options.search]
19
+ * @param {number} [options.page]
20
+ * @param {number} [options.pageSize]
21
+ * @returns {Promise<Object>}
22
+ */
23
+ async listFiles({ folderId, search, page, pageSize } = {}) {
24
+ this.sdk.validateParams(
25
+ { folderId, search, page, pageSize },
26
+ {
27
+ folderId: { type: 'string', required: false },
28
+ search: { type: 'string', required: false },
29
+ page: { type: 'number', required: false },
30
+ pageSize: { type: 'number', required: false },
31
+ },
32
+ );
33
+
34
+ const query = {};
35
+ if (folderId !== undefined) query.folderId = folderId;
36
+ if (search !== undefined) query.search = search;
37
+ if (page !== undefined) query.page = page;
38
+ if (pageSize !== undefined) query.pageSize = pageSize;
39
+
40
+ const result = await internalRequest(this.sdk, '/drive/files', 'GET', {
41
+ query,
42
+ });
43
+ return result;
44
+ }
45
+
46
+ /**
47
+ * Create a Google Drive folder.
48
+ * @param {Object} options
49
+ * @param {string} options.name
50
+ * @param {string} [options.parentId]
51
+ * @returns {Promise<Object>}
52
+ */
53
+ async createFolder({ name, parentId } = {}) {
54
+ this.sdk.validateParams(
55
+ { name, parentId },
56
+ {
57
+ name: { type: 'string', required: true },
58
+ parentId: { type: 'string', required: false },
59
+ },
60
+ );
61
+
62
+ const body = { name };
63
+ if (parentId !== undefined) body.parentId = parentId;
64
+
65
+ const result = await internalRequest(this.sdk, '/drive/folders', 'POST', {
66
+ body,
67
+ });
68
+ return result;
69
+ }
70
+
71
+ /**
72
+ * Rename and/or move a Google Drive folder.
73
+ * @param {string} id
74
+ * @param {Object} [updates]
75
+ * @param {string} [updates.name]
76
+ * @param {string} [updates.parentId]
77
+ * @returns {Promise<Object>}
78
+ */
79
+ async updateFolder(id, { name, parentId } = {}) {
80
+ this.sdk.validateParams(
81
+ { id, name, parentId },
82
+ {
83
+ id: { type: 'string', required: true },
84
+ name: { type: 'string', required: false },
85
+ parentId: { type: 'string', required: false },
86
+ },
87
+ );
88
+
89
+ const body = {};
90
+ if (name !== undefined) body.name = name;
91
+ if (parentId !== undefined) body.parentId = parentId;
92
+
93
+ const result = await internalRequest(
94
+ this.sdk,
95
+ `/drive/folders/${id}`,
96
+ 'PATCH',
97
+ { body },
98
+ );
99
+ return result;
100
+ }
101
+
102
+ async deleteFolder(id) {
103
+ this.sdk.validateParams(
104
+ { id },
105
+ {
106
+ id: { type: 'string', required: true },
107
+ },
108
+ );
109
+
110
+ const result = await internalRequest(
111
+ this.sdk,
112
+ `/drive/folders/${id}`,
113
+ 'DELETE',
114
+ );
115
+ return result;
116
+ }
117
+
118
+ /**
119
+ * Rename a Google Drive file.
120
+ * @param {string} id
121
+ * @param {Object} [updates]
122
+ * @param {string} [updates.name]
123
+ * @returns {Promise<Object>}
124
+ */
125
+ async updateFile(id, { name } = {}) {
126
+ this.sdk.validateParams(
127
+ { id, name },
128
+ {
129
+ id: { type: 'string', required: true },
130
+ name: { type: 'string', required: false },
131
+ },
132
+ );
133
+
134
+ const body = {};
135
+ if (name !== undefined) body.name = name;
136
+
137
+ const result = await internalRequest(
138
+ this.sdk,
139
+ `/drive/files/${id}`,
140
+ 'PATCH',
141
+ { body },
142
+ );
143
+ return result;
144
+ }
145
+
146
+ /**
147
+ * Move Drive files into a folder.
148
+ * @param {Object} options
149
+ * @param {string[]} options.ids
150
+ * @param {string} [options.folderId]
151
+ * @returns {Promise<Object>}
152
+ */
153
+ async moveFiles({ ids, folderId } = {}) {
154
+ this.sdk.validateParams(
155
+ { ids, folderId },
156
+ {
157
+ ids: { type: 'array', required: true },
158
+ folderId: { type: 'string', required: false },
159
+ },
160
+ );
161
+
162
+ const body = { ids };
163
+ if (folderId !== undefined) body.folderId = folderId;
164
+
165
+ const result = await internalRequest(
166
+ this.sdk,
167
+ '/drive/files/move',
168
+ 'PATCH',
169
+ { body },
170
+ );
171
+ return result;
172
+ }
173
+
174
+ async deleteFile(id) {
175
+ this.sdk.validateParams(
176
+ { id },
177
+ {
178
+ id: { type: 'string', required: true },
179
+ },
180
+ );
181
+
182
+ const result = await internalRequest(
183
+ this.sdk,
184
+ `/drive/files/${id}`,
185
+ 'DELETE',
186
+ );
187
+ return result;
188
+ }
189
+
190
+ /**
191
+ * Upload a file to Google Drive.
192
+ * @param {Object} config
193
+ * @param {Object} config.file - Buffer, File, or stream
194
+ * @param {string} [config.fileName]
195
+ * @param {string} [config.parentId]
196
+ * @param {Function} [config.onProgress]
197
+ * @returns {Promise<Object>}
198
+ */
199
+ async upload({ file, fileName, parentId, onProgress } = {}) {
200
+ this.sdk.validateParams(
201
+ { file, fileName, parentId },
202
+ {
203
+ file: { type: 'object', required: true },
204
+ fileName: { type: 'string', required: false },
205
+ parentId: { type: 'string', required: false },
206
+ },
207
+ );
208
+
209
+ const formFields = [];
210
+ if (parentId) formFields.push(['parentId', parentId]);
211
+
212
+ const storage = new StorageService(this.sdk);
213
+ return storage._performUpload(
214
+ file,
215
+ fileName,
216
+ formFields,
217
+ '/drive/upload',
218
+ 'POST',
219
+ onProgress,
220
+ );
221
+ }
222
+
223
+ async browserToken() {
224
+ const result = await internalRequest(
225
+ this.sdk,
226
+ '/drive/browserToken',
227
+ 'POST',
228
+ );
229
+ return result;
230
+ }
231
+ }
@@ -459,6 +459,7 @@ Response:
459
459
  * @param {string} [config.country='US'] - Country code for region selection
460
460
  * @param {string} [config.expireAfter] - Expiration time
461
461
  * @param {string} [config.relatedId] - Related object ID
462
+ * @param {string} [config.folderId] - Storage folder id
462
463
  * @param {boolean} [config.createAccessKey=false] - Generate an access key for the file
463
464
  * @param {number} [config.accessKeyExpiresIn] - Access key expiration in seconds
464
465
  * @param {string} [config.convertTo] - Convert uploaded file to this format before storing. Supported: 'pdf', 'tiff'. Input must be PDF, DOC, or DOCX.
@@ -479,6 +480,7 @@ Response:
479
480
  country = 'US',
480
481
  expireAfter,
481
482
  relatedId,
483
+ folderId,
482
484
  createAccessKey = false,
483
485
  accessKeyExpiresIn,
484
486
  convertTo,
@@ -496,6 +498,7 @@ Response:
496
498
  country,
497
499
  expireAfter,
498
500
  relatedId,
501
+ folderId,
499
502
  createAccessKey,
500
503
  accessKeyExpiresIn,
501
504
  convertTo,
@@ -510,6 +513,7 @@ Response:
510
513
  country: { type: 'string', required: false },
511
514
  expireAfter: { type: 'string', required: false },
512
515
  relatedId: { type: 'string', required: false },
516
+ folderId: { type: 'string', required: false },
513
517
  createAccessKey: { type: 'boolean', required: false },
514
518
  accessKeyExpiresIn: { type: 'number', required: false },
515
519
  convertTo: { type: 'string', required: false },
@@ -526,6 +530,7 @@ Response:
526
530
  if (country) formFields.push(['country', country]);
527
531
  if (expireAfter) formFields.push(['expireAfter', expireAfter]);
528
532
  if (relatedId) formFields.push(['relatedId', relatedId]);
533
+ if (folderId) formFields.push(['folderId', folderId]);
529
534
  if (createAccessKey !== undefined)
530
535
  formFields.push(['createAccessKey', createAccessKey.toString()]);
531
536
  if (accessKeyExpiresIn)
@@ -779,41 +784,83 @@ Response:
779
784
  return result;
780
785
  }
781
786
 
782
- async updateFileMetadata(storageId, metadata) {
787
+ /**
788
+ * Update file metadata (rename and/or move). Does not re-upload the file.
789
+ * @param {string} id - Storage file id
790
+ * @param {Object} [updates]
791
+ * @param {string} [updates.fileName]
792
+ * @param {string} [updates.folderId]
793
+ * @param {string} [updates.relatedId]
794
+ * @returns {Promise<Object>}
795
+ */
796
+ async updateFileMetadata(id, { fileName, folderId, relatedId } = {}) {
783
797
  this.sdk.validateParams(
784
- { storageId, metadata },
798
+ { id, fileName, folderId, relatedId },
785
799
  {
786
- storageId: { type: 'string', required: true },
787
- metadata: { type: 'object', required: true },
800
+ id: { type: 'string', required: true },
801
+ fileName: { type: 'string', required: false },
802
+ folderId: { type: 'string', required: false },
803
+ relatedId: { type: 'string', required: false },
788
804
  },
789
805
  );
790
806
 
791
- const params = {
792
- body: { metadata },
793
- };
807
+ const body = {};
808
+ if (fileName !== undefined) body.fileName = fileName;
809
+ if (folderId !== undefined) body.folderId = folderId;
810
+ if (relatedId !== undefined) body.relatedId = relatedId;
794
811
 
795
- const result = await internalRequest(this.sdk,
796
- `/storage/file/${storageId}/metadata`,
797
- 'PUT',
798
- params,
812
+ const result = await internalRequest(
813
+ this.sdk,
814
+ `/storage/files/${id}`,
815
+ 'PATCH',
816
+ { body },
799
817
  );
800
818
  return result;
801
819
  }
802
820
 
821
+ /**
822
+ * List storage files.
823
+ * @param {Object} [options]
824
+ * @param {string} [options.relatedId]
825
+ * @param {string} [options.folderId]
826
+ * @param {string} [options.folder]
827
+ * @param {string} [options.classification]
828
+ * @param {string} [options.search]
829
+ * @param {string} [options.view]
830
+ * @param {number} [options.page]
831
+ * @param {number} [options.limit]
832
+ * @param {string} [options.sortBy]
833
+ * @param {string} [options.sortOrder]
834
+ * @param {string} [options.fileType]
835
+ * @param {boolean} [options.isPublic]
836
+ * @param {number} [options.offset] - Legacy; still forwarded if provided
837
+ * @param {string} [options.orderBy] - Legacy; still forwarded if provided
838
+ * @param {string} [options.orderDirection] - Legacy; still forwarded if provided
839
+ * @returns {Promise<Object>}
840
+ */
803
841
  async listFiles(options = {}) {
804
- const { classification, folder, limit, offset, orderBy, orderDirection } =
805
- options;
806
-
807
- // Validate optional parameters
808
842
  const validationSchema = {};
809
- if ('classification' in options)
810
- validationSchema.classification = { type: 'string' };
811
- if ('folder' in options) validationSchema.folder = { type: 'string' };
812
- if ('limit' in options) validationSchema.limit = { type: 'number' };
813
- if ('offset' in options) validationSchema.offset = { type: 'number' };
814
- if ('orderBy' in options) validationSchema.orderBy = { type: 'string' };
815
- if ('orderDirection' in options)
816
- validationSchema.orderDirection = { type: 'string' };
843
+ const optionalTypes = {
844
+ relatedId: 'string',
845
+ folderId: 'string',
846
+ folder: 'string',
847
+ classification: 'string',
848
+ search: 'string',
849
+ view: 'string',
850
+ page: 'number',
851
+ limit: 'number',
852
+ sortBy: 'string',
853
+ sortOrder: 'string',
854
+ fileType: 'string',
855
+ isPublic: 'boolean',
856
+ offset: 'number',
857
+ orderBy: 'string',
858
+ orderDirection: 'string',
859
+ };
860
+
861
+ for (const [key, type] of Object.entries(optionalTypes)) {
862
+ if (key in options) validationSchema[key] = { type };
863
+ }
817
864
 
818
865
  if (Object.keys(validationSchema).length > 0) {
819
866
  this.sdk.validateParams(options, validationSchema);
@@ -827,6 +874,150 @@ Response:
827
874
  return result;
828
875
  }
829
876
 
877
+ /**
878
+ * List storage folders for a related record.
879
+ * @param {Object} options
880
+ * @param {string} options.relatedId
881
+ * @param {string} [options.parentId]
882
+ * @param {string} [options.search]
883
+ * @returns {Promise<Object>}
884
+ */
885
+ async listFolders({ relatedId, parentId, search } = {}) {
886
+ this.sdk.validateParams(
887
+ { relatedId, parentId, search },
888
+ {
889
+ relatedId: { type: 'string', required: true },
890
+ parentId: { type: 'string', required: false },
891
+ search: { type: 'string', required: false },
892
+ },
893
+ );
894
+
895
+ const query = { relatedId };
896
+ if (parentId !== undefined) query.parentId = parentId;
897
+ if (search !== undefined) query.search = search;
898
+
899
+ const result = await internalRequest(this.sdk, '/storage/folders', 'GET', {
900
+ query,
901
+ });
902
+ return result;
903
+ }
904
+
905
+ /**
906
+ * Create a storage folder.
907
+ * @param {Object} options
908
+ * @param {string} options.relatedId
909
+ * @param {string} [options.parentId]
910
+ * @param {string} options.name
911
+ * @returns {Promise<Object>}
912
+ */
913
+ async createFolder({ relatedId, parentId, name } = {}) {
914
+ this.sdk.validateParams(
915
+ { relatedId, parentId, name },
916
+ {
917
+ relatedId: { type: 'string', required: true },
918
+ parentId: { type: 'string', required: false },
919
+ name: { type: 'string', required: true },
920
+ },
921
+ );
922
+
923
+ const body = { relatedId, name };
924
+ if (parentId !== undefined) body.parentId = parentId;
925
+
926
+ const result = await internalRequest(this.sdk, '/storage/folders', 'POST', {
927
+ body,
928
+ });
929
+ return result;
930
+ }
931
+
932
+ /**
933
+ * Rename and/or move a storage folder.
934
+ * @param {string} id
935
+ * @param {Object} [updates]
936
+ * @param {string} [updates.relatedId]
937
+ * @param {string} [updates.name]
938
+ * @param {string} [updates.parentId]
939
+ * @returns {Promise<Object>}
940
+ */
941
+ async updateFolder(id, { relatedId, name, parentId } = {}) {
942
+ this.sdk.validateParams(
943
+ { id, relatedId, name, parentId },
944
+ {
945
+ id: { type: 'string', required: true },
946
+ relatedId: { type: 'string', required: false },
947
+ name: { type: 'string', required: false },
948
+ parentId: { type: 'string', required: false },
949
+ },
950
+ );
951
+
952
+ const body = {};
953
+ if (relatedId !== undefined) body.relatedId = relatedId;
954
+ if (name !== undefined) body.name = name;
955
+ if (parentId !== undefined) body.parentId = parentId;
956
+
957
+ const result = await internalRequest(
958
+ this.sdk,
959
+ `/storage/folders/${id}`,
960
+ 'PATCH',
961
+ { body },
962
+ );
963
+ return result;
964
+ }
965
+
966
+ /**
967
+ * Soft-delete a storage folder (cascades to children).
968
+ * @param {string} id
969
+ * @param {Object} options
970
+ * @param {string} options.relatedId
971
+ * @returns {Promise<Object>}
972
+ */
973
+ async deleteFolder(id, { relatedId } = {}) {
974
+ this.sdk.validateParams(
975
+ { id, relatedId },
976
+ {
977
+ id: { type: 'string', required: true },
978
+ relatedId: { type: 'string', required: true },
979
+ },
980
+ );
981
+
982
+ const result = await internalRequest(
983
+ this.sdk,
984
+ `/storage/folders/${id}`,
985
+ 'DELETE',
986
+ { query: { relatedId } },
987
+ );
988
+ return result;
989
+ }
990
+
991
+ /**
992
+ * Move files into a folder (DB folderId only).
993
+ * @param {Object} options
994
+ * @param {string[]} options.ids
995
+ * @param {string} [options.folderId]
996
+ * @param {string} options.relatedId
997
+ * @returns {Promise<Object>}
998
+ */
999
+ async moveFiles({ ids, folderId, relatedId } = {}) {
1000
+ this.sdk.validateParams(
1001
+ { ids, folderId, relatedId },
1002
+ {
1003
+ ids: { type: 'array', required: true },
1004
+ folderId: { type: 'string', required: false },
1005
+ relatedId: { type: 'string', required: true },
1006
+ },
1007
+ );
1008
+
1009
+ const body = { ids, relatedId };
1010
+ if (folderId !== undefined) body.folderId = folderId;
1011
+
1012
+ const result = await internalRequest(
1013
+ this.sdk,
1014
+ '/storage/files/move',
1015
+ 'PATCH',
1016
+ { body },
1017
+ );
1018
+ return result;
1019
+ }
1020
+
830
1021
  /**
831
1022
  * Generate an access key for an existing storage file
832
1023
  * @param {string} fileId - The storage file ID
@@ -39,6 +39,7 @@ async function testBasicSDKFunctionality() {
39
39
  'sipEndpoints',
40
40
  'externalOAuth',
41
41
  'googleCalendar',
42
+ 'drive',
42
43
  'enroll',
43
44
  ];
44
45
 
@@ -37,6 +37,7 @@ async function testPublicSDKCompleteness() {
37
37
  // Additional services found in analysis
38
38
  'externalOAuth',
39
39
  'googleCalendar',
40
+ 'drive',
40
41
  'enroll',
41
42
  'phoneNumbers',
42
43
  'recordTypes',
@@ -115,6 +115,7 @@ const services = [
115
115
  'sipEndpoints',
116
116
  'externalOAuth',
117
117
  'googleCalendar',
118
+ 'drive',
118
119
  'enroll',
119
120
  'phoneNumbers',
120
121
  'recordTypes',