@workos-inc/node 2.6.0 → 2.6.1
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/README.md +1 -1
- package/lib/common/exceptions/unprocessable-entity.exception.d.ts +8 -2
- package/lib/common/exceptions/unprocessable-entity.exception.js +15 -6
- package/lib/mfa/interfaces/verify-factor-response.d.ts +1 -6
- package/lib/mfa/mfa.spec.js +93 -0
- package/lib/workos.js +29 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# WorkOS Node.js Library
|
|
2
2
|
|
|
3
3
|

|
|
4
|
-
[](https://workos.semaphoreci.com/projects/workos-node)
|
|
5
5
|
|
|
6
6
|
The WorkOS library for Node.js provides convenient access to the WorkOS API from applications written in server-side JavaScript.
|
|
7
7
|
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { UnprocessableEntityError } from '../interfaces';
|
|
2
2
|
export declare class UnprocessableEntityException extends Error {
|
|
3
|
-
readonly requestID: string;
|
|
4
3
|
readonly status: number;
|
|
5
4
|
readonly name: string;
|
|
6
5
|
readonly message: string;
|
|
7
|
-
|
|
6
|
+
readonly code?: string;
|
|
7
|
+
readonly requestID: string;
|
|
8
|
+
constructor({ code, errors, message, requestID, }: {
|
|
9
|
+
code?: string;
|
|
10
|
+
errors?: UnprocessableEntityError[];
|
|
11
|
+
message?: string;
|
|
12
|
+
requestID: string;
|
|
13
|
+
});
|
|
8
14
|
}
|
|
@@ -6,15 +6,24 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.UnprocessableEntityException = void 0;
|
|
7
7
|
const pluralize_1 = __importDefault(require("pluralize"));
|
|
8
8
|
class UnprocessableEntityException extends Error {
|
|
9
|
-
constructor(errors, requestID) {
|
|
9
|
+
constructor({ code, errors, message, requestID, }) {
|
|
10
10
|
super();
|
|
11
|
-
this.requestID = requestID;
|
|
12
11
|
this.status = 422;
|
|
13
12
|
this.name = 'UnprocessableEntityException';
|
|
14
|
-
|
|
15
|
-
this.
|
|
16
|
-
|
|
17
|
-
this.message =
|
|
13
|
+
this.message = 'Unprocessable entity';
|
|
14
|
+
this.requestID = requestID;
|
|
15
|
+
if (message) {
|
|
16
|
+
this.message = message;
|
|
17
|
+
}
|
|
18
|
+
if (code) {
|
|
19
|
+
this.code = code;
|
|
20
|
+
}
|
|
21
|
+
if (errors) {
|
|
22
|
+
const requirement = (0, pluralize_1.default)('requirement', errors.length);
|
|
23
|
+
this.message = `The following ${requirement} must be met:\n`;
|
|
24
|
+
for (const { code } of errors) {
|
|
25
|
+
this.message = this.message.concat(`\t${code}\n`);
|
|
26
|
+
}
|
|
18
27
|
}
|
|
19
28
|
}
|
|
20
29
|
}
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { Challenge } from './challenge.interface';
|
|
2
|
-
export interface
|
|
2
|
+
export interface VerifyResponse {
|
|
3
3
|
challenge: Challenge;
|
|
4
4
|
valid: boolean;
|
|
5
5
|
}
|
|
6
|
-
export interface VerifyResponseError {
|
|
7
|
-
code: string;
|
|
8
|
-
message: string;
|
|
9
|
-
}
|
|
10
|
-
export declare type VerifyResponse = VerifyResponseSuccess | VerifyResponseError;
|
package/lib/mfa/mfa.spec.js
CHANGED
|
@@ -14,6 +14,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
const axios_1 = __importDefault(require("axios"));
|
|
16
16
|
const axios_mock_adapter_1 = __importDefault(require("axios-mock-adapter"));
|
|
17
|
+
const exceptions_1 = require("../common/exceptions");
|
|
17
18
|
const workos_1 = require("../workos");
|
|
18
19
|
describe('MFA', () => {
|
|
19
20
|
describe('getFactor', () => {
|
|
@@ -132,6 +133,24 @@ describe('MFA', () => {
|
|
|
132
133
|
}
|
|
133
134
|
`);
|
|
134
135
|
}));
|
|
136
|
+
describe('when phone number is invalid', () => {
|
|
137
|
+
it('throws an exception', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
138
|
+
const mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
139
|
+
mock.onPost('/auth/factors/enroll').reply(422, {
|
|
140
|
+
message: `Phone number is invalid: 'foo'`,
|
|
141
|
+
code: 'invalid_phone_number',
|
|
142
|
+
}, {
|
|
143
|
+
'X-Request-ID': 'req_123',
|
|
144
|
+
});
|
|
145
|
+
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU', {
|
|
146
|
+
apiHostname: 'api.workos.dev',
|
|
147
|
+
});
|
|
148
|
+
yield expect(workos.mfa.enrollFactor({
|
|
149
|
+
type: 'sms',
|
|
150
|
+
phoneNumber: 'foo',
|
|
151
|
+
})).rejects.toThrow(exceptions_1.UnprocessableEntityException);
|
|
152
|
+
}));
|
|
153
|
+
});
|
|
135
154
|
});
|
|
136
155
|
});
|
|
137
156
|
describe('challengeFactor', () => {
|
|
@@ -252,5 +271,79 @@ describe('MFA', () => {
|
|
|
252
271
|
`);
|
|
253
272
|
}));
|
|
254
273
|
});
|
|
274
|
+
describe('when the challenge has been previously verified', () => {
|
|
275
|
+
it('throws an exception', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
276
|
+
const mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
277
|
+
mock
|
|
278
|
+
.onPost('/auth/factors/verify', {
|
|
279
|
+
authentication_challenge_id: 'auth_challenge_1234',
|
|
280
|
+
code: '12345',
|
|
281
|
+
})
|
|
282
|
+
.reply(422, {
|
|
283
|
+
message: `The authentication challenge '12345' has already been verified.`,
|
|
284
|
+
code: 'authentication_challenge_previously_verified',
|
|
285
|
+
}, {
|
|
286
|
+
'X-Request-ID': 'req_123',
|
|
287
|
+
});
|
|
288
|
+
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU', {
|
|
289
|
+
apiHostname: 'api.workos.dev',
|
|
290
|
+
});
|
|
291
|
+
yield expect(workos.mfa.verifyFactor({
|
|
292
|
+
authenticationChallengeId: 'auth_challenge_1234',
|
|
293
|
+
code: '12345',
|
|
294
|
+
})).rejects.toThrow(exceptions_1.UnprocessableEntityException);
|
|
295
|
+
}));
|
|
296
|
+
});
|
|
297
|
+
describe('when the challenge has expired', () => {
|
|
298
|
+
it('throws an exception', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
299
|
+
const mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
300
|
+
mock
|
|
301
|
+
.onPost('/auth/factors/verify', {
|
|
302
|
+
authentication_challenge_id: 'auth_challenge_1234',
|
|
303
|
+
code: '12345',
|
|
304
|
+
})
|
|
305
|
+
.reply(422, {
|
|
306
|
+
message: `The authentication challenge '12345' has expired.`,
|
|
307
|
+
code: 'authentication_challenge_expired',
|
|
308
|
+
}, {
|
|
309
|
+
'X-Request-ID': 'req_123',
|
|
310
|
+
});
|
|
311
|
+
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU', {
|
|
312
|
+
apiHostname: 'api.workos.dev',
|
|
313
|
+
});
|
|
314
|
+
yield expect(workos.mfa.verifyFactor({
|
|
315
|
+
authenticationChallengeId: 'auth_challenge_1234',
|
|
316
|
+
code: '12345',
|
|
317
|
+
})).rejects.toThrow(exceptions_1.UnprocessableEntityException);
|
|
318
|
+
}));
|
|
319
|
+
it('exception has code', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
320
|
+
const mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
321
|
+
mock
|
|
322
|
+
.onPost('/auth/factors/verify', {
|
|
323
|
+
authentication_challenge_id: 'auth_challenge_1234',
|
|
324
|
+
code: '12345',
|
|
325
|
+
})
|
|
326
|
+
.reply(422, {
|
|
327
|
+
message: `The authentication challenge '12345' has expired.`,
|
|
328
|
+
code: 'authentication_challenge_expired',
|
|
329
|
+
}, {
|
|
330
|
+
'X-Request-ID': 'req_123',
|
|
331
|
+
});
|
|
332
|
+
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU', {
|
|
333
|
+
apiHostname: 'api.workos.dev',
|
|
334
|
+
});
|
|
335
|
+
try {
|
|
336
|
+
yield workos.mfa.verifyFactor({
|
|
337
|
+
authenticationChallengeId: 'auth_challenge_1234',
|
|
338
|
+
code: '12345',
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
catch (error) {
|
|
342
|
+
expect(error).toMatchObject({
|
|
343
|
+
code: 'authentication_challenge_expired',
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}));
|
|
347
|
+
});
|
|
255
348
|
});
|
|
256
349
|
});
|
package/lib/workos.js
CHANGED
|
@@ -23,7 +23,7 @@ const portal_1 = require("./portal/portal");
|
|
|
23
23
|
const sso_1 = require("./sso/sso");
|
|
24
24
|
const webhooks_1 = require("./webhooks/webhooks");
|
|
25
25
|
const mfa_1 = require("./mfa/mfa");
|
|
26
|
-
const VERSION = '2.6.
|
|
26
|
+
const VERSION = '2.6.1';
|
|
27
27
|
const DEFAULT_HOSTNAME = 'api.workos.com';
|
|
28
28
|
class WorkOS {
|
|
29
29
|
constructor(key, options = {}) {
|
|
@@ -78,14 +78,19 @@ class WorkOS {
|
|
|
78
78
|
if (response) {
|
|
79
79
|
const { status, data, headers } = response;
|
|
80
80
|
const requestID = headers['X-Request-ID'];
|
|
81
|
-
const {
|
|
81
|
+
const { code, error_description: errorDescription, error, message, } = data;
|
|
82
82
|
switch (status) {
|
|
83
83
|
case 401: {
|
|
84
84
|
throw new exceptions_1.UnauthorizedException(requestID);
|
|
85
85
|
}
|
|
86
86
|
case 422: {
|
|
87
87
|
const { errors } = data;
|
|
88
|
-
throw new exceptions_1.UnprocessableEntityException(
|
|
88
|
+
throw new exceptions_1.UnprocessableEntityException({
|
|
89
|
+
code,
|
|
90
|
+
errors,
|
|
91
|
+
message,
|
|
92
|
+
requestID,
|
|
93
|
+
});
|
|
89
94
|
}
|
|
90
95
|
case 404: {
|
|
91
96
|
throw new exceptions_1.NotFoundException(path, requestID);
|
|
@@ -122,14 +127,19 @@ class WorkOS {
|
|
|
122
127
|
if (response) {
|
|
123
128
|
const { status, data, headers } = response;
|
|
124
129
|
const requestID = headers['X-Request-ID'];
|
|
125
|
-
const {
|
|
130
|
+
const { code, error_description: errorDescription, error, message, } = data;
|
|
126
131
|
switch (status) {
|
|
127
132
|
case 401: {
|
|
128
133
|
throw new exceptions_1.UnauthorizedException(requestID);
|
|
129
134
|
}
|
|
130
135
|
case 422: {
|
|
131
136
|
const { errors } = data;
|
|
132
|
-
throw new exceptions_1.UnprocessableEntityException(
|
|
137
|
+
throw new exceptions_1.UnprocessableEntityException({
|
|
138
|
+
code,
|
|
139
|
+
errors,
|
|
140
|
+
message,
|
|
141
|
+
requestID,
|
|
142
|
+
});
|
|
133
143
|
}
|
|
134
144
|
case 404: {
|
|
135
145
|
throw new exceptions_1.NotFoundException(path, requestID);
|
|
@@ -165,14 +175,19 @@ class WorkOS {
|
|
|
165
175
|
if (response) {
|
|
166
176
|
const { status, data, headers } = response;
|
|
167
177
|
const requestID = headers['X-Request-ID'];
|
|
168
|
-
const {
|
|
178
|
+
const { code, error_description: errorDescription, error, message, } = data;
|
|
169
179
|
switch (status) {
|
|
170
180
|
case 401: {
|
|
171
181
|
throw new exceptions_1.UnauthorizedException(requestID);
|
|
172
182
|
}
|
|
173
183
|
case 422: {
|
|
174
184
|
const { errors } = data;
|
|
175
|
-
throw new exceptions_1.UnprocessableEntityException(
|
|
185
|
+
throw new exceptions_1.UnprocessableEntityException({
|
|
186
|
+
code,
|
|
187
|
+
errors,
|
|
188
|
+
message,
|
|
189
|
+
requestID,
|
|
190
|
+
});
|
|
176
191
|
}
|
|
177
192
|
case 404: {
|
|
178
193
|
throw new exceptions_1.NotFoundException(path, requestID);
|
|
@@ -203,14 +218,19 @@ class WorkOS {
|
|
|
203
218
|
if (response) {
|
|
204
219
|
const { status, data, headers } = response;
|
|
205
220
|
const requestID = headers['X-Request-ID'];
|
|
206
|
-
const {
|
|
221
|
+
const { code, error_description: errorDescription, error, message, } = data;
|
|
207
222
|
switch (status) {
|
|
208
223
|
case 401: {
|
|
209
224
|
throw new exceptions_1.UnauthorizedException(requestID);
|
|
210
225
|
}
|
|
211
226
|
case 422: {
|
|
212
227
|
const { errors } = data;
|
|
213
|
-
throw new exceptions_1.UnprocessableEntityException(
|
|
228
|
+
throw new exceptions_1.UnprocessableEntityException({
|
|
229
|
+
code,
|
|
230
|
+
errors,
|
|
231
|
+
message,
|
|
232
|
+
requestID,
|
|
233
|
+
});
|
|
214
234
|
}
|
|
215
235
|
case 404: {
|
|
216
236
|
throw new exceptions_1.NotFoundException(path, requestID);
|
package/package.json
CHANGED