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,44 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const colors = require('colors/safe');
|
|
5
|
+
|
|
6
|
+
const fileWriter = require('../../file_writer.js');
|
|
7
|
+
|
|
8
|
+
const generateTest = require('../test/_index.js');
|
|
9
|
+
|
|
10
|
+
module.exports = async (InstantPackage, params) => {
|
|
11
|
+
|
|
12
|
+
let writePathname = params.args[0] || '';
|
|
13
|
+
writePathname = writePathname.split('/').filter(v => !!v).join('/');
|
|
14
|
+
|
|
15
|
+
let newFilename;
|
|
16
|
+
|
|
17
|
+
const pathname = path.join(__dirname, '..', '..', '..', 'src', 'endpoint');
|
|
18
|
+
if (!fs.existsSync(pathname)) {
|
|
19
|
+
throw new Error(`No endpoint template found.`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
console.log();
|
|
23
|
+
console.log(colors.bold.black(`Generating:`) + ` Endpoint file ...`);
|
|
24
|
+
console.log();
|
|
25
|
+
|
|
26
|
+
const files = fileWriter.readRecursive(pathname);
|
|
27
|
+
for (const filename in files) {
|
|
28
|
+
newFilename = filename;
|
|
29
|
+
newFilename = newFilename.replace(/^\/functions\//gi, $0 => $0 + (writePathname ? `${writePathname}/` : ``));
|
|
30
|
+
let fileData = files[filename];
|
|
31
|
+
fileWriter.writeFile(newFilename, fileData, false);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
console.log();
|
|
35
|
+
console.log(colors.bold.green(`Success!`) + ` Created blank endpoint at "${newFilename}"!`);
|
|
36
|
+
console.log();
|
|
37
|
+
|
|
38
|
+
if (!params.vflags.hasOwnProperty('no-tests')) {
|
|
39
|
+
await generateTest(InstantPackage, {args: [], flags: {}, vflags: {endpoint: [newFilename]}});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return true;
|
|
43
|
+
|
|
44
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const colors = require('colors/safe');
|
|
5
|
+
|
|
6
|
+
const fileWriter = require('../../file_writer.js');
|
|
7
|
+
|
|
8
|
+
module.exports = async (InstantPackage, params) => {
|
|
9
|
+
|
|
10
|
+
let testName = params.args[0] || '';
|
|
11
|
+
testName = testName.split('/').filter(v => !!v).join('/');
|
|
12
|
+
testName = testName.replace(/\.m?js$/gi, '');
|
|
13
|
+
|
|
14
|
+
let endpointFor = ((params.vflags.endpoint || [])[0] || '');
|
|
15
|
+
|
|
16
|
+
if (testName) {
|
|
17
|
+
|
|
18
|
+
const pathname = path.join(__dirname, '..', '..', '..', 'src', 'test', 'blank.js');
|
|
19
|
+
if (!fs.existsSync(pathname)) {
|
|
20
|
+
throw new Error(`No test template found for model.`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let fileString = fs.readFileSync(pathname).toString();
|
|
24
|
+
fileString = fileString.replaceAll('Name', testName);
|
|
25
|
+
|
|
26
|
+
let newFilename = `test/tests/${testName}.js`;
|
|
27
|
+
const fileData = Buffer.from(fileString);
|
|
28
|
+
fileWriter.writeFile(newFilename, fileData, false);
|
|
29
|
+
|
|
30
|
+
console.log();
|
|
31
|
+
console.log(colors.bold.green(`Success!`) + ` Created tests for "${colors.bold.green(testName)}"!`);
|
|
32
|
+
console.log();
|
|
33
|
+
|
|
34
|
+
} else if (endpointFor) {
|
|
35
|
+
|
|
36
|
+
const pathname = path.join(__dirname, '..', '..', '..', 'src', 'test', 'endpoint.js');
|
|
37
|
+
if (!fs.existsSync(pathname)) {
|
|
38
|
+
throw new Error(`No test template found for endpoint.`);
|
|
39
|
+
}
|
|
40
|
+
if (!endpointFor.startsWith('/')) {
|
|
41
|
+
endpointFor = `/${endpointFor}`;
|
|
42
|
+
}
|
|
43
|
+
if (endpointFor.startsWith('/functions/')) {
|
|
44
|
+
endpointFor = endpointFor.slice('/functions'.length);
|
|
45
|
+
}
|
|
46
|
+
endpointFor = endpointFor.replace(/\.m?js$/, '');
|
|
47
|
+
let functionPathname = path.join(process.cwd(), `functions`, `${endpointFor}.js`);
|
|
48
|
+
if (!fs.existsSync(functionPathname)) {
|
|
49
|
+
functionPathname = path.join(process.cwd(), `functions`, `${endpointFor}.js`);
|
|
50
|
+
if (!fs.existsSync(functionPathname)) {
|
|
51
|
+
throw new Error(`Could not find matching endpoint "${endpointFor}" in "./functions" directory`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let methods = [];
|
|
56
|
+
let endpointPath;
|
|
57
|
+
if (endpointFor.endsWith('/index')) {
|
|
58
|
+
endpointPath = endpointFor.slice(0, -('/index').length) + '/';
|
|
59
|
+
} else if (endpointFor.endsWith('/__main__')) {
|
|
60
|
+
endpointPath = endpointFor.slice(0, -('/__main__').length) + '/';
|
|
61
|
+
} else if (endpointFor.endsWith('/__notfound__')) {
|
|
62
|
+
endpointPath = endpointFor.slice(0, -('/__notfound__').length) + '/*/';
|
|
63
|
+
} else if (endpointFor.endsWith('/404')) {
|
|
64
|
+
endpointPath = endpointFor.slice(0, -('/404').length) + '/*/';
|
|
65
|
+
} else {
|
|
66
|
+
endpointPath = endpointFor + '/';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const file = fs.readFileSync(pathname);
|
|
70
|
+
let fileString = file.toString();
|
|
71
|
+
let template = '';
|
|
72
|
+
fileString = fileString.replaceAll('Pathname', endpointPath);
|
|
73
|
+
fileString = fileString.replace(/(\n)([ \t]*)\/\/ Method Begin\s*?\n([\s\S]*?)\/\/ Method End[ \t]*(\n)/gi, ($0, $1, $2, $3, $4) => {
|
|
74
|
+
template = $2 + $3.trim();
|
|
75
|
+
return `${$1}/* *** */${$4}`;
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const dotenv = require(path.join(process.cwd(), `node_modules`, `dotenv`));
|
|
79
|
+
dotenv.config();
|
|
80
|
+
const endpoint = await import(functionPathname);
|
|
81
|
+
|
|
82
|
+
if ('default' in endpoint) {
|
|
83
|
+
methods.push('POST');
|
|
84
|
+
} else {
|
|
85
|
+
('GET' in endpoint) && methods.push('GET');
|
|
86
|
+
('POST' in endpoint) && methods.push('POST');
|
|
87
|
+
('PUT' in endpoint) && methods.push('PUT');
|
|
88
|
+
('DELETE' in endpoint) && methods.push('DELETE');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
fileString = fileString.replace(
|
|
92
|
+
'/* *** */',
|
|
93
|
+
methods.map(method => {
|
|
94
|
+
return template
|
|
95
|
+
.replaceAll('Method', method)
|
|
96
|
+
.replaceAll('__method__', method === `DELETE` ? `del` : method.toLowerCase());
|
|
97
|
+
}).join('\n\n')
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
let newFilename = `test/tests/functions${endpointFor}.js`;
|
|
101
|
+
const fileData = Buffer.from(fileString);
|
|
102
|
+
fileWriter.writeFile(newFilename, fileData, false);
|
|
103
|
+
|
|
104
|
+
console.log();
|
|
105
|
+
console.log(colors.bold.green(`Success!`) + ` Created tests for "${colors.bold.green(endpointFor)}"!`);
|
|
106
|
+
console.log();
|
|
107
|
+
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return true;
|
|
111
|
+
|
|
112
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const https = require('https');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
|
|
5
|
+
const verifyPackages = require('./verify_packages.js');
|
|
6
|
+
|
|
7
|
+
module.exports = async (params = null, validate = false) => {
|
|
8
|
+
|
|
9
|
+
if (validate) {
|
|
10
|
+
await verifyPackages(true);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let toolpkg;
|
|
14
|
+
const toolPathname = path.join(process.cwd(), 'superuser.json');
|
|
15
|
+
if (!fs.existsSync(toolPathname)) {
|
|
16
|
+
if (validate) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
`No "superuser.json" in this directory. Are you sure you meant to do this?\n` +
|
|
19
|
+
`Run \`$ ibot init\` to initialize a project here if you are.`
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
} else {
|
|
23
|
+
toolpkg = JSON.parse(fs.readFileSync(toolPathname));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let dotenv;
|
|
27
|
+
const dotenvPathname = path.join(process.cwd(), 'node_modules', 'dotenv');
|
|
28
|
+
if (!fs.existsSync(dotenvPathname)) {
|
|
29
|
+
if (validate) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
`dotenv should be installed in this directory to use Superuser Package locally.\n` +
|
|
32
|
+
`Run \`$ npm i dotenv --save-dev\` to install the latest version`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
36
|
+
dotenv = require(dotenvPathname);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let InstantAPI;
|
|
40
|
+
const pathname = path.join(process.cwd(), 'node_modules', '@instant.dev/api');
|
|
41
|
+
if (!fs.existsSync(pathname)) {
|
|
42
|
+
if (validate) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`@instant.dev/api should be installed in this directory to use Superuser Package locally.\n` +
|
|
45
|
+
`Run \`$ npm i @instant.dev/api --save-dev\` to install the latest version`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
InstantAPI = require(pathname);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (
|
|
53
|
+
toolpkg &&
|
|
54
|
+
dotenv &&
|
|
55
|
+
InstantAPI
|
|
56
|
+
) {
|
|
57
|
+
return { toolpkg, dotenv, InstantAPI };
|
|
58
|
+
} else {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const colors = require('colors/safe');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const childProcess = require('child_process');
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
run: ({port = null, isBackground = false} = {}) => {
|
|
7
|
+
const consoleLog = (...args) => !isBackground && console.log(...args);
|
|
8
|
+
consoleLog();
|
|
9
|
+
consoleLog(`Running ${colors.green.bold('Superuser Package')} development server ...`);
|
|
10
|
+
const pkgExists = fs.existsSync('package.json');
|
|
11
|
+
if (pkgExists) {
|
|
12
|
+
let pkg;
|
|
13
|
+
try {
|
|
14
|
+
pkg = JSON.parse(fs.readFileSync('package.json').toString());
|
|
15
|
+
} catch (e) {
|
|
16
|
+
throw new Error(`Could not read "package.json"`);
|
|
17
|
+
}
|
|
18
|
+
if (pkg?.scripts?.start) {
|
|
19
|
+
consoleLog(`Running script: ${colors.blue.bold(pkg.scripts.start)} ...`);
|
|
20
|
+
const envVars = {...process.env};
|
|
21
|
+
if (!fs.existsSync('.env')) {
|
|
22
|
+
consoleLog(
|
|
23
|
+
colors.bold.yellow(`Warn: `) +
|
|
24
|
+
`No envFile found in ".env", no environment variables loaded ...`
|
|
25
|
+
);
|
|
26
|
+
} else {
|
|
27
|
+
const lines = fs.readFileSync(`.env`)
|
|
28
|
+
.toString()
|
|
29
|
+
.split('\n')
|
|
30
|
+
.filter(line => !!line.trim() && !line.trim().startsWith('#'));
|
|
31
|
+
for (const line of lines) {
|
|
32
|
+
const key = line.split('=')[0];
|
|
33
|
+
const value = line.split('=').slice(1).join('=');
|
|
34
|
+
envVars[key] = value;
|
|
35
|
+
consoleLog(`Loading environment variable: ${colors.grey.bold(key)} ...`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
consoleLog();
|
|
39
|
+
if (isBackground) {
|
|
40
|
+
return childProcess.spawn(
|
|
41
|
+
pkg.scripts.start,
|
|
42
|
+
{
|
|
43
|
+
stdio: 'pipe',
|
|
44
|
+
shell: true,
|
|
45
|
+
env: {
|
|
46
|
+
...envVars,
|
|
47
|
+
PORT: port || envVars.PORT || '',
|
|
48
|
+
DISABLE_HOT_RELOAD: 'true'
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
} else {
|
|
53
|
+
return childProcess.spawnSync(
|
|
54
|
+
pkg.scripts.start,
|
|
55
|
+
{
|
|
56
|
+
stdio: 'inherit',
|
|
57
|
+
shell: true,
|
|
58
|
+
env: {
|
|
59
|
+
...envVars,
|
|
60
|
+
PORT: port || envVars.PORT || ''
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
} else {
|
|
66
|
+
throw new Error(`Could not find "package.json"["scripts"]["start"]`);
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
throw new Error(`No "package.json" in this directory`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const os = require('os');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const SETTINGS_FILENAME = '~/.ibotrc';
|
|
6
|
+
|
|
7
|
+
const parsePathname = (pathname) => {
|
|
8
|
+
if (!pathname) {
|
|
9
|
+
pathname = './';
|
|
10
|
+
}
|
|
11
|
+
if (
|
|
12
|
+
!pathname.startsWith('~/') &&
|
|
13
|
+
!pathname.startsWith('./') &&
|
|
14
|
+
!pathname.startsWith('/')
|
|
15
|
+
) {
|
|
16
|
+
pathname = './' + pathname;
|
|
17
|
+
}
|
|
18
|
+
if (pathname.startsWith('~/')) {
|
|
19
|
+
pathname = os.homedir().split(path.sep).join('/') + pathname.slice(1);
|
|
20
|
+
} else if (pathname.startsWith('./') || pathname.startsWith('../')) {
|
|
21
|
+
pathname = process.cwd().split(path.sep).join('/') + '/' + pathname;
|
|
22
|
+
}
|
|
23
|
+
return path.resolve(pathname);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function readSettings (validate = false) {
|
|
27
|
+
const pathname = parsePathname(SETTINGS_FILENAME);
|
|
28
|
+
if (!fs.existsSync(pathname)) {
|
|
29
|
+
fs.writeFileSync(pathname, '');
|
|
30
|
+
}
|
|
31
|
+
if (fs.statSync(pathname).isDirectory()) {
|
|
32
|
+
throw new Error(`Invalid settings file, is a directory: "${pathname}"`);
|
|
33
|
+
}
|
|
34
|
+
const file = fs.readFileSync(pathname);
|
|
35
|
+
const fileString = file.toString().replace(/\r/gi, '').trim();
|
|
36
|
+
const profileList = [];
|
|
37
|
+
if (fileString) {
|
|
38
|
+
const lines = fileString.split('\n');
|
|
39
|
+
for (const line of lines) {
|
|
40
|
+
if (line === '[profile]') {
|
|
41
|
+
profileList.push({});
|
|
42
|
+
} else if (!profileList.length) {
|
|
43
|
+
throw new Error(`Settings must start with [profile]`);
|
|
44
|
+
} else {
|
|
45
|
+
const values = line.split('=');
|
|
46
|
+
const key = values[0];
|
|
47
|
+
const value = values.slice(1).join('=');
|
|
48
|
+
profileList[profileList.length - 1][key] = value;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
let curProfile;
|
|
53
|
+
let i = 0;
|
|
54
|
+
for (const profile of profileList) {
|
|
55
|
+
if (!profile.email) {
|
|
56
|
+
throw new Error(`Profile index ${i} missing "email"`);
|
|
57
|
+
}
|
|
58
|
+
if (!profile.key) {
|
|
59
|
+
throw new Error(`Profile index ${i} missing "key"`);
|
|
60
|
+
}
|
|
61
|
+
i++;
|
|
62
|
+
}
|
|
63
|
+
if (validate && !profileList[0]) {
|
|
64
|
+
throw new Error(`You are not logged in. Try \`ibot login\` to log in first.`);
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
activeProfile: profileList[0],
|
|
68
|
+
profileList
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function writeSettings (newProfile) {
|
|
73
|
+
if (!newProfile.email) {
|
|
74
|
+
throw new Error(`Must specify newProfile "email"`);
|
|
75
|
+
} else if (!newProfile.key) {
|
|
76
|
+
throw new Error(`Must specify newProfile "key"`);
|
|
77
|
+
}
|
|
78
|
+
const settings = readSettings();
|
|
79
|
+
const activeProfile = newProfile;
|
|
80
|
+
const profileList = [].concat(
|
|
81
|
+
activeProfile,
|
|
82
|
+
settings.profileList.filter(p => p.email !== newProfile.email)
|
|
83
|
+
);
|
|
84
|
+
const pathname = parsePathname(SETTINGS_FILENAME);
|
|
85
|
+
fs.writeFileSync(
|
|
86
|
+
pathname,
|
|
87
|
+
profileList.map(p => {
|
|
88
|
+
return [
|
|
89
|
+
`[profile]`,
|
|
90
|
+
`email=${p.email}`,
|
|
91
|
+
`key=${p.key}`,
|
|
92
|
+
p.host ? `host=${p.host}` : ''
|
|
93
|
+
].filter(line => !!line.trim()).join('\n');
|
|
94
|
+
}).join('\n') + '\n'
|
|
95
|
+
);
|
|
96
|
+
console.log(`Settings: Set profile(email=${activeProfile.email}) as active in "${pathname}"`);
|
|
97
|
+
console.log(`Settings: Total of ${profileList.length} saved profiles`);
|
|
98
|
+
console.log();
|
|
99
|
+
return {
|
|
100
|
+
activeProfile,
|
|
101
|
+
profileList
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
module.exports = {
|
|
106
|
+
read: readSettings,
|
|
107
|
+
write: writeSettings
|
|
108
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const colors = require('colors/safe');
|
|
2
|
+
const semver = require('semver');
|
|
3
|
+
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const https = require('https');
|
|
6
|
+
|
|
7
|
+
const drawBox = require('./draw_box.js');
|
|
8
|
+
|
|
9
|
+
module.exports = async (print = false) => {
|
|
10
|
+
|
|
11
|
+
const pkgs = {self: require('../package.json')};
|
|
12
|
+
try {
|
|
13
|
+
pkgs.api = require(path.join(process.cwd(), '/node_modules/@instant.dev/api/package.json'));
|
|
14
|
+
} catch (e) {
|
|
15
|
+
// do nothing:
|
|
16
|
+
// @instant.dev/api not installed locally
|
|
17
|
+
}
|
|
18
|
+
const packages = [
|
|
19
|
+
{
|
|
20
|
+
title: 'Superuser Package CLI',
|
|
21
|
+
name: pkgs.self.name,
|
|
22
|
+
version: pkgs.self.version,
|
|
23
|
+
global: true
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
title: 'Superuser Package Gateway (Instant API)',
|
|
27
|
+
name: pkgs.api ? pkgs.api.name : null,
|
|
28
|
+
version: pkgs.api ? pkgs.api.version : null,
|
|
29
|
+
dev: true
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
const checkPackages = packages.filter(pkg => !!pkg.name);
|
|
33
|
+
const verifiedPackages = await Promise.all(
|
|
34
|
+
checkPackages.map(pkg => {
|
|
35
|
+
return (async () => {
|
|
36
|
+
try {
|
|
37
|
+
const response = await new Promise((resolve, reject) => {
|
|
38
|
+
const req = https.request(`https://registry.npmjs.org/${pkg.name}/latest`, res => {
|
|
39
|
+
const buffers = [];
|
|
40
|
+
res.on('data', data => buffers.push(data));
|
|
41
|
+
res.on('end', () => resolve(Buffer.concat(buffers)));
|
|
42
|
+
})
|
|
43
|
+
req.on('error', err => reject(err));
|
|
44
|
+
req.end();
|
|
45
|
+
});
|
|
46
|
+
const json = JSON.parse(response.toString());
|
|
47
|
+
pkg.latest = json.version;
|
|
48
|
+
return pkg;
|
|
49
|
+
} catch (e) {
|
|
50
|
+
// we want to be able to use CLI offline
|
|
51
|
+
// or if NPM is down / returning bad data
|
|
52
|
+
// so just set latest equal to version
|
|
53
|
+
pkg.latest = pkg.version;
|
|
54
|
+
return pkg;
|
|
55
|
+
}
|
|
56
|
+
})();
|
|
57
|
+
})
|
|
58
|
+
);
|
|
59
|
+
const updatePackages = verifiedPackages.filter(pkg => pkg.latest && semver.gt(pkg.latest, pkg.version));
|
|
60
|
+
if (updatePackages.length && print) {
|
|
61
|
+
console.log();
|
|
62
|
+
console.log(
|
|
63
|
+
drawBox.center(
|
|
64
|
+
`yellow`,
|
|
65
|
+
``,
|
|
66
|
+
`Updates are available for ${colors.bold('ibot')}:`,
|
|
67
|
+
``,
|
|
68
|
+
...updatePackages.map(pkg => {
|
|
69
|
+
return [
|
|
70
|
+
pkg.title,
|
|
71
|
+
`${pkg.version} -> ${colors.bold.green(pkg.latest)}`,
|
|
72
|
+
`${colors.bold.grey(`npm i ${pkg.name}@latest${pkg.dev ? ' --save-dev' : ''}${pkg.global ? ' -g' : ''}`)}`,
|
|
73
|
+
``
|
|
74
|
+
].join('\n')
|
|
75
|
+
}),
|
|
76
|
+
`Install all with:`,
|
|
77
|
+
`${colors.bold.grey(`ibot update`)}`,
|
|
78
|
+
``
|
|
79
|
+
)
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return verifiedPackages;
|
|
84
|
+
|
|
85
|
+
};
|
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "superuser.app",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "Superuser package manager: command line interface for building toolkits for your agents",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"/commands",
|
|
8
|
+
"/helpers",
|
|
9
|
+
"/src"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"sup": "index.js"
|
|
16
|
+
},
|
|
17
|
+
"author": "Keith Horwood",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"cmnd": "^0.4.1",
|
|
21
|
+
"colors": "^1.4.0",
|
|
22
|
+
"i": "^0.3.7",
|
|
23
|
+
"inquirer": "^8.2.6",
|
|
24
|
+
"io": "^1.5.0",
|
|
25
|
+
"minimatch": "^9.0.4",
|
|
26
|
+
"semver": "^7.5.4",
|
|
27
|
+
"tar-stream": "^3.1.7",
|
|
28
|
+
"tree-kill": "^1.2.2"
|
|
29
|
+
},
|
|
30
|
+
"keywords": []
|
|
31
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET
|
|
3
|
+
*/
|
|
4
|
+
export async function GET (context) {
|
|
5
|
+
|
|
6
|
+
return `HTTP GET!`;
|
|
7
|
+
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* POST
|
|
12
|
+
*/
|
|
13
|
+
export async function POST (context) {
|
|
14
|
+
|
|
15
|
+
return `HTTP POST!`;
|
|
16
|
+
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* PUT
|
|
21
|
+
*/
|
|
22
|
+
export async function PUT (context) {
|
|
23
|
+
|
|
24
|
+
return `HTTP PUT!`;
|
|
25
|
+
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* DELETE
|
|
30
|
+
*/
|
|
31
|
+
export async function DELETE (context) {
|
|
32
|
+
|
|
33
|
+
return `HTTP DELETE!`;
|
|
34
|
+
|
|
35
|
+
};
|
package/src/init/__.env
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
MY_SECRET=development_secret
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
MY_SECRET=production_secret
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
MY_SECRET=staging_secret
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sample welcome API
|
|
3
|
+
* We can provide types to our APIs to enforce type-safety
|
|
4
|
+
* at the HTTP request (@param) and response (@returns) layer
|
|
5
|
+
* @param {string} username
|
|
6
|
+
* @returns {object} welcomeMessage
|
|
7
|
+
* @returns {string} welcomeMessage.message
|
|
8
|
+
*/
|
|
9
|
+
export async function GET (username = 'new user') {
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
message: `Welcome to Superuser, ${username}!`
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@/not_npm_project",
|
|
3
|
+
"private": false,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"start": "node serve.instant.js",
|
|
7
|
+
"test": "mocha test/run.js"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@instant.dev/api": "latest",
|
|
12
|
+
"dotenv": "latest",
|
|
13
|
+
"mocha": "latest",
|
|
14
|
+
"chai": "latest"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is ** NOT ** used in production on the Superuser Package Registry
|
|
3
|
+
* Any code you change here ** WILL NOT ** run when hosted with Superuser Package
|
|
4
|
+
*
|
|
5
|
+
* However, it used for local development and allows you to ship your Superuser Package
|
|
6
|
+
* service to any host which relies on `package.json["scripts"]["start"]`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Third-party imports
|
|
10
|
+
import InstantAPI from '@instant.dev/api';
|
|
11
|
+
import dotenv from 'dotenv';
|
|
12
|
+
|
|
13
|
+
// Native imports
|
|
14
|
+
import cluster from 'cluster';
|
|
15
|
+
import os from 'os';
|
|
16
|
+
|
|
17
|
+
// Shorthand references
|
|
18
|
+
const Daemon = InstantAPI.Daemon;
|
|
19
|
+
const Gateway = InstantAPI.Daemon.Gateway;
|
|
20
|
+
const EncryptionTools = InstantAPI.EncryptionTools;
|
|
21
|
+
|
|
22
|
+
// Constants
|
|
23
|
+
const ENVIRONMENT = process.env.NODE_ENV || 'development';
|
|
24
|
+
const PORT = process.env.PORT || 8100;
|
|
25
|
+
|
|
26
|
+
if (cluster.isPrimary) {
|
|
27
|
+
|
|
28
|
+
// Multi-process daemon
|
|
29
|
+
const daemon = new Daemon(
|
|
30
|
+
ENVIRONMENT !== 'development'
|
|
31
|
+
? os.cpus().length
|
|
32
|
+
: 1,
|
|
33
|
+
'SuperuserDaemon'
|
|
34
|
+
);
|
|
35
|
+
daemon.start(PORT);
|
|
36
|
+
|
|
37
|
+
} else {
|
|
38
|
+
|
|
39
|
+
// Individual webserver startup
|
|
40
|
+
const gateway = new Gateway({
|
|
41
|
+
name: 'SuperuserDaemon.Gateway',
|
|
42
|
+
debug: ENVIRONMENT !== 'production'
|
|
43
|
+
});
|
|
44
|
+
// Optional: Enable Sentry or another error reporting tool
|
|
45
|
+
// gateway.setErrorHandler(err => Sentry.captureException(err));
|
|
46
|
+
const et = new EncryptionTools();
|
|
47
|
+
dotenv.config(); // load env vars
|
|
48
|
+
et.decryptProcessEnv(process.env); // decrypt env vars, if necessary
|
|
49
|
+
gateway.load(process.cwd()); // load routes from filesystem
|
|
50
|
+
gateway.listen(PORT); // start server
|
|
51
|
+
|
|
52
|
+
}
|