@usesocial/cli 0.3.3 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/index.mjs +35 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @usesocial/cli
|
|
2
2
|
|
|
3
|
+
## 0.3.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#18](https://github.com/usesocial/monorepo/pull/18) [`831fe99`](https://github.com/usesocial/monorepo/commit/831fe99ed1d8ebc045e053fd53a8c5372ec7f49a) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - Resume existing CLI login sessions at the billing step when a seat is missing, and show account-connect guidance only after login and seat setup complete.
|
|
8
|
+
|
|
9
|
+
## 0.3.4
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#17](https://github.com/usesocial/monorepo/pull/17) [`677e5a9`](https://github.com/usesocial/monorepo/commit/677e5a98f8c7603ddf5707459340e22736b6057f) Thanks [@CyrusNuevoDia](https://github.com/CyrusNuevoDia)! - Improve CLI onboarding and seat pricing copy.
|
|
14
|
+
|
|
3
15
|
## 0.3.3
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/index.mjs
CHANGED
|
@@ -32,7 +32,7 @@ const exampleDeviceCode = "KN42-A98N";
|
|
|
32
32
|
const brand = {
|
|
33
33
|
org,
|
|
34
34
|
name: "social",
|
|
35
|
-
tagline: "Let your agent
|
|
35
|
+
tagline: "Let your agent run LinkedIn & X for you",
|
|
36
36
|
description: "A CLI for LinkedIn and X: outreach, posting, and audience insights from any shell."
|
|
37
37
|
};
|
|
38
38
|
const brandURLs = {
|
|
@@ -21059,7 +21059,7 @@ const createInstance = (defaults) => {
|
|
|
21059
21059
|
const ky = createInstance();
|
|
21060
21060
|
//#endregion
|
|
21061
21061
|
//#region package.json
|
|
21062
|
-
var version$1 = "0.3.
|
|
21062
|
+
var version$1 = "0.3.5";
|
|
21063
21063
|
//#endregion
|
|
21064
21064
|
//#region src/lib/env.ts
|
|
21065
21065
|
const URLWithTrailingSlash = url().transform(ensureTrailingSlash);
|
|
@@ -27425,6 +27425,15 @@ const unknownOutputContract = (message = "Output schema is not declared.") => ({
|
|
|
27425
27425
|
});
|
|
27426
27426
|
new TextEncoder();
|
|
27427
27427
|
//#endregion
|
|
27428
|
+
//#region ../../packages/lib/src/email-hint.ts
|
|
27429
|
+
const base64URLFromText = (value) => {
|
|
27430
|
+
const bytes = new TextEncoder().encode(value);
|
|
27431
|
+
let binary = "";
|
|
27432
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
27433
|
+
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
|
|
27434
|
+
};
|
|
27435
|
+
const emailHintFromEmail = (email) => base64URLFromText(email);
|
|
27436
|
+
//#endregion
|
|
27428
27437
|
//#region ../../packages/lib/src/phone.ts
|
|
27429
27438
|
const phoneFormattingRegex = /[\s().-]/g;
|
|
27430
27439
|
const PhoneNumber = string().trim().transform((value) => value.replace(phoneFormattingRegex, "")).pipe(string().regex(/^\+[1-9]\d{1,14}$/, { message: "Enter a phone number with +country code." }));
|
|
@@ -27435,7 +27444,6 @@ const DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
|
27435
27444
|
const MAGIC_LINK_PATH = "/api/auth/sign-in/magic-link";
|
|
27436
27445
|
const TERMS_URL = new URL(siteConfig.links.terms, siteConfig.publicWebURL).toString();
|
|
27437
27446
|
const LOGIN_SUCCESS_MESSAGE = "Logged in! 🎉";
|
|
27438
|
-
const NEXT_COMMANDS_MESSAGE = "Now run `social account connect linkedin` or `social account connect x`.";
|
|
27439
27447
|
const formatUserCode = (code) => `${code.slice(0, 4)}-${code.slice(4)}`;
|
|
27440
27448
|
const isRecord$2 = (value) => typeof value === "object" && value !== null;
|
|
27441
27449
|
const isAuthErrorResponse = (data) => isRecord$2(data) && (typeof data.error === "string" || typeof data.error_description === "string" || typeof data.message === "string");
|
|
@@ -27492,6 +27500,7 @@ const deviceCallbackURLFor = (deviceCode, email) => {
|
|
|
27492
27500
|
parsed = new URL("/device", "https://social.local");
|
|
27493
27501
|
}
|
|
27494
27502
|
parsed.searchParams.set("user_code", formatUserCode(deviceCode.user_code));
|
|
27503
|
+
parsed.searchParams.set("email_hint", emailHintFromEmail(email));
|
|
27495
27504
|
parsed.searchParams.set("email", email);
|
|
27496
27505
|
return `${parsed.pathname}${parsed.search}`;
|
|
27497
27506
|
};
|
|
@@ -27553,7 +27562,6 @@ const waitForDeviceToken = async (ctx, deviceCode, phoneNumber) => {
|
|
|
27553
27562
|
await updatePhoneNumber(ctx, phoneNumber);
|
|
27554
27563
|
clearTick();
|
|
27555
27564
|
spinner.stop(LOGIN_SUCCESS_MESSAGE);
|
|
27556
|
-
ctx.ui.info(NEXT_COMMANDS_MESSAGE);
|
|
27557
27565
|
return token;
|
|
27558
27566
|
} catch (error) {
|
|
27559
27567
|
clearTick();
|
|
@@ -27586,7 +27594,7 @@ const signInPhase = async (ctx) => {
|
|
|
27586
27594
|
}
|
|
27587
27595
|
};
|
|
27588
27596
|
};
|
|
27589
|
-
const onboardingLegalNotice = (termsURL = TERMS_URL) => `By signing up and connecting accounts, you accept the terms
|
|
27597
|
+
const onboardingLegalNotice = (termsURL = TERMS_URL) => `By signing up and connecting accounts, you accept the terms\nand conditions and use this software at your own risk.\nRead the terms: ${termsURL}`;
|
|
27590
27598
|
const resolveEmail = async (ctx) => await ctx.ui.text({
|
|
27591
27599
|
message: "Email",
|
|
27592
27600
|
placeholder: "you@example.com",
|
|
@@ -27700,6 +27708,7 @@ const openBrowser = async (url) => {
|
|
|
27700
27708
|
]);
|
|
27701
27709
|
return await runCommand(["xdg-open", url]);
|
|
27702
27710
|
};
|
|
27711
|
+
const SEAT_PRICING_MESSAGE = `social costs $60/month/account + usage. Full details at ${createAbsoluteURL(env.SOCIAL_WEB_URL, siteConfig.links.pricing)}. Continue?`;
|
|
27703
27712
|
const SEAT_CHECKOUT_RETURN_PATH = "/setup/billing/done";
|
|
27704
27713
|
const SEAT_POLL_INTERVAL_MS = 2e3;
|
|
27705
27714
|
const SEAT_POLL_TIMEOUT_MS = 1800 * 1e3;
|
|
@@ -27725,7 +27734,7 @@ const runSeatPhase = async (ctx, deps = {}) => {
|
|
|
27725
27734
|
data: status
|
|
27726
27735
|
};
|
|
27727
27736
|
if (!await ctx.ui.confirm({
|
|
27728
|
-
message:
|
|
27737
|
+
message: SEAT_PRICING_MESSAGE,
|
|
27729
27738
|
initialValue: true
|
|
27730
27739
|
})) return {
|
|
27731
27740
|
status: "needs_input",
|
|
@@ -27823,6 +27832,8 @@ const assertInteractiveTerminal = () => {
|
|
|
27823
27832
|
if (!(process.stdin.isTTY && process.stdout.isTTY)) throw new UsageError("social account login requires an interactive terminal.");
|
|
27824
27833
|
};
|
|
27825
27834
|
const nextCommands = ["social account connect linkedin", "social account connect x"];
|
|
27835
|
+
const nextCommandsMessage = `Now run \`${nextCommands[0]}\` or \`${nextCommands[1]}\`.`;
|
|
27836
|
+
const billingReady = (billing) => billing.seats.available > 0;
|
|
27826
27837
|
const alreadyLoggedInOutput = ({ credential, session }) => ({
|
|
27827
27838
|
status: "already_logged_in",
|
|
27828
27839
|
message: "Already logged in.",
|
|
@@ -27838,16 +27849,19 @@ const offlineOutput = () => ({
|
|
|
27838
27849
|
code: "offline",
|
|
27839
27850
|
message: "Couldn't reach the server. Check your network connection and try again."
|
|
27840
27851
|
});
|
|
27841
|
-
const runLogin = async (ctx) => {
|
|
27852
|
+
const runLogin = async (ctx, loginPhases = phases, deps = {}) => {
|
|
27853
|
+
const bearerIsValid = deps.isBearerValid ?? isBearerValid;
|
|
27854
|
+
const readLocalCredentials = deps.readCredentials ?? readCredentials;
|
|
27842
27855
|
analytics.capture("login_started");
|
|
27843
|
-
for (const phase of
|
|
27844
|
-
if (phase.
|
|
27856
|
+
for (const phase of loginPhases) {
|
|
27857
|
+
if (phase.name !== "access" && phase.name !== "sign-in" && deps.authenticated !== true && !bearerIsValid(await readLocalCredentials())) throw new AuthError("Session expired before login finished. Run `social account login` again.");
|
|
27845
27858
|
const result = await phase.run(ctx);
|
|
27846
27859
|
if (result.status !== "done") return result;
|
|
27847
27860
|
analytics.capture("login_phase_completed", { phase: phase.name });
|
|
27848
27861
|
}
|
|
27849
27862
|
const session = await ctx.client.cli.session.me();
|
|
27850
27863
|
const billing = await ctx.client.billing.status();
|
|
27864
|
+
ctx.ui.info(nextCommandsMessage);
|
|
27851
27865
|
return {
|
|
27852
27866
|
status: "ok",
|
|
27853
27867
|
user: session.user,
|
|
@@ -27895,7 +27909,18 @@ const loginCommand = defineCommand({
|
|
|
27895
27909
|
try {
|
|
27896
27910
|
const client = createORPCAPIClient();
|
|
27897
27911
|
const existing = await readExistingAuthSession(client);
|
|
27898
|
-
if (existing.kind === "existing") output = alreadyLoggedInOutput(existing.session);
|
|
27912
|
+
if (existing.kind === "existing") if (billingReady(await client.billing.status())) output = alreadyLoggedInOutput(existing.session);
|
|
27913
|
+
else {
|
|
27914
|
+
assertInteractiveTerminal();
|
|
27915
|
+
output = await runLogin({
|
|
27916
|
+
ui: createUI(process.stdout.isTTY === true),
|
|
27917
|
+
client,
|
|
27918
|
+
args: loginArgs
|
|
27919
|
+
}, [{
|
|
27920
|
+
name: "seat",
|
|
27921
|
+
run: seatPhase
|
|
27922
|
+
}], { authenticated: true });
|
|
27923
|
+
}
|
|
27899
27924
|
else if (existing.kind === "offline") output = offlineOutput();
|
|
27900
27925
|
else {
|
|
27901
27926
|
assertInteractiveTerminal();
|