@mimicprotocol/cli 0.0.1-rc.32 → 0.0.1-rc.35
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/CHANGELOG.md +23 -0
- package/README.md +69 -3
- package/dist/commands/authenticate.js +54 -0
- package/dist/commands/deploy.js +13 -7
- package/dist/commands/login.js +102 -0
- package/dist/commands/logout.js +56 -0
- package/dist/commands/profiles.js +29 -0
- package/dist/commands/test.js +4 -7
- package/dist/lib/CredentialsManager.js +181 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @mimicprotocol/cli
|
|
2
2
|
|
|
3
|
+
## 0.0.1-rc.35
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 9a993b0: Add getNativeBalance
|
|
8
|
+
- da39b85: Added Tokens class
|
|
9
|
+
- 426a4fe: Environment refactored
|
|
10
|
+
|
|
11
|
+
## 0.0.1-rc.34
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 73a7900: Add login, logout and profiles commands
|
|
16
|
+
- d455822: Bump SDK version
|
|
17
|
+
|
|
18
|
+
## 0.0.1-rc.33
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- 9530e1c: Revert test command directory change
|
|
23
|
+
- 21aba8d: Improve mocks error messages
|
|
24
|
+
- 5c8c562: Fix MockConfig validator
|
|
25
|
+
|
|
3
26
|
## 0.0.1-rc.32
|
|
4
27
|
|
|
5
28
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -23,9 +23,10 @@
|
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
26
|
-
## Content
|
|
26
|
+
## Content
|
|
27
27
|
|
|
28
28
|
The `mimic` CLI is a command-line interface to:
|
|
29
|
+
|
|
29
30
|
- Initialize a Mimic-compatible task project
|
|
30
31
|
- Generate types from your task manifest and ABIs
|
|
31
32
|
- Compile your AssemblyScript tasks to WebAssembly
|
|
@@ -35,7 +36,7 @@ The `mimic` CLI is a command-line interface to:
|
|
|
35
36
|
|
|
36
37
|
## Setup
|
|
37
38
|
|
|
38
|
-
To set up this project you'll need [git](https://git-scm.com) and [yarn](https://classic.yarnpkg.com) installed.
|
|
39
|
+
To set up this project you'll need [git](https://git-scm.com) and [yarn](https://classic.yarnpkg.com) installed.
|
|
39
40
|
|
|
40
41
|
Install the CLI from the root of the monorepo:
|
|
41
42
|
|
|
@@ -59,6 +60,9 @@ USAGE
|
|
|
59
60
|
$ mimic [COMMAND]
|
|
60
61
|
|
|
61
62
|
COMMANDS
|
|
63
|
+
login Authenticate with Mimic by storing your API key locally
|
|
64
|
+
logout Remove stored credentials for a profile
|
|
65
|
+
profiles List all configured authentication profiles
|
|
62
66
|
codegen Generates typed interfaces for declared inputs and ABIs from your manifest.yaml file
|
|
63
67
|
compile Compiles task
|
|
64
68
|
test Tests your tasks
|
|
@@ -66,6 +70,69 @@ COMMANDS
|
|
|
66
70
|
init Initializes a new Mimic-compatible project structure in the specified directory
|
|
67
71
|
```
|
|
68
72
|
|
|
73
|
+
### Authentication
|
|
74
|
+
|
|
75
|
+
Before deploying tasks, you need to authenticate with your Mimic API key:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# Interactive login (recommended)
|
|
79
|
+
$ mimic login
|
|
80
|
+
|
|
81
|
+
# Non-interactive login (for CI/CD)
|
|
82
|
+
$ mimic login --api-key YOUR_API_KEY
|
|
83
|
+
|
|
84
|
+
# Login with a specific profile
|
|
85
|
+
$ mimic login --profile staging -api-key YOUR_API_KEY
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### Managing Profiles
|
|
89
|
+
|
|
90
|
+
The CLI supports multiple authentication profiles. Credentials are stored in `~/.mimic/credentials`.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# List all configured profiles
|
|
94
|
+
$ mimic profiles
|
|
95
|
+
|
|
96
|
+
# Login with a specific profile
|
|
97
|
+
$ mimic login --profile production
|
|
98
|
+
|
|
99
|
+
# Deploy using a specific profile
|
|
100
|
+
$ mimic deploy --profile production
|
|
101
|
+
|
|
102
|
+
# Remove credentials for a profile
|
|
103
|
+
$ mimic logout --profile staging
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
#### Credential Storage
|
|
107
|
+
|
|
108
|
+
Credentials are stored in an INI-style format at `~/.mimic/credentials`:
|
|
109
|
+
|
|
110
|
+
```ini
|
|
111
|
+
[default]
|
|
112
|
+
api_key=YOUR_DEFAULT_KEY
|
|
113
|
+
|
|
114
|
+
[staging]
|
|
115
|
+
api_key=YOUR_STAGING_KEY
|
|
116
|
+
|
|
117
|
+
[production]
|
|
118
|
+
api_key=YOUR_PRODUCTION_KEY
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
#### Deploy with Authentication
|
|
122
|
+
|
|
123
|
+
The `deploy` command now supports profile-based authentication:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Deploy using default profile
|
|
127
|
+
$ mimic deploy
|
|
128
|
+
|
|
129
|
+
# Deploy using a specific profile
|
|
130
|
+
$ mimic deploy --profile staging
|
|
131
|
+
|
|
132
|
+
# Deploy with explicit API key (overrides profile)
|
|
133
|
+
$ mimic deploy --api-key YOUR_API_KEY
|
|
134
|
+
```
|
|
135
|
+
|
|
69
136
|
For full CLI documentation and examples please visit [docs.mimic.fi](https://docs.mimic.fi/)
|
|
70
137
|
|
|
71
138
|
## Security
|
|
@@ -86,7 +153,6 @@ This project includes code from [The Graph Tooling](https://github.com/graphprot
|
|
|
86
153
|
See the [LICENSE-MIT](https://github.com/graphprotocol/graph-tooling/blob/27659e56adfa3ef395ceaf39053dc4a31e6d86b7/LICENSE-MIT) file for details.
|
|
87
154
|
Their original license and attribution are preserved.
|
|
88
155
|
|
|
89
|
-
|
|
90
156
|
---
|
|
91
157
|
|
|
92
158
|
> Website [mimic.fi](https://mimic.fi) ·
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const core_1 = require("@oclif/core");
|
|
7
|
+
const CredentialsManager_1 = require("../lib/CredentialsManager");
|
|
8
|
+
const log_1 = __importDefault(require("../log"));
|
|
9
|
+
class Authenticate extends core_1.Command {
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
+
run() {
|
|
12
|
+
throw new Error('Method not implemented.');
|
|
13
|
+
}
|
|
14
|
+
authenticate(flags) {
|
|
15
|
+
let apiKey = flags['api-key'];
|
|
16
|
+
if (!apiKey) {
|
|
17
|
+
try {
|
|
18
|
+
const credentials = CredentialsManager_1.CredentialsManager.getDefault().getCredentials(flags.profile);
|
|
19
|
+
apiKey = credentials.apiKey;
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
if (error instanceof Error) {
|
|
23
|
+
this.error(error.message, {
|
|
24
|
+
code: 'AuthenticationRequired',
|
|
25
|
+
suggestions: [
|
|
26
|
+
`Run ${log_1.default.highlightText('mimic login')} to authenticate`,
|
|
27
|
+
`Run ${log_1.default.highlightText(`mimic login --profile ${flags.profile ?? '<profile>'}`)} to create this profile`,
|
|
28
|
+
`Or use ${log_1.default.highlightText('--api-key')} flag to provide API key directly`,
|
|
29
|
+
].filter(Boolean),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return { apiKey };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
Authenticate.description = 'Authenticate with Mimic by storing your API key locally';
|
|
39
|
+
Authenticate.examples = [
|
|
40
|
+
'<%= config.bin %> <%= command.id %>',
|
|
41
|
+
'<%= config.bin %> <%= command.id %> --profile staging',
|
|
42
|
+
'<%= config.bin %> <%= command.id %> --profile production --api-key YOUR_API_KEY',
|
|
43
|
+
];
|
|
44
|
+
Authenticate.flags = {
|
|
45
|
+
profile: core_1.Flags.string({
|
|
46
|
+
char: 'p',
|
|
47
|
+
description: 'Profile name to use for this credential',
|
|
48
|
+
}),
|
|
49
|
+
'api-key': core_1.Flags.string({
|
|
50
|
+
char: 'k',
|
|
51
|
+
description: 'API key (non-interactive mode)',
|
|
52
|
+
}),
|
|
53
|
+
};
|
|
54
|
+
exports.default = Authenticate;
|
package/dist/commands/deploy.js
CHANGED
|
@@ -44,13 +44,15 @@ const path_1 = require("path");
|
|
|
44
44
|
const errors_1 = require("../errors");
|
|
45
45
|
const packageManager_1 = require("../lib/packageManager");
|
|
46
46
|
const log_1 = __importDefault(require("../log"));
|
|
47
|
+
const authenticate_1 = __importDefault(require("./authenticate"));
|
|
47
48
|
const MIMIC_REGISTRY_DEFAULT = 'https://api-protocol.mimic.fi';
|
|
48
|
-
class Deploy extends
|
|
49
|
+
class Deploy extends authenticate_1.default {
|
|
49
50
|
async run() {
|
|
50
51
|
const { flags } = await this.parse(Deploy);
|
|
51
|
-
const {
|
|
52
|
+
const { input: inputDir, output: outputDir, 'skip-compile': skipCompile, url: registryUrl } = flags;
|
|
52
53
|
const fullInputDir = (0, path_1.resolve)(inputDir);
|
|
53
54
|
const fullOutputDir = (0, path_1.resolve)(outputDir);
|
|
55
|
+
let credentials = this.authenticate(flags);
|
|
54
56
|
if (!skipCompile) {
|
|
55
57
|
const codegen = (0, packageManager_1.execBinCommand)('mimic', ['codegen'], process.cwd());
|
|
56
58
|
if (codegen.status !== 0)
|
|
@@ -74,7 +76,7 @@ class Deploy extends core_1.Command {
|
|
|
74
76
|
});
|
|
75
77
|
}
|
|
76
78
|
log_1.default.startAction('Uploading to Mimic Registry');
|
|
77
|
-
const CID = await this.uploadToRegistry(neededFiles,
|
|
79
|
+
const CID = await this.uploadToRegistry(neededFiles, credentials, registryUrl);
|
|
78
80
|
console.log(`IPFS CID: ${log_1.default.highlightText(CID)}`);
|
|
79
81
|
log_1.default.stopAction();
|
|
80
82
|
if (!fs.existsSync(fullOutputDir))
|
|
@@ -83,12 +85,12 @@ class Deploy extends core_1.Command {
|
|
|
83
85
|
console.log(`CID saved at ${log_1.default.highlightText(fullOutputDir)}`);
|
|
84
86
|
console.log(`Task deployed!`);
|
|
85
87
|
}
|
|
86
|
-
async uploadToRegistry(files,
|
|
88
|
+
async uploadToRegistry(files, credentials, registryUrl) {
|
|
87
89
|
try {
|
|
88
90
|
const form = filesToForm(files);
|
|
89
91
|
const { data } = await axios_1.default.post(`${registryUrl}/tasks`, form, {
|
|
90
92
|
headers: {
|
|
91
|
-
'x-api-key':
|
|
93
|
+
'x-api-key': credentials.apiKey,
|
|
92
94
|
'Content-Type': `multipart/form-data; boundary=${form.getBoundary()}`,
|
|
93
95
|
},
|
|
94
96
|
});
|
|
@@ -114,9 +116,13 @@ class Deploy extends core_1.Command {
|
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
118
|
Deploy.description = 'Uploads your compiled task artifacts to IPFS and registers it into the Mimic Registry';
|
|
117
|
-
Deploy.examples = [
|
|
119
|
+
Deploy.examples = [
|
|
120
|
+
'<%= config.bin %> <%= command.id %> --input ./dist --output ./dist',
|
|
121
|
+
'<%= config.bin %> <%= command.id %> --profile staging',
|
|
122
|
+
'<%= config.bin %> <%= command.id %> --api-key MY_KEY --input ./dist --output ./dist',
|
|
123
|
+
];
|
|
118
124
|
Deploy.flags = {
|
|
119
|
-
|
|
125
|
+
...authenticate_1.default.flags,
|
|
120
126
|
input: core_1.Flags.string({ char: 'i', description: 'Directory containing the compiled artifacts', default: './build' }),
|
|
121
127
|
output: core_1.Flags.string({ char: 'o', description: 'Output directory for deployment CID', default: './build' }),
|
|
122
128
|
url: core_1.Flags.string({ char: 'u', description: `Mimic Registry base URL`, default: MIMIC_REGISTRY_DEFAULT }),
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const prompts_1 = require("@inquirer/prompts");
|
|
7
|
+
const core_1 = require("@oclif/core");
|
|
8
|
+
const CredentialsManager_1 = require("../lib/CredentialsManager");
|
|
9
|
+
const log_1 = __importDefault(require("../log"));
|
|
10
|
+
const authenticate_1 = __importDefault(require("./authenticate"));
|
|
11
|
+
class Login extends authenticate_1.default {
|
|
12
|
+
async run() {
|
|
13
|
+
const { flags } = await this.parse(Login);
|
|
14
|
+
const { profile: profileInput, 'api-key': apiKeyFlag } = flags;
|
|
15
|
+
let apiKey;
|
|
16
|
+
let profileName = profileInput;
|
|
17
|
+
// Non-interactive mode
|
|
18
|
+
if (apiKeyFlag)
|
|
19
|
+
apiKey = apiKeyFlag;
|
|
20
|
+
else {
|
|
21
|
+
// Interactive mode
|
|
22
|
+
try {
|
|
23
|
+
apiKey = await (0, prompts_1.password)({
|
|
24
|
+
message: 'Enter your API key:',
|
|
25
|
+
mask: '*',
|
|
26
|
+
validate: (value) => {
|
|
27
|
+
if (!value || value.trim() === '')
|
|
28
|
+
return 'API key cannot be empty';
|
|
29
|
+
return true;
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
if (!profileName) {
|
|
33
|
+
profileName = await (0, prompts_1.input)({
|
|
34
|
+
message: `Enter a profile name (press Enter for "${CredentialsManager_1.CredentialsManager.getDefaultProfileName()}"):`,
|
|
35
|
+
default: CredentialsManager_1.CredentialsManager.getDefaultProfileName(),
|
|
36
|
+
validate: (value) => {
|
|
37
|
+
if (!value || value.trim() === '')
|
|
38
|
+
return 'Profile name cannot be empty';
|
|
39
|
+
if (value.includes('[') || value.includes(']') || value.includes('=')) {
|
|
40
|
+
return 'Profile name cannot contain [, ], or = characters';
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
49
|
+
console.log('\nLogin cancelled');
|
|
50
|
+
this.exit(0);
|
|
51
|
+
}
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
this.saveAndConfirm(profileName || CredentialsManager_1.CredentialsManager.getDefaultProfileName(), apiKey, flags['force-login']);
|
|
56
|
+
}
|
|
57
|
+
async saveAndConfirm(profileName, apiKey, forceLogin) {
|
|
58
|
+
try {
|
|
59
|
+
const credentialsManager = CredentialsManager_1.CredentialsManager.getDefault();
|
|
60
|
+
if (credentialsManager.profileExists(profileName) && !forceLogin) {
|
|
61
|
+
const shouldOverwrite = await (0, prompts_1.confirm)({
|
|
62
|
+
message: `Profile ${log_1.default.highlightText(profileName)} already exists. Overwrite?`,
|
|
63
|
+
default: false,
|
|
64
|
+
});
|
|
65
|
+
if (!shouldOverwrite) {
|
|
66
|
+
console.log('Login cancelled');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
log_1.default.startAction('Saving credentials');
|
|
71
|
+
credentialsManager.saveProfile(profileName, apiKey);
|
|
72
|
+
log_1.default.stopAction();
|
|
73
|
+
console.log(`✓ Credentials saved for profile ${log_1.default.highlightText(profileName)}`);
|
|
74
|
+
console.log(` Location: ${log_1.default.highlightText('~/.mimic/credentials')}`);
|
|
75
|
+
console.log();
|
|
76
|
+
console.log(`You can now deploy tasks using: ${log_1.default.highlightText('mimic deploy')}`);
|
|
77
|
+
if (profileName !== CredentialsManager_1.CredentialsManager.getDefaultProfileName()) {
|
|
78
|
+
console.log(`Or with your profile: ${log_1.default.highlightText(`mimic deploy --profile ${profileName}`)}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (error instanceof Error)
|
|
83
|
+
this.error(`Failed to save credentials: ${error.message}`);
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
Login.description = 'Authenticate with Mimic by storing your API key locally';
|
|
89
|
+
Login.examples = [
|
|
90
|
+
'<%= config.bin %> <%= command.id %>',
|
|
91
|
+
'<%= config.bin %> <%= command.id %> --profile staging',
|
|
92
|
+
'<%= config.bin %> <%= command.id %> --profile production --api-key YOUR_API_KEY',
|
|
93
|
+
];
|
|
94
|
+
Login.flags = {
|
|
95
|
+
...authenticate_1.default.flags,
|
|
96
|
+
'force-login': core_1.Flags.boolean({
|
|
97
|
+
char: 'f',
|
|
98
|
+
description: 'Force login even if profile exists',
|
|
99
|
+
default: false,
|
|
100
|
+
}),
|
|
101
|
+
};
|
|
102
|
+
exports.default = Login;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const prompts_1 = require("@inquirer/prompts");
|
|
7
|
+
const core_1 = require("@oclif/core");
|
|
8
|
+
const CredentialsManager_1 = require("../lib/CredentialsManager");
|
|
9
|
+
const log_1 = __importDefault(require("../log"));
|
|
10
|
+
class Logout extends core_1.Command {
|
|
11
|
+
async run() {
|
|
12
|
+
const { flags } = await this.parse(Logout);
|
|
13
|
+
const { profile: profileName, force } = flags;
|
|
14
|
+
const profiles = CredentialsManager_1.CredentialsManager.getDefault().getProfiles();
|
|
15
|
+
if (!profiles.includes(profileName)) {
|
|
16
|
+
this.error(`Profile '${profileName}' does not exist`, {
|
|
17
|
+
code: 'ProfileNotFound',
|
|
18
|
+
suggestions: profiles.length > 0
|
|
19
|
+
? [`Available profiles: ${profiles.join(', ')}`]
|
|
20
|
+
: ['No profiles found. Use `mimic login` to create one.'],
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
if (!force) {
|
|
24
|
+
const shouldRemove = await (0, prompts_1.confirm)({
|
|
25
|
+
message: `Are you sure you want to remove credentials for profile ${log_1.default.highlightText(profileName)}?`,
|
|
26
|
+
default: false,
|
|
27
|
+
});
|
|
28
|
+
if (!shouldRemove) {
|
|
29
|
+
console.log('Logout cancelled');
|
|
30
|
+
this.exit(0);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
log_1.default.startAction(`Removing credentials for profile ${profileName}`);
|
|
34
|
+
CredentialsManager_1.CredentialsManager.getDefault().removeProfile(profileName);
|
|
35
|
+
log_1.default.stopAction();
|
|
36
|
+
console.log(`✓ Credentials removed for profile ${log_1.default.highlightText(profileName)}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
Logout.description = 'Remove stored credentials for a profile';
|
|
40
|
+
Logout.examples = [
|
|
41
|
+
'<%= config.bin %> <%= command.id %>',
|
|
42
|
+
'<%= config.bin %> <%= command.id %> --profile staging',
|
|
43
|
+
];
|
|
44
|
+
Logout.flags = {
|
|
45
|
+
profile: core_1.Flags.string({
|
|
46
|
+
char: 'p',
|
|
47
|
+
description: 'Profile name to remove',
|
|
48
|
+
default: CredentialsManager_1.CredentialsManager.getDefaultProfileName(),
|
|
49
|
+
}),
|
|
50
|
+
force: core_1.Flags.boolean({
|
|
51
|
+
char: 'f',
|
|
52
|
+
description: 'Skip confirmation prompt',
|
|
53
|
+
default: false,
|
|
54
|
+
}),
|
|
55
|
+
};
|
|
56
|
+
exports.default = Logout;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const core_1 = require("@oclif/core");
|
|
7
|
+
const CredentialsManager_1 = require("../lib/CredentialsManager");
|
|
8
|
+
const log_1 = __importDefault(require("../log"));
|
|
9
|
+
class Profiles extends core_1.Command {
|
|
10
|
+
async run() {
|
|
11
|
+
const profiles = CredentialsManager_1.CredentialsManager.getDefault().getProfiles();
|
|
12
|
+
if (profiles.length === 0) {
|
|
13
|
+
console.log('No profiles found.');
|
|
14
|
+
console.log();
|
|
15
|
+
console.log(`Run ${log_1.default.highlightText('mimic login')} to create your first profile.`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
console.log(`Configured profiles (stored in ${log_1.default.highlightText('~/.mimic/credentials')}):`);
|
|
19
|
+
console.log();
|
|
20
|
+
for (const profile of profiles) {
|
|
21
|
+
console.log(`* ${log_1.default.highlightText(profile)}${profile === CredentialsManager_1.CredentialsManager.getDefaultProfileName() ? ' (default)' : ''}`);
|
|
22
|
+
}
|
|
23
|
+
console.log();
|
|
24
|
+
console.log(`Use ${log_1.default.highlightText('mimic deploy --profile <name>')} to deploy with a specific profile.`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
Profiles.description = 'List all configured authentication profiles';
|
|
28
|
+
Profiles.examples = ['<%= config.bin %> <%= command.id %>'];
|
|
29
|
+
exports.default = Profiles;
|
package/dist/commands/test.js
CHANGED
|
@@ -38,9 +38,8 @@ const path = __importStar(require("path"));
|
|
|
38
38
|
const packageManager_1 = require("../lib/packageManager");
|
|
39
39
|
class Test extends core_1.Command {
|
|
40
40
|
async run() {
|
|
41
|
-
const {
|
|
42
|
-
const { directory } =
|
|
43
|
-
const { 'skip-compile': skipCompile } = flags;
|
|
41
|
+
const { flags } = await this.parse(Test);
|
|
42
|
+
const { directory, 'skip-compile': skipCompile } = flags;
|
|
44
43
|
const baseDir = path.resolve(directory);
|
|
45
44
|
const testPath = path.join(baseDir, 'tests');
|
|
46
45
|
if (!skipCompile) {
|
|
@@ -56,11 +55,9 @@ class Test extends core_1.Command {
|
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
57
|
Test.description = 'Runs task tests';
|
|
59
|
-
Test.examples = ['<%= config.bin %> <%= command.id %> ./'];
|
|
60
|
-
Test.args = {
|
|
61
|
-
directory: core_1.Args.string({ description: 'task directory', required: false, default: './' }),
|
|
62
|
-
};
|
|
58
|
+
Test.examples = ['<%= config.bin %> <%= command.id %> --directory ./'];
|
|
63
59
|
Test.flags = {
|
|
60
|
+
directory: core_1.Flags.string({ char: 'd', description: 'task directory', default: './' }),
|
|
64
61
|
'skip-compile': core_1.Flags.boolean({ description: 'skip codegen and compile steps' }),
|
|
65
62
|
};
|
|
66
63
|
exports.default = Test;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.CredentialsManager = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const os = __importStar(require("os"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const CREDENTIALS_FILE = 'credentials';
|
|
41
|
+
const DEFAULT_PROFILE = 'default';
|
|
42
|
+
class CredentialsManager {
|
|
43
|
+
static getDefault() {
|
|
44
|
+
return new CredentialsManager();
|
|
45
|
+
}
|
|
46
|
+
static getCredentialsFileName() {
|
|
47
|
+
return CREDENTIALS_FILE;
|
|
48
|
+
}
|
|
49
|
+
static getDefaultProfileName() {
|
|
50
|
+
return DEFAULT_PROFILE;
|
|
51
|
+
}
|
|
52
|
+
constructor(baseDir) {
|
|
53
|
+
this.baseDir = baseDir || path.join(os.homedir(), '.mimic');
|
|
54
|
+
}
|
|
55
|
+
getBaseDir() {
|
|
56
|
+
return this.baseDir;
|
|
57
|
+
}
|
|
58
|
+
getCredentialsPath() {
|
|
59
|
+
return path.join(this.getBaseDir(), CREDENTIALS_FILE);
|
|
60
|
+
}
|
|
61
|
+
createCredentialsDirIfNotExists() {
|
|
62
|
+
if (fs.existsSync(this.getBaseDir()))
|
|
63
|
+
return;
|
|
64
|
+
fs.mkdirSync(this.getBaseDir(), { recursive: true });
|
|
65
|
+
if (process.platform !== 'win32') {
|
|
66
|
+
try {
|
|
67
|
+
fs.chmodSync(this.getBaseDir(), 0o700);
|
|
68
|
+
}
|
|
69
|
+
catch { }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
parseCredentials(content) {
|
|
73
|
+
const profiles = {};
|
|
74
|
+
const lines = content.split('\n');
|
|
75
|
+
let currentProfile = null;
|
|
76
|
+
for (const line of lines) {
|
|
77
|
+
const trimmed = line.trim();
|
|
78
|
+
if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith(';'))
|
|
79
|
+
continue;
|
|
80
|
+
const profileMatch = trimmed.match(/^\[([^\]]+)\]$/);
|
|
81
|
+
if (profileMatch) {
|
|
82
|
+
currentProfile = profileMatch[1];
|
|
83
|
+
profiles[currentProfile] = { apiKey: '' };
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (currentProfile) {
|
|
87
|
+
const kvMatch = trimmed.match(/^([^=]+)=(.*)$/);
|
|
88
|
+
if (kvMatch) {
|
|
89
|
+
const key = kvMatch[1].trim();
|
|
90
|
+
const value = kvMatch[2].trim();
|
|
91
|
+
if (key === 'api_key')
|
|
92
|
+
profiles[currentProfile].apiKey = value;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return profiles;
|
|
97
|
+
}
|
|
98
|
+
serializeCredentials(profiles) {
|
|
99
|
+
const lines = [];
|
|
100
|
+
const profileEntries = Object.entries(profiles);
|
|
101
|
+
profileEntries.forEach(([profileName, credentials]) => {
|
|
102
|
+
lines.push(`[${profileName}]`);
|
|
103
|
+
lines.push(`api_key=${credentials.apiKey}`);
|
|
104
|
+
lines.push('');
|
|
105
|
+
});
|
|
106
|
+
return lines.join('\n');
|
|
107
|
+
}
|
|
108
|
+
readCredentials() {
|
|
109
|
+
const credentialsPath = this.getCredentialsPath();
|
|
110
|
+
if (!fs.existsSync(credentialsPath))
|
|
111
|
+
return {};
|
|
112
|
+
const content = fs.readFileSync(credentialsPath, 'utf-8');
|
|
113
|
+
return this.parseCredentials(content);
|
|
114
|
+
}
|
|
115
|
+
writeCredentials(profiles) {
|
|
116
|
+
this.createCredentialsDirIfNotExists();
|
|
117
|
+
const credentialsPath = this.getCredentialsPath();
|
|
118
|
+
const content = this.serializeCredentials(profiles);
|
|
119
|
+
fs.writeFileSync(credentialsPath, content, { mode: 0o600 });
|
|
120
|
+
if (process.platform !== 'win32') {
|
|
121
|
+
try {
|
|
122
|
+
fs.chmodSync(credentialsPath, 0o600);
|
|
123
|
+
}
|
|
124
|
+
catch { }
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
saveProfile(profileName, apiKey) {
|
|
128
|
+
const profiles = this.readCredentials();
|
|
129
|
+
profiles[profileName] = { apiKey };
|
|
130
|
+
this.writeCredentials(profiles);
|
|
131
|
+
}
|
|
132
|
+
getProfile(profileName = DEFAULT_PROFILE) {
|
|
133
|
+
const credentialsDir = this.getBaseDir();
|
|
134
|
+
const credentialsPath = this.getCredentialsPath();
|
|
135
|
+
if (!fs.existsSync(credentialsDir)) {
|
|
136
|
+
throw new Error(`No credentials directory found at ${credentialsDir}. Run 'mimic login' to authenticate.`);
|
|
137
|
+
}
|
|
138
|
+
if (!fs.existsSync(credentialsPath)) {
|
|
139
|
+
throw new Error(`No credentials file found. Run 'mimic login' to authenticate.`);
|
|
140
|
+
}
|
|
141
|
+
const profiles = this.readCredentials();
|
|
142
|
+
if (!profiles[profileName]) {
|
|
143
|
+
const availableProfiles = Object.keys(profiles);
|
|
144
|
+
const suggestion = availableProfiles.length > 0
|
|
145
|
+
? `Available profiles: ${availableProfiles.join(', ')}`
|
|
146
|
+
: `No profiles found. Run 'mimic login' to create one.`;
|
|
147
|
+
throw new Error(`Profile '${profileName}' not found. ${suggestion}`);
|
|
148
|
+
}
|
|
149
|
+
const credentials = profiles[profileName];
|
|
150
|
+
if (!credentials.apiKey || credentials.apiKey.trim() === '') {
|
|
151
|
+
throw new Error(`Profile '${profileName}' has no API key. Run 'mimic login --profile ${profileName}' to update credentials.`);
|
|
152
|
+
}
|
|
153
|
+
return credentials;
|
|
154
|
+
}
|
|
155
|
+
getCredentials(profileName = DEFAULT_PROFILE) {
|
|
156
|
+
try {
|
|
157
|
+
return this.getProfile(profileName);
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
if (error instanceof Error)
|
|
161
|
+
throw new Error(`Authentication required: ${error.message}`);
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
getProfiles() {
|
|
166
|
+
const profiles = this.readCredentials();
|
|
167
|
+
return Object.keys(profiles);
|
|
168
|
+
}
|
|
169
|
+
removeProfile(profileName) {
|
|
170
|
+
const profiles = this.readCredentials();
|
|
171
|
+
if (!profiles[profileName])
|
|
172
|
+
throw new Error(`Profile '${profileName}' does not exist`);
|
|
173
|
+
delete profiles[profileName];
|
|
174
|
+
this.writeCredentials(profiles);
|
|
175
|
+
}
|
|
176
|
+
profileExists(profileName) {
|
|
177
|
+
const profiles = this.readCredentials();
|
|
178
|
+
return profileName in profiles;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
exports.CredentialsManager = CredentialsManager;
|