@workos-inc/node 2.7.0 → 2.9.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/lib/audit-logs/audit-logs.d.ts +7 -0
- package/lib/audit-logs/audit-logs.js +26 -0
- package/lib/audit-logs/audit-logs.spec.d.ts +1 -0
- package/lib/audit-logs/audit-logs.spec.js +110 -0
- package/lib/audit-logs/interfaces/create-audit-log-event-options.interface.d.ts +26 -0
- package/lib/{mfa/interfaces/verify-factor-response.js → audit-logs/interfaces/create-audit-log-event-options.interface.js} +0 -0
- package/lib/audit-logs/interfaces/index.d.ts +1 -0
- package/lib/audit-logs/interfaces/index.js +2 -0
- package/lib/common/exceptions/bad-request.exception.d.ts +14 -0
- package/lib/common/exceptions/bad-request.exception.js +22 -0
- package/lib/common/exceptions/not-found.exception.d.ts +8 -2
- package/lib/common/exceptions/not-found.exception.js +5 -3
- package/lib/directory-sync/directory-sync.spec.js +2 -0
- package/lib/directory-sync/interfaces/group.interface.d.ts +1 -0
- package/lib/directory-sync/interfaces/user.interface.d.ts +1 -0
- package/lib/mfa/interfaces/verify-challenge-options.d.ts +4 -0
- package/lib/mfa/interfaces/verify-challenge-options.js +2 -0
- package/lib/mfa/interfaces/{verify-factor-response.d.ts → verify-challenge-response.d.ts} +0 -0
- package/lib/mfa/interfaces/verify-challenge-response.js +2 -0
- package/lib/mfa/interfaces/verify-factor-options.d.ts +3 -0
- package/lib/mfa/mfa.d.ts +6 -1
- package/lib/mfa/mfa.js +10 -4
- package/lib/mfa/mfa.spec.js +11 -20
- package/lib/webhooks/interfaces/webhook-directory-group.interface.d.ts +1 -0
- package/lib/workos.d.ts +3 -0
- package/lib/workos.js +56 -125
- package/lib/workos.spec.js +34 -2
- package/package.json +6 -6
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { WorkOS } from '../workos';
|
|
2
|
+
import { CreateAuditLogEventOptions, CreateAuditLogEventRequestOptions } from './interfaces';
|
|
3
|
+
export declare class AuditLogs {
|
|
4
|
+
private readonly workos;
|
|
5
|
+
constructor(workos: WorkOS);
|
|
6
|
+
createEvent(organization: string, event: CreateAuditLogEventOptions, options?: CreateAuditLogEventRequestOptions): Promise<void>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AuditLogs = void 0;
|
|
13
|
+
class AuditLogs {
|
|
14
|
+
constructor(workos) {
|
|
15
|
+
this.workos = workos;
|
|
16
|
+
}
|
|
17
|
+
createEvent(organization, event, options = {}) {
|
|
18
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
yield this.workos.post('/audit_logs/events', {
|
|
20
|
+
event,
|
|
21
|
+
organization_id: organization,
|
|
22
|
+
}, options);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.AuditLogs = AuditLogs;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const axios_1 = __importDefault(require("axios"));
|
|
16
|
+
const axios_mock_adapter_1 = __importDefault(require("axios-mock-adapter"));
|
|
17
|
+
const exceptions_1 = require("../common/exceptions");
|
|
18
|
+
const bad_request_exception_1 = require("../common/exceptions/bad-request.exception");
|
|
19
|
+
const workos_1 = require("../workos");
|
|
20
|
+
const mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
21
|
+
const event = {
|
|
22
|
+
action: 'document.updated',
|
|
23
|
+
occurred_at: new Date(),
|
|
24
|
+
actor: {
|
|
25
|
+
id: 'user_1',
|
|
26
|
+
name: 'Jon Smith',
|
|
27
|
+
type: 'user',
|
|
28
|
+
},
|
|
29
|
+
targets: [
|
|
30
|
+
{
|
|
31
|
+
id: 'document_39127',
|
|
32
|
+
type: 'document',
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
context: {
|
|
36
|
+
location: ' 192.0.0.8',
|
|
37
|
+
user_agent: 'Firefox',
|
|
38
|
+
},
|
|
39
|
+
metadata: {
|
|
40
|
+
successful: true,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
const serializeEventOptions = (options) => (Object.assign(Object.assign({}, options), { occurred_at: options.occurred_at.toISOString() }));
|
|
44
|
+
describe('AuditLogs', () => {
|
|
45
|
+
describe('createEvent', () => {
|
|
46
|
+
describe('with an idempotency key', () => {
|
|
47
|
+
it('includes an idempotency key with request', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
48
|
+
mock
|
|
49
|
+
.onPost('/audit_logs/events', {
|
|
50
|
+
event: serializeEventOptions(event),
|
|
51
|
+
organization_id: 'org_123',
|
|
52
|
+
})
|
|
53
|
+
.replyOnce(201, { success: true });
|
|
54
|
+
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
|
|
55
|
+
yield expect(workos.auditLogs.createEvent('org_123', event, {
|
|
56
|
+
idempotencyKey: 'the-idempotency-key',
|
|
57
|
+
})).resolves.toBeUndefined();
|
|
58
|
+
expect(mock.history.post[0].headers['Idempotency-Key']).toEqual('the-idempotency-key');
|
|
59
|
+
}));
|
|
60
|
+
});
|
|
61
|
+
describe('when the api responds with a 200', () => {
|
|
62
|
+
it('returns void', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
63
|
+
mock
|
|
64
|
+
.onPost('/audit_logs/events', {
|
|
65
|
+
organization_id: 'org_123',
|
|
66
|
+
event: serializeEventOptions(event),
|
|
67
|
+
})
|
|
68
|
+
.replyOnce(201, { success: true });
|
|
69
|
+
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
|
|
70
|
+
yield expect(workos.auditLogs.createEvent('org_123', event)).resolves.toBeUndefined();
|
|
71
|
+
}));
|
|
72
|
+
});
|
|
73
|
+
describe('when the api responds with a 401', () => {
|
|
74
|
+
it('throws an UnauthorizedException', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
75
|
+
mock
|
|
76
|
+
.onPost('/audit_logs/events', {
|
|
77
|
+
organization_id: 'org_123',
|
|
78
|
+
event: serializeEventOptions(event),
|
|
79
|
+
})
|
|
80
|
+
.replyOnce(401, {
|
|
81
|
+
message: 'Unauthorized',
|
|
82
|
+
}, { 'X-Request-ID': 'a-request-id' });
|
|
83
|
+
const workos = new workos_1.WorkOS('invalid apikey');
|
|
84
|
+
yield expect(workos.auditLogs.createEvent('org_123', event)).rejects.toStrictEqual(new exceptions_1.UnauthorizedException('a-request-id'));
|
|
85
|
+
}));
|
|
86
|
+
});
|
|
87
|
+
describe('when the api responds with a 400', () => {
|
|
88
|
+
it('throws an BadRequestException', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
89
|
+
const errors = [
|
|
90
|
+
{
|
|
91
|
+
field: 'occurred_at',
|
|
92
|
+
code: 'occurred_at must be an ISO 8601 date string',
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
mock
|
|
96
|
+
.onPost('/audit_logs/events', {
|
|
97
|
+
organization_id: 'org_123',
|
|
98
|
+
event: serializeEventOptions(event),
|
|
99
|
+
})
|
|
100
|
+
.replyOnce(400, {
|
|
101
|
+
message: 'Audit Log could not be processed due to missing or incorrect data.',
|
|
102
|
+
code: 'invalid_audit_log',
|
|
103
|
+
errors,
|
|
104
|
+
}, { 'X-Request-ID': 'a-request-id' });
|
|
105
|
+
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
|
|
106
|
+
yield expect(workos.auditLogs.createEvent('org_123', event)).rejects.toThrow(bad_request_exception_1.BadRequestException);
|
|
107
|
+
}));
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { PostOptions } from '../../common/interfaces';
|
|
2
|
+
export interface AuditLogActor {
|
|
3
|
+
id: string;
|
|
4
|
+
name?: string;
|
|
5
|
+
type: string;
|
|
6
|
+
metadata?: Record<string, string | number | boolean>;
|
|
7
|
+
}
|
|
8
|
+
export interface AuditLogTarget {
|
|
9
|
+
id: string;
|
|
10
|
+
name?: string;
|
|
11
|
+
type: string;
|
|
12
|
+
metadata?: Record<string, string | number | boolean>;
|
|
13
|
+
}
|
|
14
|
+
export interface CreateAuditLogEventOptions {
|
|
15
|
+
action: string;
|
|
16
|
+
version?: number;
|
|
17
|
+
occurred_at: Date;
|
|
18
|
+
actor: AuditLogActor;
|
|
19
|
+
targets: AuditLogTarget[];
|
|
20
|
+
context: {
|
|
21
|
+
location: string;
|
|
22
|
+
user_agent?: string;
|
|
23
|
+
};
|
|
24
|
+
metadata?: Record<string, string | number | boolean>;
|
|
25
|
+
}
|
|
26
|
+
export declare type CreateAuditLogEventRequestOptions = Pick<PostOptions, 'idempotencyKey'>;
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CreateAuditLogEventOptions, CreateAuditLogEventRequestOptions, } from './create-audit-log-event-options.interface';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare class BadRequestException extends Error {
|
|
2
|
+
readonly status: number;
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly message: string;
|
|
5
|
+
readonly code?: string;
|
|
6
|
+
readonly errors?: unknown[];
|
|
7
|
+
readonly requestID: string;
|
|
8
|
+
constructor({ code, errors, message, requestID, }: {
|
|
9
|
+
code?: string;
|
|
10
|
+
errors?: unknown[];
|
|
11
|
+
message?: string;
|
|
12
|
+
requestID: string;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BadRequestException = void 0;
|
|
4
|
+
class BadRequestException extends Error {
|
|
5
|
+
constructor({ code, errors, message, requestID, }) {
|
|
6
|
+
super();
|
|
7
|
+
this.status = 400;
|
|
8
|
+
this.name = 'BadRequestException';
|
|
9
|
+
this.message = 'Bad request';
|
|
10
|
+
this.requestID = requestID;
|
|
11
|
+
if (message) {
|
|
12
|
+
this.message = message;
|
|
13
|
+
}
|
|
14
|
+
if (code) {
|
|
15
|
+
this.code = code;
|
|
16
|
+
}
|
|
17
|
+
if (errors) {
|
|
18
|
+
this.errors = errors;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.BadRequestException = BadRequestException;
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
export declare class NotFoundException extends Error {
|
|
2
|
-
readonly requestID: string;
|
|
3
2
|
readonly status: number;
|
|
4
3
|
readonly name: string;
|
|
5
4
|
readonly message: string;
|
|
6
|
-
|
|
5
|
+
readonly code?: string;
|
|
6
|
+
readonly requestID: string;
|
|
7
|
+
constructor({ code, message, path, requestID, }: {
|
|
8
|
+
code?: string;
|
|
9
|
+
message?: string;
|
|
10
|
+
path: string;
|
|
11
|
+
requestID: string;
|
|
12
|
+
});
|
|
7
13
|
}
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NotFoundException = void 0;
|
|
4
4
|
class NotFoundException extends Error {
|
|
5
|
-
constructor(path, requestID) {
|
|
5
|
+
constructor({ code, message, path, requestID, }) {
|
|
6
6
|
super();
|
|
7
|
-
this.requestID = requestID;
|
|
8
7
|
this.status = 404;
|
|
9
8
|
this.name = 'NotFoundException';
|
|
10
|
-
this.
|
|
9
|
+
this.code = code;
|
|
10
|
+
this.message =
|
|
11
|
+
message !== null && message !== void 0 ? message : `The requested path '${path}' could not be found.`;
|
|
12
|
+
this.requestID = requestID;
|
|
11
13
|
}
|
|
12
14
|
}
|
|
13
15
|
exports.NotFoundException = NotFoundException;
|
|
@@ -35,6 +35,7 @@ describe('DirectorySync', () => {
|
|
|
35
35
|
id: 'dir_grp_123',
|
|
36
36
|
idp_id: '123',
|
|
37
37
|
directory_id: 'dir_123',
|
|
38
|
+
organization_id: 'org_123',
|
|
38
39
|
name: 'Foo Group',
|
|
39
40
|
created_at: `2021-10-27 15:21:50.640958`,
|
|
40
41
|
updated_at: '2021-10-27 15:21:50.640959',
|
|
@@ -48,6 +49,7 @@ describe('DirectorySync', () => {
|
|
|
48
49
|
custom: true,
|
|
49
50
|
},
|
|
50
51
|
directory_id: 'dir_123',
|
|
52
|
+
organization_id: 'org_123',
|
|
51
53
|
emails: [
|
|
52
54
|
{
|
|
53
55
|
primary: true,
|
|
@@ -3,6 +3,7 @@ export declare type DefaultCustomAttributes = Record<string, unknown>;
|
|
|
3
3
|
export interface User<TCustomAttributes extends object = DefaultCustomAttributes, TRawAttributes = any> {
|
|
4
4
|
id: string;
|
|
5
5
|
directory_id: string;
|
|
6
|
+
organization_id: string | null;
|
|
6
7
|
raw_attributes: TRawAttributes;
|
|
7
8
|
custom_attributes: TCustomAttributes;
|
|
8
9
|
idp_id: string;
|
|
File without changes
|
package/lib/mfa/mfa.d.ts
CHANGED
|
@@ -4,7 +4,8 @@ import { Challenge } from './interfaces/challenge.interface';
|
|
|
4
4
|
import { EnrollFactorOptions } from './interfaces/enroll-factor-options';
|
|
5
5
|
import { Factor } from './interfaces/factor.interface';
|
|
6
6
|
import { VerifyFactorOptions } from './interfaces/verify-factor-options';
|
|
7
|
-
import { VerifyResponse } from './interfaces/verify-
|
|
7
|
+
import { VerifyResponse } from './interfaces/verify-challenge-response';
|
|
8
|
+
import { VerifyChallengeOptions } from './interfaces/verify-challenge-options';
|
|
8
9
|
export declare class Mfa {
|
|
9
10
|
private readonly workos;
|
|
10
11
|
constructor(workos: WorkOS);
|
|
@@ -12,5 +13,9 @@ export declare class Mfa {
|
|
|
12
13
|
getFactor(id: string): Promise<any>;
|
|
13
14
|
enrollFactor(options: EnrollFactorOptions): Promise<Factor>;
|
|
14
15
|
challengeFactor(options: ChallengeFactorOptions): Promise<Challenge>;
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated Please use `verifyChallenge` instead.
|
|
18
|
+
*/
|
|
15
19
|
verifyFactor(options: VerifyFactorOptions): Promise<VerifyResponse>;
|
|
20
|
+
verifyChallenge(options: VerifyChallengeOptions): Promise<VerifyResponse>;
|
|
16
21
|
}
|
package/lib/mfa/mfa.js
CHANGED
|
@@ -47,17 +47,23 @@ class Mfa {
|
|
|
47
47
|
}
|
|
48
48
|
challengeFactor(options) {
|
|
49
49
|
return __awaiter(this, void 0, void 0, function* () {
|
|
50
|
-
const { data } = yield this.workos.post(
|
|
51
|
-
authentication_factor_id: options.authenticationFactorId,
|
|
50
|
+
const { data } = yield this.workos.post(`/auth/factors/${options.authenticationFactorId}/challenge`, {
|
|
52
51
|
sms_template: 'smsTemplate' in options ? options.smsTemplate : undefined,
|
|
53
52
|
});
|
|
54
53
|
return data;
|
|
55
54
|
});
|
|
56
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* @deprecated Please use `verifyChallenge` instead.
|
|
58
|
+
*/
|
|
57
59
|
verifyFactor(options) {
|
|
58
60
|
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
return this.verifyChallenge(options);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
verifyChallenge(options) {
|
|
65
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
66
|
+
const { data } = yield this.workos.post(`/auth/challenges/${options.authenticationChallengeId}/verify`, {
|
|
61
67
|
code: options.code,
|
|
62
68
|
});
|
|
63
69
|
return data;
|
package/lib/mfa/mfa.spec.js
CHANGED
|
@@ -157,11 +157,7 @@ describe('MFA', () => {
|
|
|
157
157
|
describe('with no sms template', () => {
|
|
158
158
|
it('challenge a factor with no sms template', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
159
159
|
const mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
160
|
-
mock
|
|
161
|
-
.onPost('/auth/factors/challenge', {
|
|
162
|
-
authentication_factor_id: 'auth_factor_1234',
|
|
163
|
-
})
|
|
164
|
-
.reply(200, {
|
|
160
|
+
mock.onPost('/auth/factors/auth_factor_1234/challenge').reply(200, {
|
|
165
161
|
object: 'authentication_challenge',
|
|
166
162
|
id: 'auth_challenge_1234',
|
|
167
163
|
created_at: '2022-03-15T20:39:19.892Z',
|
|
@@ -193,8 +189,7 @@ describe('MFA', () => {
|
|
|
193
189
|
it('challenge a factor with sms template', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
194
190
|
const mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
195
191
|
mock
|
|
196
|
-
.onPost('/auth/factors/challenge', {
|
|
197
|
-
authentication_factor_id: 'auth_factor_1234',
|
|
192
|
+
.onPost('/auth/factors/auth_factor_1234/challenge', {
|
|
198
193
|
sms_template: 'This is your code: 12345',
|
|
199
194
|
})
|
|
200
195
|
.reply(200, {
|
|
@@ -227,13 +222,12 @@ describe('MFA', () => {
|
|
|
227
222
|
}));
|
|
228
223
|
});
|
|
229
224
|
});
|
|
230
|
-
describe('
|
|
225
|
+
describe('verifyChallenge', () => {
|
|
231
226
|
describe('verify with successful response', () => {
|
|
232
227
|
it('verifies a successful factor', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
233
228
|
const mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
234
229
|
mock
|
|
235
|
-
.onPost('/auth/
|
|
236
|
-
authentication_challenge_id: 'auth_challenge_1234',
|
|
230
|
+
.onPost('/auth/challenges/auth_challenge_1234/verify', {
|
|
237
231
|
code: '12345',
|
|
238
232
|
})
|
|
239
233
|
.reply(200, {
|
|
@@ -251,7 +245,7 @@ describe('MFA', () => {
|
|
|
251
245
|
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU', {
|
|
252
246
|
apiHostname: 'api.workos.dev',
|
|
253
247
|
});
|
|
254
|
-
const verifyResponse = yield workos.mfa.
|
|
248
|
+
const verifyResponse = yield workos.mfa.verifyChallenge({
|
|
255
249
|
authenticationChallengeId: 'auth_challenge_1234',
|
|
256
250
|
code: '12345',
|
|
257
251
|
});
|
|
@@ -275,8 +269,7 @@ describe('MFA', () => {
|
|
|
275
269
|
it('throws an exception', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
276
270
|
const mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
277
271
|
mock
|
|
278
|
-
.onPost('/auth/
|
|
279
|
-
authentication_challenge_id: 'auth_challenge_1234',
|
|
272
|
+
.onPost('/auth/challenges/auth_challenge_1234/verify', {
|
|
280
273
|
code: '12345',
|
|
281
274
|
})
|
|
282
275
|
.reply(422, {
|
|
@@ -288,7 +281,7 @@ describe('MFA', () => {
|
|
|
288
281
|
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU', {
|
|
289
282
|
apiHostname: 'api.workos.dev',
|
|
290
283
|
});
|
|
291
|
-
yield expect(workos.mfa.
|
|
284
|
+
yield expect(workos.mfa.verifyChallenge({
|
|
292
285
|
authenticationChallengeId: 'auth_challenge_1234',
|
|
293
286
|
code: '12345',
|
|
294
287
|
})).rejects.toThrow(exceptions_1.UnprocessableEntityException);
|
|
@@ -298,8 +291,7 @@ describe('MFA', () => {
|
|
|
298
291
|
it('throws an exception', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
299
292
|
const mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
300
293
|
mock
|
|
301
|
-
.onPost('/auth/
|
|
302
|
-
authentication_challenge_id: 'auth_challenge_1234',
|
|
294
|
+
.onPost('/auth/challenges/auth_challenge_1234/verify', {
|
|
303
295
|
code: '12345',
|
|
304
296
|
})
|
|
305
297
|
.reply(422, {
|
|
@@ -311,7 +303,7 @@ describe('MFA', () => {
|
|
|
311
303
|
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU', {
|
|
312
304
|
apiHostname: 'api.workos.dev',
|
|
313
305
|
});
|
|
314
|
-
yield expect(workos.mfa.
|
|
306
|
+
yield expect(workos.mfa.verifyChallenge({
|
|
315
307
|
authenticationChallengeId: 'auth_challenge_1234',
|
|
316
308
|
code: '12345',
|
|
317
309
|
})).rejects.toThrow(exceptions_1.UnprocessableEntityException);
|
|
@@ -319,8 +311,7 @@ describe('MFA', () => {
|
|
|
319
311
|
it('exception has code', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
320
312
|
const mock = new axios_mock_adapter_1.default(axios_1.default);
|
|
321
313
|
mock
|
|
322
|
-
.onPost('/auth/
|
|
323
|
-
authentication_challenge_id: 'auth_challenge_1234',
|
|
314
|
+
.onPost('/auth/challenges/auth_challenge_1234/verify', {
|
|
324
315
|
code: '12345',
|
|
325
316
|
})
|
|
326
317
|
.reply(422, {
|
|
@@ -333,7 +324,7 @@ describe('MFA', () => {
|
|
|
333
324
|
apiHostname: 'api.workos.dev',
|
|
334
325
|
});
|
|
335
326
|
try {
|
|
336
|
-
yield workos.mfa.
|
|
327
|
+
yield workos.mfa.verifyChallenge({
|
|
337
328
|
authenticationChallengeId: 'auth_challenge_1234',
|
|
338
329
|
code: '12345',
|
|
339
330
|
});
|
package/lib/workos.d.ts
CHANGED
|
@@ -8,11 +8,13 @@ import { Portal } from './portal/portal';
|
|
|
8
8
|
import { SSO } from './sso/sso';
|
|
9
9
|
import { Webhooks } from './webhooks/webhooks';
|
|
10
10
|
import { Mfa } from './mfa/mfa';
|
|
11
|
+
import { AuditLogs } from './audit-logs/audit-logs';
|
|
11
12
|
export declare class WorkOS {
|
|
12
13
|
readonly key?: string | undefined;
|
|
13
14
|
readonly options: WorkOSOptions;
|
|
14
15
|
readonly baseURL: string;
|
|
15
16
|
private readonly client;
|
|
17
|
+
readonly auditLogs: AuditLogs;
|
|
16
18
|
readonly auditTrail: AuditTrail;
|
|
17
19
|
readonly directorySync: DirectorySync;
|
|
18
20
|
readonly organizations: Organizations;
|
|
@@ -27,4 +29,5 @@ export declare class WorkOS {
|
|
|
27
29
|
put(path: string, entity: any, options?: PutOptions): Promise<AxiosResponse>;
|
|
28
30
|
delete(path: string, query?: any): Promise<AxiosResponse>;
|
|
29
31
|
emitWarning(warning: string): void;
|
|
32
|
+
private handleAxiosError;
|
|
30
33
|
}
|
package/lib/workos.js
CHANGED
|
@@ -23,12 +23,15 @@ 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
|
|
26
|
+
const audit_logs_1 = require("./audit-logs/audit-logs");
|
|
27
|
+
const bad_request_exception_1 = require("./common/exceptions/bad-request.exception");
|
|
28
|
+
const VERSION = '2.9.0';
|
|
27
29
|
const DEFAULT_HOSTNAME = 'api.workos.com';
|
|
28
30
|
class WorkOS {
|
|
29
31
|
constructor(key, options = {}) {
|
|
30
32
|
this.key = key;
|
|
31
33
|
this.options = options;
|
|
34
|
+
this.auditLogs = new audit_logs_1.AuditLogs(this);
|
|
32
35
|
this.auditTrail = new audit_trail_1.AuditTrail(this);
|
|
33
36
|
this.directorySync = new directory_sync_1.DirectorySync(this);
|
|
34
37
|
this.organizations = new organizations_1.Organizations(this);
|
|
@@ -74,37 +77,7 @@ class WorkOS {
|
|
|
74
77
|
});
|
|
75
78
|
}
|
|
76
79
|
catch (error) {
|
|
77
|
-
|
|
78
|
-
if (response) {
|
|
79
|
-
const { status, data, headers } = response;
|
|
80
|
-
const requestID = headers['X-Request-ID'];
|
|
81
|
-
const { code, error_description: errorDescription, error, message, } = data;
|
|
82
|
-
switch (status) {
|
|
83
|
-
case 401: {
|
|
84
|
-
throw new exceptions_1.UnauthorizedException(requestID);
|
|
85
|
-
}
|
|
86
|
-
case 422: {
|
|
87
|
-
const { errors } = data;
|
|
88
|
-
throw new exceptions_1.UnprocessableEntityException({
|
|
89
|
-
code,
|
|
90
|
-
errors,
|
|
91
|
-
message,
|
|
92
|
-
requestID,
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
case 404: {
|
|
96
|
-
throw new exceptions_1.NotFoundException(path, requestID);
|
|
97
|
-
}
|
|
98
|
-
default: {
|
|
99
|
-
if (error || errorDescription) {
|
|
100
|
-
throw new exceptions_1.OauthException(status, requestID, error, errorDescription);
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
throw new exceptions_1.GenericServerException(status, data.message, requestID);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
80
|
+
this.handleAxiosError({ path, error });
|
|
108
81
|
throw error;
|
|
109
82
|
}
|
|
110
83
|
});
|
|
@@ -123,37 +96,7 @@ class WorkOS {
|
|
|
123
96
|
});
|
|
124
97
|
}
|
|
125
98
|
catch (error) {
|
|
126
|
-
|
|
127
|
-
if (response) {
|
|
128
|
-
const { status, data, headers } = response;
|
|
129
|
-
const requestID = headers['X-Request-ID'];
|
|
130
|
-
const { code, error_description: errorDescription, error, message, } = data;
|
|
131
|
-
switch (status) {
|
|
132
|
-
case 401: {
|
|
133
|
-
throw new exceptions_1.UnauthorizedException(requestID);
|
|
134
|
-
}
|
|
135
|
-
case 422: {
|
|
136
|
-
const { errors } = data;
|
|
137
|
-
throw new exceptions_1.UnprocessableEntityException({
|
|
138
|
-
code,
|
|
139
|
-
errors,
|
|
140
|
-
message,
|
|
141
|
-
requestID,
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
case 404: {
|
|
145
|
-
throw new exceptions_1.NotFoundException(path, requestID);
|
|
146
|
-
}
|
|
147
|
-
default: {
|
|
148
|
-
if (error || errorDescription) {
|
|
149
|
-
throw new exceptions_1.OauthException(status, requestID, error, errorDescription);
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
throw new exceptions_1.GenericServerException(status, data.message, requestID);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
99
|
+
this.handleAxiosError({ path, error });
|
|
157
100
|
throw error;
|
|
158
101
|
}
|
|
159
102
|
});
|
|
@@ -171,37 +114,7 @@ class WorkOS {
|
|
|
171
114
|
});
|
|
172
115
|
}
|
|
173
116
|
catch (error) {
|
|
174
|
-
|
|
175
|
-
if (response) {
|
|
176
|
-
const { status, data, headers } = response;
|
|
177
|
-
const requestID = headers['X-Request-ID'];
|
|
178
|
-
const { code, error_description: errorDescription, error, message, } = data;
|
|
179
|
-
switch (status) {
|
|
180
|
-
case 401: {
|
|
181
|
-
throw new exceptions_1.UnauthorizedException(requestID);
|
|
182
|
-
}
|
|
183
|
-
case 422: {
|
|
184
|
-
const { errors } = data;
|
|
185
|
-
throw new exceptions_1.UnprocessableEntityException({
|
|
186
|
-
code,
|
|
187
|
-
errors,
|
|
188
|
-
message,
|
|
189
|
-
requestID,
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
case 404: {
|
|
193
|
-
throw new exceptions_1.NotFoundException(path, requestID);
|
|
194
|
-
}
|
|
195
|
-
default: {
|
|
196
|
-
if (error || errorDescription) {
|
|
197
|
-
throw new exceptions_1.OauthException(status, requestID, error, errorDescription);
|
|
198
|
-
}
|
|
199
|
-
else {
|
|
200
|
-
throw new exceptions_1.GenericServerException(status, data.message, requestID);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
117
|
+
this.handleAxiosError({ path, error });
|
|
205
118
|
throw error;
|
|
206
119
|
}
|
|
207
120
|
});
|
|
@@ -214,37 +127,7 @@ class WorkOS {
|
|
|
214
127
|
});
|
|
215
128
|
}
|
|
216
129
|
catch (error) {
|
|
217
|
-
|
|
218
|
-
if (response) {
|
|
219
|
-
const { status, data, headers } = response;
|
|
220
|
-
const requestID = headers['X-Request-ID'];
|
|
221
|
-
const { code, error_description: errorDescription, error, message, } = data;
|
|
222
|
-
switch (status) {
|
|
223
|
-
case 401: {
|
|
224
|
-
throw new exceptions_1.UnauthorizedException(requestID);
|
|
225
|
-
}
|
|
226
|
-
case 422: {
|
|
227
|
-
const { errors } = data;
|
|
228
|
-
throw new exceptions_1.UnprocessableEntityException({
|
|
229
|
-
code,
|
|
230
|
-
errors,
|
|
231
|
-
message,
|
|
232
|
-
requestID,
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
case 404: {
|
|
236
|
-
throw new exceptions_1.NotFoundException(path, requestID);
|
|
237
|
-
}
|
|
238
|
-
default: {
|
|
239
|
-
if (error || errorDescription) {
|
|
240
|
-
throw new exceptions_1.OauthException(status, requestID, error, errorDescription);
|
|
241
|
-
}
|
|
242
|
-
else {
|
|
243
|
-
throw new exceptions_1.GenericServerException(status, data.message, requestID);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
130
|
+
this.handleAxiosError({ path, error });
|
|
248
131
|
throw error;
|
|
249
132
|
}
|
|
250
133
|
});
|
|
@@ -256,5 +139,53 @@ class WorkOS {
|
|
|
256
139
|
}
|
|
257
140
|
return process.emitWarning(warning, 'WorkOS');
|
|
258
141
|
}
|
|
142
|
+
handleAxiosError({ path, error }) {
|
|
143
|
+
const { response } = error;
|
|
144
|
+
if (response) {
|
|
145
|
+
const { status, data, headers } = response;
|
|
146
|
+
const requestID = headers['X-Request-ID'];
|
|
147
|
+
const { code, error_description: errorDescription, error, errors, message, } = data;
|
|
148
|
+
switch (status) {
|
|
149
|
+
case 401: {
|
|
150
|
+
throw new exceptions_1.UnauthorizedException(requestID);
|
|
151
|
+
}
|
|
152
|
+
case 422: {
|
|
153
|
+
const { errors } = data;
|
|
154
|
+
throw new exceptions_1.UnprocessableEntityException({
|
|
155
|
+
code,
|
|
156
|
+
errors,
|
|
157
|
+
message,
|
|
158
|
+
requestID,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
case 404: {
|
|
162
|
+
throw new exceptions_1.NotFoundException({
|
|
163
|
+
code,
|
|
164
|
+
message,
|
|
165
|
+
path,
|
|
166
|
+
requestID,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
default: {
|
|
170
|
+
if (error || errorDescription) {
|
|
171
|
+
throw new exceptions_1.OauthException(status, requestID, error, errorDescription);
|
|
172
|
+
}
|
|
173
|
+
else if (code && errors) {
|
|
174
|
+
// Note: ideally this should be mapped directly with a `400` status code.
|
|
175
|
+
// However, this would break existing logic for the `OauthException` exception.
|
|
176
|
+
throw new bad_request_exception_1.BadRequestException({
|
|
177
|
+
code,
|
|
178
|
+
errors,
|
|
179
|
+
message,
|
|
180
|
+
requestID,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
throw new exceptions_1.GenericServerException(status, data.message, requestID);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
259
190
|
}
|
|
260
191
|
exports.WorkOS = WorkOS;
|
package/lib/workos.spec.js
CHANGED
|
@@ -69,11 +69,43 @@ describe('WorkOS', () => {
|
|
|
69
69
|
describe('post', () => {
|
|
70
70
|
describe('when the api responds with a 404', () => {
|
|
71
71
|
it('throws a NotFoundException', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
72
|
+
const message = 'Not Found';
|
|
72
73
|
mock.onPost().reply(404, {
|
|
73
|
-
message
|
|
74
|
+
message,
|
|
74
75
|
}, { 'X-Request-ID': 'a-request-id' });
|
|
75
76
|
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
|
|
76
|
-
yield expect(workos.post('/path', {})).rejects.toStrictEqual(new exceptions_1.NotFoundException(
|
|
77
|
+
yield expect(workos.post('/path', {})).rejects.toStrictEqual(new exceptions_1.NotFoundException({
|
|
78
|
+
message,
|
|
79
|
+
path: '/path',
|
|
80
|
+
requestID: 'a-request-id',
|
|
81
|
+
}));
|
|
82
|
+
}));
|
|
83
|
+
it('preserves the error code, status, and message from the underlying response', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
84
|
+
const message = 'The thing you are looking for is not here.';
|
|
85
|
+
const code = 'thing-not-found';
|
|
86
|
+
mock.onPost().reply(404, {
|
|
87
|
+
code,
|
|
88
|
+
message,
|
|
89
|
+
}, { 'X-Request-ID': 'a-request-id' });
|
|
90
|
+
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
|
|
91
|
+
yield expect(workos.post('/path', {})).rejects.toMatchObject({
|
|
92
|
+
code,
|
|
93
|
+
message,
|
|
94
|
+
status: 404,
|
|
95
|
+
});
|
|
96
|
+
}));
|
|
97
|
+
it('includes the path in the message if there is no message in the response', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
98
|
+
const code = 'thing-not-found';
|
|
99
|
+
const path = '/path/to/thing/that-aint-there';
|
|
100
|
+
mock.onPost().reply(404, {
|
|
101
|
+
code,
|
|
102
|
+
}, { 'X-Request-ID': 'a-request-id' });
|
|
103
|
+
const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
|
|
104
|
+
yield expect(workos.post(path, {})).rejects.toMatchObject({
|
|
105
|
+
code,
|
|
106
|
+
message: `The requested path '${path}' could not be found.`,
|
|
107
|
+
status: 404,
|
|
108
|
+
});
|
|
77
109
|
}));
|
|
78
110
|
});
|
|
79
111
|
describe('when the api responds with a 500 and no error/error_description', () => {
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "2.
|
|
2
|
+
"version": "2.9.0",
|
|
3
3
|
"name": "@workos-inc/node",
|
|
4
4
|
"author": "WorkOS",
|
|
5
5
|
"description": "A Node wrapper for the WorkOS API",
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"workos"
|
|
10
10
|
],
|
|
11
11
|
"volta": {
|
|
12
|
-
"node": "14.
|
|
13
|
-
"yarn": "1.22.
|
|
12
|
+
"node": "14.20.0",
|
|
13
|
+
"yarn": "1.22.19"
|
|
14
14
|
},
|
|
15
15
|
"main": "lib/index.js",
|
|
16
16
|
"typings": "lib/index.d.ts",
|
|
@@ -40,14 +40,14 @@
|
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/jest": "27.5.2",
|
|
43
|
-
"@types/node": "14.18.
|
|
43
|
+
"@types/node": "14.18.22",
|
|
44
44
|
"@types/pluralize": "0.0.29",
|
|
45
45
|
"axios-mock-adapter": "1.21.1",
|
|
46
46
|
"jest": "27.5.1",
|
|
47
|
-
"prettier": "2.
|
|
47
|
+
"prettier": "2.7.1",
|
|
48
48
|
"supertest": "6.2.3",
|
|
49
49
|
"ts-jest": "27.1.5",
|
|
50
50
|
"tslint": "6.1.3",
|
|
51
|
-
"typescript": "4.7.
|
|
51
|
+
"typescript": "4.7.4"
|
|
52
52
|
}
|
|
53
53
|
}
|