@knocklabs/node 0.6.1 → 0.6.3

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
@@ -154,7 +154,7 @@ const token = await Knock.signUserToken("jhammond", {
154
154
  signingKey: "S25vY2sga25vY2sh...",
155
155
  // Optional: How long the token should be valid for, in seconds (default 1 hour)
156
156
  // For long-lived connections, you will need to refresh the token before it expires.
157
- expiresIn: 60 * 60,
157
+ expiresInSeconds: 60 * 60,
158
158
  });
159
159
 
160
160
  // This token can now be safely passed to your client e.g. in a cookie or API response.
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knocklabs/node",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "description": "Library for interacting with the Knock API",
5
5
  "homepage": "https://github.com/knocklabs/knock-node",
6
6
  "author": "@knocklabs",
@@ -24,22 +24,20 @@
24
24
  "scripts": {
25
25
  "build": "tsc -p tsconfig.json",
26
26
  "lint": "tslint -p tsconfig.json -c tslint.json",
27
- "test": "jest",
28
- "test:watch": "jest --watch",
29
- "prettier": "prettier \"src/**/*.{js,ts,tsx}\" --check",
30
27
  "format": "prettier \"src/**/*.{js,ts,tsx}\" --write",
28
+ "format:check": "prettier \"src/**/*.{js,ts,tsx}\" --check",
29
+ "test": "vitest",
30
+ "coverage": "vitest run --coverage",
31
31
  "prepublishOnly": "npm run build"
32
32
  },
33
33
  "devDependencies": {
34
- "@types/jest": "26.0.23",
35
34
  "@types/node": "^15.0.1",
36
35
  "@types/pluralize": "0.0.29",
37
- "jest": "26.6.3",
36
+ "msw": "^2.1.5",
38
37
  "prettier": "2.2.1",
39
- "supertest": "6.1.3",
40
- "ts-jest": "26.5.5",
41
38
  "tslint": "6.1.3",
42
- "typescript": "^5.3.3"
39
+ "typescript": "^5.3.3",
40
+ "vitest": "^1.2.1"
43
41
  },
44
42
  "dependencies": {
45
43
  "jose": "^5.2.0"
@@ -70,7 +70,18 @@ class FetchClient {
70
70
  buildUrl(path, params) {
71
71
  const url = new URL(this.config.baseURL + path);
72
72
  if (params) {
73
- Object.entries(params).forEach(([key, value]) => url.searchParams.append(key, value));
73
+ Object.entries(params).forEach(([key, value]) => {
74
+ // Send array values as individual values instead of a comma separated list
75
+ // e.g. key[]=1&key[]=2&key[]=3 instead of key=1,2,3
76
+ if (Array.isArray(value)) {
77
+ for (const val of value) {
78
+ url.searchParams.append(`${key}[]`, val);
79
+ }
80
+ }
81
+ else {
82
+ url.searchParams.append(key, value);
83
+ }
84
+ });
74
85
  }
75
86
  return url;
76
87
  }
@@ -1,3 +1,4 @@
1
+ import { TokenGrant } from "./userTokens";
1
2
  export interface KnockOptions {
2
3
  host?: string;
3
4
  }
@@ -57,6 +58,11 @@ export interface SignUserTokenOptions {
57
58
  signingKey?: string;
58
59
  /** The expiration time of the token in seconds. Defaults to 1 hour. */
59
60
  expiresInSeconds?: number;
61
+ /**
62
+ * A list of token grants to pass along with this token. The grants here provide permissions to
63
+ * the requested entities for the user
64
+ */
65
+ grants?: TokenGrant[];
60
66
  }
61
67
  export interface MethodOptions {
62
68
  idempotencyKey?: string;
@@ -0,0 +1,26 @@
1
+ export declare enum Grants {
2
+ SlackChannelsRead = "slack_channels/read",
3
+ ChannelDataRead = "channel_data/read",
4
+ ChannelDataWrite = "channel_data/write"
5
+ }
6
+ export type TokenGrantOptions = Grants[];
7
+ export type TokenEntity = TenantTokenEntity | UserTokenEntity | ObjectTokenEntity;
8
+ export interface TenantTokenEntity {
9
+ type: "tenant";
10
+ id: string;
11
+ collection?: never;
12
+ }
13
+ export interface ObjectTokenEntity {
14
+ type: "object";
15
+ id: string;
16
+ collection: string;
17
+ }
18
+ export interface UserTokenEntity {
19
+ type: "user";
20
+ id: string;
21
+ collection?: never;
22
+ }
23
+ export type TokenGrant = {
24
+ entity: string;
25
+ grants: Partial<Record<Grants, []>>;
26
+ };
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Grants = void 0;
4
+ var Grants;
5
+ (function (Grants) {
6
+ Grants["SlackChannelsRead"] = "slack_channels/read";
7
+ Grants["ChannelDataRead"] = "channel_data/read";
8
+ Grants["ChannelDataWrite"] = "channel_data/write";
9
+ })(Grants || (exports.Grants = Grants = {}));
@@ -7,6 +7,7 @@ import { Objects } from "./resources/objects";
7
7
  import { Messages } from "./resources/messages";
8
8
  import { Tenants } from "./resources/tenants";
9
9
  import { FetchResponse } from "./common/fetchClient";
10
+ import { TokenEntity, TokenGrant, TokenGrantOptions } from "./common/userTokens";
10
11
  declare class Knock {
11
12
  readonly key?: string | undefined;
12
13
  readonly options: KnockOptions;
@@ -29,6 +30,15 @@ declare class Knock {
29
30
  * @returns {Promise<string>} A JWT token that can be used to authenticate requests to the Knock API (e.g. by passing into the <KnockFeedProvider /> component)
30
31
  */
31
32
  static signUserToken(userId: string, options?: SignUserTokenOptions): Promise<string>;
33
+ /**
34
+ * Helper function to build user token grants to pass to the `signUserToken` method.
35
+ *
36
+ * @param entity {TokenEntity} The type of entity to build a grant for
37
+ * @param grants {TokenGrantOptions} A list of grants to give to the entity for the user
38
+ *
39
+ * @returns {TokenGrant} A single token grant that can be passed to the signUserToken function
40
+ */
41
+ static buildUserTokenGrant(entity: TokenEntity, grants: TokenGrantOptions): TokenGrant;
32
42
  post(path: string, entity: any, options?: PostAndPutOptions): Promise<FetchResponse>;
33
43
  put(path: string, entity: any, options?: PostAndPutOptions): Promise<FetchResponse>;
34
44
  delete(path: string, entity?: any): Promise<FetchResponse>;
@@ -36,4 +46,5 @@ declare class Knock {
36
46
  handleErrorResponse(path: string, error: any): void;
37
47
  emitWarning(warning: string): void;
38
48
  }
49
+ export declare function maybePrepareUserTokenGrants(grants: TokenGrant[] | undefined): Record<string, TokenGrant["grants"]> | undefined;
39
50
  export { Knock };
package/dist/src/knock.js CHANGED
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.Knock = void 0;
15
+ exports.Knock = exports.maybePrepareUserTokenGrants = void 0;
16
16
  const jose_1 = require("jose");
17
17
  const package_json_1 = require("../package.json");
18
18
  const exceptions_1 = require("./common/exceptions");
@@ -78,6 +78,7 @@ class Knock {
78
78
  const keyLike = yield (0, jose_1.importPKCS8)(signingKey, "RS256");
79
79
  return yield new jose_1.SignJWT({
80
80
  sub: userId,
81
+ grants: maybePrepareUserTokenGrants(options === null || options === void 0 ? void 0 : options.grants),
81
82
  iat: currentTime,
82
83
  exp: currentTime + expireInSeconds,
83
84
  })
@@ -85,6 +86,20 @@ class Knock {
85
86
  .sign(keyLike);
86
87
  });
87
88
  }
89
+ /**
90
+ * Helper function to build user token grants to pass to the `signUserToken` method.
91
+ *
92
+ * @param entity {TokenEntity} The type of entity to build a grant for
93
+ * @param grants {TokenGrantOptions} A list of grants to give to the entity for the user
94
+ *
95
+ * @returns {TokenGrant} A single token grant that can be passed to the signUserToken function
96
+ */
97
+ static buildUserTokenGrant(entity, grants) {
98
+ return {
99
+ entity: prepareTokenEntityUri(entity),
100
+ grants: grants.reduce((acc, grant) => (Object.assign(Object.assign({}, acc), { [grant]: [] })), {}),
101
+ };
102
+ }
88
103
  post(path, entity, options = {}) {
89
104
  return __awaiter(this, void 0, void 0, function* () {
90
105
  try {
@@ -192,3 +207,29 @@ function prepareSigningKey(key) {
192
207
  return Buffer.from(maybeSigningKey, "base64").toString("utf-8");
193
208
  throw new exceptions_1.NoSigningKeyProvidedException();
194
209
  }
210
+ function prepareTokenEntityUri(entity) {
211
+ switch (entity.type) {
212
+ case "user":
213
+ return `${DEFAULT_HOSTNAME}/v1/users/${entity.id}`;
214
+ case "tenant":
215
+ return `${DEFAULT_HOSTNAME}/v1/objects/$tenants/${entity.id}`;
216
+ case "object":
217
+ return `${DEFAULT_HOSTNAME}/v1/objects/${entity.collection}/${entity.id}`;
218
+ }
219
+ }
220
+ function maybePrepareUserTokenGrants(grants) {
221
+ if (!grants)
222
+ return undefined;
223
+ // Given a list of token grants, flattens them into a single object
224
+ // like: { "entity": { "slack_channels/read": [] } }
225
+ return grants.reduce((acc, grant) => {
226
+ if (acc[grant.entity]) {
227
+ const currentGrants = acc[grant.entity];
228
+ return Object.assign(Object.assign({}, acc), { [grant.entity]: Object.assign(Object.assign({}, currentGrants), grant.grants) });
229
+ }
230
+ else {
231
+ return Object.assign(Object.assign({}, acc), { [grant.entity]: grant.grants });
232
+ }
233
+ }, {});
234
+ }
235
+ exports.maybePrepareUserTokenGrants = maybePrepareUserTokenGrants;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knocklabs/node",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "description": "Library for interacting with the Knock API",
5
5
  "homepage": "https://github.com/knocklabs/knock-node",
6
6
  "author": "@knocklabs",
@@ -24,24 +24,22 @@
24
24
  "scripts": {
25
25
  "build": "tsc -p tsconfig.json",
26
26
  "lint": "tslint -p tsconfig.json -c tslint.json",
27
- "test": "jest",
28
- "test:watch": "jest --watch",
29
- "prettier": "prettier \"src/**/*.{js,ts,tsx}\" --check",
30
27
  "format": "prettier \"src/**/*.{js,ts,tsx}\" --write",
28
+ "format:check": "prettier \"src/**/*.{js,ts,tsx}\" --check",
29
+ "test": "vitest",
30
+ "coverage": "vitest run --coverage",
31
31
  "prepublishOnly": "npm run build"
32
32
  },
33
33
  "devDependencies": {
34
- "@types/jest": "26.0.23",
35
34
  "@types/node": "^15.0.1",
36
35
  "@types/pluralize": "0.0.29",
37
- "jest": "26.6.3",
36
+ "msw": "^2.1.5",
38
37
  "prettier": "2.2.1",
39
- "supertest": "6.1.3",
40
- "ts-jest": "26.5.5",
41
38
  "tslint": "6.1.3",
42
- "typescript": "^5.3.3"
39
+ "typescript": "^5.3.3",
40
+ "vitest": "^1.2.1"
43
41
  },
44
42
  "dependencies": {
45
43
  "jose": "^5.2.0"
46
44
  }
47
- }
45
+ }