@nebulr-group/bridge-cli 0.4.3 → 0.5.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.
- package/README.md +56 -5
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +13 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/auth/logout.command.d.ts +10 -3
- package/dist/commands/auth/logout.command.d.ts.map +1 -1
- package/dist/commands/auth/logout.command.js +58 -18
- package/dist/commands/auth/logout.command.js.map +1 -1
- package/dist/commands/auth/status.command.d.ts +4 -0
- package/dist/commands/auth/status.command.d.ts.map +1 -1
- package/dist/commands/auth/status.command.js +50 -19
- package/dist/commands/auth/status.command.js.map +1 -1
- package/dist/commands/auth/use.command.d.ts +17 -0
- package/dist/commands/auth/use.command.d.ts.map +1 -0
- package/dist/commands/auth/use.command.js +47 -0
- package/dist/commands/auth/use.command.js.map +1 -0
- package/dist/commands/auth.command.d.ts +1 -0
- package/dist/commands/auth.command.d.ts.map +1 -1
- package/dist/commands/auth.command.js +3 -0
- package/dist/commands/auth.command.js.map +1 -1
- package/dist/commands/flag-init.command.d.ts.map +1 -1
- package/dist/commands/flag-init.command.js +9 -8
- package/dist/commands/flag-init.command.js.map +1 -1
- package/dist/config.d.ts +20 -13
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +120 -32
- package/dist/config.js.map +1 -1
- package/dist/credentials.d.ts +68 -5
- package/dist/credentials.d.ts.map +1 -1
- package/dist/credentials.js +202 -11
- package/dist/credentials.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -27,10 +27,48 @@ bridge auth login
|
|
|
27
27
|
Opens your default browser, runs through a PKCE-secured loopback flow (RFC 8252), and stores a 10-day token at `~/.config/bridge/credentials.json` (mode `0600`). After that, every subsequent `bridge` command picks the token up automatically — no env vars needed.
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
bridge auth status # show
|
|
31
|
-
bridge auth logout # revoke the token and
|
|
30
|
+
bridge auth status # show every stored app, and which one is active
|
|
31
|
+
bridge auth logout # revoke the active token and remove it locally
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
#### Several apps at once
|
|
35
|
+
|
|
36
|
+
The credentials file holds one credential per app, so you can log in to your
|
|
37
|
+
local, stage and prod apps and move between them without a browser round-trip —
|
|
38
|
+
the tokens are already on disk with days left on them.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
bridge auth login --label northwhistle-local # once per app
|
|
42
|
+
bridge auth login --label northwhistle-prod
|
|
43
|
+
|
|
44
|
+
bridge auth status # lists both, marks the active one
|
|
45
|
+
bridge auth use northwhistle-local # switch the default, offline
|
|
46
|
+
bridge --profile northwhistle-prod app get # target ONE command, default untouched
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
A profile is selected by its `--label`, its app id, or its app name, in that
|
|
50
|
+
order. An ambiguous name is an error rather than a guess. `BRIDGE_PROFILE` does
|
|
51
|
+
the same thing as `--profile` for a whole shell session.
|
|
52
|
+
|
|
53
|
+
Prefer `--profile` over `bridge auth use` in scripts and long-running agent
|
|
54
|
+
sessions: `use` mutates state another process may be reading, `--profile` does
|
|
55
|
+
not.
|
|
56
|
+
|
|
57
|
+
Every command prints one line to **stderr** naming the app that answered:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
bridge: northwhistle-prod (606b4416fabdc800087d09ec) · https://api.thebridge.dev · via saved default
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
stdout stays pure JSON, so this does not disturb anything parsing it. Silence it
|
|
64
|
+
with `BRIDGE_NO_BANNER=true` if you are already certain which app you are on.
|
|
65
|
+
|
|
66
|
+
`bridge auth logout` removes the active app only. Use `--profile <name>` for a
|
|
67
|
+
specific one, or `--all` to clear the file.
|
|
68
|
+
|
|
69
|
+
Existing single-app credentials files keep working and are upgraded in place the
|
|
70
|
+
next time something writes.
|
|
71
|
+
|
|
34
72
|
#### `bridge auth login` flags
|
|
35
73
|
|
|
36
74
|
| Flag | Description |
|
|
@@ -56,7 +94,17 @@ For non-interactive contexts (CI/CD pipelines, Docker images, headless agents) s
|
|
|
56
94
|
export BRIDGE_API_KEY=<your-api-token>
|
|
57
95
|
```
|
|
58
96
|
|
|
59
|
-
If you have logged in via `bridge auth login`, the credentials file always wins — a fresh login takes effect immediately, even when `BRIDGE_API_KEY` is still exported in your shell. `BRIDGE_API_KEY` is only used when no credentials file is present (the typical CI runner shape). To switch back to env-var auth on a developer machine, run `bridge auth logout` first.
|
|
97
|
+
If you have logged in via `bridge auth login`, the credentials file always wins — a fresh login takes effect immediately, even when `BRIDGE_API_KEY` is still exported in your shell. `BRIDGE_API_KEY` is only used when no credentials file is present (the typical CI runner shape). To switch back to env-var auth on a developer machine, run `bridge auth logout --all` first.
|
|
98
|
+
|
|
99
|
+
Because that trips people up, the CLI now says so at the moment it happens: with
|
|
100
|
+
both present you get a line on stderr telling you `BRIDGE_API_KEY` is set and
|
|
101
|
+
being ignored, and what to do instead. To point the CLI at a different app, use
|
|
102
|
+
`--profile`, not the env vars.
|
|
103
|
+
|
|
104
|
+
**`BRIDGE_APP_ID` has no effect on any path.** The app is carried by the
|
|
105
|
+
credential itself — a login token and an API key are both already scoped to one
|
|
106
|
+
app, so there is nothing for it to change. It is called out on stderr whenever it
|
|
107
|
+
is set, rather than being quietly ignored.
|
|
60
108
|
|
|
61
109
|
Optional configuration (applies to both auth paths):
|
|
62
110
|
|
|
@@ -139,8 +187,11 @@ bridge auth login # default: open browser, complete PKCE flow
|
|
|
139
187
|
bridge auth login --app acme # pin to a specific app
|
|
140
188
|
bridge auth login --label "work laptop"
|
|
141
189
|
bridge auth login --no-browser # print the URL (headless / SSH)
|
|
142
|
-
bridge auth status # show
|
|
143
|
-
bridge auth
|
|
190
|
+
bridge auth status # show every stored app, active one marked
|
|
191
|
+
bridge auth use <label|app-id> # switch the default app, no browser
|
|
192
|
+
bridge auth logout # revoke + remove the active app
|
|
193
|
+
bridge auth logout --all # ...or every stored app
|
|
194
|
+
bridge --profile <label> <cmd> # target one app for one command
|
|
144
195
|
```
|
|
145
196
|
|
|
146
197
|
### Auth Configuration (app-level — separate from `auth login`)
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyBpC,eAAO,MAAM,OAAO,SAAgB,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -18,6 +18,7 @@ import { registerInfoCommands } from './commands/info.command.js';
|
|
|
18
18
|
import { registerGuideCommands } from './commands/guide.command.js';
|
|
19
19
|
import { registerOpsCommands } from './commands/ops.command.js';
|
|
20
20
|
import { registerStripeCommands } from './commands/stripe.command.js';
|
|
21
|
+
import { setProfileOverride } from './config.js';
|
|
21
22
|
// Read version from package.json so `bridge --version` never drifts from the
|
|
22
23
|
// published package. dist/cli.js lives at <pkg>/dist/cli.js, so `../package.json`
|
|
23
24
|
// resolves to the package root in both the published tarball and during dev.
|
|
@@ -27,7 +28,18 @@ export const program = new Command();
|
|
|
27
28
|
program
|
|
28
29
|
.name('bridge')
|
|
29
30
|
.description('Bridge platform CLI — optimized for AI coding agents')
|
|
30
|
-
.version(version)
|
|
31
|
+
.version(version)
|
|
32
|
+
// TBP-628 — target another stored app for ONE command, without touching the
|
|
33
|
+
// persisted default another process may be reading. Named `--profile` rather
|
|
34
|
+
// than `--app` because `bridge auth login --app` already exists and means
|
|
35
|
+
// something different (which app to authorise), and because `--profile` is
|
|
36
|
+
// what aws/npm users already reach for.
|
|
37
|
+
.option('--profile <label|app-id|app-name>', 'Use a specific stored credential for this command (env: BRIDGE_PROFILE)');
|
|
38
|
+
// Runs before any subcommand action, so `getManagementClient()` sees the
|
|
39
|
+
// override wherever in the tree it is eventually called from.
|
|
40
|
+
program.hook('preAction', (thisCommand) => {
|
|
41
|
+
setProfileOverride(thisCommand.opts().profile);
|
|
42
|
+
});
|
|
31
43
|
registerAppCommands(program);
|
|
32
44
|
registerTenantCommands(program);
|
|
33
45
|
registerUserCommands(program);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,11 +3,18 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Behavior:
|
|
5
5
|
* - No credentials file → "Not logged in." (exit 0).
|
|
6
|
-
* -
|
|
6
|
+
* - Otherwise → call `POST /v1/auth/cli/revoke` with `x-api-key`,
|
|
7
7
|
* treat 401 as success (token already gone), then
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* remove it locally. Network errors → warn but still
|
|
9
|
+
* remove (the local file is the source of truth for
|
|
10
10
|
* "logged in" on this machine).
|
|
11
|
+
*
|
|
12
|
+
* TBP-628 — the file can hold several apps, so logout now has a scope.
|
|
13
|
+
* Bare `logout` removes the ACTIVE credential and leaves the others; the
|
|
14
|
+
* alternative, wiping every app because you finished with one of them, throws
|
|
15
|
+
* away valid tokens and forces browser round-trips to get them back, which is
|
|
16
|
+
* the friction this ticket exists to remove. `--profile` names one, `--all`
|
|
17
|
+
* asks for the old whole-file behaviour explicitly.
|
|
11
18
|
*/
|
|
12
19
|
import type { Command } from 'commander';
|
|
13
20
|
export declare function registerAuthLogoutCommand(auth: Command): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.command.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/logout.command.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"logout.command.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/logout.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAczC,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAgB7D"}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { credentialsPath,
|
|
1
|
+
import { credentialsPath, CredentialSelectorError, deleteAllCredentials, findCredential, listCredentials, readCredentials, removeCredential, } from '../../credentials.js';
|
|
2
2
|
import { resetManagementClient } from '../../config.js';
|
|
3
3
|
import { createCliApiClient, CliAuthApiError } from '../../auth/api-client.js';
|
|
4
4
|
export function registerAuthLogoutCommand(auth) {
|
|
5
5
|
auth
|
|
6
6
|
.command('logout')
|
|
7
|
-
.description('Revoke the
|
|
8
|
-
.
|
|
7
|
+
.description('Revoke the active CLI token and remove it locally')
|
|
8
|
+
.option('--profile <label|app-id|app-name>', 'Log out of one specific stored app')
|
|
9
|
+
.option('--all', 'Log out of every stored app and delete the credentials file')
|
|
10
|
+
.action(async (opts) => {
|
|
9
11
|
try {
|
|
10
|
-
await runLogout();
|
|
12
|
+
await runLogout(opts);
|
|
11
13
|
process.exitCode = 0;
|
|
12
14
|
}
|
|
13
15
|
catch (err) {
|
|
@@ -17,41 +19,79 @@ export function registerAuthLogoutCommand(auth) {
|
|
|
17
19
|
}
|
|
18
20
|
});
|
|
19
21
|
}
|
|
20
|
-
async function runLogout() {
|
|
22
|
+
async function runLogout(opts = {}) {
|
|
21
23
|
const stdout = process.stdout;
|
|
22
24
|
const stderr = process.stderr;
|
|
23
|
-
let
|
|
25
|
+
let entries;
|
|
24
26
|
try {
|
|
25
|
-
|
|
27
|
+
entries = listCredentials();
|
|
26
28
|
}
|
|
27
29
|
catch (err) {
|
|
28
|
-
// Malformed credentials file — still
|
|
30
|
+
// Malformed credentials file — still delete it so the user gets unstuck.
|
|
29
31
|
stderr.write(`Warning: existing credentials file at ${credentialsPath()} could not be parsed (${err instanceof Error ? err.message : String(err)}). Removing it.\n`);
|
|
30
|
-
|
|
32
|
+
deleteAllCredentials();
|
|
31
33
|
stdout.write('Logged out (credentials file removed).\n');
|
|
32
34
|
return;
|
|
33
35
|
}
|
|
34
|
-
if (
|
|
36
|
+
if (entries.length === 0) {
|
|
35
37
|
stdout.write('Not logged in.\n');
|
|
36
38
|
return;
|
|
37
39
|
}
|
|
40
|
+
if (opts.all) {
|
|
41
|
+
for (const entry of entries)
|
|
42
|
+
await revoke(entry.creds, stderr);
|
|
43
|
+
deleteAllCredentials();
|
|
44
|
+
resetManagementClient();
|
|
45
|
+
stdout.write(`Logged out of ${entries.length} app(s).\n`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
let target;
|
|
49
|
+
if (opts.profile) {
|
|
50
|
+
try {
|
|
51
|
+
target = findCredential(opts.profile);
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
if (err instanceof CredentialSelectorError)
|
|
55
|
+
throw new Error(err.message);
|
|
56
|
+
throw err;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
const active = readCredentials();
|
|
61
|
+
if (!active) {
|
|
62
|
+
// Several stored, none active. Removing one by guess is exactly the
|
|
63
|
+
// silent choice this ticket forbids.
|
|
64
|
+
throw new Error('No active credential. Name one with `--profile <label|app id>`, or use `--all`. ' +
|
|
65
|
+
`Stored: ${entries.map((e) => e.creds.label ?? e.creds.app.name).join(', ')}.`);
|
|
66
|
+
}
|
|
67
|
+
target = entries.find((e) => e.key === active.app.id);
|
|
68
|
+
}
|
|
69
|
+
await revoke(target.creds, stderr);
|
|
70
|
+
const remaining = removeCredential(target.key);
|
|
71
|
+
resetManagementClient();
|
|
72
|
+
const name = target.creds.label ?? target.creds.app.name;
|
|
73
|
+
stdout.write(`Logged out ${target.creds.user.email} from ${name}.\n`);
|
|
74
|
+
if (remaining > 0) {
|
|
75
|
+
const rest = listCredentials();
|
|
76
|
+
const nowActive = rest.find((e) => e.isActive);
|
|
77
|
+
stdout.write(` ${remaining} credential(s) still stored` +
|
|
78
|
+
(nowActive ? `; now using ${nowActive.creds.label ?? nowActive.creds.app.name}` : '') +
|
|
79
|
+
'.\n');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** Best-effort server-side revoke. Never fatal — local removal is the point. */
|
|
83
|
+
async function revoke(creds, stderr) {
|
|
38
84
|
const api = createCliApiClient({ baseUrl: creds.baseUrl });
|
|
39
85
|
try {
|
|
40
86
|
await api.revokeToken(creds.apiKey);
|
|
41
87
|
}
|
|
42
88
|
catch (err) {
|
|
43
|
-
// Network failure — warn but still proceed with local deletion.
|
|
44
89
|
if (err instanceof CliAuthApiError && err.code === 'network_error') {
|
|
45
|
-
stderr.write(`Warning: could not reach bridge-api to revoke server-side (${err.message}). Removing local credentials anyway.\n`);
|
|
90
|
+
stderr.write(`Warning: could not reach bridge-api to revoke ${creds.app.name} server-side (${err.message}). Removing local credentials anyway.\n`);
|
|
46
91
|
}
|
|
47
92
|
else {
|
|
48
|
-
|
|
49
|
-
// surface it so the user knows the server-side revoke didn't happen.
|
|
50
|
-
stderr.write(`Warning: server-side revoke returned an error (${err instanceof Error ? err.message : String(err)}). Removing local credentials anyway.\n`);
|
|
93
|
+
stderr.write(`Warning: server-side revoke for ${creds.app.name} returned an error (${err instanceof Error ? err.message : String(err)}). Removing local credentials anyway.\n`);
|
|
51
94
|
}
|
|
52
95
|
}
|
|
53
|
-
deleteCredentials();
|
|
54
|
-
resetManagementClient();
|
|
55
|
-
stdout.write(`Logged out ${creds.user.email}.\n`);
|
|
56
96
|
}
|
|
57
97
|
//# sourceMappingURL=logout.command.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logout.command.js","sourceRoot":"","sources":["../../../src/commands/auth/logout.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logout.command.js","sourceRoot":"","sources":["../../../src/commands/auth/logout.command.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
* optimize for readability over machine-parseability.
|
|
9
9
|
*
|
|
10
10
|
* If the user wants JSON, they can run `cat ~/.config/bridge/credentials.json`.
|
|
11
|
+
*
|
|
12
|
+
* TBP-628 — the file can hold several apps, so this lists ALL of them and marks
|
|
13
|
+
* the active one. Knowing which app is in force is the whole reason somebody
|
|
14
|
+
* runs this command, and it was already the only place that told them.
|
|
11
15
|
*/
|
|
12
16
|
import type { Command } from 'commander';
|
|
13
17
|
export declare function registerAuthStatusCommand(auth: Command): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.command.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/status.command.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"status.command.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/status.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUzC,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAc7D"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { credentialsPath, isExpired,
|
|
1
|
+
import { credentialsPath, isExpired, listCredentials, readCredentialsFile, } from '../../credentials.js';
|
|
2
2
|
import { formatRelativeTime } from '../../auth/relative-time.js';
|
|
3
3
|
export function registerAuthStatusCommand(auth) {
|
|
4
4
|
auth
|
|
@@ -18,18 +18,20 @@ export function registerAuthStatusCommand(auth) {
|
|
|
18
18
|
}
|
|
19
19
|
function runStatus() {
|
|
20
20
|
const stdout = process.stdout;
|
|
21
|
-
//
|
|
22
|
-
//
|
|
21
|
+
// Report on `BRIDGE_API_KEY` separately if set, so a CI user setting the env
|
|
22
|
+
// var sees something useful.
|
|
23
23
|
const envApiKey = process.env.BRIDGE_API_KEY?.trim();
|
|
24
|
-
|
|
24
|
+
const envProfile = process.env.BRIDGE_PROFILE?.trim();
|
|
25
|
+
let entries;
|
|
25
26
|
try {
|
|
26
|
-
|
|
27
|
+
readCredentialsFile();
|
|
28
|
+
entries = listCredentials();
|
|
27
29
|
}
|
|
28
30
|
catch (err) {
|
|
29
31
|
stdout.write(`Credentials file at ${credentialsPath()} is unreadable: ${err instanceof Error ? err.message : String(err)}\n` + 'Run `bridge auth login` to refresh, or delete the file manually.\n');
|
|
30
32
|
return;
|
|
31
33
|
}
|
|
32
|
-
if (
|
|
34
|
+
if (entries.length === 0) {
|
|
33
35
|
if (envApiKey && envApiKey.length > 0) {
|
|
34
36
|
stdout.write('Using BRIDGE_API_KEY from environment (service-account / CI path).\n' +
|
|
35
37
|
'Run `bridge auth login` to switch to interactive credentials.\n');
|
|
@@ -38,22 +40,51 @@ function runStatus() {
|
|
|
38
40
|
stdout.write('Not logged in. Run `bridge auth login`.\n');
|
|
39
41
|
return;
|
|
40
42
|
}
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
const active = entries.find((e) => e.isActive);
|
|
44
|
+
if (active) {
|
|
45
|
+
stdout.write(`Logged in as ${active.creds.user.email}\n`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// A pointer at a credential that is gone. Say so rather than picking one:
|
|
49
|
+
// an inferred default is exactly what this ticket is about.
|
|
50
|
+
stdout.write('No active credential selected — run `bridge auth use <profile>` to pick one.\n');
|
|
51
|
+
}
|
|
52
|
+
for (const entry of entries) {
|
|
53
|
+
writeEntry(entry, entries.length > 1);
|
|
54
|
+
}
|
|
51
55
|
stdout.write(` credentials=${credentialsPath()}\n`);
|
|
56
|
+
if (entries.length > 1) {
|
|
57
|
+
stdout.write('\nSwitch the default with `bridge auth use <label|app id>`, ' +
|
|
58
|
+
'or target one command with `--profile <label|app id>`.\n');
|
|
59
|
+
}
|
|
60
|
+
if (envProfile) {
|
|
61
|
+
stdout.write(`\nBRIDGE_PROFILE=${envProfile} is set — it overrides the active credential above.\n`);
|
|
62
|
+
}
|
|
52
63
|
if (envApiKey && envApiKey.length > 0) {
|
|
53
|
-
|
|
64
|
+
// This used to claim the opposite. The credentials file has always won;
|
|
65
|
+
// saying otherwise is how somebody comes to believe they retargeted the
|
|
66
|
+
// CLI when they did not (TBP-628).
|
|
67
|
+
stdout.write('\nNote: BRIDGE_API_KEY is set in your environment but is IGNORED while a ' +
|
|
68
|
+
'credentials file exists.\nTo use it, run `bridge auth logout --all`. ' +
|
|
69
|
+
'To target another stored app, use `--profile`.\n');
|
|
54
70
|
}
|
|
55
|
-
if (
|
|
56
|
-
|
|
71
|
+
if (process.env.BRIDGE_APP_ID?.trim()) {
|
|
72
|
+
stdout.write('\nNote: BRIDGE_APP_ID has no effect. The app is carried by the credential ' +
|
|
73
|
+
'itself; use `--profile <label|app id>` to target another one.\n');
|
|
57
74
|
}
|
|
58
75
|
}
|
|
76
|
+
function writeEntry(entry, showMarker) {
|
|
77
|
+
const stdout = process.stdout;
|
|
78
|
+
const { creds } = entry;
|
|
79
|
+
const expiryDelta = new Date(creds.expiresAt).getTime() - Date.now();
|
|
80
|
+
const expiryRel = formatRelativeTime(expiryDelta);
|
|
81
|
+
const expiredLabel = isExpired(creds) ? ' (EXPIRED)' : '';
|
|
82
|
+
const marker = showMarker ? (entry.isActive ? '* ' : ' ') : '';
|
|
83
|
+
stdout.write(` ${marker}app=${creds.app.name} (${creds.app.id})\n`);
|
|
84
|
+
if (creds.label)
|
|
85
|
+
stdout.write(` ${marker} label=${creds.label}\n`);
|
|
86
|
+
stdout.write(` ${marker} user=${creds.user.email}\n`);
|
|
87
|
+
stdout.write(` ${marker} expires=${expiryRel} — ${creds.expiresAt}${expiredLabel}\n`);
|
|
88
|
+
stdout.write(` ${marker} baseUrl=${creds.baseUrl}\n`);
|
|
89
|
+
}
|
|
59
90
|
//# sourceMappingURL=status.command.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.command.js","sourceRoot":"","sources":["../../../src/commands/auth/status.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"status.command.js","sourceRoot":"","sources":["../../../src/commands/auth/status.command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `bridge auth use <profile>` — move the persisted default to another stored
|
|
3
|
+
* credential, without a browser round-trip (TBP-628).
|
|
4
|
+
*
|
|
5
|
+
* The credential is already on disk with days left on it; switching is a
|
|
6
|
+
* pointer move. Before this existed the only way to change apps was
|
|
7
|
+
* `auth logout` + `auth login`, which discarded a perfectly valid token and
|
|
8
|
+
* cost a browser trip, so people did not switch — they ran commands against
|
|
9
|
+
* whichever app happened to be active and read the answers as if they came
|
|
10
|
+
* from the one they meant.
|
|
11
|
+
*
|
|
12
|
+
* For a single command, prefer `--profile` / `BRIDGE_PROFILE`: this command
|
|
13
|
+
* mutates state that other processes read.
|
|
14
|
+
*/
|
|
15
|
+
import type { Command } from 'commander';
|
|
16
|
+
export declare function registerAuthUseCommand(auth: Command): void;
|
|
17
|
+
//# sourceMappingURL=use.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use.command.d.ts","sourceRoot":"","sources":["../../../src/commands/auth/use.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUzC,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAc1D"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { CredentialSelectorError, findCredential, isExpired, listCredentials, setActiveCredential, } from '../../credentials.js';
|
|
2
|
+
import { resetManagementClient } from '../../config.js';
|
|
3
|
+
export function registerAuthUseCommand(auth) {
|
|
4
|
+
auth
|
|
5
|
+
.command('use <profile>')
|
|
6
|
+
.description('Switch the default app to another stored credential (no re-login)')
|
|
7
|
+
.action((profile) => {
|
|
8
|
+
try {
|
|
9
|
+
runUse(profile);
|
|
10
|
+
process.exitCode = 0;
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
14
|
+
process.stderr.write(`bridge auth use: ${msg}\n`);
|
|
15
|
+
process.exitCode = 1;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function runUse(profile) {
|
|
20
|
+
const stdout = process.stdout;
|
|
21
|
+
let entry;
|
|
22
|
+
try {
|
|
23
|
+
entry = findCredential(profile);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
if (err instanceof CredentialSelectorError)
|
|
27
|
+
throw new Error(err.message);
|
|
28
|
+
throw err;
|
|
29
|
+
}
|
|
30
|
+
setActiveCredential(entry.key);
|
|
31
|
+
resetManagementClient();
|
|
32
|
+
const name = entry.creds.label ?? entry.creds.app.name;
|
|
33
|
+
stdout.write(`Now using ${name} — ${entry.creds.app.name} (${entry.creds.app.id})\n`);
|
|
34
|
+
stdout.write(` baseUrl=${entry.creds.baseUrl}\n`);
|
|
35
|
+
// Switching TO an expired credential is allowed — it is the user's stated
|
|
36
|
+
// intent, and refusing would leave them unable to make it the default before
|
|
37
|
+
// re-authenticating it. But it must not be a surprise at the next command.
|
|
38
|
+
if (isExpired(entry.creds)) {
|
|
39
|
+
stdout.write(` WARNING: this credential expired ${entry.creds.expiresAt}. ` +
|
|
40
|
+
'Run `bridge auth login` to refresh it.\n');
|
|
41
|
+
}
|
|
42
|
+
const others = listCredentials().filter((e) => e.key !== entry.key);
|
|
43
|
+
if (others.length > 0) {
|
|
44
|
+
stdout.write(` also stored: ${others.map((e) => e.creds.label ?? e.creds.app.name).join(', ')}\n`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=use.command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use.command.js","sourceRoot":"","sources":["../../../src/commands/auth/use.command.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,SAAS,EACT,eAAe,EACf,mBAAmB,GACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,UAAU,sBAAsB,CAAC,IAAa;IAClD,IAAI;SACD,OAAO,CAAC,eAAe,CAAC;SACxB,WAAW,CAAC,mEAAmE,CAAC;SAChF,MAAM,CAAC,CAAC,OAAe,EAAE,EAAE;QAC1B,IAAI,CAAC;YACH,MAAM,CAAC,OAAO,CAAC,CAAC;YAChB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;YAClD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC;AAED,SAAS,MAAM,CAAC,OAAe;IAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAE9B,IAAI,KAAK,CAAC;IACV,IAAI,CAAC;QACH,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,uBAAuB;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzE,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,mBAAmB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,qBAAqB,EAAE,CAAC;IAExB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;IACvD,MAAM,CAAC,KAAK,CAAC,aAAa,IAAI,MAAM,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,KAAK,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IACtF,MAAM,CAAC,KAAK,CAAC,aAAa,KAAK,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC;IAEnD,0EAA0E;IAC1E,6EAA6E;IAC7E,2EAA2E;IAC3E,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,CAAC,KAAK,CACV,sCAAsC,KAAK,CAAC,KAAK,CAAC,SAAS,IAAI;YAC7D,0CAA0C,CAC7C,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,GAAG,CAAC,CAAC;IACpE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,KAAK,CACV,kBAAkB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CACtF,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* - `login` (TBP-113): browser-based PKCE auth.
|
|
6
6
|
* - `logout` (TBP-113): revoke + delete credentials.
|
|
7
7
|
* - `status` (TBP-113): show current login state.
|
|
8
|
+
* - `use` (TBP-628): switch the default app, offline.
|
|
8
9
|
* - `config`/`mfa`/`password-policy`: pre-existing app auth-config commands.
|
|
9
10
|
*/
|
|
10
11
|
import type { Command } from 'commander';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.command.d.ts","sourceRoot":"","sources":["../../src/commands/auth.command.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"auth.command.d.ts","sourceRoot":"","sources":["../../src/commands/auth.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAe3D"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { registerAuthLoginCommand } from './auth/login.command.js';
|
|
2
2
|
import { registerAuthLogoutCommand } from './auth/logout.command.js';
|
|
3
3
|
import { registerAuthStatusCommand } from './auth/status.command.js';
|
|
4
|
+
import { registerAuthUseCommand } from './auth/use.command.js';
|
|
4
5
|
import { registerAuthConfigCommands } from './auth/config.command.js';
|
|
5
6
|
export function registerAuthCommands(program) {
|
|
6
7
|
const auth = program
|
|
@@ -10,6 +11,8 @@ export function registerAuthCommands(program) {
|
|
|
10
11
|
registerAuthLoginCommand(auth);
|
|
11
12
|
registerAuthLogoutCommand(auth);
|
|
12
13
|
registerAuthStatusCommand(auth);
|
|
14
|
+
// TBP-628 — several apps side by side; switch without a browser round-trip.
|
|
15
|
+
registerAuthUseCommand(auth);
|
|
13
16
|
// Pre-existing — app-level auth configuration.
|
|
14
17
|
registerAuthConfigCommands(auth);
|
|
15
18
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.command.js","sourceRoot":"","sources":["../../src/commands/auth.command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auth.command.js","sourceRoot":"","sources":["../../src/commands/auth.command.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAEtE,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,MAAM,IAAI,GAAG,OAAO;SACjB,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,4DAA4D,CAAC,CAAC;IAE7E,qCAAqC;IACrC,wBAAwB,CAAC,IAAI,CAAC,CAAC;IAC/B,yBAAyB,CAAC,IAAI,CAAC,CAAC;IAChC,yBAAyB,CAAC,IAAI,CAAC,CAAC;IAEhC,4EAA4E;IAC5E,sBAAsB,CAAC,IAAI,CAAC,CAAC;IAE7B,+CAA+C;IAC/C,0BAA0B,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flag-init.command.d.ts","sourceRoot":"","sources":["../../src/commands/flag-init.command.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,MAAM,MAAM,cAAc,GACtB,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,SAAS,GACT,SAAS,CAAC;AAEd,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,OAAO,GAAG,IAAI,CA+DjE;AAID,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAwB1E;AAID,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"flag-init.command.d.ts","sourceRoot":"","sources":["../../src/commands/flag-init.command.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,MAAM,MAAM,cAAc,GACtB,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,SAAS,GACT,SAAS,CAAC;AAEd,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,OAAO,GAAG,IAAI,CA+DjE;AAID,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAwB1E;AAID,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,cAAc,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM,CA2ThF;AAuCD,mDAAmD;AACnD,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO/D"}
|
|
@@ -112,10 +112,13 @@ export function renderSnippet(framework, ctx) {
|
|
|
112
112
|
// "./client", server-side flags live under "./server".
|
|
113
113
|
// angular — ships a single ng-packagr entry point; everything comes
|
|
114
114
|
// from the bare specifier.
|
|
115
|
-
// nestjs —
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
//
|
|
115
|
+
// nestjs — declares "./flags" since 0.6.0 (TBP-613). Before that
|
|
116
|
+
// it had no `exports` map, so `<pkg>/flags` fell back to
|
|
117
|
+
// legacy resolution and 404'd, and this scaffolder
|
|
118
|
+
// emitted `<pkg>/dist/flags` instead. Reaching into the
|
|
119
|
+
// build directory was never right — it froze the dist
|
|
120
|
+
// layout into a public contract — and generating it here
|
|
121
|
+
// is how the wrong path spread. Requires >= 0.6.0.
|
|
119
122
|
// express — no `exports` map and no flags entry point; the flag
|
|
120
123
|
// surface is on the bare specifier.
|
|
121
124
|
const pkgFor = {
|
|
@@ -123,7 +126,7 @@ export function renderSnippet(framework, ctx) {
|
|
|
123
126
|
react: '@nebulr-group/bridge-react/flags',
|
|
124
127
|
nextjs: '@nebulr-group/bridge-nextjs/client',
|
|
125
128
|
angular: '@nebulr-group/bridge-angular',
|
|
126
|
-
nestjs: '@nebulr-group/bridge-nestjs/
|
|
129
|
+
nestjs: '@nebulr-group/bridge-nestjs/flags',
|
|
127
130
|
express: '@nebulr-group/bridge-express',
|
|
128
131
|
};
|
|
129
132
|
if (framework === 'unknown') {
|
|
@@ -324,9 +327,7 @@ export function renderSnippet(framework, ctx) {
|
|
|
324
327
|
' bun add @nebulr-group/bridge-nestjs',
|
|
325
328
|
' ```',
|
|
326
329
|
'',
|
|
327
|
-
'2. Import the module in `app.module.ts
|
|
328
|
-
' `exports` map, so `@nebulr-group/bridge-nestjs/flags` does not resolve',
|
|
329
|
-
' — import from `/dist/flags` until that is fixed:',
|
|
330
|
+
'2. Import the module in `app.module.ts` (requires bridge-nestjs >= 0.6.0):',
|
|
330
331
|
' ```ts',
|
|
331
332
|
` import { BridgeFlagsModule } from '${pkg}';`,
|
|
332
333
|
'',
|