codechronicle-cli 1.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/commands/add.js +376 -0
- package/commands/clone.js +75 -0
- package/commands/commit.js +178 -0
- package/commands/init.js +106 -0
- package/commands/login.js +56 -0
- package/commands/logout.js +12 -0
- package/commands/pull.js +94 -0
- package/commands/push.js +70 -0
- package/commands/revert.js +121 -0
- package/commands/whoami.js +11 -0
- package/config/config.js +3 -0
- package/config/supabase.js +24 -0
- package/index.js +112 -0
- package/package.json +26 -0
- package/services/api.js +11 -0
- package/services/authService.js +18 -0
- package/services/repositoryApi.js +86 -0
- package/utils/auth.js +23 -0
- package/utils/chronConfig.js +30 -0
- package/utils/unzipDirectory.js +17 -0
- package/utils/zipDirectory.js +32 -0
package/commands/init.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
const fs = require("fs").promises; //file system: we can use asynchronous Promise-based operations like await fs.mkdir(...), await fs.writeFile(...)
|
|
2
|
+
const path = require("path"); //helps safely construct filesystem paths
|
|
3
|
+
const { getToken } = require("../utils/auth");
|
|
4
|
+
const repositoryApi = require("../services/repositoryApi");
|
|
5
|
+
const { requireAuth } = require("../utils/auth");
|
|
6
|
+
|
|
7
|
+
async function initRepo(repoName) {
|
|
8
|
+
requireAuth();
|
|
9
|
+
// process.cwd() returns the directory from which the CLI command was executed.
|
|
10
|
+
const repoPath = path.resolve(process.cwd(), ".chron");
|
|
11
|
+
|
|
12
|
+
const commitsPath = path.join(repoPath, "commits");
|
|
13
|
+
const stagingPath = path.join(repoPath, "staging");
|
|
14
|
+
const configPath = path.join(repoPath, "config.json");
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
// fs.access() checks whether .chron already exists to prevent reinitialization.
|
|
18
|
+
try {
|
|
19
|
+
await fs.access(repoPath);
|
|
20
|
+
console.log("Repository is already initialized.");
|
|
21
|
+
return;
|
|
22
|
+
} catch {
|
|
23
|
+
// Repository doesn't exist yet, so initialization can continue.
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const token = getToken();
|
|
27
|
+
|
|
28
|
+
const response = await repositoryApi.createRepository(token, {
|
|
29
|
+
name: repoName,
|
|
30
|
+
description: "",
|
|
31
|
+
visibility: "public",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const repository = response.data;
|
|
35
|
+
|
|
36
|
+
// recursive:true also creates the parent .vcsGit directory automatically.
|
|
37
|
+
await fs.mkdir(commitsPath, { recursive: true });
|
|
38
|
+
await fs.mkdir(stagingPath, { recursive: true });
|
|
39
|
+
|
|
40
|
+
// information of the repository
|
|
41
|
+
const config = {
|
|
42
|
+
repositoryId: repository.repositoryId,
|
|
43
|
+
repositoryName: repository.repositoryName,
|
|
44
|
+
defaultBranch: "main",
|
|
45
|
+
lastPushedCommit: null,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// JSON.stringify(..., null, 2) converts the object to readable, indented JSON.
|
|
49
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
50
|
+
|
|
51
|
+
console.log(`Repository '${repoName}' initialized successfully.`);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
console.error("Error initializing repository:", err.message);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = { initRepo };
|
|
58
|
+
|
|
59
|
+
/*
|
|
60
|
+
============================================================
|
|
61
|
+
WORKING OF INIT COMMAND
|
|
62
|
+
============================================================
|
|
63
|
+
|
|
64
|
+
The initRepo() function initializes a local Code Chronicle repository.
|
|
65
|
+
|
|
66
|
+
When the user runs:
|
|
67
|
+
node index.js init <repoName>
|
|
68
|
+
|
|
69
|
+
1. index.js uses Yargs to detect the "init" command and passes the
|
|
70
|
+
repository name to initRepo(repoName).
|
|
71
|
+
|
|
72
|
+
2. process.cwd() identifies the directory where the user executed
|
|
73
|
+
the command. This directory is treated as the project root.
|
|
74
|
+
|
|
75
|
+
3. A hidden ".vcsGit" directory is used to store all metadata related
|
|
76
|
+
to our custom version-control system.
|
|
77
|
+
|
|
78
|
+
4. Before initialization, fs.access() checks whether ".vcsGit" already
|
|
79
|
+
exists. If it exists, initialization stops to avoid accidentally
|
|
80
|
+
overwriting an existing repository.
|
|
81
|
+
|
|
82
|
+
5. Two directories are created inside ".vcsGit":
|
|
83
|
+
|
|
84
|
+
.vcsGit/
|
|
85
|
+
├── commits/ -> Stores locally created commits.
|
|
86
|
+
└── staging/ -> Stores files added before they are committed.
|
|
87
|
+
|
|
88
|
+
6. A config.json file is created to store repository configuration:
|
|
89
|
+
|
|
90
|
+
{
|
|
91
|
+
"storage": "supabase",
|
|
92
|
+
"bucket": "codechronicle",
|
|
93
|
+
"repoName": "<repository-name>"
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
7. At this stage, everything exists only on the local system.
|
|
97
|
+
No files or repository data are uploaded to Supabase.
|
|
98
|
+
|
|
99
|
+
8. Supabase will act as the remote storage and will be used later
|
|
100
|
+
when commands such as "push" and "pull" are executed.
|
|
101
|
+
|
|
102
|
+
This is conceptually similar to "git init", where Git creates a
|
|
103
|
+
.git directory to maintain repository metadata. In Code Chronicle,
|
|
104
|
+
.vcsGit serves a similar purpose for our custom version-control system.
|
|
105
|
+
============================================================
|
|
106
|
+
*/
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const inquirer = require("inquirer").default;
|
|
2
|
+
const { login: loginUser } = require("../services/authService");
|
|
3
|
+
const { saveConfig, getConfig } = require("../utils/chronConfig");
|
|
4
|
+
const { getToken } = require("../utils/auth");
|
|
5
|
+
|
|
6
|
+
async function login() {
|
|
7
|
+
const config = getConfig();
|
|
8
|
+
if (config) {
|
|
9
|
+
console.log(`✔ You are already logged in as ${config.user.username}.`);
|
|
10
|
+
console.log("Run 'chron logout' to login with another account.");
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const answers = await inquirer.prompt([
|
|
15
|
+
{
|
|
16
|
+
type: "input",
|
|
17
|
+
name: "email",
|
|
18
|
+
message: "Enter your email:",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
type: "password",
|
|
22
|
+
name: "password",
|
|
23
|
+
message: "Enter your password:",
|
|
24
|
+
mask: "*",
|
|
25
|
+
},
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
console.log("\nLogging in...\n");
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const response = await loginUser(answers.email, answers.password);
|
|
32
|
+
|
|
33
|
+
saveConfig({
|
|
34
|
+
token: response.data.token,
|
|
35
|
+
user: response.data.user,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
console.log(`✔ ${response.message}`);
|
|
39
|
+
console.log(`Welcome back, ${response.data.user.username}!`);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
// Server is not reachable
|
|
42
|
+
if (error.code === "ECONNREFUSED") {
|
|
43
|
+
console.log("Backend server is not running.");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// // No response received (network issue / timeout)
|
|
48
|
+
// if (!error.response) {
|
|
49
|
+
// console.log("Unable to connect. Please check your internet connection.");
|
|
50
|
+
// return;
|
|
51
|
+
// }
|
|
52
|
+
console.log(`✖ ${error.response?.data?.message || error.message}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = { login };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const { getConfig, clearConfig } = require("../utils/chronConfig");
|
|
2
|
+
const { requireAuth } = require("../utils/auth");
|
|
3
|
+
|
|
4
|
+
async function logout() {
|
|
5
|
+
const config = requireAuth();
|
|
6
|
+
clearConfig();
|
|
7
|
+
|
|
8
|
+
console.log("✔ Logged out successfully.");
|
|
9
|
+
console.log(`Goodbye, ${config.user.username}!`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
module.exports = { logout };
|
package/commands/pull.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
const fs = require("fs").promises; //file system
|
|
2
|
+
const fswp = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const supabase = require("../config/supabase");
|
|
5
|
+
const { requireAuth } = require("../utils/auth");
|
|
6
|
+
const repositoryApi = require("../services/repositoryApi");
|
|
7
|
+
const { getToken } = require("../utils/auth");
|
|
8
|
+
const { unzipDirectory } = require("../utils/unzipDirectory");
|
|
9
|
+
|
|
10
|
+
async function pullRepo() {
|
|
11
|
+
let tempDirectory = null;
|
|
12
|
+
try {
|
|
13
|
+
requireAuth(); //checks user logged in or not
|
|
14
|
+
console.log("pulling commits back...");
|
|
15
|
+
const repoPath = path.resolve(process.cwd(), ".chron"); //gives the current directory path
|
|
16
|
+
const configPath = path.join(repoPath, "config.json"); //path to json
|
|
17
|
+
|
|
18
|
+
if (!fswp.existsSync(repoPath)) {
|
|
19
|
+
console.log("Repository not initialized.");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const config = JSON.parse(await fs.readFile(configPath, "utf8")); //reads the json file
|
|
24
|
+
const { repositoryId } = config; //storing repoId
|
|
25
|
+
|
|
26
|
+
if (!repositoryId) {
|
|
27
|
+
console.log("Repository id not found.");
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const token = getToken(); //get the token
|
|
32
|
+
const latestCommitResponse = await repositoryApi.getLatestCommit(
|
|
33
|
+
repositoryId,
|
|
34
|
+
token
|
|
35
|
+
);
|
|
36
|
+
const latestCommit = latestCommitResponse.data.response;
|
|
37
|
+
console.log("Remote latest commit:", latestCommit);
|
|
38
|
+
|
|
39
|
+
const response = await repositoryApi.pullRepository(repositoryId, token); //receive the zip file from backend
|
|
40
|
+
// console.log(response);
|
|
41
|
+
const tempDir = path.join(repoPath, "temp"); //create temporary folder
|
|
42
|
+
tempDirectory = tempDir;
|
|
43
|
+
fswp.mkdirSync(tempDir, { recursive: true });
|
|
44
|
+
const zipPath = path.join(tempDir, "pull.zip");
|
|
45
|
+
|
|
46
|
+
const writer = fswp.createWriteStream(zipPath);
|
|
47
|
+
response.data.pipe(writer);
|
|
48
|
+
|
|
49
|
+
await new Promise((resolve, reject) => {
|
|
50
|
+
writer.on("finish", resolve);
|
|
51
|
+
writer.on("error", reject);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// console.log("ZIP downloaded successfully.");
|
|
55
|
+
const commitsPath = path.join(repoPath, "commits");
|
|
56
|
+
|
|
57
|
+
await unzipDirectory(zipPath, commitsPath);
|
|
58
|
+
|
|
59
|
+
// Update local config only after pull succeeds
|
|
60
|
+
config.lastCommit = latestCommit;
|
|
61
|
+
config.lastPushedCommit = latestCommit;
|
|
62
|
+
|
|
63
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf8");
|
|
64
|
+
|
|
65
|
+
console.log("done");
|
|
66
|
+
} catch (err) {
|
|
67
|
+
if (err.code === "ECONNREFUSED") {
|
|
68
|
+
console.log("Backend server is not running.");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (!err.response) {
|
|
72
|
+
console.log("Unable to connect. Please check your internet connection.");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log("Pull failed");
|
|
77
|
+
console.log("Status:", err.response.status);
|
|
78
|
+
console.log("Backend response:", err.response.data);
|
|
79
|
+
} finally {
|
|
80
|
+
//deleting the temp folder
|
|
81
|
+
try {
|
|
82
|
+
if (tempDirectory && fswp.existsSync(tempDirectory)) {
|
|
83
|
+
fswp.rmSync(tempDirectory, {
|
|
84
|
+
recursive: true,
|
|
85
|
+
force: true,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
} catch (err) {
|
|
89
|
+
console.log(err.code);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = { pullRepo };
|
package/commands/push.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const fs = require("fs").promises;
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { zipDirectory } = require("../utils/zipDirectory");
|
|
4
|
+
const repositoryApi = require("../services/repositoryApi");
|
|
5
|
+
const { getToken } = require("../utils/auth");
|
|
6
|
+
const { requireAuth } = require("../utils/auth");
|
|
7
|
+
|
|
8
|
+
async function pushRepo() {
|
|
9
|
+
requireAuth();
|
|
10
|
+
const repoPath = path.resolve(process.cwd(), ".chron");
|
|
11
|
+
const commitsPath = path.join(repoPath, "commits");
|
|
12
|
+
const configPath = path.join(repoPath, "config.json");
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
try {
|
|
16
|
+
await fs.access(repoPath); // .chron exists
|
|
17
|
+
} catch {
|
|
18
|
+
console.log("Repository not initialized.");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const config = JSON.parse(await fs.readFile(configPath, "utf8"));
|
|
22
|
+
const { repositoryId, lastCommit, lastPushedCommit } = config;
|
|
23
|
+
|
|
24
|
+
if (!lastCommit) {
|
|
25
|
+
console.log("No commits found. Commit your changes before pushing.");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (lastCommit === lastPushedCommit) {
|
|
30
|
+
console.log("Everything is up to date.");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const zipPath = path.join(commitsPath, `${lastCommit}.zip`);
|
|
35
|
+
const commitPath = path.join(commitsPath, lastCommit);
|
|
36
|
+
|
|
37
|
+
await fs.access(commitPath);
|
|
38
|
+
await zipDirectory(commitPath, zipPath);
|
|
39
|
+
|
|
40
|
+
const token = getToken();
|
|
41
|
+
|
|
42
|
+
const response = await repositoryApi.pushRepository(
|
|
43
|
+
repositoryId,
|
|
44
|
+
zipPath,
|
|
45
|
+
token
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
console.log(response);
|
|
49
|
+
|
|
50
|
+
config.lastPushedCommit = lastCommit;
|
|
51
|
+
await fs.writeFile(configPath, JSON.stringify(config, null, 2), "utf8");
|
|
52
|
+
} catch (err) {
|
|
53
|
+
if (err.code === "ECONNREFUSED") {
|
|
54
|
+
console.log("Backend server is not running.");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!err.response) {
|
|
59
|
+
console.log("Unable to connect. Please check your internet connection.");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log(
|
|
64
|
+
"problem in pushing...",
|
|
65
|
+
err.response?.data?.message || err.message
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = { pushRepo };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
const fs = require("fs"); //file system
|
|
2
|
+
const fsp = require("fs").promises;
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const { requireAuth } = require("../utils/auth");
|
|
5
|
+
|
|
6
|
+
async function revertRepo(commitID) {
|
|
7
|
+
requireAuth();
|
|
8
|
+
const repoPath = path.join(process.cwd(), ".chron"); //current working directory
|
|
9
|
+
const commitPath = path.join(repoPath, "commits", commitID); //path to the commit folder
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
try {
|
|
13
|
+
await fsp.access(repoPath);
|
|
14
|
+
// .chron exists
|
|
15
|
+
} catch {
|
|
16
|
+
console.log("Repository not initialized.");
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Check whether the commit exists
|
|
21
|
+
if (!fs.existsSync(commitPath)) {
|
|
22
|
+
console.log("Commit not found.");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
clearProjectRoot(process.cwd());
|
|
27
|
+
|
|
28
|
+
const commitItems = fs.readdirSync(commitPath); //read the particular commit folder
|
|
29
|
+
for (const item of commitItems) {
|
|
30
|
+
if (item === "commit.json") {
|
|
31
|
+
// Skip metadata file
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const sourcePath = path.join(commitPath, item);
|
|
36
|
+
const destinationPath = path.join(process.cwd(), item);
|
|
37
|
+
const stats = fs.statSync(sourcePath);
|
|
38
|
+
|
|
39
|
+
if (stats.isFile()) {
|
|
40
|
+
// Restore file
|
|
41
|
+
fs.copyFileSync(sourcePath, destinationPath);
|
|
42
|
+
console.log(`Restored file: ${item}`);
|
|
43
|
+
} else if (stats.isDirectory()) {
|
|
44
|
+
if (fs.existsSync(destinationPath)) {
|
|
45
|
+
// Restore folder
|
|
46
|
+
fs.rmSync(destinationPath, {
|
|
47
|
+
recursive: true,
|
|
48
|
+
force: true,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
copyDirectory(sourcePath, destinationPath);
|
|
53
|
+
console.log(`Restored folder: ${item}`);
|
|
54
|
+
|
|
55
|
+
const commitData = JSON.parse(
|
|
56
|
+
fs.readFileSync(path.join(commitPath, "commit.json"), "utf8")
|
|
57
|
+
);
|
|
58
|
+
const config = JSON.parse(
|
|
59
|
+
fs.readFileSync(path.join(repoPath, "config.json"), "utf8")
|
|
60
|
+
);
|
|
61
|
+
config.lastCommit = commitData.id;
|
|
62
|
+
|
|
63
|
+
fs.writeFileSync(
|
|
64
|
+
path.join(repoPath, "config.json"),
|
|
65
|
+
JSON.stringify(config, null, 2)
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
console.log("\nRepository reverted successfully.");
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.log(error);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function clearProjectRoot(projectPath) {
|
|
76
|
+
const entries = fs.readdirSync(projectPath, {
|
|
77
|
+
withFileTypes: true,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
for (const entry of entries) {
|
|
81
|
+
// Never delete the .chron directory
|
|
82
|
+
if (entry.name === ".chron") {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const fullPath = path.join(projectPath, entry.name);
|
|
87
|
+
|
|
88
|
+
fs.rmSync(fullPath, {
|
|
89
|
+
recursive: true,
|
|
90
|
+
force: true,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
console.log(`Deleted: ${entry.name}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function copyDirectory(source, destination) {
|
|
98
|
+
if (!fs.existsSync(destination)) {
|
|
99
|
+
fs.mkdirSync(destination, { recursive: true });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const items = fs.readdirSync(source);
|
|
103
|
+
|
|
104
|
+
for (const item of items) {
|
|
105
|
+
if (item === "commit.json") {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const sourcePath = path.join(source, item);
|
|
109
|
+
const destinationPath = path.join(destination, item);
|
|
110
|
+
|
|
111
|
+
const stats = fs.statSync(sourcePath);
|
|
112
|
+
|
|
113
|
+
if (stats.isDirectory()) {
|
|
114
|
+
copyDirectory(sourcePath, destinationPath);
|
|
115
|
+
} else {
|
|
116
|
+
fs.copyFileSync(sourcePath, destinationPath);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
module.exports = { revertRepo };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const { requireAuth } = require("../utils/auth");
|
|
2
|
+
|
|
3
|
+
async function whoami() {
|
|
4
|
+
const config = requireAuth();
|
|
5
|
+
console.log("Logged in as\n");
|
|
6
|
+
|
|
7
|
+
console.log(`Username : ${config.user.username}`);
|
|
8
|
+
console.log(`Email : ${config.user.email}`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
module.exports = { whoami };
|
package/config/config.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
const { createClient } = require("@supabase/supabase-js");
|
|
3
|
+
require("dotenv").config({
|
|
4
|
+
path: path.join(__dirname, "..", ".env"),
|
|
5
|
+
quiet : true
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
const supabase = createClient(
|
|
9
|
+
process.env.SUPABASE_URL,
|
|
10
|
+
process.env.SUPABASE_KEY
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
module.exports = supabase;
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
---------------------------------------------------------
|
|
17
|
+
Supabase Configuration
|
|
18
|
+
---------------------------------------------------------
|
|
19
|
+
This file initializes the Supabase client using the
|
|
20
|
+
project URL and secret key stored in the .env file.
|
|
21
|
+
The configured client is exported so it can be used
|
|
22
|
+
throughout the application for Storage operations.
|
|
23
|
+
---------------------------------------------------------
|
|
24
|
+
*/
|
package/index.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
require("dotenv").config({
|
|
4
|
+
quiet: true,
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
//yargs
|
|
8
|
+
const yargs = require("yargs");
|
|
9
|
+
const { hideBin } = require("yargs/helpers");
|
|
10
|
+
|
|
11
|
+
//commands
|
|
12
|
+
const { login } = require("./commands/login");
|
|
13
|
+
const { logout } = require("./commands/logout");
|
|
14
|
+
const { whoami } = require("./commands/whoami");
|
|
15
|
+
const { initRepo } = require("./commands/init");
|
|
16
|
+
const { addRepo } = require("./commands/add");
|
|
17
|
+
const { commitRepo } = require("./commands/commit");
|
|
18
|
+
const { pushRepo } = require("./commands/push");
|
|
19
|
+
const { pullRepo } = require("./commands/pull");
|
|
20
|
+
const { revertRepo } = require("./commands/revert");
|
|
21
|
+
const { cloneRepo } = require("./commands/clone");
|
|
22
|
+
|
|
23
|
+
yargs(hideBin(process.argv))
|
|
24
|
+
.scriptName("chron") //change the name from index.js to chron
|
|
25
|
+
.usage("Usage: chron <command> [options]")
|
|
26
|
+
|
|
27
|
+
.example("chron login", "Login to your Code Chronicle account")
|
|
28
|
+
.example("chron init my-repo", "Initialize a new repository")
|
|
29
|
+
.example("chron add .", "Stage all files")
|
|
30
|
+
.example("chron push", "Push commits to remote")
|
|
31
|
+
|
|
32
|
+
.strict() //gives complete list of commands and verify the unknown commands
|
|
33
|
+
|
|
34
|
+
.command({
|
|
35
|
+
command: "login",
|
|
36
|
+
describe: "Login to Code Chronicle",
|
|
37
|
+
handler: login,
|
|
38
|
+
})
|
|
39
|
+
.command({
|
|
40
|
+
command: "logout",
|
|
41
|
+
describe: "Logout from Code Chronicle",
|
|
42
|
+
handler: logout,
|
|
43
|
+
})
|
|
44
|
+
.command({
|
|
45
|
+
command: "whoami",
|
|
46
|
+
describe: "check the current user detail",
|
|
47
|
+
handler: whoami,
|
|
48
|
+
})
|
|
49
|
+
.command(
|
|
50
|
+
"init <repoName>",
|
|
51
|
+
"Initialize a new repository",
|
|
52
|
+
(yargs) => {
|
|
53
|
+
yargs.positional("repoName", {
|
|
54
|
+
describe: "Repository name",
|
|
55
|
+
type: "string",
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
(argv) => {
|
|
59
|
+
initRepo(argv.repoName);
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
.command(
|
|
63
|
+
"add <file>",
|
|
64
|
+
"Add file to the repository",
|
|
65
|
+
(yargs) => {
|
|
66
|
+
yargs.positional("file", {
|
|
67
|
+
describe: "File to add to staging area",
|
|
68
|
+
type: "string",
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
(argv) => {
|
|
72
|
+
addRepo(argv.file);
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
.command(
|
|
76
|
+
"commit <message>",
|
|
77
|
+
"Commit the staged file",
|
|
78
|
+
(yargs) => {
|
|
79
|
+
yargs.positional("message", {
|
|
80
|
+
describe: "Commit message",
|
|
81
|
+
type: "string",
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
(argv) => {
|
|
85
|
+
commitRepo(argv.message);
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
.command(
|
|
89
|
+
"push",
|
|
90
|
+
"Push the latest commit to the remote repository",
|
|
91
|
+
{},
|
|
92
|
+
pushRepo
|
|
93
|
+
)
|
|
94
|
+
.command("pull", "pull the commits in to local machine", {}, pullRepo)
|
|
95
|
+
.command(
|
|
96
|
+
"revert <commitId>",
|
|
97
|
+
"Restore the project to a specific commit",
|
|
98
|
+
() => {},
|
|
99
|
+
(argv) => {
|
|
100
|
+
revertRepo(argv.commitId);
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
.command(
|
|
104
|
+
"clone <repoId>",
|
|
105
|
+
"Clone the Project",
|
|
106
|
+
() => {},
|
|
107
|
+
(argv) => {
|
|
108
|
+
cloneRepo(argv.repoId);
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
.help()
|
|
112
|
+
.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "codechronicle-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"bin": {
|
|
5
|
+
"chron": "./index.js"
|
|
6
|
+
},
|
|
7
|
+
"main": "index.js",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"start": "node index.js"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [],
|
|
12
|
+
"author": "",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"description": "",
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@supabase/supabase-js": "^2.111.0",
|
|
17
|
+
"archiver": "^6.0.2",
|
|
18
|
+
"axios": "^1.18.1",
|
|
19
|
+
"dotenv": "^17.4.2",
|
|
20
|
+
"form-data": "^4.0.6",
|
|
21
|
+
"inquirer": "^14.0.2",
|
|
22
|
+
"unzipper": "^0.12.5",
|
|
23
|
+
"uuid": "^14.0.1",
|
|
24
|
+
"yargs": "^18.1.0"
|
|
25
|
+
}
|
|
26
|
+
}
|
package/services/api.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const api = require("./api");
|
|
2
|
+
|
|
3
|
+
async function login(email, password) {
|
|
4
|
+
try {
|
|
5
|
+
const response = await api.post("/api/auth/login", {
|
|
6
|
+
email,
|
|
7
|
+
password,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
return response.data;
|
|
11
|
+
} catch (error) {
|
|
12
|
+
throw error;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
login,
|
|
18
|
+
};
|