@saidulbadhon/jssm-cli 1.9.5 → 1.9.8
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/dist/index.js +167 -10
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -5012,6 +5012,7 @@ async function pushCommand2(args2) {
|
|
|
5012
5012
|
let updatedFilesCount = 0;
|
|
5013
5013
|
let newFilesCount = 0;
|
|
5014
5014
|
let deletedFilesCount = 0;
|
|
5015
|
+
let deletionEndpointUnavailable = false;
|
|
5015
5016
|
let totalChangedLines = 0;
|
|
5016
5017
|
for (const file of selectedFiles) {
|
|
5017
5018
|
let fileContent = "";
|
|
@@ -5036,11 +5037,11 @@ async function pushCommand2(args2) {
|
|
|
5036
5037
|
failCount++;
|
|
5037
5038
|
continue;
|
|
5038
5039
|
}
|
|
5039
|
-
if (fileSize >
|
|
5040
|
+
if (fileSize > 65536) {
|
|
5040
5041
|
console.error(
|
|
5041
|
-
`\u274C ${file}: File size (${fileSize} bytes) exceeds maximum (
|
|
5042
|
+
`\u274C ${file}: File size (${fileSize} bytes) exceeds maximum (65536 bytes / 64 KB)`
|
|
5042
5043
|
);
|
|
5043
|
-
console.error("
|
|
5044
|
+
console.error(" Files >4 KB are auto-chunked, but this exceeds the overall cap.");
|
|
5044
5045
|
failCount++;
|
|
5045
5046
|
continue;
|
|
5046
5047
|
}
|
|
@@ -5132,6 +5133,19 @@ async function pushCommand2(args2) {
|
|
|
5132
5133
|
}
|
|
5133
5134
|
} catch (error) {
|
|
5134
5135
|
const message = error instanceof Error ? error.message : String(error);
|
|
5136
|
+
if (message.includes("HTTP 404")) {
|
|
5137
|
+
if (!deletionEndpointUnavailable) {
|
|
5138
|
+
console.error(
|
|
5139
|
+
"\u274C Deletion sync is not supported by this server (missing /files/delete endpoint)."
|
|
5140
|
+
);
|
|
5141
|
+
console.error(
|
|
5142
|
+
" \u{1F4A1} Upgrade/redeploy the backend with the latest files route changes, then run jssm push again."
|
|
5143
|
+
);
|
|
5144
|
+
deletionEndpointUnavailable = true;
|
|
5145
|
+
failCount++;
|
|
5146
|
+
}
|
|
5147
|
+
break;
|
|
5148
|
+
}
|
|
5135
5149
|
console.error(`\u274C ${remoteFile}: Failed to delete - ${message}`);
|
|
5136
5150
|
failCount++;
|
|
5137
5151
|
}
|
|
@@ -5601,13 +5615,156 @@ Note:
|
|
|
5601
5615
|
|
|
5602
5616
|
// src/commands/login.ts
|
|
5603
5617
|
init_auth();
|
|
5604
|
-
|
|
5618
|
+
|
|
5619
|
+
// src/commands/loginBrowser.ts
|
|
5620
|
+
init_auth();
|
|
5621
|
+
import { hostname, platform } from "os";
|
|
5622
|
+
import { spawn } from "child_process";
|
|
5623
|
+
function openBrowser(url) {
|
|
5624
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
5625
|
+
const args2 = process.platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
5626
|
+
try {
|
|
5627
|
+
const child = spawn(cmd, args2, {
|
|
5628
|
+
detached: true,
|
|
5629
|
+
stdio: "ignore"
|
|
5630
|
+
});
|
|
5631
|
+
child.unref();
|
|
5632
|
+
child.on("error", () => {
|
|
5633
|
+
});
|
|
5634
|
+
return true;
|
|
5635
|
+
} catch {
|
|
5636
|
+
return false;
|
|
5637
|
+
}
|
|
5638
|
+
}
|
|
5639
|
+
function sleep(ms) {
|
|
5640
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
5641
|
+
}
|
|
5642
|
+
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
5643
|
+
async function loginBrowserCommand() {
|
|
5644
|
+
const host = getHost();
|
|
5645
|
+
let init;
|
|
5646
|
+
try {
|
|
5647
|
+
const response = await fetch(`${host}/auth/cli/init`, {
|
|
5648
|
+
method: "POST",
|
|
5649
|
+
headers: { "Content-Type": "application/json" },
|
|
5650
|
+
body: JSON.stringify({
|
|
5651
|
+
deviceInfo: {
|
|
5652
|
+
hostname: hostname(),
|
|
5653
|
+
platform: platform()
|
|
5654
|
+
}
|
|
5655
|
+
})
|
|
5656
|
+
});
|
|
5657
|
+
if (!response.ok) {
|
|
5658
|
+
const body = await response.json().catch(() => ({}));
|
|
5659
|
+
return {
|
|
5660
|
+
success: false,
|
|
5661
|
+
error: body.error || `Failed to start login (HTTP ${response.status})`
|
|
5662
|
+
};
|
|
5663
|
+
}
|
|
5664
|
+
init = await response.json();
|
|
5665
|
+
} catch (err) {
|
|
5666
|
+
return {
|
|
5667
|
+
success: false,
|
|
5668
|
+
error: `Unable to reach JSSM at ${host}: ${err?.message || err}`
|
|
5669
|
+
};
|
|
5670
|
+
}
|
|
5671
|
+
console.log("");
|
|
5672
|
+
console.log("\u{1F510} Sign in to JSSM");
|
|
5673
|
+
console.log("");
|
|
5674
|
+
console.log(` Verification code: \x1B[1m${init.userCode}\x1B[0m`);
|
|
5675
|
+
console.log(` Open this URL: ${init.verificationUrl}`);
|
|
5676
|
+
console.log("");
|
|
5677
|
+
console.log(" Confirm the code matches what's shown in the browser.");
|
|
5678
|
+
console.log("");
|
|
5679
|
+
const opened = openBrowser(init.verificationUrl);
|
|
5680
|
+
if (!opened) {
|
|
5681
|
+
console.log("\u26A0\uFE0F Could not auto-open browser \u2014 open the URL above manually.");
|
|
5682
|
+
}
|
|
5683
|
+
const intervalMs = Math.max(1, init.interval) * 1e3;
|
|
5684
|
+
const deadline = Date.now() + init.expiresIn * 1e3;
|
|
5685
|
+
let frame = 0;
|
|
5686
|
+
const isTty = !!process.stdout.isTTY;
|
|
5687
|
+
while (Date.now() < deadline) {
|
|
5688
|
+
if (isTty) {
|
|
5689
|
+
const spinner = SPINNER_FRAMES[frame++ % SPINNER_FRAMES.length];
|
|
5690
|
+
process.stdout.write(`\r${spinner} Waiting for approval in browser\u2026`);
|
|
5691
|
+
}
|
|
5692
|
+
await sleep(intervalMs);
|
|
5693
|
+
let poll;
|
|
5694
|
+
try {
|
|
5695
|
+
const response = await fetch(`${host}/auth/cli/poll`, {
|
|
5696
|
+
method: "POST",
|
|
5697
|
+
headers: { "Content-Type": "application/json" },
|
|
5698
|
+
body: JSON.stringify({ code: init.code })
|
|
5699
|
+
});
|
|
5700
|
+
if (!response.ok) {
|
|
5701
|
+
continue;
|
|
5702
|
+
}
|
|
5703
|
+
poll = await response.json();
|
|
5704
|
+
} catch {
|
|
5705
|
+
continue;
|
|
5706
|
+
}
|
|
5707
|
+
if (poll.status === "pending")
|
|
5708
|
+
continue;
|
|
5709
|
+
if (isTty)
|
|
5710
|
+
process.stdout.write("\r\x1B[K");
|
|
5711
|
+
if (poll.status === "approved" && poll.token && poll.user) {
|
|
5712
|
+
const expiresAt = Date.now() + 7 * 24 * 60 * 60 * 1e3;
|
|
5713
|
+
await saveAuthData({
|
|
5714
|
+
token: poll.token,
|
|
5715
|
+
user: poll.user,
|
|
5716
|
+
expiresAt
|
|
5717
|
+
});
|
|
5718
|
+
return { success: true };
|
|
5719
|
+
}
|
|
5720
|
+
if (poll.status === "denied") {
|
|
5721
|
+
return { success: false, error: "Sign-in was canceled in the browser." };
|
|
5722
|
+
}
|
|
5723
|
+
if (poll.status === "expired") {
|
|
5724
|
+
return { success: false, error: "Sign-in request expired before approval." };
|
|
5725
|
+
}
|
|
5726
|
+
}
|
|
5727
|
+
if (isTty)
|
|
5728
|
+
process.stdout.write("\r\x1B[K");
|
|
5729
|
+
return {
|
|
5730
|
+
success: false,
|
|
5731
|
+
error: "Sign-in timed out. Run `jssm login` again to retry."
|
|
5732
|
+
};
|
|
5733
|
+
}
|
|
5734
|
+
|
|
5735
|
+
// src/commands/login.ts
|
|
5736
|
+
async function loginCommand(args2 = []) {
|
|
5605
5737
|
const authData = await loadAuthData();
|
|
5606
5738
|
if (authData) {
|
|
5607
5739
|
console.log(`\u2705 Already logged in as ${authData.user.email}`);
|
|
5608
5740
|
console.log(`\u{1F4A1} Use 'jssm logout' to logout`);
|
|
5609
5741
|
return;
|
|
5610
5742
|
}
|
|
5743
|
+
const wantsManual = args2.includes("--manual");
|
|
5744
|
+
const useBrowser = !wantsManual && process.stdout.isTTY;
|
|
5745
|
+
if (useBrowser) {
|
|
5746
|
+
try {
|
|
5747
|
+
const result = await loginBrowserCommand();
|
|
5748
|
+
if (result.success) {
|
|
5749
|
+
const fresh = await loadAuthData();
|
|
5750
|
+
console.log(`\u2705 Successfully logged in as ${fresh?.user.email}`);
|
|
5751
|
+
console.log(`\u{1F464} Name: ${fresh?.user.name}`);
|
|
5752
|
+
console.log(`
|
|
5753
|
+
\u{1F4A1} You can now use 'jssm init' to set up your projects`);
|
|
5754
|
+
return;
|
|
5755
|
+
}
|
|
5756
|
+
console.error(`\u274C ${result.error}`);
|
|
5757
|
+
console.log(`
|
|
5758
|
+
\u{1F4A1} Run 'jssm login --manual' to use email + password.`);
|
|
5759
|
+
process.exit(1);
|
|
5760
|
+
} catch (err) {
|
|
5761
|
+
console.error(`\u274C Error: ${err?.message || err}`);
|
|
5762
|
+
process.exit(1);
|
|
5763
|
+
}
|
|
5764
|
+
}
|
|
5765
|
+
await loginManual();
|
|
5766
|
+
}
|
|
5767
|
+
async function loginManual() {
|
|
5611
5768
|
const host = getHost();
|
|
5612
5769
|
console.log("\u{1F510} Login to JSSM\n");
|
|
5613
5770
|
try {
|
|
@@ -5633,10 +5790,10 @@ async function loginCommand() {
|
|
|
5633
5790
|
console.log("\n\u{1F504} Logging in...");
|
|
5634
5791
|
const result = await login(host, email, pass);
|
|
5635
5792
|
if (result.success) {
|
|
5636
|
-
const
|
|
5793
|
+
const authData = await loadAuthData();
|
|
5637
5794
|
console.log(`
|
|
5638
|
-
\u2705 Successfully logged in as ${
|
|
5639
|
-
console.log(`\u{1F464} Name: ${
|
|
5795
|
+
\u2705 Successfully logged in as ${authData?.user.email}`);
|
|
5796
|
+
console.log(`\u{1F464} Name: ${authData?.user.name}`);
|
|
5640
5797
|
console.log(`
|
|
5641
5798
|
\u{1F4A1} You can now use 'jssm init' to set up your projects`);
|
|
5642
5799
|
} else {
|
|
@@ -6027,7 +6184,7 @@ ${import_chalk.default.bold("Usage in Docker:")}
|
|
|
6027
6184
|
|
|
6028
6185
|
// src/utils/versionCheck.ts
|
|
6029
6186
|
var PACKAGE_NAME = "@saidulbadhon/jssm-cli";
|
|
6030
|
-
var CURRENT_VERSION = "1.9.
|
|
6187
|
+
var CURRENT_VERSION = "1.9.8";
|
|
6031
6188
|
async function getLatestVersion() {
|
|
6032
6189
|
try {
|
|
6033
6190
|
const response = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}`);
|
|
@@ -6144,7 +6301,7 @@ async function main() {
|
|
|
6144
6301
|
await checkVersion(command);
|
|
6145
6302
|
switch (command) {
|
|
6146
6303
|
case "login":
|
|
6147
|
-
await loginCommand();
|
|
6304
|
+
await loginCommand(args.slice(1));
|
|
6148
6305
|
break;
|
|
6149
6306
|
case "register":
|
|
6150
6307
|
await registerCommand();
|
|
@@ -6210,7 +6367,7 @@ Usage:
|
|
|
6210
6367
|
jssm <command> [options]
|
|
6211
6368
|
|
|
6212
6369
|
Commands:
|
|
6213
|
-
login Login
|
|
6370
|
+
login Login via your browser (use --manual for email/password prompt)
|
|
6214
6371
|
register Register a new JSSM account
|
|
6215
6372
|
logout Logout from your account
|
|
6216
6373
|
init Initialize current directory (creates .jssm config file)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saidulbadhon/jssm-cli",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "CLI for JSSM - Simple environment variable manager",
|
|
6
6
|
"author": "Saidul Badhon",
|
|
@@ -49,4 +49,4 @@
|
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@inquirer/prompts": "^8.2.0"
|
|
51
51
|
}
|
|
52
|
-
}
|
|
52
|
+
}
|