Skip to content

Commit 3cc653d

Browse files
committed
add logout command
1 parent 4f65043 commit 3cc653d

8 files changed

Lines changed: 43 additions & 70 deletions

File tree

install.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,11 @@ main() {
118118
fi
119119
chmod +x "${INSTALL_DIR}/${BINARY_NAME}"
120120

121+
local tokens_file="${HOME}/.polar/tokens.json"
122+
if [ -f "$tokens_file" ]; then
123+
rm -f "$tokens_file"
124+
fi
125+
121126
info "Polar CLI ${version} installed successfully!"
122127
echo ""
123128
echo " Run 'polar --help' to get started."

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "polar-cli",
3-
"version": "1.3.5",
3+
"version": "1.3.6",
44
"description": "",
55
"bin": "bin/cli.js",
66
"type": "module",

src/cli.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { BunContext, BunRuntime } from "@effect/platform-bun";
33
import { Effect, Layer } from "effect";
44
import { listen } from "./commands/listen";
55
import { login } from "./commands/login";
6+
import { logout } from "./commands/logout";
67
import { migrate } from "./commands/migrate";
78
import { update } from "./commands/update";
89
import * as Migration from "./services/migration/migrate";
@@ -14,6 +15,7 @@ import { VERSION } from "./version";
1415
const mainCommand = Command.make("polar").pipe(
1516
Command.withSubcommands([
1617
login,
18+
logout,
1719
migrate,
1820
listen,
1921
update

src/commands/logout.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Command } from "@effect/cli";
2+
import { Console, Effect } from "effect";
3+
import * as OAuth from "../services/oauth";
4+
5+
export const logout = Command.make("logout", {}, () =>
6+
Effect.gen(function* () {
7+
const oauth = yield* OAuth.OAuth;
8+
yield* oauth.logout();
9+
yield* Console.log("Successfully logged out of Polar");
10+
}),
11+
);

src/commands/update.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { createHash } from "crypto";
44
import { chmod, mkdtemp, rename, rm, unlink } from "fs/promises";
55
import { tmpdir } from "os";
66
import { dirname, join } from "path";
7+
import * as OAuth from "../services/oauth";
78
import { VERSION } from "../version";
89

910
const fsError = (e: unknown): Error =>
@@ -308,5 +309,8 @@ export const update = Command.make("update", {}, () =>
308309
}
309310

310311
yield* downloadAndUpdate(release, latestVersion);
312+
313+
const oauth = yield* OAuth.OAuth;
314+
yield* oauth.logout().pipe(Effect.catchAll(() => Effect.void));
311315
}),
312316
);

src/schemas/Tokens.ts

Lines changed: 1 addition & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,6 @@
11
import { Schema } from "effect";
22

3-
export const TokenScope = Schema.Array(
4-
Schema.Literal(
5-
'benefits:read',
6-
'benefits:write',
7-
'checkout_links:read',
8-
'checkout_links:write',
9-
'checkouts:read',
10-
'checkouts:write',
11-
'custom_fields:read',
12-
'custom_fields:write',
13-
'customer_meters:read',
14-
'customer_portal:read',
15-
'customer_portal:write',
16-
'customer_seats:read',
17-
'customer_seats:write',
18-
'customer_sessions:write',
19-
'customers:read',
20-
'customers:write',
21-
'discounts:read',
22-
'discounts:write',
23-
'disputes:read',
24-
'email',
25-
'events:read',
26-
'events:write',
27-
'files:read',
28-
'files:write',
29-
'license_keys:read',
30-
'license_keys:write',
31-
'member_sessions:write',
32-
'members:read',
33-
'members:write',
34-
'meters:read',
35-
'meters:write',
36-
'metrics:read',
37-
'metrics:write',
38-
'notification_recipients:read',
39-
'notification_recipients:write',
40-
'notifications:read',
41-
'notifications:write',
42-
'openid',
43-
'orders:read',
44-
'orders:write',
45-
'organization_access_tokens:read',
46-
'organization_access_tokens:write',
47-
'organizations:read',
48-
'organizations:write',
49-
'payments:read',
50-
'payouts:read',
51-
'payouts:write',
52-
'products:read',
53-
'products:write',
54-
'profile',
55-
'refunds:read',
56-
'refunds:write',
57-
'subscriptions:read',
58-
'subscriptions:write',
59-
'transactions:read',
60-
'transactions:write',
61-
'user:read',
62-
'user:write',
63-
'wallets:read',
64-
'wallets:write',
65-
'webhooks:read',
66-
'webhooks:write',
67-
),
68-
);
3+
export const TokenScope = Schema.Array(Schema.String);
694

705
export const Token = Schema.Struct({
716
token: Schema.Redacted(Schema.String),

src/services/oauth.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ export class OAuth extends Context.Tag("OAuth")<OAuth, OAuthImpl>() { }
148148

149149
interface OAuthImpl {
150150
login: (server: PolarEnvironment) => Effect.Effect<Token, OAuthError, never>;
151+
logout: () => Effect.Effect<void, OAuthError, never>;
151152
refresh: (token: Token) => Effect.Effect<Token, OAuthError, never>;
152153
isAuthenticated: (
153154
server: PolarEnvironment,
@@ -186,6 +187,9 @@ export const make = Effect.gen(function* () {
186187
return savedToken;
187188
}).pipe(Effect.scoped, Effect.provide(OAuthRequirementsLayer));
188189

190+
const logout = () =>
191+
deleteTokenFile.pipe(Effect.provide(OAuthRequirementsLayer));
192+
189193
const refresh = (token: Token) =>
190194
Effect.gen(function* () {
191195
const refreshedToken = yield* refreshAccessToken(token);
@@ -224,6 +228,7 @@ export const make = Effect.gen(function* () {
224228

225229
return OAuth.of({
226230
login,
231+
logout,
227232
refresh,
228233
isAuthenticated,
229234
getAccessToken,
@@ -321,6 +326,17 @@ const saveToken = (token: Token) =>
321326
return yield* writeToTokenFile(token).pipe(Effect.map(() => token));
322327
});
323328

329+
const deleteTokenFile = Effect.gen(function* () {
330+
const fileSystem = yield* FileSystem.FileSystem;
331+
const filePath = yield* tokenFilePath;
332+
333+
yield* Effect.logDebug("Deleting token file...");
334+
335+
return yield* fileSystem.remove(filePath).pipe(
336+
Effect.catchAll(() => Effect.void),
337+
);
338+
});
339+
324340
const generateRandomString = Effect.sync(() => randomBytes(48).toString("hex"));
325341

326342
const generateHash = (value: string) =>
@@ -458,7 +474,7 @@ const refreshAccessToken = (token: Token) =>
458474
server: token.server,
459475
}).pipe(
460476
Effect.catchTag("ParseError", (error) =>
461-
Effect.die(
477+
Effect.fail(
462478
new OAuthError({
463479
message: "Failed to parse token response into a Token Schema",
464480
cause: error,
@@ -544,7 +560,7 @@ const redeemCodeForAccessToken = (
544560
server,
545561
}).pipe(
546562
Effect.catchTag("ParseError", (error) =>
547-
Effect.die(
563+
Effect.fail(
548564
new OAuthError({
549565
message: "Failed to parse token response into a Token Schema",
550566
cause: error,

src/version.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export const VERSION = "v1.3.5";
1+
export const VERSION = "v1.3.6";

0 commit comments

Comments
 (0)