@linkedctl/cli
Advanced tools
Sorry, the diff of this file is not supported yet
| export interface CallbackResult { | ||
| code: string; | ||
| state: string; | ||
| } | ||
| /** | ||
| * Start a local HTTP server on a random available port and wait for the | ||
| * OAuth2 callback from LinkedIn. | ||
| * | ||
| * Returns an object containing the port, a promise that resolves with the | ||
| * authorization code and state, and a stop function to shut down the server. | ||
| */ | ||
| export declare function startCallbackServer(port: number): Promise<{ | ||
| port: number; | ||
| result: Promise<CallbackResult>; | ||
| stop: () => Promise<void>; | ||
| }>; | ||
| //# sourceMappingURL=callback-server.d.ts.map |
| {"version":3,"file":"callback-server.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/callback-server.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B,CAAC,CA0DD"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { createServer } from "node:http"; | ||
| const SUCCESS_HTML = `<!DOCTYPE html> | ||
| <html><head><title>LinkedCtl</title></head> | ||
| <body style="font-family:system-ui;text-align:center;padding:4rem"> | ||
| <h1>Authorization successful</h1> | ||
| <p>You may close this window and return to your terminal.</p> | ||
| </body></html>`; | ||
| const ERROR_HTML = `<!DOCTYPE html> | ||
| <html><head><title>LinkedCtl</title></head> | ||
| <body style="font-family:system-ui;text-align:center;padding:4rem"> | ||
| <h1>Authorization failed</h1> | ||
| <p>Something went wrong. Please check your terminal for details.</p> | ||
| </body></html>`; | ||
| /** | ||
| * Start a local HTTP server on a random available port and wait for the | ||
| * OAuth2 callback from LinkedIn. | ||
| * | ||
| * Returns an object containing the port, a promise that resolves with the | ||
| * authorization code and state, and a stop function to shut down the server. | ||
| */ | ||
| export async function startCallbackServer(port) { | ||
| let resolveResult; | ||
| let rejectResult; | ||
| const result = new Promise((resolve, reject) => { | ||
| resolveResult = resolve; | ||
| rejectResult = reject; | ||
| }); | ||
| const server = createServer((req, res) => { | ||
| const url = new URL(req.url ?? "/", `http://localhost`); | ||
| if (url.pathname !== "/callback") { | ||
| res.writeHead(404, { "Content-Type": "text/plain" }); | ||
| res.end("Not Found"); | ||
| return; | ||
| } | ||
| const code = url.searchParams.get("code"); | ||
| const state = url.searchParams.get("state"); | ||
| const error = url.searchParams.get("error"); | ||
| const errorDescription = url.searchParams.get("error_description"); | ||
| if (error !== null) { | ||
| res.writeHead(200, { "Content-Type": "text/html" }); | ||
| res.end(ERROR_HTML); | ||
| rejectResult(new Error(`Authorization denied: ${errorDescription ?? error}`)); | ||
| return; | ||
| } | ||
| if (code === null || state === null) { | ||
| res.writeHead(400, { "Content-Type": "text/html" }); | ||
| res.end(ERROR_HTML); | ||
| rejectResult(new Error("Missing code or state in callback. " + | ||
| 'The OAuth2 flow may have been interrupted. Run "linkedctl auth login" to try again.')); | ||
| return; | ||
| } | ||
| res.writeHead(200, { "Content-Type": "text/html" }); | ||
| res.end(SUCCESS_HTML); | ||
| resolveResult({ code, state }); | ||
| }); | ||
| const actualPort = await listen(server, port); | ||
| const stop = async () => { | ||
| await new Promise((resolve, reject) => { | ||
| server.close((err) => { | ||
| if (err) | ||
| reject(err); | ||
| else | ||
| resolve(); | ||
| }); | ||
| }); | ||
| }; | ||
| return { port: actualPort, result, stop }; | ||
| } | ||
| function listen(server, port) { | ||
| return new Promise((resolve, reject) => { | ||
| server.on("error", reject); | ||
| server.listen(port, "127.0.0.1", () => { | ||
| const addr = server.address(); | ||
| if (addr === null || typeof addr === "string") { | ||
| reject(new Error("Unexpected server address type")); | ||
| return; | ||
| } | ||
| resolve(addr.port); | ||
| }); | ||
| }); | ||
| } | ||
| //# sourceMappingURL=callback-server.js.map |
| {"version":3,"file":"callback-server.js","sourceRoot":"","sources":["../../../src/commands/auth/callback-server.ts"],"names":[],"mappings":"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"} |
| import { Command } from "commander"; | ||
| export declare function authCommand(): Command; | ||
| //# sourceMappingURL=index.d.ts.map |
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,wBAAgB,WAAW,IAAI,OAAO,CAarC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { Command } from "commander"; | ||
| import { setupCommand } from "./setup.js"; | ||
| import { tokenCommand } from "./token.js"; | ||
| import { statusCommand } from "./status.js"; | ||
| import { logoutCommand } from "./logout.js"; | ||
| import { revokeCommand } from "./revoke.js"; | ||
| import { loginCommand } from "./login.js"; | ||
| import { refreshCommand } from "./refresh.js"; | ||
| export function authCommand() { | ||
| const cmd = new Command("auth"); | ||
| cmd.description("Manage authentication"); | ||
| cmd.addCommand(setupCommand()); | ||
| cmd.addCommand(tokenCommand()); | ||
| cmd.addCommand(statusCommand()); | ||
| cmd.addCommand(logoutCommand()); | ||
| cmd.addCommand(revokeCommand()); | ||
| cmd.addCommand(loginCommand()); | ||
| cmd.addCommand(refreshCommand()); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/auth/index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,UAAU,WAAW;IACzB,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,GAAG,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC;IAEzC,GAAG,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC,CAAC;IAC/B,GAAG,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC,CAAC;IAC/B,GAAG,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;IAChC,GAAG,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;IAChC,GAAG,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;IAChC,GAAG,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC,CAAC;IAC/B,GAAG,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC,CAAC;IAEjC,OAAO,GAAG,CAAC;AACb,CAAC"} |
| import { Command } from "commander"; | ||
| export declare const DEFAULT_REDIRECT_PORT = 18920; | ||
| export declare function loginCommand(): Command; | ||
| //# sourceMappingURL=login.d.ts.map |
| {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/login.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC,eAAO,MAAM,qBAAqB,QAAQ,CAAC;AAE3C,wBAAgB,YAAY,IAAI,OAAO,CAiItC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { randomUUID } from "node:crypto"; | ||
| import { execFile } from "node:child_process"; | ||
| import { platform } from "node:os"; | ||
| import { Command } from "commander"; | ||
| import { loadConfigFile, validateConfig, saveOAuthTokens, saveOAuthClientCredentials, buildAuthorizationUrl, exchangeAuthorizationCode, refreshAccessToken, generateCodeVerifier, computeCodeChallenge, } from "@linkedctl/core"; | ||
| import { startCallbackServer } from "./callback-server.js"; | ||
| export const DEFAULT_REDIRECT_PORT = 18920; | ||
| export function loginCommand() { | ||
| const cmd = new Command("login"); | ||
| cmd.description("Authenticate with LinkedIn via OAuth2"); | ||
| cmd.option("--client-id <id>", "OAuth2 client ID (overrides config value)"); | ||
| cmd.option("--client-secret <secret>", "OAuth2 client secret (overrides config value)"); | ||
| cmd.option("--scope <scopes>", "OAuth2 scopes (space-separated)"); | ||
| cmd.option("--port <number>", "local callback server port", String(DEFAULT_REDIRECT_PORT)); | ||
| cmd.option("--pkce", "use PKCE flow (requires LinkedIn to enable it for your app)"); | ||
| cmd.action(async (opts) => { | ||
| const program = cmd.parent?.parent; | ||
| // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment | ||
| const profileFlag = program?.opts()["profile"]; | ||
| const { raw } = await loadConfigFile({ profile: profileFlag }); | ||
| const { config } = validateConfig(raw); | ||
| // Resolve client credentials: CLI flags > config | ||
| const clientId = opts.clientId ?? config.oauth?.clientId; | ||
| const clientSecret = opts.clientSecret ?? config.oauth?.clientSecret; | ||
| if (clientId === undefined || clientSecret === undefined) { | ||
| throw new Error("Missing OAuth2 credentials. Provide --client-id and --client-secret, " + | ||
| 'or run "linkedctl auth setup" to configure them interactively.'); | ||
| } | ||
| // Resolve scope: CLI flag > config | ||
| const scope = opts.scope ?? config.oauth?.scope; | ||
| if (scope === undefined) { | ||
| throw new Error("Missing OAuth2 scope. Provide --scope, " + 'or run "linkedctl auth setup" to configure it interactively.'); | ||
| } | ||
| const writeOpts = { profile: profileFlag }; | ||
| // Check for existing refresh token and attempt refresh first | ||
| const existingRefreshToken = config.oauth?.refreshToken; | ||
| if (existingRefreshToken !== undefined) { | ||
| console.error("Attempting token refresh..."); | ||
| const refreshConfig = { | ||
| clientId, | ||
| clientSecret, | ||
| redirectUri: "", // not used for refresh | ||
| scope, | ||
| }; | ||
| try { | ||
| const tokens = await refreshAccessToken(refreshConfig, existingRefreshToken); | ||
| const expiry = new Date(Date.now() + tokens.expiresIn * 1000).toISOString(); | ||
| await saveOAuthTokens({ | ||
| accessToken: tokens.accessToken, | ||
| refreshToken: tokens.refreshToken, | ||
| tokenExpiresAt: expiry, | ||
| }, writeOpts); | ||
| await saveOAuthClientCredentials({ clientId, clientSecret }, writeOpts); | ||
| if (profileFlag !== undefined) { | ||
| console.error(`Token refreshed for profile "${profileFlag}".`); | ||
| } | ||
| else { | ||
| console.error("Token refreshed."); | ||
| } | ||
| return; | ||
| } | ||
| catch { | ||
| console.error("Token refresh failed, starting full authorization flow..."); | ||
| } | ||
| } | ||
| // Full OAuth2 authorization code flow | ||
| const port = Number.parseInt(opts.port, 10); | ||
| const { result, stop } = await startCallbackServer(port); | ||
| const redirectUri = `http://127.0.0.1:${port}/callback`; | ||
| const state = randomUUID(); | ||
| const usePkce = opts.pkce === true || config.oauth?.pkce === true; | ||
| let codeVerifier; | ||
| let codeChallenge; | ||
| if (usePkce) { | ||
| codeVerifier = generateCodeVerifier(); | ||
| codeChallenge = computeCodeChallenge(codeVerifier); | ||
| } | ||
| const oauth2Config = { | ||
| clientId, | ||
| clientSecret, | ||
| redirectUri, | ||
| scope, | ||
| }; | ||
| const authUrl = buildAuthorizationUrl(oauth2Config, state, codeChallenge); | ||
| console.error("Opening browser for LinkedIn authorization..."); | ||
| console.error(`If the browser does not open, visit:\n${authUrl}`); | ||
| openBrowser(authUrl); | ||
| try { | ||
| const callback = await result; | ||
| if (callback.state !== state) { | ||
| throw new Error("OAuth2 state mismatch — possible CSRF attack. " + | ||
| 'The authorization response may have been tampered with. Run "linkedctl auth login" to try again.'); | ||
| } | ||
| const tokens = await exchangeAuthorizationCode(oauth2Config, callback.code, codeVerifier); | ||
| const expiry = new Date(Date.now() + tokens.expiresIn * 1000).toISOString(); | ||
| await saveOAuthTokens({ | ||
| accessToken: tokens.accessToken, | ||
| refreshToken: tokens.refreshToken, | ||
| tokenExpiresAt: expiry, | ||
| }, writeOpts); | ||
| await saveOAuthClientCredentials({ clientId, clientSecret }, writeOpts); | ||
| if (profileFlag !== undefined) { | ||
| console.error(`Authenticated and saved to profile "${profileFlag}".`); | ||
| } | ||
| else { | ||
| console.error("Authenticated successfully."); | ||
| } | ||
| } | ||
| finally { | ||
| await stop(); | ||
| } | ||
| }); | ||
| return cmd; | ||
| } | ||
| function openBrowser(url) { | ||
| switch (platform()) { | ||
| case "darwin": | ||
| execFile("open", [url]); | ||
| break; | ||
| case "win32": | ||
| execFile("cmd", ["/c", "start", "", url]); | ||
| break; | ||
| default: | ||
| execFile("xdg-open", [url]); | ||
| break; | ||
| } | ||
| } | ||
| //# sourceMappingURL=login.js.map |
| {"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/commands/auth/login.ts"],"names":[],"mappings":"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"} |
| import { Command } from "commander"; | ||
| export declare function logoutCommand(): Command; | ||
| //# sourceMappingURL=logout.d.ts.map |
| {"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/logout.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,wBAAgB,aAAa,IAAI,OAAO,CAwBvC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { Command } from "commander"; | ||
| import { loadConfigFile, validateConfig, clearOAuthTokens } from "@linkedctl/core"; | ||
| export function logoutCommand() { | ||
| const cmd = new Command("logout"); | ||
| cmd.description("Clear stored credentials from the active config"); | ||
| cmd.action(async (_opts, actionCmd) => { | ||
| const rootOpts = actionCmd.optsWithGlobals(); | ||
| const profileFlag = typeof rootOpts["profile"] === "string" ? rootOpts["profile"] : undefined; | ||
| const { raw } = await loadConfigFile({ profile: profileFlag }); | ||
| const { config } = validateConfig(raw); | ||
| if (config.oauth === undefined) { | ||
| throw new Error('No OAuth credentials configured. Run "linkedctl auth setup" to configure credentials, ' + | ||
| 'or "linkedctl auth login" to authenticate.'); | ||
| } | ||
| await clearOAuthTokens({ profile: profileFlag }); | ||
| const label = profileFlag ?? "default"; | ||
| console.log(`Credentials cleared for profile "${label}".`); | ||
| }); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=logout.js.map |
| {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../../src/commands/auth/logout.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnF,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,GAAG,CAAC,WAAW,CAAC,iDAAiD,CAAC,CAAC;IAEnE,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,KAA8B,EAAE,SAAkB,EAAE,EAAE;QACtE,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,EAAE,CAAC;QAC7C,MAAM,WAAW,GAAG,OAAO,QAAQ,CAAC,SAAS,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAE9F,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,cAAc,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QAC/D,MAAM,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAEvC,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CACb,wFAAwF;gBACtF,4CAA4C,CAC/C,CAAC;QACJ,CAAC;QAED,MAAM,gBAAgB,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QACjD,MAAM,KAAK,GAAG,WAAW,IAAI,SAAS,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,oCAAoC,KAAK,IAAI,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"} |
| import { Command } from "commander"; | ||
| export declare function refreshCommand(): Command; | ||
| //# sourceMappingURL=refresh.d.ts.map |
| {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/refresh.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,wBAAgB,cAAc,IAAI,OAAO,CA6DxC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { Command } from "commander"; | ||
| import { loadConfigFile, validateConfig, saveOAuthTokens, saveOAuthClientCredentials, refreshAccessToken, } from "@linkedctl/core"; | ||
| export function refreshCommand() { | ||
| const cmd = new Command("refresh"); | ||
| cmd.description("Refresh the access token using a stored refresh token"); | ||
| cmd.action(async (_opts, actionCmd) => { | ||
| const rootOpts = actionCmd.optsWithGlobals(); | ||
| const profileFlag = typeof rootOpts["profile"] === "string" ? rootOpts["profile"] : undefined; | ||
| const { raw } = await loadConfigFile({ profile: profileFlag }); | ||
| const { config } = validateConfig(raw); | ||
| const clientId = config.oauth?.clientId; | ||
| const clientSecret = config.oauth?.clientSecret; | ||
| if (clientId === undefined || clientSecret === undefined) { | ||
| throw new Error("Missing OAuth2 credentials in config. " + | ||
| 'Run "linkedctl auth login --client-id <id> --client-secret <secret>" first.'); | ||
| } | ||
| const existingRefreshToken = config.oauth?.refreshToken; | ||
| if (existingRefreshToken === undefined) { | ||
| throw new Error("No refresh token available. " + | ||
| "Refresh tokens are only available for approved LinkedIn Marketing Developer Platform (MDP) partners. " + | ||
| 'Run "linkedctl auth login" to re-authenticate.'); | ||
| } | ||
| const oauth2Config = { | ||
| clientId, | ||
| clientSecret, | ||
| redirectUri: "", | ||
| scope: "", | ||
| }; | ||
| const writeOpts = { profile: profileFlag }; | ||
| try { | ||
| const tokens = await refreshAccessToken(oauth2Config, existingRefreshToken); | ||
| const expiry = new Date(Date.now() + tokens.expiresIn * 1000).toISOString(); | ||
| await saveOAuthTokens({ | ||
| accessToken: tokens.accessToken, | ||
| refreshToken: tokens.refreshToken ?? existingRefreshToken, | ||
| tokenExpiresAt: expiry, | ||
| }, writeOpts); | ||
| await saveOAuthClientCredentials({ clientId, clientSecret }, writeOpts); | ||
| const label = profileFlag ?? "default"; | ||
| console.log(`Token refreshed for profile "${label}".`); | ||
| } | ||
| catch (error) { | ||
| const message = error instanceof Error ? error.message : String(error); | ||
| throw new Error(`Token refresh failed: ${message}. ` + 'Run "linkedctl auth login" to re-authenticate.'); | ||
| } | ||
| }); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=refresh.js.map |
| {"version":3,"file":"refresh.js","sourceRoot":"","sources":["../../../src/commands/auth/refresh.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,cAAc,EACd,cAAc,EACd,eAAe,EACf,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AAGzB,MAAM,UAAU,cAAc;IAC5B,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;IACnC,GAAG,CAAC,WAAW,CAAC,uDAAuD,CAAC,CAAC;IAEzE,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,KAA8B,EAAE,SAAkB,EAAE,EAAE;QACtE,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,EAAE,CAAC;QAC7C,MAAM,WAAW,GAAG,OAAO,QAAQ,CAAC,SAAS,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAE9F,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,cAAc,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QAC/D,MAAM,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAEvC,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC;QACxC,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,EAAE,YAAY,CAAC;QAEhD,IAAI,QAAQ,KAAK,SAAS,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YACzD,MAAM,IAAI,KAAK,CACb,wCAAwC;gBACtC,6EAA6E,CAChF,CAAC;QACJ,CAAC;QAED,MAAM,oBAAoB,GAAG,MAAM,CAAC,KAAK,EAAE,YAAY,CAAC;QAExD,IAAI,oBAAoB,KAAK,SAAS,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CACb,8BAA8B;gBAC5B,uGAAuG;gBACvG,gDAAgD,CACnD,CAAC;QACJ,CAAC;QAED,MAAM,YAAY,GAAiB;YACjC,QAAQ;YACR,YAAY;YACZ,WAAW,EAAE,EAAE;YACf,KAAK,EAAE,EAAE;SACV,CAAC;QAEF,MAAM,SAAS,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;QAE3C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,YAAY,EAAE,oBAAoB,CAAC,CAAC;YAC5E,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;YAC5E,MAAM,eAAe,CACnB;gBACE,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,oBAAoB;gBACzD,cAAc,EAAE,MAAM;aACvB,EACD,SAAS,CACV,CAAC;YACF,MAAM,0BAA0B,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,SAAS,CAAC,CAAC;YACxE,MAAM,KAAK,GAAG,WAAW,IAAI,SAAS,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,gCAAgC,KAAK,IAAI,CAAC,CAAC;QACzD,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,MAAM,IAAI,KAAK,CAAC,yBAAyB,OAAO,IAAI,GAAG,gDAAgD,CAAC,CAAC;QAC3G,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"} |
| import { Command } from "commander"; | ||
| export declare function revokeCommand(): Command; | ||
| //# sourceMappingURL=revoke.d.ts.map |
| {"version":3,"file":"revoke.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/revoke.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,wBAAgB,aAAa,IAAI,OAAO,CAsCvC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { Command } from "commander"; | ||
| import { loadConfigFile, validateConfig, clearOAuthTokens, revokeAccessToken } from "@linkedctl/core"; | ||
| export function revokeCommand() { | ||
| const cmd = new Command("revoke"); | ||
| cmd.description("Revoke the access token server-side and clear local credentials"); | ||
| cmd.action(async (_opts, actionCmd) => { | ||
| const rootOpts = actionCmd.optsWithGlobals(); | ||
| const profileFlag = typeof rootOpts["profile"] === "string" ? rootOpts["profile"] : undefined; | ||
| const { raw } = await loadConfigFile({ profile: profileFlag }); | ||
| const { config } = validateConfig(raw); | ||
| const accessToken = config.oauth?.accessToken; | ||
| const clientId = config.oauth?.clientId; | ||
| const clientSecret = config.oauth?.clientSecret; | ||
| const label = profileFlag ?? "default"; | ||
| if (accessToken === undefined || accessToken === "" || clientId === undefined || clientSecret === undefined) { | ||
| await clearOAuthTokens({ profile: profileFlag }); | ||
| console.log(`No complete credentials for server-side revocation (missing access token, client ID, or client secret). Local credentials cleared for profile "${label}".`); | ||
| return; | ||
| } | ||
| try { | ||
| await revokeAccessToken(clientId, clientSecret, accessToken); | ||
| console.log(`Access token revoked server-side for profile "${label}".`); | ||
| } | ||
| catch (error) { | ||
| const message = error instanceof Error ? error.message : String(error); | ||
| console.warn(`Warning: Server-side revocation failed: ${message}`); | ||
| console.warn("Local credentials will still be cleared."); | ||
| } | ||
| await clearOAuthTokens({ profile: profileFlag }); | ||
| console.log(`Local credentials cleared for profile "${label}".`); | ||
| }); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=revoke.js.map |
| {"version":3,"file":"revoke.js","sourceRoot":"","sources":["../../../src/commands/auth/revoke.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEtG,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,GAAG,CAAC,WAAW,CAAC,iEAAiE,CAAC,CAAC;IAEnF,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,KAA8B,EAAE,SAAkB,EAAE,EAAE;QACtE,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,EAAE,CAAC;QAC7C,MAAM,WAAW,GAAG,OAAO,QAAQ,CAAC,SAAS,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAE9F,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,cAAc,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QAC/D,MAAM,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAEvC,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC;QAC9C,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC;QACxC,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,EAAE,YAAY,CAAC;QAChD,MAAM,KAAK,GAAG,WAAW,IAAI,SAAS,CAAC;QAEvC,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,EAAE,IAAI,QAAQ,KAAK,SAAS,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC5G,MAAM,gBAAgB,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;YACjD,OAAO,CAAC,GAAG,CACT,kJAAkJ,KAAK,IAAI,CAC5J,CAAC;YACF,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,iBAAiB,CAAC,QAAQ,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;YAC7D,OAAO,CAAC,GAAG,CAAC,iDAAiD,KAAK,IAAI,CAAC,CAAC;QAC1E,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO,CAAC,IAAI,CAAC,2CAA2C,OAAO,EAAE,CAAC,CAAC;YACnE,OAAO,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,gBAAgB,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,0CAA0C,KAAK,IAAI,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"} |
| import { Command } from "commander"; | ||
| export declare function setupCommand(): Command; | ||
| //# sourceMappingURL=setup.d.ts.map |
| {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/setup.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,wBAAgB,YAAY,IAAI,OAAO,CA8HtC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { copyFile } from "node:fs/promises"; | ||
| import { dirname, join } from "node:path"; | ||
| import { homedir } from "node:os"; | ||
| import { fileURLToPath } from "node:url"; | ||
| import { createInterface } from "node:readline/promises"; | ||
| import { Command } from "commander"; | ||
| import { saveOAuthClientCredentials, saveOAuthScope, saveOAuthPkce, saveApiVersion, DEFAULT_API_VERSION, } from "@linkedctl/core"; | ||
| import { DEFAULT_REDIRECT_PORT } from "./login.js"; | ||
| export function setupCommand() { | ||
| const cmd = new Command("setup"); | ||
| cmd.description("Configure OAuth client credentials interactively"); | ||
| cmd.addHelpText("after", "\nLinkedIn Developer Portal: https://www.linkedin.com/developers/apps"); | ||
| cmd.action(async () => { | ||
| const program = cmd.parent?.parent; | ||
| // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment | ||
| const profileFlag = program?.opts()["profile"]; | ||
| const rl = createInterface({ input: process.stdin, output: process.stderr }); | ||
| // Offer to save logo to ~/Downloads for easy upload during app registration | ||
| const logoSource = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "..", "assets", "logo.png"); | ||
| const logoDestination = join(homedir(), "Downloads", "linkedctl-logo.png"); | ||
| let logoSaved = false; | ||
| const saveLogo = await rl.question("Save LinkedCtl logo to ~/Downloads for app registration? [y/N] "); | ||
| if (saveLogo.trim().toLowerCase() === "y" || saveLogo.trim().toLowerCase() === "yes") { | ||
| try { | ||
| await copyFile(logoSource, logoDestination); | ||
| logoSaved = true; | ||
| } | ||
| catch { | ||
| process.stderr.write(" Could not save logo (file not available).\n"); | ||
| } | ||
| } | ||
| process.stderr.write("\n"); | ||
| process.stderr.write("To use OAuth authentication, you need a LinkedIn OAuth application.\n"); | ||
| process.stderr.write("\n"); | ||
| process.stderr.write('1. Go to https://www.linkedin.com/developers/apps and click "Create app"\n'); | ||
| process.stderr.write("2. Fill in the app details:\n"); | ||
| process.stderr.write(' - App name: "LinkedCtl - <your name>"\n'); | ||
| process.stderr.write(" - LinkedIn Page: select your company page (or personal default page)\n"); | ||
| if (logoSaved) { | ||
| process.stderr.write(` - App logo: use the file saved to ${logoDestination}\n`); | ||
| } | ||
| else { | ||
| process.stderr.write(" - App logo: use the LinkedCtl logo from the repository (square, >= 100px)\n"); | ||
| } | ||
| process.stderr.write('3. Under the "Auth" tab, note your Client ID and Primary Client Secret\n'); | ||
| process.stderr.write(`4. Add a redirect URL: http://127.0.0.1:${DEFAULT_REDIRECT_PORT}/callback\n`); | ||
| process.stderr.write('5. Under "Products", request access to the products you need\n'); | ||
| process.stderr.write(" (e.g. Share on LinkedIn, Sign In with LinkedIn using OpenID Connect)\n"); | ||
| process.stderr.write("6. Copy the Client ID and Client Secret below\n"); | ||
| process.stderr.write("\n"); | ||
| try { | ||
| const clientId = await rl.question("Client ID: "); | ||
| if (clientId.trim() === "") { | ||
| throw new Error("Client ID cannot be empty. " + | ||
| 'Find your Client ID in the "Auth" tab of your app at https://www.linkedin.com/developers/apps'); | ||
| } | ||
| const clientSecret = await rl.question("Client Secret: "); | ||
| if (clientSecret.trim() === "") { | ||
| throw new Error("Client Secret cannot be empty. " + | ||
| 'Find your Client Secret in the "Auth" tab of your app at https://www.linkedin.com/developers/apps'); | ||
| } | ||
| const writeOpts = profileFlag !== undefined ? { profile: profileFlag } : undefined; | ||
| await saveOAuthClientCredentials({ clientId: clientId.trim(), clientSecret: clientSecret.trim() }, writeOpts); | ||
| process.stderr.write("\n"); | ||
| process.stderr.write("Which LinkedIn products have you enabled for this app?\n"); | ||
| process.stderr.write("\n"); | ||
| const scopes = []; | ||
| const signIn = await rl.question("Sign In with LinkedIn using OpenID Connect? [y/N] "); | ||
| if (signIn.trim().toLowerCase() === "y" || signIn.trim().toLowerCase() === "yes") { | ||
| scopes.push("openid", "profile", "email"); | ||
| } | ||
| const share = await rl.question("Share on LinkedIn? [y/N] "); | ||
| if (share.trim().toLowerCase() === "y" || share.trim().toLowerCase() === "yes") { | ||
| scopes.push("w_member_social"); | ||
| // Posting requires the author's person URN, which is only available via | ||
| // the /v2/userinfo endpoint. That endpoint needs openid scopes, so we | ||
| // force-enable them when Share on LinkedIn is selected. | ||
| if (!scopes.includes("openid")) { | ||
| scopes.push("openid", "profile", "email"); | ||
| process.stderr.write(' → Also enabling "Sign In with LinkedIn" scopes (required to resolve author identity for posts)\n'); | ||
| } | ||
| } | ||
| if (scopes.length === 0) { | ||
| throw new Error("At least one LinkedIn product must be enabled for OAuth to work. " + | ||
| 'Enable products under the "Products" tab of your app at https://www.linkedin.com/developers/apps ' + | ||
| "and then re-run this setup."); | ||
| } | ||
| const scope = [...new Set(scopes)].join(" "); | ||
| await saveOAuthScope(scope, writeOpts); | ||
| process.stderr.write("\n"); | ||
| process.stderr.write("PKCE (Proof Key for Code Exchange) improves security for native OAuth apps.\n"); | ||
| process.stderr.write("LinkedIn requires PKCE to be enabled for your app by LinkedIn support.\n"); | ||
| const pkceAnswer = await rl.question("Is PKCE enabled for your app? [y/N] "); | ||
| const pkce = pkceAnswer.trim().toLowerCase() === "y" || pkceAnswer.trim().toLowerCase() === "yes"; | ||
| await saveOAuthPkce(pkce, writeOpts); | ||
| await saveApiVersion(DEFAULT_API_VERSION, writeOpts); | ||
| if (profileFlag !== undefined) { | ||
| process.stderr.write(`\nOAuth client credentials and scope saved to profile "${profileFlag}".\n`); | ||
| } | ||
| else { | ||
| process.stderr.write("\nOAuth client credentials and scope saved.\n"); | ||
| } | ||
| process.stderr.write(`Scope: ${scope}\n`); | ||
| if (pkce) { | ||
| process.stderr.write("PKCE: enabled\n"); | ||
| } | ||
| process.stderr.write('Run "linkedctl auth login" to authenticate.\n'); | ||
| } | ||
| finally { | ||
| rl.close(); | ||
| } | ||
| }); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=setup.js.map |
| {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/commands/auth/setup.ts"],"names":[],"mappings":"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"} |
| import { Command } from "commander"; | ||
| export declare function statusCommand(): Command; | ||
| //# sourceMappingURL=status.d.ts.map |
| {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/status.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuBpC,wBAAgB,aAAa,IAAI,OAAO,CA0CvC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { Command } from "commander"; | ||
| import { loadConfigFile, validateConfig, getTokenExpiry } from "@linkedctl/core"; | ||
| /** | ||
| * Format remaining time until token expiry as a human-readable string. | ||
| */ | ||
| function formatTimeRemaining(expiresAt) { | ||
| const diffMs = expiresAt.getTime() - Date.now(); | ||
| const totalMinutes = Math.floor(diffMs / 60_000); | ||
| const totalHours = Math.floor(totalMinutes / 60); | ||
| const days = Math.floor(totalHours / 24); | ||
| const hours = totalHours % 24; | ||
| if (days > 0) { | ||
| return hours > 0 ? `${String(days)}d ${String(hours)}h` : `${String(days)}d`; | ||
| } | ||
| if (totalHours > 0) { | ||
| const minutes = totalMinutes % 60; | ||
| return minutes > 0 ? `${String(totalHours)}h ${String(minutes)}m` : `${String(totalHours)}h`; | ||
| } | ||
| return `${String(totalMinutes)}m`; | ||
| } | ||
| export function statusCommand() { | ||
| const cmd = new Command("status"); | ||
| cmd.description("Show authentication status for the active profile"); | ||
| cmd.action(async (_opts, actionCmd) => { | ||
| const rootOpts = actionCmd.optsWithGlobals(); | ||
| const profileFlag = typeof rootOpts["profile"] === "string" ? rootOpts["profile"] : undefined; | ||
| const { raw } = await loadConfigFile({ profile: profileFlag }); | ||
| const { config } = validateConfig(raw); | ||
| const label = profileFlag ?? "default"; | ||
| if (config.oauth?.accessToken === undefined || config.oauth.accessToken === "") { | ||
| console.log(`Profile: ${label}`); | ||
| console.log("Status: not configured"); | ||
| console.error('Run "linkedctl auth login" to set up authentication.'); | ||
| return; | ||
| } | ||
| const expiry = getTokenExpiry(config.oauth.accessToken); | ||
| console.log(`Profile: ${label}`); | ||
| if (expiry === undefined) { | ||
| console.log("Status: authenticated"); | ||
| console.log("Expiry: unknown (token is not a JWT)"); | ||
| return; | ||
| } | ||
| if (expiry.isExpired) { | ||
| console.log("Status: expired"); | ||
| console.log(`Expired: ${expiry.expiresAt.toISOString()}`); | ||
| console.error('Run "linkedctl auth login" to re-authenticate.'); | ||
| return; | ||
| } | ||
| const remaining = formatTimeRemaining(expiry.expiresAt); | ||
| console.log("Status: authenticated"); | ||
| console.log(`Expires: ${expiry.expiresAt.toISOString()} (${remaining} remaining)`); | ||
| }); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=status.js.map |
| {"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/commands/auth/status.ts"],"names":[],"mappings":"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"} |
| import { Command } from "commander"; | ||
| export declare function tokenCommand(): Command; | ||
| //# sourceMappingURL=token.d.ts.map |
| {"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/token.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,wBAAgB,YAAY,IAAI,OAAO,CAetC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { Command } from "commander"; | ||
| import { saveOAuthTokens } from "@linkedctl/core"; | ||
| export function tokenCommand() { | ||
| const cmd = new Command("token"); | ||
| cmd.description("Store a direct access token in the active profile"); | ||
| cmd.requiredOption("--access-token <token>", "access token to store"); | ||
| cmd.action(async (_opts, command) => { | ||
| const globals = command.optsWithGlobals(); | ||
| const profileFlag = globals.profile; | ||
| await saveOAuthTokens({ accessToken: globals.accessToken }, { profile: profileFlag }); | ||
| const label = profileFlag ?? "default"; | ||
| console.log(`Access token stored in profile "${label}".`); | ||
| }); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=token.js.map |
| {"version":3,"file":"token.js","sourceRoot":"","sources":["../../../src/commands/auth/token.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,UAAU,YAAY;IAC1B,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACjC,GAAG,CAAC,WAAW,CAAC,mDAAmD,CAAC,CAAC;IACrE,GAAG,CAAC,cAAc,CAAC,wBAAwB,EAAE,uBAAuB,CAAC,CAAC;IAEtE,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,KAA8B,EAAE,OAAgB,EAAE,EAAE;QACpE,MAAM,OAAO,GAAG,OAAO,CAAC,eAAe,EAAyD,CAAC;QACjG,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;QAEpC,MAAM,eAAe,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;QACtF,MAAM,KAAK,GAAG,WAAW,IAAI,SAAS,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,mCAAmC,KAAK,IAAI,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"} |
| import { Command } from "commander"; | ||
| export declare function completionCommand(program: Command): Command; | ||
| //# sourceMappingURL=completion.d.ts.map |
| {"version":3,"file":"completion.d.ts","sourceRoot":"","sources":["../../src/commands/completion.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6MpC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAiC3D"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { Command } from "commander"; | ||
| function collectCommands(cmd, prefix) { | ||
| const result = []; | ||
| const name = prefix ? `${prefix} ${cmd.name()}` : cmd.name(); | ||
| const subcommands = cmd.commands.map((c) => c.name()); | ||
| const options = cmd.options.map((o) => o.long).filter((o) => o !== undefined); | ||
| result.push({ name, subcommands, options }); | ||
| for (const sub of cmd.commands) { | ||
| result.push(...collectCommands(sub, name)); | ||
| } | ||
| return result; | ||
| } | ||
| function generateBash(program) { | ||
| const commands = collectCommands(program, ""); | ||
| const rootName = program.name(); | ||
| const d = "$"; | ||
| const cases = commands | ||
| .map((cmd) => { | ||
| const words = [...cmd.subcommands, ...cmd.options].join(" "); | ||
| const pattern = cmd.name === rootName ? rootName : cmd.name.replace(`${rootName} `, "").replace(/ /g, "__"); | ||
| return ` ${pattern})\n COMPREPLY=(${d}(compgen -W "${words}" -- "${d}{cur}"))\n return 0\n ;;`; | ||
| }) | ||
| .join("\n"); | ||
| const cmdLookup = commands | ||
| .filter((cmd) => cmd.name !== rootName) | ||
| .map((cmd) => { | ||
| const parts = cmd.name.replace(`${rootName} `, "").split(" "); | ||
| return ` ${parts.join("__")}) cmd="${parts.join("__")}" ;;`; | ||
| }) | ||
| .join("\n"); | ||
| return `# bash completion for ${rootName} | ||
| # eval "${d}(${rootName} completion bash)" | ||
| _${rootName}_completions() { | ||
| local cur prev words cword cmd | ||
| _init_completion || return | ||
| cmd="${rootName}" | ||
| for ((i=1; i < cword; i++)); do | ||
| case "${d}{words[i]}" in | ||
| -*) ;; | ||
| *) | ||
| local subcmd | ||
| if [ "${d}{cmd}" = "${rootName}" ]; then | ||
| subcmd="${d}{words[i]}" | ||
| else | ||
| subcmd="${d}{cmd}__${d}{words[i]}" | ||
| fi | ||
| case "${d}{subcmd}" in | ||
| ${cmdLookup} | ||
| *) ;; | ||
| esac | ||
| ;; | ||
| esac | ||
| done | ||
| case "${d}{cmd}" in | ||
| ${cases} | ||
| esac | ||
| } | ||
| complete -F _${rootName}_completions ${rootName} | ||
| `; | ||
| } | ||
| function generateZsh(program) { | ||
| const commands = collectCommands(program, ""); | ||
| const rootName = program.name(); | ||
| const d = "$"; | ||
| const helperPrefix = `__${rootName}`; | ||
| const functions = []; | ||
| for (const cmd of commands) { | ||
| const fnName = cmd.name.replace(/ /g, "_"); | ||
| const optionArgs = cmd.options.map((opt) => `'${opt}[option]'`); | ||
| if (cmd.subcommands.length > 0) { | ||
| const subcmds = cmd.subcommands.map((s) => `'${s}:${s} command'`); | ||
| functions.push(`${helperPrefix}_${fnName}() { | ||
| local -a commands options | ||
| commands=(${subcmds.join(" ")}) | ||
| options=(${optionArgs.join(" ")}) | ||
| _describe -t commands 'commands' commands | ||
| _describe -t options 'options' options | ||
| }`); | ||
| } | ||
| else if (optionArgs.length > 0) { | ||
| functions.push(`${helperPrefix}_${fnName}() { | ||
| local -a options | ||
| options=(${optionArgs.join(" ")}) | ||
| _describe -t options 'options' options | ||
| }`); | ||
| } | ||
| } | ||
| // Build routing cases for root subcommands | ||
| const rootCmd = commands.find((c) => c.name === rootName); | ||
| const rootSubcases = (rootCmd?.subcommands ?? []) | ||
| .map((sub) => { | ||
| const childCmd = commands.find((c) => c.name === `${rootName} ${sub}`); | ||
| if (!childCmd || (childCmd.subcommands.length === 0 && childCmd.options.length === 0)) | ||
| return null; | ||
| const childSubcases = childCmd.subcommands | ||
| .map((subsub) => { | ||
| const leafFn = `${rootName}_${sub}_${subsub}`; | ||
| const exists = functions.some((f) => f.includes(`${helperPrefix}_${leafFn}()`)); | ||
| return exists ? ` ${subsub}) ${helperPrefix}_${leafFn} ;;` : null; | ||
| }) | ||
| .filter(Boolean) | ||
| .join("\n"); | ||
| if (childCmd.subcommands.length > 0 && childSubcases) { | ||
| return ` ${sub}) | ||
| if (( CURRENT == 2 )); then | ||
| ${helperPrefix}_${rootName}_${sub} | ||
| else | ||
| case "${d}{line[2]}" in | ||
| ${childSubcases} | ||
| esac | ||
| fi | ||
| ;;`; | ||
| } | ||
| return ` ${sub}) ${helperPrefix}_${rootName}_${sub} ;;`; | ||
| }) | ||
| .filter(Boolean) | ||
| .join("\n"); | ||
| return `#compdef ${rootName} | ||
| # eval "${d}(${rootName} completion zsh)" | ||
| ${functions.join("\n\n")} | ||
| _${rootName}() { | ||
| local curcontext="${d}curcontext" state line | ||
| typeset -A opt_args | ||
| _arguments -C \\ | ||
| '1:command:->command' \\ | ||
| '*::arg:->args' | ||
| case "${d}state" in | ||
| command) | ||
| ${helperPrefix}_${rootName} | ||
| ;; | ||
| args) | ||
| case "${d}{line[1]}" in | ||
| ${rootSubcases} | ||
| esac | ||
| ;; | ||
| esac | ||
| } | ||
| _${rootName} "${d}@" | ||
| `; | ||
| } | ||
| function generateFish(program) { | ||
| const commands = collectCommands(program, ""); | ||
| const rootName = program.name(); | ||
| const lines = [`# fish completion for ${rootName}`, `# ${rootName} completion fish | source`]; | ||
| for (const cmd of commands) { | ||
| const parts = cmd.name.split(" "); | ||
| if (cmd.name === rootName) { | ||
| for (const sub of cmd.subcommands) { | ||
| lines.push(`complete -c ${rootName} -n "__fish_use_subcommand" -a "${sub}" -d "${sub} command"`); | ||
| } | ||
| for (const opt of cmd.options) { | ||
| const longFlag = opt.replace(/^--/, ""); | ||
| lines.push(`complete -c ${rootName} -n "__fish_use_subcommand" -l "${longFlag}"`); | ||
| } | ||
| } | ||
| else { | ||
| const parentArgs = parts.slice(1); | ||
| const condition = parentArgs.length === 1 | ||
| ? `__fish_seen_subcommand_from ${parentArgs[0]}` | ||
| : parentArgs.map((a) => `__fish_seen_subcommand_from ${a}`).join("; and "); | ||
| for (const sub of cmd.subcommands) { | ||
| lines.push(`complete -c ${rootName} -n "${condition}" -a "${sub}" -d "${sub} command"`); | ||
| } | ||
| for (const opt of cmd.options) { | ||
| const longFlag = opt.replace(/^--/, ""); | ||
| lines.push(`complete -c ${rootName} -n "${condition}" -l "${longFlag}"`); | ||
| } | ||
| } | ||
| } | ||
| return lines.join("\n") + "\n"; | ||
| } | ||
| export function completionCommand(program) { | ||
| const cmd = new Command("completion"); | ||
| cmd.description("Generate shell completion scripts"); | ||
| cmd.argument("<shell>", "shell type (bash, zsh, fish)"); | ||
| cmd.addHelpText("after", ` | ||
| Examples: | ||
| eval "$(linkedctl completion bash)" | ||
| linkedctl completion zsh > ~/.zsh/completions/_linkedctl | ||
| linkedctl completion fish | source`); | ||
| cmd.action((shell) => { | ||
| switch (shell) { | ||
| case "bash": | ||
| process.stdout.write(generateBash(program)); | ||
| break; | ||
| case "zsh": | ||
| process.stdout.write(generateZsh(program)); | ||
| break; | ||
| case "fish": | ||
| process.stdout.write(generateFish(program)); | ||
| break; | ||
| default: | ||
| console.error(`Unsupported shell: ${shell}. Supported shells: bash, zsh, fish`); | ||
| process.exitCode = 1; | ||
| break; | ||
| } | ||
| }); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=completion.js.map |
| {"version":3,"file":"completion.js","sourceRoot":"","sources":["../../src/commands/completion.ts"],"names":[],"mappings":"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"} |
| import { Command } from "commander"; | ||
| interface CreateOpts { | ||
| text?: string | undefined; | ||
| visibility?: string | undefined; | ||
| format?: string | undefined; | ||
| } | ||
| /** | ||
| * Shared action handler for creating a text post. | ||
| */ | ||
| export declare function createPostAction(textArg: string | undefined, opts: CreateOpts, cmd: Command): Promise<void>; | ||
| export declare function createCommand(): Command; | ||
| export {}; | ||
| //# sourceMappingURL=create.d.ts.map |
| {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/post/create.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAO5C,UAAU,UAAU;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AA0BD;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAiCjH;AAED,wBAAgB,aAAa,IAAI,OAAO,CAiBvC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { Command, Option } from "commander"; | ||
| import { resolveConfig, LinkedInClient, getCurrentPersonUrn, createTextPost, LinkedInApiError } from "@linkedctl/core"; | ||
| import { resolveFormat, formatOutput } from "../../output/index.js"; | ||
| import { readStdin } from "./stdin.js"; | ||
| /** | ||
| * Resolve the post text from --text option, positional argument, or stdin. | ||
| * | ||
| * Precedence: --text > positional argument > stdin. | ||
| */ | ||
| async function resolveText(textOpt, textArg) { | ||
| if (textOpt !== undefined && textOpt !== "") { | ||
| return textOpt; | ||
| } | ||
| if (textArg !== undefined && textArg !== "") { | ||
| return textArg; | ||
| } | ||
| if (!process.stdin.isTTY) { | ||
| const stdin = await readStdin(); | ||
| if (stdin !== "") { | ||
| return stdin; | ||
| } | ||
| } | ||
| throw new Error('No text provided. Use --text "message", pass text as an argument, or pipe text via stdin.'); | ||
| } | ||
| /** | ||
| * Shared action handler for creating a text post. | ||
| */ | ||
| export async function createPostAction(textArg, opts, cmd) { | ||
| const text = await resolveText(opts.text, textArg); | ||
| const globals = cmd.optsWithGlobals(); | ||
| const { config } = await resolveConfig({ | ||
| profile: globals.profile, | ||
| requiredScopes: ["openid", "profile", "email", "w_member_social"], | ||
| }); | ||
| // resolveConfig guarantees oauth.accessToken and apiVersion are defined | ||
| const accessToken = config.oauth?.accessToken ?? ""; | ||
| const apiVersion = config.apiVersion ?? ""; | ||
| const client = new LinkedInClient({ accessToken, apiVersion }); | ||
| const authorUrn = await getCurrentPersonUrn(client); | ||
| const visibility = opts.visibility ?? "PUBLIC"; | ||
| try { | ||
| const postUrn = await createTextPost(client, { | ||
| author: authorUrn, | ||
| text, | ||
| visibility, | ||
| }); | ||
| const format = resolveFormat(opts.format, process.stdout); | ||
| const output = formatOutput({ urn: postUrn }, format); | ||
| console.log(output); | ||
| } | ||
| catch (error) { | ||
| if (error instanceof LinkedInApiError) { | ||
| throw new Error(`Failed to create post: ${error.message}`); | ||
| } | ||
| throw error; | ||
| } | ||
| } | ||
| export function createCommand() { | ||
| const cmd = new Command("create"); | ||
| cmd.description("Create a text post on LinkedIn (text: --text > positional > stdin)"); | ||
| cmd.argument("[text]", "text content of the post"); | ||
| cmd.option("--text <text>", "text content of the post (takes precedence over positional argument)"); | ||
| cmd.addOption(new Option("--visibility <visibility>", "post visibility (PUBLIC or CONNECTIONS)") | ||
| .choices(["PUBLIC", "CONNECTIONS"]) | ||
| .default("PUBLIC")); | ||
| cmd.addOption(new Option("--format <format>", "output format (json or table)").choices(["json", "table"])); | ||
| cmd.action(async (text, opts, actionCmd) => { | ||
| await createPostAction(text, opts, actionCmd); | ||
| }); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=create.js.map |
| {"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/commands/post/create.ts"],"names":[],"mappings":"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"} |
| import { Command } from "commander"; | ||
| export declare function postCommand(): Command; | ||
| //# sourceMappingURL=index.d.ts.map |
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/post/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAG5C,wBAAgB,WAAW,IAAI,OAAO,CAsBrC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { Command, Option } from "commander"; | ||
| import { createCommand, createPostAction } from "./create.js"; | ||
| export function postCommand() { | ||
| const cmd = new Command("post"); | ||
| cmd.description("Manage LinkedIn posts"); | ||
| cmd.enablePositionalOptions(); | ||
| cmd.argument("[text]", "shorthand: create a post with the given text (text > stdin)"); | ||
| cmd.option("--text <text>", "text content of the post (takes precedence over positional argument)"); | ||
| cmd.addOption(new Option("--visibility <visibility>", "post visibility (PUBLIC or CONNECTIONS)") | ||
| .choices(["PUBLIC", "CONNECTIONS"]) | ||
| .default("PUBLIC")); | ||
| cmd.addOption(new Option("--format <format>", "output format (json or table)").choices(["json", "table"])); | ||
| cmd.action(async (text, opts, actionCmd) => { | ||
| await createPostAction(text, opts, actionCmd); | ||
| }); | ||
| cmd.addCommand(createCommand()); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/post/index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE9D,MAAM,UAAU,WAAW;IACzB,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,GAAG,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC;IAEzC,GAAG,CAAC,uBAAuB,EAAE,CAAC;IAE9B,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,6DAA6D,CAAC,CAAC;IACtF,GAAG,CAAC,MAAM,CAAC,eAAe,EAAE,sEAAsE,CAAC,CAAC;IACpG,GAAG,CAAC,SAAS,CACX,IAAI,MAAM,CAAC,2BAA2B,EAAE,yCAAyC,CAAC;SAC/E,OAAO,CAAC,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;SAClC,OAAO,CAAC,QAAQ,CAAC,CACrB,CAAC;IACF,GAAG,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,mBAAmB,EAAE,+BAA+B,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAE3G,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,IAAwB,EAAE,IAA6B,EAAE,SAAkB,EAAE,EAAE;QAC/F,MAAM,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;IAEhC,OAAO,GAAG,CAAC;AACb,CAAC"} |
| /** | ||
| * Read all available data from stdin and return it as a trimmed string. | ||
| */ | ||
| export declare function readStdin(): Promise<string>; | ||
| //# sourceMappingURL=stdin.d.ts.map |
| {"version":3,"file":"stdin.d.ts","sourceRoot":"","sources":["../../../src/commands/post/stdin.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAc3C"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| /** | ||
| * Read all available data from stdin and return it as a trimmed string. | ||
| */ | ||
| export function readStdin() { | ||
| return new Promise((resolve, reject) => { | ||
| const chunks = []; | ||
| process.stdin.on("data", (chunk) => { | ||
| chunks.push(chunk); | ||
| }); | ||
| process.stdin.on("end", () => { | ||
| resolve(Buffer.concat(chunks).toString("utf-8").trim()); | ||
| }); | ||
| process.stdin.on("error", reject); | ||
| }); | ||
| } | ||
| //# sourceMappingURL=stdin.js.map |
| {"version":3,"file":"stdin.js","sourceRoot":"","sources":["../../../src/commands/post/stdin.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC;;GAEG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAa,EAAE,CAAC;QAE5B,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACzC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YAC3B,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC"} |
| import { Command } from "commander"; | ||
| export declare function createCommand(): Command; | ||
| //# sourceMappingURL=create.d.ts.map |
| {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/commands/profile/create.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,wBAAgB,aAAa,IAAI,OAAO,CAgCvC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { join } from "node:path"; | ||
| import { homedir } from "node:os"; | ||
| import { writeFile, mkdir } from "node:fs/promises"; | ||
| import { Command } from "commander"; | ||
| import { loadConfigFile, isValidProfileName, saveOAuthTokens, CONFIG_DIR, DEFAULT_API_VERSION } from "@linkedctl/core"; | ||
| export function createCommand() { | ||
| const cmd = new Command("create"); | ||
| cmd.description("Create a new profile"); | ||
| cmd.argument("<name>", "profile name"); | ||
| cmd.requiredOption("--access-token <token>", "OAuth2 access token"); | ||
| cmd.option("--api-version <version>", "LinkedIn API version", DEFAULT_API_VERSION); | ||
| cmd.action(async (name, opts) => { | ||
| if (!isValidProfileName(name)) { | ||
| throw new Error(`Invalid profile name "${name}". Names must not contain path separators or be empty.`); | ||
| } | ||
| const { path } = await loadConfigFile({ profile: name }); | ||
| if (path !== undefined) { | ||
| throw new Error(`Profile "${name}" already exists. Delete it first or use a different name.`); | ||
| } | ||
| // Ensure the profile directory exists | ||
| const profileDir = join(homedir(), CONFIG_DIR); | ||
| await mkdir(profileDir, { recursive: true }); | ||
| // Write the initial config with api-version | ||
| const profilePath = join(profileDir, `${name}.yaml`); | ||
| await writeFile(profilePath, `api-version: "${opts.apiVersion}"\n`, { mode: 0o600 }); | ||
| // Save the access token (merges into existing file) | ||
| await saveOAuthTokens({ accessToken: opts.accessToken }, { profile: name }); | ||
| console.log(`Profile "${name}" created.`); | ||
| }); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=create.js.map |
| {"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/commands/profile/create.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,eAAe,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEvH,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,GAAG,CAAC,WAAW,CAAC,sBAAsB,CAAC,CAAC;IACxC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IACvC,GAAG,CAAC,cAAc,CAAC,wBAAwB,EAAE,qBAAqB,CAAC,CAAC;IACpE,GAAG,CAAC,MAAM,CAAC,yBAAyB,EAAE,sBAAsB,EAAE,mBAAmB,CAAC,CAAC;IAEnF,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,IAAiD,EAAE,EAAE;QACnF,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,wDAAwD,CAAC,CAAC;QACzG,CAAC;QAED,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,cAAc,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,4DAA4D,CAAC,CAAC;QAChG,CAAC;QAED,sCAAsC;QACtC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;QAC/C,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE7C,4CAA4C;QAC5C,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;QACrD,MAAM,SAAS,CAAC,WAAW,EAAE,iBAAiB,IAAI,CAAC,UAAU,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAErF,oDAAoD;QACpD,MAAM,eAAe,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAE5E,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,YAAY,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"} |
| import { Command } from "commander"; | ||
| export declare function deleteCommand(): Command; | ||
| //# sourceMappingURL=delete.d.ts.map |
| {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/commands/profile/delete.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,wBAAgB,aAAa,IAAI,OAAO,CAyBvC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { join } from "node:path"; | ||
| import { homedir } from "node:os"; | ||
| import { unlink } from "node:fs/promises"; | ||
| import { Command } from "commander"; | ||
| import { isValidProfileName, CONFIG_DIR } from "@linkedctl/core"; | ||
| export function deleteCommand() { | ||
| const cmd = new Command("delete"); | ||
| cmd.description("Delete a profile"); | ||
| cmd.argument("<name>", "profile name"); | ||
| cmd.action(async (name) => { | ||
| if (!isValidProfileName(name)) { | ||
| throw new Error(`Invalid profile name "${name}". Names must not contain path separators or be empty.`); | ||
| } | ||
| const profilePath = join(homedir(), CONFIG_DIR, `${name}.yaml`); | ||
| try { | ||
| await unlink(profilePath); | ||
| } | ||
| catch (error) { | ||
| if (error instanceof Error && "code" in error && error.code === "ENOENT") { | ||
| throw new Error(`Profile "${name}" not found. Run "linkedctl profile list" to see available profiles.`); | ||
| } | ||
| throw error; | ||
| } | ||
| console.log(`Profile "${name}" deleted.`); | ||
| }); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=delete.js.map |
| {"version":3,"file":"delete.js","sourceRoot":"","sources":["../../../src/commands/profile/delete.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEjE,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,GAAG,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC;IACpC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IAEvC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;QAChC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,wDAAwD,CAAC,CAAC;QACzG,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;QAEhE,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACpG,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,sEAAsE,CAAC,CAAC;YAC1G,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,YAAY,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"} |
| import { Command } from "commander"; | ||
| export declare function profileCommand(): Command; | ||
| //# sourceMappingURL=index.d.ts.map |
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/profile/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,cAAc,IAAI,OAAO,CAUxC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { Command } from "commander"; | ||
| import { createCommand } from "./create.js"; | ||
| import { listCommand } from "./list.js"; | ||
| import { showCommand } from "./show.js"; | ||
| import { deleteCommand } from "./delete.js"; | ||
| export function profileCommand() { | ||
| const cmd = new Command("profile"); | ||
| cmd.description("Manage configuration profiles"); | ||
| cmd.addCommand(createCommand()); | ||
| cmd.addCommand(listCommand()); | ||
| cmd.addCommand(showCommand()); | ||
| cmd.addCommand(deleteCommand()); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/profile/index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,UAAU,cAAc;IAC5B,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;IACnC,GAAG,CAAC,WAAW,CAAC,+BAA+B,CAAC,CAAC;IAEjD,GAAG,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;IAChC,GAAG,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;IAC9B,GAAG,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;IAC9B,GAAG,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;IAEhC,OAAO,GAAG,CAAC;AACb,CAAC"} |
| import { Command } from "commander"; | ||
| export declare function listCommand(): Command; | ||
| //# sourceMappingURL=list.d.ts.map |
| {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/profile/list.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,wBAAgB,WAAW,IAAI,OAAO,CA8BrC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { join } from "node:path"; | ||
| import { homedir } from "node:os"; | ||
| import { readdir } from "node:fs/promises"; | ||
| import { Command } from "commander"; | ||
| import { CONFIG_DIR } from "@linkedctl/core"; | ||
| export function listCommand() { | ||
| const cmd = new Command("list"); | ||
| cmd.description("List all profiles"); | ||
| cmd.action(async () => { | ||
| const profileDir = join(homedir(), CONFIG_DIR); | ||
| let entries; | ||
| try { | ||
| entries = await readdir(profileDir); | ||
| } | ||
| catch (error) { | ||
| if (error instanceof Error && "code" in error && error.code === "ENOENT") { | ||
| console.log("No profiles configured."); | ||
| return; | ||
| } | ||
| throw error; | ||
| } | ||
| const names = entries.filter((e) => e.endsWith(".yaml")).map((e) => e.replace(/\.yaml$/, "")); | ||
| if (names.length === 0) { | ||
| console.log("No profiles configured."); | ||
| return; | ||
| } | ||
| for (const name of names) { | ||
| console.log(name); | ||
| } | ||
| }); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=list.js.map |
| {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/commands/profile/list.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,UAAU,WAAW;IACzB,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,GAAG,CAAC,WAAW,CAAC,mBAAmB,CAAC,CAAC;IAErC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;QACpB,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;QAC/C,IAAI,OAAiB,CAAC;QACtB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACpG,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;gBACvC,OAAO;YACT,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;QAE9F,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;YACvC,OAAO;QACT,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"} |
| import { Command } from "commander"; | ||
| export declare function showCommand(): Command; | ||
| //# sourceMappingURL=show.d.ts.map |
| {"version":3,"file":"show.d.ts","sourceRoot":"","sources":["../../../src/commands/profile/show.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,wBAAgB,WAAW,IAAI,OAAO,CA2CrC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { Command } from "commander"; | ||
| import { loadConfigFile, validateConfig, isValidProfileName } from "@linkedctl/core"; | ||
| function redactSecret(value) { | ||
| if (value.length <= 8) { | ||
| return "****"; | ||
| } | ||
| return value.slice(0, 4) + "****" + value.slice(-4); | ||
| } | ||
| export function showCommand() { | ||
| const cmd = new Command("show"); | ||
| cmd.description("Show profile details (secrets redacted)"); | ||
| cmd.argument("<name>", "profile name"); | ||
| cmd.action(async (name) => { | ||
| if (!isValidProfileName(name)) { | ||
| throw new Error(`Invalid profile name "${name}". Names must not contain path separators or be empty.`); | ||
| } | ||
| const { raw, path } = await loadConfigFile({ profile: name }); | ||
| if (path === undefined) { | ||
| throw new Error(`Profile "${name}" not found. Run "linkedctl profile list" to see available profiles.`); | ||
| } | ||
| const { config } = validateConfig(raw); | ||
| console.log(`Profile: ${name}`); | ||
| if (config.oauth !== undefined) { | ||
| if (config.oauth.clientId !== undefined) { | ||
| console.log(` client-id: ${redactSecret(config.oauth.clientId)}`); | ||
| } | ||
| if (config.oauth.clientSecret !== undefined) { | ||
| console.log(` client-secret: ${redactSecret(config.oauth.clientSecret)}`); | ||
| } | ||
| if (config.oauth.accessToken !== undefined) { | ||
| console.log(` access-token: ${redactSecret(config.oauth.accessToken)}`); | ||
| } | ||
| if (config.oauth.refreshToken !== undefined) { | ||
| console.log(` refresh-token: ${redactSecret(config.oauth.refreshToken)}`); | ||
| } | ||
| if (config.oauth.tokenExpiresAt !== undefined) { | ||
| console.log(` token-expires-at: ${config.oauth.tokenExpiresAt}`); | ||
| } | ||
| } | ||
| if (config.apiVersion !== undefined) { | ||
| console.log(` api-version: ${config.apiVersion}`); | ||
| } | ||
| }); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=show.js.map |
| {"version":3,"file":"show.js","sourceRoot":"","sources":["../../../src/commands/profile/show.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErF,SAAS,YAAY,CAAC,KAAa;IACjC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,GAAG,CAAC,WAAW,CAAC,yCAAyC,CAAC,CAAC;IAC3D,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;IAEvC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;QAChC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,wDAAwD,CAAC,CAAC;QACzG,CAAC;QAED,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,MAAM,cAAc,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,YAAY,IAAI,sEAAsE,CAAC,CAAC;QAC1G,CAAC;QAED,MAAM,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAEvC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;QAEhC,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC/B,IAAI,MAAM,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBACxC,OAAO,CAAC,GAAG,CAAC,gBAAgB,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YACrE,CAAC;YACD,IAAI,MAAM,CAAC,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;gBAC5C,OAAO,CAAC,GAAG,CAAC,oBAAoB,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;YAC7E,CAAC;YACD,IAAI,MAAM,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;gBAC3C,OAAO,CAAC,GAAG,CAAC,mBAAmB,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YAC3E,CAAC;YACD,IAAI,MAAM,CAAC,KAAK,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;gBAC5C,OAAO,CAAC,GAAG,CAAC,oBAAoB,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;YAC7E,CAAC;YACD,IAAI,MAAM,CAAC,KAAK,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;gBAC9C,OAAO,CAAC,GAAG,CAAC,uBAAuB,MAAM,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC;YACpE,CAAC;QACH,CAAC;QAED,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"} |
| import { Command } from "commander"; | ||
| export declare function whoamiCommand(): Command; | ||
| //# sourceMappingURL=whoami.d.ts.map |
| {"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAK5C,wBAAgB,aAAa,IAAI,OAAO,CA6BvC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { Command, Option } from "commander"; | ||
| import { resolveConfig, LinkedInClient, getUserInfo } from "@linkedctl/core"; | ||
| import { resolveFormat, formatOutput } from "../output/index.js"; | ||
| export function whoamiCommand() { | ||
| const cmd = new Command("whoami"); | ||
| cmd.description("Display the current authenticated user's profile"); | ||
| cmd.addOption(new Option("--format <format>", "output format (json or table)").choices(["json", "table"])); | ||
| cmd.action(async (opts, actionCmd) => { | ||
| const rootOpts = actionCmd.optsWithGlobals(); | ||
| const profileFlag = typeof rootOpts["profile"] === "string" ? rootOpts["profile"] : undefined; | ||
| const { config } = await resolveConfig({ profile: profileFlag, requiredScopes: ["openid", "profile", "email"] }); | ||
| // resolveConfig guarantees oauth.accessToken and apiVersion are defined | ||
| const accessToken = config.oauth?.accessToken ?? ""; | ||
| const apiVersion = config.apiVersion ?? ""; | ||
| const client = new LinkedInClient({ accessToken, apiVersion }); | ||
| const userInfo = await getUserInfo(client); | ||
| const format = resolveFormat(opts["format"], process.stdout); | ||
| const data = { | ||
| name: userInfo.name, | ||
| email: userInfo.email, | ||
| picture: userInfo.picture, | ||
| }; | ||
| console.log(formatOutput(data, format)); | ||
| }); | ||
| return cmd; | ||
| } | ||
| //# sourceMappingURL=whoami.js.map |
| {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE7E,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEjE,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,GAAG,CAAC,WAAW,CAAC,kDAAkD,CAAC,CAAC;IACpE,GAAG,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,mBAAmB,EAAE,+BAA+B,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAE3G,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,IAA6B,EAAE,SAAkB,EAAE,EAAE;QACrE,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,EAAE,CAAC;QAC7C,MAAM,WAAW,GAAG,OAAO,QAAQ,CAAC,SAAS,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAE9F,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;QACjH,wEAAwE;QACxE,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,EAAE,WAAW,IAAI,EAAE,CAAC;QACpD,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;QAC3C,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,CAAC;QAE/D,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;QAE3C,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,QAAQ,CAA6B,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAEzF,MAAM,IAAI,GAAG;YACX,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,OAAO,EAAE,QAAQ,CAAC,OAAO;SAC1B,CAAC;QAEF,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"} |
| /** | ||
| * Determine whether color output is enabled. | ||
| * | ||
| * Color is disabled when: | ||
| * - The `NO_COLOR` environment variable is set (any value, per https://no-color.org/) | ||
| * - The `noColor` flag is `true` (from `--no-color` CLI flag) | ||
| * | ||
| * @param options.noColor - Whether the `--no-color` CLI flag was provided | ||
| * @param options.env - Environment variables to check (defaults to `process.env`) | ||
| */ | ||
| export declare function isColorEnabled(options?: { | ||
| noColor?: boolean | undefined; | ||
| env?: Record<string, string | undefined> | undefined; | ||
| }): boolean; | ||
| //# sourceMappingURL=color.d.ts.map |
| {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../src/output/color.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE;IACvC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;CACtD,GAAG,OAAO,CAYV"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| /** | ||
| * Determine whether color output is enabled. | ||
| * | ||
| * Color is disabled when: | ||
| * - The `NO_COLOR` environment variable is set (any value, per https://no-color.org/) | ||
| * - The `noColor` flag is `true` (from `--no-color` CLI flag) | ||
| * | ||
| * @param options.noColor - Whether the `--no-color` CLI flag was provided | ||
| * @param options.env - Environment variables to check (defaults to `process.env`) | ||
| */ | ||
| export function isColorEnabled(options) { | ||
| const env = options?.env ?? process.env; | ||
| if ("NO_COLOR" in env) { | ||
| return false; | ||
| } | ||
| if (options?.noColor === true) { | ||
| return false; | ||
| } | ||
| return true; | ||
| } | ||
| //# sourceMappingURL=color.js.map |
| {"version":3,"file":"color.js","sourceRoot":"","sources":["../../src/output/color.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,OAG9B;IACC,MAAM,GAAG,GAAG,OAAO,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IAExC,IAAI,UAAU,IAAI,GAAG,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,OAAO,EAAE,OAAO,KAAK,IAAI,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"} |
| /** | ||
| * Supported output formats. | ||
| */ | ||
| export type OutputFormat = "json" | "table"; | ||
| /** | ||
| * Detect the default output format based on whether the stream is a TTY. | ||
| * TTY streams default to "table"; piped streams default to "json". | ||
| */ | ||
| export declare function detectFormat(stream: { | ||
| isTTY?: boolean; | ||
| }): OutputFormat; | ||
| /** | ||
| * Resolve the effective output format: an explicit choice overrides TTY detection. | ||
| */ | ||
| export declare function resolveFormat(explicit: OutputFormat | undefined, stream: { | ||
| isTTY?: boolean; | ||
| }): OutputFormat; | ||
| //# sourceMappingURL=format.d.ts.map |
| {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/output/format.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,CAAC;AAE5C;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,YAAY,CAEtE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,EAAE,MAAM,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,YAAY,CAE3G"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| /** | ||
| * Detect the default output format based on whether the stream is a TTY. | ||
| * TTY streams default to "table"; piped streams default to "json". | ||
| */ | ||
| export function detectFormat(stream) { | ||
| return stream.isTTY === true ? "table" : "json"; | ||
| } | ||
| /** | ||
| * Resolve the effective output format: an explicit choice overrides TTY detection. | ||
| */ | ||
| export function resolveFormat(explicit, stream) { | ||
| return explicit ?? detectFormat(stream); | ||
| } | ||
| //# sourceMappingURL=format.js.map |
| {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/output/format.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAOpC;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,MAA2B;IACtD,OAAO,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,QAAkC,EAAE,MAA2B;IAC3F,OAAO,QAAQ,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;AAC1C,CAAC"} |
| import type { OutputFormat } from "./format.js"; | ||
| /** | ||
| * Format data according to the specified output format. | ||
| */ | ||
| export declare function formatOutput(data: unknown, format: OutputFormat): string; | ||
| //# sourceMappingURL=formatter.d.ts.map |
| {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/output/formatter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,GAAG,MAAM,CAOxE"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { formatJson } from "./json-formatter.js"; | ||
| import { formatTable } from "./table-formatter.js"; | ||
| /** | ||
| * Format data according to the specified output format. | ||
| */ | ||
| export function formatOutput(data, format) { | ||
| switch (format) { | ||
| case "json": | ||
| return formatJson(data); | ||
| case "table": | ||
| return formatTable(data); | ||
| } | ||
| } | ||
| //# sourceMappingURL=formatter.js.map |
| {"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../src/output/formatter.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAGpC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAa,EAAE,MAAoB;IAC9D,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM;YACT,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;QAC1B,KAAK,OAAO;YACV,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC"} |
| export type { OutputFormat } from "./format.js"; | ||
| export { detectFormat, resolveFormat } from "./format.js"; | ||
| export { formatJson } from "./json-formatter.js"; | ||
| export { formatTable } from "./table-formatter.js"; | ||
| export { formatOutput } from "./formatter.js"; | ||
| export { isColorEnabled } from "./color.js"; | ||
| //# sourceMappingURL=index.d.ts.map |
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/output/index.ts"],"names":[],"mappings":"AAGA,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| export { detectFormat, resolveFormat } from "./format.js"; | ||
| export { formatJson } from "./json-formatter.js"; | ||
| export { formatTable } from "./table-formatter.js"; | ||
| export { formatOutput } from "./formatter.js"; | ||
| export { isColorEnabled } from "./color.js"; | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/output/index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAGpC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"} |
| /** | ||
| * Format data as a pretty-printed JSON string. | ||
| */ | ||
| export declare function formatJson(data: unknown): string; | ||
| //# sourceMappingURL=json-formatter.d.ts.map |
| {"version":3,"file":"json-formatter.d.ts","sourceRoot":"","sources":["../../src/output/json-formatter.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAEhD"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| /** | ||
| * Format data as a pretty-printed JSON string. | ||
| */ | ||
| export function formatJson(data) { | ||
| return JSON.stringify(data, null, 2); | ||
| } | ||
| //# sourceMappingURL=json-formatter.js.map |
| {"version":3,"file":"json-formatter.js","sourceRoot":"","sources":["../../src/output/json-formatter.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,IAAa;IACtC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACvC,CAAC"} |
| /** | ||
| * Format data as a human-readable table string. | ||
| * | ||
| * - Array of objects: columnar table with headers derived from object keys. | ||
| * - Single object: two-column key/value table. | ||
| * - Primitive: stringified value. | ||
| */ | ||
| export declare function formatTable(data: unknown): string; | ||
| //# sourceMappingURL=table-formatter.d.ts.map |
| {"version":3,"file":"table-formatter.d.ts","sourceRoot":"","sources":["../../src/output/table-formatter.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAQjD"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| /** | ||
| * Format data as a human-readable table string. | ||
| * | ||
| * - Array of objects: columnar table with headers derived from object keys. | ||
| * - Single object: two-column key/value table. | ||
| * - Primitive: stringified value. | ||
| */ | ||
| export function formatTable(data) { | ||
| if (Array.isArray(data)) { | ||
| return data.length === 0 ? "" : formatArrayTable(data); | ||
| } | ||
| if (typeof data === "object" && data !== null) { | ||
| return formatRecordTable(data); | ||
| } | ||
| return String(data); | ||
| } | ||
| function formatArrayTable(rows) { | ||
| const records = rows.map(toRecord); | ||
| const columns = deriveColumns(records); | ||
| if (columns.length === 0) { | ||
| return ""; | ||
| } | ||
| const widths = computeColumnWidths(columns, records); | ||
| const header = columns.map((col, i) => pad(col, widths[i] ?? 0)).join(" "); | ||
| const separator = widths.map((w) => "\u2500".repeat(w)).join(" "); | ||
| const body = records | ||
| .map((row) => columns.map((col, i) => pad(cellValue(row[col]), widths[i] ?? 0)).join(" ")) | ||
| .join("\n"); | ||
| return `${header}\n${separator}\n${body}`; | ||
| } | ||
| function formatRecordTable(record) { | ||
| const entries = Object.entries(record); | ||
| if (entries.length === 0) { | ||
| return ""; | ||
| } | ||
| const keyWidth = Math.max(...entries.map(([key]) => key.length)); | ||
| return entries.map(([key, value]) => `${pad(key, keyWidth)} ${cellValue(value)}`).join("\n"); | ||
| } | ||
| function deriveColumns(records) { | ||
| const seen = new Set(); | ||
| const columns = []; | ||
| for (const record of records) { | ||
| for (const key of Object.keys(record)) { | ||
| if (!seen.has(key)) { | ||
| seen.add(key); | ||
| columns.push(key); | ||
| } | ||
| } | ||
| } | ||
| return columns; | ||
| } | ||
| function computeColumnWidths(columns, records) { | ||
| return columns.map((col) => { | ||
| const headerLen = col.length; | ||
| const maxValueLen = records.reduce((max, row) => Math.max(max, cellValue(row[col]).length), 0); | ||
| return Math.max(headerLen, maxValueLen); | ||
| }); | ||
| } | ||
| function cellValue(value) { | ||
| if (value === null || value === undefined) { | ||
| return ""; | ||
| } | ||
| if (typeof value === "object") { | ||
| return JSON.stringify(value); | ||
| } | ||
| return String(value); | ||
| } | ||
| function pad(value, width) { | ||
| return value.padEnd(width); | ||
| } | ||
| function toRecord(value) { | ||
| if (typeof value === "object" && value !== null && !Array.isArray(value)) { | ||
| return value; | ||
| } | ||
| return { value }; | ||
| } | ||
| //# sourceMappingURL=table-formatter.js.map |
| {"version":3,"file":"table-formatter.js","sourceRoot":"","sources":["../../src/output/table-formatter.ts"],"names":[],"mappings":"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"} |
| import { Command } from "commander"; | ||
| /** | ||
| * Build and return the top-level Commander program. | ||
| */ | ||
| export declare function createProgram(version?: string): Command; | ||
| //# sourceMappingURL=program.d.ts.map |
| {"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAmBvD"} |
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| import { Command } from "commander"; | ||
| import { authCommand } from "./commands/auth/index.js"; | ||
| import { completionCommand } from "./commands/completion.js"; | ||
| import { postCommand } from "./commands/post/index.js"; | ||
| import { profileCommand } from "./commands/profile/index.js"; | ||
| import { whoamiCommand } from "./commands/whoami.js"; | ||
| /** | ||
| * Build and return the top-level Commander program. | ||
| */ | ||
| export function createProgram(version) { | ||
| const program = new Command("linkedctl"); | ||
| program.description("CLI for the LinkedIn API"); | ||
| if (version !== undefined) { | ||
| program.version(version); | ||
| } | ||
| program.enablePositionalOptions(); | ||
| program.option("--profile <name>", "profile to use from config file"); | ||
| program.option("--no-color", "disable color output"); | ||
| program.addCommand(authCommand()); | ||
| program.addCommand(completionCommand(program)); | ||
| program.addCommand(postCommand()); | ||
| program.addCommand(profileCommand()); | ||
| program.addCommand(whoamiCommand()); | ||
| program.addHelpText("after", "\nGet started: linkedctl auth setup"); | ||
| return program; | ||
| } | ||
| //# sourceMappingURL=program.js.map |
| {"version":3,"file":"program.js","sourceRoot":"","sources":["../src/program.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;IACzC,OAAO,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC;IAChD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,CAAC,uBAAuB,EAAE,CAAC;IAClC,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,iCAAiC,CAAC,CAAC;IACtE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,sBAAsB,CAAC,CAAC;IAErD,OAAO,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;IAClC,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/C,OAAO,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;IAClC,OAAO,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC,CAAC;IACrC,OAAO,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC;IAEpC,OAAO,CAAC,WAAW,CAAC,OAAO,EAAE,qCAAqC,CAAC,CAAC;IAEpE,OAAO,OAAO,CAAC;AACjB,CAAC"} |
+21
| # @linkedctl/cli | ||
| CLI commands for LinkedIn API integration -- the command-line interface used by [`linkedctl`](https://github.com/alexey-pelykh/linkedctl). | ||
| ## Installation | ||
| ```sh | ||
| npm install @linkedctl/cli | ||
| ``` | ||
| Requires Node.js >= 24. | ||
| ## Overview | ||
| This package provides the CLI command definitions and program setup for LinkedCtl. It includes commands for authentication (`auth`), posting (`post`), profile management (`profile`), and user info (`whoami`). | ||
| For full CLI documentation and usage examples, see the [main project](https://github.com/alexey-pelykh/linkedctl). | ||
| ## License | ||
| [AGPL-3.0-only](https://www.gnu.org/licenses/agpl-3.0.txt) |
+3
-1
@@ -1,2 +0,4 @@ | ||
| export {}; | ||
| export type { OutputFormat } from "./output/index.js"; | ||
| export { detectFormat, resolveFormat, formatJson, formatTable, formatOutput, isColorEnabled } from "./output/index.js"; | ||
| export { createProgram } from "./program.js"; | ||
| //# sourceMappingURL=index.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC"} | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACvH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"} |
+2
-1
| // SPDX-License-Identifier: AGPL-3.0-only | ||
| // Copyright (C) 2026 Oleksii PELYKH | ||
| export {}; | ||
| export { detectFormat, resolveFormat, formatJson, formatTable, formatOutput, isColorEnabled } from "./output/index.js"; | ||
| export { createProgram } from "./program.js"; | ||
| //# sourceMappingURL=index.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,CAAC"} | ||
| {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAGpC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACvH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"} |
+14
-14
| { | ||
| "name": "@linkedctl/cli", | ||
| "version": "0.0.0", | ||
| "version": "0.1.0", | ||
| "description": "CLI for LinkedIn API integration", | ||
@@ -29,3 +29,4 @@ "type": "module", | ||
| "files": [ | ||
| "dist" | ||
| "dist", | ||
| "assets" | ||
| ], | ||
@@ -42,5 +43,14 @@ "keywords": [ | ||
| }, | ||
| "dependencies": { | ||
| "commander": "^14.0.3", | ||
| "@linkedctl/core": "^0.1.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/node": "^24", | ||
| "eslint": "^9.39.2", | ||
| "typescript": "^5.9.3", | ||
| "vitest": "^4.0.18" | ||
| }, | ||
| "scripts": { | ||
| "clean": "rm -rf dist tsconfig.tsbuildinfo", | ||
| "prepack": "cp ../../LICENSE .", | ||
| "build": "tsc", | ||
@@ -51,13 +61,3 @@ "typecheck": "tsc --noEmit", | ||
| "dev": "tsc --watch" | ||
| }, | ||
| "dependencies": { | ||
| "@linkedctl/core": "workspace:^", | ||
| "commander": "catalog:" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/node": "catalog:", | ||
| "eslint": "catalog:", | ||
| "typescript": "catalog:", | ||
| "vitest": "catalog:" | ||
| } | ||
| } | ||
| } |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Network access
Supply chain riskThis module accesses the network.
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Trivial Package
Supply chain riskPackages less than 10 lines of code are easily copied into your own project and may not warrant the additional supply chain risk of an external dependency.
162917
347.68%112
1766.67%1332
33200%1
-50%22
Infinity%6
Infinity%3
200%+ Added
+ Added
+ Added
Updated
Updated