seamless-cli 0.5.1 → 0.6.0

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.
Files changed (47) hide show
  1. package/README.md +133 -0
  2. package/dist/commands/adminShared.js +23 -0
  3. package/dist/commands/adminShared.js.map +1 -0
  4. package/dist/commands/config.js +187 -0
  5. package/dist/commands/config.js.map +1 -0
  6. package/dist/commands/help.js +98 -0
  7. package/dist/commands/help.js.map +1 -1
  8. package/dist/commands/login.js +86 -0
  9. package/dist/commands/login.js.map +1 -0
  10. package/dist/commands/logout.js +43 -0
  11. package/dist/commands/logout.js.map +1 -0
  12. package/dist/commands/org.js +249 -0
  13. package/dist/commands/org.js.map +1 -0
  14. package/dist/commands/profile.js +150 -0
  15. package/dist/commands/profile.js.map +1 -0
  16. package/dist/commands/sessions.js +112 -0
  17. package/dist/commands/sessions.js.map +1 -0
  18. package/dist/commands/users.js +147 -0
  19. package/dist/commands/users.js.map +1 -0
  20. package/dist/commands/verify.js +133 -9
  21. package/dist/commands/verify.js.map +1 -1
  22. package/dist/commands/whoami.js +29 -0
  23. package/dist/commands/whoami.js.map +1 -0
  24. package/dist/core/admin.js +142 -0
  25. package/dist/core/admin.js.map +1 -0
  26. package/dist/core/args.js +19 -0
  27. package/dist/core/args.js.map +1 -0
  28. package/dist/core/authClient.js +113 -0
  29. package/dist/core/authClient.js.map +1 -0
  30. package/dist/core/config.js +146 -0
  31. package/dist/core/config.js.map +1 -0
  32. package/dist/core/http.js +34 -0
  33. package/dist/core/http.js.map +1 -0
  34. package/dist/core/images.js +1 -1
  35. package/dist/core/keychain.js +112 -0
  36. package/dist/core/keychain.js.map +1 -0
  37. package/dist/core/loginFlow.js +143 -0
  38. package/dist/core/loginFlow.js.map +1 -0
  39. package/dist/core/session.js +30 -0
  40. package/dist/core/session.js.map +1 -0
  41. package/dist/core/sessions.js +41 -0
  42. package/dist/core/sessions.js.map +1 -0
  43. package/dist/core/systemConfig.js +125 -0
  44. package/dist/core/systemConfig.js.map +1 -0
  45. package/dist/index.js +40 -0
  46. package/dist/index.js.map +1 -1
  47. package/package.json +8 -2
package/README.md CHANGED
@@ -120,6 +120,139 @@ npm run dev
120
120
 
121
121
  ---
122
122
 
123
+ ## Authenticating against an instance
124
+
125
+ Beyond scaffolding, the CLI can log in to a Seamless Auth instance (self-hosted, a managed
126
+ tenant, or local dev) and call its authenticated and admin endpoints from the terminal. It talks
127
+ to the instance directly over Bearer and JSON, so no server or contract changes are required.
128
+
129
+ ### Profiles
130
+
131
+ The CLI targets instances through named profiles stored at `~/.config/seamless/config.json`
132
+ (respecting `XDG_CONFIG_HOME`). Profiles hold no secrets; tokens live in the OS keychain (see
133
+ below). Pick the active profile per command with `--profile <name>` or the `SEAMLESS_PROFILE`
134
+ environment variable, otherwise the `default` profile is used.
135
+
136
+ ```bash
137
+ # Add a profile (prompts if you omit the flags)
138
+ seamless profile add prod --instance-url https://auth.example.com
139
+ seamless profile add local --instance-url http://localhost:5312
140
+
141
+ seamless profile list # active profile is marked with *
142
+ seamless profile use local # switch the active profile
143
+ seamless profile remove local # delete a profile (also clears its keychain tokens)
144
+ ```
145
+
146
+ `instanceUrl` is normalized: the trailing slash is stripped and `https` is required for any host
147
+ other than `localhost`, `127.0.0.1`, or `::1`.
148
+
149
+ ### Logging in
150
+
151
+ Login uses email OTP: you paste the code from your inbox, so nothing needs to be delivered to the
152
+ CLI and no service token is required.
153
+
154
+ ```bash
155
+ seamless login # prompts for the identifier, then the code
156
+ seamless login you@example.com # identifier as an argument
157
+ seamless login --identifier you@example.com --profile prod
158
+ ```
159
+
160
+ The command honors the instance's advertised login methods, caps local retries so it does not trip
161
+ the OTP rate limiter, and refreshes the code automatically if the five minute window lapses.
162
+
163
+ ### Identity and sessions
164
+
165
+ ```bash
166
+ seamless whoami # sub, email, roles, active profile, and instance URL
167
+ seamless logout # end the current session and clear local tokens
168
+ seamless logout --all # revoke every session for the user, then clear local tokens
169
+
170
+ seamless sessions # list active sessions (current one marked)
171
+ seamless sessions revoke <id> # revoke one session (confirms if it is the current one)
172
+ seamless sessions revoke --all # revoke every session (confirms, then clears local tokens)
173
+ ```
174
+
175
+ ### Configuration as code
176
+
177
+ Read and write the instance system configuration (requires an admin role). This turns the
178
+ dashboard's config panel into something you can version, diff, and apply in CI.
179
+
180
+ ```bash
181
+ seamless config get # print the whole config
182
+ seamless config get access_token_ttl # print a single key
183
+ seamless config get --json > config.json # capture as JSON
184
+
185
+ # Values are parsed as JSON, falling back to a string, so every shape works:
186
+ seamless config set access_token_ttl 15m
187
+ seamless config set rate_limit 250
188
+ seamless config set passkey_login_fallback_enabled false
189
+ seamless config set login_methods '["email_otp","passkey"]'
190
+
191
+ seamless config roles # list the instance's roles
192
+
193
+ seamless config diff config.json # show how a local file differs from the instance
194
+ seamless config apply config.json --dry-run # preview the delta
195
+ seamless config apply config.json # apply after a confirmation prompt
196
+ ```
197
+
198
+ `apply` sends only the changed keys and ignores read-only or unknown keys, so a full config
199
+ captured with `config get --json` can be edited and applied directly. Token TTLs, origins, login
200
+ methods, and the WebAuthn RP id are all readable and writable.
201
+
202
+ ### Admin: users and organizations
203
+
204
+ Manage users and organizations from the terminal (requires an admin role).
205
+
206
+ ```bash
207
+ seamless users list --limit 50 --offset 0
208
+ seamless users delete <id> # confirms first
209
+ seamless users credentials <id> # registered credentials for a user
210
+ seamless users prepare-device-replacement <id> # admin-assisted recovery
211
+
212
+ seamless org list
213
+ seamless org create "Acme Inc" --slug acme
214
+ seamless org get <id>
215
+ seamless org update <id> --name "Acme" --slug acme
216
+
217
+ seamless org members list <orgId>
218
+ seamless org members add <orgId> --email person@example.com --roles member,billing
219
+ seamless org members update <orgId> <userId> --roles admin
220
+ seamless org members remove <orgId> <userId>
221
+ ```
222
+
223
+ A non-admin user receives a clear permission error rather than a stack trace.
224
+
225
+ ### Token storage and the keychain
226
+
227
+ The refresh token is the durable secret, so sessions are stored in the operating system keychain,
228
+ never in a plaintext file:
229
+
230
+ - macOS: Keychain
231
+ - Windows: Credential Manager
232
+ - Linux: Secret Service (libsecret, for example GNOME Keyring or KWallet)
233
+
234
+ Tokens are keyed per profile (by name and instance URL) so multiple instances never collide, and
235
+ they are removed when you log out or remove the profile. Access tokens are refreshed transparently:
236
+ on a `401` the CLI rotates the pair via `/refresh`, stores the new tokens, and retries once. A
237
+ rotated or reused refresh token clears the local session and prompts a fresh login.
238
+
239
+ ### Headless and CI
240
+
241
+ When no OS keychain is available (for example a headless CI runner), the CLI does not fall back to
242
+ a plaintext file. Instead, set `SEAMLESS_REFRESH_TOKEN` to a valid refresh token and the CLI will
243
+ use it to obtain an access token for the run:
244
+
245
+ ```bash
246
+ export SEAMLESS_PROFILE=prod
247
+ export SEAMLESS_REFRESH_TOKEN=<refresh-token>
248
+ seamless whoami
249
+ ```
250
+
251
+ Because `/refresh` rotates the refresh token on every call, this path is best for a single
252
+ invocation; the rotated token is held only in memory for that process.
253
+
254
+ ---
255
+
123
256
  ## What is configured for you
124
257
 
125
258
  Seamless CLI handles the parts that are usually difficult to get right:
@@ -0,0 +1,23 @@
1
+ import kleur from "kleur";
2
+ import { ReauthRequiredError } from "../core/authClient.js";
3
+ import { AdminApiError, PermissionError } from "../core/admin.js";
4
+ export function reportAdminError(err) {
5
+ if (err instanceof ReauthRequiredError) {
6
+ console.log(kleur.yellow(err.message));
7
+ process.exit(1);
8
+ }
9
+ if (err instanceof PermissionError || err instanceof AdminApiError) {
10
+ console.error(kleur.red(err.message));
11
+ process.exit(1);
12
+ }
13
+ throw err;
14
+ }
15
+ export function parseList(value) {
16
+ if (value === undefined)
17
+ return undefined;
18
+ return value
19
+ .split(",")
20
+ .map((item) => item.trim())
21
+ .filter((item) => item.length > 0);
22
+ }
23
+ //# sourceMappingURL=adminShared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adminShared.js","sourceRoot":"","sources":["../../src/commands/adminShared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAElE,MAAM,UAAU,gBAAgB,CAAC,GAAY;IAC3C,IAAI,GAAG,YAAY,mBAAmB,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,IAAI,GAAG,YAAY,eAAe,IAAI,GAAG,YAAY,aAAa,EAAE,CAAC;QACnE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,GAAG,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1C,OAAO,KAAK;SACT,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACvC,CAAC"}
@@ -0,0 +1,187 @@
1
+ import fs from "fs";
2
+ import { confirm, isCancel } from "@clack/prompts";
3
+ import kleur from "kleur";
4
+ import { extractFlag } from "../core/args.js";
5
+ import { createAuthClient, ReauthRequiredError } from "../core/authClient.js";
6
+ import { ConfigApiError, diffConfig, filterWritable, getRoles, getSystemConfig, parseValue, patchSystemConfig, PermissionError, } from "../core/systemConfig.js";
7
+ export async function runConfig(args) {
8
+ const sub = args[0];
9
+ const { value: profileFlag, rest } = extractFlag(args.slice(1), "profile");
10
+ try {
11
+ const client = await createAuthClient({ profileFlag });
12
+ switch (sub) {
13
+ case "get":
14
+ await configGet(client, rest);
15
+ return;
16
+ case "set":
17
+ await configSet(client, rest);
18
+ return;
19
+ case "roles":
20
+ await configRoles(client, rest);
21
+ return;
22
+ case "diff":
23
+ await configDiff(client, rest);
24
+ return;
25
+ case "apply":
26
+ await configApply(client, rest);
27
+ return;
28
+ default:
29
+ console.error(kleur.red(`Unknown config subcommand: ${sub ?? "(none)"}`));
30
+ console.log("Usage: seamless config <get|set|roles|diff|apply>");
31
+ process.exit(1);
32
+ }
33
+ }
34
+ catch (err) {
35
+ if (err instanceof ReauthRequiredError) {
36
+ console.log(kleur.yellow(err.message));
37
+ process.exit(1);
38
+ }
39
+ if (err instanceof PermissionError || err instanceof ConfigApiError) {
40
+ console.error(kleur.red(err.message));
41
+ process.exit(1);
42
+ }
43
+ throw err;
44
+ }
45
+ }
46
+ async function configGet(client, rest) {
47
+ const json = rest.includes("--json");
48
+ const key = rest.find((arg) => !arg.startsWith("--"));
49
+ const config = await getSystemConfig(client);
50
+ if (key) {
51
+ if (!(key in config)) {
52
+ console.error(kleur.red(`No such config key: ${key}`));
53
+ process.exit(1);
54
+ }
55
+ const value = config[key];
56
+ console.log(json
57
+ ? JSON.stringify(value, null, 2)
58
+ : typeof value === "string"
59
+ ? value
60
+ : JSON.stringify(value, null, 2));
61
+ return;
62
+ }
63
+ if (json) {
64
+ console.log(JSON.stringify(config, null, 2));
65
+ return;
66
+ }
67
+ printConfig(config);
68
+ }
69
+ async function configSet(client, rest) {
70
+ const positional = rest.filter((arg) => !arg.startsWith("--"));
71
+ const [key, ...valueParts] = positional;
72
+ if (!key || valueParts.length === 0) {
73
+ console.error(kleur.red("Usage: seamless config set <key> <value>"));
74
+ process.exit(1);
75
+ }
76
+ const value = parseValue(valueParts.join(" "));
77
+ const result = await patchSystemConfig(client, { [key]: value });
78
+ if (result.updatedKeys.length) {
79
+ console.log(kleur.green(`Updated: ${result.updatedKeys.join(", ")}`));
80
+ }
81
+ else {
82
+ console.log(kleur.dim("No changes."));
83
+ }
84
+ }
85
+ async function configRoles(client, rest) {
86
+ const json = rest.includes("--json");
87
+ const roles = await getRoles(client);
88
+ if (json) {
89
+ console.log(JSON.stringify(roles, null, 2));
90
+ return;
91
+ }
92
+ if (roles.length === 0) {
93
+ console.log(kleur.dim("No roles."));
94
+ return;
95
+ }
96
+ for (const role of roles) {
97
+ console.log(" " + role);
98
+ }
99
+ }
100
+ async function configDiff(client, rest) {
101
+ const file = rest.find((arg) => !arg.startsWith("--"));
102
+ if (!file) {
103
+ console.error(kleur.red("Usage: seamless config diff <file>"));
104
+ process.exit(1);
105
+ }
106
+ const local = readConfigFile(file);
107
+ const remote = await getSystemConfig(client);
108
+ const changes = diffConfig(local, remote);
109
+ if (changes.length === 0) {
110
+ console.log(kleur.green("In sync. No differences."));
111
+ return;
112
+ }
113
+ printChanges(changes);
114
+ }
115
+ async function configApply(client, rest) {
116
+ const dryRun = rest.includes("--dry-run");
117
+ const file = rest.find((arg) => !arg.startsWith("--"));
118
+ if (!file) {
119
+ console.error(kleur.red("Usage: seamless config apply <file> [--dry-run]"));
120
+ process.exit(1);
121
+ }
122
+ const local = readConfigFile(file);
123
+ const { patch, dropped } = filterWritable(local);
124
+ if (dropped.length) {
125
+ console.log(kleur.dim(`Ignoring read-only or unknown keys: ${dropped.join(", ")}`));
126
+ }
127
+ const remote = await getSystemConfig(client);
128
+ const changes = diffConfig(patch, remote);
129
+ if (changes.length === 0) {
130
+ console.log(kleur.green("Already in sync. Nothing to apply."));
131
+ return;
132
+ }
133
+ printChanges(changes);
134
+ if (dryRun) {
135
+ console.log(kleur.dim("Dry run: no changes applied."));
136
+ return;
137
+ }
138
+ const proceed = await confirm({
139
+ message: `Apply ${changes.length} change${changes.length === 1 ? "" : "s"} to ${client.profile.instanceUrl}?`,
140
+ initialValue: false,
141
+ });
142
+ if (isCancel(proceed) || !proceed) {
143
+ console.log("Cancelled.");
144
+ return;
145
+ }
146
+ const body = Object.fromEntries(changes.map((change) => [change.key, change.to]));
147
+ const result = await patchSystemConfig(client, body);
148
+ console.log(kleur.green(`Applied. Updated: ${result.updatedKeys.join(", ") || "(none reported)"}`));
149
+ }
150
+ function readConfigFile(file) {
151
+ let raw;
152
+ try {
153
+ raw = fs.readFileSync(file, "utf-8");
154
+ }
155
+ catch {
156
+ throw new ConfigApiError(`Could not read file: ${file}`);
157
+ }
158
+ let parsed;
159
+ try {
160
+ parsed = JSON.parse(raw);
161
+ }
162
+ catch {
163
+ throw new ConfigApiError(`${file} is not valid JSON.`);
164
+ }
165
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
166
+ throw new ConfigApiError(`${file} must contain a JSON object.`);
167
+ }
168
+ return parsed;
169
+ }
170
+ function inline(value) {
171
+ return value === undefined ? "(unset)" : JSON.stringify(value);
172
+ }
173
+ function printConfig(config) {
174
+ const keys = Object.keys(config).sort();
175
+ const width = keys.reduce((max, key) => Math.max(max, key.length), 0);
176
+ for (const key of keys) {
177
+ console.log(kleur.dim(key.padEnd(width) + " ") + inline(config[key]));
178
+ }
179
+ }
180
+ function printChanges(changes) {
181
+ for (const change of changes) {
182
+ console.log(kleur.bold(change.key));
183
+ console.log(" " + kleur.red(`- ${inline(change.from)}`));
184
+ console.log(" " + kleur.green(`+ ${inline(change.to)}`));
185
+ }
186
+ }
187
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,16 @@ USAGE
13
13
  seamless check
14
14
  seamless bootstrap-admin [email]
15
15
  seamless verify [--api-only] [--filter=<flow>] [--keep-up]
16
+ seamless profile <list|add|use|remove>
17
+ seamless login [identifier] [--identifier <email>] [--profile <name>]
18
+ seamless whoami [--profile <name>]
19
+ seamless logout [--all] [--profile <name>]
20
+ seamless sessions [list]
21
+ seamless sessions revoke <id | --all>
22
+ seamless config <get|set|roles|diff|apply>
23
+ seamless users <list|delete|credentials|prepare-device-replacement>
24
+ seamless org <list|create|get|update>
25
+ seamless org members <list|add|update|remove>
16
26
  seamless --help
17
27
  seamless --version
18
28
 
@@ -35,6 +45,94 @@ COMMANDS
35
45
  GitLab) and wires the ones you configure into the auth server
36
46
  • Run an unknown flag to see the available examples
37
47
 
48
+ profile <list|add|use|remove>
49
+ Manage the Seamless Auth instances the CLI targets, stored as named
50
+ profiles in ~/.config/seamless/config.json (respects XDG_CONFIG_HOME).
51
+
52
+ profile list
53
+ • Show configured profiles; the active one is marked with *
54
+
55
+ profile add <name> --instance-url <url> [--identifier-type email|phone]
56
+ • Create or update a profile (prompts interactively if flags are omitted)
57
+
58
+ profile use <name>
59
+ • Switch the active profile for subsequent commands
60
+
61
+ profile remove <name>
62
+ • Delete a profile
63
+
64
+ The active profile can also be chosen per command with --profile <name> or
65
+ the SEAMLESS_PROFILE environment variable.
66
+
67
+ login [identifier]
68
+ Log in to the active profile's Seamless Auth instance using email OTP.
69
+ Prompts for the identifier (or pass it positionally or with --identifier)
70
+ and the code sent to your inbox, then stores the session in the OS keychain.
71
+
72
+ --profile <name>
73
+ • Log in against a specific profile instead of the active one
74
+ • Also selectable with the SEAMLESS_PROFILE environment variable
75
+
76
+ whoami
77
+ Show the identity behind the active profile's session (sub, email, roles),
78
+ alongside the profile name and instance URL. Fails cleanly if not logged in.
79
+
80
+ logout [--all]
81
+ End the current session on the instance and clear the local keychain tokens.
82
+ --all revokes every session for the user before clearing local tokens.
83
+
84
+ sessions [list]
85
+ List the active sessions for the logged-in user, with the current session
86
+ marked. Shows the session id, device or user agent, IP, and last-used time.
87
+
88
+ sessions revoke <id | --all>
89
+ Revoke one session by id, or every session with --all. Revoking the current
90
+ session (or --all) prompts for confirmation and then clears local tokens.
91
+
92
+ config <get|set|roles|diff|apply>
93
+ Read and write the instance system configuration (requires an admin role).
94
+
95
+ config get [key] [--json]
96
+ • Print the whole config or a single key
97
+
98
+ config set <key> <value>
99
+ • Update one key; the value is parsed as JSON, falling back to a string
100
+ (for example: config set access_token_ttl 15m,
101
+ config set login_methods '["email_otp","passkey"]')
102
+
103
+ config roles [--json]
104
+ • List the instance's available roles
105
+
106
+ config diff <file>
107
+ • Show how a local JSON config file differs from the instance
108
+
109
+ config apply <file> [--dry-run]
110
+ • Apply a local JSON config file after a confirmation prompt
111
+
112
+ users <list|delete|credentials|prepare-device-replacement>
113
+ Admin user management (requires an admin role).
114
+
115
+ users list [--limit <n>] [--offset <n>] [--json]
116
+ • List users
117
+ users delete <id>
118
+ • Delete a user (asks for confirmation)
119
+ users credentials <id> [--json]
120
+ • Show a user's registered credentials
121
+ users prepare-device-replacement <id> [--keep-sessions] [--keep-passkeys] [--keep-totp]
122
+ • Admin-assisted account recovery (needs an elevated session)
123
+
124
+ org <list|create|get|update>, org members <list|add|update|remove>
125
+ Admin organization management (requires an admin role).
126
+
127
+ org list [--json]
128
+ org create <name> [--slug <slug>]
129
+ org get <id> [--json]
130
+ org update <id> [--name <name>] [--slug <slug>]
131
+ org members list <orgId> [--json]
132
+ org members add <orgId> (--user <id> | --email <email>) [--roles a,b] [--scopes a,b]
133
+ org members update <orgId> <userId> [--roles a,b] [--scopes a,b]
134
+ org members remove <orgId> <userId>
135
+
38
136
  check
39
137
  Validate project setup, Docker, and running services
40
138
 
@@ -1 +1 @@
1
- {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/commands/help.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,MAAM,UAAU,SAAS;IACvB,OAAO,CAAC,GAAG,CAAC;YACF,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoHlB,CAAC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/commands/help.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,MAAM,UAAU,SAAS;IACvB,OAAO,CAAC,GAAG,CAAC;YACF,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsNlB,CAAC,CAAC;AACH,CAAC"}
@@ -0,0 +1,86 @@
1
+ import { intro, outro, text, isCancel, cancel } from "@clack/prompts";
2
+ import kleur from "kleur";
3
+ import { extractFlag } from "../core/args.js";
4
+ import { getActiveProfile, upsertProfile } from "../core/config.js";
5
+ import { KeychainUnavailableError, saveTokens } from "../core/keychain.js";
6
+ import { completeLogin, LoginError } from "../core/loginFlow.js";
7
+ export async function runLogin(args) {
8
+ const profileFlag = extractFlag(args, "profile");
9
+ const idFlag = extractFlag(profileFlag.rest, "identifier");
10
+ const profile = getActiveProfile({ profileFlag: profileFlag.value });
11
+ if (!profile) {
12
+ console.error(kleur.red("No active profile is configured."));
13
+ console.log("Add one with: " +
14
+ kleur.cyan("seamless profile add <name> --instance-url <url>"));
15
+ process.exit(1);
16
+ }
17
+ intro(`Log in to ${kleur.bold(profile.name)} (${profile.instanceUrl})`);
18
+ let identifier = (idFlag.value ?? idFlag.rest[0])?.trim();
19
+ if (!identifier) {
20
+ const answer = await text({
21
+ message: "Email or phone",
22
+ placeholder: profile.email ?? "you@example.com",
23
+ initialValue: profile.email ?? "",
24
+ validate: (value) => value && value.trim() ? undefined : "An identifier is required",
25
+ });
26
+ if (isCancel(answer)) {
27
+ cancel("Cancelled.");
28
+ return;
29
+ }
30
+ identifier = answer.trim();
31
+ }
32
+ try {
33
+ const result = await completeLogin({
34
+ instanceUrl: profile.instanceUrl,
35
+ identifier,
36
+ getCode: async ({ resent }) => {
37
+ const answer = await text({
38
+ message: resent ? "Enter the new code" : "Enter the code we sent you",
39
+ placeholder: "123456",
40
+ validate: (value) => /^\d{4,8}$/.test((value ?? "").trim())
41
+ ? undefined
42
+ : "Enter the numeric code from the message",
43
+ });
44
+ if (isCancel(answer))
45
+ return null;
46
+ return answer.trim();
47
+ },
48
+ notify: (event) => {
49
+ switch (event.type) {
50
+ case "code_sent":
51
+ console.log(kleur.dim(`A code was sent to ${identifier}.`));
52
+ break;
53
+ case "code_resent":
54
+ console.log(kleur.dim("Your previous code expired, so we sent a new one."));
55
+ break;
56
+ case "incorrect":
57
+ console.log(kleur.yellow(`That code was not accepted. ${event.attemptsLeft} attempt${event.attemptsLeft === 1 ? "" : "s"} left.`));
58
+ break;
59
+ }
60
+ },
61
+ });
62
+ if (!result) {
63
+ cancel("Cancelled.");
64
+ return;
65
+ }
66
+ await persistSession(profile, result);
67
+ outro(kleur.green(`Logged in as ${result.identity.email ?? identifier}.`));
68
+ }
69
+ catch (err) {
70
+ if (err instanceof LoginError || err instanceof KeychainUnavailableError) {
71
+ outro(kleur.red(err.message));
72
+ process.exit(1);
73
+ }
74
+ throw err;
75
+ }
76
+ }
77
+ async function persistSession(profile, result) {
78
+ await saveTokens(profile, result.tokens);
79
+ upsertProfile({
80
+ ...profile,
81
+ sub: result.identity.sub ?? profile.sub,
82
+ email: result.identity.email ?? profile.email,
83
+ identifierType: result.identity.identifierType,
84
+ });
85
+ }
86
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import kleur from "kleur";
2
+ import { extractFlag } from "../core/args.js";
3
+ import { createAuthClient, ReauthRequiredError } from "../core/authClient.js";
4
+ import { getActiveProfile } from "../core/config.js";
5
+ import { clearLocalSession, revokeSession } from "../core/session.js";
6
+ export async function runLogout(args) {
7
+ const all = args.includes("--all");
8
+ const { value: profileFlag } = extractFlag(args.filter((a) => a !== "--all"), "profile");
9
+ const profile = getActiveProfile({ profileFlag });
10
+ if (!profile) {
11
+ console.log(kleur.yellow("No active profile. Nothing to log out of."));
12
+ return;
13
+ }
14
+ let client;
15
+ try {
16
+ client = await createAuthClient({ profileFlag });
17
+ }
18
+ catch (err) {
19
+ if (err instanceof ReauthRequiredError) {
20
+ await clearLocalSession(profile);
21
+ console.log(kleur.green("You are already logged out."));
22
+ return;
23
+ }
24
+ throw err;
25
+ }
26
+ let revoked = false;
27
+ try {
28
+ revoked = await revokeSession(client, { all });
29
+ }
30
+ catch (err) {
31
+ if (!(err instanceof ReauthRequiredError))
32
+ throw err;
33
+ revoked = true;
34
+ }
35
+ await clearLocalSession(profile);
36
+ if (revoked) {
37
+ console.log(kleur.green(all ? "Logged out of all sessions." : "Logged out."));
38
+ }
39
+ else {
40
+ console.log(kleur.yellow("Cleared the local session. The instance reported a problem revoking the session."));
41
+ }
42
+ }
43
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEtE,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAc;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACnC,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,WAAW,CACxC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,EACjC,SAAS,CACV,CAAC;IAEF,MAAM,OAAO,GAAG,gBAAgB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC;IAClD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,2CAA2C,CAAC,CAAC,CAAC;QACvE,OAAO;IACT,CAAC;IAED,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,gBAAgB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC;IACnD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,mBAAmB,EAAE,CAAC;YACvC,MAAM,iBAAiB,CAAC,OAAO,CAAC,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;YACxD,OAAO;QACT,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,CAAC,GAAG,YAAY,mBAAmB,CAAC;YAAE,MAAM,GAAG,CAAC;QACrD,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,MAAM,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAEjC,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,aAAa,CAAC,CACjE,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CACV,kFAAkF,CACnF,CACF,CAAC;IACJ,CAAC;AACH,CAAC"}