Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 3 additions & 28 deletions packages/cli/src/cli/cmd/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,14 @@ import { Command } from "interactive-commander";
import Ora from "ora";
import { getSettings, saveSettings } from "../utils/settings";
import { createAuthenticator } from "../utils/auth";
import { exitGracefully } from "../utils/exit-gracefully";

export default new Command()
.command("auth")
.description("Show current authentication status and user email")
.helpOption("-h, --help", "Show help")
// Deprecated options, safe to remove after September 2025
.option(
"--login",
"DEPRECATED: Shows deprecation warning and exits. Use `lingo.dev login` instead",
)
.option(
"--logout",
"DEPRECATED: Shows deprecation warning and exits. Use `lingo.dev logout` instead",
)
.action(async (options) => {
.action(async () => {
try {
// Handle deprecated login option
if (options.login) {
Ora().warn(
"⚠️ DEPRECATED: '--login' is deprecated. Please use 'lingo.dev login' instead.",
);
process.exit(1);
}

// Handle deprecated logout option
if (options.logout) {
Ora().warn(
"⚠️ DEPRECATED: '--logout' is deprecated. Please use 'lingo.dev logout' instead.",
);
process.exit(1);
}

// Default behavior: show authentication status
const settings = await getSettings(undefined);
const authenticator = createAuthenticator({
apiUrl: settings.auth.apiUrl,
Expand All @@ -48,6 +23,6 @@ export default new Command()
}
} catch (error: any) {
Ora().fail(error.message);
process.exit(1);
exitGracefully(1);
}
});
3 changes: 2 additions & 1 deletion packages/cli/src/cli/cmd/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
renderBanner,
renderHero,
} from "../utils/ui";
import { exitGracefully } from "../utils/exit-gracefully";

export default new Command()
.command("login")
Expand All @@ -33,7 +34,7 @@ export default new Command()
Ora().succeed("Successfully logged in");
} catch (error: any) {
Ora().fail(error.message);
process.exit(1);
exitGracefully(1);
}
});

Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/cli/cmd/logout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
renderBanner,
renderHero,
} from "../utils/ui";
import { exitGracefully } from "../utils/exit-gracefully";

export default new Command()
.command("logout")
Expand All @@ -26,6 +27,6 @@ export default new Command()
Ora().succeed("Successfully logged out");
} catch (error: any) {
Ora().fail(error.message);
process.exit(1);
exitGracefully(1);
}
});
5 changes: 3 additions & 2 deletions packages/cli/src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import mayTheFourthCmd from "./cmd/may-the-fourth";
import packageJson from "../../package.json";
import run from "./cmd/run";
import purgeCmd from "./cmd/purge";
import { exitGracefully } from "./utils/exit-gracefully";

export default new InteractiveCommand()
.name("lingo.dev")
Expand Down Expand Up @@ -69,7 +70,7 @@ Star the the repo :) https://github.com/LingoDotDev/lingo.dev
err.code === "commander.version" ||
err.code === "commander.help"
) {
process.exit(0);
exitGracefully(0);
}
process.exit(1);
exitGracefully(1);
});
33 changes: 30 additions & 3 deletions packages/cli/src/cli/utils/exit-gracefully.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ describe("exitGracefully", () => {
expect(mockExit).toHaveBeenCalledWith(0);
});

it("should exit with specified exit code when no pending operations", () => {
// Mock no pending operations
(process as any)._getActiveHandles.mockReturnValue([]);
(process as any)._getActiveRequests.mockReturnValue([]);

exitGracefully(1);

expect(mockExit).toHaveBeenCalledWith(1);
});

it("should wait and retry when there are pending operations", () => {
vi.useFakeTimers();

Expand Down Expand Up @@ -142,8 +152,8 @@ describe("exitGracefully", () => {
]);
(process as any)._getActiveRequests.mockReturnValue([]);

// Start with 1500ms already elapsed
exitGracefully(1500);
// Start with 1500ms already elapsed (exitCode=0, elapsedMs=1500)
exitGracefully(0, 1500);

// Should exit after 500ms more (reaching 2000ms max)
vi.advanceTimersByTime(500);
Expand All @@ -158,12 +168,29 @@ describe("exitGracefully", () => {
]);
(process as any)._getActiveRequests.mockReturnValue([]);

exitGracefully(2500);
exitGracefully(0, 2500);

// Should exit immediately as elapsed time exceeds max wait interval
expect(mockExit).toHaveBeenCalledWith(0);
});

it("should exit with non-zero exit code when specified", () => {
vi.useFakeTimers();

// Mock pending operations
(process as any)._getActiveHandles.mockReturnValue([
{ hasRef: () => true, close: () => {} },
]);
(process as any)._getActiveRequests.mockReturnValue([]);

exitGracefully(1);

// Fast-forward to max wait time
vi.advanceTimersByTime(2000);

expect(mockExit).toHaveBeenCalledWith(1);
});

it("should handle mixed types of pending operations", () => {
vi.useFakeTimers();

Expand Down
8 changes: 4 additions & 4 deletions packages/cli/src/cli/utils/exit-gracefully.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
const STEP_WAIT_INTERVAL = 250;
const MAX_WAIT_INTERVAL = 2000;

export function exitGracefully(elapsedMs = 0) {
export function exitGracefully(exitCode: number = 0, elapsedMs = 0) {
// Check if there are any pending operations
const hasPendingOperations = checkForPendingOperations();

if (hasPendingOperations && elapsedMs < MAX_WAIT_INTERVAL) {
// Wait a bit longer if there are pending operations
setTimeout(
() => exitGracefully(elapsedMs + STEP_WAIT_INTERVAL),
() => exitGracefully(exitCode, elapsedMs + STEP_WAIT_INTERVAL),
STEP_WAIT_INTERVAL,
);
} else {
// Exit immediately if no pending operations
process.exit(0);
// Exit with the specified exit code
process.exit(exitCode);
}
}

Expand Down
Loading