zaccl 3.0.18 → 4.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 (68) hide show
  1. package/docs/ECatCloudRecording.js.html +69 -26
  2. package/docs/ECatGroup.js.html +213 -0
  3. package/docs/ECatMeeting.js.html +79 -11
  4. package/docs/ECatUser.js.html +7 -10
  5. package/docs/ECatWebinar.js.html +6 -5
  6. package/docs/api.cloudRecording.html +368 -28
  7. package/docs/api.group.html +396 -0
  8. package/docs/api.meeting.html +466 -15
  9. package/docs/api.user.html +10 -10
  10. package/docs/api.webinar.html +5 -5
  11. package/docs/index.html +1 -1
  12. package/lib/endpoints/ECatCloudRecording.d.ts +34 -8
  13. package/lib/endpoints/ECatCloudRecording.js +68 -25
  14. package/lib/endpoints/ECatCloudRecording.js.map +1 -1
  15. package/lib/endpoints/ECatGroup.d.ts +45 -0
  16. package/lib/endpoints/ECatGroup.js +148 -0
  17. package/lib/endpoints/ECatGroup.js.map +1 -0
  18. package/lib/endpoints/ECatMeeting.d.ts +43 -10
  19. package/lib/endpoints/ECatMeeting.js +78 -10
  20. package/lib/endpoints/ECatMeeting.js.map +1 -1
  21. package/lib/endpoints/ECatUser.d.ts +5 -5
  22. package/lib/endpoints/ECatUser.js +6 -9
  23. package/lib/endpoints/ECatUser.js.map +1 -1
  24. package/lib/endpoints/ECatWebinar.d.ts +4 -4
  25. package/lib/endpoints/ECatWebinar.js +5 -4
  26. package/lib/endpoints/ECatWebinar.js.map +1 -1
  27. package/lib/index.d.ts +22 -0
  28. package/lib/index.js +19 -0
  29. package/lib/index.js.map +1 -1
  30. package/lib/shared/helpers/genVisitEndpoint.js +154 -81
  31. package/lib/shared/helpers/genVisitEndpoint.js.map +1 -1
  32. package/lib/shared/types/VisitEndpointFunc.d.ts +3 -1
  33. package/lib/types/ZoomAPI.d.ts +2 -0
  34. package/lib/types/ZoomAPI.js.map +1 -1
  35. package/lib/types/ZoomGroup.d.ts +10 -0
  36. package/lib/types/ZoomGroup.js +3 -0
  37. package/lib/types/ZoomGroup.js.map +1 -0
  38. package/lib/types/ZoomGroupMember.d.ts +12 -0
  39. package/lib/types/ZoomGroupMember.js +3 -0
  40. package/lib/types/ZoomGroupMember.js.map +1 -0
  41. package/lib/types/ZoomMeetingTranscript.d.ts +17 -0
  42. package/lib/types/ZoomMeetingTranscript.js +3 -0
  43. package/lib/types/ZoomMeetingTranscript.js.map +1 -0
  44. package/lib/types/ZoomPastMeetingDetails.d.ts +22 -0
  45. package/lib/types/ZoomPastMeetingDetails.js +3 -0
  46. package/lib/types/ZoomPastMeetingDetails.js.map +1 -0
  47. package/lib/types/ZoomPastMeetingParticipant.d.ts +18 -0
  48. package/lib/types/ZoomPastMeetingParticipant.js +3 -0
  49. package/lib/types/ZoomPastMeetingParticipant.js.map +1 -0
  50. package/lib/types/ZoomRecordingInAccount.d.ts +22 -0
  51. package/lib/types/ZoomRecordingInAccount.js +3 -0
  52. package/lib/types/ZoomRecordingInAccount.js.map +1 -0
  53. package/package.json +2 -2
  54. package/src/endpoints/ECatCloudRecording.ts +83 -29
  55. package/src/endpoints/ECatGroup.ts +97 -0
  56. package/src/endpoints/ECatMeeting.ts +85 -10
  57. package/src/endpoints/ECatUser.ts +6 -9
  58. package/src/endpoints/ECatWebinar.ts +5 -4
  59. package/src/index.ts +53 -0
  60. package/src/shared/helpers/genVisitEndpoint.ts +143 -77
  61. package/src/shared/types/VisitEndpointFunc.ts +6 -2
  62. package/src/types/ZoomAPI.ts +2 -0
  63. package/src/types/ZoomGroup.ts +14 -0
  64. package/src/types/ZoomGroupMember.ts +20 -0
  65. package/src/types/ZoomMeetingTranscript.ts +28 -0
  66. package/src/types/ZoomPastMeetingDetails.ts +38 -0
  67. package/src/types/ZoomPastMeetingParticipant.ts +30 -0
  68. package/src/types/ZoomRecordingInAccount.ts +38 -0
@@ -28,6 +28,11 @@ const genVisitEndpoint = (zoomAPIConfig: ZoomAPIConfig): VisitEndpointFunc => {
28
28
  * @param [opts.postProcessor] function that processes the response before
29
29
  * returning
30
30
  * @param [opts.params] Parameters/args/body to send with request
31
+ * @param [opts.onNewPage] callback function that is called when a
32
+ * new page of results is received
33
+ * @param [opts.itemKey] the key in the response body where the list of items can be found
34
+ * @param [opts.minMsBetweenPageRequests] minimum time (in ms) to wait between
35
+ * paginated requests, for custom throttle control
31
36
  * @returns response body
32
37
  */
33
38
  return async (
@@ -44,7 +49,9 @@ const genVisitEndpoint = (zoomAPIConfig: ZoomAPIConfig): VisitEndpointFunc => {
44
49
  )
45
50
  },
46
51
  params?: { [k: string]: any },
47
- postProcessor?: (response: any) => any,
52
+ itemKey?: string,
53
+ onNewPage?: (page: any) => void,
54
+ minMsBetweenPageRequests?: number,
48
55
  },
49
56
  ): Promise<any> => {
50
57
  const {
@@ -52,101 +59,160 @@ const genVisitEndpoint = (zoomAPIConfig: ZoomAPIConfig): VisitEndpointFunc => {
52
59
  params,
53
60
  action,
54
61
  errorMap,
55
- postProcessor,
62
+ itemKey,
63
+ onNewPage,
64
+ minMsBetweenPageRequests
56
65
  } = opts;
57
66
  const method = (opts.method ?? 'GET');
58
67
 
59
- /* ---------- Send Request ---------- */
60
-
61
- const { status, headers, body } = await sendZoomRequest({
62
- path,
63
- method,
64
- params,
65
- zoomAPIConfig,
66
- });
68
+ // Paging state
69
+ let nextPageToken: string | undefined = undefined;
70
+ let isFirstPage = true;
71
+ let isPaginated = false; // Inferred by responses, always starts false
72
+ const allItems: any[] = [];
73
+ let lastPageRequestTimestamp = 0;
74
+
75
+ // Fetch page by page
76
+ while (nextPageToken || isFirstPage) {
77
+ // Don't fetch another page unless we get a token
78
+ isFirstPage = false;
79
+
80
+ /* ---------- Send Request ---------- */
81
+
82
+ // If minMsBetweenPageRequests is set, ensure we wait at least that long between requests
83
+ if (minMsBetweenPageRequests) {
84
+ // Check how long since the last request
85
+ const now = Date.now();
86
+ const timeSinceLastRequest = now - lastPageRequestTimestamp;
87
+
88
+ // Wait extra time if we haven't waited long enough yet
89
+ if (timeSinceLastRequest < minMsBetweenPageRequests) {
90
+ await new Promise((resolve) => {
91
+ setTimeout(resolve, minMsBetweenPageRequests - timeSinceLastRequest);
92
+ });
93
+ }
67
94
 
68
- /* ----------- Rate Error ----------- */
95
+ // Update timestamp of last page request
96
+ lastPageRequestTimestamp = Date.now();
97
+ }
69
98
 
70
- if (status === 429) {
71
- // Case-insensitive header lookup
72
- const [rateLimitTypeHeader] = Object.keys(headers).filter((header) => {
73
- return (header.toLowerCase() === 'x-ratelimit-type');
99
+ // Send the request
100
+ const { status, headers, body } = await sendZoomRequest({
101
+ path,
102
+ method,
103
+ params: {
104
+ ...params,
105
+ next_page_token: nextPageToken,
106
+ },
107
+ zoomAPIConfig,
74
108
  });
75
109
 
76
- // Case-insensitive limit type lookup
77
- const rateLimitType = (
78
- headers[rateLimitTypeHeader]
79
- && headers[rateLimitTypeHeader].toLowerCase()
80
- );
110
+ /* ----------- Rate Error ----------- */
81
111
 
82
- if (rateLimitType === ThrottleHeader.DailyLimitHeader) {
83
- // Daily limit
84
- throw new ZACCLError({
85
- message: 'Zoom is very busy today. Please try this operation again tomorrow.',
86
- code: ErrorCode.DailyLimitError,
87
- });
88
- } else if (rateLimitType === ThrottleHeader.RateLimitHeader) {
89
- // Rate limit
90
- throw new ZACCLError({
91
- message: 'Zoom is very busy right now. Please try this operation again later.',
92
- code: ErrorCode.RateLimitError,
93
- });
94
- } else {
95
- // Unknown rate limit
96
- throw new ZACCLError({
97
- message: 'Zoom is very busy right now. Please try this operation again.',
98
- code: ErrorCode.UnknownLimitError,
112
+ if (status === 429) {
113
+ // Case-insensitive header lookup
114
+ const [rateLimitTypeHeader] = Object.keys(headers).filter((header) => {
115
+ return (header.toLowerCase() === 'x-ratelimit-type');
99
116
  });
117
+
118
+ // Case-insensitive limit type lookup
119
+ const rateLimitType = (
120
+ headers[rateLimitTypeHeader]
121
+ && headers[rateLimitTypeHeader].toLowerCase()
122
+ );
123
+
124
+ if (rateLimitType === ThrottleHeader.DailyLimitHeader) {
125
+ // Daily limit
126
+ throw new ZACCLError({
127
+ message: 'Zoom is very busy today. Please try this operation again tomorrow.',
128
+ code: ErrorCode.DailyLimitError,
129
+ });
130
+ } else if (rateLimitType === ThrottleHeader.RateLimitHeader) {
131
+ // Rate limit
132
+ throw new ZACCLError({
133
+ message: 'Zoom is very busy right now. Please try this operation again later.',
134
+ code: ErrorCode.RateLimitError,
135
+ });
136
+ } else {
137
+ // Unknown rate limit
138
+ throw new ZACCLError({
139
+ message: 'Zoom is very busy right now. Please try this operation again.',
140
+ code: ErrorCode.UnknownLimitError,
141
+ });
142
+ }
100
143
  }
101
- }
102
-
103
- /* -------- Custom Error Code ------- */
104
-
105
- if (status < 200 || status >= 300) {
106
- // A Zoom error occurred
107
-
108
- // Check status to see if its in the error map
109
- let zoomErrorMessage = 'An unknown Zoom error occurred.';
110
- if (errorMap[status]) {
111
- if (typeof errorMap[status] === 'string') {
112
- // Found the error message
113
- zoomErrorMessage = (errorMap[status] as string);
114
- } else if (body.code) {
115
- // Check for nested error message
116
- if (typeof errorMap[status][body.code] === 'string') {
117
- // Found nested error message
118
- zoomErrorMessage = errorMap[status][body.code];
119
- } else if (body.message) {
120
- // errorMap[status][code] did not return err message
121
- // so we check body
122
- if (typeof body.message === 'string') {
123
- zoomErrorMessage = body.message;
144
+
145
+ /* -------- Custom Error Code ------- */
146
+
147
+ if (status < 200 || status >= 300) {
148
+ // A Zoom error occurred
149
+
150
+ // Check status to see if its in the error map
151
+ let zoomErrorMessage = 'An unknown Zoom error occurred.';
152
+ if (errorMap[status]) {
153
+ if (typeof errorMap[status] === 'string') {
154
+ // Found the error message
155
+ zoomErrorMessage = (errorMap[status] as string);
156
+ } else if (body.code) {
157
+ // Check for nested error message
158
+ if (typeof errorMap[status][body.code] === 'string') {
159
+ // Found nested error message
160
+ zoomErrorMessage = errorMap[status][body.code];
161
+ } else if (body.message) {
162
+ // errorMap[status][code] did not return err message
163
+ // so we check body
164
+ if (typeof body.message === 'string') {
165
+ zoomErrorMessage = body.message;
166
+ }
124
167
  }
125
168
  }
169
+ } else if (body.message) {
170
+ // Error message not in the error map so check body
171
+ if (typeof body.message === 'string') {
172
+ zoomErrorMessage = body.message;
173
+ }
126
174
  }
127
- } else if (body.message) {
128
- // Error message not in the error map so check body
129
- if (typeof body.message === 'string') {
130
- zoomErrorMessage = body.message;
131
- }
175
+
176
+ const errorMessage = `We couldn't ${action} because an error occurred: ${zoomErrorMessage}`;
177
+ const errorCode = `ZOOM${status}${body.code ? `-${body.code}` : ''}`;
178
+
179
+ throw new ZACCLError({
180
+ message: errorMessage,
181
+ code: errorCode,
182
+ });
132
183
  }
133
184
 
134
- const errorMessage = `We couldn't ${action} because an error occurred: ${zoomErrorMessage}`;
135
- const errorCode = `ZOOM${status}${body.code ? `-${body.code}` : ''}`;
185
+ /* ----------- Postprocess ---------- */
136
186
 
137
- throw new ZACCLError({
138
- message: errorMessage,
139
- code: errorCode,
140
- });
141
- }
187
+ // Extract results
188
+ let results = itemKey ? body[itemKey] : body;
142
189
 
143
- /* ----- Post-process and Return ---- */
190
+ // Update next page token
191
+ nextPageToken = body.next_page_token;
192
+ if (nextPageToken) {
193
+ isPaginated = true;
194
+ }
144
195
 
145
- if (postProcessor) {
146
- return postProcessor(body);
147
- }
196
+ // End if not paginated
197
+ if (!isPaginated) {
198
+ return results;
199
+ }
200
+
201
+ /* --------- Paging Handling -------- */
202
+
203
+ // Add items to allItems if paginated
204
+ if (Array.isArray(results)) {
205
+ allItems.push(...results);
206
+ }
207
+
208
+ // Call onNewPage callback if it exists
209
+ if (onNewPage) {
210
+ onNewPage(results);
211
+ }
212
+ };
148
213
 
149
- return body;
214
+ // Return all items (if we got here, response is paginated)
215
+ return allItems;
150
216
  };
151
217
  };
152
218
 
@@ -22,8 +22,12 @@ type VisitEndpointFunc = (
22
22
  },
23
23
  // Parameters/args/body to send with request
24
24
  params?: { [k: string]: any },
25
- // Function that processes the response before returning
26
- postProcessor?: (response: any) => any,
25
+ // The key in the response body where the list of items can be found (for paginated endpoints)
26
+ itemKey?: string,
27
+ // Callback function that is called when a new page of results is received (for paginated endpoints)
28
+ onNewPage?: (items: any[]) => void,
29
+ // Minimum time (in ms) to wait between paginated requests, for custom throttle control (for paginated endpoints)
30
+ minMsBetweenPageRequests?: number,
27
31
  },
28
32
  ) => Promise<any>
29
33
  );
@@ -1,4 +1,5 @@
1
1
  import ECatCloudRecording from '../endpoints/ECatCloudRecording';
2
+ import ECatGroup from '../endpoints/ECatGroup';
2
3
  import ECatMeeting from '../endpoints/ECatMeeting';
3
4
  import ECatUser from '../endpoints/ECatUser';
4
5
  import ECatWebinar from '../endpoints/ECatWebinar';
@@ -12,6 +13,7 @@ interface ZoomAPI {
12
13
  meeting: ECatMeeting,
13
14
  user: ECatUser,
14
15
  webinar: ECatWebinar,
16
+ group: ECatGroup,
15
17
  };
16
18
 
17
19
  export default ZoomAPI;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Zoom user group
3
+ * @author Gabe Abrams
4
+ */
5
+ type ZoomGroup = {
6
+ // Unique id for the group
7
+ id: string,
8
+ // Name of the group
9
+ name: string,
10
+ // Total number of members in the group
11
+ total_members: number,
12
+ };
13
+
14
+ export default ZoomGroup;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * A single group member within a Zoom group
3
+ * @author Gabe Abrams
4
+ */
5
+ type ZoomGroupMember = {
6
+ // User's email address
7
+ email: string,
8
+ // First name of the user
9
+ first_name: string,
10
+ // Unique Identifier of the user
11
+ id: string,
12
+ // Last name of the user
13
+ last_name: string,
14
+ // User type:
15
+ // 1 - Basic
16
+ // 2 - Licensed
17
+ type: (1 | 2),
18
+ };
19
+
20
+ export default ZoomGroupMember;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Transcript for a specific zoom meeting instance
3
+ * @author Gabe Abrams
4
+ */
5
+ type ZoomMeetingTranscript = {
6
+ // The meeting ID
7
+ meeting_id: string,
8
+ // The user account's unique identifier.
9
+ account_id: string,
10
+ // The meeting topic.
11
+ meeting_topic: string,
12
+ // ID of the user set as the host of the meeting.
13
+ host_id: string,
14
+ // The date and time that the meeting's transcript was created.
15
+ transcript_created_time: string,
16
+ // Whether the meeting transcript is available for download.
17
+ can_download: boolean,
18
+ // Auto-delete status of a meeting's transcript
19
+ auto_delete: boolean,
20
+ // The date when the recording will be auto-deleted when `auto_delete` is true.
21
+ auto_delete_date: string,
22
+ // The URL to download the transcript. Present only when `can_download` is `true`.
23
+ download_url: string | null,
24
+ // The reason why the transcript cannot be downloaded when `can_download` is `false`.
25
+ download_restriction_reason: 'DELETED_OR_TRASHED' | 'UNSUPPORTED' | 'NO_TRANSCRIPT_DATA' | 'NOT_READY' | null,
26
+ };
27
+
28
+ export default ZoomMeetingTranscript;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Details about a past meeting
3
+ * @author Gabe Abrams
4
+ */
5
+ type ZoomPastMeetingDetails = {
6
+ // The meeting ID,
7
+ id: number,
8
+ // The meeting's UUID
9
+ uuid: string,
10
+ // The meeting's duration, in minutes
11
+ duration: number,
12
+ // The meeting's start date and time
13
+ start_time: string,
14
+ // The meeting's end date and time
15
+ end_time: string,
16
+ // The host's ID
17
+ host_id: string,
18
+ // The meeting host's department
19
+ dept: string,
20
+ // The number of meeting participants
21
+ participants_count: number,
22
+ // Whether the meeting was created directly through Zoom or via an API request
23
+ source: string,
24
+ // The meeting's topic
25
+ topic: string,
26
+ // The total number of minutes attended by the meeting's host and participants
27
+ total_minutes: number,
28
+ // The meeting type (0-4, 7-8)
29
+ type: 0 | 1 | 2 | 3 | 4 | 7 | 8,
30
+ // The user's email address
31
+ user_email: string,
32
+ // The user's display name
33
+ user_name: string,
34
+ // Whether the summary feature was used in the meeting
35
+ has_meeting_summary: boolean,
36
+ };
37
+
38
+ export default ZoomPastMeetingDetails;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Represents a participant in a Zoom past meeting.
3
+ * @author Gabe Abrams
4
+ */
5
+ type ZoomPastMeetingParticipant = {
6
+ // Unique identifier for the participant
7
+ id?: string;
8
+ // Display name of the participant
9
+ name?: string;
10
+ // Zoom user ID of the participant
11
+ user_id?: string;
12
+ // Registration ID if participant registered beforehand
13
+ registrant_id?: string;
14
+ // Email address of the participant
15
+ user_email?: string;
16
+ // ISO 8601 timestamp when participant joined the meeting
17
+ join_time?: string;
18
+ // ISO 8601 timestamp when participant left the meeting
19
+ leave_time?: string;
20
+ // Duration in seconds that the participant was in the meeting
21
+ duration?: number;
22
+ // Indicates if participant connected via failover
23
+ failover?: boolean;
24
+ // Current status of the participant in the meeting
25
+ status?: 'in_meeting' | 'in_waiting_room';
26
+ // Indicates if the participant is an internal Zoom user
27
+ internal_user?: boolean;
28
+ };
29
+
30
+ export default ZoomPastMeetingParticipant;
@@ -0,0 +1,38 @@
1
+ import ZoomRecordingFile from './ZoomRecordingFile';
2
+
3
+ /**
4
+ * A single recording in an account
5
+ * @author Gabe Abrams
6
+ */
7
+ type ZoomRecordingInAccount = {
8
+ // The meeting's scheduled duration
9
+ duration: number,
10
+ // The meeting host's user ID
11
+ host_id: string,
12
+ // The meeting's ID
13
+ id: number,
14
+ // The total number of recordings retrieved from the account
15
+ recording_count: number,
16
+ // The information about the recording files
17
+ recording_files: ZoomRecordingFile[],
18
+ // The date and time when the meeting started
19
+ start_time: string,
20
+ // The meeting's topic
21
+ topic: string,
22
+ // The total size of the recording file, in bytes
23
+ total_size: number,
24
+ // The recording's associated type of meeting or webinar
25
+ type: number,
26
+ // The meeting's universally unique ID
27
+ uuid: string,
28
+ // Recording zone used in the Zoom Node Platform
29
+ rc_zone?: string,
30
+ // The unique ID for the hybrid recorder or recording connector
31
+ instance_id?: string,
32
+ // The name of the Zoom Node Service
33
+ service_name?: string,
34
+ // NFS address
35
+ external_storage_addr?: string,
36
+ };
37
+
38
+ export default ZoomRecordingInAccount;