@workos-inc/node 2.6.0 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +1 -1
  2. package/lib/audit-logs/audit-logs.d.ts +7 -0
  3. package/lib/audit-logs/audit-logs.js +26 -0
  4. package/lib/audit-logs/audit-logs.spec.d.ts +1 -0
  5. package/lib/audit-logs/audit-logs.spec.js +110 -0
  6. package/lib/audit-logs/interfaces/create-audit-log-event-options.interface.d.ts +26 -0
  7. package/lib/{mfa/interfaces/verify-factor-response.js → audit-logs/interfaces/create-audit-log-event-options.interface.js} +0 -0
  8. package/lib/audit-logs/interfaces/index.d.ts +1 -0
  9. package/lib/audit-logs/interfaces/index.js +2 -0
  10. package/lib/common/exceptions/bad-request.exception.d.ts +14 -0
  11. package/lib/common/exceptions/bad-request.exception.js +22 -0
  12. package/lib/common/exceptions/unprocessable-entity.exception.d.ts +8 -2
  13. package/lib/common/exceptions/unprocessable-entity.exception.js +15 -6
  14. package/lib/common/interfaces/pagination-options.interface.d.ts +1 -0
  15. package/lib/directory-sync/directory-sync.spec.js +3 -0
  16. package/lib/directory-sync/interfaces/group.interface.d.ts +3 -0
  17. package/lib/mfa/interfaces/challenge.interface.d.ts +1 -1
  18. package/lib/mfa/interfaces/verify-challenge-options.d.ts +4 -0
  19. package/lib/mfa/interfaces/verify-challenge-options.js +2 -0
  20. package/lib/mfa/interfaces/verify-challenge-response.d.ts +5 -0
  21. package/lib/mfa/interfaces/verify-challenge-response.js +2 -0
  22. package/lib/mfa/interfaces/verify-factor-options.d.ts +3 -0
  23. package/lib/mfa/mfa.d.ts +6 -1
  24. package/lib/mfa/mfa.js +10 -4
  25. package/lib/mfa/mfa.spec.js +95 -11
  26. package/lib/sso/interfaces/connection-type.enum.d.ts +18 -0
  27. package/lib/sso/interfaces/connection-type.enum.js +18 -0
  28. package/lib/workos.d.ts +2 -0
  29. package/lib/workos.js +42 -9
  30. package/package.json +8 -8
  31. package/lib/mfa/interfaces/verify-factor-response.d.ts +0 -10
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # WorkOS Node.js Library
2
2
 
3
3
  ![npm](https://img.shields.io/npm/v/@workos-inc/node)
4
- [![Build Status](https://workos.semaphoreci.com/badges/workos-node/branches/master.svg?style=shields)](https://workos.semaphoreci.com/projects/workos-node)
4
+ [![Build Status](https://workos.semaphoreci.com/badges/workos-node/branches/main.svg?style=shields)](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
 
@@ -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'>;
@@ -0,0 +1 @@
1
+ export { CreateAuditLogEventOptions, CreateAuditLogEventRequestOptions, } from './create-audit-log-event-options.interface';
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -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,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
- constructor(errors: UnprocessableEntityError[], requestID: string);
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
- const requirement = (0, pluralize_1.default)('requirement', errors.length);
15
- this.message = `The following ${requirement} must be met:\n`;
16
- for (const { code } of errors) {
17
- this.message = this.message.concat(`\t${code}\n`);
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
  }
@@ -2,4 +2,5 @@ export interface PaginationOptions {
2
2
  limit?: number;
3
3
  before?: string;
4
4
  after?: string;
5
+ order?: 'asc' | 'desc';
5
6
  }
@@ -33,8 +33,11 @@ describe('DirectorySync', () => {
33
33
  };
34
34
  const groupResponse = {
35
35
  id: 'dir_grp_123',
36
+ idp_id: '123',
36
37
  directory_id: 'dir_123',
37
38
  name: 'Foo Group',
39
+ created_at: `2021-10-27 15:21:50.640958`,
40
+ updated_at: '2021-10-27 15:21:50.640959',
38
41
  raw_attributes: {
39
42
  foo: 'bar',
40
43
  },
@@ -1,6 +1,9 @@
1
1
  export interface Group {
2
2
  id: string;
3
+ idp_id: string;
3
4
  directory_id: string;
4
5
  name: string;
6
+ created_at: string;
7
+ updated_at: string;
5
8
  raw_attributes: any;
6
9
  }
@@ -3,7 +3,7 @@ export interface Challenge {
3
3
  id: string;
4
4
  created_at: string;
5
5
  updated_at: string;
6
- expires_at: string;
6
+ expires_at?: string;
7
7
  code: string;
8
8
  authentication_factor_id: string;
9
9
  }
@@ -0,0 +1,4 @@
1
+ export interface VerifyChallengeOptions {
2
+ authenticationChallengeId: string;
3
+ code: string;
4
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ import { Challenge } from './challenge.interface';
2
+ export interface VerifyResponse {
3
+ challenge: Challenge;
4
+ valid: boolean;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,3 +1,6 @@
1
+ /**
2
+ * @deprecated Please use `VerifyChallengeOptions` instead.
3
+ */
1
4
  export declare type VerifyFactorOptions = {
2
5
  authenticationChallengeId: string;
3
6
  code: string;
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-factor-response';
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('/auth/factors/challenge', {
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
- const { data } = yield this.workos.post('/auth/factors/verify', {
60
- authentication_challenge_id: options.authenticationChallengeId,
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;
@@ -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,17 +133,31 @@ 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', () => {
138
157
  describe('with no sms template', () => {
139
158
  it('challenge a factor with no sms template', () => __awaiter(void 0, void 0, void 0, function* () {
140
159
  const mock = new axios_mock_adapter_1.default(axios_1.default);
141
- mock
142
- .onPost('/auth/factors/challenge', {
143
- authentication_factor_id: 'auth_factor_1234',
144
- })
145
- .reply(200, {
160
+ mock.onPost('/auth/factors/auth_factor_1234/challenge').reply(200, {
146
161
  object: 'authentication_challenge',
147
162
  id: 'auth_challenge_1234',
148
163
  created_at: '2022-03-15T20:39:19.892Z',
@@ -174,8 +189,7 @@ describe('MFA', () => {
174
189
  it('challenge a factor with sms template', () => __awaiter(void 0, void 0, void 0, function* () {
175
190
  const mock = new axios_mock_adapter_1.default(axios_1.default);
176
191
  mock
177
- .onPost('/auth/factors/challenge', {
178
- authentication_factor_id: 'auth_factor_1234',
192
+ .onPost('/auth/factors/auth_factor_1234/challenge', {
179
193
  sms_template: 'This is your code: 12345',
180
194
  })
181
195
  .reply(200, {
@@ -208,13 +222,12 @@ describe('MFA', () => {
208
222
  }));
209
223
  });
210
224
  });
211
- describe('verifyFactor', () => {
225
+ describe('verifyChallenge', () => {
212
226
  describe('verify with successful response', () => {
213
227
  it('verifies a successful factor', () => __awaiter(void 0, void 0, void 0, function* () {
214
228
  const mock = new axios_mock_adapter_1.default(axios_1.default);
215
229
  mock
216
- .onPost('/auth/factors/verify', {
217
- authentication_challenge_id: 'auth_challenge_1234',
230
+ .onPost('/auth/challenges/auth_challenge_1234/verify', {
218
231
  code: '12345',
219
232
  })
220
233
  .reply(200, {
@@ -232,7 +245,7 @@ describe('MFA', () => {
232
245
  const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU', {
233
246
  apiHostname: 'api.workos.dev',
234
247
  });
235
- const verifyResponse = yield workos.mfa.verifyFactor({
248
+ const verifyResponse = yield workos.mfa.verifyChallenge({
236
249
  authenticationChallengeId: 'auth_challenge_1234',
237
250
  code: '12345',
238
251
  });
@@ -252,5 +265,76 @@ describe('MFA', () => {
252
265
  `);
253
266
  }));
254
267
  });
268
+ describe('when the challenge has been previously verified', () => {
269
+ it('throws an exception', () => __awaiter(void 0, void 0, void 0, function* () {
270
+ const mock = new axios_mock_adapter_1.default(axios_1.default);
271
+ mock
272
+ .onPost('/auth/challenges/auth_challenge_1234/verify', {
273
+ code: '12345',
274
+ })
275
+ .reply(422, {
276
+ message: `The authentication challenge '12345' has already been verified.`,
277
+ code: 'authentication_challenge_previously_verified',
278
+ }, {
279
+ 'X-Request-ID': 'req_123',
280
+ });
281
+ const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU', {
282
+ apiHostname: 'api.workos.dev',
283
+ });
284
+ yield expect(workos.mfa.verifyChallenge({
285
+ authenticationChallengeId: 'auth_challenge_1234',
286
+ code: '12345',
287
+ })).rejects.toThrow(exceptions_1.UnprocessableEntityException);
288
+ }));
289
+ });
290
+ describe('when the challenge has expired', () => {
291
+ it('throws an exception', () => __awaiter(void 0, void 0, void 0, function* () {
292
+ const mock = new axios_mock_adapter_1.default(axios_1.default);
293
+ mock
294
+ .onPost('/auth/challenges/auth_challenge_1234/verify', {
295
+ code: '12345',
296
+ })
297
+ .reply(422, {
298
+ message: `The authentication challenge '12345' has expired.`,
299
+ code: 'authentication_challenge_expired',
300
+ }, {
301
+ 'X-Request-ID': 'req_123',
302
+ });
303
+ const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU', {
304
+ apiHostname: 'api.workos.dev',
305
+ });
306
+ yield expect(workos.mfa.verifyChallenge({
307
+ authenticationChallengeId: 'auth_challenge_1234',
308
+ code: '12345',
309
+ })).rejects.toThrow(exceptions_1.UnprocessableEntityException);
310
+ }));
311
+ it('exception has code', () => __awaiter(void 0, void 0, void 0, function* () {
312
+ const mock = new axios_mock_adapter_1.default(axios_1.default);
313
+ mock
314
+ .onPost('/auth/challenges/auth_challenge_1234/verify', {
315
+ code: '12345',
316
+ })
317
+ .reply(422, {
318
+ message: `The authentication challenge '12345' has expired.`,
319
+ code: 'authentication_challenge_expired',
320
+ }, {
321
+ 'X-Request-ID': 'req_123',
322
+ });
323
+ const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU', {
324
+ apiHostname: 'api.workos.dev',
325
+ });
326
+ try {
327
+ yield workos.mfa.verifyChallenge({
328
+ authenticationChallengeId: 'auth_challenge_1234',
329
+ code: '12345',
330
+ });
331
+ }
332
+ catch (error) {
333
+ expect(error).toMatchObject({
334
+ code: 'authentication_challenge_expired',
335
+ });
336
+ }
337
+ }));
338
+ });
255
339
  });
256
340
  });
@@ -1,15 +1,33 @@
1
1
  export declare enum ConnectionType {
2
2
  ADFSSAML = "ADFSSAML",
3
+ AdpOidc = "AdpOidc",
3
4
  Auth0SAML = "Auth0SAML",
4
5
  AzureSAML = "AzureSAML",
6
+ CasSAML = "CasSAML",
7
+ ClassLinkSAML = "ClassLinkSAML",
8
+ CloudflareSAML = "CloudflareSAML",
9
+ CyberArkSAML = "CyberArkSAML",
10
+ DuoSAML = "DuoSAML",
5
11
  GenericOIDC = "GenericOIDC",
6
12
  GenericSAML = "GenericSAML",
7
13
  GoogleOAuth = "GoogleOAuth",
8
14
  GoogleSAML = "GoogleSAML",
15
+ JumpCloudSAML = "JumpCloudSAML",
16
+ KeycloakSAML = "KeycloakSAML",
17
+ LastPassSAML = "LastPassSAML",
9
18
  MagicLink = "MagicLink",
19
+ MicrosoftOAuth = "MicrosoftOAuth",
20
+ MiniOrangeSAML = "MiniOrangeSAML",
21
+ NetIqSAML = "NetIqSAML",
10
22
  OktaSAML = "OktaSAML",
11
23
  OneLoginSAML = "OneLoginSAML",
24
+ OracleSAML = "OracleSAML",
12
25
  PingFederateSAML = "PingFederateSAML",
13
26
  PingOneSAML = "PingOneSAML",
27
+ RipplingSAML = "RipplingSAML",
28
+ SalesforceSAML = "SalesforceSAML",
29
+ ShibbolethGenericSAML = "ShibbolethGenericSAML",
30
+ ShibbolethSAML = "ShibbolethSAML",
31
+ SimpleSamlPhpSAML = "SimpleSamlPhpSAML",
14
32
  VMwareSAML = "VMwareSAML"
15
33
  }
@@ -4,16 +4,34 @@ exports.ConnectionType = void 0;
4
4
  var ConnectionType;
5
5
  (function (ConnectionType) {
6
6
  ConnectionType["ADFSSAML"] = "ADFSSAML";
7
+ ConnectionType["AdpOidc"] = "AdpOidc";
7
8
  ConnectionType["Auth0SAML"] = "Auth0SAML";
8
9
  ConnectionType["AzureSAML"] = "AzureSAML";
10
+ ConnectionType["CasSAML"] = "CasSAML";
11
+ ConnectionType["ClassLinkSAML"] = "ClassLinkSAML";
12
+ ConnectionType["CloudflareSAML"] = "CloudflareSAML";
13
+ ConnectionType["CyberArkSAML"] = "CyberArkSAML";
14
+ ConnectionType["DuoSAML"] = "DuoSAML";
9
15
  ConnectionType["GenericOIDC"] = "GenericOIDC";
10
16
  ConnectionType["GenericSAML"] = "GenericSAML";
11
17
  ConnectionType["GoogleOAuth"] = "GoogleOAuth";
12
18
  ConnectionType["GoogleSAML"] = "GoogleSAML";
19
+ ConnectionType["JumpCloudSAML"] = "JumpCloudSAML";
20
+ ConnectionType["KeycloakSAML"] = "KeycloakSAML";
21
+ ConnectionType["LastPassSAML"] = "LastPassSAML";
13
22
  ConnectionType["MagicLink"] = "MagicLink";
23
+ ConnectionType["MicrosoftOAuth"] = "MicrosoftOAuth";
24
+ ConnectionType["MiniOrangeSAML"] = "MiniOrangeSAML";
25
+ ConnectionType["NetIqSAML"] = "NetIqSAML";
14
26
  ConnectionType["OktaSAML"] = "OktaSAML";
15
27
  ConnectionType["OneLoginSAML"] = "OneLoginSAML";
28
+ ConnectionType["OracleSAML"] = "OracleSAML";
16
29
  ConnectionType["PingFederateSAML"] = "PingFederateSAML";
17
30
  ConnectionType["PingOneSAML"] = "PingOneSAML";
31
+ ConnectionType["RipplingSAML"] = "RipplingSAML";
32
+ ConnectionType["SalesforceSAML"] = "SalesforceSAML";
33
+ ConnectionType["ShibbolethGenericSAML"] = "ShibbolethGenericSAML";
34
+ ConnectionType["ShibbolethSAML"] = "ShibbolethSAML";
35
+ ConnectionType["SimpleSamlPhpSAML"] = "SimpleSamlPhpSAML";
18
36
  ConnectionType["VMwareSAML"] = "VMwareSAML";
19
37
  })(ConnectionType = exports.ConnectionType || (exports.ConnectionType = {}));
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;
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 VERSION = '2.6.0';
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.8.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);
@@ -78,14 +81,19 @@ class WorkOS {
78
81
  if (response) {
79
82
  const { status, data, headers } = response;
80
83
  const requestID = headers['X-Request-ID'];
81
- const { error, error_description: errorDescription } = data;
84
+ const { code, error_description: errorDescription, error, errors, message, } = data;
82
85
  switch (status) {
83
86
  case 401: {
84
87
  throw new exceptions_1.UnauthorizedException(requestID);
85
88
  }
86
89
  case 422: {
87
90
  const { errors } = data;
88
- throw new exceptions_1.UnprocessableEntityException(errors, requestID);
91
+ throw new exceptions_1.UnprocessableEntityException({
92
+ code,
93
+ errors,
94
+ message,
95
+ requestID,
96
+ });
89
97
  }
90
98
  case 404: {
91
99
  throw new exceptions_1.NotFoundException(path, requestID);
@@ -94,6 +102,16 @@ class WorkOS {
94
102
  if (error || errorDescription) {
95
103
  throw new exceptions_1.OauthException(status, requestID, error, errorDescription);
96
104
  }
105
+ else if (code && errors) {
106
+ // Note: ideally this should be mapped directly with a `400` status code.
107
+ // However, this would break existing logic for the `OauthException` exception.
108
+ throw new bad_request_exception_1.BadRequestException({
109
+ code,
110
+ errors,
111
+ message,
112
+ requestID,
113
+ });
114
+ }
97
115
  else {
98
116
  throw new exceptions_1.GenericServerException(status, data.message, requestID);
99
117
  }
@@ -122,14 +140,19 @@ class WorkOS {
122
140
  if (response) {
123
141
  const { status, data, headers } = response;
124
142
  const requestID = headers['X-Request-ID'];
125
- const { error, error_description: errorDescription } = data;
143
+ const { code, error_description: errorDescription, error, message, } = data;
126
144
  switch (status) {
127
145
  case 401: {
128
146
  throw new exceptions_1.UnauthorizedException(requestID);
129
147
  }
130
148
  case 422: {
131
149
  const { errors } = data;
132
- throw new exceptions_1.UnprocessableEntityException(errors, requestID);
150
+ throw new exceptions_1.UnprocessableEntityException({
151
+ code,
152
+ errors,
153
+ message,
154
+ requestID,
155
+ });
133
156
  }
134
157
  case 404: {
135
158
  throw new exceptions_1.NotFoundException(path, requestID);
@@ -165,14 +188,19 @@ class WorkOS {
165
188
  if (response) {
166
189
  const { status, data, headers } = response;
167
190
  const requestID = headers['X-Request-ID'];
168
- const { error, error_description: errorDescription } = data;
191
+ const { code, error_description: errorDescription, error, message, } = data;
169
192
  switch (status) {
170
193
  case 401: {
171
194
  throw new exceptions_1.UnauthorizedException(requestID);
172
195
  }
173
196
  case 422: {
174
197
  const { errors } = data;
175
- throw new exceptions_1.UnprocessableEntityException(errors, requestID);
198
+ throw new exceptions_1.UnprocessableEntityException({
199
+ code,
200
+ errors,
201
+ message,
202
+ requestID,
203
+ });
176
204
  }
177
205
  case 404: {
178
206
  throw new exceptions_1.NotFoundException(path, requestID);
@@ -203,14 +231,19 @@ class WorkOS {
203
231
  if (response) {
204
232
  const { status, data, headers } = response;
205
233
  const requestID = headers['X-Request-ID'];
206
- const { error, error_description: errorDescription } = data;
234
+ const { code, error_description: errorDescription, error, message, } = data;
207
235
  switch (status) {
208
236
  case 401: {
209
237
  throw new exceptions_1.UnauthorizedException(requestID);
210
238
  }
211
239
  case 422: {
212
240
  const { errors } = data;
213
- throw new exceptions_1.UnprocessableEntityException(errors, requestID);
241
+ throw new exceptions_1.UnprocessableEntityException({
242
+ code,
243
+ errors,
244
+ message,
245
+ requestID,
246
+ });
214
247
  }
215
248
  case 404: {
216
249
  throw new exceptions_1.NotFoundException(path, requestID);
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.6.0",
2
+ "version": "2.8.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.19.3",
13
- "yarn": "1.22.18"
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",
@@ -39,15 +39,15 @@
39
39
  "query-string": "7.1.1"
40
40
  },
41
41
  "devDependencies": {
42
- "@types/jest": "27.5.1",
43
- "@types/node": "14.18.18",
42
+ "@types/jest": "27.5.2",
43
+ "@types/node": "14.18.21",
44
44
  "@types/pluralize": "0.0.29",
45
- "axios-mock-adapter": "1.20.0",
45
+ "axios-mock-adapter": "1.21.1",
46
46
  "jest": "27.5.1",
47
- "prettier": "2.6.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.6.4"
51
+ "typescript": "4.7.4"
52
52
  }
53
53
  }
@@ -1,10 +0,0 @@
1
- import { Challenge } from './challenge.interface';
2
- export interface VerifyResponseSuccess {
3
- challenge: Challenge;
4
- valid: boolean;
5
- }
6
- export interface VerifyResponseError {
7
- code: string;
8
- message: string;
9
- }
10
- export declare type VerifyResponse = VerifyResponseSuccess | VerifyResponseError;