Skip to content
This repository was archived by the owner on Feb 25, 2024. It is now read-only.

Commit 8a80f51

Browse files
authored
v2.0.0
1 parent 383359b commit 8a80f51

13 files changed

Lines changed: 3176 additions & 0 deletions

File tree

package-lock.json

Lines changed: 2698 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"name": "@is-a-dev/cli",
3+
"version": "2.0.0",
4+
"description": "Register your own is-a.dev subdomain from your command line!",
5+
"main": "src/index.js",
6+
"bin": {
7+
"is-a-dev": "src/index.js"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/wdhdev/is-a-dev-cli.git"
12+
},
13+
"keywords": [],
14+
"author": "William Harrison <william@williamharrison.dev>",
15+
"license": "MIT",
16+
"bugs": {
17+
"url": "https://github.com/wdhdev/is-a-dev-cli/issues"
18+
},
19+
"homepage": "https://www.npmjs.com/package/@is-a-dev/cli",
20+
"dependencies": {
21+
"@octokit/auth-oauth-device": "^4.0.4",
22+
"@octokit/core": "^4.2.0",
23+
"axios": "^1.3.4",
24+
"cli-handle-unhandled": "^1.1.1",
25+
"cli-meow-help": "^3.1.0",
26+
"cli-welcome": "^2.2.2",
27+
"conf": "^10.2.0",
28+
"js-base64": "^3.7.2",
29+
"meow": "^9.0.0",
30+
"node-fetch": "^2.6.7",
31+
"prompts": "^2.4.2"
32+
}
33+
}

src/functions/account.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const Conf = require("conf");
2+
3+
const userAccount = new Conf();
4+
5+
module.exports = function account() {
6+
const username = userAccount.get("username");
7+
const email = userAccount.get("email");
8+
const token = userAccount.get("token");
9+
10+
if(!username) {
11+
console.log("You are not logged in!");
12+
console.log("To log in, run the command: `is-a-dev login`");
13+
return;
14+
}
15+
16+
console.log(`Username: ${username}\nEmail: ${email}\nToken: ${token}`);
17+
}

src/functions/check.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const axios = require("axios");
2+
const prompts = require("prompts");
3+
4+
const questions = require("../util/questions").check;
5+
6+
module.exports = async function check() {
7+
const response = await prompts(questions);
8+
9+
const subdomain = response.subdomain.toLowerCase();
10+
11+
let res;
12+
13+
try {
14+
const request = await axios.get(`https://api.is-a.dev/check?domain=${subdomain}`);
15+
16+
res = request;
17+
} catch(err) {
18+
res = err.response;
19+
}
20+
21+
if(res.status === 500) return console.log("An error occurred, please try again later.");
22+
23+
const message = res.data.message;
24+
25+
if(message === "DOMAIN_UNAVAILABLE") return console.log("\nSorry, that subdomain is taken!");
26+
27+
if(message === "DOMAIN_AVAILABLE") {
28+
console.log("\nCongratulations, that subdomain is available!");
29+
console.log("To register, run the command: `is-a-dev register`");
30+
}
31+
}

src/functions/domains.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const axios = require("axios");
2+
const Conf = require("conf");
3+
4+
const account = new Conf();
5+
6+
module.exports = async function domains() {
7+
if(!account.has("username")) {
8+
console.log("You are not logged in!");
9+
console.log("To log in, run the command: `is-a-dev login`");
10+
return;
11+
}
12+
13+
console.log(`Username: ${account.get("username")}`);
14+
console.log(`Email: ${account.get("email")}\n`);
15+
16+
const email = account.get("email");
17+
18+
let res;
19+
20+
try {
21+
const request = await axios.get(`https://api.is-a.dev/lookup/user?email=${email}`);
22+
23+
res = request;
24+
} catch(err) {
25+
res = err.response;
26+
}
27+
28+
if(res.status === 500) return console.log("An error occurred, please try again later.");
29+
if(res.status === 404) return console.log("You do not own any domains.");
30+
31+
const domains = res.data.subdomains;
32+
33+
return console.log(`${domains.join(".is-a.dev\n")}.is-a.dev`);
34+
}

src/functions/login.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
const Conf = require("conf");
2+
const { createOAuthDeviceAuth } = require("@octokit/auth-oauth-device");
3+
const { Octokit } = require("@octokit/core");
4+
const prompts = require("prompts");
5+
6+
const account = new Conf();
7+
8+
module.exports = async function login() {
9+
if(account.has("username")) {
10+
console.log(`You are already logged in as ${account.get("username")}!`);
11+
console.log("To log out, run the command: `is-a-dev logout`");
12+
return;
13+
}
14+
15+
const auth = createOAuthDeviceAuth({
16+
clientType: "oauth-app",
17+
clientId: "77432389afa6fe09b63e",
18+
scopes: ["public_repo, user:email"],
19+
onVerification(verification) {
20+
console.log("Open the URL: %s", verification.verification_uri);
21+
console.log("Enter code: %s", verification.user_code);
22+
}
23+
})
24+
25+
const tokenAuthentication = await auth({ type: "oauth" });
26+
27+
account.set("token", tokenAuthentication.token);
28+
29+
const octokit = new Octokit({ auth: tokenAuthentication.token });
30+
31+
const res1 = await octokit.request("GET /user", {});
32+
account.set("username", res1.data.login);
33+
34+
const res2 = await octokit.request("GET /user/emails", {});
35+
36+
const emails = [];
37+
38+
res2.data.forEach(res => {
39+
if(res.email.endsWith("@users.noreply.github.com") || !res.verified) return;
40+
41+
emails.push(res.email);
42+
})
43+
44+
if(emails.length === 1) {
45+
account.set("email", emails[0]);
46+
} else {
47+
const question = {
48+
type: "select",
49+
name: "email",
50+
message: "Which email do you want to use?",
51+
choices: []
52+
}
53+
54+
for (const email of emails) {
55+
question.choices.push({ value: email });
56+
}
57+
58+
console.log(" ");
59+
60+
const response = await prompts(question);
61+
62+
account.set("email", response.email);
63+
}
64+
65+
console.log(`\nLogged in as: ${account.get("username")} <${account.get("email")}>`);
66+
}

src/functions/logout.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const Conf = require("conf");
2+
const account = new Conf();
3+
4+
module.exports = function logout() {
5+
if(!account.has("username")) {
6+
console.log("You are not logged in!");
7+
console.log("To log in, run the command: `is-a-dev login`")
8+
return;
9+
}
10+
11+
account.delete("email");
12+
account.delete("token");
13+
account.delete("username");
14+
15+
console.log("You have been logged out.");
16+
}

src/functions/register.js

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
const { Base64 } = require("js-base64");
2+
const Conf = require("conf");
3+
const fetch = require("node-fetch");
4+
const { Octokit } = require("@octokit/core");
5+
const prompts = require("prompts");
6+
7+
const account = new Conf();
8+
const questions = require("../util/questions").register;
9+
10+
function delay(time) {
11+
return new Promise((resolve) => setTimeout(resolve, time));
12+
}
13+
14+
module.exports = async function register() {
15+
if(!account.has("username")) {
16+
console.log("You are not logged in!");
17+
console.log("To log in, run the command: `is-a-dev login`");
18+
return;
19+
}
20+
21+
console.log(`Username: ${account.get("username")}`);
22+
console.log(`Email: ${account.get("email")}\n`);
23+
24+
const octokit = new Octokit({ auth: account.get("token") });
25+
26+
const response = await prompts(questions);
27+
28+
let forkName;
29+
30+
await octokit.request("POST /repos/{owner}/{repo}/forks", {
31+
owner: "is-a-dev",
32+
repo: "register",
33+
default_branch_only: true
34+
}).then(res => forkName = res.data.name)
35+
36+
const username = account.get("username");
37+
const email = account.get("email");
38+
39+
const subdomain = response.subdomain.toLowerCase();
40+
const recordType = response.record;
41+
let recordValue = response.record_value.toLowerCase();
42+
43+
if(recordType === "A" || recordType === "AAAA" || recordType === "MX") {
44+
recordValue = JSON.stringify(recordValue.split(",").map((s) => s.trim()));
45+
} else {
46+
recordValue = `"${recordValue.trim()}"`;
47+
}
48+
49+
let fullContent = `{
50+
"owner": {
51+
"username": "${username}",
52+
"email": "${email}"
53+
},
54+
55+
"records": {
56+
"${recordType}": ${recordValue}
57+
}
58+
}
59+
`;
60+
61+
const contentEncoded = Base64.encode(fullContent);
62+
63+
fetch(
64+
`https://api.github.com/repos/is-a-dev/register/contents/domains/${subdomain}.json`,
65+
{
66+
method: "GET",
67+
headers: {
68+
"User-Agent": username,
69+
},
70+
}
71+
).then(async (res) => {
72+
if(res.status && res.status == 404) {
73+
octokit
74+
.request("PUT /repos/{owner}/{repo}/contents/{path}", {
75+
owner: username,
76+
repo: forkName,
77+
path: "domains/" + subdomain + ".json",
78+
message: `feat(domain): add \`${subdomain}.is-a.dev\``,
79+
content: contentEncoded
80+
})
81+
.catch((err) => { throw new Error(err); });
82+
} else throw new Error("That subdomain is taken!");
83+
})
84+
85+
await delay(2000);
86+
87+
const pr = await octokit.request("POST /repos/{owner}/{repo}/pulls", {
88+
owner: "is-a-dev",
89+
repo: "register",
90+
title: `Register ${subdomain}.is-a.dev`,
91+
body: `Added \`${subdomain}.is-a.dev\` using the [CLI](https://www.npmjs.com/package/@is-a-dev/cli).`,
92+
head: username + ":main",
93+
base: "main"
94+
})
95+
96+
console.log(`\nYour pull request has been submitted.\nYou can check the status of your pull request here: ${pr.data.html_url}`);
97+
}

src/index.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env node
2+
3+
const functions = require("./util/functions");
4+
5+
const cli = require("./util/cli");
6+
const init = require("./util/init");
7+
8+
const input = cli.input;
9+
const flags = cli.flags;
10+
const { clear, debug } = flags;
11+
12+
(async () => {
13+
init({ clear });
14+
15+
input.includes("account") && functions.account();
16+
input.includes("check") && functions.check();
17+
input.includes("domains") && functions.domains();
18+
input.includes("help") && cli.showHelp(0);
19+
input.includes("login") && functions.login();
20+
input.includes("logout") && functions.logout();
21+
input.includes("register") && functions.register();
22+
23+
debug && console.log(flags);
24+
})();

src/util/cli.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
const meow = require("meow");
2+
const meowHelp = require("cli-meow-help");
3+
4+
const flags = {
5+
clear: {
6+
type: "boolean",
7+
default: true,
8+
alias: "c",
9+
desc: "Clear the console"
10+
},
11+
debug: {
12+
type: "boolean",
13+
default: false,
14+
alias: "d",
15+
desc: "Print debug info"
16+
},
17+
noClear: {
18+
type: "boolean",
19+
default: false,
20+
alias: "nc",
21+
desc: "Don't clear the console"
22+
},
23+
version: {
24+
type: "boolean",
25+
alias: "v",
26+
desc: "Print CLI version"
27+
}
28+
};
29+
30+
const commands = {
31+
account: { desc: "Get information about your account." },
32+
check: { desc: "Check if a subdomain is available." },
33+
domains: { desc: "See a list of all of your subdomains." },
34+
login: { desc: "Login to your GitHub account." },
35+
logout: { desc: "Logout of your GitHub account." },
36+
register: { desc: "Register a subdomain." }
37+
}
38+
39+
const helpText = meowHelp({
40+
name: "is-a-dev",
41+
flags,
42+
commands
43+
})
44+
45+
const options = {
46+
inferType: true,
47+
description: false,
48+
hardRejection: false,
49+
flags
50+
}
51+
52+
module.exports = meow(helpText, options);

0 commit comments

Comments
 (0)