@workos-inc/node 2.5.1 → 2.6.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/README.md CHANGED
@@ -33,6 +33,10 @@ import WorkOS from '@workos-inc/node';
33
33
  const workos = new WorkOS('sk_1234');
34
34
  ```
35
35
 
36
+ ## SDK Versioning
37
+
38
+ For our SDKs WorkOS follows a Semantic Versioning ([SemVer](https://semver.org/)) process where all releases will have a version X.Y.Z (like 1.0.0) pattern wherein Z would be a bug fix (e.g., 1.0.1), Y would be a minor release (1.1.0) and X would be a major release (2.0.0). We permit any breaking changes to only be released in major versions and strongly recommend reading changelogs before making any major version upgrades.
39
+
36
40
  ## More Information
37
41
 
38
42
  - [Single Sign-On Guide](https://workos.com/docs/sso/guide)
@@ -28,12 +28,15 @@ const event = {
28
28
  action_type: 'U',
29
29
  action: 'document.updated',
30
30
  };
31
+ const serializeEventOptions = (options) => (Object.assign(Object.assign({}, options), { occurred_at: options.occurred_at.toISOString() }));
31
32
  describe('AuditTrail', () => {
32
33
  describe('createEvent', () => {
33
34
  describe('when the api responds with a 201 CREATED', () => {
34
35
  describe('with an idempotency key', () => {
35
36
  it('includes an idempotency key with request', () => __awaiter(void 0, void 0, void 0, function* () {
36
- mock.onPost().reply(201, { success: true });
37
+ mock
38
+ .onPost('/events', serializeEventOptions(event))
39
+ .replyOnce(201, { success: true });
37
40
  const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
38
41
  yield expect(workos.auditTrail.createEvent(event, {
39
42
  idempotencyKey: 'the-idempotency-key',
@@ -42,14 +45,16 @@ describe('AuditTrail', () => {
42
45
  }));
43
46
  });
44
47
  it('posts Event successfully', () => __awaiter(void 0, void 0, void 0, function* () {
45
- mock.onPost().reply(201, { success: true });
48
+ mock
49
+ .onPost('/events', serializeEventOptions(event))
50
+ .replyOnce(201, { success: true });
46
51
  const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
47
52
  yield expect(workos.auditTrail.createEvent(event)).resolves.toBeUndefined();
48
53
  }));
49
54
  });
50
55
  describe('when the api responds with a 401', () => {
51
56
  it('throws an UnauthorizedException', () => __awaiter(void 0, void 0, void 0, function* () {
52
- mock.onPost().reply(401, {
57
+ mock.onPost('/events', serializeEventOptions(event)).replyOnce(401, {
53
58
  message: 'Unauthorized',
54
59
  }, { 'X-Request-ID': 'a-request-id' });
55
60
  const workos = new workos_1.WorkOS('invalid apikey');
@@ -68,7 +73,7 @@ describe('AuditTrail', () => {
68
73
  code: 'occurred_at must be an ISO 8601 date string',
69
74
  },
70
75
  ];
71
- mock.onPost().reply(422, {
76
+ mock.onPost('/events', serializeEventOptions(event)).replyOnce(422, {
72
77
  message: 'Validation failed',
73
78
  errors,
74
79
  }, { 'X-Request-ID': 'a-request-id' });
@@ -80,7 +85,7 @@ describe('AuditTrail', () => {
80
85
  describe('listEvents', () => {
81
86
  describe('With no filters', () => {
82
87
  it('Returns all events', () => __awaiter(void 0, void 0, void 0, function* () {
83
- mock.onGet().reply(200, {
88
+ mock.onGet('/events').replyOnce(200, {
84
89
  data: [
85
90
  {
86
91
  object: 'event',
@@ -136,7 +141,11 @@ describe('AuditTrail', () => {
136
141
  });
137
142
  describe('With a filter', () => {
138
143
  it('Returns events that match the filter', () => __awaiter(void 0, void 0, void 0, function* () {
139
- mock.onGet().reply(200, {
144
+ mock
145
+ .onGet('/events', {
146
+ action: ['user.searched_directories'],
147
+ })
148
+ .replyOnce(200, {
140
149
  data: [
141
150
  {
142
151
  object: 'event',
@@ -15,7 +15,6 @@ export interface Event {
15
15
  actor_id: string;
16
16
  target_name: string;
17
17
  target_id: string;
18
- environment_id: string;
19
18
  occurred_at: Date;
20
19
  action: EventAction;
21
20
  metadata?: {
@@ -18,81 +18,149 @@ const workos_1 = require("../workos");
18
18
  const mock = new axios_mock_adapter_1.default(axios_1.default);
19
19
  describe('DirectorySync', () => {
20
20
  afterEach(() => mock.resetHistory());
21
+ const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
22
+ const directoryResponse = {
23
+ id: 'directory_123',
24
+ created_at: '2020-05-06 04:21:48.649164',
25
+ domain: 'foo-corp.com',
26
+ external_key: '9asBRBVHz2ASEkgg',
27
+ name: 'Foo',
28
+ object: 'directory',
29
+ organization_id: 'org_01EXSR7M9QTKCC5D531SMCWMYG',
30
+ state: 'linked',
31
+ type: 'okta scim v1.1',
32
+ updated_at: '2021-10-27 15:21:50.640958',
33
+ };
34
+ const groupResponse = {
35
+ id: 'dir_grp_123',
36
+ directory_id: 'dir_123',
37
+ name: 'Foo Group',
38
+ raw_attributes: {
39
+ foo: 'bar',
40
+ },
41
+ };
42
+ const userWithGroupResponse = {
43
+ id: 'user_123',
44
+ custom_attributes: {
45
+ custom: true,
46
+ },
47
+ directory_id: 'dir_123',
48
+ emails: [
49
+ {
50
+ primary: true,
51
+ type: 'type',
52
+ value: 'jonsnow@workos.com',
53
+ },
54
+ ],
55
+ first_name: 'Jon',
56
+ groups: [groupResponse],
57
+ idp_id: 'idp_foo',
58
+ last_name: 'Snow',
59
+ raw_attributes: {},
60
+ state: 'active',
61
+ username: 'jonsnow',
62
+ };
21
63
  describe('listDirectories', () => {
22
64
  describe('with options', () => {
23
65
  it('requests Directories with query parameters', () => __awaiter(void 0, void 0, void 0, function* () {
24
- mock.onGet().reply(200, {});
25
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
26
- yield workos.directorySync.listDirectories({
66
+ const directoryListResponse = {
67
+ object: 'list',
68
+ data: [directoryResponse],
69
+ list_metadata: {},
70
+ };
71
+ mock
72
+ .onGet('/directories', {
27
73
  domain: 'google.com',
28
- });
29
- expect(mock.history.get[0].params).toEqual({
74
+ })
75
+ .replyOnce(200, directoryListResponse);
76
+ const directories = yield workos.directorySync.listDirectories({
30
77
  domain: 'google.com',
31
78
  });
32
- expect(mock.history.get[0].url).toEqual('/directories');
79
+ expect(directories).toEqual(directoryListResponse);
33
80
  }));
34
81
  });
35
82
  });
36
83
  describe('getDirectory', () => {
37
84
  it(`requests a Directory`, () => __awaiter(void 0, void 0, void 0, function* () {
38
- mock.onGet().reply(200, {});
39
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
40
- yield workos.directorySync.getDirectory('directory_123');
41
- expect(mock.history.get[0].url).toEqual('/directories/directory_123');
85
+ mock
86
+ .onGet('/directories/directory_123')
87
+ .replyOnce(200, directoryResponse);
88
+ const directory = yield workos.directorySync.getDirectory('directory_123');
89
+ expect(directory).toEqual(directoryResponse);
42
90
  }));
43
91
  });
44
92
  describe('deleteDirectory', () => {
45
93
  it('sends a request to delete the directory', () => __awaiter(void 0, void 0, void 0, function* () {
46
- mock.onDelete().reply(202, {});
47
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
94
+ mock.onDelete('/directories/directory_123').replyOnce(202, {});
48
95
  yield workos.directorySync.deleteDirectory('directory_123');
49
96
  expect(mock.history.delete[0].url).toEqual('/directories/directory_123');
50
97
  }));
51
98
  });
99
+ describe('getGroup', () => {
100
+ it(`requests a Directory Group`, () => __awaiter(void 0, void 0, void 0, function* () {
101
+ mock.onGet('/directory_groups/dir_grp_123').replyOnce(200, groupResponse);
102
+ const group = yield workos.directorySync.getGroup('dir_grp_123');
103
+ expect(group).toEqual(groupResponse);
104
+ }));
105
+ });
52
106
  describe('listGroups', () => {
107
+ const groupListResponse = {
108
+ object: 'list',
109
+ data: [groupResponse],
110
+ list_metadata: {},
111
+ };
53
112
  describe('with a Directory', () => {
54
113
  it(`requests a Directory's Groups`, () => __awaiter(void 0, void 0, void 0, function* () {
55
- mock.onGet().reply(200, {});
56
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
57
- yield workos.directorySync.listGroups({
114
+ mock
115
+ .onGet('/directory_groups', {
58
116
  directory: 'directory_123',
59
- });
60
- expect(mock.history.get[0].params).toEqual({
117
+ })
118
+ .replyOnce(200, groupListResponse);
119
+ const list = yield workos.directorySync.listGroups({
61
120
  directory: 'directory_123',
62
121
  });
63
- expect(mock.history.get[0].url).toEqual('/directory_groups');
122
+ expect(list).toEqual(groupListResponse);
64
123
  }));
65
124
  });
66
125
  describe('with a User', () => {
67
126
  it(`requests a Directory's Groups`, () => __awaiter(void 0, void 0, void 0, function* () {
68
- mock.onGet().reply(200, {});
69
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
70
- yield workos.directorySync.listGroups({
127
+ mock
128
+ .onGet('/directory_groups', {
71
129
  user: 'directory_usr_123',
72
- });
73
- expect(mock.history.get[0].params).toEqual({
130
+ })
131
+ .replyOnce(200, groupListResponse);
132
+ const list = yield workos.directorySync.listGroups({
74
133
  user: 'directory_usr_123',
75
134
  });
76
- expect(mock.history.get[0].url).toEqual('/directory_groups');
135
+ expect(list).toEqual(groupListResponse);
77
136
  }));
78
137
  });
79
138
  });
80
139
  describe('listUsers', () => {
140
+ const userWithGroupListResponse = {
141
+ object: 'list',
142
+ data: [userWithGroupResponse],
143
+ list_metadata: {},
144
+ };
81
145
  describe('with a Directory', () => {
82
146
  it(`requests a Directory's Users`, () => __awaiter(void 0, void 0, void 0, function* () {
83
- mock.onGet().reply(200, {});
84
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
85
- yield workos.directorySync.listUsers({
147
+ mock
148
+ .onGet('/directory_users', {
86
149
  directory: 'directory_123',
87
- });
88
- expect(mock.history.get[0].params).toEqual({
150
+ })
151
+ .replyOnce(200, userWithGroupListResponse);
152
+ const list = yield workos.directorySync.listUsers({
89
153
  directory: 'directory_123',
90
154
  });
91
- expect(mock.history.get[0].url).toEqual('/directory_users');
155
+ expect(list).toEqual(userWithGroupListResponse);
92
156
  }));
93
157
  describe('with custom attributes', () => {
94
158
  it('returns the custom attributes, using the provided type', () => __awaiter(void 0, void 0, void 0, function* () {
95
- mock.onGet().reply(200, {
159
+ mock
160
+ .onGet('/directory_users', {
161
+ directory: 'directory_123',
162
+ })
163
+ .replyOnce(200, {
96
164
  data: [
97
165
  {
98
166
  object: 'directory_user',
@@ -144,7 +212,6 @@ describe('DirectorySync', () => {
144
212
  },
145
213
  ],
146
214
  });
147
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
148
215
  const users = yield workos.directorySync.listUsers({
149
216
  directory: 'directory_123',
150
217
  });
@@ -158,32 +225,25 @@ describe('DirectorySync', () => {
158
225
  });
159
226
  describe('with a Group', () => {
160
227
  it(`requests a Directory's Users`, () => __awaiter(void 0, void 0, void 0, function* () {
161
- mock.onGet().reply(200, {});
162
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
163
- yield workos.directorySync.listUsers({
228
+ mock
229
+ .onGet('/directory_users', {
164
230
  group: 'directory_grp_123',
165
- });
166
- expect(mock.history.get[0].params).toEqual({
231
+ })
232
+ .replyOnce(200, userWithGroupListResponse);
233
+ const list = yield workos.directorySync.listUsers({
167
234
  group: 'directory_grp_123',
168
235
  });
169
- expect(mock.history.get[0].url).toEqual('/directory_users');
236
+ expect(list).toEqual(userWithGroupListResponse);
170
237
  }));
171
238
  });
172
239
  });
173
240
  describe('getUser', () => {
174
241
  it(`requests a Directory User`, () => __awaiter(void 0, void 0, void 0, function* () {
175
- mock.onGet().reply(200, {});
176
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
177
- yield workos.directorySync.getUser('dir_usr_123');
178
- expect(mock.history.get[0].url).toEqual('/directory_users/dir_usr_123');
179
- }));
180
- });
181
- describe('getGroup', () => {
182
- it(`requests a Directory Group`, () => __awaiter(void 0, void 0, void 0, function* () {
183
- mock.onGet().reply(200, {});
184
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
185
- yield workos.directorySync.getGroup('dir_grp_123');
186
- expect(mock.history.get[0].url).toEqual('/directory_groups/dir_grp_123');
242
+ mock
243
+ .onGet('/directory_users/dir_usr_123')
244
+ .replyOnce(200, userWithGroupResponse);
245
+ const user = yield workos.directorySync.getUser('dir_usr_123');
246
+ expect(user).toEqual(userWithGroupResponse);
187
247
  }));
188
248
  });
189
249
  });
@@ -4,7 +4,6 @@ export interface Directory {
4
4
  domain: string;
5
5
  external_key: string;
6
6
  name: string;
7
- environment_id: string;
8
7
  organization_id?: string;
9
8
  state: 'unlinked' | 'linked' | 'invalid_credentials';
10
9
  type: string;
@@ -1,9 +1,9 @@
1
1
  import { Group } from './group.interface';
2
2
  export declare type DefaultCustomAttributes = Record<string, unknown>;
3
- export interface User<TCustomAttributes extends object = DefaultCustomAttributes> {
3
+ export interface User<TCustomAttributes extends object = DefaultCustomAttributes, TRawAttributes = any> {
4
4
  id: string;
5
5
  directory_id: string;
6
- raw_attributes: any;
6
+ raw_attributes: TRawAttributes;
7
7
  custom_attributes: TCustomAttributes;
8
8
  idp_id: string;
9
9
  first_name: string;
@@ -6,7 +6,6 @@ export interface Factor {
6
6
  created_at: string;
7
7
  updated_at: string;
8
8
  type: string;
9
- environment_id: string;
10
9
  sms: Sms;
11
10
  totp: Totp;
12
11
  }
@@ -44,7 +44,6 @@ describe('MFA', () => {
44
44
  created_at: '2022-03-15T20:39:19.892Z',
45
45
  updated_at: '2022-03-15T20:39:19.892Z',
46
46
  type: 'generic_otp',
47
- environment_id: 'environment_1234',
48
47
  });
49
48
  const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU', {
50
49
  apiHostname: 'api.workos.dev',
@@ -55,7 +54,6 @@ describe('MFA', () => {
55
54
  expect(enrollResponse).toMatchInlineSnapshot(`
56
55
  Object {
57
56
  "created_at": "2022-03-15T20:39:19.892Z",
58
- "environment_id": "environment_1234",
59
57
  "id": "auth_factor_1234",
60
58
  "object": "authentication_factor",
61
59
  "type": "generic_otp",
@@ -73,7 +71,6 @@ describe('MFA', () => {
73
71
  created_at: '2022-03-15T20:39:19.892Z',
74
72
  updated_at: '2022-03-15T20:39:19.892Z',
75
73
  type: 'totp',
76
- environment_id: 'environment_1234',
77
74
  totp: {
78
75
  qr_code: 'qr-code-test',
79
76
  secret: 'secret-test',
@@ -90,7 +87,6 @@ describe('MFA', () => {
90
87
  expect(enrollResponse).toMatchInlineSnapshot(`
91
88
  Object {
92
89
  "created_at": "2022-03-15T20:39:19.892Z",
93
- "environment_id": "environment_1234",
94
90
  "id": "auth_factor_1234",
95
91
  "object": "authentication_factor",
96
92
  "totp": Object {
@@ -112,7 +108,6 @@ describe('MFA', () => {
112
108
  created_at: '2022-03-15T20:39:19.892Z',
113
109
  updated_at: '2022-03-15T20:39:19.892Z',
114
110
  type: 'sms',
115
- environment_id: 'environment_1234',
116
111
  sms: {
117
112
  phone_number: '+15555555555',
118
113
  },
@@ -127,7 +122,6 @@ describe('MFA', () => {
127
122
  expect(enrollResponse).toMatchInlineSnapshot(`
128
123
  Object {
129
124
  "created_at": "2022-03-15T20:39:19.892Z",
130
- "environment_id": "environment_1234",
131
125
  "id": "auth_factor_1234",
132
126
  "object": "authentication_factor",
133
127
  "sms": Object {
@@ -27,7 +27,7 @@ describe('Organizations', () => {
27
27
  describe('listOrganizations', () => {
28
28
  describe('without any options', () => {
29
29
  it('returns organizations and metadata', () => __awaiter(void 0, void 0, void 0, function* () {
30
- mock.onGet().reply(200, list_organizations_json_1.default);
30
+ mock.onGet('/organizations').replyOnce(200, list_organizations_json_1.default);
31
31
  const { data, list_metadata: listMetadata } = yield workos.organizations.listOrganizations();
32
32
  expect(mock.history.get[0].params).toBeUndefined();
33
33
  expect(mock.history.get[0].url).toEqual('/organizations');
@@ -40,7 +40,11 @@ describe('Organizations', () => {
40
40
  });
41
41
  describe('with the domain option', () => {
42
42
  it('forms the proper request to the API', () => __awaiter(void 0, void 0, void 0, function* () {
43
- mock.onGet().reply(200, list_organizations_json_1.default);
43
+ mock
44
+ .onGet('/organizations', {
45
+ domains: ['example.com'],
46
+ })
47
+ .replyOnce(200, list_organizations_json_1.default);
44
48
  const { data } = yield workos.organizations.listOrganizations({
45
49
  domains: ['example.com'],
46
50
  });
@@ -53,7 +57,11 @@ describe('Organizations', () => {
53
57
  });
54
58
  describe('with the before option', () => {
55
59
  it('forms the proper request to the API', () => __awaiter(void 0, void 0, void 0, function* () {
56
- mock.onGet().reply(200, list_organizations_json_1.default);
60
+ mock
61
+ .onGet('/organizations', {
62
+ before: 'before-id',
63
+ })
64
+ .replyOnce(200, list_organizations_json_1.default);
57
65
  const { data } = yield workos.organizations.listOrganizations({
58
66
  before: 'before-id',
59
67
  });
@@ -66,7 +74,11 @@ describe('Organizations', () => {
66
74
  });
67
75
  describe('with the after option', () => {
68
76
  it('forms the proper request to the API', () => __awaiter(void 0, void 0, void 0, function* () {
69
- mock.onGet().reply(200, list_organizations_json_1.default);
77
+ mock
78
+ .onGet('/organizations', {
79
+ after: 'after-id',
80
+ })
81
+ .replyOnce(200, list_organizations_json_1.default);
70
82
  const { data } = yield workos.organizations.listOrganizations({
71
83
  after: 'after-id',
72
84
  });
@@ -79,7 +91,11 @@ describe('Organizations', () => {
79
91
  });
80
92
  describe('with the limit option', () => {
81
93
  it('forms the proper request to the API', () => __awaiter(void 0, void 0, void 0, function* () {
82
- mock.onGet().reply(200, list_organizations_json_1.default);
94
+ mock
95
+ .onGet('/organizations', {
96
+ limit: 10,
97
+ })
98
+ .replyOnce(200, list_organizations_json_1.default);
83
99
  const { data } = yield workos.organizations.listOrganizations({
84
100
  limit: 10,
85
101
  });
@@ -94,7 +110,12 @@ describe('Organizations', () => {
94
110
  describe('createOrganization', () => {
95
111
  describe('with a valid payload', () => {
96
112
  it('creates an organization', () => __awaiter(void 0, void 0, void 0, function* () {
97
- mock.onPost().reply(201, create_organization_json_1.default);
113
+ mock
114
+ .onPost('/organizations', {
115
+ domains: ['example.com'],
116
+ name: 'Test Organization',
117
+ })
118
+ .replyOnce(201, create_organization_json_1.default);
98
119
  const subject = yield workos.organizations.createOrganization({
99
120
  domains: ['example.com'],
100
121
  name: 'Test Organization',
@@ -106,7 +127,12 @@ describe('Organizations', () => {
106
127
  });
107
128
  describe('with an invalid payload', () => {
108
129
  it('returns an error', () => __awaiter(void 0, void 0, void 0, function* () {
109
- mock.onPost().reply(409, create_organization_invalid_json_1.default, {
130
+ mock
131
+ .onPost('/organizations', {
132
+ domains: ['example.com'],
133
+ name: 'Test Organization',
134
+ })
135
+ .replyOnce(409, create_organization_invalid_json_1.default, {
110
136
  'X-Request-ID': 'a-request-id',
111
137
  });
112
138
  yield expect(workos.organizations.createOrganization({
@@ -119,7 +145,9 @@ describe('Organizations', () => {
119
145
  describe('getOrganization', () => {
120
146
  it(`requests an Organization`, () => __awaiter(void 0, void 0, void 0, function* () {
121
147
  const mock = new axios_mock_adapter_1.default(axios_1.default);
122
- mock.onGet().reply(200, get_organization_json_1.default);
148
+ mock
149
+ .onGet('/organizations/org_01EHT88Z8J8795GZNQ4ZP1J81T')
150
+ .replyOnce(200, get_organization_json_1.default);
123
151
  const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
124
152
  const subject = yield workos.organizations.getOrganization('org_01EHT88Z8J8795GZNQ4ZP1J81T');
125
153
  expect(mock.history.get[0].url).toEqual('/organizations/org_01EHT88Z8J8795GZNQ4ZP1J81T');
@@ -132,7 +160,9 @@ describe('Organizations', () => {
132
160
  describe('deleteOrganization', () => {
133
161
  it('sends request to delete an Organization', () => __awaiter(void 0, void 0, void 0, function* () {
134
162
  const mock = new axios_mock_adapter_1.default(axios_1.default);
135
- mock.onDelete().reply(200, {});
163
+ mock
164
+ .onDelete('/organizations/org_01EHT88Z8J8795GZNQ4ZP1J81T')
165
+ .replyOnce(200, {});
136
166
  const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
137
167
  yield workos.organizations.deleteOrganization('org_01EHT88Z8J8795GZNQ4ZP1J81T');
138
168
  expect(mock.history.delete[0].url).toEqual('/organizations/org_01EHT88Z8J8795GZNQ4ZP1J81T');
@@ -141,7 +171,12 @@ describe('Organizations', () => {
141
171
  describe('updateOrganization', () => {
142
172
  describe('with a valid payload', () => {
143
173
  it('updates an organization', () => __awaiter(void 0, void 0, void 0, function* () {
144
- mock.onPut().reply(201, update_organization_json_1.default);
174
+ mock
175
+ .onPut('/organizations/org_01EHT88Z8J8795GZNQ4ZP1J81T', {
176
+ domains: ['example.com'],
177
+ name: 'Test Organization 2',
178
+ })
179
+ .replyOnce(201, update_organization_json_1.default);
145
180
  const subject = yield workos.organizations.updateOrganization({
146
181
  organization: 'org_01EHT88Z8J8795GZNQ4ZP1J81T',
147
182
  domains: ['example.com'],
@@ -22,10 +22,16 @@ describe('Passwordless', () => {
22
22
  describe('createSession', () => {
23
23
  describe('with valid options', () => {
24
24
  it('creates a passwordless session', () => __awaiter(void 0, void 0, void 0, function* () {
25
- mock.onPost().reply(201, create_session_json_1.default);
26
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
27
25
  const email = 'passwordless-session-email@workos.com';
28
26
  const redirectURI = 'https://example.com/passwordless/callback';
27
+ mock
28
+ .onPost('/passwordless/sessions', {
29
+ type: 'MagicLink',
30
+ email,
31
+ redirect_uri: redirectURI,
32
+ })
33
+ .replyOnce(201, create_session_json_1.default);
34
+ const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
29
35
  const session = yield workos.passwordless.createSession({
30
36
  type: 'MagicLink',
31
37
  email,
@@ -42,7 +48,7 @@ describe('Passwordless', () => {
42
48
  describe('sendEmail', () => {
43
49
  describe('with a valid session id', () => {
44
50
  it(`sends a request to send a magic link email`, () => __awaiter(void 0, void 0, void 0, function* () {
45
- mock.onPost().reply(200);
51
+ mock.onPost('/passwordless/sessions/session_123/send').replyOnce(200);
46
52
  const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
47
53
  const sessionId = 'session_123';
48
54
  yield workos.passwordless.sendSession(sessionId);
@@ -26,7 +26,13 @@ describe('Portal', () => {
26
26
  describe('with a valid organization', () => {
27
27
  describe('with the sso intent', () => {
28
28
  it('returns an Admin Portal link', () => __awaiter(void 0, void 0, void 0, function* () {
29
- mock.onPost().reply(201, generate_link_json_1.default);
29
+ mock
30
+ .onPost('/portal/generate_link', {
31
+ intent: generate_portal_link_intent_interface_1.GeneratePortalLinkIntent.SSO,
32
+ organization: 'org_01EHQMYV6MBK39QC5PZXHY59C3',
33
+ return_url: 'https://www.example.com',
34
+ })
35
+ .replyOnce(201, generate_link_json_1.default);
30
36
  const { link } = yield workos.portal.generateLink({
31
37
  intent: generate_portal_link_intent_interface_1.GeneratePortalLinkIntent.SSO,
32
38
  organization: 'org_01EHQMYV6MBK39QC5PZXHY59C3',
@@ -37,7 +43,13 @@ describe('Portal', () => {
37
43
  });
38
44
  describe('with the dsync intent', () => {
39
45
  it('returns an Admin Portal link', () => __awaiter(void 0, void 0, void 0, function* () {
40
- mock.onPost().reply(201, generate_link_json_1.default);
46
+ mock
47
+ .onPost('/portal/generate_link', {
48
+ intent: generate_portal_link_intent_interface_1.GeneratePortalLinkIntent.DSync,
49
+ organization: 'org_01EHQMYV6MBK39QC5PZXHY59C3',
50
+ return_url: 'https://www.example.com',
51
+ })
52
+ .reply(201, generate_link_json_1.default);
41
53
  const { link } = yield workos.portal.generateLink({
42
54
  intent: generate_portal_link_intent_interface_1.GeneratePortalLinkIntent.DSync,
43
55
  organization: 'org_01EHQMYV6MBK39QC5PZXHY59C3',
@@ -49,7 +61,13 @@ describe('Portal', () => {
49
61
  });
50
62
  describe('with an invalid organization', () => {
51
63
  it('throws an error', () => __awaiter(void 0, void 0, void 0, function* () {
52
- mock.onPost().reply(400, generate_link_invalid_json_1.default, {
64
+ mock
65
+ .onPost('/portal/generate_link', {
66
+ intent: generate_portal_link_intent_interface_1.GeneratePortalLinkIntent.SSO,
67
+ organization: 'bogus-id',
68
+ return_url: 'https://www.example.com',
69
+ })
70
+ .reply(400, generate_link_invalid_json_1.default, {
53
71
  'X-Request-ID': 'a-request-id',
54
72
  });
55
73
  yield expect(workos.portal.generateLink({
@@ -134,23 +134,40 @@ describe('SSO', () => {
134
134
  describe('with all information provided', () => {
135
135
  it('sends a request to the WorkOS api for a profile', () => __awaiter(void 0, void 0, void 0, function* () {
136
136
  const mock = new axios_mock_adapter_1.default(axios_1.default);
137
- mock.onPost('/sso/token').reply(200, {
138
- access_token: '01DMEK0J53CVMC32CK5SE0KZ8Q',
139
- profile: {
140
- id: 'prof_123',
141
- idp_id: '123',
142
- organization_id: 'org_123',
143
- connection_id: 'conn_123',
144
- connection_type: 'OktaSAML',
145
- email: 'foo@test.com',
146
- first_name: 'foo',
147
- last_name: 'bar',
148
- raw_attributes: {
149
- email: 'foo@test.com',
150
- first_name: 'foo',
151
- last_name: 'bar',
152
- },
153
- },
137
+ const expectedBody = new URLSearchParams({
138
+ client_id: 'proj_123',
139
+ client_secret: 'sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU',
140
+ code: 'authorization_code',
141
+ grant_type: 'authorization_code',
142
+ });
143
+ expectedBody.sort();
144
+ mock.onPost('/sso/token').replyOnce((config) => {
145
+ const actualBody = new URLSearchParams(config.data);
146
+ actualBody.sort();
147
+ if (actualBody.toString() === expectedBody.toString()) {
148
+ return [
149
+ 200,
150
+ {
151
+ access_token: '01DMEK0J53CVMC32CK5SE0KZ8Q',
152
+ profile: {
153
+ id: 'prof_123',
154
+ idp_id: '123',
155
+ organization_id: 'org_123',
156
+ connection_id: 'conn_123',
157
+ connection_type: 'OktaSAML',
158
+ email: 'foo@test.com',
159
+ first_name: 'foo',
160
+ last_name: 'bar',
161
+ raw_attributes: {
162
+ email: 'foo@test.com',
163
+ first_name: 'foo',
164
+ last_name: 'bar',
165
+ },
166
+ },
167
+ },
168
+ ];
169
+ }
170
+ return [404];
154
171
  });
155
172
  const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
156
173
  const { access_token: accessToken, profile } = yield workos.sso.getProfileAndToken({
@@ -169,7 +186,11 @@ describe('SSO', () => {
169
186
  describe('getProfile', () => {
170
187
  it('calls the `/sso/profile` endpoint with the provided access token', () => __awaiter(void 0, void 0, void 0, function* () {
171
188
  const mock = new axios_mock_adapter_1.default(axios_1.default);
172
- mock.onGet().reply(200, {
189
+ mock
190
+ .onGet('/sso/profile', {
191
+ accessToken: 'access_token',
192
+ })
193
+ .replyOnce(200, {
173
194
  id: 'prof_123',
174
195
  idp_id: '123',
175
196
  organization_id: 'org_123',
@@ -197,7 +218,7 @@ describe('SSO', () => {
197
218
  describe('deleteConnection', () => {
198
219
  it('sends request to delete a Connection', () => __awaiter(void 0, void 0, void 0, function* () {
199
220
  const mock = new axios_mock_adapter_1.default(axios_1.default);
200
- mock.onDelete().reply(200, {});
221
+ mock.onDelete('/connections/conn_123').replyOnce(200, {});
201
222
  const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
202
223
  yield workos.sso.deleteConnection('conn_123');
203
224
  expect(mock.history.delete[0].url).toEqual('/connections/conn_123');
@@ -206,7 +227,7 @@ describe('SSO', () => {
206
227
  describe('getConnection', () => {
207
228
  it(`requests a Connection`, () => __awaiter(void 0, void 0, void 0, function* () {
208
229
  const mock = new axios_mock_adapter_1.default(axios_1.default);
209
- mock.onGet().reply(200, {});
230
+ mock.onGet('/connections/conn_123').replyOnce(200, {});
210
231
  const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
211
232
  yield workos.sso.getConnection('conn_123');
212
233
  expect(mock.history.get[0].url).toEqual('/connections/conn_123');
@@ -215,7 +236,7 @@ describe('SSO', () => {
215
236
  describe('listConnections', () => {
216
237
  it(`requests a list of Connections`, () => __awaiter(void 0, void 0, void 0, function* () {
217
238
  const mock = new axios_mock_adapter_1.default(axios_1.default);
218
- mock.onGet().reply(200, {});
239
+ mock.onGet('/connections').replyOnce(200, {});
219
240
  const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
220
241
  yield workos.sso.listConnections();
221
242
  expect(mock.history.get[0].url).toEqual('/connections');
@@ -1,2 +1,4 @@
1
1
  export * from './webhook.interface';
2
2
  export * from './webhook-directory.interface';
3
+ export * from './webhook-directory-group.interface';
4
+ export * from './webhook-directory-user.interface';
@@ -16,3 +16,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./webhook.interface"), exports);
18
18
  __exportStar(require("./webhook-directory.interface"), exports);
19
+ __exportStar(require("./webhook-directory-group.interface"), exports);
20
+ __exportStar(require("./webhook-directory-user.interface"), exports);
@@ -0,0 +1,9 @@
1
+ export interface WebhookDirectoryGroup<TRawAttributes = any> {
2
+ id: string;
3
+ idp_id: string;
4
+ directory_id: string;
5
+ name: string;
6
+ created_at: string;
7
+ updated_at: string;
8
+ raw_attributes: TRawAttributes;
9
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ import { User } from '../../directory-sync/interfaces';
2
+ export interface WebhookDirectoryUser extends User {
3
+ created_at: string;
4
+ updated_at: string;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,4 +1,20 @@
1
- import { Directory } from '../../directory-sync/interfaces';
2
- export interface WebhookDirectory extends Omit<Directory, 'state'> {
3
- state: 'active' | 'validating' | 'invalid_credentials' | 'inactive' | 'deleting';
1
+ export declare type WebhookDirectoryType = 'okta scim v1.1' | 'okta scim v2.0' | 'azure scim v2.0' | 'bamboohr' | 'breathe hr' | 'cyberark scim v2.0' | 'fourth hr' | 'gsuite directory' | 'generic scim v1.1' | 'generic scim v2.0' | 'gusto' | 'hibob' | 'jump cloud scim v2.0' | 'onelogin scim v2.0' | 'people hr' | 'pingfederate scim v2.0' | 'rippling' | 's3' | 'workday';
2
+ export declare type WebhookDirectoryState = 'active' | 'validating' | 'invalid_credentials' | 'inactive' | 'deleting';
3
+ interface WebhookDirectoryDomain {
4
+ object: 'organization_domain';
5
+ id: string;
6
+ domain: string;
4
7
  }
8
+ export interface WebhookDirectory {
9
+ object: 'directory';
10
+ id: string;
11
+ external_key: string;
12
+ type: WebhookDirectoryType;
13
+ state: WebhookDirectoryState;
14
+ name: string;
15
+ organization_id?: string;
16
+ domains: WebhookDirectoryDomain[];
17
+ created_at: string;
18
+ updated_at: string;
19
+ }
20
+ export {};
@@ -1,5 +1,6 @@
1
- import { Group, User } from '../../directory-sync/interfaces';
2
1
  import { Connection } from '../../sso/interfaces';
2
+ import { WebhookDirectoryGroup as Group } from './webhook-directory-group.interface';
3
+ import { WebhookDirectoryUser as User } from './webhook-directory-user.interface';
3
4
  import { WebhookDirectory as Directory } from './webhook-directory.interface';
4
5
  interface WebhookBase {
5
6
  id: string;
@@ -26,7 +27,7 @@ export interface DsyncDeactivatedWebhook extends WebhookBase {
26
27
  }
27
28
  export interface DsyncDeletedWebhook extends WebhookBase {
28
29
  event: 'dsync.deleted';
29
- data: Directory;
30
+ data: Omit<Directory, 'domains' | 'external_key'>;
30
31
  }
31
32
  export interface DsyncGroupCreatedWebhook extends WebhookBase {
32
33
  event: 'dsync.group.created';
@@ -38,14 +39,14 @@ export interface DsyncGroupDeletedWebhook extends WebhookBase {
38
39
  }
39
40
  export interface DsyncGroupUpdatedWebhook extends WebhookBase {
40
41
  event: 'dsync.group.updated';
41
- data: Group;
42
+ data: Group & Record<'previous_attributes', any>;
42
43
  }
43
44
  export interface DsyncGroupUserAddedWebhook extends WebhookBase {
44
45
  event: 'dsync.group.user_added';
45
46
  data: {
46
47
  directory_id: string;
47
48
  user: User;
48
- group: Group;
49
+ group: Pick<Group, 'id' | 'name'>;
49
50
  };
50
51
  }
51
52
  export interface DsyncGroupUserRemovedWebhook extends WebhookBase {
@@ -53,7 +54,7 @@ export interface DsyncGroupUserRemovedWebhook extends WebhookBase {
53
54
  data: {
54
55
  directory_id: string;
55
56
  user: User;
56
- group: Group;
57
+ group: Pick<Group, 'id' | 'name'>;
57
58
  };
58
59
  }
59
60
  export interface DsyncUserCreatedWebhook extends WebhookBase {
@@ -66,7 +67,7 @@ export interface DsyncUserDeletedWebhook extends WebhookBase {
66
67
  }
67
68
  export interface DsyncUserUpdatedWebhook extends WebhookBase {
68
69
  event: 'dsync.user.updated';
69
- data: User;
70
+ data: User & Record<'previous_attributes', any>;
70
71
  }
71
72
  export declare type Webhook = ConnectionActivatedWebhook | ConnectionDeactivatedWebhook | ConnectionDeletedWebhook | DsyncActivatedWebhook | DsyncDeactivatedWebhook | DsyncDeletedWebhook | DsyncGroupCreatedWebhook | DsyncGroupUpdatedWebhook | DsyncGroupDeletedWebhook | DsyncGroupUserAddedWebhook | DsyncGroupUserRemovedWebhook | DsyncUserCreatedWebhook | DsyncUserUpdatedWebhook | DsyncUserDeletedWebhook;
72
73
  export {};
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.5.1';
26
+ const VERSION = '2.6.0';
27
27
  const DEFAULT_HOSTNAME = 'api.workos.com';
28
28
  class WorkOS {
29
29
  constructor(key, options = {}) {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.5.1",
2
+ "version": "2.6.0",
3
3
  "name": "@workos-inc/node",
4
4
  "author": "WorkOS",
5
5
  "description": "A Node wrapper for the WorkOS API",
@@ -9,7 +9,7 @@
9
9
  "workos"
10
10
  ],
11
11
  "volta": {
12
- "node": "14.19.1",
12
+ "node": "14.19.3",
13
13
  "yarn": "1.22.18"
14
14
  },
15
15
  "main": "lib/index.js",
@@ -39,15 +39,15 @@
39
39
  "query-string": "7.1.1"
40
40
  },
41
41
  "devDependencies": {
42
- "@types/jest": "27.4.1",
43
- "@types/node": "14.18.12",
42
+ "@types/jest": "27.5.1",
43
+ "@types/node": "14.18.18",
44
44
  "@types/pluralize": "0.0.29",
45
45
  "axios-mock-adapter": "1.20.0",
46
46
  "jest": "27.5.1",
47
- "prettier": "2.6.1",
48
- "supertest": "6.2.2",
49
- "ts-jest": "27.1.4",
47
+ "prettier": "2.6.2",
48
+ "supertest": "6.2.3",
49
+ "ts-jest": "27.1.5",
50
50
  "tslint": "6.1.3",
51
- "typescript": "4.6.3"
51
+ "typescript": "4.6.4"
52
52
  }
53
53
  }