@workos-inc/node 7.50.0 → 7.51.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 (58) hide show
  1. package/lib/actions/actions.js +2 -2
  2. package/lib/actions/actions.spec.js +3 -3
  3. package/lib/common/crypto/crypto-provider.d.ts +33 -0
  4. package/lib/common/crypto/{CryptoProvider.spec.js → crypto-provider.spec.js} +8 -8
  5. package/lib/common/crypto/node-crypto-provider.d.ts +7 -0
  6. package/lib/common/crypto/node-crypto-provider.js +38 -2
  7. package/lib/common/crypto/{SignatureProvider.d.ts → signature-provider.d.ts} +1 -1
  8. package/lib/common/crypto/{SignatureProvider.spec.js → signature-provider.spec.js} +4 -4
  9. package/lib/common/crypto/subtle-crypto-provider.d.ts +7 -0
  10. package/lib/common/crypto/subtle-crypto-provider.js +48 -0
  11. package/lib/common/utils/base64.d.ts +12 -0
  12. package/lib/common/utils/base64.js +52 -0
  13. package/lib/common/utils/pagination.d.ts +1 -1
  14. package/lib/fga/fga.d.ts +2 -1
  15. package/lib/fga/fga.js +3 -1
  16. package/lib/fga/fga.spec.js +144 -0
  17. package/lib/fga/interfaces/check.interface.d.ts +4 -0
  18. package/lib/fga/interfaces/check.interface.js +1 -0
  19. package/lib/fga/interfaces/list.interface.d.ts +8 -0
  20. package/lib/fga/interfaces/list.interface.js +2 -0
  21. package/lib/fga/interfaces/warning.interface.d.ts +9 -0
  22. package/lib/fga/interfaces/warning.interface.js +2 -0
  23. package/lib/fga/serializers/index.d.ts +1 -0
  24. package/lib/fga/serializers/index.js +1 -0
  25. package/lib/fga/serializers/list.serializer.d.ts +5 -0
  26. package/lib/fga/serializers/list.serializer.js +10 -0
  27. package/lib/fga/serializers/query-result.serializer.d.ts +5 -0
  28. package/lib/fga/utils/fetch-and-deserialize-list.d.ts +5 -0
  29. package/lib/fga/utils/fetch-and-deserialize-list.js +18 -0
  30. package/lib/fga/utils/fga-paginatable.d.ts +9 -0
  31. package/lib/fga/utils/fga-paginatable.js +13 -0
  32. package/lib/index.d.ts +2 -0
  33. package/lib/index.js +5 -9
  34. package/lib/index.worker.d.ts +2 -0
  35. package/lib/index.worker.js +3 -0
  36. package/lib/user-management/interfaces/update-user-options.interface.d.ts +4 -2
  37. package/lib/user-management/serializers/update-user-options.serializer.js +2 -1
  38. package/lib/user-management/user-management.spec.js +10 -0
  39. package/lib/vault/vault.d.ts +5 -3
  40. package/lib/vault/vault.js +60 -6
  41. package/lib/vault/vault.spec.js +39 -0
  42. package/lib/webhooks/webhooks.js +2 -2
  43. package/lib/workos.d.ts +2 -0
  44. package/lib/workos.js +6 -3
  45. package/package.json +1 -1
  46. package/lib/common/crypto/CryptoProvider.d.ts +0 -32
  47. package/lib/common/crypto/CryptoProvider.js +0 -13
  48. package/lib/common/crypto/NodeCryptoProvider.d.ts +0 -12
  49. package/lib/common/crypto/NodeCryptoProvider.js +0 -73
  50. package/lib/common/crypto/SubtleCryptoProvider.d.ts +0 -15
  51. package/lib/common/crypto/SubtleCryptoProvider.js +0 -75
  52. package/lib/vault/cryptography/decrypt.d.ts +0 -9
  53. package/lib/vault/cryptography/decrypt.js +0 -39
  54. package/lib/vault/cryptography/encrypt.d.ts +0 -1
  55. package/lib/vault/cryptography/encrypt.js +0 -33
  56. /package/lib/common/crypto/{CryptoProvider.spec.d.ts → crypto-provider.spec.d.ts} +0 -0
  57. /package/lib/common/crypto/{SignatureProvider.js → signature-provider.js} +0 -0
  58. /package/lib/common/crypto/{SignatureProvider.spec.d.ts → signature-provider.spec.d.ts} +0 -0
@@ -10,12 +10,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.Actions = void 0;
13
- const SignatureProvider_1 = require("../common/crypto/SignatureProvider");
13
+ const signature_provider_1 = require("../common/crypto/signature-provider");
14
14
  const unreachable_1 = require("../common/utils/unreachable");
15
15
  const action_serializer_1 = require("./serializers/action.serializer");
16
16
  class Actions {
17
17
  constructor(cryptoProvider) {
18
- this.signatureProvider = new SignatureProvider_1.SignatureProvider(cryptoProvider);
18
+ this.signatureProvider = new signature_provider_1.SignatureProvider(cryptoProvider);
19
19
  }
20
20
  get computeSignature() {
21
21
  return this.signatureProvider.computeSignature.bind(this.signatureProvider);
@@ -16,8 +16,8 @@ const crypto_1 = __importDefault(require("crypto"));
16
16
  const workos_1 = require("../workos");
17
17
  const authentication_action_context_json_1 = __importDefault(require("./fixtures/authentication-action-context.json"));
18
18
  const user_registration_action_context_json_1 = __importDefault(require("./fixtures/user-registration-action-context.json"));
19
+ const node_crypto_provider_1 = require("../common/crypto/node-crypto-provider");
19
20
  const workos = new workos_1.WorkOS('sk_test_Sz3IQjepeSWaI4cMS4ms4sMuU');
20
- const NodeCryptoProvider_1 = require("../common/crypto/NodeCryptoProvider");
21
21
  describe('Actions', () => {
22
22
  let secret;
23
23
  beforeEach(() => {
@@ -36,7 +36,7 @@ describe('Actions', () => {
36
36
  describe('signResponse', () => {
37
37
  describe('type: authentication', () => {
38
38
  it('returns a signed response', () => __awaiter(void 0, void 0, void 0, function* () {
39
- const nodeCryptoProvider = new NodeCryptoProvider_1.NodeCryptoProvider();
39
+ const nodeCryptoProvider = new node_crypto_provider_1.NodeCryptoProvider();
40
40
  const response = yield workos.actions.signResponse({
41
41
  type: 'authentication',
42
42
  verdict: 'Allow',
@@ -51,7 +51,7 @@ describe('Actions', () => {
51
51
  });
52
52
  describe('type: user_registration', () => {
53
53
  it('returns a signed response', () => __awaiter(void 0, void 0, void 0, function* () {
54
- const nodeCryptoProvider = new NodeCryptoProvider_1.NodeCryptoProvider();
54
+ const nodeCryptoProvider = new node_crypto_provider_1.NodeCryptoProvider();
55
55
  const response = yield workos.actions.signResponse({
56
56
  type: 'user_registration',
57
57
  verdict: 'Deny',
@@ -29,4 +29,37 @@ export declare abstract class CryptoProvider {
29
29
  * Cryptographically determine whether two signatures are equal
30
30
  */
31
31
  abstract secureCompare(stringA: string, stringB: string): Promise<boolean>;
32
+ /**
33
+ * Encrypts data using AES-256-GCM algorithm.
34
+ *
35
+ * @param plaintext The data to encrypt
36
+ * @param key The encryption key (should be 32 bytes for AES-256)
37
+ * @param iv Optional initialization vector (if not provided, a random one will be generated)
38
+ * @param aad Optional additional authenticated data
39
+ * @returns Object containing the encrypted ciphertext, the IV used, and the authentication tag
40
+ */
41
+ abstract encrypt(plaintext: Uint8Array, key: Uint8Array, iv?: Uint8Array, aad?: Uint8Array): Promise<{
42
+ ciphertext: Uint8Array;
43
+ iv: Uint8Array;
44
+ tag: Uint8Array;
45
+ }>;
46
+ /**
47
+ * Decrypts data that was encrypted using AES-256-GCM algorithm.
48
+ *
49
+ * @param ciphertext The encrypted data
50
+ * @param key The decryption key (must be the same key used for encryption)
51
+ * @param iv The initialization vector used during encryption
52
+ * @param tag The authentication tag produced during encryption
53
+ * @param aad Optional additional authenticated data (must match what was used during encryption)
54
+ * @returns The decrypted data
55
+ * @throws Will throw an error if authentication fails or the data has been tampered with
56
+ */
57
+ abstract decrypt(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array, tag: Uint8Array, aad?: Uint8Array): Promise<Uint8Array>;
58
+ /**
59
+ * Generates cryptographically secure random bytes.
60
+ *
61
+ * @param length The number of random bytes to generate
62
+ * @returns A Uint8Array containing the random bytes
63
+ */
64
+ abstract randomBytes(length: number): Uint8Array;
32
65
  }
@@ -13,10 +13,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const crypto_1 = __importDefault(require("crypto"));
16
- const NodeCryptoProvider_1 = require("./NodeCryptoProvider");
17
- const SubtleCryptoProvider_1 = require("./SubtleCryptoProvider");
16
+ const node_crypto_provider_1 = require("./node-crypto-provider");
17
+ const subtle_crypto_provider_1 = require("./subtle-crypto-provider");
18
18
  const webhook_json_1 = __importDefault(require("../../webhooks/fixtures/webhook.json"));
19
- const SignatureProvider_1 = require("./SignatureProvider");
19
+ const signature_provider_1 = require("./signature-provider");
20
20
  describe('CryptoProvider', () => {
21
21
  let payload;
22
22
  let secret;
@@ -35,8 +35,8 @@ describe('CryptoProvider', () => {
35
35
  });
36
36
  describe('when computing HMAC signature', () => {
37
37
  it('returns the same for the Node crypto and Web Crypto versions', () => __awaiter(void 0, void 0, void 0, function* () {
38
- const nodeCryptoProvider = new NodeCryptoProvider_1.NodeCryptoProvider();
39
- const subtleCryptoProvider = new SubtleCryptoProvider_1.SubtleCryptoProvider();
38
+ const nodeCryptoProvider = new node_crypto_provider_1.NodeCryptoProvider();
39
+ const subtleCryptoProvider = new subtle_crypto_provider_1.SubtleCryptoProvider();
40
40
  const stringifiedPayload = JSON.stringify(payload);
41
41
  const payloadHMAC = `${timestamp}.${stringifiedPayload}`;
42
42
  const nodeCompare = yield nodeCryptoProvider.computeHMACSignatureAsync(payloadHMAC, secret);
@@ -46,9 +46,9 @@ describe('CryptoProvider', () => {
46
46
  });
47
47
  describe('when securely comparing', () => {
48
48
  it('returns the same for the Node crypto and Web Crypto versions', () => __awaiter(void 0, void 0, void 0, function* () {
49
- const nodeCryptoProvider = new NodeCryptoProvider_1.NodeCryptoProvider();
50
- const subtleCryptoProvider = new SubtleCryptoProvider_1.SubtleCryptoProvider();
51
- const signatureProvider = new SignatureProvider_1.SignatureProvider(subtleCryptoProvider);
49
+ const nodeCryptoProvider = new node_crypto_provider_1.NodeCryptoProvider();
50
+ const subtleCryptoProvider = new subtle_crypto_provider_1.SubtleCryptoProvider();
51
+ const signatureProvider = new signature_provider_1.SignatureProvider(subtleCryptoProvider);
52
52
  const signature = yield signatureProvider.computeSignature(timestamp, payload, secret);
53
53
  expect(nodeCryptoProvider.secureCompare(signature, signatureHash)).toEqual(subtleCryptoProvider.secureCompare(signature, signatureHash));
54
54
  expect(nodeCryptoProvider.secureCompare(signature, 'foo')).toEqual(subtleCryptoProvider.secureCompare(signature, 'foo'));
@@ -9,4 +9,11 @@ export declare class NodeCryptoProvider extends CryptoProvider {
9
9
  computeHMACSignatureAsync(payload: string, secret: string): Promise<string>;
10
10
  /** @override */
11
11
  secureCompare(stringA: string, stringB: string): Promise<boolean>;
12
+ encrypt(plaintext: Uint8Array, key: Uint8Array, iv?: Uint8Array, aad?: Uint8Array): Promise<{
13
+ ciphertext: Uint8Array;
14
+ iv: Uint8Array;
15
+ tag: Uint8Array;
16
+ }>;
17
+ decrypt(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array, tag: Uint8Array, aad?: Uint8Array): Promise<Uint8Array>;
18
+ randomBytes(length: number): Uint8Array;
12
19
  }
@@ -33,7 +33,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
33
33
  };
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
35
  exports.NodeCryptoProvider = void 0;
36
- const crypto = __importStar(require("node:crypto"));
36
+ const crypto = __importStar(require("crypto"));
37
37
  const crypto_provider_1 = require("./crypto-provider");
38
38
  /**
39
39
  * `CryptoProvider which uses the Node `crypto` package for its computations.
@@ -49,7 +49,7 @@ class NodeCryptoProvider extends crypto_provider_1.CryptoProvider {
49
49
  /** @override */
50
50
  computeHMACSignatureAsync(payload, secret) {
51
51
  return __awaiter(this, void 0, void 0, function* () {
52
- const signature = yield this.computeHMACSignature(payload, secret);
52
+ const signature = this.computeHMACSignature(payload, secret);
53
53
  return signature;
54
54
  });
55
55
  }
@@ -69,5 +69,41 @@ class NodeCryptoProvider extends crypto_provider_1.CryptoProvider {
69
69
  return crypto.timingSafeEqual(hmacA, hmacB);
70
70
  });
71
71
  }
72
+ encrypt(plaintext, key, iv, aad) {
73
+ return __awaiter(this, void 0, void 0, function* () {
74
+ const actualIv = iv || crypto.randomBytes(32);
75
+ const cipher = crypto.createCipheriv('aes-256-gcm', key, actualIv);
76
+ if (aad) {
77
+ cipher.setAAD(Buffer.from(aad));
78
+ }
79
+ const ciphertext = Buffer.concat([
80
+ cipher.update(Buffer.from(plaintext)),
81
+ cipher.final(),
82
+ ]);
83
+ const tag = cipher.getAuthTag();
84
+ return {
85
+ ciphertext: new Uint8Array(ciphertext),
86
+ iv: new Uint8Array(actualIv),
87
+ tag: new Uint8Array(tag),
88
+ };
89
+ });
90
+ }
91
+ decrypt(ciphertext, key, iv, tag, aad) {
92
+ return __awaiter(this, void 0, void 0, function* () {
93
+ const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
94
+ decipher.setAuthTag(Buffer.from(tag));
95
+ if (aad) {
96
+ decipher.setAAD(Buffer.from(aad));
97
+ }
98
+ const decrypted = Buffer.concat([
99
+ decipher.update(Buffer.from(ciphertext)),
100
+ decipher.final(),
101
+ ]);
102
+ return new Uint8Array(decrypted);
103
+ });
104
+ }
105
+ randomBytes(length) {
106
+ return new Uint8Array(crypto.randomBytes(length));
107
+ }
72
108
  }
73
109
  exports.NodeCryptoProvider = NodeCryptoProvider;
@@ -1,4 +1,4 @@
1
- import { CryptoProvider } from './CryptoProvider';
1
+ import { CryptoProvider } from './crypto-provider';
2
2
  export declare class SignatureProvider {
3
3
  private cryptoProvider;
4
4
  constructor(cryptoProvider: CryptoProvider);
@@ -13,15 +13,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  const crypto_1 = __importDefault(require("crypto"));
16
- const SubtleCryptoProvider_1 = require("./SubtleCryptoProvider");
16
+ const subtle_crypto_provider_1 = require("./subtle-crypto-provider");
17
17
  const webhook_json_1 = __importDefault(require("../../webhooks/fixtures/webhook.json"));
18
- const SignatureProvider_1 = require("./SignatureProvider");
18
+ const signature_provider_1 = require("./signature-provider");
19
19
  describe('SignatureProvider', () => {
20
20
  let payload;
21
21
  let secret;
22
22
  let timestamp;
23
23
  let signatureHash;
24
- const signatureProvider = new SignatureProvider_1.SignatureProvider(new SubtleCryptoProvider_1.SubtleCryptoProvider());
24
+ const signatureProvider = new signature_provider_1.SignatureProvider(new subtle_crypto_provider_1.SubtleCryptoProvider());
25
25
  beforeEach(() => {
26
26
  payload = webhook_json_1.default;
27
27
  secret = 'secret';
@@ -60,7 +60,7 @@ describe('SignatureProvider', () => {
60
60
  describe('when in an environment that supports SubtleCrypto', () => {
61
61
  it('automatically uses the subtle crypto library', () => {
62
62
  // tslint:disable-next-line
63
- expect(signatureProvider['cryptoProvider']).toBeInstanceOf(SubtleCryptoProvider_1.SubtleCryptoProvider);
63
+ expect(signatureProvider['cryptoProvider']).toBeInstanceOf(subtle_crypto_provider_1.SubtleCryptoProvider);
64
64
  });
65
65
  });
66
66
  });
@@ -12,4 +12,11 @@ export declare class SubtleCryptoProvider extends CryptoProvider {
12
12
  computeHMACSignatureAsync(payload: string, secret: string): Promise<string>;
13
13
  /** @override */
14
14
  secureCompare(stringA: string, stringB: string): Promise<boolean>;
15
+ encrypt(plaintext: Uint8Array, key: Uint8Array, iv?: Uint8Array, aad?: Uint8Array): Promise<{
16
+ ciphertext: Uint8Array;
17
+ iv: Uint8Array;
18
+ tag: Uint8Array;
19
+ }>;
20
+ decrypt(ciphertext: Uint8Array, key: Uint8Array, iv: Uint8Array, tag: Uint8Array, aad?: Uint8Array): Promise<Uint8Array>;
21
+ randomBytes(length: number): Uint8Array;
15
22
  }
@@ -65,6 +65,54 @@ class SubtleCryptoProvider extends crypto_provider_1.CryptoProvider {
65
65
  return equal;
66
66
  });
67
67
  }
68
+ encrypt(plaintext, key, iv, aad) {
69
+ return __awaiter(this, void 0, void 0, function* () {
70
+ const actualIv = iv || crypto.getRandomValues(new Uint8Array(32));
71
+ const cryptoKey = yield this.subtleCrypto.importKey('raw', key, { name: 'AES-GCM' }, false, ['encrypt']);
72
+ const encryptParams = {
73
+ name: 'AES-GCM',
74
+ iv: actualIv,
75
+ };
76
+ if (aad) {
77
+ encryptParams.additionalData = aad;
78
+ }
79
+ const encryptedData = yield this.subtleCrypto.encrypt(encryptParams, cryptoKey, plaintext);
80
+ const encryptedBytes = new Uint8Array(encryptedData);
81
+ // Extract tag (last 16 bytes)
82
+ const tagSize = 16;
83
+ const tagStart = encryptedBytes.length - tagSize;
84
+ const tag = encryptedBytes.slice(tagStart);
85
+ const ciphertext = encryptedBytes.slice(0, tagStart);
86
+ return {
87
+ ciphertext,
88
+ iv: actualIv,
89
+ tag,
90
+ };
91
+ });
92
+ }
93
+ decrypt(ciphertext, key, iv, tag, aad) {
94
+ return __awaiter(this, void 0, void 0, function* () {
95
+ // SubtleCrypto expects tag to be appended to ciphertext for AES-GCM
96
+ const combinedData = new Uint8Array(ciphertext.length + tag.length);
97
+ combinedData.set(ciphertext, 0);
98
+ combinedData.set(tag, ciphertext.length);
99
+ const cryptoKey = yield this.subtleCrypto.importKey('raw', key, { name: 'AES-GCM' }, false, ['decrypt']);
100
+ const decryptParams = {
101
+ name: 'AES-GCM',
102
+ iv,
103
+ };
104
+ if (aad) {
105
+ decryptParams.additionalData = aad;
106
+ }
107
+ const decryptedData = yield this.subtleCrypto.decrypt(decryptParams, cryptoKey, combinedData);
108
+ return new Uint8Array(decryptedData);
109
+ });
110
+ }
111
+ randomBytes(length) {
112
+ const bytes = new Uint8Array(length);
113
+ crypto.getRandomValues(bytes);
114
+ return bytes;
115
+ }
68
116
  }
69
117
  exports.SubtleCryptoProvider = SubtleCryptoProvider;
70
118
  // Cached mapping of byte to hex representation. We do this once to avoid re-
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Cross-runtime compatible base64 encoding/decoding utilities
3
+ * that work in both Node.js and browser environments
4
+ */
5
+ /**
6
+ * Converts a base64 string to a Uint8Array
7
+ */
8
+ export declare function base64ToUint8Array(base64: string): Uint8Array;
9
+ /**
10
+ * Converts a Uint8Array to a base64 string
11
+ */
12
+ export declare function uint8ArrayToBase64(bytes: Uint8Array): string;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ /**
3
+ * Cross-runtime compatible base64 encoding/decoding utilities
4
+ * that work in both Node.js and browser environments
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.uint8ArrayToBase64 = exports.base64ToUint8Array = void 0;
8
+ /**
9
+ * Converts a base64 string to a Uint8Array
10
+ */
11
+ function base64ToUint8Array(base64) {
12
+ // In browsers and modern Node.js
13
+ if (typeof atob === 'function') {
14
+ const binary = atob(base64);
15
+ const bytes = new Uint8Array(binary.length);
16
+ for (let i = 0; i < binary.length; i++) {
17
+ bytes[i] = binary.charCodeAt(i);
18
+ }
19
+ return bytes;
20
+ }
21
+ // Node.js fallback using Buffer
22
+ else if (typeof Buffer !== 'undefined') {
23
+ return new Uint8Array(Buffer.from(base64, 'base64'));
24
+ }
25
+ // Fallback implementation if neither is available
26
+ else {
27
+ throw new Error('No base64 decoding implementation available');
28
+ }
29
+ }
30
+ exports.base64ToUint8Array = base64ToUint8Array;
31
+ /**
32
+ * Converts a Uint8Array to a base64 string
33
+ */
34
+ function uint8ArrayToBase64(bytes) {
35
+ // In browsers and modern Node.js
36
+ if (typeof btoa === 'function') {
37
+ let binary = '';
38
+ for (let i = 0; i < bytes.byteLength; i++) {
39
+ binary += String.fromCharCode(bytes[i]);
40
+ }
41
+ return btoa(binary);
42
+ }
43
+ // Node.js fallback using Buffer
44
+ else if (typeof Buffer !== 'undefined') {
45
+ return Buffer.from(bytes).toString('base64');
46
+ }
47
+ // Fallback implementation if neither is available
48
+ else {
49
+ throw new Error('No base64 encoding implementation available');
50
+ }
51
+ }
52
+ exports.uint8ArrayToBase64 = uint8ArrayToBase64;
@@ -1,6 +1,6 @@
1
1
  import { List, PaginationOptions } from '../interfaces';
2
2
  export declare class AutoPaginatable<T> {
3
- private list;
3
+ protected list: List<T>;
4
4
  private apiCall;
5
5
  readonly object: 'list';
6
6
  readonly options: PaginationOptions;
package/lib/fga/fga.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { WorkOS } from '../workos';
2
2
  import { Resource, CheckBatchOptions, CheckOptions, CheckRequestOptions, CheckResult, CreateResourceOptions, DeleteResourceOptions, ListResourcesOptions, ListWarrantsRequestOptions, ListWarrantsOptions, QueryOptions, QueryRequestOptions, QueryResult, ResourceInterface, ResourceOptions, UpdateResourceOptions, WriteWarrantOptions, Warrant, WarrantToken, BatchWriteResourcesOptions } from './interfaces';
3
3
  import { AutoPaginatable } from '../common/utils/pagination';
4
+ import { FgaPaginatable } from './utils/fga-paginatable';
4
5
  export declare class FGA {
5
6
  private readonly workos;
6
7
  constructor(workos: WorkOS);
@@ -15,5 +16,5 @@ export declare class FGA {
15
16
  writeWarrant(options: WriteWarrantOptions): Promise<WarrantToken>;
16
17
  batchWriteWarrants(options: WriteWarrantOptions[]): Promise<WarrantToken>;
17
18
  listWarrants(options?: ListWarrantsOptions, requestOptions?: ListWarrantsRequestOptions): Promise<AutoPaginatable<Warrant>>;
18
- query(options: QueryOptions, requestOptions?: QueryRequestOptions): Promise<AutoPaginatable<QueryResult>>;
19
+ query(options: QueryOptions, requestOptions?: QueryRequestOptions): Promise<FgaPaginatable<QueryResult>>;
19
20
  }
package/lib/fga/fga.js CHANGED
@@ -15,6 +15,8 @@ const serializers_1 = require("./serializers");
15
15
  const interface_check_1 = require("./utils/interface-check");
16
16
  const pagination_1 = require("../common/utils/pagination");
17
17
  const fetch_and_deserialize_1 = require("../common/utils/fetch-and-deserialize");
18
+ const fga_paginatable_1 = require("./utils/fga-paginatable");
19
+ const fetch_and_deserialize_list_1 = require("./utils/fetch-and-deserialize-list");
18
20
  class FGA {
19
21
  constructor(workos) {
20
22
  this.workos = workos;
@@ -104,7 +106,7 @@ class FGA {
104
106
  }
105
107
  query(options, requestOptions = {}) {
106
108
  return __awaiter(this, void 0, void 0, function* () {
107
- return new pagination_1.AutoPaginatable(yield (0, fetch_and_deserialize_1.fetchAndDeserialize)(this.workos, '/fga/v1/query', serializers_1.deserializeQueryResult, (0, serializers_1.serializeQueryOptions)(options), requestOptions), (params) => (0, fetch_and_deserialize_1.fetchAndDeserialize)(this.workos, '/fga/v1/query', serializers_1.deserializeQueryResult, params, requestOptions), (0, serializers_1.serializeQueryOptions)(options));
109
+ return new fga_paginatable_1.FgaPaginatable(yield (0, fetch_and_deserialize_list_1.fetchAndDeserializeFGAList)(this.workos, '/fga/v1/query', serializers_1.deserializeQueryResult, (0, serializers_1.serializeQueryOptions)(options), requestOptions), (params) => (0, fetch_and_deserialize_list_1.fetchAndDeserializeFGAList)(this.workos, '/fga/v1/query', serializers_1.deserializeQueryResult, params, requestOptions), (0, serializers_1.serializeQueryOptions)(options));
108
110
  });
109
111
  }
110
112
  }
@@ -48,6 +48,56 @@ describe('FGA', () => {
48
48
  warrantToken: 'abc',
49
49
  });
50
50
  }));
51
+ it('deserializes warnings in check response', () => __awaiter(void 0, void 0, void 0, function* () {
52
+ (0, test_utils_1.fetchOnce)({
53
+ result: 'authorized',
54
+ is_implicit: false,
55
+ warrant_token: 'abc',
56
+ warnings: [
57
+ {
58
+ code: 'missing_context_keys',
59
+ message: 'Missing required context keys',
60
+ keys: ['tenant_id', 'region'],
61
+ },
62
+ {
63
+ code: 'some_other_warning',
64
+ message: 'Some other warning message',
65
+ },
66
+ ],
67
+ });
68
+ const checkResult = yield workos.fga.check({
69
+ checks: [
70
+ {
71
+ resource: {
72
+ resourceType: 'role',
73
+ resourceId: 'admin',
74
+ },
75
+ relation: 'member',
76
+ subject: {
77
+ resourceType: 'user',
78
+ resourceId: 'user_123',
79
+ },
80
+ },
81
+ ],
82
+ });
83
+ expect((0, test_utils_1.fetchURL)()).toContain('/fga/v1/check');
84
+ expect(checkResult).toMatchObject({
85
+ result: 'authorized',
86
+ isImplicit: false,
87
+ warrantToken: 'abc',
88
+ warnings: [
89
+ {
90
+ code: 'missing_context_keys',
91
+ message: 'Missing required context keys',
92
+ keys: ['tenant_id', 'region'],
93
+ },
94
+ {
95
+ code: 'some_other_warning',
96
+ message: 'Some other warning message',
97
+ },
98
+ ],
99
+ });
100
+ }));
51
101
  });
52
102
  describe('createResource', () => {
53
103
  it('creates resource', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -606,6 +656,100 @@ describe('FGA', () => {
606
656
  },
607
657
  ]);
608
658
  }));
659
+ it('deserializes warnings in query response', () => __awaiter(void 0, void 0, void 0, function* () {
660
+ (0, test_utils_1.fetchOnce)({
661
+ data: [
662
+ {
663
+ resource_type: 'role',
664
+ resource_id: 'admin',
665
+ warrant: {
666
+ resource_type: 'role',
667
+ resource_id: 'admin',
668
+ relation: 'member',
669
+ subject: {
670
+ resource_type: 'user',
671
+ resource_id: 'user_123',
672
+ },
673
+ },
674
+ is_implicit: false,
675
+ },
676
+ {
677
+ resource_type: 'role',
678
+ resource_id: 'manager',
679
+ warrant: {
680
+ resource_type: 'role',
681
+ resource_id: 'manager',
682
+ relation: 'member',
683
+ subject: {
684
+ resource_type: 'user',
685
+ resource_id: 'user_123',
686
+ },
687
+ },
688
+ is_implicit: true,
689
+ },
690
+ ],
691
+ list_metadata: {
692
+ before: null,
693
+ after: null,
694
+ },
695
+ warnings: [
696
+ {
697
+ code: 'missing_context_keys',
698
+ message: 'Missing required context keys',
699
+ keys: ['tenant_id'],
700
+ },
701
+ {
702
+ code: 'some_other_warning',
703
+ message: 'Some other warning message',
704
+ },
705
+ ],
706
+ });
707
+ const result = yield workos.fga.query({
708
+ q: 'select role where user:user_123 is member',
709
+ });
710
+ expect((0, test_utils_1.fetchURL)()).toContain('/fga/v1/query');
711
+ expect(result.data).toMatchObject([
712
+ {
713
+ resourceType: 'role',
714
+ resourceId: 'admin',
715
+ warrant: {
716
+ resourceType: 'role',
717
+ resourceId: 'admin',
718
+ relation: 'member',
719
+ subject: {
720
+ resourceType: 'user',
721
+ resourceId: 'user_123',
722
+ },
723
+ },
724
+ isImplicit: false,
725
+ },
726
+ {
727
+ resourceType: 'role',
728
+ resourceId: 'manager',
729
+ warrant: {
730
+ resourceType: 'role',
731
+ resourceId: 'manager',
732
+ relation: 'member',
733
+ subject: {
734
+ resourceType: 'user',
735
+ resourceId: 'user_123',
736
+ },
737
+ },
738
+ isImplicit: true,
739
+ },
740
+ ]);
741
+ expect(result.warnings).toMatchObject([
742
+ {
743
+ code: 'missing_context_keys',
744
+ message: 'Missing required context keys',
745
+ keys: ['tenant_id'],
746
+ },
747
+ {
748
+ code: 'some_other_warning',
749
+ message: 'Some other warning message',
750
+ },
751
+ ]);
752
+ }));
609
753
  it('sends correct params and options', () => __awaiter(void 0, void 0, void 0, function* () {
610
754
  (0, test_utils_1.fetchOnce)({
611
755
  data: [
@@ -2,6 +2,7 @@ import { ResourceInterface, ResourceOptions } from './resource.interface';
2
2
  import { PolicyContext, SerializedSubject, Subject } from './warrant.interface';
3
3
  import { CheckOp } from './check-op.enum';
4
4
  import { PostOptions } from '../../common/interfaces';
5
+ import { Warning } from './warning.interface';
5
6
  export interface CheckWarrantOptions {
6
7
  resource: ResourceInterface | ResourceOptions;
7
8
  relation: string;
@@ -39,6 +40,7 @@ export interface CheckResultResponse {
39
40
  is_implicit: boolean;
40
41
  warrant_token: string;
41
42
  debug_info?: DebugInfoResponse;
43
+ warnings?: Warning[];
42
44
  }
43
45
  export interface DebugInfo {
44
46
  processingTime: number;
@@ -67,12 +69,14 @@ export interface CheckResultInterface {
67
69
  isImplicit: boolean;
68
70
  warrantToken: string;
69
71
  debugInfo?: DebugInfo;
72
+ warnings?: Warning[];
70
73
  }
71
74
  export declare class CheckResult implements CheckResultInterface {
72
75
  result: string;
73
76
  isImplicit: boolean;
74
77
  warrantToken: string;
75
78
  debugInfo?: DebugInfo;
79
+ warnings?: Warning[];
76
80
  constructor(json: CheckResultResponse);
77
81
  isAuthorized(): boolean;
78
82
  }
@@ -14,6 +14,7 @@ class CheckResult {
14
14
  decisionTree: (0, check_options_serializer_1.deserializeDecisionTreeNode)(json.debug_info.decision_tree),
15
15
  }
16
16
  : undefined;
17
+ this.warnings = json.warnings;
17
18
  }
18
19
  isAuthorized() {
19
20
  return this.result === CHECK_RESULT_AUTHORIZED;
@@ -0,0 +1,8 @@
1
+ import { List, ListResponse } from '../../common/interfaces';
2
+ import { Warning } from './warning.interface';
3
+ export interface FGAListResponse<T> extends ListResponse<T> {
4
+ warnings?: Warning[];
5
+ }
6
+ export interface FGAList<T> extends List<T> {
7
+ warnings?: Warning[];
8
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,9 @@
1
+ export interface BaseWarning {
2
+ code: string;
3
+ message: string;
4
+ }
5
+ export interface MissingContextKeysWarning extends BaseWarning {
6
+ code: 'missing_context_keys';
7
+ keys: string[];
8
+ }
9
+ export type Warning = BaseWarning | MissingContextKeysWarning;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -10,3 +10,4 @@ export * from './resource.serializer';
10
10
  export * from './warrant-token.serializer';
11
11
  export * from './warrant.serializer';
12
12
  export * from './write-warrant-options.serializer';
13
+ export * from './list.serializer';
@@ -26,3 +26,4 @@ __exportStar(require("./resource.serializer"), exports);
26
26
  __exportStar(require("./warrant-token.serializer"), exports);
27
27
  __exportStar(require("./warrant.serializer"), exports);
28
28
  __exportStar(require("./write-warrant-options.serializer"), exports);
29
+ __exportStar(require("./list.serializer"), exports);
@@ -0,0 +1,5 @@
1
+ import { FGAList } from '../interfaces/list.interface';
2
+ import { ListResponse } from '../../common/interfaces';
3
+ export declare const deserializeFGAList: <T, U>(response: ListResponse<T> & {
4
+ warnings?: any[] | undefined;
5
+ }, deserializeFn: (data: T) => U) => FGAList<U>;