@knocklabs/cli 0.1.23 → 0.2.1

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/bin/dev.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node_modules/.bin/ts-node
2
2
  // eslint-disable-next-line node/shebang, unicorn/prefer-top-level-await
3
- ;(async () => {
4
- const oclif = await import('@oclif/core')
5
- await oclif.execute({development: true, dir: __dirname})
6
- })()
3
+ (async () => {
4
+ const oclif = await import("@oclif/core");
5
+ await oclif.execute({ development: true, dir: __dirname });
6
+ })();
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "default", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return BranchCreate;
9
+ }
10
+ });
11
+ const _basecommand = /*#__PURE__*/ _interop_require_default(require("../../lib/base-command"));
12
+ const _arg = require("../../lib/helpers/arg");
13
+ const _request = require("../../lib/helpers/request");
14
+ function _define_property(obj, key, value) {
15
+ if (key in obj) {
16
+ Object.defineProperty(obj, key, {
17
+ value: value,
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true
21
+ });
22
+ } else {
23
+ obj[key] = value;
24
+ }
25
+ return obj;
26
+ }
27
+ function _interop_require_default(obj) {
28
+ return obj && obj.__esModule ? obj : {
29
+ default: obj
30
+ };
31
+ }
32
+ class BranchCreate extends _basecommand.default {
33
+ async run() {
34
+ const { args, flags } = this.props;
35
+ const resp = await this.request(args.slug);
36
+ if (flags.json) return resp;
37
+ this.render(resp);
38
+ }
39
+ async request(slug) {
40
+ return (0, _request.withSpinnerV2)(()=>this.apiV1.mgmtClient.post(`/v1/branches/${slug}`));
41
+ }
42
+ async render(data) {
43
+ this.log(`‣ Successfully created branch \`${data.slug}\``);
44
+ this.log(` Created at: ${data.created_at}`);
45
+ }
46
+ }
47
+ // Hide until branches are released in GA
48
+ _define_property(BranchCreate, "hidden", true);
49
+ _define_property(BranchCreate, "summary", "Creates a new branch off of the development environment.");
50
+ _define_property(BranchCreate, "enableJsonFlag", true);
51
+ _define_property(BranchCreate, "args", {
52
+ slug: _arg.CustomArgs.slugArg({
53
+ required: true,
54
+ description: "The slug for the new branch"
55
+ })
56
+ });
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "default", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return BranchDelete;
9
+ }
10
+ });
11
+ const _core = require("@oclif/core");
12
+ const _basecommand = /*#__PURE__*/ _interop_require_default(require("../../lib/base-command"));
13
+ const _arg = require("../../lib/helpers/arg");
14
+ const _request = require("../../lib/helpers/request");
15
+ const _ux = require("../../lib/helpers/ux");
16
+ function _define_property(obj, key, value) {
17
+ if (key in obj) {
18
+ Object.defineProperty(obj, key, {
19
+ value: value,
20
+ enumerable: true,
21
+ configurable: true,
22
+ writable: true
23
+ });
24
+ } else {
25
+ obj[key] = value;
26
+ }
27
+ return obj;
28
+ }
29
+ function _interop_require_default(obj) {
30
+ return obj && obj.__esModule ? obj : {
31
+ default: obj
32
+ };
33
+ }
34
+ class BranchDelete extends _basecommand.default {
35
+ async run() {
36
+ const { args, flags } = this.props;
37
+ // Confirm before deleting the branch, unless forced
38
+ const prompt = `Delete branch \`${args.slug}\`?`;
39
+ const input = flags.force || await (0, _ux.promptToConfirm)(prompt);
40
+ if (!input) return;
41
+ await (0, _request.withSpinnerV2)(()=>this.apiV1.mgmtClient.delete(`/v1/branches/${args.slug}`), {
42
+ action: "‣ Deleting branch"
43
+ });
44
+ this.log(`‣ Successfully deleted branch \`${args.slug}\``);
45
+ }
46
+ }
47
+ // Hide until branches are released in GA
48
+ _define_property(BranchDelete, "hidden", true);
49
+ _define_property(BranchDelete, "summary", "Deletes an existing branch with the given slug.");
50
+ _define_property(BranchDelete, "args", {
51
+ slug: _arg.CustomArgs.slugArg({
52
+ required: true,
53
+ description: "The slug of the branch to delete"
54
+ })
55
+ });
56
+ _define_property(BranchDelete, "flags", {
57
+ force: _core.Flags.boolean({
58
+ summary: "Remove the confirmation prompt."
59
+ })
60
+ });
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "default", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return BranchList;
9
+ }
10
+ });
11
+ const _core = require("@oclif/core");
12
+ const _basecommand = /*#__PURE__*/ _interop_require_default(require("../../lib/base-command"));
13
+ const _date = require("../../lib/helpers/date");
14
+ const _page = require("../../lib/helpers/page");
15
+ const _request = require("../../lib/helpers/request");
16
+ function _define_property(obj, key, value) {
17
+ if (key in obj) {
18
+ Object.defineProperty(obj, key, {
19
+ value: value,
20
+ enumerable: true,
21
+ configurable: true,
22
+ writable: true
23
+ });
24
+ } else {
25
+ obj[key] = value;
26
+ }
27
+ return obj;
28
+ }
29
+ function _interop_require_default(obj) {
30
+ return obj && obj.__esModule ? obj : {
31
+ default: obj
32
+ };
33
+ }
34
+ class BranchList extends _basecommand.default {
35
+ async run() {
36
+ const resp = await this.request();
37
+ const { flags } = this.props;
38
+ if (flags.json) return resp;
39
+ this.render(resp);
40
+ }
41
+ async request(pageParams = {}) {
42
+ const queryParams = (0, _page.toPageParams)({
43
+ ...this.props.flags,
44
+ ...pageParams
45
+ });
46
+ return (0, _request.withSpinnerV2)(()=>this.apiV1.mgmtClient.get("/v1/branches", {
47
+ query: queryParams
48
+ }));
49
+ }
50
+ async render(data) {
51
+ const { entries } = data;
52
+ this.log(`‣ Showing ${entries.length} branches off of the development environment\n`);
53
+ _core.ux.table(entries, {
54
+ slug: {
55
+ header: "Slug"
56
+ },
57
+ created_at: {
58
+ header: "Created at",
59
+ get: (entry)=>(0, _date.formatDate)(entry.created_at)
60
+ },
61
+ updated_at: {
62
+ header: "Updated at",
63
+ get: (entry)=>(0, _date.formatDate)(entry.updated_at)
64
+ },
65
+ last_commit_at: {
66
+ header: "Last commit at",
67
+ get: (entry)=>entry.last_commit_at ? (0, _date.formatDate)(entry.last_commit_at) : "Never"
68
+ }
69
+ });
70
+ return this.prompt(data);
71
+ }
72
+ async prompt(data) {
73
+ const { page_info } = data;
74
+ const pageAction = await (0, _page.maybePromptPageAction)(page_info);
75
+ const pageParams = pageAction && (0, _page.paramsForPageAction)(pageAction, page_info);
76
+ if (pageParams) {
77
+ this.log("\n");
78
+ const resp = await this.request(pageParams);
79
+ return this.render(resp);
80
+ }
81
+ }
82
+ }
83
+ // Hide until branches are released in GA
84
+ _define_property(BranchList, "hidden", true);
85
+ _define_property(BranchList, "summary", "Display all existing branches off of the development environment.");
86
+ _define_property(BranchList, "flags", {
87
+ ..._page.pageFlags
88
+ });
89
+ _define_property(BranchList, "enableJsonFlag", true);
@@ -112,6 +112,9 @@ class Knock extends _basecommand.default {
112
112
  this.log("");
113
113
  this.log("Thank you for using Knock, and have a nice day! 🙂");
114
114
  }
115
+ constructor(...args){
116
+ super(...args), _define_property(this, "requiresAuth", false);
117
+ }
115
118
  }
116
119
  // Because, it's a secret :)
117
120
  _define_property(Knock, "hidden", true);
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "default", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return Login;
9
+ }
10
+ });
11
+ const _auth = /*#__PURE__*/ _interop_require_default(require("../lib/auth"));
12
+ const _basecommand = /*#__PURE__*/ _interop_require_default(require("../lib/base-command"));
13
+ const _ux = require("../lib/helpers/ux");
14
+ function _define_property(obj, key, value) {
15
+ if (key in obj) {
16
+ Object.defineProperty(obj, key, {
17
+ value: value,
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true
21
+ });
22
+ } else {
23
+ obj[key] = value;
24
+ }
25
+ return obj;
26
+ }
27
+ function _interop_require_default(obj) {
28
+ return obj && obj.__esModule ? obj : {
29
+ default: obj
30
+ };
31
+ }
32
+ class Login extends _basecommand.default {
33
+ async run() {
34
+ const { flags } = this.props;
35
+ if (flags["service-token"]) {
36
+ this.log("Service token provided, skipping login.");
37
+ return;
38
+ }
39
+ _ux.spinner.start("‣ Authenticating with Knock...");
40
+ const resp = await _auth.default.waitForAccessToken(this.sessionContext.dashboardOrigin, this.sessionContext.authOrigin);
41
+ _ux.spinner.stop();
42
+ await this.configStore.set({
43
+ userSession: resp
44
+ });
45
+ this.log("‣ Successfully authenticated with Knock.");
46
+ }
47
+ constructor(...args){
48
+ super(...args), _define_property(this, "requiresAuth", false);
49
+ }
50
+ }
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "default", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return Logout;
9
+ }
10
+ });
11
+ const _basecommand = /*#__PURE__*/ _interop_require_default(require("../lib/base-command"));
12
+ const _ux = require("../lib/helpers/ux");
13
+ function _define_property(obj, key, value) {
14
+ if (key in obj) {
15
+ Object.defineProperty(obj, key, {
16
+ value: value,
17
+ enumerable: true,
18
+ configurable: true,
19
+ writable: true
20
+ });
21
+ } else {
22
+ obj[key] = value;
23
+ }
24
+ return obj;
25
+ }
26
+ function _interop_require_default(obj) {
27
+ return obj && obj.__esModule ? obj : {
28
+ default: obj
29
+ };
30
+ }
31
+ class Logout extends _basecommand.default {
32
+ async run() {
33
+ const { flags } = this.props;
34
+ if (flags["service-token"]) {
35
+ this.log("Service token provided, skipping logout.");
36
+ return;
37
+ }
38
+ _ux.spinner.start("‣ Logging out of Knock...");
39
+ await this.configStore.set({
40
+ userSession: undefined
41
+ });
42
+ _ux.spinner.stop();
43
+ this.log("‣ Successfully logged out of Knock. See you around.");
44
+ }
45
+ constructor(...args){
46
+ super(...args), _define_property(this, "requiresAuth", false);
47
+ }
48
+ }
@@ -31,13 +31,16 @@ function _interop_require_default(obj) {
31
31
  }
32
32
  class Whoami extends _basecommand.default {
33
33
  async run() {
34
- const resp = await (0, _request.withSpinner)(()=>this.apiV1.whoami());
34
+ const resp = await (0, _request.withSpinnerV2)(()=>this.apiV1.mgmtClient.auth.verify());
35
35
  const { flags } = this.props;
36
- if (flags.json) return resp.data;
37
- this.log(`‣ Successfully verified the provided service token:`);
38
- const info = [
39
- `Account name: ${resp.data.account_name}`,
40
- `Service token name: ${resp.data.service_token_name}`
36
+ if (flags.json) return resp;
37
+ this.log(`‣ Successfully authenticated:`);
38
+ const info = resp.service_token_name ? [
39
+ `Account name: ${resp.account_name}`,
40
+ `Service token name: ${resp.service_token_name}`
41
+ ] : [
42
+ `Account name: ${resp.account_name}`,
43
+ `User ID: ${resp.user_id}`
41
44
  ];
42
45
  this.log((0, _string.indentString)(info.join("\n"), 4));
43
46
  }
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "default", {
8
8
  return ApiV1;
9
9
  }
10
10
  });
11
+ const _mgmt = /*#__PURE__*/ _interop_require_default(require("@knocklabs/mgmt"));
11
12
  const _axios = /*#__PURE__*/ _interop_require_default(require("axios"));
12
13
  const _objectisomorphic = require("./helpers/object.isomorphic");
13
14
  const _page = require("./helpers/page");
@@ -29,9 +30,16 @@ function _interop_require_default(obj) {
29
30
  default: obj
30
31
  };
31
32
  }
32
- const DEFAULT_ORIGIN = "https://control.knock.app";
33
33
  const API_VERSION = "v1";
34
+ /**
35
+ * KnockMgmt client requires a service token, but we set the Authorization
36
+ * request header directly, so use a placeholder when service token is not
37
+ * provided.
38
+ */ const PLACEHOLDER_SERVICE_TOKEN = "placeholder-service-token";
34
39
  class ApiV1 {
40
+ getToken(sessionContext) {
41
+ return sessionContext.session ? sessionContext.session.accessToken : sessionContext.token;
42
+ }
35
43
  async ping() {
36
44
  return this.get("/ping");
37
45
  }
@@ -401,17 +409,32 @@ class ApiV1 {
401
409
  async put(subpath, data, config) {
402
410
  return this.client.put(`/${API_VERSION}` + subpath, data, config);
403
411
  }
404
- constructor(flags, config){
412
+ constructor(sessionContext, config){
413
+ var _sessionContext_session;
405
414
  _define_property(this, "client", void 0);
406
- const baseURL = flags["api-origin"] || DEFAULT_ORIGIN;
415
+ _define_property(this, "mgmtClient", void 0);
416
+ const baseURL = sessionContext.apiOrigin;
417
+ const token = this.getToken(sessionContext);
418
+ var _sessionContext_session_clientId;
419
+ const headers = {
420
+ // Used to authenticate the request to the API.
421
+ Authorization: `Bearer ${token}`,
422
+ // Used in conjunction with the JWT access token, to allow the OAuth server to
423
+ // verify the client ID of the OAuth client that issued the access token.
424
+ "x-knock-client-id": (_sessionContext_session_clientId = (_sessionContext_session = sessionContext.session) === null || _sessionContext_session === void 0 ? void 0 : _sessionContext_session.clientId) !== null && _sessionContext_session_clientId !== void 0 ? _sessionContext_session_clientId : undefined,
425
+ "User-Agent": `${config.userAgent}`
426
+ };
407
427
  this.client = _axios.default.create({
408
428
  baseURL,
409
- headers: {
410
- Authorization: `Bearer ${flags["service-token"]}`,
411
- "User-Agent": `${config.userAgent}`
412
- },
429
+ headers,
413
430
  // Don't reject the promise based on a response status code.
414
431
  validateStatus: null
415
432
  });
433
+ // This should eventually replace the Axios client
434
+ this.mgmtClient = new _mgmt.default({
435
+ serviceToken: sessionContext.token || PLACEHOLDER_SERVICE_TOKEN,
436
+ baseURL,
437
+ defaultHeaders: headers
438
+ });
416
439
  }
417
440
  }
@@ -0,0 +1,256 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get default () {
13
+ return _default;
14
+ },
15
+ get exchangeCodeForToken () {
16
+ return exchangeCodeForToken;
17
+ },
18
+ get getOAuthServerUrls () {
19
+ return getOAuthServerUrls;
20
+ },
21
+ get refreshAccessToken () {
22
+ return refreshAccessToken;
23
+ },
24
+ get registerClient () {
25
+ return registerClient;
26
+ },
27
+ get waitForAccessToken () {
28
+ return waitForAccessToken;
29
+ }
30
+ });
31
+ const _nodecrypto = /*#__PURE__*/ _interop_require_default(require("node:crypto"));
32
+ const _nodehttp = /*#__PURE__*/ _interop_require_default(require("node:http"));
33
+ const _browser = require("./helpers/browser");
34
+ const _urls = require("./urls");
35
+ function _interop_require_default(obj) {
36
+ return obj && obj.__esModule ? obj : {
37
+ default: obj
38
+ };
39
+ }
40
+ const DEFAULT_TIMEOUT = 5000;
41
+ function createChallenge() {
42
+ // PKCE code verifier and challenge
43
+ const codeVerifier = _nodecrypto.default.randomBytes(32).toString("base64url");
44
+ const codeChallenge = _nodecrypto.default.createHash("sha256").update(codeVerifier).digest("base64").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
45
+ const state = _nodecrypto.default.randomUUID();
46
+ return {
47
+ codeVerifier,
48
+ codeChallenge,
49
+ state
50
+ };
51
+ }
52
+ async function getOAuthServerUrls(apiUrl) {
53
+ const { protocol, host } = new URL(apiUrl);
54
+ const wellKnownUrl = `${protocol}//${host}/.well-known/oauth-authorization-server`;
55
+ const response = await fetch(wellKnownUrl, {
56
+ signal: AbortSignal.timeout(DEFAULT_TIMEOUT)
57
+ });
58
+ if (response.ok) {
59
+ const data = await response.json();
60
+ return {
61
+ registrationEndpoint: data.registration_endpoint,
62
+ authorizationEndpoint: data.authorization_endpoint,
63
+ tokenEndpoint: data.token_endpoint,
64
+ issuer: data.issuer
65
+ };
66
+ }
67
+ throw new Error("Failed to fetch OAuth server metadata");
68
+ }
69
+ async function registerClient(registrationEndpoint, redirectUri) {
70
+ const registrationResponse = await fetch(registrationEndpoint, {
71
+ method: "POST",
72
+ headers: {
73
+ "Content-Type": "application/json"
74
+ },
75
+ body: JSON.stringify({
76
+ client_name: "Knock CLI",
77
+ token_endpoint_auth_method: "none",
78
+ grant_types: [
79
+ "authorization_code"
80
+ ],
81
+ response_types: [
82
+ "code"
83
+ ],
84
+ redirect_uris: [
85
+ redirectUri
86
+ ]
87
+ }),
88
+ signal: AbortSignal.timeout(DEFAULT_TIMEOUT)
89
+ });
90
+ if (!registrationResponse.ok) {
91
+ console.log(await registrationResponse.json());
92
+ throw new Error(`Could not register client with OAuth server`);
93
+ }
94
+ const registrationData = await registrationResponse.json();
95
+ return registrationData.client_id;
96
+ }
97
+ async function parseTokenResponse(response) {
98
+ const data = await response.json();
99
+ return {
100
+ accessToken: data.access_token,
101
+ refreshToken: data.refresh_token,
102
+ idToken: data.id_token,
103
+ expiresAt: new Date(Date.now() + data.expires_in * 1000)
104
+ };
105
+ }
106
+ async function exchangeCodeForToken(params) {
107
+ const response = await fetch(params.tokenEndpoint, {
108
+ method: "POST",
109
+ headers: {
110
+ "Content-Type": "application/x-www-form-urlencoded"
111
+ },
112
+ body: new URLSearchParams({
113
+ grant_type: "authorization_code",
114
+ client_id: params.clientId,
115
+ code: params.code,
116
+ code_verifier: params.codeVerifier,
117
+ redirect_uri: params.redirectUri
118
+ }),
119
+ signal: AbortSignal.timeout(5000)
120
+ });
121
+ if (!response.ok) {
122
+ let errorDescription;
123
+ try {
124
+ const errorResponse = await response.json();
125
+ errorDescription = errorResponse.error_description || errorResponse.error;
126
+ } catch {
127
+ // ignore
128
+ }
129
+ return {
130
+ error: errorDescription !== null && errorDescription !== void 0 ? errorDescription : "unknown error"
131
+ };
132
+ }
133
+ return {
134
+ ...await parseTokenResponse(response),
135
+ clientId: params.clientId
136
+ };
137
+ }
138
+ async function refreshAccessToken(params) {
139
+ const { tokenEndpoint } = await getOAuthServerUrls(params.authUrl);
140
+ const response = await fetch(tokenEndpoint, {
141
+ method: "POST",
142
+ headers: {
143
+ "Content-Type": "application/x-www-form-urlencoded"
144
+ },
145
+ body: new URLSearchParams({
146
+ grant_type: "refresh_token",
147
+ client_id: params.clientId,
148
+ refresh_token: params.refreshToken
149
+ }),
150
+ signal: AbortSignal.timeout(5000)
151
+ });
152
+ if (!response.ok) {
153
+ throw new Error("Failed to refresh access token");
154
+ }
155
+ return {
156
+ ...await parseTokenResponse(response),
157
+ clientId: params.clientId
158
+ };
159
+ }
160
+ async function waitForAccessToken(dashboardUrl, authUrl) {
161
+ const { authorizationEndpoint, tokenEndpoint, registrationEndpoint } = await getOAuthServerUrls(authUrl);
162
+ let resolve;
163
+ let reject;
164
+ const promise = new Promise((res, rej)=>{
165
+ resolve = res;
166
+ reject = rej;
167
+ });
168
+ const { codeVerifier, codeChallenge, state } = createChallenge();
169
+ const timeout = setTimeout(()=>{
170
+ cleanupAndReject(`authentication timed out after ${DEFAULT_TIMEOUT / 1000} seconds`);
171
+ }, 60000);
172
+ function cleanupAndReject(message) {
173
+ cleanup();
174
+ reject(new Error(`Could not authenticate: ${message}`));
175
+ }
176
+ function cleanup() {
177
+ clearTimeout(timeout);
178
+ server.close();
179
+ server.closeAllConnections();
180
+ }
181
+ const server = _nodehttp.default.createServer();
182
+ server.listen();
183
+ const address = server.address();
184
+ if (address === null || typeof address !== "object") {
185
+ throw new Error("Could not start server");
186
+ }
187
+ const callbackPath = "/oauth_callback";
188
+ const redirectUri = `http://localhost:${address.port}${callbackPath}`;
189
+ const clientId = await registerClient(registrationEndpoint, redirectUri);
190
+ const params = {
191
+ response_type: "code",
192
+ client_id: clientId,
193
+ redirect_uri: redirectUri,
194
+ state,
195
+ code_challenge: codeChallenge,
196
+ code_challenge_method: "S256",
197
+ scope: "openid email offline_access"
198
+ };
199
+ const browserUrl = `${authorizationEndpoint}?${new URLSearchParams(params).toString()}`;
200
+ server.on("request", async (req, res)=>{
201
+ if (!clientId || !redirectUri) {
202
+ res.writeHead(500).end("Something went wrong");
203
+ cleanupAndReject("something went wrong");
204
+ return;
205
+ }
206
+ var _req_url;
207
+ const url = new URL((_req_url = req.url) !== null && _req_url !== void 0 ? _req_url : "/", "http://127.0.0.1");
208
+ if (url.pathname !== callbackPath) {
209
+ res.writeHead(404).end("Invalid path");
210
+ cleanupAndReject("invalid path");
211
+ return;
212
+ }
213
+ const error = url.searchParams.get("error");
214
+ if (error) {
215
+ res.writeHead(400).end("Could not authenticate");
216
+ const errorDescription = url.searchParams.get("error_description");
217
+ cleanupAndReject(`${errorDescription || error} `);
218
+ return;
219
+ }
220
+ const code = url.searchParams.get("code");
221
+ if (!code) {
222
+ res.writeHead(400).end("Could not authenticate");
223
+ cleanupAndReject("no code provided");
224
+ return;
225
+ }
226
+ const response = await exchangeCodeForToken({
227
+ tokenEndpoint,
228
+ clientId,
229
+ code,
230
+ codeVerifier,
231
+ redirectUri
232
+ });
233
+ if ("error" in response) {
234
+ res.writeHead(302, {
235
+ location: (0, _urls.authErrorUrl)(dashboardUrl, "Could not authenticate: unable to fetch access token")
236
+ }).end("Could not authenticate");
237
+ cleanupAndReject(JSON.stringify(response.error));
238
+ return;
239
+ }
240
+ res.writeHead(302, {
241
+ location: (0, _urls.authSuccessUrl)(dashboardUrl)
242
+ }).end("Authentication successful");
243
+ cleanup();
244
+ resolve({
245
+ ...response,
246
+ clientId
247
+ });
248
+ });
249
+ console.log(`Opened web browser to facilitate auth: ${browserUrl}`);
250
+ _browser.browser.openUrl(browserUrl);
251
+ return promise;
252
+ }
253
+ const _default = {
254
+ waitForAccessToken,
255
+ refreshAccessToken
256
+ };