stepzen 0.13.0-beta.2 → 0.14.0-beta.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.
- package/README.md +1 -1
- package/lib/commands/deploy.d.ts +1 -0
- package/lib/commands/import.d.ts +1 -0
- package/lib/commands/import.js +4 -12
- package/lib/commands/init.d.ts +1 -0
- package/lib/commands/lint.d.ts +1 -0
- package/lib/commands/list.d.ts +2 -0
- package/lib/commands/login.d.ts +1 -0
- package/lib/commands/login.js +10 -9
- package/lib/commands/logout.d.ts +2 -0
- package/lib/commands/logout.js +1 -1
- package/lib/commands/start.d.ts +1 -0
- package/lib/commands/start.js +3 -4
- package/lib/commands/transpile.d.ts +1 -0
- package/lib/commands/upload.d.ts +1 -0
- package/lib/commands/upload.js +13 -4
- package/lib/commands/validate.d.ts +2 -0
- package/lib/commands/whoami.d.ts +2 -0
- package/lib/commands/whoami.js +2 -2
- package/lib/generate/helpers.d.ts +0 -4
- package/lib/generate/helpers.js +27 -110
- package/lib/generate/index.js +5 -5
- package/lib/hooks/prerun/{ensure-api-key.d.ts → ensure-config-file.d.ts} +0 -0
- package/lib/hooks/prerun/ensure-config-file.js +28 -0
- package/lib/shared/actions.d.ts +1 -1
- package/lib/shared/actions.js +5 -18
- package/lib/shared/configuration.d.ts +24 -5
- package/lib/shared/configuration.js +92 -34
- package/lib/shared/constants.d.ts +2 -2
- package/lib/shared/constants.js +4 -3
- package/lib/shared/curl-parser.js +22 -8
- package/lib/shared/path-params-parser.js +17 -9
- package/lib/shared/stepzen-sdk.d.ts +14 -14
- package/lib/shared/stepzen-sdk.js +25 -17
- package/lib/shared/types.d.ts +14 -2
- package/lib/shared/utils.d.ts +0 -2
- package/lib/shared/utils.js +1 -50
- package/lib/shared/zen-command.d.ts +6 -5
- package/lib/shared/zen-command.js +28 -8
- package/lib/start/deploy.js +4 -4
- package/oclif.manifest.json +1 -1
- package/package.json +6 -6
- package/lib/hooks/prerun/ensure-api-key.js +0 -8
|
@@ -1,5 +1,24 @@
|
|
|
1
|
-
import { MachineConfiguration } from './types';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { LoggedInMachineConfiguration, LoggedOutMachineConfiguration, MachineConfiguration, StepZenCredentials } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Ensure that the `stepzen-config.yaml` file exists and has valid content.
|
|
4
|
+
* Cover 3 cases:
|
|
5
|
+
* - file does not exist (this is the first time the CLI is run)
|
|
6
|
+
* -> initialize the config file and add a UUID into it
|
|
7
|
+
* - file exists but does not include a UUID (it was created by an earlier
|
|
8
|
+
* version of the CLI)
|
|
9
|
+
* -> add a UUID into the existing config file
|
|
10
|
+
* - file exists, has stepzen credentials, but does not include an API key
|
|
11
|
+
* (it was created by an earlier version of the CLI)
|
|
12
|
+
* -> either fetch the API key from StepZen or remove logged in credentials
|
|
13
|
+
*
|
|
14
|
+
* @param {*} maybeConfiguration raw contents of the configuration file
|
|
15
|
+
*/
|
|
16
|
+
export declare const ensureValidConfiguration: (maybeConfiguration: Record<string, any> | null) => Promise<{
|
|
17
|
+
configuration: MachineConfiguration;
|
|
18
|
+
modified: boolean;
|
|
19
|
+
}>;
|
|
20
|
+
export declare const importConfiguration: (filepath: string) => Promise<Record<string, any>>;
|
|
21
|
+
export declare const readConfiguration: () => Promise<MachineConfiguration>;
|
|
22
|
+
export declare const writeConfiguration: (configuration: MachineConfiguration) => Promise<MachineConfiguration>;
|
|
23
|
+
export declare const writeCredentialsToConfigFile: (credentials: StepZenCredentials) => Promise<LoggedInMachineConfiguration>;
|
|
24
|
+
export declare const removeCredentialsFromConfigFile: () => Promise<LoggedOutMachineConfiguration>;
|
|
@@ -1,61 +1,106 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// Copyright (c) 2020,2021,2022, StepZen, Inc.
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.
|
|
4
|
+
exports.removeCredentialsFromConfigFile = exports.writeCredentialsToConfigFile = exports.writeConfiguration = exports.readConfiguration = exports.importConfiguration = exports.ensureValidConfiguration = void 0;
|
|
5
5
|
// This file contains methods for managing configuration
|
|
6
6
|
const errors_1 = require("@oclif/errors");
|
|
7
7
|
const debug = require("debug");
|
|
8
8
|
const fs = require("fs");
|
|
9
|
+
const crypto = require("crypto");
|
|
9
10
|
const path = require("path");
|
|
10
11
|
const yaml = require("yaml");
|
|
12
|
+
const stepzen_sdk_1 = require("./stepzen-sdk");
|
|
11
13
|
const constants_1 = require("./constants");
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
const configFilePath = path.join(constants_1.STEPZEN_CONFIG_DIRECTORY, constants_1.STEPZEN_CONFIG_FILE);
|
|
15
|
+
/**
|
|
16
|
+
* Ensure that the `stepzen-config.yaml` file exists and has valid content.
|
|
17
|
+
* Cover 3 cases:
|
|
18
|
+
* - file does not exist (this is the first time the CLI is run)
|
|
19
|
+
* -> initialize the config file and add a UUID into it
|
|
20
|
+
* - file exists but does not include a UUID (it was created by an earlier
|
|
21
|
+
* version of the CLI)
|
|
22
|
+
* -> add a UUID into the existing config file
|
|
23
|
+
* - file exists, has stepzen credentials, but does not include an API key
|
|
24
|
+
* (it was created by an earlier version of the CLI)
|
|
25
|
+
* -> either fetch the API key from StepZen or remove logged in credentials
|
|
26
|
+
*
|
|
27
|
+
* @param {*} maybeConfiguration raw contents of the configuration file
|
|
28
|
+
*/
|
|
29
|
+
exports.ensureValidConfiguration = async (maybeConfiguration) => {
|
|
30
|
+
let modified = false;
|
|
31
|
+
const configuration = Object.assign({}, maybeConfiguration);
|
|
32
|
+
// ensure configuration exists
|
|
33
|
+
if (!maybeConfiguration) {
|
|
34
|
+
modified = true;
|
|
35
|
+
}
|
|
36
|
+
// ensure configuration has a UUID
|
|
37
|
+
if (!configuration.uuid) {
|
|
38
|
+
configuration.uuid = crypto.randomUUID();
|
|
39
|
+
debug('stepzen:configuration')(`Generated a new machine UUID: ${configuration.uuid}`);
|
|
40
|
+
modified = true;
|
|
41
|
+
}
|
|
42
|
+
// ensure a logged-in configuration includes an API key
|
|
43
|
+
if (configuration.account && !configuration.apikey) {
|
|
44
|
+
try {
|
|
45
|
+
debug('stepzen:configuration')(`Fetching an API key for account ${configuration.account}`);
|
|
46
|
+
const credentials = await stepzen_sdk_1.default.login(configuration.adminkey, configuration.account);
|
|
47
|
+
configuration.apikey = credentials.apikey;
|
|
18
48
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (error instanceof Error &&
|
|
51
|
+
error.message.includes('Your credentials are invalid')) {
|
|
52
|
+
debug('stepzen:configuration')(`Removing the stored account credentials because logging in failed. ${error}`);
|
|
53
|
+
delete configuration.account;
|
|
54
|
+
delete configuration.adminkey;
|
|
55
|
+
delete configuration.apikey;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// ignore other errors
|
|
59
|
+
}
|
|
23
60
|
}
|
|
24
|
-
|
|
25
|
-
const parsed = yaml.parse(configuration);
|
|
26
|
-
debug('stepzen:configuration')(parsed);
|
|
27
|
-
return parsed;
|
|
28
|
-
}
|
|
29
|
-
catch (_a) {
|
|
30
|
-
return null;
|
|
61
|
+
modified = true;
|
|
31
62
|
}
|
|
63
|
+
return {
|
|
64
|
+
configuration: configuration,
|
|
65
|
+
modified,
|
|
66
|
+
};
|
|
32
67
|
};
|
|
33
|
-
exports.importConfiguration = (filepath) => {
|
|
68
|
+
exports.importConfiguration = async (filepath) => {
|
|
34
69
|
if (!fs.existsSync(filepath)) {
|
|
35
70
|
throw new errors_1.CLIError('Configuration file does not exist');
|
|
36
71
|
}
|
|
37
|
-
const
|
|
72
|
+
const content = fs.readFileSync(filepath, 'utf8');
|
|
38
73
|
try {
|
|
39
|
-
|
|
40
|
-
debug('stepzen:configuration')(parsed);
|
|
41
|
-
return parsed;
|
|
74
|
+
return yaml.parse(content);
|
|
42
75
|
}
|
|
43
76
|
catch (_a) {
|
|
44
77
|
throw new errors_1.CLIError('Configuration file is not valid yaml');
|
|
45
78
|
}
|
|
46
79
|
};
|
|
47
|
-
exports.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
80
|
+
exports.readConfiguration = async () => {
|
|
81
|
+
let maybeConfiguration = null;
|
|
82
|
+
// If the configuration comes from an env var, use it
|
|
83
|
+
if (process.env.STEPZEN_CONFIG_CONTENT) {
|
|
84
|
+
try {
|
|
85
|
+
maybeConfiguration = yaml.parse(process.env.STEPZEN_CONFIG_CONTENT);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
debug('stepzen:configuration')(`Could not parse the STEPZEN_CONFIG_CONTENT env var as YAML: ${error}`);
|
|
89
|
+
}
|
|
53
90
|
}
|
|
54
|
-
|
|
55
|
-
|
|
91
|
+
else {
|
|
92
|
+
try {
|
|
93
|
+
maybeConfiguration = await exports.importConfiguration(configFilePath);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
debug('stepzen:configuration')(`Could not read the config file at ${configFilePath}: ${error}`);
|
|
97
|
+
}
|
|
56
98
|
}
|
|
99
|
+
const { configuration } = await exports.ensureValidConfiguration(maybeConfiguration);
|
|
100
|
+
debug('stepzen:configuration')(configuration);
|
|
101
|
+
return configuration;
|
|
57
102
|
};
|
|
58
|
-
exports.
|
|
103
|
+
exports.writeConfiguration = async (configuration) => {
|
|
59
104
|
// Generate YAML from the configuration
|
|
60
105
|
const content = yaml.stringify(configuration);
|
|
61
106
|
// Check that the configuration directory exists. If not, create it.
|
|
@@ -63,7 +108,20 @@ exports.writeConfigurationToLoginFile = (configuration) => {
|
|
|
63
108
|
fs.mkdirSync(constants_1.STEPZEN_CONFIG_DIRECTORY);
|
|
64
109
|
}
|
|
65
110
|
// Write the configuration file. Overwrites if it already exists.
|
|
66
|
-
|
|
67
|
-
|
|
111
|
+
fs.writeFileSync(configFilePath, content, { mode: '600' });
|
|
112
|
+
return exports.readConfiguration();
|
|
113
|
+
};
|
|
114
|
+
exports.writeCredentialsToConfigFile = async (credentials) => {
|
|
115
|
+
const oldConfig = await exports.readConfiguration();
|
|
116
|
+
const newConfig = Object.assign(Object.assign({}, oldConfig), credentials);
|
|
117
|
+
const writtenConfig = await exports.writeConfiguration(newConfig);
|
|
118
|
+
return Object.assign(Object.assign({}, newConfig), writtenConfig);
|
|
119
|
+
};
|
|
120
|
+
exports.removeCredentialsFromConfigFile = async () => {
|
|
121
|
+
const configuration = await exports.readConfiguration();
|
|
122
|
+
delete configuration.account;
|
|
123
|
+
delete configuration.apikey;
|
|
124
|
+
delete configuration.adminkey;
|
|
125
|
+
await exports.writeConfiguration(configuration);
|
|
68
126
|
return configuration;
|
|
69
127
|
};
|
|
@@ -5,11 +5,11 @@ export declare const STEPZEN_DOMAIN: string;
|
|
|
5
5
|
export declare const STEPZEN_SERVER_URL: string;
|
|
6
6
|
export declare const STEPZEN_GENERATOR_ENGINES_SCHEMA: string;
|
|
7
7
|
export declare const STEPZEN_GENERATOR_ENGINES_ENDPOINT = "stepzen-generator/engines";
|
|
8
|
-
export declare const STEPZEN_DIRECT_GENERATOR_ENGINES_URL: string
|
|
8
|
+
export declare const STEPZEN_DIRECT_GENERATOR_ENGINES_URL: string;
|
|
9
9
|
export declare const STEPZEN_API_TEMPLATES_REPOSITORY = "https://github.com/steprz/stepzen-schemas";
|
|
10
10
|
export declare const ADMIN_DEPLOY_URL = "/cli/admin/deploy";
|
|
11
11
|
export declare const ADMIN_LIST_URL = "/cli/admin/list";
|
|
12
12
|
export declare const ADMIN_UPLOAD_URL = "/cli/admin/upload";
|
|
13
|
-
export declare const
|
|
13
|
+
export declare const ADMIN_ACCOUNT_URL = "/cli/admin/account";
|
|
14
14
|
export declare const STEPZEN_JSON2SDL_SERVER_URL: string;
|
|
15
15
|
export declare const STEPZEN_DISCORD_URL = "https://discord.gg/9k2VdPn2FR";
|
package/lib/shared/constants.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// Copyright (c) 2020,2021,2022, StepZen, Inc.
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.STEPZEN_DISCORD_URL = exports.STEPZEN_JSON2SDL_SERVER_URL = exports.
|
|
4
|
+
exports.STEPZEN_DISCORD_URL = exports.STEPZEN_JSON2SDL_SERVER_URL = exports.ADMIN_ACCOUNT_URL = exports.ADMIN_UPLOAD_URL = exports.ADMIN_LIST_URL = exports.ADMIN_DEPLOY_URL = exports.STEPZEN_API_TEMPLATES_REPOSITORY = exports.STEPZEN_DIRECT_GENERATOR_ENGINES_URL = exports.STEPZEN_GENERATOR_ENGINES_ENDPOINT = exports.STEPZEN_GENERATOR_ENGINES_SCHEMA = exports.STEPZEN_SERVER_URL = exports.STEPZEN_DOMAIN = exports.STEPZEN_CONFIG_FILE = exports.STEPZEN_LAST_UPDATE_CHECK_TIMESTAMP = exports.STEPZEN_CONFIG_DIRECTORY = void 0;
|
|
5
5
|
// This file contains constants and all magic strings
|
|
6
6
|
const dotenv = require("dotenv");
|
|
7
7
|
const os = require("os");
|
|
@@ -24,14 +24,15 @@ exports.STEPZEN_GENERATOR_ENGINES_SCHEMA = ENV_VAR_STEPZEN_GENERATOR_ENGINES_SCH
|
|
|
24
24
|
// Generator Engines schema: target API endpoint
|
|
25
25
|
exports.STEPZEN_GENERATOR_ENGINES_ENDPOINT = 'stepzen-generator/engines';
|
|
26
26
|
// If defined, call the generator engines cloud function directly, skipping zenctl
|
|
27
|
-
exports.STEPZEN_DIRECT_GENERATOR_ENGINES_URL = ENV_VAR_STEPZEN_DIRECT_GENERATOR_ENGINES_URL
|
|
27
|
+
exports.STEPZEN_DIRECT_GENERATOR_ENGINES_URL = ENV_VAR_STEPZEN_DIRECT_GENERATOR_ENGINES_URL ||
|
|
28
|
+
'https://us-central1-stepzen-functions.cloudfunctions.net/generator-engine';
|
|
28
29
|
// API Templates repository
|
|
29
30
|
exports.STEPZEN_API_TEMPLATES_REPOSITORY = 'https://github.com/steprz/stepzen-schemas';
|
|
30
31
|
// Paths to the endpoints used (only for tests)
|
|
31
32
|
exports.ADMIN_DEPLOY_URL = '/cli/admin/deploy';
|
|
32
33
|
exports.ADMIN_LIST_URL = '/cli/admin/list';
|
|
33
34
|
exports.ADMIN_UPLOAD_URL = '/cli/admin/upload';
|
|
34
|
-
exports.
|
|
35
|
+
exports.ADMIN_ACCOUNT_URL = '/cli/admin/account';
|
|
35
36
|
exports.STEPZEN_JSON2SDL_SERVER_URL = ENV_VAR_STEPZEN_JSON2SDL_SERVER_URL ||
|
|
36
37
|
'https://jsonintrospection-ng-prod-xynkgeaaaa-uc.a.run.app';
|
|
37
38
|
exports.STEPZEN_DISCORD_URL = 'https://discord.gg/9k2VdPn2FR';
|
|
@@ -87,6 +87,17 @@ const parseMethodFlag = (value, partialCurlArgs) => {
|
|
|
87
87
|
result: Object.assign(Object.assign({}, partialCurlArgs), { method }),
|
|
88
88
|
};
|
|
89
89
|
};
|
|
90
|
+
const parseURLFlag = (value, partialCurlArgs) => {
|
|
91
|
+
if (partialCurlArgs.url) {
|
|
92
|
+
return {
|
|
93
|
+
error: `Multiple URLs are not currently supported by StepZen CLI (${value}).` +
|
|
94
|
+
` If this is a blocker for you, please let us know on Discord (${constants_1.STEPZEN_DISCORD_URL})`,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
result: Object.assign(Object.assign({}, partialCurlArgs), { url: value }),
|
|
99
|
+
};
|
|
100
|
+
};
|
|
90
101
|
const flags = [
|
|
91
102
|
{
|
|
92
103
|
matches: ['-H', '--header'],
|
|
@@ -100,6 +111,10 @@ const flags = [
|
|
|
100
111
|
matches: ['-X', '--request'],
|
|
101
112
|
parse: parseMethodFlag,
|
|
102
113
|
},
|
|
114
|
+
{
|
|
115
|
+
matches: ['--url'],
|
|
116
|
+
parse: parseURLFlag,
|
|
117
|
+
},
|
|
103
118
|
];
|
|
104
119
|
const tryMatchCurlFlag = (matches, argv, i) => {
|
|
105
120
|
for (const match of matches) {
|
|
@@ -155,7 +170,7 @@ exports.parseCurlArgv = (argv) => {
|
|
|
155
170
|
continue;
|
|
156
171
|
}
|
|
157
172
|
if ('error' in matcherResult) {
|
|
158
|
-
// flag matched but it
|
|
173
|
+
// flag matched but it requires a value which is missing
|
|
159
174
|
return matcherResult;
|
|
160
175
|
}
|
|
161
176
|
const parserResult = flag.parse(matcherResult.value, result, matcherResult.match);
|
|
@@ -174,14 +189,13 @@ exports.parseCurlArgv = (argv) => {
|
|
|
174
189
|
};
|
|
175
190
|
}
|
|
176
191
|
}
|
|
177
|
-
else if (result.url) {
|
|
178
|
-
return {
|
|
179
|
-
error: `Multiple URLs are not currently supported by StepZen CLI (${argv[i]}).` +
|
|
180
|
-
` If this is a blocker for you, please let us know on Discord (${constants_1.STEPZEN_DISCORD_URL})`,
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
192
|
else {
|
|
184
|
-
|
|
193
|
+
// The only curl argument that's not a flag is the URL
|
|
194
|
+
const resultOrError = parseURLFlag(argv[i], result, '');
|
|
195
|
+
if ('error' in resultOrError) {
|
|
196
|
+
return resultOrError;
|
|
197
|
+
}
|
|
198
|
+
result = resultOrError.result;
|
|
185
199
|
}
|
|
186
200
|
}
|
|
187
201
|
if (!result.url) {
|
|
@@ -4,6 +4,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
exports.parsePathParamsPattern = exports.formatPatternDiffWithPath = void 0;
|
|
5
5
|
const chalk = require("chalk");
|
|
6
6
|
const pathParamRegex = /^\$[_A-Za-z]\w*$/;
|
|
7
|
+
// in a literal segment, $ should be escaped as $$
|
|
8
|
+
const pathSegmentRegex = /^([^$]|\$\$)+$/;
|
|
7
9
|
exports.formatPatternDiffWithPath = (patternSegments, pathSegments) => {
|
|
8
10
|
let hasErrors = false;
|
|
9
11
|
const diff = [];
|
|
@@ -13,12 +15,9 @@ exports.formatPatternDiffWithPath = (patternSegments, pathSegments) => {
|
|
|
13
15
|
diff.push(chalk.red(`< ${patternSegment} >`));
|
|
14
16
|
hasErrors = true;
|
|
15
17
|
}
|
|
16
|
-
else if (
|
|
17
|
-
diff.push(patternSegment);
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
18
|
+
else if (pathSegmentRegex.test(patternSegment)) {
|
|
20
19
|
const pathSegment = pathSegments[i];
|
|
21
|
-
if (pathSegment === patternSegment) {
|
|
20
|
+
if (pathSegment === patternSegment.replace('$$', '$')) {
|
|
22
21
|
diff.push(pathSegment);
|
|
23
22
|
}
|
|
24
23
|
else {
|
|
@@ -26,6 +25,13 @@ exports.formatPatternDiffWithPath = (patternSegments, pathSegments) => {
|
|
|
26
25
|
hasErrors = true;
|
|
27
26
|
}
|
|
28
27
|
}
|
|
28
|
+
else {
|
|
29
|
+
// If the path segment contains some unescaped (single) $ chars,
|
|
30
|
+
// interpret it as a pattern for now. An error will be reported
|
|
31
|
+
// later (in parsePathParamsPattern) if it doesn't match
|
|
32
|
+
// pathParamRegex (starts with $)
|
|
33
|
+
diff.push(patternSegment);
|
|
34
|
+
}
|
|
29
35
|
}
|
|
30
36
|
for (let i = patternSegments.length; i < pathSegments.length; i++) {
|
|
31
37
|
diff.push(chalk.magenta(`< ${pathSegments[i]} >`));
|
|
@@ -52,22 +58,24 @@ exports.parsePathParamsPattern = (url, pathParamsPattern) => {
|
|
|
52
58
|
error: `Path parameters do not align with the URL path: /${maybeDiff}`,
|
|
53
59
|
};
|
|
54
60
|
}
|
|
55
|
-
const invalidParameterSegments = patternSegments.filter(segment =>
|
|
61
|
+
const invalidParameterSegments = patternSegments.filter(segment => !pathSegmentRegex.test(segment) && !pathParamRegex.test(segment));
|
|
56
62
|
if (invalidParameterSegments.length > 0) {
|
|
57
63
|
return {
|
|
58
64
|
error: `The path parameter name '${invalidParameterSegments[0]}' is not` +
|
|
59
65
|
` allowed. Path parameter names should be valid GraphQL identifiers` +
|
|
60
|
-
` prefixed with $ (dollar sign)
|
|
66
|
+
` prefixed with $ (dollar sign). $ in literal path segments must be` +
|
|
67
|
+
` escaped as $$.`,
|
|
61
68
|
};
|
|
62
69
|
}
|
|
63
|
-
|
|
70
|
+
const retval = patternSegments
|
|
64
71
|
.map((segment, index) => ({
|
|
65
72
|
index,
|
|
66
73
|
name: segment,
|
|
67
74
|
}))
|
|
68
|
-
.filter(({ name }) =>
|
|
75
|
+
.filter(({ name }) => pathParamRegex.test(name))
|
|
69
76
|
.map(({ index, name }) => ({
|
|
70
77
|
index,
|
|
71
78
|
name: name.slice(1),
|
|
72
79
|
}));
|
|
80
|
+
return retval;
|
|
73
81
|
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import { StepZenCredentials } from './types';
|
|
1
2
|
declare const stepzen: {
|
|
2
|
-
login: (adminkey: string, account?: string) => Promise<
|
|
3
|
-
|
|
4
|
-
adminkey: string;
|
|
5
|
-
}>;
|
|
6
|
-
createAnonymousAccount: () => {
|
|
7
|
-
account: string;
|
|
8
|
-
adminkey: string;
|
|
9
|
-
};
|
|
3
|
+
login: (adminkey: string, account?: string) => Promise<StepZenCredentials>;
|
|
4
|
+
createAnonymousAccount: (uuid: string) => Promise<StepZenCredentials>;
|
|
10
5
|
verify: (account: string, adminkey: string) => Promise<boolean>;
|
|
11
|
-
client: (options:
|
|
6
|
+
client: (options: import("@stepzen/sdk/lib/client").AnonymousClientOptions | import("@stepzen/sdk/lib/client").UserCredentialsClientOptions) => Promise<{
|
|
7
|
+
readonly credentials: {
|
|
8
|
+
account: string;
|
|
9
|
+
adminkey: string;
|
|
10
|
+
apikey: string;
|
|
11
|
+
};
|
|
12
12
|
account: () => Promise<{
|
|
13
13
|
account: string;
|
|
14
14
|
apikey: string;
|
|
@@ -19,14 +19,14 @@ declare const stepzen: {
|
|
|
19
19
|
deploy: (destination: string, properties: {
|
|
20
20
|
configurationsets?: string[] | undefined;
|
|
21
21
|
schema: string;
|
|
22
|
-
}) => Promise<import("@stepzen/sdk").ZenCtlResponse>;
|
|
22
|
+
}) => Promise<import("@stepzen/sdk/lib/client").ZenCtlResponse>;
|
|
23
23
|
list: {
|
|
24
|
-
configurationsets: () => Promise<import("@stepzen/sdk").ZenCtlResponse>;
|
|
25
|
-
schemas: () => Promise<import("@stepzen/sdk").ZenCtlResponse>;
|
|
24
|
+
configurationsets: () => Promise<import("@stepzen/sdk/lib/client").ZenCtlResponse>;
|
|
25
|
+
schemas: () => Promise<import("@stepzen/sdk/lib/client").ZenCtlResponse>;
|
|
26
26
|
};
|
|
27
27
|
upload: {
|
|
28
|
-
configurationset: (destination: string, file: string) => Promise<import("@stepzen/sdk").ZenCtlResponse>;
|
|
29
|
-
schema: (destination: string, directory: string) => Promise<import("@stepzen/sdk").ZenCtlResponse>;
|
|
28
|
+
configurationset: (destination: string, file: string) => Promise<import("@stepzen/sdk/lib/client").ZenCtlResponse>;
|
|
29
|
+
schema: (destination: string, directory: string) => Promise<import("@stepzen/sdk/lib/client").ZenCtlResponse>;
|
|
30
30
|
};
|
|
31
31
|
}>;
|
|
32
32
|
};
|
|
@@ -3,26 +3,34 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const errors_1 = require("@oclif/errors");
|
|
5
5
|
const sdk_1 = require("@stepzen/sdk");
|
|
6
|
+
const constants_1 = require("./constants");
|
|
6
7
|
const { version } = require('../../package.json');
|
|
7
8
|
const stepzen = Object.assign(Object.assign({}, sdk_1.init({ appName: `stepzen-cli/${version}` })), { login: async (adminkey, account = adminkey.split(':')[0]) => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
try {
|
|
10
|
+
const client = await stepzen.client({
|
|
11
|
+
account,
|
|
12
|
+
adminkey,
|
|
13
|
+
domain: constants_1.STEPZEN_DOMAIN,
|
|
14
|
+
server: constants_1.STEPZEN_SERVER_URL,
|
|
15
|
+
});
|
|
16
|
+
return client.credentials;
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
12
19
|
// Exit, with error
|
|
13
|
-
throw new errors_1.CLIError('We are unable to verify your account details. Could you please check them?'
|
|
20
|
+
throw new errors_1.CLIError('We are unable to verify your account details. Could you please check them?' +
|
|
21
|
+
` (${error})`);
|
|
22
|
+
}
|
|
23
|
+
}, createAnonymousAccount: async (uuid) => {
|
|
24
|
+
try {
|
|
25
|
+
const client = await stepzen.client({
|
|
26
|
+
publicAccountToken: uuid,
|
|
27
|
+
domain: constants_1.STEPZEN_DOMAIN,
|
|
28
|
+
server: constants_1.STEPZEN_SERVER_URL,
|
|
29
|
+
});
|
|
30
|
+
return client.credentials;
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
throw new errors_1.CLIError(`Could not create a public account (${error})`);
|
|
14
34
|
}
|
|
15
|
-
return {
|
|
16
|
-
account,
|
|
17
|
-
adminkey,
|
|
18
|
-
};
|
|
19
|
-
}, createAnonymousAccount: () => {
|
|
20
|
-
const anonAdminKey = process.env.STEPZEN_ANONYMOUS_ADMINKEY ||
|
|
21
|
-
// LATER: call the actual API (pending https://github.com/steprz/zen/issues/5545)
|
|
22
|
-
'test::steprz.io+666::test';
|
|
23
|
-
return {
|
|
24
|
-
account: anonAdminKey.split(':')[0],
|
|
25
|
-
adminkey: anonAdminKey,
|
|
26
|
-
};
|
|
27
35
|
} });
|
|
28
36
|
exports.default = stepzen;
|
package/lib/shared/types.d.ts
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface StepZenCredentials {
|
|
2
2
|
account: string;
|
|
3
3
|
adminkey: string;
|
|
4
|
-
apikey
|
|
4
|
+
apikey: string;
|
|
5
5
|
}
|
|
6
|
+
export interface LoggedOutMachineConfiguration {
|
|
7
|
+
uuid: string;
|
|
8
|
+
}
|
|
9
|
+
export declare type LoggedInMachineConfiguration = LoggedOutMachineConfiguration & StepZenCredentials;
|
|
10
|
+
/**
|
|
11
|
+
* In-memory representation of the `~/.stepzen/stepzen-config.yaml`
|
|
12
|
+
* configuration file.
|
|
13
|
+
*
|
|
14
|
+
* If the user is not logged in, it has only a UUID of the CLI installation.
|
|
15
|
+
* If the user is logged in, it has also has the StepZen account credentials.
|
|
16
|
+
*/
|
|
17
|
+
export declare type MachineConfiguration = LoggedInMachineConfiguration | LoggedOutMachineConfiguration;
|
|
6
18
|
/**
|
|
7
19
|
* On-disk representation of a workspace config file, `stepzen.config.json`
|
|
8
20
|
*/
|
package/lib/shared/utils.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
export declare const checkAuth: () => Promise<void>;
|
|
2
1
|
export declare const clearConsole: () => void;
|
|
3
|
-
export declare const ensureApiKey: () => Promise<void>;
|
|
4
2
|
export declare const getDirectory: (d?: string | undefined) => string;
|
|
5
3
|
export declare const getStepZenExtensions: () => Promise<string>;
|
|
6
4
|
export declare const validateEndpoint: (endpoint: string) => any;
|
package/lib/shared/utils.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// Copyright (c) 2020,2021,2022, StepZen, Inc.
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.maskStepZenKey = exports.validateEndpoint = exports.getStepZenExtensions = exports.getDirectory = exports.
|
|
4
|
+
exports.maskStepZenKey = exports.validateEndpoint = exports.getStepZenExtensions = exports.getDirectory = exports.clearConsole = void 0;
|
|
5
5
|
const errors_1 = require("@oclif/errors");
|
|
6
|
-
const chalk = require("chalk");
|
|
7
6
|
const debug = require("debug");
|
|
8
7
|
const node_fetch_1 = require("node-fetch");
|
|
9
8
|
const fs = require("fs");
|
|
@@ -11,60 +10,12 @@ const os = require("os");
|
|
|
11
10
|
const path = require("path");
|
|
12
11
|
const prettier = require("prettier");
|
|
13
12
|
const constants_1 = require("./constants");
|
|
14
|
-
const configuration_1 = require("./configuration");
|
|
15
|
-
const stepzen_sdk_1 = require("./stepzen-sdk");
|
|
16
|
-
exports.checkAuth = async () => {
|
|
17
|
-
var _a;
|
|
18
|
-
const configuration = configuration_1.readConfiguration();
|
|
19
|
-
// If there is no configuration, you're not logged in
|
|
20
|
-
if (!configuration) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
const details = configuration;
|
|
24
|
-
// If the account is called 'test', return. It's a test.
|
|
25
|
-
if (details.account === 'test') {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const isValidAccount = await stepzen_sdk_1.default.verify(details.account, details.adminkey);
|
|
29
|
-
if (!isValidAccount) {
|
|
30
|
-
if ((_a = details.account) === null || _a === void 0 ? void 0 : _a.endsWith('Playground')) {
|
|
31
|
-
console.log(chalk.yellow(`
|
|
32
|
-
╔════════════════════════════════════════╗
|
|
33
|
-
║ Your playground account has expired! ║
|
|
34
|
-
║ Sign up for a full account: ║
|
|
35
|
-
║ www.stepzen.com ║
|
|
36
|
-
╚════════════════════════════════════════╝
|
|
37
|
-
`));
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
console.log('Could not complete the request. Please check your authentication details are correct.');
|
|
41
|
-
}
|
|
42
|
-
// eslint-disable-next-line no-process-exit,unicorn/no-process-exit
|
|
43
|
-
process.exit(1);
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
13
|
exports.clearConsole = () => {
|
|
47
14
|
process.stdout.write(
|
|
48
15
|
// Taken from create-react-app
|
|
49
16
|
// eslint-disable-next-line unicorn/no-hex-escape
|
|
50
17
|
process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H');
|
|
51
18
|
};
|
|
52
|
-
exports.ensureApiKey = async () => {
|
|
53
|
-
const configuration = configuration_1.readConfiguration();
|
|
54
|
-
const details = configuration;
|
|
55
|
-
if (details && !details.apikey) {
|
|
56
|
-
debug('stepzen:account')(`Fetching API key for account ${details.account}`);
|
|
57
|
-
try {
|
|
58
|
-
const client = await stepzen_sdk_1.default.client(details);
|
|
59
|
-
const response = await client.account();
|
|
60
|
-
if ('apikey' in response) {
|
|
61
|
-
details.apikey = response.apikey;
|
|
62
|
-
await configuration_1.writeConfigurationToLoginFile(details);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
catch (_a) { }
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
19
|
exports.getDirectory = (d = process.cwd()) => {
|
|
69
20
|
let directory = d;
|
|
70
21
|
// If it starts with `~`, expand this
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { Command } from '@oclif/command';
|
|
2
|
-
import { MachineConfiguration } from './types';
|
|
1
|
+
import { Command, flags } from '@oclif/command';
|
|
2
|
+
import { MachineConfiguration, StepZenCredentials } from './types';
|
|
3
3
|
export declare abstract class ZenCommand extends Command {
|
|
4
4
|
static flags: {
|
|
5
5
|
'non-interactive': import("@oclif/parser/lib/flags").IBooleanFlag<boolean>;
|
|
6
|
+
'enable-login-prompt': flags.IOptionFlag<boolean | undefined>;
|
|
6
7
|
};
|
|
7
8
|
ensureStepZenAccount(): Promise<{
|
|
8
|
-
configuration:
|
|
9
|
+
configuration: import("./types").LoggedInMachineConfiguration;
|
|
9
10
|
}>;
|
|
10
|
-
promptUserToLogIn(): Promise<{
|
|
11
|
-
configuration: MachineConfiguration;
|
|
11
|
+
promptUserToLogIn(uuid: string): Promise<{
|
|
12
|
+
configuration: MachineConfiguration & StepZenCredentials;
|
|
12
13
|
}>;
|
|
13
14
|
}
|
|
14
15
|
export default ZenCommand;
|
|
@@ -3,21 +3,28 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.ZenCommand = void 0;
|
|
5
5
|
const command_1 = require("@oclif/command");
|
|
6
|
+
const errors_1 = require("@oclif/errors");
|
|
6
7
|
const inquirer = require("inquirer");
|
|
7
8
|
const chalk = require("chalk");
|
|
8
9
|
const configuration_1 = require("./configuration");
|
|
9
10
|
const stepzen_sdk_1 = require("./stepzen-sdk");
|
|
10
11
|
class ZenCommand extends command_1.Command {
|
|
11
12
|
async ensureStepZenAccount() {
|
|
12
|
-
const configuration = configuration_1.readConfiguration();
|
|
13
|
-
if (
|
|
13
|
+
const configuration = await configuration_1.readConfiguration();
|
|
14
|
+
if ('account' in configuration) {
|
|
14
15
|
return {
|
|
15
16
|
configuration,
|
|
16
17
|
};
|
|
17
18
|
}
|
|
18
|
-
|
|
19
|
+
const TheCommand = this.constructor;
|
|
20
|
+
const { flags } = this.parse(TheCommand);
|
|
21
|
+
if (flags['enable-login-prompt']) {
|
|
22
|
+
return this.promptUserToLogIn(configuration.uuid);
|
|
23
|
+
}
|
|
24
|
+
throw new errors_1.CLIError('Could not find StepZen account credentials.' +
|
|
25
|
+
' Please run `stepzen login` first.');
|
|
19
26
|
}
|
|
20
|
-
async promptUserToLogIn() {
|
|
27
|
+
async promptUserToLogIn(uuid) {
|
|
21
28
|
this.log(chalk.bold(chalk.cyan('Welcome to StepZen CLI!')));
|
|
22
29
|
this.log('');
|
|
23
30
|
this.log(`Please log in with your StepZen account to make your GraphQL API private.` +
|
|
@@ -53,14 +60,14 @@ class ZenCommand extends command_1.Command {
|
|
|
53
60
|
suffix: chalk.blue(` (available at ${chalk.bold('https://stepzen.com/account')})`),
|
|
54
61
|
},
|
|
55
62
|
]);
|
|
56
|
-
|
|
57
|
-
configuration_1.
|
|
63
|
+
const credentials = await stepzen_sdk_1.default.login(answers.adminkey);
|
|
64
|
+
configuration = await configuration_1.writeCredentialsToConfigFile(credentials);
|
|
58
65
|
this.log('You have successfully logged in.');
|
|
59
66
|
this.log('');
|
|
60
67
|
}
|
|
61
68
|
else {
|
|
62
|
-
|
|
63
|
-
configuration_1.
|
|
69
|
+
const credentials = await stepzen_sdk_1.default.createAnonymousAccount(uuid);
|
|
70
|
+
configuration = await configuration_1.writeCredentialsToConfigFile(credentials);
|
|
64
71
|
this.log(`We've created a temporary public account for you.\nAll endpoints` +
|
|
65
72
|
` deployed to this account will be automatically deleted after 24` +
|
|
66
73
|
` hours. You can log in with your regular StepZen account at any` +
|
|
@@ -76,5 +83,18 @@ ZenCommand.flags = {
|
|
|
76
83
|
description: 'disable all interactive prompts',
|
|
77
84
|
hidden: true,
|
|
78
85
|
}),
|
|
86
|
+
// The flag type has to be `option` (not `boolean`) for `env` to take effect
|
|
87
|
+
'enable-login-prompt': command_1.flags.option({
|
|
88
|
+
description: 'An (internal) feature flag to enable the "prompt user to log in"' +
|
|
89
|
+
' feature for the users who run the CLI without being logged in. It' +
|
|
90
|
+
' is intentially hidden and not documented because in the future' +
|
|
91
|
+
' this feature will be enabled for all users and the flag will be' +
|
|
92
|
+
' removed.',
|
|
93
|
+
hidden: true,
|
|
94
|
+
options: ['true', 'false'],
|
|
95
|
+
parse: value => Boolean(value),
|
|
96
|
+
default: false,
|
|
97
|
+
env: 'STEPZEN_ENABLE_LOGIN_PROMPT',
|
|
98
|
+
}),
|
|
79
99
|
};
|
|
80
100
|
exports.default = ZenCommand;
|