@sleekcms/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/index.js +157 -0
- package/package.json +20 -0
package/index.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs-extra");
|
|
4
|
+
const axios = require("axios");
|
|
5
|
+
const chokidar = require("chokidar");
|
|
6
|
+
const { program } = require("commander");
|
|
7
|
+
|
|
8
|
+
const API_BASE_URLS = {
|
|
9
|
+
localhost: "http://localhost:9000/api/template",
|
|
10
|
+
development: "https://app.sleekcms.net/api/template",
|
|
11
|
+
production: "https://app.sleekcms.com/api/template",
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const PORT = 8080;
|
|
15
|
+
const DEBOUNCE_DELAY = 1000; // 2 seconds delay
|
|
16
|
+
let isShuttingDown = false;
|
|
17
|
+
const pendingUpdates = {};
|
|
18
|
+
let fileMap = {};
|
|
19
|
+
|
|
20
|
+
// CLI Setup to take `--token=<token>`
|
|
21
|
+
program
|
|
22
|
+
.option("--token <token>", "API authentication token")
|
|
23
|
+
.option("--env <env>", "Environment (localhost, development, production)", "production")
|
|
24
|
+
.parse(process.argv);
|
|
25
|
+
|
|
26
|
+
const options = program.opts();
|
|
27
|
+
const AUTH_TOKEN = options.token;
|
|
28
|
+
const ENV = options.env.toLowerCase();
|
|
29
|
+
|
|
30
|
+
if (!AUTH_TOKEN) {
|
|
31
|
+
console.error("โ Missing required --token parameter.");
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const API_BASE_URL = API_BASE_URLS[ENV] || API_BASE_URLS.production;
|
|
36
|
+
|
|
37
|
+
const VIEWS_DIR = AUTH_TOKEN.split('-')[0] + "-views/";
|
|
38
|
+
|
|
39
|
+
// Axios instance with authorization
|
|
40
|
+
const apiClient = axios.create({
|
|
41
|
+
baseURL: API_BASE_URL,
|
|
42
|
+
headers: { Authorization: `Bearer ${AUTH_TOKEN}` },
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
// Function to fetch and save files
|
|
47
|
+
async function fetchFiles() {
|
|
48
|
+
try {
|
|
49
|
+
console.log("๐ฅ Fetching files from API...");
|
|
50
|
+
const response = await apiClient.get("/");
|
|
51
|
+
|
|
52
|
+
await fs.ensureDir(`./${VIEWS_DIR}`);
|
|
53
|
+
|
|
54
|
+
for (const file of response.data) {
|
|
55
|
+
if (file.file_path) {
|
|
56
|
+
const filePath = `./${VIEWS_DIR}${file.file_path}`;
|
|
57
|
+
await fs.outputFile(filePath, file.code);
|
|
58
|
+
fileMap[file.file_path] = file.id;
|
|
59
|
+
console.log(`โ
Created: ${filePath}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log("โ๏ธ All files downloaded. They will be deleted on exit.");
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.error("โ Error fetching files:", error.response?.data || error.message);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Function to clean up views directory
|
|
70
|
+
async function cleanupFiles() {
|
|
71
|
+
console.log("๐งน Cleaning up files...");
|
|
72
|
+
try {
|
|
73
|
+
await fs.remove(`./${VIEWS_DIR}`);
|
|
74
|
+
console.log("โ
Cleanup complete. Exiting...");
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error("โ Error during cleanup:", error.message);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
// Function to handle debounced updates
|
|
82
|
+
function scheduleUpdate(filePath) {
|
|
83
|
+
if (isShuttingDown) return;
|
|
84
|
+
|
|
85
|
+
const relativePath = filePath.replace(VIEWS_DIR, ""); // Extract relative file path
|
|
86
|
+
const fileId = fileMap[relativePath];
|
|
87
|
+
|
|
88
|
+
// Clear previous timeout if it exists
|
|
89
|
+
if (pendingUpdates[fileId]) {
|
|
90
|
+
clearTimeout(pendingUpdates[fileId]);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Schedule a new update after the debounce delay
|
|
94
|
+
pendingUpdates[fileId] = setTimeout(async () => {
|
|
95
|
+
try {
|
|
96
|
+
const code = await fs.readFile(filePath, "utf-8");
|
|
97
|
+
|
|
98
|
+
await apiClient.patch(`/${fileId}`, { code });
|
|
99
|
+
console.log("โ
Updated template for:", relativePath);
|
|
100
|
+
|
|
101
|
+
delete pendingUpdates[fileId]; // Cleanup
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error("โ Error updating API:", error.response?.data || error.message);
|
|
104
|
+
}
|
|
105
|
+
}, DEBOUNCE_DELAY);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function createSchema(filePath) {
|
|
109
|
+
if (isShuttingDown) return;
|
|
110
|
+
|
|
111
|
+
const relativePath = filePath.replace(VIEWS_DIR, ""); // Extract relative file path
|
|
112
|
+
const resp = await apiClient.post("/cli", { file_path: relativePath});
|
|
113
|
+
const schema = resp.data;
|
|
114
|
+
fileMap[relativePath] = schema.tmpl_main_id;
|
|
115
|
+
console.log("โ
Created model for:", relativePath);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Function to monitor file changes
|
|
119
|
+
function monitorFiles() {
|
|
120
|
+
console.log("๐ Watching for file changes...");
|
|
121
|
+
|
|
122
|
+
chokidar.watch(`./${VIEWS_DIR}`, { persistent: true, ignoreInitial: true })
|
|
123
|
+
.on("change", scheduleUpdate)
|
|
124
|
+
.on("add", createSchema);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Graceful shutdown handler
|
|
128
|
+
async function handleExit() {
|
|
129
|
+
if (isShuttingDown) return;
|
|
130
|
+
isShuttingDown = true;
|
|
131
|
+
console.log("\nโ ๏ธ Shutting down...");
|
|
132
|
+
|
|
133
|
+
//await finalSync();
|
|
134
|
+
await cleanupFiles();
|
|
135
|
+
|
|
136
|
+
process.exit(0);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Main function
|
|
140
|
+
async function main() {
|
|
141
|
+
await fetchFiles();
|
|
142
|
+
monitorFiles();
|
|
143
|
+
//const server = startServer();
|
|
144
|
+
|
|
145
|
+
process.on("SIGINT", async () => {
|
|
146
|
+
console.log("\n๐ Caught interrupt signal (Ctrl+C)");
|
|
147
|
+
await handleExit();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
process.on("SIGTERM", async () => {
|
|
151
|
+
console.log("\n๐ Caught termination signal");
|
|
152
|
+
await handleExit();
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Execute when script runs
|
|
157
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sleekcms/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "SleekCMS CLI for locally editing SleekCMS site template code",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"sleekcms": "index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
|
+
},
|
|
12
|
+
"author": "Yusuf Bhabhrawala",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"axios": "^1.7.9",
|
|
16
|
+
"chokidar": "^4.0.3",
|
|
17
|
+
"commander": "^13.1.0",
|
|
18
|
+
"fs-extra": "^11.3.0"
|
|
19
|
+
}
|
|
20
|
+
}
|