@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.
@@ -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,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "CustomArgs", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return CustomArgs;
9
+ }
10
+ });
11
+ const _core = require("@oclif/core");
12
+ const slugArg = _core.Args.custom({
13
+ parse: async (str)=>{
14
+ const slug = str.toLowerCase().trim().replace(/\s+/g, "-");
15
+ if (!slug) {
16
+ throw new Error("Invalid slug provided");
17
+ }
18
+ return slug;
19
+ }
20
+ });
21
+ const CustomArgs = {
22
+ slugArg
23
+ };
@@ -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
+ };
@@ -12,16 +12,28 @@ _export(exports, {
12
12
  get formatErrorRespMessage () {
13
13
  return formatErrorRespMessage;
14
14
  },
15
+ get formatMgmtError () {
16
+ return formatMgmtError;
17
+ },
15
18
  get isSuccessResp () {
16
19
  return isSuccessResp;
17
20
  },
18
21
  get withSpinner () {
19
22
  return withSpinner;
23
+ },
24
+ get withSpinnerV2 () {
25
+ return withSpinnerV2;
20
26
  }
21
27
  });
28
+ const _mgmt = /*#__PURE__*/ _interop_require_default(require("@knocklabs/mgmt"));
22
29
  const _core = require("@oclif/core");
23
30
  const _error = require("./error");
24
31
  const _ux = require("./ux");
32
+ function _interop_require_default(obj) {
33
+ return obj && obj.__esModule ? obj : {
34
+ default: obj
35
+ };
36
+ }
25
37
  const isSuccessResp = (resp)=>resp.status >= 200 && resp.status < 300;
26
38
  const formatErrorRespMessage = ({ status, data })=>{
27
39
  if (status === 500) {
@@ -36,16 +48,50 @@ const formatErrorRespMessage = ({ status, data })=>{
36
48
  }
37
49
  return message;
38
50
  };
51
+ const formatMgmtError = (apiError)=>{
52
+ if (apiError.status === 500) {
53
+ return "An internal server error occurred";
54
+ }
55
+ var _apiError_error_message;
56
+ // Prefer the error message from the error object over
57
+ // the error message formatted by the Stainless SDK
58
+ const description = `${(_apiError_error_message = apiError.error.message) !== null && _apiError_error_message !== void 0 ? _apiError_error_message : apiError.message} (status: ${apiError.status})`;
59
+ var _apiError_error_errors;
60
+ const inputErrors = (_apiError_error_errors = apiError.error.errors) !== null && _apiError_error_errors !== void 0 ? _apiError_error_errors : [];
61
+ if (Array.isArray(inputErrors) && inputErrors.length > 0) {
62
+ const errs = inputErrors.map((e)=>new _error.JsonDataError(e.message, e.field));
63
+ return errs.length === 0 ? description : description + "\n\n" + (0, _error.formatErrors)(errs, {
64
+ indentBy: 2
65
+ });
66
+ }
67
+ return description;
68
+ };
39
69
  const withSpinner = async (requestFn, opts = {})=>{
40
- const { action = "‣ Loading", ensureSuccess = true } = opts;
70
+ const { action = "‣ Loading" } = opts;
41
71
  // Suppress printing the spinner in tests, oclif doesn't for some reasons.
42
72
  _ux.spinner.start(action);
43
73
  const resp = await requestFn();
44
74
  // Error out before the action stop so the spinner can update accordingly.
45
- if (ensureSuccess && !isSuccessResp(resp)) {
75
+ if (!isSuccessResp(resp)) {
46
76
  const message = formatErrorRespMessage(resp);
47
77
  _core.ux.error(new _error.ApiError(message));
48
78
  }
49
79
  _ux.spinner.stop();
50
80
  return resp;
51
81
  };
82
+ const withSpinnerV2 = async (requestFn, opts = {})=>{
83
+ const { action = "‣ Loading" } = opts;
84
+ // Suppress printing the spinner in tests, oclif doesn't for some reasons.
85
+ _ux.spinner.start(action);
86
+ try {
87
+ const resp = await requestFn();
88
+ _ux.spinner.stop();
89
+ return resp;
90
+ } catch (error) {
91
+ if (error instanceof _mgmt.default.APIError) {
92
+ const message = formatMgmtError(error);
93
+ return _core.ux.error(new _error.ApiError(message));
94
+ }
95
+ throw error;
96
+ }
97
+ };
@@ -23,16 +23,20 @@ _export(exports, {
23
23
  get buildPartialDirBundle () {
24
24
  return _processorisomorphic3.buildPartialDirBundle;
25
25
  },
26
+ get buildReusableStepDirBundle () {
27
+ return _processorisomorphic4.buildReusableStepDirBundle;
28
+ },
26
29
  get buildTranslationDirBundle () {
27
- return _processorisomorphic4.buildTranslationDirBundle;
30
+ return _processorisomorphic5.buildTranslationDirBundle;
28
31
  },
29
32
  get buildWorkflowDirBundle () {
30
- return _processorisomorphic5.buildWorkflowDirBundle;
33
+ return _processorisomorphic6.buildWorkflowDirBundle;
31
34
  }
32
35
  });
33
36
  const _processorisomorphic = require("./email-layout/processor.isomorphic");
34
37
  const _processorisomorphic1 = require("./guide/processor.isomorphic");
35
38
  const _processorisomorphic2 = require("./message-type/processor.isomorphic");
36
39
  const _processorisomorphic3 = require("./partial/processor.isomorphic");
37
- const _processorisomorphic4 = require("./translation/processor.isomorphic");
38
- const _processorisomorphic5 = require("./workflow/processor.isomorphic");
40
+ const _processorisomorphic4 = require("./reusable-step/processor.isomorphic");
41
+ const _processorisomorphic5 = require("./translation/processor.isomorphic");
42
+ const _processorisomorphic6 = require("./workflow/processor.isomorphic");
@@ -0,0 +1,72 @@
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 isReusableStepDir () {
13
+ return isReusableStepDir;
14
+ },
15
+ get lsReusableStepJson () {
16
+ return lsReusableStepJson;
17
+ },
18
+ get reusableStepJsonPath () {
19
+ return reusableStepJsonPath;
20
+ }
21
+ });
22
+ const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
23
+ const _fsextra = /*#__PURE__*/ _interop_require_wildcard(require("fs-extra"));
24
+ const _processorisomorphic = require("./processor.isomorphic");
25
+ function _getRequireWildcardCache(nodeInterop) {
26
+ if (typeof WeakMap !== "function") return null;
27
+ var cacheBabelInterop = new WeakMap();
28
+ var cacheNodeInterop = new WeakMap();
29
+ return (_getRequireWildcardCache = function(nodeInterop) {
30
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
31
+ })(nodeInterop);
32
+ }
33
+ function _interop_require_wildcard(obj, nodeInterop) {
34
+ if (!nodeInterop && obj && obj.__esModule) {
35
+ return obj;
36
+ }
37
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
38
+ return {
39
+ default: obj
40
+ };
41
+ }
42
+ var cache = _getRequireWildcardCache(nodeInterop);
43
+ if (cache && cache.has(obj)) {
44
+ return cache.get(obj);
45
+ }
46
+ var newObj = {
47
+ __proto__: null
48
+ };
49
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
50
+ for(var key in obj){
51
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
52
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
53
+ if (desc && (desc.get || desc.set)) {
54
+ Object.defineProperty(newObj, key, desc);
55
+ } else {
56
+ newObj[key] = obj[key];
57
+ }
58
+ }
59
+ }
60
+ newObj.default = obj;
61
+ if (cache) {
62
+ cache.set(obj, newObj);
63
+ }
64
+ return newObj;
65
+ }
66
+ const reusableStepJsonPath = (reusableStepDirCtx)=>_nodepath.resolve(reusableStepDirCtx.abspath, _processorisomorphic.REUSABLE_STEP_JSON);
67
+ const isReusableStepDir = async (dirPath)=>Boolean(await lsReusableStepJson(dirPath));
68
+ const lsReusableStepJson = async (dirPath)=>{
69
+ const reusableStepJsonPath = _nodepath.resolve(dirPath, _processorisomorphic.REUSABLE_STEP_JSON);
70
+ const exists = await _fsextra.pathExists(reusableStepJsonPath);
71
+ return exists ? reusableStepJsonPath : undefined;
72
+ };
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ _export_star(require("./processor.isomorphic"), exports);
6
+ _export_star(require("./types"), exports);
7
+ function _export_star(from, to) {
8
+ Object.keys(from).forEach(function(k) {
9
+ if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
10
+ Object.defineProperty(to, k, {
11
+ enumerable: true,
12
+ get: function() {
13
+ return from[k];
14
+ }
15
+ });
16
+ }
17
+ });
18
+ return from;
19
+ }
@@ -0,0 +1,86 @@
1
+ /*
2
+ * IMPORTANT:
3
+ *
4
+ * This file is suffixed with `.isomorphic` because the code in this file is
5
+ * meant to run not just in a nodejs environment but also in a browser. For this
6
+ * reason there are some restrictions for which nodejs imports are allowed in
7
+ * this module. See `.eslintrc.json` for more details.
8
+ */ "use strict";
9
+ Object.defineProperty(exports, "__esModule", {
10
+ value: true
11
+ });
12
+ function _export(target, all) {
13
+ for(var name in all)Object.defineProperty(target, name, {
14
+ enumerable: true,
15
+ get: Object.getOwnPropertyDescriptor(all, name).get
16
+ });
17
+ }
18
+ _export(exports, {
19
+ get REUSABLE_STEP_JSON () {
20
+ return REUSABLE_STEP_JSON;
21
+ },
22
+ get buildReusableStepDirBundle () {
23
+ return buildReusableStepDirBundle;
24
+ }
25
+ });
26
+ const _lodash = require("lodash");
27
+ const _objectisomorphic = require("../../helpers/object.isomorphic");
28
+ const _constisomorphic = require("../shared/const.isomorphic");
29
+ const _helpersisomorphic = require("../shared/helpers.isomorphic");
30
+ const REUSABLE_STEP_JSON = "reusable_step.json";
31
+ const compileExtractionSettings = (reusableStep)=>{
32
+ const extractableFields = (0, _lodash.get)(reusableStep, [
33
+ "__annotation",
34
+ "extractable_fields"
35
+ ], {});
36
+ const map = new Map();
37
+ for (const key of Object.keys(reusableStep)){
38
+ // If the field we are on is extractable, then add its extraction
39
+ // settings to the map with the current object path.
40
+ if (key in extractableFields) {
41
+ map.set([
42
+ key
43
+ ], extractableFields[key]);
44
+ }
45
+ }
46
+ return map;
47
+ };
48
+ const buildReusableStepDirBundle = (remoteReusableStep, localReusableStep = {})=>{
49
+ const bundle = {};
50
+ const mutRemoteReusableStep = (0, _lodash.cloneDeep)(remoteReusableStep);
51
+ // A map of extraction settings of every field in the reusable step
52
+ const compiledExtractionSettings = compileExtractionSettings(mutRemoteReusableStep);
53
+ // Iterate through each extractable field, determine whether we need to
54
+ // extract the field content, and if so, perform the extraction.
55
+ for (const [objPathParts, extractionSettings] of compiledExtractionSettings){
56
+ // If this reusable step doesn't have this field path, then we don't extract.
57
+ if (!(0, _lodash.has)(mutRemoteReusableStep, objPathParts)) continue;
58
+ // If the field at this path is extracted in the local reusable step, then
59
+ // always extract; otherwise extract based on the field settings default.
60
+ const objPathStr = _objectisomorphic.ObjPath.stringify(objPathParts);
61
+ const extractedFilePath = (0, _lodash.get)(localReusableStep, `${objPathStr}${_constisomorphic.FILEPATH_MARKER}`);
62
+ const { default: extractByDefault, file_ext: fileExt } = extractionSettings;
63
+ if (!extractedFilePath && !extractByDefault) continue;
64
+ // By this point, we have a field where we need to extract its content.
65
+ const data = (0, _lodash.get)(mutRemoteReusableStep, objPathParts);
66
+ const fileName = objPathParts.pop();
67
+ // If we have an extracted file path from the local reusable step, we use that.
68
+ // In the other case we use the default path.
69
+ const relpath = typeof extractedFilePath === "string" ? extractedFilePath : `${fileName}.${fileExt}`;
70
+ // Perform the extraction by adding the content and its file path to the
71
+ // bundle for writing to the file system later. Then replace the field
72
+ // content with the extracted file path and mark the field as extracted
73
+ // with @ suffix.
74
+ const content = typeof data === "string" ? data : JSON.stringify(data, null, 2);
75
+ (0, _lodash.set)(bundle, [
76
+ relpath
77
+ ], content);
78
+ (0, _lodash.set)(mutRemoteReusableStep, `${objPathStr}${_constisomorphic.FILEPATH_MARKER}`, relpath);
79
+ (0, _lodash.unset)(mutRemoteReusableStep, objPathStr);
80
+ }
81
+ // At this point the bundle contains all extractable files, so we finally add
82
+ // the reusable step JSON relative path + the file content.
83
+ return (0, _lodash.set)(bundle, [
84
+ REUSABLE_STEP_JSON
85
+ ], (0, _helpersisomorphic.prepareResourceJson)(mutRemoteReusableStep));
86
+ };
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
@@ -0,0 +1,32 @@
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_API_URL () {
13
+ return DEFAULT_API_URL;
14
+ },
15
+ get DEFAULT_AUTH_URL () {
16
+ return DEFAULT_AUTH_URL;
17
+ },
18
+ get DEFAULT_DASHBOARD_URL () {
19
+ return DEFAULT_DASHBOARD_URL;
20
+ },
21
+ get authErrorUrl () {
22
+ return authErrorUrl;
23
+ },
24
+ get authSuccessUrl () {
25
+ return authSuccessUrl;
26
+ }
27
+ });
28
+ const DEFAULT_DASHBOARD_URL = "https://dashboard.knock.app";
29
+ const DEFAULT_AUTH_URL = "https://signin.knock.app";
30
+ const DEFAULT_API_URL = "https://control.knock.app";
31
+ const authSuccessUrl = (dashboardUrl)=>`${dashboardUrl}/auth/oauth/cli`;
32
+ const authErrorUrl = (dashboardUrl, error)=>`${dashboardUrl}/auth/oauth/cli?error=${error}`;
@@ -4,16 +4,29 @@
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- Object.defineProperty(exports, "default", {
7
+ Object.defineProperty(exports, "UserConfigStore", {
8
8
  enumerable: true,
9
9
  get: function() {
10
- return _default;
10
+ return UserConfigStore;
11
11
  }
12
12
  });
13
13
  const _nodepath = /*#__PURE__*/ _interop_require_wildcard(require("node:path"));
14
14
  const _fsextra = /*#__PURE__*/ _interop_require_wildcard(require("fs-extra"));
15
- const _yup = /*#__PURE__*/ _interop_require_wildcard(require("yup"));
15
+ const _zod = require("zod");
16
16
  const _const = require("./helpers/const");
17
+ function _define_property(obj, key, value) {
18
+ if (key in obj) {
19
+ Object.defineProperty(obj, key, {
20
+ value: value,
21
+ enumerable: true,
22
+ configurable: true,
23
+ writable: true
24
+ });
25
+ } else {
26
+ obj[key] = value;
27
+ }
28
+ return obj;
29
+ }
17
30
  function _getRequireWildcardCache(nodeInterop) {
18
31
  if (typeof WeakMap !== "function") return null;
19
32
  var cacheBabelInterop = new WeakMap();
@@ -55,33 +68,58 @@ function _interop_require_wildcard(obj, nodeInterop) {
55
68
  }
56
69
  return newObj;
57
70
  }
58
- const userConfigSchema = _yup.object({
59
- serviceToken: _yup.string(),
60
- apiOrigin: _yup.string()
71
+ // When a user has authenticated via OAuth, we store the session in the user config.
72
+ const userSessionSchema = _zod.z.object({
73
+ accessToken: _zod.z.string(),
74
+ clientId: _zod.z.string(),
75
+ refreshToken: _zod.z.string()
76
+ });
77
+ const userConfigSchema = _zod.z.object({
78
+ serviceToken: _zod.z.string().optional(),
79
+ apiOrigin: _zod.z.string().optional(),
80
+ dashboardOrigin: _zod.z.string().optional(),
81
+ authOrigin: _zod.z.string().optional(),
82
+ userSession: userSessionSchema.optional()
61
83
  });
62
- let USER_CONFIG;
63
- const maybeReadJsonConfig = async (configDir)=>{
64
- // Don't use a user config file in tests.
65
- if (_const.isTestEnv) return null;
66
- const pathToJsonConfig = _nodepath.resolve(configDir, "config.json");
67
- const exists = await _fsextra.pathExists(pathToJsonConfig);
68
- if (!exists) return null;
69
- return _fsextra.readJSON(pathToJsonConfig);
70
- };
71
- const load = async (configDir)=>{
72
- const readConfig = await maybeReadJsonConfig(configDir);
73
- const validConfig = await userConfigSchema.validate(readConfig || {});
74
- // If no valid user config was available, give it an empty map.
75
- USER_CONFIG = validConfig || {};
76
- return USER_CONFIG;
77
- };
78
- const get = ()=>{
79
- if (!USER_CONFIG) {
80
- throw new Error("User config must be loaded first.");
84
+ class UserConfigStore {
85
+ async load() {
86
+ const readConfig = await this.maybeReadJsonConfig();
87
+ const validConfig = userConfigSchema.parse(readConfig || {});
88
+ this.userConfig = validConfig || {};
89
+ return this.userConfig;
90
+ }
91
+ get() {
92
+ return this.userConfig;
93
+ }
94
+ async set(updatedConfig) {
95
+ this.userConfig = {
96
+ ...this.userConfig,
97
+ ...updatedConfig
98
+ };
99
+ await this.maybeWriteJsonConfig();
100
+ return this.userConfig;
81
101
  }
82
- return USER_CONFIG;
83
- };
84
- const _default = {
85
- load,
86
- get
87
- };
102
+ configPath() {
103
+ return _nodepath.resolve(this.configDir, "config.json");
104
+ }
105
+ async maybeReadJsonConfig() {
106
+ if (_const.isTestEnv) return {};
107
+ const path = this.configPath();
108
+ const exists = await _fsextra.pathExists(path);
109
+ if (!exists) return {};
110
+ return _fsextra.readJSON(path);
111
+ }
112
+ async maybeWriteJsonConfig() {
113
+ if (_const.isTestEnv) return;
114
+ const path = this.configPath();
115
+ await _fsextra.outputJson(path, this.userConfig, {
116
+ spaces: 2
117
+ });
118
+ }
119
+ constructor(configDir){
120
+ _define_property(this, "configDir", void 0);
121
+ _define_property(this, "userConfig", void 0);
122
+ this.configDir = configDir;
123
+ this.userConfig = {};
124
+ }
125
+ }