@dereekb/zoom 13.0.0 → 13.0.2
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.cjs.default.js +1 -0
- package/index.cjs.js +476 -525
- package/index.cjs.mjs +2 -0
- package/index.esm.js +476 -525
- package/nestjs/index.cjs.default.js +1 -0
- package/nestjs/index.cjs.js +487 -452
- package/nestjs/index.cjs.mjs +2 -0
- package/nestjs/index.esm.js +487 -452
- package/nestjs/package.json +20 -15
- package/package.json +21 -24
package/nestjs/index.esm.js
CHANGED
|
@@ -48,58 +48,59 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
48
48
|
* Configuration for ZoomService
|
|
49
49
|
*/
|
|
50
50
|
class ZoomOAuthServiceConfig {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
51
|
+
zoomOAuth;
|
|
52
|
+
factoryConfig;
|
|
53
|
+
static assertValidConfig(config) {
|
|
54
|
+
const { zoomOAuth } = config;
|
|
55
|
+
if (!zoomOAuth) {
|
|
56
|
+
throw new Error('ZoomOAuthServiceConfig.zoomOAuth is required');
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
if (!zoomOAuth.accountId) {
|
|
60
|
+
throw new Error('ZoomOAuthServiceConfig.zoomOAuth.accountId is required');
|
|
61
|
+
}
|
|
62
|
+
else if (!zoomOAuth.clientSecret) {
|
|
63
|
+
throw new Error('ZoomOAuthServiceConfig.zoomOAuth.clientSecret is required');
|
|
64
|
+
}
|
|
65
|
+
else if (!zoomOAuth.clientId) {
|
|
66
|
+
throw new Error('ZoomOAuthServiceConfig.zoomOAuth.clientId is required');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
69
70
|
}
|
|
70
71
|
function readZoomOAuthServiceConfigFromConfigService(configService, prefix) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
};
|
|
89
|
-
ZoomOAuthServiceConfig.assertValidConfig(config);
|
|
90
|
-
return config;
|
|
72
|
+
const prefixString = characterPrefixSuffixInstance({ suffix: '_', suffixEmptyString: false }).prefixSuffixString(prefix ?? '');
|
|
73
|
+
const accountIdKey = `${prefixString}ZOOM_ACCOUNT_ID`;
|
|
74
|
+
const clientIdKey = `${prefixString}ZOOM_CLIENT_ID`;
|
|
75
|
+
const clientSecretKey = `${prefixString}ZOOM_CLIENT_SECRET`;
|
|
76
|
+
const accountId = configService.getOrThrow(accountIdKey);
|
|
77
|
+
const clientId = configService.getOrThrow(clientIdKey);
|
|
78
|
+
const clientSecret = configService.getOrThrow(clientSecretKey);
|
|
79
|
+
const config = {
|
|
80
|
+
zoomOAuth: {
|
|
81
|
+
authEntityType: 'account',
|
|
82
|
+
accountId,
|
|
83
|
+
clientId,
|
|
84
|
+
clientSecret
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
ZoomOAuthServiceConfig.assertValidConfig(config);
|
|
88
|
+
return config;
|
|
91
89
|
}
|
|
92
90
|
|
|
93
91
|
/**
|
|
94
92
|
* Service used for retrieving ZoomAccessTokenCache for Zoom services.
|
|
95
93
|
*/
|
|
96
|
-
let ZoomOAuthAccessTokenCacheService = class ZoomOAuthAccessTokenCacheService {
|
|
97
|
-
|
|
94
|
+
let ZoomOAuthAccessTokenCacheService = class ZoomOAuthAccessTokenCacheService {
|
|
95
|
+
};
|
|
96
|
+
ZoomOAuthAccessTokenCacheService = __decorate([
|
|
97
|
+
Injectable()
|
|
98
|
+
], ZoomOAuthAccessTokenCacheService);
|
|
98
99
|
function logMergeZoomOAuthAccessTokenCacheServiceErrorFunction(failedUpdates) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
console.warn(`mergeZoomOAuthAccessTokenCacheServices(): failed updating ${failedUpdates.length} caches.`);
|
|
101
|
+
failedUpdates.forEach(([x, e], i) => {
|
|
102
|
+
console.warn(`Cache update failure ${i + 1}: - ${e}`);
|
|
103
|
+
});
|
|
103
104
|
}
|
|
104
105
|
/**
|
|
105
106
|
* Merges the input services in order to use some as a backup source.
|
|
@@ -111,54 +112,62 @@ function logMergeZoomOAuthAccessTokenCacheServiceErrorFunction(failedUpdates) {
|
|
|
111
112
|
* @param servicesToMerge Must include atleast one service. Empty arrays will throw an error.
|
|
112
113
|
*/
|
|
113
114
|
function mergeZoomOAuthAccessTokenCacheServices(inputServicesToMerge, logError) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return loadCachedTokenFromFirstService();
|
|
134
|
-
},
|
|
135
|
-
updateCachedToken: async function (accessToken) {
|
|
136
|
-
return Promise.allSettled(accessCachesForServices.map(x => x.updateCachedToken(accessToken).then(() => null).catch(e => {
|
|
137
|
-
return [x, e];
|
|
138
|
-
}))).then(x => {
|
|
139
|
-
// only find the failures if we're logging
|
|
140
|
-
if (logErrorFunction != null) {
|
|
141
|
-
const failedUpdates = filterMaybeArrayValues(x.map(y => y.value));
|
|
142
|
-
if (failedUpdates.length) {
|
|
143
|
-
logErrorFunction(failedUpdates);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
115
|
+
const allServices = [...inputServicesToMerge];
|
|
116
|
+
const logErrorFunction = typeof logError === 'function' ? logError : logError !== false ? logMergeZoomOAuthAccessTokenCacheServiceErrorFunction : undefined;
|
|
117
|
+
if (allServices.length === 0) {
|
|
118
|
+
throw new Error('mergeZoomOAuthAccessTokenCacheServices() input cannot be empty.');
|
|
119
|
+
}
|
|
120
|
+
const loadZoomAccessTokenCache = (accessCachesForServices) => {
|
|
121
|
+
const loadCachedTokenFromFirstService = tryWithPromiseFactoriesFunction({
|
|
122
|
+
promiseFactories: accessCachesForServices.map((x) => () => x
|
|
123
|
+
.loadCachedToken()
|
|
124
|
+
.catch(() => null)
|
|
125
|
+
.then((x) => {
|
|
126
|
+
let result = undefined;
|
|
127
|
+
if (x && !isPast(x.expiresAt)) {
|
|
128
|
+
result = x; // only return from cache if it is not expired
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
})),
|
|
132
|
+
successOnMaybe: false,
|
|
133
|
+
throwErrors: false
|
|
146
134
|
});
|
|
147
|
-
|
|
135
|
+
const cacheForService = {
|
|
136
|
+
loadCachedToken: function () {
|
|
137
|
+
return loadCachedTokenFromFirstService();
|
|
138
|
+
},
|
|
139
|
+
updateCachedToken: async function (accessToken) {
|
|
140
|
+
return Promise.allSettled(accessCachesForServices.map((x) => x
|
|
141
|
+
.updateCachedToken(accessToken)
|
|
142
|
+
.then(() => null)
|
|
143
|
+
.catch((e) => {
|
|
144
|
+
return [x, e];
|
|
145
|
+
}))).then((x) => {
|
|
146
|
+
// only find the failures if we're logging
|
|
147
|
+
if (logErrorFunction != null) {
|
|
148
|
+
const failedUpdates = filterMaybeArrayValues(x.map((y) => y.value));
|
|
149
|
+
if (failedUpdates.length) {
|
|
150
|
+
logErrorFunction(failedUpdates);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
return cacheForService;
|
|
157
|
+
};
|
|
158
|
+
const allServiceAccessTokenCaches = allServices.map((x) => x.loadZoomAccessTokenCache());
|
|
159
|
+
const allServicesWithCacheForRefreshToken = allServices.filter((x) => x.cacheForRefreshToken != null);
|
|
160
|
+
const cacheForRefreshToken = allServiceAccessTokenCaches.length > 0
|
|
161
|
+
? (refreshToken) => {
|
|
162
|
+
const allCaches = allServicesWithCacheForRefreshToken.map((x) => x.cacheForRefreshToken(refreshToken));
|
|
163
|
+
return loadZoomAccessTokenCache(allCaches);
|
|
164
|
+
}
|
|
165
|
+
: undefined;
|
|
166
|
+
const service = {
|
|
167
|
+
loadZoomAccessTokenCache: () => loadZoomAccessTokenCache(allServiceAccessTokenCaches),
|
|
168
|
+
cacheForRefreshToken
|
|
148
169
|
};
|
|
149
|
-
return
|
|
150
|
-
};
|
|
151
|
-
const allServiceAccessTokenCaches = allServices.map(x => x.loadZoomAccessTokenCache());
|
|
152
|
-
const allServicesWithCacheForRefreshToken = allServices.filter(x => x.cacheForRefreshToken != null);
|
|
153
|
-
const cacheForRefreshToken = allServiceAccessTokenCaches.length > 0 ? refreshToken => {
|
|
154
|
-
const allCaches = allServicesWithCacheForRefreshToken.map(x => x.cacheForRefreshToken(refreshToken));
|
|
155
|
-
return loadZoomAccessTokenCache(allCaches);
|
|
156
|
-
} : undefined;
|
|
157
|
-
const service = {
|
|
158
|
-
loadZoomAccessTokenCache: () => loadZoomAccessTokenCache(allServiceAccessTokenCaches),
|
|
159
|
-
cacheForRefreshToken
|
|
160
|
-
};
|
|
161
|
-
return service;
|
|
170
|
+
return service;
|
|
162
171
|
}
|
|
163
172
|
// MARK: Memory Access Token Cache
|
|
164
173
|
/**
|
|
@@ -167,32 +176,28 @@ function mergeZoomOAuthAccessTokenCacheServices(inputServicesToMerge, logError)
|
|
|
167
176
|
* @returns
|
|
168
177
|
*/
|
|
169
178
|
function memoryZoomOAuthAccessTokenCacheService(existingToken, logAccessToConsole) {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
179
|
+
let token = existingToken;
|
|
180
|
+
function loadZoomAccessTokenCache() {
|
|
181
|
+
const accessTokenCache = {
|
|
182
|
+
loadCachedToken: async function () {
|
|
183
|
+
if (logAccessToConsole) {
|
|
184
|
+
console.log('retrieving access token from memory: ', { token });
|
|
185
|
+
}
|
|
186
|
+
return token;
|
|
187
|
+
},
|
|
188
|
+
updateCachedToken: async function (accessToken) {
|
|
189
|
+
token = accessToken;
|
|
190
|
+
if (logAccessToConsole) {
|
|
191
|
+
console.log('updating access token in memory: ', { accessToken });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
return accessTokenCache;
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
loadZoomAccessTokenCache,
|
|
199
|
+
cacheForRefreshToken: () => loadZoomAccessTokenCache()
|
|
189
200
|
};
|
|
190
|
-
return accessTokenCache;
|
|
191
|
-
}
|
|
192
|
-
return {
|
|
193
|
-
loadZoomAccessTokenCache,
|
|
194
|
-
cacheForRefreshToken: () => loadZoomAccessTokenCache()
|
|
195
|
-
};
|
|
196
201
|
}
|
|
197
202
|
// MARK: File System Access Token Cache
|
|
198
203
|
const DEFAULT_FILE_ZOOM_ACCOUNTS_ACCESS_TOKEN_CACHE_SERVICE_PATH = '.tmp/zoom-access-tokens.json';
|
|
@@ -204,128 +209,137 @@ const DEFAULT_FILE_ZOOM_ACCOUNTS_ACCESS_TOKEN_CACHE_SERVICE_PATH = '.tmp/zoom-ac
|
|
|
204
209
|
* @returns
|
|
205
210
|
*/
|
|
206
211
|
function fileZoomOAuthAccessTokenCacheService(filename = DEFAULT_FILE_ZOOM_ACCOUNTS_ACCESS_TOKEN_CACHE_SERVICE_PATH, useMemoryCache = true) {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
} else {
|
|
213
|
-
token = loadedToken;
|
|
214
|
-
}
|
|
215
|
-
return token;
|
|
216
|
-
}
|
|
217
|
-
function readTokenFile() {
|
|
218
|
-
return new Promise(resolve => {
|
|
219
|
-
mkdirSync(dirname(filename), {
|
|
220
|
-
recursive: true
|
|
221
|
-
}); // make the directory first
|
|
222
|
-
readFile(filename, {}, (x, data) => {
|
|
223
|
-
let result = undefined;
|
|
224
|
-
if (!x) {
|
|
225
|
-
try {
|
|
226
|
-
result = JSON.parse(data.toString());
|
|
227
|
-
if (result?.token) {
|
|
228
|
-
result.token.expiresAt = new Date(result.token.expiresAt);
|
|
229
|
-
}
|
|
230
|
-
} catch (e) {
|
|
231
|
-
console.error('Failed reading token file: ', e);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
resolve(result);
|
|
235
|
-
});
|
|
236
|
-
}).then(x => {
|
|
237
|
-
// update loaded tokens
|
|
238
|
-
if (useMemoryCache) {
|
|
239
|
-
loadedToken = {
|
|
240
|
-
...loadedToken,
|
|
241
|
-
...x
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
return x;
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
async function writeTokenFile(tokens) {
|
|
248
|
-
return new Promise((resolve, reject) => {
|
|
249
|
-
writeFile(filename, JSON.stringify(tokens), {}, x => {
|
|
250
|
-
if (!x) {
|
|
251
|
-
resolve();
|
|
252
|
-
} else {
|
|
253
|
-
reject(x);
|
|
212
|
+
let loadedToken = null;
|
|
213
|
+
async function loadTokenFile() {
|
|
214
|
+
let token = undefined;
|
|
215
|
+
if (!loadedToken) {
|
|
216
|
+
token = (await readTokenFile()) ?? {};
|
|
254
217
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
async function deleteTokenFile() {
|
|
259
|
-
return new Promise((resolve, reject) => {
|
|
260
|
-
rm(filename, x => {
|
|
261
|
-
if (!x) {
|
|
262
|
-
resolve();
|
|
263
|
-
} else {
|
|
264
|
-
reject(x);
|
|
218
|
+
else {
|
|
219
|
+
token = loadedToken;
|
|
265
220
|
}
|
|
266
|
-
});
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
function loadZoomAccessTokenCache() {
|
|
270
|
-
const accessTokenCache = {
|
|
271
|
-
loadCachedToken: async function () {
|
|
272
|
-
const tokens = await loadTokenFile();
|
|
273
|
-
const token = tokens.token;
|
|
274
|
-
// console.log('retrieving access token from file: ', { token });
|
|
275
221
|
return token;
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
222
|
+
}
|
|
223
|
+
function readTokenFile() {
|
|
224
|
+
return new Promise((resolve) => {
|
|
225
|
+
mkdirSync(dirname(filename), { recursive: true }); // make the directory first
|
|
226
|
+
readFile(filename, {}, (x, data) => {
|
|
227
|
+
let result = undefined;
|
|
228
|
+
if (!x) {
|
|
229
|
+
try {
|
|
230
|
+
result = JSON.parse(data.toString());
|
|
231
|
+
if (result?.token) {
|
|
232
|
+
result.token.expiresAt = new Date(result.token.expiresAt);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
catch (e) {
|
|
236
|
+
console.error('Failed reading token file: ', e);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
resolve(result);
|
|
240
|
+
});
|
|
241
|
+
}).then((x) => {
|
|
242
|
+
// update loaded tokens
|
|
243
|
+
if (useMemoryCache) {
|
|
244
|
+
loadedToken = {
|
|
245
|
+
...loadedToken,
|
|
246
|
+
...x
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
return x;
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
async function writeTokenFile(tokens) {
|
|
253
|
+
return new Promise((resolve, reject) => {
|
|
254
|
+
writeFile(filename, JSON.stringify(tokens), {}, (x) => {
|
|
255
|
+
if (!x) {
|
|
256
|
+
resolve();
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
reject(x);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
async function deleteTokenFile() {
|
|
265
|
+
return new Promise((resolve, reject) => {
|
|
266
|
+
rm(filename, (x) => {
|
|
267
|
+
if (!x) {
|
|
268
|
+
resolve();
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
reject(x);
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
function loadZoomAccessTokenCache() {
|
|
277
|
+
const accessTokenCache = {
|
|
278
|
+
loadCachedToken: async function () {
|
|
279
|
+
const tokens = await loadTokenFile();
|
|
280
|
+
const token = tokens.token;
|
|
281
|
+
// console.log('retrieving access token from file: ', { token });
|
|
282
|
+
return token;
|
|
283
|
+
},
|
|
284
|
+
updateCachedToken: async function (accessToken) {
|
|
285
|
+
const tokenFile = await loadTokenFile();
|
|
286
|
+
if (tokenFile) {
|
|
287
|
+
tokenFile.token = accessToken;
|
|
288
|
+
}
|
|
289
|
+
// console.log('updating access token in file: ', { accessToken });
|
|
290
|
+
try {
|
|
291
|
+
await writeTokenFile(tokenFile);
|
|
292
|
+
}
|
|
293
|
+
catch (e) {
|
|
294
|
+
console.error('Failed updating access token in file: ', e);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
return accessTokenCache;
|
|
299
|
+
}
|
|
300
|
+
return {
|
|
301
|
+
loadZoomAccessTokenCache,
|
|
302
|
+
readTokenFile,
|
|
303
|
+
writeTokenFile,
|
|
304
|
+
deleteTokenFile
|
|
289
305
|
};
|
|
290
|
-
return accessTokenCache;
|
|
291
|
-
}
|
|
292
|
-
return {
|
|
293
|
-
loadZoomAccessTokenCache,
|
|
294
|
-
readTokenFile,
|
|
295
|
-
writeTokenFile,
|
|
296
|
-
deleteTokenFile
|
|
297
|
-
};
|
|
298
306
|
}
|
|
299
307
|
|
|
300
308
|
let ZoomOAuthApi = class ZoomOAuthApi {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
309
|
+
config;
|
|
310
|
+
cacheService;
|
|
311
|
+
zoomOAuth;
|
|
312
|
+
get oauthContext() {
|
|
313
|
+
return this.zoomOAuth.oauthContext;
|
|
314
|
+
}
|
|
315
|
+
constructor(config, cacheService) {
|
|
316
|
+
this.config = config;
|
|
317
|
+
this.cacheService = cacheService;
|
|
318
|
+
const accessTokenCache = config.zoomOAuth.accessTokenCache ? config.zoomOAuth.accessTokenCache : cacheService.loadZoomAccessTokenCache();
|
|
319
|
+
this.zoomOAuth = zoomOAuthFactory(config.factoryConfig ?? {})({
|
|
320
|
+
accessTokenCache,
|
|
321
|
+
...config.zoomOAuth
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
// MARK: Accessors
|
|
325
|
+
get serverAccessToken() {
|
|
326
|
+
return serverAccessToken(this.oauthContext);
|
|
327
|
+
}
|
|
328
|
+
get userAccessToken() {
|
|
329
|
+
return userAccessToken(this.oauthContext);
|
|
330
|
+
}
|
|
323
331
|
};
|
|
324
|
-
ZoomOAuthApi = __decorate([
|
|
332
|
+
ZoomOAuthApi = __decorate([
|
|
333
|
+
Injectable(),
|
|
334
|
+
__param(0, Inject(ZoomOAuthServiceConfig)),
|
|
335
|
+
__param(1, Inject(ZoomOAuthAccessTokenCacheService)),
|
|
336
|
+
__metadata("design:paramtypes", [ZoomOAuthServiceConfig,
|
|
337
|
+
ZoomOAuthAccessTokenCacheService])
|
|
338
|
+
], ZoomOAuthApi);
|
|
325
339
|
|
|
326
340
|
function zoomOAuthServiceConfigFactory(configService) {
|
|
327
|
-
|
|
328
|
-
|
|
341
|
+
const config = readZoomOAuthServiceConfigFromConfigService(configService);
|
|
342
|
+
return config;
|
|
329
343
|
}
|
|
330
344
|
/**
|
|
331
345
|
* Convenience function used to generate ModuleMetadata for an app's ZoomOAuthModule.
|
|
@@ -335,22 +349,21 @@ function zoomOAuthServiceConfigFactory(configService) {
|
|
|
335
349
|
* @returns
|
|
336
350
|
*/
|
|
337
351
|
function appZoomOAuthModuleMetadata(config) {
|
|
338
|
-
|
|
339
|
-
dependencyModule
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
353
|
-
};
|
|
352
|
+
const { dependencyModule, imports, exports: exports$1, providers } = config;
|
|
353
|
+
const dependencyModuleImport = dependencyModule ? [dependencyModule] : [];
|
|
354
|
+
return {
|
|
355
|
+
imports: [ConfigModule, ...dependencyModuleImport, ...(imports ?? [])],
|
|
356
|
+
exports: [ZoomOAuthApi, ...(exports$1 ?? [])],
|
|
357
|
+
providers: [
|
|
358
|
+
{
|
|
359
|
+
provide: ZoomOAuthServiceConfig,
|
|
360
|
+
inject: [ConfigService],
|
|
361
|
+
useFactory: config.zoomOAuthServiceConfigFactory ?? zoomOAuthServiceConfigFactory
|
|
362
|
+
},
|
|
363
|
+
ZoomOAuthApi,
|
|
364
|
+
...(providers ?? [])
|
|
365
|
+
]
|
|
366
|
+
};
|
|
354
367
|
}
|
|
355
368
|
|
|
356
369
|
const ZOOM_SECRET_TOKEN_ENV_VAR = 'ZOOM_SECRET_TOKEN';
|
|
@@ -358,12 +371,12 @@ const ZOOM_SECRET_TOKEN_ENV_VAR = 'ZOOM_SECRET_TOKEN';
|
|
|
358
371
|
* Configuration for ZoomService
|
|
359
372
|
*/
|
|
360
373
|
class ZoomWebhookServiceConfig {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
374
|
+
webhookConfig;
|
|
375
|
+
static assertValidConfig(config) {
|
|
376
|
+
if (!config.webhookConfig.zoomSecretToken) {
|
|
377
|
+
throw new Error('No zoom secret token specified.');
|
|
378
|
+
}
|
|
365
379
|
}
|
|
366
|
-
}
|
|
367
380
|
}
|
|
368
381
|
|
|
369
382
|
// MARK: Meeting Alert
|
|
@@ -388,29 +401,29 @@ const ZOOM_WEBHOOK_MEETING_PERMANENTLY_DELETED_EVENT_TYPE = 'meeting.permanently
|
|
|
388
401
|
* @returns
|
|
389
402
|
*/
|
|
390
403
|
function zoomWebhookEvent(event) {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
404
|
+
return {
|
|
405
|
+
event: event.event,
|
|
406
|
+
event_ts: event.event_ts,
|
|
407
|
+
payload: event.payload
|
|
408
|
+
};
|
|
396
409
|
}
|
|
397
|
-
const zoomEventHandlerFactory = handlerFactory(x => x.event);
|
|
410
|
+
const zoomEventHandlerFactory = handlerFactory((x) => x.event);
|
|
398
411
|
const zoomEventHandlerConfigurerFactory = handlerConfigurerFactory({
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
412
|
+
configurerForAccessor: (accessor) => {
|
|
413
|
+
// eslint-disable-next-line
|
|
414
|
+
const fnWithKey = handlerMappedSetFunctionFactory(accessor, zoomWebhookEvent);
|
|
415
|
+
const configurer = {
|
|
416
|
+
...accessor,
|
|
417
|
+
// Meetings
|
|
418
|
+
handleMeetingCreated: fnWithKey(ZOOM_WEBHOOK_MEETING_CREATED_EVENT_TYPE),
|
|
419
|
+
handleMeetingUpdated: fnWithKey(ZOOM_WEBHOOK_MEETING_UPDATED_EVENT_TYPE),
|
|
420
|
+
handleMeetingDeleted: fnWithKey(ZOOM_WEBHOOK_MEETING_DELETED_EVENT_TYPE),
|
|
421
|
+
handleMeetingStarted: fnWithKey(ZOOM_WEBHOOK_MEETING_STARTED_EVENT_TYPE),
|
|
422
|
+
handleMeetingEnded: fnWithKey(ZOOM_WEBHOOK_MEETING_ENDED_EVENT_TYPE),
|
|
423
|
+
handleMeetingPermanentlyDeleted: fnWithKey(ZOOM_WEBHOOK_MEETING_PERMANENTLY_DELETED_EVENT_TYPE)
|
|
424
|
+
};
|
|
425
|
+
return configurer;
|
|
426
|
+
}
|
|
414
427
|
});
|
|
415
428
|
|
|
416
429
|
/**
|
|
@@ -422,18 +435,18 @@ const zoomEventHandlerConfigurerFactory = handlerConfigurerFactory({
|
|
|
422
435
|
* @returns A function that verifies a Zoom webhook event.
|
|
423
436
|
*/
|
|
424
437
|
function zoomWebhookEventVerifier(zoomSecretToken) {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
438
|
+
return (request, rawBody) => {
|
|
439
|
+
const requestBodyString = String(request.body);
|
|
440
|
+
const message = `v0:${request.headers['x-zm-request-timestamp']}:${requestBodyString}`;
|
|
441
|
+
const hashForVerify = createHmac('sha256', zoomSecretToken).update(message).digest('hex');
|
|
442
|
+
const signature = `v0=${hashForVerify}`;
|
|
443
|
+
const valid = request.headers['x-zm-signature'] === signature;
|
|
444
|
+
const result = {
|
|
445
|
+
valid,
|
|
446
|
+
event: JSON.parse(requestBodyString)
|
|
447
|
+
};
|
|
448
|
+
return result;
|
|
434
449
|
};
|
|
435
|
-
return result;
|
|
436
|
-
};
|
|
437
450
|
}
|
|
438
451
|
|
|
439
452
|
const ZOOM_WEBHOOK_URL_VALIDATION_EVENT_TYPE = 'endpoint.url_validation';
|
|
@@ -445,193 +458,216 @@ const ZOOM_WEBHOOK_URL_VALIDATION_EVENT_TYPE = 'endpoint.url_validation';
|
|
|
445
458
|
* @returns A ZoomWebhookEventValidationFunction.
|
|
446
459
|
*/
|
|
447
460
|
function zoomWebhookEventValidationFunction(zoomSecretToken) {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
461
|
+
return (event) => {
|
|
462
|
+
const { plainToken } = event.payload;
|
|
463
|
+
if (!plainToken) {
|
|
464
|
+
throw new Error(`The expected plaintoken value was not provided by the event's payload.`);
|
|
465
|
+
}
|
|
466
|
+
const encryptedToken = createHmac('sha256', zoomSecretToken).update(plainToken).digest('hex');
|
|
467
|
+
const result = {
|
|
468
|
+
plainToken,
|
|
469
|
+
encryptedToken
|
|
470
|
+
};
|
|
471
|
+
return result;
|
|
459
472
|
};
|
|
460
|
-
return result;
|
|
461
|
-
};
|
|
462
473
|
}
|
|
463
474
|
|
|
464
475
|
/**
|
|
465
476
|
* Service that makes system changes based on Zoom webhook events.
|
|
466
477
|
*/
|
|
467
478
|
let ZoomWebhookService = class ZoomWebhookService {
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
}
|
|
479
|
+
logger = new Logger('ZoomWebhookService');
|
|
480
|
+
_verifier;
|
|
481
|
+
_validator;
|
|
482
|
+
handler = zoomEventHandlerFactory();
|
|
483
|
+
configure = zoomEventHandlerConfigurerFactory(this.handler);
|
|
484
|
+
constructor(config) {
|
|
485
|
+
this._verifier = zoomWebhookEventVerifier(config.webhookConfig.zoomSecretToken);
|
|
486
|
+
this._validator = zoomWebhookEventValidationFunction(config.webhookConfig.zoomSecretToken);
|
|
487
|
+
}
|
|
488
|
+
async updateForWebhook(req, rawBody) {
|
|
489
|
+
const { valid, event } = this._verifier(req, rawBody);
|
|
490
|
+
let handled = false;
|
|
491
|
+
let validationEventResponse;
|
|
492
|
+
if (!valid) {
|
|
493
|
+
this.logger.warn('Received invalid zoom event: ', event);
|
|
494
|
+
}
|
|
495
|
+
else if (event.event === ZOOM_WEBHOOK_URL_VALIDATION_EVENT_TYPE) {
|
|
496
|
+
validationEventResponse = this._validator(event);
|
|
497
|
+
handled = true;
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
500
|
+
handled = await this.updateForZoomEvent(event);
|
|
501
|
+
}
|
|
502
|
+
const result = {
|
|
503
|
+
valid,
|
|
504
|
+
handled,
|
|
505
|
+
event,
|
|
506
|
+
validationEventResponse
|
|
507
|
+
};
|
|
508
|
+
return result;
|
|
509
|
+
}
|
|
510
|
+
async updateForZoomEvent(event) {
|
|
511
|
+
const handled = await this.handler(event);
|
|
512
|
+
if (!handled) {
|
|
513
|
+
this.logger.warn('Received unexpected/unhandled zoom event: ', event);
|
|
514
|
+
}
|
|
515
|
+
return handled;
|
|
516
|
+
}
|
|
507
517
|
};
|
|
508
|
-
ZoomWebhookService = __decorate([
|
|
518
|
+
ZoomWebhookService = __decorate([
|
|
519
|
+
Injectable(),
|
|
520
|
+
__param(0, Inject(ZoomWebhookServiceConfig)),
|
|
521
|
+
__metadata("design:paramtypes", [ZoomWebhookServiceConfig])
|
|
522
|
+
], ZoomWebhookService);
|
|
509
523
|
|
|
510
524
|
let ZoomWebhookController = class ZoomWebhookController {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
}
|
|
526
|
-
}
|
|
525
|
+
zoomWebhookService;
|
|
526
|
+
constructor(zoomWebhookService) {
|
|
527
|
+
this.zoomWebhookService = zoomWebhookService;
|
|
528
|
+
}
|
|
529
|
+
async handleZoomWebhook(res, req, rawBody) {
|
|
530
|
+
const { valid, validationEventResponse } = await this.zoomWebhookService.updateForWebhook(req, rawBody);
|
|
531
|
+
const response = res.status(200); // always return a 200 status code
|
|
532
|
+
if (valid && validationEventResponse) {
|
|
533
|
+
response.json(validationEventResponse);
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
response.json({});
|
|
537
|
+
}
|
|
538
|
+
}
|
|
527
539
|
};
|
|
528
|
-
__decorate([
|
|
529
|
-
|
|
540
|
+
__decorate([
|
|
541
|
+
Post(),
|
|
542
|
+
__param(0, Res()),
|
|
543
|
+
__param(1, Req()),
|
|
544
|
+
__param(2, RawBody()),
|
|
545
|
+
__metadata("design:type", Function),
|
|
546
|
+
__metadata("design:paramtypes", [Object, Object, Object]),
|
|
547
|
+
__metadata("design:returntype", Promise)
|
|
548
|
+
], ZoomWebhookController.prototype, "handleZoomWebhook", null);
|
|
549
|
+
ZoomWebhookController = __decorate([
|
|
550
|
+
Controller('/webhook/zoom'),
|
|
551
|
+
__param(0, Inject(ZoomWebhookService)),
|
|
552
|
+
__metadata("design:paramtypes", [ZoomWebhookService])
|
|
553
|
+
], ZoomWebhookController);
|
|
530
554
|
|
|
531
555
|
function zoomWebhookServiceConfigFactory(configService) {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
556
|
+
const config = {
|
|
557
|
+
webhookConfig: {
|
|
558
|
+
zoomSecretToken: configService.get(ZOOM_SECRET_TOKEN_ENV_VAR)
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
ZoomWebhookServiceConfig.assertValidConfig(config);
|
|
562
|
+
return config;
|
|
539
563
|
}
|
|
540
564
|
/**
|
|
541
565
|
* Configures webhooks for the service.
|
|
542
566
|
*/
|
|
543
|
-
let ZoomWebhookModule = class ZoomWebhookModule {
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
567
|
+
let ZoomWebhookModule = class ZoomWebhookModule {
|
|
568
|
+
};
|
|
569
|
+
ZoomWebhookModule = __decorate([
|
|
570
|
+
Module({
|
|
571
|
+
imports: [ConfigModule],
|
|
572
|
+
controllers: [ZoomWebhookController],
|
|
573
|
+
exports: [ZoomWebhookService],
|
|
574
|
+
providers: [
|
|
575
|
+
{
|
|
576
|
+
provide: ZoomWebhookServiceConfig,
|
|
577
|
+
inject: [ConfigService],
|
|
578
|
+
useFactory: zoomWebhookServiceConfigFactory
|
|
579
|
+
},
|
|
580
|
+
ZoomWebhookService
|
|
581
|
+
]
|
|
582
|
+
})
|
|
583
|
+
], ZoomWebhookModule);
|
|
554
584
|
|
|
555
585
|
/**
|
|
556
586
|
* Configuration for ZoomService
|
|
557
587
|
*/
|
|
558
588
|
class ZoomServiceConfig {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
589
|
+
zoom;
|
|
590
|
+
factoryConfig;
|
|
591
|
+
static assertValidConfig(config) {
|
|
592
|
+
// TODO?
|
|
593
|
+
}
|
|
564
594
|
}
|
|
565
595
|
|
|
566
596
|
let ZoomApi = class ZoomApi {
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
597
|
+
config;
|
|
598
|
+
zoomOAuthApi;
|
|
599
|
+
zoom;
|
|
600
|
+
get zoomContext() {
|
|
601
|
+
return this.zoom.zoomServerContext;
|
|
602
|
+
}
|
|
603
|
+
get zoomRateLimiter() {
|
|
604
|
+
return this.zoom.zoomServerContext.zoomRateLimiter;
|
|
605
|
+
}
|
|
606
|
+
constructor(config, zoomOAuthApi) {
|
|
607
|
+
this.config = config;
|
|
608
|
+
this.zoomOAuthApi = zoomOAuthApi;
|
|
609
|
+
this.zoom = zoomFactory({
|
|
610
|
+
...config.factoryConfig,
|
|
611
|
+
oauthContext: zoomOAuthApi.oauthContext
|
|
612
|
+
})(config.zoom);
|
|
613
|
+
}
|
|
614
|
+
// MARK: Users
|
|
615
|
+
get getUser() {
|
|
616
|
+
return getUser(this.zoomContext);
|
|
617
|
+
}
|
|
618
|
+
get listUsers() {
|
|
619
|
+
return listUsers(this.zoomContext);
|
|
620
|
+
}
|
|
621
|
+
get listUsersPageFactory() {
|
|
622
|
+
return listUsersPageFactory(this.zoomContext);
|
|
623
|
+
}
|
|
624
|
+
// MARK: Meetings
|
|
625
|
+
get listMeetingsForUser() {
|
|
626
|
+
return listMeetingsForUser(this.zoomContext);
|
|
627
|
+
}
|
|
628
|
+
get listMeetingsForUserPageFactory() {
|
|
629
|
+
return listMeetingsForUserPageFactory(this.zoomContext);
|
|
630
|
+
}
|
|
631
|
+
get createMeetingForUser() {
|
|
632
|
+
return createMeetingForUser(this.zoomContext);
|
|
633
|
+
}
|
|
634
|
+
get getMeeting() {
|
|
635
|
+
return getMeeting(this.zoomContext);
|
|
636
|
+
}
|
|
637
|
+
get updateMeeting() {
|
|
638
|
+
return updateMeeting(this.zoomContext);
|
|
639
|
+
}
|
|
640
|
+
get deleteMeeting() {
|
|
641
|
+
return deleteMeeting(this.zoomContext);
|
|
642
|
+
}
|
|
643
|
+
// MARK: Past Meetings
|
|
644
|
+
get getPastMeeting() {
|
|
645
|
+
return getPastMeeting(this.zoomContext);
|
|
646
|
+
}
|
|
647
|
+
get getPastMeetingParticipants() {
|
|
648
|
+
return getPastMeetingParticipants(this.zoomContext);
|
|
649
|
+
}
|
|
620
650
|
};
|
|
621
|
-
ZoomApi = __decorate([
|
|
651
|
+
ZoomApi = __decorate([
|
|
652
|
+
Injectable(),
|
|
653
|
+
__param(0, Inject(ZoomServiceConfig)),
|
|
654
|
+
__param(1, Inject(ZoomOAuthApi)),
|
|
655
|
+
__metadata("design:paramtypes", [ZoomServiceConfig,
|
|
656
|
+
ZoomOAuthApi])
|
|
657
|
+
], ZoomApi);
|
|
622
658
|
class ZoomApiUserContext {
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
659
|
+
constructor(refreshToken) {
|
|
660
|
+
// TODO: ...
|
|
661
|
+
}
|
|
626
662
|
}
|
|
627
663
|
|
|
628
664
|
// MARK: Provider Factories
|
|
629
665
|
function zoomServiceConfigFactory(configService) {
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
666
|
+
const config = {
|
|
667
|
+
zoom: {}
|
|
668
|
+
};
|
|
669
|
+
ZoomServiceConfig.assertValidConfig(config);
|
|
670
|
+
return config;
|
|
635
671
|
}
|
|
636
672
|
/**
|
|
637
673
|
* Convenience function used to generate ModuleMetadata for an app's ZoomModule.
|
|
@@ -641,22 +677,21 @@ function zoomServiceConfigFactory(configService) {
|
|
|
641
677
|
* @returns
|
|
642
678
|
*/
|
|
643
679
|
function appZoomModuleMetadata(config) {
|
|
644
|
-
|
|
645
|
-
dependencyModule
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
}
|
|
659
|
-
};
|
|
680
|
+
const { dependencyModule, imports, exports: exports$1, providers } = config;
|
|
681
|
+
const dependencyModuleImport = dependencyModule ? [dependencyModule] : [];
|
|
682
|
+
return {
|
|
683
|
+
imports: [ConfigModule, ...dependencyModuleImport, ...(imports ?? [])],
|
|
684
|
+
exports: [ZoomApi, ...(exports$1 ?? [])],
|
|
685
|
+
providers: [
|
|
686
|
+
{
|
|
687
|
+
provide: ZoomServiceConfig,
|
|
688
|
+
inject: [ConfigService],
|
|
689
|
+
useFactory: zoomServiceConfigFactory
|
|
690
|
+
},
|
|
691
|
+
ZoomApi,
|
|
692
|
+
...(providers ?? [])
|
|
693
|
+
]
|
|
694
|
+
};
|
|
660
695
|
}
|
|
661
696
|
|
|
662
697
|
export { DEFAULT_FILE_ZOOM_ACCOUNTS_ACCESS_TOKEN_CACHE_SERVICE_PATH, ZOOM_SECRET_TOKEN_ENV_VAR, ZOOM_WEBHOOK_MEETING_ALERT_EVENT_TYPE, ZOOM_WEBHOOK_MEETING_CREATED_EVENT_TYPE, ZOOM_WEBHOOK_MEETING_DELETED_EVENT_TYPE, ZOOM_WEBHOOK_MEETING_ENDED_EVENT_TYPE, ZOOM_WEBHOOK_MEETING_PERMANENTLY_DELETED_EVENT_TYPE, ZOOM_WEBHOOK_MEETING_STARTED_EVENT_TYPE, ZOOM_WEBHOOK_MEETING_UPDATED_EVENT_TYPE, ZOOM_WEBHOOK_URL_VALIDATION_EVENT_TYPE, ZoomApi, ZoomApiUserContext, ZoomOAuthAccessTokenCacheService, ZoomOAuthApi, ZoomOAuthServiceConfig, ZoomServiceConfig, ZoomWebhookController, ZoomWebhookModule, ZoomWebhookService, ZoomWebhookServiceConfig, appZoomModuleMetadata, appZoomOAuthModuleMetadata, fileZoomOAuthAccessTokenCacheService, logMergeZoomOAuthAccessTokenCacheServiceErrorFunction, memoryZoomOAuthAccessTokenCacheService, mergeZoomOAuthAccessTokenCacheServices, readZoomOAuthServiceConfigFromConfigService, zoomEventHandlerConfigurerFactory, zoomEventHandlerFactory, zoomOAuthServiceConfigFactory, zoomServiceConfigFactory, zoomWebhookEvent, zoomWebhookEventValidationFunction, zoomWebhookEventVerifier, zoomWebhookServiceConfigFactory };
|