@knocklabs/cli 0.1.22 → 0.2.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 (66) hide show
  1. package/README.md +191 -106
  2. package/bin/dev.js +4 -4
  3. package/dist/commands/commit/list.js +21 -1
  4. package/dist/commands/guide/activate.js +121 -0
  5. package/dist/commands/guide/generate-types.js +148 -0
  6. package/dist/commands/guide/get.js +139 -0
  7. package/dist/commands/guide/list.js +112 -0
  8. package/dist/commands/guide/pull.js +209 -0
  9. package/dist/commands/guide/push.js +171 -0
  10. package/dist/commands/guide/validate.js +148 -0
  11. package/dist/commands/knock.js +3 -0
  12. package/dist/commands/login.js +50 -0
  13. package/dist/commands/logout.js +48 -0
  14. package/dist/commands/whoami.js +6 -2
  15. package/dist/commands/workflow/generate-types.js +6 -5
  16. package/dist/lib/api-v1.js +74 -4
  17. package/dist/lib/auth.js +256 -0
  18. package/dist/lib/base-command.js +85 -12
  19. package/dist/lib/helpers/browser.js +25 -0
  20. package/dist/lib/helpers/const.js +4 -4
  21. package/dist/lib/helpers/date.js +3 -3
  22. package/dist/lib/helpers/error.js +8 -8
  23. package/dist/lib/helpers/flag.js +7 -7
  24. package/dist/lib/helpers/json.js +5 -5
  25. package/dist/lib/helpers/object.isomorphic.js +8 -8
  26. package/dist/lib/helpers/page.js +9 -9
  27. package/dist/lib/helpers/request.js +4 -4
  28. package/dist/lib/helpers/string.js +3 -3
  29. package/dist/lib/helpers/typegen.js +59 -0
  30. package/dist/lib/helpers/ux.js +3 -3
  31. package/dist/lib/marshal/email-layout/helpers.js +5 -5
  32. package/dist/lib/marshal/email-layout/processor.isomorphic.js +3 -3
  33. package/dist/lib/marshal/email-layout/reader.js +5 -5
  34. package/dist/lib/marshal/email-layout/writer.js +4 -4
  35. package/dist/lib/marshal/guide/helpers.js +283 -0
  36. package/dist/lib/marshal/guide/index.js +3 -0
  37. package/dist/lib/marshal/guide/processor.isomorphic.js +3 -3
  38. package/dist/lib/marshal/guide/reader.js +193 -0
  39. package/dist/lib/marshal/guide/writer.js +175 -0
  40. package/dist/lib/marshal/index.isomorphic.js +7 -7
  41. package/dist/lib/marshal/message-type/helpers.js +5 -5
  42. package/dist/lib/marshal/message-type/processor.isomorphic.js +3 -3
  43. package/dist/lib/marshal/message-type/reader.js +5 -5
  44. package/dist/lib/marshal/message-type/writer.js +4 -4
  45. package/dist/lib/marshal/partial/helpers.js +5 -5
  46. package/dist/lib/marshal/partial/processor.isomorphic.js +3 -3
  47. package/dist/lib/marshal/partial/reader.js +5 -5
  48. package/dist/lib/marshal/partial/writer.js +4 -4
  49. package/dist/lib/marshal/shared/const.isomorphic.js +3 -3
  50. package/dist/lib/marshal/shared/helpers.isomorphic.js +9 -2
  51. package/dist/lib/marshal/shared/helpers.js +4 -4
  52. package/dist/lib/marshal/translation/helpers.js +10 -10
  53. package/dist/lib/marshal/translation/processor.isomorphic.js +6 -6
  54. package/dist/lib/marshal/translation/writer.js +3 -3
  55. package/dist/lib/marshal/workflow/generator.js +4 -4
  56. package/dist/lib/marshal/workflow/helpers.js +53 -10
  57. package/dist/lib/marshal/workflow/processor.isomorphic.js +5 -5
  58. package/dist/lib/marshal/workflow/reader.js +5 -5
  59. package/dist/lib/marshal/workflow/writer.js +5 -5
  60. package/dist/lib/resources.js +3 -3
  61. package/dist/lib/types.js +4 -0
  62. package/dist/lib/urls.js +32 -0
  63. package/dist/lib/user-config.js +69 -31
  64. package/oclif.manifest.json +749 -114
  65. package/package.json +12 -11
  66. package/dist/lib/type-generator.js +0 -100
@@ -17,8 +17,9 @@ const _flag = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/helpers
17
17
  const _objectisomorphic = require("../../lib/helpers/object.isomorphic");
18
18
  const _page = require("../../lib/helpers/page");
19
19
  const _request = require("../../lib/helpers/request");
20
+ const _typegen = require("../../lib/helpers/typegen");
20
21
  const _ux = require("../../lib/helpers/ux");
21
- const _typegenerator = require("../../lib/type-generator");
22
+ const _workflow = /*#__PURE__*/ _interop_require_wildcard(require("../../lib/marshal/workflow"));
22
23
  function _define_property(obj, key, value) {
23
24
  if (key in obj) {
24
25
  Object.defineProperty(obj, key, {
@@ -82,17 +83,17 @@ class WorkflowGenerateTypes extends _basecommand.default {
82
83
  async run() {
83
84
  const { flags } = this.props;
84
85
  const fileExtension = flags["output-file"].abspath.split(".").pop();
85
- const targetLanguage = (0, _typegenerator.getLanguageFromExtension)(fileExtension);
86
+ const targetLanguage = (0, _typegen.getLanguageFromExtension)(fileExtension);
86
87
  if (!targetLanguage) {
87
88
  this.error(new _error.ApiError(`Unsupported file extension: ${fileExtension}. We currently support .ts, .rb, .go, .py files only.`));
88
89
  }
89
90
  _ux.spinner.start(`‣ Loading workflows`);
90
- // 1. List all workflows in the development environment.
91
+ // 1. List all workflows in the target environment.
91
92
  const workflows = await this.listAllWorkflows();
92
93
  _ux.spinner.stop();
93
94
  // 2. Generate types for all workflows.
94
95
  _ux.spinner.start(`‣ Generating types`);
95
- const { result, workflows: workflowsWithValidTypes } = await (0, _typegenerator.generateWorkflowTypes)(workflows, targetLanguage);
96
+ const { result, workflows: workflowsWithValidTypes } = await _workflow.generateWorkflowTypes(workflows, targetLanguage);
96
97
  _ux.spinner.stop();
97
98
  if (!result) {
98
99
  this.log(`‣ No workflows with valid trigger data JSON schema found, skipping type generation`);
@@ -125,7 +126,7 @@ class WorkflowGenerateTypes extends _basecommand.default {
125
126
  }, workflows) : workflows;
126
127
  }
127
128
  }
128
- _define_property(WorkflowGenerateTypes, "description", "Generate types for all workflows in the development environment and write them to a file.");
129
+ _define_property(WorkflowGenerateTypes, "description", "Generate types for all workflows in an environment and write them to a file.");
129
130
  _define_property(WorkflowGenerateTypes, "flags", {
130
131
  environment: _core.Flags.string({
131
132
  summary: "Select the environment to generate types for.",
@@ -29,9 +29,11 @@ function _interop_require_default(obj) {
29
29
  default: obj
30
30
  };
31
31
  }
32
- const DEFAULT_ORIGIN = "https://control.knock.app";
33
32
  const API_VERSION = "v1";
34
33
  class ApiV1 {
34
+ getToken(sessionContext) {
35
+ return sessionContext.session ? sessionContext.session.accessToken : sessionContext.token;
36
+ }
35
37
  async ping() {
36
38
  return this.get("/ping");
37
39
  }
@@ -113,6 +115,8 @@ class ApiV1 {
113
115
  const params = (0, _objectisomorphic.prune)({
114
116
  environment: flags.environment,
115
117
  promoted: flags.promoted,
118
+ resource_type: flags["resource-type"],
119
+ resource_id: flags["resource-id"],
116
120
  ...(0, _page.toPageParams)(flags)
117
121
  });
118
122
  return this.get("/commits", {
@@ -333,6 +337,65 @@ class ApiV1 {
333
337
  params
334
338
  });
335
339
  }
340
+ // By resources: Guides
341
+ async listGuides({ flags }) {
342
+ const params = (0, _objectisomorphic.prune)({
343
+ environment: flags.environment,
344
+ annotate: flags.annotate,
345
+ hide_uncommitted_changes: flags["hide-uncommitted-changes"],
346
+ include_json_schema: flags["include-json-schema"],
347
+ ...(0, _page.toPageParams)(flags)
348
+ });
349
+ return this.get("/guides", {
350
+ params
351
+ });
352
+ }
353
+ async getGuide({ args, flags }) {
354
+ const params = (0, _objectisomorphic.prune)({
355
+ environment: flags.environment,
356
+ annotate: flags.annotate,
357
+ hide_uncommitted_changes: flags["hide-uncommitted-changes"]
358
+ });
359
+ return this.get(`/guides/${args.guideKey}`, {
360
+ params
361
+ });
362
+ }
363
+ async validateGuide({ flags }, guide) {
364
+ const params = (0, _objectisomorphic.prune)({
365
+ environment: flags.environment
366
+ });
367
+ const data = {
368
+ guide
369
+ };
370
+ return this.put(`/guides/${guide.key}/validate`, data, {
371
+ params
372
+ });
373
+ }
374
+ async upsertGuide({ flags }, guide) {
375
+ const params = (0, _objectisomorphic.prune)({
376
+ environment: flags.environment,
377
+ annotate: flags.annotate,
378
+ commit: flags.commit,
379
+ commit_message: flags["commit-message"]
380
+ });
381
+ const data = {
382
+ guide
383
+ };
384
+ return this.put(`/guides/${guide.key}`, data, {
385
+ params
386
+ });
387
+ }
388
+ async activateGuide({ args, flags }) {
389
+ const params = (0, _objectisomorphic.prune)({
390
+ environment: flags.environment,
391
+ status: flags.status,
392
+ from: flags.from,
393
+ until: flags.until
394
+ });
395
+ return this.put(`/guides/${args.guideKey}/activate`, {}, {
396
+ params
397
+ });
398
+ }
336
399
  // By methods:
337
400
  async get(subpath, config) {
338
401
  return this.client.get(`/${API_VERSION}` + subpath, config);
@@ -340,13 +403,20 @@ class ApiV1 {
340
403
  async put(subpath, data, config) {
341
404
  return this.client.put(`/${API_VERSION}` + subpath, data, config);
342
405
  }
343
- constructor(flags, config){
406
+ constructor(sessionContext, config){
407
+ var _sessionContext_session;
344
408
  _define_property(this, "client", void 0);
345
- const baseURL = flags["api-origin"] || DEFAULT_ORIGIN;
409
+ const baseURL = sessionContext.apiOrigin;
410
+ const token = this.getToken(sessionContext);
411
+ var _sessionContext_session_clientId;
346
412
  this.client = _axios.default.create({
347
413
  baseURL,
348
414
  headers: {
349
- Authorization: `Bearer ${flags["service-token"]}`,
415
+ // Used to authenticate the request to the API.
416
+ Authorization: `Bearer ${token}`,
417
+ // Used in conjunction with the JWT access token, to allow the OAuth server to
418
+ // verify the client ID of the OAuth client that issued the access token.
419
+ "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,
350
420
  "User-Agent": `${config.userAgent}`
351
421
  },
352
422
  // Don't reject the promise based on a response status code.
@@ -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
+ };
@@ -10,8 +10,10 @@ Object.defineProperty(exports, "default", {
10
10
  });
11
11
  const _core = require("@oclif/core");
12
12
  const _apiv1 = /*#__PURE__*/ _interop_require_default(require("./api-v1"));
13
+ const _auth = /*#__PURE__*/ _interop_require_default(require("./auth"));
13
14
  const _runcontext = /*#__PURE__*/ _interop_require_wildcard(require("./run-context"));
14
- const _userconfig = /*#__PURE__*/ _interop_require_default(require("./user-config"));
15
+ const _urls = require("./urls");
16
+ const _userconfig = require("./user-config");
15
17
  function _define_property(obj, key, value) {
16
18
  if (key in obj) {
17
19
  Object.defineProperty(obj, key, {
@@ -71,24 +73,97 @@ function _interop_require_wildcard(obj, nodeInterop) {
71
73
  }
72
74
  return newObj;
73
75
  }
76
+ function sessionWithDefaultOrigins(sessionContext) {
77
+ var _sessionContext_apiOrigin, _sessionContext_dashboardOrigin, _sessionContext_authOrigin;
78
+ return {
79
+ ...sessionContext,
80
+ apiOrigin: (_sessionContext_apiOrigin = sessionContext.apiOrigin) !== null && _sessionContext_apiOrigin !== void 0 ? _sessionContext_apiOrigin : _urls.DEFAULT_API_URL,
81
+ dashboardOrigin: (_sessionContext_dashboardOrigin = sessionContext.dashboardOrigin) !== null && _sessionContext_dashboardOrigin !== void 0 ? _sessionContext_dashboardOrigin : _urls.DEFAULT_DASHBOARD_URL,
82
+ authOrigin: (_sessionContext_authOrigin = sessionContext.authOrigin) !== null && _sessionContext_authOrigin !== void 0 ? _sessionContext_authOrigin : _urls.DEFAULT_AUTH_URL
83
+ };
84
+ }
74
85
  class BaseCommand extends _core.Command {
75
86
  async init() {
76
87
  await super.init();
88
+ this.configStore = new _userconfig.UserConfigStore(this.config.configDir);
77
89
  // 1. Load user's config from the config dir, as available.
78
- await _userconfig.default.load(this.config.configDir);
90
+ await this.configStore.load();
79
91
  // 2. Parse flags and args, must come after the user config load.
80
92
  const { args, flags } = await this.parse(this.ctor);
81
93
  this.props = {
82
94
  args: args,
83
95
  flags: flags
84
96
  };
85
- // 3. Instantiate a knock api client.
86
- this.apiV1 = new _apiv1.default(this.props.flags, this.config);
87
- // 4. Load the run context of the invoked command.
97
+ // 3. Build the initial session context.
98
+ this.sessionContext = this.buildSessionContext();
99
+ // 4. If the command requires authentication, ensure the session is authenticated.
100
+ if (this.requiresAuth) {
101
+ this.ensureAuthenticated();
102
+ }
103
+ // 5. If the session context is an OAuth session, refresh the access token.
104
+ if (this.sessionContext.type === "oauth") {
105
+ await this.refreshAccessTokenForSession();
106
+ }
107
+ // 6. Instantiate a knock api client.
108
+ this.apiV1 = new _apiv1.default(this.sessionContext, this.config);
109
+ // 7. Load the run context of the invoked command.
88
110
  this.runContext = await _runcontext.load(this.id);
89
111
  }
112
+ buildSessionContext() {
113
+ const userConfig = this.configStore.get();
114
+ const session = userConfig.userSession;
115
+ // If the user has a session and a service token is not provided, use the session.
116
+ if (session && !this.props.flags["service-token"]) {
117
+ var _this_props_flags_apiorigin;
118
+ return sessionWithDefaultOrigins({
119
+ type: "oauth",
120
+ session,
121
+ apiOrigin: (_this_props_flags_apiorigin = this.props.flags["api-origin"]) !== null && _this_props_flags_apiorigin !== void 0 ? _this_props_flags_apiorigin : userConfig.apiOrigin,
122
+ dashboardOrigin: userConfig.dashboardOrigin,
123
+ authOrigin: userConfig.authOrigin
124
+ });
125
+ }
126
+ var _this_props_flags_servicetoken, _this_props_flags_apiorigin1;
127
+ // Otherwise, default to this being a service token session.
128
+ return sessionWithDefaultOrigins({
129
+ type: "service",
130
+ token: (_this_props_flags_servicetoken = this.props.flags["service-token"]) !== null && _this_props_flags_servicetoken !== void 0 ? _this_props_flags_servicetoken : userConfig.serviceToken,
131
+ apiOrigin: (_this_props_flags_apiorigin1 = this.props.flags["api-origin"]) !== null && _this_props_flags_apiorigin1 !== void 0 ? _this_props_flags_apiorigin1 : userConfig.apiOrigin,
132
+ dashboardOrigin: userConfig.dashboardOrigin,
133
+ authOrigin: userConfig.authOrigin
134
+ });
135
+ }
136
+ ensureAuthenticated() {
137
+ if (this.sessionContext.type === "service" && !this.sessionContext.token || this.sessionContext.type === "oauth" && !this.sessionContext.session) {
138
+ this.error("No token found. Refusing to run command.");
139
+ }
140
+ }
141
+ async refreshAccessTokenForSession() {
142
+ // Maybe refresh the access token?
143
+ try {
144
+ var _this_sessionContext_session, _this_sessionContext_session1;
145
+ var _this_sessionContext_session_clientId, _this_sessionContext_session_refreshToken;
146
+ const refreshedSession = await _auth.default.refreshAccessToken({
147
+ authUrl: this.sessionContext.authOrigin,
148
+ clientId: (_this_sessionContext_session_clientId = (_this_sessionContext_session = this.sessionContext.session) === null || _this_sessionContext_session === void 0 ? void 0 : _this_sessionContext_session.clientId) !== null && _this_sessionContext_session_clientId !== void 0 ? _this_sessionContext_session_clientId : "",
149
+ refreshToken: (_this_sessionContext_session_refreshToken = (_this_sessionContext_session1 = this.sessionContext.session) === null || _this_sessionContext_session1 === void 0 ? void 0 : _this_sessionContext_session1.refreshToken) !== null && _this_sessionContext_session_refreshToken !== void 0 ? _this_sessionContext_session_refreshToken : ""
150
+ });
151
+ this.debug("Successfully refreshed access token.");
152
+ // Update the user config to use the new session.
153
+ await this.configStore.set({
154
+ userSession: refreshedSession
155
+ });
156
+ // Update the session context to use the new session.
157
+ this.sessionContext = this.buildSessionContext();
158
+ } catch {
159
+ this.debug("Failed to refresh access token, clearing session.");
160
+ await this.configStore.set({
161
+ userSession: undefined
162
+ });
163
+ }
164
+ }
90
165
  constructor(...args){
91
- super(...args), _define_property(this, "props", void 0), _define_property(this, "apiV1", void 0), _define_property(this, "runContext", void 0);
166
+ super(...args), _define_property(this, "props", void 0), _define_property(this, "apiV1", void 0), _define_property(this, "runContext", void 0), _define_property(this, "sessionContext", void 0), _define_property(this, "configStore", void 0), _define_property(this, "requiresAuth", true);
92
167
  }
93
168
  }
94
169
  // Base flags are inherited by any command that extends BaseCommand.
@@ -99,17 +174,15 @@ _define_property(BaseCommand, "baseFlags", {
99
174
  // - if not available, fall back to user config
100
175
  "service-token": _core.Flags.string({
101
176
  summary: "The service token to authenticate with.",
102
- required: true,
177
+ required: false,
103
178
  multiple: false,
104
- env: "KNOCK_SERVICE_TOKEN",
105
- default: async ()=>_userconfig.default.get().serviceToken
179
+ env: "KNOCK_SERVICE_TOKEN"
106
180
  }),
107
- // Hidden flag to use a different api base url for development purposes.
181
+ // Hidden flags to use a different api url for development purposes.
108
182
  "api-origin": _core.Flags.string({
109
183
  hidden: true,
110
184
  required: false,
111
- multiple: false,
112
- default: async ()=>_userconfig.default.get().apiOrigin
185
+ multiple: false
113
186
  })
114
187
  });
115
188
  const _default = BaseCommand;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "browser", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return browser;
9
+ }
10
+ });
11
+ const _open = /*#__PURE__*/ _interop_require_default(require("open"));
12
+ function _interop_require_default(obj) {
13
+ return obj && obj.__esModule ? obj : {
14
+ default: obj
15
+ };
16
+ }
17
+ const browser = {
18
+ /**
19
+ * Opens a URL in the default browser
20
+ * @param url The URL to open
21
+ * @returns A promise that resolves when the URL is opened
22
+ */ async openUrl (url) {
23
+ await (0, _open.default)(url);
24
+ }
25
+ };
@@ -5,17 +5,17 @@ Object.defineProperty(exports, "__esModule", {
5
5
  function _export(target, all) {
6
6
  for(var name in all)Object.defineProperty(target, name, {
7
7
  enumerable: true,
8
- get: all[name]
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
9
  });
10
10
  }
11
11
  _export(exports, {
12
- KnockEnv: function() {
12
+ get KnockEnv () {
13
13
  return KnockEnv;
14
14
  },
15
- isTestEnv: function() {
15
+ get isTestEnv () {
16
16
  return isTestEnv;
17
17
  },
18
- sandboxDir: function() {
18
+ get sandboxDir () {
19
19
  return sandboxDir;
20
20
  }
21
21
  });
@@ -5,14 +5,14 @@ Object.defineProperty(exports, "__esModule", {
5
5
  function _export(target, all) {
6
6
  for(var name in all)Object.defineProperty(target, name, {
7
7
  enumerable: true,
8
- get: all[name]
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
9
  });
10
10
  }
11
11
  _export(exports, {
12
- formatDate: function() {
12
+ get formatDate () {
13
13
  return formatDate;
14
14
  },
15
- formatDateTime: function() {
15
+ get formatDateTime () {
16
16
  return formatDateTime;
17
17
  }
18
18
  });
@@ -5,29 +5,29 @@ Object.defineProperty(exports, "__esModule", {
5
5
  function _export(target, all) {
6
6
  for(var name in all)Object.defineProperty(target, name, {
7
7
  enumerable: true,
8
- get: all[name]
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
9
  });
10
10
  }
11
11
  _export(exports, {
12
- ApiError: function() {
12
+ get ApiError () {
13
13
  return ApiError;
14
14
  },
15
- JsonDataError: function() {
15
+ get JsonDataError () {
16
16
  return JsonDataError;
17
17
  },
18
- JsonSyntaxError: function() {
18
+ get JsonSyntaxError () {
19
19
  return JsonSyntaxError;
20
20
  },
21
- LiquidParseError: function() {
21
+ get LiquidParseError () {
22
22
  return LiquidParseError;
23
23
  },
24
- SourceError: function() {
24
+ get SourceError () {
25
25
  return SourceError;
26
26
  },
27
- formatError: function() {
27
+ get formatError () {
28
28
  return formatError;
29
29
  },
30
- formatErrors: function() {
30
+ get formatErrors () {
31
31
  return formatErrors;
32
32
  }
33
33
  });