@workos-inc/node 7.9.0 → 7.11.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 (34) hide show
  1. package/README.md +4 -0
  2. package/lib/common/crypto/crypto-provider.d.ts +32 -0
  3. package/lib/common/crypto/crypto-provider.js +13 -0
  4. package/lib/common/crypto/node-crypto-provider.d.ts +12 -0
  5. package/lib/common/crypto/node-crypto-provider.js +73 -0
  6. package/lib/common/crypto/subtle-crypto-provider.d.ts +15 -0
  7. package/lib/common/crypto/subtle-crypto-provider.js +75 -0
  8. package/lib/common/interfaces/http-client.interface.d.ts +20 -0
  9. package/lib/common/interfaces/http-client.interface.js +2 -0
  10. package/lib/common/interfaces/index.d.ts +1 -0
  11. package/lib/common/interfaces/index.js +1 -0
  12. package/lib/common/interfaces/workos-options.interface.d.ts +1 -0
  13. package/lib/common/net/fetch-client.d.ts +22 -0
  14. package/lib/common/net/fetch-client.js +112 -0
  15. package/lib/common/net/http-client.d.ts +39 -0
  16. package/lib/common/net/http-client.js +76 -0
  17. package/lib/common/net/node-client.d.ts +23 -0
  18. package/lib/common/net/node-client.js +155 -0
  19. package/lib/index.d.ts +10 -2
  20. package/lib/index.js +31 -3
  21. package/lib/index.worker.d.ts +23 -0
  22. package/lib/index.worker.js +46 -0
  23. package/lib/organizations/interfaces/create-organization-options.interface.d.ts +8 -2
  24. package/lib/organizations/interfaces/update-organization-options.interface.d.ts +8 -2
  25. package/lib/user-management/user-management.js +13 -1
  26. package/lib/webhooks/webhooks.d.ts +3 -2
  27. package/lib/webhooks/webhooks.js +5 -37
  28. package/lib/webhooks/webhooks.spec.js +30 -0
  29. package/lib/workos.d.ts +5 -2
  30. package/lib/workos.js +28 -14
  31. package/lib/workos.spec.js +85 -20
  32. package/package.json +12 -5
  33. package/lib/common/utils/fetch-client.d.ts +0 -31
  34. package/lib/common/utils/fetch-client.js +0 -108
@@ -16,8 +16,12 @@ const jest_fetch_mock_1 = __importDefault(require("jest-fetch-mock"));
16
16
  const test_utils_1 = require("./common/utils/test-utils");
17
17
  const promises_1 = __importDefault(require("fs/promises"));
18
18
  const exceptions_1 = require("./common/exceptions");
19
- const workos_1 = require("./workos");
19
+ const index_1 = require("./index");
20
+ const index_worker_1 = require("./index.worker");
20
21
  const rate_limit_exceeded_exception_1 = require("./common/exceptions/rate-limit-exceeded.exception");
22
+ const fetch_client_1 = require("./common/net/fetch-client");
23
+ const node_client_1 = require("./common/net/node-client");
24
+ const subtle_crypto_provider_1 = require("./common/crypto/subtle-crypto-provider");
21
25
  describe('WorkOS', () => {
22
26
  beforeEach(() => jest_fetch_mock_1.default.resetMocks());
23
27
  describe('constructor', () => {
@@ -32,35 +36,35 @@ describe('WorkOS', () => {
32
36
  });
33
37
  describe('when no API key is provided', () => {
34
38
  it('throws a NoApiKeyFoundException error', () => __awaiter(void 0, void 0, void 0, function* () {
35
- expect(() => new workos_1.WorkOS()).toThrowError(exceptions_1.NoApiKeyProvidedException);
39
+ expect(() => new index_1.WorkOS()).toThrowError(exceptions_1.NoApiKeyProvidedException);
36
40
  }));
37
41
  });
38
42
  describe('when API key is provided with environment variable', () => {
39
43
  it('initializes', () => __awaiter(void 0, void 0, void 0, function* () {
40
44
  process.env.WORKOS_API_KEY = 'sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU';
41
- expect(() => new workos_1.WorkOS()).not.toThrow();
45
+ expect(() => new index_1.WorkOS()).not.toThrow();
42
46
  }));
43
47
  });
44
48
  describe('when API key is provided with constructor', () => {
45
49
  it('initializes', () => __awaiter(void 0, void 0, void 0, function* () {
46
- expect(() => new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU')).not.toThrow();
50
+ expect(() => new index_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU')).not.toThrow();
47
51
  }));
48
52
  });
49
53
  describe('with https option', () => {
50
54
  it('sets baseURL', () => {
51
- const workos = new workos_1.WorkOS('foo', { https: false });
55
+ const workos = new index_1.WorkOS('foo', { https: false });
52
56
  expect(workos.baseURL).toEqual('http://api.workos.com');
53
57
  });
54
58
  });
55
59
  describe('with apiHostname option', () => {
56
60
  it('sets baseURL', () => {
57
- const workos = new workos_1.WorkOS('foo', { apiHostname: 'localhost' });
61
+ const workos = new index_1.WorkOS('foo', { apiHostname: 'localhost' });
58
62
  expect(workos.baseURL).toEqual('https://localhost');
59
63
  });
60
64
  });
61
65
  describe('with port option', () => {
62
66
  it('sets baseURL', () => {
63
- const workos = new workos_1.WorkOS('foo', {
67
+ const workos = new index_1.WorkOS('foo', {
64
68
  apiHostname: 'localhost',
65
69
  port: 4000,
66
70
  });
@@ -70,7 +74,7 @@ describe('WorkOS', () => {
70
74
  describe('when the `config` option is provided', () => {
71
75
  it('applies the configuration to the fetch client', () => __awaiter(void 0, void 0, void 0, function* () {
72
76
  (0, test_utils_1.fetchOnce)('{}', { headers: { 'X-Request-ID': 'a-request-id' } });
73
- const workos = new workos_1.WorkOS('sk_test', {
77
+ const workos = new index_1.WorkOS('sk_test', {
74
78
  config: {
75
79
  headers: {
76
80
  'X-My-Custom-Header': 'Hey there!',
@@ -87,7 +91,7 @@ describe('WorkOS', () => {
87
91
  it('applies the configuration to the fetch client user-agent', () => __awaiter(void 0, void 0, void 0, function* () {
88
92
  (0, test_utils_1.fetchOnce)('{}');
89
93
  const packageJson = JSON.parse(yield promises_1.default.readFile('package.json', 'utf8'));
90
- const workos = new workos_1.WorkOS('sk_test', {
94
+ const workos = new index_1.WorkOS('sk_test', {
91
95
  appInfo: {
92
96
  name: 'fooApp',
93
97
  version: '1.0.0',
@@ -95,14 +99,44 @@ describe('WorkOS', () => {
95
99
  });
96
100
  yield workos.post('/somewhere', {});
97
101
  expect((0, test_utils_1.fetchHeaders)()).toMatchObject({
98
- 'User-Agent': `workos-node/${packageJson.version} fooApp: 1.0.0`,
102
+ 'User-Agent': `workos-node/${packageJson.version}/fetch fooApp: 1.0.0`,
99
103
  });
100
104
  }));
101
105
  });
106
+ describe('when no `appInfo` option is provided', () => {
107
+ it('adds the HTTP client name to the user-agent', () => __awaiter(void 0, void 0, void 0, function* () {
108
+ (0, test_utils_1.fetchOnce)('{}');
109
+ const packageJson = JSON.parse(yield promises_1.default.readFile('package.json', 'utf8'));
110
+ const workos = new index_1.WorkOS('sk_test');
111
+ yield workos.post('/somewhere', {});
112
+ expect((0, test_utils_1.fetchHeaders)()).toMatchObject({
113
+ 'User-Agent': `workos-node/${packageJson.version}/fetch`,
114
+ });
115
+ }));
116
+ });
117
+ describe('when no `appInfo` option is provided', () => {
118
+ it('adds the HTTP client name to the user-agent', () => __awaiter(void 0, void 0, void 0, function* () {
119
+ (0, test_utils_1.fetchOnce)('{}');
120
+ const packageJson = JSON.parse(yield promises_1.default.readFile('package.json', 'utf8'));
121
+ const workos = new index_1.WorkOS('sk_test');
122
+ yield workos.post('/somewhere', {});
123
+ expect((0, test_utils_1.fetchHeaders)()).toMatchObject({
124
+ 'User-Agent': `workos-node/${packageJson.version}/fetch`,
125
+ });
126
+ }));
127
+ });
128
+ describe('when using an environment that supports fetch', () => {
129
+ it('automatically uses the fetch HTTP client', () => {
130
+ const workos = new index_1.WorkOS('sk_test');
131
+ // Bracket notation gets past private visibility
132
+ // tslint:disable-next-line
133
+ expect(workos['client']).toBeInstanceOf(fetch_client_1.FetchHttpClient);
134
+ });
135
+ });
102
136
  });
103
137
  describe('version', () => {
104
138
  it('matches the version in `package.json`', () => __awaiter(void 0, void 0, void 0, function* () {
105
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
139
+ const workos = new index_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
106
140
  // Read `package.json` using file I/O instead of `require` so we don't run
107
141
  // into issues with the `require` cache.
108
142
  const packageJson = JSON.parse(yield promises_1.default.readFile('package.json', 'utf8'));
@@ -114,7 +148,7 @@ describe('WorkOS', () => {
114
148
  it('throws a NotFoundException', () => __awaiter(void 0, void 0, void 0, function* () {
115
149
  const message = 'Not Found';
116
150
  (0, test_utils_1.fetchOnce)({ message }, { status: 404, headers: { 'X-Request-ID': 'a-request-id' } });
117
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
151
+ const workos = new index_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
118
152
  yield expect(workos.post('/path', {})).rejects.toStrictEqual(new exceptions_1.NotFoundException({
119
153
  message,
120
154
  path: '/path',
@@ -125,7 +159,7 @@ describe('WorkOS', () => {
125
159
  const message = 'The thing you are looking for is not here.';
126
160
  const code = 'thing-not-found';
127
161
  (0, test_utils_1.fetchOnce)({ code, message }, { status: 404, headers: { 'X-Request-ID': 'a-request-id' } });
128
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
162
+ const workos = new index_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
129
163
  yield expect(workos.post('/path', {})).rejects.toMatchObject({
130
164
  code,
131
165
  message,
@@ -136,7 +170,7 @@ describe('WorkOS', () => {
136
170
  const code = 'thing-not-found';
137
171
  const path = '/path/to/thing/that-aint-there';
138
172
  (0, test_utils_1.fetchOnce)({ code }, { status: 404, headers: { 'X-Request-ID': 'a-request-id' } });
139
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
173
+ const workos = new index_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
140
174
  yield expect(workos.post(path, {})).rejects.toMatchObject({
141
175
  code,
142
176
  message: `The requested path '${path}' could not be found.`,
@@ -150,7 +184,7 @@ describe('WorkOS', () => {
150
184
  status: 500,
151
185
  headers: { 'X-Request-ID': 'a-request-id' },
152
186
  });
153
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
187
+ const workos = new index_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
154
188
  yield expect(workos.post('/path', {})).rejects.toStrictEqual(new exceptions_1.GenericServerException(500, undefined, {}, 'a-request-id'));
155
189
  }));
156
190
  });
@@ -160,7 +194,7 @@ describe('WorkOS', () => {
160
194
  status: 400,
161
195
  headers: { 'X-Request-ID': 'a-request-id' },
162
196
  });
163
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
197
+ const workos = new index_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
164
198
  yield expect(workos.post('/path', {})).rejects.toStrictEqual(new exceptions_1.OauthException(400, 'a-request-id', 'error', 'error description', { error: 'error', error_description: 'error description' }));
165
199
  }));
166
200
  });
@@ -172,17 +206,48 @@ describe('WorkOS', () => {
172
206
  status: 429,
173
207
  headers: { 'X-Request-ID': 'a-request-id', 'Retry-After': '10' },
174
208
  });
175
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
209
+ const workos = new index_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
176
210
  yield expect(workos.get('/path')).rejects.toStrictEqual(new rate_limit_exceeded_exception_1.RateLimitExceededException('Too many requests', 'a-request-id', 10));
177
211
  }));
178
212
  });
179
213
  describe('when the entity is null', () => {
180
- it('sends a null body', () => __awaiter(void 0, void 0, void 0, function* () {
214
+ it('sends an empty string body', () => __awaiter(void 0, void 0, void 0, function* () {
181
215
  (0, test_utils_1.fetchOnce)();
182
- const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
216
+ const workos = new index_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
183
217
  yield workos.post('/somewhere', null);
184
- expect((0, test_utils_1.fetchBody)({ raw: true })).toBeNull();
218
+ expect((0, test_utils_1.fetchBody)({ raw: true })).toBe('');
185
219
  }));
186
220
  });
187
221
  });
222
+ describe('when in an environment that does not support fetch', () => {
223
+ const fetchFn = globalThis.fetch;
224
+ beforeEach(() => {
225
+ // @ts-ignore
226
+ delete globalThis.fetch;
227
+ });
228
+ afterEach(() => {
229
+ globalThis.fetch = fetchFn;
230
+ });
231
+ it('automatically uses the node HTTP client', () => {
232
+ const workos = new index_1.WorkOS('sk_test_key');
233
+ // tslint:disable-next-line
234
+ expect(workos['client']).toBeInstanceOf(node_client_1.NodeHttpClient);
235
+ });
236
+ it('uses a fetch function if provided', () => {
237
+ const workos = new index_1.WorkOS('sk_test_key', {
238
+ fetchFn,
239
+ });
240
+ // tslint:disable-next-line
241
+ expect(workos['client']).toBeInstanceOf(fetch_client_1.FetchHttpClient);
242
+ });
243
+ });
244
+ describe('when in a worker environment', () => {
245
+ it('uses the worker client', () => {
246
+ const workos = new index_worker_1.WorkOS('sk_test_key');
247
+ // tslint:disable-next-line
248
+ expect(workos['client']).toBeInstanceOf(fetch_client_1.FetchHttpClient);
249
+ // tslint:disable-next-line
250
+ expect(workos.webhooks['cryptoProvider']).toBeInstanceOf(subtle_crypto_provider_1.SubtleCryptoProvider);
251
+ });
252
+ });
188
253
  });
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "7.9.0",
2
+ "version": "7.11.0",
3
3
  "name": "@workos-inc/node",
4
4
  "author": "WorkOS",
5
5
  "description": "A Node wrapper for the WorkOS API",
@@ -13,11 +13,8 @@
13
13
  "yarn": "1.22.19"
14
14
  },
15
15
  "engines": {
16
- "node": ">=19"
16
+ "node": ">=16"
17
17
  },
18
- "engineStrict": true,
19
- "main": "lib/index.js",
20
- "typings": "lib/index.d.ts",
21
18
  "files": [
22
19
  "lib/"
23
20
  ],
@@ -29,6 +26,7 @@
29
26
  "url": "https://github.com/workos-inc/workos-node/issues"
30
27
  },
31
28
  "scripts": {
29
+ "clean": "rm -rf lib",
32
30
  "build": "tsc -p .",
33
31
  "lint": "tslint -p tsconfig.json -c tslint.json",
34
32
  "test": "jest",
@@ -52,5 +50,14 @@
52
50
  "ts-jest": "29.1.3",
53
51
  "tslint": "6.1.3",
54
52
  "typescript": "5.1.6"
53
+ },
54
+ "exports": {
55
+ "types": "./types/index.d.ts",
56
+ "worker": {
57
+ "import": "./lib/index.worker.js"
58
+ },
59
+ "default": {
60
+ "import": "./lib/index.js"
61
+ }
55
62
  }
56
63
  }
@@ -1,31 +0,0 @@
1
- export declare class FetchClient {
2
- readonly baseURL: string;
3
- readonly options?: RequestInit | undefined;
4
- constructor(baseURL: string, options?: RequestInit | undefined);
5
- get(path: string, options: {
6
- params?: Record<string, any>;
7
- headers?: HeadersInit;
8
- }): Promise<{
9
- data: any;
10
- }>;
11
- post<Entity = any>(path: string, entity: Entity, options: {
12
- params?: Record<string, any>;
13
- headers?: HeadersInit;
14
- }): Promise<{
15
- data: any;
16
- }>;
17
- put<Entity = any>(path: string, entity: Entity, options: {
18
- params?: Record<string, any>;
19
- headers?: HeadersInit;
20
- }): Promise<{
21
- data: any;
22
- }>;
23
- delete(path: string, options: {
24
- params?: Record<string, any>;
25
- headers?: HeadersInit;
26
- }): Promise<{
27
- data: any;
28
- }>;
29
- private getResourceURL;
30
- private fetch;
31
- }
@@ -1,108 +0,0 @@
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.FetchClient = void 0;
13
- const fetch_error_1 = require("./fetch-error");
14
- class FetchClient {
15
- constructor(baseURL, options) {
16
- this.baseURL = baseURL;
17
- this.options = options;
18
- }
19
- get(path, options) {
20
- return __awaiter(this, void 0, void 0, function* () {
21
- const resourceURL = this.getResourceURL(path, options.params);
22
- return yield this.fetch(resourceURL, {
23
- headers: options.headers,
24
- });
25
- });
26
- }
27
- post(path, entity, options) {
28
- return __awaiter(this, void 0, void 0, function* () {
29
- const resourceURL = this.getResourceURL(path, options.params);
30
- return yield this.fetch(resourceURL, {
31
- method: 'POST',
32
- headers: Object.assign(Object.assign({}, getContentTypeHeader(entity)), options.headers),
33
- body: getBody(entity),
34
- });
35
- });
36
- }
37
- put(path, entity, options) {
38
- return __awaiter(this, void 0, void 0, function* () {
39
- const resourceURL = this.getResourceURL(path, options.params);
40
- return yield this.fetch(resourceURL, {
41
- method: 'PUT',
42
- headers: Object.assign(Object.assign({}, getContentTypeHeader(entity)), options.headers),
43
- body: getBody(entity),
44
- });
45
- });
46
- }
47
- delete(path, options) {
48
- return __awaiter(this, void 0, void 0, function* () {
49
- const resourceURL = this.getResourceURL(path, options.params);
50
- return yield this.fetch(resourceURL, {
51
- method: 'DELETE',
52
- headers: options.headers,
53
- });
54
- });
55
- }
56
- getResourceURL(path, params) {
57
- const queryString = getQueryString(params);
58
- const url = new URL([path, queryString].filter(Boolean).join('?'), this.baseURL);
59
- return url.toString();
60
- }
61
- fetch(url, options) {
62
- var _a;
63
- return __awaiter(this, void 0, void 0, function* () {
64
- const response = yield fetch(url, Object.assign(Object.assign(Object.assign({}, this.options), options), { headers: Object.assign(Object.assign({ Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json' }, (_a = this.options) === null || _a === void 0 ? void 0 : _a.headers), options === null || options === void 0 ? void 0 : options.headers) }));
65
- if (!response.ok) {
66
- throw new fetch_error_1.FetchError({
67
- message: response.statusText,
68
- response: {
69
- status: response.status,
70
- headers: response.headers,
71
- data: yield response.json(),
72
- },
73
- });
74
- }
75
- const contentType = response.headers.get('content-type');
76
- const isJsonResponse = contentType === null || contentType === void 0 ? void 0 : contentType.includes('application/json');
77
- if (isJsonResponse) {
78
- return { data: yield response.json() };
79
- }
80
- return { data: null };
81
- });
82
- }
83
- }
84
- exports.FetchClient = FetchClient;
85
- function getQueryString(queryObj) {
86
- if (!queryObj)
87
- return undefined;
88
- const sanitizedQueryObj = {};
89
- Object.entries(queryObj).forEach(([param, value]) => {
90
- if (value !== '' && value !== undefined)
91
- sanitizedQueryObj[param] = value;
92
- });
93
- return new URLSearchParams(sanitizedQueryObj).toString();
94
- }
95
- function getContentTypeHeader(entity) {
96
- if (entity instanceof URLSearchParams) {
97
- return {
98
- 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
99
- };
100
- }
101
- return undefined;
102
- }
103
- function getBody(entity) {
104
- if (entity === null || entity instanceof URLSearchParams) {
105
- return entity;
106
- }
107
- return JSON.stringify(entity);
108
- }