@workos-inc/node 7.13.0 → 7.15.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.
@@ -21,23 +21,28 @@ var __rest = (this && this.__rest) || function (s, e) {
21
21
  };
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
23
  exports.UserManagement = void 0;
24
- const pagination_1 = require("../common/utils/pagination");
25
- const serializers_1 = require("./serializers");
24
+ const iron_session_1 = require("iron-session");
25
+ const jose_1 = require("jose");
26
+ const oauth_exception_1 = require("../common/exceptions/oauth.exception");
26
27
  const fetch_and_deserialize_1 = require("../common/utils/fetch-and-deserialize");
27
- const serializers_2 = require("../mfa/serializers");
28
- const organization_membership_serializer_1 = require("./serializers/organization-membership.serializer");
29
- const list_organization_memberships_options_serializer_1 = require("./serializers/list-organization-memberships-options.serializer");
28
+ const pagination_1 = require("../common/utils/pagination");
29
+ const serializers_1 = require("../mfa/serializers");
30
+ const authenticate_with_session_cookie_interface_1 = require("./interfaces/authenticate-with-session-cookie.interface");
31
+ const refresh_and_seal_session_data_interface_1 = require("./interfaces/refresh-and-seal-session-data.interface");
32
+ const revoke_session_options_interface_1 = require("./interfaces/revoke-session-options.interface");
33
+ const serializers_2 = require("./serializers");
34
+ const authenticate_with_email_verification_serializer_1 = require("./serializers/authenticate-with-email-verification.serializer");
35
+ const authenticate_with_organization_selection_options_serializer_1 = require("./serializers/authenticate-with-organization-selection-options.serializer");
30
36
  const create_organization_membership_options_serializer_1 = require("./serializers/create-organization-membership-options.serializer");
37
+ const factor_serializer_1 = require("./serializers/factor.serializer");
38
+ const identity_serializer_1 = require("./serializers/identity.serializer");
31
39
  const invitation_serializer_1 = require("./serializers/invitation.serializer");
32
40
  const list_invitations_options_serializer_1 = require("./serializers/list-invitations-options.serializer");
33
- const send_invitation_options_serializer_1 = require("./serializers/send-invitation-options.serializer");
41
+ const list_organization_memberships_options_serializer_1 = require("./serializers/list-organization-memberships-options.serializer");
34
42
  const list_users_options_serializer_1 = require("./serializers/list-users-options.serializer");
35
- const authenticate_with_email_verification_serializer_1 = require("./serializers/authenticate-with-email-verification.serializer");
36
- const authenticate_with_organization_selection_options_serializer_1 = require("./serializers/authenticate-with-organization-selection-options.serializer");
37
- const factor_serializer_1 = require("./serializers/factor.serializer");
38
- const revoke_session_options_interface_1 = require("./interfaces/revoke-session-options.interface");
43
+ const organization_membership_serializer_1 = require("./serializers/organization-membership.serializer");
44
+ const send_invitation_options_serializer_1 = require("./serializers/send-invitation-options.serializer");
39
45
  const update_organization_membership_options_serializer_1 = require("./serializers/update-organization-membership-options.serializer");
40
- const identity_serializer_1 = require("./serializers/identity.serializer");
41
46
  const toQueryString = (options) => {
42
47
  const searchParams = new URLSearchParams();
43
48
  const keys = Object.keys(options).sort();
@@ -52,88 +57,261 @@ const toQueryString = (options) => {
52
57
  class UserManagement {
53
58
  constructor(workos) {
54
59
  this.workos = workos;
60
+ const { clientId } = workos.options;
61
+ // Set the JWKS URL. This is used to verify if the JWT is still valid
62
+ this.jwks = clientId
63
+ ? (0, jose_1.createRemoteJWKSet)(new URL(this.getJwksUrl(clientId)))
64
+ : undefined;
55
65
  }
56
66
  getUser(userId) {
57
67
  return __awaiter(this, void 0, void 0, function* () {
58
68
  const { data } = yield this.workos.get(`/user_management/users/${userId}`);
59
- return (0, serializers_1.deserializeUser)(data);
69
+ return (0, serializers_2.deserializeUser)(data);
60
70
  });
61
71
  }
62
72
  listUsers(options) {
63
73
  return __awaiter(this, void 0, void 0, function* () {
64
- return new pagination_1.AutoPaginatable(yield (0, fetch_and_deserialize_1.fetchAndDeserialize)(this.workos, '/user_management/users', serializers_1.deserializeUser, options ? (0, list_users_options_serializer_1.serializeListUsersOptions)(options) : undefined), (params) => (0, fetch_and_deserialize_1.fetchAndDeserialize)(this.workos, '/user_management/users', serializers_1.deserializeUser, params), options ? (0, list_users_options_serializer_1.serializeListUsersOptions)(options) : undefined);
74
+ return new pagination_1.AutoPaginatable(yield (0, fetch_and_deserialize_1.fetchAndDeserialize)(this.workos, '/user_management/users', serializers_2.deserializeUser, options ? (0, list_users_options_serializer_1.serializeListUsersOptions)(options) : undefined), (params) => (0, fetch_and_deserialize_1.fetchAndDeserialize)(this.workos, '/user_management/users', serializers_2.deserializeUser, params), options ? (0, list_users_options_serializer_1.serializeListUsersOptions)(options) : undefined);
65
75
  });
66
76
  }
67
77
  createUser(payload) {
68
78
  return __awaiter(this, void 0, void 0, function* () {
69
- const { data } = yield this.workos.post('/user_management/users', (0, serializers_1.serializeCreateUserOptions)(payload));
70
- return (0, serializers_1.deserializeUser)(data);
79
+ const { data } = yield this.workos.post('/user_management/users', (0, serializers_2.serializeCreateUserOptions)(payload));
80
+ return (0, serializers_2.deserializeUser)(data);
71
81
  });
72
82
  }
73
83
  authenticateWithMagicAuth(payload) {
74
84
  return __awaiter(this, void 0, void 0, function* () {
75
- const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_1.serializeAuthenticateWithMagicAuthOptions)(Object.assign(Object.assign({}, payload), { clientSecret: this.workos.key })));
76
- return (0, serializers_1.deserializeAuthenticationResponse)(data);
85
+ const { session } = payload, remainingPayload = __rest(payload, ["session"]);
86
+ const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_2.serializeAuthenticateWithMagicAuthOptions)(Object.assign(Object.assign({}, remainingPayload), { clientSecret: this.workos.key })));
87
+ return this.prepareAuthenticationResponse({
88
+ authenticationResponse: (0, serializers_2.deserializeAuthenticationResponse)(data),
89
+ session,
90
+ });
77
91
  });
78
92
  }
79
93
  authenticateWithPassword(payload) {
80
94
  return __awaiter(this, void 0, void 0, function* () {
81
- const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_1.serializeAuthenticateWithPasswordOptions)(Object.assign(Object.assign({}, payload), { clientSecret: this.workos.key })));
82
- return (0, serializers_1.deserializeAuthenticationResponse)(data);
95
+ const { session } = payload, remainingPayload = __rest(payload, ["session"]);
96
+ const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_2.serializeAuthenticateWithPasswordOptions)(Object.assign(Object.assign({}, remainingPayload), { clientSecret: this.workos.key })));
97
+ return this.prepareAuthenticationResponse({
98
+ authenticationResponse: (0, serializers_2.deserializeAuthenticationResponse)(data),
99
+ session,
100
+ });
83
101
  });
84
102
  }
85
103
  authenticateWithCode(payload) {
86
104
  return __awaiter(this, void 0, void 0, function* () {
87
- const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_1.serializeAuthenticateWithCodeOptions)(Object.assign(Object.assign({}, payload), { clientSecret: this.workos.key })));
88
- return (0, serializers_1.deserializeAuthenticationResponse)(data);
105
+ const { session } = payload, remainingPayload = __rest(payload, ["session"]);
106
+ const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_2.serializeAuthenticateWithCodeOptions)(Object.assign(Object.assign({}, remainingPayload), { clientSecret: this.workos.key })));
107
+ return this.prepareAuthenticationResponse({
108
+ authenticationResponse: (0, serializers_2.deserializeAuthenticationResponse)(data),
109
+ session,
110
+ });
89
111
  });
90
112
  }
91
113
  authenticateWithRefreshToken(payload) {
92
114
  return __awaiter(this, void 0, void 0, function* () {
93
- const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_1.serializeAuthenticateWithRefreshTokenOptions)(Object.assign(Object.assign({}, payload), { clientSecret: this.workos.key })));
94
- return (0, serializers_1.deserializeAuthenticationResponse)(data);
115
+ const { session } = payload, remainingPayload = __rest(payload, ["session"]);
116
+ const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_2.serializeAuthenticateWithRefreshTokenOptions)(Object.assign(Object.assign({}, remainingPayload), { clientSecret: this.workos.key })));
117
+ return this.prepareAuthenticationResponse({
118
+ authenticationResponse: (0, serializers_2.deserializeAuthenticationResponse)(data),
119
+ session,
120
+ });
95
121
  });
96
122
  }
97
123
  authenticateWithTotp(payload) {
98
124
  return __awaiter(this, void 0, void 0, function* () {
99
- const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_1.serializeAuthenticateWithTotpOptions)(Object.assign(Object.assign({}, payload), { clientSecret: this.workos.key })));
100
- return (0, serializers_1.deserializeAuthenticationResponse)(data);
125
+ const { session } = payload, remainingPayload = __rest(payload, ["session"]);
126
+ const { data } = yield this.workos.post('/user_management/authenticate', (0, serializers_2.serializeAuthenticateWithTotpOptions)(Object.assign(Object.assign({}, remainingPayload), { clientSecret: this.workos.key })));
127
+ return this.prepareAuthenticationResponse({
128
+ authenticationResponse: (0, serializers_2.deserializeAuthenticationResponse)(data),
129
+ session,
130
+ });
101
131
  });
102
132
  }
103
133
  authenticateWithEmailVerification(payload) {
104
134
  return __awaiter(this, void 0, void 0, function* () {
105
- const { data } = yield this.workos.post('/user_management/authenticate', (0, authenticate_with_email_verification_serializer_1.serializeAuthenticateWithEmailVerificationOptions)(Object.assign(Object.assign({}, payload), { clientSecret: this.workos.key })));
106
- return (0, serializers_1.deserializeAuthenticationResponse)(data);
135
+ const { session } = payload, remainingPayload = __rest(payload, ["session"]);
136
+ const { data } = yield this.workos.post('/user_management/authenticate', (0, authenticate_with_email_verification_serializer_1.serializeAuthenticateWithEmailVerificationOptions)(Object.assign(Object.assign({}, remainingPayload), { clientSecret: this.workos.key })));
137
+ return this.prepareAuthenticationResponse({
138
+ authenticationResponse: (0, serializers_2.deserializeAuthenticationResponse)(data),
139
+ session,
140
+ });
107
141
  });
108
142
  }
109
143
  authenticateWithOrganizationSelection(payload) {
110
144
  return __awaiter(this, void 0, void 0, function* () {
111
- const { data } = yield this.workos.post('/user_management/authenticate', (0, authenticate_with_organization_selection_options_serializer_1.serializeAuthenticateWithOrganizationSelectionOptions)(Object.assign(Object.assign({}, payload), { clientSecret: this.workos.key })));
112
- return (0, serializers_1.deserializeAuthenticationResponse)(data);
145
+ const { session } = payload, remainingPayload = __rest(payload, ["session"]);
146
+ const { data } = yield this.workos.post('/user_management/authenticate', (0, authenticate_with_organization_selection_options_serializer_1.serializeAuthenticateWithOrganizationSelectionOptions)(Object.assign(Object.assign({}, remainingPayload), { clientSecret: this.workos.key })));
147
+ return this.prepareAuthenticationResponse({
148
+ authenticationResponse: (0, serializers_2.deserializeAuthenticationResponse)(data),
149
+ session,
150
+ });
151
+ });
152
+ }
153
+ authenticateWithSessionCookie({ sessionData, cookiePassword = process.env.WORKOS_COOKIE_PASSWORD, }) {
154
+ return __awaiter(this, void 0, void 0, function* () {
155
+ if (!cookiePassword) {
156
+ throw new Error('Cookie password is required');
157
+ }
158
+ if (!this.jwks) {
159
+ throw new Error('Must provide clientId to initialize JWKS');
160
+ }
161
+ if (!sessionData) {
162
+ return {
163
+ authenticated: false,
164
+ reason: authenticate_with_session_cookie_interface_1.AuthenticateWithSessionCookieFailureReason.NO_SESSION_COOKIE_PROVIDED,
165
+ };
166
+ }
167
+ const session = yield (0, iron_session_1.unsealData)(sessionData, {
168
+ password: cookiePassword,
169
+ });
170
+ if (!session.accessToken) {
171
+ return {
172
+ authenticated: false,
173
+ reason: authenticate_with_session_cookie_interface_1.AuthenticateWithSessionCookieFailureReason.INVALID_SESSION_COOKIE,
174
+ };
175
+ }
176
+ if (!(yield this.isValidJwt(session.accessToken))) {
177
+ return {
178
+ authenticated: false,
179
+ reason: authenticate_with_session_cookie_interface_1.AuthenticateWithSessionCookieFailureReason.INVALID_JWT,
180
+ };
181
+ }
182
+ const { sid: sessionId, org_id: organizationId, role, permissions, } = (0, jose_1.decodeJwt)(session.accessToken);
183
+ return {
184
+ authenticated: true,
185
+ sessionId,
186
+ organizationId,
187
+ role,
188
+ permissions,
189
+ };
190
+ });
191
+ }
192
+ isValidJwt(accessToken) {
193
+ return __awaiter(this, void 0, void 0, function* () {
194
+ if (!this.jwks) {
195
+ throw new Error('Must provide clientId to initialize JWKS');
196
+ }
197
+ try {
198
+ yield (0, jose_1.jwtVerify)(accessToken, this.jwks);
199
+ return true;
200
+ }
201
+ catch (e) {
202
+ return false;
203
+ }
204
+ });
205
+ }
206
+ refreshAndSealSessionData({ sessionData, cookiePassword = process.env.WORKOS_COOKIE_PASSWORD, }) {
207
+ return __awaiter(this, void 0, void 0, function* () {
208
+ if (!cookiePassword) {
209
+ throw new Error('Cookie password is required');
210
+ }
211
+ if (!sessionData) {
212
+ return {
213
+ authenticated: false,
214
+ reason: refresh_and_seal_session_data_interface_1.RefreshAndSealSessionDataFailureReason.NO_SESSION_COOKIE_PROVIDED,
215
+ };
216
+ }
217
+ const session = yield (0, iron_session_1.unsealData)(sessionData, {
218
+ password: cookiePassword,
219
+ });
220
+ if (!session.refreshToken || !session.user) {
221
+ return {
222
+ authenticated: false,
223
+ reason: refresh_and_seal_session_data_interface_1.RefreshAndSealSessionDataFailureReason.INVALID_SESSION_COOKE,
224
+ };
225
+ }
226
+ try {
227
+ const { sealedSession } = yield this.authenticateWithRefreshToken({
228
+ clientId: this.workos.clientId,
229
+ refreshToken: session.refreshToken,
230
+ session: { sealSession: true, cookiePassword },
231
+ });
232
+ if (!sealedSession) {
233
+ return {
234
+ authenticated: false,
235
+ reason: refresh_and_seal_session_data_interface_1.RefreshAndSealSessionDataFailureReason.INVALID_SESSION_COOKE,
236
+ };
237
+ }
238
+ return { authenticated: true, sealedSession };
239
+ }
240
+ catch (error) {
241
+ if (error instanceof oauth_exception_1.OauthException &&
242
+ // TODO: Add additional known errors and remove re-throw
243
+ (error.error === refresh_and_seal_session_data_interface_1.RefreshAndSealSessionDataFailureReason.INVALID_GRANT ||
244
+ error.error ===
245
+ refresh_and_seal_session_data_interface_1.RefreshAndSealSessionDataFailureReason.ORGANIZATION_NOT_AUTHORIZED)) {
246
+ return {
247
+ authenticated: false,
248
+ reason: error.error,
249
+ };
250
+ }
251
+ throw error;
252
+ }
253
+ });
254
+ }
255
+ prepareAuthenticationResponse({ authenticationResponse, session, }) {
256
+ return __awaiter(this, void 0, void 0, function* () {
257
+ if (session) {
258
+ return Object.assign(Object.assign({}, authenticationResponse), { sealedSession: yield this.sealSessionDataFromAuthenticationResponse({
259
+ authenticationResponse,
260
+ cookiePassword: session.cookiePassword,
261
+ }) });
262
+ }
263
+ return authenticationResponse;
264
+ });
265
+ }
266
+ sealSessionDataFromAuthenticationResponse({ authenticationResponse, cookiePassword, }) {
267
+ return __awaiter(this, void 0, void 0, function* () {
268
+ if (!cookiePassword) {
269
+ throw new Error('Cookie password is required');
270
+ }
271
+ const sessionData = {
272
+ user: authenticationResponse.user,
273
+ accessToken: authenticationResponse.accessToken,
274
+ refreshToken: authenticationResponse.refreshToken,
275
+ impersonator: authenticationResponse.impersonator,
276
+ };
277
+ return (0, iron_session_1.sealData)(sessionData, { password: cookiePassword });
278
+ });
279
+ }
280
+ getSessionFromCookie({ sessionData, cookiePassword = process.env.WORKOS_COOKIE_PASSWORD, }) {
281
+ return __awaiter(this, void 0, void 0, function* () {
282
+ if (!cookiePassword) {
283
+ throw new Error('Cookie password is required');
284
+ }
285
+ if (sessionData) {
286
+ return (0, iron_session_1.unsealData)(sessionData, {
287
+ password: cookiePassword,
288
+ });
289
+ }
290
+ return undefined;
113
291
  });
114
292
  }
115
293
  getEmailVerification(emailVerificationId) {
116
294
  return __awaiter(this, void 0, void 0, function* () {
117
295
  const { data } = yield this.workos.get(`/user_management/email_verification/${emailVerificationId}`);
118
- return (0, serializers_1.deserializeEmailVerification)(data);
296
+ return (0, serializers_2.deserializeEmailVerification)(data);
119
297
  });
120
298
  }
121
299
  sendVerificationEmail({ userId, }) {
122
300
  return __awaiter(this, void 0, void 0, function* () {
123
301
  const { data } = yield this.workos.post(`/user_management/users/${userId}/email_verification/send`, {});
124
- return { user: (0, serializers_1.deserializeUser)(data.user) };
302
+ return { user: (0, serializers_2.deserializeUser)(data.user) };
125
303
  });
126
304
  }
127
305
  getMagicAuth(magicAuthId) {
128
306
  return __awaiter(this, void 0, void 0, function* () {
129
307
  const { data } = yield this.workos.get(`/user_management/magic_auth/${magicAuthId}`);
130
- return (0, serializers_1.deserializeMagicAuth)(data);
308
+ return (0, serializers_2.deserializeMagicAuth)(data);
131
309
  });
132
310
  }
133
311
  createMagicAuth(options) {
134
312
  return __awaiter(this, void 0, void 0, function* () {
135
- const { data } = yield this.workos.post('/user_management/magic_auth', (0, serializers_1.serializeCreateMagicAuthOptions)(Object.assign({}, options)));
136
- return (0, serializers_1.deserializeMagicAuth)(data);
313
+ const { data } = yield this.workos.post('/user_management/magic_auth', (0, serializers_2.serializeCreateMagicAuthOptions)(Object.assign({}, options)));
314
+ return (0, serializers_2.deserializeMagicAuth)(data);
137
315
  });
138
316
  }
139
317
  /**
@@ -141,7 +319,7 @@ class UserManagement {
141
319
  */
142
320
  sendMagicAuthCode(options) {
143
321
  return __awaiter(this, void 0, void 0, function* () {
144
- yield this.workos.post('/user_management/magic_auth/send', (0, serializers_1.serializeSendMagicAuthCodeOptions)(options));
322
+ yield this.workos.post('/user_management/magic_auth/send', (0, serializers_2.serializeSendMagicAuthCodeOptions)(options));
145
323
  });
146
324
  }
147
325
  verifyEmail({ code, userId, }) {
@@ -149,19 +327,19 @@ class UserManagement {
149
327
  const { data } = yield this.workos.post(`/user_management/users/${userId}/email_verification/confirm`, {
150
328
  code,
151
329
  });
152
- return { user: (0, serializers_1.deserializeUser)(data.user) };
330
+ return { user: (0, serializers_2.deserializeUser)(data.user) };
153
331
  });
154
332
  }
155
333
  getPasswordReset(passwordResetId) {
156
334
  return __awaiter(this, void 0, void 0, function* () {
157
335
  const { data } = yield this.workos.get(`/user_management/password_reset/${passwordResetId}`);
158
- return (0, serializers_1.deserializePasswordReset)(data);
336
+ return (0, serializers_2.deserializePasswordReset)(data);
159
337
  });
160
338
  }
161
339
  createPasswordReset(options) {
162
340
  return __awaiter(this, void 0, void 0, function* () {
163
- const { data } = yield this.workos.post('/user_management/password_reset', (0, serializers_1.serializeCreatePasswordResetOptions)(Object.assign({}, options)));
164
- return (0, serializers_1.deserializePasswordReset)(data);
341
+ const { data } = yield this.workos.post('/user_management/password_reset', (0, serializers_2.serializeCreatePasswordResetOptions)(Object.assign({}, options)));
342
+ return (0, serializers_2.deserializePasswordReset)(data);
165
343
  });
166
344
  }
167
345
  /**
@@ -169,27 +347,27 @@ class UserManagement {
169
347
  */
170
348
  sendPasswordResetEmail(payload) {
171
349
  return __awaiter(this, void 0, void 0, function* () {
172
- yield this.workos.post('/user_management/password_reset/send', (0, serializers_1.serializeSendPasswordResetEmailOptions)(payload));
350
+ yield this.workos.post('/user_management/password_reset/send', (0, serializers_2.serializeSendPasswordResetEmailOptions)(payload));
173
351
  });
174
352
  }
175
353
  resetPassword(payload) {
176
354
  return __awaiter(this, void 0, void 0, function* () {
177
- const { data } = yield this.workos.post('/user_management/password_reset/confirm', (0, serializers_1.serializeResetPasswordOptions)(payload));
178
- return { user: (0, serializers_1.deserializeUser)(data.user) };
355
+ const { data } = yield this.workos.post('/user_management/password_reset/confirm', (0, serializers_2.serializeResetPasswordOptions)(payload));
356
+ return { user: (0, serializers_2.deserializeUser)(data.user) };
179
357
  });
180
358
  }
181
359
  updateUser(payload) {
182
360
  return __awaiter(this, void 0, void 0, function* () {
183
- const { data } = yield this.workos.put(`/user_management/users/${payload.userId}`, (0, serializers_1.serializeUpdateUserOptions)(payload));
184
- return (0, serializers_1.deserializeUser)(data);
361
+ const { data } = yield this.workos.put(`/user_management/users/${payload.userId}`, (0, serializers_2.serializeUpdateUserOptions)(payload));
362
+ return (0, serializers_2.deserializeUser)(data);
185
363
  });
186
364
  }
187
365
  enrollAuthFactor(payload) {
188
366
  return __awaiter(this, void 0, void 0, function* () {
189
- const { data } = yield this.workos.post(`/user_management/users/${payload.userId}/auth_factors`, (0, serializers_1.serializeEnrollAuthFactorOptions)(payload));
367
+ const { data } = yield this.workos.post(`/user_management/users/${payload.userId}/auth_factors`, (0, serializers_2.serializeEnrollAuthFactorOptions)(payload));
190
368
  return {
191
- authenticationFactor: (0, serializers_1.deserializeFactorWithSecrets)(data.authentication_factor),
192
- authenticationChallenge: (0, serializers_2.deserializeChallenge)(data.authentication_challenge),
369
+ authenticationFactor: (0, serializers_2.deserializeFactorWithSecrets)(data.authentication_factor),
370
+ authenticationChallenge: (0, serializers_1.deserializeChallenge)(data.authentication_challenge),
193
371
  };
194
372
  });
195
373
  }