superuser.app 0.0.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/LICENSE +20 -0
- package/README.md +296 -0
- package/commands/domains/add.js +102 -0
- package/commands/domains/list.js +71 -0
- package/commands/domains/remove.js +97 -0
- package/commands/domains/verify.js +130 -0
- package/commands/g/endpoint.js +32 -0
- package/commands/g/test.js +42 -0
- package/commands/init.js +220 -0
- package/commands/login.js +123 -0
- package/commands/me.js +54 -0
- package/commands/organizations/create.js +68 -0
- package/commands/profile.js +58 -0
- package/commands/register.js +127 -0
- package/commands/run.js +194 -0
- package/commands/serve.js +35 -0
- package/commands/test.js +68 -0
- package/commands/up.js +257 -0
- package/commands/update.js +84 -0
- package/commands/version.js +31 -0
- package/helpers/constants.js +3 -0
- package/helpers/draw_box.js +38 -0
- package/helpers/draw_table.js +144 -0
- package/helpers/file_writer.js +101 -0
- package/helpers/generate/endpoint/_index.js +44 -0
- package/helpers/generate/test/_index.js +112 -0
- package/helpers/load_package.js +62 -0
- package/helpers/local_server.js +72 -0
- package/helpers/settings_manager.js +108 -0
- package/helpers/verify_packages.js +85 -0
- package/index.js +7 -0
- package/package.json +31 -0
- package/src/endpoint/functions/index.js +35 -0
- package/src/init/__.env +1 -0
- package/src/init/__.env.production +1 -0
- package/src/init/__.env.staging +1 -0
- package/src/init/__.gitignore +6 -0
- package/src/init/functions/index.js +15 -0
- package/src/init/instant.package.json +3 -0
- package/src/init/package.json +16 -0
- package/src/init/serve.instant.js +52 -0
- package/src/init/test/run.js +45 -0
- package/src/init/test/tests/_index.js +53 -0
- package/src/test/blank.mjs +16 -0
- package/src/test/endpoint.mjs +20 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const { Command } = require('cmnd');
|
|
2
|
+
const colors = require('colors/safe');
|
|
3
|
+
const inquirer = require('inquirer');
|
|
4
|
+
|
|
5
|
+
const SettingsManager = require('../helpers/settings_manager.js');
|
|
6
|
+
const DrawTable = require('../helpers/draw_table.js');
|
|
7
|
+
|
|
8
|
+
class ProfileCommand extends Command {
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
super('profile');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
help () {
|
|
15
|
+
return {
|
|
16
|
+
description: 'Change your active profile',
|
|
17
|
+
args: [],
|
|
18
|
+
flags: {},
|
|
19
|
+
vflags: {}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async run (params) {
|
|
24
|
+
|
|
25
|
+
const settings = SettingsManager.read(true);
|
|
26
|
+
const profiles = settings.profileList;
|
|
27
|
+
|
|
28
|
+
console.log();
|
|
29
|
+
|
|
30
|
+
const columns = ['email', 'host', 'active'];
|
|
31
|
+
const rows = profiles.map((p, i) => {
|
|
32
|
+
return {
|
|
33
|
+
email: p.email,
|
|
34
|
+
host: p.host || '',
|
|
35
|
+
active: i === 0
|
|
36
|
+
? colors.bold.green('yes')
|
|
37
|
+
: ''
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const index = await DrawTable.selectIndexFromTable(
|
|
42
|
+
'Choose your active profile',
|
|
43
|
+
columns,
|
|
44
|
+
rows
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
console.log();
|
|
48
|
+
if (index !== -1) {
|
|
49
|
+
SettingsManager.write(profiles[index]);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return void 0;
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = ProfileCommand;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const { Command } = require('cmnd');
|
|
2
|
+
const io = require('io');
|
|
3
|
+
const colors = require('colors/safe');
|
|
4
|
+
const inquirer = require('inquirer');
|
|
5
|
+
|
|
6
|
+
const constants = require('../helpers/constants.js');
|
|
7
|
+
|
|
8
|
+
const LoginCommand = require('./login.js');
|
|
9
|
+
|
|
10
|
+
class RegisterCommand extends Command {
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
super('register');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
help () {
|
|
17
|
+
return {
|
|
18
|
+
description: 'Registers a new user account with the Superuser Package Registry',
|
|
19
|
+
args: [],
|
|
20
|
+
flags: {},
|
|
21
|
+
vflags: {}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async run (params) {
|
|
26
|
+
|
|
27
|
+
let host = (params.flags.h || [])[0] || constants.BASE_URL;
|
|
28
|
+
if (!host.startsWith('http://') && !host.startsWith('https://')) {
|
|
29
|
+
host = host.startsWith('localhost')
|
|
30
|
+
? `http://${host}`
|
|
31
|
+
: `https://${host}`
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let registerResult = await inquirer.prompt([
|
|
35
|
+
{
|
|
36
|
+
name: 'email',
|
|
37
|
+
type: 'input',
|
|
38
|
+
message: `E-mail`,
|
|
39
|
+
validate: e => {
|
|
40
|
+
if (!e.match(/^[^@]+@[^@]+\.[a-z0-9\-]+$/gi)) {
|
|
41
|
+
return 'Must be a valid e-mail address';
|
|
42
|
+
} else {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'organization_name',
|
|
49
|
+
type: 'input',
|
|
50
|
+
message: `Username`,
|
|
51
|
+
validate: v => {
|
|
52
|
+
if (
|
|
53
|
+
v.match(/[a-z][a-z0-9\-]*[a-z0-9]/i) &&
|
|
54
|
+
v.indexOf('--') === -1
|
|
55
|
+
) {
|
|
56
|
+
return true;
|
|
57
|
+
} else {
|
|
58
|
+
return 'must start with a letter, end with a letter or number, and contain only A-Z, a-z, 0-9 or -';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'password',
|
|
64
|
+
type: 'password',
|
|
65
|
+
message: `Password`
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'repeat_password',
|
|
69
|
+
type: 'password',
|
|
70
|
+
message: `Repeat password`
|
|
71
|
+
}
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
let result = await io.post(
|
|
75
|
+
`${host}/users`,
|
|
76
|
+
null,
|
|
77
|
+
null,
|
|
78
|
+
registerResult
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
if (result.statusCode !== 200) {
|
|
82
|
+
const e = result.data.error;
|
|
83
|
+
const message = e.message;
|
|
84
|
+
const details = e.details || {};
|
|
85
|
+
const more = [];
|
|
86
|
+
if (Object.keys(details).length) {
|
|
87
|
+
for (const key in details) {
|
|
88
|
+
more.push(`- ${colors.bold(key)}: ${details[key].message}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
throw new Error(
|
|
92
|
+
message +
|
|
93
|
+
(
|
|
94
|
+
more.length
|
|
95
|
+
? '\n\n' + more.join('\n')
|
|
96
|
+
: ''
|
|
97
|
+
)
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const user = result.data; // grab json {data:}
|
|
102
|
+
|
|
103
|
+
console.log();
|
|
104
|
+
console.log(colors.bold(`${colors.blue(`Registered`)} for ${colors.green('Superuser')} successfully!`));
|
|
105
|
+
console.log(`${colors.bold(`email`)}: ${user.email}`);
|
|
106
|
+
console.log(`${colors.bold(`username`)}: ${user.memberships[0].organization.name}`);
|
|
107
|
+
console.log(`${colors.bold(`created at`)}: ${user.created_at}`);
|
|
108
|
+
|
|
109
|
+
return LoginCommand.prototype.run.call(
|
|
110
|
+
this,
|
|
111
|
+
{
|
|
112
|
+
args: [],
|
|
113
|
+
flags: {
|
|
114
|
+
h: params.flags.h
|
|
115
|
+
},
|
|
116
|
+
vflags: {
|
|
117
|
+
email: [user.email],
|
|
118
|
+
password: [registerResult.password]
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
module.exports = RegisterCommand;
|
package/commands/run.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
const { Command } = require('cmnd');
|
|
2
|
+
const colors = require('colors/safe');
|
|
3
|
+
const io = require('io');
|
|
4
|
+
const kill = require('tree-kill');
|
|
5
|
+
|
|
6
|
+
const loadPackage = require('../helpers/load_package.js');
|
|
7
|
+
const localServer = require('../helpers/local_server.js');
|
|
8
|
+
|
|
9
|
+
const sleep = t => new Promise(r => setTimeout(() => r(1), t));
|
|
10
|
+
const killProcess = pid => {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
kill(pid, (err) => {
|
|
13
|
+
if (err) {
|
|
14
|
+
reject(err);
|
|
15
|
+
} else {
|
|
16
|
+
resolve(true);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
class RunCommand extends Command {
|
|
23
|
+
|
|
24
|
+
constructor() {
|
|
25
|
+
super('run');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
help() {
|
|
29
|
+
return {
|
|
30
|
+
description: 'Runs a function in the local project',
|
|
31
|
+
args: [],
|
|
32
|
+
flags: {
|
|
33
|
+
'm': 'Specify method, default is "get"',
|
|
34
|
+
'v': 'Verbose mode: shows URL, status code and arguments'
|
|
35
|
+
},
|
|
36
|
+
vflags: {
|
|
37
|
+
'*': 'Used to populate query and / or body parameters'
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async run(params) {
|
|
43
|
+
|
|
44
|
+
// Use 8199 for test runs
|
|
45
|
+
const InstantPackage = await loadPackage(params, true);
|
|
46
|
+
const port = 8199;
|
|
47
|
+
const timeout = 5000;
|
|
48
|
+
const url = `http://localhost:${port}`;
|
|
49
|
+
|
|
50
|
+
// Validate arguments, default method is "get"
|
|
51
|
+
const method = ((params.flags['m'] || [])[0] || 'get').toLowerCase();
|
|
52
|
+
if (['get', 'post', 'put', 'delete', 'del'].indexOf(method) === -1) {
|
|
53
|
+
throw new Error(`Method "${method}" not supported.`);
|
|
54
|
+
}
|
|
55
|
+
if (method === 'del') {
|
|
56
|
+
method = 'delete';
|
|
57
|
+
}
|
|
58
|
+
const functionParams = Object.keys(params.vflags).reduce((functionParams, key) => {
|
|
59
|
+
functionParams[key] = params.vflags[key].join(' ');
|
|
60
|
+
return functionParams;
|
|
61
|
+
}, {});
|
|
62
|
+
let pathname = params.args[0] || '';
|
|
63
|
+
if (!pathname) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Please provide a pathname as the first argument.\n` +
|
|
66
|
+
`Use "/" to execute the root method (index.js)`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
if (pathname.startsWith('..')) {
|
|
70
|
+
throw new Error(`Invalid pathname: "${pathname}"`);
|
|
71
|
+
}
|
|
72
|
+
if (pathname.startsWith('.')) {
|
|
73
|
+
pathname = pathname.slice(1);
|
|
74
|
+
}
|
|
75
|
+
if (pathname.startsWith('/')) {
|
|
76
|
+
pathname = pathname.slice(1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const proc = localServer.run({ port, isBackground: true });
|
|
80
|
+
let isConnected = false;
|
|
81
|
+
proc.stdout.on('data', data => {
|
|
82
|
+
const message = data.toString();
|
|
83
|
+
|
|
84
|
+
if (message.includes(`*** Listening on localhost:${port}`)) {
|
|
85
|
+
isConnected = true;
|
|
86
|
+
} else if (message.includes(`Unable to spawn HTTP Workers, listening on port ${port}`)) {
|
|
87
|
+
isConnected = true;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Wait for connection or timeout
|
|
92
|
+
let isTimedOut = false
|
|
93
|
+
await Promise.race([
|
|
94
|
+
(async () => {
|
|
95
|
+
await sleep(timeout);
|
|
96
|
+
if (!isConnected) {
|
|
97
|
+
isTimedOut = true;
|
|
98
|
+
await killProcess(proc.pid);
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Timed out waiting for development server.\n` +
|
|
101
|
+
`Are you sure you're not running another server on :${port}?\n` +
|
|
102
|
+
`To kill any processes running on this port on a unix system, use:\n` +
|
|
103
|
+
`$ lsof -ti :${port} | xargs kill -9`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
})(),
|
|
107
|
+
(async () => {
|
|
108
|
+
while (!isConnected && !isTimedOut) {
|
|
109
|
+
await sleep(1);
|
|
110
|
+
}
|
|
111
|
+
return true;
|
|
112
|
+
})()
|
|
113
|
+
]);
|
|
114
|
+
|
|
115
|
+
const queryParams = (method === 'get' || method === 'delete')
|
|
116
|
+
? { ...functionParams }
|
|
117
|
+
: {};
|
|
118
|
+
queryParams._debug = true;
|
|
119
|
+
const bodyParams = (method === 'post' || method === 'put')
|
|
120
|
+
? JSON.stringify(functionParams)
|
|
121
|
+
: '';
|
|
122
|
+
|
|
123
|
+
let result;
|
|
124
|
+
const streamResult = await io.request(
|
|
125
|
+
method.toUpperCase(),
|
|
126
|
+
`${url}/${pathname}`,
|
|
127
|
+
queryParams,
|
|
128
|
+
{},
|
|
129
|
+
bodyParams,
|
|
130
|
+
({id, event, data}) => {
|
|
131
|
+
if (event === '@response') {
|
|
132
|
+
let json = JSON.parse(data);
|
|
133
|
+
result = json;
|
|
134
|
+
} else if (event === '@stdout') {
|
|
135
|
+
let json = JSON.parse(data);
|
|
136
|
+
json.split('\n').forEach(line => {
|
|
137
|
+
console.log(colors.grey(`${params.flags.v ? colors.bold(`stdout> `) : ''}${line}`));
|
|
138
|
+
});
|
|
139
|
+
} else if (event === '@stderr') {
|
|
140
|
+
let json = JSON.parse(data);
|
|
141
|
+
json.split('\n').forEach(line => {
|
|
142
|
+
console.log(colors.yellow(`${params.flags.v ? colors.bold(`stderr> `) : ''}${line}`));
|
|
143
|
+
});
|
|
144
|
+
} else {
|
|
145
|
+
console.log(colors.blue(`${colors.bold(`${event}> `)}${data}`));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
// Handle non-event errors given by server
|
|
151
|
+
if (streamResult.statusCode === 500) {
|
|
152
|
+
const errorBody = streamResult.body.toString();
|
|
153
|
+
let errorMessage = errorBody;
|
|
154
|
+
// cut out the "Application Error: " prefix and only capture the first line
|
|
155
|
+
if (errorBody.startsWith('Application Error:')) {
|
|
156
|
+
errorMessage = errorBody.slice('Application Error: '.length);
|
|
157
|
+
}
|
|
158
|
+
// ignore the stack trace
|
|
159
|
+
errorMessage = errorMessage.split('\n')[0];
|
|
160
|
+
throw new Error(errorMessage);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// retrieve details
|
|
164
|
+
const body = result.body.toString();
|
|
165
|
+
let json;
|
|
166
|
+
try {
|
|
167
|
+
json = JSON.parse(body);
|
|
168
|
+
} catch (e) {
|
|
169
|
+
// do nothing
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Terminate process
|
|
173
|
+
await killProcess(proc.pid);
|
|
174
|
+
if (params.flags.v) {
|
|
175
|
+
console.log(colors.bold.green('location: ') + `${url}/${pathname}`);
|
|
176
|
+
console.log(colors.bold.green('method: ') + method.toUpperCase());
|
|
177
|
+
console.log(colors.bold.green('status: ') + result.statusCode);
|
|
178
|
+
console.log(colors.bold.green('arguments: '));
|
|
179
|
+
console.log(JSON.stringify(functionParams, null, 2));
|
|
180
|
+
console.log(colors.bold.green('result:'));
|
|
181
|
+
}
|
|
182
|
+
if (json) {
|
|
183
|
+
console.log(JSON.stringify(json, null, 2));
|
|
184
|
+
} else {
|
|
185
|
+
console.log(body);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return void 0;
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
module.exports = RunCommand;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const { Command } = require('cmnd');
|
|
2
|
+
|
|
3
|
+
const loadPackage = require('../helpers/load_package.js');
|
|
4
|
+
const localServer = require('../helpers/local_server.js');
|
|
5
|
+
|
|
6
|
+
class ServeCommand extends Command {
|
|
7
|
+
|
|
8
|
+
constructor() {
|
|
9
|
+
super('serve');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
help () {
|
|
13
|
+
return {
|
|
14
|
+
description: 'Starts a development server using package.json["scripts"]["start"]',
|
|
15
|
+
args: [],
|
|
16
|
+
flags: {},
|
|
17
|
+
vflags: {
|
|
18
|
+
port: 'specify a port to run on'
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async run (params) {
|
|
24
|
+
|
|
25
|
+
const InstantPackage = await loadPackage(params, true);
|
|
26
|
+
|
|
27
|
+
localServer.run({ port: 8100 });
|
|
28
|
+
|
|
29
|
+
return void 0;
|
|
30
|
+
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = ServeCommand;
|
package/commands/test.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const { Command } = require('cmnd');
|
|
2
|
+
const colors = require('colors/safe');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const childProcess = require('child_process');
|
|
5
|
+
|
|
6
|
+
const loadPackage = require('../helpers/load_package.js');
|
|
7
|
+
|
|
8
|
+
class TestCommand extends Command {
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
super('test');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
help () {
|
|
15
|
+
return {
|
|
16
|
+
description: 'Runs tests using package.json["scripts"]["test"]',
|
|
17
|
+
args: [],
|
|
18
|
+
flags: {},
|
|
19
|
+
vflags: {}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async run (params) {
|
|
24
|
+
|
|
25
|
+
const InstantPackage = await loadPackage(params, true);
|
|
26
|
+
|
|
27
|
+
console.log();
|
|
28
|
+
console.log(`Running tests ...`);
|
|
29
|
+
const pkgExists = fs.existsSync('package.json');
|
|
30
|
+
if (pkgExists) {
|
|
31
|
+
let pkg;
|
|
32
|
+
try {
|
|
33
|
+
pkg = JSON.parse(fs.readFileSync('package.json').toString());
|
|
34
|
+
} catch (e) {
|
|
35
|
+
throw new Error(`Could not read "package.json"`);
|
|
36
|
+
}
|
|
37
|
+
if (pkg?.scripts?.test) {
|
|
38
|
+
console.log(`Running script: ${colors.blue.bold(pkg.scripts.test)} ...`);
|
|
39
|
+
console.log();
|
|
40
|
+
const result = childProcess.spawnSync(
|
|
41
|
+
`${pkg.scripts.test} ${params.args.join(' ')}`,
|
|
42
|
+
{
|
|
43
|
+
stdio: 'inherit',
|
|
44
|
+
shell: true,
|
|
45
|
+
env: {...process.env, PATH: process.env.PATH + ':./node_modules/.bin'}
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
if (result.status === 0) {
|
|
49
|
+
console.log(colors.bold.green(`Success!`) + ` All tests passed.`);
|
|
50
|
+
console.log();
|
|
51
|
+
} else {
|
|
52
|
+
console.log(colors.bold.red(`Failure:`) + ` One or more of your tests failed.`);
|
|
53
|
+
console.log();
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
throw new Error(`Could not find "package.json"["scripts"]["test"]`);
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
throw new Error(`No "package.json" in this directory`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return void 0;
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
module.exports = TestCommand;
|