charis-cli 1.0.0 → 1.0.2

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.
Files changed (4) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +44 -0
  3. package/login.js +154 -14
  4. package/package.json +19 -7
package/LICENSE ADDED
@@ -0,0 +1,7 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026 Charis Production
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # charis-cli
2
+
3
+ šŸŽµ Command-line tool to manage your Spotify account via the Charis Web Services.
4
+
5
+ ---
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install -g charis-cli
11
+ ```
12
+
13
+ ---
14
+
15
+ ## Usage
16
+
17
+ ```bash
18
+ # Login to Spotify
19
+ charis login
20
+
21
+ # Logout and delete your Spotify tokens
22
+ charis logout
23
+
24
+ # Uninstall the CLI
25
+ charis remove
26
+ ```
27
+
28
+ ### Notes
29
+
30
+ * After logging out, you **cannot use Charis Spotify services** with that account anymore.
31
+ * Make sure you have your **Spotify User ID, Client ID, and Client Secret** ready before logging in.
32
+
33
+ ---
34
+
35
+ ## Requirements
36
+
37
+ * Node.js v18+
38
+ * NPM
39
+
40
+ ---
41
+
42
+ ## License
43
+
44
+ ISC Ā© Charis Production
package/login.js CHANGED
@@ -1,19 +1,51 @@
1
1
  #!/usr/bin/env node
2
+ import fetch from "node-fetch";
2
3
  import open from "open";
3
- import readline from "readline";
4
+ import promptSync from "prompt-sync";
5
+ import { exec } from "child_process";
6
+ import chalk from "chalk";
4
7
 
5
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
6
- const question = (q) => new Promise(resolve => rl.question(q, resolve));
8
+ const prompt = promptSync({ sigint: true });
7
9
 
8
- (async () => {
9
- const userId = await question("Enter your Spotify userId: ");
10
- const clientId = await question("Enter your Spotify clientId: ");
11
- const clientSecret = await question("Enter your Spotify clientSecret: ");
12
- rl.close();
10
+ // ===== Banner =====
11
+ function printBanner() {
12
+ console.log(chalk.cyanBright(`
13
+ ╔══════════════════════════════════════════╗
14
+ ā•‘ ā•‘
15
+ ā•‘ šŸŽµ CHARIS SPOTIFY CLI šŸŽµ ā•‘
16
+ ā•‘ ā•‘
17
+ ā•‘ Manage your Spotify account ā•‘
18
+ ā•‘ directly from the CLI ā•‘
19
+ ā•‘ ā•‘
20
+ ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•
21
+ `));
22
+ console.log(chalk.yellowBright("šŸš€ Welcome! Let's get you logged in.\n"));
23
+ }
13
24
 
14
- // Redirect ke API Vercel
15
- const redirectUri = "https://api.charisprod.xyz/v1/spotify/callback";
25
+ // ===== Input wajib =====
26
+ async function askNonEmpty(promptText, hidden = false) {
27
+ let answer = "";
28
+ do {
29
+ if (hidden) {
30
+ answer = prompt.hide ? prompt.hide(promptText) : prompt(promptText);
31
+ } else {
32
+ answer = prompt(promptText);
33
+ }
34
+ answer = answer.trim();
35
+ if (!answer) console.log(chalk.red("āŒ Input cannot be empty. Please try again."));
36
+ } while (!answer);
37
+ return answer;
38
+ }
39
+
40
+ // ===== Login flow =====
41
+ async function loginFlow() {
42
+ printBanner();
43
+
44
+ const userId = await askNonEmpty("Enter your Spotify User ID: ");
45
+ const clientId = await askNonEmpty("Enter your Spotify Client ID: ");
46
+ const clientSecret = await askNonEmpty("Enter your Spotify Client Secret: ", true);
16
47
 
48
+ const redirectUri = "https://api.charisprod.xyz/v1/spotify/callback";
17
49
  const state = Buffer.from(JSON.stringify({ userId, clientId, clientSecret })).toString("base64url");
18
50
 
19
51
  const scope = [
@@ -31,7 +63,115 @@ const question = (q) => new Promise(resolve => rl.question(q, resolve));
31
63
  authUrl.searchParams.set("state", state);
32
64
  authUrl.searchParams.set("show_dialog", "true");
33
65
 
34
- console.log("Opening Spotify login in your browser...");
35
- await open(authUrl.toString());
36
- console.log("After login, your tokens will be stored on the server. You can continue using the CLI after that.");
37
- })();
66
+ const urlString = authUrl.toString();
67
+
68
+ console.log("\nšŸ”— Open this URL in your browser if it doesn't open automatically:\n");
69
+ console.log(chalk.green(urlString) + "\n");
70
+
71
+ try {
72
+ await open(urlString);
73
+ } catch {
74
+ console.log(chalk.red("āš ļø Could not open browser automatically. Please copy the link above and open manually."));
75
+ }
76
+
77
+ // Prompt uninstall CLI
78
+ const removeChoice = prompt("\nDo you want to remove charis-cli from your system now? [y/N]: ").trim().toLowerCase();
79
+ if (removeChoice === "y" || removeChoice === "yes") {
80
+ console.log("āš ļø Uninstalling charis-cli globally...");
81
+ exec("npm uninstall -g charis-cli", (error, stdout, stderr) => {
82
+ if (error) {
83
+ console.error(`āŒ Failed to uninstall: ${error.message}`);
84
+ return;
85
+ }
86
+ if (stderr) console.error(stderr);
87
+ console.log("āœ… charis-cli has been uninstalled.");
88
+ });
89
+ } else {
90
+ console.log("ā„¹ļø CLI remains installed. You can run 'charis login' anytime.");
91
+ }
92
+ }
93
+
94
+ // ===== Logout flow =====
95
+ async function logoutFlow() {
96
+ console.log(chalk.cyanBright("\n=== Logout from Spotify (Charis CLI) ===\n"));
97
+
98
+ const userId = prompt("Enter your Spotify User ID to logout: ").trim();
99
+ if (!userId) {
100
+ console.log(chalk.red("āŒ User ID cannot be empty."));
101
+ return;
102
+ }
103
+
104
+ console.log(`\nāš ļø WARNING: Logging out will delete your Spotify tokens for userId "${userId}"`);
105
+ console.log(" You will NO LONGER be able to use our Spotify service.\n");
106
+
107
+ const confirm = prompt("Are you sure you want to proceed? [y/N]: ").trim().toLowerCase();
108
+ if (confirm !== "y" && confirm !== "yes") {
109
+ console.log(chalk.yellow("āš ļø Logout canceled."));
110
+ return;
111
+ }
112
+
113
+ console.log("ā³ Logging out and deleting your tokens...");
114
+
115
+ try {
116
+ const res = await fetch(
117
+ `https://api.charisprod.xyz/v1/spotify/delete?userId=${userId}`,
118
+ { method: "DELETE", headers: { "Content-Type": "application/json" } }
119
+ );
120
+
121
+ // Ambil response dari API apa adanya
122
+ const data = await res.json();
123
+
124
+ // Selalu tampilkan message dari API
125
+ if (data.message) {
126
+ if (res.ok) {
127
+ console.log(chalk.green(`āœ… ${data.message}`));
128
+ } else {
129
+ console.log(chalk.yellow(`āš ļø ${data.message}`));
130
+ }
131
+ } else if (data.error) {
132
+ console.log(chalk.red(`āŒ ${data.error}`));
133
+ } else {
134
+ console.log(chalk.red("āŒ Unknown response from API"));
135
+ }
136
+ } catch (err) {
137
+ console.log(chalk.red(`āŒ Logout failed: ${err.message}`));
138
+ }
139
+ }
140
+
141
+ // ===== Remove CLI =====
142
+ async function removeFlow() {
143
+ console.log("āš ļø Uninstalling charis-cli globally...");
144
+ exec("npm uninstall -g charis-cli", (error, stdout, stderr) => {
145
+ if (error) {
146
+ console.error(`āŒ Failed to uninstall: ${error.message}`);
147
+ return;
148
+ }
149
+ if (stderr) console.error(stderr);
150
+ console.log("āœ… charis-cli has been uninstalled.");
151
+ });
152
+ }
153
+
154
+ // ===== Main dispatcher =====
155
+ const subcommand = process.argv[2]?.toLowerCase();
156
+
157
+ switch (subcommand) {
158
+ case "login":
159
+ await loginFlow();
160
+ break;
161
+ case "logout":
162
+ await logoutFlow();
163
+ break;
164
+ case "remove":
165
+ await removeFlow();
166
+ break;
167
+ case undefined:
168
+ console.log(chalk.cyan("\nUsage: charis <command>"));
169
+ console.log(chalk.cyan("Commands:"));
170
+ console.log(chalk.green(" login Login to Spotify"));
171
+ console.log(chalk.green(" logout Logout from Spotify"));
172
+ console.log(chalk.green(" remove Uninstall charis-cli\n"));
173
+ break;
174
+ default:
175
+ console.log(chalk.red(`āŒ Unknown command: ${subcommand}`));
176
+ console.log("Use 'charis' to see available commands.");
177
+ }
package/package.json CHANGED
@@ -1,19 +1,31 @@
1
1
  {
2
2
  "name": "charis-cli",
3
- "version": "1.0.0",
4
- "main": "index.js",
3
+ "version": "1.0.2",
4
+ "main": "login.js",
5
5
  "type": "module",
6
6
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "start": "node login.js",
9
+ "login": "node login.js login",
10
+ "logout": "node login.js logout"
8
11
  },
9
12
  "bin": {
10
13
  "charis": "./login.js"
11
14
  },
12
- "keywords": [],
13
- "author": "",
15
+ "keywords": [
16
+ "spotify",
17
+ "cli",
18
+ "charis",
19
+ "music",
20
+ "api"
21
+ ],
22
+ "author": "Charis Production",
14
23
  "license": "ISC",
15
- "description": "",
24
+ "description": "CLI for managing Spotify accounts via Charis Web Services",
16
25
  "dependencies": {
17
- "open": "^11.0.0"
26
+ "chalk": "^5.6.2",
27
+ "open": "^11.0.0",
28
+ "prompt-sync": "^4.2.0",
29
+ "node-fetch": "^2.7.0"
18
30
  }
19
31
  }